[llvm-commits] CVS: llvm/lib/Target/ARM/ARMConstantIslandPass.cpp ARMMachineFunctionInfo.h ARMRegisterInfo.cpp

Evan Cheng evan.cheng at apple.com
Mon Jan 29 17:18:54 PST 2007



Changes in directory llvm/lib/Target/ARM:

ARMConstantIslandPass.cpp updated: 1.12 -> 1.13
ARMMachineFunctionInfo.h updated: 1.4 -> 1.5
ARMRegisterInfo.cpp updated: 1.43 -> 1.44
---
Log message:

- 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


---
Diffs of the changes:  (+123 -41)

 ARMConstantIslandPass.cpp |  130 +++++++++++++++++++++++++++++++++++-----------
 ARMMachineFunctionInfo.h  |   14 ++--
 ARMRegisterInfo.cpp       |   20 ++++++-
 3 files changed, 123 insertions(+), 41 deletions(-)


Index: llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
diff -u llvm/lib/Target/ARM/ARMConstantIslandPass.cpp:1.12 llvm/lib/Target/ARM/ARMConstantIslandPass.cpp:1.13
--- llvm/lib/Target/ARM/ARMConstantIslandPass.cpp:1.12	Mon Jan 29 17:45:17 2007
+++ llvm/lib/Target/ARM/ARMConstantIslandPass.cpp	Mon Jan 29 19:18:38 2007
@@ -29,7 +29,9 @@
 #include <iostream>
 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 @@
     ///
     std::vector<ImmBranch> ImmBranches;
 
+    /// PushPopMIs - Keep track of all the Thumb push / pop instructions.
+    ///
+    std::vector<MachineInstr*> 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 @@
     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 @@
   MachineConstantPool &MCP = *Fn.getConstantPool();
   
   TII = Fn.getTarget().getInstrInfo();
-  
+  AFI = Fn.getInfo<ARMFunctionInfo>();
+
+  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 @@
   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 @@
         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 @@
 /// account for this change.
 void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
   MachineBasicBlock *OrigBB = MI->getParent();
-  const ARMFunctionInfo *AFI = OrigBB->getParent()->getInfo<ARMFunctionInfo>();
   bool isThumb = AFI->isThumbFunction();
 
   // Create a new MBB for the code after the OrigBB.
@@ -524,32 +552,53 @@
   return false;
 }
 
+/// 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)
+    return FixUpUnconditionalBr(Fn, Br);
+  return FixUpConditionalBr(Fn, Br);
+}
+
+/// 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;
 }
 
-/// 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.
+/// 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::FixUpImmediateBranch(MachineFunction &Fn, ImmBranch &Br) {
+ARMConstantIslands::FixUpConditionalBr(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;
-  }
-
-  // Otherwise, add a unconditional branch to the destination and 
-  // invert the branch condition to jump over it:
+  // Add a unconditional branch to the destination and invert the branch
+  // condition to jump over it:
   // blt L1
   // =>
   // bge L2
@@ -565,6 +614,7 @@
   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 @@
   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;
+}


Index: llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
diff -u llvm/lib/Target/ARM/ARMMachineFunctionInfo.h:1.4 llvm/lib/Target/ARM/ARMMachineFunctionInfo.h:1.5
--- llvm/lib/Target/ARM/ARMMachineFunctionInfo.h:1.4	Mon Jan 29 16:22:24 2007
+++ llvm/lib/Target/ARM/ARMMachineFunctionInfo.h	Mon Jan 29 19:18:38 2007
@@ -36,9 +36,9 @@
   /// 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 @@
 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<ARMSubtarget>().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 @@
   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; }


Index: llvm/lib/Target/ARM/ARMRegisterInfo.cpp
diff -u llvm/lib/Target/ARM/ARMRegisterInfo.cpp:1.43 llvm/lib/Target/ARM/ARMRegisterInfo.cpp:1.44
--- llvm/lib/Target/ARM/ARMRegisterInfo.cpp:1.43	Mon Jan 29 16:22:24 2007
+++ llvm/lib/Target/ARM/ARMRegisterInfo.cpp	Mon Jan 29 19:18:38 2007
@@ -770,17 +770,29 @@
   }
 
   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+  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 @@
     }
   }
 
-  // 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






More information about the llvm-commits mailing list