[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:
dcarney 2015-04-21 06:05:05 -07:00 committed by Commit bot
parent bb346227db
commit d04aee2482
2 changed files with 169 additions and 155 deletions

View File

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

View File

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