summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReed Kotler <rkotler@mips.com>2014-06-16 22:05:47 +0000
committerReed Kotler <rkotler@mips.com>2014-06-16 22:05:47 +0000
commit8b3a8d6343ae078a881abac4b5be067e74e5739a (patch)
treeacee7306f4e007ee9174fcee4a9a8577b8938e47
parent44d2cdcbf35d97b558198efa0861e0d289a657e6 (diff)
downloadllvm-8b3a8d6343ae078a881abac4b5be067e74e5739a.tar.gz
llvm-8b3a8d6343ae078a881abac4b5be067e74e5739a.tar.bz2
llvm-8b3a8d6343ae078a881abac4b5be067e74e5739a.tar.xz
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211061 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/Mips/MipsFastISel.cpp100
-rw-r--r--test/CodeGen/Mips/Fast-ISel/loadstore2.ll83
2 files changed, 176 insertions, 7 deletions
diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp
index 9a60aa7b9f..375d9b2055 100644
--- a/lib/Target/Mips/MipsFastISel.cpp
+++ b/lib/Target/Mips/MipsFastISel.cpp
@@ -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:
diff --git a/test/CodeGen/Mips/Fast-ISel/loadstore2.ll b/test/CodeGen/Mips/Fast-ISel/loadstore2.ll
new file mode 100644
index 0000000000..f113a0eb1d
--- /dev/null
+++ b/test/CodeGen/Mips/Fast-ISel/loadstore2.ll
@@ -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" }
+
+