Newer
Older
Alkis Evlogimenos
committed
//===-- 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");
Alkis Evlogimenos
committed
class RA : public MachineFunctionPass {
public:
typedef std::vector<const LiveIntervals::Interval*> IntervalPtrs;
private:
MachineFunction* mf_;
const TargetMachine* tm_;
const MRegisterInfo* mri_;
MachineBasicBlock* currentMbb_;
MachineBasicBlock::iterator currentInstr_;
typedef LiveIntervals::Intervals Intervals;
const Intervals* li_;
IntervalPtrs active_, inactive_;
typedef std::vector<unsigned> Regs;
Regs tempUseOperands_;
Regs tempDefOperands_;
typedef std::vector<bool> RegMask;
RegMask reserved_;
unsigned regUse_[MRegisterInfo::FirstVirtualRegister];
Alkis Evlogimenos
committed
typedef LiveIntervals::MachineBasicBlockPtrs MachineBasicBlockPtrs;
MachineBasicBlockPtrs mbbs_;
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&);
/// verifyIntervals - verify that we have no inconsistencies
/// in the register assignments we have in active and inactive
/// lists
bool verifyIntervals();
Alkis Evlogimenos
committed
/// processActiveIntervals - expire old intervals and move
/// non-overlapping ones to the incative list
void processActiveIntervals(Intervals::const_iterator cur);
/// processInactiveIntervals - expire old intervals and move
/// overlapping ones to the active list
void processInactiveIntervals(Intervals::const_iterator 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(Intervals::const_iterator cur);
///
/// register handling helpers
///
/// reservePhysReg - reserves a physical register and spills
/// any value assigned to it if any
void reservePhysReg(unsigned reg);
/// clearReservedPhysReg - marks pysical register as free for
/// use
void clearReservedPhysReg(unsigned reg);
/// getFreePhysReg - return a free physical register for this
/// virtual register interval if we have one, otherwise return
/// 0
unsigned getFreePhysReg(Intervals::const_iterator cur);
Alkis Evlogimenos
committed
/// 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);
Alkis Evlogimenos
committed
/// 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);
Alkis Evlogimenos
committed
/// 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);
Alkis Evlogimenos
committed
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';
}
Alkis Evlogimenos
committed
};
}
bool RA::runOnMachineFunction(MachineFunction &fn) {
mf_ = &fn;
tm_ = &fn.getTarget();
mri_ = tm_->getRegisterInfo();
li_ = &getAnalysis<LiveIntervals>().getIntervals();
active_.clear();
inactive_.clear();
Alkis Evlogimenos
committed
mbbs_ = getAnalysis<LiveIntervals>().getOrderedMachineBasicBlockPtrs();
v2pMap_.clear();
v2ssMap_.clear();
memset(regUse_, 0, sizeof(regUse_));
Alkis Evlogimenos
committed
DEBUG(
for (MachineBasicBlockPtrs::iterator
mbbi = mbbs_.begin(), mbbe = mbbs_.end();
mbbi != mbbe; ++mbbi) {
MachineBasicBlock* mbb = *mbbi;
std::cerr << mbb->getBasicBlock()->getName() << '\n';
for (MachineBasicBlock::iterator
ii = mbb->begin(), ie = mbb->end();
ii != ie; ++ii) {
MachineInstr* instr = *ii;
std::cerr << i++ << "\t";
instr->print(std::cerr, *tm_);
}
}
);
Alkis Evlogimenos
committed
// 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 R32: EDI, EBX,
// R16: DI, BX,
// R8: BH, BL
Alkis Evlogimenos
committed
// RFP: FP5, FP6
reserved_.assign(MRegisterInfo::FirstVirtualRegister, false);
reserved_[19] = true; /* EDI */
reserved_[17] = true; /* EBX */
reserved_[12] = true; /* DI */
reserved_[ 7] = true; /* BX */
reserved_[ 4] = true; /* BH */
reserved_[ 5] = true; /* BL */
reserved_[28] = true; /* FP5 */
reserved_[29] = true; /* FP6 */
Alkis Evlogimenos
committed
// liner scan algorithm
for (Intervals::const_iterator
i = li_->begin(), e = li_->end(); i != e; ++i) {
DEBUG(std::cerr << "processing current interval: " << *i << '\n');
DEBUG(printIntervals("\tactive", active_.begin(), active_.end()));
DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end()));
for (MRegisterInfo::regclass_iterator c = mri_->regclass_begin();
c != mri_->regclass_end(); ++c) {
const TargetRegisterClass* rc = *c;
DEBUG(printFreeRegs("\tfree registers", rc));
}
//assert(verifyIntervals());
Alkis Evlogimenos
committed
processActiveIntervals(i);
processInactiveIntervals(i);
DEBUG(std::cerr << "\tallocating current interval:\n");
// if this register is preallocated reserve it
Alkis Evlogimenos
committed
if (i->reg < MRegisterInfo::FirstVirtualRegister) {
reservePhysReg(i->reg);
active_.push_back(&*i);
}
// 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 {
unsigned physReg = getFreePhysReg(i);
Alkis Evlogimenos
committed
if (!physReg) {
assignStackSlotAtInterval(i);
}
else {
assignVirt2PhysReg(i->reg, physReg);
active_.push_back(&*i);
}
}
}
// 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) {
markPhysRegFree(reg);
}
else {
markPhysRegFree(v2pMap_[reg]);
}
}
// expire any remaining inactive intervals
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();
++i) {
unsigned reg = (*i)->reg;
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
if (reg < MRegisterInfo::FirstVirtualRegister) {
markPhysRegFree(reg);
}
else {
markPhysRegFree(v2pMap_[reg]);
}
}
Alkis Evlogimenos
committed
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
DEBUG(std::cerr << "finished register allocation\n");
DEBUG(printVirt2PhysMap());
DEBUG(std::cerr << "Rewrite machine code:\n");
for (MachineBasicBlockPtrs::iterator
mbbi = mbbs_.begin(), mbbe = mbbs_.end(); mbbi != mbbe; ++mbbi) {
instrAdded_ = 0;
currentMbb_ = *mbbi;
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()) {
Alkis Evlogimenos
committed
unsigned virtReg = op.getAllocatedRegNum();
unsigned physReg = v2pMap_[virtReg];
if (!physReg) {
physReg = getFreeTempPhysReg(virtReg);
loadVirt2PhysReg(virtReg, physReg);
tempUseOperands_.push_back(virtReg);
Alkis Evlogimenos
committed
}
(*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()) {
Alkis Evlogimenos
committed
unsigned virtReg = op.getAllocatedRegNum();
unsigned physReg = v2pMap_[virtReg];
if (!physReg) {
physReg = getFreeTempPhysReg(virtReg);
}
if (op.isUse()) { // def and use
Alkis Evlogimenos
committed
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();
Alkis Evlogimenos
committed
}
}
return true;
}
bool RA::verifyIntervals()
{
std::set<unsigned> assignedRegisters;
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) {
if ((*i)->reg >= MRegisterInfo::FirstVirtualRegister) {
unsigned reg = v2pMap_.find((*i)->reg)->second;
bool inserted = assignedRegisters.insert(reg).second;
assert(inserted && "registers in active list conflict");
}
}
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();
++i) {
if ((*i)->reg >= MRegisterInfo::FirstVirtualRegister) {
unsigned reg = v2pMap_.find((*i)->reg)->second;
bool inserted = assignedRegisters.insert(reg).second;
assert(inserted && "registers in inactive list conflict");
}
}
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_.find((*i)->reg)->second;
}
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) {
assert(assignedRegisters.find(*as) == assignedRegisters.end() &&
"registers in active list alias each other");
}
}
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();
++i) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_.find((*i)->reg)->second;
}
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as) {
assert(assignedRegisters.find(*as) == assignedRegisters.end() &&
"registers in inactive list alias each other");
}
}
return true;
}
Alkis Evlogimenos
committed
void RA::processActiveIntervals(Intervals::const_iterator 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)) {
Alkis Evlogimenos
committed
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
if (reg < MRegisterInfo::FirstVirtualRegister) {
markPhysRegFree(reg);
Alkis Evlogimenos
committed
}
else {
markPhysRegFree(v2pMap_[reg]);
Alkis Evlogimenos
committed
}
// 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");
// add to inactive
inactive_.push_back(*i);
// remove from active
Alkis Evlogimenos
committed
i = active_.erase(i);
}
else {
++i;
}
}
}
void RA::processInactiveIntervals(Intervals::const_iterator cur)
{
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
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");
if (reg < MRegisterInfo::FirstVirtualRegister) {
markPhysRegFree(reg);
}
else {
markPhysRegFree(v2pMap_[reg]);
}
// 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");
// add to active
active_.push_back(*i);
// remove from inactive
i = inactive_.erase(i);
}
else {
++i;
}
}
}
namespace {
void updateWeight(unsigned rw[], unsigned reg, unsigned w)
{
if (rw[reg] == std::numeric_limits<unsigned>::max() ||
w == std::numeric_limits<unsigned>::max())
rw[reg] = std::numeric_limits<unsigned>::max();
else
rw[reg] += w;
}
Alkis Evlogimenos
committed
}
void RA::assignStackSlotAtInterval(Intervals::const_iterator cur)
{
DEBUG(std::cerr << "\t\tassigning stack slot at interval "
<< *cur << ":\n");
assert((!active_.empty() || !inactive_.empty()) &&
"active and inactive sets cannot be both empty when choosing "
"a register to spill");
// set all weights to zero
unsigned regWeight[MRegisterInfo::FirstVirtualRegister];
memset(regWeight, 0, sizeof(regWeight));
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) {
// if (!cur->overlaps(**i))
// continue;
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
Alkis Evlogimenos
committed
}
updateWeight(regWeight, reg, (*i)->weight);
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
updateWeight(regWeight, *as, (*i)->weight);
Alkis Evlogimenos
committed
}
for (IntervalPtrs::iterator i = inactive_.begin();
i != inactive_.end(); ++i) {
// if (!cur->overlaps(**i))
// continue;
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister) {
reg = v2pMap_[reg];
Alkis Evlogimenos
committed
}
updateWeight(regWeight, reg, (*i)->weight);
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
updateWeight(regWeight, *as, (*i)->weight);
Alkis Evlogimenos
committed
}
unsigned minWeight = std::numeric_limits<unsigned>::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;
Alkis Evlogimenos
committed
}
}
DEBUG(std::cerr << "\t\t\t\tspill candidate: "
<< mri_->getName(minReg) << '\n');
Alkis Evlogimenos
committed
if (cur->weight < minWeight) {
assignVirt2StackSlot(cur->reg);
}
else {
std::set<unsigned> toSpill;
toSpill.insert(minReg);
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
toSpill.insert(*as);
for (IntervalPtrs::iterator i = active_.begin();
i != active_.end(); ) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister &&
toSpill.find(v2pMap_[reg]) != toSpill.end()) {
assignVirt2StackSlot(reg);
i = active_.erase(i);
}
else {
++i;
}
Alkis Evlogimenos
committed
}
for (IntervalPtrs::iterator i = inactive_.begin();
i != inactive_.end(); ) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister &&
toSpill.find(v2pMap_[reg]) != toSpill.end()) {
assignVirt2StackSlot(reg);
i = inactive_.erase(i);
}
else {
++i;
}
Alkis Evlogimenos
committed
}
unsigned physReg = getFreePhysReg(cur);
Alkis Evlogimenos
committed
assert(physReg && "no free physical register after spill?");
assignVirt2PhysReg(cur->reg, physReg);
active_.push_back(&*cur);
}
}
void RA::reservePhysReg(unsigned physReg)
{
DEBUG(std::cerr << "\t\t\treserving physical register: "
Alkis Evlogimenos
committed
<< mri_->getName(physReg) << '\n');
Regs clobbered;
clobbered.push_back(physReg);
for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) {
clobbered.push_back(*as);
}
// remove interval from active
for (IntervalPtrs::iterator i = active_.begin(), e = active_.end();
i != e; ) {
unsigned reg = (*i)->reg;
if (reg < MRegisterInfo::FirstVirtualRegister) {
++i;
continue;
}
if (find(clobbered.begin(), clobbered.end(), v2pMap_[reg]) !=
clobbered.end()) {
i = active_.erase(i);
assignVirt2StackSlot(reg);
}
else {
++i;
Alkis Evlogimenos
committed
}
}
// or from inactive
for (IntervalPtrs::iterator i = inactive_.begin(), e = inactive_.end();
i != e; ) {
unsigned reg = (*i)->reg;
if (reg < MRegisterInfo::FirstVirtualRegister) {
++i;
continue;
}
if (find(clobbered.begin(), clobbered.end(), v2pMap_[reg]) !=
clobbered.end()) {
i = inactive_.erase(i);
assignVirt2StackSlot(reg);
}
else {
++i;
}
}
markPhysRegNotFree(physReg);
Alkis Evlogimenos
committed
}
void RA::clearReservedPhysReg(unsigned physReg)
{
DEBUG(std::cerr << "\t\t\tclearing reserved physical register: "
Alkis Evlogimenos
committed
<< mri_->getName(physReg) << '\n');
markPhysRegFree(physReg);
Alkis Evlogimenos
committed
}
bool RA::physRegAvailable(unsigned physReg)
{
assert(!reserved_[physReg] &&
"cannot call this method with a reserved register");
Alkis Evlogimenos
committed
return !regUse_[physReg];
Alkis Evlogimenos
committed
}
unsigned RA::getFreePhysReg(Intervals::const_iterator cur)
Alkis Evlogimenos
committed
{
DEBUG(std::cerr << "\t\tgetting free physical register: ");
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
// save the regUse counts because we are going to modify them
// specifically for this interval
unsigned regUseBackup[MRegisterInfo::FirstVirtualRegister];
memcpy(regUseBackup, regUse_, sizeof(regUseBackup));
// for every interval in inactive we don't overlap mark the
// register as free
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();
++i) {
unsigned reg = (*i)->reg;
if (reg >= MRegisterInfo::FirstVirtualRegister)
reg = v2pMap_[reg];
if (!cur->overlaps(**i)) {
markPhysRegFree(reg);
}
}
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');
memcpy(regUse_, regUseBackup, sizeof(regUseBackup));
return reg;
Alkis Evlogimenos
committed
}
}
DEBUG(std::cerr << "no free register\n");
memcpy(regUse_, regUseBackup, sizeof(regUseBackup));
Alkis Evlogimenos
committed
return 0;
}
bool RA::tempPhysRegAvailable(unsigned physReg)
{
assert(reserved_[physReg] &&
"cannot call this method with a not reserved temp register");
Alkis Evlogimenos
committed
return !regUse_[physReg];
Alkis Evlogimenos
committed
}
unsigned RA::getFreeTempPhysReg(unsigned virtReg)
Alkis Evlogimenos
committed
{
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;
Alkis Evlogimenos
committed
}
}
Alkis Evlogimenos
committed
assert(0 && "no free temporary physical register?");
return 0;
}
void RA::assignVirt2PhysReg(unsigned virtReg, unsigned physReg)
{
v2pMap_[virtReg] = physReg;
markPhysRegNotFree(physReg);
Alkis Evlogimenos
committed
}
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);
Alkis Evlogimenos
committed
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
}
Alkis Evlogimenos
committed
}
int RA::getStackSlot(unsigned virtReg)
Alkis Evlogimenos
committed
{
// 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;
Alkis Evlogimenos
committed
}
void RA::spillVirtReg(unsigned virtReg)
{
DEBUG(std::cerr << "\t\t\tspilling register: " << virtReg);
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
int frameIndex = getStackSlot(virtReg);
Alkis Evlogimenos
committed
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);
Alkis Evlogimenos
committed
DEBUG(std::cerr << " from stack slot #" << frameIndex << '\n');
Alkis Evlogimenos
committed
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];
}
}
Alkis Evlogimenos
committed
FunctionPass* llvm::createLinearScanRegisterAllocator() {
return new RA();
}