/// 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)
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.
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,
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"
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) {
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) {
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);
// 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<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.
// Thumb Instruction Format Definitions.
//
-
// TI - Thumb instruction.
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>
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>
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>;
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,
let PrintMethod = "printSBitModifierOperand";
}
-//===----------------------------------------------------------------------===//
-// 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"
//
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", []>;
}
}], 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...
//
// 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.
//
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);
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();
O << "#" << lsb << ", #" << width;
}
+//===--------------------------------------------------------------------===//
+
void
ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) {
const MachineOperand &MO1 = MI->getOperand(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
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];
}
}
-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";
}
-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]) {
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())
// 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;
}
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).
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;
}
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;
}
// 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.
-; 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
+}
--- /dev/null
+; 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
+}