1. LiveIntervals now implement a 4 slot per instruction model. Load, Use, Def and a Store slot. This is required in order to correctly represent caller saved register clobbering on function calls, register reuse in the same instruction (def resues last use) and also spill code added later by the allocator. The previous representation (2 slots per instruction) was insufficient and as a result was causing subtle bugs. 2. Fixes in spill code generation. This was the major cause of failures in the test suite. 3. Linear scan now has core support for folding memory operands. This is untested and not enabled (the live interval update function does not attempt to fold loads/stores in instructions). 4. Lots of improvements in the debugging output of both live intervals and linear scan. Give it a try... it is beautiful :-) In summary the above fixes all the issues with the recent reserved register elimination changes and get the allocator very close to the next big step: folding memory operands. llvm-svn: 11654
681 lines
24 KiB
C++
681 lines
24 KiB
C++
//===-- LiveIntervals.cpp - Live Interval Analysis ------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the LiveInterval analysis pass which is used
|
|
// by the Linear Scan Register allocator. This pass linearizes the
|
|
// basic blocks of the function in DFS order and uses the
|
|
// LiveVariables pass to conservatively compute live intervals for
|
|
// each virtual and physical register.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "liveintervals"
|
|
#include "llvm/CodeGen/LiveIntervals.h"
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
#include "llvm/CodeGen/LiveVariables.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
|
#include "llvm/Target/MRegisterInfo.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Support/CFG.h"
|
|
#include "Support/CommandLine.h"
|
|
#include "Support/Debug.h"
|
|
#include "Support/Statistic.h"
|
|
#include "Support/STLExtras.h"
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
RegisterAnalysis<LiveIntervals> X("liveintervals",
|
|
"Live Interval Analysis");
|
|
|
|
Statistic<> numIntervals("liveintervals", "Number of intervals");
|
|
Statistic<> numJoined ("liveintervals", "Number of joined intervals");
|
|
Statistic<> numPeep ("liveintervals", "Number of identity moves "
|
|
"eliminated after coalescing");
|
|
Statistic<> numFolded ("liveintervals", "Number of register operands "
|
|
"folded");
|
|
cl::opt<bool>
|
|
join("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);
|
|
}
|
|
|
|
void LiveIntervals::releaseMemory()
|
|
{
|
|
mbbi2mbbMap_.clear();
|
|
mi2iMap_.clear();
|
|
i2miMap_.clear();
|
|
r2iMap_.clear();
|
|
r2rMap_.clear();
|
|
intervals_.clear();
|
|
}
|
|
|
|
|
|
/// runOnMachineFunction - Register allocate the whole function
|
|
///
|
|
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
|
|
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) {
|
|
const std::pair<MachineBasicBlock*, unsigned>& entry =
|
|
lv_->getMachineBasicBlockInfo(mbb);
|
|
bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
|
|
entry.first)).second;
|
|
assert(inserted && "multiple index -> MachineBasicBlock");
|
|
|
|
for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
|
|
mi != miEnd; ++mi) {
|
|
inserted = mi2iMap_.insert(std::make_pair(mi, miIndex)).second;
|
|
assert(inserted && "multiple MachineInstr -> index mappings");
|
|
i2miMap_.push_back(mi);
|
|
miIndex += InstrSlots::NUM;
|
|
}
|
|
}
|
|
|
|
computeIntervals();
|
|
|
|
numIntervals += intervals_.size();
|
|
|
|
// join intervals if requested
|
|
if (join) joinIntervals();
|
|
|
|
// 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; ) {
|
|
for (unsigned i = 0; i < mii->getNumOperands(); ++i) {
|
|
const MachineOperand& mop = mii->getOperand(i);
|
|
if (mop.isRegister()) {
|
|
// replace register with representative register
|
|
unsigned reg = rep(mop.getReg());
|
|
mii->SetMachineOperandReg(i, reg);
|
|
|
|
if (MRegisterInfo::isVirtualRegister(reg)) {
|
|
Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
|
|
assert(r2iit != r2iMap_.end());
|
|
r2iit->second->weight += pow(10.0F, loopDepth);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the move is now an identity move delete it
|
|
unsigned srcReg, dstReg;
|
|
if (tii.isMoveInstr(*mii, srcReg, dstReg) && srcReg == dstReg) {
|
|
// 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
|
|
++mii;
|
|
}
|
|
}
|
|
|
|
intervals_.sort(StartPointComp());
|
|
DEBUG(std::cerr << "********** INTERVALS **********\n");
|
|
DEBUG(std::copy(intervals_.begin(), intervals_.end(),
|
|
std::ostream_iterator<Interval>(std::cerr, "\n")));
|
|
DEBUG(std::cerr << "********** MACHINEINSTRS **********\n");
|
|
DEBUG(
|
|
for (unsigned i = 0; i != i2miMap_.size(); ++i) {
|
|
if (const MachineInstr* mi = i2miMap_[i]) {
|
|
std:: cerr << i * InstrSlots::NUM << '\t';
|
|
mi->print(std::cerr, *tm_);
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
void LiveIntervals::updateSpilledInterval(Interval& li, int slot)
|
|
{
|
|
assert(li.weight != std::numeric_limits<float>::infinity() &&
|
|
"attempt to spill already spilled interval!");
|
|
Interval::Ranges oldRanges;
|
|
swap(oldRanges, li.ranges);
|
|
|
|
DEBUG(std::cerr << "\t\t\t\tupdating interval: " << li);
|
|
|
|
for (Interval::Ranges::iterator i = oldRanges.begin(), e = oldRanges.end();
|
|
i != e; ++i) {
|
|
unsigned index = getBaseIndex(i->first);
|
|
unsigned end = getBaseIndex(i->second-1) + InstrSlots::NUM;
|
|
for (; index < end; index += InstrSlots::NUM) {
|
|
// skip deleted instructions
|
|
while (!getInstructionFromIndex(index)) index += InstrSlots::NUM;
|
|
MachineBasicBlock::iterator mi = getInstructionFromIndex(index);
|
|
|
|
for (unsigned i = 0; i < mi->getNumOperands(); ++i) {
|
|
MachineOperand& mop = mi->getOperand(i);
|
|
if (mop.isRegister() && mop.getReg() == li.reg) {
|
|
// 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() ?
|
|
getUseIndex(index+InstrSlots::NUM) :
|
|
getUseIndex(index));
|
|
li.addRange(start, end);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// the new spill weight is now infinity as it cannot be spilled again
|
|
li.weight = std::numeric_limits<float>::infinity();
|
|
DEBUG(std::cerr << '\n');
|
|
}
|
|
|
|
void LiveIntervals::printRegName(unsigned reg) const
|
|
{
|
|
if (MRegisterInfo::isPhysicalRegister(reg))
|
|
std::cerr << mri_->getName(reg);
|
|
else
|
|
std::cerr << "%reg" << reg;
|
|
}
|
|
|
|
void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg)
|
|
{
|
|
DEBUG(std::cerr << "\t\tregister: "; printRegName(reg));
|
|
LiveVariables::VarInfo& vi = lv_->getVarInfo(reg);
|
|
|
|
Interval* interval = 0;
|
|
Reg2IntervalMap::iterator r2iit = r2iMap_.lower_bound(reg);
|
|
if (r2iit == r2iMap_.end() || r2iit->first != reg) {
|
|
// add new interval
|
|
intervals_.push_back(Interval(reg));
|
|
// update interval index for this register
|
|
r2iMap_.insert(r2iit, std::make_pair(reg, --intervals_.end()));
|
|
interval = &intervals_.back();
|
|
|
|
// iterate over all of the blocks that the variable is
|
|
// completely live in, adding them to the live
|
|
// interval. obviously we only need to do this once.
|
|
for (unsigned i = 0, e = vi.AliveBlocks.size(); i != e; ++i) {
|
|
if (vi.AliveBlocks[i]) {
|
|
MachineBasicBlock* mbb = lv_->getIndexMachineBasicBlock(i);
|
|
if (!mbb->empty()) {
|
|
interval->addRange(
|
|
getInstructionIndex(&mbb->front()),
|
|
getInstructionIndex(&mbb->back()) + InstrSlots::NUM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
interval = &*r2iit->second;
|
|
}
|
|
|
|
unsigned baseIndex = getInstructionIndex(mi);
|
|
|
|
bool killedInDefiningBasicBlock = false;
|
|
for (int i = 0, e = vi.Kills.size(); i != e; ++i) {
|
|
MachineBasicBlock* killerBlock = vi.Kills[i].first;
|
|
MachineInstr* killerInstr = vi.Kills[i].second;
|
|
unsigned start = (mbb == killerBlock ?
|
|
getDefIndex(baseIndex) :
|
|
getInstructionIndex(&killerBlock->front()));
|
|
unsigned end = (killerInstr == mi ?
|
|
// dead
|
|
start + 1 :
|
|
// killed
|
|
getUseIndex(getInstructionIndex(killerInstr))+1);
|
|
// we do not want to add invalid ranges. these can happen when
|
|
// a variable has its latest use and is redefined later on in
|
|
// the same basic block (common with variables introduced by
|
|
// PHI elimination)
|
|
if (start < end) {
|
|
killedInDefiningBasicBlock |= mbb == killerBlock;
|
|
interval->addRange(start, end);
|
|
}
|
|
}
|
|
|
|
if (!killedInDefiningBasicBlock) {
|
|
unsigned end = getInstructionIndex(&mbb->back()) + InstrSlots::NUM;
|
|
interval->addRange(getDefIndex(baseIndex), end);
|
|
}
|
|
DEBUG(std::cerr << '\n');
|
|
}
|
|
|
|
void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg)
|
|
{
|
|
DEBUG(std::cerr << "\t\tregister: "; printRegName(reg));
|
|
typedef LiveVariables::killed_iterator KillIter;
|
|
|
|
MachineBasicBlock::iterator e = mbb->end();
|
|
unsigned baseIndex = getInstructionIndex(mi);
|
|
unsigned start = getDefIndex(baseIndex);
|
|
unsigned end = start;
|
|
|
|
// a variable can be dead by the instruction defining it
|
|
for (KillIter ki = lv_->dead_begin(mi), ke = lv_->dead_end(mi);
|
|
ki != ke; ++ki) {
|
|
if (reg == ki->second) {
|
|
DEBUG(std::cerr << " dead");
|
|
end = getDefIndex(start) + 1;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// a variable can only be killed by subsequent instructions
|
|
do {
|
|
++mi;
|
|
baseIndex += InstrSlots::NUM;
|
|
for (KillIter ki = lv_->killed_begin(mi), ke = lv_->killed_end(mi);
|
|
ki != ke; ++ki) {
|
|
if (reg == ki->second) {
|
|
DEBUG(std::cerr << " killed");
|
|
end = getUseIndex(baseIndex) + 1;
|
|
goto exit;
|
|
}
|
|
}
|
|
} while (mi != e);
|
|
|
|
exit:
|
|
assert(start < end && "did not find end of interval?");
|
|
|
|
Reg2IntervalMap::iterator r2iit = r2iMap_.lower_bound(reg);
|
|
if (r2iit != r2iMap_.end() && r2iit->first == reg) {
|
|
r2iit->second->addRange(start, end);
|
|
}
|
|
else {
|
|
intervals_.push_back(Interval(reg));
|
|
// update interval index for this register
|
|
r2iMap_.insert(r2iit, std::make_pair(reg, --intervals_.end()));
|
|
intervals_.back().addRange(start, end);
|
|
}
|
|
DEBUG(std::cerr << '\n');
|
|
}
|
|
|
|
void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg)
|
|
{
|
|
if (MRegisterInfo::isPhysicalRegister(reg)) {
|
|
if (lv_->getAllocatablePhysicalRegisters()[reg]) {
|
|
handlePhysicalRegisterDef(mbb, mi, reg);
|
|
for (const unsigned* as = mri_->getAliasSet(reg); *as; ++as)
|
|
handlePhysicalRegisterDef(mbb, mi, *as);
|
|
}
|
|
}
|
|
else {
|
|
handleVirtualRegisterDef(mbb, mi, reg);
|
|
}
|
|
}
|
|
|
|
unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const
|
|
{
|
|
Mi2IndexMap::const_iterator it = mi2iMap_.find(instr);
|
|
return (it == mi2iMap_.end() ?
|
|
std::numeric_limits<unsigned>::max() :
|
|
it->second);
|
|
}
|
|
|
|
MachineInstr* LiveIntervals::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];
|
|
}
|
|
|
|
/// computeIntervals - computes the live intervals for virtual
|
|
/// registers. for some ordering of the machine instructions [1,N] a
|
|
/// live interval is an interval [i, j) where 1 <= i <= j < N for
|
|
/// which a variable is live
|
|
void LiveIntervals::computeIntervals()
|
|
{
|
|
DEBUG(std::cerr << "********** COMPUTING LIVE INTERVALS **********\n");
|
|
DEBUG(std::cerr << "********** Function: "
|
|
<< mf_->getFunction()->getName() << '\n');
|
|
|
|
for (MbbIndex2MbbMap::iterator
|
|
it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
|
|
it != itEnd; ++it) {
|
|
MachineBasicBlock* mbb = it->second;
|
|
DEBUG(std::cerr << 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_));
|
|
|
|
// 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.isDef())
|
|
handleRegisterDef(mbb, mi, mop.getReg());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned LiveIntervals::rep(unsigned reg)
|
|
{
|
|
Reg2RegMap::iterator it = r2rMap_.find(reg);
|
|
if (it != r2rMap_.end())
|
|
return it->second = rep(it->second);
|
|
return reg;
|
|
}
|
|
|
|
void LiveIntervals::joinIntervals()
|
|
{
|
|
DEBUG(std::cerr << "********** JOINING INTERVALS ***********\n");
|
|
|
|
const TargetInstrInfo& tii = tm_->getInstrInfo();
|
|
|
|
for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end();
|
|
mbbi != mbbe; ++mbbi) {
|
|
MachineBasicBlock* mbb = mbbi;
|
|
DEBUG(std::cerr << mbb->getBasicBlock()->getName() << ":\n");
|
|
|
|
for (MachineBasicBlock::iterator mi = mbb->begin(), mie = mbb->end();
|
|
mi != mie; ++mi) {
|
|
const TargetInstrDescriptor& tid =
|
|
tm_->getInstrInfo().get(mi->getOpcode());
|
|
DEBUG(std::cerr << getInstructionIndex(mi) << '\t';
|
|
mi->print(std::cerr, *tm_););
|
|
|
|
// we only join virtual registers with allocatable
|
|
// physical registers since we do not have liveness information
|
|
// on not allocatable physical registers
|
|
unsigned regA, regB;
|
|
if (tii.isMoveInstr(*mi, regA, regB) &&
|
|
(MRegisterInfo::isVirtualRegister(regA) ||
|
|
lv_->getAllocatablePhysicalRegisters()[regA]) &&
|
|
(MRegisterInfo::isVirtualRegister(regB) ||
|
|
lv_->getAllocatablePhysicalRegisters()[regB])) {
|
|
|
|
// get representative registers
|
|
regA = rep(regA);
|
|
regB = rep(regB);
|
|
|
|
// if they are already joined we continue
|
|
if (regA == regB)
|
|
continue;
|
|
|
|
Reg2IntervalMap::iterator r2iA = r2iMap_.find(regA);
|
|
assert(r2iA != r2iMap_.end());
|
|
Reg2IntervalMap::iterator r2iB = r2iMap_.find(regB);
|
|
assert(r2iB != r2iMap_.end());
|
|
|
|
Intervals::iterator intA = r2iA->second;
|
|
Intervals::iterator intB = r2iB->second;
|
|
|
|
// both A and B are virtual registers
|
|
if (MRegisterInfo::isVirtualRegister(intA->reg) &&
|
|
MRegisterInfo::isVirtualRegister(intB->reg)) {
|
|
|
|
const TargetRegisterClass *rcA, *rcB;
|
|
rcA = mf_->getSSARegMap()->getRegClass(intA->reg);
|
|
rcB = mf_->getSSARegMap()->getRegClass(intB->reg);
|
|
assert(rcA == rcB && "registers must be of the same class");
|
|
|
|
// if their intervals do not overlap we join them
|
|
if (!intB->overlaps(*intA)) {
|
|
intA->join(*intB);
|
|
r2iB->second = r2iA->second;
|
|
r2rMap_.insert(std::make_pair(intB->reg, intA->reg));
|
|
intervals_.erase(intB);
|
|
++numJoined;
|
|
}
|
|
}
|
|
else if (MRegisterInfo::isPhysicalRegister(intA->reg) ^
|
|
MRegisterInfo::isPhysicalRegister(intB->reg)) {
|
|
if (MRegisterInfo::isPhysicalRegister(intB->reg)) {
|
|
std::swap(regA, regB);
|
|
std::swap(intA, intB);
|
|
std::swap(r2iA, r2iB);
|
|
}
|
|
|
|
assert(MRegisterInfo::isPhysicalRegister(intA->reg) &&
|
|
MRegisterInfo::isVirtualRegister(intB->reg) &&
|
|
"A must be physical and B must be virtual");
|
|
|
|
if (!intA->overlaps(*intB) &&
|
|
!overlapsAliases(*intA, *intB)) {
|
|
intA->join(*intB);
|
|
r2iB->second = r2iA->second;
|
|
r2rMap_.insert(std::make_pair(intB->reg, intA->reg));
|
|
intervals_.erase(intB);
|
|
++numJoined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LiveIntervals::overlapsAliases(const Interval& lhs,
|
|
const Interval& rhs) const
|
|
{
|
|
assert(MRegisterInfo::isPhysicalRegister(lhs.reg) &&
|
|
"first interval must describe a physical register");
|
|
|
|
for (const unsigned* as = mri_->getAliasSet(lhs.reg); *as; ++as) {
|
|
Reg2IntervalMap::const_iterator r2i = r2iMap_.find(*as);
|
|
assert(r2i != r2iMap_.end() && "alias does not have interval?");
|
|
if (rhs.overlaps(*r2i->second))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
LiveIntervals::Interval::Interval(unsigned r)
|
|
: reg(r),
|
|
weight((MRegisterInfo::isPhysicalRegister(r) ?
|
|
std::numeric_limits<float>::infinity() : 0.0F))
|
|
{
|
|
|
|
}
|
|
|
|
bool LiveIntervals::Interval::spilled() const
|
|
{
|
|
return (weight == std::numeric_limits<float>::infinity() &&
|
|
MRegisterInfo::isVirtualRegister(reg));
|
|
}
|
|
|
|
// An example for liveAt():
|
|
//
|
|
// this = [1,4), liveAt(0) will return false. The instruction defining
|
|
// this spans slots [0,3]. The interval belongs to an spilled
|
|
// definition of the variable it represents. This is because slot 1 is
|
|
// used (def slot) and spans up to slot 3 (store slot).
|
|
//
|
|
bool LiveIntervals::Interval::liveAt(unsigned index) const
|
|
{
|
|
Range dummy(index, index+1);
|
|
Ranges::const_iterator r = std::upper_bound(ranges.begin(),
|
|
ranges.end(),
|
|
dummy);
|
|
if (r == ranges.begin())
|
|
return false;
|
|
|
|
--r;
|
|
return index >= r->first && index < r->second;
|
|
}
|
|
|
|
// An example for overlaps():
|
|
//
|
|
// 0: A = ...
|
|
// 4: B = ...
|
|
// 8: C = A + B ;; last use of A
|
|
//
|
|
// The live intervals should look like:
|
|
//
|
|
// A = [3, 11)
|
|
// B = [7, x)
|
|
// C = [11, y)
|
|
//
|
|
// A->overlaps(C) should return false since we want to be able to join
|
|
// A and C.
|
|
bool LiveIntervals::Interval::overlaps(const Interval& other) const
|
|
{
|
|
Ranges::const_iterator i = ranges.begin();
|
|
Ranges::const_iterator ie = ranges.end();
|
|
Ranges::const_iterator j = other.ranges.begin();
|
|
Ranges::const_iterator je = other.ranges.end();
|
|
if (i->first < j->first) {
|
|
i = std::upper_bound(i, ie, *j);
|
|
if (i != ranges.begin()) --i;
|
|
}
|
|
else if (j->first < i->first) {
|
|
j = std::upper_bound(j, je, *i);
|
|
if (j != other.ranges.begin()) --j;
|
|
}
|
|
|
|
while (i != ie && j != je) {
|
|
if (i->first == j->first) {
|
|
return true;
|
|
}
|
|
else {
|
|
if (i->first > j->first) {
|
|
swap(i, j);
|
|
swap(ie, je);
|
|
}
|
|
assert(i->first < j->first);
|
|
|
|
if (i->second > j->first) {
|
|
return true;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LiveIntervals::Interval::addRange(unsigned start, unsigned end)
|
|
{
|
|
assert(start < end && "Invalid range to add!");
|
|
DEBUG(std::cerr << " +[" << start << ',' << end << ")");
|
|
//assert(start < end && "invalid range?");
|
|
Range range = std::make_pair(start, end);
|
|
Ranges::iterator it =
|
|
ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), range),
|
|
range);
|
|
|
|
it = mergeRangesForward(it);
|
|
it = mergeRangesBackward(it);
|
|
}
|
|
|
|
void LiveIntervals::Interval::join(const LiveIntervals::Interval& other)
|
|
{
|
|
DEBUG(std::cerr << "\t\tjoining " << *this << " with " << other << '\n');
|
|
Ranges::iterator cur = ranges.begin();
|
|
|
|
for (Ranges::const_iterator i = other.ranges.begin(),
|
|
e = other.ranges.end(); i != e; ++i) {
|
|
cur = ranges.insert(std::upper_bound(cur, ranges.end(), *i), *i);
|
|
cur = mergeRangesForward(cur);
|
|
cur = mergeRangesBackward(cur);
|
|
}
|
|
if (MRegisterInfo::isVirtualRegister(reg))
|
|
weight += other.weight;
|
|
}
|
|
|
|
LiveIntervals::Interval::Ranges::iterator
|
|
LiveIntervals::Interval::mergeRangesForward(Ranges::iterator it)
|
|
{
|
|
for (Ranges::iterator n = next(it);
|
|
n != ranges.end() && ((it->second & 1) + it->second) >= n->first; ) {
|
|
it->second = std::max(it->second, n->second);
|
|
n = ranges.erase(n);
|
|
}
|
|
return it;
|
|
}
|
|
|
|
LiveIntervals::Interval::Ranges::iterator
|
|
LiveIntervals::Interval::mergeRangesBackward(Ranges::iterator it)
|
|
{
|
|
while (it != ranges.begin()) {
|
|
Ranges::iterator p = prior(it);
|
|
if (it->first > ((p->second & 1) + p->second)) break;
|
|
|
|
it->first = std::min(it->first, p->first);
|
|
it->second = std::max(it->second, p->second);
|
|
it = ranges.erase(p);
|
|
}
|
|
|
|
return it;
|
|
}
|
|
|
|
std::ostream& llvm::operator<<(std::ostream& os,
|
|
const LiveIntervals::Interval& li)
|
|
{
|
|
os << "%reg" << li.reg << ',' << li.weight << " = ";
|
|
if (li.empty())
|
|
return os << "EMPTY";
|
|
for (LiveIntervals::Interval::Ranges::const_iterator
|
|
i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
|
|
os << "[" << i->first << "," << i->second << ")";
|
|
}
|
|
return os;
|
|
}
|