forked from OSchip/llvm-project
Add support for spreading register allocation.
Add a -linearscan-skip-count argument (default to 0) that tells the allocator to remember the last N registers it allocated and skip them when looking for a register candidate. This tends to spread out register usage and free up post-allocation scheduling at the cost of slightly more register pressure. The primary benefit is the ability to backschedule reloads. This is turned off by default. llvm-svn: 89356
This commit is contained in:
parent
aff01ceb95
commit
f37756d609
|
@ -64,9 +64,30 @@ linearscanRegAlloc("linearscan", "linear scan register allocator",
|
|||
createLinearScanRegisterAllocator);
|
||||
|
||||
namespace {
|
||||
// When we allocate a register, add it to a fixed-size queue of
|
||||
// registers to skip in subsequent allocations. This trades a small
|
||||
// amount of register pressure and increased spills for flexibility in
|
||||
// the post-pass scheduler.
|
||||
//
|
||||
// Note that in a the number of registers used for reloading spills
|
||||
// will be one greater than the value of this option.
|
||||
//
|
||||
// One big limitation of this is that it doesn't differentiate between
|
||||
// different register classes. So on x86-64, if there is xmm register
|
||||
// pressure, it can caused fewer GPRs to be held in the queue.
|
||||
static cl::opt<unsigned>
|
||||
NumRecentlyUsedRegs("linearscan-skip-count",
|
||||
cl::desc("Number of registers for linearscan to remember to skip."),
|
||||
cl::init(0),
|
||||
cl::Hidden);
|
||||
|
||||
struct RALinScan : public MachineFunctionPass {
|
||||
static char ID;
|
||||
RALinScan() : MachineFunctionPass(&ID) {}
|
||||
RALinScan() : MachineFunctionPass(&ID) {
|
||||
// Initialize the queue to record recently-used registers.
|
||||
if (NumRecentlyUsedRegs > 0)
|
||||
RecentRegs.resize(NumRecentlyUsedRegs, 0);
|
||||
}
|
||||
|
||||
typedef std::pair<LiveInterval*, LiveInterval::iterator> IntervalPtr;
|
||||
typedef SmallVector<IntervalPtr, 32> IntervalPtrs;
|
||||
|
@ -132,6 +153,18 @@ namespace {
|
|||
|
||||
std::auto_ptr<Spiller> spiller_;
|
||||
|
||||
// The queue of recently-used registers.
|
||||
SmallVector<unsigned, 3> RecentRegs;
|
||||
|
||||
// Record that we just picked this register.
|
||||
void recordRecentlyUsed(unsigned reg) {
|
||||
assert(reg != 0 && "Recently used register is NOREG!");
|
||||
if (!RecentRegs.empty()) {
|
||||
std::copy(RecentRegs.begin() + 1, RecentRegs.end(), RecentRegs.begin());
|
||||
RecentRegs.back() = reg;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const char* getPassName() const {
|
||||
return "Linear Scan Register Allocator";
|
||||
|
@ -161,6 +194,12 @@ namespace {
|
|||
/// runOnMachineFunction - register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
// Determine if we skip this register due to its being recently used.
|
||||
bool isRecentlyUsed(unsigned reg) const {
|
||||
return std::find(RecentRegs.begin(), RecentRegs.end(), reg) !=
|
||||
RecentRegs.end();
|
||||
}
|
||||
|
||||
private:
|
||||
/// linearScan - the linear scan algorithm
|
||||
void linearScan();
|
||||
|
@ -833,9 +872,15 @@ void RALinScan::findIntervalsToSpill(LiveInterval *cur,
|
|||
|
||||
namespace {
|
||||
struct WeightCompare {
|
||||
private:
|
||||
const RALinScan &Allocator;
|
||||
|
||||
public:
|
||||
WeightCompare(const RALinScan &Alloc) : Allocator(Alloc) {};
|
||||
|
||||
typedef std::pair<unsigned, float> RegWeightPair;
|
||||
bool operator()(const RegWeightPair &LHS, const RegWeightPair &RHS) const {
|
||||
return LHS.second < RHS.second;
|
||||
return LHS.second < RHS.second && !Allocator.isRecentlyUsed(LHS.first);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1079,7 +1124,8 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) {
|
|||
e = RC->allocation_order_end(*mf_); i != e; ++i) {
|
||||
unsigned reg = *i;
|
||||
float regWeight = SpillWeights[reg];
|
||||
if (minWeight > regWeight)
|
||||
// Skip recently allocated registers.
|
||||
if (minWeight > regWeight && !isRecentlyUsed(reg))
|
||||
Found = true;
|
||||
RegsWeights.push_back(std::make_pair(reg, regWeight));
|
||||
}
|
||||
|
@ -1097,7 +1143,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) {
|
|||
}
|
||||
|
||||
// Sort all potential spill candidates by weight.
|
||||
std::sort(RegsWeights.begin(), RegsWeights.end(), WeightCompare());
|
||||
std::sort(RegsWeights.begin(), RegsWeights.end(), WeightCompare(*this));
|
||||
minReg = RegsWeights[0].first;
|
||||
minWeight = RegsWeights[0].second;
|
||||
if (minWeight == HUGE_VALF) {
|
||||
|
@ -1360,7 +1406,8 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,
|
|||
// Ignore "downgraded" registers.
|
||||
if (SkipDGRegs && DowngradedRegs.count(Reg))
|
||||
continue;
|
||||
if (isRegAvail(Reg)) {
|
||||
// Skip recently allocated registers.
|
||||
if (isRegAvail(Reg) && !isRecentlyUsed(Reg)) {
|
||||
FreeReg = Reg;
|
||||
if (FreeReg < inactiveCounts.size())
|
||||
FreeRegInactiveCount = inactiveCounts[FreeReg];
|
||||
|
@ -1372,9 +1419,12 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,
|
|||
|
||||
// If there are no free regs, or if this reg has the max inactive count,
|
||||
// return this register.
|
||||
if (FreeReg == 0 || FreeRegInactiveCount == MaxInactiveCount)
|
||||
if (FreeReg == 0 || FreeRegInactiveCount == MaxInactiveCount) {
|
||||
// Remember what register we picked so we can skip it next time.
|
||||
if (FreeReg != 0) recordRecentlyUsed(FreeReg);
|
||||
return FreeReg;
|
||||
|
||||
}
|
||||
|
||||
// Continue scanning the registers, looking for the one with the highest
|
||||
// inactive count. Alkis found that this reduced register pressure very
|
||||
// slightly on X86 (in rev 1.94 of this file), though this should probably be
|
||||
|
@ -1393,6 +1443,9 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,
|
|||
}
|
||||
}
|
||||
|
||||
// Remember what register we picked so we can skip it next time.
|
||||
recordRecentlyUsed(FreeReg);
|
||||
|
||||
return FreeReg;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue