RegAllocGreedy.cpp [plain text]
#define DEBUG_TYPE "regalloc"
#include "AllocationOrder.h"
#include "InterferenceCache.h"
#include "LiveDebugVariables.h"
#include "LiveRangeEdit.h"
#include "RegAllocBase.h"
#include "Spiller.h"
#include "SpillPlacement.h"
#include "SplitKit.h"
#include "VirtRegMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Function.h"
#include "llvm/PassAnalysisSupport.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/EdgeBundles.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/LiveStackAnalysis.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineLoopRanges.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/RegisterCoalescer.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
#include <queue>
using namespace llvm;
STATISTIC(NumGlobalSplits, "Number of split global live ranges");
STATISTIC(NumLocalSplits, "Number of split local live ranges");
STATISTIC(NumEvicted, "Number of interferences evicted");
static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator",
createGreedyRegisterAllocator);
namespace {
class RAGreedy : public MachineFunctionPass,
public RegAllocBase,
private LiveRangeEdit::Delegate {
MachineFunction *MF;
BitVector ReservedRegs;
SlotIndexes *Indexes;
LiveStacks *LS;
MachineDominatorTree *DomTree;
MachineLoopInfo *Loops;
MachineLoopRanges *LoopRanges;
EdgeBundles *Bundles;
SpillPlacement *SpillPlacer;
std::auto_ptr<Spiller> SpillerInstance;
std::priority_queue<std::pair<unsigned, unsigned> > Queue;
enum LiveRangeStage {
RS_New, RS_First, RS_Second, RS_Global, RS_Local, RS_Spill };
IndexedMap<unsigned char, VirtReg2IndexFunctor> LRStage;
LiveRangeStage getStage(const LiveInterval &VirtReg) const {
return LiveRangeStage(LRStage[VirtReg.reg]);
}
template<typename Iterator>
void setStage(Iterator Begin, Iterator End, LiveRangeStage NewStage) {
LRStage.resize(MRI->getNumVirtRegs());
for (;Begin != End; ++Begin) {
unsigned Reg = (*Begin)->reg;
if (LRStage[Reg] == RS_New)
LRStage[Reg] = NewStage;
}
}
std::auto_ptr<SplitAnalysis> SA;
std::auto_ptr<SplitEditor> SE;
InterferenceCache IntfCache;
SmallVector<SpillPlacement::BlockConstraint, 8> SplitConstraints;
struct GlobalSplitCandidate {
unsigned PhysReg;
BitVector LiveBundles;
SmallVector<unsigned, 8> ActiveBlocks;
void reset(unsigned Reg) {
PhysReg = Reg;
LiveBundles.clear();
ActiveBlocks.clear();
}
};
SmallVector<GlobalSplitCandidate, 32> GlobalCand;
SmallVector<SlotIndex, 8> PrevSlot;
public:
RAGreedy();
virtual const char* getPassName() const {
return "Greedy Register Allocator";
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual void releaseMemory();
virtual Spiller &spiller() { return *SpillerInstance; }
virtual void enqueue(LiveInterval *LI);
virtual LiveInterval *dequeue();
virtual unsigned selectOrSplit(LiveInterval&,
SmallVectorImpl<LiveInterval*>&);
virtual bool runOnMachineFunction(MachineFunction &mf);
static char ID;
private:
void LRE_WillEraseInstruction(MachineInstr*);
bool LRE_CanEraseVirtReg(unsigned);
void LRE_WillShrinkVirtReg(unsigned);
void LRE_DidCloneVirtReg(unsigned, unsigned);
float calcSpillCost();
bool addSplitConstraints(InterferenceCache::Cursor, float&);
void addThroughConstraints(InterferenceCache::Cursor, ArrayRef<unsigned>);
void growRegion(GlobalSplitCandidate &Cand, InterferenceCache::Cursor);
float calcGlobalSplitCost(GlobalSplitCandidate&, InterferenceCache::Cursor);
void splitAroundRegion(LiveInterval&, GlobalSplitCandidate&,
SmallVectorImpl<LiveInterval*>&);
void calcGapWeights(unsigned, SmallVectorImpl<float>&);
SlotIndex getPrevMappedIndex(const MachineInstr*);
void calcPrevSlots();
unsigned nextSplitPoint(unsigned);
bool canEvictInterference(LiveInterval&, unsigned, float&);
unsigned tryAssign(LiveInterval&, AllocationOrder&,
SmallVectorImpl<LiveInterval*>&);
unsigned tryEvict(LiveInterval&, AllocationOrder&,
SmallVectorImpl<LiveInterval*>&, unsigned = ~0u);
unsigned tryRegionSplit(LiveInterval&, AllocationOrder&,
SmallVectorImpl<LiveInterval*>&);
unsigned tryLocalSplit(LiveInterval&, AllocationOrder&,
SmallVectorImpl<LiveInterval*>&);
unsigned trySplit(LiveInterval&, AllocationOrder&,
SmallVectorImpl<LiveInterval*>&);
};
}
char RAGreedy::ID = 0;
const float Hysteresis = 0.98f;
FunctionPass* llvm::createGreedyRegisterAllocator() {
return new RAGreedy();
}
RAGreedy::RAGreedy(): MachineFunctionPass(ID), LRStage(RS_New) {
initializeLiveDebugVariablesPass(*PassRegistry::getPassRegistry());
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry());
initializeRegisterCoalescerAnalysisGroup(*PassRegistry::getPassRegistry());
initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry());
initializeLiveStacksPass(*PassRegistry::getPassRegistry());
initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry());
initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry());
initializeMachineLoopRangesPass(*PassRegistry::getPassRegistry());
initializeVirtRegMapPass(*PassRegistry::getPassRegistry());
initializeEdgeBundlesPass(*PassRegistry::getPassRegistry());
initializeSpillPlacementPass(*PassRegistry::getPassRegistry());
}
void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<AliasAnalysis>();
AU.addPreserved<AliasAnalysis>();
AU.addRequired<LiveIntervals>();
AU.addRequired<SlotIndexes>();
AU.addPreserved<SlotIndexes>();
AU.addRequired<LiveDebugVariables>();
AU.addPreserved<LiveDebugVariables>();
if (StrongPHIElim)
AU.addRequiredID(StrongPHIEliminationID);
AU.addRequiredTransitive<RegisterCoalescer>();
AU.addRequired<CalculateSpillWeights>();
AU.addRequired<LiveStacks>();
AU.addPreserved<LiveStacks>();
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
AU.addRequired<MachineLoopInfo>();
AU.addPreserved<MachineLoopInfo>();
AU.addRequired<MachineLoopRanges>();
AU.addPreserved<MachineLoopRanges>();
AU.addRequired<VirtRegMap>();
AU.addPreserved<VirtRegMap>();
AU.addRequired<EdgeBundles>();
AU.addRequired<SpillPlacement>();
MachineFunctionPass::getAnalysisUsage(AU);
}
void RAGreedy::LRE_WillEraseInstruction(MachineInstr *MI) {
VRM->RemoveMachineInstrFromMaps(MI);
}
bool RAGreedy::LRE_CanEraseVirtReg(unsigned VirtReg) {
if (unsigned PhysReg = VRM->getPhys(VirtReg)) {
unassign(LIS->getInterval(VirtReg), PhysReg);
return true;
}
return false;
}
void RAGreedy::LRE_WillShrinkVirtReg(unsigned VirtReg) {
unsigned PhysReg = VRM->getPhys(VirtReg);
if (!PhysReg)
return;
LiveInterval &LI = LIS->getInterval(VirtReg);
unassign(LI, PhysReg);
enqueue(&LI);
}
void RAGreedy::LRE_DidCloneVirtReg(unsigned New, unsigned Old) {
LRStage.grow(New);
LRStage[New] = LRStage[Old];
}
void RAGreedy::releaseMemory() {
SpillerInstance.reset(0);
LRStage.clear();
GlobalCand.clear();
RegAllocBase::releaseMemory();
}
void RAGreedy::enqueue(LiveInterval *LI) {
const unsigned Size = LI->getSize();
const unsigned Reg = LI->reg;
assert(TargetRegisterInfo::isVirtualRegister(Reg) &&
"Can only enqueue virtual registers");
unsigned Prio;
LRStage.grow(Reg);
if (LRStage[Reg] == RS_New)
LRStage[Reg] = RS_First;
if (LRStage[Reg] == RS_Second)
Prio = (1u << 31) - Size;
else {
Prio = (1u << 31) + Size;
if (TargetRegisterInfo::isPhysicalRegister(VRM->getRegAllocPref(Reg)))
Prio |= (1u << 30);
}
Queue.push(std::make_pair(Prio, Reg));
}
LiveInterval *RAGreedy::dequeue() {
if (Queue.empty())
return 0;
LiveInterval *LI = &LIS->getInterval(Queue.top().second);
Queue.pop();
return LI;
}
unsigned RAGreedy::tryAssign(LiveInterval &VirtReg,
AllocationOrder &Order,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
Order.rewind();
unsigned PhysReg;
while ((PhysReg = Order.next()))
if (!checkPhysRegInterference(VirtReg, PhysReg))
break;
if (!PhysReg || Order.isHint(PhysReg))
return PhysReg;
unsigned Cost = TRI->getCostPerUse(PhysReg);
if (!Cost)
return PhysReg;
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << " is available at cost " << Cost
<< '\n');
unsigned CheapReg = tryEvict(VirtReg, Order, NewVRegs, Cost);
return CheapReg ? CheapReg : PhysReg;
}
bool RAGreedy::canEvictInterference(LiveInterval &VirtReg, unsigned PhysReg,
float &MaxWeight) {
float Weight = 0;
for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) {
LiveIntervalUnion::Query &Q = query(VirtReg, *AliasI);
if (Q.collectInterferingVRegs(10, MaxWeight) >= 10)
return false;
for (unsigned i = Q.interferingVRegs().size(); i; --i) {
LiveInterval *Intf = Q.interferingVRegs()[i - 1];
if (TargetRegisterInfo::isPhysicalRegister(Intf->reg))
return false;
if (Intf->weight >= MaxWeight)
return false;
Weight = std::max(Weight, Intf->weight);
}
}
MaxWeight = Weight;
return true;
}
unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
AllocationOrder &Order,
SmallVectorImpl<LiveInterval*> &NewVRegs,
unsigned CostPerUseLimit) {
NamedRegionTimer T("Evict", TimerGroupName, TimePassesIsEnabled);
float BestWeight = VirtReg.weight;
unsigned BestPhys = 0;
Order.rewind();
while (unsigned PhysReg = Order.next()) {
if (TRI->getCostPerUse(PhysReg) >= CostPerUseLimit)
continue;
if (CostPerUseLimit == 1 && !MRI->isPhysRegUsed(PhysReg))
continue;
float Weight = BestWeight;
if (!canEvictInterference(VirtReg, PhysReg, Weight))
continue;
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << " interference = "
<< Weight << '\n');
if (BestPhys && Weight >= BestWeight)
continue;
BestPhys = PhysReg;
BestWeight = Weight;
if (Order.isHint(PhysReg))
break;
}
if (!BestPhys)
return 0;
DEBUG(dbgs() << "evicting " << PrintReg(BestPhys, TRI) << " interference\n");
for (const unsigned *AliasI = TRI->getOverlaps(BestPhys); *AliasI; ++AliasI) {
LiveIntervalUnion::Query &Q = query(VirtReg, *AliasI);
assert(Q.seenAllInterferences() && "Didn't check all interfererences.");
for (unsigned i = 0, e = Q.interferingVRegs().size(); i != e; ++i) {
LiveInterval *Intf = Q.interferingVRegs()[i];
unassign(*Intf, VRM->getPhys(Intf->reg));
++NumEvicted;
NewVRegs.push_back(Intf);
}
}
return BestPhys;
}
bool RAGreedy::addSplitConstraints(InterferenceCache::Cursor Intf,
float &Cost) {
ArrayRef<SplitAnalysis::BlockInfo> UseBlocks = SA->getUseBlocks();
SplitConstraints.resize(UseBlocks.size());
float StaticCost = 0;
for (unsigned i = 0; i != UseBlocks.size(); ++i) {
const SplitAnalysis::BlockInfo &BI = UseBlocks[i];
SpillPlacement::BlockConstraint &BC = SplitConstraints[i];
BC.Number = BI.MBB->getNumber();
Intf.moveToBlock(BC.Number);
BC.Entry = BI.LiveIn ? SpillPlacement::PrefReg : SpillPlacement::DontCare;
BC.Exit = BI.LiveOut ? SpillPlacement::PrefReg : SpillPlacement::DontCare;
if (!Intf.hasInterference())
continue;
unsigned Ins = 0;
if (BI.LiveIn) {
if (Intf.first() <= Indexes->getMBBStartIdx(BC.Number))
BC.Entry = SpillPlacement::MustSpill, ++Ins;
else if (Intf.first() < BI.FirstUse)
BC.Entry = SpillPlacement::PrefSpill, ++Ins;
else if (Intf.first() < (BI.LiveThrough ? BI.LastUse : BI.Kill))
++Ins;
}
if (BI.LiveOut) {
if (Intf.last() >= SA->getLastSplitPoint(BC.Number))
BC.Exit = SpillPlacement::MustSpill, ++Ins;
else if (Intf.last() > BI.LastUse)
BC.Exit = SpillPlacement::PrefSpill, ++Ins;
else if (Intf.last() > (BI.LiveThrough ? BI.FirstUse : BI.Def))
++Ins;
}
if (Ins)
StaticCost += Ins * SpillPlacer->getBlockFrequency(BC.Number);
}
Cost = StaticCost;
SpillPlacer->addConstraints(SplitConstraints);
return SpillPlacer->scanActiveBundles();
}
void RAGreedy::addThroughConstraints(InterferenceCache::Cursor Intf,
ArrayRef<unsigned> Blocks) {
const unsigned GroupSize = 8;
SpillPlacement::BlockConstraint BCS[GroupSize];
unsigned TBS[GroupSize];
unsigned B = 0, T = 0;
for (unsigned i = 0; i != Blocks.size(); ++i) {
unsigned Number = Blocks[i];
Intf.moveToBlock(Number);
if (!Intf.hasInterference()) {
assert(T < GroupSize && "Array overflow");
TBS[T] = Number;
if (++T == GroupSize) {
SpillPlacer->addLinks(ArrayRef<unsigned>(TBS, T));
T = 0;
}
continue;
}
assert(B < GroupSize && "Array overflow");
BCS[B].Number = Number;
if (Intf.first() <= Indexes->getMBBStartIdx(Number))
BCS[B].Entry = SpillPlacement::MustSpill;
else
BCS[B].Entry = SpillPlacement::PrefSpill;
if (Intf.last() >= SA->getLastSplitPoint(Number))
BCS[B].Exit = SpillPlacement::MustSpill;
else
BCS[B].Exit = SpillPlacement::PrefSpill;
if (++B == GroupSize) {
ArrayRef<SpillPlacement::BlockConstraint> Array(BCS, B);
SpillPlacer->addConstraints(Array);
B = 0;
}
}
ArrayRef<SpillPlacement::BlockConstraint> Array(BCS, B);
SpillPlacer->addConstraints(Array);
SpillPlacer->addLinks(ArrayRef<unsigned>(TBS, T));
}
void RAGreedy::growRegion(GlobalSplitCandidate &Cand,
InterferenceCache::Cursor Intf) {
BitVector Todo = SA->getThroughBlocks();
SmallVectorImpl<unsigned> &ActiveBlocks = Cand.ActiveBlocks;
unsigned AddedTo = 0;
#ifndef NDEBUG
unsigned Visited = 0;
#endif
for (;;) {
ArrayRef<unsigned> NewBundles = SpillPlacer->getRecentPositive();
if (NewBundles.empty())
break;
for (int i = 0, e = NewBundles.size(); i != e; ++i) {
unsigned Bundle = NewBundles[i];
ArrayRef<unsigned> Blocks = Bundles->getBlocks(Bundle);
for (ArrayRef<unsigned>::iterator I = Blocks.begin(), E = Blocks.end();
I != E; ++I) {
unsigned Block = *I;
if (!Todo.test(Block))
continue;
Todo.reset(Block);
ActiveBlocks.push_back(Block);
#ifndef NDEBUG
++Visited;
#endif
}
}
if (ActiveBlocks.size() > AddedTo) {
ArrayRef<unsigned> Add(&ActiveBlocks[AddedTo],
ActiveBlocks.size() - AddedTo);
addThroughConstraints(Intf, Add);
AddedTo = ActiveBlocks.size();
}
SpillPlacer->iterate();
}
DEBUG(dbgs() << ", v=" << Visited);
}
float RAGreedy::calcSpillCost() {
float Cost = 0;
const LiveInterval &LI = SA->getParent();
ArrayRef<SplitAnalysis::BlockInfo> UseBlocks = SA->getUseBlocks();
for (unsigned i = 0; i != UseBlocks.size(); ++i) {
const SplitAnalysis::BlockInfo &BI = UseBlocks[i];
unsigned Number = BI.MBB->getNumber();
Cost += SpillPlacer->getBlockFrequency(Number);
if (BI.LiveIn && BI.LiveOut) {
SlotIndex Start, Stop;
tie(Start, Stop) = Indexes->getMBBRange(Number);
LiveInterval::const_iterator I = LI.find(Start);
assert(I != LI.end() && "Expected live-in value");
if (I->end < Stop)
Cost += SpillPlacer->getBlockFrequency(Number);
}
}
return Cost;
}
float RAGreedy::calcGlobalSplitCost(GlobalSplitCandidate &Cand,
InterferenceCache::Cursor Intf) {
float GlobalCost = 0;
const BitVector &LiveBundles = Cand.LiveBundles;
ArrayRef<SplitAnalysis::BlockInfo> UseBlocks = SA->getUseBlocks();
for (unsigned i = 0; i != UseBlocks.size(); ++i) {
const SplitAnalysis::BlockInfo &BI = UseBlocks[i];
SpillPlacement::BlockConstraint &BC = SplitConstraints[i];
bool RegIn = LiveBundles[Bundles->getBundle(BC.Number, 0)];
bool RegOut = LiveBundles[Bundles->getBundle(BC.Number, 1)];
unsigned Ins = 0;
if (BI.LiveIn)
Ins += RegIn != (BC.Entry == SpillPlacement::PrefReg);
if (BI.LiveOut)
Ins += RegOut != (BC.Exit == SpillPlacement::PrefReg);
if (Ins)
GlobalCost += Ins * SpillPlacer->getBlockFrequency(BC.Number);
}
for (unsigned i = 0, e = Cand.ActiveBlocks.size(); i != e; ++i) {
unsigned Number = Cand.ActiveBlocks[i];
bool RegIn = LiveBundles[Bundles->getBundle(Number, 0)];
bool RegOut = LiveBundles[Bundles->getBundle(Number, 1)];
if (!RegIn && !RegOut)
continue;
if (RegIn && RegOut) {
Intf.moveToBlock(Number);
if (Intf.hasInterference())
GlobalCost += 2*SpillPlacer->getBlockFrequency(Number);
continue;
}
GlobalCost += SpillPlacer->getBlockFrequency(Number);
}
return GlobalCost;
}
void RAGreedy::splitAroundRegion(LiveInterval &VirtReg,
GlobalSplitCandidate &Cand,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
const BitVector &LiveBundles = Cand.LiveBundles;
DEBUG({
dbgs() << "Splitting around region for " << PrintReg(Cand.PhysReg, TRI)
<< " with bundles";
for (int i = LiveBundles.find_first(); i>=0; i = LiveBundles.find_next(i))
dbgs() << " EB#" << i;
dbgs() << ".\n";
});
InterferenceCache::Cursor Intf(IntfCache, Cand.PhysReg);
LiveRangeEdit LREdit(VirtReg, NewVRegs, this);
SE->reset(LREdit);
const unsigned MainIntv = SE->openIntv();
ArrayRef<SplitAnalysis::BlockInfo> UseBlocks = SA->getUseBlocks();
for (unsigned i = 0; i != UseBlocks.size(); ++i) {
const SplitAnalysis::BlockInfo &BI = UseBlocks[i];
bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)];
bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)];
if (!RegIn && !RegOut && BI.FirstUse != BI.LastUse) {
DEBUG(dbgs() << "BB#" << BI.MBB->getNumber() << " isolated.\n");
SE->splitSingleBlock(BI);
SE->selectIntv(MainIntv);
continue;
}
if (!BI.LiveOut || !RegOut)
continue;
SlotIndex Start, Stop;
tie(Start, Stop) = Indexes->getMBBRange(BI.MBB);
Intf.moveToBlock(BI.MBB->getNumber());
DEBUG(dbgs() << "BB#" << BI.MBB->getNumber() << " -> EB#"
<< Bundles->getBundle(BI.MBB->getNumber(), 1)
<< " [" << Start << ';'
<< SA->getLastSplitPoint(BI.MBB->getNumber()) << '-' << Stop
<< ") intf [" << Intf.first() << ';' << Intf.last() << ')');
assert((!Intf.hasInterference() || Intf.first() < Stop)
&& "Bad interference");
assert((!Intf.hasInterference() || Intf.last() > Start)
&& "Bad interference");
if (!Intf.hasInterference()) {
DEBUG(dbgs() << ", no interference");
if (!BI.LiveThrough) {
DEBUG(dbgs() << ", not live-through.\n");
SE->useIntv(SE->enterIntvBefore(BI.Def), Stop);
continue;
}
if (!RegIn) {
DEBUG(dbgs() << ", not live-in, enter before first use.\n");
SE->useIntv(SE->enterIntvBefore(BI.FirstUse), Stop);
continue;
}
DEBUG(dbgs() << ", live-through.\n");
continue;
}
DEBUG(dbgs() << ", interference to " << Intf.last());
if (!BI.LiveThrough && Intf.last() <= BI.Def) {
DEBUG(dbgs() << " doesn't affect def from " << BI.Def << '\n');
SE->useIntv(BI.Def, Stop);
continue;
}
SlotIndex LastSplitPoint = SA->getLastSplitPoint(BI.MBB->getNumber());
if (Intf.last().getBoundaryIndex() < BI.LastUse) {
SmallVectorImpl<SlotIndex>::const_iterator UI =
std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(),
Intf.last().getBoundaryIndex());
assert(UI != SA->UseSlots.end() && "Couldn't find last use");
SlotIndex Use = *UI;
assert(Use <= BI.LastUse && "Couldn't find last use");
if (Use.getBaseIndex() <= LastSplitPoint) {
DEBUG(dbgs() << ", free use at " << Use << ".\n");
SlotIndex SegStart = SE->enterIntvBefore(Use);
assert(SegStart >= Intf.last() && "Couldn't avoid interference");
assert(SegStart < LastSplitPoint && "Impossible split point");
SE->useIntv(SegStart, Stop);
continue;
}
}
DEBUG(dbgs() << " after last use.\n");
SlotIndex SegStart = SE->enterIntvAtEnd(*BI.MBB);
assert(SegStart >= Intf.last() && "Couldn't avoid interference");
}
for (unsigned i = 0; i != UseBlocks.size(); ++i) {
const SplitAnalysis::BlockInfo &BI = UseBlocks[i];
bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)];
bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)];
if (!BI.LiveIn || !RegIn)
continue;
SlotIndex Start, Stop;
tie(Start, Stop) = Indexes->getMBBRange(BI.MBB);
Intf.moveToBlock(BI.MBB->getNumber());
DEBUG(dbgs() << "EB#" << Bundles->getBundle(BI.MBB->getNumber(), 0)
<< " -> BB#" << BI.MBB->getNumber() << " [" << Start << ';'
<< SA->getLastSplitPoint(BI.MBB->getNumber()) << '-' << Stop
<< ')');
if (!Intf.hasInterference()) {
DEBUG(dbgs() << ", no interference");
if (!BI.LiveThrough) {
DEBUG(dbgs() << ", killed in block.\n");
SE->useIntv(Start, SE->leaveIntvAfter(BI.Kill));
continue;
}
if (!RegOut) {
SlotIndex LastSplitPoint = SA->getLastSplitPoint(BI.MBB->getNumber());
if (BI.LastUse < LastSplitPoint) {
DEBUG(dbgs() << ", uses, stack-out.\n");
SE->useIntv(Start, SE->leaveIntvAfter(BI.LastUse));
continue;
}
DEBUG(dbgs() << ", uses at " << BI.LastUse << " after split point "
<< LastSplitPoint << ", stack-out.\n");
SlotIndex SegEnd = SE->leaveIntvBefore(LastSplitPoint);
SE->useIntv(Start, SegEnd);
SE->overlapIntv(SegEnd, BI.LastUse);
continue;
}
DEBUG(dbgs() << ", uses, live-through.\n");
SE->useIntv(Start, Stop);
continue;
}
DEBUG(dbgs() << ", interference from " << Intf.first());
if (!BI.LiveThrough && Intf.first() >= BI.Kill) {
DEBUG(dbgs() << " doesn't affect kill at " << BI.Kill << '\n');
SE->useIntv(Start, BI.Kill);
continue;
}
if (Intf.first().getBaseIndex() > BI.FirstUse) {
SmallVectorImpl<SlotIndex>::const_iterator UI =
std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(),
Intf.first().getBaseIndex());
assert(UI != SA->UseSlots.begin() && "Couldn't find first use");
SlotIndex Use = (--UI)->getBoundaryIndex();
DEBUG(dbgs() << ", free use at " << *UI << ".\n");
SlotIndex SegEnd = SE->leaveIntvAfter(Use);
assert(SegEnd <= Intf.first() && "Couldn't avoid interference");
SE->useIntv(Start, SegEnd);
continue;
}
DEBUG(dbgs() << " before first use.\n");
SlotIndex SegEnd = SE->leaveIntvAtTop(*BI.MBB);
assert(SegEnd <= Intf.first() && "Couldn't avoid interference");
}
for (unsigned i = 0, e = Cand.ActiveBlocks.size(); i != e; ++i) {
unsigned Number = Cand.ActiveBlocks[i];
bool RegIn = LiveBundles[Bundles->getBundle(Number, 0)];
bool RegOut = LiveBundles[Bundles->getBundle(Number, 1)];
DEBUG(dbgs() << "Live through BB#" << Number << '\n');
if (RegIn && RegOut) {
Intf.moveToBlock(Number);
if (!Intf.hasInterference()) {
SE->useIntv(Indexes->getMBBStartIdx(Number),
Indexes->getMBBEndIdx(Number));
continue;
}
}
MachineBasicBlock *MBB = MF->getBlockNumbered(Number);
if (RegIn)
SE->leaveIntvAtTop(*MBB);
if (RegOut)
SE->enterIntvAtEnd(*MBB);
}
++NumGlobalSplits;
SmallVector<unsigned, 8> IntvMap;
SE->finish(&IntvMap);
LRStage.resize(MRI->getNumVirtRegs());
unsigned OrigBlocks = SA->getNumThroughBlocks() + SA->getUseBlocks().size();
for (unsigned i = 0, e = LREdit.size(); i != e; ++i) {
unsigned Reg = LREdit.get(i)->reg;
if (LRStage[Reg] != RS_New)
continue;
if (IntvMap[i] == 0) {
LRStage[Reg] = RS_Global;
continue;
}
if (IntvMap[i] == MainIntv) {
if (SA->countLiveBlocks(LREdit.get(i)) >= OrigBlocks) {
DEBUG(dbgs() << "Main interval covers the same " << OrigBlocks
<< " blocks as original.\n");
LRStage[Reg] = RS_Global;
}
continue;
}
}
if (VerifyEnabled)
MF->verify(this, "After splitting live range around region");
}
unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
float BestCost = Hysteresis * calcSpillCost();
DEBUG(dbgs() << "Cost of isolating all blocks = " << BestCost << '\n');
const unsigned NoCand = ~0u;
unsigned BestCand = NoCand;
Order.rewind();
for (unsigned Cand = 0; unsigned PhysReg = Order.next(); ++Cand) {
if (GlobalCand.size() <= Cand)
GlobalCand.resize(Cand+1);
GlobalCand[Cand].reset(PhysReg);
SpillPlacer->prepare(GlobalCand[Cand].LiveBundles);
float Cost;
InterferenceCache::Cursor Intf(IntfCache, PhysReg);
if (!addSplitConstraints(Intf, Cost)) {
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << "\tno positive bundles\n");
continue;
}
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << "\tstatic = " << Cost);
if (Cost >= BestCost) {
DEBUG({
if (BestCand == NoCand)
dbgs() << " worse than no bundles\n";
else
dbgs() << " worse than "
<< PrintReg(GlobalCand[BestCand].PhysReg, TRI) << '\n';
});
continue;
}
growRegion(GlobalCand[Cand], Intf);
SpillPlacer->finish();
if (!GlobalCand[Cand].LiveBundles.any()) {
DEBUG(dbgs() << " no bundles.\n");
continue;
}
Cost += calcGlobalSplitCost(GlobalCand[Cand], Intf);
DEBUG({
dbgs() << ", total = " << Cost << " with bundles";
for (int i = GlobalCand[Cand].LiveBundles.find_first(); i>=0;
i = GlobalCand[Cand].LiveBundles.find_next(i))
dbgs() << " EB#" << i;
dbgs() << ".\n";
});
if (Cost < BestCost) {
BestCand = Cand;
BestCost = Hysteresis * Cost; }
}
if (BestCand == NoCand)
return 0;
splitAroundRegion(VirtReg, GlobalCand[BestCand], NewVRegs);
return 0;
}
void RAGreedy::calcGapWeights(unsigned PhysReg,
SmallVectorImpl<float> &GapWeight) {
assert(SA->getUseBlocks().size() == 1 && "Not a local interval");
const SplitAnalysis::BlockInfo &BI = SA->getUseBlocks().front();
const SmallVectorImpl<SlotIndex> &Uses = SA->UseSlots;
const unsigned NumGaps = Uses.size()-1;
SlotIndex StartIdx = BI.LiveIn ? BI.FirstUse.getBaseIndex() : BI.FirstUse;
SlotIndex StopIdx = BI.LiveOut ? BI.LastUse.getBoundaryIndex() : BI.LastUse;
GapWeight.assign(NumGaps, 0.0f);
for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) {
if (!query(const_cast<LiveInterval&>(SA->getParent()), *AI)
.checkInterference())
continue;
LiveIntervalUnion::SegmentIter IntI = PhysReg2LiveUnion[*AI].find(StartIdx);
for (unsigned Gap = 0; IntI.valid() && IntI.start() < StopIdx; ++IntI) {
while (Uses[Gap+1].getBoundaryIndex() < IntI.start())
if (++Gap == NumGaps)
break;
if (Gap == NumGaps)
break;
const float weight = IntI.value()->weight;
for (; Gap != NumGaps; ++Gap) {
GapWeight[Gap] = std::max(GapWeight[Gap], weight);
if (Uses[Gap+1].getBaseIndex() >= IntI.stop())
break;
}
if (Gap == NumGaps)
break;
}
}
}
SlotIndex RAGreedy::getPrevMappedIndex(const MachineInstr *MI) {
assert(MI && "Missing MachineInstr");
const MachineBasicBlock *MBB = MI->getParent();
MachineBasicBlock::const_iterator B = MBB->begin(), I = MI;
while (I != B)
if (!(--I)->isDebugValue() && !I->isCopy())
return Indexes->getInstructionIndex(I);
return Indexes->getMBBStartIdx(MBB);
}
void RAGreedy::calcPrevSlots() {
const SmallVectorImpl<SlotIndex> &Uses = SA->UseSlots;
PrevSlot.clear();
PrevSlot.reserve(Uses.size());
for (unsigned i = 0, e = Uses.size(); i != e; ++i) {
const MachineInstr *MI = Indexes->getInstructionFromIndex(Uses[i]);
PrevSlot.push_back(getPrevMappedIndex(MI).getDefIndex());
}
}
unsigned RAGreedy::nextSplitPoint(unsigned i) {
const SmallVectorImpl<SlotIndex> &Uses = SA->UseSlots;
const unsigned Size = Uses.size();
assert(i != Size && "No split points after the end");
while (++i != Size && PrevSlot[i].getBaseIndex() <= Uses[i-1].getBaseIndex())
;
return i;
}
unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
assert(SA->getUseBlocks().size() == 1 && "Not a local interval");
const SplitAnalysis::BlockInfo &BI = SA->getUseBlocks().front();
const SmallVectorImpl<SlotIndex> &Uses = SA->UseSlots;
if (Uses.size() <= 2)
return 0;
const unsigned NumGaps = Uses.size()-1;
DEBUG({
dbgs() << "tryLocalSplit: ";
for (unsigned i = 0, e = Uses.size(); i != e; ++i)
dbgs() << ' ' << SA->UseSlots[i];
dbgs() << '\n';
});
calcPrevSlots();
unsigned BestBefore = NumGaps;
unsigned BestAfter = 0;
float BestDiff = 0;
const float blockFreq = SpillPlacer->getBlockFrequency(BI.MBB->getNumber());
SmallVector<float, 8> GapWeight;
Order.rewind();
while (unsigned PhysReg = Order.next()) {
calcGapWeights(PhysReg, GapWeight);
unsigned SplitBefore = 0, SplitAfter = nextSplitPoint(1) - 1;
float MaxGap = GapWeight[0];
for (unsigned i = 1; i != SplitAfter; ++i)
MaxGap = std::max(MaxGap, GapWeight[i]);
for (;;) {
const bool LiveBefore = SplitBefore != 0 || BI.LiveIn;
const bool LiveAfter = SplitAfter != NumGaps || BI.LiveOut;
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << ' '
<< Uses[SplitBefore] << '-' << Uses[SplitAfter]
<< " i=" << MaxGap);
if (!LiveBefore && !LiveAfter) {
DEBUG(dbgs() << " all\n");
break;
}
bool Shrink = true;
if (MaxGap < HUGE_VALF) {
const unsigned EstUses = 2*(SplitAfter - SplitBefore) +
2*(LiveBefore + LiveAfter);
const float EstWeight = normalizeSpillWeight(blockFreq * EstUses,
PrevSlot[SplitBefore].distance(Uses[SplitAfter]));
DEBUG(dbgs() << " w=" << EstWeight);
if (EstWeight * Hysteresis >= MaxGap) {
Shrink = false;
float Diff = EstWeight - MaxGap;
if (Diff > BestDiff) {
DEBUG(dbgs() << " (best)");
BestDiff = Hysteresis * Diff;
BestBefore = SplitBefore;
BestAfter = SplitAfter;
}
}
}
if (Shrink) {
SplitBefore = nextSplitPoint(SplitBefore);
if (SplitBefore < SplitAfter) {
DEBUG(dbgs() << " shrink\n");
if (GapWeight[SplitBefore - 1] >= MaxGap) {
MaxGap = GapWeight[SplitBefore];
for (unsigned i = SplitBefore + 1; i != SplitAfter; ++i)
MaxGap = std::max(MaxGap, GapWeight[i]);
}
continue;
}
MaxGap = 0;
}
if (SplitAfter >= NumGaps) {
DEBUG(dbgs() << " end\n");
break;
}
DEBUG(dbgs() << " extend\n");
for (unsigned e = nextSplitPoint(SplitAfter + 1) - 1;
SplitAfter != e; ++SplitAfter)
MaxGap = std::max(MaxGap, GapWeight[SplitAfter]);
continue;
}
}
if (BestBefore == NumGaps)
return 0;
DEBUG(dbgs() << "Best local split range: " << Uses[BestBefore]
<< '-' << Uses[BestAfter] << ", " << BestDiff
<< ", " << (BestAfter - BestBefore + 1) << " instrs\n");
LiveRangeEdit LREdit(VirtReg, NewVRegs, this);
SE->reset(LREdit);
SE->openIntv();
SlotIndex SegStart = SE->enterIntvBefore(Uses[BestBefore]);
SlotIndex SegStop = SE->leaveIntvAfter(Uses[BestAfter]);
SE->useIntv(SegStart, SegStop);
SE->finish();
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Local);
++NumLocalSplits;
return 0;
}
unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order,
SmallVectorImpl<LiveInterval*>&NewVRegs) {
if (LIS->intervalIsInOneMBB(VirtReg)) {
NamedRegionTimer T("Local Splitting", TimerGroupName, TimePassesIsEnabled);
SA->analyze(&VirtReg);
return tryLocalSplit(VirtReg, Order, NewVRegs);
}
NamedRegionTimer T("Global Splitting", TimerGroupName, TimePassesIsEnabled);
if (getStage(VirtReg) >= RS_Global)
return 0;
SA->analyze(&VirtReg);
if (SA->didRepairRange()) {
Order.rewind();
while (unsigned PhysReg = Order.next())
query(VirtReg, PhysReg).clear();
if (unsigned PhysReg = tryAssign(VirtReg, Order, NewVRegs))
return PhysReg;
}
unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs);
if (PhysReg || !NewVRegs.empty())
return PhysReg;
SplitAnalysis::BlockPtrSet Blocks;
if (SA->getMultiUseBlocks(Blocks)) {
LiveRangeEdit LREdit(VirtReg, NewVRegs, this);
SE->reset(LREdit);
SE->splitSingleBlocks(Blocks);
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Global);
if (VerifyEnabled)
MF->verify(this, "After splitting live range around basic blocks");
}
return 0;
}
unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs);
if (unsigned PhysReg = tryAssign(VirtReg, Order, NewVRegs))
return PhysReg;
if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
return PhysReg;
assert(NewVRegs.empty() && "Cannot append to existing NewVRegs");
LiveRangeStage Stage = getStage(VirtReg);
if (Stage == RS_First) {
LRStage[VirtReg.reg] = RS_Second;
DEBUG(dbgs() << "wait for second round\n");
NewVRegs.push_back(&VirtReg);
return 0;
}
assert(Stage < RS_Spill && "Cannot allocate after spilling");
unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs);
if (PhysReg || !NewVRegs.empty())
return PhysReg;
NamedRegionTimer T("Spiller", TimerGroupName, TimePassesIsEnabled);
LiveRangeEdit LRE(VirtReg, NewVRegs, this);
spiller().spill(LRE);
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Spill);
if (VerifyEnabled)
MF->verify(this, "After spilling");
return 0;
}
bool RAGreedy::runOnMachineFunction(MachineFunction &mf) {
DEBUG(dbgs() << "********** GREEDY REGISTER ALLOCATION **********\n"
<< "********** Function: "
<< ((Value*)mf.getFunction())->getName() << '\n');
MF = &mf;
if (VerifyEnabled)
MF->verify(this, "Before greedy register allocator");
RegAllocBase::init(getAnalysis<VirtRegMap>(), getAnalysis<LiveIntervals>());
Indexes = &getAnalysis<SlotIndexes>();
DomTree = &getAnalysis<MachineDominatorTree>();
ReservedRegs = TRI->getReservedRegs(*MF);
SpillerInstance.reset(createInlineSpiller(*this, *MF, *VRM));
Loops = &getAnalysis<MachineLoopInfo>();
LoopRanges = &getAnalysis<MachineLoopRanges>();
Bundles = &getAnalysis<EdgeBundles>();
SpillPlacer = &getAnalysis<SpillPlacement>();
SA.reset(new SplitAnalysis(*VRM, *LIS, *Loops));
SE.reset(new SplitEditor(*SA, *LIS, *VRM, *DomTree));
LRStage.clear();
LRStage.resize(MRI->getNumVirtRegs());
IntfCache.init(MF, &PhysReg2LiveUnion[0], Indexes, TRI);
allocatePhysRegs();
addMBBLiveIns(MF);
LIS->addKillFlags();
{
NamedRegionTimer T("Rewriter", TimerGroupName, TimePassesIsEnabled);
VRM->rewrite(Indexes);
}
getAnalysis<LiveDebugVariables>().emitDebugValues(VRM);
releaseMemory();
return true;
}