[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 <sigurds@chromium.org>
Commit-Queue: Stephan Herhut <herhut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57990}
This commit is contained in:
Stephan Herhut 2018-11-28 15:27:28 +01:00 committed by Commit Bot
parent 3e9cd32cde
commit 2394b2683b
2 changed files with 78 additions and 28 deletions

View File

@ -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 {

View File

@ -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