[llvm-commits] [llvm] r121388 - in /llvm/trunk/lib/CodeGen: LiveIntervalUnion.cpp LiveIntervalUnion.h RegAllocBase.h RegAllocBasic.cpp RegAllocGreedy.cpp

Andrew Trick atrick at apple.com
Thu Dec 9 10:15:21 PST 2010


Author: atrick
Date: Thu Dec  9 12:15:21 2010
New Revision: 121388

URL: http://llvm.org/viewvc/llvm-project?rev=121388&view=rev
Log:
Added register reassignment prototype to RAGreedy. It's a simple
heuristic to reshuffle register assignments when we can't find an
available reg.

Modified:
    llvm/trunk/lib/CodeGen/LiveIntervalUnion.cpp
    llvm/trunk/lib/CodeGen/LiveIntervalUnion.h
    llvm/trunk/lib/CodeGen/RegAllocBase.h
    llvm/trunk/lib/CodeGen/RegAllocBasic.cpp
    llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp

Modified: llvm/trunk/lib/CodeGen/LiveIntervalUnion.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveIntervalUnion.cpp?rev=121388&r1=121387&r2=121388&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveIntervalUnion.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveIntervalUnion.cpp Thu Dec  9 12:15:21 2010
@@ -247,10 +247,13 @@
       if (!IR.LiveUnionI.value()->isSpillable())
         SeenUnspillableVReg = true;
 
-      InterferingVRegs.push_back(IR.LiveUnionI.value());
       if (InterferingVRegs.size() == MaxInterferingRegs)
+        // Leave SeenAllInterferences set to false to indicate that at least one
+        // interference exists beyond those we collected.
         return MaxInterferingRegs;
 
+      InterferingVRegs.push_back(IR.LiveUnionI.value());
+
       // Cache the most recent interfering vreg to bypass isSeenInterference.
       RecentInterferingVReg = IR.LiveUnionI.value();
       ++IR.LiveUnionI;

Modified: llvm/trunk/lib/CodeGen/LiveIntervalUnion.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveIntervalUnion.h?rev=121388&r1=121387&r2=121388&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveIntervalUnion.h (original)
+++ llvm/trunk/lib/CodeGen/LiveIntervalUnion.h Thu Dec  9 12:15:21 2010
@@ -159,10 +159,7 @@
     }
 
     void init(LiveInterval *VReg, LiveIntervalUnion *LIU) {
-      if (VirtReg == VReg) {
-        // We currently allow query objects to be reused acrossed live virtual
-        // registers, but always for the same live interval union.
-        assert(LiveUnion == LIU && "inconsistent initialization");
+      if (VirtReg == VReg && LiveUnion == LIU) {
         // Retain cached results, e.g. firstInterference.
         return;
       }

Modified: llvm/trunk/lib/CodeGen/RegAllocBase.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocBase.h?rev=121388&r1=121387&r2=121388&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/RegAllocBase.h (original)
+++ llvm/trunk/lib/CodeGen/RegAllocBase.h Thu Dec  9 12:15:21 2010
@@ -58,8 +58,8 @@
 /// be extended to add interesting heuristics.
 ///
 /// Register allocators must override the selectOrSplit() method to implement
-/// live range splitting. LessSpillWeightPriority is provided as a standard
-/// comparator, but we may add an interface to override it if necessary.
+/// live range splitting. They may also override getPriority() which otherwise
+/// defaults to the spill weight computed by CalculateSpillWeights.
 class RegAllocBase {
   LiveIntervalUnion::Allocator UnionAllocator;
 protected:

Modified: llvm/trunk/lib/CodeGen/RegAllocBasic.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocBasic.cpp?rev=121388&r1=121387&r2=121388&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/RegAllocBasic.cpp (original)
+++ llvm/trunk/lib/CodeGen/RegAllocBasic.cpp Thu Dec  9 12:15:21 2010
@@ -435,15 +435,13 @@
     LiveInterval *interferingVirtReg =
       Queries[interfReg].firstInterference().liveUnionPos().value();
 
-    // The current VirtReg must either spillable, or one of its interferences
+    // The current VirtReg must either be spillable, or one of its interferences
     // must have less spill weight.
     if (interferingVirtReg->weight < VirtReg.weight ) {
       PhysRegSpillCands.push_back(PhysReg);
     }
   }
   // Try to spill another interfering reg with less spill weight.
-  //
-  // FIXME: RAGreedy will sort this list by spill weight.
   for (SmallVectorImpl<unsigned>::iterator PhysRegI = PhysRegSpillCands.begin(),
          PhysRegE = PhysRegSpillCands.end(); PhysRegI != PhysRegE; ++PhysRegI) {
 

Modified: llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp?rev=121388&r1=121387&r2=121388&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp (original)
+++ llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp Thu Dec  9 12:15:21 2010
@@ -79,6 +79,10 @@
   virtual bool runOnMachineFunction(MachineFunction &mf);
 
   static char ID;
+
+private:
+  bool reassignVReg(LiveInterval &InterferingVReg, unsigned OldPhysReg);
+  bool reassignInterferences(LiveInterval &VirtReg, unsigned PhysReg);
 };
 } // end anonymous namespace
 
@@ -142,10 +146,84 @@
   return Priority;
 }
 
+// Attempt to reassign this virtual register to a different physical register.
+//
+// FIXME: we are not yet caching these "second-level" interferences discovered
+// in the sub-queries. These interferences can change with each call to
+// selectOrSplit. However, we could implement a "may-interfere" cache that
+// could be conservatively dirtied when we reassign or split.
+//
+// FIXME: This may result in a lot of alias queries. We could summarize alias
+// live intervals in their parent register's live union, but it's messy.
+bool RAGreedy::reassignVReg(LiveInterval &InterferingVReg,
+                            unsigned OldPhysReg) {
+  assert(OldPhysReg == VRM->getPhys(InterferingVReg.reg) &&
+         "inconsistent phys reg assigment");
+
+  const TargetRegisterClass *TRC = MRI->getRegClass(InterferingVReg.reg);
+  for (TargetRegisterClass::iterator I = TRC->allocation_order_begin(*MF),
+         E = TRC->allocation_order_end(*MF);
+       I != E; ++I) {
+    unsigned PhysReg = *I;
+    if (PhysReg == OldPhysReg)
+      continue;
+
+    // Instantiate a "subquery", not to be confused with the Queries array.
+    LiveIntervalUnion::Query subQ(&InterferingVReg,
+                                  &PhysReg2LiveUnion[PhysReg]);
+    if (subQ.checkInterference())
+      continue;
+
+    for (const unsigned *AliasI = TRI->getAliasSet(PhysReg);
+         *AliasI; ++AliasI) {
+      subQ.init(&InterferingVReg, &PhysReg2LiveUnion[*AliasI]);
+      if (subQ.checkInterference())
+        continue;
+    }
+    DEBUG(dbgs() << "reassigning: " << InterferingVReg << " from " <<
+          TRI->getName(OldPhysReg) << " to " << TRI->getName(PhysReg) << '\n');
+
+    // Reassign the interfering virtual reg to this physical reg.
+    PhysReg2LiveUnion[OldPhysReg].extract(InterferingVReg);
+    VRM->clearVirt(InterferingVReg.reg);
+    VRM->assignVirt2Phys(InterferingVReg.reg, PhysReg);
+    PhysReg2LiveUnion[PhysReg].unify(InterferingVReg);
+
+    return true;
+  }
+  return false;
+}
+
+// Collect all virtual regs currently assigned to PhysReg that interfere with
+// VirtReg.
+//
+// Currently, for simplicity, we only attempt to reassign a single interference
+// within the same register class.
+bool RAGreedy::reassignInterferences(LiveInterval &VirtReg, unsigned PhysReg) {
+  LiveIntervalUnion::Query &Q = query(VirtReg, PhysReg);
+
+  // Limit the interference search to one interference.
+  Q.collectInterferingVRegs(1);
+  assert(Q.interferingVRegs().size() == 1 &&
+         "expected at least one interference");
+
+  // Do not attempt reassignment unless we find only a single interference.
+  if (!Q.seenAllInterferences())
+    return false;
+
+  // Don't allow any interferences on aliases.
+  for (const unsigned *AliasI = TRI->getAliasSet(PhysReg); *AliasI; ++AliasI) {
+    if (query(VirtReg, *AliasI).checkInterference())
+      return false;
+  }
+
+  return reassignVReg(*Q.interferingVRegs()[0], PhysReg);
+}
+
 unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
                                 SmallVectorImpl<LiveInterval*> &SplitVRegs) {
   // Populate a list of physical register spill candidates.
-  SmallVector<unsigned, 8> PhysRegSpillCands;
+  SmallVector<unsigned, 8> PhysRegSpillCands, ReassignCands;
 
   // Check for an available register in this class.
   const TargetRegisterClass *TRC = MRI->getRegClass(VirtReg.reg);
@@ -168,24 +246,44 @@
 
     // Check interference and as a side effect, intialize queries for this
     // VirtReg and its aliases.
-    unsigned interfReg = checkPhysRegInterference(VirtReg, PhysReg);
-    if (interfReg == 0) {
+    unsigned InterfReg = checkPhysRegInterference(VirtReg, PhysReg);
+    if (InterfReg == 0) {
       // Found an available register.
       return PhysReg;
     }
     assert(!VirtReg.empty() && "Empty VirtReg has interference");
-    LiveInterval *interferingVirtReg =
-      Queries[interfReg].firstInterference().liveUnionPos().value();
+    LiveInterval *InterferingVirtReg =
+      Queries[InterfReg].firstInterference().liveUnionPos().value();
 
-    // The current VirtReg must either spillable, or one of its interferences
+    // The current VirtReg must either be spillable, or one of its interferences
     // must have less spill weight.
-    if (interferingVirtReg->weight < VirtReg.weight ) {
-      PhysRegSpillCands.push_back(PhysReg);
+    if (InterferingVirtReg->weight < VirtReg.weight ) {
+      // For simplicity, only consider reassigning registers in the same class.
+      if (InterfReg == PhysReg)
+        ReassignCands.push_back(PhysReg);
+      else
+        PhysRegSpillCands.push_back(PhysReg);
     }
   }
+
+  // Try to reassign interfering physical register. Priority among
+  // PhysRegSpillCands does not matter yet, because the reassigned virtual
+  // registers will still be assigned to physical registers.
+  for (SmallVectorImpl<unsigned>::iterator PhysRegI = ReassignCands.begin(),
+         PhysRegE = ReassignCands.end(); PhysRegI != PhysRegE; ++PhysRegI) {
+    if (reassignInterferences(VirtReg, *PhysRegI))
+      // Reassignment successfull. The caller may allocate now to this PhysReg.
+      return *PhysRegI;
+  }
+
+  PhysRegSpillCands.insert(PhysRegSpillCands.end(), ReassignCands.begin(),
+                           ReassignCands.end());
+
   // Try to spill another interfering reg with less spill weight.
   //
-  // FIXME: RAGreedy will sort this list by spill weight.
+  // FIXME: do this in two steps: (1) check for unspillable interferences while
+  // accumulating spill weight; (2) spill the interferences with lowest
+  // aggregate spill weight.
   for (SmallVectorImpl<unsigned>::iterator PhysRegI = PhysRegSpillCands.begin(),
          PhysRegE = PhysRegSpillCands.end(); PhysRegI != PhysRegE; ++PhysRegI) {
 
@@ -196,6 +294,7 @@
     // Tell the caller to allocate to this newly freed physical register.
     return *PhysRegI;
   }
+
   // No other spill candidates were found, so spill the current VirtReg.
   DEBUG(dbgs() << "spilling: " << VirtReg << '\n');
   SmallVector<LiveInterval*, 1> pendingSpills;





More information about the llvm-commits mailing list