Commit 037fa1d9 by Jim Stichnoth

Subzero: Optimize live range overlaps() computation through trimming.

The main optimization is for the repeated overlaps() calls against the Inactive set, by iteratively trimming away the early sections of the Inactive live ranges that can no longer overlap with Cur. A more minor optimization doesn't bother checking pure point-valued Inactive ranges for expiring or reactivating. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/627203002
parent e3f64d09
...@@ -105,10 +105,11 @@ bool LiveRange::endsBefore(const LiveRange &Other) const { ...@@ -105,10 +105,11 @@ bool LiveRange::endsBefore(const LiveRange &Other) const {
} }
// Returns true if there is any overlap between the two live ranges. // Returns true if there is any overlap between the two live ranges.
bool LiveRange::overlaps(const LiveRange &Other) const { bool LiveRange::overlaps(const LiveRange &Other, bool UseTrimmed) const {
// Do a two-finger walk through the two sorted lists of segments. // Do a two-finger walk through the two sorted lists of segments.
RangeType::const_iterator I1 = Range.begin(), I2 = Other.Range.begin(); auto I1 = (UseTrimmed ? TrimmedBegin : Range.begin()),
RangeType::const_iterator E1 = Range.end(), E2 = Other.Range.end(); I2 = (UseTrimmed ? Other.TrimmedBegin : Other.Range.begin());
auto E1 = Range.end(), E2 = Other.Range.end();
while (I1 != E1 && I2 != E2) { while (I1 != E1 && I2 != E2) {
if (I1->second <= I2->first) { if (I1->second <= I2->first) {
++I1; ++I1;
...@@ -123,16 +124,17 @@ bool LiveRange::overlaps(const LiveRange &Other) const { ...@@ -123,16 +124,17 @@ bool LiveRange::overlaps(const LiveRange &Other) const {
return false; return false;
} }
bool LiveRange::overlaps(InstNumberT OtherBegin) const { bool LiveRange::overlapsInst(InstNumberT OtherBegin, bool UseTrimmed) const {
if (!IsNonpoints) if (!IsNonpoints)
return false; return false;
bool Result = false; bool Result = false;
for (const RangeElementType &I : Range) { for (auto I = (UseTrimmed ? TrimmedBegin : Range.begin()), E = Range.end();
if (OtherBegin < I.first) { I != E; ++I) {
if (OtherBegin < I->first) {
Result = false; Result = false;
break; break;
} }
if (OtherBegin < I.second) { if (OtherBegin < I->second) {
Result = true; Result = true;
break; break;
} }
...@@ -158,6 +160,11 @@ bool LiveRange::containsValue(InstNumberT Value) const { ...@@ -158,6 +160,11 @@ bool LiveRange::containsValue(InstNumberT Value) const {
return false; return false;
} }
void LiveRange::trim(InstNumberT Lower) {
while (TrimmedBegin != Range.end() && TrimmedBegin->second <= Lower)
++TrimmedBegin;
}
IceString Variable::getName() const { IceString Variable::getName() const {
if (!Name.empty()) if (!Name.empty())
return Name; return Name;
...@@ -221,6 +228,9 @@ void VariableTracking::markDef(const Inst *Instr, const CfgNode *Node) { ...@@ -221,6 +228,9 @@ void VariableTracking::markDef(const Inst *Instr, const CfgNode *Node) {
// be careful not to omit all uses of the variable if markDef() and // be careful not to omit all uses of the variable if markDef() and
// markUse() both use this optimization. // markUse() both use this optimization.
assert(Node); assert(Node);
// Verify that instructions are added in increasing order.
assert(Definitions.empty() ||
Instr->getNumber() >= Definitions.back()->getNumber());
Definitions.push_back(Instr); Definitions.push_back(Instr);
const bool IsFromDef = true; const bool IsFromDef = true;
const bool IsImplicit = false; const bool IsImplicit = false;
......
...@@ -303,19 +303,24 @@ public: ...@@ -303,19 +303,24 @@ public:
void reset() { void reset() {
Range.clear(); Range.clear();
Weight.setWeight(0); Weight.setWeight(0);
untrim();
IsNonpoints = false; IsNonpoints = false;
} }
void addSegment(InstNumberT Start, InstNumberT End); void addSegment(InstNumberT Start, InstNumberT End);
bool endsBefore(const LiveRange &Other) const; bool endsBefore(const LiveRange &Other) const;
bool overlaps(const LiveRange &Other) const; bool overlaps(const LiveRange &Other, bool UseTrimmed = false) const;
bool overlaps(InstNumberT OtherBegin) const; bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const;
bool containsValue(InstNumberT Value) const; bool containsValue(InstNumberT Value) const;
bool isEmpty() const { return Range.empty(); } bool isEmpty() const { return Range.empty(); }
bool isNonpoints() const { return IsNonpoints; }
InstNumberT getStart() const { InstNumberT getStart() const {
return Range.empty() ? -1 : Range.begin()->first; return Range.empty() ? -1 : Range.begin()->first;
} }
void untrim() { TrimmedBegin = Range.begin(); }
void trim(InstNumberT Lower);
RegWeight getWeight() const { return Weight; } RegWeight getWeight() const { return Weight; }
void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; } void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; }
void addWeight(uint32_t Delta) { Weight.addWeight(Delta); } void addWeight(uint32_t Delta) { Weight.addWeight(Delta); }
...@@ -336,6 +341,15 @@ private: ...@@ -336,6 +341,15 @@ private:
#endif #endif
RangeType Range; RangeType Range;
RegWeight Weight; RegWeight Weight;
// TrimmedBegin is an optimization for the overlaps() computation.
// Since the linear-scan algorithm always calls it as overlaps(Cur)
// and Cur advances monotonically according to live range start, we
// can optimize overlaps() by ignoring all segments that end before
// the start of Cur's range. The linear-scan code enables this by
// calling trim() on the ranges of interest as Cur advances. Note
// that linear-scan also has to initialize TrimmedBegin at the
// beginning by calling untrim().
RangeType::const_iterator TrimmedBegin;
// IsNonpoints keeps track of whether the live range contains at // IsNonpoints keeps track of whether the live range contains at
// least one interval where Start!=End. If it is empty or has the // least one interval where Start!=End. If it is empty or has the
// form [x,x),[y,y),...,[z,z), then overlaps(InstNumberT) is // form [x,x),[y,y),...,[z,z), then overlaps(InstNumberT) is
...@@ -404,6 +418,8 @@ public: ...@@ -404,6 +418,8 @@ public:
Live.addWeight(WeightDelta * Weight.getWeight()); Live.addWeight(WeightDelta * Weight.getWeight());
} }
void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); } void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); }
void trimLiveRange(InstNumberT Start) { Live.trim(Start); }
void untrimLiveRange() { Live.untrim(); }
Variable *getLo() const { return LoVar; } Variable *getLo() const { return LoVar; }
Variable *getHi() const { return HiVar; } Variable *getHi() const { return HiVar; }
...@@ -509,10 +525,8 @@ private: ...@@ -509,10 +525,8 @@ private:
MultiBlockState MultiBlock; MultiBlockState MultiBlock;
const CfgNode *SingleUseNode; const CfgNode *SingleUseNode;
const CfgNode *SingleDefNode; const CfgNode *SingleDefNode;
// All definitions of the variable are collected here, in the order // All definitions of the variable are collected here, in increasing
// encountered. Definitions in the same basic block are in // order of instruction number.
// instruction order, but there's no guarantee for the basic block
// order.
InstDefList Definitions; InstDefList Definitions;
}; };
......
...@@ -24,11 +24,18 @@ namespace Ice { ...@@ -24,11 +24,18 @@ namespace Ice {
namespace { namespace {
// Returns true if Var has any definitions within Item's live range. // Returns true if Var has any definitions within Item's live range.
// TODO(stichnot): Consider trimming the Definitions list similar to
// how the live ranges are trimmed, since all the overlapsDefs() tests
// are whether some variable's definitions overlap Cur, and trimming
// is with respect Cur.start. Initial tests show no measurable
// performance difference, so we'll keep the code simple for now.
bool overlapsDefs(const Cfg *Func, const LiveRangeWrapper &Item, bool overlapsDefs(const Cfg *Func, const LiveRangeWrapper &Item,
const Variable *Var) { const Variable *Var) {
const InstDefList &Defs = Func->getVMetadata()->getDefinitions(Var); const bool UseTrimmed = true;
VariablesMetadata *VMetadata = Func->getVMetadata();
const InstDefList &Defs = VMetadata->getDefinitions(Var);
for (size_t i = 0; i < Defs.size(); ++i) { for (size_t i = 0; i < Defs.size(); ++i) {
if (Item.range().overlaps(Defs[i]->getNumber())) if (Item.range().overlapsInst(Defs[i]->getNumber(), UseTrimmed))
return true; return true;
} }
return false; return false;
...@@ -37,10 +44,11 @@ bool overlapsDefs(const Cfg *Func, const LiveRangeWrapper &Item, ...@@ -37,10 +44,11 @@ bool overlapsDefs(const Cfg *Func, const LiveRangeWrapper &Item,
void dumpDisableOverlap(const Cfg *Func, const Variable *Var, void dumpDisableOverlap(const Cfg *Func, const Variable *Var,
const char *Reason) { const char *Reason) {
if (Func->getContext()->isVerbose(IceV_LinearScan)) { if (Func->getContext()->isVerbose(IceV_LinearScan)) {
VariablesMetadata *VMetadata = Func->getVMetadata();
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Str << "Disabling Overlap due to " << Reason << " " << *Var Str << "Disabling Overlap due to " << Reason << " " << *Var
<< " LIVE=" << Var->getLiveRange() << " Defs="; << " LIVE=" << Var->getLiveRange() << " Defs=";
const InstDefList &Defs = Func->getVMetadata()->getDefinitions(Var); const InstDefList &Defs = VMetadata->getDefinitions(Var);
for (size_t i = 0; i < Defs.size(); ++i) { for (size_t i = 0; i < Defs.size(); ++i) {
if (i > 0) if (i > 0)
Str << ","; Str << ",";
...@@ -95,6 +103,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -95,6 +103,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
// it was never referenced. // it was never referenced.
if (Var->getLiveRange().isEmpty()) if (Var->getLiveRange().isEmpty())
continue; continue;
Var->untrimLiveRange();
LiveRangeWrapper R(Var); LiveRangeWrapper R(Var);
Unhandled.insert(R); Unhandled.insert(R);
if (Var->hasReg()) { if (Var->hasReg()) {
...@@ -156,6 +165,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -156,6 +165,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Next = I; Next = I;
++Next; ++Next;
LiveRangeWrapper Item = *I; LiveRangeWrapper Item = *I;
Item.Var->trimLiveRange(Cur.range().getStart());
bool Moved = false; bool Moved = false;
if (Item.endsBefore(Cur)) { if (Item.endsBefore(Cur)) {
// Move Item from Active to Handled list. // Move Item from Active to Handled list.
...@@ -192,6 +202,16 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -192,6 +202,16 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
Next = I; Next = I;
++Next; ++Next;
LiveRangeWrapper Item = *I; LiveRangeWrapper Item = *I;
Item.Var->trimLiveRange(Cur.range().getStart());
// As an optimization, don't bother checking pure point-valued
// Inactive ranges, because the overlapsStart() test will never
// succeed, and the endsBefore() test will generally only
// succeed after the last call instruction, which statistically
// happens near the end. TODO(stichnot): Consider suppressing
// this check every N iterations in case calls are only at the
// beginning of the function.
if (!Item.range().isNonpoints())
continue;
if (Item.endsBefore(Cur)) { if (Item.endsBefore(Cur)) {
// Move Item from Inactive to Handled list. // Move Item from Inactive to Handled list.
if (Verbose) { if (Verbose) {
......
...@@ -34,10 +34,12 @@ public: ...@@ -34,10 +34,12 @@ public:
return range().endsBefore(Other.range()); return range().endsBefore(Other.range());
} }
bool overlaps(const LiveRangeWrapper &Other) const { bool overlaps(const LiveRangeWrapper &Other) const {
return range().overlaps(Other.range()); const bool UseTrimmed = true;
return range().overlaps(Other.range(), UseTrimmed);
} }
bool overlapsStart(const LiveRangeWrapper &Other) const { bool overlapsStart(const LiveRangeWrapper &Other) const {
return range().overlaps(Other.range().getStart()); const bool UseTrimmed = true;
return range().overlapsInst(Other.range().getStart(), UseTrimmed);
} }
Variable *const Var; Variable *const Var;
void dump(const Cfg *Func) const; void dump(const Cfg *Func) const;
......
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