Add a spiller option to llc. A simple spiller will come soon. When we get CFG in the machine code represenation a global spiller will also be possible. Also document the linear scan register allocator but mark it as experimental for now.

llvm-svn: 12062
This commit is contained in:
Alkis Evlogimenos 2004-03-01 23:18:15 +00:00
parent b76d234ee9
commit 31953c7a10
5 changed files with 87 additions and 46 deletions

View File

@ -150,6 +150,19 @@ OPTIONS
<di> local <di> local
<dd>Local register allocator</dd> <dd>Local register allocator</dd>
<di> linearscan
<dd>Linear scan global register allocator (experimental)</dd>
<li>-spiller=&lt;sp&gt;
<br>
Specify the spiller to use for register allocators that support it.
Currently this option is used by the linear scan register
allocator. The default is <i>local</i>.
Valid spillers are:
<dl compact>
<di> local
<dd>Local spiller</dd>
</dl> </dl>
<p> <p>

View File

@ -26,7 +26,7 @@ namespace {
cl::Prefix, cl::Prefix,
cl::values(clEnumVal(simple, " simple register allocator"), cl::values(clEnumVal(simple, " simple register allocator"),
clEnumVal(local, " local register allocator"), clEnumVal(local, " local register allocator"),
clEnumVal(linearscan, " linear-scan global register allocator"), clEnumVal(linearscan, " linear scan register allocator (experimental)"),
0), 0),
cl::init(local)); cl::init(local));
} }

View File

@ -41,6 +41,7 @@ namespace {
std::auto_ptr<PhysRegTracker> prt_; std::auto_ptr<PhysRegTracker> prt_;
std::auto_ptr<VirtRegMap> vrm_; std::auto_ptr<VirtRegMap> vrm_;
std::auto_ptr<Spiller> spiller_;
typedef std::vector<float> SpillWeights; typedef std::vector<float> SpillWeights;
SpillWeights spillWeights_; SpillWeights spillWeights_;
@ -147,12 +148,13 @@ bool RA::runOnMachineFunction(MachineFunction &fn) {
li_ = &getAnalysis<LiveIntervals>(); li_ = &getAnalysis<LiveIntervals>();
if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_)); if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_));
vrm_.reset(new VirtRegMap(*mf_)); vrm_.reset(new VirtRegMap(*mf_));
if (!spiller_.get()) spiller_.reset(createSpiller());
initIntervalSets(li_->getIntervals()); initIntervalSets(li_->getIntervals());
linearScan(); linearScan();
eliminateVirtRegs(*mf_, *vrm_); spiller_->runOnMachineFunction(*mf_, *vrm_);
return true; return true;
} }

View File

@ -22,9 +22,10 @@
#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetInstrInfo.h"
#include "Support/Statistic.h" #include "Support/CommandLine.h"
#include "Support/Debug.h" #include "Support/Debug.h"
#include "Support/DenseMap.h" #include "Support/DenseMap.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h" #include "Support/STLExtras.h"
#include <iostream> #include <iostream>
@ -35,6 +36,15 @@ namespace {
Statistic<> numStores("spiller", "Number of stores added"); Statistic<> numStores("spiller", "Number of stores added");
Statistic<> numLoads ("spiller", "Number of loads added"); Statistic<> numLoads ("spiller", "Number of loads added");
enum SpillerName { local };
cl::opt<SpillerName>
SpillerOpt("spiller",
cl::desc("Spiller to use: (default: local)"),
cl::Prefix,
cl::values(clEnumVal(local, " local spiller"),
0),
cl::init(local));
} }
int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) int VirtRegMap::assignVirt2StackSlot(unsigned virtReg)
@ -88,41 +98,44 @@ std::ostream& llvm::operator<<(std::ostream& os, const VirtRegMap& vrm)
return std::cerr << '\n'; return std::cerr << '\n';
} }
Spiller::~Spiller()
{
}
namespace { namespace {
class Spiller { class LocalSpiller : public Spiller {
typedef std::vector<unsigned> Phys2VirtMap; typedef std::vector<unsigned> Phys2VirtMap;
typedef std::vector<bool> PhysFlag; typedef std::vector<bool> PhysFlag;
typedef DenseMap<MachineInstr*, VirtReg2IndexFunctor> Virt2MI; typedef DenseMap<MachineInstr*, VirtReg2IndexFunctor> Virt2MI;
MachineFunction& mf_; MachineFunction* mf_;
const TargetMachine& tm_; const TargetMachine* tm_;
const TargetInstrInfo& tii_; const TargetInstrInfo* tii_;
const MRegisterInfo& mri_; const MRegisterInfo* mri_;
const VirtRegMap& vrm_; const VirtRegMap* vrm_;
Phys2VirtMap p2vMap_; Phys2VirtMap p2vMap_;
PhysFlag dirty_; PhysFlag dirty_;
Virt2MI lastDef_; Virt2MI lastDef_;
public: public:
Spiller(MachineFunction& mf, const VirtRegMap& vrm) bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) {
: mf_(mf), mf_ = &mf;
tm_(mf_.getTarget()), tm_ = &mf_->getTarget();
tii_(tm_.getInstrInfo()), tii_ = &tm_->getInstrInfo();
mri_(*tm_.getRegisterInfo()), mri_ = tm_->getRegisterInfo();
vrm_(vrm), vrm_ = &vrm;
p2vMap_(mri_.getNumRegs(), 0), p2vMap_.assign(mri_->getNumRegs(), 0);
dirty_(mri_.getNumRegs(), false), dirty_.assign(mri_->getNumRegs(), false);
lastDef_() {
DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n"); DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n");
DEBUG(std::cerr << "********** Function: " DEBUG(std::cerr << "********** Function: "
<< mf_.getFunction()->getName() << '\n'); << mf_->getFunction()->getName() << '\n');
}
void eliminateVirtRegs() { for (MachineFunction::iterator mbbi = mf_->begin(),
for (MachineFunction::iterator mbbi = mf_.begin(), mbbe = mf_->end(); mbbi != mbbe; ++mbbi) {
mbbe = mf_.end(); mbbi != mbbe; ++mbbi) { lastDef_.grow(mf_->getSSARegMap()->getLastVirtReg());
lastDef_.grow(mf_.getSSARegMap()->getLastVirtReg());
DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n"); DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n");
eliminateVirtRegsInMbb(*mbbi); eliminateVirtRegsInMbb(*mbbi);
// clear map, dirty flag and last ref // clear map, dirty flag and last ref
@ -130,6 +143,7 @@ namespace {
dirty_.assign(dirty_.size(), false); dirty_.assign(dirty_.size(), false);
lastDef_.clear(); lastDef_.clear();
} }
return true;
} }
private: private:
@ -137,21 +151,21 @@ namespace {
MachineBasicBlock::iterator mii, MachineBasicBlock::iterator mii,
unsigned physReg) { unsigned physReg) {
unsigned virtReg = p2vMap_[physReg]; unsigned virtReg = p2vMap_[physReg];
if (dirty_[physReg] && vrm_.hasStackSlot(virtReg)) { if (dirty_[physReg] && vrm_->hasStackSlot(virtReg)) {
assert(lastDef_[virtReg] && "virtual register is mapped " assert(lastDef_[virtReg] && "virtual register is mapped "
"to a register and but was not defined!"); "to a register and but was not defined!");
MachineBasicBlock::iterator lastDef = lastDef_[virtReg]; MachineBasicBlock::iterator lastDef = lastDef_[virtReg];
MachineBasicBlock::iterator nextLastRef = next(lastDef); MachineBasicBlock::iterator nextLastRef = next(lastDef);
mri_.storeRegToStackSlot(*lastDef->getParent(), mri_->storeRegToStackSlot(*lastDef->getParent(),
nextLastRef, nextLastRef,
physReg, physReg,
vrm_.getStackSlot(virtReg), vrm_->getStackSlot(virtReg),
mri_.getRegClass(physReg)); mri_->getRegClass(physReg));
++numStores; ++numStores;
DEBUG(std::cerr << "added: "; DEBUG(std::cerr << "added: ";
prior(nextLastRef)->print(std::cerr, tm_); prior(nextLastRef)->print(std::cerr, *tm_);
std::cerr << "after: "; std::cerr << "after: ";
lastDef->print(std::cerr, tm_)); lastDef->print(std::cerr, *tm_));
lastDef_[virtReg] = 0; lastDef_[virtReg] = 0;
} }
p2vMap_[physReg] = 0; p2vMap_[physReg] = 0;
@ -162,7 +176,7 @@ namespace {
MachineBasicBlock::iterator mii, MachineBasicBlock::iterator mii,
unsigned physReg) { unsigned physReg) {
vacateJustPhysReg(mbb, mii, physReg); vacateJustPhysReg(mbb, mii, physReg);
for (const unsigned* as = mri_.getAliasSet(physReg); *as; ++as) for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as)
vacateJustPhysReg(mbb, mii, *as); vacateJustPhysReg(mbb, mii, *as);
} }
@ -175,13 +189,13 @@ namespace {
vacatePhysReg(mbb, mii, physReg); vacatePhysReg(mbb, mii, physReg);
p2vMap_[physReg] = virtReg; p2vMap_[physReg] = virtReg;
// load if necessary // load if necessary
if (vrm_.hasStackSlot(virtReg)) { if (vrm_->hasStackSlot(virtReg)) {
mri_.loadRegFromStackSlot(mbb, mii, physReg, mri_->loadRegFromStackSlot(mbb, mii, physReg,
vrm_.getStackSlot(virtReg), vrm_->getStackSlot(virtReg),
mri_.getRegClass(physReg)); mri_->getRegClass(physReg));
++numLoads; ++numLoads;
DEBUG(std::cerr << "added: "; DEBUG(std::cerr << "added: ";
prior(mii)->print(std::cerr,tm_)); prior(mii)->print(std::cerr, *tm_));
lastDef_[virtReg] = mii; lastDef_[virtReg] = mii;
} }
} }
@ -208,8 +222,8 @@ namespace {
// we clear all physical registers that may contain // we clear all physical registers that may contain
// the value of the spilled virtual register // the value of the spilled virtual register
VirtRegMap::MI2VirtMap::const_iterator i, e; VirtRegMap::MI2VirtMap::const_iterator i, e;
for (tie(i, e) = vrm_.getFoldedVirts(mii); i != e; ++i) { for (tie(i, e) = vrm_->getFoldedVirts(mii); i != e; ++i) {
unsigned physReg = vrm_.getPhys(i->second); unsigned physReg = vrm_->getPhys(i->second);
if (physReg) vacateJustPhysReg(mbb, mii, physReg); if (physReg) vacateJustPhysReg(mbb, mii, physReg);
} }
@ -219,7 +233,7 @@ namespace {
if (op.isRegister() && op.getReg() && op.isUse() && if (op.isRegister() && op.getReg() && op.isUse() &&
MRegisterInfo::isVirtualRegister(op.getReg())) { MRegisterInfo::isVirtualRegister(op.getReg())) {
unsigned virtReg = op.getReg(); unsigned virtReg = op.getReg();
unsigned physReg = vrm_.getPhys(virtReg); unsigned physReg = vrm_->getPhys(virtReg);
handleUse(mbb, mii, virtReg, physReg); handleUse(mbb, mii, virtReg, physReg);
mii->SetMachineOperandReg(i, physReg); mii->SetMachineOperandReg(i, physReg);
// mark as dirty if this is def&use // mark as dirty if this is def&use
@ -231,7 +245,7 @@ namespace {
} }
// spill implicit defs // spill implicit defs
const TargetInstrDescriptor& tid =tii_.get(mii->getOpcode()); const TargetInstrDescriptor& tid = tii_->get(mii->getOpcode());
for (const unsigned* id = tid.ImplicitDefs; *id; ++id) for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
vacatePhysReg(mbb, mii, *id); vacatePhysReg(mbb, mii, *id);
@ -243,13 +257,13 @@ namespace {
if (MRegisterInfo::isPhysicalRegister(op.getReg())) if (MRegisterInfo::isPhysicalRegister(op.getReg()))
vacatePhysReg(mbb, mii, op.getReg()); vacatePhysReg(mbb, mii, op.getReg());
else { else {
unsigned physReg = vrm_.getPhys(op.getReg()); unsigned physReg = vrm_->getPhys(op.getReg());
handleDef(mbb, mii, op.getReg(), physReg); handleDef(mbb, mii, op.getReg(), physReg);
mii->SetMachineOperandReg(i, physReg); mii->SetMachineOperandReg(i, physReg);
} }
} }
DEBUG(std::cerr << '\t'; mii->print(std::cerr, tm_)); DEBUG(std::cerr << '\t'; mii->print(std::cerr, *tm_));
} }
for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i) for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i)
@ -259,8 +273,13 @@ namespace {
}; };
} }
llvm::Spiller* llvm::createSpiller()
void llvm::eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm)
{ {
Spiller(mf, vrm).eliminateVirtRegs(); switch (SpillerOpt) {
default:
std::cerr << "no spiller selected";
abort();
case local:
return new LocalSpiller();
}
} }

View File

@ -108,7 +108,14 @@ namespace llvm {
std::ostream& operator<<(std::ostream& os, const VirtRegMap& li); std::ostream& operator<<(std::ostream& os, const VirtRegMap& li);
void eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm); struct Spiller {
virtual ~Spiller();
virtual bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) = 0;
};
Spiller* createSpiller();
} // End llvm namespace } // End llvm namespace