[regalloc] Fix slow edge case in BuildBundles
The issue is with this pattern, assuming disjoint uses for all vregs: phi: v1 = v0 ... phi: v2 = v0 ... phi: v3 = v0 ... ... phi: vN = v0 ... For every phi, BuildBundles proceeds as follows: - Create a new bundle for the output - Merge the input bundle into the output bundle Since the bundle gets bigger at every iteration, the merges become more and more expensive and consume Zone memory that is immediately thrown away at the next iteration. A simple fix is to check the size of the bundles before merging and always copy the smallest one into the biggest. In the pattern above this should always copy the single-range output bundle into the large input bundle. R=sigurds@chromium.org Bug: v8:11237 Change-Id: I6ad9152035da698d94b02b5b41802545ba149307 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2584879 Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/master@{#71714}
This commit is contained in:
parent
2b9a4d9a72
commit
c46c195795
@ -2600,7 +2600,12 @@ void BundleBuilder::BuildBundles() {
|
||||
LiveRangeBundle* input_bundle = input_range->get_bundle();
|
||||
if (input_bundle != nullptr) {
|
||||
TRACE("Merge\n");
|
||||
if (out->TryMerge(input_bundle, data()->is_trace_alloc())) {
|
||||
LiveRangeBundle* merged = LiveRangeBundle::TryMerge(
|
||||
out, input_bundle, data()->is_trace_alloc());
|
||||
if (merged != nullptr) {
|
||||
DCHECK_EQ(out_range->get_bundle(), merged);
|
||||
DCHECK_EQ(input_range->get_bundle(), merged);
|
||||
out = merged;
|
||||
TRACE("Merged %d and %d to %d\n", phi->virtual_register(), input,
|
||||
out->id());
|
||||
} else if (input_range->Start() > out_range->Start()) {
|
||||
@ -2641,13 +2646,16 @@ bool LiveRangeBundle::TryAddRange(LiveRange* range) {
|
||||
InsertUses(range->first_interval());
|
||||
return true;
|
||||
}
|
||||
bool LiveRangeBundle::TryMerge(LiveRangeBundle* other, bool trace_alloc) {
|
||||
if (other == this) return true;
|
||||
|
||||
auto iter1 = uses_.begin();
|
||||
auto iter2 = other->uses_.begin();
|
||||
LiveRangeBundle* LiveRangeBundle::TryMerge(LiveRangeBundle* lhs,
|
||||
LiveRangeBundle* rhs,
|
||||
bool trace_alloc) {
|
||||
if (rhs == lhs) return nullptr;
|
||||
|
||||
while (iter1 != uses_.end() && iter2 != other->uses_.end()) {
|
||||
auto iter1 = lhs->uses_.begin();
|
||||
auto iter2 = rhs->uses_.begin();
|
||||
|
||||
while (iter1 != lhs->uses_.end() && iter2 != rhs->uses_.end()) {
|
||||
if (iter1->start >= iter2->end) {
|
||||
++iter2;
|
||||
} else if (iter2->start >= iter1->end) {
|
||||
@ -2655,21 +2663,25 @@ bool LiveRangeBundle::TryMerge(LiveRangeBundle* other, bool trace_alloc) {
|
||||
} else {
|
||||
TRACE_COND(trace_alloc, "No merge %d:%d %d:%d\n", iter1->start,
|
||||
iter1->end, iter2->start, iter2->end);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Uses are disjoint, merging is possible.
|
||||
for (auto it = other->ranges_.begin(); it != other->ranges_.end(); ++it) {
|
||||
(*it)->set_bundle(this);
|
||||
InsertUses((*it)->first_interval());
|
||||
if (lhs->uses_.size() < rhs->uses_.size()) {
|
||||
// Merge the smallest bundle into the biggest.
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
ranges_.insert(other->ranges_.begin(), other->ranges_.end());
|
||||
other->ranges_.clear();
|
||||
|
||||
return true;
|
||||
for (auto it = rhs->ranges_.begin(); it != rhs->ranges_.end(); ++it) {
|
||||
(*it)->set_bundle(lhs);
|
||||
lhs->InsertUses((*it)->first_interval());
|
||||
}
|
||||
lhs->ranges_.insert(rhs->ranges_.begin(), rhs->ranges_.end());
|
||||
rhs->ranges_.clear();
|
||||
return lhs;
|
||||
}
|
||||
|
||||
void LiveRangeBundle::MergeSpillRanges() {
|
||||
DCHECK_IMPLIES(ranges_.empty(), uses_.empty());
|
||||
SpillRange* target = nullptr;
|
||||
for (auto range : ranges_) {
|
||||
if (range->TopLevel()->HasSpillRange()) {
|
||||
|
@ -782,7 +782,11 @@ class LiveRangeBundle : public ZoneObject {
|
||||
: ranges_(zone), uses_(zone), id_(id) {}
|
||||
|
||||
bool TryAddRange(LiveRange* range);
|
||||
bool TryMerge(LiveRangeBundle* other, bool trace_alloc);
|
||||
|
||||
// If merging is possible, merge either {lhs} into {rhs} or {rhs} into
|
||||
// {lhs}, clear the source and return the result. Otherwise return nullptr.
|
||||
static LiveRangeBundle* TryMerge(LiveRangeBundle* lhs, LiveRangeBundle* rhs,
|
||||
bool trace_alloc);
|
||||
|
||||
ZoneSet<LiveRange*, LiveRangeOrdering> ranges_;
|
||||
ZoneSet<Range, RangeOrdering> uses_;
|
||||
|
Loading…
Reference in New Issue
Block a user