Implement RAGreedy::splitAroundRegion and remove loop splitting.
authorJakob Stoklund Olesen <stoklund@2pi.dk>
Wed, 19 Jan 2011 22:11:48 +0000 (22:11 +0000)
committerJakob Stoklund Olesen <stoklund@2pi.dk>
Wed, 19 Jan 2011 22:11:48 +0000 (22:11 +0000)
Region splitting includes loop splitting as a subset, and it is more generic.
The splitting heuristics for variables that are live in more than one block are
now:

1. Try to create a region that covers multiple basic blocks.
2. Try to create a new live range for each block with multiple uses.
3. Spill.

Steps 2 and 3 are similar to what the standard spiller is doing.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123853 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/LiveInterval.cpp
lib/CodeGen/RegAllocGreedy.cpp
lib/CodeGen/SplitKit.cpp

index c6a014951636ce0884110c2ef11c5f26a5c0bf2e..c2dbd6ab75a1aba7b638d01e198c7ee0214d2222 100644 (file)
@@ -650,7 +650,9 @@ void LiveRange::dump() const {
 }
 
 void LiveInterval::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const {
-  OS << PrintReg(reg, TRI) << ',' << weight;
+  OS << PrintReg(reg, TRI);
+  if (weight != 0)
+    OS << ',' << weight;
 
   if (empty())
     OS << " EMPTY";
index dc45df5bb24a9d75db5089d25d421e2c7eb8702a..fa3b5871fcefe4a87fc291868a21b1f7da40581a 100644 (file)
@@ -83,7 +83,7 @@ class RAGreedy : public MachineFunctionPass, public RegAllocBase {
   ///  6. |-----------| Live-through without uses. Transparent.
   ///
   struct BlockInfo {
-    const MachineBasicBlock *MBB;
+    MachineBasicBlock *MBB;
     SlotIndex FirstUse;   ///< First instr using current reg.
     SlotIndex LastUse;    ///< Last instr using current reg.
     SlotIndex Kill;       ///< Interval end point inside block.
@@ -119,8 +119,8 @@ public:
 
   virtual float getPriority(LiveInterval *LI);
 
-  virtual unsigned selectOrSplit(LiveInterval &VirtReg,
-                                 SmallVectorImpl<LiveInterval*> &SplitVRegs);
+  virtual unsigned selectOrSplit(LiveInterval&,
+                                 SmallVectorImpl<LiveInterval*>&);
 
   /// Perform register allocation.
   virtual bool runOnMachineFunction(MachineFunction &mf);
@@ -132,12 +132,12 @@ private:
   LiveInterval *getSingleInterference(LiveInterval&, unsigned);
   bool reassignVReg(LiveInterval &InterferingVReg, unsigned OldPhysReg);
   bool reassignInterferences(LiveInterval &VirtReg, unsigned PhysReg);
-  unsigned findInterferenceFreeReg(MachineLoopRange*,
-                                   LiveInterval&, AllocationOrder&);
   float calcInterferenceWeight(LiveInterval&, unsigned);
   void calcLiveBlockInfo(LiveInterval&);
   float calcInterferenceInfo(LiveInterval&, unsigned);
   float calcGlobalSplitCost(const BitVector&);
+  void splitAroundRegion(LiveInterval&, unsigned, const BitVector&,
+                         SmallVectorImpl<LiveInterval*>&);
 
   unsigned tryReassign(LiveInterval&, AllocationOrder&);
   unsigned tryRegionSplit(LiveInterval&, AllocationOrder&,
@@ -323,90 +323,6 @@ unsigned RAGreedy::tryReassign(LiveInterval &VirtReg, AllocationOrder &Order) {
 }
 
 
-//===----------------------------------------------------------------------===//
-//                              Loop Splitting
-//===----------------------------------------------------------------------===//
-
-/// findInterferenceFreeReg - Find a physical register in Order where Loop has
-/// no interferences with VirtReg.
-unsigned RAGreedy::findInterferenceFreeReg(MachineLoopRange *Loop,
-                                           LiveInterval &VirtReg,
-                                           AllocationOrder &Order) {
-  Order.rewind();
-  while (unsigned PhysReg = Order.next()) {
-    bool interference = false;
-    for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) {
-      if (query(VirtReg, *AI).checkLoopInterference(Loop)) {
-        interference = true;
-        break;
-      }
-    }
-    if (!interference)
-      return PhysReg;
-  }
-  // No physreg found.
-  return 0;
-}
-
-/// trySplit - Try to split VirtReg or one of its interferences, making it
-/// assignable.
-/// @return Physreg when VirtReg may be assigned and/or new SplitVRegs.
-unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order,
-                            SmallVectorImpl<LiveInterval*>&SplitVRegs) {
-  // Don't attempt splitting on local intervals for now.
-  if (LIS->intervalIsInOneMBB(VirtReg))
-    return 0;
-
-  NamedRegionTimer T("Splitter", TimerGroupName, TimePassesIsEnabled);
-  SA->analyze(&VirtReg);
-
-  // Get the set of loops that have VirtReg uses and are splittable.
-  SplitAnalysis::LoopPtrSet SplitLoopSet;
-  SA->getSplitLoops(SplitLoopSet);
-
-  // Order loops by descending area.
-  SmallVector<MachineLoopRange*, 8> SplitLoops;
-  for (SplitAnalysis::LoopPtrSet::const_iterator I = SplitLoopSet.begin(),
-         E = SplitLoopSet.end(); I != E; ++I)
-    SplitLoops.push_back(LoopRanges->getLoopRange(*I));
-  array_pod_sort(SplitLoops.begin(), SplitLoops.end(),
-                 MachineLoopRange::byAreaDesc);
-
-  // Find the first loop that is interference-free for some register in the
-  // allocation order.
-  MachineLoopRange *Loop = 0;
-  for (unsigned i = 0, e = SplitLoops.size(); i != e; ++i) {
-    DEBUG(dbgs() << "  Checking " << *SplitLoops[i]);
-    if (unsigned PhysReg = findInterferenceFreeReg(SplitLoops[i],
-                                                   VirtReg, Order)) {
-      (void)PhysReg;
-      Loop = SplitLoops[i];
-      DEBUG(dbgs() << ": Use %" << TRI->getName(PhysReg) << '\n');
-      break;
-    } else {
-      DEBUG(dbgs() << ": Interference.\n");
-    }
-  }
-
-  if (!Loop) {
-    DEBUG(dbgs() << "  All candidate loops have interference.\n");
-    return 0;
-  }
-
-  // Execute the split around Loop.
-  SmallVector<LiveInterval*, 4> SpillRegs;
-  LiveRangeEdit LREdit(VirtReg, SplitVRegs, SpillRegs);
-  SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit)
-    .splitAroundLoop(Loop->getLoop());
-
-  if (VerifyEnabled)
-    MF->verify(this, "After splitting live range around loop");
-
-  // We have new split regs, don't assign anything.
-  return 0;
-}
-
-
 //===----------------------------------------------------------------------===//
 //                              Region Splitting
 //===----------------------------------------------------------------------===//
@@ -427,7 +343,7 @@ void RAGreedy::calcLiveBlockInfo(LiveInterval &VirtReg) {
   UseE = SA->UseSlots.end();
 
   // Loop over basic blocks where VirtReg is live.
-  MachineFunction::const_iterator MFI = Indexes->getMBBFromIndex(LVI->start);
+  MachineFunction::iterator MFI = Indexes->getMBBFromIndex(LVI->start);
   for (;;) {
     // Block constraints depend on the interference pattern.
     // Just allocate them here, don't compute anything.
@@ -665,6 +581,236 @@ float RAGreedy::calcGlobalSplitCost(const BitVector &LiveBundles) {
   return GlobalCost;
 }
 
+/// splitAroundRegion - Split VirtReg around the region determined by
+/// LiveBundles. Make an effort to avoid interference from PhysReg.
+///
+/// The 'register' interval is going to contain as many uses as possible while
+/// avoiding interference. The 'stack' interval is the complement constructed by
+/// SplitEditor. It will contain the rest.
+///
+void RAGreedy::splitAroundRegion(LiveInterval &VirtReg, unsigned PhysReg,
+                                 const BitVector &LiveBundles,
+                                 SmallVectorImpl<LiveInterval*> &NewVRegs) {
+  DEBUG({
+    dbgs() << "Splitting around region for " << PrintReg(PhysReg, TRI)
+           << " with bundles";
+    for (int i = LiveBundles.find_first(); i>=0; i = LiveBundles.find_next(i))
+      dbgs() << " EB#" << i;
+    dbgs() << ".\n";
+  });
+
+  // First compute interference ranges in the live blocks.
+  typedef std::pair<SlotIndex, SlotIndex> IndexPair;
+  SmallVector<IndexPair, 8> InterferenceRanges;
+  InterferenceRanges.resize(LiveBlocks.size());
+  for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) {
+    if (!query(VirtReg, *AI).checkInterference())
+      continue;
+    LiveIntervalUnion::SegmentIter IntI =
+      PhysReg2LiveUnion[*AI].find(VirtReg.beginIndex());
+    if (!IntI.valid())
+      continue;
+    for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) {
+      BlockInfo &BI = LiveBlocks[i];
+      if (!BI.Uses)
+        continue;
+      IndexPair &IP = InterferenceRanges[i];
+      SlotIndex Start, Stop;
+      tie(Start, Stop) = Indexes->getMBBRange(BI.MBB);
+      // Skip interference-free blocks.
+      if (IntI.start() >= Stop)
+        continue;
+
+      // First interference in block.
+      if (BI.LiveIn) {
+        IntI.advanceTo(Start);
+        if (!IntI.valid())
+          break;
+        if (!IP.first.isValid() || IntI.start() < IP.first)
+          IP.first = IntI.start();
+      }
+
+      // Last interference in block.
+      if (BI.LiveOut) {
+        IntI.advanceTo(Stop);
+        if (!IntI.valid() || IntI.start() >= Stop)
+          --IntI;
+        if (!IP.second.isValid() || IntI.stop() > IP.second)
+          IP.second = IntI.stop();
+      }
+    }
+  }
+
+  SmallVector<LiveInterval*, 4> SpillRegs;
+  LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs);
+  SplitEditor SE(*SA, *LIS, *VRM, *DomTree, LREdit);
+
+  // Create the main cross-block interval.
+  SE.openIntv();
+
+  // First add all defs that are live out of a block.
+  for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) {
+    BlockInfo &BI = LiveBlocks[i];
+    bool RegIn  = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)];
+    bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)];
+
+    // Should the register be live out?
+    if (!BI.LiveOut || !RegOut)
+      continue;
+
+    IndexPair &IP = InterferenceRanges[i];
+    SlotIndex Start, Stop;
+    tie(Start, Stop) = Indexes->getMBBRange(BI.MBB);
+
+    DEBUG(dbgs() << "BB#" << BI.MBB->getNumber() << " -> EB#"
+                 << Bundles->getBundle(BI.MBB->getNumber(), 1));
+
+    // Check interference leaving the block.
+    if (!IP.second.isValid() || IP.second < Start) {
+      // Block is interference-free.
+      DEBUG(dbgs() << ", no interference");
+      if (!BI.Uses) {
+        assert(BI.LiveThrough && "No uses, but not live through block?");
+        // Block is live-through without interference.
+        DEBUG(dbgs() << ", no uses"
+                     << (RegIn ? ", live-through.\n" : ", stack in.\n"));
+        if (!RegIn)
+          SE.enterIntvAtEnd(*BI.MBB);
+        continue;
+      }
+      if (!BI.LiveThrough) {
+        DEBUG(dbgs() << ", not live-through.\n");
+        SE.enterIntvBefore(BI.Def);
+        SE.useIntv(BI.Def, Stop);
+        continue;
+      }
+      if (!RegIn) {
+        // Block is live-through, but entry bundle is on the stack.
+        // Reload just before the first use.
+        DEBUG(dbgs() << ", not live-in, enter before first use.\n");
+        SE.enterIntvBefore(BI.FirstUse);
+        SE.useIntv(BI.FirstUse, Stop);
+        continue;
+      }
+      DEBUG(dbgs() << ", live-through.\n");
+      continue;
+    }
+
+    // Block has interference.
+    DEBUG(dbgs() << ", interference to " << IP.second);
+    if (!BI.Uses) {
+      // No uses in block, avoid interference by reloading as late as possible.
+      DEBUG(dbgs() << ", no uses.\n");
+      SE.enterIntvAtEnd(*BI.MBB);
+      continue;
+    }
+    if (IP.second < BI.LastUse) {
+      // There are interference-free uses at the end of the block.
+      // Find the first use that can get the live-out register.
+      SlotIndex Use = *std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(),
+                                        IP.second);
+      DEBUG(dbgs() << ", free use at " << Use << ".\n");
+      assert(Use > IP.second && Use <= BI.LastUse);
+      SE.enterIntvBefore(Use);
+      SE.useIntv(Use, Stop);
+      continue;
+    }
+
+    // Interference is after the last use.
+    DEBUG(dbgs() << " after last use.\n");
+    SE.enterIntvAtEnd(*BI.MBB);
+  }
+
+  // Now all defs leading to live bundles are handled, do everything else.
+  for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) {
+    BlockInfo &BI = LiveBlocks[i];
+    bool RegIn  = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)];
+    bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)];
+
+    // Is the register live-in?
+    if (!BI.LiveIn || !RegIn)
+      continue;
+
+    // We have an incoming register. Check for interference.
+    IndexPair &IP = InterferenceRanges[i];
+    SlotIndex Start, Stop;
+    tie(Start, Stop) = Indexes->getMBBRange(BI.MBB);
+
+    DEBUG(dbgs() << "EB#" << Bundles->getBundle(BI.MBB->getNumber(), 0)
+                 << " -> BB#" << BI.MBB->getNumber());
+
+    // Check interference entering the block.
+    if (!IP.first.isValid() || IP.first > Stop) {
+      // Block is interference-free.
+      DEBUG(dbgs() << ", no interference");
+      if (!BI.Uses) {
+        assert(BI.LiveThrough && "No uses, but not live through block?");
+        // Block is live-through without interference.
+        if (RegOut) {
+          DEBUG(dbgs() << ", no uses, live-through.\n");
+          SE.useIntv(Start, Stop);
+        } else {
+          DEBUG(dbgs() << ", no uses, stack-out.\n");
+          SE.leaveIntvAtTop(*BI.MBB);
+        }
+        continue;
+      }
+      if (!BI.LiveThrough) {
+        DEBUG(dbgs() << ", killed in block.\n");
+        SE.useIntv(Start, BI.Kill);
+        SE.leaveIntvAfter(BI.Kill);
+        continue;
+      }
+      if (!RegOut) {
+        // Block is live-through, but exit bundle is on the stack.
+        // Spill immediately after the last use.
+        DEBUG(dbgs() << ", uses, stack-out.\n");
+        SE.useIntv(Start, BI.LastUse);
+        SE.leaveIntvAfter(BI.LastUse);
+        continue;
+      }
+      // Register is live-through.
+      DEBUG(dbgs() << ", uses, live-through.\n");
+      SE.useIntv(Start, Stop);
+      continue;
+    }
+
+    // Block has interference.
+    DEBUG(dbgs() << ", interference from " << IP.first);
+    if (!BI.Uses) {
+      // No uses in block, avoid interference by spilling as soon as possible.
+      DEBUG(dbgs() << ", no uses.\n");
+      SE.leaveIntvAtTop(*BI.MBB);
+      continue;
+    }
+    if (IP.first > BI.FirstUse) {
+      // There are interference-free uses at the beginning of the block.
+      // Find the last use that can get the register.
+      SlotIndex Use = std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(),
+                                       IP.second)[-1];
+      DEBUG(dbgs() << ", free use at " << Use << ".\n");
+      assert(Use >= BI.FirstUse && Use < IP.first);
+      SE.useIntv(Start, Use);
+      SE.leaveIntvAfter(Use);
+      continue;
+    }
+
+    // Interference is before the first use.
+    DEBUG(dbgs() << " before first use.\n");
+    SE.leaveIntvAtTop(*BI.MBB);
+  }
+
+  SE.closeIntv();
+
+  // FIXME: Should we be more aggressive about splitting the stack region into
+  // per-block segments? The current approach allows the stack region to
+  // separate into connected components. Some components may be allocatable.
+  SE.finish();
+
+  if (VerifyEnabled)
+    MF->verify(this, "After splitting live range around region");
+}
+
 unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order,
                                   SmallVectorImpl<LiveInterval*> &NewVRegs) {
   calcLiveBlockInfo(VirtReg);
@@ -676,18 +822,62 @@ unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order,
     float Cost = calcInterferenceInfo(VirtReg, PhysReg);
     if (BestReg && Cost >= BestCost)
       continue;
-    if (!SpillPlacer->placeSpills(SpillConstraints, LiveBundles))
-      Cost += calcGlobalSplitCost(LiveBundles);
+
+    SpillPlacer->placeSpills(SpillConstraints, LiveBundles);
+    // No live bundles, defer to splitSingleBlocks().
+    if (!LiveBundles.any())
+      continue;
+
+    Cost += calcGlobalSplitCost(LiveBundles);
     if (!BestReg || Cost < BestCost) {
       BestReg = PhysReg;
       BestCost = Cost;
       BestBundles.swap(LiveBundles);
     }
   }
-  // FIXME: Actually execute the split.
+
+  if (!BestReg)
+    return 0;
+
+  splitAroundRegion(VirtReg, BestReg, BestBundles, NewVRegs);
   return 0;
 }
 
+
+//===----------------------------------------------------------------------===//
+//                          Live Range Splitting
+//===----------------------------------------------------------------------===//
+
+/// trySplit - Try to split VirtReg or one of its interferences, making it
+/// assignable.
+/// @return Physreg when VirtReg may be assigned and/or new NewVRegs.
+unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order,
+                            SmallVectorImpl<LiveInterval*>&NewVRegs) {
+  NamedRegionTimer T("Splitter", TimerGroupName, TimePassesIsEnabled);
+  SA->analyze(&VirtReg);
+
+  // Don't attempt splitting on local intervals for now. TBD.
+  if (LIS->intervalIsInOneMBB(VirtReg))
+    return 0;
+
+  // First try to split around a region spanning multiple blocks.
+  unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs);
+  if (PhysReg || !NewVRegs.empty())
+    return PhysReg;
+
+  // Then isolate blocks with multiple uses.
+  SplitAnalysis::BlockPtrSet Blocks;
+  if (SA->getMultiUseBlocks(Blocks)) {
+    SmallVector<LiveInterval*, 4> SpillRegs;
+    LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs);
+    SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit).splitSingleBlocks(Blocks);
+  }
+
+  // Don't assign any physregs.
+  return 0;
+}
+
+
 //===----------------------------------------------------------------------===//
 //                                Spilling
 //===----------------------------------------------------------------------===//
@@ -756,7 +946,7 @@ unsigned RAGreedy::trySpillInterferences(LiveInterval &VirtReg,
 //===----------------------------------------------------------------------===//
 
 unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
-                                 SmallVectorImpl<LiveInterval*> &SplitVRegs) {
+                                 SmallVectorImpl<LiveInterval*> &NewVRegs) {
   // First try assigning a free register.
   AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs);
   while (unsigned PhysReg = Order.next()) {
@@ -768,20 +958,22 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
   if (unsigned PhysReg = tryReassign(VirtReg, Order))
     return PhysReg;
 
+  assert(NewVRegs.empty() && "Cannot append to existing NewVRegs");
+
   // Try splitting VirtReg or interferences.
-  unsigned PhysReg = trySplit(VirtReg, Order, SplitVRegs);
-  if (PhysReg || !SplitVRegs.empty())
+  unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs);
+  if (PhysReg || !NewVRegs.empty())
     return PhysReg;
 
   // Try to spill another interfering reg with less spill weight.
-  PhysReg = trySpillInterferences(VirtReg, Order, SplitVRegs);
+  PhysReg = trySpillInterferences(VirtReg, Order, NewVRegs);
   if (PhysReg)
     return PhysReg;
 
   // Finally spill VirtReg itself.
   NamedRegionTimer T("Spiller", TimerGroupName, TimePassesIsEnabled);
   SmallVector<LiveInterval*, 1> pendingSpills;
-  spiller().spill(&VirtReg, SplitVRegs, pendingSpills);
+  spiller().spill(&VirtReg, NewVRegs, pendingSpills);
 
   // The live virtual register requesting allocation was spilled, so tell
   // the caller not to allocate anything during this round.
index 7ed9089ecd0267aff4f2bf4673cfae125c48fc28..a13134403a574ccbd6bdbd6669ff6368c74ece73 100644 (file)
@@ -867,9 +867,7 @@ void SplitEditor::leaveIntvAtTop(MachineBasicBlock &MBB) {
 /// LiveInterval, and ranges can be trimmed.
 void SplitEditor::closeIntv() {
   assert(openli_.getLI() && "openIntv not called before closeIntv");
-
-  DEBUG(dbgs() << "    closeIntv cleaning up\n");
-  DEBUG(dbgs() << "    open " << *openli_.getLI() << '\n');
+  DEBUG(dbgs() << "    closeIntv " << *openli_.getLI() << '\n');
   openli_.reset(0);
 }
 
@@ -966,6 +964,8 @@ void SplitEditor::computeRemainder() {
   // FIXME: If a single value is redefined, just move the def and truncate.
   LiveInterval &parent = edit_.getParent();
 
+  DEBUG(dbgs() << "computeRemainder from " << parent << '\n');
+
   // Values that are fully contained in the split intervals.
   SmallPtrSet<const VNInfo*, 8> deadValues;
   // Map all curli values that should have live defs in dupli.