[LLVMdev] Spillers
David Greene
dag at cray.com
Mon Aug 6 09:20:56 PDT 2007
Can someone explain the theory behind the spillers in VirtRegMap.cpp?
It seems as though the spillers do triple duty:
- Insert load/store operations and/or fold instructions as necessary to carry
out spills
- Rewrite the spilled virtual registers to use machine registers (mapping
given by the caller in the VRM).
- Rewrite machine code to change virtual registers to physical registers
(mapping given by the caller in the VRM, presumably the caller is regalloc).
My question concerns duty #2. There is code in the spiller that assumes
intervals created to spill a virtual register have been mapped to physical
registers. Why is this so? This puts a constraint on register allocation
that is potentially bad.
For example, the prototype graph coloring allocator posted by Bill W. some
time ago has this code in it (the **** comments are my own):
/// SpillLiveInterval - Assign a live interval to a stack slot.
///
void RegAlloc::SpillLiveInterval(LiveInterval* LI) {
[...]
int Slot = VRM->assignVirt2StackSlot(LI->reg);
DEBUG(std::cerr << "Spilling " << *LI << " into slot " << Slot << "\n");
std::vector<LiveInterval*> Added =
LIs->addIntervalsForSpills(*LI, *VRM, Slot);
static unsigned J = 0;
for (unsigned I = 0; I < Added.size(); ++I, ++J) {
unsigned VReg = Added[I]->reg;
const TargetRegisterClass* RC = MF->getSSARegMap()->getRegClass(VReg);
TargetRegisterClass::const_iterator Iter =
RC->allocation_order_begin(*MF);
if (Iter + J >= RC->allocation_order_end(*MF)) J = 0;
unsigned PReg = *(Iter + J);
// **** Assign the newly-created live interval to a physical register
VRM->assignVirt2Phys(VReg, PReg);
PRT->addRegUse(PReg);
DEBUG(std::cerr << "\tAdded LI: " << *Added[I]
<< " assigned Reg " << MRI->getName(PReg)
<< "\n");
for (LiveIntervals::const_iterator
K = LIs->begin(); K != LIs->end(); ++K) {
const LiveInterval& L = K->second;
unsigned LIReg = L.reg;
if (!MRegisterInfo::isVirtualRegister(LIReg) || LIReg == VReg) continue;
// **** Check to see if the physreg we assigned conflicts with something
// **** else. If so, that thing has to live in memory too.
if (VRM->hasPhys(LIReg) && VRM->getPhys(LIReg) == PReg &&
!VRM->hasStackSlot(LIReg) && Added[I]->overlaps(L))
VRM->assignVirt2StackSlot(LIReg);
}
}
The two points I want to talk about are noted by the **** comments. The first
takes a newly-created live interval to represent the lifetime between a reload
and use of the reload (or def and store) and assigns it a physical register
*outside of the coloring algorithm proper.* This is due to the requirement
that the spiller see spill intervals mapped to physical registers.
The second is a consequence of the first. Because of this hackish "coloring"
of the spill interval, we may have to patch up code and move other things
into memory as well. This is bad.
Traditionally, a graph coloring algorithm spills some number of candidates and
then restarts the algorithm with the graph representing the newly-inserted
live intervals for the spills. Those intervals get colored along with
everything else and therefore the allocator can make a better decision based
on the global information available.
It seems as though the current spillers assume they are the last thing to run.
That's not true in the general case as allocators often want to iterate to get
the best mapping possible. In fact the priority-based coloring algorithm Bill
posted avoids this iteration precisely because it can't easily happen (as I'm
discovering as I implement my own algorithm). This leads to poorer register
allocation than is necessary.
Right now, I'm simply trying to understand the logic of the spillers and why
they expect spill intervals to be pre-colored. Can someone help?
Thanks.
-Dave
More information about the llvm-dev
mailing list