summaryrefslogtreecommitdiff
path: root/lib/Target/ARM
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/ARM')
-rw-r--r--lib/Target/ARM/ARM.h18
-rw-r--r--lib/Target/ARM/ARMCodeEmitter.cpp4
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp53
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp2
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td73
-rw-r--r--lib/Target/ARM/ARMInstrInfo.cpp267
-rw-r--r--lib/Target/ARM/ARMInstrInfo.h110
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td135
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td281
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td444
-rw-r--r--lib/Target/ARM/ARMTargetAsmInfo.cpp4
-rw-r--r--lib/Target/ARM/ARMTargetAsmInfo.h6
-rw-r--r--lib/Target/ARM/ARMTargetMachine.cpp102
-rw-r--r--lib/Target/ARM/ARMTargetMachine.h63
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp128
-rw-r--r--lib/Target/ARM/AsmPrinter/CMakeLists.txt1
-rw-r--r--lib/Target/ARM/CMakeLists.txt1
-rw-r--r--lib/Target/ARM/README.txt52
-rw-r--r--lib/Target/ARM/ThumbInstrInfo.cpp282
-rw-r--r--lib/Target/ARM/ThumbInstrInfo.h85
20 files changed, 1313 insertions, 798 deletions
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
index 7edd1180f2786..8bf1b7c00400c 100644
--- a/lib/Target/ARM/ARM.h
+++ b/lib/Target/ARM/ARM.h
@@ -20,7 +20,7 @@
namespace llvm {
-class ARMTargetMachine;
+class ARMBaseTargetMachine;
class FunctionPass;
class MachineCodeEmitter;
class JITCodeEmitter;
@@ -28,8 +28,8 @@ class raw_ostream;
// Enums corresponding to ARM condition codes
namespace ARMCC {
- // The CondCodes constants map directly to the 4-bit encoding of the
- // condition field for predicated instructions.
+ // The CondCodes constants map directly to the 4-bit encoding of the
+ // condition field for predicated instructions.
enum CondCodes {
EQ,
NE,
@@ -47,7 +47,7 @@ namespace ARMCC {
LE,
AL
};
-
+
inline static CondCodes getOppositeCondition(CondCodes CC){
switch (CC) {
default: assert(0 && "Unknown condition code");
@@ -90,17 +90,17 @@ inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) {
}
}
-FunctionPass *createARMISelDag(ARMTargetMachine &TM);
+FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM);
FunctionPass *createARMCodePrinterPass(raw_ostream &O,
- ARMTargetMachine &TM,
+ ARMBaseTargetMachine &TM,
CodeGenOpt::Level OptLevel,
bool Verbose);
-FunctionPass *createARMCodeEmitterPass(ARMTargetMachine &TM,
+FunctionPass *createARMCodeEmitterPass(ARMBaseTargetMachine &TM,
MachineCodeEmitter &MCE);
-FunctionPass *createARMCodeEmitterPass(ARMTargetMachine &TM,
+FunctionPass *createARMCodeEmitterPass(ARMBaseTargetMachine &TM,
MachineCodeEmitter &MCE);
-FunctionPass *createARMJITCodeEmitterPass(ARMTargetMachine &TM,
+FunctionPass *createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM,
JITCodeEmitter &JCE);
FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false);
diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp
index f6629fe3c8758..8424c2eaed1d7 100644
--- a/lib/Target/ARM/ARMCodeEmitter.cpp
+++ b/lib/Target/ARM/ARMCodeEmitter.cpp
@@ -176,11 +176,11 @@ namespace {
namespace llvm {
-FunctionPass *createARMCodeEmitterPass(ARMTargetMachine &TM,
+FunctionPass *createARMCodeEmitterPass(ARMBaseTargetMachine &TM,
MachineCodeEmitter &MCE) {
return new Emitter<MachineCodeEmitter>(TM, MCE);
}
-FunctionPass *createARMJITCodeEmitterPass(ARMTargetMachine &TM,
+FunctionPass *createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM,
JITCodeEmitter &JCE) {
return new Emitter<JITCodeEmitter>(TM, JCE);
}
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index be543a91ef26e..200371bbaf75a 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -41,14 +41,14 @@ static const unsigned arm_dsubreg_1 = 6;
///
namespace {
class ARMDAGToDAGISel : public SelectionDAGISel {
- ARMTargetMachine &TM;
+ ARMBaseTargetMachine &TM;
/// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
/// make the right decision when generating code for different targets.
const ARMSubtarget *Subtarget;
public:
- explicit ARMDAGToDAGISel(ARMTargetMachine &tm)
+ explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm)
: SelectionDAGISel(tm), TM(tm),
Subtarget(&TM.getSubtarget<ARMSubtarget>()) {
}
@@ -92,11 +92,10 @@ public:
bool SelectThumbAddrModeSP(SDValue Op, SDValue N, SDValue &Base,
SDValue &OffImm);
- bool SelectThumb2ShifterOperandReg(SDValue Op, SDValue N,
- SDValue &BaseReg, SDValue &Opc);
-
bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A,
SDValue &B, SDValue &C);
+ bool SelectT2ShifterOperandReg(SDValue Op, SDValue N,
+ SDValue &BaseReg, SDValue &Opc);
// Include the pieces autogenerated from the target description.
#include "ARMGenDAGISel.inc"
@@ -520,28 +519,6 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue Op, SDValue N,
return false;
}
-bool ARMDAGToDAGISel::SelectThumb2ShifterOperandReg(SDValue Op,
- SDValue N,
- SDValue &BaseReg,
- 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)))
- ShImmVal = RHS->getZExtValue() & 31;
- else
- return false;
-
- Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal));
-
- return true;
-}
-
bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue Op,
SDValue N,
SDValue &BaseReg,
@@ -566,6 +543,26 @@ bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue Op,
return true;
}
+bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue Op, SDValue N,
+ SDValue &BaseReg,
+ 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))) {
+ ShImmVal = RHS->getZExtValue() & 31;
+ Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal));
+ return true;
+ }
+
+ return false;
+}
+
/// getAL - Returns a ARMCC::AL immediate node.
static inline SDValue getAL(SelectionDAG *CurDAG) {
return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32);
@@ -1003,6 +1000,6 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
/// createARMISelDag - This pass converts a legalized DAG into a
/// ARM-specific DAG, ready for instruction scheduling.
///
-FunctionPass *llvm::createARMISelDag(ARMTargetMachine &TM) {
+FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM) {
return new ARMDAGToDAGISel(TM);
}
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index 29d3da2b79c15..c24bb2eb2ba9d 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -266,7 +266,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
setOperationAction(ISD::ROTL, MVT::i32, Expand);
setOperationAction(ISD::CTTZ, MVT::i32, Expand);
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
- if (!Subtarget->hasV5TOps() || Subtarget->isThumb())
+ if (!Subtarget->hasV5TOps() || Subtarget->isThumb1Only())
setOperationAction(ISD::CTLZ, MVT::i32, Expand);
// Only ARMv6 has BSWAP.
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index d70d2e2d1709e..d7371b0254048 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -742,32 +742,85 @@ class TIx2<dag outs, dag ins, string asm, list<dag> pattern>
class TJTI<dag outs, dag ins, string asm, list<dag> pattern>
: ThumbI<outs, ins, AddrModeNone, SizeSpecial, asm, "", pattern>;
-// ThumbPat - Same as Pat<>, but requires that the compiler be in Thumb mode.
-class ThumbPat<dag pattern, dag result> : Pat<pattern, result> {
+// TPat - Same as Pat<>, but requires that the compiler be in Thumb mode.
+class TPat<dag pattern, dag result> : Pat<pattern, result> {
list<Predicate> Predicates = [IsThumb];
}
-class ThumbV5Pat<dag pattern, dag result> : Pat<pattern, result> {
+class Tv5Pat<dag pattern, dag result> : Pat<pattern, result> {
list<Predicate> Predicates = [IsThumb, HasV5T];
}
-// T2I - Thumb2 instruction.
-
-class Thumb2I<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
+// Thumb1 only
+class Thumb1I<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
string asm, string cstr, list<dag> pattern>
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
let OutOperandList = outs;
let InOperandList = ins;
let AsmString = asm;
let Pattern = pattern;
+ list<Predicate> Predicates = [IsThumb1Only];
+}
+
+class T1I<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeNone, Size2Bytes, asm, "", pattern>;
+
+// Two-address instructions
+class T1It<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeNone, Size2Bytes, asm, "$lhs = $dst", pattern>;
+
+class T1Pat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb1Only];
+}
+
+// Thumb2I - Thumb2 instruction. Almost all Thumb2 instructions are predicable.
+class Thumb2I<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
+ string opc, string asm, string cstr, list<dag> pattern>
+ : InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
+ let OutOperandList = oops;
+ let InOperandList = !con(iops, (ops pred:$p));
+ let AsmString = !strconcat(opc, !strconcat("${p}", asm));
+ let Pattern = pattern;
+ list<Predicate> Predicates = [IsThumb, HasThumb2];
+}
+
+// Same as Thumb2I except it can optionally modify CPSR. Note it's modeled as
+// an input operand since by default it's a zero register. It will
+// become an implicit def once it's "flipped".
+// FIXME: This uses unified syntax so {s} comes before {p}. We should make it
+// more consistent.
+class Thumb2sI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
+ string opc, string asm, string cstr, list<dag> pattern>
+ : InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
+ let OutOperandList = oops;
+ let InOperandList = !con(iops, (ops pred:$p, cc_out:$s));
+ let AsmString = !strconcat(opc, !strconcat("${s}${p}", asm));
+ let Pattern = pattern;
+ list<Predicate> Predicates = [IsThumb, HasThumb2];
+}
+
+// Special cases
+class Thumb2XI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
+ string asm, string cstr, list<dag> pattern>
+ : InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
+ let OutOperandList = oops;
+ let InOperandList = iops;
+ let AsmString = asm;
+ let Pattern = pattern;
list<Predicate> Predicates = [IsThumb, HasThumb2];
}
-class T2I<dag outs, dag ins, string asm, list<dag> pattern>
- : Thumb2I<outs, ins, AddrModeNone, Size4Bytes, asm, "", pattern>;
+class T2I<dag oops, dag iops, string opc, string asm, list<dag> pattern>
+ : Thumb2I<oops, iops, AddrModeNone, 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>;
+
+class T2XI<dag oops, dag iops, string asm, list<dag> pattern>
+ : Thumb2XI<oops, iops, AddrModeNone, Size4Bytes, asm, "", pattern>;
-// Thumb2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
-class Thumb2Pat<dag pattern, dag result> : Pat<pattern, result> {
+// T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
+class T2Pat<dag pattern, dag result> : Pat<pattern, result> {
list<Predicate> Predicates = [IsThumb, HasThumb2];
}
diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp
index e8da9276243f0..d95089dd484d4 100644
--- a/lib/Target/ARM/ARMInstrInfo.cpp
+++ b/lib/Target/ARM/ARMInstrInfo.cpp
@@ -39,11 +39,14 @@ const MachineInstrBuilder &AddDefaultCC(const MachineInstrBuilder &MIB) {
return MIB.addReg(0);
}
-ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI)
+ARMBaseInstrInfo::ARMBaseInstrInfo(const ARMSubtarget &STI)
: TargetInstrInfoImpl(ARMInsts, array_lengthof(ARMInsts)),
RI(*this, STI) {
}
+ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI)
+ : ARMBaseInstrInfo(STI) {
+}
/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
@@ -65,10 +68,6 @@ bool ARMInstrInfo::isMoveInstr(const MachineInstr &MI,
DstReg = MI.getOperand(0).getReg();
return true;
case ARM::MOVr:
- case ARM::tMOVr:
- case ARM::tMOVhir2lor:
- case ARM::tMOVlor2hir:
- case ARM::tMOVhir2hir:
assert(MI.getDesc().getNumOperands() >= 2 &&
MI.getOperand(0).isReg() &&
MI.getOperand(1).isReg() &&
@@ -102,14 +101,6 @@ unsigned ARMInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
return MI->getOperand(0).getReg();
}
break;
- case ARM::tRestore:
- if (MI->getOperand(1).isFI() &&
- MI->getOperand(2).isImm() &&
- MI->getOperand(2).getImm() == 0) {
- FrameIndex = MI->getOperand(1).getIndex();
- return MI->getOperand(0).getReg();
- }
- break;
}
return 0;
}
@@ -137,22 +128,15 @@ unsigned ARMInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
return MI->getOperand(0).getReg();
}
break;
- case ARM::tSpill:
- if (MI->getOperand(1).isFI() &&
- MI->getOperand(2).isImm() &&
- MI->getOperand(2).getImm() == 0) {
- FrameIndex = MI->getOperand(1).getIndex();
- return MI->getOperand(0).getReg();
- }
- break;
}
+
return 0;
}
-void ARMInstrInfo::reMaterialize(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I,
- unsigned DestReg,
- const MachineInstr *Orig) const {
+void ARMBaseInstrInfo::reMaterialize(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg,
+ const MachineInstr *Orig) const {
DebugLoc dl = Orig->getDebugLoc();
if (Orig->getOpcode() == ARM::MOVi2pieces) {
RI.emitLoadConstPool(MBB, I, DestReg, Orig->getOperand(1).getImm(),
@@ -198,9 +182,9 @@ static unsigned getUnindexedOpcode(unsigned Opc) {
}
MachineInstr *
-ARMInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
- MachineBasicBlock::iterator &MBBI,
- LiveVariables *LV) const {
+ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
+ MachineBasicBlock::iterator &MBBI,
+ LiveVariables *LV) const {
if (!EnableARM3Addr)
return NULL;
@@ -261,7 +245,7 @@ ARMInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
get(isSub ? ARM::SUBrs : ARM::ADDrs), WBReg)
.addReg(BaseReg).addReg(OffReg).addReg(0).addImm(SOOpc)
.addImm(Pred).addReg(0).addReg(0);
- } else
+ } else
UpdateMI = BuildMI(MF, MI->getDebugLoc(),
get(isSub ? ARM::SUBrr : ARM::ADDrr), WBReg)
.addReg(BaseReg).addReg(OffReg)
@@ -312,7 +296,7 @@ ARMInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
NewMIs.push_back(UpdateMI);
NewMIs.push_back(MemMI);
}
-
+
// Transfer LiveVariables states, kill / dead info.
if (LV) {
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
@@ -320,7 +304,7 @@ ARMInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
if (MO.isReg() && MO.getReg() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
unsigned Reg = MO.getReg();
-
+
LiveVariables::VarInfo &VI = LV->getVarInfo(Reg);
if (MO.isDef()) {
MachineInstr *NewMI = (Reg == WBReg) ? UpdateMI : MemMI;
@@ -349,18 +333,19 @@ ARMInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
}
// Branch analysis.
-bool ARMInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
- MachineBasicBlock *&FBB,
- SmallVectorImpl<MachineOperand> &Cond,
- bool AllowModify) const {
+bool
+ ARMBaseInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ bool AllowModify) const {
// If the block has no terminators, it just falls into the block after it.
MachineBasicBlock::iterator I = MBB.end();
if (I == MBB.begin() || !isUnpredicatedTerminator(--I))
return false;
-
+
// Get the last instruction in the block.
MachineInstr *LastInst = I;
-
+
// If there is only one terminator instruction, process it.
unsigned LastOpc = LastInst->getOpcode();
if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) {
@@ -377,14 +362,14 @@ bool ARMInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
}
return true; // Can't handle indirect branch.
}
-
+
// Get the instruction before it if it is a terminator.
MachineInstr *SecondLastInst = I;
-
+
// If there are three terminators, we don't know what sort of block this is.
if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I))
return true;
-
+
// If the block ends with ARM::B/ARM::tB and a ARM::Bcc/ARM::tBcc, handle it.
unsigned SecondLastOpc = SecondLastInst->getOpcode();
if ((SecondLastOpc == ARM::Bcc && LastOpc == ARM::B) ||
@@ -395,8 +380,8 @@ bool ARMInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
FBB = LastInst->getOperand(0).getMBB();
return false;
}
-
- // If the block ends with two unconditional branches, handle it. The second
+
+ // If the block ends with two unconditional branches, handle it. The second
// one is not executed, so remove it.
if ((SecondLastOpc == ARM::B || SecondLastOpc==ARM::tB) &&
(LastOpc == ARM::B || LastOpc == ARM::tB)) {
@@ -417,14 +402,14 @@ bool ARMInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
if (AllowModify)
I->eraseFromParent();
return true;
- }
+ }
// Otherwise, can't handle this.
return true;
}
-unsigned ARMInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned ARMBaseInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
int BOpc = AFI->isThumbFunction() ? ARM::tB : ARM::B;
@@ -435,26 +420,26 @@ unsigned ARMInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
--I;
if (I->getOpcode() != BOpc && I->getOpcode() != BccOpc)
return 0;
-
+
// Remove the branch.
I->eraseFromParent();
-
+
I = MBB.end();
-
+
if (I == MBB.begin()) return 1;
--I;
if (I->getOpcode() != BccOpc)
return 1;
-
+
// Remove the branch.
I->eraseFromParent();
return 2;
}
unsigned
-ARMInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
- MachineBasicBlock *FBB,
- const SmallVectorImpl<MachineOperand> &Cond) const {
+ARMBaseInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ const SmallVectorImpl<MachineOperand> &Cond) const {
// FIXME this should probably have a DebugLoc argument
DebugLoc dl = DebugLoc::getUnknownLoc();
MachineFunction &MF = *MBB.getParent();
@@ -466,7 +451,7 @@ ARMInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"ARM branch conditions have two components!");
-
+
if (FBB == 0) {
if (Cond.empty()) // Unconditional branch?
BuildMI(&MBB, dl, get(BOpc)).addMBB(TBB);
@@ -475,7 +460,7 @@ ARMInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
.addImm(Cond[0].getImm()).addReg(Cond[1].getReg());
return 1;
}
-
+
// Two-way conditional branch.
BuildMI(&MBB, dl, get(BccOpc)).addMBB(TBB)
.addImm(Cond[0].getImm()).addReg(Cond[1].getReg());
@@ -488,43 +473,18 @@ bool ARMInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *DestRC,
const TargetRegisterClass *SrcRC) const {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL = DebugLoc::getUnknownLoc();
if (I != MBB.end()) DL = I->getDebugLoc();
- if (!AFI->isThumbFunction()) {
- if (DestRC == ARM::GPRRegisterClass) {
- AddDefaultCC(AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::MOVr), DestReg)
- .addReg(SrcReg)));
- return true;
- }
- } else {
- if (DestRC == ARM::GPRRegisterClass) {
- if (SrcRC == ARM::GPRRegisterClass) {
- BuildMI(MBB, I, DL, get(ARM::tMOVhir2hir), DestReg).addReg(SrcReg);
- return true;
- } else if (SrcRC == ARM::tGPRRegisterClass) {
- BuildMI(MBB, I, DL, get(ARM::tMOVlor2hir), DestReg).addReg(SrcReg);
- return true;
- }
- } else if (DestRC == ARM::tGPRRegisterClass) {
- if (SrcRC == ARM::GPRRegisterClass) {
- BuildMI(MBB, I, DL, get(ARM::tMOVhir2lor), DestReg).addReg(SrcReg);
- return true;
- } else if (SrcRC == ARM::tGPRRegisterClass) {
- BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg).addReg(SrcReg);
- return true;
- }
- }
- }
if (DestRC != SrcRC) {
// Not yet supported!
return false;
}
-
- if (DestRC == ARM::SPRRegisterClass)
+ if (DestRC == ARM::GPRRegisterClass)
+ AddDefaultCC(AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::MOVr), DestReg)
+ .addReg(SrcReg)));
+ else if (DestRC == ARM::SPRRegisterClass)
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FCPYS), DestReg)
.addReg(SrcReg));
else if (DestRC == ARM::DPRRegisterClass)
@@ -534,7 +494,7 @@ bool ARMInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
BuildMI(MBB, I, DL, get(ARM::VMOVQ), DestReg).addReg(SrcReg);
else
return false;
-
+
return true;
}
@@ -546,19 +506,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
if (RC == ARM::GPRRegisterClass) {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- assert (!AFI->isThumbFunction());
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::STR))
.addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI).addReg(0).addImm(0));
- } else if (RC == ARM::tGPRRegisterClass) {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- assert (AFI->isThumbFunction());
- BuildMI(MBB, I, DL, get(ARM::tSpill))
- .addReg(SrcReg, getKillRegState(isKill))
- .addFrameIndex(FI).addImm(0);
} else if (RC == ARM::DPRRegisterClass) {
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FSTD))
.addReg(SrcReg, getKillRegState(isKill))
@@ -579,16 +529,6 @@ void ARMInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
DebugLoc DL = DebugLoc::getUnknownLoc();
unsigned Opc = 0;
if (RC == ARM::GPRRegisterClass) {
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- if (AFI->isThumbFunction()) {
- Opc = Addr[0].isFI() ? ARM::tSpill : ARM::tSTR;
- MachineInstrBuilder MIB =
- BuildMI(MF, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill));
- for (unsigned i = 0, e = Addr.size(); i != e; ++i)
- MIB.addOperand(Addr[i]);
- NewMIs.push_back(MIB);
- return;
- }
Opc = ARM::STR;
} else if (RC == ARM::DPRRegisterClass) {
Opc = ARM::FSTD;
@@ -597,7 +537,7 @@ void ARMInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
Opc = ARM::FSTS;
}
- MachineInstrBuilder MIB =
+ MachineInstrBuilder MIB =
BuildMI(MF, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill));
for (unsigned i = 0, e = Addr.size(); i != e; ++i)
MIB.addOperand(Addr[i]);
@@ -614,17 +554,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
if (RC == ARM::GPRRegisterClass) {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- assert (!AFI->isThumbFunction());
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::LDR), DestReg)
.addFrameIndex(FI).addReg(0).addImm(0));
- } else if (RC == ARM::tGPRRegisterClass) {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- assert (AFI->isThumbFunction());
- BuildMI(MBB, I, DL, get(ARM::tRestore), DestReg)
- .addFrameIndex(FI).addImm(0);
} else if (RC == ARM::DPRRegisterClass) {
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FLDD), DestReg)
.addFrameIndex(FI).addImm(0));
@@ -643,15 +574,6 @@ loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
DebugLoc DL = DebugLoc::getUnknownLoc();
unsigned Opc = 0;
if (RC == ARM::GPRRegisterClass) {
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- if (AFI->isThumbFunction()) {
- Opc = Addr[0].isFI() ? ARM::tRestore : ARM::tLDR;
- MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
- for (unsigned i = 0, e = Addr.size(); i != e; ++i)
- MIB.addOperand(Addr[i]);
- NewMIs.push_back(MIB);
- return;
- }
Opc = ARM::LDR;
} else if (RC == ARM::DPRRegisterClass) {
Opc = ARM::FLDD;
@@ -668,59 +590,6 @@ loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
return;
}
-bool ARMInstrInfo::
-spillCalleeSavedRegisters(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MI,
- const std::vector<CalleeSavedInfo> &CSI) const {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- if (!AFI->isThumbFunction() || CSI.empty())
- return false;
-
- DebugLoc DL = DebugLoc::getUnknownLoc();
- if (MI != MBB.end()) DL = MI->getDebugLoc();
-
- MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, get(ARM::tPUSH));
- for (unsigned i = CSI.size(); i != 0; --i) {
- unsigned Reg = CSI[i-1].getReg();
- // Add the callee-saved register as live-in. It's killed at the spill.
- MBB.addLiveIn(Reg);
- MIB.addReg(Reg, RegState::Kill);
- }
- return true;
-}
-
-bool ARMInstrInfo::
-restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MI,
- const std::vector<CalleeSavedInfo> &CSI) const {
- MachineFunction &MF = *MBB.getParent();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- if (!AFI->isThumbFunction() || CSI.empty())
- return false;
-
- bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
- MachineInstr *PopMI = MF.CreateMachineInstr(get(ARM::tPOP),MI->getDebugLoc());
- for (unsigned i = CSI.size(); i != 0; --i) {
- unsigned Reg = CSI[i-1].getReg();
- if (Reg == ARM::LR) {
- // Special epilogue for vararg functions. See emitEpilogue
- if (isVarArg)
- continue;
- Reg = ARM::PC;
- PopMI->setDesc(get(ARM::tPOP_RET));
- MI = MBB.erase(MI);
- }
- PopMI->addOperand(MachineOperand::CreateReg(Reg, true));
- }
-
- // It's illegal to emit pop instruction without operands.
- if (PopMI->getNumOperands() > 0)
- MBB.insert(MI, PopMI);
-
- return true;
-}
-
MachineInstr *ARMInstrInfo::
foldMemoryOperandImpl(MachineFunction &MF, MachineInstr *MI,
const SmallVectorImpl<unsigned> &Ops, int FI) const {
@@ -752,31 +621,6 @@ foldMemoryOperandImpl(MachineFunction &MF, MachineInstr *MI,
}
break;
}
- case ARM::tMOVr:
- case ARM::tMOVlor2hir:
- case ARM::tMOVhir2lor:
- case ARM::tMOVhir2hir: {
- if (OpNum == 0) { // move -> store
- unsigned SrcReg = MI->getOperand(1).getReg();
- bool isKill = MI->getOperand(1).isKill();
- if (RI.isPhysicalRegister(SrcReg) && !RI.isLowRegister(SrcReg))
- // tSpill cannot take a high register operand.
- break;
- NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tSpill))
- .addReg(SrcReg, getKillRegState(isKill))
- .addFrameIndex(FI).addImm(0);
- } else { // move -> load
- unsigned DstReg = MI->getOperand(0).getReg();
- if (RI.isPhysicalRegister(DstReg) && !RI.isLowRegister(DstReg))
- // tRestore cannot target a high register operand.
- break;
- bool isDead = MI->getOperand(0).isDead();
- NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tRestore))
- .addReg(DstReg, RegState::Define | getDeadRegState(isDead))
- .addFrameIndex(FI).addImm(0);
- }
- break;
- }
case ARM::FCPYS: {
unsigned Pred = MI->getOperand(2).getImm();
unsigned PredReg = MI->getOperand(3).getReg();
@@ -816,7 +660,7 @@ foldMemoryOperandImpl(MachineFunction &MF, MachineInstr *MI,
return NewMI;
}
-bool ARMInstrInfo::
+bool ARMBaseInstrInfo::
canFoldMemoryOperand(const MachineInstr *MI,
const SmallVectorImpl<unsigned> &Ops) const {
if (Ops.size() != 1) return false;
@@ -857,9 +701,10 @@ canFoldMemoryOperand(const MachineInstr *MI,
return false;
}
-bool ARMInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
+bool
+ ARMBaseInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
if (MBB.empty()) return false;
-
+
switch (MBB.back().getOpcode()) {
case ARM::BX_RET: // Return.
case ARM::LDM_RET:
@@ -877,19 +722,19 @@ bool ARMInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
}
}
-bool ARMInstrInfo::
+bool ARMBaseInstrInfo::
ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
ARMCC::CondCodes CC = (ARMCC::CondCodes)(int)Cond[0].getImm();
Cond[0].setImm(ARMCC::getOppositeCondition(CC));
return false;
}
-bool ARMInstrInfo::isPredicated(const MachineInstr *MI) const {
+bool ARMBaseInstrInfo::isPredicated(const MachineInstr *MI) const {
int PIdx = MI->findFirstPredOperandIdx();
return PIdx != -1 && MI->getOperand(PIdx).getImm() != ARMCC::AL;
}
-bool ARMInstrInfo::
+bool ARMBaseInstrInfo::
PredicateInstruction(MachineInstr *MI,
const SmallVectorImpl<MachineOperand> &Pred) const {
unsigned Opc = MI->getOpcode();
@@ -910,7 +755,7 @@ PredicateInstruction(MachineInstr *MI,
return false;
}
-bool ARMInstrInfo::
+bool ARMBaseInstrInfo::
SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
const SmallVectorImpl<MachineOperand> &Pred2) const {
if (Pred1.size() > 2 || Pred2.size() > 2)
@@ -937,7 +782,7 @@ SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
}
}
-bool ARMInstrInfo::DefinesPredicate(MachineInstr *MI,
+bool ARMBaseInstrInfo::DefinesPredicate(MachineInstr *MI,
std::vector<MachineOperand> &Pred) const {
const TargetInstrDesc &TID = MI->getDesc();
if (!TID.getImplicitDefs() && !TID.hasOptionalDef())
@@ -966,7 +811,7 @@ static unsigned getNumJTEntries(const std::vector<MachineJumpTableEntry> &JT,
/// GetInstSize - Return the size of the specified MachineInstr.
///
-unsigned ARMInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
+unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
const MachineBasicBlock &MBB = *MI->getParent();
const MachineFunction *MF = MBB.getParent();
const TargetAsmInfo *TAI = MF->getTarget().getTargetAsmInfo();
@@ -974,7 +819,7 @@ unsigned ARMInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
// Basic size info comes from the TSFlags field.
const TargetInstrDesc &TID = MI->getDesc();
unsigned TSFlags = TID.TSFlags;
-
+
switch ((TSFlags & ARMII::SizeMask) >> ARMII::SizeShift) {
default: {
// If this machine instr is an inline asm, measure it.
@@ -1024,7 +869,7 @@ unsigned ARMInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
// FIXME: If we know the size of the function is less than (1 << 16) *2
// bytes, we can use 16-bit entries instead. Then there won't be an
// alignment issue.
- return getNumJTEntries(JT, JTI) * 4 +
+ return getNumJTEntries(JT, JTI) * 4 +
(MI->getOpcode()==ARM::tBR_JTr ? 2 : 4);
}
default:
diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h
index 9658f3bcba8b8..131960b9c7a74 100644
--- a/lib/Target/ARM/ARMInstrInfo.h
+++ b/lib/Target/ARM/ARMInstrInfo.h
@@ -51,14 +51,14 @@ namespace ARMII {
Size8Bytes = 2,
Size4Bytes = 3,
Size2Bytes = 4,
-
+
// IndexMode - Unindex, pre-indexed, or post-indexed. Only valid for load
- // and store ops
+ // and store ops
IndexModeShift = 7,
IndexModeMask = 3 << IndexModeShift,
IndexModePre = 1,
IndexModePost = 2,
-
+
//===------------------------------------------------------------------===//
// Misc flags.
@@ -146,10 +146,12 @@ namespace ARMII {
};
}
-class ARMInstrInfo : public TargetInstrInfoImpl {
+class ARMBaseInstrInfo : public TargetInstrInfoImpl {
const ARMRegisterInfo RI;
+protected:
+ // Can be only subclassed.
+ explicit ARMBaseInstrInfo(const ARMSubtarget &STI);
public:
- explicit ARMInstrInfo(const ARMSubtarget &STI);
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
@@ -157,17 +159,6 @@ public:
///
virtual const ARMRegisterInfo &getRegisterInfo() const { return RI; }
- /// Return true if the instruction is a register to register move and return
- /// the source and dest operands and their sub-register indices by reference.
- virtual bool isMoveInstr(const MachineInstr &MI,
- unsigned &SrcReg, unsigned &DstReg,
- unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
-
- virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
- int &FrameIndex) const;
- virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
- int &FrameIndex) const;
-
void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned DestReg, const MachineInstr *Orig) const;
@@ -184,6 +175,54 @@ public:
virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
const SmallVectorImpl<MachineOperand> &Cond) const;
+
+ virtual bool canFoldMemoryOperand(const MachineInstr *MI,
+ const SmallVectorImpl<unsigned> &Ops) const;
+
+ virtual bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;
+ virtual
+ bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const;
+
+ // Predication support.
+ virtual bool isPredicated(const MachineInstr *MI) const;
+
+ ARMCC::CondCodes getPredicate(const MachineInstr *MI) const {
+ int PIdx = MI->findFirstPredOperandIdx();
+ return PIdx != -1 ? (ARMCC::CondCodes)MI->getOperand(PIdx).getImm()
+ : ARMCC::AL;
+ }
+
+ virtual
+ bool PredicateInstruction(MachineInstr *MI,
+ const SmallVectorImpl<MachineOperand> &Pred) const;
+
+ virtual
+ bool SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
+ const SmallVectorImpl<MachineOperand> &Pred2) const;
+
+ virtual bool DefinesPredicate(MachineInstr *MI,
+ std::vector<MachineOperand> &Pred) const;
+
+ /// GetInstSize - Returns the size of the specified MachineInstr.
+ ///
+ virtual unsigned GetInstSizeInBytes(const MachineInstr* MI) const;
+};
+
+class ARMInstrInfo : public ARMBaseInstrInfo {
+public:
+ explicit ARMInstrInfo(const ARMSubtarget &STI);
+
+ /// Return true if the instruction is a register to register move and return
+ /// the source and dest operands and their sub-register indices by reference.
+ virtual bool isMoveInstr(const MachineInstr &MI,
+ unsigned &SrcReg, unsigned &DstReg,
+ unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
+
+ virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+ virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+
virtual bool copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg, unsigned SrcReg,
@@ -208,13 +247,7 @@ public:
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const;
- virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MI,
- const std::vector<CalleeSavedInfo> &CSI) const;
- virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MI,
- const std::vector<CalleeSavedInfo> &CSI) const;
-
+
virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF,
MachineInstr* MI,
const SmallVectorImpl<unsigned> &Ops,
@@ -226,37 +259,6 @@ public:
MachineInstr* LoadMI) const {
return 0;
}
-
- virtual bool canFoldMemoryOperand(const MachineInstr *MI,
- const SmallVectorImpl<unsigned> &Ops) const;
-
- virtual bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;
- virtual
- bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const;
-
- // Predication support.
- virtual bool isPredicated(const MachineInstr *MI) const;
-
- ARMCC::CondCodes getPredicate(const MachineInstr *MI) const {
- int PIdx = MI->findFirstPredOperandIdx();
- return PIdx != -1 ? (ARMCC::CondCodes)MI->getOperand(PIdx).getImm()
- : ARMCC::AL;
- }
-
- virtual
- bool PredicateInstruction(MachineInstr *MI,
- const SmallVectorImpl<MachineOperand> &Pred) const;
-
- virtual
- bool SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
- const SmallVectorImpl<MachineOperand> &Pred2) const;
-
- virtual bool DefinesPredicate(MachineInstr *MI,
- std::vector<MachineOperand> &Pred) const;
-
- /// GetInstSize - Returns the size of the specified MachineInstr.
- ///
- virtual unsigned GetInstSizeInBytes(const MachineInstr* MI) const;
};
}
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index 7003a6587ad81..cb7b7b98c7c95 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -103,6 +103,8 @@ def HasThumb2 : Predicate<"Subtarget->hasThumb2()">;
def IsARM : Predicate<"!Subtarget->isThumb()">;
def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">;
def IsNotDarwin : Predicate<"!Subtarget->isTargetDarwin()">;
+def CarryDefIsUnused : Predicate<"!N.getNode()->hasAnyUseOfValue(1)">;
+def CarryDefIsUsed : Predicate<"N.getNode()->hasAnyUseOfValue(1)">;
//===----------------------------------------------------------------------===//
// ARM Flag Definitions.
@@ -353,28 +355,34 @@ include "ARMInstrFormats.td"
/// AsI1_bin_irs - Defines a set of (op r, {so_imm|r|so_reg}) patterns for a
/// binop that produces a value.
-multiclass AsI1_bin_irs<bits<4> opcod, string opc, PatFrag opnode> {
+multiclass AsI1_bin_irs<bits<4> opcod, string opc, PatFrag opnode,
+ bit Commutable = 0> {
def ri : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
opc, " $dst, $a, $b",
[(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>;
def rr : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm,
opc, " $dst, $a, $b",
- [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>;
+ [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]> {
+ let isCommutable = Commutable;
+ }
def rs : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
opc, " $dst, $a, $b",
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>;
}
-/// ASI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the
+/// AI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the
/// instruction modifies the CSPR register.
let Defs = [CPSR] in {
-multiclass ASI1_bin_s_irs<bits<4> opcod, string opc, PatFrag opnode> {
+multiclass AI1_bin_s_irs<bits<4> opcod, string opc, PatFrag opnode,
+ bit Commutable = 0> {
def ri : AI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
opc, "s $dst, $a, $b",
[(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>;
def rr : AI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm,
opc, "s $dst, $a, $b",
- [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>;
+ [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]> {
+ let isCommutable = Commutable;
+ }
def rs : AI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
opc, "s $dst, $a, $b",
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>;
@@ -385,13 +393,16 @@ multiclass ASI1_bin_s_irs<bits<4> opcod, string opc, PatFrag opnode> {
/// patterns. Similar to AsI1_bin_irs except the instruction does not produce
/// a explicit result, only implicitly set CPSR.
let Defs = [CPSR] in {
-multiclass AI1_cmp_irs<bits<4> opcod, string opc, PatFrag opnode> {
+multiclass AI1_cmp_irs<bits<4> opcod, string opc, PatFrag opnode,
+ bit Commutable = 0> {
def ri : AI1<opcod, (outs), (ins GPR:$a, so_imm:$b), DPFrm,
opc, " $a, $b",
[(opnode GPR:$a, so_imm:$b)]>;
def rr : AI1<opcod, (outs), (ins GPR:$a, GPR:$b), DPFrm,
opc, " $a, $b",
- [(opnode GPR:$a, GPR:$b)]>;
+ [(opnode GPR:$a, GPR:$b)]> {
+ let isCommutable = Commutable;
+ }
def rs : AI1<opcod, (outs), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
opc, " $a, $b",
[(opnode GPR:$a, so_reg:$b)]>;
@@ -430,19 +441,43 @@ multiclass AI_bin_rrot<bits<8> opcod, string opc, PatFrag opnode> {
Requires<[IsARM, HasV6]>;
}
-/// AsXI1_bin_c_irs - Same as AsI1_bin_irs but without the predicate operand and
-/// setting carry bit. But it can optionally set CPSR.
+/// AI1_adde_sube_irs - Define instructions and patterns for adde and sube.
let Uses = [CPSR] in {
-multiclass AsXI1_bin_c_irs<bits<4> opcod, string opc, PatFrag opnode> {
- def ri : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b, cc_out:$s),
- DPFrm, !strconcat(opc, "${s} $dst, $a, $b"),
- [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>;
- def rr : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b, cc_out:$s),
- DPFrm, !strconcat(opc, "${s} $dst, $a, $b"),
- [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>;
- def rs : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b, cc_out:$s),
- DPSoRegFrm, !strconcat(opc, "${s} $dst, $a, $b"),
- [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>;
+multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
+ bit Commutable = 0> {
+ def ri : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
+ DPFrm, opc, " $dst, $a, $b",
+ [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
+ def rr : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
+ DPFrm, opc, " $dst, $a, $b",
+ [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>,
+ Requires<[IsARM, CarryDefIsUnused]> {
+ let isCommutable = Commutable;
+ }
+ def rs : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
+ DPSoRegFrm, opc, " $dst, $a, $b",
+ [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
+ // Carry setting variants
+ def Sri : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
+ DPFrm, !strconcat(opc, "s $dst, $a, $b"),
+ [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>,
+ Requires<[IsARM, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
+ def Srr : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
+ DPFrm, !strconcat(opc, "s $dst, $a, $b"),
+ [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>,
+ Requires<[IsARM, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
+ def Srs : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
+ DPSoRegFrm, !strconcat(opc, "s $dst, $a, $b"),
+ [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>,
+ Requires<[IsARM, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
}
}
@@ -535,7 +570,8 @@ def LEApcrel : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, pred:$p), Pseudo,
"add$p $dst, pc, #PCRELV${:uid}")),
[]>;
-def LEApcrelJT : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, i32imm:$id, pred:$p),
+def LEApcrelJT : AXI1<0x0, (outs GPR:$dst),
+ (ins i32imm:$label, i32imm:$id, pred:$p),
Pseudo,
!strconcat(!strconcat(".set PCRELV${:uid}, (${label}_${id:no_hash}-(",
"${:private}PCRELL${:uid}+8))\n"),
@@ -899,21 +935,20 @@ defm UXTAH : AI_bin_rrot<0b01101111, "uxtah",
//
defm ADD : AsI1_bin_irs<0b0100, "add",
- BinOpFrag<(add node:$LHS, node:$RHS)>>;
+ BinOpFrag<(add node:$LHS, node:$RHS)>, 1>;
defm SUB : AsI1_bin_irs<0b0010, "sub",
BinOpFrag<(sub node:$LHS, node:$RHS)>>;
// ADD and SUB with 's' bit set.
-defm ADDS : ASI1_bin_s_irs<0b0100, "add",
- BinOpFrag<(addc node:$LHS, node:$RHS)>>;
-defm SUBS : ASI1_bin_s_irs<0b0010, "sub",
- BinOpFrag<(subc node:$LHS, node:$RHS)>>;
+defm ADDS : AI1_bin_s_irs<0b0100, "add",
+ BinOpFrag<(addc node:$LHS, node:$RHS)>>;
+defm SUBS : AI1_bin_s_irs<0b0010, "sub",
+ BinOpFrag<(subc node:$LHS, node:$RHS)>>;
-// FIXME: Do not allow ADC / SBC to be predicated for now.
-defm ADC : AsXI1_bin_c_irs<0b0101, "adc",
- BinOpFrag<(adde node:$LHS, node:$RHS)>>;
-defm SBC : AsXI1_bin_c_irs<0b0110, "sbc",
- BinOpFrag<(sube node:$LHS, node:$RHS)>>;
+defm ADC : AI1_adde_sube_irs<0b0101, "adc",
+ BinOpFrag<(adde node:$LHS, node:$RHS)>, 1>;
+defm SBC : AI1_adde_sube_irs<0b0110, "sbc",
+ BinOpFrag<(sube node:$LHS, node:$RHS)>>;
// These don't define reg/reg forms, because they are handled above.
def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
@@ -934,14 +969,27 @@ def RSBSrs : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
[(set GPR:$dst, (subc so_reg:$b, GPR:$a))]>;
}
-// FIXME: Do not allow RSC to be predicated for now. But they can set CPSR.
let Uses = [CPSR] in {
-def RSCri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b, cc_out:$s),
- DPFrm, "rsc${s} $dst, $a, $b",
- [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>;
-def RSCrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b, cc_out:$s),
- DPSoRegFrm, "rsc${s} $dst, $a, $b",
- [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>;
+def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
+ DPFrm, "rsc", " $dst, $a, $b",
+ [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
+def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
+ DPSoRegFrm, "rsc", " $dst, $a, $b",
+ [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
+}
+
+// FIXME: Allow these to be predicated.
+let Defs = [CPSR], Uses = [CPSR] in {
+def RSCSri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
+ DPFrm, "rscs $dst, $a, $b",
+ [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
+def RSCSrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
+ DPSoRegFrm, "rscs $dst, $a, $b",
+ [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>,
+ Requires<[IsARM, CarryDefIsUnused]>;
}
// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
@@ -965,11 +1013,11 @@ def : ARMPat<(add GPR:$src, so_imm_neg:$imm),
//
defm AND : AsI1_bin_irs<0b0000, "and",
- BinOpFrag<(and node:$LHS, node:$RHS)>>;
+ BinOpFrag<(and node:$LHS, node:$RHS)>, 1>;
defm ORR : AsI1_bin_irs<0b1100, "orr",
- BinOpFrag<(or node:$LHS, node:$RHS)>>;
+ BinOpFrag<(or node:$LHS, node:$RHS)>, 1>;
defm EOR : AsI1_bin_irs<0b0001, "eor",
- BinOpFrag<(xor node:$LHS, node:$RHS)>>;
+ BinOpFrag<(xor node:$LHS, node:$RHS)>, 1>;
defm BIC : AsI1_bin_irs<0b1110, "bic",
BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
@@ -991,6 +1039,7 @@ def : ARMPat<(and GPR:$src, so_imm_not:$imm),
// Multiply Instructions.
//
+let isCommutable = 1 in
def MUL : AsMul1I<0b0000000, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
"mul", " $dst, $a, $b",
[(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
@@ -1001,6 +1050,7 @@ def MLA : AsMul1I<0b0000001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
// Extra precision multiplies with low / high results
let neverHasSideEffects = 1 in {
+let isCommutable = 1 in {
def SMULL : AsMul1I<0b0000110, (outs GPR:$ldst, GPR:$hdst),
(ins GPR:$a, GPR:$b),
"smull", " $ldst, $hdst, $a, $b", []>;
@@ -1008,6 +1058,7 @@ def SMULL : AsMul1I<0b0000110, (outs GPR:$ldst, GPR:$hdst),
def UMULL : AsMul1I<0b0000100, (outs GPR:$ldst, GPR:$hdst),
(ins GPR:$a, GPR:$b),
"umull", " $ldst, $hdst, $a, $b", []>;
+}
// Multiply + accumulate
def SMLAL : AsMul1I<0b0000111, (outs GPR:$ldst, GPR:$hdst),
@@ -1258,9 +1309,9 @@ defm CMN : AI1_cmp_irs<0b1011, "cmn",
// Note that TST/TEQ don't set all the same flags that CMP does!
defm TST : AI1_cmp_irs<0b1000, "tst",
- BinOpFrag<(ARMcmpNZ (and node:$LHS, node:$RHS), 0)>>;
+ BinOpFrag<(ARMcmpNZ (and node:$LHS, node:$RHS), 0)>, 1>;
defm TEQ : AI1_cmp_irs<0b1001, "teq",
- BinOpFrag<(ARMcmpNZ (xor node:$LHS, node:$RHS), 0)>>;
+ BinOpFrag<(ARMcmpNZ (xor node:$LHS, node:$RHS), 0)>, 1>;
defm CMPnz : AI1_cmp_irs<0b1010, "cmp",
BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>;
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index 1def0933d6c02..7927ca53b8fd5 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -128,10 +128,28 @@ PseudoInst<(outs), (ins i32imm:$amt),
}
let isNotDuplicable = 1 in
-def tPICADD : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, pclabel:$cp),
+def tPICADD : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, pclabel:$cp),
"$cp:\n\tadd $dst, pc",
[(set tGPR:$dst, (ARMpic_add tGPR:$lhs, imm:$cp))]>;
+// PC relative add.
+def tADDrPCi : T1I<(outs tGPR:$dst), (ins i32imm:$rhs),
+ "add $dst, pc, $rhs * 4", []>;
+
+// ADD rd, sp, #imm8
+// FIXME: hard code sp?
+def tADDrSPi : T1I<(outs tGPR:$dst), (ins GPR:$sp, i32imm:$rhs),
+ "add $dst, $sp, $rhs * 4 @ addrspi", []>;
+
+// ADD sp, sp, #imm7
+// FIXME: hard code sp?
+def tADDspi : T1It<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
+ "add $dst, $rhs * 4", []>;
+
+// FIXME: Make use of the following?
+// ADD rm, sp, rm
+// ADD sp, rm
+
//===----------------------------------------------------------------------===//
// Control Flow Instructions.
//
@@ -276,113 +294,135 @@ def tPUSH : TI<(outs), (ins reglist:$src1, variable_ops),
// Arithmetic Instructions.
//
-// Add with carry
-let isCommutable = 1 in
-def tADC : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
- "adc $dst, $rhs",
- [(set tGPR:$dst, (adde tGPR:$lhs, tGPR:$rhs))]>;
+// Add with carry register
+let isCommutable = 1, Defs = [CPSR], Uses = [CPSR] in
+def tADCS : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+ "adc $dst, $rhs",
+ [(set tGPR:$dst, (adde tGPR:$lhs, tGPR:$rhs))]>;
-def tADDS : TI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
- "add $dst, $lhs, $rhs",
- [(set tGPR:$dst, (addc tGPR:$lhs, tGPR:$rhs))]>;
-
-
-def tADDi3 : TI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// Add immediate
+let Defs = [CPSR] in {
+def tADDi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"add $dst, $lhs, $rhs",
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7:$rhs))]>;
+def tADDSi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+ "add $dst, $lhs, $rhs",
+ [(set tGPR:$dst, (addc tGPR:$lhs, imm0_7:$rhs))]>;
+}
-def tADDi8 : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+let Defs = [CPSR] in {
+def tADDi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"add $dst, $rhs",
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255:$rhs))]>;
+def tADDSi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+ "add $dst, $rhs",
+ [(set tGPR:$dst, (addc tGPR:$lhs, imm8_255:$rhs))]>;
+}
-def tADDrr : TI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// Add register
+let isCommutable = 1, Defs = [CPSR] in {
+def tADDrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"add $dst, $lhs, $rhs",
[(set tGPR:$dst, (add tGPR:$lhs, tGPR:$rhs))]>;
+def tADDSrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+ "add $dst, $lhs, $rhs",
+ [(set tGPR:$dst, (addc tGPR:$lhs, tGPR:$rhs))]>;
+}
let neverHasSideEffects = 1 in
-def tADDhirr : TIt<(outs tGPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+def tADDhirr : T1It<(outs tGPR:$dst), (ins GPR:$lhs, GPR:$rhs),
"add $dst, $rhs @ addhirr", []>;
-def tADDrPCi : TI<(outs tGPR:$dst), (ins i32imm:$rhs),
- "add $dst, pc, $rhs * 4", []>;
-
-def tADDrSPi : TI<(outs tGPR:$dst), (ins GPR:$sp, i32imm:$rhs),
- "add $dst, $sp, $rhs * 4 @ addrspi", []>;
-
-def tADDspi : TIt<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- "add $dst, $rhs * 4", []>;
-
-let isCommutable = 1 in
-def tAND : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// And register
+let isCommutable = 1, Defs = [CPSR] in
+def tAND : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"and $dst, $rhs",
[(set tGPR:$dst, (and tGPR:$lhs, tGPR:$rhs))]>;
-def tASRri : TI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// ASR immediate
+let Defs = [CPSR] in
+def tASRri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"asr $dst, $lhs, $rhs",
[(set tGPR:$dst, (sra tGPR:$lhs, (i32 imm:$rhs)))]>;
-def tASRrr : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// ASR register
+let Defs = [CPSR] in
+def tASRrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"asr $dst, $rhs",
[(set tGPR:$dst, (sra tGPR:$lhs, tGPR:$rhs))]>;
-def tBIC : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// BIC register
+let Defs = [CPSR] in
+def tBIC : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"bic $dst, $rhs",
[(set tGPR:$dst, (and tGPR:$lhs, (not tGPR:$rhs)))]>;
-
-def tCMN : TI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
+// CMN register
+let Defs = [CPSR] in {
+def tCMN : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
"cmn $lhs, $rhs",
[(ARMcmp tGPR:$lhs, (ineg tGPR:$rhs))]>;
-
-def tCMPi8 : TI<(outs), (ins tGPR:$lhs, i32imm:$rhs),
- "cmp $lhs, $rhs",
- [(ARMcmp tGPR:$lhs, imm0_255:$rhs)]>;
-
-def tCMPr : TI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
- "cmp $lhs, $rhs",
- [(ARMcmp tGPR:$lhs, tGPR:$rhs)]>;
-
-def tTST : TI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
- "tst $lhs, $rhs",
- [(ARMcmpNZ (and tGPR:$lhs, tGPR:$rhs), 0)]>;
-
-def tCMNNZ : TI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
+def tCMNNZ : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
"cmn $lhs, $rhs",
[(ARMcmpNZ tGPR:$lhs, (ineg tGPR:$rhs))]>;
+}
-def tCMPNZi8 : TI<(outs), (ins tGPR:$lhs, i32imm:$rhs),
+// CMP immediate
+let Defs = [CPSR] in {
+def tCMPi8 : T1I<(outs), (ins tGPR:$lhs, i32imm:$rhs),
+ "cmp $lhs, $rhs",
+ [(ARMcmp tGPR:$lhs, imm0_255:$rhs)]>;
+def tCMPNZi8 : T1I<(outs), (ins tGPR:$lhs, i32imm:$rhs),
"cmp $lhs, $rhs",
[(ARMcmpNZ tGPR:$lhs, imm0_255:$rhs)]>;
-def tCMPNZr : TI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
+}
+
+// CMP register
+let Defs = [CPSR] in {
+def tCMPr : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
+ "cmp $lhs, $rhs",
+ [(ARMcmp tGPR:$lhs, tGPR:$rhs)]>;
+def tCMPNZr : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
"cmp $lhs, $rhs",
[(ARMcmpNZ tGPR:$lhs, tGPR:$rhs)]>;
+}
// TODO: A7-37: CMP(3) - cmp hi regs
-let isCommutable = 1 in
-def tEOR : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// XOR register
+let isCommutable = 1, Defs = [CPSR] in
+def tEOR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"eor $dst, $rhs",
[(set tGPR:$dst, (xor tGPR:$lhs, tGPR:$rhs))]>;
-def tLSLri : TI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// LSL immediate
+let Defs = [CPSR] in
+def tLSLri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"lsl $dst, $lhs, $rhs",
[(set tGPR:$dst, (shl tGPR:$lhs, (i32 imm:$rhs)))]>;
-def tLSLrr : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// LSL register
+let Defs = [CPSR] in
+def tLSLrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"lsl $dst, $rhs",
[(set tGPR:$dst, (shl tGPR:$lhs, tGPR:$rhs))]>;
-def tLSRri : TI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// LSR immediate
+let Defs = [CPSR] in
+def tLSRri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"lsr $dst, $lhs, $rhs",
[(set tGPR:$dst, (srl tGPR:$lhs, (i32 imm:$rhs)))]>;
-def tLSRrr : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// LSR register
+let Defs = [CPSR] in
+def tLSRrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"lsr $dst, $rhs",
[(set tGPR:$dst, (srl tGPR:$lhs, tGPR:$rhs))]>;
-// FIXME: This is not rematerializable because mov changes the condition code.
-def tMOVi8 : TI<(outs tGPR:$dst), (ins i32imm:$src),
+// move register
+let Defs = [CPSR] in
+def tMOVi8 : T1I<(outs tGPR:$dst), (ins i32imm:$src),
"mov $dst, $src",
[(set tGPR:$dst, imm0_255:$src)]>;
@@ -392,41 +432,47 @@ def tMOVi8 : TI<(outs tGPR:$dst), (ins i32imm:$src),
// Note: MOV(2) of two low regs updates the flags, so we emit this as 'cpy',
// which is MOV(3). This also supports high registers.
let neverHasSideEffects = 1 in {
-def tMOVr : TI<(outs tGPR:$dst), (ins tGPR:$src),
+def tMOVr : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"cpy $dst, $src", []>;
-def tMOVhir2lor : TI<(outs tGPR:$dst), (ins GPR:$src),
+def tMOVhir2lor : T1I<(outs tGPR:$dst), (ins GPR:$src),
"cpy $dst, $src\t@ hir2lor", []>;
-def tMOVlor2hir : TI<(outs GPR:$dst), (ins tGPR:$src),
+def tMOVlor2hir : T1I<(outs GPR:$dst), (ins tGPR:$src),
"cpy $dst, $src\t@ lor2hir", []>;
-def tMOVhir2hir : TI<(outs GPR:$dst), (ins GPR:$src),
+def tMOVhir2hir : T1I<(outs GPR:$dst), (ins GPR:$src),
"cpy $dst, $src\t@ hir2hir", []>;
} // neverHasSideEffects
-let isCommutable = 1 in
-def tMUL : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// multiply register
+let isCommutable = 1, Defs = [CPSR] in
+def tMUL : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"mul $dst, $rhs",
[(set tGPR:$dst, (mul tGPR:$lhs, tGPR:$rhs))]>;
-def tMVN : TI<(outs tGPR:$dst), (ins tGPR:$src),
+// move inverse register
+let Defs = [CPSR] in
+def tMVN : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"mvn $dst, $src",
[(set tGPR:$dst, (not tGPR:$src))]>;
-def tNEG : TI<(outs tGPR:$dst), (ins tGPR:$src),
+// negate register
+let Defs = [CPSR] in
+def tNEG : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"neg $dst, $src",
[(set tGPR:$dst, (ineg tGPR:$src))]>;
-let isCommutable = 1 in
-def tORR : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// bitwise or register
+let isCommutable = 1, Defs = [CPSR] in
+def tORR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"orr $dst, $rhs",
[(set tGPR:$dst, (or tGPR:$lhs, tGPR:$rhs))]>;
-
-def tREV : TI<(outs tGPR:$dst), (ins tGPR:$src),
+// swaps
+def tREV : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"rev $dst, $src",
[(set tGPR:$dst, (bswap tGPR:$src))]>,
Requires<[IsThumb, HasV6]>;
-def tREV16 : TI<(outs tGPR:$dst), (ins tGPR:$src),
+def tREV16 : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"rev16 $dst, $src",
[(set tGPR:$dst,
(or (and (srl tGPR:$src, (i32 8)), 0xFF),
@@ -435,7 +481,7 @@ def tREV16 : TI<(outs tGPR:$dst), (ins tGPR:$src),
(and (shl tGPR:$src, (i32 8)), 0xFF000000)))))]>,
Requires<[IsThumb, HasV6]>;
-def tREVSH : TI<(outs tGPR:$dst), (ins tGPR:$src),
+def tREVSH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"revsh $dst, $src",
[(set tGPR:$dst,
(sext_inreg
@@ -443,53 +489,78 @@ def tREVSH : TI<(outs tGPR:$dst), (ins tGPR:$src),
(shl tGPR:$src, (i32 8))), i16))]>,
Requires<[IsThumb, HasV6]>;
-def tROR : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// rotate right register
+let Defs = [CPSR] in
+def tROR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"ror $dst, $rhs",
[(set tGPR:$dst, (rotr tGPR:$lhs, tGPR:$rhs))]>;
-
-// Subtract with carry
-def tSBC : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// Subtract with carry register
+let Defs = [CPSR], Uses = [CPSR] in
+def tSBCS : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"sbc $dst, $rhs",
[(set tGPR:$dst, (sube tGPR:$lhs, tGPR:$rhs))]>;
-def tSUBS : TI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
- "sub $dst, $lhs, $rhs",
- [(set tGPR:$dst, (subc tGPR:$lhs, tGPR:$rhs))]>;
-
-
-// TODO: A7-96: STMIA - store multiple.
-
-def tSUBi3 : TI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// Subtract immediate
+let Defs = [CPSR] in {
+def tSUBi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"sub $dst, $lhs, $rhs",
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7_neg:$rhs))]>;
+def tSUBSi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+ "sub $dst, $lhs, $rhs",
+ [(set tGPR:$dst, (addc tGPR:$lhs, imm0_7_neg:$rhs))]>;
+}
-def tSUBi8 : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+let Defs = [CPSR] in {
+def tSUBi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"sub $dst, $rhs",
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255_neg:$rhs))]>;
+def tSUBSi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+ "sub $dst, $rhs",
+ [(set tGPR:$dst, (addc tGPR:$lhs, imm8_255_neg:$rhs))]>;
+}
-def tSUBrr : TI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+// subtract register
+let Defs = [CPSR] in {
+def tSUBrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
"sub $dst, $lhs, $rhs",
[(set tGPR:$dst, (sub tGPR:$lhs, tGPR:$rhs))]>;
+def tSUBSrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
+ "sub $dst, $lhs, $rhs",
+ [(set tGPR:$dst, (subc tGPR:$lhs, tGPR:$rhs))]>;
+}
-def tSUBspi : TIt<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
+// TODO: A7-96: STMIA - store multiple.
+
+def tSUBspi : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
"sub $dst, $rhs * 4", []>;
-def tSXTB : TI<(outs tGPR:$dst), (ins tGPR:$src),
+// sign-extend byte
+def tSXTB : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"sxtb $dst, $src",
[(set tGPR:$dst, (sext_inreg tGPR:$src, i8))]>,
Requires<[IsThumb, HasV6]>;
-def tSXTH : TI<(outs tGPR:$dst), (ins tGPR:$src),
+
+// sign-extend short
+def tSXTH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"sxth $dst, $src",
[(set tGPR:$dst, (sext_inreg tGPR:$src, i16))]>,
Requires<[IsThumb, HasV6]>;
+// test
+let isCommutable = 1, Defs = [CPSR] in
+def tTST : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
+ "tst $lhs, $rhs",
+ [(ARMcmpNZ (and tGPR:$lhs, tGPR:$rhs), 0)]>;
-def tUXTB : TI<(outs tGPR:$dst), (ins tGPR:$src),
+// zero-extend byte
+def tUXTB : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"uxtb $dst, $src",
[(set tGPR:$dst, (and tGPR:$src, 0xFF))]>,
Requires<[IsThumb, HasV6]>;
-def tUXTH : TI<(outs tGPR:$dst), (ins tGPR:$src),
+
+// zero-extend short
+def tUXTH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
"uxth $dst, $src",
[(set tGPR:$dst, (and tGPR:$src, 0xFFFF))]>,
Requires<[IsThumb, HasV6]>;
@@ -536,35 +607,35 @@ let isCall = 1,
//
// ConstantPool, GlobalAddress
-def : ThumbPat<(ARMWrapper tglobaladdr :$dst), (tLEApcrel tglobaladdr :$dst)>;
-def : ThumbPat<(ARMWrapper tconstpool :$dst), (tLEApcrel tconstpool :$dst)>;
+def : TPat<(ARMWrapper tglobaladdr :$dst), (tLEApcrel tglobaladdr :$dst)>;
+def : TPat<(ARMWrapper tconstpool :$dst), (tLEApcrel tconstpool :$dst)>;
// JumpTable
-def : ThumbPat<(ARMWrapperJT tjumptable:$dst, imm:$id),
- (tLEApcrelJT tjumptable:$dst, imm:$id)>;
+def : TPat<(ARMWrapperJT tjumptable:$dst, imm:$id),
+ (tLEApcrelJT tjumptable:$dst, imm:$id)>;
// Direct calls
-def : ThumbPat<(ARMtcall texternalsym:$func), (tBL texternalsym:$func)>;
-def : ThumbV5Pat<(ARMcall texternalsym:$func), (tBLXi texternalsym:$func)>;
+def : TPat<(ARMtcall texternalsym:$func), (tBL texternalsym:$func)>;
+def : Tv5Pat<(ARMcall texternalsym:$func), (tBLXi texternalsym:$func)>;
// Indirect calls to ARM routines
-def : ThumbV5Pat<(ARMcall tGPR:$dst), (tBLXr tGPR:$dst)>;
+def : Tv5Pat<(ARMcall tGPR:$dst), (tBLXr tGPR:$dst)>;
// zextload i1 -> zextload i8
-def : ThumbPat<(zextloadi1 t_addrmode_s1:$addr),
- (tLDRB t_addrmode_s1:$addr)>;
+def : TPat<(zextloadi1 t_addrmode_s1:$addr),
+ (tLDRB t_addrmode_s1:$addr)>;
// extload -> zextload
-def : ThumbPat<(extloadi1 t_addrmode_s1:$addr), (tLDRB t_addrmode_s1:$addr)>;
-def : ThumbPat<(extloadi8 t_addrmode_s1:$addr), (tLDRB t_addrmode_s1:$addr)>;
-def : ThumbPat<(extloadi16 t_addrmode_s2:$addr), (tLDRH t_addrmode_s2:$addr)>;
+def : TPat<(extloadi1 t_addrmode_s1:$addr), (tLDRB t_addrmode_s1:$addr)>;
+def : TPat<(extloadi8 t_addrmode_s1:$addr), (tLDRB t_addrmode_s1:$addr)>;
+def : TPat<(extloadi16 t_addrmode_s2:$addr), (tLDRH t_addrmode_s2:$addr)>;
// Large immediate handling.
// Two piece imms.
-def : ThumbPat<(i32 thumb_immshifted:$src),
- (tLSLri (tMOVi8 (thumb_immshifted_val imm:$src)),
- (thumb_immshifted_shamt imm:$src))>;
+def : T1Pat<(i32 thumb_immshifted:$src),
+ (tLSLri (tMOVi8 (thumb_immshifted_val imm:$src)),
+ (thumb_immshifted_shamt imm:$src))>;
-def : ThumbPat<(i32 imm0_255_comp:$src),
- (tMVN (tMOVi8 (imm_comp_XFORM imm:$src)))>;
+def : T1Pat<(i32 imm0_255_comp:$src),
+ (tMVN (tMOVi8 (imm_comp_XFORM imm:$src)))>;
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index e0617e466208a..bfdf7192f4d19 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -14,9 +14,9 @@
// Shifted operands. No register controlled shifts for Thumb2.
// Note: We do not support rrx shifted operands yet.
def t2_so_reg : Operand<i32>, // reg imm
- ComplexPattern<i32, 2, "SelectThumb2ShifterOperandReg",
+ ComplexPattern<i32, 2, "SelectT2ShifterOperandReg",
[shl,srl,sra,rotr]> {
- let PrintMethod = "printSOOperand";
+ let PrintMethod = "printT2SOOperand";
let MIOperandInfo = (ops GPR, i32imm);
}
@@ -69,6 +69,11 @@ def t2_so_imm_neg : Operand<i32>,
let PrintMethod = "printT2SOImmOperand";
}
+/// imm1_31 predicate - True if the 32-bit immediate is in the range [1,31].
+def imm1_31 : PatLeaf<(i32 imm), [{
+ return (int32_t)N->getZExtValue() >= 1 && (int32_t)N->getZExtValue() < 32;
+}]>;
+
/// imm0_4095 predicate - True if the 32-bit immediate is in the range [0.4095].
def imm0_4095 : PatLeaf<(i32 imm), [{
return (uint32_t)N->getZExtValue() < 4096;
@@ -121,137 +126,287 @@ def t2_lo16AllZero : PatLeaf<(i32 imm), [{
return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0;
}], t2_hi16>;
+
//===----------------------------------------------------------------------===//
-// Thumb2 to cover the functionality of the ARM instruction set.
+// Multiclass helpers...
//
-/// T2I_bin_is - Defines a set of (op reg, {so_imm|so_reg}) patterns for a
-// binary operation that produces a value.
-multiclass T2I_bin_is<string opc, PatFrag opnode> {
+/// T2I_un_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a
+/// unary operation that produces a value. These are predicable and can be
+/// changed to modify CPSR.
+multiclass T2I_un_irs<string opc, PatFrag opnode, bit Cheap = 0, bit ReMat = 0>{
// shifted imm
- def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+ def i : T2sI<(outs GPR:$dst), (ins t2_so_imm:$src),
+ opc, " $dst, $src",
+ [(set GPR:$dst, (opnode t2_so_imm:$src))]> {
+ let isAsCheapAsAMove = Cheap;
+ let isReMaterializable = ReMat;
+ }
+ // register
+ def r : T2I<(outs GPR:$dst), (ins GPR:$src),
+ opc, " $dst, $src",
+ [(set GPR:$dst, (opnode GPR:$src))]>;
// shifted register
- def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+ def s : T2I<(outs GPR:$dst), (ins t2_so_reg:$src),
+ opc, " $dst, $src",
+ [(set GPR:$dst, (opnode t2_so_reg:$src))]>;
}
-/// T2I_2bin_is - Same as T2I_bin_is except the order of operands are reversed.
+/// T2I_bin_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a
+// binary operation that produces a value. These are predicable and can be
+/// changed to modify CPSR.
+multiclass T2I_bin_irs<string opc, PatFrag opnode, bit Commutable = 0> {
+ // shifted imm
+ def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+ // register
+ def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> {
+ let isCommutable = Commutable;
+ }
+ // shifted register
+ def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+}
+
+/// T2I_rbin_is - Same as T2I_bin_irs except the order of operands are
+/// reversed. It doesn't define the 'rr' form since it's handled by its
+/// T2I_bin_irs counterpart.
multiclass T2I_rbin_is<string opc, PatFrag opnode> {
// shifted imm
def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
+ opc, " $dst, $rhs, $lhs",
[(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
// shifted register
def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
+ opc, " $dst, $rhs, $lhs",
[(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
}
-/// T2I_bin_s_is - Similar to T2I_bin_is except it sets the 's' bit so the
+/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
/// instruction modifies the CPSR register.
let Defs = [CPSR] in {
-multiclass T2I_bin_s_is<string opc, PatFrag opnode> {
+multiclass T2I_bin_s_irs<string opc, PatFrag opnode, bit Commutable = 0> {
// shifted imm
def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
+ !strconcat(opc, "s"), " $dst, $lhs, $rhs",
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
-
+ // register
+ def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ !strconcat(opc, "s"), " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> {
+ let isCommutable = Commutable;
+ }
// shifted register
def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
+ !strconcat(opc, "s"), " $dst, $lhs, $rhs",
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
}
}
-/// T2I_rbin_s_is - Same as T2I_bin_s_is except the order of operands are
-/// reversed.
-let Defs = [CPSR] in {
-multiclass T2I_rbin_s_is<string opc, PatFrag opnode> {
+/// T2I_bin_ii12rs - Defines a set of (op reg, {so_imm|imm0_4095|r|so_reg})
+/// patterns for a binary operation that produces a value.
+multiclass T2I_bin_ii12rs<string opc, PatFrag opnode, bit Commutable = 0> {
// shifted imm
- def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
-
+ def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+ // 12-bit imm
+ def ri12 : T2sI<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
+ !strconcat(opc, "w"), " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]>;
+ // register
+ def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> {
+ let isCommutable = Commutable;
+ }
// shifted register
- def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
-}
+ def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
}
-/// T2I_bin_ii12s - Defines a set of (op reg, {so_imm|imm0_4095|so_reg}) patterns
-/// for a binary operation that produces a value.
-multiclass T2I_bin_ii12s<string opc, PatFrag opnode> {
+/// T2I_adde_sube_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a
+/// binary operation that produces a value and use and define the carry bit.
+/// It's not predicable.
+let Uses = [CPSR] in {
+multiclass T2I_adde_sube_irs<string opc, PatFrag opnode, bit Commutable = 0> {
// shifted imm
- def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
- // 12-bit imm
- def ri12 : T2I<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- !strconcat(opc, "w $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]>;
+ def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>;
+ // register
+ def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUnused]> {
+ let isCommutable = Commutable;
+ }
// shifted register
- def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+ def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>;
+ // Carry setting variants
+ // shifted imm
+ def Sri : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
+ // register
+ def Srr : T2XI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ let isCommutable = Commutable;
+ }
+ // shifted register
+ def Srs : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
+}
}
-/// T2I_bin_c_is - Defines a set of (op reg, {so_imm|reg}) patterns for a
-// binary operation that produces a value and set the carry bit. It can also
-/// optionally set CPSR.
-let Uses = [CPSR] in {
-multiclass T2I_bin_c_is<string opc, PatFrag opnode> {
+/// T2I_rsc_is - Same as T2I_adde_sube_irs except the order of operands are
+/// reversed. It doesn't define the 'rr' form since it's handled by its
+/// T2I_adde_sube_irs counterpart.
+let Defs = [CPSR], Uses = [CPSR] in {
+multiclass T2I_rsc_is<string opc, PatFrag opnode> {
// shifted imm
- def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
-
+ def ri : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
+ opc, " $dst, $rhs, $lhs",
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>;
// shifted register
- def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+ def rs : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
+ opc, " $dst, $rhs, $lhs",
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>;
+ // shifted imm
+ def Sri : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
+ !strconcat(opc, "s $dst, $rhs, $lhs"),
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
+ // shifted register
+ def Srs : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
+ !strconcat(opc, "s $dst, $rhs, $lhs"),
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>,
+ Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> {
+ let Defs = [CPSR];
+ }
}
}
-/// T2I_rbin_c_is - Same as T2I_bin_c_is except the order of operands are
-/// reversed.
-let Uses = [CPSR] in {
-multiclass T2I_rbin_c_is<string opc, PatFrag opnode> {
+/// T2I_rbin_s_is - Same as T2I_bin_s_irs except the order of operands are
+/// reversed. It doesn't define the 'rr' form since it's handled by its
+/// T2I_bin_s_irs counterpart.
+let Defs = [CPSR] in {
+multiclass T2I_rbin_s_is<string opc, PatFrag opnode> {
// shifted imm
- def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
-
+ def ri : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $rhs, $lhs"),
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
// shifted register
- def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
+ def rs : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $rhs, $lhs"),
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
}
}
+/// T2I_sh_ir - Defines a set of (op reg, {so_imm|r}) patterns for a shift /
+// rotate operation that produces a value.
+multiclass T2I_sh_ir<string opc, PatFrag opnode> {
+ // 5-bit imm
+ def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, imm1_31:$rhs))]>;
+ // register
+ def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
+ opc, " $dst, $lhs, $rhs",
+ [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>;
+}
-/// T21_cmp_irs - Defines a set of (op r, {so_imm|so_reg}) cmp / test
-/// patterns. Similar to T2I_bin_is except the instruction does not produce
+/// T21_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test
+/// patterns. Similar to T2I_bin_irs except the instruction does not produce
/// a explicit result, only implicitly set CPSR.
let Uses = [CPSR] in {
multiclass T2I_cmp_is<string opc, PatFrag opnode> {
// shifted imm
def ri : T2I<(outs), (ins GPR:$lhs, t2_so_imm:$rhs),
- !strconcat(opc, " $lhs, $rhs"),
+ opc, " $lhs, $rhs",
[(opnode GPR:$lhs, t2_so_imm:$rhs)]>;
-
+ // register
+ def rr : T2I<(outs), (ins GPR:$lhs, GPR:$rhs),
+ opc, " $lhs, $rhs",
+ [(opnode GPR:$lhs, GPR:$rhs)]>;
// shifted register
def rs : T2I<(outs), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, " $lhs, $rhs"),
+ opc, " $lhs, $rhs",
[(opnode GPR:$lhs, t2_so_reg:$rhs)]>;
}
}
//===----------------------------------------------------------------------===//
-// Arithmetic Instructions.
+// Instructions
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instructions.
+//
+
+let isNotDuplicable = 1 in
+def t2PICADD : T2XI<(outs tGPR:$dst), (ins tGPR:$lhs, pclabel:$cp),
+ "$cp:\n\tadd $dst, pc",
+ [(set tGPR:$dst, (ARMpic_add tGPR:$lhs, imm:$cp))]>;
+
+
+// LEApcrel - Load a pc-relative address into a register without offending the
+// assembler.
+def t2LEApcrel : T2XI<(outs GPR:$dst), (ins i32imm:$label, pred:$p),
+ !strconcat(!strconcat(".set PCRELV${:uid}, ($label-(",
+ "${:private}PCRELL${:uid}+8))\n"),
+ !strconcat("${:private}PCRELL${:uid}:\n\t",
+ "add$p $dst, pc, #PCRELV${:uid}")),
+ []>;
+
+def t2LEApcrelJT : T2XI<(outs GPR:$dst),
+ (ins i32imm:$label, i32imm:$id, pred:$p),
+ !strconcat(!strconcat(".set PCRELV${:uid}, (${label}_${id:no_hash}-(",
+ "${:private}PCRELL${:uid}+8))\n"),
+ !strconcat("${:private}PCRELL${:uid}:\n\t",
+ "add$p $dst, pc, #PCRELV${:uid}")),
+ []>;
+
+// ADD rd, sp, #so_imm
+def t2ADDrSPi : T2XI<(outs GPR:$dst), (ins GPR:$sp, t2_so_imm:$imm),
+ "add $dst, $sp, $imm",
+ []>;
+
+// ADD rd, sp, #imm12
+def t2ADDrSPi12 : T2XI<(outs GPR:$dst), (ins GPR:$sp, i32imm:$imm),
+ "addw $dst, $sp, $imm",
+ []>;
+
+def t2ADDrSPs : T2XI<(outs GPR:$dst), (ins GPR:$sp, t2_so_reg:$rhs),
+ "addw $dst, $sp, $rhs",
+ []>;
+
+
+//===----------------------------------------------------------------------===//
+// Load / store Instructions.
//
//===----------------------------------------------------------------------===//
@@ -259,90 +414,95 @@ multiclass T2I_cmp_is<string opc, PatFrag opnode> {
//
let neverHasSideEffects = 1 in
-def t2MOVr : T2I<(outs GPR:$dst), (ins GPR:$src),
- "mov $dst, $src", []>;
+def t2MOVr : T2sI<(outs GPR:$dst), (ins GPR:$src),
+ "mov", " $dst, $src", []>;
+
+let isReMaterializable = 1, isAsCheapAsAMove = 1 in
+def t2MOVi : T2sI<(outs GPR:$dst), (ins t2_so_imm:$src),
+ "mov", " $dst, $src",
+ [(set GPR:$dst, t2_so_imm:$src)]>;
+let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src),
- "movw $dst, $src",
+ "movw", " $dst, $src",
[(set GPR:$dst, imm0_65535:$src)]>;
-
-// FIXME: Move (shifted register) is a pseudo-instruction for ASR, LSL, LSR,
-// ROR, and RRX. Consider splitting into multiple instructions.
-def t2MOVs : T2I<(outs GPR:$dst), (ins t2_so_reg:$src),
- "mov $dst, $src",
- [(set GPR:$dst, t2_so_reg:$src)]>;
-def t2MOVrx : T2I<(outs GPR:$dst), (ins GPR:$src),
- "mov $dst, $src, rrx",
- [(set GPR:$dst, (ARMrrx GPR:$src))]>;
-
-
// FIXME: Also available in ARM mode.
let Constraints = "$src = $dst" in
-def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
- "movt $dst, $imm",
- [(set GPR:$dst,
- (or (and GPR:$src, 0xffff), t2_lo16AllZero:$imm))]>;
+def t2MOVTi16 : T2sI<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
+ "movt", " $dst, $imm",
+ [(set GPR:$dst,
+ (or (and GPR:$src, 0xffff), t2_lo16AllZero:$imm))]>;
//===----------------------------------------------------------------------===//
// Arithmetic Instructions.
//
-defm t2ADD : T2I_bin_ii12s<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>;
-defm t2SUB : T2I_bin_ii12s<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
+defm t2ADD : T2I_bin_ii12rs<"add", BinOpFrag<(add node:$LHS, node:$RHS)>, 1>;
+defm t2SUB : T2I_bin_ii12rs<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants.
-defm t2ADDS : T2I_bin_s_is<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
-defm t2SUBS : T2I_bin_s_is<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
+defm t2ADDS : T2I_bin_s_irs <"add", BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
+defm t2SUBS : T2I_bin_s_irs <"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
-// FIXME: predication support
-defm t2ADC : T2I_bin_c_is<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
-defm t2SBC : T2I_bin_c_is<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
+defm t2ADC : T2I_adde_sube_irs<"adc",BinOpFrag<(adde node:$LHS, node:$RHS)>,1>;
+defm t2SBC : T2I_adde_sube_irs<"sbc",BinOpFrag<(sube node:$LHS, node:$RHS)>>;
// RSB, RSC
-defm t2RSB : T2I_rbin_is <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
-defm t2RSBS : T2I_rbin_c_is<"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
-defm t2RSC : T2I_rbin_s_is<"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
+defm t2RSB : T2I_rbin_is <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
+defm t2RSBS : T2I_rbin_s_is <"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
+defm t2RSC : T2I_rsc_is <"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
-def : Thumb2Pat<(add GPR:$src, t2_so_imm_neg:$imm),
- (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>;
-def : Thumb2Pat<(add GPR:$src, imm0_4095_neg:$imm),
- (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>;
+def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm),
+ (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>;
+def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm),
+ (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>;
//===----------------------------------------------------------------------===//
+// Shift and rotate Instructions.
+//
+
+defm t2LSL : T2I_sh_ir<"lsl", BinOpFrag<(shl node:$LHS, node:$RHS)>>;
+defm t2LSR : T2I_sh_ir<"lsr", BinOpFrag<(srl node:$LHS, node:$RHS)>>;
+defm t2ASR : T2I_sh_ir<"asr", BinOpFrag<(sra node:$LHS, node:$RHS)>>;
+defm t2ROR : T2I_sh_ir<"ror", BinOpFrag<(rotr node:$LHS, node:$RHS)>>;
+
+def t2MOVrx : T2sI<(outs GPR:$dst), (ins GPR:$src),
+ "mov", " $dst, $src, rrx",
+ [(set GPR:$dst, (ARMrrx GPR:$src))]>;
+
+//===----------------------------------------------------------------------===//
// Bitwise Instructions.
//
-defm t2AND : T2I_bin_is <"and", BinOpFrag<(and node:$LHS, node:$RHS)>>;
-defm t2ORR : T2I_bin_is <"orr", BinOpFrag<(or node:$LHS, node:$RHS)>>;
-defm t2EOR : T2I_bin_is <"eor", BinOpFrag<(xor node:$LHS, node:$RHS)>>;
+defm t2AND : T2I_bin_irs<"and", BinOpFrag<(and node:$LHS, node:$RHS)>, 1>;
+defm t2ORR : T2I_bin_irs<"orr", BinOpFrag<(or node:$LHS, node:$RHS)>, 1>;
+defm t2EOR : T2I_bin_irs<"eor", BinOpFrag<(xor node:$LHS, node:$RHS)>, 1>;
-defm t2BIC : T2I_bin_is <"bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
+defm t2BIC : T2I_bin_irs<"bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
-def : Thumb2Pat<(and GPR:$src, t2_so_imm_not:$imm),
- (t2BICri GPR:$src, t2_so_imm_not:$imm)>;
+def : T2Pat<(and GPR:$src, t2_so_imm_not:$imm),
+ (t2BICri GPR:$src, t2_so_imm_not:$imm)>;
-defm t2ORN : T2I_bin_is <"orn", BinOpFrag<(or node:$LHS, (not node:$RHS))>>;
+defm t2ORN : T2I_bin_irs<"orn", BinOpFrag<(or node:$LHS, (not node:$RHS))>>;
-def : Thumb2Pat<(or GPR:$src, t2_so_imm_not:$imm),
- (t2ORNri GPR:$src, t2_so_imm_not:$imm)>;
+def : T2Pat<(or GPR:$src, t2_so_imm_not:$imm),
+ (t2ORNri GPR:$src, t2_so_imm_not:$imm)>;
+// Prefer over of t2EORri ra, rb, -1 because mvn has 16-bit version
+let AddedComplexity = 1 in
+defm t2MVN : T2I_un_irs <"mvn", UnOpFrag<(not node:$Src)>, 1, 1>;
-def t2MVNr : T2I<(outs GPR:$dst), (ins t2_so_reg:$rhs),
- "mvn $dst, $rhs",
- [(set GPR:$dst, (not t2_so_reg:$rhs))]>;
-let isReMaterializable = 1, isAsCheapAsAMove = 1 in
-def t2MVNi : T2I<(outs GPR:$dst), (ins t2_so_imm_not:$rhs),
- "mvn $dst, $rhs",
- [(set GPR:$dst, t2_so_imm_not:$rhs)]>;
+def : T2Pat<(t2_so_imm_not:$src),
+ (t2MVNi t2_so_imm_not:$src)>;
// A8.6.17 BFC - Bitfield clear
// FIXME: Also available in ARM mode.
let Constraints = "$src = $dst" in
def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
- "bfc $dst, $imm",
+ "bfc", " $dst, $imm",
[(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>;
// FIXME: A8.6.18 BFI - Bitfield insert (Encoding T1)
@@ -350,16 +510,17 @@ def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
//===----------------------------------------------------------------------===//
// Multiply Instructions.
//
+let isCommutable = 1 in
def t2MUL: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b),
- "mul $dst, $a, $b",
+ "mul", " $dst, $a, $b",
[(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
def t2MLA: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
- "mla $dst, $a, $b, $c",
+ "mla", " $dst, $a, $b, $c",
[(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>;
def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
- "mls $dst, $a, $b, $c",
+ "mls", " $dst, $a, $b, $c",
[(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>;
// FIXME: SMULL, etc.
@@ -368,20 +529,16 @@ def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
// Misc. Arithmetic Instructions.
//
-/////
-/// A8.6.31 CLZ
-/////
-// FIXME not firing? but ARM version does...
def t2CLZ : T2I<(outs GPR:$dst), (ins GPR:$src),
- "clz $dst, $src",
+ "clz", " $dst, $src",
[(set GPR:$dst, (ctlz GPR:$src))]>;
def t2REV : T2I<(outs GPR:$dst), (ins GPR:$src),
- "rev $dst, $src",
+ "rev", " $dst, $src",
[(set GPR:$dst, (bswap GPR:$src))]>;
def t2REV16 : T2I<(outs GPR:$dst), (ins GPR:$src),
- "rev16 $dst, $src",
+ "rev16", " $dst, $src",
[(set GPR:$dst,
(or (and (srl GPR:$src, (i32 8)), 0xFF),
(or (and (shl GPR:$src, (i32 8)), 0xFF00),
@@ -392,7 +549,7 @@ def t2REV16 : T2I<(outs GPR:$dst), (ins GPR:$src),
/// A8.6.137 REVSH
/////
def t2REVSH : T2I<(outs GPR:$dst), (ins GPR:$src),
- "revsh $dst, $src",
+ "revsh", " $dst, $src",
[(set GPR:$dst,
(sext_inreg
(or (srl (and GPR:$src, 0xFFFF), (i32 8)),
@@ -414,11 +571,11 @@ defm t2CMN : T2I_cmp_is<"cmn",
defm t2CMNnz : T2I_cmp_is<"cmn",
BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>;
-def : Thumb2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm),
- (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
+def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm),
+ (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
-def : Thumb2Pat<(ARMcmpNZ GPR:$src, t2_so_imm_neg:$imm),
- (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
+def : T2Pat<(ARMcmpNZ GPR:$src, t2_so_imm_neg:$imm),
+ (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
// FIXME: TST, TEQ, etc.
@@ -433,8 +590,13 @@ def : Thumb2Pat<(ARMcmpNZ GPR:$src, t2_so_imm_neg:$imm),
// Non-Instruction Patterns
//
+// ConstantPool, GlobalAddress, and JumpTable
+def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>;
+def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>;
+def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id),
+ (t2LEApcrelJT tjumptable:$dst, imm:$id)>;
+
// Large immediate handling.
-def : Thumb2Pat<(i32 imm:$src),
- (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)),
- (t2_hi16 imm:$src))>;
+def : T2Pat<(i32 imm:$src),
+ (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)), (t2_hi16 imm:$src))>;
diff --git a/lib/Target/ARM/ARMTargetAsmInfo.cpp b/lib/Target/ARM/ARMTargetAsmInfo.cpp
index 42b8eae5e0568..bf2c14e859652 100644
--- a/lib/Target/ARM/ARMTargetAsmInfo.cpp
+++ b/lib/Target/ARM/ARMTargetAsmInfo.cpp
@@ -43,7 +43,7 @@ const char *const llvm::arm_asm_table[] = {
0,0
};
-ARMDarwinTargetAsmInfo::ARMDarwinTargetAsmInfo(const ARMTargetMachine &TM):
+ARMDarwinTargetAsmInfo::ARMDarwinTargetAsmInfo(const ARMBaseTargetMachine &TM):
ARMTargetAsmInfo<DarwinTargetAsmInfo>(TM) {
Subtarget = &TM.getSubtarget<ARMSubtarget>();
@@ -55,7 +55,7 @@ ARMDarwinTargetAsmInfo::ARMDarwinTargetAsmInfo(const ARMTargetMachine &TM):
SupportsDebugInformation = true;
}
-ARMELFTargetAsmInfo::ARMELFTargetAsmInfo(const ARMTargetMachine &TM):
+ARMELFTargetAsmInfo::ARMELFTargetAsmInfo(const ARMBaseTargetMachine &TM):
ARMTargetAsmInfo<ELFTargetAsmInfo>(TM) {
Subtarget = &TM.getSubtarget<ARMSubtarget>();
diff --git a/lib/Target/ARM/ARMTargetAsmInfo.h b/lib/Target/ARM/ARMTargetAsmInfo.h
index 683692f00aabe..d3f2da0f4b098 100644
--- a/lib/Target/ARM/ARMTargetAsmInfo.h
+++ b/lib/Target/ARM/ARMTargetAsmInfo.h
@@ -26,7 +26,7 @@ namespace llvm {
template <class BaseTAI>
struct ARMTargetAsmInfo : public BaseTAI {
- explicit ARMTargetAsmInfo(const ARMTargetMachine &TM) : BaseTAI(TM) {
+ explicit ARMTargetAsmInfo(const ARMBaseTargetMachine &TM) : BaseTAI(TM) {
BaseTAI::AsmTransCBE = arm_asm_table;
BaseTAI::AlignmentIsInBytes = false;
@@ -51,11 +51,11 @@ namespace llvm {
EXTERN_TEMPLATE_INSTANTIATION(class ARMTargetAsmInfo<TargetAsmInfo>);
struct ARMDarwinTargetAsmInfo : public ARMTargetAsmInfo<DarwinTargetAsmInfo> {
- explicit ARMDarwinTargetAsmInfo(const ARMTargetMachine &TM);
+ explicit ARMDarwinTargetAsmInfo(const ARMBaseTargetMachine &TM);
};
struct ARMELFTargetAsmInfo : public ARMTargetAsmInfo<ELFTargetAsmInfo> {
- explicit ARMELFTargetAsmInfo(const ARMTargetMachine &TM);
+ explicit ARMELFTargetAsmInfo(const ARMBaseTargetMachine &TM);
};
} // namespace llvm
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 8006b9be32ebe..f7b821539df1c 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -39,13 +39,11 @@ int ARMTargetMachineModule = 0;
static RegisterTarget<ARMTargetMachine> X("arm", "ARM");
static RegisterTarget<ThumbTargetMachine> Y("thumb", "Thumb");
-// Force static initialization when called from llvm/InitializeAllTargets.h
-namespace llvm {
- void InitializeARMTarget() { }
-}
+// Force static initialization.
+extern "C" void LLVMInitializeARMTarget() { }
// No assembler printer by default
-ARMTargetMachine::AsmPrinterCtorFn ARMTargetMachine::AsmPrinterCtor = 0;
+ARMBaseTargetMachine::AsmPrinterCtorFn ARMBaseTargetMachine::AsmPrinterCtor = 0;
/// ThumbTargetMachine - Create an Thumb architecture model.
///
@@ -76,34 +74,36 @@ unsigned ThumbTargetMachine::getModuleMatchQuality(const Module &M) {
return getJITMatchQuality()/2;
}
-ThumbTargetMachine::ThumbTargetMachine(const Module &M, const std::string &FS)
- : ARMTargetMachine(M, FS, true) {
-}
-
/// TargetMachine ctor - Create an ARM architecture model.
///
-ARMTargetMachine::ARMTargetMachine(const Module &M, const std::string &FS,
- bool isThumb)
+ARMBaseTargetMachine::ARMBaseTargetMachine(const Module &M,
+ const std::string &FS,
+ bool isThumb)
: Subtarget(M, FS, isThumb),
- DataLayout(Subtarget.isAPCS_ABI() ?
- // APCS ABI
- (isThumb ?
- std::string("e-p:32:32-f64:32:32-i64:32:32-"
- "i16:16:32-i8:8:32-i1:8:32-a:0:32") :
- std::string("e-p:32:32-f64:32:32-i64:32:32")) :
- // AAPCS ABI
- (isThumb ?
- std::string("e-p:32:32-f64:64:64-i64:64:64-"
- "i16:16:32-i8:8:32-i1:8:32-a:0:32") :
- std::string("e-p:32:32-f64:64:64-i64:64:64"))),
- InstrInfo(Subtarget),
FrameInfo(Subtarget),
JITInfo(),
- TLInfo(*this),
InstrItins(Subtarget.getInstrItineraryData()) {
DefRelocModel = getRelocationModel();
}
+ARMTargetMachine::ARMTargetMachine(const Module &M, const std::string &FS)
+ : ARMBaseTargetMachine(M, FS, false), InstrInfo(Subtarget),
+ DataLayout(Subtarget.isAPCS_ABI() ?
+ std::string("e-p:32:32-f64:32:32-i64:32:32") :
+ std::string("e-p:32:32-f64:64:64-i64:64:64")),
+ TLInfo(*this) {
+}
+
+ThumbTargetMachine::ThumbTargetMachine(const Module &M, const std::string &FS)
+ : ARMBaseTargetMachine(M, FS, true), InstrInfo(Subtarget),
+ DataLayout(Subtarget.isAPCS_ABI() ?
+ std::string("e-p:32:32-f64:32:32-i64:32:32-"
+ "i16:16:32-i8:8:32-i1:8:32-a:0:32") :
+ std::string("e-p:32:32-f64:64:64-i64:64:64-"
+ "i16:16:32-i8:8:32-i1:8:32-a:0:32")),
+ TLInfo(*this) {
+}
+
unsigned ARMTargetMachine::getJITMatchQuality() {
#if defined(__arm__)
return 10;
@@ -131,7 +131,7 @@ unsigned ARMTargetMachine::getModuleMatchQuality(const Module &M) {
}
-const TargetAsmInfo *ARMTargetMachine::createTargetAsmInfo() const {
+const TargetAsmInfo *ARMBaseTargetMachine::createTargetAsmInfo() const {
switch (Subtarget.TargetType) {
case ARMSubtarget::isDarwin:
return new ARMDarwinTargetAsmInfo(*this);
@@ -144,22 +144,22 @@ const TargetAsmInfo *ARMTargetMachine::createTargetAsmInfo() const {
// Pass Pipeline Configuration
-bool ARMTargetMachine::addInstSelector(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel) {
+bool ARMBaseTargetMachine::addInstSelector(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel) {
PM.add(createARMISelDag(*this));
return false;
}
-bool ARMTargetMachine::addPreRegAlloc(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel) {
+bool ARMBaseTargetMachine::addPreRegAlloc(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel) {
// FIXME: temporarily disabling load / store optimization pass for Thumb mode.
if (OptLevel != CodeGenOpt::None && !DisableLdStOpti && !Subtarget.isThumb())
PM.add(createARMLoadStoreOptimizationPass(true));
return true;
}
-bool ARMTargetMachine::addPreEmitPass(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel) {
+bool ARMBaseTargetMachine::addPreEmitPass(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel) {
// FIXME: temporarily disabling load / store optimization pass for Thumb mode.
if (OptLevel != CodeGenOpt::None && !DisableLdStOpti && !Subtarget.isThumb())
PM.add(createARMLoadStoreOptimizationPass());
@@ -172,10 +172,10 @@ bool ARMTargetMachine::addPreEmitPass(PassManagerBase &PM,
return true;
}
-bool ARMTargetMachine::addAssemblyEmitter(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel,
- bool Verbose,
- raw_ostream &Out) {
+bool ARMBaseTargetMachine::addAssemblyEmitter(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel,
+ bool Verbose,
+ raw_ostream &Out) {
// Output assembly language.
assert(AsmPrinterCtor && "AsmPrinter was not linked in");
if (AsmPrinterCtor)
@@ -185,10 +185,10 @@ bool ARMTargetMachine::addAssemblyEmitter(PassManagerBase &PM,
}
-bool ARMTargetMachine::addCodeEmitter(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel,
- bool DumpAsm,
- MachineCodeEmitter &MCE) {
+bool ARMBaseTargetMachine::addCodeEmitter(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel,
+ bool DumpAsm,
+ MachineCodeEmitter &MCE) {
// FIXME: Move this to TargetJITInfo!
if (DefRelocModel == Reloc::Default)
setRelocationModel(Reloc::Static);
@@ -204,10 +204,10 @@ bool ARMTargetMachine::addCodeEmitter(PassManagerBase &PM,
return false;
}
-bool ARMTargetMachine::addCodeEmitter(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel,
- bool DumpAsm,
- JITCodeEmitter &JCE) {
+bool ARMBaseTargetMachine::addCodeEmitter(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel,
+ bool DumpAsm,
+ JITCodeEmitter &JCE) {
// FIXME: Move this to TargetJITInfo!
if (DefRelocModel == Reloc::Default)
setRelocationModel(Reloc::Static);
@@ -223,10 +223,10 @@ bool ARMTargetMachine::addCodeEmitter(PassManagerBase &PM,
return false;
}
-bool ARMTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel,
- bool DumpAsm,
- MachineCodeEmitter &MCE) {
+bool ARMBaseTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel,
+ bool DumpAsm,
+ MachineCodeEmitter &MCE) {
// Machine code emitter pass for ARM.
PM.add(createARMCodeEmitterPass(*this, MCE));
if (DumpAsm) {
@@ -238,10 +238,10 @@ bool ARMTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM,
return false;
}
-bool ARMTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM,
- CodeGenOpt::Level OptLevel,
- bool DumpAsm,
- JITCodeEmitter &JCE) {
+bool ARMBaseTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel,
+ bool DumpAsm,
+ JITCodeEmitter &JCE) {
// Machine code emitter pass for ARM.
PM.add(createARMJITCodeEmitterPass(*this, JCE));
if (DumpAsm) {
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
index c4c8e6c1d9858..0b49b9275b90b 100644
--- a/lib/Target/ARM/ARMTargetMachine.h
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -22,18 +22,19 @@
#include "ARMJITInfo.h"
#include "ARMSubtarget.h"
#include "ARMISelLowering.h"
+#include "ThumbInstrInfo.h"
namespace llvm {
class Module;
-class ARMTargetMachine : public LLVMTargetMachine {
+class ARMBaseTargetMachine : public LLVMTargetMachine {
+protected:
ARMSubtarget Subtarget;
- const TargetData DataLayout; // Calculates type size & alignment
- ARMInstrInfo InstrInfo;
+
+private:
ARMFrameInfo FrameInfo;
ARMJITInfo JITInfo;
- ARMTargetLowering TLInfo;
InstrItineraryData InstrItins;
Reloc::Model DefRelocModel; // Reloc model before it's overridden.
@@ -41,26 +42,18 @@ protected:
// To avoid having target depend on the asmprinter stuff libraries, asmprinter
// set this functions to ctor pointer at startup time if they are linked in.
typedef FunctionPass *(*AsmPrinterCtorFn)(raw_ostream &o,
- ARMTargetMachine &tm,
+ ARMBaseTargetMachine &tm,
CodeGenOpt::Level OptLevel,
bool verbose);
static AsmPrinterCtorFn AsmPrinterCtor;
public:
- ARMTargetMachine(const Module &M, const std::string &FS, bool isThumb = false);
+ ARMBaseTargetMachine(const Module &M, const std::string &FS, bool isThumb);
- virtual const ARMInstrInfo *getInstrInfo() const { return &InstrInfo; }
virtual const ARMFrameInfo *getFrameInfo() const { return &FrameInfo; }
virtual ARMJITInfo *getJITInfo() { return &JITInfo; }
- virtual const ARMRegisterInfo *getRegisterInfo() const {
- return &InstrInfo.getRegisterInfo();
- }
- virtual const TargetData *getTargetData() const { return &DataLayout; }
virtual const ARMSubtarget *getSubtargetImpl() const { return &Subtarget; }
- virtual ARMTargetLowering *getTargetLowering() const {
- return const_cast<ARMTargetLowering*>(&TLInfo);
- }
- virtual const InstrItineraryData getInstrItineraryData() const {
+ virtual const InstrItineraryData getInstrItineraryData() const {
return InstrItins;
}
@@ -94,12 +87,50 @@ public:
JITCodeEmitter &MCE);
};
+/// ARMTargetMachine - ARM target machine.
+///
+class ARMTargetMachine : public ARMBaseTargetMachine {
+ ARMInstrInfo InstrInfo;
+ const TargetData DataLayout; // Calculates type size & alignment
+ ARMTargetLowering TLInfo;
+public:
+ ARMTargetMachine(const Module &M, const std::string &FS);
+
+ virtual const ARMRegisterInfo *getRegisterInfo() const {
+ return &InstrInfo.getRegisterInfo();
+ }
+
+ virtual ARMTargetLowering *getTargetLowering() const {
+ return const_cast<ARMTargetLowering*>(&TLInfo);
+ }
+
+ virtual const ARMInstrInfo *getInstrInfo() const { return &InstrInfo; }
+ virtual const TargetData *getTargetData() const { return &DataLayout; }
+
+ static unsigned getJITMatchQuality();
+ static unsigned getModuleMatchQuality(const Module &M);
+};
+
/// ThumbTargetMachine - Thumb target machine.
///
-class ThumbTargetMachine : public ARMTargetMachine {
+class ThumbTargetMachine : public ARMBaseTargetMachine {
+ ThumbInstrInfo InstrInfo;
+ const TargetData DataLayout; // Calculates type size & alignment
+ ARMTargetLowering TLInfo;
public:
ThumbTargetMachine(const Module &M, const std::string &FS);
+ virtual const ARMRegisterInfo *getRegisterInfo() const {
+ return &InstrInfo.getRegisterInfo();
+ }
+
+ virtual ARMTargetLowering *getTargetLowering() const {
+ return const_cast<ARMTargetLowering*>(&TLInfo);
+ }
+
+ virtual const ThumbInstrInfo *getInstrInfo() const { return &InstrInfo; }
+ virtual const TargetData *getTargetData() const { return &DataLayout; }
+
static unsigned getJITMatchQuality();
static unsigned getModuleMatchQuality(const Module &M);
};
diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
index fe1c9806cbb9f..400f628aa568d 100644
--- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
+++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
@@ -21,6 +21,7 @@
#include "ARMMachineFunctionInfo.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
+#include "llvm/MDNode.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
@@ -96,9 +97,7 @@ namespace {
const char *Modifier = 0);
void printSOImmOperand(const MachineInstr *MI, int opNum);
void printSOImm2PartOperand(const MachineInstr *MI, int opNum);
- void printSOOperand(const MachineInstr *MI, int OpNum);
void printSORegOperand(const MachineInstr *MI, int opNum);
- void printT2SOImmOperand(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);
@@ -110,6 +109,7 @@ namespace {
void printAddrModePCOperand(const MachineInstr *MI, int OpNo,
const char *Modifier = 0);
void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNo);
+
void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNo);
void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNo,
unsigned Scale);
@@ -117,6 +117,10 @@ namespace {
void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNo);
void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNo);
void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNo);
+
+ 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);
@@ -169,11 +173,6 @@ namespace {
O << ")";
}
O << "\n";
-
- // If the constant pool value is a extern weak symbol, remember to emit
- // the weak reference.
- if (GV && GV->hasExternalWeakLinkage())
- ExtWeakSymbols.insert(GV);
}
void getAnalysisUsage(AnalysisUsage &AU) const {
@@ -331,8 +330,6 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
if (isCallOp && Subtarget->isTargetELF() &&
TM.getRelocationModel() == Reloc::PIC_)
O << "(PLT)";
- if (GV->hasExternalWeakLinkage())
- ExtWeakSymbols.insert(GV);
break;
}
case MachineOperand::MO_ExternalSymbol: {
@@ -408,32 +405,10 @@ void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum) {
printSOImm(O, ARM_AM::getSOImmVal(V2), VerboseAsm, TAI);
}
-// Constant shifts so_reg is a 3-operand unit corresponding to register forms of
-// the A5.1 "Addressing Mode 1 - Data-processing operands" forms. This
-// includes:
-// REG 0 - e.g. R5
-// REG IMM, SH_OPC - e.g. R5, LSL #3
-void ARMAsmPrinter::printSOOperand(const MachineInstr *MI, int OpNum) {
- const MachineOperand &MO1 = MI->getOperand(OpNum);
- const MachineOperand &MO2 = MI->getOperand(OpNum+1);
-
- unsigned Reg = MO1.getReg();
- assert(TargetRegisterInfo::isPhysicalRegister(Reg));
- O << TM.getRegisterInfo()->getAsmName(Reg);
-
- // Print the shift opc.
- O << ", "
- << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm()))
- << " ";
-
- assert(MO2.isImm() && "Not a valid t2_so_reg value!");
- O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
-}
-
// so_reg is a 4-operand unit corresponding to register forms of the A5.1
// "Addressing Mode 1 - Data-processing operands" forms. This includes:
-// REG 0 0 - e.g. R5
-// REG REG 0,SH_OPC - e.g. R5, ROR R3
+// REG 0 0 - e.g. R5
+// REG REG 0,SH_OPC - e.g. R5, ROR R3
// REG 0 IMM,SH_OPC - e.g. R5, LSL #3
void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) {
const MachineOperand &MO1 = MI->getOperand(Op);
@@ -457,24 +432,6 @@ void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) {
}
}
-static void printT2SOImm(raw_ostream &O, int64_t V) {
- unsigned Imm = ARM_AM::getT2SOImmValDecode(V);
-
- // Always print the immediate directly, as the "rotate" form
- // is deprecated in some contexts.
- O << "#" << Imm;
-}
-
-/// 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
-/// represented by a normalizedin 7-bit value (msb is always 1)
-void ARMAsmPrinter::printT2SOImmOperand(const MachineInstr *MI, int OpNum) {
- const MachineOperand &MO = MI->getOperand(OpNum);
- assert(MO.isImm() && "Not a valid so_imm value!");
- printT2SOImm(O, MO.getImm());
-}
-
void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) {
const MachineOperand &MO1 = MI->getOperand(Op);
const MachineOperand &MO2 = MI->getOperand(Op+1);
@@ -643,8 +600,8 @@ void
ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op) {
const MachineOperand &MO = MI->getOperand(Op);
uint32_t v = ~MO.getImm();
- int32_t lsb = ffs (v) - 1;
- int32_t width = fls (v) - lsb;
+ int32_t lsb = CountTrailingZeros_32(v);
+ int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb;
assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!");
O << "#" << lsb << ", #" << width;
}
@@ -702,6 +659,42 @@ 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
+/// represented by a normalizedin 7-bit value (msb is always 1)
+void ARMAsmPrinter::printT2SOImmOperand(const MachineInstr *MI, int OpNum) {
+ const MachineOperand &MO = MI->getOperand(OpNum);
+ assert(MO.isImm() && "Not a valid so_imm value!");
+
+ unsigned Imm = ARM_AM::getT2SOImmValDecode(MO.getImm());
+ // Always print the immediate directly, as the "rotate" form
+ // is deprecated in some contexts.
+ O << "#" << Imm;
+}
+
+// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2
+// register with shift forms.
+// REG 0 0 - e.g. R5
+// REG IMM, SH_OPC - e.g. R5, LSL #3
+void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum) {
+ const MachineOperand &MO1 = MI->getOperand(OpNum);
+ const MachineOperand &MO2 = MI->getOperand(OpNum+1);
+
+ unsigned Reg = MO1.getReg();
+ assert(TargetRegisterInfo::isPhysicalRegister(Reg));
+ O << TM.getRegisterInfo()->getAsmName(Reg);
+
+ // Print the shift opc.
+ O << ", "
+ << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm()))
+ << " ";
+
+ assert(MO2.isImm() && "Not a valid t2_so_reg value!");
+ O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
+}
+
+
void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int opNum) {
ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(opNum).getImm();
if (CC != ARMCC::AL)
@@ -749,10 +742,6 @@ void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNo,
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
} else {
EmitGlobalConstant(MCPE.Val.ConstVal);
- // remember to emit the weak reference
- if (const GlobalValue *GV = dyn_cast<GlobalValue>(MCPE.Val.ConstVal))
- if (GV->hasExternalWeakLinkage())
- ExtWeakSymbols.insert(GV);
}
}
}
@@ -934,6 +923,8 @@ void ARMAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
std::string name = Mang->getValueName(GVar);
Constant *C = GVar->getInitializer();
+ if (isa<MDNode>(C) || isa<MDString>(C))
+ return;
const Type *Type = C->getType();
unsigned Size = TD->getTypeAllocSize(Type);
unsigned Align = TD->getPreferredAlignmentLog(GVar);
@@ -1046,12 +1037,6 @@ void ARMAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
if (TAI->hasDotTypeDotSizeDirective())
O << "\t.size " << name << ", " << Size << "\n";
- // If the initializer is a extern weak symbol, remember to emit the weak
- // reference!
- if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
- if (GV->hasExternalWeakLinkage())
- ExtWeakSymbols.insert(GV);
-
EmitGlobalConstant(C);
O << '\n';
}
@@ -1135,18 +1120,12 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
}
- // Emit initial debug information.
- DW->EndModule();
-
// Funny Darwin hack: This flag tells the linker that no global symbols
// contain code that falls through to other global symbols (e.g. the obvious
// implementation of multiple entry points). If this doesn't occur, the
// linker can safely perform dead code stripping. Since LLVM never
// generates code that does this, it is always safe to set.
O << "\t.subsections_via_symbols\n";
- } else {
- // Emit final debug information for ELF.
- DW->EndModule();
}
return AsmPrinter::doFinalization(M);
@@ -1158,7 +1137,7 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
/// regardless of whether the function is in SSA form.
///
FunctionPass *llvm::createARMCodePrinterPass(raw_ostream &o,
- ARMTargetMachine &tm,
+ ARMBaseTargetMachine &tm,
CodeGenOpt::Level OptLevel,
bool verbose) {
return new ARMAsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose);
@@ -1167,13 +1146,10 @@ FunctionPass *llvm::createARMCodePrinterPass(raw_ostream &o,
namespace {
static struct Register {
Register() {
- ARMTargetMachine::registerAsmPrinter(createARMCodePrinterPass);
+ ARMBaseTargetMachine::registerAsmPrinter(createARMCodePrinterPass);
}
} Registrator;
}
-// Force static initialization when called from
-// llvm/InitializeAllAsmPrinters.h
-namespace llvm {
- void InitializeARMAsmPrinter() { }
-}
+// Force static initialization.
+extern "C" void LLVMInitializeARMAsmPrinter() { }
diff --git a/lib/Target/ARM/AsmPrinter/CMakeLists.txt b/lib/Target/ARM/AsmPrinter/CMakeLists.txt
index c22964f6c879b..a67fc8471a631 100644
--- a/lib/Target/ARM/AsmPrinter/CMakeLists.txt
+++ b/lib/Target/ARM/AsmPrinter/CMakeLists.txt
@@ -3,3 +3,4 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/
add_llvm_library(LLVMARMAsmPrinter
ARMAsmPrinter.cpp
)
+add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen) \ No newline at end of file
diff --git a/lib/Target/ARM/CMakeLists.txt b/lib/Target/ARM/CMakeLists.txt
index 2ac40f5354972..e665ed94d09fc 100644
--- a/lib/Target/ARM/CMakeLists.txt
+++ b/lib/Target/ARM/CMakeLists.txt
@@ -24,4 +24,5 @@ add_llvm_target(ARMCodeGen
ARMSubtarget.cpp
ARMTargetAsmInfo.cpp
ARMTargetMachine.cpp
+ ThumbInstrInfo.cpp
)
diff --git a/lib/Target/ARM/README.txt b/lib/Target/ARM/README.txt
index 0252a4aef413f..4223699b9d093 100644
--- a/lib/Target/ARM/README.txt
+++ b/lib/Target/ARM/README.txt
@@ -96,20 +96,7 @@ Which would be better. This occurs in png decode.
//===---------------------------------------------------------------------===//
More load / store optimizations:
-1) Look past instructions without side-effects (not load, store, branch, etc.)
- when forming the list of loads / stores to optimize.
-
-2) Smarter register allocation?
-We are probably missing some opportunities to use ldm / stm. Consider:
-
-ldr r5, [r0]
-ldr r4, [r0, #4]
-
-This cannot be merged into a ldm. Perhaps we will need to do the transformation
-before register allocation. Then teach the register allocator to allocate a
-chunk of consecutive registers.
-
-3) Better representation for block transfer? This is from Olden/power:
+1) Better representation for block transfer? This is from Olden/power:
fldd d0, [r4]
fstd d0, [r4, #+32]
@@ -123,7 +110,7 @@ chunk of consecutive registers.
If we can spare the registers, it would be better to use fldm and fstm here.
Need major register allocator enhancement though.
-4) Can we recognize the relative position of constantpool entries? i.e. Treat
+2) Can we recognize the relative position of constantpool entries? i.e. Treat
ldr r0, LCPI17_3
ldr r1, LCPI17_4
@@ -147,13 +134,7 @@ L6:
.long -858993459
.long 1074318540
-5) Can we make use of ldrd and strd? Instead of generating ldm / stm, use
-ldrd/strd instead if there are only two destination registers that form an
-odd/even pair. However, we probably would pay a penalty if the address is not
-aligned on 8-byte boundary. This requires more information on load / store
-nodes (and MI's?) then we currently carry.
-
-6) struct copies appear to be done field by field
+3) struct copies appear to be done field by field
instead of by words, at least sometimes:
struct foo { int x; short s; char c1; char c2; };
@@ -313,11 +294,6 @@ See McCat/18-imp/ComputeBoundingBoxes for an example.
//===---------------------------------------------------------------------===//
-Register scavenging is now implemented. The example in the previous version
-of this document produces optimal code at -O2.
-
-//===---------------------------------------------------------------------===//
-
Pre-/post- indexed load / stores:
1) We should not make the pre/post- indexed load/store transform if the base ptr
@@ -353,20 +329,6 @@ time.
//===---------------------------------------------------------------------===//
-We should add i64 support to take advantage of the 64-bit load / stores.
-We can add a pseudo i64 register class containing pseudo registers that are
-register pairs. All other ops (e.g. add, sub) would be expanded as usual.
-
-We need to add pseudo instructions (i.e. gethi / getlo) to extract i32 registers
-from the i64 register. These are single moves which can be eliminated if the
-destination register is a sub-register of the source. We should implement proper
-subreg support in the register allocator to coalesce these away.
-
-There are other minor issues such as multiple instructions for a spill / restore
-/ move.
-
-//===---------------------------------------------------------------------===//
-
Implement support for some more tricky ways to materialize immediates. For
example, to get 0xffff8000, we can use:
@@ -465,12 +427,6 @@ More register scavenging work:
1. Use the register scavenger to track frame index materialized into registers
(those that do not fit in addressing modes) to allow reuse in the same BB.
2. Finish scavenging for Thumb.
-3. We know some spills and restores are unnecessary. The issue is once live
- intervals are merged, they are not never split. So every def is spilled
- and every use requires a restore if the register allocator decides the
- resulting live interval is not assigned a physical register. It may be
- possible (with the help of the scavenger) to turn some spill / restore
- pairs into register copies.
//===---------------------------------------------------------------------===//
@@ -572,3 +528,5 @@ 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.
diff --git a/lib/Target/ARM/ThumbInstrInfo.cpp b/lib/Target/ARM/ThumbInstrInfo.cpp
new file mode 100644
index 0000000000000..075d940bcca0a
--- /dev/null
+++ b/lib/Target/ARM/ThumbInstrInfo.cpp
@@ -0,0 +1,282 @@
+//===- ThumbInstrInfo.cpp - Thumb Instruction Information --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Thumb implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMInstrInfo.h"
+#include "ARM.h"
+#include "ARMGenInstrInfo.inc"
+#include "ARMMachineFunctionInfo.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/ADT/SmallVector.h"
+#include "ThumbInstrInfo.h"
+
+using namespace llvm;
+
+ThumbInstrInfo::ThumbInstrInfo(const ARMSubtarget &STI)
+ : ARMBaseInstrInfo(STI) {
+}
+
+bool ThumbInstrInfo::isMoveInstr(const MachineInstr &MI,
+ unsigned &SrcReg, unsigned &DstReg,
+ unsigned& SrcSubIdx, unsigned& DstSubIdx) const {
+ SrcSubIdx = DstSubIdx = 0; // No sub-registers.
+
+ unsigned oc = MI.getOpcode();
+ switch (oc) {
+ default:
+ return false;
+ // FIXME: Thumb2
+ case ARM::tMOVr:
+ case ARM::tMOVhir2lor:
+ case ARM::tMOVlor2hir:
+ case ARM::tMOVhir2hir:
+ assert(MI.getDesc().getNumOperands() >= 2 &&
+ MI.getOperand(0).isReg() &&
+ MI.getOperand(1).isReg() &&
+ "Invalid Thumb MOV instruction");
+ SrcReg = MI.getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ return true;
+ }
+}
+
+unsigned ThumbInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ switch (MI->getOpcode()) {
+ default: break;
+ // FIXME: Thumb2
+ case ARM::tRestore:
+ if (MI->getOperand(1).isFI() &&
+ MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 0) {
+ FrameIndex = MI->getOperand(1).getIndex();
+ return MI->getOperand(0).getReg();
+ }
+ break;
+ }
+ return 0;
+}
+
+unsigned ThumbInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ switch (MI->getOpcode()) {
+ default: break;
+ // FIXME: Thumb2
+ case ARM::tSpill:
+ if (MI->getOperand(1).isFI() &&
+ MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 0) {
+ FrameIndex = MI->getOperand(1).getIndex();
+ return MI->getOperand(0).getReg();
+ }
+ break;
+ }
+ return 0;
+}
+
+bool ThumbInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg, unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ // FIXME: Thumb2
+ if (DestRC == ARM::GPRRegisterClass) {
+ if (SrcRC == ARM::GPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tMOVhir2hir), DestReg).addReg(SrcReg);
+ return true;
+ } else if (SrcRC == ARM::tGPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tMOVlor2hir), DestReg).addReg(SrcReg);
+ return true;
+ }
+ } else if (DestRC == ARM::tGPRRegisterClass) {
+ if (SrcRC == ARM::GPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tMOVhir2lor), DestReg).addReg(SrcReg);
+ return true;
+ } else if (SrcRC == ARM::tGPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg).addReg(SrcReg);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ThumbInstrInfo::
+storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned SrcReg, bool isKill, int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ assert(RC == ARM::tGPRRegisterClass && "Unknown regclass!");
+
+ // FIXME: Thumb2
+ if (RC == ARM::tGPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tSpill))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI).addImm(0);
+ }
+}
+
+void ThumbInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
+ bool isKill,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const{
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ unsigned Opc = 0;
+
+ // FIXME: Thumb2. Is GPRRegClass here correct?
+ assert(RC == ARM::GPRRegisterClass && "Unknown regclass!");
+ if (RC == ARM::GPRRegisterClass) {
+ Opc = Addr[0].isFI() ? ARM::tSpill : ARM::tSTR;
+ }
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill));
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB.addOperand(Addr[i]);
+ NewMIs.push_back(MIB);
+ return;
+}
+
+void ThumbInstrInfo::
+loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned DestReg, int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ // FIXME: Thumb2
+ assert(RC == ARM::tGPRRegisterClass && "Unknown regclass!");
+
+ if (RC == ARM::tGPRRegisterClass) {
+ BuildMI(MBB, I, DL, get(ARM::tRestore), DestReg)
+ .addFrameIndex(FI).addImm(0);
+ }
+}
+
+void ThumbInstrInfo::
+loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ unsigned Opc = 0;
+
+ // FIXME: Thumb2. Is GPRRegClass ok here?
+ if (RC == ARM::GPRRegisterClass) {
+ Opc = Addr[0].isFI() ? ARM::tRestore : ARM::tLDR;
+ }
+
+ MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB.addOperand(Addr[i]);
+ NewMIs.push_back(MIB);
+ return;
+}
+
+bool ThumbInstrInfo::
+spillCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const {
+ if (CSI.empty())
+ return false;
+
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (MI != MBB.end()) DL = MI->getDebugLoc();
+
+ MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, get(ARM::tPUSH));
+ for (unsigned i = CSI.size(); i != 0; --i) {
+ unsigned Reg = CSI[i-1].getReg();
+ // Add the callee-saved register as live-in. It's killed at the spill.
+ MBB.addLiveIn(Reg);
+ MIB.addReg(Reg, RegState::Kill);
+ }
+ return true;
+}
+
+bool ThumbInstrInfo::
+restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (CSI.empty())
+ return false;
+
+ bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
+ MachineInstr *PopMI = MF.CreateMachineInstr(get(ARM::tPOP),MI->getDebugLoc());
+ for (unsigned i = CSI.size(); i != 0; --i) {
+ unsigned Reg = CSI[i-1].getReg();
+ if (Reg == ARM::LR) {
+ // Special epilogue for vararg functions. See emitEpilogue
+ if (isVarArg)
+ continue;
+ Reg = ARM::PC;
+ PopMI->setDesc(get(ARM::tPOP_RET));
+ MI = MBB.erase(MI);
+ }
+ PopMI->addOperand(MachineOperand::CreateReg(Reg, true));
+ }
+
+ // It's illegal to emit pop instruction without operands.
+ if (PopMI->getNumOperands() > 0)
+ MBB.insert(MI, PopMI);
+
+ return true;
+}
+
+MachineInstr *ThumbInstrInfo::
+foldMemoryOperandImpl(MachineFunction &MF, MachineInstr *MI,
+ const SmallVectorImpl<unsigned> &Ops, int FI) const {
+ if (Ops.size() != 1) return NULL;
+ const ARMRegisterInfo &RI = getRegisterInfo();
+
+ unsigned OpNum = Ops[0];
+ unsigned Opc = MI->getOpcode();
+ MachineInstr *NewMI = NULL;
+ switch (Opc) {
+ default: break;
+ case ARM::tMOVr:
+ case ARM::tMOVlor2hir:
+ case ARM::tMOVhir2lor:
+ case ARM::tMOVhir2hir: {
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ bool isKill = MI->getOperand(1).isKill();
+ if (RI.isPhysicalRegister(SrcReg) && !RI.isLowRegister(SrcReg))
+ // tSpill cannot take a high register operand.
+ break;
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tSpill))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI).addImm(0);
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ if (RI.isPhysicalRegister(DstReg) && !RI.isLowRegister(DstReg))
+ // tRestore cannot target a high register operand.
+ break;
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tRestore))
+ .addReg(DstReg, RegState::Define | getDeadRegState(isDead))
+ .addFrameIndex(FI).addImm(0);
+ }
+ break;
+ }
+ }
+
+ return NewMI;
+}
diff --git a/lib/Target/ARM/ThumbInstrInfo.h b/lib/Target/ARM/ThumbInstrInfo.h
new file mode 100644
index 0000000000000..dcf1095750828
--- /dev/null
+++ b/lib/Target/ARM/ThumbInstrInfo.h
@@ -0,0 +1,85 @@
+//===- ThumbInstrInfo.h - Thumb Instruction Information ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the ARM implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef THUMBINSTRUCTIONINFO_H
+#define THUMBINSTRUCTIONINFO_H
+
+#include "llvm/Target/TargetInstrInfo.h"
+#include "ARMRegisterInfo.h"
+#include "ARM.h"
+#include "ARMInstrInfo.h"
+
+namespace llvm {
+ class ARMSubtarget;
+
+class ThumbInstrInfo : public ARMBaseInstrInfo {
+public:
+ explicit ThumbInstrInfo(const ARMSubtarget &STI);
+
+ /// Return true if the instruction is a register to register move and return
+ /// the source and dest operands and their sub-register indices by reference.
+ virtual bool isMoveInstr(const MachineInstr &MI,
+ unsigned &SrcReg, unsigned &DstReg,
+ unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
+
+ virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+ virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+
+ virtual bool copyRegToReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg, unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const;
+ virtual void storeRegToStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned SrcReg, bool isKill, int FrameIndex,
+ const TargetRegisterClass *RC) const;
+
+ virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const;
+
+ virtual void loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned DestReg, int FrameIndex,
+ const TargetRegisterClass *RC) const;
+
+ virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const;
+ virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const;
+ virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const;
+
+ virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF,
+ MachineInstr* MI,
+ const SmallVectorImpl<unsigned> &Ops,
+ MachineInstr* LoadMI) const {
+ return 0;
+ }
+
+ virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF,
+ MachineInstr* MI,
+ const SmallVectorImpl<unsigned> &Ops,
+ int FrameIndex) const;
+};
+}
+
+#endif // THUMBINSTRUCTIONINFO_H