Add load/store functionality

Summary:
This patches allows non conversions like i1=i2; where both are global ints.
In addition, arithmetic and other things start to work since fast-isel will use
existing patterns for non fast-isel from tablegen files where applicable.

In addition i8, i16 will work in this limited context for assignment without the need
for sign extension (zero or signed). It does not matter how i8 or i16 are loaded (zero or sign extended)
since only the 8 or 16 relevant bits are used and clang will ask for sign extension before using them in
arithmetic. This is all made more complete in forthcoming patches.

for example:
  int i, j=1, k=3;
 
  void foo() {
    i = j + k;
  }

Keep in mind that this pass is not enabled right now and is an experimental pass
It can only be enabled with a hidden option to llvm of -mips-fast-isel.

Test Plan: Run test-suite, loadstore2.ll and I will run some executable tests.

Reviewers: dsanders

Subscribers: mcrosier

Differential Revision: http://reviews.llvm.org/D3856

llvm-svn: 211061
This commit is contained in:
Reed Kotler 2014-06-16 22:05:47 +00:00
parent 79140826bc
commit 9fe3bfd087
2 changed files with 176 additions and 7 deletions

View File

@ -69,8 +69,11 @@ public:
bool ComputeAddress(const Value *Obj, Address &Addr);
private:
bool EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
unsigned Alignment = 0);
bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
unsigned Alignment = 0);
bool SelectLoad(const Instruction *I);
bool SelectRet(const Instruction *I);
bool SelectStore(const Instruction *I);
@ -105,6 +108,11 @@ private:
return EmitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset);
}
MachineInstrBuilder EmitInstLoad(unsigned Opc, unsigned DstReg,
unsigned MemReg, int64_t MemOffset) {
return EmitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset);
}
#include "MipsGenFastISel.inc"
};
@ -126,6 +134,8 @@ bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) {
// We will extend this in a later patch:
// If this is a type than can be sign or zero-extended to a basic operation
// go ahead and accept it now.
if (VT == MVT::i8 || VT == MVT::i16)
return true;
return false;
}
@ -142,6 +152,45 @@ bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) {
return Addr.Base.Reg != 0;
}
bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
unsigned Alignment) {
//
// more cases will be handled here in following patches.
//
unsigned Opc;
switch (VT.SimpleTy) {
case MVT::i32: {
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LW;
break;
}
case MVT::i16: {
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LHu;
break;
}
case MVT::i8: {
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LBu;
break;
}
case MVT::f32: {
ResultReg = createResultReg(&Mips::FGR32RegClass);
Opc = Mips::LWC1;
break;
}
case MVT::f64: {
ResultReg = createResultReg(&Mips::AFGR64RegClass);
Opc = Mips::LDC1;
break;
}
default:
return false;
}
EmitInstLoad(Opc, ResultReg, Addr.Base.Reg, Addr.Offset);
return true;
}
// Materialize a constant into a register, and return the register
// number (or zero if we failed to handle it).
unsigned MipsFastISel::TargetMaterializeConstant(const Constant *C) {
@ -167,14 +216,49 @@ bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
//
// more cases will be handled here in following patches.
//
if (VT == MVT::i32)
EmitInstStore(Mips::SW, SrcReg, Addr.Base.Reg, Addr.Offset);
else if (VT == MVT::f32)
EmitInstStore(Mips::SWC1, SrcReg, Addr.Base.Reg, Addr.Offset);
else if (VT == MVT::f64)
EmitInstStore(Mips::SDC1, SrcReg, Addr.Base.Reg, Addr.Offset);
else
unsigned Opc;
switch (VT.SimpleTy) {
case MVT::i8:
Opc = Mips::SB;
break;
case MVT::i16:
Opc = Mips::SH;
break;
case MVT::i32:
Opc = Mips::SW;
break;
case MVT::f32:
Opc = Mips::SWC1;
break;
case MVT::f64:
Opc = Mips::SDC1;
break;
default:
return false;
}
EmitInstStore(Opc, SrcReg, Addr.Base.Reg, Addr.Offset);
return true;
}
bool MipsFastISel::SelectLoad(const Instruction *I) {
// Atomic loads need special handling.
if (cast<LoadInst>(I)->isAtomic())
return false;
// Verify we have a legal type before going any further.
MVT VT;
if (!isLoadTypeLegal(I->getType(), VT))
return false;
// See if we can handle this address.
Address Addr;
if (!ComputeAddress(I->getOperand(0), Addr))
return false;
unsigned ResultReg;
if (!EmitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment()))
return false;
UpdateValueMap(I, ResultReg);
return true;
}
@ -224,6 +308,8 @@ bool MipsFastISel::TargetSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default:
break;
case Instruction::Load:
return SelectLoad(I);
case Instruction::Store:
return SelectStore(I);
case Instruction::Ret:

View File

@ -0,0 +1,83 @@
; ModuleID = 'loadstore2.c'
target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"
target triple = "mips--linux-gnu"
@c2 = common global i8 0, align 1
@c1 = common global i8 0, align 1
; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \
; RUN: < %s | FileCheck %s
@s2 = common global i16 0, align 2
@s1 = common global i16 0, align 2
@i2 = common global i32 0, align 4
@i1 = common global i32 0, align 4
@f2 = common global float 0.000000e+00, align 4
@f1 = common global float 0.000000e+00, align 4
@d2 = common global double 0.000000e+00, align 8
@d1 = common global double 0.000000e+00, align 8
; Function Attrs: nounwind
define void @cfoo() #0 {
entry:
%0 = load i8* @c2, align 1
store i8 %0, i8* @c1, align 1
; CHECK-LABEL: cfoo:
; CHECK: lbu $[[REGc:[0-9]+]], 0(${{[0-9]+}})
; CHECK: sb $[[REGc]], 0(${{[0-9]+}})
ret void
}
; Function Attrs: nounwind
define void @sfoo() #0 {
entry:
%0 = load i16* @s2, align 2
store i16 %0, i16* @s1, align 2
; CHECK-LABEL: sfoo:
; CHECK: lhu $[[REGs:[0-9]+]], 0(${{[0-9]+}})
; CHECK: sh $[[REGs]], 0(${{[0-9]+}})
ret void
}
; Function Attrs: nounwind
define void @ifoo() #0 {
entry:
%0 = load i32* @i2, align 4
store i32 %0, i32* @i1, align 4
; CHECK-LABEL: ifoo:
; CHECK: lw $[[REGi:[0-9]+]], 0(${{[0-9]+}})
; CHECK: sw $[[REGi]], 0(${{[0-9]+}})
ret void
}
; Function Attrs: nounwind
define void @ffoo() #0 {
entry:
%0 = load float* @f2, align 4
store float %0, float* @f1, align 4
; CHECK-LABEL: ffoo:
; CHECK: lwc1 $f[[REGf:[0-9]+]], 0(${{[0-9]+}})
; CHECK: swc1 $f[[REGf]], 0(${{[0-9]+}})
ret void
}
; Function Attrs: nounwind
define void @dfoo() #0 {
entry:
%0 = load double* @d2, align 8
store double %0, double* @d1, align 8
; CHECK-LABEL: dfoo:
; CHECK: ldc1 $f[[REGd:[0-9]+]], 0(${{[0-9]+}})
; CHECK: sdc1 $f[[REGd]], 0(${{[0-9]+}})
; CHECK: .end dfoo
ret void
}
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }