Index: src/compiler/register-allocator.cc |
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc |
index 7a8276849a00372eb309b8f3599d284538a0b590..c65b906bbc6eab87045bd1af0c1e6047864bd0cd 100644 |
--- a/src/compiler/register-allocator.cc |
+++ b/src/compiler/register-allocator.cc |
@@ -199,7 +199,7 @@ bool LiveRange::CanBeSpilled(LifetimePosition pos) { |
} |
-InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) { |
+InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) const { |
InstructionOperand* op = NULL; |
if (HasRegisterAssigned()) { |
DCHECK(!IsSpilled()); |
@@ -507,23 +507,24 @@ LifetimePosition LiveRange::FirstIntersection(LiveRange* other) { |
RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, |
- Zone* local_zone, Frame* frame, |
+ Zone* zone, Frame* frame, |
InstructionSequence* code, |
const char* debug_name) |
- : zone_(local_zone), |
+ : local_zone_(zone), |
frame_(frame), |
code_(code), |
debug_name_(debug_name), |
config_(config), |
- live_in_sets_(code->InstructionBlockCount(), zone()), |
- live_ranges_(code->VirtualRegisterCount() * 2, zone()), |
- fixed_live_ranges_(this->config()->num_general_registers(), NULL, zone()), |
+ live_in_sets_(code->InstructionBlockCount(), local_zone()), |
+ live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), |
+ fixed_live_ranges_(this->config()->num_general_registers(), NULL, |
+ local_zone()), |
fixed_double_live_ranges_(this->config()->num_double_registers(), NULL, |
- zone()), |
- unhandled_live_ranges_(code->VirtualRegisterCount() * 2, zone()), |
- active_live_ranges_(8, zone()), |
- inactive_live_ranges_(8, zone()), |
- reusable_slots_(8, zone()), |
+ local_zone()), |
+ unhandled_live_ranges_(code->VirtualRegisterCount() * 2, local_zone()), |
+ active_live_ranges_(8, local_zone()), |
+ inactive_live_ranges_(8, local_zone()), |
+ reusable_slots_(8, local_zone()), |
mode_(UNALLOCATED_REGISTERS), |
num_registers_(-1), |
allocation_ok_(true) { |
@@ -541,16 +542,16 @@ RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, |
void RegisterAllocator::InitializeLivenessAnalysis() { |
// Initialize the live_in sets for each block to NULL. |
int block_count = code()->InstructionBlockCount(); |
- live_in_sets_.Initialize(block_count, zone()); |
- live_in_sets_.AddBlock(NULL, block_count, zone()); |
+ live_in_sets_.Initialize(block_count, local_zone()); |
+ live_in_sets_.AddBlock(NULL, block_count, local_zone()); |
} |
BitVector* RegisterAllocator::ComputeLiveOut(const InstructionBlock* block) { |
// Compute live out for the given block, except not including backward |
// successor edges. |
- BitVector* live_out = |
- new (zone()) BitVector(code()->VirtualRegisterCount(), zone()); |
+ BitVector* live_out = new (local_zone()) |
+ BitVector(code()->VirtualRegisterCount(), local_zone()); |
// Process all successor blocks. |
for (auto succ : block->successors()) { |
@@ -584,7 +585,7 @@ void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block, |
while (!iterator.Done()) { |
int operand_index = iterator.Current(); |
LiveRange* range = LiveRangeFor(operand_index); |
- range->AddUseInterval(start, end, zone()); |
+ range->AddUseInterval(start, end, local_zone()); |
iterator.Advance(); |
} |
} |
@@ -630,7 +631,7 @@ LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) { |
// The LiveRange object itself can go in this zone, but the |
// InstructionOperand needs |
// to go in the code zone, since it may survive register allocation. |
- result = new (zone()) LiveRange(FixedLiveRangeID(index), code_zone()); |
+ result = new (local_zone()) LiveRange(FixedLiveRangeID(index), code_zone()); |
DCHECK(result->IsFixed()); |
result->kind_ = GENERAL_REGISTERS; |
SetLiveRangeAssignedRegister(result, index); |
@@ -644,7 +645,8 @@ LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) { |
DCHECK(index < config()->num_aliased_double_registers()); |
LiveRange* result = fixed_double_live_ranges_[index]; |
if (result == NULL) { |
- result = new (zone()) LiveRange(FixedDoubleLiveRangeID(index), code_zone()); |
+ result = new (local_zone()) |
+ LiveRange(FixedDoubleLiveRangeID(index), code_zone()); |
DCHECK(result->IsFixed()); |
result->kind_ = DOUBLE_REGISTERS; |
SetLiveRangeAssignedRegister(result, index); |
@@ -656,11 +658,12 @@ LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) { |
LiveRange* RegisterAllocator::LiveRangeFor(int index) { |
if (index >= live_ranges_.length()) { |
- live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1, zone()); |
+ live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1, |
+ local_zone()); |
} |
LiveRange* result = live_ranges_[index]; |
if (result == NULL) { |
- result = new (zone()) LiveRange(index, code_zone()); |
+ result = new (local_zone()) LiveRange(index, code_zone()); |
live_ranges_[index] = result; |
} |
return result; |
@@ -694,15 +697,15 @@ void RegisterAllocator::Define(LifetimePosition position, |
if (range->IsEmpty() || range->Start().Value() > position.Value()) { |
// Can happen if there is a definition without use. |
- range->AddUseInterval(position, position.NextInstruction(), zone()); |
- range->AddUsePosition(position.NextInstruction(), NULL, NULL, zone()); |
+ range->AddUseInterval(position, position.NextInstruction(), local_zone()); |
+ range->AddUsePosition(position.NextInstruction(), NULL, NULL, local_zone()); |
} else { |
range->ShortenTo(position); |
} |
if (operand->IsUnallocated()) { |
UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, zone()); |
+ range->AddUsePosition(position, unalloc_operand, hint, local_zone()); |
} |
} |
@@ -715,9 +718,9 @@ void RegisterAllocator::Use(LifetimePosition block_start, |
if (range == NULL) return; |
if (operand->IsUnallocated()) { |
UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, zone()); |
+ range->AddUsePosition(position, unalloc_operand, hint, local_zone()); |
} |
- range->AddUseInterval(block_start, position, zone()); |
+ range->AddUseInterval(block_start, position, local_zone()); |
} |
@@ -1023,7 +1026,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, |
if (!IsOutputRegisterOf(instr, i)) { |
LiveRange* range = FixedLiveRangeFor(i); |
range->AddUseInterval(curr_position, curr_position.InstructionEnd(), |
- zone()); |
+ local_zone()); |
} |
} |
} |
@@ -1033,7 +1036,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, |
if (!IsOutputDoubleRegisterOf(instr, i)) { |
LiveRange* range = FixedDoubleLiveRangeFor(i); |
range->AddUseInterval(curr_position, curr_position.InstructionEnd(), |
- zone()); |
+ local_zone()); |
} |
} |
} |
@@ -1160,9 +1163,8 @@ bool RegisterAllocator::Allocate(PipelineStatistics* stats) { |
void RegisterAllocator::MeetRegisterConstraints() { |
- for (int i = 0; i < code()->InstructionBlockCount(); ++i) { |
- MeetRegisterConstraints( |
- code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i))); |
+ for (auto block : code()->instruction_blocks()) { |
+ MeetRegisterConstraints(block); |
if (!AllocationOk()) return; |
} |
} |
@@ -1170,55 +1172,9 @@ void RegisterAllocator::MeetRegisterConstraints() { |
void RegisterAllocator::ResolvePhis() { |
// Process the blocks in reverse order. |
- for (int i = code()->InstructionBlockCount() - 1; i >= 0; --i) { |
- ResolvePhis(code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i))); |
- } |
-} |
- |
- |
-void RegisterAllocator::ResolveControlFlow(LiveRange* range, |
- const InstructionBlock* block, |
- const InstructionBlock* pred) { |
- LifetimePosition pred_end = |
- LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
- LifetimePosition cur_start = |
- LifetimePosition::FromInstructionIndex(block->first_instruction_index()); |
- LiveRange* pred_cover = NULL; |
- LiveRange* cur_cover = NULL; |
- LiveRange* cur_range = range; |
- while (cur_range != NULL && (cur_cover == NULL || pred_cover == NULL)) { |
- if (cur_range->CanCover(cur_start)) { |
- DCHECK(cur_cover == NULL); |
- cur_cover = cur_range; |
- } |
- if (cur_range->CanCover(pred_end)) { |
- DCHECK(pred_cover == NULL); |
- pred_cover = cur_range; |
- } |
- cur_range = cur_range->next(); |
- } |
- |
- if (cur_cover->IsSpilled()) return; |
- DCHECK(pred_cover != NULL && cur_cover != NULL); |
- if (pred_cover != cur_cover) { |
- InstructionOperand* pred_op = |
- pred_cover->CreateAssignedOperand(code_zone()); |
- InstructionOperand* cur_op = cur_cover->CreateAssignedOperand(code_zone()); |
- if (!pred_op->Equals(cur_op)) { |
- GapInstruction* gap = NULL; |
- if (block->PredecessorCount() == 1) { |
- gap = code()->GapAt(block->first_instruction_index()); |
- } else { |
- DCHECK(pred->SuccessorCount() == 1); |
- gap = GetLastGap(pred); |
- |
- Instruction* branch = InstructionAt(pred->last_instruction_index()); |
- DCHECK(!branch->HasPointerMap()); |
- USE(branch); |
- } |
- gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()) |
- ->AddMove(pred_op, cur_op, code_zone()); |
- } |
+ for (auto i = code()->instruction_blocks().rbegin(); |
+ i != code()->instruction_blocks().rend(); ++i) { |
+ ResolvePhis(*i); |
} |
} |
@@ -1288,20 +1244,146 @@ bool RegisterAllocator::CanEagerlyResolveControlFlow( |
} |
+namespace { |
+ |
+class LiveRangeBound { |
+ public: |
+ explicit LiveRangeBound(const LiveRange* range) |
+ : range_(range), start_(range->Start()), end_(range->End()) { |
+ DCHECK(!range->IsEmpty()); |
+ } |
+ |
+ bool CanCover(LifetimePosition position) { |
+ return start_.Value() <= position.Value() && |
+ position.Value() < end_.Value(); |
+ } |
+ |
+ const LiveRange* const range_; |
+ const LifetimePosition start_; |
+ const LifetimePosition end_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeBound); |
+}; |
+ |
+ |
+struct FindResult { |
+ const LiveRange* cur_cover_; |
+ const LiveRange* pred_cover_; |
+}; |
+ |
+ |
+class LiveRangeBoundArray { |
+ public: |
+ LiveRangeBoundArray() : length_(0), start_(nullptr) {} |
+ |
+ bool ShouldInitialize() { return start_ == NULL; } |
+ |
+ void Initialize(Zone* zone, const LiveRange* const range) { |
+ size_t length = 0; |
+ for (const LiveRange* i = range; i != NULL; i = i->next()) length++; |
+ start_ = zone->NewArray<LiveRangeBound>(static_cast<int>(length)); |
+ length_ = length; |
+ LiveRangeBound* curr = start_; |
+ for (const LiveRange* i = range; i != NULL; i = i->next(), ++curr) { |
+ new (curr) LiveRangeBound(i); |
+ } |
+ } |
+ |
+ LiveRangeBound* Find(const LifetimePosition position) const { |
+ size_t left_index = 0; |
+ size_t right_index = length_; |
+ while (true) { |
+ size_t current_index = left_index + (right_index - left_index) / 2; |
+ DCHECK(right_index > current_index); |
+ LiveRangeBound* bound = &start_[current_index]; |
+ if (bound->start_.Value() <= position.Value()) { |
+ if (position.Value() < bound->end_.Value()) return bound; |
+ DCHECK(left_index < current_index); |
+ left_index = current_index; |
+ } else { |
Jarin
2014/11/05 12:30:18
Thanks, this looks much better!
|
+ right_index = current_index; |
+ } |
+ } |
+ } |
+ |
+ void Find(const InstructionBlock* block, const InstructionBlock* pred, |
+ FindResult* result) const { |
+ const LifetimePosition pred_end = |
+ LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
+ LiveRangeBound* bound = Find(pred_end); |
+ result->pred_cover_ = bound->range_; |
+ const LifetimePosition cur_start = LifetimePosition::FromInstructionIndex( |
+ block->first_instruction_index()); |
+ // Common case. |
+ if (bound->CanCover(cur_start)) { |
+ result->cur_cover_ = bound->range_; |
+ return; |
+ } |
+ result->cur_cover_ = Find(cur_start)->range_; |
+ DCHECK(result->pred_cover_ != NULL && result->cur_cover_ != NULL); |
+ } |
+ |
+ private: |
+ size_t length_; |
+ LiveRangeBound* start_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray); |
+}; |
+ |
+ |
+class LiveRangeFinder { |
+ public: |
+ explicit LiveRangeFinder(const RegisterAllocator& allocator) |
+ : allocator_(allocator), |
+ bounds_length_(allocator.live_ranges().length()), |
+ bounds_(allocator.local_zone()->NewArray<LiveRangeBoundArray>( |
+ bounds_length_)) { |
+ for (int i = 0; i < bounds_length_; ++i) { |
+ new (&bounds_[i]) LiveRangeBoundArray(); |
+ } |
+ } |
+ |
+ LiveRangeBoundArray* ArrayFor(int operand_index) { |
+ DCHECK(operand_index < bounds_length_); |
+ const LiveRange* range = allocator_.live_ranges()[operand_index]; |
+ DCHECK(range != nullptr && !range->IsEmpty()); |
+ LiveRangeBoundArray* array = &bounds_[operand_index]; |
+ if (array->ShouldInitialize()) { |
+ array->Initialize(allocator_.local_zone(), range); |
+ } |
+ return array; |
+ } |
+ |
+ private: |
+ const RegisterAllocator& allocator_; |
+ const int bounds_length_; |
+ LiveRangeBoundArray* const bounds_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); |
+}; |
+ |
+} // namespace |
+ |
+ |
void RegisterAllocator::ResolveControlFlow() { |
- for (int block_id = 1; block_id < code()->InstructionBlockCount(); |
- ++block_id) { |
- const InstructionBlock* block = |
- code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id)); |
+ // Lazily linearize live ranges in memory for fast lookup. |
+ LiveRangeFinder finder(*this); |
+ for (auto block : code()->instruction_blocks()) { |
if (CanEagerlyResolveControlFlow(block)) continue; |
BitVector* live = live_in_sets_[block->rpo_number().ToInt()]; |
BitVector::Iterator iterator(live); |
while (!iterator.Done()) { |
- int operand_index = iterator.Current(); |
+ LiveRangeBoundArray* array = finder.ArrayFor(iterator.Current()); |
for (auto pred : block->predecessors()) { |
- const InstructionBlock* cur = code()->InstructionBlockAt(pred); |
- LiveRange* cur_range = LiveRangeFor(operand_index); |
- ResolveControlFlow(cur_range, block, cur); |
+ FindResult result; |
+ const InstructionBlock* pred_block = code()->InstructionBlockAt(pred); |
+ array->Find(block, pred_block, &result); |
+ if (result.cur_cover_ == result.pred_cover_ || |
+ result.cur_cover_->IsSpilled()) |
+ continue; |
+ ResolveControlFlow(block, result.cur_cover_, pred_block, |
+ result.pred_cover_); |
} |
iterator.Advance(); |
} |
@@ -1309,6 +1391,30 @@ void RegisterAllocator::ResolveControlFlow() { |
} |
+void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, |
+ const LiveRange* cur_cover, |
+ const InstructionBlock* pred, |
+ const LiveRange* pred_cover) { |
+ InstructionOperand* pred_op = pred_cover->CreateAssignedOperand(code_zone()); |
+ InstructionOperand* cur_op = cur_cover->CreateAssignedOperand(code_zone()); |
+ if (!pred_op->Equals(cur_op)) { |
+ GapInstruction* gap = NULL; |
+ if (block->PredecessorCount() == 1) { |
+ gap = code()->GapAt(block->first_instruction_index()); |
+ } else { |
+ DCHECK(pred->SuccessorCount() == 1); |
+ gap = GetLastGap(pred); |
+ |
+ Instruction* branch = InstructionAt(pred->last_instruction_index()); |
+ DCHECK(!branch->HasPointerMap()); |
+ USE(branch); |
+ } |
+ gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()) |
+ ->AddMove(pred_op, cur_op, code_zone()); |
+ } |
+} |
+ |
+ |
void RegisterAllocator::BuildLiveRanges() { |
InitializeLivenessAnalysis(); |
// Process the blocks in reverse order. |
@@ -1371,7 +1477,7 @@ void RegisterAllocator::BuildLiveRanges() { |
while (!iterator.Done()) { |
int operand_index = iterator.Current(); |
LiveRange* range = LiveRangeFor(operand_index); |
- range->EnsureInterval(start, end, zone()); |
+ range->EnsureInterval(start, end, local_zone()); |
iterator.Advance(); |
} |
@@ -1667,13 +1773,13 @@ RegisterKind RegisterAllocator::RequiredRegisterKind( |
void RegisterAllocator::AddToActive(LiveRange* range) { |
TraceAlloc("Add live range %d to active\n", range->id()); |
- active_live_ranges_.Add(range, zone()); |
+ active_live_ranges_.Add(range, local_zone()); |
} |
void RegisterAllocator::AddToInactive(LiveRange* range) { |
TraceAlloc("Add live range %d to inactive\n", range->id()); |
- inactive_live_ranges_.Add(range, zone()); |
+ inactive_live_ranges_.Add(range, local_zone()); |
} |
@@ -1685,13 +1791,13 @@ void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) { |
LiveRange* cur_range = unhandled_live_ranges_.at(i); |
if (range->ShouldBeAllocatedBefore(cur_range)) { |
TraceAlloc("Add live range %d to unhandled at %d\n", range->id(), i + 1); |
- unhandled_live_ranges_.InsertAt(i + 1, range, zone()); |
+ unhandled_live_ranges_.InsertAt(i + 1, range, local_zone()); |
DCHECK(UnhandledIsSorted()); |
return; |
} |
} |
TraceAlloc("Add live range %d to unhandled at start\n", range->id()); |
- unhandled_live_ranges_.InsertAt(0, range, zone()); |
+ unhandled_live_ranges_.InsertAt(0, range, local_zone()); |
DCHECK(UnhandledIsSorted()); |
} |
@@ -1700,7 +1806,7 @@ void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) { |
if (range == NULL || range->IsEmpty()) return; |
DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); |
TraceAlloc("Add live range %d to unhandled unsorted at end\n", range->id()); |
- unhandled_live_ranges_.Add(range, zone()); |
+ unhandled_live_ranges_.Add(range, local_zone()); |
} |
@@ -1742,7 +1848,7 @@ void RegisterAllocator::FreeSpillSlot(LiveRange* range) { |
InstructionOperand* spill_operand = range->TopLevel()->GetSpillOperand(); |
if (spill_operand->IsConstant()) return; |
if (spill_operand->index() >= 0) { |
- reusable_slots_.Add(range, zone()); |
+ reusable_slots_.Add(range, local_zone()); |
} |
} |
@@ -1771,7 +1877,7 @@ void RegisterAllocator::ActiveToHandled(LiveRange* range) { |
void RegisterAllocator::ActiveToInactive(LiveRange* range) { |
DCHECK(active_live_ranges_.Contains(range)); |
active_live_ranges_.RemoveElement(range); |
- inactive_live_ranges_.Add(range, zone()); |
+ inactive_live_ranges_.Add(range, local_zone()); |
TraceAlloc("Moving live range %d from active to inactive\n", range->id()); |
} |
@@ -1787,7 +1893,7 @@ void RegisterAllocator::InactiveToHandled(LiveRange* range) { |
void RegisterAllocator::InactiveToActive(LiveRange* range) { |
DCHECK(inactive_live_ranges_.Contains(range)); |
inactive_live_ranges_.RemoveElement(range); |
- active_live_ranges_.Add(range, zone()); |
+ active_live_ranges_.Add(range, local_zone()); |
TraceAlloc("Moving live range %d from inactive to active\n", range->id()); |
} |
@@ -2063,7 +2169,7 @@ LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, |
int vreg = GetVirtualRegister(); |
if (!AllocationOk()) return NULL; |
LiveRange* result = LiveRangeFor(vreg); |
- range->SplitAt(pos, result, zone()); |
+ range->SplitAt(pos, result, local_zone()); |
return result; |
} |
@@ -2171,10 +2277,10 @@ void RegisterAllocator::Spill(LiveRange* range) { |
RegisterKind kind = range->Kind(); |
int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
if (kind == DOUBLE_REGISTERS) { |
- op = DoubleStackSlotOperand::Create(index, zone()); |
+ op = DoubleStackSlotOperand::Create(index, local_zone()); |
} else { |
DCHECK(kind == GENERAL_REGISTERS); |
- op = StackSlotOperand::Create(index, zone()); |
+ op = StackSlotOperand::Create(index, local_zone()); |
} |
} |
first->SetSpillOperand(op); |