| Index: src/IceRegAlloc.cpp
|
| diff --git a/src/IceRegAlloc.cpp b/src/IceRegAlloc.cpp
|
| index 395c5aa16486f9d32e729dc1d5546605add9ba98..fc46e2b7820881aed8dddba4e5429cff9b3719b2 100644
|
| --- a/src/IceRegAlloc.cpp
|
| +++ b/src/IceRegAlloc.cpp
|
| @@ -76,11 +76,25 @@ void dumpLiveRange(const Variable *Var, const Cfg *Func) {
|
| Str << " Range=" << Var->getLiveRange();
|
| }
|
|
|
| +int32_t findMinWeightIndex(
|
| + const llvm::SmallBitVector &RegMask,
|
| + const llvm::SmallVector<RegWeight, LinearScan::REGS_SIZE> &Weights) {
|
| + int32_t MinWeightIndex = RegMask.find_first();
|
| + assert(MinWeightIndex >= 0);
|
| + for (int32_t i = RegMask.find_next(MinWeightIndex); i != -1;
|
| + i = RegMask.find_next(i)) {
|
| + if (Weights[i] < Weights[MinWeightIndex])
|
| + MinWeightIndex = i;
|
| + }
|
| + return MinWeightIndex;
|
| +}
|
| +
|
| } // end of anonymous namespace
|
|
|
| LinearScan::LinearScan(Cfg *Func)
|
| : Func(Func), Ctx(Func->getContext()), Target(Func->getTarget()),
|
| - Verbose(BuildDefs::dump() && Func->isVerbose(IceV_LinearScan)) {}
|
| + Verbose(BuildDefs::dump() && Func->isVerbose(IceV_LinearScan)),
|
| + UseReserve(Ctx->getFlags().getRegAllocReserve()) {}
|
|
|
| // Prepare for full register allocation of all variables. We depend on liveness
|
| // analysis to have calculated live ranges.
|
| @@ -545,8 +559,8 @@ void LinearScan::findRegisterPreference(IterationState &Iter) {
|
| }
|
| }
|
|
|
| -// Remove registers from the Free[] list where an Inactive range overlaps with
|
| -// the current range.
|
| +// Remove registers from the Iter.Free[] list where an Inactive range overlaps
|
| +// with the current range.
|
| void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) {
|
| for (const Variable *Item : Inactive) {
|
| if (!Item->rangeOverlaps(Iter.Cur))
|
| @@ -555,10 +569,11 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) {
|
| // TODO(stichnot): Do this with bitvector ops, not a loop, for efficiency.
|
| for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| RegAlias = Aliases.find_next(RegAlias)) {
|
| - // Don't assert(Free[RegNum]) because in theory (though probably never in
|
| - // practice) there could be two inactive variables that were marked with
|
| - // AllowOverlap.
|
| + // Don't assert(Iter.Free[RegNum]) because in theory (though probably
|
| + // never in practice) there could be two inactive variables that were
|
| + // marked with AllowOverlap.
|
| Iter.Free[RegAlias] = false;
|
| + Iter.FreeUnfiltered[RegAlias] = false;
|
| // Disable AllowOverlap if an Inactive variable, which is not Prefer,
|
| // shares Prefer's register, and has a definition within Cur's live range.
|
| if (Iter.AllowOverlap && Item != Iter.Prefer &&
|
| @@ -570,11 +585,11 @@ void LinearScan::filterFreeWithInactiveRanges(IterationState &Iter) {
|
| }
|
| }
|
|
|
| -// Remove registers from the Free[] list where an Unhandled pre-colored range
|
| -// overlaps with the current range, and set those registers to infinite weight
|
| -// so that they aren't candidates for eviction. Cur->rangeEndsBefore(Item) is an
|
| -// early exit check that turns a guaranteed O(N^2) algorithm into expected
|
| -// linear complexity.
|
| +// Remove registers from the Iter.Free[] list where an Unhandled pre-colored
|
| +// range overlaps with the current range, and set those registers to infinite
|
| +// weight so that they aren't candidates for eviction.
|
| +// Cur->rangeEndsBefore(Item) is an early exit check that turns a guaranteed
|
| +// O(N^2) algorithm into expected linear complexity.
|
| void LinearScan::filterFreeWithPrecoloredRanges(IterationState &Iter) {
|
| // TODO(stichnot): Partition UnhandledPrecolored according to register class,
|
| // to restrict the number of overlap comparisons needed.
|
| @@ -590,6 +605,7 @@ void LinearScan::filterFreeWithPrecoloredRanges(IterationState &Iter) {
|
| RegAlias = Aliases.find_next(RegAlias)) {
|
| Iter.Weights[RegAlias].setWeight(RegWeight::Inf);
|
| Iter.Free[RegAlias] = false;
|
| + Iter.FreeUnfiltered[RegAlias] = false;
|
| Iter.PrecoloredUnhandledMask[RegAlias] = true;
|
| // Disable Iter.AllowOverlap if the preferred register is one of these
|
| // pre-colored unhandled overlapping ranges.
|
| @@ -630,10 +646,14 @@ void LinearScan::allocatePreferredRegister(IterationState &Iter) {
|
| Active.push_back(Iter.Cur);
|
| }
|
|
|
| -void LinearScan::allocateFreeRegister(IterationState &Iter) {
|
| - int32_t RegNum = Iter.Free.find_first();
|
| +void LinearScan::allocateFreeRegister(IterationState &Iter, bool Filtered) {
|
| + const int32_t RegNum =
|
| + Filtered ? Iter.Free.find_first() : Iter.FreeUnfiltered.find_first();
|
| Iter.Cur->setRegNumTmp(RegNum);
|
| - dumpLiveRangeTrace("Allocating ", Iter.Cur);
|
| + if (Filtered)
|
| + dumpLiveRangeTrace("Allocating ", Iter.Cur);
|
| + else
|
| + dumpLiveRangeTrace("Allocating X ", Iter.Cur);
|
| const llvm::SmallBitVector &Aliases = *RegAliases[RegNum];
|
| for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| RegAlias = Aliases.find_next(RegAlias)) {
|
| @@ -672,77 +692,97 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) {
|
| }
|
|
|
| // All the weights are now calculated. Find the register with smallest weight.
|
| - int32_t MinWeightIndex = Iter.RegMask.find_first();
|
| - // MinWeightIndex must be valid because of the initial RegMask.any() test.
|
| - assert(MinWeightIndex >= 0);
|
| - for (SizeT i = MinWeightIndex + 1; i < Iter.Weights.size(); ++i) {
|
| - if (Iter.RegMask[i] && Iter.Weights[i] < Iter.Weights[MinWeightIndex])
|
| - MinWeightIndex = i;
|
| - }
|
| + int32_t MinWeightIndex = findMinWeightIndex(Iter.RegMask, Iter.Weights);
|
|
|
| if (Iter.Cur->getWeight(Func) <= Iter.Weights[MinWeightIndex]) {
|
| - // Cur doesn't have priority over any other live ranges, so don't allocate
|
| - // any register to it, and move it to the Handled state.
|
| - Handled.push_back(Iter.Cur);
|
| - if (Iter.Cur->mustHaveReg()) {
|
| - if (Kind == RAK_Phi) {
|
| - addSpillFill(Iter);
|
| - } else {
|
| - dumpLiveRangeTrace("Failing ", Iter.Cur);
|
| - Func->setError("Unable to find a physical register for an "
|
| - "infinite-weight live range: " +
|
| - Iter.Cur->getName(Func));
|
| - }
|
| + if (!Iter.Cur->mustHaveReg()) {
|
| + // Iter.Cur doesn't have priority over any other live ranges, so don't
|
| + // allocate any register to it, and move it to the Handled state.
|
| + Handled.push_back(Iter.Cur);
|
| + return;
|
| }
|
| - } else {
|
| - // Evict all live ranges in Active that register number MinWeightIndex is
|
| - // assigned to.
|
| - const llvm::SmallBitVector &Aliases = *RegAliases[MinWeightIndex];
|
| - for (SizeT I = Active.size(); I > 0; --I) {
|
| - const SizeT Index = I - 1;
|
| - Variable *Item = Active[Index];
|
| - int32_t RegNum = Item->getRegNumTmp();
|
| - if (Aliases[RegNum]) {
|
| - dumpLiveRangeTrace("Evicting A ", Item);
|
| - const llvm::SmallBitVector &Aliases = *RegAliases[RegNum];
|
| - for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| - RegAlias = Aliases.find_next(RegAlias)) {
|
| - --RegUses[RegAlias];
|
| - assert(RegUses[RegAlias] >= 0);
|
| - }
|
| - Item->setRegNumTmp(Variable::NoRegister);
|
| - moveItem(Active, Index, Handled);
|
| - Evicted.push_back(Item);
|
| + if (Kind == RAK_Phi) {
|
| + // Iter.Cur is infinite-weight but all physical registers are already
|
| + // taken, so we need to force one to be temporarily available.
|
| + addSpillFill(Iter);
|
| + Handled.push_back(Iter.Cur);
|
| + return;
|
| + }
|
| + // The remaining portion of the enclosing "if" block should only be
|
| + // reachable if we are manually limiting physical registers for testing.
|
| + if (UseReserve) {
|
| + if (Iter.FreeUnfiltered.any()) {
|
| + // There is some available physical register held in reserve, so use it.
|
| + constexpr bool NotFiltered = false;
|
| + allocateFreeRegister(Iter, NotFiltered);
|
| + // Iter.Cur is now on the Active list.
|
| + return;
|
| }
|
| + // At this point, we need to find some reserve register that is already
|
| + // assigned to a non-infinite-weight variable. This could happen if some
|
| + // variable was previously assigned an alias of such a register.
|
| + MinWeightIndex = findMinWeightIndex(Iter.RegMaskUnfiltered, Iter.Weights);
|
| + }
|
| + if (Iter.Cur->getWeight(Func) <= Iter.Weights[MinWeightIndex]) {
|
| + dumpLiveRangeTrace("Failing ", Iter.Cur);
|
| + Func->setError("Unable to find a physical register for an "
|
| + "infinite-weight live range "
|
| + "(consider using -reg-reserve): " +
|
| + Iter.Cur->getName(Func));
|
| + Handled.push_back(Iter.Cur);
|
| + return;
|
| }
|
| - // Do the same for Inactive.
|
| - for (SizeT I = Inactive.size(); I > 0; --I) {
|
| - const SizeT Index = I - 1;
|
| - Variable *Item = Inactive[Index];
|
| - // Note: The Item->rangeOverlaps(Cur) clause is not part of the
|
| - // 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
|
| - // overlap with the live range currently being considered. It's especially
|
| - // bad if we would end up evicting an infinite-weight but
|
| - // currently-inactive live range. The most common situation for this would
|
| - // be a scratch register kill set for call instructions.
|
| - if (Aliases[Item->getRegNumTmp()] && Item->rangeOverlaps(Iter.Cur)) {
|
| - dumpLiveRangeTrace("Evicting I ", Item);
|
| - Item->setRegNumTmp(Variable::NoRegister);
|
| - moveItem(Inactive, Index, Handled);
|
| - Evicted.push_back(Item);
|
| + // At this point, MinWeightIndex points to a valid reserve register to
|
| + // reallocate to Iter.Cur, so drop into the eviction code.
|
| + }
|
| +
|
| + // Evict all live ranges in Active that register number MinWeightIndex is
|
| + // assigned to.
|
| + const llvm::SmallBitVector &Aliases = *RegAliases[MinWeightIndex];
|
| + for (SizeT I = Active.size(); I > 0; --I) {
|
| + const SizeT Index = I - 1;
|
| + Variable *Item = Active[Index];
|
| + int32_t RegNum = Item->getRegNumTmp();
|
| + if (Aliases[RegNum]) {
|
| + dumpLiveRangeTrace("Evicting A ", Item);
|
| + const llvm::SmallBitVector &Aliases = *RegAliases[RegNum];
|
| + for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| + RegAlias = Aliases.find_next(RegAlias)) {
|
| + --RegUses[RegAlias];
|
| + assert(RegUses[RegAlias] >= 0);
|
| }
|
| + Item->setRegNumTmp(Variable::NoRegister);
|
| + moveItem(Active, Index, Handled);
|
| + Evicted.push_back(Item);
|
| }
|
| - // Assign the register to Cur.
|
| - Iter.Cur->setRegNumTmp(MinWeightIndex);
|
| - for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| - RegAlias = Aliases.find_next(RegAlias)) {
|
| - assert(RegUses[RegAlias] >= 0);
|
| - ++RegUses[RegAlias];
|
| + }
|
| + // Do the same for Inactive.
|
| + for (SizeT I = Inactive.size(); I > 0; --I) {
|
| + const SizeT Index = I - 1;
|
| + Variable *Item = Inactive[Index];
|
| + // Note: The Item->rangeOverlaps(Cur) clause is not part of the 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 overlap with the live
|
| + // range currently being considered. It's especially bad if we would end up
|
| + // evicting an infinite-weight but currently-inactive live range. The most
|
| + // common situation for this would be a scratch register kill set for call
|
| + // instructions.
|
| + if (Aliases[Item->getRegNumTmp()] && Item->rangeOverlaps(Iter.Cur)) {
|
| + dumpLiveRangeTrace("Evicting I ", Item);
|
| + Item->setRegNumTmp(Variable::NoRegister);
|
| + moveItem(Inactive, Index, Handled);
|
| + Evicted.push_back(Item);
|
| }
|
| - Active.push_back(Iter.Cur);
|
| - dumpLiveRangeTrace("Allocating ", Iter.Cur);
|
| }
|
| + // Assign the register to Cur.
|
| + Iter.Cur->setRegNumTmp(MinWeightIndex);
|
| + for (int32_t RegAlias = Aliases.find_first(); RegAlias >= 0;
|
| + RegAlias = Aliases.find_next(RegAlias)) {
|
| + assert(RegUses[RegAlias] >= 0);
|
| + ++RegUses[RegAlias];
|
| + }
|
| + Active.push_back(Iter.Cur);
|
| + dumpLiveRangeTrace("Allocating ", Iter.Cur);
|
| }
|
|
|
| void LinearScan::assignFinalRegisters(
|
| @@ -843,6 +883,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
|
| dumpLiveRangeTrace("\nConsidering ", Iter.Cur);
|
| assert(Target->getRegistersForVariable(Iter.Cur).any());
|
| Iter.RegMask = RegMaskFull & Target->getRegistersForVariable(Iter.Cur);
|
| + Iter.RegMaskUnfiltered =
|
| + RegMaskFull & Target->getAllRegistersForVariable(Iter.Cur);
|
| KillsRange.trim(Iter.Cur->getLiveRange().getStart());
|
|
|
| // Check for pre-colored ranges. If Cur is pre-colored, it definitely gets
|
| @@ -857,11 +899,14 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
|
| handleActiveRangeExpiredOrInactive(Iter.Cur);
|
| handleInactiveRangeExpiredOrReactivated(Iter.Cur);
|
|
|
| - // Calculate available registers into Free[].
|
| + // Calculate available registers into Iter.Free[] and Iter.FreeUnfiltered[].
|
| Iter.Free = Iter.RegMask;
|
| + Iter.FreeUnfiltered = Iter.RegMaskUnfiltered;
|
| for (SizeT i = 0; i < Iter.RegMask.size(); ++i) {
|
| - if (RegUses[i] > 0)
|
| + if (RegUses[i] > 0) {
|
| Iter.Free[i] = false;
|
| + Iter.FreeUnfiltered[i] = false;
|
| + }
|
| }
|
|
|
| findRegisterPreference(Iter);
|
| @@ -889,11 +934,12 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
|
|
|
| filterFreeWithPrecoloredRanges(Iter);
|
|
|
| - // Remove scratch registers from the Free[] list, and mark their Weights[]
|
| - // as infinite, if KillsRange overlaps Cur's live range.
|
| + // Remove scratch registers from the Iter.Free[] list, and mark their
|
| + // Iter.Weights[] as infinite, if KillsRange overlaps Cur's live range.
|
| constexpr bool UseTrimmed = true;
|
| if (Iter.Cur->getLiveRange().overlaps(KillsRange, UseTrimmed)) {
|
| Iter.Free.reset(KillsMask);
|
| + Iter.FreeUnfiltered.reset(KillsMask);
|
| for (int i = KillsMask.find_first(); i != -1;
|
| i = KillsMask.find_next(i)) {
|
| Iter.Weights[i].setWeight(RegWeight::Inf);
|
| @@ -906,7 +952,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
|
| if (BuildDefs::dump() && Verbose) {
|
| Ostream &Str = Ctx->getStrDump();
|
| for (SizeT i = 0; i < Iter.RegMask.size(); ++i) {
|
| - if (Iter.RegMask[i]) {
|
| + if (Iter.RegMaskUnfiltered[i]) {
|
| Str << Target->getRegName(i, Iter.Cur->getType())
|
| << "(U=" << RegUses[i] << ",F=" << Iter.Free[i]
|
| << ",P=" << Iter.PrecoloredUnhandledMask[i] << ") ";
|
| @@ -921,7 +967,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull,
|
| allocatePreferredRegister(Iter);
|
| } else if (Iter.Free.any()) {
|
| // Second choice: any free register.
|
| - allocateFreeRegister(Iter);
|
| + constexpr bool Filtered = true;
|
| + allocateFreeRegister(Iter, Filtered);
|
| } else {
|
| // Fallback: there are no free registers, so we look for the lowest-weight
|
| // register and see if Cur has higher weight.
|
|
|