From 2394b2683b478081804684f9b491c0db2f76966d Mon Sep 17 00:00:00 2001 From: Stephan Herhut Date: Wed, 28 Nov 2018 15:27:28 +0100 Subject: [PATCH] [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/1352308 Reviewed-by: Sigurd Schneider Commit-Queue: Stephan Herhut Cr-Commit-Position: refs/heads/master@{#57990} --- src/compiler/backend/register-allocator.cc | 93 ++++++++++++++++------ src/compiler/backend/register-allocator.h | 13 ++- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/compiler/backend/register-allocator.cc b/src/compiler/backend/register-allocator.cc index 74a27dec05..50ed29b20b 100644 --- a/src/compiler/backend/register-allocator.cc +++ b/src/compiler/backend/register-allocator.cc @@ -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::iterator LinearScanAllocator::ActiveToHandled( } ZoneVector::iterator LinearScanAllocator::ActiveToInactive( - const ZoneVector::iterator it) { + const ZoneVector::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::iterator LinearScanAllocator::InactiveToHandled( } ZoneVector::iterator LinearScanAllocator::InactiveToActive( - ZoneVector::iterator it) { + ZoneVector::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 { diff --git a/src/compiler/backend/register-allocator.h b/src/compiler/backend/register-allocator.h index 2b4d1d0a18..bc4cc13e90 100644 --- a/src/compiler/backend/register-allocator.h +++ b/src/compiler/backend/register-allocator.h @@ -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::iterator ActiveToHandled( ZoneVector::iterator it); ZoneVector::iterator ActiveToInactive( - ZoneVector::iterator it); + ZoneVector::iterator it, LifetimePosition position); ZoneVector::iterator InactiveToHandled( ZoneVector::iterator it); ZoneVector::iterator InactiveToActive( - ZoneVector::iterator it); + ZoneVector::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 active_live_ranges_; ZoneVector 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