Add conditional and unconditional thumb-2 branch. Add thumb-2 jump table.

llvm-svn: 74543
This commit is contained in:
David Goodwin 2009-06-30 18:04:13 +00:00
parent a8560219c7
commit 27303cde82
7 changed files with 112 additions and 33 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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> {

View File

@ -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.

View File

@ -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)*/]>;
//===----------------------------------------------------------------------===//

View File

@ -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

View File

@ -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; }