Commit d992246d authored by Stephan Herhut's avatar Stephan Herhut Committed by Commit Bot

[regalloc] Add control flow hinting

This adds a new hint type for live ranges that allows the control
flow aware allocation to hint the register that should be used on
reload. Avoid unnecessary register to register moves and helps
with code size.

Change-Id: I01e870514446eab3bffb89b2e00644bd215b81d5
Reviewed-on: https://chromium-review.googlesource.com/c/1460944Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Stephan Herhut <herhut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59698}
parent d3308d04
......@@ -391,7 +391,8 @@ LiveRange::LiveRange(int relative_id, MachineRepresentation rep,
splitting_pointer_(nullptr) {
DCHECK(AllocatedOperand::IsSupportedRepresentation(rep));
bits_ = AssignedRegisterField::encode(kUnassignedRegister) |
RepresentationField::encode(rep);
RepresentationField::encode(rep) |
ControlFlowRegisterHint::encode(kUnassignedRegister);
}
void LiveRange::VerifyPositions() const {
......@@ -723,6 +724,17 @@ bool LiveRange::ShouldBeAllocatedBefore(const LiveRange* other) const {
LifetimePosition start = Start();
LifetimePosition other_start = other->Start();
if (start == other_start) {
// Prefer register that has a controlflow hint to make sure it gets
// allocated first. This allows the control flow aware alloction to
// just put ranges back into the queue without other ranges interfering.
if (controlflow_hint() < other->controlflow_hint()) {
return true;
}
// The other has a smaller hint.
if (other->controlflow_hint() != kUnassignedRegister) {
return false;
}
// No hint, use first use position.
UsePosition* pos = first_pos();
UsePosition* other_pos = other->first_pos();
// To make the order total, handle the case where both positions are null.
......@@ -3056,6 +3068,7 @@ void LinearScanAllocator::SpillNotLiveRanges(RangeWithRegisterSet& to_be_live,
TRACE("Scheduling %d:%d\n", toplevel->vreg(),
active_range->relative_id());
LiveRange* split = SplitRangeAt(active_range, position);
split->set_controlflow_hint(expected_register);
AddToUnhandled(split);
it = ActiveToHandled(it);
}
......@@ -3142,6 +3155,7 @@ void LinearScanAllocator::ReloadLiveRanges(RangeWithRegisterSet& to_be_live,
to_resurrect->relative_id(), position.value());
if (to_resurrect->spilled()) {
to_resurrect->Unspill();
to_resurrect->set_controlflow_hint(reg);
AddToUnhandled(to_resurrect);
} else {
// Assign the preassigned register if we know. Otherwise, nothing to
......@@ -3172,6 +3186,7 @@ void LinearScanAllocator::ReloadLiveRanges(RangeWithRegisterSet& to_be_live,
AddToActive(split);
} else {
// Let normal register assignment find a suitable register.
split->set_controlflow_hint(reg);
AddToUnhandled(split);
}
}
......@@ -3830,7 +3845,8 @@ void LinearScanAllocator::ProcessCurrentRange(LiveRange* current) {
bool LinearScanAllocator::TryAllocatePreferredReg(
LiveRange* current, const Vector<LifetimePosition>& free_until_pos) {
int hint_register;
if (current->FirstHintPosition(&hint_register) != nullptr ||
if (current->RegisterFromControlFlow(&hint_register) ||
current->FirstHintPosition(&hint_register) != nullptr ||
current->RegisterFromBundle(&hint_register)) {
TRACE(
"Found reg hint %s (free until [%d) for live range %d:%d (end %d[).\n",
......@@ -3894,7 +3910,8 @@ bool LinearScanAllocator::TryAllocateFreeReg(
LiveRange* current, const Vector<LifetimePosition>& free_until_pos) {
// Compute register hint, if such exists.
int hint_reg = kUnassignedRegister;
current->FirstHintPosition(&hint_reg) != nullptr ||
current->RegisterFromControlFlow(&hint_reg) ||
current->FirstHintPosition(&hint_reg) != nullptr ||
current->RegisterFromBundle(&hint_reg);
int reg =
......
......@@ -335,6 +335,20 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) {
bool ShouldRecombine() const { return RecombineField::decode(bits_); }
void SetRecombine() { bits_ = RecombineField::update(bits_, true); }
void set_controlflow_hint(int reg) {
bits_ = ControlFlowRegisterHint::update(bits_, reg);
}
int controlflow_hint() const {
return ControlFlowRegisterHint::decode(bits_);
}
bool RegisterFromControlFlow(int* reg) {
int hint = controlflow_hint();
if (hint != kUnassignedRegister) {
*reg = hint;
return true;
}
return false;
}
bool spilled() const { return SpilledField::decode(bits_); }
void AttachToNext();
void Unspill();
......@@ -453,9 +467,11 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) {
void VerifyIntervals() const;
typedef BitField<bool, 0, 1> SpilledField;
// Bits (1,6] are used by TopLevelLiveRange.
typedef BitField<int32_t, 6, 6> AssignedRegisterField;
typedef BitField<MachineRepresentation, 12, 8> RepresentationField;
typedef BitField<bool, 20, 1> RecombineField;
typedef BitField<uint8_t, 21, 6> ControlFlowRegisterHint;
// Unique among children and splinters of the same virtual register.
int relative_id_;
......
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