Commit c46c1957 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Commit Bot

[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/+/2584879Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71714}
parent 2b9a4d9a
......@@ -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_;
......
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