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

Alkis Evlogimenos alkis at cs.uiuc.edu
Wed Nov 5 20:26:01 PST 2003


Changes in directory llvm/lib/CodeGen:

RegAllocLinearScan.cpp updated: 1.1.2.6 -> 1.1.2.7

---
Log message:

A compilable sketch of the linear register allocation algorithm.


---
Diffs of the changes:  (+214 -254)

Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp
diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.6 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.7
--- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.6	Fri Oct 24 10:57:32 2003
+++ llvm/lib/CodeGen/RegAllocLinearScan.cpp	Wed Nov  5 20:25:37 2003
@@ -1,10 +1,10 @@
 //===-- RegAllocLinearScan.cpp - Linear Scan register allocator -----------===//
-// 
+//
 //                     The LLVM Compiler Infrastructure
 //
 // This file was developed by the LLVM research group and is distributed under
 // the University of Illinois Open Source License. See LICENSE.TXT for details.
-// 
+//
 //===----------------------------------------------------------------------===//
 //
 // This file implements a linear scan register allocator.
@@ -26,6 +26,7 @@
 #include "Support/Debug.h"
 #include "Support/DepthFirstIterator.h"
 #include "Support/Statistic.h"
+#include "Support/STLExtras.h"
 #include <iostream>
 
 namespace {
@@ -34,26 +35,38 @@
 
     class RA : public MachineFunctionPass {
     private:
-        MachineFunction* _mf;
-        const TargetMachine* _tm;
-        const TargetRegInfo* _tri;
-        const MRegisterInfo* _mri;
-        MachineBasicBlock* _currentMbb;
-        MachineBasicBlock::iterator _currentInstr;
+        MachineFunction* mf_;
+        const TargetMachine* tm_;
+        const TargetRegInfo* tri_;
+        const MRegisterInfo* mri_;
+        MachineBasicBlock* currentMbb_;
+        MachineBasicBlock::iterator currentInstr_;
+
+        typedef LiveIntervals::Intervals Intervals;
+        Intervals* li_;
+
+        typedef std::vector<LiveIntervals::Interval*> IntervalPtrs;
+        IntervalPtrs active_, inactive_;
 
-        LiveIntervals* _li;
+        typedef LiveIntervals::MiIndex2MbbMap MiIndex2MbbMap;
+        MiIndex2MbbMap* mii2mbbMap_;
+
+        typedef LiveIntervals::Mbb2MiIndexMap Mbb2MiIndexMap;
+        Mbb2MiIndexMap* mbb2miiMap_;
 
         typedef std::map<MachineInstr*, unsigned> Instr2IndexMap;
-        Instr2IndexMap _i2iMap;
+        Instr2IndexMap i2iMap_;
 
         typedef std::vector<unsigned> Phys2VirtMap;
-        Phys2VirtMap _p2vMap;
+        Phys2VirtMap p2vMap_;
 
         typedef std::map<unsigned, unsigned> Virt2PhysMap;
-        Virt2PhysMap _v2pMap;
+        Virt2PhysMap v2pMap_;
 
         typedef std::map<unsigned, int> Virt2StackSlotMap;
-        Virt2StackSlotMap _v2ssMap;
+        Virt2StackSlotMap v2ssMap_;
+
+        int instrAdded_;
 
     public:
         virtual const char* getPassName() const {
@@ -66,27 +79,39 @@
         }
 
     private:
-        /// runOnMachineFunction - Register allocate the whole function
+        /// runOnMachineFunction - register allocate the whole function
         bool runOnMachineFunction(MachineFunction&);
 
-        /// expireOldIntervals - in each iteration of the linear scan
-        /// loop, expire the old intervals; that is the registers that
-        /// are killed
-//         void expireOldIntervals(Intervals::iterator li);
+        /// processActiveIntervals - expire old intervals and move
+        /// non-overlapping ones to the incative list
+        void processActiveIntervals(Intervals::iterator cur);
+
+        /// expireOldInterval - expire old intervals and move
+        /// overlapping ones to the active list
+        void processInactiveIntervals(Intervals::iterator cur);
 
         /// spillAtInterval - choose and spill at the specified
-        /// interval. Currently we spill using a heuristic: the active
-        /// interval that ends last
-//         void spillAtInterval(Intervals::iterator li);
-
-        /// computeIntervals - computes the live intervals for
-        /// virtual registers
-        void computeIntervals();
+        /// interval. Currently we spill the interval with the last
+        /// end point in the active and inactive lists
+        void spillAtInterval(Intervals::iterator cur);
 
         /// getFreeReg - return a free register for this virtual
         /// register if we have one, otherwise return 0
         unsigned getFreeReg(unsigned virtReg);
 
+        /// freeReg - free the physical register associated with this
+        /// virtual register and disassociate virtual->physical and
+        /// physical->virtual mappings
+        void freeReg(unsigned virtReg);
+
+        /// markReg - mark the physical register as not free
+        /// (preserves mappings)
+        void markReg(unsigned virtReg);
+
+        /// unmarkReg - mark the physical register as free (preserves
+        /// mappings)
+        void unmarkReg(unsigned virtReg);
+
         /// physRegAvailable - returns true if the specifed physical
         /// register is available
         bool physRegAvailable(unsigned physReg);
@@ -97,240 +122,142 @@
         int findOrCreateStackSlot(unsigned virtReg);
 
         /// spillVirtReg - spills the virtual register
-        void spillVirtReg(unsigned virtReg, unsigned physReg);
+        void spillVirtReg(unsigned virtReg);
 
         /// loadPhysReg - loads to the physical register the value of
         /// the virtual register specifed
         void loadPhysReg(unsigned physReg, unsigned virtReg);
+
+        /// getMbbMbbIteratorPair - returns a pair of the
+        /// MachineBasicBlock this instruction is on and the iterator
+        /// pointing to the instruction
+        std::pair<MachineBasicBlock*, MachineBasicBlock::iterator>
+        getMbbMbbIteratorPair(unsigned miIndex) const;
     };
 }
 
-/// runOnMachineFunction - Register allocate the whole function
-///
 bool RA::runOnMachineFunction(MachineFunction &fn) {
     DEBUG(std::cerr << "Machine Function\n");
-    _mf = &fn;
-    _tm = &fn.getTarget();
-    _tri = &_tm->getRegInfo();
-    _mri = _tm->getRegisterInfo();
-    _li = &getAnalysis<LiveIntervals>();
-    _p2vMap.clear();
-    _v2pMap.clear();
-    _v2ssMap.clear();
-
-//    computeIntervals();
-
-//     // liner scan algorithm
-//     for (Intervals::iterator li = _intervals.begin(), liEnd = _intervals.end();
-//          li != liEnd; ++li) {
-//         // FIXME: find a more efficient way to keep track of the
-//         // iterator on the current instruction
-//         MachineInstr* mi = _instrOrdering[li->start].first;
-//         _currentMbb = _instrOrdering[li->start].second;
-//         _currentInstr = find(_currentMbb->begin(), _currentMbb->end(), mi);
-//         assert(_currentInstr != _currentMbb->end() &&
-//                "Cannot find instruction in basic block");
-//         // check if this interval is for a physical or a virtual register
-//         if (li->mop->isVirtualRegister()) {
-//             expireOldIntervals(li);
-//             if (unsigned physReg = getFreeReg(li->mop->getAllocatedRegNum())) {
-//                 loadPhysReg(physReg, li->mop->getAllocatedRegNum());
-//             }
-//             else {
-//                 spillAtInterval(li);
-//             }
-//         }
-//         else {
-//             // spill register if it is used
-//             // mark register as used
-//         }
-//     }
+    mf_ = &fn;
+    tm_ = &fn.getTarget();
+    tri_ = &tm_->getRegInfo();
+    mri_ = tm_->getRegisterInfo();
+    li_ = &getAnalysis<LiveIntervals>().getIntervals();
+    active_.clear();
+    inactive_.clear();
+    mii2mbbMap_ = &getAnalysis<LiveIntervals>().getMiIndex2MbbMap();
+    mbb2miiMap_ = &getAnalysis<LiveIntervals>().getMbb2MiIndexMap();
+    p2vMap_.clear();
+    v2pMap_.clear();
+    v2ssMap_.clear();
+    instrAdded_ = 0;
+
+    // liner scan algorithm
+
+    for (Intervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i) {
+        unsigned curInstrIndex = i->start();
+        tie(currentMbb_, currentInstr_) = getMbbMbbIteratorPair(curInstrIndex);
+        assert(currentInstr_ >= currentMbb_->begin() &&
+               currentInstr_ < currentMbb_->end() &&
+               "current instruction/machine basic block mismatch");
+        processActiveIntervals(i);
+        processInactiveIntervals(i);
+
+        unsigned physReg = getFreeReg(i->reg);
+        if (!physReg) {
+            spillAtInterval(i);
+            physReg = getFreeReg(i->reg);
+        }
+        loadPhysReg(physReg, i->reg);
+        active_.push_back(&*i);
+    }
 
     return true;
 }
 
-/// computeIntervals - computes the live intervals for virtual
-/// registers. for some ordering of the machine instructions [1,N] a
-/// live interval is an interval [i, j] where 1 <= i <= j <= N for
-/// which a variable is live
-void RA::computeIntervals()
-{
-    DEBUG(std::cerr << "\tcomputing live intervals:\n");
-
-    // create a mapping from BasicBlock* to MachineBasicBlock*
-    typedef std::map<const BasicBlock*, MachineBasicBlock*> BB2MBBMap;
-    BB2MBBMap bb2mbbMap;
-    for (MachineFunction::iterator mbb = _mf->begin(), mbbEnd = _mf->end();
-         mbb != mbbEnd; ++mbb) {
-        bool inserted = bb2mbbMap.insert(
-            std::make_pair(mbb->getBasicBlock(), &*mbb)).second;
-        assert(inserted && "multiple BasicBlock -> MachineBasicBlock mappings");
+void RA::processActiveIntervals(Intervals::iterator cur)
+{
+    unsigned curInstrIndex = cur->start();
+    for (IntervalPtrs::iterator
+             i = active_.begin(), e = active_.end(); i != e;) {
+        unsigned virtReg = (*i)->reg;
+        // remove expired intervals
+        if ((*i)->expired(curInstrIndex)) {
+            freeReg(virtReg);
+            // remove interval from active
+            i = active_.erase(i);
+        }
+        else if (!(*i)->overlaps(curInstrIndex)) {
+            unmarkReg(virtReg);
+            // add interval to inactive
+            inactive_.push_back(*i);
+            // remove interval from active
+            i = active_.erase(i);
+        }
+        else {
+            ++i;
+        }
+    }
+}
+
+void RA::processInactiveIntervals(Intervals::iterator cur)
+{
+    unsigned curInstrIndex = cur->start();
+    for (IntervalPtrs::iterator
+             i = inactive_.begin(), e = inactive_.end(); i != e;) {
+        unsigned virtReg = (*i)->reg;
+        if ((*i)->expired(curInstrIndex)) {
+            freeReg(virtReg);
+            // remove from inactive
+            i = inactive_.erase(i);
+        }
+        else if ((*i)->overlaps(curInstrIndex)) {
+            markReg(virtReg);
+            // add to active
+            active_.push_back(*i);
+            // remove from inactive
+            i = inactive_.erase(i);
+        }
+        else {
+            ++i;
+        }
+    }
+}
+
+void RA::spillAtInterval(Intervals::iterator cur)
+{
+    assert(!active_.empty() &&
+           "active set cannot be empty when choosing a register to spill");
+    IntervalPtrs::iterator lastEnd = active_.begin();
+    for (IntervalPtrs::iterator i = lastEnd + 1, e = active_.end();
+         i != e; ++i) {
+        if ((*lastEnd)->end() < (*i)->end()) {
+            lastEnd = i;
+        }
+    }
+    bool inInactive = false;
+    for (IntervalPtrs::iterator i = inactive_.begin(), e = inactive_.end();
+         i != e; ++i) {
+        if ((*lastEnd)->end() < (*i)->end()) {
+            lastEnd = i;
+            inInactive = true;
+        }
     }
 
-    // depth first ordering for the instructions (use depth first
-    // ordering of BasicBlocks, map to MachineBasicBlocks and
-    // sequentially order the instructions in each block
-    const BasicBlock* entry = _mf->getFunction()->begin();
-
-    // register -> live interval index
-    typedef std::map<unsigned, unsigned> Reg2IntervalMap;
-    Reg2IntervalMap r2iMap;
-
-    unsigned index = 0;
-//     for (df_iterator<const BasicBlock*>
-//              bb = df_begin(entry), bbEnd = df_end(entry);
-//          bb != bbEnd; ++bb) {
-//         MachineBasicBlock* mbb = bb2mbbMap.find(*bb)->second;
-//         assert(mbb && "MachineBasicBlock for BasicBlock cannot be null");
-
-//         for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
-//              mi != miEnd; ++index, ++mi) {
-//             MachineInstr* instr = *mi;
-//             const TargetInstrDescriptor& tid =
-//                 _tm->getInstrInfo().get(instr->getOpcode());
-//             _i2iMap.insert(std::make_pair(instr, index));
-//             DEBUG(std::cerr << "\t\tinstruction[" << index << "]: " << *instr << '\n');
-//             for (const unsigned* id =tid.ImplicitDefs; *id; ++id) {
-//                 unsigned reg = *id;
-//                 assert(r2iMap.find(reg) == r2iMap.end() &&
-//                        "multiple definitions of virtual register");
-//                 // initialize intervals to [index, inf]
-//                 _intervals.push_back(
-//                     Interval(reg,
-//                              index,
-//                              std::numeric_limits<unsigned>::max()));
-//                 r2iMap.insert(std::make_pair(reg, _intervals.size() - 1));
-//                 DEBUG(std::cerr << "\t\t\tadded interval for register "
-//                       << _tri->getUnifiedRegName(reg)
-//                       << ": " << _intervals.back() << '\n');
-//             }
-
-//             for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
-//                 MachineOperand& mop = instr->getOperand(i);
-
-//                 if (!mop.isRegister())
-//                     continue;
-
-//                 // mark start and end points
-//                 if (mop.opIsDefOnly() || mop.opIsDefAndUse()) {
-//                     Intervals::iterator li;
-//                     unsigned reg = mop.getAllocatedRegNum();
-//                     assert(r2iMap.find(reg) == r2iMap.end() &&
-//                            "multiple definitions of virtual register");
-//                     // initialize intervals to [index, inf]
-//                     _intervals.push_back(
-//                         Interval(reg,
-//                                  index,
-//                                  std::numeric_limits<unsigned>::max()));
-//                     r2iMap.insert(std::make_pair(reg, _intervals.size() - 1));
-//                     DEBUG(std::cerr << "\t\t\tadded interval for register "
-//                           << _tri->getUnifiedRegName(reg)
-//                           << ": " << _intervals.back() << '\n');
-//                 }
-//             }
-
-//             for (LiveVariables::killed_iterator
-//                      ki = _lv->killed_begin(instr),
-//                      kiEnd = _lv->killed_end(instr);
-//                  ki != kiEnd; ++ki) {
-//                 unsigned reg = ki->second;
-//                 DEBUG(std::cerr << "\t\t\tmarking end of interval for register " << _tri->getUnifiedRegName(reg) << '\n');
-//                 Reg2IntervalMap::iterator ri = r2iMap.find(reg);
-//                 assert(ri != r2iMap.end()
-//                        && "did not find interval for killed register");
-//                 Interval& interval = _intervals[ri->second];
-//                 assert(interval.end > index
-//                        && "attempt to mark killed an already killed variable");
-//                 interval.end = index;
-//             }
-//         }
-
-//         // kill all physical registers in the end of each basic block
-//         for (Intervals::iterator it =
-//                  _intervals.begin(), itEnd = _intervals.end();
-//              it != itEnd; ++it) {
-//             if (it->reg < MRegisterInfo::FirstVirtualRegister) {
-//                 Reg2IntervalMap::iterator ri = r2iMap.find(it->reg);
-//                 assert(ri != r2iMap.end()
-//                        && "did not find interval for killed register");
-//                 Interval& interval = _intervals[ri->second];
-//                 assert(interval.end > index
-//                        && "attempt to mark killed an already killed variable");
-//                 interval.end = index;
-//             }
-//         }
-//     }
-
-//     // sort the live intervals in increasing start point
-//     sort(_intervals.begin(), _intervals.end(), StartPointComp());
-
-//     DEBUG(
-//         for(Intervals::iterator
-//                 it = _intervals.begin(), itEnd = _intervals.end();
-//             it != itEnd; ++it) {
-//             std::cerr << *it << '\n';
-//         });
-}
-
-//// expireOldIntervals - expire the old intervals
-////
-// void RA::expireOldIntervals(Intervals::iterator li)
-// {
-//     // the active list is sorted on increasing end point
-//     IntervalPtrs::iterator lip = _active.begin();
-//     for (IntervalPtrs::iterator lipEnd = _active.end();
-//          lip != lipEnd && (*lip)->end < li->start;
-//          ++lip) {
-//         unsigned reg = li->reg;
-//         // if it is a virtual register
-//         if (reg >= MRegisterInfo::FirstVirtualRegister) {
-//             Virt2PhysMap::iterator it = _v2pMap.find(reg);
-//             assert(it != _v2pMap.end());
-//             reg = it->second;
-//             _v2pMap.erase(it);
-//         }
-//         assert(_p2vMap[reg] != 0);
-//         _p2vMap[reg] = 0;
-//     }
-//     _active.erase(_active.begin(), lip);
-// }
-
-//// spillAtInterval - chooses and spills a register for this
-//// interval. The heuristic here is the register with the last end
-//// point thus it can be either the last of the active list or the
-//// current one
-////
-// void RA::spillAtInterval(Intervals::iterator li)
-// {
-//     assert(!_active.empty() && "active set cannot be empty when choosing a register to spill");
-//     Interval* toSpill = _active.back();
-//     // if last in active is ending after the current spill it and add
-//     // current to active
-//     if (toSpill->end > li->end) {
-//         // spill register toSpill->mop->getAllocatedRegNum();
-//         _active.pop_back();
-//         for(IntervalPtrs::iterator it = _active.begin(), itEnd = _active.end();
-//             it != itEnd; ++it) {
-//             if ((*it)->end > li->end) {
-//                 _active.insert(it, &*li);
-//             }
-//         }
-//     }
-//     // spill the current
-//     else {
-//         // spill register li->mop->getAllocatedRegNum()
-//     }
-// }
+    // spill last in active and inactive
+    spillVirtReg((*lastEnd)->reg);
+    freeReg((*lastEnd)->reg);
+}
 
 bool RA::physRegAvailable(unsigned physReg)
 {
-    if (_p2vMap[physReg]) {
+    if (p2vMap_[physReg]) {
         return false;
     }
 
     // if it aliases other registers it is still not free
-    for (const unsigned* as = _mri->getAliasSet(physReg); *as; ++as) {
-        if (_p2vMap[*as]) {
+    for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) {
+        if (p2vMap_[*as]) {
             return false;
         }
     }
@@ -340,9 +267,9 @@
 
 unsigned RA::getFreeReg(unsigned virtReg)
 {
-    const TargetRegisterClass* rc = _mf->getSSARegMap()->getRegClass(virtReg);
-    TargetRegisterClass::iterator reg = rc->allocation_order_begin(*_mf);
-    TargetRegisterClass::iterator regEnd = rc->allocation_order_end(*_mf);
+    const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
+    TargetRegisterClass::iterator reg = rc->allocation_order_begin(*mf_);
+    TargetRegisterClass::iterator regEnd = rc->allocation_order_end(*mf_);
 
     for (; reg != regEnd; ++reg) {
         if (physRegAvailable(*reg)) {
@@ -354,39 +281,72 @@
     return 0;
 }
 
+void RA::freeReg(unsigned virtReg)
+{
+    unmarkReg(virtReg);
+    v2pMap_.erase(v2pMap_.find(virtReg));
+}
+
+void RA::markReg(unsigned virtReg)
+{
+    Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
+    assert(it != v2pMap_.end() &&
+           "attempting to mark an already disassociated register");
+    unsigned physReg = it->second;
+    p2vMap_[physReg] = virtReg;
+}
+
+void RA::unmarkReg(unsigned virtReg)
+{
+    Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
+    assert(it != v2pMap_.end() &&
+           "attempting to mark an already disassociated register");
+    unsigned physReg = it->second;
+    p2vMap_[physReg] = 0;
+}
+
 int RA::findOrCreateStackSlot(unsigned virtReg)
 {
     // use lower_bound so that we can do a O(1) insert later if necessary
-    Virt2StackSlotMap::iterator it = _v2ssMap.lower_bound(virtReg);
-    if (it != _v2ssMap.end() && it->first == virtReg) {
+    Virt2StackSlotMap::iterator it = v2ssMap_.lower_bound(virtReg);
+    if (it != v2ssMap_.end() && it->first == virtReg) {
         return it->second;
     }
-    const TargetRegisterClass* rc = _mf->getSSARegMap()->getRegClass(virtReg);
-    int frameIndex = _mf->getFrameInfo()->CreateStackObject(rc);
+    const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
+    int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc);
 
-    _v2ssMap.insert(it, std::make_pair(virtReg, frameIndex));
+    v2ssMap_.insert(it, std::make_pair(virtReg, frameIndex));
 
     return frameIndex;
 }
 
-void RA::spillVirtReg(unsigned virtReg, unsigned physReg)
+void RA::spillVirtReg(unsigned virtReg)
 {
-    const TargetRegisterClass* rc = _mf->getSSARegMap()->getRegClass(virtReg);
+    const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
     int frameIndex = findOrCreateStackSlot(virtReg);
     ++numSpilled;
-    _mri->storeRegToStackSlot(*_currentMbb, _currentInstr,
-                              physReg, frameIndex, rc);
+    instrAdded_ += mri_->storeRegToStackSlot(*currentMbb_, currentInstr_,
+                                             v2pMap_[virtReg], frameIndex, rc);
 }
 
 void RA::loadPhysReg(unsigned physReg, unsigned virtReg)
 {
-    const TargetRegisterClass* rc = _mf->getSSARegMap()->getRegClass(virtReg);
+    const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
     int frameIndex = findOrCreateStackSlot(virtReg);
     ++numReloaded;
-    _mri->loadRegFromStackSlot(*_currentMbb, _currentInstr,
-                               physReg, frameIndex, rc);
-    _v2pMap[virtReg] = physReg;
-    _p2vMap[physReg] = virtReg;
+    instrAdded_ += mri_->loadRegFromStackSlot(*currentMbb_, currentInstr_,
+                                              physReg, frameIndex, rc);
+    v2pMap_[virtReg] = physReg;
+    p2vMap_[physReg] = virtReg;
+}
+
+std::pair<MachineBasicBlock*, MachineBasicBlock::iterator>
+RA::getMbbMbbIteratorPair(unsigned miIndex) const
+{
+    MachineBasicBlock* mbb = (*mii2mbbMap_)[miIndex];
+    MachineBasicBlock::iterator instr =
+        mbb->begin() + instrAdded_ + miIndex - (*mbb2miiMap_)[mbb];
+    return std::make_pair(mbb, instr);
 }
 
 FunctionPass *createLinearScanRegisterAllocator() {





More information about the llvm-commits mailing list