mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-30 04:35:00 +00:00
Reindent code, improve comments, move huge nested methods out of classes,
prune #includes, add print/dump methods, etc. No functionality changes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16604 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
23367a779c
commit
8c4d88d369
@ -7,353 +7,367 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the virtual register map. It also implements
|
||||
// the eliminateVirtRegs() function that given a virtual register map
|
||||
// and a machine function it eliminates all virtual references by
|
||||
// replacing them with physical register references and adds spill
|
||||
// This file implements the VirtRegMap class.
|
||||
//
|
||||
// It also contains implementations of the the Spiller interface, which, given a
|
||||
// virtual register map and a machine function, eliminates all virtual
|
||||
// references by replacing them with physical register references - adding spill
|
||||
// code as necessary.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "regalloc"
|
||||
#define DEBUG_TYPE "spiller"
|
||||
#include "VirtRegMap.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
Statistic<> numSpills("spiller", "Number of register spills");
|
||||
Statistic<> numStores("spiller", "Number of stores added");
|
||||
Statistic<> numLoads ("spiller", "Number of loads added");
|
||||
Statistic<> NumSpills("spiller", "Number of register spills");
|
||||
Statistic<> NumStores("spiller", "Number of stores added");
|
||||
Statistic<> NumLoads ("spiller", "Number of loads added");
|
||||
|
||||
enum SpillerName { simple, local };
|
||||
enum SpillerName { simple, local };
|
||||
|
||||
cl::opt<SpillerName>
|
||||
SpillerOpt("spiller",
|
||||
cl::desc("Spiller to use: (default: local)"),
|
||||
cl::Prefix,
|
||||
cl::values(clEnumVal(simple, " simple spiller"),
|
||||
clEnumVal(local, " local spiller"),
|
||||
clEnumValEnd),
|
||||
cl::init(local));
|
||||
cl::opt<SpillerName>
|
||||
SpillerOpt("spiller",
|
||||
cl::desc("Spiller to use: (default: local)"),
|
||||
cl::Prefix,
|
||||
cl::values(clEnumVal(simple, " simple spiller"),
|
||||
clEnumVal(local, " local spiller"),
|
||||
clEnumValEnd),
|
||||
cl::init(local));
|
||||
}
|
||||
|
||||
int VirtRegMap::assignVirt2StackSlot(unsigned virtReg)
|
||||
{
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2ssMap_[virtReg] == NO_STACK_SLOT &&
|
||||
"attempt to assign stack slot to already spilled register");
|
||||
const TargetRegisterClass* RC =
|
||||
mf_->getSSARegMap()->getRegClass(virtReg);
|
||||
int frameIndex = mf_->getFrameInfo()->CreateStackObject(RC->getSize(),
|
||||
RC->getAlignment());
|
||||
v2ssMap_[virtReg] = frameIndex;
|
||||
++numSpills;
|
||||
return frameIndex;
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VirtRegMap implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void VirtRegMap::grow() {
|
||||
v2pMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
|
||||
v2ssMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
|
||||
}
|
||||
|
||||
void VirtRegMap::assignVirt2StackSlot(unsigned virtReg, int frameIndex)
|
||||
{
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2ssMap_[virtReg] == NO_STACK_SLOT &&
|
||||
"attempt to assign stack slot to already spilled register");
|
||||
v2ssMap_[virtReg] = frameIndex;
|
||||
int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2ssMap_[virtReg] == NO_STACK_SLOT &&
|
||||
"attempt to assign stack slot to already spilled register");
|
||||
const TargetRegisterClass* RC = mf_->getSSARegMap()->getRegClass(virtReg);
|
||||
int frameIndex = mf_->getFrameInfo()->CreateStackObject(RC->getSize(),
|
||||
RC->getAlignment());
|
||||
v2ssMap_[virtReg] = frameIndex;
|
||||
++NumSpills;
|
||||
return frameIndex;
|
||||
}
|
||||
|
||||
void VirtRegMap::assignVirt2StackSlot(unsigned virtReg, int frameIndex) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2ssMap_[virtReg] == NO_STACK_SLOT &&
|
||||
"attempt to assign stack slot to already spilled register");
|
||||
v2ssMap_[virtReg] = frameIndex;
|
||||
}
|
||||
|
||||
void VirtRegMap::virtFolded(unsigned virtReg,
|
||||
MachineInstr* oldMI,
|
||||
MachineInstr* newMI)
|
||||
{
|
||||
// move previous memory references folded to new instruction
|
||||
MI2VirtMap::iterator i, e;
|
||||
std::vector<MI2VirtMap::mapped_type> regs;
|
||||
for (tie(i, e) = mi2vMap_.equal_range(oldMI); i != e; ) {
|
||||
regs.push_back(i->second);
|
||||
mi2vMap_.erase(i++);
|
||||
}
|
||||
for (unsigned i = 0, e = regs.size(); i != e; ++i)
|
||||
mi2vMap_.insert(std::make_pair(newMI, i));
|
||||
MachineInstr* newMI) {
|
||||
// move previous memory references folded to new instruction
|
||||
MI2VirtMap::iterator i, e;
|
||||
std::vector<MI2VirtMap::mapped_type> regs;
|
||||
for (tie(i, e) = mi2vMap_.equal_range(oldMI); i != e; ) {
|
||||
regs.push_back(i->second);
|
||||
mi2vMap_.erase(i++);
|
||||
}
|
||||
for (unsigned i = 0, e = regs.size(); i != e; ++i)
|
||||
mi2vMap_.insert(std::make_pair(newMI, i));
|
||||
|
||||
// add new memory reference
|
||||
mi2vMap_.insert(std::make_pair(newMI, virtReg));
|
||||
// add new memory reference
|
||||
mi2vMap_.insert(std::make_pair(newMI, virtReg));
|
||||
}
|
||||
|
||||
std::ostream& llvm::operator<<(std::ostream& os, const VirtRegMap& vrm)
|
||||
{
|
||||
const MRegisterInfo* mri = vrm.mf_->getTarget().getRegisterInfo();
|
||||
void VirtRegMap::print(std::ostream& os) const {
|
||||
const MRegisterInfo* mri = mf_->getTarget().getRegisterInfo();
|
||||
|
||||
std::cerr << "********** REGISTER MAP **********\n";
|
||||
for (unsigned i = MRegisterInfo::FirstVirtualRegister,
|
||||
e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
|
||||
if (vrm.v2pMap_[i] != VirtRegMap::NO_PHYS_REG)
|
||||
std::cerr << "[reg" << i << " -> "
|
||||
<< mri->getName(vrm.v2pMap_[i]) << "]\n";
|
||||
}
|
||||
for (unsigned i = MRegisterInfo::FirstVirtualRegister,
|
||||
e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
|
||||
if (vrm.v2ssMap_[i] != VirtRegMap::NO_STACK_SLOT)
|
||||
std::cerr << "[reg" << i << " -> fi#"
|
||||
<< vrm.v2ssMap_[i] << "]\n";
|
||||
}
|
||||
return std::cerr << '\n';
|
||||
std::cerr << "********** REGISTER MAP **********\n";
|
||||
for (unsigned i = MRegisterInfo::FirstVirtualRegister,
|
||||
e = mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
|
||||
if (v2pMap_[i] != (unsigned)VirtRegMap::NO_PHYS_REG)
|
||||
std::cerr << "[reg" << i << " -> "
|
||||
<< mri->getName(v2pMap_[i]) << "]\n";
|
||||
}
|
||||
|
||||
for (unsigned i = MRegisterInfo::FirstVirtualRegister,
|
||||
e = mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
|
||||
if (v2ssMap_[i] != VirtRegMap::NO_STACK_SLOT)
|
||||
std::cerr << "[reg" << i << " -> fi#"
|
||||
<< v2ssMap_[i] << "]\n";
|
||||
}
|
||||
std::cerr << '\n';
|
||||
}
|
||||
|
||||
Spiller::~Spiller()
|
||||
{
|
||||
void VirtRegMap::dump() const { print(std::cerr); }
|
||||
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Simple Spiller Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Spiller::~Spiller() {}
|
||||
|
||||
namespace {
|
||||
|
||||
class SimpleSpiller : public Spiller {
|
||||
public:
|
||||
bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) {
|
||||
DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< mf.getFunction()->getName() << '\n');
|
||||
const TargetMachine& tm = mf.getTarget();
|
||||
const MRegisterInfo& mri = *tm.getRegisterInfo();
|
||||
|
||||
typedef DenseMap<bool, VirtReg2IndexFunctor> Loaded;
|
||||
Loaded loaded;
|
||||
|
||||
for (MachineFunction::iterator mbbi = mf.begin(),
|
||||
mbbe = mf.end(); mbbi != mbbe; ++mbbi) {
|
||||
DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n");
|
||||
for (MachineBasicBlock::iterator mii = mbbi->begin(),
|
||||
mie = mbbi->end(); mii != mie; ++mii) {
|
||||
loaded.grow(mf.getSSARegMap()->getLastVirtReg());
|
||||
for (unsigned i = 0,e = mii->getNumOperands(); i != e; ++i){
|
||||
MachineOperand& mop = mii->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() &&
|
||||
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
||||
unsigned virtReg = mop.getReg();
|
||||
unsigned physReg = vrm.getPhys(virtReg);
|
||||
if (mop.isUse() &&
|
||||
vrm.hasStackSlot(mop.getReg()) &&
|
||||
!loaded[virtReg]) {
|
||||
mri.loadRegFromStackSlot(
|
||||
*mbbi,
|
||||
mii,
|
||||
physReg,
|
||||
vrm.getStackSlot(virtReg));
|
||||
loaded[virtReg] = true;
|
||||
DEBUG(std::cerr << '\t';
|
||||
prior(mii)->print(std::cerr, &tm));
|
||||
++numLoads;
|
||||
}
|
||||
if (mop.isDef() &&
|
||||
vrm.hasStackSlot(mop.getReg())) {
|
||||
mri.storeRegToStackSlot(
|
||||
*mbbi,
|
||||
next(mii),
|
||||
physReg,
|
||||
vrm.getStackSlot(virtReg));
|
||||
++numStores;
|
||||
}
|
||||
mii->SetMachineOperandReg(i, physReg);
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << '\t'; mii->print(std::cerr, &tm));
|
||||
loaded.clear();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class LocalSpiller : public Spiller {
|
||||
typedef std::vector<unsigned> Phys2VirtMap;
|
||||
typedef std::vector<bool> PhysFlag;
|
||||
typedef DenseMap<MachineInstr*, VirtReg2IndexFunctor> Virt2MI;
|
||||
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const TargetInstrInfo* tii_;
|
||||
const MRegisterInfo* mri_;
|
||||
const VirtRegMap* vrm_;
|
||||
Phys2VirtMap p2vMap_;
|
||||
PhysFlag dirty_;
|
||||
Virt2MI lastDef_;
|
||||
|
||||
public:
|
||||
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');
|
||||
|
||||
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
|
||||
p2vMap_.assign(p2vMap_.size(), 0);
|
||||
dirty_.assign(dirty_.size(), false);
|
||||
lastDef_.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void vacateJustPhysReg(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned physReg) {
|
||||
unsigned virtReg = p2vMap_[physReg];
|
||||
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(),
|
||||
nextLastRef,
|
||||
physReg,
|
||||
vrm_->getStackSlot(virtReg));
|
||||
++numStores;
|
||||
DEBUG(std::cerr << "added: ";
|
||||
prior(nextLastRef)->print(std::cerr, tm_);
|
||||
std::cerr << "after: ";
|
||||
lastDef->print(std::cerr, tm_));
|
||||
lastDef_[virtReg] = 0;
|
||||
}
|
||||
p2vMap_[physReg] = 0;
|
||||
dirty_[physReg] = false;
|
||||
}
|
||||
|
||||
void vacatePhysReg(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned physReg) {
|
||||
vacateJustPhysReg(mbb, mii, physReg);
|
||||
for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as)
|
||||
vacateJustPhysReg(mbb, mii, *as);
|
||||
}
|
||||
|
||||
void handleUse(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned virtReg,
|
||||
unsigned physReg) {
|
||||
// check if we are replacing a previous mapping
|
||||
if (p2vMap_[physReg] != virtReg) {
|
||||
vacatePhysReg(mbb, mii, physReg);
|
||||
p2vMap_[physReg] = virtReg;
|
||||
// load if necessary
|
||||
if (vrm_->hasStackSlot(virtReg)) {
|
||||
mri_->loadRegFromStackSlot(mbb, mii, physReg,
|
||||
vrm_->getStackSlot(virtReg));
|
||||
++numLoads;
|
||||
DEBUG(std::cerr << "added: ";
|
||||
prior(mii)->print(std::cerr, tm_));
|
||||
lastDef_[virtReg] = mii;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleDef(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned virtReg,
|
||||
unsigned physReg) {
|
||||
// check if we are replacing a previous mapping
|
||||
if (p2vMap_[physReg] != virtReg)
|
||||
vacatePhysReg(mbb, mii, physReg);
|
||||
|
||||
p2vMap_[physReg] = virtReg;
|
||||
dirty_[physReg] = true;
|
||||
lastDef_[virtReg] = mii;
|
||||
}
|
||||
|
||||
void eliminateVirtRegsInMbb(MachineBasicBlock& mbb) {
|
||||
for (MachineBasicBlock::iterator mii = mbb.begin(),
|
||||
mie = mbb.end(); mii != mie; ++mii) {
|
||||
|
||||
// if we have references to memory operands make sure
|
||||
// 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) {
|
||||
if (vrm_->hasPhys(i->second))
|
||||
vacateJustPhysReg(mbb, mii, vrm_->getPhys(i->second));
|
||||
}
|
||||
|
||||
// rewrite all used operands
|
||||
for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = mii->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && op.isUse() &&
|
||||
MRegisterInfo::isVirtualRegister(op.getReg())) {
|
||||
unsigned virtReg = op.getReg();
|
||||
unsigned physReg = vrm_->getPhys(virtReg);
|
||||
handleUse(mbb, mii, virtReg, physReg);
|
||||
mii->SetMachineOperandReg(i, physReg);
|
||||
// mark as dirty if this is def&use
|
||||
if (op.isDef()) {
|
||||
dirty_[physReg] = true;
|
||||
lastDef_[virtReg] = mii;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spill implicit physical register defs
|
||||
const TargetInstrDescriptor& tid = tii_->get(mii->getOpcode());
|
||||
for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
|
||||
vacatePhysReg(mbb, mii, *id);
|
||||
|
||||
// spill explicit physical register defs
|
||||
for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = mii->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && !op.isUse() &&
|
||||
MRegisterInfo::isPhysicalRegister(op.getReg()))
|
||||
vacatePhysReg(mbb, mii, op.getReg());
|
||||
}
|
||||
|
||||
// rewrite def operands (def&use was handled with the
|
||||
// uses so don't check for those here)
|
||||
for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = mii->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && !op.isUse())
|
||||
if (MRegisterInfo::isPhysicalRegister(op.getReg()))
|
||||
vacatePhysReg(mbb, mii, op.getReg());
|
||||
else {
|
||||
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_));
|
||||
}
|
||||
|
||||
for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i)
|
||||
vacateJustPhysReg(mbb, mbb.getFirstTerminator(), i);
|
||||
|
||||
}
|
||||
};
|
||||
struct SimpleSpiller : public Spiller {
|
||||
bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap &VRM);
|
||||
};
|
||||
}
|
||||
|
||||
llvm::Spiller* llvm::createSpiller()
|
||||
{
|
||||
switch (SpillerOpt) {
|
||||
default:
|
||||
std::cerr << "no spiller selected";
|
||||
abort();
|
||||
case local:
|
||||
return new LocalSpiller();
|
||||
case simple:
|
||||
return new SimpleSpiller();
|
||||
bool SimpleSpiller::runOnMachineFunction(MachineFunction& MF,
|
||||
const VirtRegMap& VRM) {
|
||||
DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< MF.getFunction()->getName() << '\n');
|
||||
const TargetMachine& TM = MF.getTarget();
|
||||
const MRegisterInfo& mri = *TM.getRegisterInfo();
|
||||
|
||||
DenseMap<bool, VirtReg2IndexFunctor> Loaded;
|
||||
|
||||
for (MachineFunction::iterator mbbi = MF.begin(), E = MF.end();
|
||||
mbbi != E; ++mbbi) {
|
||||
DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n");
|
||||
for (MachineBasicBlock::iterator mii = mbbi->begin(),
|
||||
mie = mbbi->end(); mii != mie; ++mii) {
|
||||
Loaded.grow(MF.getSSARegMap()->getLastVirtReg());
|
||||
for (unsigned i = 0,e = mii->getNumOperands(); i != e; ++i){
|
||||
MachineOperand& mop = mii->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() &&
|
||||
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
||||
unsigned virtReg = mop.getReg();
|
||||
unsigned physReg = VRM.getPhys(virtReg);
|
||||
if (mop.isUse() && VRM.hasStackSlot(mop.getReg()) &&
|
||||
!Loaded[virtReg]) {
|
||||
mri.loadRegFromStackSlot(*mbbi, mii, physReg,
|
||||
VRM.getStackSlot(virtReg));
|
||||
Loaded[virtReg] = true;
|
||||
DEBUG(std::cerr << '\t';
|
||||
prior(mii)->print(std::cerr, &TM));
|
||||
++NumLoads;
|
||||
}
|
||||
|
||||
if (mop.isDef() && VRM.hasStackSlot(mop.getReg())) {
|
||||
mri.storeRegToStackSlot(*mbbi, next(mii), physReg,
|
||||
VRM.getStackSlot(virtReg));
|
||||
++NumStores;
|
||||
}
|
||||
mii->SetMachineOperandReg(i, physReg);
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << '\t'; mii->print(std::cerr, &TM));
|
||||
Loaded.clear();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Local Spiller Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class LocalSpiller : public Spiller {
|
||||
typedef std::vector<unsigned> Phys2VirtMap;
|
||||
typedef std::vector<bool> PhysFlag;
|
||||
typedef DenseMap<MachineInstr*, VirtReg2IndexFunctor> Virt2MI;
|
||||
|
||||
MachineFunction *MF;
|
||||
const TargetMachine *TM;
|
||||
const TargetInstrInfo *TII;
|
||||
const MRegisterInfo *MRI;
|
||||
const VirtRegMap *VRM;
|
||||
Phys2VirtMap p2vMap_;
|
||||
PhysFlag dirty_;
|
||||
Virt2MI lastDef_;
|
||||
|
||||
public:
|
||||
bool runOnMachineFunction(MachineFunction &MF, const VirtRegMap &VRM);
|
||||
|
||||
private:
|
||||
void vacateJustPhysReg(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned physReg);
|
||||
|
||||
void vacatePhysReg(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned physReg) {
|
||||
vacateJustPhysReg(mbb, mii, physReg);
|
||||
for (const unsigned* as = MRI->getAliasSet(physReg); *as; ++as)
|
||||
vacateJustPhysReg(mbb, mii, *as);
|
||||
}
|
||||
|
||||
void handleUse(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned virtReg,
|
||||
unsigned physReg) {
|
||||
// check if we are replacing a previous mapping
|
||||
if (p2vMap_[physReg] != virtReg) {
|
||||
vacatePhysReg(mbb, mii, physReg);
|
||||
p2vMap_[physReg] = virtReg;
|
||||
// load if necessary
|
||||
if (VRM->hasStackSlot(virtReg)) {
|
||||
MRI->loadRegFromStackSlot(mbb, mii, physReg,
|
||||
VRM->getStackSlot(virtReg));
|
||||
++NumLoads;
|
||||
DEBUG(std::cerr << "added: ";
|
||||
prior(mii)->print(std::cerr, TM));
|
||||
lastDef_[virtReg] = mii;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleDef(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned virtReg,
|
||||
unsigned physReg) {
|
||||
// check if we are replacing a previous mapping
|
||||
if (p2vMap_[physReg] != virtReg)
|
||||
vacatePhysReg(mbb, mii, physReg);
|
||||
|
||||
p2vMap_[physReg] = virtReg;
|
||||
dirty_[physReg] = true;
|
||||
lastDef_[virtReg] = mii;
|
||||
}
|
||||
|
||||
void eliminateVirtRegsInMbb(MachineBasicBlock& mbb);
|
||||
};
|
||||
}
|
||||
|
||||
bool LocalSpiller::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');
|
||||
|
||||
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
|
||||
p2vMap_.assign(p2vMap_.size(), 0);
|
||||
dirty_.assign(dirty_.size(), false);
|
||||
lastDef_.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LocalSpiller::vacateJustPhysReg(MachineBasicBlock& mbb,
|
||||
MachineBasicBlock::iterator mii,
|
||||
unsigned physReg) {
|
||||
unsigned virtReg = p2vMap_[physReg];
|
||||
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(),
|
||||
nextLastRef,
|
||||
physReg,
|
||||
VRM->getStackSlot(virtReg));
|
||||
++NumStores;
|
||||
DEBUG(std::cerr << "added: ";
|
||||
prior(nextLastRef)->print(std::cerr, TM);
|
||||
std::cerr << "after: ";
|
||||
lastDef->print(std::cerr, TM));
|
||||
lastDef_[virtReg] = 0;
|
||||
}
|
||||
p2vMap_[physReg] = 0;
|
||||
dirty_[physReg] = false;
|
||||
}
|
||||
|
||||
void LocalSpiller::eliminateVirtRegsInMbb(MachineBasicBlock &MBB) {
|
||||
for (MachineBasicBlock::iterator MI = MBB.begin(), E = MBB.end();
|
||||
MI != E; ++MI) {
|
||||
|
||||
// if we have references to memory operands make sure
|
||||
// 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(MI); i != e; ++i) {
|
||||
if (VRM->hasPhys(i->second))
|
||||
vacateJustPhysReg(MBB, MI, VRM->getPhys(i->second));
|
||||
}
|
||||
|
||||
// rewrite all used operands
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = MI->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && op.isUse() &&
|
||||
MRegisterInfo::isVirtualRegister(op.getReg())) {
|
||||
unsigned virtReg = op.getReg();
|
||||
unsigned physReg = VRM->getPhys(virtReg);
|
||||
handleUse(MBB, MI, virtReg, physReg);
|
||||
MI->SetMachineOperandReg(i, physReg);
|
||||
// mark as dirty if this is def&use
|
||||
if (op.isDef()) {
|
||||
dirty_[physReg] = true;
|
||||
lastDef_[virtReg] = MI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spill implicit physical register defs
|
||||
const TargetInstrDescriptor& tid = TII->get(MI->getOpcode());
|
||||
for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
|
||||
vacatePhysReg(MBB, MI, *id);
|
||||
|
||||
// spill explicit physical register defs
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = MI->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && !op.isUse() &&
|
||||
MRegisterInfo::isPhysicalRegister(op.getReg()))
|
||||
vacatePhysReg(MBB, MI, op.getReg());
|
||||
}
|
||||
|
||||
// rewrite def operands (def&use was handled with the
|
||||
// uses so don't check for those here)
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& op = MI->getOperand(i);
|
||||
if (op.isRegister() && op.getReg() && !op.isUse())
|
||||
if (MRegisterInfo::isPhysicalRegister(op.getReg()))
|
||||
vacatePhysReg(MBB, MI, op.getReg());
|
||||
else {
|
||||
unsigned physReg = VRM->getPhys(op.getReg());
|
||||
handleDef(MBB, MI, op.getReg(), physReg);
|
||||
MI->SetMachineOperandReg(i, physReg);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << '\t'; MI->print(std::cerr, TM));
|
||||
}
|
||||
|
||||
for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i)
|
||||
vacateJustPhysReg(MBB, MBB.getFirstTerminator(), i);
|
||||
}
|
||||
|
||||
|
||||
llvm::Spiller* llvm::createSpiller() {
|
||||
switch (SpillerOpt) {
|
||||
default: assert(0 && "Unreachable!");
|
||||
case local:
|
||||
return new LocalSpiller();
|
||||
case simple:
|
||||
return new SimpleSpiller();
|
||||
}
|
||||
}
|
||||
|
@ -7,125 +7,121 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a virtual register map. This maps virtual
|
||||
// registers to physical registers and virtual registers to stack
|
||||
// slots. It is created and updated by a register allocator and then
|
||||
// used by a machine code rewriter that adds spill code and rewrites
|
||||
// virtual into physical register references.
|
||||
// This file implements a virtual register map. This maps virtual registers to
|
||||
// physical registers and virtual registers to stack slots. It is created and
|
||||
// updated by a register allocator and then used by a machine code rewriter that
|
||||
// adds spill code and rewrites virtual into physical register references.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_VIRTREGMAP_H
|
||||
#define LLVM_CODEGEN_VIRTREGMAP_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
#include "llvm/Target/MRegisterInfo.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <climits>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
class MachineInstr;
|
||||
|
||||
class MachineInstr;
|
||||
class VirtRegMap {
|
||||
public:
|
||||
typedef DenseMap<unsigned, VirtReg2IndexFunctor> Virt2PhysMap;
|
||||
typedef DenseMap<int, VirtReg2IndexFunctor> Virt2StackSlotMap;
|
||||
typedef std::multimap<MachineInstr*, unsigned> MI2VirtMap;
|
||||
|
||||
class VirtRegMap {
|
||||
public:
|
||||
typedef DenseMap<unsigned, VirtReg2IndexFunctor> Virt2PhysMap;
|
||||
typedef DenseMap<int, VirtReg2IndexFunctor> Virt2StackSlotMap;
|
||||
typedef std::multimap<MachineInstr*, unsigned> MI2VirtMap;
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
Virt2PhysMap v2pMap_;
|
||||
Virt2StackSlotMap v2ssMap_;
|
||||
MI2VirtMap mi2vMap_;
|
||||
|
||||
VirtRegMap(const VirtRegMap&); // DO NOT IMPLEMENT
|
||||
void operator=(const VirtRegMap&); // DO NOT IMPLEMENT
|
||||
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
Virt2PhysMap v2pMap_;
|
||||
Virt2StackSlotMap v2ssMap_;
|
||||
MI2VirtMap mi2vMap_;
|
||||
|
||||
// do not implement
|
||||
VirtRegMap(const VirtRegMap& rhs);
|
||||
const VirtRegMap& operator=(const VirtRegMap& rhs);
|
||||
|
||||
enum {
|
||||
NO_PHYS_REG = 0,
|
||||
NO_STACK_SLOT = INT_MAX
|
||||
};
|
||||
|
||||
public:
|
||||
VirtRegMap(MachineFunction& mf)
|
||||
: mf_(&mf),
|
||||
v2pMap_(NO_PHYS_REG),
|
||||
v2ssMap_(NO_STACK_SLOT) {
|
||||
grow();
|
||||
}
|
||||
|
||||
void grow() {
|
||||
v2pMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
|
||||
v2ssMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
|
||||
}
|
||||
|
||||
bool hasPhys(unsigned virtReg) const {
|
||||
return getPhys(virtReg) != NO_PHYS_REG;
|
||||
}
|
||||
|
||||
unsigned getPhys(unsigned virtReg) const {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
return v2pMap_[virtReg];
|
||||
}
|
||||
|
||||
void assignVirt2Phys(unsigned virtReg, unsigned physReg) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg) &&
|
||||
MRegisterInfo::isPhysicalRegister(physReg));
|
||||
assert(v2pMap_[virtReg] == NO_PHYS_REG &&
|
||||
"attempt to assign physical register to already mapped "
|
||||
"virtual register");
|
||||
v2pMap_[virtReg] = physReg;
|
||||
}
|
||||
|
||||
void clearVirt(unsigned virtReg) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2pMap_[virtReg] != NO_PHYS_REG &&
|
||||
"attempt to clear a not assigned virtual register");
|
||||
v2pMap_[virtReg] = NO_PHYS_REG;
|
||||
}
|
||||
|
||||
void clearAllVirt() {
|
||||
v2pMap_.clear();
|
||||
grow();
|
||||
}
|
||||
|
||||
bool hasStackSlot(unsigned virtReg) const {
|
||||
return getStackSlot(virtReg) != NO_STACK_SLOT;
|
||||
}
|
||||
|
||||
int getStackSlot(unsigned virtReg) const {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
return v2ssMap_[virtReg];
|
||||
}
|
||||
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
void assignVirt2StackSlot(unsigned virtReg, int frameIndex);
|
||||
|
||||
void virtFolded(unsigned virtReg,
|
||||
MachineInstr* oldMI,
|
||||
MachineInstr* newMI);
|
||||
|
||||
std::pair<MI2VirtMap::const_iterator, MI2VirtMap::const_iterator>
|
||||
getFoldedVirts(MachineInstr* MI) const {
|
||||
return mi2vMap_.equal_range(MI);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const VirtRegMap& li);
|
||||
enum {
|
||||
NO_PHYS_REG = 0,
|
||||
NO_STACK_SLOT = ~0 >> 1
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const VirtRegMap& li);
|
||||
public:
|
||||
VirtRegMap(MachineFunction& mf)
|
||||
: mf_(&mf), v2pMap_(NO_PHYS_REG), v2ssMap_(NO_STACK_SLOT) {
|
||||
grow();
|
||||
}
|
||||
|
||||
struct Spiller {
|
||||
virtual ~Spiller();
|
||||
void grow();
|
||||
|
||||
virtual bool runOnMachineFunction(MachineFunction& mf, const VirtRegMap& vrm) = 0;
|
||||
bool hasPhys(unsigned virtReg) const {
|
||||
return getPhys(virtReg) != NO_PHYS_REG;
|
||||
}
|
||||
|
||||
};
|
||||
unsigned getPhys(unsigned virtReg) const {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
return v2pMap_[virtReg];
|
||||
}
|
||||
|
||||
Spiller* createSpiller();
|
||||
void assignVirt2Phys(unsigned virtReg, unsigned physReg) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg) &&
|
||||
MRegisterInfo::isPhysicalRegister(physReg));
|
||||
assert(v2pMap_[virtReg] == NO_PHYS_REG &&
|
||||
"attempt to assign physical register to already mapped "
|
||||
"virtual register");
|
||||
v2pMap_[virtReg] = physReg;
|
||||
}
|
||||
|
||||
void clearVirt(unsigned virtReg) {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
assert(v2pMap_[virtReg] != NO_PHYS_REG &&
|
||||
"attempt to clear a not assigned virtual register");
|
||||
v2pMap_[virtReg] = NO_PHYS_REG;
|
||||
}
|
||||
|
||||
void clearAllVirt() {
|
||||
v2pMap_.clear();
|
||||
grow();
|
||||
}
|
||||
|
||||
bool hasStackSlot(unsigned virtReg) const {
|
||||
return getStackSlot(virtReg) != NO_STACK_SLOT;
|
||||
}
|
||||
|
||||
int getStackSlot(unsigned virtReg) const {
|
||||
assert(MRegisterInfo::isVirtualRegister(virtReg));
|
||||
return v2ssMap_[virtReg];
|
||||
}
|
||||
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
void assignVirt2StackSlot(unsigned virtReg, int frameIndex);
|
||||
|
||||
void virtFolded(unsigned virtReg, MachineInstr* oldMI,
|
||||
MachineInstr* newMI);
|
||||
|
||||
std::pair<MI2VirtMap::const_iterator, MI2VirtMap::const_iterator>
|
||||
getFoldedVirts(MachineInstr* MI) const {
|
||||
return mi2vMap_.equal_range(MI);
|
||||
}
|
||||
|
||||
void print(std::ostream &OS) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &OS, const VirtRegMap &VRM) {
|
||||
VRM.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Spiller interface: Implementations of this interface assign spilled
|
||||
/// virtual registers to stack slots, rewriting the code.
|
||||
struct Spiller {
|
||||
virtual ~Spiller();
|
||||
virtual bool runOnMachineFunction(MachineFunction &MF,
|
||||
const VirtRegMap &VRM) = 0;
|
||||
};
|
||||
|
||||
/// createSpiller - Create an return a spiller object, as specified on the
|
||||
/// command line.
|
||||
Spiller* createSpiller();
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user