llvm-6502/lib/CodeGen/RegAllocLinearScan.cpp
Alkis Evlogimenos 7d629b50a5 Add a separate list of fixed intervals. This improves the running time
of the register allocator as follows:

       before   after
mesa   2.3790  1.5994
vpr    2.6008  1.2078
gcc    1.9840  0.5273
mcf    0.2569  0.0470
eon    1.8468  1.4359
twolf  0.9475  0.2004
burg   1.6807  1.3300
lambda 1.2191  0.3764

Speedups range anyware from 30% to over 400% :-)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10712 91177308-0d34-0410-b5e6-96231b3b80d8
2004-01-07 09:20:58 +00:00

771 lines
28 KiB
C++

//===-- 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.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "regalloc"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h"
using namespace llvm;
namespace {
Statistic<> numSpilled ("ra-linearscan", "Number of registers spilled");
Statistic<> numReloaded("ra-linearscan", "Number of registers reloaded");
class RA : public MachineFunctionPass {
private:
MachineFunction* mf_;
const TargetMachine* tm_;
const MRegisterInfo* mri_;
MachineFunction::iterator currentMbb_;
MachineBasicBlock::iterator currentInstr_;
typedef std::vector<const LiveIntervals::Interval*> IntervalPtrs;
IntervalPtrs unhandled_, fixed_, active_, inactive_;
typedef std::vector<unsigned> Regs;
Regs tempUseOperands_;
Regs tempDefOperands_;
typedef std::vector<bool> RegMask;
RegMask reserved_;
unsigned regUse_[MRegisterInfo::FirstVirtualRegister];
unsigned regUseBackup_[MRegisterInfo::FirstVirtualRegister];
typedef std::map<unsigned, unsigned> Virt2PhysMap;
Virt2PhysMap v2pMap_;
typedef std::map<unsigned, int> Virt2StackSlotMap;
Virt2StackSlotMap v2ssMap_;
int instrAdded_;
public:
virtual const char* getPassName() const {
return "Linear Scan Register Allocator";
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LiveVariables>();
AU.addRequired<LiveIntervals>();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
/// runOnMachineFunction - register allocate the whole function
bool runOnMachineFunction(MachineFunction&);
/// initIntervalSets - initializa the four interval sets:
/// unhandled, fixed, active and inactive
void initIntervalSets(const LiveIntervals::Intervals& li);
/// processActiveIntervals - expire old intervals and move
/// non-overlapping ones to the incative list
void processActiveIntervals(IntervalPtrs::value_type cur);
/// processInactiveIntervals - expire old intervals and move
/// overlapping ones to the active list
void processInactiveIntervals(IntervalPtrs::value_type cur);
/// assignStackSlotAtInterval - choose and spill
/// interval. Currently we spill the interval with the last
/// end point in the active and inactive lists and the current
/// interval
void assignStackSlotAtInterval(IntervalPtrs::value_type cur);
///
/// register handling helpers
///
/// getFreePhysReg - return a free physical register for this
/// virtual register interval if we have one, otherwise return
/// 0
unsigned getFreePhysReg(IntervalPtrs::value_type cur);
/// physRegAvailable - returns true if the specifed physical
/// register is available
bool physRegAvailable(unsigned physReg);
/// tempPhysRegAvailable - returns true if the specifed
/// temporary physical register is available
bool tempPhysRegAvailable(unsigned physReg);
/// getFreeTempPhysReg - return a free temprorary physical
/// register for this virtual register if we have one (should
/// never return 0)
unsigned getFreeTempPhysReg(unsigned virtReg);
/// assignVirt2PhysReg - assigns the free physical register to
/// the virtual register passed as arguments
void assignVirt2PhysReg(unsigned virtReg, unsigned physReg);
/// clearVirtReg - free the physical register associated with this
/// virtual register and disassociate virtual->physical and
/// physical->virtual mappings
void clearVirtReg(unsigned virtReg);
/// assignVirt2StackSlot - assigns this virtual register to a
/// stack slot
void assignVirt2StackSlot(unsigned virtReg);
/// getStackSlot - returns the offset of the specified
/// register on the stack
int getStackSlot(unsigned virtReg);
/// spillVirtReg - spills the virtual register
void spillVirtReg(unsigned virtReg);
/// loadPhysReg - loads to the physical register the value of
/// the virtual register specifed. Virtual register must have
/// an assigned stack slot
void loadVirt2PhysReg(unsigned virtReg, unsigned physReg);
void markPhysRegFree(unsigned physReg);
void markPhysRegNotFree(unsigned physReg);
void backupRegUse() {
memcpy(regUseBackup_, regUse_, sizeof(regUseBackup_));
}
void restoreRegUse() {
memcpy(regUse_, regUseBackup_, sizeof(regUseBackup_));
}
void printVirt2PhysMap() const {
std::cerr << "allocated registers:\n";
for (Virt2PhysMap::const_iterator
i = v2pMap_.begin(), e = v2pMap_.end(); i != e; ++i) {
std::cerr << '[' << i->first << ','
<< mri_->getName(i->second) << "]\n";
}
std::cerr << '\n';
}
void printIntervals(const char* const str,
RA::IntervalPtrs::const_iterator i,
RA::IntervalPtrs::const_iterator e) const {
if (str) std::cerr << str << " intervals:\n";
for (; i != e; ++i) {
std::cerr << "\t\t" << **i << " -> ";
if ((*i)->reg < MRegisterInfo::FirstVirtualRegister) {
std::cerr << mri_->getName((*i)->reg);
}
else {
std::cerr << mri_->getName(v2pMap_.find((*i)->reg)->second);
}
std::cerr << '\n';
}
}
void printFreeRegs(const char* const str,
const TargetRegisterClass* rc) const {
if (str) std::cerr << str << ':';
for (TargetRegisterClass::iterator i =
rc->allocation_order_begin(*mf_);
i != rc->allocation_order_end(*mf_); ++i) {
unsigned reg = *i;
if (!regUse_[reg]) {
std::cerr << ' ' << mri_->getName(reg);
if (reserved_[reg]) std::cerr << "*";
}
}
std::cerr << '\n';
}
};
}
bool RA::runOnMachineFunction(MachineFunction &fn) {
mf_ = &fn;
tm_ = &fn.getTarget();
mri_ = tm_->getRegisterInfo();
initIntervalSets(getAnalysis<LiveIntervals>().getIntervals());
v2pMap_.clear();
v2ssMap_.clear();
memset(regUse_, 0, sizeof(regUse_));
memset(regUseBackup_, 0, sizeof(regUseBackup_));
// FIXME: this will work only for the X86 backend. I need to
// device an algorthm to select the minimal (considering register
// aliasing) number of temp registers to reserve so that we have 2
// registers for each register class available.
// reserve R8: CH, CL
// R16: CX, DI,
// R32: ECX, EDI,
// RFP: FP5, FP6
reserved_.assign(MRegisterInfo::FirstVirtualRegister, false);
reserved_[ 8] = true; /* CH */
reserved_[ 9] = true; /* CL */
reserved_[10] = true; /* CX */
reserved_[12] = true; /* DI */
reserved_[18] = true; /* ECX */
reserved_[19] = true; /* EDI */
reserved_[28] = true; /* FP5 */
reserved_[29] = true; /* FP6 */
// linear scan algorithm
DEBUG(printIntervals("\tunhandled", unhandled_.begin(), unhandled_.end()));
DEBUG(printIntervals("\tfixed", fixed_.begin(), fixed_.end()));
DEBUG(printIntervals("\tactive", active_.begin(), active_.end()));
DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end()));
while (!unhandled_.empty() || !fixed_.empty()) {
// pick the interval with the earliest start point
IntervalPtrs::value_type cur;
if (fixed_.empty()) {
cur = unhandled_.front();
unhandled_.erase(unhandled_.begin());
}
else if (unhandled_.empty()) {
cur = fixed_.front();
fixed_.erase(fixed_.begin());
}
else if (unhandled_.front()->start() < fixed_.front()->start()) {
cur = unhandled_.front();
unhandled_.erase(unhandled_.begin());
}
else {
cur = fixed_.front();
fixed_.erase(fixed_.begin());
}
DEBUG(std::cerr << "processing current interval: " << *cur << '\n');
processActiveIntervals(cur);
processInactiveIntervals(cur);
// if this register is fixed we are done
if (cur->reg < MRegisterInfo::FirstVirtualRegister) {
markPhysRegNotFree(cur->reg);
active_.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 {
backupRegUse();
// for every interval in inactive we overlap with, mark the
// register as not free
for (IntervalPtrs::const_iterator i = inactive_.begin(),
e = inactive_.end(); i != e; ++i) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister)
reg = v2pMap_[reg];
if (cur->overlaps(**i)) {
markPhysRegNotFree(reg);
}
}
// for every interval in fixed we overlap with,
// mark the register as not free
for (IntervalPtrs::const_iterator i = fixed_.begin(),
e = fixed_.end(); i != e; ++i) {
assert((*i)->reg < MRegisterInfo::FirstVirtualRegister &&
"virtual register interval in fixed set?");
if (cur->overlaps(**i))
markPhysRegNotFree((*i)->reg);
}
DEBUG(std::cerr << "\tallocating current interval:\n");
unsigned physReg = getFreePhysReg(cur);
if (!physReg) {
assignStackSlotAtInterval(cur);
}
else {
restoreRegUse();
assignVirt2PhysReg(cur->reg, physReg);
active_.push_back(cur);
}
}
DEBUG(printIntervals("\tactive", active_.begin(), active_.end()));
DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end())); }
// expire any remaining active intervals
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) {
unsigned reg = (*i)->reg;
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
markPhysRegFree(reg);
}
active_.clear();
inactive_.clear();
DEBUG(std::cerr << "finished register allocation\n");
DEBUG(printVirt2PhysMap());
DEBUG(std::cerr << "Rewrite machine code:\n");
for (currentMbb_ = mf_->begin(); currentMbb_ != mf_->end(); ++currentMbb_) {
instrAdded_ = 0;
for (currentInstr_ = currentMbb_->begin();
currentInstr_ != currentMbb_->end(); ++currentInstr_) {
DEBUG(std::cerr << "\tinstruction: ";
(*currentInstr_)->print(std::cerr, *tm_););
// use our current mapping and actually replace and
// virtual register with its allocated physical registers
DEBUG(std::cerr << "\t\treplacing virtual registers with mapped "
"physical registers:\n");
for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
i != e; ++i) {
MachineOperand& op = (*currentInstr_)->getOperand(i);
if (op.isVirtualRegister()) {
unsigned virtReg = op.getAllocatedRegNum();
unsigned physReg = v2pMap_[virtReg];
if (physReg) {
DEBUG(std::cerr << "\t\t\t%reg" << virtReg
<< " -> " << mri_->getName(physReg) << '\n');
(*currentInstr_)->SetMachineOperandReg(i, physReg);
}
}
}
DEBUG(std::cerr << "\t\tloading temporarily used operands to "
"registers:\n");
for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
i != e; ++i) {
MachineOperand& op = (*currentInstr_)->getOperand(i);
if (op.isVirtualRegister() && op.isUse() && !op.isDef()) {
unsigned virtReg = op.getAllocatedRegNum();
unsigned physReg = v2pMap_[virtReg];
if (!physReg) {
physReg = getFreeTempPhysReg(virtReg);
loadVirt2PhysReg(virtReg, physReg);
tempUseOperands_.push_back(virtReg);
}
(*currentInstr_)->SetMachineOperandReg(i, physReg);
}
}
DEBUG(std::cerr << "\t\tclearing temporarily used operands:\n");
for (unsigned i = 0, e = tempUseOperands_.size(); i != e; ++i) {
clearVirtReg(tempUseOperands_[i]);
}
tempUseOperands_.clear();
DEBUG(std::cerr << "\t\tassigning temporarily defined operands to "
"registers:\n");
for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
i != e; ++i) {
MachineOperand& op = (*currentInstr_)->getOperand(i);
if (op.isVirtualRegister() && op.isDef()) {
unsigned virtReg = op.getAllocatedRegNum();
unsigned physReg = v2pMap_[virtReg];
if (!physReg) {
physReg = getFreeTempPhysReg(virtReg);
}
if (op.isUse()) { // def and use
loadVirt2PhysReg(virtReg, physReg);
}
else {
assignVirt2PhysReg(virtReg, physReg);
}
tempDefOperands_.push_back(virtReg);
(*currentInstr_)->SetMachineOperandReg(i, physReg);
}
}
DEBUG(std::cerr << "\t\tspilling temporarily defined operands "
"of this instruction:\n");
++currentInstr_; // we want to insert after this instruction
for (unsigned i = 0, e = tempDefOperands_.size(); i != e; ++i) {
spillVirtReg(tempDefOperands_[i]);
}
--currentInstr_; // restore currentInstr_ iterator
tempDefOperands_.clear();
}
}
return true;
}
void RA::initIntervalSets(const LiveIntervals::Intervals& li)
{
assert(unhandled_.empty() && fixed_.empty() &&
active_.empty() && inactive_.empty() &&
"interval sets should be empty on initialization");
for (LiveIntervals::Intervals::const_iterator i = li.begin(), e = li.end();
i != e; ++i) {
if (i->reg < MRegisterInfo::FirstVirtualRegister)
fixed_.push_back(&*i);
else
unhandled_.push_back(&*i);
}
}
void RA::processActiveIntervals(IntervalPtrs::value_type cur)
{
DEBUG(std::cerr << "\tprocessing active intervals:\n");
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end();) {
unsigned reg = (*i)->reg;
// remove expired intervals. we expire earlier because this if
// an interval expires this is going to be the last use. in
// this case we can reuse the register for a def in the same
// instruction
if ((*i)->expiredAt(cur->start() + 1)) {
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
markPhysRegFree(reg);
// remove from active
i = active_.erase(i);
}
// move inactive intervals to inactive list
else if (!(*i)->liveAt(cur->start())) {
DEBUG(std::cerr << "\t\t\tinterval " << **i << " inactive\n");
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
markPhysRegFree(reg);
// add to inactive
inactive_.push_back(*i);
// remove from active
i = active_.erase(i);
}
else {
++i;
}
}
}
void RA::processInactiveIntervals(IntervalPtrs::value_type cur)
{
DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();) {
unsigned reg = (*i)->reg;
// remove expired intervals. we expire earlier because this if
// an interval expires this is going to be the last use. in
// this case we can reuse the register for a def in the same
// instruction
if ((*i)->expiredAt(cur->start() + 1)) {
DEBUG(std::cerr << "\t\t\tinterval " << **i << " expired\n");
// remove from inactive
i = inactive_.erase(i);
}
// move re-activated intervals in active list
else if ((*i)->liveAt(cur->start())) {
DEBUG(std::cerr << "\t\t\tinterval " << **i << " active\n");
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
markPhysRegNotFree(reg);
// add to active
active_.push_back(*i);
// remove from inactive
i = inactive_.erase(i);
}
else {
++i;
}
}
}
namespace {
template <typename T>
void updateWeight(T rw[], int reg, T w)
{
if (rw[reg] == std::numeric_limits<T>::max() ||
w == std::numeric_limits<T>::max())
rw[reg] = std::numeric_limits<T>::max();
else
rw[reg] += w;
}
}
void RA::assignStackSlotAtInterval(IntervalPtrs::value_type cur)
{
DEBUG(std::cerr << "\t\tassigning stack slot at interval "
<< *cur << ":\n");
// set all weights to zero
float regWeight[MRegisterInfo::FirstVirtualRegister];
for (unsigned i = 0; i < MRegisterInfo::FirstVirtualRegister; ++i)
regWeight[i] = 0.0F;
// for each interval in active that overlaps
for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
i != e; ++i) {
if (!cur->overlaps(**i))
continue;
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
updateWeight(regWeight, reg, (*i)->weight);
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
updateWeight(regWeight, *as, (*i)->weight);
}
// for each interval in inactive that overlaps
for (IntervalPtrs::const_iterator i = inactive_.begin(),
e = inactive_.end(); i != e; ++i) {
if (!cur->overlaps(**i))
continue;
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
}
updateWeight(regWeight, reg, (*i)->weight);
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
updateWeight(regWeight, *as, (*i)->weight);
}
// for each fixed interval that overlaps
for (IntervalPtrs::const_iterator i = fixed_.begin(), e = fixed_.end();
i != e; ++i) {
assert((*i)->reg < MRegisterInfo::FirstVirtualRegister &&
"virtual register interval in fixed set?");
updateWeight(regWeight, (*i)->reg, (*i)->weight);
for (const unsigned* as = mri_->getAliasSet((*i)->reg); *as; ++as)
updateWeight(regWeight, *as, (*i)->weight);
}
float minWeight = std::numeric_limits<float>::max();
unsigned minReg = 0;
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->reg);
for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_);
i != rc->allocation_order_end(*mf_); ++i) {
unsigned reg = *i;
if (!reserved_[reg] && minWeight > regWeight[reg]) {
minWeight = regWeight[reg];
minReg = reg;
}
}
if (cur->weight < minWeight) {
restoreRegUse();
DEBUG(std::cerr << "\t\t\t\tspilling : " << *cur << '\n');
assignVirt2StackSlot(cur->reg);
}
else {
std::set<unsigned> toSpill;
toSpill.insert(minReg);
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
toSpill.insert(*as);
std::vector<unsigned> spilled;
for (IntervalPtrs::iterator i = active_.begin();
i != active_.end(); ) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister &&
toSpill.find(v2pMap_[reg]) != toSpill.end() &&
cur->overlaps(**i)) {
spilled.push_back(v2pMap_[reg]);
DEBUG(std::cerr << "\t\t\t\tspilling : " << **i << '\n');
assignVirt2StackSlot(reg);
i = active_.erase(i);
}
else {
++i;
}
}
for (IntervalPtrs::iterator i = inactive_.begin();
i != inactive_.end(); ) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister &&
toSpill.find(v2pMap_[reg]) != toSpill.end() &&
cur->overlaps(**i)) {
DEBUG(std::cerr << "\t\t\t\tspilling : " << **i << '\n');
assignVirt2StackSlot(reg);
i = inactive_.erase(i);
}
else {
++i;
}
}
unsigned physReg = getFreePhysReg(cur);
assert(physReg && "no free physical register after spill?");
restoreRegUse();
for (unsigned i = 0; i < spilled.size(); ++i)
markPhysRegFree(spilled[i]);
assignVirt2PhysReg(cur->reg, physReg);
active_.push_back(cur);
}
}
bool RA::physRegAvailable(unsigned physReg)
{
assert(!reserved_[physReg] &&
"cannot call this method with a reserved register");
return !regUse_[physReg];
}
unsigned RA::getFreePhysReg(IntervalPtrs::value_type cur)
{
DEBUG(std::cerr << "\t\tgetting free physical register: ");
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->reg);
for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_);
i != rc->allocation_order_end(*mf_); ++i) {
unsigned reg = *i;
if (!reserved_[reg] && !regUse_[reg]) {
DEBUG(std::cerr << mri_->getName(reg) << '\n');
return reg;
}
}
DEBUG(std::cerr << "no free register\n");
return 0;
}
bool RA::tempPhysRegAvailable(unsigned physReg)
{
assert(reserved_[physReg] &&
"cannot call this method with a not reserved temp register");
return !regUse_[physReg];
}
unsigned RA::getFreeTempPhysReg(unsigned virtReg)
{
DEBUG(std::cerr << "\t\tgetting free temporary physical register: ");
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
// go in reverse allocation order for the temp registers
for (TargetRegisterClass::iterator i = rc->allocation_order_end(*mf_) - 1;
i != rc->allocation_order_begin(*mf_) - 1; --i) {
unsigned reg = *i;
if (reserved_[reg] && !regUse_[reg]) {
DEBUG(std::cerr << mri_->getName(reg) << '\n');
return reg;
}
}
assert(0 && "no free temporary physical register?");
return 0;
}
void RA::assignVirt2PhysReg(unsigned virtReg, unsigned physReg)
{
v2pMap_[virtReg] = physReg;
markPhysRegNotFree(physReg);
}
void RA::clearVirtReg(unsigned virtReg)
{
Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
assert(it != v2pMap_.end() &&
"attempting to clear a not allocated virtual register");
unsigned physReg = it->second;
markPhysRegFree(physReg);
v2pMap_[virtReg] = 0; // this marks that this virtual register
// lives on the stack
DEBUG(std::cerr << "\t\t\tcleared register " << mri_->getName(physReg)
<< "\n");
}
void RA::assignVirt2StackSlot(unsigned virtReg)
{
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc);
bool inserted = v2ssMap_.insert(std::make_pair(virtReg, frameIndex)).second;
assert(inserted &&
"attempt to assign stack slot to already assigned register?");
// if the virtual register was previously assigned clear the mapping
// and free the virtual register
if (v2pMap_.find(virtReg) != v2pMap_.end()) {
clearVirtReg(virtReg);
}
else {
v2pMap_[virtReg] = 0; // this marks that this virtual register
// lives on the stack
}
}
int RA::getStackSlot(unsigned virtReg)
{
// use lower_bound so that we can do a possibly O(1) insert later
// if necessary
Virt2StackSlotMap::iterator it = v2ssMap_.find(virtReg);
assert(it != v2ssMap_.end() &&
"attempt to get stack slot on register that does not live on the stack");
return it->second;
}
void RA::spillVirtReg(unsigned virtReg)
{
DEBUG(std::cerr << "\t\t\tspilling register: " << virtReg);
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
int frameIndex = getStackSlot(virtReg);
DEBUG(std::cerr << " to stack slot #" << frameIndex << '\n');
++numSpilled;
instrAdded_ += mri_->storeRegToStackSlot(*currentMbb_, currentInstr_,
v2pMap_[virtReg], frameIndex, rc);
clearVirtReg(virtReg);
}
void RA::loadVirt2PhysReg(unsigned virtReg, unsigned physReg)
{
DEBUG(std::cerr << "\t\t\tloading register: " << virtReg);
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
int frameIndex = getStackSlot(virtReg);
DEBUG(std::cerr << " from stack slot #" << frameIndex << '\n');
++numReloaded;
instrAdded_ += mri_->loadRegFromStackSlot(*currentMbb_, currentInstr_,
physReg, frameIndex, rc);
assignVirt2PhysReg(virtReg, physReg);
}
void RA::markPhysRegFree(unsigned physReg)
{
assert(regUse_[physReg] != 0);
--regUse_[physReg];
for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) {
physReg = *as;
assert(regUse_[physReg] != 0);
--regUse_[physReg];
}
}
void RA::markPhysRegNotFree(unsigned physReg)
{
++regUse_[physReg];
for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) {
physReg = *as;
++regUse_[physReg];
}
}
FunctionPass* llvm::createLinearScanRegisterAllocator() {
return new RA();
}