From d1b2c1e88fe4a7728ca9739b0f1c6fd90a19c5fd Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Tue, 30 Jan 2007 01:18:38 +0000 Subject: [PATCH] - In thumb mode, if size of MachineFunction is >= 2048, force LR to be spilled (if it is not already). - If LR is spilled, use BL to implement far jumps. LR is not used as a GPR in thumb mode so it can be clobbered if it is properly spilled / restored in prologue / epilogue. - If LR is force spilled but no far jump has been emitted, try undo'ing the spill by: push lr -> delete pop pc -> bx lr git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33650 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMConstantIslandPass.cpp | 132 +++++++++++++++++------ lib/Target/ARM/ARMMachineFunctionInfo.h | 14 +-- lib/Target/ARM/ARMRegisterInfo.cpp | 20 +++- 3 files changed, 124 insertions(+), 42 deletions(-) diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index 927d16f864e..f3264e72872 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -29,7 +29,9 @@ #include using namespace llvm; -STATISTIC(NumSplit, "Number of uncond branches inserted"); +STATISTIC(NumSplit, "Number of uncond branches inserted"); +STATISTIC(NumCBrFixed, "Number of cond branches fixed"); +STATISTIC(NumUBrFixed, "Number of uncond branches fixed"); namespace { /// ARMConstantIslands - Due to limited pc-relative displacements, ARM @@ -88,7 +90,16 @@ namespace { /// std::vector ImmBranches; + /// PushPopMIs - Keep track of all the Thumb push / pop instructions. + /// + std::vector PushPopMIs; + + /// HasFarJump - True if any far jump instruction has been emitted during + /// the branch fix up pass. + bool HasFarJump; + const TargetInstrInfo *TII; + const ARMFunctionInfo *AFI; public: virtual bool runOnMachineFunction(MachineFunction &Fn); @@ -105,7 +116,10 @@ namespace { void UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB); bool HandleConstantPoolUser(MachineFunction &Fn, CPUser &U); bool BBIsInBranchRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned D); - bool FixUpImmediateBranch(MachineFunction &Fn, ImmBranch &Br); + bool FixUpImmediateBr(MachineFunction &Fn, ImmBranch &Br); + bool FixUpConditionalBr(MachineFunction &Fn, ImmBranch &Br); + bool FixUpUnconditionalBr(MachineFunction &Fn, ImmBranch &Br); + bool UndoLRSpillRestore(); unsigned GetOffsetOf(MachineInstr *MI) const; unsigned GetOffsetOf(MachineBasicBlock *MBB) const; @@ -122,7 +136,10 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &Fn) { MachineConstantPool &MCP = *Fn.getConstantPool(); TII = Fn.getTarget().getInstrInfo(); - + AFI = Fn.getInfo(); + + HasFarJump = false; + // Renumber all of the machine basic blocks in the function, guaranteeing that // the numbers agree with the position of the block in the function. Fn.RenumberBlocks(); @@ -142,22 +159,31 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &Fn) { InitialFunctionScan(Fn, CPEMIs); CPEMIs.clear(); - // Iteratively place constant pool entries until there is no change. - bool MadeChange; - do { - MadeChange = false; + // Iteratively place constant pool entries and fix up branches until there + // is no change. + bool MadeChange = false; + while (true) { + bool Change = false; for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) - MadeChange |= HandleConstantPoolUser(Fn, CPUsers[i]); + Change |= HandleConstantPoolUser(Fn, CPUsers[i]); for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) - MadeChange |= FixUpImmediateBranch(Fn, ImmBranches[i]); - } while (MadeChange); + Change |= FixUpImmediateBr(Fn, ImmBranches[i]); + if (!Change) + break; + MadeChange = true; + } + // If LR has been forced spilled and no far jumps (i.e. BL) has been issued. + // Undo the spill / restore of LR if possible. + if (!HasFarJump && AFI->isLRForceSpilled() && AFI->isThumbFunction()) + MadeChange |= UndoLRSpillRestore(); + BBSizes.clear(); WaterList.clear(); CPUsers.clear(); ImmBranches.clear(); - - return true; + + return MadeChange; } /// DoInitialPlacement - Perform the initial placement of the constant pool @@ -258,6 +284,9 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn, ImmBranches.push_back(ImmBranch(I, MaxDisp, isCond, UOpc)); } + if (Opc == ARM::tPUSH || Opc == ARM::tPOP_RET) + PushPopMIs.push_back(I); + // Scan the instructions for constant pool operands. for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) if (I->getOperand(op).isConstantPoolIndex()) { @@ -380,7 +409,6 @@ void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) { /// account for this change. void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { MachineBasicBlock *OrigBB = MI->getParent(); - const ARMFunctionInfo *AFI = OrigBB->getParent()->getInfo(); bool isThumb = AFI->isThumbFunction(); // Create a new MBB for the code after the OrigBB. @@ -524,32 +552,53 @@ bool ARMConstantIslands::BBIsInBranchRange(MachineInstr *MI, return false; } -static inline unsigned getUncondBranchDisp(int Opc) { - return (Opc == ARM::tB) ? (1<<10)*2 : (1<<23)*4; -} - -/// FixUpImmediateBranch - Fix up immediate branches whose destination is too -/// far away to fit in its displacement field. If it is a conditional branch, -/// then it is converted to an inverse conditional branch + an unconditional -/// branch to the destination. If it is an unconditional branch, then it is -/// converted to a branch to a branch. -bool -ARMConstantIslands::FixUpImmediateBranch(MachineFunction &Fn, ImmBranch &Br) { +/// FixUpImmediateBr - Fix up an immediate branch whose destination is too far +/// away to fit in its displacement field. +bool ARMConstantIslands::FixUpImmediateBr(MachineFunction &Fn, ImmBranch &Br) { MachineInstr *MI = Br.MI; MachineBasicBlock *DestBB = MI->getOperand(0).getMachineBasicBlock(); if (BBIsInBranchRange(MI, DestBB, Br.MaxDisp)) return false; - if (!Br.isCond) { - // Unconditional branch. We have to insert a branch somewhere to perform - // a two level branch (branch to branch). FIXME: not yet implemented. - assert(false && "Can't handle unconditional branch yet!"); - return false; - } + if (!Br.isCond) + return FixUpUnconditionalBr(Fn, Br); + return FixUpConditionalBr(Fn, Br); +} - // Otherwise, add a unconditional branch to the destination and - // invert the branch condition to jump over it: +/// FixUpUnconditionalBr - Fix up an unconditional branches whose destination is +/// too far away to fit in its displacement field. If LR register has been +/// spilled in the epilogue, then we can use BL to implement a far jump. +/// Otherwise, add a intermediate branch instruction to to a branch. +bool +ARMConstantIslands::FixUpUnconditionalBr(MachineFunction &Fn, ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *MBB = MI->getParent(); + assert(AFI->isThumbFunction() && "Expected a Thumb function!"); + + // Use BL to implement far jump. + Br.MaxDisp = (1 << 21) * 2; + MI->setInstrDescriptor(TII->get(ARM::tBfar)); + BBSizes[MBB->getNumber()] += 2; + HasFarJump = true; + NumUBrFixed++; + return true; +} + +static inline unsigned getUncondBranchDisp(int Opc) { + return (Opc == ARM::tB) ? (1<<10)*2 : (1<<23)*4; +} + +/// FixUpConditionalBr - Fix up a conditional branches whose destination is too +/// far away to fit in its displacement field. It is converted to an inverse +/// conditional branch + an unconditional branch to the destination. +bool +ARMConstantIslands::FixUpConditionalBr(MachineFunction &Fn, ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *DestBB = MI->getOperand(0).getMachineBasicBlock(); + + // Add a unconditional branch to the destination and invert the branch + // condition to jump over it: // blt L1 // => // bge L2 @@ -565,6 +614,7 @@ ARMConstantIslands::FixUpImmediateBranch(MachineFunction &Fn, ImmBranch &Br) { MachineInstr *BackMI = &MBB->back(); bool NeedSplit = (BackMI != MI) || !BBHasFallthrough(MBB); + NumCBrFixed++; if (BackMI != MI) { if (next(MachineBasicBlock::iterator(MI)) == MBB->back() && BackMI->getOpcode() == Br.UncondBr) { @@ -606,3 +656,21 @@ ARMConstantIslands::FixUpImmediateBranch(MachineFunction &Fn, ImmBranch &Br) { BBSizes[MBB->getNumber()] += ARM::GetInstSize(&MBB->back()); return true; } + + +/// UndoLRSpillRestore - Remove Thumb push / pop instructions that only spills +/// LR / restores LR to pc. +bool ARMConstantIslands::UndoLRSpillRestore() { + bool MadeChange = false; + for (unsigned i = 0, e = PushPopMIs.size(); i != e; ++i) { + MachineInstr *MI = PushPopMIs[i]; + if (MI->getNumOperands() == 1) { + if (MI->getOpcode() == ARM::tPOP_RET && + MI->getOperand(0).getReg() == ARM::PC) + BuildMI(MI->getParent(), TII->get(ARM::tBX_RET)); + MI->eraseFromParent(); + MadeChange = true; + } + } + return MadeChange; +} diff --git a/lib/Target/ARM/ARMMachineFunctionInfo.h b/lib/Target/ARM/ARMMachineFunctionInfo.h index 6ce4d532ff0..6b3ac21d527 100644 --- a/lib/Target/ARM/ARMMachineFunctionInfo.h +++ b/lib/Target/ARM/ARMMachineFunctionInfo.h @@ -36,9 +36,9 @@ class ARMFunctionInfo : public MachineFunctionInfo { /// processFunctionBeforeCalleeSavedScan(). bool HasStackFrame; - /// LRSpilled - True if the LR register has been spilled. - /// - bool LRSpilled; + /// LRSForceSpilled - True if the LR register has been for spilled to enable + /// far jump. + bool LRForceSpilled; /// FramePtrSpillOffset - If HasStackFrame, this records the frame pointer /// spill stack offset. @@ -75,13 +75,13 @@ class ARMFunctionInfo : public MachineFunctionInfo { public: ARMFunctionInfo() : isThumb(false), - VarArgsRegSaveSize(0), HasStackFrame(false), LRSpilled(false), + VarArgsRegSaveSize(0), HasStackFrame(false), LRForceSpilled(false), FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0), GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0), JumpTableUId(0) {} ARMFunctionInfo(MachineFunction &MF) : isThumb(MF.getTarget().getSubtarget().isThumb()), - VarArgsRegSaveSize(0), HasStackFrame(false), LRSpilled(false), + VarArgsRegSaveSize(0), HasStackFrame(false), LRForceSpilled(false), FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0), GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0), JumpTableUId(0) {} @@ -93,8 +93,8 @@ public: bool hasStackFrame() const { return HasStackFrame; } void setHasStackFrame(bool s) { HasStackFrame = s; } - bool isLRSpilled() const { return LRSpilled; } - void setLRIsSpilled(bool s) { LRSpilled = s; } + bool isLRForceSpilled() const { return LRForceSpilled; } + void setLRIsForceSpilled(bool s) { LRForceSpilled = s; } unsigned getFramePtrSpillOffset() const { return FramePtrSpillOffset; } void setFramePtrSpillOffset(unsigned o) { FramePtrSpillOffset = o; } diff --git a/lib/Target/ARM/ARMRegisterInfo.cpp b/lib/Target/ARM/ARMRegisterInfo.cpp index 2accaf890e6..07869e4cf8a 100644 --- a/lib/Target/ARM/ARMRegisterInfo.cpp +++ b/lib/Target/ARM/ARMRegisterInfo.cpp @@ -770,17 +770,29 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF) const { } ARMFunctionInfo *AFI = MF.getInfo(); + bool ForceLRSpill = false; + if (!LRSpilled && AFI->isThumbFunction()) { + unsigned FnSize = ARM::GetFunctionSize(MF); + // Force LR spill if the Thumb function size is > 2048. This enables the + // use of BL to implement far jump. If it turns out that it's not needed + // the branch fix up path will undo it. + if (FnSize >= (1 << 11)) { + CanEliminateFrame = false; + ForceLRSpill = true; + } + } + if (!CanEliminateFrame) { AFI->setHasStackFrame(true); // If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled. // Spill LR as well so we can fold BX_RET to the registers restore (LDM). if (!LRSpilled && CS1Spilled) { - LRSpilled = true; MF.changePhyRegUsed(ARM::LR, true); NumGPRSpills++; UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(), (unsigned)ARM::LR)); + ForceLRSpill = false; } if (STI.isTargetDarwin()) { @@ -800,8 +812,10 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF) const { } } - // Remembe if LR has been spilled. - AFI->setLRIsSpilled(LRSpilled); + if (ForceLRSpill) { + MF.changePhyRegUsed(ARM::LR, true); + AFI->setLRIsForceSpilled(true); + } } /// Move iterator pass the next bunch of callee save load / store ops for