aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Cheng <evan.cheng@apple.com>2009-06-29 07:51:04 +0000
committerEvan Cheng <evan.cheng@apple.com>2009-06-29 07:51:04 +0000
commit532cdc58e657497cde9cfb163b37c08057ad387a (patch)
tree6924272e732298bf99146b69c12f9029a5e1adc5
parentbfd255c0717ec4b7fcefa93ece7a3a190063a441 (diff)
downloadexternal_llvm-532cdc58e657497cde9cfb163b37c08057ad387a.zip
external_llvm-532cdc58e657497cde9cfb163b37c08057ad387a.tar.gz
external_llvm-532cdc58e657497cde9cfb163b37c08057ad387a.tar.bz2
Implement Thumb2 ldr.
After much back and forth, I decided to deviate from ARM design and split LDR into 4 instructions (r + imm12, r + imm8, r + r << imm12, constantpool). The advantage of this is 1) it follows the latest ARM technical manual, and 2) makes it easier to reduce the width of the instruction later. The down side is this creates more inconsistency between the two sub-targets. We should split ARM LDR instruction in a similar fashion later. I've added a README entry for this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74420 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/ARM/ARMAddressingModes.h2
-rw-r--r--lib/Target/ARM/ARMConstantIslandPass.cpp11
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp159
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td70
-rw-r--r--lib/Target/ARM/ARMInstrInfo.h12
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td37
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td28
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td44
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp167
-rw-r--r--lib/Target/ARM/README.txt7
-rw-r--r--lib/Target/ARM/ThumbRegisterInfo.cpp6
-rw-r--r--test/CodeGen/ARM/ldr.ll50
-rw-r--r--test/CodeGen/Thumb2/thumb2-ldr.ll59
13 files changed, 489 insertions, 163 deletions
diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h
index 005eb7a..bf79152 100644
--- a/lib/Target/ARM/ARMAddressingModes.h
+++ b/lib/Target/ARM/ARMAddressingModes.h
@@ -305,7 +305,7 @@ namespace ARM_AM {
/// abcdefgh abcdefgh abcdefgh abcdefgh control = 3
/// Return -1 if none of the above apply.
/// See ARM Reference Manual A6.3.2.
- static inline int getT2SOImmValSplat (unsigned V) {
+ static inline int getT2SOImmValSplat(unsigned V) {
unsigned u, Vs, Imm;
// control = 0
if ((V & 0xffffff00) == 0)
diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp
index db723fe..d37e9f2 100644
--- a/lib/Target/ARM/ARMConstantIslandPass.cpp
+++ b/lib/Target/ARM/ARMConstantIslandPass.cpp
@@ -447,21 +447,24 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn,
Bits = 8;
Scale = 4; // +-(offset_8*4)
break;
- case ARMII::AddrModeT1:
+ case ARMII::AddrModeT1_1:
Bits = 5; // +offset_5
break;
- case ARMII::AddrModeT2:
+ case ARMII::AddrModeT1_2:
Bits = 5;
Scale = 2; // +(offset_5*2)
break;
- case ARMII::AddrModeT4:
+ case ARMII::AddrModeT1_4:
Bits = 5;
Scale = 4; // +(offset_5*4)
break;
- case ARMII::AddrModeTs:
+ case ARMII::AddrModeT1_s:
Bits = 8;
Scale = 4; // +(offset_8*4)
break;
+ case ARMII::AddrModeT2_pc:
+ Bits = 12; // +-offset_12
+ break;
}
// Remember that this is a user of a CP entry.
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 200371b..7035064 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -64,6 +64,8 @@ public:
SDNode *Select(SDValue Op);
virtual void InstructionSelect();
+ bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A,
+ SDValue &B, SDValue &C);
bool SelectAddrMode2(SDValue Op, SDValue N, SDValue &Base,
SDValue &Offset, SDValue &Opc);
bool SelectAddrMode2Offset(SDValue Op, SDValue N,
@@ -92,10 +94,15 @@ public:
bool SelectThumbAddrModeSP(SDValue Op, SDValue N, SDValue &Base,
SDValue &OffImm);
- bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A,
- SDValue &B, SDValue &C);
bool SelectT2ShifterOperandReg(SDValue Op, SDValue N,
SDValue &BaseReg, SDValue &Opc);
+ bool SelectT2AddrModeImm12(SDValue Op, SDValue N, SDValue &Base,
+ SDValue &OffImm);
+ bool SelectT2AddrModeImm8(SDValue Op, SDValue N, SDValue &Base,
+ SDValue &OffImm);
+ bool SelectT2AddrModeSoReg(SDValue Op, SDValue N, SDValue &Base,
+ SDValue &OffReg, SDValue &ShImm);
+
// Include the pieces autogenerated from the target description.
#include "ARMGenDAGISel.inc"
@@ -116,6 +123,30 @@ void ARMDAGToDAGISel::InstructionSelect() {
CurDAG->RemoveDeadNodes();
}
+bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue Op,
+ SDValue N,
+ SDValue &BaseReg,
+ SDValue &ShReg,
+ SDValue &Opc) {
+ ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
+
+ // Don't match base register only case. That is matched to a separate
+ // lower complexity pattern with explicit register operand.
+ if (ShOpcVal == ARM_AM::no_shift) return false;
+
+ BaseReg = N.getOperand(0);
+ unsigned ShImmVal = 0;
+ if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ ShReg = CurDAG->getRegister(0, MVT::i32);
+ ShImmVal = RHS->getZExtValue() & 31;
+ } else {
+ ShReg = N.getOperand(1);
+ }
+ Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
+ MVT::i32);
+ return true;
+}
+
bool ARMDAGToDAGISel::SelectAddrMode2(SDValue Op, SDValue N,
SDValue &Base, SDValue &Offset,
SDValue &Opc) {
@@ -519,30 +550,6 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue Op, SDValue N,
return false;
}
-bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue Op,
- SDValue N,
- SDValue &BaseReg,
- SDValue &ShReg,
- SDValue &Opc) {
- ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
-
- // Don't match base register only case. That is matched to a separate
- // lower complexity pattern with explicit register operand.
- if (ShOpcVal == ARM_AM::no_shift) return false;
-
- BaseReg = N.getOperand(0);
- unsigned ShImmVal = 0;
- if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
- ShReg = CurDAG->getRegister(0, MVT::i32);
- ShImmVal = RHS->getZExtValue() & 31;
- } else {
- ShReg = N.getOperand(1);
- }
- Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
- MVT::i32);
- return true;
-}
-
bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue Op, SDValue N,
SDValue &BaseReg,
SDValue &Opc) {
@@ -563,6 +570,106 @@ bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue Op, SDValue N,
return false;
}
+bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue Op, SDValue N,
+ SDValue &Base, SDValue &OffImm) {
+ // Match simple R + imm12 operands.
+ if (N.getOpcode() != ISD::ADD)
+ return false;
+
+ if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ int RHSC = (int)RHS->getZExtValue();
+ if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits.
+ Base = N.getOperand(0);
+ OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue Op, SDValue N,
+ SDValue &Base, SDValue &OffImm) {
+ if (N.getOpcode() == ISD::ADD) {
+ if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ int RHSC = (int)RHS->getZExtValue();
+ if (RHSC < 0 && RHSC > -0x100) { // 8 bits.
+ Base = N.getOperand(0);
+ OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
+ return true;
+ }
+ }
+ } else if (N.getOpcode() == ISD::SUB) {
+ if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ int RHSC = (int)RHS->getZExtValue();
+ if (RHSC >= 0 && RHSC < 0x100) { // 8 bits.
+ Base = N.getOperand(0);
+ OffImm = CurDAG->getTargetConstant(-RHSC, MVT::i32);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue Op, SDValue N,
+ SDValue &Base,
+ SDValue &OffReg, SDValue &ShImm) {
+ // Base only.
+ if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) {
+ Base = N;
+ if (N.getOpcode() == ISD::FrameIndex) {
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
+ } else if (N.getOpcode() == ARMISD::Wrapper) {
+ Base = N.getOperand(0);
+ if (Base.getOpcode() == ISD::TargetConstantPool)
+ return false; // We want to select t2LDRpci instead.
+ }
+ OffReg = CurDAG->getRegister(0, MVT::i32);
+ ShImm = CurDAG->getTargetConstant(0, MVT::i32);
+ return true;
+ }
+
+ // Look for (R + R) or (R + (R << [1,2,3])).
+ unsigned ShAmt = 0;
+ Base = N.getOperand(0);
+ OffReg = N.getOperand(1);
+
+ // Swap if it is ((R << c) + R).
+ ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg);
+ if (ShOpcVal != ARM_AM::lsl) {
+ ShOpcVal = ARM_AM::getShiftOpcForNode(Base);
+ if (ShOpcVal == ARM_AM::lsl)
+ std::swap(Base, OffReg);
+ }
+
+ if (ShOpcVal == ARM_AM::lsl) {
+ // Check to see if the RHS of the shift is a constant, if not, we can't fold
+ // it.
+ if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) {
+ ShAmt = Sh->getZExtValue();
+ if (ShAmt >= 4) {
+ ShAmt = 0;
+ ShOpcVal = ARM_AM::no_shift;
+ } else
+ OffReg = OffReg.getOperand(0);
+ } else {
+ ShOpcVal = ARM_AM::no_shift;
+ }
+ } else if (SelectT2AddrModeImm12(Op, N, Base, ShImm) ||
+ SelectT2AddrModeImm8 (Op, N, Base, ShImm))
+ // Don't match if it's possible to match to one of the r +/- imm cases.
+ return false;
+
+ ShImm = CurDAG->getTargetConstant(ShAmt, MVT::i32);
+
+ return true;
+}
+
+//===--------------------------------------------------------------------===//
+
/// getAL - Returns a ARMCC::AL immediate node.
static inline SDValue getAL(SelectionDAG *CurDAG) {
return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32);
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index d7371b0..a98bf1e 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -59,6 +59,47 @@ def NEONDupFrm : Format<27>;
class UnaryDP { bit isUnaryDataProc = 1; }
//===----------------------------------------------------------------------===//
+// ARM Instruction flags. These need to match ARMInstrInfo.h.
+//
+
+// Addressing mode.
+class AddrMode<bits<4> val> {
+ bits<4> Value = val;
+}
+def AddrModeNone : AddrMode<0>;
+def AddrMode1 : AddrMode<1>;
+def AddrMode2 : AddrMode<2>;
+def AddrMode3 : AddrMode<3>;
+def AddrMode4 : AddrMode<4>;
+def AddrMode5 : AddrMode<5>;
+def AddrModeT1_1 : AddrMode<6>;
+def AddrModeT1_2 : AddrMode<7>;
+def AddrModeT1_4 : AddrMode<8>;
+def AddrModeT1_s : AddrMode<9>;
+def AddrModeT2_i12: AddrMode<10>;
+def AddrModeT2_i8 : AddrMode<11>;
+def AddrModeT2_so : AddrMode<12>;
+def AddrModeT2_pc : AddrMode<13>;
+
+// Instruction size.
+class SizeFlagVal<bits<3> val> {
+ bits<3> Value = val;
+}
+def SizeInvalid : SizeFlagVal<0>; // Unset.
+def SizeSpecial : SizeFlagVal<1>; // Pseudo or special.
+def Size8Bytes : SizeFlagVal<2>;
+def Size4Bytes : SizeFlagVal<3>;
+def Size2Bytes : SizeFlagVal<4>;
+
+// Load / store index mode.
+class IndexMode<bits<2> val> {
+ bits<2> Value = val;
+}
+def IndexModeNone : IndexMode<0>;
+def IndexModePre : IndexMode<1>;
+def IndexModePost : IndexMode<2>;
+
+//===----------------------------------------------------------------------===//
// ARM Instruction templates.
//
@@ -706,7 +747,6 @@ class ARMV6Pat<dag pattern, dag result> : Pat<pattern, result> {
// Thumb Instruction Format Definitions.
//
-
// TI - Thumb instruction.
class ThumbI<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
@@ -721,18 +761,6 @@ class ThumbI<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
class TI<dag outs, dag ins, string asm, list<dag> pattern>
: ThumbI<outs, ins, AddrModeNone, Size2Bytes, asm, "", pattern>;
-class TI1<dag outs, dag ins, string asm, list<dag> pattern>
- : ThumbI<outs, ins, AddrModeT1, Size2Bytes, asm, "", pattern>;
-class TI2<dag outs, dag ins, string asm, list<dag> pattern>
- : ThumbI<outs, ins, AddrModeT2, Size2Bytes, asm, "", pattern>;
-class TI4<dag outs, dag ins, string asm, list<dag> pattern>
- : ThumbI<outs, ins, AddrModeT4, Size2Bytes, asm, "", pattern>;
-class TIs<dag outs, dag ins, string asm, list<dag> pattern>
- : ThumbI<outs, ins, AddrModeTs, Size2Bytes, asm, "", pattern>;
-
-// Two-address instructions
-class TIt<dag outs, dag ins, string asm, list<dag> pattern>
- : ThumbI<outs, ins, AddrModeNone, Size2Bytes, asm, "$lhs = $dst", pattern>;
// BL, BLX(1) are translated by assembler into two instructions
class TIx2<dag outs, dag ins, string asm, list<dag> pattern>
@@ -764,6 +792,14 @@ class Thumb1I<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
class T1I<dag outs, dag ins, string asm, list<dag> pattern>
: Thumb1I<outs, ins, AddrModeNone, Size2Bytes, asm, "", pattern>;
+class T1I1<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeT1_1, Size2Bytes, asm, "", pattern>;
+class T1I2<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeT1_2, Size2Bytes, asm, "", pattern>;
+class T1I4<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeT1_4, Size2Bytes, asm, "", pattern>;
+class T1Is<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeT1_s, Size2Bytes, asm, "", pattern>;
// Two-address instructions
class T1It<dag outs, dag ins, string asm, list<dag> pattern>
@@ -812,6 +848,14 @@ class Thumb2XI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
class T2I<dag oops, dag iops, string opc, string asm, list<dag> pattern>
: Thumb2I<oops, iops, AddrModeNone, Size4Bytes, opc, asm, "", pattern>;
+class T2Ii12<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+ : Thumb2I<oops, iops, AddrModeT2_i12, Size4Bytes, opc, asm, "", pattern>;
+class T2Ii8<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+ : Thumb2I<oops, iops, AddrModeT2_i8, Size4Bytes, opc, asm, "", pattern>;
+class T2Iso<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+ : Thumb2I<oops, iops, AddrModeT2_so, Size4Bytes, opc, asm, "", pattern>;
+class T2Ipc<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+ : Thumb2I<oops, iops, AddrModeT2_pc, Size4Bytes, opc, asm, "", pattern>;
class T2sI<dag oops, dag iops, string opc, string asm, list<dag> pattern>
: Thumb2sI<oops, iops, AddrModeNone, Size4Bytes, opc, asm, "", pattern>;
diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h
index 7e3aa6c..ac1eec0 100644
--- a/lib/Target/ARM/ARMInstrInfo.h
+++ b/lib/Target/ARM/ARMInstrInfo.h
@@ -39,10 +39,14 @@ namespace ARMII {
AddrMode3 = 3,
AddrMode4 = 4,
AddrMode5 = 5,
- AddrModeT1 = 6,
- AddrModeT2 = 7,
- AddrModeT4 = 8,
- AddrModeTs = 9, // i8 * 4 for pc and sp relative data
+ AddrModeT1_1 = 6,
+ AddrModeT1_2 = 7,
+ AddrModeT1_4 = 8,
+ AddrModeT1_s = 9, // i8 * 4 for pc and sp relative data
+ AddrModeT2_i12= 10,
+ AddrModeT2_i8 = 11,
+ AddrModeT2_so = 12,
+ AddrModeT2_pc = 13, // +/- i12 for pc relative data
// Size* - Flags to keep track of the size of an instruction.
SizeShift = 4,
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index cb7b7b9..611cb60 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -309,43 +309,6 @@ def cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 zero_reg))> {
}
//===----------------------------------------------------------------------===//
-// ARM Instruction flags. These need to match ARMInstrInfo.h.
-//
-
-// Addressing mode.
-class AddrMode<bits<4> val> {
- bits<4> Value = val;
-}
-def AddrModeNone : AddrMode<0>;
-def AddrMode1 : AddrMode<1>;
-def AddrMode2 : AddrMode<2>;
-def AddrMode3 : AddrMode<3>;
-def AddrMode4 : AddrMode<4>;
-def AddrMode5 : AddrMode<5>;
-def AddrModeT1 : AddrMode<6>;
-def AddrModeT2 : AddrMode<7>;
-def AddrModeT4 : AddrMode<8>;
-def AddrModeTs : AddrMode<9>;
-
-// Instruction size.
-class SizeFlagVal<bits<3> val> {
- bits<3> Value = val;
-}
-def SizeInvalid : SizeFlagVal<0>; // Unset.
-def SizeSpecial : SizeFlagVal<1>; // Pseudo or special.
-def Size8Bytes : SizeFlagVal<2>;
-def Size4Bytes : SizeFlagVal<3>;
-def Size2Bytes : SizeFlagVal<4>;
-
-// Load / store index mode.
-class IndexMode<bits<2> val> {
- bits<2> Value = val;
-}
-def IndexModeNone : IndexMode<0>;
-def IndexModePre : IndexMode<1>;
-def IndexModePost : IndexMode<2>;
-
-//===----------------------------------------------------------------------===//
include "ARMInstrFormats.td"
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index 7927ca5..dce0c1d 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -211,68 +211,68 @@ let isBranch = 1, isTerminator = 1 in
//
let canFoldAsLoad = 1 in
-def tLDR : TI4<(outs tGPR:$dst), (ins t_addrmode_s4:$addr),
+def tLDR : T1I4<(outs tGPR:$dst), (ins t_addrmode_s4:$addr),
"ldr $dst, $addr",
[(set tGPR:$dst, (load t_addrmode_s4:$addr))]>;
-def tLDRB : TI1<(outs tGPR:$dst), (ins t_addrmode_s1:$addr),
+def tLDRB : T1I1<(outs tGPR:$dst), (ins t_addrmode_s1:$addr),
"ldrb $dst, $addr",
[(set tGPR:$dst, (zextloadi8 t_addrmode_s1:$addr))]>;
-def tLDRH : TI2<(outs tGPR:$dst), (ins t_addrmode_s2:$addr),
+def tLDRH : T1I2<(outs tGPR:$dst), (ins t_addrmode_s2:$addr),
"ldrh $dst, $addr",
[(set tGPR:$dst, (zextloadi16 t_addrmode_s2:$addr))]>;
-def tLDRSB : TI1<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
+def tLDRSB : T1I1<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
"ldrsb $dst, $addr",
[(set tGPR:$dst, (sextloadi8 t_addrmode_rr:$addr))]>;
-def tLDRSH : TI2<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
+def tLDRSH : T1I2<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
"ldrsh $dst, $addr",
[(set tGPR:$dst, (sextloadi16 t_addrmode_rr:$addr))]>;
let canFoldAsLoad = 1 in
-def tLDRspi : TIs<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
+def tLDRspi : T1Is<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
"ldr $dst, $addr",
[(set tGPR:$dst, (load t_addrmode_sp:$addr))]>;
// Special instruction for restore. It cannot clobber condition register
// when it's expanded by eliminateCallFramePseudoInstr().
let canFoldAsLoad = 1, mayLoad = 1 in
-def tRestore : TIs<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
+def tRestore : T1Is<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
"ldr $dst, $addr", []>;
// Load tconstpool
let canFoldAsLoad = 1 in
-def tLDRpci : TIs<(outs tGPR:$dst), (ins i32imm:$addr),
+def tLDRpci : T1Is<(outs tGPR:$dst), (ins i32imm:$addr),
"ldr $dst, $addr",
[(set tGPR:$dst, (load (ARMWrapper tconstpool:$addr)))]>;
// Special LDR for loads from non-pc-relative constpools.
let canFoldAsLoad = 1, mayLoad = 1, isReMaterializable = 1 in
-def tLDRcp : TIs<(outs tGPR:$dst), (ins i32imm:$addr),
+def tLDRcp : T1Is<(outs tGPR:$dst), (ins i32imm:$addr),
"ldr $dst, $addr", []>;
-def tSTR : TI4<(outs), (ins tGPR:$src, t_addrmode_s4:$addr),
+def tSTR : T1I4<(outs), (ins tGPR:$src, t_addrmode_s4:$addr),
"str $src, $addr",
[(store tGPR:$src, t_addrmode_s4:$addr)]>;
-def tSTRB : TI1<(outs), (ins tGPR:$src, t_addrmode_s1:$addr),
+def tSTRB : T1I1<(outs), (ins tGPR:$src, t_addrmode_s1:$addr),
"strb $src, $addr",
[(truncstorei8 tGPR:$src, t_addrmode_s1:$addr)]>;
-def tSTRH : TI2<(outs), (ins tGPR:$src, t_addrmode_s2:$addr),
+def tSTRH : T1I2<(outs), (ins tGPR:$src, t_addrmode_s2:$addr),
"strh $src, $addr",
[(truncstorei16 tGPR:$src, t_addrmode_s2:$addr)]>;
-def tSTRspi : TIs<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
+def tSTRspi : T1Is<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
"str $src, $addr",
[(store tGPR:$src, t_addrmode_sp:$addr)]>;
let mayStore = 1 in {
// Special instruction for spill. It cannot clobber condition register
// when it's expanded by eliminateCallFramePseudoInstr().
-def tSpill : TIs<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
+def tSpill : T1Is<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
"str $src, $addr", []>;
}
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index bfdf719..538fcc2 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -127,6 +127,30 @@ def t2_lo16AllZero : PatLeaf<(i32 imm), [{
}], t2_hi16>;
+// Define Thumb2 specific addressing modes.
+
+// t2addrmode_imm12 := reg + imm12
+def t2addrmode_imm12 : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectT2AddrModeImm12", []> {
+ let PrintMethod = "printT2AddrModeImm12Operand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+
+// t2addrmode_imm8 := reg - imm8
+def t2addrmode_imm8 : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
+ let PrintMethod = "printT2AddrModeImm8Operand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+
+// t2addrmode_so_reg := reg + reg << imm2
+def t2addrmode_so_reg : Operand<i32>,
+ ComplexPattern<i32, 3, "SelectT2AddrModeSoReg", []> {
+ let PrintMethod = "printT2AddrModeSoRegOperand";
+ let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
+}
+
+
//===----------------------------------------------------------------------===//
// Multiclass helpers...
//
@@ -409,6 +433,26 @@ def t2ADDrSPs : T2XI<(outs GPR:$dst), (ins GPR:$sp, t2_so_reg:$rhs),
// Load / store Instructions.
//
+// Load
+let canFoldAsLoad = 1 in {
+def t2LDRi12 : T2Ii12<(outs GPR:$dst), (ins t2addrmode_imm12:$addr),
+ "ldr", " $dst, $addr",
+ [(set GPR:$dst, (load t2addrmode_imm12:$addr))]>;
+
+def t2LDRi8 : T2Ii8<(outs GPR:$dst), (ins t2addrmode_imm8:$addr),
+ "ldr", " $dst, $addr",
+ [(set GPR:$dst, (load t2addrmode_imm8:$addr))]>;
+
+def t2LDRs : T2Iso<(outs GPR:$dst), (ins t2addrmode_so_reg:$addr),
+ "ldr", " $dst, $addr",
+ [(set GPR:$dst, (load t2addrmode_so_reg:$addr))]>;
+
+// Load tconstpool
+def t2LDRpci : T2Ipc<(outs GPR:$dst), (ins i32imm:$addr),
+ "ldr", " $dst, $addr",
+ [(set GPR:$dst, (load (ARMWrapper tconstpool:$addr)))]>;
+} // canFoldAsLoad
+
//===----------------------------------------------------------------------===//
// Move Instructions.
//
diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
index 400f628..45c6727 100644
--- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
+++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
@@ -93,45 +93,48 @@ namespace {
return "ARM Assembly Printer";
}
- void printOperand(const MachineInstr *MI, int opNum,
+ void printOperand(const MachineInstr *MI, int OpNum,
const char *Modifier = 0);
- void printSOImmOperand(const MachineInstr *MI, int opNum);
- void printSOImm2PartOperand(const MachineInstr *MI, int opNum);
- void printSORegOperand(const MachineInstr *MI, int opNum);
- void printAddrMode2Operand(const MachineInstr *MI, int OpNo);
- void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNo);
- void printAddrMode3Operand(const MachineInstr *MI, int OpNo);
- void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNo);
- void printAddrMode4Operand(const MachineInstr *MI, int OpNo,
+ void printSOImmOperand(const MachineInstr *MI, int OpNum);
+ void printSOImm2PartOperand(const MachineInstr *MI, int OpNum);
+ void printSORegOperand(const MachineInstr *MI, int OpNum);
+ void printAddrMode2Operand(const MachineInstr *MI, int OpNum);
+ void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum);
+ void printAddrMode3Operand(const MachineInstr *MI, int OpNum);
+ void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum);
+ void printAddrMode4Operand(const MachineInstr *MI, int OpNum,
const char *Modifier = 0);
- void printAddrMode5Operand(const MachineInstr *MI, int OpNo,
+ void printAddrMode5Operand(const MachineInstr *MI, int OpNum,
const char *Modifier = 0);
- void printAddrModePCOperand(const MachineInstr *MI, int OpNo,
+ void printAddrModePCOperand(const MachineInstr *MI, int OpNum,
const char *Modifier = 0);
- void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNo);
+ void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNum);
- void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNo);
- void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNo,
+ void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum);
+ void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum,
unsigned Scale);
- void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNo);
- void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNo);
- void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNo);
- void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNo);
+ void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum);
+ void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum);
+ void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum);
+ void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum);
- void printT2SOImmOperand(const MachineInstr *MI, int opNum);
+ void printT2SOImmOperand(const MachineInstr *MI, int OpNum);
void printT2SOOperand(const MachineInstr *MI, int OpNum);
-
- void printPredicateOperand(const MachineInstr *MI, int opNum);
- void printSBitModifierOperand(const MachineInstr *MI, int opNum);
- void printPCLabel(const MachineInstr *MI, int opNum);
- void printRegisterList(const MachineInstr *MI, int opNum);
- void printCPInstOperand(const MachineInstr *MI, int opNum,
+ void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum);
+ void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum);
+ void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum);
+
+ void printPredicateOperand(const MachineInstr *MI, int OpNum);
+ void printSBitModifierOperand(const MachineInstr *MI, int OpNum);
+ void printPCLabel(const MachineInstr *MI, int OpNum);
+ void printRegisterList(const MachineInstr *MI, int OpNum);
+ void printCPInstOperand(const MachineInstr *MI, int OpNum,
const char *Modifier);
- void printJTBlockOperand(const MachineInstr *MI, int opNum);
+ void printJTBlockOperand(const MachineInstr *MI, int OpNum);
- virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
unsigned AsmVariant, const char *ExtraCode);
- virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+ virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
unsigned AsmVariant,
const char *ExtraCode);
@@ -282,9 +285,9 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
return false;
}
-void ARMAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
+void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
const char *Modifier) {
- const MachineOperand &MO = MI->getOperand(opNum);
+ const MachineOperand &MO = MI->getOperand(OpNum);
switch (MO.getType()) {
case MachineOperand::MO_Register: {
unsigned Reg = MO.getReg();
@@ -606,6 +609,8 @@ ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op) {
O << "#" << lsb << ", #" << width;
}
+//===--------------------------------------------------------------------===//
+
void
ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) {
const MachineOperand &MO1 = MI->getOperand(Op);
@@ -659,6 +664,8 @@ void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op) {
O << "]";
}
+//===--------------------------------------------------------------------===//
+
/// printT2SOImmOperand - T2SOImm is:
/// 1. a 4-bit splat control value and 8 bit immediate value
/// 2. a 5-bit rotate amount and a non-zero 8-bit immediate value
@@ -694,47 +701,99 @@ void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum) {
O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
}
+void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI,
+ int OpNum) {
+ const MachineOperand &MO1 = MI->getOperand(OpNum);
+ const MachineOperand &MO2 = MI->getOperand(OpNum+1);
+
+ O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).AsmName;
+
+ unsigned OffImm = MO2.getImm();
+ if (OffImm) // Don't print +0.
+ O << ", #+" << OffImm;
+ O << "]";
+}
+
+void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI,
+ int OpNum) {
+ const MachineOperand &MO1 = MI->getOperand(OpNum);
+ const MachineOperand &MO2 = MI->getOperand(OpNum+1);
+
+ O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).AsmName;
+
+ int32_t OffImm = (int32_t)MO2.getImm();
+ // Don't print +0.
+ if (OffImm < 0)
+ O << ", #-" << -OffImm;
+ else if (OffImm > 0)
+ O << ", #+" << OffImm;
+ O << "]";
+}
+
+void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
+ int OpNum) {
+ const MachineOperand &MO1 = MI->getOperand(OpNum);
+ const MachineOperand &MO2 = MI->getOperand(OpNum+1);
+ const MachineOperand &MO3 = MI->getOperand(OpNum+2);
+
+ O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).AsmName;
+
+ if (MO2.getReg()) {
+ O << ", +"
+ << TM.getRegisterInfo()->get(MO2.getReg()).AsmName;
-void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int opNum) {
- ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(opNum).getImm();
+ unsigned ShAmt = MO3.getImm();
+ if (ShAmt) {
+ assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!");
+ O << ", lsl #" << ShAmt;
+ }
+ }
+ O << "]";
+}
+
+
+//===--------------------------------------------------------------------===//
+
+void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum) {
+ ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
if (CC != ARMCC::AL)
O << ARMCondCodeToString(CC);
}
-void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int opNum){
- unsigned Reg = MI->getOperand(opNum).getReg();
+void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum){
+ unsigned Reg = MI->getOperand(OpNum).getReg();
if (Reg) {
assert(Reg == ARM::CPSR && "Expect ARM CPSR register!");
O << 's';
}
}
-void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int opNum) {
- int Id = (int)MI->getOperand(opNum).getImm();
+void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum) {
+ int Id = (int)MI->getOperand(OpNum).getImm();
O << TAI->getPrivateGlobalPrefix() << "PC" << Id;
}
-void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int opNum) {
+void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum) {
O << "{";
- for (unsigned i = opNum, e = MI->getNumOperands(); i != e; ++i) {
+ for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) {
printOperand(MI, i);
if (i != e-1) O << ", ";
}
O << "}";
}
-void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNo,
+void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum,
const char *Modifier) {
assert(Modifier && "This operand only works with a modifier!");
// There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the
// data itself.
if (!strcmp(Modifier, "label")) {
- unsigned ID = MI->getOperand(OpNo).getImm();
+ unsigned ID = MI->getOperand(OpNum).getImm();
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
<< '_' << ID << ":\n";
} else {
assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE");
- unsigned CPI = MI->getOperand(OpNo).getIndex();
+ unsigned CPI = MI->getOperand(OpNum).getIndex();
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI];
@@ -746,9 +805,9 @@ void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNo,
}
}
-void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNo) {
- const MachineOperand &MO1 = MI->getOperand(OpNo);
- const MachineOperand &MO2 = MI->getOperand(OpNo+1); // Unique Id
+void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum) {
+ const MachineOperand &MO1 = MI->getOperand(OpNum);
+ const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
unsigned JTI = MO1.getIndex();
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << JTI << '_' << MO2.getImm() << ":\n";
@@ -787,7 +846,7 @@ void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNo) {
}
-bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
unsigned AsmVariant, const char *ExtraCode){
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
@@ -797,10 +856,10 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
default: return true; // Unknown modifier.
case 'a': // Don't print "#" before a global var name or constant.
case 'c': // Don't print "$" before a global var name or constant.
- printOperand(MI, OpNo, "no_hash");
+ printOperand(MI, OpNum, "no_hash");
return false;
case 'P': // Print a VFP double precision register.
- printOperand(MI, OpNo);
+ printOperand(MI, OpNum);
return false;
case 'Q':
if (TM.getTargetData()->isLittleEndian())
@@ -812,24 +871,24 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
// Fallthrough
case 'H': // Write second word of DI / DF reference.
// Verify that this operand has two consecutive registers.
- if (!MI->getOperand(OpNo).isReg() ||
- OpNo+1 == MI->getNumOperands() ||
- !MI->getOperand(OpNo+1).isReg())
+ if (!MI->getOperand(OpNum).isReg() ||
+ OpNum+1 == MI->getNumOperands() ||
+ !MI->getOperand(OpNum+1).isReg())
return true;
- ++OpNo; // Return the high-part.
+ ++OpNum; // Return the high-part.
}
}
- printOperand(MI, OpNo);
+ printOperand(MI, OpNum);
return false;
}
bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
- unsigned OpNo, unsigned AsmVariant,
+ unsigned OpNum, unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
- printAddrMode2Operand(MI, OpNo);
+ printAddrMode2Operand(MI, OpNum);
return false;
}
diff --git a/lib/Target/ARM/README.txt b/lib/Target/ARM/README.txt
index 4223699..f3377f9 100644
--- a/lib/Target/ARM/README.txt
+++ b/lib/Target/ARM/README.txt
@@ -530,3 +530,10 @@ those operations and the ARMv6 scalar versions.
ARM::MOVCCr is commutable (by flipping the condition). But we need to implement
ARMInstrInfo::commuteInstruction() to support it.
+
+//===---------------------------------------------------------------------===//
+
+Split out LDR (literal) from normal ARM LDR instruction. Also consider spliting
+LDR into imm12 and so_reg forms. This allows us to clean up some code. e.g.
+ARMLoadStoreOptimizer does not need to look at LDR (literal) and LDR (so_reg)
+while ARMConstantIslandPass only need to worry about LDR (literal).
diff --git a/lib/Target/ARM/ThumbRegisterInfo.cpp b/lib/Target/ARM/ThumbRegisterInfo.cpp
index 513126f..751aa72 100644
--- a/lib/Target/ARM/ThumbRegisterInfo.cpp
+++ b/lib/Target/ARM/ThumbRegisterInfo.cpp
@@ -444,7 +444,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
unsigned NumBits = 0;
unsigned Scale = 1;
switch (AddrMode) {
- case ARMII::AddrModeTs: {
+ case ARMII::AddrModeT1_s: {
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
@@ -472,7 +472,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
}
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
- if (AddrMode == ARMII::AddrModeTs) {
+ if (AddrMode == ARMII::AddrModeT1_s) {
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
// a different base register.
NumBits = 5;
@@ -480,7 +480,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
}
// If this is a thumb spill / restore, we will be using a constpool load to
// materialize the offset.
- if (AddrMode == ARMII::AddrModeTs && isThumSpillRestore)
+ if (AddrMode == ARMII::AddrModeT1_s && isThumSpillRestore)
ImmOp.ChangeToImmediate(0);
else {
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
diff --git a/test/CodeGen/ARM/ldr.ll b/test/CodeGen/ARM/ldr.ll
index 23c0b99..ea99655 100644
--- a/test/CodeGen/ARM/ldr.ll
+++ b/test/CodeGen/ARM/ldr.ll
@@ -1,23 +1,59 @@
-; RUN: llvm-as < %s | llc -march=arm | \
-; RUN: grep {ldr r0} | count 3
+; RUN: llvm-as < %s | llc -march=arm | grep {ldr r0} | count 7
+; RUN: llvm-as < %s | llc -march=arm | grep mov | grep 1
+; RUN: llvm-as < %s | llc -march=arm | not grep mvn
+; RUN: llvm-as < %s | llc -march=arm | grep ldr | grep lsl
+; RUN: llvm-as < %s | llc -march=arm | grep ldr | grep lsr
define i32 @f1(i32* %v) {
entry:
- %tmp = load i32* %v ; <i32> [#uses=1]
+ %tmp = load i32* %v
ret i32 %tmp
}
define i32 @f2(i32* %v) {
entry:
- %tmp2 = getelementptr i32* %v, i32 1023 ; <i32*> [#uses=1]
- %tmp = load i32* %tmp2 ; <i32> [#uses=1]
+ %tmp2 = getelementptr i32* %v, i32 1023
+ %tmp = load i32* %tmp2
ret i32 %tmp
}
define i32 @f3(i32* %v) {
entry:
- %tmp2 = getelementptr i32* %v, i32 1024 ; <i32*> [#uses=1]
- %tmp = load i32* %tmp2 ; <i32> [#uses=1]
+ %tmp2 = getelementptr i32* %v, i32 1024
+ %tmp = load i32* %tmp2
ret i32 %tmp
}
+define i32 @f4(i32 %base) {
+entry:
+ %tmp1 = sub i32 %base, 128
+ %tmp2 = inttoptr i32 %tmp1 to i32*
+ %tmp3 = load i32* %tmp2
+ ret i32 %tmp3
+}
+
+define i32 @f5(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = add i32 %base, %offset
+ %tmp2 = inttoptr i32 %tmp1 to i32*
+ %tmp3 = load i32* %tmp2
+ ret i32 %tmp3
+}
+
+define i32 @f6(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = shl i32 %offset, 2
+ %tmp2 = add i32 %base, %tmp1
+ %tmp3 = inttoptr i32 %tmp2 to i32*
+ %tmp4 = load i32* %tmp3
+ ret i32 %tmp4
+}
+
+define i32 @f7(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = lshr i32 %offset, 2
+ %tmp2 = add i32 %base, %tmp1
+ %tmp3 = inttoptr i32 %tmp2 to i32*
+ %tmp4 = load i32* %tmp3
+ ret i32 %tmp4
+}
diff --git a/test/CodeGen/Thumb2/thumb2-ldr.ll b/test/CodeGen/Thumb2/thumb2-ldr.ll
new file mode 100644
index 0000000..19c7584
--- /dev/null
+++ b/test/CodeGen/Thumb2/thumb2-ldr.ll
@@ -0,0 +1,59 @@
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep {ldr r0} | count 7
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep 1
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | not grep mvn
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ldr | grep lsl
+; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsr | not grep ldr
+
+define i32 @f1(i32* %v) {
+entry:
+ %tmp = load i32* %v
+ ret i32 %tmp
+}
+
+define i32 @f2(i32* %v) {
+entry:
+ %tmp2 = getelementptr i32* %v, i32 1023
+ %tmp = load i32* %tmp2
+ ret i32 %tmp
+}
+
+define i32 @f3(i32* %v) {
+entry:
+ %tmp2 = getelementptr i32* %v, i32 1024
+ %tmp = load i32* %tmp2
+ ret i32 %tmp
+}
+
+define i32 @f4(i32 %base) {
+entry:
+ %tmp1 = sub i32 %base, 128
+ %tmp2 = inttoptr i32 %tmp1 to i32*
+ %tmp3 = load i32* %tmp2
+ ret i32 %tmp3
+}
+
+define i32 @f5(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = add i32 %base, %offset
+ %tmp2 = inttoptr i32 %tmp1 to i32*
+ %tmp3 = load i32* %tmp2
+ ret i32 %tmp3
+}
+
+define i32 @f6(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = shl i32 %offset, 2
+ %tmp2 = add i32 %base, %tmp1
+ %tmp3 = inttoptr i32 %tmp2 to i32*
+ %tmp4 = load i32* %tmp3
+ ret i32 %tmp4
+}
+
+define i32 @f7(i32 %base, i32 %offset) {
+entry:
+ %tmp1 = lshr i32 %offset, 2
+ %tmp2 = add i32 %base, %tmp1
+ %tmp3 = inttoptr i32 %tmp2 to i32*
+ %tmp4 = load i32* %tmp3
+ ret i32 %tmp4
+}