From 5e47a9a6e46bd271eba058fb831da1a1edf8707c Mon Sep 17 00:00:00 2001 From: David Goodwin Date: Tue, 30 Jun 2009 18:04:13 +0000 Subject: [PATCH] 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 --- lib/Target/ARM/ARMConstantIslandPass.cpp | 36 +++++++++++++++--- lib/Target/ARM/ARMISelDAGToDAG.cpp | 7 +++- lib/Target/ARM/ARMInstrFormats.td | 6 +++ lib/Target/ARM/ARMInstrInfo.cpp | 47 +++++++++++++++--------- lib/Target/ARM/ARMInstrThumb.td | 17 +++++---- lib/Target/ARM/ARMInstrThumb2.td | 22 +++++++++++ lib/Target/ARM/ARMMachineFunctionInfo.h | 10 ++++- 7 files changed, 112 insertions(+), 33 deletions(-) diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index d37e9f2cf04..50badfffecd 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(); 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 7035064c7fe..527659a6234 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 f49e38fb2ce..a9c66a5506d 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -801,6 +801,10 @@ class T1I4 pattern> : Thumb1I; class T1Is pattern> : Thumb1I; +class T1Ix2 pattern> + : Thumb1I; +class T1JTI pattern> + : Thumb1I; // Two-address instructions class T1It pattern> @@ -865,6 +869,8 @@ class T2sI pattern> class T2XI pattern> : Thumb2XI; +class T2JTI pattern> + : Thumb2XI; // T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode. class T2Pat : Pat { diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index 5d77e991368..5941b1eddb3 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(); - 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(); - 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 &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 c8e75384849..904d9b1d527 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 f848550a45b..b6d54f00230 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 0b0e2892828..66d3df60e07 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().isThumb()), + hasThumb2(MF.getTarget().getSubtarget().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; } -- 2.34.1