From 532cdc58e657497cde9cfb163b37c08057ad387a Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Mon, 29 Jun 2009 07:51:04 +0000 Subject: 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 --- lib/Target/ARM/ARMAddressingModes.h | 2 +- lib/Target/ARM/ARMConstantIslandPass.cpp | 11 +- lib/Target/ARM/ARMISelDAGToDAG.cpp | 159 +++++++++++++++++++++----- lib/Target/ARM/ARMInstrFormats.td | 70 +++++++++--- lib/Target/ARM/ARMInstrInfo.h | 12 +- lib/Target/ARM/ARMInstrInfo.td | 37 ------ lib/Target/ARM/ARMInstrThumb.td | 28 ++--- lib/Target/ARM/ARMInstrThumb2.td | 44 ++++++++ lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp | 167 +++++++++++++++++++--------- lib/Target/ARM/README.txt | 7 ++ lib/Target/ARM/ThumbRegisterInfo.cpp | 6 +- test/CodeGen/ARM/ldr.ll | 50 +++++++-- test/CodeGen/Thumb2/thumb2-ldr.ll | 59 ++++++++++ 13 files changed, 489 insertions(+), 163 deletions(-) create mode 100644 test/CodeGen/Thumb2/thumb2-ldr.ll 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(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(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(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(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(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(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(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 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 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 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 : Pat { // Thumb Instruction Format Definitions. // - // TI - Thumb instruction. class ThumbI pattern> : ThumbI; -class TI1 pattern> - : ThumbI; -class TI2 pattern> - : ThumbI; -class TI4 pattern> - : ThumbI; -class TIs pattern> - : ThumbI; - -// Two-address instructions -class TIt pattern> - : ThumbI; // BL, BLX(1) are translated by assembler into two instructions class TIx2 pattern> @@ -764,6 +792,14 @@ class Thumb1I pattern> : Thumb1I; +class T1I1 pattern> + : Thumb1I; +class T1I2 pattern> + : Thumb1I; +class T1I4 pattern> + : Thumb1I; +class T1Is pattern> + : Thumb1I; // Two-address instructions class T1It pattern> @@ -812,6 +848,14 @@ class Thumb2XI pattern> : Thumb2I; +class T2Ii12 pattern> + : Thumb2I; +class T2Ii8 pattern> + : Thumb2I; +class T2Iso pattern> + : Thumb2I; +class T2Ipc pattern> + : Thumb2I; class T2sI pattern> : Thumb2sI; 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 { } //===----------------------------------------------------------------------===// -// ARM Instruction flags. These need to match ARMInstrInfo.h. -// - -// Addressing mode. -class AddrMode 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 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 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, + ComplexPattern { + let PrintMethod = "printT2AddrModeImm12Operand"; + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); +} + +// t2addrmode_imm8 := reg - imm8 +def t2addrmode_imm8 : Operand, + ComplexPattern { + let PrintMethod = "printT2AddrModeImm8Operand"; + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); +} + +// t2addrmode_so_reg := reg + reg << imm2 +def t2addrmode_so_reg : Operand, + ComplexPattern { + 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 ; [#uses=1] + %tmp = load i32* %v ret i32 %tmp } define i32 @f2(i32* %v) { entry: - %tmp2 = getelementptr i32* %v, i32 1023 ; [#uses=1] - %tmp = load i32* %tmp2 ; [#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 ; [#uses=1] - %tmp = load i32* %tmp2 ; [#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 +} -- cgit v1.1