Commit 2394b268 authored by Stephan Herhut's avatar Stephan Herhut Committed by Commit Bot

[regalloc] Speed up state handling

The register allocator spends significant amounts of time on updating
the state of active and inactive live range sets. In many cases, no
update is needed. By precomputing when the next update is due during
state management, we can avoid unnecessary checks. This cuts the time
spent for managing queues in half.

Change-Id: I44074266bed2f09171872a829f115e61608b76c8
Reviewed-on: https://chromium-review.googlesource.com/c/1352308Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Stephan Herhut <herhut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57990}
parent 3e9cd32c
......@@ -732,6 +732,22 @@ bool LiveRange::Covers(LifetimePosition position) const {
return false;
}
LifetimePosition LiveRange::NextEndAfter(LifetimePosition position) const {
UseInterval* start_search = FirstSearchIntervalForPosition(position);
while (start_search->end() < position) {
start_search = start_search->next();
}
return start_search->end();
}
LifetimePosition LiveRange::NextStartAfter(LifetimePosition position) const {
UseInterval* start_search = FirstSearchIntervalForPosition(position);
while (start_search->start() < position) {
start_search = start_search->next();
}
return start_search->start();
}
LifetimePosition LiveRange::FirstIntersection(LiveRange* other) const {
UseInterval* b = other->first_interval();
if (b == nullptr) return LifetimePosition::Invalid();
......@@ -2705,7 +2721,9 @@ LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
: RegisterAllocator(data, kind),
unhandled_live_ranges_(local_zone),
active_live_ranges_(local_zone),
inactive_live_ranges_(local_zone) {
inactive_live_ranges_(local_zone),
next_active_ranges_change_(LifetimePosition::Invalid()),
next_inactive_ranges_change_(LifetimePosition::Invalid()) {
active_live_ranges().reserve(8);
inactive_live_ranges().reserve(8);
// TryAllocateFreeReg and AllocateBlockedReg assume this
......@@ -2765,29 +2783,7 @@ void LinearScanAllocator::AllocateRegisters() {
if (current->IsTopLevel() && TryReuseSpillForPhi(current->TopLevel()))
continue;
for (auto it = active_live_ranges().begin();
it != active_live_ranges().end();) {
LiveRange* cur_active = *it;
if (cur_active->End() <= position) {
it = ActiveToHandled(it);
} else if (!cur_active->Covers(position)) {
it = ActiveToInactive(it);
} else {
++it;
}
}
for (auto it = inactive_live_ranges().begin();
it != inactive_live_ranges().end();) {
LiveRange* cur_inactive = *it;
if (cur_inactive->End() <= position) {
it = InactiveToHandled(it);
} else if (cur_inactive->Covers(position)) {
it = InactiveToActive(it);
} else {
++it;
}
}
ForwardStateTo(position);
DCHECK(!current->HasRegisterAssigned() && !current->spilled());
......@@ -2834,12 +2830,16 @@ void LinearScanAllocator::AddToActive(LiveRange* range) {
TRACE("Add live range %d:%d to active\n", range->TopLevel()->vreg(),
range->relative_id());
active_live_ranges().push_back(range);
next_active_ranges_change_ =
std::min(next_active_ranges_change_, range->NextEndAfter(range->Start()));
}
void LinearScanAllocator::AddToInactive(LiveRange* range) {
TRACE("Add live range %d:%d to inactive\n", range->TopLevel()->vreg(),
range->relative_id());
inactive_live_ranges().push_back(range);
next_inactive_ranges_change_ = std::min(
next_inactive_ranges_change_, range->NextStartAfter(range->Start()));
}
void LinearScanAllocator::AddToUnhandled(LiveRange* range) {
......@@ -2860,11 +2860,13 @@ ZoneVector<LiveRange*>::iterator LinearScanAllocator::ActiveToHandled(
}
ZoneVector<LiveRange*>::iterator LinearScanAllocator::ActiveToInactive(
const ZoneVector<LiveRange*>::iterator it) {
const ZoneVector<LiveRange*>::iterator it, LifetimePosition position) {
LiveRange* range = *it;
inactive_live_ranges().push_back(range);
TRACE("Moving live range %d:%d from active to inactive\n",
(range)->TopLevel()->vreg(), range->relative_id());
next_inactive_ranges_change_ =
std::min(next_inactive_ranges_change_, range->NextStartAfter(position));
return active_live_ranges().erase(it);
}
......@@ -2876,14 +2878,53 @@ ZoneVector<LiveRange*>::iterator LinearScanAllocator::InactiveToHandled(
}
ZoneVector<LiveRange*>::iterator LinearScanAllocator::InactiveToActive(
ZoneVector<LiveRange*>::iterator it) {
ZoneVector<LiveRange*>::iterator it, LifetimePosition position) {
LiveRange* range = *it;
active_live_ranges().push_back(range);
TRACE("Moving live range %d:%d from inactive to active\n",
range->TopLevel()->vreg(), range->relative_id());
next_active_ranges_change_ =
std::min(next_active_ranges_change_, range->NextEndAfter(position));
return inactive_live_ranges().erase(it);
}
void LinearScanAllocator::ForwardStateTo(LifetimePosition position) {
if (position >= next_active_ranges_change_) {
next_active_ranges_change_ = LifetimePosition::MaxPosition();
for (auto it = active_live_ranges().begin();
it != active_live_ranges().end();) {
LiveRange* cur_active = *it;
if (cur_active->End() <= position) {
it = ActiveToHandled(it);
} else if (!cur_active->Covers(position)) {
it = ActiveToInactive(it, position);
} else {
next_active_ranges_change_ = std::min(
next_active_ranges_change_, cur_active->NextEndAfter(position));
++it;
}
}
}
if (position >= next_inactive_ranges_change_) {
next_inactive_ranges_change_ = LifetimePosition::MaxPosition();
for (auto it = inactive_live_ranges().begin();
it != inactive_live_ranges().end();) {
LiveRange* cur_inactive = *it;
if (cur_inactive->End() <= position) {
it = InactiveToHandled(it);
} else if (cur_inactive->Covers(position)) {
it = InactiveToActive(it, position);
} else {
next_inactive_ranges_change_ =
std::min(next_inactive_ranges_change_,
cur_inactive->NextStartAfter(position));
++it;
}
}
}
}
void LinearScanAllocator::GetFPRegisterSet(MachineRepresentation rep,
int* num_regs, int* num_codes,
const int** codes) const {
......
......@@ -412,6 +412,8 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) {
bool ShouldBeAllocatedBefore(const LiveRange* other) const;
bool CanCover(LifetimePosition position) const;
bool Covers(LifetimePosition position) const;
LifetimePosition NextStartAfter(LifetimePosition position) const;
LifetimePosition NextEndAfter(LifetimePosition position) const;
LifetimePosition FirstIntersection(LiveRange* other) const;
void VerifyChildStructure() const {
......@@ -1047,11 +1049,13 @@ class LinearScanAllocator final : public RegisterAllocator {
ZoneVector<LiveRange*>::iterator ActiveToHandled(
ZoneVector<LiveRange*>::iterator it);
ZoneVector<LiveRange*>::iterator ActiveToInactive(
ZoneVector<LiveRange*>::iterator it);
ZoneVector<LiveRange*>::iterator it, LifetimePosition position);
ZoneVector<LiveRange*>::iterator InactiveToHandled(
ZoneVector<LiveRange*>::iterator it);
ZoneVector<LiveRange*>::iterator InactiveToActive(
ZoneVector<LiveRange*>::iterator it);
ZoneVector<LiveRange*>::iterator it, LifetimePosition position);
void ForwardStateTo(LifetimePosition position);
// Helper methods for allocating registers.
bool TryReuseSpillForPhi(TopLevelLiveRange* range);
......@@ -1086,6 +1090,11 @@ class LinearScanAllocator final : public RegisterAllocator {
ZoneVector<LiveRange*> active_live_ranges_;
ZoneVector<LiveRange*> inactive_live_ranges_;
// Approximate at what position the set of ranges will change next.
// Used to avoid scanning for updates even if none are present.
LifetimePosition next_active_ranges_change_;
LifetimePosition next_inactive_ranges_change_;
#ifdef DEBUG
LifetimePosition allocation_finger_;
#endif
......
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