[turbofan] split all functions off of LinearScanAllocator which are unrelated to LinearScan
this is in preparation for landing the GreedyAllocator BUG= Review URL: https://codereview.chromium.org/1100713003 Cr-Commit-Position: refs/heads/master@{#27963}
This commit is contained in:
parent
bb346227db
commit
d04aee2482
@ -1462,9 +1462,125 @@ void LiveRangeBuilder::Verify() const {
|
||||
}
|
||||
|
||||
|
||||
RegisterAllocator::RegisterAllocator(RegisterAllocationData* data)
|
||||
: data_(data) {}
|
||||
|
||||
|
||||
LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range,
|
||||
LifetimePosition pos) {
|
||||
DCHECK(!range->IsFixed());
|
||||
TRACE("Splitting live range %d at %d\n", range->id(), pos.Value());
|
||||
|
||||
if (pos.Value() <= range->Start().Value()) return range;
|
||||
|
||||
// We can't properly connect liveranges if splitting occurred at the end
|
||||
// a block.
|
||||
DCHECK(pos.IsStart() || pos.IsGapPosition() ||
|
||||
(GetInstructionBlock(code(), pos)->last_instruction_index() !=
|
||||
pos.ToInstructionIndex()));
|
||||
|
||||
int vreg = code()->NextVirtualRegister();
|
||||
auto result = LiveRangeFor(vreg);
|
||||
range->SplitAt(pos, result, allocation_zone());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LiveRange* RegisterAllocator::SplitBetween(LiveRange* range,
|
||||
LifetimePosition start,
|
||||
LifetimePosition end) {
|
||||
DCHECK(!range->IsFixed());
|
||||
TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(),
|
||||
start.Value(), end.Value());
|
||||
|
||||
auto split_pos = FindOptimalSplitPos(start, end);
|
||||
DCHECK(split_pos.Value() >= start.Value());
|
||||
return SplitRangeAt(range, split_pos);
|
||||
}
|
||||
|
||||
|
||||
LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start,
|
||||
LifetimePosition end) {
|
||||
int start_instr = start.ToInstructionIndex();
|
||||
int end_instr = end.ToInstructionIndex();
|
||||
DCHECK(start_instr <= end_instr);
|
||||
|
||||
// We have no choice
|
||||
if (start_instr == end_instr) return end;
|
||||
|
||||
auto start_block = GetInstructionBlock(code(), start);
|
||||
auto end_block = GetInstructionBlock(code(), end);
|
||||
|
||||
if (end_block == start_block) {
|
||||
// The interval is split in the same basic block. Split at the latest
|
||||
// possible position.
|
||||
return end;
|
||||
}
|
||||
|
||||
auto block = end_block;
|
||||
// Find header of outermost loop.
|
||||
// TODO(titzer): fix redundancy below.
|
||||
while (GetContainingLoop(code(), block) != nullptr &&
|
||||
GetContainingLoop(code(), block)->rpo_number().ToInt() >
|
||||
start_block->rpo_number().ToInt()) {
|
||||
block = GetContainingLoop(code(), block);
|
||||
}
|
||||
|
||||
// We did not find any suitable outer loop. Split at the latest possible
|
||||
// position unless end_block is a loop header itself.
|
||||
if (block == end_block && !end_block->IsLoopHeader()) return end;
|
||||
|
||||
return LifetimePosition::GapFromInstructionIndex(
|
||||
block->first_instruction_index());
|
||||
}
|
||||
|
||||
|
||||
LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
|
||||
LiveRange* range, LifetimePosition pos) {
|
||||
auto block = GetInstructionBlock(code(), pos.Start());
|
||||
auto loop_header =
|
||||
block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
|
||||
|
||||
if (loop_header == nullptr) return pos;
|
||||
|
||||
auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos);
|
||||
|
||||
while (loop_header != nullptr) {
|
||||
// We are going to spill live range inside the loop.
|
||||
// If possible try to move spilling position backwards to loop header.
|
||||
// This will reduce number of memory moves on the back edge.
|
||||
auto loop_start = LifetimePosition::GapFromInstructionIndex(
|
||||
loop_header->first_instruction_index());
|
||||
|
||||
if (range->Covers(loop_start)) {
|
||||
if (prev_use == nullptr || prev_use->pos().Value() < loop_start.Value()) {
|
||||
// No register beneficial use inside the loop before the pos.
|
||||
pos = loop_start;
|
||||
}
|
||||
}
|
||||
|
||||
// Try hoisting out to an outer loop.
|
||||
loop_header = GetContainingLoop(code(), loop_header);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::Spill(LiveRange* range) {
|
||||
DCHECK(!range->IsSpilled());
|
||||
TRACE("Spilling live range %d\n", range->id());
|
||||
auto first = range->TopLevel();
|
||||
if (first->HasNoSpillType()) {
|
||||
data()->AssignSpillRangeToLiveRange(first);
|
||||
}
|
||||
range->MakeSpilled();
|
||||
}
|
||||
|
||||
|
||||
LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
|
||||
RegisterKind kind, Zone* local_zone)
|
||||
: data_(data),
|
||||
: RegisterAllocator(data),
|
||||
mode_(kind),
|
||||
num_registers_(GetRegisterCount(data->config(), kind)),
|
||||
unhandled_live_ranges_(local_zone),
|
||||
@ -1825,38 +1941,6 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) {
|
||||
}
|
||||
|
||||
|
||||
LifetimePosition LinearScanAllocator::FindOptimalSpillingPos(
|
||||
LiveRange* range, LifetimePosition pos) {
|
||||
auto block = GetInstructionBlock(code(), pos.Start());
|
||||
auto loop_header =
|
||||
block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
|
||||
|
||||
if (loop_header == nullptr) return pos;
|
||||
|
||||
auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos);
|
||||
|
||||
while (loop_header != nullptr) {
|
||||
// We are going to spill live range inside the loop.
|
||||
// If possible try to move spilling position backwards to loop header.
|
||||
// This will reduce number of memory moves on the back edge.
|
||||
auto loop_start = LifetimePosition::GapFromInstructionIndex(
|
||||
loop_header->first_instruction_index());
|
||||
|
||||
if (range->Covers(loop_start)) {
|
||||
if (prev_use == nullptr || prev_use->pos().Value() < loop_start.Value()) {
|
||||
// No register beneficial use inside the loop before the pos.
|
||||
pos = loop_start;
|
||||
}
|
||||
}
|
||||
|
||||
// Try hoisting out to an outer loop.
|
||||
loop_header = GetContainingLoop(code(), loop_header);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) {
|
||||
DCHECK(current->HasRegisterAssigned());
|
||||
int reg = current->assigned_register();
|
||||
@ -1991,75 +2075,6 @@ bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) {
|
||||
}
|
||||
|
||||
|
||||
LiveRange* LinearScanAllocator::SplitRangeAt(LiveRange* range,
|
||||
LifetimePosition pos) {
|
||||
DCHECK(!range->IsFixed());
|
||||
TRACE("Splitting live range %d at %d\n", range->id(), pos.Value());
|
||||
|
||||
if (pos.Value() <= range->Start().Value()) return range;
|
||||
|
||||
// We can't properly connect liveranges if splitting occurred at the end
|
||||
// a block.
|
||||
DCHECK(pos.IsStart() || pos.IsGapPosition() ||
|
||||
(GetInstructionBlock(code(), pos)->last_instruction_index() !=
|
||||
pos.ToInstructionIndex()));
|
||||
|
||||
int vreg = code()->NextVirtualRegister();
|
||||
auto result = LiveRangeFor(vreg);
|
||||
range->SplitAt(pos, result, allocation_zone());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LiveRange* LinearScanAllocator::SplitBetween(LiveRange* range,
|
||||
LifetimePosition start,
|
||||
LifetimePosition end) {
|
||||
DCHECK(!range->IsFixed());
|
||||
TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(),
|
||||
start.Value(), end.Value());
|
||||
|
||||
auto split_pos = FindOptimalSplitPos(start, end);
|
||||
DCHECK(split_pos.Value() >= start.Value());
|
||||
return SplitRangeAt(range, split_pos);
|
||||
}
|
||||
|
||||
|
||||
LifetimePosition LinearScanAllocator::FindOptimalSplitPos(
|
||||
LifetimePosition start, LifetimePosition end) {
|
||||
int start_instr = start.ToInstructionIndex();
|
||||
int end_instr = end.ToInstructionIndex();
|
||||
DCHECK(start_instr <= end_instr);
|
||||
|
||||
// We have no choice
|
||||
if (start_instr == end_instr) return end;
|
||||
|
||||
auto start_block = GetInstructionBlock(code(), start);
|
||||
auto end_block = GetInstructionBlock(code(), end);
|
||||
|
||||
if (end_block == start_block) {
|
||||
// The interval is split in the same basic block. Split at the latest
|
||||
// possible position.
|
||||
return end;
|
||||
}
|
||||
|
||||
auto block = end_block;
|
||||
// Find header of outermost loop.
|
||||
// TODO(titzer): fix redundancy below.
|
||||
while (GetContainingLoop(code(), block) != nullptr &&
|
||||
GetContainingLoop(code(), block)->rpo_number().ToInt() >
|
||||
start_block->rpo_number().ToInt()) {
|
||||
block = GetContainingLoop(code(), block);
|
||||
}
|
||||
|
||||
// We did not find any suitable outer loop. Split at the latest possible
|
||||
// position unless end_block is a loop header itself.
|
||||
if (block == end_block && !end_block->IsLoopHeader()) return end;
|
||||
|
||||
return LifetimePosition::GapFromInstructionIndex(
|
||||
block->first_instruction_index());
|
||||
}
|
||||
|
||||
|
||||
void LinearScanAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
|
||||
auto second_part = SplitRangeAt(range, pos);
|
||||
Spill(second_part);
|
||||
@ -2102,17 +2117,6 @@ void LinearScanAllocator::SpillBetweenUntil(LiveRange* range,
|
||||
}
|
||||
|
||||
|
||||
void LinearScanAllocator::Spill(LiveRange* range) {
|
||||
DCHECK(!range->IsSpilled());
|
||||
TRACE("Spilling live range %d\n", range->id());
|
||||
auto first = range->TopLevel();
|
||||
if (first->HasNoSpillType()) {
|
||||
data()->AssignSpillRangeToLiveRange(first);
|
||||
}
|
||||
range->MakeSpilled();
|
||||
}
|
||||
|
||||
|
||||
OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {}
|
||||
|
||||
|
||||
|
@ -583,50 +583,17 @@ class LiveRangeBuilder final : public ZoneObject {
|
||||
};
|
||||
|
||||
|
||||
class LinearScanAllocator final : public ZoneObject {
|
||||
class RegisterAllocator : public ZoneObject {
|
||||
public:
|
||||
LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind,
|
||||
Zone* local_zone);
|
||||
explicit RegisterAllocator(RegisterAllocationData* data);
|
||||
|
||||
// Phase 4: compute register assignments.
|
||||
void AllocateRegisters();
|
||||
|
||||
private:
|
||||
protected:
|
||||
RegisterAllocationData* data() const { return data_; }
|
||||
InstructionSequence* code() const { return data()->code(); }
|
||||
Zone* allocation_zone() const { return data()->allocation_zone(); }
|
||||
int num_registers() const { return num_registers_; }
|
||||
const char* RegisterName(int allocation_index) const;
|
||||
|
||||
ZoneVector<LiveRange*>& unhandled_live_ranges() {
|
||||
return unhandled_live_ranges_;
|
||||
}
|
||||
ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; }
|
||||
ZoneVector<LiveRange*>& inactive_live_ranges() {
|
||||
return inactive_live_ranges_;
|
||||
}
|
||||
|
||||
LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
|
||||
|
||||
// Helper methods for updating the life range lists.
|
||||
void AddToActive(LiveRange* range);
|
||||
void AddToInactive(LiveRange* range);
|
||||
void AddToUnhandledSorted(LiveRange* range);
|
||||
void AddToUnhandledUnsorted(LiveRange* range);
|
||||
void SortUnhandled();
|
||||
bool UnhandledIsSorted();
|
||||
void ActiveToHandled(LiveRange* range);
|
||||
void ActiveToInactive(LiveRange* range);
|
||||
void InactiveToHandled(LiveRange* range);
|
||||
void InactiveToActive(LiveRange* range);
|
||||
|
||||
// Helper methods for allocating registers.
|
||||
bool TryReuseSpillForPhi(LiveRange* range);
|
||||
bool TryAllocateFreeReg(LiveRange* range);
|
||||
void AllocateBlockedReg(LiveRange* range);
|
||||
|
||||
// Live range splitting helpers.
|
||||
|
||||
// Split the given range at the given position.
|
||||
// If range starts at or after the given position then the
|
||||
// original range is returned.
|
||||
@ -647,6 +614,55 @@ class LinearScanAllocator final : public ZoneObject {
|
||||
|
||||
void Spill(LiveRange* range);
|
||||
|
||||
// If we are trying to spill a range inside the loop try to
|
||||
// hoist spill position out to the point just before the loop.
|
||||
LifetimePosition FindOptimalSpillingPos(LiveRange* range,
|
||||
LifetimePosition pos);
|
||||
|
||||
private:
|
||||
RegisterAllocationData* const data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
|
||||
};
|
||||
|
||||
|
||||
class LinearScanAllocator final : public RegisterAllocator {
|
||||
public:
|
||||
LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind,
|
||||
Zone* local_zone);
|
||||
|
||||
// Phase 4: compute register assignments.
|
||||
void AllocateRegisters();
|
||||
|
||||
private:
|
||||
int num_registers() const { return num_registers_; }
|
||||
const char* RegisterName(int allocation_index) const;
|
||||
|
||||
ZoneVector<LiveRange*>& unhandled_live_ranges() {
|
||||
return unhandled_live_ranges_;
|
||||
}
|
||||
ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; }
|
||||
ZoneVector<LiveRange*>& inactive_live_ranges() {
|
||||
return inactive_live_ranges_;
|
||||
}
|
||||
|
||||
// Helper methods for updating the life range lists.
|
||||
void AddToActive(LiveRange* range);
|
||||
void AddToInactive(LiveRange* range);
|
||||
void AddToUnhandledSorted(LiveRange* range);
|
||||
void AddToUnhandledUnsorted(LiveRange* range);
|
||||
void SortUnhandled();
|
||||
bool UnhandledIsSorted();
|
||||
void ActiveToHandled(LiveRange* range);
|
||||
void ActiveToInactive(LiveRange* range);
|
||||
void InactiveToHandled(LiveRange* range);
|
||||
void InactiveToActive(LiveRange* range);
|
||||
|
||||
// Helper methods for allocating registers.
|
||||
bool TryReuseSpillForPhi(LiveRange* range);
|
||||
bool TryAllocateFreeReg(LiveRange* range);
|
||||
void AllocateBlockedReg(LiveRange* range);
|
||||
|
||||
// Spill the given life range after position pos.
|
||||
void SpillAfter(LiveRange* range, LifetimePosition pos);
|
||||
|
||||
@ -661,12 +677,6 @@ class LinearScanAllocator final : public ZoneObject {
|
||||
|
||||
void SplitAndSpillIntersecting(LiveRange* range);
|
||||
|
||||
// If we are trying to spill a range inside the loop try to
|
||||
// hoist spill position out to the point just before the loop.
|
||||
LifetimePosition FindOptimalSpillingPos(LiveRange* range,
|
||||
LifetimePosition pos);
|
||||
|
||||
RegisterAllocationData* const data_;
|
||||
const RegisterKind mode_;
|
||||
const int num_registers_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user