Keep track of which stage produced a live range, and bypass earlier stages when revisiting.

This effectively disables the 'turbo' functionality of the greedy register
allocator where all new live ranges created by splitting would be reconsidered
as if they were originals.

There are two reasons for doing this, 1. It guarantees that the algorithm
terminates. Early versions were prone to infinite looping in certain corner
cases. 2. It is a 2x speedup. We can skip a lot of unnecessary interference
checks that won't lead to good splitting anyway.

The problem is that region splitting only gets one shot, so it should probably
be changed to target multiple physical registers at once.

Local live range splitting is still 'turbo' enabled. It only accounts for a
small fraction of compile time, so it is probably not necessary to do anything
about that.

llvm-svn: 126781
This commit is contained in:
Jakob Stoklund Olesen 2011-03-01 21:10:07 +00:00
parent c76ae9c8e0
commit 5f9f081d76
1 changed files with 76 additions and 20 deletions

View File

@ -72,11 +72,45 @@ class RAGreedy : public MachineFunctionPass, public RegAllocBase {
// state
std::auto_ptr<Spiller> SpillerInstance;
std::auto_ptr<SplitAnalysis> SA;
std::priority_queue<std::pair<unsigned, unsigned> > Queue;
IndexedMap<unsigned, VirtReg2IndexFunctor> Generation;
// Live ranges pass through a number of stages as we try to allocate them.
// Some of the stages may also create new live ranges:
//
// - Region splitting.
// - Per-block splitting.
// - Local splitting.
// - Spilling.
//
// Ranges produced by one of the stages skip the previous stages when they are
// dequeued. This improves performance because we can skip interference checks
// that are unlikely to give any results. It also guarantees that the live
// range splitting algorithm terminates, something that is otherwise hard to
// ensure.
enum LiveRangeStage {
RS_Original, ///< Never seen before, never split.
RS_Second, ///< Second time in the queue.
RS_Region, ///< Produced by region splitting.
RS_Block, ///< Produced by per-block splitting.
RS_Local, ///< Produced by local splitting.
RS_Spill ///< Produced by spilling.
};
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)
LRStage[(*Begin)->reg] = NewStage;
}
// splitting state.
std::auto_ptr<SplitAnalysis> SA;
/// All basic blocks where the current register is live.
SmallVector<SpillPlacement::BlockConstraint, 8> SpillConstraints;
@ -143,7 +177,7 @@ FunctionPass* llvm::createGreedyRegisterAllocator() {
return new RAGreedy();
}
RAGreedy::RAGreedy(): MachineFunctionPass(ID) {
RAGreedy::RAGreedy(): MachineFunctionPass(ID), LRStage(RS_Original) {
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
@ -187,7 +221,7 @@ void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const {
void RAGreedy::releaseMemory() {
SpillerInstance.reset(0);
Generation.clear();
LRStage.clear();
RegAllocBase::releaseMemory();
}
@ -198,11 +232,10 @@ void RAGreedy::enqueue(LiveInterval *LI) {
const unsigned Reg = LI->reg;
assert(TargetRegisterInfo::isVirtualRegister(Reg) &&
"Can only enqueue virtual registers");
const unsigned Hint = VRM->getRegAllocPref(Reg);
unsigned Prio;
Generation.grow(Reg);
if (++Generation[Reg] == 1)
LRStage.grow(Reg);
if (LRStage[Reg] == RS_Original)
// 1st generation ranges are handled first, long -> short.
Prio = (1u << 31) + Size;
else
@ -210,6 +243,7 @@ void RAGreedy::enqueue(LiveInterval *LI) {
Prio = (1u << 30) - Size;
// Boost ranges that have a physical register hint.
const unsigned Hint = VRM->getRegAllocPref(Reg);
if (TargetRegisterInfo::isPhysicalRegister(Hint))
Prio |= (1u << 30);
@ -926,6 +960,7 @@ unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order,
return 0;
splitAroundRegion(VirtReg, BestReg, BestBundles, NewVRegs);
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Region);
return 0;
}
@ -1191,6 +1226,7 @@ unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order,
SE.useIntv(SegStart, SegStop);
SE.closeIntv();
SE.finish();
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Local);
++NumLocalSplits;
return 0;
@ -1205,29 +1241,41 @@ unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order,
/// @return Physreg when VirtReg may be assigned and/or new NewVRegs.
unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order,
SmallVectorImpl<LiveInterval*>&NewVRegs) {
SA->analyze(&VirtReg);
// Local intervals are handled separately.
if (LIS->intervalIsInOneMBB(VirtReg)) {
NamedRegionTimer T("Local Splitting", TimerGroupName, TimePassesIsEnabled);
SA->analyze(&VirtReg);
return tryLocalSplit(VirtReg, Order, NewVRegs);
}
NamedRegionTimer T("Global Splitting", TimerGroupName, TimePassesIsEnabled);
// Don't iterate global splitting.
// Move straight to spilling if this range was produced by a global split.
LiveRangeStage Stage = getStage(VirtReg);
if (Stage >= RS_Block)
return 0;
SA->analyze(&VirtReg);
// First try to split around a region spanning multiple blocks.
unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs);
if (PhysReg || !NewVRegs.empty())
return PhysReg;
if (Stage < RS_Region) {
unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs);
if (PhysReg || !NewVRegs.empty())
return PhysReg;
}
// Then isolate blocks with multiple uses.
SplitAnalysis::BlockPtrSet Blocks;
if (SA->getMultiUseBlocks(Blocks)) {
SmallVector<LiveInterval*, 4> SpillRegs;
LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs);
SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit).splitSingleBlocks(Blocks);
if (VerifyEnabled)
MF->verify(this, "After splitting live range around basic blocks");
if (Stage < RS_Block) {
SplitAnalysis::BlockPtrSet Blocks;
if (SA->getMultiUseBlocks(Blocks)) {
SmallVector<LiveInterval*, 4> SpillRegs;
LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs);
SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit).splitSingleBlocks(Blocks);
setStage(NewVRegs.begin(), NewVRegs.end(), RS_Block);
if (VerifyEnabled)
MF->verify(this, "After splitting live range around basic blocks");
}
}
// Don't assign any physregs.
@ -1303,6 +1351,10 @@ unsigned RAGreedy::trySpillInterferences(LiveInterval &VirtReg,
unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
SmallVectorImpl<LiveInterval*> &NewVRegs) {
LiveRangeStage Stage = getStage(VirtReg);
if (Stage == RS_Original)
LRStage[VirtReg.reg] = RS_Second;
// First try assigning a free register.
AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs);
while (unsigned PhysReg = Order.next()) {
@ -1321,11 +1373,13 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
// The first time we see a live range, don't try to split or spill.
// Wait until the second time, when all smaller ranges have been allocated.
// This gives a better picture of the interference to split around.
if (Generation[VirtReg.reg] == 1) {
if (Stage == RS_Original) {
NewVRegs.push_back(&VirtReg);
return 0;
}
assert(Stage < RS_Spill && "Cannot allocate after spilling");
// Try splitting VirtReg or interferences.
unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs);
if (PhysReg || !NewVRegs.empty())
@ -1366,6 +1420,8 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) {
SpillPlacer = &getAnalysis<SpillPlacement>();
SA.reset(new SplitAnalysis(*VRM, *LIS, *Loops));
LRStage.clear();
LRStage.resize(MRI->getNumVirtRegs());
allocatePhysRegs();
addMBBLiveIns(MF);