Commit e22f8236 by Jim Stichnoth

Subzero: Translation-time improvements in the register allocator.

1. Use a sorted std::vector instead of std::set to improve management of the Unhandled sets. This is the main performance gain. 2. Use std::list.splice() to move items between lists, instead of erase()+push_back(). This doesn't really save much, but the intention is somewhat clearer. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/642603005
parent fe14fb8e
...@@ -58,6 +58,14 @@ void dumpDisableOverlap(const Cfg *Func, const Variable *Var, ...@@ -58,6 +58,14 @@ void dumpDisableOverlap(const Cfg *Func, const Variable *Var,
} }
} }
bool compareRanges(const LiveRangeWrapper &L, const LiveRangeWrapper &R) {
InstNumberT Lstart = L.Var->getLiveRange().getStart();
InstNumberT Rstart = R.Var->getLiveRange().getStart();
if (Lstart == Rstart)
return L.Var->getIndex() < R.Var->getIndex();
return Lstart < Rstart;
}
} // end of anonymous namespace } // end of anonymous namespace
// Implements the linear-scan algorithm. Based on "Linear Scan // Implements the linear-scan algorithm. Based on "Linear Scan
...@@ -85,15 +93,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -85,15 +93,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
VariablesMetadata *VMetadata = Func->getVMetadata(); VariablesMetadata *VMetadata = Func->getVMetadata();
// Gather the live ranges of all variables and add them to the // Gather the live ranges of all variables and add them to the
// Unhandled set. TODO: Unhandled is a set<> which is based on a // Unhandled set.
// balanced binary tree, so inserting live ranges for N variables is
// O(N log N) complexity. N may be proportional to the number of
// instructions, thanks to temporary generation during lowering. As
// a result, it may be useful to design a better data structure for
// storing Func->getVariables().
const VarList &Vars = Func->getVariables(); const VarList &Vars = Func->getVariables();
{ {
TimerMarker T(TimerStack::TT_initUnhandled, Func); TimerMarker T(TimerStack::TT_initUnhandled, Func);
Unhandled.reserve(Vars.size());
for (Variable *Var : Vars) { for (Variable *Var : Vars) {
// Explicitly don't consider zero-weight variables, which are // Explicitly don't consider zero-weight variables, which are
// meant to be spill slots. // meant to be spill slots.
...@@ -105,13 +109,17 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -105,13 +109,17 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
continue; continue;
Var->untrimLiveRange(); Var->untrimLiveRange();
LiveRangeWrapper R(Var); LiveRangeWrapper R(Var);
Unhandled.insert(R); Unhandled.push_back(R);
if (Var->hasReg()) { if (Var->hasReg()) {
Var->setRegNumTmp(Var->getRegNum()); Var->setRegNumTmp(Var->getRegNum());
Var->setLiveRangeInfiniteWeight(); Var->setLiveRangeInfiniteWeight();
UnhandledPrecolored.insert(R); UnhandledPrecolored.push_back(R);
} }
} }
// Do a reverse sort so that erasing elements (from the end) is fast.
std::sort(Unhandled.rbegin(), Unhandled.rend(), compareRanges);
std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(),
compareRanges);
} }
// RegUses[I] is the number of live ranges (variables) that register // RegUses[I] is the number of live ranges (variables) that register
...@@ -126,8 +134,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -126,8 +134,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
UnorderedRanges::iterator Next; UnorderedRanges::iterator Next;
while (!Unhandled.empty()) { while (!Unhandled.empty()) {
LiveRangeWrapper Cur = *Unhandled.begin(); LiveRangeWrapper Cur = Unhandled.back();
Unhandled.erase(Unhandled.begin()); Unhandled.pop_back();
if (Verbose) { if (Verbose) {
Str << "\nConsidering "; Str << "\nConsidering ";
Cur.dump(Func); Cur.dump(Func);
...@@ -155,8 +163,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -155,8 +163,8 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
assert(RegUses[RegNum] >= 0); assert(RegUses[RegNum] >= 0);
++RegUses[RegNum]; ++RegUses[RegNum];
assert(!UnhandledPrecolored.empty()); assert(!UnhandledPrecolored.empty());
assert(UnhandledPrecolored.begin()->Var == Cur.Var); assert(UnhandledPrecolored.back().Var == Cur.Var);
UnhandledPrecolored.erase(UnhandledPrecolored.begin()); UnhandledPrecolored.pop_back();
continue; continue;
} }
...@@ -174,8 +182,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -174,8 +182,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Item.dump(Func); Item.dump(Func);
Str << "\n"; Str << "\n";
} }
Active.erase(I); Handled.splice(Handled.end(), Active, I);
Handled.push_back(Item);
Moved = true; Moved = true;
} else if (!Item.overlapsStart(Cur)) { } else if (!Item.overlapsStart(Cur)) {
// Move Item from Active to Inactive list. // Move Item from Active to Inactive list.
...@@ -184,8 +191,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -184,8 +191,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Item.dump(Func); Item.dump(Func);
Str << "\n"; Str << "\n";
} }
Active.erase(I); Inactive.splice(Inactive.end(), Active, I);
Inactive.push_back(Item);
Moved = true; Moved = true;
} }
if (Moved) { if (Moved) {
...@@ -219,8 +225,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -219,8 +225,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Item.dump(Func); Item.dump(Func);
Str << "\n"; Str << "\n";
} }
Inactive.erase(I); Handled.splice(Handled.end(), Inactive, I);
Handled.push_back(Item);
} else if (Item.overlapsStart(Cur)) { } else if (Item.overlapsStart(Cur)) {
// Move Item from Inactive to Active list. // Move Item from Inactive to Active list.
if (Verbose) { if (Verbose) {
...@@ -228,8 +233,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -228,8 +233,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Item.dump(Func); Item.dump(Func);
Str << "\n"; Str << "\n";
} }
Inactive.erase(I); Active.splice(Active.end(), Inactive, I);
Active.push_back(Item);
// Increment Item in RegUses[]. // Increment Item in RegUses[].
assert(Item.Var->hasRegTmp()); assert(Item.Var->hasRegTmp());
int32_t RegNum = Item.Var->getRegNumTmp(); int32_t RegNum = Item.Var->getRegNumTmp();
...@@ -339,7 +343,9 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -339,7 +343,9 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
// complexity. // complexity.
llvm::SmallBitVector PrecoloredUnhandledMask(RegMask.size()); llvm::SmallBitVector PrecoloredUnhandledMask(RegMask.size());
// Note: PrecoloredUnhandledMask is only used for dumping. // Note: PrecoloredUnhandledMask is only used for dumping.
for (const LiveRangeWrapper &Item : UnhandledPrecolored) { for (auto I = UnhandledPrecolored.rbegin(), E = UnhandledPrecolored.rend();
I != E; ++I) {
LiveRangeWrapper &Item = *I;
assert(Item.Var->hasReg()); assert(Item.Var->hasReg());
if (Cur.endsBefore(Item)) if (Cur.endsBefore(Item))
break; break;
...@@ -449,8 +455,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -449,8 +455,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
--RegUses[MinWeightIndex]; --RegUses[MinWeightIndex];
assert(RegUses[MinWeightIndex] >= 0); assert(RegUses[MinWeightIndex] >= 0);
Item.Var->setRegNumTmp(Variable::NoRegister); Item.Var->setRegNumTmp(Variable::NoRegister);
Active.erase(I); Handled.splice(Handled.end(), Active, I);
Handled.push_back(Item);
} }
} }
// Do the same for Inactive. // Do the same for Inactive.
...@@ -475,8 +480,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -475,8 +480,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Str << "\n"; Str << "\n";
} }
Item.Var->setRegNumTmp(Variable::NoRegister); Item.Var->setRegNumTmp(Variable::NoRegister);
Inactive.erase(I); Handled.splice(Handled.end(), Inactive, I);
Handled.push_back(Item);
} }
} }
// Assign the register to Cur. // Assign the register to Cur.
...@@ -557,8 +561,8 @@ void LinearScan::dump(Cfg *Func) const { ...@@ -557,8 +561,8 @@ void LinearScan::dump(Cfg *Func) const {
Str << "\n"; Str << "\n";
} }
Str << "++++++ Unhandled:\n"; Str << "++++++ Unhandled:\n";
for (const LiveRangeWrapper &Item : Unhandled) { for (auto I = Unhandled.rbegin(), E = Unhandled.rend(); I != E; ++I) {
Item.dump(Func); I->dump(Func);
Str << "\n"; Str << "\n";
} }
Str << "++++++ Active:\n"; Str << "++++++ Active:\n";
......
...@@ -41,12 +41,12 @@ public: ...@@ -41,12 +41,12 @@ public:
const bool UseTrimmed = true; const bool UseTrimmed = true;
return range().overlapsInst(Other.range().getStart(), UseTrimmed); return range().overlapsInst(Other.range().getStart(), UseTrimmed);
} }
Variable *const Var; Variable *Var;
void dump(const Cfg *Func) const; void dump(const Cfg *Func) const;
private: private:
// LiveRangeWrapper(const LiveRangeWrapper &) = delete; // LiveRangeWrapper(const LiveRangeWrapper &) = delete;
LiveRangeWrapper &operator=(const LiveRangeWrapper &) = delete; // LiveRangeWrapper &operator=(const LiveRangeWrapper &) = delete;
}; };
class LinearScan { class LinearScan {
...@@ -57,20 +57,7 @@ public: ...@@ -57,20 +57,7 @@ public:
private: private:
Cfg *const Func; Cfg *const Func;
// RangeCompare is the comparator for sorting an LiveRangeWrapper typedef std::vector<LiveRangeWrapper> OrderedRanges;
// by starting point in a std::set<>. Ties are broken by variable
// number so that sorting is stable.
struct RangeCompare {
bool operator()(const LiveRangeWrapper &L,
const LiveRangeWrapper &R) const {
InstNumberT Lstart = L.Var->getLiveRange().getStart();
InstNumberT Rstart = R.Var->getLiveRange().getStart();
if (Lstart == Rstart)
return L.Var->getIndex() < R.Var->getIndex();
return Lstart < Rstart;
}
};
typedef std::set<LiveRangeWrapper, RangeCompare> OrderedRanges;
typedef std::list<LiveRangeWrapper> UnorderedRanges; typedef std::list<LiveRangeWrapper> UnorderedRanges;
OrderedRanges Unhandled; OrderedRanges Unhandled;
// UnhandledPrecolored is a subset of Unhandled, specially collected // UnhandledPrecolored is a subset of Unhandled, specially collected
......
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