forked from OSchip/llvm-project
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:
parent
b76d234ee9
commit
31953c7a10
|
@ -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=<sp>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue