Commit a1da6ff9 by Jim Stichnoth

Subzero: Do some cleanup on the regalloc code.

No functional changes, as measured by identical spec2k asm output. 1. Use early "return" and "continue" to reduce "if" nesting. 2. Reflow comments to 80 columns (instead of presumably 79). 3. Add some BuildDefs::dump() tests to reduce translator code size. BUG= none R=kschimpf@google.com Review URL: https://codereview.chromium.org/1448773002 .
parent 6c4ad849
...@@ -49,19 +49,20 @@ void dumpDisableOverlap(const Cfg *Func, const Variable *Var, ...@@ -49,19 +49,20 @@ void dumpDisableOverlap(const Cfg *Func, const Variable *Var,
const char *Reason) { const char *Reason) {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
if (Func->isVerbose(IceV_LinearScan)) { if (!Func->isVerbose(IceV_LinearScan))
VariablesMetadata *VMetadata = Func->getVMetadata(); return;
Ostream &Str = Func->getContext()->getStrDump();
Str << "Disabling Overlap due to " << Reason << " " << *Var VariablesMetadata *VMetadata = Func->getVMetadata();
<< " LIVE=" << Var->getLiveRange() << " Defs="; Ostream &Str = Func->getContext()->getStrDump();
if (const Inst *FirstDef = VMetadata->getFirstDefinition(Var)) Str << "Disabling Overlap due to " << Reason << " " << *Var
Str << FirstDef->getNumber(); << " LIVE=" << Var->getLiveRange() << " Defs=";
const InstDefList &Defs = VMetadata->getLatterDefinitions(Var); if (const Inst *FirstDef = VMetadata->getFirstDefinition(Var))
for (size_t i = 0; i < Defs.size(); ++i) { Str << FirstDef->getNumber();
Str << "," << Defs[i]->getNumber(); const InstDefList &Defs = VMetadata->getLatterDefinitions(Var);
} for (size_t i = 0; i < Defs.size(); ++i) {
Str << "\n"; Str << "," << Defs[i]->getNumber();
} }
Str << "\n";
} }
void dumpLiveRange(const Variable *Var, const Cfg *Func) { void dumpLiveRange(const Variable *Var, const Cfg *Func) {
...@@ -160,9 +161,8 @@ bool LinearScan::livenessValidateIntervals( ...@@ -160,9 +161,8 @@ bool LinearScan::livenessValidateIntervals(
return false; return false;
} }
// Prepare for very simple register allocation of only infinite-weight // Prepare for very simple register allocation of only infinite-weight Variables
// Variables while respecting pre-colored Variables. Some properties we take // while respecting pre-colored Variables. Some properties we take advantage of:
// advantage of:
// //
// * Live ranges of interest consist of a single segment. // * Live ranges of interest consist of a single segment.
// //
...@@ -172,9 +172,9 @@ bool LinearScan::livenessValidateIntervals( ...@@ -172,9 +172,9 @@ bool LinearScan::livenessValidateIntervals(
// lowered, or they don't contain any pre-colored or infinite-weight // lowered, or they don't contain any pre-colored or infinite-weight
// Variables. // Variables.
// //
// * We don't need to renumber instructions before computing live ranges // * We don't need to renumber instructions before computing live ranges because
// because all the high-level ICE instructions are deleted prior to lowering, // all the high-level ICE instructions are deleted prior to lowering, and the
// and the low-level instructions are added in monotonically increasing order. // low-level instructions are added in monotonically increasing order.
// //
// * There are no opportunities for register preference or allowing overlap. // * There are no opportunities for register preference or allowing overlap.
// //
...@@ -183,8 +183,7 @@ bool LinearScan::livenessValidateIntervals( ...@@ -183,8 +183,7 @@ bool LinearScan::livenessValidateIntervals(
// * Because live ranges are a single segment, the Inactive set will always be // * Because live ranges are a single segment, the Inactive set will always be
// empty, and the live range trimming operation is unnecessary. // empty, and the live range trimming operation is unnecessary.
// //
// * Calculating overlap of single-segment live ranges could be optimized a // * Calculating overlap of single-segment live ranges could be optimized a bit.
// bit.
void LinearScan::initForInfOnly() { void LinearScan::initForInfOnly() {
TimerMarker T(TimerStack::TT_initUnhandled, Func); TimerMarker T(TimerStack::TT_initUnhandled, Func);
FindPreference = false; FindPreference = false;
...@@ -350,10 +349,10 @@ void LinearScan::init(RegAllocKind Kind) { ...@@ -350,10 +349,10 @@ void LinearScan::init(RegAllocKind Kind) {
} }
// This is called when Cur must be allocated a register but no registers are // This is called when Cur must be allocated a register but no registers are
// available across Cur's live range. To handle this, we find a register that // available across Cur's live range. To handle this, we find a register that is
// is not explicitly used during Cur's live range, spill that register to a // not explicitly used during Cur's live range, spill that register to a stack
// stack location right before Cur's live range begins, and fill (reload) the // location right before Cur's live range begins, and fill (reload) the register
// register from the stack location right after Cur's live range ends. // from the stack location right after Cur's live range ends.
void LinearScan::addSpillFill(IterationState &Iter) { void LinearScan::addSpillFill(IterationState &Iter) {
// Identify the actual instructions that begin and end Iter.Cur's live range. // Identify the actual instructions that begin and end Iter.Cur's live range.
// Iterate through Iter.Cur's node's instruction list until we find the actual // Iterate through Iter.Cur's node's instruction list until we find the actual
...@@ -385,9 +384,9 @@ void LinearScan::addSpillFill(IterationState &Iter) { ...@@ -385,9 +384,9 @@ void LinearScan::addSpillFill(IterationState &Iter) {
if (I->getNumber() == End) if (I->getNumber() == End)
FillPoint = I; FillPoint = I;
if (SpillPoint != E) { if (SpillPoint != E) {
// Remove from RegMask any physical registers referenced during Cur's // Remove from RegMask any physical registers referenced during Cur's live
// live range. Start looking after SpillPoint gets set, i.e. once Cur's // range. Start looking after SpillPoint gets set, i.e. once Cur's live
// live range begins. // range begins.
FOREACH_VAR_IN_INST(Var, *I) { FOREACH_VAR_IN_INST(Var, *I) {
if (!Var->hasRegTmp()) if (!Var->hasRegTmp())
continue; continue;
...@@ -407,9 +406,8 @@ void LinearScan::addSpillFill(IterationState &Iter) { ...@@ -407,9 +406,8 @@ void LinearScan::addSpillFill(IterationState &Iter) {
assert(RegNum != -1); assert(RegNum != -1);
Iter.Cur->setRegNumTmp(RegNum); Iter.Cur->setRegNumTmp(RegNum);
Variable *Preg = Target->getPhysicalRegister(RegNum, Iter.Cur->getType()); Variable *Preg = Target->getPhysicalRegister(RegNum, Iter.Cur->getType());
// TODO(stichnot): Add SpillLoc to VariablesMetadata tracking so that // TODO(stichnot): Add SpillLoc to VariablesMetadata tracking so that SpillLoc
// SpillLoc is correctly identified as !isMultiBlock(), reducing stack frame // is correctly identified as !isMultiBlock(), reducing stack frame size.
// size.
Variable *SpillLoc = Func->makeVariable(Iter.Cur->getType()); Variable *SpillLoc = Func->makeVariable(Iter.Cur->getType());
// Add "reg=FakeDef;spill=reg" before SpillPoint // Add "reg=FakeDef;spill=reg" before SpillPoint
Target->lowerInst(Node, SpillPoint, InstFakeDef::create(Func, Preg)); Target->lowerInst(Node, SpillPoint, InstFakeDef::create(Func, Preg));
...@@ -475,68 +473,67 @@ void LinearScan::handleInactiveRangeExpiredOrReactivated(const Variable *Cur) { ...@@ -475,68 +473,67 @@ void LinearScan::handleInactiveRangeExpiredOrReactivated(const Variable *Cur) {
} }
// Infer register preference and allowable overlap. Only form a preference when // Infer register preference and allowable overlap. Only form a preference when
// the current Variable has an unambiguous "first" definition. The preference // the current Variable has an unambiguous "first" definition. The preference is
// is some source Variable of the defining instruction that either is assigned // some source Variable of the defining instruction that either is assigned a
// a register that is currently free, or that is assigned a register that is // register that is currently free, or that is assigned a register that is not
// not free but overlap is allowed. Overlap is allowed when the Variable under // free but overlap is allowed. Overlap is allowed when the Variable under
// consideration is single-definition, and its definition is a simple // consideration is single-definition, and its definition is a simple assignment
// assignment - i.e., the register gets copied/aliased but is never modified. // - i.e., the register gets copied/aliased but is never modified. Furthermore,
// Furthermore, overlap is only allowed when preferred Variable definition // overlap is only allowed when preferred Variable definition instructions do
// instructions do not appear within the current Variable's live range. // not appear within the current Variable's live range.
void LinearScan::findRegisterPreference(IterationState &Iter) { void LinearScan::findRegisterPreference(IterationState &Iter) {
Iter.Prefer = nullptr; Iter.Prefer = nullptr;
Iter.PreferReg = Variable::NoRegister; Iter.PreferReg = Variable::NoRegister;
Iter.AllowOverlap = false; Iter.AllowOverlap = false;
if (FindPreference) { if (!FindPreference)
VariablesMetadata *VMetadata = Func->getVMetadata(); return;
if (const Inst *DefInst =
VMetadata->getFirstDefinitionSingleBlock(Iter.Cur)) { VariablesMetadata *VMetadata = Func->getVMetadata();
assert(DefInst->getDest() == Iter.Cur); const Inst *DefInst = VMetadata->getFirstDefinitionSingleBlock(Iter.Cur);
bool IsAssign = DefInst->isVarAssign(); if (DefInst == nullptr)
bool IsSingleDef = !VMetadata->isMultiDef(Iter.Cur); return;
FOREACH_VAR_IN_INST(SrcVar, *DefInst) {
// Only consider source variables that have (so far) been assigned a assert(DefInst->getDest() == Iter.Cur);
// register. That register must be one in the RegMask set, e.g. don't const bool IsSingleDefAssign =
// try to prefer the stack pointer as a result of the stacksave DefInst->isVarAssign() && !VMetadata->isMultiDef(Iter.Cur);
// intrinsic. FOREACH_VAR_IN_INST(SrcVar, *DefInst) {
if (SrcVar->hasRegTmp()) { // Only consider source variables that have (so far) been assigned a
const llvm::SmallBitVector &Aliases = // register.
*RegAliases[SrcVar->getRegNumTmp()]; if (!SrcVar->hasRegTmp())
const int32_t SrcReg = (Iter.RegMask & Aliases).find_first(); continue;
const bool IsAliasAvailable = (SrcReg != -1);
if (IsAliasAvailable) { // That register must be one in the RegMask set, e.g. don't try to prefer
if (FindOverlap && !Iter.Free[SrcReg]) { // the stack pointer as a result of the stacksave intrinsic.
// Don't bother trying to enable AllowOverlap if the register is const llvm::SmallBitVector &Aliases = *RegAliases[SrcVar->getRegNumTmp()];
// already free. const int32_t SrcReg = (Iter.RegMask & Aliases).find_first();
Iter.AllowOverlap = IsSingleDef && IsAssign && if (SrcReg == -1)
!overlapsDefs(Func, Iter.Cur, SrcVar); continue;
}
if (Iter.AllowOverlap || Iter.Free[SrcReg]) { if (FindOverlap && IsSingleDefAssign && !Iter.Free[SrcReg]) {
Iter.Prefer = SrcVar; // Don't bother trying to enable AllowOverlap if the register is already
Iter.PreferReg = SrcReg; // free (hence the test on Iter.Free[SrcReg]).
// Stop looking for a preference after the first valid preference Iter.AllowOverlap = !overlapsDefs(Func, Iter.Cur, SrcVar);
// is found. One might think that we should look at all }
// instruction variables to find the best <Prefer,AllowOverlap> if (Iter.AllowOverlap || Iter.Free[SrcReg]) {
// combination, but note that AllowOverlap can only be true for a Iter.Prefer = SrcVar;
// simple assignment statement which can have only one source Iter.PreferReg = SrcReg;
// operand, so it's not possible for AllowOverlap to be true // Stop looking for a preference after the first valid preference is
// beyond the first source operand. // found. One might think that we should look at all instruction
FOREACH_VAR_IN_INST_BREAK; // variables to find the best <Prefer,AllowOverlap> combination, but note
} // that AllowOverlap can only be true for a simple assignment statement
} // which can have only one source operand, so it's not possible for
} // AllowOverlap to be true beyond the first source operand.
} FOREACH_VAR_IN_INST_BREAK;
if (Verbose && Iter.Prefer) {
Ostream &Str = Ctx->getStrDump();
Str << "Initial Iter.Prefer=";
Iter.Prefer->dump(Func);
Str << " R=" << Iter.PreferReg
<< " LIVE=" << Iter.Prefer->getLiveRange()
<< " Overlap=" << Iter.AllowOverlap << "\n";
}
} }
} }
if (BuildDefs::dump() && Verbose && Iter.Prefer) {
Ostream &Str = Ctx->getStrDump();
Str << "Initial Iter.Prefer=";
Iter.Prefer->dump(Func);
Str << " R=" << Iter.PreferReg << " LIVE=" << Iter.Prefer->getLiveRange()
<< " Overlap=" << Iter.AllowOverlap << "\n";
}
} }
// Remove registers from the Free[] list where an Inactive range overlaps with // Remove registers from the Free[] list where an Inactive range overlaps with
...@@ -554,8 +551,7 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) { ...@@ -554,8 +551,7 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) {
// AllowOverlap. // AllowOverlap.
Iter.Free[RegAlias] = false; Iter.Free[RegAlias] = false;
// Disable AllowOverlap if an Inactive variable, which is not Prefer, // Disable AllowOverlap if an Inactive variable, which is not Prefer,
// shares Prefer's register, and has a definition within Cur's live // shares Prefer's register, and has a definition within Cur's live range.
// range.
if (Iter.AllowOverlap && Item != Iter.Prefer && if (Iter.AllowOverlap && Item != Iter.Prefer &&
RegAlias == Iter.PreferReg && overlapsDefs(Func, Iter.Cur, Item)) { RegAlias == Iter.PreferReg && overlapsDefs(Func, Iter.Cur, Item)) {
Iter.AllowOverlap = false; Iter.AllowOverlap = false;
...@@ -567,28 +563,28 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) { ...@@ -567,28 +563,28 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) {
// Remove registers from the Free[] list where an Unhandled pre-colored range // Remove registers from the Free[] list where an Unhandled pre-colored range
// overlaps with the current range, and set those registers to infinite weight // overlaps with the current range, and set those registers to infinite weight
// so that they aren't candidates for eviction. Cur->rangeEndsBefore(Item) is // so that they aren't candidates for eviction. Cur->rangeEndsBefore(Item) is an
// an early exit check that turns a guaranteed O(N^2) algorithm into expected // early exit check that turns a guaranteed O(N^2) algorithm into expected
// linear complexity. // linear complexity.
void LinearScan::filterFreeWithPrecoloredRanges(IterationState &Iter) { void LinearScan::filterFreeWithPrecoloredRanges(IterationState &Iter) {
for (Variable *Item : reverse_range(UnhandledPrecolored)) { for (Variable *Item : reverse_range(UnhandledPrecolored)) {
assert(Item->hasReg()); assert(Item->hasReg());
if (Iter.Cur->rangeEndsBefore(Item)) if (Iter.Cur->rangeEndsBefore(Item))
break; break;
if (Item->rangeOverlaps(Iter.Cur)) { if (!Item->rangeOverlaps(Iter.Cur))
const llvm::SmallBitVector &Aliases = continue;
*RegAliases[Item->getRegNum()]; // Note: not getRegNumTmp() const llvm::SmallBitVector &Aliases =
for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0; *RegAliases[Item->getRegNum()]; // Note: not getRegNumTmp()
RegAlias = Aliases.find_next(RegAlias)) { for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
Iter.Weights[RegAlias].setWeight(RegWeight::Inf); RegAlias = Aliases.find_next(RegAlias)) {
Iter.Free[RegAlias] = false; Iter.Weights[RegAlias].setWeight(RegWeight::Inf);
Iter.PrecoloredUnhandledMask[RegAlias] = true; Iter.Free[RegAlias] = false;
// Disable Iter.AllowOverlap if the preferred register is one of these Iter.PrecoloredUnhandledMask[RegAlias] = true;
// pre-colored unhandled overlapping ranges. // Disable Iter.AllowOverlap if the preferred register is one of these
if (Iter.AllowOverlap && RegAlias == Iter.PreferReg) { // pre-colored unhandled overlapping ranges.
Iter.AllowOverlap = false; if (Iter.AllowOverlap && RegAlias == Iter.PreferReg) {
dumpDisableOverlap(Func, Item, "PrecoloredUnhandled"); Iter.AllowOverlap = false;
} dumpDisableOverlap(Func, Item, "PrecoloredUnhandled");
} }
} }
} }
...@@ -664,8 +660,7 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) { ...@@ -664,8 +660,7 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) {
} }
} }
// All the weights are now calculated. Find the register with smallest // All the weights are now calculated. Find the register with smallest weight.
// weight.
int32_t MinWeightIndex = Iter.RegMask.find_first(); int32_t MinWeightIndex = Iter.RegMask.find_first();
// MinWeightIndex must be valid because of the initial RegMask.any() test. // MinWeightIndex must be valid because of the initial RegMask.any() test.
assert(MinWeightIndex >= 0); assert(MinWeightIndex >= 0);
...@@ -713,10 +708,10 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) { ...@@ -713,10 +708,10 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) {
// Note: The Item->rangeOverlaps(Cur) clause is not part of the // Note: The Item->rangeOverlaps(Cur) clause is not part of the
// description of AssignMemLoc() in the original paper. But there doesn't // description of AssignMemLoc() in the original paper. But there doesn't
// seem to be any need to evict an inactive live range that doesn't // seem to be any need to evict an inactive live range that doesn't
// overlap with the live range currently being considered. It's // overlap with the live range currently being considered. It's especially
// especially bad if we would end up evicting an infinite-weight but // bad if we would end up evicting an infinite-weight but
// currently-inactive live range. The most common situation for this // currently-inactive live range. The most common situation for this would
// would be a scratch register kill set for call instructions. // be a scratch register kill set for call instructions.
if (Aliases[Item->getRegNumTmp()] && Item->rangeOverlaps(Iter.Cur)) { if (Aliases[Item->getRegNumTmp()] && Item->rangeOverlaps(Iter.Cur)) {
dumpLiveRangeTrace("Evicting I ", Item); dumpLiveRangeTrace("Evicting I ", Item);
Item->setRegNumTmp(Variable::NoRegister); Item->setRegNumTmp(Variable::NoRegister);
...@@ -762,7 +757,7 @@ void LinearScan::assignFinalRegisters( ...@@ -762,7 +757,7 @@ void LinearScan::assignFinalRegisters(
if (Randomized && Item->hasRegTmp() && !Item->hasReg()) { if (Randomized && Item->hasRegTmp() && !Item->hasReg()) {
AssignedRegNum = Permutation[RegNum]; AssignedRegNum = Permutation[RegNum];
} }
if (Verbose) { if (BuildDefs::dump() && Verbose) {
Ostream &Str = Ctx->getStrDump(); Ostream &Str = Ctx->getStrDump();
if (!Item->hasRegTmp()) { if (!Item->hasRegTmp()) {
Str << "Not assigning "; Str << "Not assigning ";
...@@ -785,8 +780,8 @@ void LinearScan::assignFinalRegisters( ...@@ -785,8 +780,8 @@ void LinearScan::assignFinalRegisters(
// Allocation in the Context of SSA Form and Register Constraints" by Hanspeter // Allocation in the Context of SSA Form and Register Constraints" by Hanspeter
// Mössenböck and Michael Pfeiffer, // Mössenböck and Michael Pfeiffer,
// ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF. This implementation is // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF. This implementation is
// modified to take affinity into account and allow two interfering variables // modified to take affinity into account and allow two interfering variables to
// to share the same register in certain cases. // share the same register in certain cases.
// //
// Requires running Cfg::liveness(Liveness_Intervals) in preparation. Results // Requires running Cfg::liveness(Liveness_Intervals) in preparation. Results
// are assigned to Variable::RegNum for each Variable. // are assigned to Variable::RegNum for each Variable.
...@@ -809,12 +804,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull, ...@@ -809,12 +804,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
LiveRange KillsRange(Kills); LiveRange KillsRange(Kills);
KillsRange.untrim(); KillsRange.untrim();
// Reset the register use count // Reset the register use count.
RegUses.resize(NumRegisters); RegUses.resize(NumRegisters);
std::fill(RegUses.begin(), RegUses.end(), 0); std::fill(RegUses.begin(), RegUses.end(), 0);
// Unhandled is already set to all ranges in increasing order of start // Unhandled is already set to all ranges in increasing order of start points.
// points.
assert(Active.empty()); assert(Active.empty());
assert(Inactive.empty()); assert(Inactive.empty());
assert(Handled.empty()); assert(Handled.empty());
...@@ -824,7 +818,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull, ...@@ -824,7 +818,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
const llvm::SmallBitVector KillsMask = const llvm::SmallBitVector KillsMask =
Target->getRegisterSet(RegsInclude, RegsExclude); Target->getRegisterSet(RegsInclude, RegsExclude);
// Allocate memory once outside the loop // Allocate memory once outside the loop.
IterationState Iter; IterationState Iter;
Iter.Weights.reserve(NumRegisters); Iter.Weights.reserve(NumRegisters);
Iter.PrecoloredUnhandledMask.reserve(NumRegisters); Iter.PrecoloredUnhandledMask.reserve(NumRegisters);
...@@ -894,7 +888,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull, ...@@ -894,7 +888,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
} }
// Print info about physical register availability. // Print info about physical register availability.
if (Verbose) { if (BuildDefs::dump() && Verbose) {
Ostream &Str = Ctx->getStrDump(); Ostream &Str = Ctx->getStrDump();
for (SizeT i = 0; i < Iter.RegMask.size(); ++i) { for (SizeT i = 0; i < Iter.RegMask.size(); ++i) {
if (Iter.RegMask[i]) { if (Iter.RegMask[i]) {
...@@ -907,15 +901,15 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull, ...@@ -907,15 +901,15 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
} }
if (Iter.Prefer && (Iter.AllowOverlap || Iter.Free[Iter.PreferReg])) { if (Iter.Prefer && (Iter.AllowOverlap || Iter.Free[Iter.PreferReg])) {
// First choice: a preferred register that is either free or is allowed // First choice: a preferred register that is either free or is allowed to
// to overlap with its linked variable. // overlap with its linked variable.
allocatePreferredRegister(Iter); allocatePreferredRegister(Iter);
} else if (Iter.Free.any()) { } else if (Iter.Free.any()) {
// Second choice: any free register. // Second choice: any free register.
allocateFreeRegister(Iter); allocateFreeRegister(Iter);
} else { } else {
// Fallback: there are no free registers, so we look for the // Fallback: there are no free registers, so we look for the lowest-weight
// lowest-weight register and see if Cur has higher weight. // register and see if Cur has higher weight.
handleNoFreeRegisters(Iter); handleNoFreeRegisters(Iter);
} }
dump(Func); dump(Func);
...@@ -930,16 +924,6 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull, ...@@ -930,16 +924,6 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
assignFinalRegisters(RegMaskFull, PreDefinedRegisters, Randomized); assignFinalRegisters(RegMaskFull, PreDefinedRegisters, Randomized);
// TODO: Consider running register allocation one more time, with infinite
// registers, for two reasons. First, evicted live ranges get a second chance
// for a register. Second, it allows coalescing of stack slots. If there is
// no time budget for the second register allocation run, each unallocated
// variable just gets its own slot.
//
// Another idea for coalescing stack slots is to initialize the Unhandled
// list with just the unallocated variables, saving time but not offering
// second-chance opportunities.
if (Verbose) if (Verbose)
Ctx->unlockStr(); Ctx->unlockStr();
} }
...@@ -961,7 +945,7 @@ void LinearScan::dumpLiveRangeTrace(const char *Label, const Variable *Item) { ...@@ -961,7 +945,7 @@ void LinearScan::dumpLiveRangeTrace(const char *Label, const Variable *Item) {
void LinearScan::dump(Cfg *Func) const { void LinearScan::dump(Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
if (!Func->isVerbose(IceV_LinearScan)) if (!Verbose)
return; return;
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Func->resetCurrentNode(); Func->resetCurrentNode();
......
...@@ -293,6 +293,11 @@ void TargetLowering::regAlloc(RegAllocKind Kind) { ...@@ -293,6 +293,11 @@ void TargetLowering::regAlloc(RegAllocKind Kind) {
Repeat = false; Repeat = false;
Kind = RAK_SecondChance; Kind = RAK_SecondChance;
} while (Repeat); } while (Repeat);
// TODO(stichnot): Run the register allocator one more time to do stack slot
// coalescing. The idea would be to initialize the Unhandled list with the
// set of Variables that have no register and a non-empty live range, and
// model an infinite number of registers. Maybe use the register aliasing
// mechanism to get better packing of narrower slots.
} }
void TargetLowering::markRedefinitions() { void TargetLowering::markRedefinitions() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment