summaryrefslogtreecommitdiff
path: root/lib/Target
diff options
context:
space:
mode:
authorDavid Goodwin <david_goodwin@apple.com>2009-06-30 18:04:13 +0000
committerDavid Goodwin <david_goodwin@apple.com>2009-06-30 18:04:13 +0000
commit5e47a9a6e46bd271eba058fb831da1a1edf8707c (patch)
tree73f05805997bc9b61372e9d25dbfba51e828e4d5 /lib/Target
parent72bf4473a6ca3809dd1f97a15b00f70b56358213 (diff)
downloadllvm-5e47a9a6e46bd271eba058fb831da1a1edf8707c.tar.gz
llvm-5e47a9a6e46bd271eba058fb831da1a1edf8707c.tar.bz2
llvm-5e47a9a6e46bd271eba058fb831da1a1edf8707c.tar.xz
Add conditional and unconditional thumb-2 branch. Add thumb-2 jump table.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74543 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r--lib/Target/ARM/ARMConstantIslandPass.cpp36
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp7
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td6
-rw-r--r--lib/Target/ARM/ARMInstrInfo.cpp47
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td17
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td22
-rw-r--r--lib/Target/ARM/ARMMachineFunctionInfo.h10
7 files changed, 112 insertions, 33 deletions
diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp
index d37e9f2cf0..50badfffec 100644
--- a/lib/Target/ARM/ARMConstantIslandPass.cpp
+++ b/lib/Target/ARM/ARMConstantIslandPass.cpp
@@ -124,6 +124,7 @@ namespace {
const TargetInstrInfo *TII;
ARMFunctionInfo *AFI;
bool isThumb;
+ bool isThumb2;
public:
static char ID;
ARMConstantIslands() : MachineFunctionPass(&ID) {}
@@ -213,6 +214,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &Fn) {
TII = Fn.getTarget().getInstrInfo();
AFI = Fn.getInfo<ARMFunctionInfo>();
isThumb = AFI->isThumbFunction();
+ isThumb2 = AFI->isThumb2Function();
HasFarJump = false;
@@ -376,6 +378,7 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn,
int UOpc = Opc;
switch (Opc) {
case ARM::tBR_JTr:
+ case ARM::t2BR_JTr:
// A Thumb table jump may involve padding; for the offsets to
// be right, functions containing these must be 4-byte aligned.
AFI->setAlign(2U);
@@ -402,6 +405,16 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn,
Bits = 11;
Scale = 2;
break;
+ case ARM::t2Bcc:
+ isCond = true;
+ UOpc = ARM::t2B;
+ Bits = 20;
+ Scale = 2;
+ break;
+ case ARM::t2B:
+ Bits = 24;
+ Scale = 2;
+ break;
}
// Record this immediate branch.
@@ -575,7 +588,7 @@ MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
// There doesn't seem to be meaningful DebugInfo available; this doesn't
// correspond to anything in the source.
BuildMI(OrigBB, DebugLoc::getUnknownLoc(),
- TII->get(isThumb ? ARM::tB : ARM::B)).addMBB(NewBB);
+ TII->get(isThumb ? ((isThumb2) ? ARM::t2B : ARM::tB) : ARM::B)).addMBB(NewBB);
NumSplit++;
// Update the CFG. All succs of OrigBB are now succs of NewBB.
@@ -719,7 +732,8 @@ static bool BBIsJumpedOver(MachineBasicBlock *MBB) {
MachineBasicBlock *Succ = *MBB->succ_begin();
MachineBasicBlock *Pred = *MBB->pred_begin();
MachineInstr *PredMI = &Pred->back();
- if (PredMI->getOpcode() == ARM::B || PredMI->getOpcode() == ARM::tB)
+ if (PredMI->getOpcode() == ARM::B || PredMI->getOpcode() == ARM::tB
+ || PredMI->getOpcode() == ARM::t2B)
return PredMI->getOperand(0).getMBB() == Succ;
return false;
}
@@ -751,7 +765,8 @@ void ARMConstantIslands::AdjustBBOffsetsAfter(MachineBasicBlock *BB,
// Thumb jump tables require padding. They should be at the end;
// following unconditional branches are removed by AnalyzeBranch.
MachineInstr *ThumbJTMI = NULL;
- if (prior(MBB->end())->getOpcode() == ARM::tBR_JTr)
+ if ((prior(MBB->end())->getOpcode() == ARM::tBR_JTr)
+ || (prior(MBB->end())->getOpcode() == ARM::t2BR_JTr))
ThumbJTMI = prior(MBB->end());
if (ThumbJTMI) {
unsigned newMIOffset = GetOffsetOf(ThumbJTMI);
@@ -842,7 +857,16 @@ int ARMConstantIslands::LookForExistingCPEntry(CPUser& U, unsigned UserOffset)
/// getUnconditionalBrDisp - Returns the maximum displacement that can fit in
/// the specific unconditional branch instruction.
static inline unsigned getUnconditionalBrDisp(int Opc) {
- return (Opc == ARM::tB) ? ((1<<10)-1)*2 : ((1<<23)-1)*4;
+ switch (Opc) {
+ case ARM::tB:
+ return ((1<<10)-1)*2;
+ case ARM::t2B:
+ return ((1<<23)-1)*2;
+ default:
+ break;
+ }
+
+ return ((1<<23)-1)*4;
}
/// AcceptWater - Small amount of common code factored out of the following.
@@ -938,7 +962,7 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex,
// range, but if the preceding conditional branch is out of range, the
// targets will be exchanged, and the altered branch may be out of
// range, so the machinery has to know about it.
- int UncondBr = isThumb ? ARM::tB : ARM::B;
+ int UncondBr = isThumb ? ((isThumb2) ? ARM::t2B : ARM::tB) : ARM::B;
BuildMI(UserMBB, DebugLoc::getUnknownLoc(),
TII->get(UncondBr)).addMBB(*NewMBB);
unsigned MaxDisp = getUnconditionalBrDisp(UncondBr);
@@ -1168,7 +1192,7 @@ bool
ARMConstantIslands::FixUpUnconditionalBr(MachineFunction &Fn, ImmBranch &Br) {
MachineInstr *MI = Br.MI;
MachineBasicBlock *MBB = MI->getParent();
- assert(isThumb && "Expected a Thumb function!");
+ assert(isThumb && !isThumb2 && "Expected a Thumb-1 function!");
// Use BL to implement far jump.
Br.MaxDisp = (1 << 21) * 2;
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 7035064c7f..527659a623 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -858,7 +858,12 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
// Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc)
// Pattern complexity = 6 cost = 1 size = 0
- unsigned Opc = Subtarget->isThumb() ? ARM::tBcc : ARM::Bcc;
+ // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
+ // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc)
+ // Pattern complexity = 6 cost = 1 size = 0
+
+ unsigned Opc = Subtarget->isThumb() ?
+ ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
SDValue Chain = Op.getOperand(0);
SDValue N1 = Op.getOperand(1);
SDValue N2 = Op.getOperand(2);
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index f49e38fb2c..a9c66a5506 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -801,6 +801,10 @@ class T1I4<dag outs, dag ins, string asm, list<dag> pattern>
: Thumb1I<outs, ins, AddrModeT1_4, Size2Bytes, asm, "", pattern>;
class T1Is<dag outs, dag ins, string asm, list<dag> pattern>
: Thumb1I<outs, ins, AddrModeT1_s, Size2Bytes, asm, "", pattern>;
+class T1Ix2<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeNone, Size4Bytes, asm, "", pattern>;
+class T1JTI<dag outs, dag ins, string asm, list<dag> pattern>
+ : Thumb1I<outs, ins, AddrModeNone, SizeSpecial, asm, "", pattern>;
// Two-address instructions
class T1It<dag outs, dag ins, string asm, list<dag> pattern>
@@ -865,6 +869,8 @@ class T2sI<dag oops, dag iops, string opc, string asm, list<dag> pattern>
class T2XI<dag oops, dag iops, string asm, list<dag> pattern>
: Thumb2XI<oops, iops, AddrModeNone, Size4Bytes, asm, "", pattern>;
+class T2JTI<dag oops, dag iops, string asm, list<dag> pattern>
+ : Thumb2XI<oops, iops, AddrModeNone, SizeSpecial, asm, "", pattern>;
// T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
class T2Pat<dag pattern, dag result> : Pat<pattern, result> {
diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp
index 5d77e99136..5941b1eddb 100644
--- a/lib/Target/ARM/ARMInstrInfo.cpp
+++ b/lib/Target/ARM/ARMInstrInfo.cpp
@@ -350,11 +350,11 @@ bool
// If there is only one terminator instruction, process it.
unsigned LastOpc = LastInst->getOpcode();
if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) {
- if (LastOpc == ARM::B || LastOpc == ARM::tB) {
+ if (LastOpc == ARM::B || LastOpc == ARM::tB || LastOpc == ARM::t2B) {
TBB = LastInst->getOperand(0).getMBB();
return false;
}
- if (LastOpc == ARM::Bcc || LastOpc == ARM::tBcc) {
+ if (LastOpc == ARM::Bcc || LastOpc == ARM::tBcc || LastOpc == ARM::t2Bcc) {
// Block ends with fall-through condbranch.
TBB = LastInst->getOperand(0).getMBB();
Cond.push_back(LastInst->getOperand(1));
@@ -371,10 +371,12 @@ bool
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.
+ // If the block ends with ARM::B/ARM::tB/ARM::t2B and a
+ // ARM::Bcc/ARM::tBcc/ARM::t2Bcc, handle it.
unsigned SecondLastOpc = SecondLastInst->getOpcode();
if ((SecondLastOpc == ARM::Bcc && LastOpc == ARM::B) ||
- (SecondLastOpc == ARM::tBcc && LastOpc == ARM::tB)) {
+ (SecondLastOpc == ARM::tBcc && LastOpc == ARM::tB) ||
+ (SecondLastOpc == ARM::t2Bcc && LastOpc == ARM::t2B)) {
TBB = SecondLastInst->getOperand(0).getMBB();
Cond.push_back(SecondLastInst->getOperand(1));
Cond.push_back(SecondLastInst->getOperand(2));
@@ -384,8 +386,9 @@ bool
// 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)) {
+ if ((SecondLastOpc == ARM::B || SecondLastOpc==ARM::tB ||
+ SecondLastOpc==ARM::t2B) &&
+ (LastOpc == ARM::B || LastOpc == ARM::tB || LastOpc == ARM::t2B)) {
TBB = SecondLastInst->getOperand(0).getMBB();
I = LastInst;
if (AllowModify)
@@ -397,8 +400,9 @@ bool
// branch. The branch folder can create these, and we must get rid of them for
// correctness of Thumb constant islands.
if ((SecondLastOpc == ARM::BR_JTr || SecondLastOpc==ARM::BR_JTm ||
- SecondLastOpc == ARM::BR_JTadd || SecondLastOpc==ARM::tBR_JTr) &&
- (LastOpc == ARM::B || LastOpc == ARM::tB)) {
+ SecondLastOpc == ARM::BR_JTadd || SecondLastOpc==ARM::tBR_JTr ||
+ SecondLastOpc==ARM::t2BR_JTr) &&
+ (LastOpc == ARM::B || LastOpc == ARM::tB || LastOpc == ARM::t2B)) {
I = LastInst;
if (AllowModify)
I->eraseFromParent();
@@ -413,8 +417,10 @@ bool
unsigned ARMBaseInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- int BOpc = AFI->isThumbFunction() ? ARM::tB : ARM::B;
- int BccOpc = AFI->isThumbFunction() ? ARM::tBcc : ARM::Bcc;
+ int BOpc = AFI->isThumbFunction() ?
+ (AFI->isThumb2Function() ? ARM::t2B : ARM::tB) : ARM::B;
+ int BccOpc = AFI->isThumbFunction() ?
+ (AFI->isThumb2Function() ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
MachineBasicBlock::iterator I = MBB.end();
if (I == MBB.begin()) return 0;
@@ -445,8 +451,10 @@ ARMBaseInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
DebugLoc dl = DebugLoc::getUnknownLoc();
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- int BOpc = AFI->isThumbFunction() ? ARM::tB : ARM::B;
- int BccOpc = AFI->isThumbFunction() ? ARM::tBcc : ARM::Bcc;
+ int BOpc = AFI->isThumbFunction() ?
+ (AFI->isThumb2Function() ? ARM::t2B : ARM::tB) : ARM::B;
+ int BccOpc = AFI->isThumbFunction() ?
+ (AFI->isThumb2Function() ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
// Shouldn't be a fall through.
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
@@ -695,8 +703,10 @@ ARMBaseInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
case ARM::tBX_RET_vararg:
case ARM::tPOP_RET:
case ARM::B:
- case ARM::tB: // Uncond branch.
+ case ARM::tB:
+ case ARM::t2B: // Uncond branch.
case ARM::tBR_JTr:
+ case ARM::t2BR_JTr:
case ARM::BR_JTr: // Jumptable branch.
case ARM::BR_JTm: // Jumptable branch through mem.
case ARM::BR_JTadd: // Jumptable branch add to pc.
@@ -721,8 +731,9 @@ bool ARMBaseInstrInfo::
PredicateInstruction(MachineInstr *MI,
const SmallVectorImpl<MachineOperand> &Pred) const {
unsigned Opc = MI->getOpcode();
- if (Opc == ARM::B || Opc == ARM::tB) {
- MI->setDesc(get(Opc == ARM::B ? ARM::Bcc : ARM::tBcc));
+ if (Opc == ARM::B || Opc == ARM::tB || Opc == ARM::t2B) {
+ MI->setDesc(get((Opc == ARM::B) ? ARM::Bcc :
+ ((Opc == ARM::tB) ? ARM::tBcc : ARM::t2Bcc)));
MI->addOperand(MachineOperand::CreateImm(Pred[0].getImm()));
MI->addOperand(MachineOperand::CreateReg(Pred[1].getReg(), false));
return true;
@@ -835,7 +846,8 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
case ARM::BR_JTr:
case ARM::BR_JTm:
case ARM::BR_JTadd:
- case ARM::tBR_JTr: {
+ case ARM::tBR_JTr:
+ case ARM::t2BR_JTr: {
// These are jumptable branches, i.e. a branch followed by an inlined
// jumptable. The size is 4 + 4 * number of entries.
unsigned NumOps = TID.getNumOperands();
@@ -853,7 +865,8 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
// bytes, we can use 16-bit entries instead. Then there won't be an
// alignment issue.
return getNumJTEntries(JT, JTI) * 4 +
- (MI->getOpcode()==ARM::tBR_JTr ? 2 : 4);
+ ((MI->getOpcode()==ARM::tBR_JTr ||
+ MI->getOpcode()==ARM::t2BR_JTr) ? 2 : 4);
}
default:
// Otherwise, pseudo-instruction sizes are zero.
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index c8e7538484..904d9b1d52 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -187,23 +187,24 @@ let isCall = 1,
let isBranch = 1, isTerminator = 1 in {
let isBarrier = 1 in {
let isPredicable = 1 in
- def tB : TI<(outs), (ins brtarget:$target), "b $target",
- [(br bb:$target)]>;
+ def tB : T1I<(outs), (ins brtarget:$target), "b $target",
+ [(br bb:$target)]>;
// Far jump
- def tBfar : TIx2<(outs), (ins brtarget:$target), "bl $target\t@ far jump",[]>;
+ def tBfar : T1Ix2<(outs), (ins brtarget:$target),
+ "bl $target\t@ far jump",[]>;
- def tBR_JTr : TJTI<(outs),
- (ins tGPR:$target, jtblock_operand:$jt, i32imm:$id),
- "cpy pc, $target \n\t.align\t2\n$jt",
- [(ARMbrjt tGPR:$target, tjumptable:$jt, imm:$id)]>;
+ def tBR_JTr : T1JTI<(outs),
+ (ins tGPR:$target, jtblock_operand:$jt, i32imm:$id),
+ "cpy pc, $target \n\t.align\t2\n$jt",
+ [(ARMbrjt tGPR:$target, tjumptable:$jt, imm:$id)]>;
}
}
// FIXME: should be able to write a pattern for ARMBrcond, but can't use
// a two-value operand where a dag node expects two operands. :(
let isBranch = 1, isTerminator = 1 in
- def tBcc : TI<(outs), (ins brtarget:$target, pred:$cc), "b$cc $target",
+ def tBcc : T1I<(outs), (ins brtarget:$target, pred:$cc), "b$cc $target",
[/*(ARMbrcond bb:$target, imm:$cc)*/]>;
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index f848550a45..b6d54f0023 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -688,6 +688,28 @@ defm t2TEQ : T2I_cmp_is<"teq",
// FIXME: Conditional moves
+//===----------------------------------------------------------------------===//
+// Control-Flow Instructions
+//
+
+let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
+let isPredicable = 1 in
+def t2B : T2XI<(outs), (ins brtarget:$target),
+ "b $target",
+ [(br bb:$target)]>;
+
+def t2BR_JTr : T2JTI<(outs),
+ (ins tGPR:$target, jtblock_operand:$jt, i32imm:$id),
+ "cpy pc, $target \n\t.align\t2\n$jt",
+ [(ARMbrjt tGPR:$target, tjumptable:$jt, imm:$id)]>;
+}
+
+// FIXME: should be able to write a pattern for ARMBrcond, but can't use
+// a two-value operand where a dag node expects two operands. :(
+let isBranch = 1, isTerminator = 1 in
+def t2Bcc : T2I<(outs), (ins brtarget:$target),
+ "b", " $target",
+ [/*(ARMbrcond bb:$target, imm:$cc)*/]>;
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
diff --git a/lib/Target/ARM/ARMMachineFunctionInfo.h b/lib/Target/ARM/ARMMachineFunctionInfo.h
index 0b0e289282..66d3df60e0 100644
--- a/lib/Target/ARM/ARMMachineFunctionInfo.h
+++ b/lib/Target/ARM/ARMMachineFunctionInfo.h
@@ -30,6 +30,11 @@ class ARMFunctionInfo : public MachineFunctionInfo {
/// Used to initialized Align, so must precede it.
bool isThumb;
+ /// hasThumb2 - True if the target architecture supports Thumb2. Do not use
+ /// to determine if function is compiled under Thumb mode, for that use
+ /// 'isThumb'.
+ bool hasThumb2;
+
/// Align - required alignment. ARM functions and Thumb functions with
/// constant pools require 4-byte alignment; other Thumb functions
/// require only 2-byte alignment.
@@ -91,7 +96,8 @@ class ARMFunctionInfo : public MachineFunctionInfo {
public:
ARMFunctionInfo() :
- isThumb(false),
+ isThumb(false),
+ hasThumb2(false),
Align(2U),
VarArgsRegSaveSize(0), HasStackFrame(false),
LRSpilledForFarJump(false), R3IsLiveIn(false),
@@ -102,6 +108,7 @@ public:
explicit ARMFunctionInfo(MachineFunction &MF) :
isThumb(MF.getTarget().getSubtarget<ARMSubtarget>().isThumb()),
+ hasThumb2(MF.getTarget().getSubtarget<ARMSubtarget>().hasThumb2()),
Align(isThumb ? 1U : 2U),
VarArgsRegSaveSize(0), HasStackFrame(false),
LRSpilledForFarJump(false), R3IsLiveIn(false),
@@ -112,6 +119,7 @@ public:
JumpTableUId(0), ConstPoolEntryUId(0) {}
bool isThumbFunction() const { return isThumb; }
+ bool isThumb2Function() const { return isThumb && hasThumb2; }
unsigned getAlign() const { return Align; }
void setAlign(unsigned a) { Align = a; }