From 31953c7a10124fc950aadb180ff54f0a97610e54 Mon Sep 17 00:00:00 2001 From: Alkis Evlogimenos Date: Mon, 1 Mar 2004 23:18:15 +0000 Subject: [PATCH] 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 --- llvm/docs/CommandGuide/llc.html | 13 +++ llvm/lib/CodeGen/Passes.cpp | 2 +- llvm/lib/CodeGen/RegAllocLinearScan.cpp | 4 +- llvm/lib/CodeGen/VirtRegMap.cpp | 105 ++++++++++++++---------- llvm/lib/CodeGen/VirtRegMap.h | 9 +- 5 files changed, 87 insertions(+), 46 deletions(-) diff --git a/llvm/docs/CommandGuide/llc.html b/llvm/docs/CommandGuide/llc.html index 36710427642e..4583b11fc60b 100644 --- a/llvm/docs/CommandGuide/llc.html +++ b/llvm/docs/CommandGuide/llc.html @@ -150,6 +150,19 @@ OPTIONS local
Local register allocator
+ + linearscan +
Linear scan global register allocator (experimental)
+ +
  • -spiller=<sp> +
    + 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 local. + Valid spillers are: +
    + local +
    Local spiller

    diff --git a/llvm/lib/CodeGen/Passes.cpp b/llvm/lib/CodeGen/Passes.cpp index bdcac4c6d12f..2fb6cb465c25 100644 --- a/llvm/lib/CodeGen/Passes.cpp +++ b/llvm/lib/CodeGen/Passes.cpp @@ -26,7 +26,7 @@ namespace { cl::Prefix, cl::values(clEnumVal(simple, " simple register allocator"), clEnumVal(local, " local register allocator"), - clEnumVal(linearscan, " linear-scan global register allocator"), + clEnumVal(linearscan, " linear scan register allocator (experimental)"), 0), cl::init(local)); } diff --git a/llvm/lib/CodeGen/RegAllocLinearScan.cpp b/llvm/lib/CodeGen/RegAllocLinearScan.cpp index d6c53cd0a72e..e92abe10bd31 100644 --- a/llvm/lib/CodeGen/RegAllocLinearScan.cpp +++ b/llvm/lib/CodeGen/RegAllocLinearScan.cpp @@ -41,6 +41,7 @@ namespace { std::auto_ptr prt_; std::auto_ptr vrm_; + std::auto_ptr spiller_; typedef std::vector SpillWeights; SpillWeights spillWeights_; @@ -147,12 +148,13 @@ bool RA::runOnMachineFunction(MachineFunction &fn) { li_ = &getAnalysis(); if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_)); vrm_.reset(new VirtRegMap(*mf_)); + if (!spiller_.get()) spiller_.reset(createSpiller()); initIntervalSets(li_->getIntervals()); linearScan(); - eliminateVirtRegs(*mf_, *vrm_); + spiller_->runOnMachineFunction(*mf_, *vrm_); return true; } diff --git a/llvm/lib/CodeGen/VirtRegMap.cpp b/llvm/lib/CodeGen/VirtRegMap.cpp index 1238a2cefbb4..1187fc26f198 100644 --- a/llvm/lib/CodeGen/VirtRegMap.cpp +++ b/llvm/lib/CodeGen/VirtRegMap.cpp @@ -22,9 +22,10 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" -#include "Support/Statistic.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/DenseMap.h" +#include "Support/Statistic.h" #include "Support/STLExtras.h" #include @@ -35,6 +36,15 @@ namespace { Statistic<> numStores("spiller", "Number of stores added"); Statistic<> numLoads ("spiller", "Number of loads added"); + enum SpillerName { local }; + + cl::opt + 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) @@ -88,41 +98,44 @@ std::ostream& llvm::operator<<(std::ostream& os, const VirtRegMap& vrm) return std::cerr << '\n'; } +Spiller::~Spiller() +{ + +} + namespace { - class Spiller { + class LocalSpiller : public Spiller { typedef std::vector Phys2VirtMap; typedef std::vector PhysFlag; typedef DenseMap Virt2MI; - MachineFunction& mf_; - const TargetMachine& tm_; - const TargetInstrInfo& tii_; - const MRegisterInfo& mri_; - const VirtRegMap& vrm_; + MachineFunction* mf_; + const TargetMachine* tm_; + const TargetInstrInfo* tii_; + const MRegisterInfo* mri_; + const VirtRegMap* vrm_; Phys2VirtMap p2vMap_; PhysFlag dirty_; Virt2MI lastDef_; public: - Spiller(MachineFunction& mf, const VirtRegMap& vrm) - : mf_(mf), - tm_(mf_.getTarget()), - tii_(tm_.getInstrInfo()), - mri_(*tm_.getRegisterInfo()), - vrm_(vrm), - p2vMap_(mri_.getNumRegs(), 0), - dirty_(mri_.getNumRegs(), false), - lastDef_() { + bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) { + mf_ = &mf; + tm_ = &mf_->getTarget(); + tii_ = &tm_->getInstrInfo(); + mri_ = tm_->getRegisterInfo(); + vrm_ = &vrm; + p2vMap_.assign(mri_->getNumRegs(), 0); + dirty_.assign(mri_->getNumRegs(), false); + DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n"); DEBUG(std::cerr << "********** Function: " - << mf_.getFunction()->getName() << '\n'); - } + << mf_->getFunction()->getName() << '\n'); - void eliminateVirtRegs() { - for (MachineFunction::iterator mbbi = mf_.begin(), - mbbe = mf_.end(); mbbi != mbbe; ++mbbi) { - lastDef_.grow(mf_.getSSARegMap()->getLastVirtReg()); + for (MachineFunction::iterator mbbi = mf_->begin(), + mbbe = mf_->end(); mbbi != mbbe; ++mbbi) { + lastDef_.grow(mf_->getSSARegMap()->getLastVirtReg()); DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n"); eliminateVirtRegsInMbb(*mbbi); // clear map, dirty flag and last ref @@ -130,6 +143,7 @@ namespace { dirty_.assign(dirty_.size(), false); lastDef_.clear(); } + return true; } private: @@ -137,21 +151,21 @@ namespace { MachineBasicBlock::iterator mii, unsigned physReg) { unsigned virtReg = p2vMap_[physReg]; - if (dirty_[physReg] && vrm_.hasStackSlot(virtReg)) { + if (dirty_[physReg] && vrm_->hasStackSlot(virtReg)) { assert(lastDef_[virtReg] && "virtual register is mapped " "to a register and but was not defined!"); MachineBasicBlock::iterator lastDef = lastDef_[virtReg]; MachineBasicBlock::iterator nextLastRef = next(lastDef); - mri_.storeRegToStackSlot(*lastDef->getParent(), + mri_->storeRegToStackSlot(*lastDef->getParent(), nextLastRef, physReg, - vrm_.getStackSlot(virtReg), - mri_.getRegClass(physReg)); + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); ++numStores; DEBUG(std::cerr << "added: "; - prior(nextLastRef)->print(std::cerr, tm_); + prior(nextLastRef)->print(std::cerr, *tm_); std::cerr << "after: "; - lastDef->print(std::cerr, tm_)); + lastDef->print(std::cerr, *tm_)); lastDef_[virtReg] = 0; } p2vMap_[physReg] = 0; @@ -162,7 +176,7 @@ namespace { MachineBasicBlock::iterator mii, unsigned 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); } @@ -175,13 +189,13 @@ namespace { vacatePhysReg(mbb, mii, physReg); p2vMap_[physReg] = virtReg; // load if necessary - if (vrm_.hasStackSlot(virtReg)) { - mri_.loadRegFromStackSlot(mbb, mii, physReg, - vrm_.getStackSlot(virtReg), - mri_.getRegClass(physReg)); + if (vrm_->hasStackSlot(virtReg)) { + mri_->loadRegFromStackSlot(mbb, mii, physReg, + vrm_->getStackSlot(virtReg), + mri_->getRegClass(physReg)); ++numLoads; DEBUG(std::cerr << "added: "; - prior(mii)->print(std::cerr,tm_)); + prior(mii)->print(std::cerr, *tm_)); lastDef_[virtReg] = mii; } } @@ -208,8 +222,8 @@ namespace { // we clear all physical registers that may contain // the value of the spilled virtual register VirtRegMap::MI2VirtMap::const_iterator i, e; - for (tie(i, e) = vrm_.getFoldedVirts(mii); i != e; ++i) { - unsigned physReg = vrm_.getPhys(i->second); + for (tie(i, e) = vrm_->getFoldedVirts(mii); i != e; ++i) { + unsigned physReg = vrm_->getPhys(i->second); if (physReg) vacateJustPhysReg(mbb, mii, physReg); } @@ -219,7 +233,7 @@ namespace { if (op.isRegister() && op.getReg() && op.isUse() && MRegisterInfo::isVirtualRegister(op.getReg())) { unsigned virtReg = op.getReg(); - unsigned physReg = vrm_.getPhys(virtReg); + unsigned physReg = vrm_->getPhys(virtReg); handleUse(mbb, mii, virtReg, physReg); mii->SetMachineOperandReg(i, physReg); // mark as dirty if this is def&use @@ -231,7 +245,7 @@ namespace { } // 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) vacatePhysReg(mbb, mii, *id); @@ -243,13 +257,13 @@ namespace { if (MRegisterInfo::isPhysicalRegister(op.getReg())) vacatePhysReg(mbb, mii, op.getReg()); else { - unsigned physReg = vrm_.getPhys(op.getReg()); + unsigned physReg = vrm_->getPhys(op.getReg()); handleDef(mbb, mii, op.getReg(), 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) @@ -259,8 +273,13 @@ namespace { }; } - -void llvm::eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm) +llvm::Spiller* llvm::createSpiller() { - Spiller(mf, vrm).eliminateVirtRegs(); + switch (SpillerOpt) { + default: + std::cerr << "no spiller selected"; + abort(); + case local: + return new LocalSpiller(); + } } diff --git a/llvm/lib/CodeGen/VirtRegMap.h b/llvm/lib/CodeGen/VirtRegMap.h index 90cc44d31c42..3c2f8eec4ad7 100644 --- a/llvm/lib/CodeGen/VirtRegMap.h +++ b/llvm/lib/CodeGen/VirtRegMap.h @@ -108,7 +108,14 @@ namespace llvm { 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