[llvm-commits] [llvm] r132358 - /llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp

Jakob Stoklund Olesen stoklund at 2pi.dk
Tue May 31 14:02:44 PDT 2011


Author: stoklund
Date: Tue May 31 16:02:44 2011
New Revision: 132358

URL: http://llvm.org/viewvc/llvm-project?rev=132358&view=rev
Log:
Simplify the eviction policy by making the failsafe explicit.

When assigned ranges are evicted, they are put in the RS_Evicted stage and are
not allowed to evict anything else. That prevents looping automatically.

When evicting ranges just to get a cheaper register, use only spill weights to
find the possible candidates. Avoid breaking hints for this purpose, it is not
worth it.

Start implementing more complex eviction heuristics, guarded by the temporary
-complex-eviction flag. The initial version permits a heavier range to be
evicted if it doesn't have any uses where the evicting range is live. This makes
it a good candidate for live ranfge splitting.

Modified:
    llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp

Modified: llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp?rev=132358&r1=132357&r2=132358&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp (original)
+++ llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp Tue May 31 16:02:44 2011
@@ -39,6 +39,7 @@
 #include "llvm/CodeGen/RegAllocRegistry.h"
 #include "llvm/CodeGen/RegisterCoalescer.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -52,6 +53,10 @@
 STATISTIC(NumLocalSplits,  "Number of split local live ranges");
 STATISTIC(NumEvicted,      "Number of interferences evicted");
 
+static cl::opt<bool>
+ComplexEviction("complex-eviction", cl::Hidden,
+                cl::desc("Use complex eviction heuristics"));
+
 static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator",
                                        createGreedyRegisterAllocator);
 
@@ -94,7 +99,8 @@
   enum LiveRangeStage {
     RS_New,      ///< Never seen before.
     RS_First,    ///< First time in the queue.
-    RS_Second,   ///< Second time in the queue.
+    RS_Evicted,  ///< Requeued after being evicted.
+    RS_Second,   ///< Second time in the queue, ready for splitting.
     RS_Global,   ///< Produced by global splitting.
     RS_Local,    ///< Produced by local splitting.
     RS_Spill     ///< Produced by spilling.
@@ -118,15 +124,6 @@
     }
   }
 
-  // Eviction. Sometimes an assigned live range can be evicted without
-  // conditions, but other times it must be split after being evicted to avoid
-  // infinite loops.
-  enum CanEvict {
-    CE_Never,    ///< Can never evict.
-    CE_Always,   ///< Can always evict.
-    CE_WithSplit ///< Can evict only if range is also split or spilled.
-  };
-
   // splitting state.
   std::auto_ptr<SplitAnalysis> SA;
   std::auto_ptr<SplitEditor> SE;
@@ -198,8 +195,10 @@
   SlotIndex getPrevMappedIndex(const MachineInstr*);
   void calcPrevSlots();
   unsigned nextSplitPoint(unsigned);
-  CanEvict canEvict(LiveInterval &A, LiveInterval &B);
-  bool canEvictInterference(LiveInterval&, unsigned, float&);
+  bool hasDefInRange(const LiveInterval&, const LiveInterval&);
+  bool hasUseInRange(const LiveInterval&, const LiveInterval&);
+  bool canEvict(LiveInterval &A, LiveInterval &B);
+  bool canEvictInterference(LiveInterval&, unsigned, float&, bool);
 
   unsigned tryAssign(LiveInterval&, AllocationOrder&,
                      SmallVectorImpl<LiveInterval*>&);
@@ -220,6 +219,7 @@
 const char *const RAGreedy::StageName[] = {
   "RS_New",
   "RS_First",
+  "RS_Evicted",
   "RS_Second",
   "RS_Global",
   "RS_Local",
@@ -401,18 +401,60 @@
 //                         Interference eviction
 //===----------------------------------------------------------------------===//
 
+/// hasDefInRange - Returns true when any def of A happens where B is live.
+///
+/// The SSA form of live intervals guarantees:
+///
+///   A.overlaps(B) == hasDefInRange(A, B) || hasDefInRange(B, A)
+///
+bool RAGreedy::hasDefInRange(const LiveInterval &A, const LiveInterval &B) {
+  for (LiveInterval::const_vni_iterator I = A.vni_begin(), E = A.vni_end();
+       I != E; ++I) {
+    const VNInfo *VNI = *I;
+    if (VNI->isUnused())
+      continue;
+    if (B.liveAt(VNI->def))
+      return true;
+  }
+  return false;
+}
+
+/// hasUseInRange - Returns true when any def or use of A happens where B is
+/// live. The following is always true:
+///
+///   A.overlaps(B) == hasUseInRange(A, B) || hasUseInRange(B, A)
+///
+bool RAGreedy::hasUseInRange(const LiveInterval &A, const LiveInterval &B) {
+  if (hasDefInRange(A, B))
+    return true;
+  for (MachineRegisterInfo::use_nodbg_iterator I = MRI->use_nodbg_begin(A.reg),
+       E = MRI->use_nodbg_end(); I != E; ++I) {
+    if (I.getOperand().isUndef())
+      continue;
+    SlotIndex Idx = Indexes->getInstructionIndex(&*I).getDefIndex();
+    if (B.liveAt(Idx))
+      return true;
+  }
+  return false;
+}
+
 /// canEvict - determine if A can evict the assigned live range B. The eviction
 /// policy defined by this function together with the allocation order defined
 /// by enqueue() decides which registers ultimately end up being split and
 /// spilled.
 ///
-/// This function must define a non-circular relation when it returns CE_Always,
-/// otherwise infinite eviction loops are possible. When evicting a <= RS_Second
-/// range, it is possible to return CE_WithSplit which forces the evicted
-/// register to be split or spilled before it can evict anything again. That
-/// guarantees progress.
-RAGreedy::CanEvict RAGreedy::canEvict(LiveInterval &A, LiveInterval &B) {
-  return A.weight > B.weight ? CE_Always : CE_Never;
+/// Safeguards ensure that canEvict can never cause an infinite loop.
+///
+bool RAGreedy::canEvict(LiveInterval &A, LiveInterval &B) {
+  if (!ComplexEviction)
+    return A.weight > B.weight;
+
+  // Evict B if it has no uses in A's live range.
+  if (!hasUseInRange(B, A)) {
+    DEBUG(dbgs() << "Bypass: " << B << '\n');
+    return true;
+  }
+  return A.weight > B.weight;
 }
 
 /// canEvict - Return true if all interferences between VirtReg and PhysReg can
@@ -420,7 +462,7 @@
 /// Return false if any interference is heavier than MaxWeight.
 /// On return, set MaxWeight to the maximal spill weight of an interference.
 bool RAGreedy::canEvictInterference(LiveInterval &VirtReg, unsigned PhysReg,
-                                    float &MaxWeight) {
+                                    float &MaxWeight, bool OnlyCheap) {
   float Weight = 0;
   for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) {
     LiveIntervalUnion::Query &Q = query(VirtReg, *AliasI);
@@ -433,18 +475,22 @@
       LiveInterval *Intf = Q.interferingVRegs()[i - 1];
       if (TargetRegisterInfo::isPhysicalRegister(Intf->reg))
         return false;
-      if (Intf->weight >= MaxWeight)
+      if (getStage(*Intf) == RS_Spill)
         return false;
-      switch (canEvict(VirtReg, *Intf)) {
-      case CE_Always:
-        break;
-      case CE_Never:
+      if (Intf->weight >= MaxWeight)
         return false;
-      case CE_WithSplit:
-        if (getStage(*Intf) > RS_Second)
+      // When we are simply looking for a cheaper alternative, don't try too
+      // hard. The evicted range shouldn't end up getting split.
+      if (OnlyCheap) {
+        // Don't evict something that won't be able to reevict something else.
+        if (getStage(*Intf) != RS_First)
+          return false;
+        // Don't break a satisfied hint.
+        if (VRM->getRegAllocPref(Intf->reg) == *AliasI)
           return false;
-        break;
       }
+      if (VirtReg.isSpillable() && !canEvict(VirtReg, *Intf))
+        return false;
       Weight = std::max(Weight, Intf->weight);
     }
   }
@@ -453,17 +499,28 @@
 }
 
 /// tryEvict - Try to evict all interferences for a physreg.
-/// @param  VirtReg Currently unassigned virtual register.
-/// @param  Order   Physregs to try.
-/// @return         Physreg to assign VirtReg, or 0.
+/// @param  VirtReg         Currently unassigned virtual register.
+/// @param  Order           Physregs to try.
+/// @param  CostPerUseLimit Only look at physregs below this cost per use.
+/// @return                 Physreg to assign VirtReg, or 0.
 unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
                             AllocationOrder &Order,
                             SmallVectorImpl<LiveInterval*> &NewVRegs,
                             unsigned CostPerUseLimit) {
+  // Ranges that may have been evicted or requeued for splitting may never evict
+  // other ranges. That could cause looping.
+  // Spill ranges can always evict.
+  LiveRangeStage Stage = getStage(VirtReg);
+  if (Stage >= RS_Evicted && VirtReg.isSpillable())
+    return 0;
   NamedRegionTimer T("Evict", TimerGroupName, TimePassesIsEnabled);
 
+  bool OnlyCheap = CostPerUseLimit != ~0u;
+
   // Keep track of the lightest single interference seen so far.
-  float BestWeight = HUGE_VALF;
+  // When scavenging for a cheap register, never consider evicting heavier
+  // ranges.
+  float BestWeight = OnlyCheap ? VirtReg.weight : HUGE_VALF;
   unsigned BestPhys = 0;
 
   Order.rewind();
@@ -475,7 +532,7 @@
       continue;
 
     float Weight = BestWeight;
-    if (!canEvictInterference(VirtReg, PhysReg, Weight))
+    if (!canEvictInterference(VirtReg, PhysReg, Weight, OnlyCheap))
       continue;
 
     // This is an eviction candidate.
@@ -504,11 +561,11 @@
       unassign(*Intf, VRM->getPhys(Intf->reg));
       ++NumEvicted;
       NewVRegs.push_back(Intf);
-      // Prevent looping by forcing the evicted ranges to be split before they
-      // can evict anything else.
-      if (getStage(*Intf) < RS_Second &&
-          canEvict(VirtReg, *Intf) == CE_WithSplit)
-        LRStage[Intf->reg] = RS_Second;
+      // Prevent looping by marking the evicted ranges as RS_Evicted.
+      // When OnlyCheap is set, Intf is guaranteed to have a smaller spill
+      // weight which also prevents looping.
+      if (!OnlyCheap && getStage(*Intf) < RS_Evicted)
+        LRStage[Intf->reg] = RS_Evicted;
     }
   }
   return BestPhys;
@@ -1417,12 +1474,8 @@
   LiveRangeStage Stage = getStage(VirtReg);
   DEBUG(dbgs() << StageName[Stage] << '\n');
 
-  // Try to evict a less worthy live range, but only for ranges from the primary
-  // queue. The RS_Second ranges already failed to do this, and they should not
-  // get a second chance until they have been split.
-  if (Stage != RS_Second)
-    if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
-      return PhysReg;
+  if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
+    return PhysReg;
 
   assert(NewVRegs.empty() && "Cannot append to existing NewVRegs");
 





More information about the llvm-commits mailing list