diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index 005eb7a10f9..bf79152093a 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 db723fe8325..d37e9f2cf04 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 200371bbaf7..7035064c7fe 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 d7371b02540..a98bf1e8567 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -58,6 +58,47 @@ def NEONDupFrm : Format<27>; // the instruction has a Rn register operand. 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 7e3aa6c7a36..ac1eec0921c 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 cb7b7b98c7c..611cb60a9d0 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -308,43 +308,6 @@ def cc_out : OptionalDefOperand { let PrintMethod = "printSBitModifierOperand"; } -//===----------------------------------------------------------------------===// -// 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 7927ca53b8f..dce0c1d5734 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 bfdf7192f4d..538fcc22a10 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 400f628aa56..45c6727c72a 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 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, + 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); -void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int opNum) { - ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(opNum).getImm(); + 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; + + 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 4223699b9d0..f3377f91ab9 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 513126f5712..751aa72beaf 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 23c0b99a862..ea996557231 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 00000000000..19c75849e11 --- /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 +}