mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
Convert indentation to 2 spaces.
llvm-svn: 15489
This commit is contained in:
parent
f846e483bb
commit
db3b503b6f
@ -37,447 +37,446 @@
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
RegisterAnalysis<LiveIntervals> X("liveintervals",
|
||||
"Live Interval Analysis");
|
||||
RegisterAnalysis<LiveIntervals> X("liveintervals", "Live Interval Analysis");
|
||||
|
||||
Statistic<> numIntervals
|
||||
("liveintervals", "Number of original intervals");
|
||||
Statistic<> numIntervals
|
||||
("liveintervals", "Number of original intervals");
|
||||
|
||||
Statistic<> numIntervalsAfter
|
||||
("liveintervals", "Number of intervals after coalescing");
|
||||
Statistic<> numIntervalsAfter
|
||||
("liveintervals", "Number of intervals after coalescing");
|
||||
|
||||
Statistic<> numJoins
|
||||
("liveintervals", "Number of interval joins performed");
|
||||
Statistic<> numJoins
|
||||
("liveintervals", "Number of interval joins performed");
|
||||
|
||||
Statistic<> numPeep
|
||||
("liveintervals", "Number of identity moves eliminated after coalescing");
|
||||
Statistic<> numPeep
|
||||
("liveintervals", "Number of identity moves eliminated after coalescing");
|
||||
|
||||
Statistic<> numFolded
|
||||
("liveintervals", "Number of loads/stores folded into instructions");
|
||||
Statistic<> numFolded
|
||||
("liveintervals", "Number of loads/stores folded into instructions");
|
||||
|
||||
cl::opt<bool>
|
||||
EnableJoining("join-liveintervals",
|
||||
cl::desc("Join compatible live intervals"),
|
||||
cl::init(true));
|
||||
cl::opt<bool>
|
||||
EnableJoining("join-liveintervals",
|
||||
cl::desc("Join compatible live intervals"),
|
||||
cl::init(true));
|
||||
};
|
||||
|
||||
void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const
|
||||
{
|
||||
AU.addPreserved<LiveVariables>();
|
||||
AU.addRequired<LiveVariables>();
|
||||
AU.addPreservedID(PHIEliminationID);
|
||||
AU.addRequiredID(PHIEliminationID);
|
||||
AU.addRequiredID(TwoAddressInstructionPassID);
|
||||
AU.addRequired<LoopInfo>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
AU.addPreserved<LiveVariables>();
|
||||
AU.addRequired<LiveVariables>();
|
||||
AU.addPreservedID(PHIEliminationID);
|
||||
AU.addRequiredID(PHIEliminationID);
|
||||
AU.addRequiredID(TwoAddressInstructionPassID);
|
||||
AU.addRequired<LoopInfo>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
void LiveIntervals::releaseMemory()
|
||||
{
|
||||
mi2iMap_.clear();
|
||||
i2miMap_.clear();
|
||||
r2iMap_.clear();
|
||||
r2rMap_.clear();
|
||||
mi2iMap_.clear();
|
||||
i2miMap_.clear();
|
||||
r2iMap_.clear();
|
||||
r2rMap_.clear();
|
||||
}
|
||||
|
||||
|
||||
/// runOnMachineFunction - Register allocate the whole function
|
||||
///
|
||||
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
lv_ = &getAnalysis<LiveVariables>();
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
lv_ = &getAnalysis<LiveVariables>();
|
||||
|
||||
// number MachineInstrs
|
||||
unsigned miIndex = 0;
|
||||
for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
|
||||
mbb != mbbEnd; ++mbb)
|
||||
for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
|
||||
mi != miEnd; ++mi) {
|
||||
bool inserted = mi2iMap_.insert(std::make_pair(mi, miIndex)).second;
|
||||
assert(inserted && "multiple MachineInstr -> index mappings");
|
||||
i2miMap_.push_back(mi);
|
||||
miIndex += InstrSlots::NUM;
|
||||
}
|
||||
|
||||
computeIntervals();
|
||||
|
||||
numIntervals += getNumIntervals();
|
||||
|
||||
#if 1
|
||||
DEBUG(std::cerr << "********** INTERVALS **********\n");
|
||||
DEBUG(for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
std::cerr << I->second << "\n");
|
||||
#endif
|
||||
|
||||
// join intervals if requested
|
||||
if (EnableJoining) joinIntervals();
|
||||
|
||||
numIntervalsAfter += getNumIntervals();
|
||||
|
||||
// perform a final pass over the instructions and compute spill
|
||||
// weights, coalesce virtual registers and remove identity moves
|
||||
const LoopInfo& loopInfo = getAnalysis<LoopInfo>();
|
||||
const TargetInstrInfo& tii = *tm_->getInstrInfo();
|
||||
|
||||
for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end();
|
||||
mbbi != mbbe; ++mbbi) {
|
||||
MachineBasicBlock* mbb = mbbi;
|
||||
unsigned loopDepth = loopInfo.getLoopDepth(mbb->getBasicBlock());
|
||||
|
||||
for (MachineBasicBlock::iterator mii = mbb->begin(), mie = mbb->end();
|
||||
mii != mie; ) {
|
||||
// if the move will be an identity move delete it
|
||||
unsigned srcReg, dstReg, RegRep;
|
||||
if (tii.isMoveInstr(*mii, srcReg, dstReg) &&
|
||||
(RegRep = rep(srcReg)) == rep(dstReg)) {
|
||||
// remove from def list
|
||||
LiveInterval &interval = getOrCreateInterval(RegRep);
|
||||
// remove index -> MachineInstr and
|
||||
// MachineInstr -> index mappings
|
||||
Mi2IndexMap::iterator mi2i = mi2iMap_.find(mii);
|
||||
if (mi2i != mi2iMap_.end()) {
|
||||
i2miMap_[mi2i->second/InstrSlots::NUM] = 0;
|
||||
mi2iMap_.erase(mi2i);
|
||||
}
|
||||
mii = mbbi->erase(mii);
|
||||
++numPeep;
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < mii->getNumOperands(); ++i) {
|
||||
const MachineOperand& mop = mii->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() &&
|
||||
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
||||
// replace register with representative register
|
||||
unsigned reg = rep(mop.getReg());
|
||||
mii->SetMachineOperandReg(i, reg);
|
||||
|
||||
LiveInterval &RegInt = getInterval(reg);
|
||||
RegInt.weight +=
|
||||
(mop.isUse() + mop.isDef()) * pow(10.0F, loopDepth);
|
||||
}
|
||||
}
|
||||
++mii;
|
||||
}
|
||||
}
|
||||
// number MachineInstrs
|
||||
unsigned miIndex = 0;
|
||||
for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
|
||||
mbb != mbbEnd; ++mbb)
|
||||
for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
|
||||
mi != miEnd; ++mi) {
|
||||
bool inserted = mi2iMap_.insert(std::make_pair(mi, miIndex)).second;
|
||||
assert(inserted && "multiple MachineInstr -> index mappings");
|
||||
i2miMap_.push_back(mi);
|
||||
miIndex += InstrSlots::NUM;
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "********** INTERVALS **********\n");
|
||||
DEBUG (for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
std::cerr << I->second << "\n");
|
||||
DEBUG(std::cerr << "********** MACHINEINSTRS **********\n");
|
||||
DEBUG(
|
||||
for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end();
|
||||
mbbi != mbbe; ++mbbi) {
|
||||
std::cerr << ((Value*)mbbi->getBasicBlock())->getName() << ":\n";
|
||||
for (MachineBasicBlock::iterator mii = mbbi->begin(),
|
||||
mie = mbbi->end(); mii != mie; ++mii) {
|
||||
std::cerr << getInstructionIndex(mii) << '\t';
|
||||
mii->print(std::cerr, tm_);
|
||||
}
|
||||
});
|
||||
computeIntervals();
|
||||
|
||||
return true;
|
||||
numIntervals += getNumIntervals();
|
||||
|
||||
#if 1
|
||||
DEBUG(std::cerr << "********** INTERVALS **********\n");
|
||||
DEBUG(for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
std::cerr << I->second << "\n");
|
||||
#endif
|
||||
|
||||
// join intervals if requested
|
||||
if (EnableJoining) joinIntervals();
|
||||
|
||||
numIntervalsAfter += getNumIntervals();
|
||||
|
||||
// perform a final pass over the instructions and compute spill
|
||||
// weights, coalesce virtual registers and remove identity moves
|
||||
const LoopInfo& loopInfo = getAnalysis<LoopInfo>();
|
||||
const TargetInstrInfo& tii = *tm_->getInstrInfo();
|
||||
|
||||
for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end();
|
||||
mbbi != mbbe; ++mbbi) {
|
||||
MachineBasicBlock* mbb = mbbi;
|
||||
unsigned loopDepth = loopInfo.getLoopDepth(mbb->getBasicBlock());
|
||||
|
||||
for (MachineBasicBlock::iterator mii = mbb->begin(), mie = mbb->end();
|
||||
mii != mie; ) {
|
||||
// if the move will be an identity move delete it
|
||||
unsigned srcReg, dstReg, RegRep;
|
||||
if (tii.isMoveInstr(*mii, srcReg, dstReg) &&
|
||||
(RegRep = rep(srcReg)) == rep(dstReg)) {
|
||||
// remove from def list
|
||||
LiveInterval &interval = getOrCreateInterval(RegRep);
|
||||
// remove index -> MachineInstr and
|
||||
// MachineInstr -> index mappings
|
||||
Mi2IndexMap::iterator mi2i = mi2iMap_.find(mii);
|
||||
if (mi2i != mi2iMap_.end()) {
|
||||
i2miMap_[mi2i->second/InstrSlots::NUM] = 0;
|
||||
mi2iMap_.erase(mi2i);
|
||||
}
|
||||
mii = mbbi->erase(mii);
|
||||
++numPeep;
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < mii->getNumOperands(); ++i) {
|
||||
const MachineOperand& mop = mii->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() &&
|
||||
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
||||
// replace register with representative register
|
||||
unsigned reg = rep(mop.getReg());
|
||||
mii->SetMachineOperandReg(i, reg);
|
||||
|
||||
LiveInterval &RegInt = getInterval(reg);
|
||||
RegInt.weight +=
|
||||
(mop.isUse() + mop.isDef()) * pow(10.0F, loopDepth);
|
||||
}
|
||||
}
|
||||
++mii;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "********** INTERVALS **********\n");
|
||||
DEBUG (for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
std::cerr << I->second << "\n");
|
||||
DEBUG(std::cerr << "********** MACHINEINSTRS **********\n");
|
||||
DEBUG(
|
||||
for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end();
|
||||
mbbi != mbbe; ++mbbi) {
|
||||
std::cerr << ((Value*)mbbi->getBasicBlock())->getName() << ":\n";
|
||||
for (MachineBasicBlock::iterator mii = mbbi->begin(),
|
||||
mie = mbbi->end(); mii != mie; ++mii) {
|
||||
std::cerr << getInstructionIndex(mii) << '\t';
|
||||
mii->print(std::cerr, tm_);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<LiveInterval*> LiveIntervals::addIntervalsForSpills(
|
||||
const LiveInterval& li,
|
||||
VirtRegMap& vrm,
|
||||
int slot)
|
||||
const LiveInterval& li,
|
||||
VirtRegMap& vrm,
|
||||
int slot)
|
||||
{
|
||||
std::vector<LiveInterval*> added;
|
||||
std::vector<LiveInterval*> added;
|
||||
|
||||
assert(li.weight != HUGE_VAL &&
|
||||
"attempt to spill already spilled interval!");
|
||||
assert(li.weight != HUGE_VAL &&
|
||||
"attempt to spill already spilled interval!");
|
||||
|
||||
DEBUG(std::cerr << "\t\t\t\tadding intervals for spills for interval: "
|
||||
<< li << '\n');
|
||||
DEBUG(std::cerr << "\t\t\t\tadding intervals for spills for interval: "
|
||||
<< li << '\n');
|
||||
|
||||
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(li.reg);
|
||||
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(li.reg);
|
||||
|
||||
for (LiveInterval::Ranges::const_iterator
|
||||
i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
|
||||
unsigned index = getBaseIndex(i->start);
|
||||
unsigned end = getBaseIndex(i->end-1) + InstrSlots::NUM;
|
||||
for (; index != end; index += InstrSlots::NUM) {
|
||||
// skip deleted instructions
|
||||
while (index != end && !getInstructionFromIndex(index))
|
||||
index += InstrSlots::NUM;
|
||||
if (index == end) break;
|
||||
for (LiveInterval::Ranges::const_iterator
|
||||
i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
|
||||
unsigned index = getBaseIndex(i->start);
|
||||
unsigned end = getBaseIndex(i->end-1) + InstrSlots::NUM;
|
||||
for (; index != end; index += InstrSlots::NUM) {
|
||||
// skip deleted instructions
|
||||
while (index != end && !getInstructionFromIndex(index))
|
||||
index += InstrSlots::NUM;
|
||||
if (index == end) break;
|
||||
|
||||
MachineBasicBlock::iterator mi = getInstructionFromIndex(index);
|
||||
MachineBasicBlock::iterator mi = getInstructionFromIndex(index);
|
||||
|
||||
for_operand:
|
||||
for (unsigned i = 0; i != mi->getNumOperands(); ++i) {
|
||||
MachineOperand& mop = mi->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() == li.reg) {
|
||||
if (MachineInstr* fmi =
|
||||
mri_->foldMemoryOperand(mi, i, slot)) {
|
||||
lv_->instructionChanged(mi, fmi);
|
||||
vrm.virtFolded(li.reg, mi, fmi);
|
||||
mi2iMap_.erase(mi);
|
||||
i2miMap_[index/InstrSlots::NUM] = fmi;
|
||||
mi2iMap_[fmi] = index;
|
||||
MachineBasicBlock& mbb = *mi->getParent();
|
||||
mi = mbb.insert(mbb.erase(mi), fmi);
|
||||
++numFolded;
|
||||
goto for_operand;
|
||||
}
|
||||
else {
|
||||
// This is tricky. We need to add information in
|
||||
// the interval about the spill code so we have to
|
||||
// use our extra load/store slots.
|
||||
//
|
||||
// If we have a use we are going to have a load so
|
||||
// we start the interval from the load slot
|
||||
// onwards. Otherwise we start from the def slot.
|
||||
unsigned start = (mop.isUse() ?
|
||||
getLoadIndex(index) :
|
||||
getDefIndex(index));
|
||||
// If we have a def we are going to have a store
|
||||
// right after it so we end the interval after the
|
||||
// use of the next instruction. Otherwise we end
|
||||
// after the use of this instruction.
|
||||
unsigned end = 1 + (mop.isDef() ?
|
||||
getStoreIndex(index) :
|
||||
getUseIndex(index));
|
||||
for_operand:
|
||||
for (unsigned i = 0; i != mi->getNumOperands(); ++i) {
|
||||
MachineOperand& mop = mi->getOperand(i);
|
||||
if (mop.isRegister() && mop.getReg() == li.reg) {
|
||||
if (MachineInstr* fmi =
|
||||
mri_->foldMemoryOperand(mi, i, slot)) {
|
||||
lv_->instructionChanged(mi, fmi);
|
||||
vrm.virtFolded(li.reg, mi, fmi);
|
||||
mi2iMap_.erase(mi);
|
||||
i2miMap_[index/InstrSlots::NUM] = fmi;
|
||||
mi2iMap_[fmi] = index;
|
||||
MachineBasicBlock& mbb = *mi->getParent();
|
||||
mi = mbb.insert(mbb.erase(mi), fmi);
|
||||
++numFolded;
|
||||
goto for_operand;
|
||||
}
|
||||
else {
|
||||
// This is tricky. We need to add information in
|
||||
// the interval about the spill code so we have to
|
||||
// use our extra load/store slots.
|
||||
//
|
||||
// If we have a use we are going to have a load so
|
||||
// we start the interval from the load slot
|
||||
// onwards. Otherwise we start from the def slot.
|
||||
unsigned start = (mop.isUse() ?
|
||||
getLoadIndex(index) :
|
||||
getDefIndex(index));
|
||||
// If we have a def we are going to have a store
|
||||
// right after it so we end the interval after the
|
||||
// use of the next instruction. Otherwise we end
|
||||
// after the use of this instruction.
|
||||
unsigned end = 1 + (mop.isDef() ?
|
||||
getStoreIndex(index) :
|
||||
getUseIndex(index));
|
||||
|
||||
// create a new register for this spill
|
||||
unsigned nReg =
|
||||
mf_->getSSARegMap()->createVirtualRegister(rc);
|
||||
mi->SetMachineOperandReg(i, nReg);
|
||||
vrm.grow();
|
||||
vrm.assignVirt2StackSlot(nReg, slot);
|
||||
LiveInterval& nI = getOrCreateInterval(nReg);
|
||||
assert(nI.empty());
|
||||
// the spill weight is now infinity as it
|
||||
// cannot be spilled again
|
||||
nI.weight = HUGE_VAL;
|
||||
LiveRange LR(start, end, nI.getNextValue());
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
nI.addRange(LR);
|
||||
added.push_back(&nI);
|
||||
// update live variables
|
||||
lv_->addVirtualRegisterKilled(nReg, mi);
|
||||
DEBUG(std::cerr << "\t\t\t\tadded new interval: "
|
||||
<< nI << '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
// create a new register for this spill
|
||||
unsigned nReg =
|
||||
mf_->getSSARegMap()->createVirtualRegister(rc);
|
||||
mi->SetMachineOperandReg(i, nReg);
|
||||
vrm.grow();
|
||||
vrm.assignVirt2StackSlot(nReg, slot);
|
||||
LiveInterval& nI = getOrCreateInterval(nReg);
|
||||
assert(nI.empty());
|
||||
// the spill weight is now infinity as it
|
||||
// cannot be spilled again
|
||||
nI.weight = HUGE_VAL;
|
||||
LiveRange LR(start, end, nI.getNextValue());
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
nI.addRange(LR);
|
||||
added.push_back(&nI);
|
||||
// update live variables
|
||||
lv_->addVirtualRegisterKilled(nReg, mi);
|
||||
DEBUG(std::cerr << "\t\t\t\tadded new interval: "
|
||||
<< nI << '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
return added;
|
||||
}
|
||||
|
||||
void LiveIntervals::printRegName(unsigned reg) const
|
||||
{
|
||||
if (MRegisterInfo::isPhysicalRegister(reg))
|
||||
std::cerr << mri_->getName(reg);
|
||||
else
|
||||
std::cerr << "%reg" << reg;
|
||||
if (MRegisterInfo::isPhysicalRegister(reg))
|
||||
std::cerr << mri_->getName(reg);
|
||||
else
|
||||
std::cerr << "%reg" << reg;
|
||||
}
|
||||
|
||||
void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval)
|
||||
{
|
||||
DEBUG(std::cerr << "\t\tregister: "; printRegName(interval.reg));
|
||||
LiveVariables::VarInfo& vi = lv_->getVarInfo(interval.reg);
|
||||
DEBUG(std::cerr << "\t\tregister: "; printRegName(interval.reg));
|
||||
LiveVariables::VarInfo& vi = lv_->getVarInfo(interval.reg);
|
||||
|
||||
// Virtual registers may be defined multiple times (due to phi
|
||||
// elimination and 2-addr elimination). Much of what we do only has to be
|
||||
// done once for the vreg. We use an empty interval to detect the first
|
||||
// time we see a vreg.
|
||||
if (interval.empty()) {
|
||||
// Get the Idx of the defining instructions.
|
||||
unsigned defIndex = getDefIndex(getInstructionIndex(mi));
|
||||
// Virtual registers may be defined multiple times (due to phi
|
||||
// elimination and 2-addr elimination). Much of what we do only has to be
|
||||
// done once for the vreg. We use an empty interval to detect the first
|
||||
// time we see a vreg.
|
||||
if (interval.empty()) {
|
||||
// Get the Idx of the defining instructions.
|
||||
unsigned defIndex = getDefIndex(getInstructionIndex(mi));
|
||||
|
||||
unsigned ValNum = interval.getNextValue();
|
||||
assert(ValNum == 0 && "First value in interval is not 0?");
|
||||
ValNum = 0; // Clue in the optimizer.
|
||||
unsigned ValNum = interval.getNextValue();
|
||||
assert(ValNum == 0 && "First value in interval is not 0?");
|
||||
ValNum = 0; // Clue in the optimizer.
|
||||
|
||||
// Loop over all of the blocks that the vreg is defined in. There are
|
||||
// two cases we have to handle here. The most common case is a vreg
|
||||
// whose lifetime is contained within a basic block. In this case there
|
||||
// will be a single kill, in MBB, which comes after the definition.
|
||||
if (vi.Kills.size() == 1 && vi.Kills[0]->getParent() == mbb) {
|
||||
// FIXME: what about dead vars?
|
||||
unsigned killIdx;
|
||||
if (vi.Kills[0] != mi)
|
||||
killIdx = getUseIndex(getInstructionIndex(vi.Kills[0]))+1;
|
||||
else
|
||||
killIdx = defIndex+1;
|
||||
// Loop over all of the blocks that the vreg is defined in. There are
|
||||
// two cases we have to handle here. The most common case is a vreg
|
||||
// whose lifetime is contained within a basic block. In this case there
|
||||
// will be a single kill, in MBB, which comes after the definition.
|
||||
if (vi.Kills.size() == 1 && vi.Kills[0]->getParent() == mbb) {
|
||||
// FIXME: what about dead vars?
|
||||
unsigned killIdx;
|
||||
if (vi.Kills[0] != mi)
|
||||
killIdx = getUseIndex(getInstructionIndex(vi.Kills[0]))+1;
|
||||
else
|
||||
killIdx = defIndex+1;
|
||||
|
||||
// If the kill happens after the definition, we have an intra-block
|
||||
// live range.
|
||||
if (killIdx > defIndex) {
|
||||
assert(vi.AliveBlocks.empty() &&
|
||||
"Shouldn't be alive across any blocks!");
|
||||
LiveRange LR(defIndex, killIdx, ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR << "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The other case we handle is when a virtual register lives to the end
|
||||
// of the defining block, potentially live across some blocks, then is
|
||||
// live into some number of blocks, but gets killed. Start by adding a
|
||||
// range that goes from this definition to the end of the defining block.
|
||||
LiveRange NewLR(defIndex, getInstructionIndex(&mbb->back()) +
|
||||
InstrSlots::NUM, ValNum);
|
||||
DEBUG(std::cerr << " +" << NewLR);
|
||||
interval.addRange(NewLR);
|
||||
|
||||
// Iterate over all of the blocks that the variable is completely
|
||||
// live in, adding [insrtIndex(begin), instrIndex(end)+4) to the
|
||||
// live interval.
|
||||
for (unsigned i = 0, e = vi.AliveBlocks.size(); i != e; ++i) {
|
||||
if (vi.AliveBlocks[i]) {
|
||||
MachineBasicBlock* mbb = mf_->getBlockNumbered(i);
|
||||
if (!mbb->empty()) {
|
||||
LiveRange LR(getInstructionIndex(&mbb->front()),
|
||||
getInstructionIndex(&mbb->back())+InstrSlots::NUM,
|
||||
ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, this virtual register is live from the start of any killing
|
||||
// block to the 'use' slot of the killing instruction.
|
||||
for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i) {
|
||||
MachineInstr *Kill = vi.Kills[i];
|
||||
LiveRange LR(getInstructionIndex(Kill->getParent()->begin()),
|
||||
getUseIndex(getInstructionIndex(Kill))+1, ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
|
||||
} else {
|
||||
// If this is the second time we see a virtual register definition, it
|
||||
// must be due to phi elimination or two addr elimination. If this is
|
||||
// the result of two address elimination, then the vreg is the first
|
||||
// operand, and is a def-and-use.
|
||||
if (mi->getOperand(0).isRegister() &&
|
||||
mi->getOperand(0).getReg() == interval.reg &&
|
||||
mi->getOperand(0).isDef() && mi->getOperand(0).isUse()) {
|
||||
// If this is a two-address definition, then we have already processed
|
||||
// the live range. The only problem is that we didn't realize there
|
||||
// are actually two values in the live interval. Because of this we
|
||||
// need to take the LiveRegion that defines this register and split it
|
||||
// into two values.
|
||||
unsigned DefIndex = getDefIndex(getInstructionIndex(vi.DefInst));
|
||||
unsigned RedefIndex = getDefIndex(getInstructionIndex(mi));
|
||||
|
||||
// Delete the initial value, which should be short and continuous,
|
||||
// becuase the 2-addr copy must be in the same MBB as the redef.
|
||||
interval.removeRange(DefIndex, RedefIndex);
|
||||
|
||||
LiveRange LR(DefIndex, RedefIndex, interval.getNextValue());
|
||||
DEBUG(std::cerr << " replace range with " << LR);
|
||||
interval.addRange(LR);
|
||||
|
||||
// If this redefinition is dead, we need to add a dummy unit live
|
||||
// range covering the def slot.
|
||||
for (LiveVariables::killed_iterator KI = lv_->dead_begin(mi),
|
||||
E = lv_->dead_end(mi); KI != E; ++KI)
|
||||
if (KI->second == interval.reg) {
|
||||
interval.addRange(LiveRange(RedefIndex, RedefIndex+1, 0));
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
|
||||
} else {
|
||||
// Otherwise, this must be because of phi elimination. If this is the
|
||||
// first redefinition of the vreg that we have seen, go back and change
|
||||
// the live range in the PHI block to be a different value number.
|
||||
if (interval.containsOneValue()) {
|
||||
assert(vi.Kills.size() == 1 &&
|
||||
"PHI elimination vreg should have one kill, the PHI itself!");
|
||||
|
||||
// Remove the old range that we now know has an incorrect number.
|
||||
MachineInstr *Killer = vi.Kills[0];
|
||||
unsigned Start = getInstructionIndex(Killer->getParent()->begin());
|
||||
unsigned End = getUseIndex(getInstructionIndex(Killer))+1;
|
||||
DEBUG(std::cerr << "Removing [" << Start << "," << End << "] from: "
|
||||
<< interval << "\n");
|
||||
interval.removeRange(Start, End);
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
|
||||
// Replace the interval with one of a NEW value number.
|
||||
LiveRange LR(Start, End, interval.getNextValue());
|
||||
DEBUG(std::cerr << " replace range with " << LR);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
}
|
||||
|
||||
// In the case of PHI elimination, each variable definition is only
|
||||
// live until the end of the block. We've already taken care of the
|
||||
// rest of the live range.
|
||||
unsigned defIndex = getDefIndex(getInstructionIndex(mi));
|
||||
LiveRange LR(defIndex,
|
||||
getInstructionIndex(&mbb->back()) + InstrSlots::NUM,
|
||||
interval.getNextValue());
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
// If the kill happens after the definition, we have an intra-block
|
||||
// live range.
|
||||
if (killIdx > defIndex) {
|
||||
assert(vi.AliveBlocks.empty() &&
|
||||
"Shouldn't be alive across any blocks!");
|
||||
LiveRange LR(defIndex, killIdx, ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR << "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << '\n');
|
||||
// The other case we handle is when a virtual register lives to the end
|
||||
// of the defining block, potentially live across some blocks, then is
|
||||
// live into some number of blocks, but gets killed. Start by adding a
|
||||
// range that goes from this definition to the end of the defining block.
|
||||
LiveRange NewLR(defIndex, getInstructionIndex(&mbb->back()) +
|
||||
InstrSlots::NUM, ValNum);
|
||||
DEBUG(std::cerr << " +" << NewLR);
|
||||
interval.addRange(NewLR);
|
||||
|
||||
// Iterate over all of the blocks that the variable is completely
|
||||
// live in, adding [insrtIndex(begin), instrIndex(end)+4) to the
|
||||
// live interval.
|
||||
for (unsigned i = 0, e = vi.AliveBlocks.size(); i != e; ++i) {
|
||||
if (vi.AliveBlocks[i]) {
|
||||
MachineBasicBlock* mbb = mf_->getBlockNumbered(i);
|
||||
if (!mbb->empty()) {
|
||||
LiveRange LR(getInstructionIndex(&mbb->front()),
|
||||
getInstructionIndex(&mbb->back())+InstrSlots::NUM,
|
||||
ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, this virtual register is live from the start of any killing
|
||||
// block to the 'use' slot of the killing instruction.
|
||||
for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i) {
|
||||
MachineInstr *Kill = vi.Kills[i];
|
||||
LiveRange LR(getInstructionIndex(Kill->getParent()->begin()),
|
||||
getUseIndex(getInstructionIndex(Kill))+1, ValNum);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
|
||||
} else {
|
||||
// If this is the second time we see a virtual register definition, it
|
||||
// must be due to phi elimination or two addr elimination. If this is
|
||||
// the result of two address elimination, then the vreg is the first
|
||||
// operand, and is a def-and-use.
|
||||
if (mi->getOperand(0).isRegister() &&
|
||||
mi->getOperand(0).getReg() == interval.reg &&
|
||||
mi->getOperand(0).isDef() && mi->getOperand(0).isUse()) {
|
||||
// If this is a two-address definition, then we have already processed
|
||||
// the live range. The only problem is that we didn't realize there
|
||||
// are actually two values in the live interval. Because of this we
|
||||
// need to take the LiveRegion that defines this register and split it
|
||||
// into two values.
|
||||
unsigned DefIndex = getDefIndex(getInstructionIndex(vi.DefInst));
|
||||
unsigned RedefIndex = getDefIndex(getInstructionIndex(mi));
|
||||
|
||||
// Delete the initial value, which should be short and continuous,
|
||||
// becuase the 2-addr copy must be in the same MBB as the redef.
|
||||
interval.removeRange(DefIndex, RedefIndex);
|
||||
|
||||
LiveRange LR(DefIndex, RedefIndex, interval.getNextValue());
|
||||
DEBUG(std::cerr << " replace range with " << LR);
|
||||
interval.addRange(LR);
|
||||
|
||||
// If this redefinition is dead, we need to add a dummy unit live
|
||||
// range covering the def slot.
|
||||
for (LiveVariables::killed_iterator KI = lv_->dead_begin(mi),
|
||||
E = lv_->dead_end(mi); KI != E; ++KI)
|
||||
if (KI->second == interval.reg) {
|
||||
interval.addRange(LiveRange(RedefIndex, RedefIndex+1, 0));
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
|
||||
} else {
|
||||
// Otherwise, this must be because of phi elimination. If this is the
|
||||
// first redefinition of the vreg that we have seen, go back and change
|
||||
// the live range in the PHI block to be a different value number.
|
||||
if (interval.containsOneValue()) {
|
||||
assert(vi.Kills.size() == 1 &&
|
||||
"PHI elimination vreg should have one kill, the PHI itself!");
|
||||
|
||||
// Remove the old range that we now know has an incorrect number.
|
||||
MachineInstr *Killer = vi.Kills[0];
|
||||
unsigned Start = getInstructionIndex(Killer->getParent()->begin());
|
||||
unsigned End = getUseIndex(getInstructionIndex(Killer))+1;
|
||||
DEBUG(std::cerr << "Removing [" << Start << "," << End << "] from: "
|
||||
<< interval << "\n");
|
||||
interval.removeRange(Start, End);
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
|
||||
// Replace the interval with one of a NEW value number.
|
||||
LiveRange LR(Start, End, interval.getNextValue());
|
||||
DEBUG(std::cerr << " replace range with " << LR);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << "RESULT: " << interval);
|
||||
}
|
||||
|
||||
// In the case of PHI elimination, each variable definition is only
|
||||
// live until the end of the block. We've already taken care of the
|
||||
// rest of the live range.
|
||||
unsigned defIndex = getDefIndex(getInstructionIndex(mi));
|
||||
LiveRange LR(defIndex,
|
||||
getInstructionIndex(&mbb->back()) + InstrSlots::NUM,
|
||||
interval.getNextValue());
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << '\n');
|
||||
}
|
||||
|
||||
void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock *MBB,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval)
|
||||
{
|
||||
// A physical register cannot be live across basic block, so its
|
||||
// lifetime must end somewhere in its defining basic block.
|
||||
DEBUG(std::cerr << "\t\tregister: "; printRegName(interval.reg));
|
||||
typedef LiveVariables::killed_iterator KillIter;
|
||||
// A physical register cannot be live across basic block, so its
|
||||
// lifetime must end somewhere in its defining basic block.
|
||||
DEBUG(std::cerr << "\t\tregister: "; printRegName(interval.reg));
|
||||
typedef LiveVariables::killed_iterator KillIter;
|
||||
|
||||
unsigned baseIndex = getInstructionIndex(mi);
|
||||
unsigned start = getDefIndex(baseIndex);
|
||||
unsigned end = start;
|
||||
unsigned baseIndex = getInstructionIndex(mi);
|
||||
unsigned start = getDefIndex(baseIndex);
|
||||
unsigned end = start;
|
||||
|
||||
// If it is not used after definition, it is considered dead at
|
||||
// the instruction defining it. Hence its interval is:
|
||||
// [defSlot(def), defSlot(def)+1)
|
||||
for (KillIter ki = lv_->dead_begin(mi), ke = lv_->dead_end(mi);
|
||||
// If it is not used after definition, it is considered dead at
|
||||
// the instruction defining it. Hence its interval is:
|
||||
// [defSlot(def), defSlot(def)+1)
|
||||
for (KillIter ki = lv_->dead_begin(mi), ke = lv_->dead_end(mi);
|
||||
ki != ke; ++ki) {
|
||||
if (interval.reg == ki->second) {
|
||||
DEBUG(std::cerr << " dead");
|
||||
end = getDefIndex(start) + 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is not dead on definition, it must be killed by a
|
||||
// subsequent instruction. Hence its interval is:
|
||||
// [defSlot(def), useSlot(kill)+1)
|
||||
while (true) {
|
||||
++mi;
|
||||
assert(mi != MBB->end() && "physreg was not killed in defining block!");
|
||||
baseIndex += InstrSlots::NUM;
|
||||
for (KillIter ki = lv_->killed_begin(mi), ke = lv_->killed_end(mi);
|
||||
ki != ke; ++ki) {
|
||||
if (interval.reg == ki->second) {
|
||||
DEBUG(std::cerr << " dead");
|
||||
end = getDefIndex(start) + 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is not dead on definition, it must be killed by a
|
||||
// subsequent instruction. Hence its interval is:
|
||||
// [defSlot(def), useSlot(kill)+1)
|
||||
while (true) {
|
||||
++mi;
|
||||
assert(mi != MBB->end() && "physreg was not killed in defining block!");
|
||||
baseIndex += InstrSlots::NUM;
|
||||
for (KillIter ki = lv_->killed_begin(mi), ke = lv_->killed_end(mi);
|
||||
ki != ke; ++ki) {
|
||||
if (interval.reg == ki->second) {
|
||||
DEBUG(std::cerr << " killed");
|
||||
end = getUseIndex(baseIndex) + 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (interval.reg == ki->second) {
|
||||
DEBUG(std::cerr << " killed");
|
||||
end = getUseIndex(baseIndex) + 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
assert(start < end && "did not find end of interval?");
|
||||
LiveRange LR(start, end, interval.getNextValue());
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR << '\n');
|
||||
assert(start < end && "did not find end of interval?");
|
||||
LiveRange LR(start, end, interval.getNextValue());
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR << '\n');
|
||||
}
|
||||
|
||||
void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB,
|
||||
@ -498,35 +497,35 @@ void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB,
|
||||
/// which a variable is live
|
||||
void LiveIntervals::computeIntervals()
|
||||
{
|
||||
DEBUG(std::cerr << "********** COMPUTING LIVE INTERVALS **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< ((Value*)mf_->getFunction())->getName() << '\n');
|
||||
DEBUG(std::cerr << "********** COMPUTING LIVE INTERVALS **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< ((Value*)mf_->getFunction())->getName() << '\n');
|
||||
|
||||
for (MachineFunction::iterator I = mf_->begin(), E = mf_->end();
|
||||
I != E; ++I) {
|
||||
MachineBasicBlock* mbb = I;
|
||||
DEBUG(std::cerr << ((Value*)mbb->getBasicBlock())->getName() << ":\n");
|
||||
for (MachineFunction::iterator I = mf_->begin(), E = mf_->end();
|
||||
I != E; ++I) {
|
||||
MachineBasicBlock* mbb = I;
|
||||
DEBUG(std::cerr << ((Value*)mbb->getBasicBlock())->getName() << ":\n");
|
||||
|
||||
for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
|
||||
mi != miEnd; ++mi) {
|
||||
const TargetInstrDescriptor& tid =
|
||||
tm_->getInstrInfo()->get(mi->getOpcode());
|
||||
DEBUG(std::cerr << getInstructionIndex(mi) << "\t";
|
||||
mi->print(std::cerr, tm_));
|
||||
for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
|
||||
mi != miEnd; ++mi) {
|
||||
const TargetInstrDescriptor& tid =
|
||||
tm_->getInstrInfo()->get(mi->getOpcode());
|
||||
DEBUG(std::cerr << getInstructionIndex(mi) << "\t";
|
||||
mi->print(std::cerr, tm_));
|
||||
|
||||
// handle implicit defs
|
||||
for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
|
||||
handleRegisterDef(mbb, mi, *id);
|
||||
// handle implicit defs
|
||||
for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
|
||||
handleRegisterDef(mbb, mi, *id);
|
||||
|
||||
// handle explicit defs
|
||||
for (int i = mi->getNumOperands() - 1; i >= 0; --i) {
|
||||
MachineOperand& mop = mi->getOperand(i);
|
||||
// handle register defs - build intervals
|
||||
if (mop.isRegister() && mop.getReg() && mop.isDef())
|
||||
handleRegisterDef(mbb, mi, mop.getReg());
|
||||
}
|
||||
}
|
||||
// handle explicit defs
|
||||
for (int i = mi->getNumOperands() - 1; i >= 0; --i) {
|
||||
MachineOperand& mop = mi->getOperand(i);
|
||||
// handle register defs - build intervals
|
||||
if (mop.isRegister() && mop.getReg() && mop.isDef())
|
||||
handleRegisterDef(mbb, mi, mop.getReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiveIntervals::joinIntervalsInMachineBB(MachineBasicBlock *MBB) {
|
||||
@ -543,9 +542,9 @@ void LiveIntervals::joinIntervalsInMachineBB(MachineBasicBlock *MBB) {
|
||||
unsigned regA, regB;
|
||||
if (TII.isMoveInstr(*mi, regA, regB) &&
|
||||
(MRegisterInfo::isVirtualRegister(regA) ||
|
||||
lv_->getAllocatablePhysicalRegisters()[regA]) &&
|
||||
lv_->getAllocatablePhysicalRegisters()[regA]) &&
|
||||
(MRegisterInfo::isVirtualRegister(regB) ||
|
||||
lv_->getAllocatablePhysicalRegisters()[regB])) {
|
||||
lv_->getAllocatablePhysicalRegisters()[regB])) {
|
||||
|
||||
// Get representative registers.
|
||||
regA = rep(regA);
|
||||
@ -609,7 +608,7 @@ namespace {
|
||||
bool operator()(const DepthMBBPair &LHS, const DepthMBBPair &RHS) const {
|
||||
if (LHS.first > RHS.first) return true; // Deeper loops first
|
||||
return LHS.first == RHS.first &&
|
||||
LHS.second->getNumber() < RHS.second->getNumber();
|
||||
LHS.second->getNumber() < RHS.second->getNumber();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -642,8 +641,8 @@ void LiveIntervals::joinIntervals() {
|
||||
|
||||
DEBUG(std::cerr << "*** Register mapping ***\n");
|
||||
DEBUG(for (std::map<unsigned, unsigned>::iterator I = r2rMap_.begin(),
|
||||
E = r2rMap_.end(); I != E; ++I)
|
||||
std::cerr << " reg " << I->first << " -> reg " << I->second << "\n";);
|
||||
E = r2rMap_.end(); I != E; ++I)
|
||||
std::cerr << " reg " << I->first << " -> reg " << I->second << "\n";);
|
||||
}
|
||||
|
||||
/// Return true if the two specified registers belong to different register
|
||||
|
@ -25,160 +25,160 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LiveVariables;
|
||||
class MRegisterInfo;
|
||||
class VirtRegMap;
|
||||
class LiveVariables;
|
||||
class MRegisterInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
class LiveIntervals : public MachineFunctionPass {
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveVariables* lv_;
|
||||
class LiveIntervals : public MachineFunctionPass {
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveVariables* lv_;
|
||||
|
||||
typedef std::map<MachineInstr*, unsigned> Mi2IndexMap;
|
||||
Mi2IndexMap mi2iMap_;
|
||||
typedef std::map<MachineInstr*, unsigned> Mi2IndexMap;
|
||||
Mi2IndexMap mi2iMap_;
|
||||
|
||||
typedef std::vector<MachineInstr*> Index2MiMap;
|
||||
Index2MiMap i2miMap_;
|
||||
typedef std::vector<MachineInstr*> Index2MiMap;
|
||||
Index2MiMap i2miMap_;
|
||||
|
||||
typedef std::map<unsigned, LiveInterval> Reg2IntervalMap;
|
||||
Reg2IntervalMap r2iMap_;
|
||||
typedef std::map<unsigned, LiveInterval> Reg2IntervalMap;
|
||||
Reg2IntervalMap r2iMap_;
|
||||
|
||||
typedef std::map<unsigned, unsigned> Reg2RegMap;
|
||||
Reg2RegMap r2rMap_;
|
||||
typedef std::map<unsigned, unsigned> Reg2RegMap;
|
||||
Reg2RegMap r2rMap_;
|
||||
|
||||
public:
|
||||
struct InstrSlots
|
||||
{
|
||||
enum {
|
||||
LOAD = 0,
|
||||
USE = 1,
|
||||
DEF = 2,
|
||||
STORE = 3,
|
||||
NUM = 4,
|
||||
};
|
||||
};
|
||||
|
||||
static unsigned getBaseIndex(unsigned index) {
|
||||
return index - (index % InstrSlots::NUM);
|
||||
}
|
||||
static unsigned getBoundaryIndex(unsigned index) {
|
||||
return getBaseIndex(index + InstrSlots::NUM - 1);
|
||||
}
|
||||
static unsigned getLoadIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::LOAD;
|
||||
}
|
||||
static unsigned getUseIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::USE;
|
||||
}
|
||||
static unsigned getDefIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::DEF;
|
||||
}
|
||||
static unsigned getStoreIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::STORE;
|
||||
}
|
||||
|
||||
// FIXME: this should really be a const_iterator
|
||||
typedef Reg2IntervalMap::iterator iterator;
|
||||
iterator begin() { return r2iMap_.begin(); }
|
||||
iterator end() { return r2iMap_.end(); }
|
||||
unsigned getNumIntervals() const { return r2iMap_.size(); }
|
||||
|
||||
LiveInterval &getInterval(unsigned reg) {
|
||||
Reg2IntervalMap::iterator I = r2iMap_.find(reg);
|
||||
assert(I != r2iMap_.end() && "Interval does not exist for register");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const LiveInterval &getInterval(unsigned reg) const {
|
||||
Reg2IntervalMap::const_iterator I = r2iMap_.find(reg);
|
||||
assert(I != r2iMap_.end() && "Interval does not exist for register");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// getInstructionIndex - returns the base index of instr
|
||||
unsigned getInstructionIndex(MachineInstr* instr) const {
|
||||
Mi2IndexMap::const_iterator it = mi2iMap_.find(instr);
|
||||
assert(it != mi2iMap_.end() && "Invalid instruction!");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/// getInstructionFromIndex - given an index in any slot of an
|
||||
/// instruction return a pointer the instruction
|
||||
MachineInstr* getInstructionFromIndex(unsigned index) const {
|
||||
index /= InstrSlots::NUM; // convert index to vector index
|
||||
assert(index < i2miMap_.size() &&
|
||||
"index does not correspond to an instruction");
|
||||
return i2miMap_[index];
|
||||
}
|
||||
|
||||
std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i,
|
||||
VirtRegMap& vrm,
|
||||
int slot);
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual void releaseMemory();
|
||||
|
||||
/// runOnMachineFunction - pass entry point
|
||||
virtual bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
private:
|
||||
/// computeIntervals - compute live intervals
|
||||
void computeIntervals();
|
||||
|
||||
/// joinIntervals - join compatible live intervals
|
||||
void joinIntervals();
|
||||
|
||||
/// joinIntervalsInMachineBB - Join intervals based on move
|
||||
/// instructions in the specified basic block.
|
||||
void joinIntervalsInMachineBB(MachineBasicBlock *MBB);
|
||||
|
||||
/// handleRegisterDef - update intervals for a register def
|
||||
/// (calls handlePhysicalRegisterDef and
|
||||
/// handleVirtualRegisterDef)
|
||||
void handleRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
unsigned reg);
|
||||
|
||||
/// handleVirtualRegisterDef - update intervals for a virtual
|
||||
/// register def
|
||||
void handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval);
|
||||
|
||||
/// handlePhysicalRegisterDef - update intervals for a
|
||||
/// physical register def
|
||||
void handlePhysicalRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval);
|
||||
|
||||
/// Return true if the two specified registers belong to different
|
||||
/// register classes. The registers may be either phys or virt regs.
|
||||
bool differingRegisterClasses(unsigned RegA, unsigned RegB) const;
|
||||
|
||||
bool overlapsAliases(const LiveInterval *lhs,
|
||||
const LiveInterval *rhs) const;
|
||||
|
||||
static LiveInterval createInterval(unsigned Reg);
|
||||
|
||||
LiveInterval &getOrCreateInterval(unsigned reg) {
|
||||
Reg2IntervalMap::iterator I = r2iMap_.find(reg);
|
||||
if (I == r2iMap_.end())
|
||||
I = r2iMap_.insert(I, std::make_pair(reg, createInterval(reg)));
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// rep - returns the representative of this register
|
||||
unsigned rep(unsigned reg) {
|
||||
Reg2RegMap::iterator it = r2rMap_.find(reg);
|
||||
if (it != r2rMap_.end())
|
||||
return it->second = rep(it->second);
|
||||
return reg;
|
||||
}
|
||||
|
||||
void printRegName(unsigned reg) const;
|
||||
public:
|
||||
struct InstrSlots
|
||||
{
|
||||
enum {
|
||||
LOAD = 0,
|
||||
USE = 1,
|
||||
DEF = 2,
|
||||
STORE = 3,
|
||||
NUM = 4,
|
||||
};
|
||||
};
|
||||
|
||||
static unsigned getBaseIndex(unsigned index) {
|
||||
return index - (index % InstrSlots::NUM);
|
||||
}
|
||||
static unsigned getBoundaryIndex(unsigned index) {
|
||||
return getBaseIndex(index + InstrSlots::NUM - 1);
|
||||
}
|
||||
static unsigned getLoadIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::LOAD;
|
||||
}
|
||||
static unsigned getUseIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::USE;
|
||||
}
|
||||
static unsigned getDefIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::DEF;
|
||||
}
|
||||
static unsigned getStoreIndex(unsigned index) {
|
||||
return getBaseIndex(index) + InstrSlots::STORE;
|
||||
}
|
||||
|
||||
// FIXME: this should really be a const_iterator
|
||||
typedef Reg2IntervalMap::iterator iterator;
|
||||
iterator begin() { return r2iMap_.begin(); }
|
||||
iterator end() { return r2iMap_.end(); }
|
||||
unsigned getNumIntervals() const { return r2iMap_.size(); }
|
||||
|
||||
LiveInterval &getInterval(unsigned reg) {
|
||||
Reg2IntervalMap::iterator I = r2iMap_.find(reg);
|
||||
assert(I != r2iMap_.end() && "Interval does not exist for register");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const LiveInterval &getInterval(unsigned reg) const {
|
||||
Reg2IntervalMap::const_iterator I = r2iMap_.find(reg);
|
||||
assert(I != r2iMap_.end() && "Interval does not exist for register");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// getInstructionIndex - returns the base index of instr
|
||||
unsigned getInstructionIndex(MachineInstr* instr) const {
|
||||
Mi2IndexMap::const_iterator it = mi2iMap_.find(instr);
|
||||
assert(it != mi2iMap_.end() && "Invalid instruction!");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/// getInstructionFromIndex - given an index in any slot of an
|
||||
/// instruction return a pointer the instruction
|
||||
MachineInstr* getInstructionFromIndex(unsigned index) const {
|
||||
index /= InstrSlots::NUM; // convert index to vector index
|
||||
assert(index < i2miMap_.size() &&
|
||||
"index does not correspond to an instruction");
|
||||
return i2miMap_[index];
|
||||
}
|
||||
|
||||
std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i,
|
||||
VirtRegMap& vrm,
|
||||
int slot);
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual void releaseMemory();
|
||||
|
||||
/// runOnMachineFunction - pass entry point
|
||||
virtual bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
private:
|
||||
/// computeIntervals - compute live intervals
|
||||
void computeIntervals();
|
||||
|
||||
/// joinIntervals - join compatible live intervals
|
||||
void joinIntervals();
|
||||
|
||||
/// joinIntervalsInMachineBB - Join intervals based on move
|
||||
/// instructions in the specified basic block.
|
||||
void joinIntervalsInMachineBB(MachineBasicBlock *MBB);
|
||||
|
||||
/// handleRegisterDef - update intervals for a register def
|
||||
/// (calls handlePhysicalRegisterDef and
|
||||
/// handleVirtualRegisterDef)
|
||||
void handleRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
unsigned reg);
|
||||
|
||||
/// handleVirtualRegisterDef - update intervals for a virtual
|
||||
/// register def
|
||||
void handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval);
|
||||
|
||||
/// handlePhysicalRegisterDef - update intervals for a
|
||||
/// physical register def
|
||||
void handlePhysicalRegisterDef(MachineBasicBlock* mbb,
|
||||
MachineBasicBlock::iterator mi,
|
||||
LiveInterval& interval);
|
||||
|
||||
/// Return true if the two specified registers belong to different
|
||||
/// register classes. The registers may be either phys or virt regs.
|
||||
bool differingRegisterClasses(unsigned RegA, unsigned RegB) const;
|
||||
|
||||
bool overlapsAliases(const LiveInterval *lhs,
|
||||
const LiveInterval *rhs) const;
|
||||
|
||||
static LiveInterval createInterval(unsigned Reg);
|
||||
|
||||
LiveInterval &getOrCreateInterval(unsigned reg) {
|
||||
Reg2IntervalMap::iterator I = r2iMap_.find(reg);
|
||||
if (I == r2iMap_.end())
|
||||
I = r2iMap_.insert(I, std::make_pair(reg, createInterval(reg)));
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// rep - returns the representative of this register
|
||||
unsigned rep(unsigned reg) {
|
||||
Reg2RegMap::iterator it = r2rMap_.find(reg);
|
||||
if (it != r2rMap_.end())
|
||||
return it->second = rep(it->second);
|
||||
return reg;
|
||||
}
|
||||
|
||||
void printRegName(unsigned reg) const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -40,439 +40,439 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
Statistic<double> efficiency
|
||||
("regalloc", "Ratio of intervals processed over total intervals");
|
||||
Statistic<double> efficiency
|
||||
("regalloc", "Ratio of intervals processed over total intervals");
|
||||
|
||||
static unsigned numIterations = 0;
|
||||
static unsigned numIntervals = 0;
|
||||
static unsigned numIterations = 0;
|
||||
static unsigned numIntervals = 0;
|
||||
|
||||
class RA : public MachineFunctionPass {
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveIntervals* li_;
|
||||
typedef std::vector<LiveInterval*> IntervalPtrs;
|
||||
IntervalPtrs unhandled_, fixed_, active_, inactive_, handled_, spilled_;
|
||||
class RA : public MachineFunctionPass {
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveIntervals* li_;
|
||||
typedef std::vector<LiveInterval*> IntervalPtrs;
|
||||
IntervalPtrs unhandled_, fixed_, active_, inactive_, handled_, spilled_;
|
||||
|
||||
std::auto_ptr<PhysRegTracker> prt_;
|
||||
std::auto_ptr<VirtRegMap> vrm_;
|
||||
std::auto_ptr<Spiller> spiller_;
|
||||
std::auto_ptr<PhysRegTracker> prt_;
|
||||
std::auto_ptr<VirtRegMap> vrm_;
|
||||
std::auto_ptr<Spiller> spiller_;
|
||||
|
||||
typedef std::vector<float> SpillWeights;
|
||||
SpillWeights spillWeights_;
|
||||
typedef std::vector<float> SpillWeights;
|
||||
SpillWeights spillWeights_;
|
||||
|
||||
public:
|
||||
virtual const char* getPassName() const {
|
||||
return "Iterative Scan Register Allocator";
|
||||
public:
|
||||
virtual const char* getPassName() const {
|
||||
return "Iterative Scan Register Allocator";
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<LiveVariables>();
|
||||
AU.addRequired<LiveIntervals>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
private:
|
||||
/// linearScan - the linear scan algorithm. Returns a boolean
|
||||
/// indicating if there were any spills
|
||||
bool linearScan();
|
||||
|
||||
/// initIntervalSets - initializes the four interval sets:
|
||||
/// unhandled, fixed, active and inactive
|
||||
void initIntervalSets();
|
||||
|
||||
/// processActiveIntervals - expire old intervals and move
|
||||
/// non-overlapping ones to the incative list
|
||||
void processActiveIntervals(IntervalPtrs::value_type cur);
|
||||
|
||||
/// processInactiveIntervals - expire old intervals and move
|
||||
/// overlapping ones to the active list
|
||||
void processInactiveIntervals(IntervalPtrs::value_type cur);
|
||||
|
||||
/// updateSpillWeights - updates the spill weights of the
|
||||
/// specifed physical register and its weight
|
||||
void updateSpillWeights(unsigned reg, SpillWeights::value_type weight);
|
||||
|
||||
/// assignRegOrStackSlotAtInterval - assign a register if one
|
||||
/// is available, or spill.
|
||||
void assignRegOrSpillAtInterval(IntervalPtrs::value_type cur);
|
||||
|
||||
///
|
||||
/// register handling helpers
|
||||
///
|
||||
|
||||
/// getFreePhysReg - return a free physical register for this
|
||||
/// virtual register interval if we have one, otherwise return
|
||||
/// 0
|
||||
unsigned getFreePhysReg(IntervalPtrs::value_type cur);
|
||||
|
||||
/// assignVirt2StackSlot - assigns this virtual register to a
|
||||
/// stack slot. returns the stack slot
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
|
||||
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" << **i << " -> ";
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg)) {
|
||||
reg = vrm_->getPhys(reg);
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<LiveVariables>();
|
||||
AU.addRequired<LiveIntervals>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
private:
|
||||
/// linearScan - the linear scan algorithm. Returns a boolean
|
||||
/// indicating if there were any spills
|
||||
bool linearScan();
|
||||
|
||||
/// initIntervalSets - initializes the four interval sets:
|
||||
/// unhandled, fixed, active and inactive
|
||||
void initIntervalSets();
|
||||
|
||||
/// processActiveIntervals - expire old intervals and move
|
||||
/// non-overlapping ones to the incative list
|
||||
void processActiveIntervals(IntervalPtrs::value_type cur);
|
||||
|
||||
/// processInactiveIntervals - expire old intervals and move
|
||||
/// overlapping ones to the active list
|
||||
void processInactiveIntervals(IntervalPtrs::value_type cur);
|
||||
|
||||
/// updateSpillWeights - updates the spill weights of the
|
||||
/// specifed physical register and its weight
|
||||
void updateSpillWeights(unsigned reg, SpillWeights::value_type weight);
|
||||
|
||||
/// assignRegOrStackSlotAtInterval - assign a register if one
|
||||
/// is available, or spill.
|
||||
void assignRegOrSpillAtInterval(IntervalPtrs::value_type cur);
|
||||
|
||||
///
|
||||
/// register handling helpers
|
||||
///
|
||||
|
||||
/// getFreePhysReg - return a free physical register for this
|
||||
/// virtual register interval if we have one, otherwise return
|
||||
/// 0
|
||||
unsigned getFreePhysReg(IntervalPtrs::value_type cur);
|
||||
|
||||
/// assignVirt2StackSlot - assigns this virtual register to a
|
||||
/// stack slot. returns the stack slot
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
|
||||
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" << **i << " -> ";
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg)) {
|
||||
reg = vrm_->getPhys(reg);
|
||||
}
|
||||
std::cerr << mri_->getName(reg) << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
std::cerr << mri_->getName(reg) << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void RA::releaseMemory()
|
||||
{
|
||||
unhandled_.clear();
|
||||
fixed_.clear();
|
||||
active_.clear();
|
||||
inactive_.clear();
|
||||
handled_.clear();
|
||||
spilled_.clear();
|
||||
unhandled_.clear();
|
||||
fixed_.clear();
|
||||
active_.clear();
|
||||
inactive_.clear();
|
||||
handled_.clear();
|
||||
spilled_.clear();
|
||||
}
|
||||
|
||||
bool RA::runOnMachineFunction(MachineFunction &fn) {
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
li_ = &getAnalysis<LiveIntervals>();
|
||||
if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_));
|
||||
vrm_.reset(new VirtRegMap(*mf_));
|
||||
if (!spiller_.get()) spiller_.reset(createSpiller());
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
li_ = &getAnalysis<LiveIntervals>();
|
||||
if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_));
|
||||
vrm_.reset(new VirtRegMap(*mf_));
|
||||
if (!spiller_.get()) spiller_.reset(createSpiller());
|
||||
|
||||
initIntervalSets();
|
||||
initIntervalSets();
|
||||
|
||||
numIntervals += li_->getNumIntervals();
|
||||
numIntervals += li_->getNumIntervals();
|
||||
|
||||
while (linearScan()) {
|
||||
// we spilled some registers, so we need to add intervals for
|
||||
// the spill code and restart the algorithm
|
||||
std::set<unsigned> spilledRegs;
|
||||
for (IntervalPtrs::iterator
|
||||
i = spilled_.begin(); i != spilled_.end(); ++i) {
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> added =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(added.begin(), added.end(), std::back_inserter(handled_));
|
||||
spilledRegs.insert((*i)->reg);
|
||||
}
|
||||
spilled_.clear();
|
||||
for (IntervalPtrs::iterator
|
||||
i = handled_.begin(); i != handled_.end(); )
|
||||
if (spilledRegs.count((*i)->reg))
|
||||
i = handled_.erase(i);
|
||||
else
|
||||
++i;
|
||||
handled_.swap(unhandled_);
|
||||
vrm_->clearAllVirt();
|
||||
while (linearScan()) {
|
||||
// we spilled some registers, so we need to add intervals for
|
||||
// the spill code and restart the algorithm
|
||||
std::set<unsigned> spilledRegs;
|
||||
for (IntervalPtrs::iterator
|
||||
i = spilled_.begin(); i != spilled_.end(); ++i) {
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> added =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(added.begin(), added.end(), std::back_inserter(handled_));
|
||||
spilledRegs.insert((*i)->reg);
|
||||
}
|
||||
spilled_.clear();
|
||||
for (IntervalPtrs::iterator
|
||||
i = handled_.begin(); i != handled_.end(); )
|
||||
if (spilledRegs.count((*i)->reg))
|
||||
i = handled_.erase(i);
|
||||
else
|
||||
++i;
|
||||
handled_.swap(unhandled_);
|
||||
vrm_->clearAllVirt();
|
||||
}
|
||||
|
||||
efficiency = double(numIterations) / double(numIntervals);
|
||||
efficiency = double(numIterations) / double(numIntervals);
|
||||
|
||||
DEBUG(std::cerr << *vrm_);
|
||||
DEBUG(std::cerr << *vrm_);
|
||||
|
||||
spiller_->runOnMachineFunction(*mf_, *vrm_);
|
||||
spiller_->runOnMachineFunction(*mf_, *vrm_);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RA::linearScan()
|
||||
{
|
||||
// linear scan algorithm
|
||||
DEBUG(std::cerr << "********** LINEAR SCAN **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< mf_->getFunction()->getName() << '\n');
|
||||
// linear scan algorithm
|
||||
DEBUG(std::cerr << "********** LINEAR SCAN **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< mf_->getFunction()->getName() << '\n');
|
||||
|
||||
|
||||
std::sort(unhandled_.begin(), unhandled_.end(),
|
||||
greater_ptr<LiveInterval>());
|
||||
DEBUG(printIntervals("unhandled", unhandled_.begin(), unhandled_.end()));
|
||||
DEBUG(printIntervals("fixed", fixed_.begin(), fixed_.end()));
|
||||
std::sort(unhandled_.begin(), unhandled_.end(),
|
||||
greater_ptr<LiveInterval>());
|
||||
DEBUG(printIntervals("unhandled", unhandled_.begin(), unhandled_.end()));
|
||||
DEBUG(printIntervals("fixed", fixed_.begin(), fixed_.end()));
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
|
||||
while (!unhandled_.empty()) {
|
||||
// pick the interval with the earliest start point
|
||||
IntervalPtrs::value_type cur = unhandled_.back();
|
||||
unhandled_.pop_back();
|
||||
++numIterations;
|
||||
DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n');
|
||||
|
||||
processActiveIntervals(cur);
|
||||
processInactiveIntervals(cur);
|
||||
|
||||
// if this register is fixed we are done
|
||||
if (MRegisterInfo::isPhysicalRegister(cur->reg)) {
|
||||
prt_->addRegUse(cur->reg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
}
|
||||
// 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 {
|
||||
assignRegOrSpillAtInterval(cur);
|
||||
}
|
||||
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
}
|
||||
|
||||
while (!unhandled_.empty()) {
|
||||
// pick the interval with the earliest start point
|
||||
IntervalPtrs::value_type cur = unhandled_.back();
|
||||
unhandled_.pop_back();
|
||||
++numIterations;
|
||||
DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n');
|
||||
// expire any remaining active intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
processActiveIntervals(cur);
|
||||
processInactiveIntervals(cur);
|
||||
// expire any remaining inactive intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend(); ) {
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
// if this register is fixed we are done
|
||||
if (MRegisterInfo::isPhysicalRegister(cur->reg)) {
|
||||
prt_->addRegUse(cur->reg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
}
|
||||
// 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 {
|
||||
assignRegOrSpillAtInterval(cur);
|
||||
}
|
||||
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
}
|
||||
|
||||
// expire any remaining active intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
// expire any remaining inactive intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend(); ) {
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
// return true if we spilled anything
|
||||
return !spilled_.empty();
|
||||
// return true if we spilled anything
|
||||
return !spilled_.empty();
|
||||
}
|
||||
|
||||
void RA::initIntervalSets() {
|
||||
assert(unhandled_.empty() && fixed_.empty() &&
|
||||
active_.empty() && inactive_.empty() &&
|
||||
"interval sets should be empty on initialization");
|
||||
assert(unhandled_.empty() && fixed_.empty() &&
|
||||
active_.empty() && inactive_.empty() &&
|
||||
"interval sets should be empty on initialization");
|
||||
|
||||
for (LiveIntervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i){
|
||||
unhandled_.push_back(&i->second);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->second.reg))
|
||||
fixed_.push_back(&i->second);
|
||||
}
|
||||
for (LiveIntervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i){
|
||||
unhandled_.push_back(&i->second);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->second.reg))
|
||||
fixed_.push_back(&i->second);
|
||||
}
|
||||
}
|
||||
|
||||
void RA::processActiveIntervals(IntervalPtrs::value_type cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tprocessing active intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
// move inactive intervals to inactive list
|
||||
else if (!(*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " inactive\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// add to inactive
|
||||
inactive_.push_back(*i);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
DEBUG(std::cerr << "\tprocessing active intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
// move inactive intervals to inactive list
|
||||
else if (!(*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " inactive\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// add to inactive
|
||||
inactive_.push_back(*i);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RA::processInactiveIntervals(IntervalPtrs::value_type cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
// move re-activated intervals in active list
|
||||
else if ((*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " active\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
// add to active
|
||||
active_.push_back(*i);
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
// move re-activated intervals in active list
|
||||
else if ((*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " active\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
// add to active
|
||||
active_.push_back(*i);
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RA::updateSpillWeights(unsigned reg, SpillWeights::value_type weight)
|
||||
{
|
||||
spillWeights_[reg] += weight;
|
||||
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
|
||||
spillWeights_[*as] += weight;
|
||||
spillWeights_[reg] += weight;
|
||||
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
|
||||
spillWeights_[*as] += weight;
|
||||
}
|
||||
|
||||
void RA::assignRegOrSpillAtInterval(IntervalPtrs::value_type cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tallocating current interval: ");
|
||||
DEBUG(std::cerr << "\tallocating current interval: ");
|
||||
|
||||
PhysRegTracker backupPrt = *prt_;
|
||||
PhysRegTracker backupPrt = *prt_;
|
||||
|
||||
spillWeights_.assign(mri_->getNumRegs(), 0.0);
|
||||
spillWeights_.assign(mri_->getNumRegs(), 0.0);
|
||||
|
||||
// for each interval in active update spill weights
|
||||
for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
|
||||
i != e; ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
// for each interval in active update spill weights
|
||||
for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
|
||||
i != e; ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
|
||||
// for every interval in inactive we overlap with, mark the
|
||||
// register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = inactive_.begin(),
|
||||
e = inactive_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
}
|
||||
|
||||
// for every interval in inactive we overlap with, mark the
|
||||
// register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = inactive_.begin(),
|
||||
e = inactive_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
// for every interval in fixed we overlap with,
|
||||
// mark the register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = fixed_.begin(),
|
||||
e = fixed_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
}
|
||||
|
||||
// for every interval in fixed we overlap with,
|
||||
// mark the register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = fixed_.begin(),
|
||||
e = fixed_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned physReg = getFreePhysReg(cur);
|
||||
// restore the physical register tracker
|
||||
*prt_ = backupPrt;
|
||||
// if we find a free register, we are done: assign this virtual to
|
||||
// the free physical register and add this interval to the active
|
||||
// list.
|
||||
if (physReg) {
|
||||
DEBUG(std::cerr << mri_->getName(physReg) << '\n');
|
||||
vrm_->assignVirt2Phys(cur->reg, physReg);
|
||||
prt_->addRegUse(physReg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
DEBUG(std::cerr << "no free registers\n");
|
||||
|
||||
DEBUG(std::cerr << "\tassigning stack slot at interval "<< *cur << ":\n");
|
||||
|
||||
float minWeight = HUGE_VAL;
|
||||
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 (minWeight > spillWeights_[reg]) {
|
||||
minWeight = spillWeights_[reg];
|
||||
minReg = reg;
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << "\t\tregister with min weight: "
|
||||
<< mri_->getName(minReg) << " (" << minWeight << ")\n");
|
||||
|
||||
// if the current has the minimum weight, we spill it and move on
|
||||
if (cur->weight <= minWeight) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n');
|
||||
spilled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise we spill all intervals aliasing the register with
|
||||
// minimum weight, assigned the newly cleared register to the
|
||||
// current interval and continue
|
||||
assert(MRegisterInfo::isPhysicalRegister(minReg) &&
|
||||
"did not choose a register to spill?");
|
||||
std::vector<bool> toSpill(mri_->getNumRegs(), false);
|
||||
toSpill[minReg] = true;
|
||||
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
|
||||
toSpill[*as] = true;
|
||||
unsigned earliestStart = cur->start();
|
||||
|
||||
std::set<unsigned> spilled;
|
||||
|
||||
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n');
|
||||
spilled_.push_back(*i);
|
||||
prt_->delRegUse(vrm_->getPhys(reg));
|
||||
vrm_->clearVirt(reg);
|
||||
i = active_.erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n');
|
||||
spilled_.push_back(*i);
|
||||
vrm_->clearVirt(reg);
|
||||
i = inactive_.erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
vrm_->assignVirt2Phys(cur->reg, minReg);
|
||||
prt_->addRegUse(minReg);
|
||||
unsigned physReg = getFreePhysReg(cur);
|
||||
// restore the physical register tracker
|
||||
*prt_ = backupPrt;
|
||||
// if we find a free register, we are done: assign this virtual to
|
||||
// the free physical register and add this interval to the active
|
||||
// list.
|
||||
if (physReg) {
|
||||
DEBUG(std::cerr << mri_->getName(physReg) << '\n');
|
||||
vrm_->assignVirt2Phys(cur->reg, physReg);
|
||||
prt_->addRegUse(physReg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
DEBUG(std::cerr << "no free registers\n");
|
||||
|
||||
DEBUG(std::cerr << "\tassigning stack slot at interval "<< *cur << ":\n");
|
||||
|
||||
float minWeight = HUGE_VAL;
|
||||
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 (minWeight > spillWeights_[reg]) {
|
||||
minWeight = spillWeights_[reg];
|
||||
minReg = reg;
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << "\t\tregister with min weight: "
|
||||
<< mri_->getName(minReg) << " (" << minWeight << ")\n");
|
||||
|
||||
// if the current has the minimum weight, we spill it and move on
|
||||
if (cur->weight <= minWeight) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n');
|
||||
spilled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise we spill all intervals aliasing the register with
|
||||
// minimum weight, assigned the newly cleared register to the
|
||||
// current interval and continue
|
||||
assert(MRegisterInfo::isPhysicalRegister(minReg) &&
|
||||
"did not choose a register to spill?");
|
||||
std::vector<bool> toSpill(mri_->getNumRegs(), false);
|
||||
toSpill[minReg] = true;
|
||||
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
|
||||
toSpill[*as] = true;
|
||||
unsigned earliestStart = cur->start();
|
||||
|
||||
std::set<unsigned> spilled;
|
||||
|
||||
for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n');
|
||||
spilled_.push_back(*i);
|
||||
prt_->delRegUse(vrm_->getPhys(reg));
|
||||
vrm_->clearVirt(reg);
|
||||
i = active_.erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n');
|
||||
spilled_.push_back(*i);
|
||||
vrm_->clearVirt(reg);
|
||||
i = inactive_.erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
vrm_->assignVirt2Phys(cur->reg, minReg);
|
||||
prt_->addRegUse(minReg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
|
||||
}
|
||||
|
||||
unsigned RA::getFreePhysReg(IntervalPtrs::value_type cur)
|
||||
{
|
||||
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->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 (prt_->isRegAvail(reg))
|
||||
return reg;
|
||||
}
|
||||
return 0;
|
||||
for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_);
|
||||
i != rc->allocation_order_end(*mf_); ++i) {
|
||||
unsigned reg = *i;
|
||||
if (prt_->isRegAvail(reg))
|
||||
return reg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FunctionPass* llvm::createIterativeScanRegisterAllocator() {
|
||||
return new RA();
|
||||
return new RA();
|
||||
}
|
||||
|
@ -35,502 +35,502 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
Statistic<double> efficiency
|
||||
("regalloc", "Ratio of intervals processed over total intervals");
|
||||
Statistic<double> efficiency
|
||||
("regalloc", "Ratio of intervals processed over total intervals");
|
||||
|
||||
static unsigned numIterations = 0;
|
||||
static unsigned numIntervals = 0;
|
||||
static unsigned numIterations = 0;
|
||||
static unsigned numIntervals = 0;
|
||||
|
||||
class RA : public MachineFunctionPass {
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveIntervals* li_;
|
||||
typedef std::vector<LiveInterval*> IntervalPtrs;
|
||||
IntervalPtrs handled_, fixed_, active_, inactive_;
|
||||
typedef std::priority_queue<LiveInterval*,
|
||||
IntervalPtrs,
|
||||
greater_ptr<LiveInterval> > IntervalHeap;
|
||||
IntervalHeap unhandled_;
|
||||
std::auto_ptr<PhysRegTracker> prt_;
|
||||
std::auto_ptr<VirtRegMap> vrm_;
|
||||
std::auto_ptr<Spiller> spiller_;
|
||||
class RA : public MachineFunctionPass {
|
||||
private:
|
||||
MachineFunction* mf_;
|
||||
const TargetMachine* tm_;
|
||||
const MRegisterInfo* mri_;
|
||||
LiveIntervals* li_;
|
||||
typedef std::vector<LiveInterval*> IntervalPtrs;
|
||||
IntervalPtrs handled_, fixed_, active_, inactive_;
|
||||
typedef std::priority_queue<LiveInterval*,
|
||||
IntervalPtrs,
|
||||
greater_ptr<LiveInterval> > IntervalHeap;
|
||||
IntervalHeap unhandled_;
|
||||
std::auto_ptr<PhysRegTracker> prt_;
|
||||
std::auto_ptr<VirtRegMap> vrm_;
|
||||
std::auto_ptr<Spiller> spiller_;
|
||||
|
||||
typedef std::vector<float> SpillWeights;
|
||||
SpillWeights spillWeights_;
|
||||
typedef std::vector<float> SpillWeights;
|
||||
SpillWeights spillWeights_;
|
||||
|
||||
public:
|
||||
virtual const char* getPassName() const {
|
||||
return "Linear Scan Register Allocator";
|
||||
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);
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
private:
|
||||
/// linearScan - the linear scan algorithm
|
||||
void linearScan();
|
||||
|
||||
/// initIntervalSets - initializa the four interval sets:
|
||||
/// unhandled, fixed, active and inactive
|
||||
void initIntervalSets();
|
||||
|
||||
/// processActiveIntervals - expire old intervals and move
|
||||
/// non-overlapping ones to the incative list
|
||||
void processActiveIntervals(LiveInterval* cur);
|
||||
|
||||
/// processInactiveIntervals - expire old intervals and move
|
||||
/// overlapping ones to the active list
|
||||
void processInactiveIntervals(LiveInterval* cur);
|
||||
|
||||
/// updateSpillWeights - updates the spill weights of the
|
||||
/// specifed physical register and its weight
|
||||
void updateSpillWeights(unsigned reg, SpillWeights::value_type weight);
|
||||
|
||||
/// assignRegOrStackSlotAtInterval - assign a register if one
|
||||
/// is available, or spill.
|
||||
void assignRegOrStackSlotAtInterval(LiveInterval* cur);
|
||||
|
||||
///
|
||||
/// register handling helpers
|
||||
///
|
||||
|
||||
/// getFreePhysReg - return a free physical register for this
|
||||
/// virtual register interval if we have one, otherwise return
|
||||
/// 0
|
||||
unsigned getFreePhysReg(LiveInterval* cur);
|
||||
|
||||
/// assignVirt2StackSlot - assigns this virtual register to a
|
||||
/// stack slot. returns the stack slot
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
|
||||
template <typename ItTy>
|
||||
void printIntervals(const char* const str, ItTy i, ItTy e) const {
|
||||
if (str) std::cerr << str << " intervals:\n";
|
||||
for (; i != e; ++i) {
|
||||
std::cerr << "\t" << **i << " -> ";
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg)) {
|
||||
reg = vrm_->getPhys(reg);
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<LiveVariables>();
|
||||
AU.addRequired<LiveIntervals>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
private:
|
||||
/// linearScan - the linear scan algorithm
|
||||
void linearScan();
|
||||
|
||||
/// initIntervalSets - initializa the four interval sets:
|
||||
/// unhandled, fixed, active and inactive
|
||||
void initIntervalSets();
|
||||
|
||||
/// processActiveIntervals - expire old intervals and move
|
||||
/// non-overlapping ones to the incative list
|
||||
void processActiveIntervals(LiveInterval* cur);
|
||||
|
||||
/// processInactiveIntervals - expire old intervals and move
|
||||
/// overlapping ones to the active list
|
||||
void processInactiveIntervals(LiveInterval* cur);
|
||||
|
||||
/// updateSpillWeights - updates the spill weights of the
|
||||
/// specifed physical register and its weight
|
||||
void updateSpillWeights(unsigned reg, SpillWeights::value_type weight);
|
||||
|
||||
/// assignRegOrStackSlotAtInterval - assign a register if one
|
||||
/// is available, or spill.
|
||||
void assignRegOrStackSlotAtInterval(LiveInterval* cur);
|
||||
|
||||
///
|
||||
/// register handling helpers
|
||||
///
|
||||
|
||||
/// getFreePhysReg - return a free physical register for this
|
||||
/// virtual register interval if we have one, otherwise return
|
||||
/// 0
|
||||
unsigned getFreePhysReg(LiveInterval* cur);
|
||||
|
||||
/// assignVirt2StackSlot - assigns this virtual register to a
|
||||
/// stack slot. returns the stack slot
|
||||
int assignVirt2StackSlot(unsigned virtReg);
|
||||
|
||||
template <typename ItTy>
|
||||
void printIntervals(const char* const str, ItTy i, ItTy e) const {
|
||||
if (str) std::cerr << str << " intervals:\n";
|
||||
for (; i != e; ++i) {
|
||||
std::cerr << "\t" << **i << " -> ";
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg)) {
|
||||
reg = vrm_->getPhys(reg);
|
||||
}
|
||||
std::cerr << mri_->getName(reg) << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
std::cerr << mri_->getName(reg) << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void RA::releaseMemory()
|
||||
{
|
||||
while (!unhandled_.empty()) unhandled_.pop();
|
||||
fixed_.clear();
|
||||
active_.clear();
|
||||
inactive_.clear();
|
||||
handled_.clear();
|
||||
while (!unhandled_.empty()) unhandled_.pop();
|
||||
fixed_.clear();
|
||||
active_.clear();
|
||||
inactive_.clear();
|
||||
handled_.clear();
|
||||
}
|
||||
|
||||
bool RA::runOnMachineFunction(MachineFunction &fn) {
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
li_ = &getAnalysis<LiveIntervals>();
|
||||
if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_));
|
||||
vrm_.reset(new VirtRegMap(*mf_));
|
||||
if (!spiller_.get()) spiller_.reset(createSpiller());
|
||||
mf_ = &fn;
|
||||
tm_ = &fn.getTarget();
|
||||
mri_ = tm_->getRegisterInfo();
|
||||
li_ = &getAnalysis<LiveIntervals>();
|
||||
if (!prt_.get()) prt_.reset(new PhysRegTracker(*mri_));
|
||||
vrm_.reset(new VirtRegMap(*mf_));
|
||||
if (!spiller_.get()) spiller_.reset(createSpiller());
|
||||
|
||||
initIntervalSets();
|
||||
initIntervalSets();
|
||||
|
||||
linearScan();
|
||||
linearScan();
|
||||
|
||||
spiller_->runOnMachineFunction(*mf_, *vrm_);
|
||||
spiller_->runOnMachineFunction(*mf_, *vrm_);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RA::linearScan()
|
||||
{
|
||||
// linear scan algorithm
|
||||
DEBUG(std::cerr << "********** LINEAR SCAN **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< mf_->getFunction()->getName() << '\n');
|
||||
// linear scan algorithm
|
||||
DEBUG(std::cerr << "********** LINEAR SCAN **********\n");
|
||||
DEBUG(std::cerr << "********** Function: "
|
||||
<< mf_->getFunction()->getName() << '\n');
|
||||
|
||||
// DEBUG(printIntervals("unhandled", unhandled_.begin(), unhandled_.end()));
|
||||
DEBUG(printIntervals("fixed", fixed_.begin(), fixed_.end()));
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
|
||||
while (!unhandled_.empty()) {
|
||||
// pick the interval with the earliest start point
|
||||
LiveInterval* cur = unhandled_.top();
|
||||
unhandled_.pop();
|
||||
++numIterations;
|
||||
DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n');
|
||||
|
||||
processActiveIntervals(cur);
|
||||
processInactiveIntervals(cur);
|
||||
|
||||
// if this register is fixed we are done
|
||||
if (MRegisterInfo::isPhysicalRegister(cur->reg)) {
|
||||
prt_->addRegUse(cur->reg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
}
|
||||
// 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 {
|
||||
assignRegOrStackSlotAtInterval(cur);
|
||||
}
|
||||
|
||||
// DEBUG(printIntervals("unhandled", unhandled_.begin(), unhandled_.end()));
|
||||
DEBUG(printIntervals("fixed", fixed_.begin(), fixed_.end()));
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
}
|
||||
numIntervals += li_->getNumIntervals();
|
||||
efficiency = double(numIterations) / double(numIntervals);
|
||||
|
||||
while (!unhandled_.empty()) {
|
||||
// pick the interval with the earliest start point
|
||||
LiveInterval* cur = unhandled_.top();
|
||||
unhandled_.pop();
|
||||
++numIterations;
|
||||
DEBUG(std::cerr << "\n*** CURRENT ***: " << *cur << '\n');
|
||||
// expire any remaining active intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
processActiveIntervals(cur);
|
||||
processInactiveIntervals(cur);
|
||||
// expire any remaining inactive intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend(); ) {
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
// if this register is fixed we are done
|
||||
if (MRegisterInfo::isPhysicalRegister(cur->reg)) {
|
||||
prt_->addRegUse(cur->reg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
}
|
||||
// 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 {
|
||||
assignRegOrStackSlotAtInterval(cur);
|
||||
}
|
||||
|
||||
DEBUG(printIntervals("active", active_.begin(), active_.end()));
|
||||
DEBUG(printIntervals("inactive", inactive_.begin(), inactive_.end()));
|
||||
}
|
||||
numIntervals += li_->getNumIntervals();
|
||||
efficiency = double(numIterations) / double(numIntervals);
|
||||
|
||||
// expire any remaining active intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend(); ) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
// expire any remaining inactive intervals
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend(); ) {
|
||||
DEBUG(std::cerr << "\tinterval " << **i << " expired\n");
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << *vrm_);
|
||||
DEBUG(std::cerr << *vrm_);
|
||||
}
|
||||
|
||||
void RA::initIntervalSets()
|
||||
{
|
||||
assert(unhandled_.empty() && fixed_.empty() &&
|
||||
active_.empty() && inactive_.empty() &&
|
||||
"interval sets should be empty on initialization");
|
||||
assert(unhandled_.empty() && fixed_.empty() &&
|
||||
active_.empty() && inactive_.empty() &&
|
||||
"interval sets should be empty on initialization");
|
||||
|
||||
for (LiveIntervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i){
|
||||
unhandled_.push(&i->second);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->second.reg))
|
||||
fixed_.push_back(&i->second);
|
||||
}
|
||||
for (LiveIntervals::iterator i = li_->begin(), e = li_->end(); i != e; ++i){
|
||||
unhandled_.push(&i->second);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->second.reg))
|
||||
fixed_.push_back(&i->second);
|
||||
}
|
||||
}
|
||||
|
||||
void RA::processActiveIntervals(IntervalPtrs::value_type cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tprocessing active intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
// move inactive intervals to inactive list
|
||||
else if (!(*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " inactive\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// add to inactive
|
||||
inactive_.push_back(*i);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
DEBUG(std::cerr << "\tprocessing active intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = active_.rbegin(); i != active_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
// move inactive intervals to inactive list
|
||||
else if (!(*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " inactive\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->delRegUse(reg);
|
||||
// add to inactive
|
||||
inactive_.push_back(*i);
|
||||
// remove from active
|
||||
i = IntervalPtrs::reverse_iterator(active_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RA::processInactiveIntervals(IntervalPtrs::value_type cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
|
||||
for (IntervalPtrs::reverse_iterator
|
||||
i = inactive_.rbegin(); i != inactive_.rend();) {
|
||||
unsigned reg = (*i)->reg;
|
||||
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
// move re-activated intervals in active list
|
||||
else if ((*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " active\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
// add to active
|
||||
active_.push_back(*i);
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
// remove expired intervals
|
||||
if ((*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
// move re-activated intervals in active list
|
||||
else if ((*i)->liveAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\tinterval " << **i << " active\n");
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
// add to active
|
||||
active_.push_back(*i);
|
||||
// remove from inactive
|
||||
i = IntervalPtrs::reverse_iterator(inactive_.erase(i.base()-1));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RA::updateSpillWeights(unsigned reg, SpillWeights::value_type weight)
|
||||
{
|
||||
spillWeights_[reg] += weight;
|
||||
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
|
||||
spillWeights_[*as] += weight;
|
||||
spillWeights_[reg] += weight;
|
||||
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
|
||||
spillWeights_[*as] += weight;
|
||||
}
|
||||
|
||||
void RA::assignRegOrStackSlotAtInterval(LiveInterval* cur)
|
||||
{
|
||||
DEBUG(std::cerr << "\tallocating current interval: ");
|
||||
DEBUG(std::cerr << "\tallocating current interval: ");
|
||||
|
||||
PhysRegTracker backupPrt = *prt_;
|
||||
PhysRegTracker backupPrt = *prt_;
|
||||
|
||||
spillWeights_.assign(mri_->getNumRegs(), 0.0);
|
||||
spillWeights_.assign(mri_->getNumRegs(), 0.0);
|
||||
|
||||
// for each interval in active update spill weights
|
||||
for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
|
||||
i != e; ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
// for each interval in active update spill weights
|
||||
for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end();
|
||||
i != e; ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
|
||||
// for every interval in inactive we overlap with, mark the
|
||||
// register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = inactive_.begin(),
|
||||
e = inactive_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
}
|
||||
|
||||
// for every interval in inactive we overlap with, mark the
|
||||
// register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = inactive_.begin(),
|
||||
e = inactive_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg))
|
||||
reg = vrm_->getPhys(reg);
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
// for every interval in fixed we overlap with,
|
||||
// mark the register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = fixed_.begin(),
|
||||
e = fixed_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
}
|
||||
|
||||
// for every interval in fixed we overlap with,
|
||||
// mark the register as not free and update spill weights
|
||||
for (IntervalPtrs::const_iterator i = fixed_.begin(),
|
||||
e = fixed_.end(); i != e; ++i) {
|
||||
if (cur->overlaps(**i)) {
|
||||
unsigned reg = (*i)->reg;
|
||||
prt_->addRegUse(reg);
|
||||
updateSpillWeights(reg, (*i)->weight);
|
||||
}
|
||||
unsigned physReg = getFreePhysReg(cur);
|
||||
// restore the physical register tracker
|
||||
*prt_ = backupPrt;
|
||||
// if we find a free register, we are done: assign this virtual to
|
||||
// the free physical register and add this interval to the active
|
||||
// list.
|
||||
if (physReg) {
|
||||
DEBUG(std::cerr << mri_->getName(physReg) << '\n');
|
||||
vrm_->assignVirt2Phys(cur->reg, physReg);
|
||||
prt_->addRegUse(physReg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
DEBUG(std::cerr << "no free registers\n");
|
||||
|
||||
DEBUG(std::cerr << "\tassigning stack slot at interval "<< *cur << ":\n");
|
||||
|
||||
float minWeight = HUGE_VAL;
|
||||
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 (minWeight > spillWeights_[reg]) {
|
||||
minWeight = spillWeights_[reg];
|
||||
minReg = reg;
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << "\t\tregister with min weight: "
|
||||
<< mri_->getName(minReg) << " (" << minWeight << ")\n");
|
||||
|
||||
unsigned physReg = getFreePhysReg(cur);
|
||||
// restore the physical register tracker
|
||||
*prt_ = backupPrt;
|
||||
// if we find a free register, we are done: assign this virtual to
|
||||
// the free physical register and add this interval to the active
|
||||
// list.
|
||||
if (physReg) {
|
||||
DEBUG(std::cerr << mri_->getName(physReg) << '\n');
|
||||
vrm_->assignVirt2Phys(cur->reg, physReg);
|
||||
prt_->addRegUse(physReg);
|
||||
active_.push_back(cur);
|
||||
handled_.push_back(cur);
|
||||
return;
|
||||
}
|
||||
DEBUG(std::cerr << "no free registers\n");
|
||||
// if the current has the minimum weight, we need to spill it and
|
||||
// add any added intervals back to unhandled, and restart
|
||||
// linearscan.
|
||||
if (cur->weight <= minWeight) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n';);
|
||||
int slot = vrm_->assignVirt2StackSlot(cur->reg);
|
||||
std::vector<LiveInterval*> added =
|
||||
li_->addIntervalsForSpills(*cur, *vrm_, slot);
|
||||
if (added.empty())
|
||||
return; // Early exit if all spills were folded.
|
||||
|
||||
DEBUG(std::cerr << "\tassigning stack slot at interval "<< *cur << ":\n");
|
||||
|
||||
float minWeight = HUGE_VAL;
|
||||
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 (minWeight > spillWeights_[reg]) {
|
||||
minWeight = spillWeights_[reg];
|
||||
minReg = reg;
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << "\t\tregister with min weight: "
|
||||
<< mri_->getName(minReg) << " (" << minWeight << ")\n");
|
||||
|
||||
// if the current has the minimum weight, we need to spill it and
|
||||
// add any added intervals back to unhandled, and restart
|
||||
// linearscan.
|
||||
if (cur->weight <= minWeight) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(c): " << *cur << '\n';);
|
||||
int slot = vrm_->assignVirt2StackSlot(cur->reg);
|
||||
std::vector<LiveInterval*> added =
|
||||
li_->addIntervalsForSpills(*cur, *vrm_, slot);
|
||||
if (added.empty())
|
||||
return; // Early exit if all spills were folded.
|
||||
|
||||
// Merge added with unhandled. Note that we know that
|
||||
// addIntervalsForSpills returns intervals sorted by their starting
|
||||
// point.
|
||||
for (unsigned i = 0, e = added.size(); i != e; ++i)
|
||||
unhandled_.push(added[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
// push the current interval back to unhandled since we are going
|
||||
// to re-run at least this iteration. Since we didn't modify it it
|
||||
// should go back right in the front of the list
|
||||
unhandled_.push(cur);
|
||||
|
||||
// otherwise we spill all intervals aliasing the register with
|
||||
// minimum weight, rollback to the interval with the earliest
|
||||
// start point and let the linear scan algorithm run again
|
||||
std::vector<LiveInterval*> added;
|
||||
assert(MRegisterInfo::isPhysicalRegister(minReg) &&
|
||||
"did not choose a register to spill?");
|
||||
std::vector<bool> toSpill(mri_->getNumRegs(), false);
|
||||
// we are going to spill minReg and all its aliases
|
||||
toSpill[minReg] = true;
|
||||
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
|
||||
toSpill[*as] = true;
|
||||
|
||||
// the earliest start of a spilled interval indicates up to where
|
||||
// in handled we need to roll back
|
||||
unsigned earliestStart = cur->start();
|
||||
|
||||
// set of spilled vregs (used later to rollback properly)
|
||||
std::set<unsigned> spilled;
|
||||
|
||||
// spill live intervals of virtual regs mapped to the physical
|
||||
// register we want to clear (and its aliases). we only spill
|
||||
// those that overlap with the current interval as the rest do not
|
||||
// affect its allocation. we also keep track of the earliest start
|
||||
// of all spilled live intervals since this will mark our rollback
|
||||
// point
|
||||
for (IntervalPtrs::iterator
|
||||
i = active_.begin(); i != active_.end(); ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n');
|
||||
earliestStart = std::min(earliestStart, (*i)->start());
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> newIs =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
|
||||
spilled.insert(reg);
|
||||
}
|
||||
}
|
||||
for (IntervalPtrs::iterator
|
||||
i = inactive_.begin(); i != inactive_.end(); ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n');
|
||||
earliestStart = std::min(earliestStart, (*i)->start());
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> newIs =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
|
||||
spilled.insert(reg);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "\t\trolling back to: " << earliestStart << '\n');
|
||||
// scan handled in reverse order up to the earliaset start of a
|
||||
// spilled live interval and undo each one, restoring the state of
|
||||
// unhandled
|
||||
while (!handled_.empty()) {
|
||||
LiveInterval* i = handled_.back();
|
||||
// if this interval starts before t we are done
|
||||
if (i->start() < earliestStart)
|
||||
break;
|
||||
DEBUG(std::cerr << "\t\t\tundo changes for: " << *i << '\n');
|
||||
handled_.pop_back();
|
||||
// when undoing a live interval allocation we must know if it
|
||||
// is active or inactive to properly update the PhysRegTracker
|
||||
// and the VirtRegMap
|
||||
IntervalPtrs::iterator it;
|
||||
if ((it = find(active_.begin(), active_.end(), i)) != active_.end()) {
|
||||
active_.erase(it);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->reg)) {
|
||||
prt_->delRegUse(i->reg);
|
||||
unhandled_.push(i);
|
||||
}
|
||||
else {
|
||||
if (!spilled.count(i->reg))
|
||||
unhandled_.push(i);
|
||||
prt_->delRegUse(vrm_->getPhys(i->reg));
|
||||
vrm_->clearVirt(i->reg);
|
||||
}
|
||||
}
|
||||
else if ((it = find(inactive_.begin(), inactive_.end(), i)) != inactive_.end()) {
|
||||
inactive_.erase(it);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->reg))
|
||||
unhandled_.push(i);
|
||||
else {
|
||||
if (!spilled.count(i->reg))
|
||||
unhandled_.push(i);
|
||||
vrm_->clearVirt(i->reg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MRegisterInfo::isVirtualRegister(i->reg))
|
||||
vrm_->clearVirt(i->reg);
|
||||
unhandled_.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// scan the rest and undo each interval that expired after t and
|
||||
// insert it in active (the next iteration of the algorithm will
|
||||
// put it in inactive if required)
|
||||
IntervalPtrs::iterator i = handled_.begin(), e = handled_.end();
|
||||
for (; i != e; ++i) {
|
||||
if (!(*i)->expiredAt(earliestStart) && (*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\t\tundo changes for: " << **i << '\n');
|
||||
active_.push_back(*i);
|
||||
if (MRegisterInfo::isPhysicalRegister((*i)->reg))
|
||||
prt_->addRegUse((*i)->reg);
|
||||
else
|
||||
prt_->addRegUse(vrm_->getPhys((*i)->reg));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(added.begin(), added.end(), less_ptr<LiveInterval>());
|
||||
// merge added with unhandled
|
||||
// Merge added with unhandled. Note that we know that
|
||||
// addIntervalsForSpills returns intervals sorted by their starting
|
||||
// point.
|
||||
for (unsigned i = 0, e = added.size(); i != e; ++i)
|
||||
unhandled_.push(added[i]);
|
||||
unhandled_.push(added[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
// push the current interval back to unhandled since we are going
|
||||
// to re-run at least this iteration. Since we didn't modify it it
|
||||
// should go back right in the front of the list
|
||||
unhandled_.push(cur);
|
||||
|
||||
// otherwise we spill all intervals aliasing the register with
|
||||
// minimum weight, rollback to the interval with the earliest
|
||||
// start point and let the linear scan algorithm run again
|
||||
std::vector<LiveInterval*> added;
|
||||
assert(MRegisterInfo::isPhysicalRegister(minReg) &&
|
||||
"did not choose a register to spill?");
|
||||
std::vector<bool> toSpill(mri_->getNumRegs(), false);
|
||||
// we are going to spill minReg and all its aliases
|
||||
toSpill[minReg] = true;
|
||||
for (const unsigned* as = mri_->getAliasSet(minReg); *as; ++as)
|
||||
toSpill[*as] = true;
|
||||
|
||||
// the earliest start of a spilled interval indicates up to where
|
||||
// in handled we need to roll back
|
||||
unsigned earliestStart = cur->start();
|
||||
|
||||
// set of spilled vregs (used later to rollback properly)
|
||||
std::set<unsigned> spilled;
|
||||
|
||||
// spill live intervals of virtual regs mapped to the physical
|
||||
// register we want to clear (and its aliases). we only spill
|
||||
// those that overlap with the current interval as the rest do not
|
||||
// affect its allocation. we also keep track of the earliest start
|
||||
// of all spilled live intervals since this will mark our rollback
|
||||
// point
|
||||
for (IntervalPtrs::iterator
|
||||
i = active_.begin(); i != active_.end(); ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(a): " << **i << '\n');
|
||||
earliestStart = std::min(earliestStart, (*i)->start());
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> newIs =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
|
||||
spilled.insert(reg);
|
||||
}
|
||||
}
|
||||
for (IntervalPtrs::iterator
|
||||
i = inactive_.begin(); i != inactive_.end(); ++i) {
|
||||
unsigned reg = (*i)->reg;
|
||||
if (MRegisterInfo::isVirtualRegister(reg) &&
|
||||
toSpill[vrm_->getPhys(reg)] &&
|
||||
cur->overlaps(**i)) {
|
||||
DEBUG(std::cerr << "\t\t\tspilling(i): " << **i << '\n');
|
||||
earliestStart = std::min(earliestStart, (*i)->start());
|
||||
int slot = vrm_->assignVirt2StackSlot((*i)->reg);
|
||||
std::vector<LiveInterval*> newIs =
|
||||
li_->addIntervalsForSpills(**i, *vrm_, slot);
|
||||
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
|
||||
spilled.insert(reg);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "\t\trolling back to: " << earliestStart << '\n');
|
||||
// scan handled in reverse order up to the earliaset start of a
|
||||
// spilled live interval and undo each one, restoring the state of
|
||||
// unhandled
|
||||
while (!handled_.empty()) {
|
||||
LiveInterval* i = handled_.back();
|
||||
// if this interval starts before t we are done
|
||||
if (i->start() < earliestStart)
|
||||
break;
|
||||
DEBUG(std::cerr << "\t\t\tundo changes for: " << *i << '\n');
|
||||
handled_.pop_back();
|
||||
// when undoing a live interval allocation we must know if it
|
||||
// is active or inactive to properly update the PhysRegTracker
|
||||
// and the VirtRegMap
|
||||
IntervalPtrs::iterator it;
|
||||
if ((it = find(active_.begin(), active_.end(), i)) != active_.end()) {
|
||||
active_.erase(it);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->reg)) {
|
||||
prt_->delRegUse(i->reg);
|
||||
unhandled_.push(i);
|
||||
}
|
||||
else {
|
||||
if (!spilled.count(i->reg))
|
||||
unhandled_.push(i);
|
||||
prt_->delRegUse(vrm_->getPhys(i->reg));
|
||||
vrm_->clearVirt(i->reg);
|
||||
}
|
||||
}
|
||||
else if ((it = find(inactive_.begin(), inactive_.end(), i)) != inactive_.end()) {
|
||||
inactive_.erase(it);
|
||||
if (MRegisterInfo::isPhysicalRegister(i->reg))
|
||||
unhandled_.push(i);
|
||||
else {
|
||||
if (!spilled.count(i->reg))
|
||||
unhandled_.push(i);
|
||||
vrm_->clearVirt(i->reg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MRegisterInfo::isVirtualRegister(i->reg))
|
||||
vrm_->clearVirt(i->reg);
|
||||
unhandled_.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// scan the rest and undo each interval that expired after t and
|
||||
// insert it in active (the next iteration of the algorithm will
|
||||
// put it in inactive if required)
|
||||
IntervalPtrs::iterator i = handled_.begin(), e = handled_.end();
|
||||
for (; i != e; ++i) {
|
||||
if (!(*i)->expiredAt(earliestStart) && (*i)->expiredAt(cur->start())) {
|
||||
DEBUG(std::cerr << "\t\t\tundo changes for: " << **i << '\n');
|
||||
active_.push_back(*i);
|
||||
if (MRegisterInfo::isPhysicalRegister((*i)->reg))
|
||||
prt_->addRegUse((*i)->reg);
|
||||
else
|
||||
prt_->addRegUse(vrm_->getPhys((*i)->reg));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(added.begin(), added.end(), less_ptr<LiveInterval>());
|
||||
// merge added with unhandled
|
||||
for (unsigned i = 0, e = added.size(); i != e; ++i)
|
||||
unhandled_.push(added[i]);
|
||||
}
|
||||
|
||||
unsigned RA::getFreePhysReg(LiveInterval* cur)
|
||||
{
|
||||
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(cur->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 (prt_->isRegAvail(reg))
|
||||
return reg;
|
||||
}
|
||||
return 0;
|
||||
for (TargetRegisterClass::iterator i = rc->allocation_order_begin(*mf_);
|
||||
i != rc->allocation_order_end(*mf_); ++i) {
|
||||
unsigned reg = *i;
|
||||
if (prt_->isRegAvail(reg))
|
||||
return reg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FunctionPass* llvm::createLinearScanRegisterAllocator() {
|
||||
return new RA();
|
||||
return new RA();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user