[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