mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-03 13:31:05 +00:00
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
This commit is contained in:
parent
72bf4473a6
commit
5e47a9a6e4
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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> {
|
||||
|
@ -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.
|
||||
|
@ -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)*/]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user