[llvm-commits] CVS: llvm/lib/CodeGen/RegAllocLinearScan.cpp

Chris Lattner lattner at cs.uiuc.edu
Wed Nov 17 18:42:39 PST 2004



Changes in directory llvm/lib/CodeGen:

RegAllocLinearScan.cpp updated: 1.98 -> 1.99
---
Log message:

* Improve comments/documentation substantially
* Eliminate the releaseMemory method, this is not an analysis
* Change the fixed, active, and inactive lists of intervals to maintain an
  iterator for the current position in the interval.  This allows us to do
  constant time increments of the iterator instead of having to do a binary
  search to find our liverange in our liveinterval all of the time, which
  substantially speeds up cases where LiveIntervals have many LiveRanges
  - which is very common for physical registers.  On targets with many 
  physregs, this can make a noticable difference.

  With a release build of LLC for PPC, this halves the time in 
  processInactiveIntervals and processActiveIntervals, from 1.5s to .75s.
  
  This also lays the ground for more to come. 



---
Diffs of the changes:  (+174 -130)

Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp
diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.98 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.99
--- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.98	Wed Nov 17 19:29:39 2004
+++ llvm/lib/CodeGen/RegAllocLinearScan.cpp	Wed Nov 17 20:42:27 2004
@@ -29,6 +29,7 @@
 #include <cmath>
 #include <set>
 #include <queue>
+
 using namespace llvm;
 
 namespace {
@@ -39,16 +40,33 @@
   static unsigned numIterations = 0;
   static unsigned numIntervals = 0;
 
-  class RA : public MachineFunctionPass {
+  struct RA : public MachineFunctionPass {
+    typedef std::pair<LiveInterval*, LiveInterval::iterator> IntervalPtr;
+    typedef std::vector<IntervalPtr> IntervalPtrs;
+  private:
     MachineFunction* mf_;
     const TargetMachine* tm_;
     const MRegisterInfo* mri_;
     LiveIntervals* li_;
-    typedef LiveInterval* IntervalPtr;
-    typedef std::vector<IntervalPtr> IntervalPtrs;
-    IntervalPtrs handled_, fixed_, active_, inactive_;
+
+    /// handled_ - Intervals are added to the handled_ set in the order of their
+    /// start value.  This is uses for backtracking.
+    std::vector<LiveInterval*> handled_;
+
+    /// fixed_ - Intervals that correspond to machine registers.
+    ///
+    IntervalPtrs fixed_;
+
+    /// active_ - Intervals that are currently being processed, and which have a
+    /// live range active for the current point.
+    IntervalPtrs active_;
+
+    /// inactive_ - Intervals that are currently being processed, but which have
+    /// a hold at the current point.
+    IntervalPtrs inactive_;
+
     typedef std::priority_queue<LiveInterval*,
-                                IntervalPtrs,
+                                std::vector<LiveInterval*>,
                                 greater_ptr<LiveInterval> > IntervalHeap;
     IntervalHeap unhandled_;
     std::auto_ptr<PhysRegTracker> prt_;
@@ -71,26 +89,24 @@
     /// runOnMachineFunction - register allocate the whole function
     bool runOnMachineFunction(MachineFunction&);
 
-    void releaseMemory();
-
   private:
     /// linearScan - the linear scan algorithm
     void linearScan();
 
-    /// initIntervalSets - initializa the four interval sets:
-    /// unhandled, fixed, active and inactive
+    /// initIntervalSets - initialize the interval sets.
+    ///
     void initIntervalSets();
 
-    /// processActiveIntervals - expire old intervals and move
-    /// non-overlapping ones to the incative list
-    void processActiveIntervals(LiveInterval* cur);
-
-    /// processInactiveIntervals - expire old intervals and move
-    /// overlapping ones to the active list
-    void processInactiveIntervals(LiveInterval* cur);
+    /// processActiveIntervals - expire old intervals and move non-overlapping
+    /// ones to the inactive list.
+    void processActiveIntervals(unsigned CurPoint);
+
+    /// processInactiveIntervals - expire old intervals and move overlapping
+    /// ones to the active list.
+    void processInactiveIntervals(unsigned CurPoint);
 
     /// updateSpillWeights - updates the spill weights of the
-    /// specifed physical register and its weight
+    /// specifed physical register and its weight.
     void updateSpillWeights(unsigned reg, SpillWeights::value_type weight);
 
     /// assignRegOrStackSlotAtInterval - assign a register if one
@@ -101,9 +117,8 @@
     /// register handling helpers
     ///
 
-    /// getFreePhysReg - return a free physical register for this
-    /// virtual register interval if we have one, otherwise return
-    /// 0
+    /// getFreePhysReg - return a free physical register for this virtual
+    /// register interval if we have one, otherwise return 0.
     unsigned getFreePhysReg(LiveInterval* cur);
 
     /// assignVirt2StackSlot - assigns this virtual register to a
@@ -114,8 +129,8 @@
     void printIntervals(const char* const str, ItTy i, ItTy e) const {
       if (str) std::cerr << str << " intervals:\n";
       for (; i != e; ++i) {
-        std::cerr << "\t" << **i << " -> ";
-        unsigned reg = (*i)->reg;
+        std::cerr << "\t" << *i->first << " -> ";
+        unsigned reg = i->first->reg;
         if (MRegisterInfo::isVirtualRegister(reg)) {
           reg = vrm_->getPhys(reg);
         }
@@ -125,15 +140,6 @@
   };
 }
 
-void RA::releaseMemory()
-{
-  while (!unhandled_.empty()) unhandled_.pop();
-  fixed_.clear();
-  active_.clear();
-  inactive_.clear();
-  handled_.clear();
-}
-
 bool RA::runOnMachineFunction(MachineFunction &fn) {
   mf_ = &fn;
   tm_ = &fn.getTarget();
@@ -150,6 +156,14 @@
   spiller_->runOnMachineFunction(*mf_, *vrm_);
 
   vrm_.reset();  // Free the VirtRegMap
+
+
+  while (!unhandled_.empty()) unhandled_.pop();
+  fixed_.clear();
+  active_.clear();
+  inactive_.clear();
+  handled_.clear();
+
   return true;
 }
 
@@ -172,19 +186,18 @@
     ++numIterations;
     DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n');
 
-    processActiveIntervals(cur);
-    processInactiveIntervals(cur);
+    processActiveIntervals(cur->beginNumber());
+    processInactiveIntervals(cur->beginNumber());
 
     // if this register is fixed we are done
     if (MRegisterInfo::isPhysicalRegister(cur->reg)) {
       prt_->addRegUse(cur->reg);
-      active_.push_back(cur);
+      active_.push_back(std::make_pair(cur, cur->begin()));
       handled_.push_back(cur);
-    }
-    // otherwise we are allocating a virtual register. try to find
-    // a free physical register or spill an interval in order to
-    // assign it one (we could spill the current though).
-    else {
+    } else {
+      // otherwise we are allocating a virtual register. try to find a free
+      // physical register or spill an interval in order to assign it one (we
+      // could spill the current though).
       assignRegOrStackSlotAtInterval(cur);
     }
 
@@ -197,8 +210,8 @@
   // expire any remaining active intervals
   for (IntervalPtrs::reverse_iterator
          i = active_.rbegin(); i != active_.rend(); ) {
-    unsigned reg = (*i)->reg;
-    DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
+    unsigned reg = i->first->reg;
+    DEBUG(std::cerr << "\tinterval " << *i->first << " expired\n");
     if (MRegisterInfo::isVirtualRegister(reg))
       reg = vrm_->getPhys(reg);
     prt_->delRegUse(reg);
@@ -208,13 +221,15 @@
   // expire any remaining inactive intervals
   for (IntervalPtrs::reverse_iterator
          i = inactive_.rbegin(); i != inactive_.rend(); ) {
-    DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
+    DEBUG(std::cerr << "\tinterval " << *i->first << " expired\n");
     i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
   }
 
   DEBUG(std::cerr << *vrm_);
 }
 
+/// initIntervalSets - initialize the interval sets.
+///
 void RA::initIntervalSets()
 {
   assert(unhandled_.empty() && fixed_.empty() &&
@@ -224,79 +239,95 @@
   for (LiveIntervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i){
     unhandled_.push(&i->second);
     if (MRegisterInfo::isPhysicalRegister(i->second.reg))
-      fixed_.push_back(&i->second);
+      fixed_.push_back(std::make_pair(&i->second, i->second.begin()));
   }
 }
 
-void RA::processActiveIntervals(IntervalPtrs::value_type cur)
+/// processActiveIntervals - expire old intervals and move non-overlapping ones
+/// to the inactive list.
+void RA::processActiveIntervals(unsigned CurPoint)
 {
   DEBUG(std::cerr << "\tprocessing active intervals:\n");
 
-  IntervalPtrs::iterator ii = active_.begin(), ie = active_.end();
-  while (ii != ie) {
-    LiveInterval* i = *ii;
-    unsigned reg = i->reg;
-
-    // remove expired intervals
-    if (i->expiredAt(cur->beginNumber())) {
-      DEBUG(std::cerr << "\t\tinterval " << *i << " expired\n");
+  for (unsigned i = 0, e = active_.size(); i != e; ++i) {
+    LiveInterval *Interval = active_[i].first;
+    LiveInterval::iterator IntervalPos = active_[i].second;
+    unsigned reg = Interval->reg;
+
+    IntervalPos = Interval->advanceTo(IntervalPos, CurPoint);
+
+    if (IntervalPos == Interval->end()) {     // Remove expired intervals.
+      DEBUG(std::cerr << "\t\tinterval " << *Interval << " expired\n");
       if (MRegisterInfo::isVirtualRegister(reg))
         reg = vrm_->getPhys(reg);
       prt_->delRegUse(reg);
-      // swap with last element and move end iterator back one position
-      std::iter_swap(ii, --ie);
-    }
-    // move inactive intervals to inactive list
-    else if (!i->liveAt(cur->beginNumber())) {
-      DEBUG(std::cerr << "\t\tinterval " << *i << " inactive\n");
+
+      // Pop off the end of the list.
+      active_[i] = active_.back();
+      active_.pop_back();
+      --i; --e;
+      
+    } else if (IntervalPos->start > CurPoint) {
+      // Move inactive intervals to inactive list.
+      DEBUG(std::cerr << "\t\tinterval " << *Interval << " inactive\n");
       if (MRegisterInfo::isVirtualRegister(reg))
         reg = vrm_->getPhys(reg);
       prt_->delRegUse(reg);
-      // add to inactive
-      inactive_.push_back(i);
-      // swap with last element and move end iterator back one postion
-      std::iter_swap(ii, --ie);
-    }
-    else {
-      ++ii;
+      // add to inactive.
+      inactive_.push_back(std::make_pair(Interval, IntervalPos));
+
+      // Pop off the end of the list.
+      active_[i] = active_.back();
+      active_.pop_back();
+      --i; --e;
+    } else {
+      // Otherwise, just update the iterator position.
+      active_[i].second = IntervalPos;
     }
   }
-  active_.erase(ie, active_.end());
 }
 
-void RA::processInactiveIntervals(IntervalPtrs::value_type cur)
+/// processInactiveIntervals - expire old intervals and move overlapping
+/// ones to the active list.
+void RA::processInactiveIntervals(unsigned CurPoint)
 {
   DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
-  IntervalPtrs::iterator ii = inactive_.begin(), ie = inactive_.end();
-
-  while (ii != ie) {
-    LiveInterval* i = *ii;
-    unsigned reg = i->reg;
-
-    // remove expired intervals
-    if (i->expiredAt(cur->beginNumber())) {
-      DEBUG(std::cerr << "\t\tinterval " << *i << " expired\n");
-      // swap with last element and move end iterator back one position
-      std::iter_swap(ii, --ie);
-    }
-    // move re-activated intervals in active list
-    else if (i->liveAt(cur->beginNumber())) {
-      DEBUG(std::cerr << "\t\tinterval " << *i << " active\n");
+  for (unsigned i = 0, e = inactive_.size(); i != e; ++i) {
+    LiveInterval *Interval = inactive_[i].first;
+    LiveInterval::iterator IntervalPos = inactive_[i].second;
+    unsigned reg = Interval->reg;
+
+    IntervalPos = Interval->advanceTo(IntervalPos, CurPoint);
+    
+    if (IntervalPos == Interval->end()) {       // remove expired intervals.
+      DEBUG(std::cerr << "\t\tinterval " << *Interval << " expired\n");
+
+      // Pop off the end of the list.
+      inactive_[i] = inactive_.back();
+      inactive_.pop_back();
+      --i; --e;
+    } else if (IntervalPos->start <= CurPoint) {
+      // move re-activated intervals in active list
+      DEBUG(std::cerr << "\t\tinterval " << *Interval << " active\n");
       if (MRegisterInfo::isVirtualRegister(reg))
         reg = vrm_->getPhys(reg);
       prt_->addRegUse(reg);
       // add to active
-      active_.push_back(i);
-      // swap with last element and move end iterator back one position
-      std::iter_swap(ii, --ie);
-    }
-    else {
-      ++ii;
+      active_.push_back(std::make_pair(Interval, IntervalPos));
+
+      // Pop off the end of the list.
+      inactive_[i] = inactive_.back();
+      inactive_.pop_back();
+      --i; --e;
+    } else {
+      // Otherwise, just update the iterator position.
+      inactive_[i].second = IntervalPos;
     }
   }
-  inactive_.erase(ie, inactive_.end());
 }
 
+/// updateSpillWeights - updates the spill weights of the specifed physical
+/// register and its weight.
 void RA::updateSpillWeights(unsigned reg, SpillWeights::value_type weight)
 {
   spillWeights_[reg] += weight;
@@ -304,6 +335,17 @@
     spillWeights_[*as] += weight;
 }
 
+static RA::IntervalPtrs::iterator FindIntervalInVector(RA::IntervalPtrs &IP,
+                                                       LiveInterval *LI) {
+  for (RA::IntervalPtrs::iterator I = IP.begin(), E = IP.end(); I != E; ++I)
+    if (I->first == LI) return I;
+  return IP.end();
+}
+
+
+
+/// assignRegOrStackSlotAtInterval - assign a register if one is available, or
+/// spill.
 void RA::assignRegOrStackSlotAtInterval(LiveInterval* cur)
 {
   DEBUG(std::cerr << "\tallocating current interval: ");
@@ -315,22 +357,22 @@
   // for each interval in active update spill weights
   for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
        i != e; ++i) {
-    unsigned reg = (*i)->reg;
+    unsigned reg = i->first->reg;
     if (MRegisterInfo::isVirtualRegister(reg))
       reg = vrm_->getPhys(reg);
-    updateSpillWeights(reg, (*i)->weight);
+    updateSpillWeights(reg, i->first->weight);
   }
 
   // for every interval in inactive we overlap with, mark the
   // register as not free and update spill weights
   for (IntervalPtrs::const_iterator i = inactive_.begin(),
          e = inactive_.end(); i != e; ++i) {
-    if (cur->overlaps(**i)) {
-      unsigned reg = (*i)->reg;
+    if (cur->overlaps(*i->first)) {
+      unsigned reg = i->first->reg;
       if (MRegisterInfo::isVirtualRegister(reg))
         reg = vrm_->getPhys(reg);
       prt_->addRegUse(reg);
-      updateSpillWeights(reg, (*i)->weight);
+      updateSpillWeights(reg, i->first->weight);
     }
   }
 
@@ -338,10 +380,10 @@
   // mark the register as not free and update spill weights
   for (IntervalPtrs::const_iterator i = fixed_.begin(),
          e = fixed_.end(); i != e; ++i) {
-    if (cur->overlaps(**i)) {
-      unsigned reg = (*i)->reg;
+    if (cur->overlaps(*i->first)) {
+      unsigned reg = i->first->reg;
       prt_->addRegUse(reg);
-      updateSpillWeights(reg, (*i)->weight);
+      updateSpillWeights(reg, i->first->weight);
     }
   }
 
@@ -355,7 +397,7 @@
     DEBUG(std::cerr <<  mri_->getName(physReg) << '\n');
     vrm_->assignVirt2Phys(cur->reg, physReg);
     prt_->addRegUse(physReg);
-    active_.push_back(cur);
+    active_.push_back(std::make_pair(cur, cur->begin()));
     handled_.push_back(cur);
     return;
   }
@@ -428,64 +470,63 @@
   // point
   for (IntervalPtrs::iterator
          i = active_.begin(); i != active_.end(); ++i) {
-    unsigned reg = (*i)->reg;
+    unsigned reg = i->first->reg;
     if (MRegisterInfo::isVirtualRegister(reg) &&
         toSpill[vrm_->getPhys(reg)] &&
-        cur->overlaps(**i)) {
-      DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n');
-      earliestStart = std::min(earliestStart, (*i)->beginNumber());
-      int slot = vrm_->assignVirt2StackSlot((*i)->reg);
+        cur->overlaps(*i->first)) {
+      DEBUG(std::cerr << "\t\t\tspilling(a): " << *i->first << '\n');
+      earliestStart = std::min(earliestStart, i->first->beginNumber());
+      int slot = vrm_->assignVirt2StackSlot(i->first->reg);
       std::vector<LiveInterval*> newIs =
-        li_->addIntervalsForSpills(**i, *vrm_, slot);
+        li_->addIntervalsForSpills(*i->first, *vrm_, slot);
       std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
       spilled.insert(reg);
     }
   }
   for (IntervalPtrs::iterator
          i = inactive_.begin(); i != inactive_.end(); ++i) {
-    unsigned reg = (*i)->reg;
+    unsigned reg = i->first->reg;
     if (MRegisterInfo::isVirtualRegister(reg) &&
         toSpill[vrm_->getPhys(reg)] &&
-        cur->overlaps(**i)) {
-      DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n');
-      earliestStart = std::min(earliestStart, (*i)->beginNumber());
-      int slot = vrm_->assignVirt2StackSlot((*i)->reg);
+        cur->overlaps(*i->first)) {
+      DEBUG(std::cerr << "\t\t\tspilling(i): " << *i->first << '\n');
+      earliestStart = std::min(earliestStart, i->first->beginNumber());
+      int slot = vrm_->assignVirt2StackSlot(reg);
       std::vector<LiveInterval*> newIs =
-        li_->addIntervalsForSpills(**i, *vrm_, slot);
+        li_->addIntervalsForSpills(*i->first, *vrm_, slot);
       std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
       spilled.insert(reg);
     }
   }
 
   DEBUG(std::cerr << "\t\trolling back to: " << earliestStart << '\n');
-  // scan handled in reverse order up to the earliaset start of a
+
+  // Scan handled in reverse order up to the earliest start of a
   // spilled live interval and undo each one, restoring the state of
-  // unhandled
+  // unhandled.
   while (!handled_.empty()) {
     LiveInterval* i = handled_.back();
-    // if this interval starts before t we are done
+    // If this interval starts before t we are done.
     if (i->beginNumber() < earliestStart)
       break;
     DEBUG(std::cerr << "\t\t\tundo changes for: " << *i << '\n');
     handled_.pop_back();
-    // when undoing a live interval allocation we must know if it
-    // is active or inactive to properly update the PhysRegTracker
-    // and the VirtRegMap
+
+    // When undoing a live interval allocation we must know if it is active or
+    // inactive to properly update the PhysRegTracker and the VirtRegMap.
     IntervalPtrs::iterator it;
-    if ((it = std::find(active_.begin(), active_.end(), i)) != active_.end()) {
+    if ((it = FindIntervalInVector(active_, i)) != active_.end()) {
       active_.erase(it);
       if (MRegisterInfo::isPhysicalRegister(i->reg)) {
         prt_->delRegUse(i->reg);
         unhandled_.push(i);
-      }
-      else {
+      } else {
         if (!spilled.count(i->reg))
           unhandled_.push(i);
         prt_->delRegUse(vrm_->getPhys(i->reg));
         vrm_->clearVirt(i->reg);
       }
-    }
-    else if ((it = std::find(inactive_.begin(), inactive_.end(), i)) != inactive_.end()) {
+    } else if ((it = FindIntervalInVector(inactive_, i)) != inactive_.end()) {
       inactive_.erase(it);
       if (MRegisterInfo::isPhysicalRegister(i->reg))
         unhandled_.push(i);
@@ -505,15 +546,16 @@
   // scan the rest and undo each interval that expired after t and
   // insert it in active (the next iteration of the algorithm will
   // put it in inactive if required)
-  for (IntervalPtrs::iterator i = handled_.begin(), e = handled_.end(); 
-       i != e; ++i) {
-    if (!(*i)->expiredAt(earliestStart) && (*i)->expiredAt(cur->beginNumber())){
-      DEBUG(std::cerr << "\t\t\tundo changes for: " << **i << '\n');
-      active_.push_back(*i);
-      if (MRegisterInfo::isPhysicalRegister((*i)->reg))
-        prt_->addRegUse((*i)->reg);
+  for (unsigned i = 0, e = handled_.size(); i != e; ++i) {
+    LiveInterval *HI = handled_[i];
+    if (!HI->expiredAt(earliestStart) &&
+        HI->expiredAt(cur->beginNumber())) {
+      DEBUG(std::cerr << "\t\t\tundo changes for: " << *HI << '\n');
+      active_.push_back(std::make_pair(HI, HI->begin()));
+      if (MRegisterInfo::isPhysicalRegister(HI->reg))
+        prt_->addRegUse(HI->reg);
       else
-        prt_->addRegUse(vrm_->getPhys((*i)->reg));
+        prt_->addRegUse(vrm_->getPhys(HI->reg));
     }
   }
 
@@ -522,12 +564,14 @@
     unhandled_.push(added[i]);
 }
 
+/// getFreePhysReg - return a free physical register for this virtual register
+/// interval if we have one, otherwise return 0.
 unsigned RA::getFreePhysReg(LiveInterval* cur)
 {
   std::vector<unsigned> inactiveCounts(mri_->getNumRegs(), 0);
   for (IntervalPtrs::iterator i = inactive_.begin(), e = inactive_.end();
        i != e; ++i) {
-    unsigned reg = (*i)->reg;
+    unsigned reg = i->first->reg;
     if (MRegisterInfo::isVirtualRegister(reg))
       reg = vrm_->getPhys(reg);
     ++inactiveCounts[reg];






More information about the llvm-commits mailing list