Index: src/compiler/register-allocator.cc |
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc |
index c96a7e94f7fe333ecb78d546b27d90a40f012ba6..cff644d24c9c42167c62b4ed2b37191511256e71 100644 |
--- a/src/compiler/register-allocator.cc |
+++ b/src/compiler/register-allocator.cc |
@@ -69,6 +69,11 @@ bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) { |
} |
+Instruction* GetLastInstruction(InstructionSequence* code, |
+ const InstructionBlock* block) { |
+ return code->InstructionAt(block->last_instruction_index()); |
+} |
+ |
} // namespace |
@@ -833,67 +838,12 @@ void RegisterAllocationData::SetLiveRangeAssignedRegister(LiveRange* range, |
} |
-LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data) |
+ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) |
: data_(data) {} |
-BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { |
- // Compute live out for the given block, except not including backward |
- // successor edges. |
- auto live_out = new (allocation_zone()) |
- BitVector(code()->VirtualRegisterCount(), allocation_zone()); |
- |
- // Process all successor blocks. |
- for (auto succ : block->successors()) { |
- // Add values live on entry to the successor. Note the successor's |
- // live_in will not be computed yet for backwards edges. |
- auto live_in = live_in_sets()[succ.ToSize()]; |
- if (live_in != nullptr) live_out->Union(*live_in); |
- |
- // All phi input operands corresponding to this successor edge are live |
- // out from this block. |
- auto successor = code()->InstructionBlockAt(succ); |
- size_t index = successor->PredecessorIndexOf(block->rpo_number()); |
- DCHECK(index < successor->PredecessorCount()); |
- for (auto phi : successor->phis()) { |
- live_out->Add(phi->operands()[index]); |
- } |
- } |
- return live_out; |
-} |
- |
- |
-void LiveRangeBuilder::AddInitialIntervals(const InstructionBlock* block, |
- BitVector* live_out) { |
- // Add an interval that includes the entire block to the live range for |
- // each live_out value. |
- auto start = LifetimePosition::GapFromInstructionIndex( |
- block->first_instruction_index()); |
- auto end = LifetimePosition::InstructionFromInstructionIndex( |
- block->last_instruction_index()).NextStart(); |
- BitVector::Iterator iterator(live_out); |
- while (!iterator.Done()) { |
- int operand_index = iterator.Current(); |
- auto range = LiveRangeFor(operand_index); |
- range->AddUseInterval(start, end, allocation_zone()); |
- iterator.Advance(); |
- } |
-} |
- |
- |
-Instruction* LiveRangeBuilder::GetLastInstruction( |
- const InstructionBlock* block) { |
- return code()->InstructionAt(block->last_instruction_index()); |
-} |
- |
- |
-int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) { |
- return -index - 1 - config()->num_general_registers(); |
-} |
- |
- |
-InstructionOperand* LiveRangeBuilder::AllocateFixed(UnallocatedOperand* operand, |
- int pos, bool is_tagged) { |
+InstructionOperand* ConstraintBuilder::AllocateFixed( |
+ UnallocatedOperand* operand, int pos, bool is_tagged) { |
TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
DCHECK(operand->HasFixedPolicy()); |
InstructionOperand allocated; |
@@ -921,87 +871,14 @@ InstructionOperand* LiveRangeBuilder::AllocateFixed(UnallocatedOperand* operand, |
} |
-LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
- DCHECK(index < config()->num_general_registers()); |
- auto result = fixed_live_ranges()[index]; |
- if (result == nullptr) { |
- result = data()->NewLiveRange(FixedLiveRangeID(index)); |
- DCHECK(result->IsFixed()); |
- result->set_kind(GENERAL_REGISTERS); |
- data()->SetLiveRangeAssignedRegister(result, index); |
- fixed_live_ranges()[index] = result; |
- } |
- return result; |
-} |
- |
- |
-LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
- DCHECK(index < config()->num_aliased_double_registers()); |
- auto result = fixed_double_live_ranges()[index]; |
- if (result == nullptr) { |
- result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); |
- DCHECK(result->IsFixed()); |
- result->set_kind(DOUBLE_REGISTERS); |
- data()->SetLiveRangeAssignedRegister(result, index); |
- fixed_double_live_ranges()[index] = result; |
- } |
- return result; |
-} |
- |
- |
-LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
- if (operand->IsUnallocated()) { |
- return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
- } else if (operand->IsConstant()) { |
- return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); |
- } else if (operand->IsRegister()) { |
- return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); |
- } else if (operand->IsDoubleRegister()) { |
- return FixedDoubleLiveRangeFor( |
- DoubleRegisterOperand::cast(operand)->index()); |
- } else { |
- return nullptr; |
- } |
-} |
- |
- |
-void LiveRangeBuilder::Define(LifetimePosition position, |
- InstructionOperand* operand, |
- InstructionOperand* hint) { |
- auto range = LiveRangeFor(operand); |
- if (range == nullptr) return; |
- |
- if (range->IsEmpty() || range->Start().Value() > position.Value()) { |
- // Can happen if there is a definition without use. |
- range->AddUseInterval(position, position.NextStart(), allocation_zone()); |
- range->AddUsePosition(position.NextStart(), nullptr, nullptr, |
- allocation_zone()); |
- } else { |
- range->ShortenTo(position); |
- } |
- |
- if (operand->IsUnallocated()) { |
- auto unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
- } |
-} |
- |
- |
-void LiveRangeBuilder::Use(LifetimePosition block_start, |
- LifetimePosition position, |
- InstructionOperand* operand, |
- InstructionOperand* hint) { |
- auto range = LiveRangeFor(operand); |
- if (range == nullptr) return; |
- if (operand->IsUnallocated()) { |
- UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
+void ConstraintBuilder::MeetRegisterConstraints() { |
+ for (auto block : code()->instruction_blocks()) { |
+ MeetRegisterConstraints(block); |
} |
- range->AddUseInterval(block_start, position, allocation_zone()); |
} |
-void LiveRangeBuilder::MeetRegisterConstraints(const InstructionBlock* block) { |
+void ConstraintBuilder::MeetRegisterConstraints(const InstructionBlock* block) { |
int start = block->first_instruction_index(); |
int end = block->last_instruction_index(); |
DCHECK_NE(-1, start); |
@@ -1014,7 +891,7 @@ void LiveRangeBuilder::MeetRegisterConstraints(const InstructionBlock* block) { |
} |
-void LiveRangeBuilder::MeetRegisterConstraintsForLastInstructionInBlock( |
+void ConstraintBuilder::MeetRegisterConstraintsForLastInstructionInBlock( |
const InstructionBlock* block) { |
int end = block->last_instruction_index(); |
auto last_instruction = InstructionAt(end); |
@@ -1060,7 +937,7 @@ void LiveRangeBuilder::MeetRegisterConstraintsForLastInstructionInBlock( |
} |
-void LiveRangeBuilder::MeetConstraintsAfter(int instr_index) { |
+void ConstraintBuilder::MeetConstraintsAfter(int instr_index) { |
auto first = InstructionAt(instr_index); |
// Handle fixed temporaries. |
for (size_t i = 0; i < first->TempCount(); i++) { |
@@ -1108,7 +985,7 @@ void LiveRangeBuilder::MeetConstraintsAfter(int instr_index) { |
} |
-void LiveRangeBuilder::MeetConstraintsBefore(int instr_index) { |
+void ConstraintBuilder::MeetConstraintsBefore(int instr_index) { |
auto second = InstructionAt(instr_index); |
// Handle fixed input operands of second instruction. |
for (size_t i = 0; i < second->InputCount(); i++) { |
@@ -1153,6 +1030,177 @@ void LiveRangeBuilder::MeetConstraintsBefore(int instr_index) { |
} |
+void ConstraintBuilder::ResolvePhis() { |
+ // Process the blocks in reverse order. |
+ for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) { |
+ ResolvePhis(block); |
+ } |
+} |
+ |
+ |
+void ConstraintBuilder::ResolvePhis(const InstructionBlock* block) { |
+ for (auto phi : block->phis()) { |
+ int phi_vreg = phi->virtual_register(); |
+ auto map_value = new (allocation_zone()) |
+ RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
+ auto res = data()->phi_map().insert(std::make_pair(phi_vreg, map_value)); |
+ DCHECK(res.second); |
+ USE(res); |
+ auto& output = phi->output(); |
+ for (size_t i = 0; i < phi->operands().size(); ++i) { |
+ InstructionBlock* cur_block = |
+ code()->InstructionBlockAt(block->predecessors()[i]); |
+ UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); |
+ auto move = data()->AddGapMove(cur_block->last_instruction_index(), |
+ Instruction::END, input, output); |
+ map_value->incoming_moves.push_back(move); |
+ DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
+ ->HasReferenceMap()); |
+ } |
+ auto live_range = LiveRangeFor(phi_vreg); |
+ int gap_index = block->first_instruction_index(); |
+ live_range->SpillAtDefinition(allocation_zone(), gap_index, &output); |
+ live_range->SetSpillStartIndex(gap_index); |
+ // We use the phi-ness of some nodes in some later heuristics. |
+ live_range->set_is_phi(true); |
+ live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
+ } |
+} |
+ |
+ |
+LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data) |
+ : data_(data) {} |
+ |
+ |
+BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { |
+ // Compute live out for the given block, except not including backward |
+ // successor edges. |
+ auto live_out = new (allocation_zone()) |
+ BitVector(code()->VirtualRegisterCount(), allocation_zone()); |
+ |
+ // Process all successor blocks. |
+ for (auto succ : block->successors()) { |
+ // Add values live on entry to the successor. Note the successor's |
+ // live_in will not be computed yet for backwards edges. |
+ auto live_in = live_in_sets()[succ.ToSize()]; |
+ if (live_in != nullptr) live_out->Union(*live_in); |
+ |
+ // All phi input operands corresponding to this successor edge are live |
+ // out from this block. |
+ auto successor = code()->InstructionBlockAt(succ); |
+ size_t index = successor->PredecessorIndexOf(block->rpo_number()); |
+ DCHECK(index < successor->PredecessorCount()); |
+ for (auto phi : successor->phis()) { |
+ live_out->Add(phi->operands()[index]); |
+ } |
+ } |
+ return live_out; |
+} |
+ |
+ |
+void LiveRangeBuilder::AddInitialIntervals(const InstructionBlock* block, |
+ BitVector* live_out) { |
+ // Add an interval that includes the entire block to the live range for |
+ // each live_out value. |
+ auto start = LifetimePosition::GapFromInstructionIndex( |
+ block->first_instruction_index()); |
+ auto end = LifetimePosition::InstructionFromInstructionIndex( |
+ block->last_instruction_index()).NextStart(); |
+ BitVector::Iterator iterator(live_out); |
+ while (!iterator.Done()) { |
+ int operand_index = iterator.Current(); |
+ auto range = LiveRangeFor(operand_index); |
+ range->AddUseInterval(start, end, allocation_zone()); |
+ iterator.Advance(); |
+ } |
+} |
+ |
+ |
+int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) { |
+ return -index - 1 - config()->num_general_registers(); |
+} |
+ |
+ |
+LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
+ DCHECK(index < config()->num_general_registers()); |
+ auto result = data()->fixed_live_ranges()[index]; |
+ if (result == nullptr) { |
+ result = data()->NewLiveRange(FixedLiveRangeID(index)); |
+ DCHECK(result->IsFixed()); |
+ result->set_kind(GENERAL_REGISTERS); |
+ data()->SetLiveRangeAssignedRegister(result, index); |
+ data()->fixed_live_ranges()[index] = result; |
+ } |
+ return result; |
+} |
+ |
+ |
+LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
+ DCHECK(index < config()->num_aliased_double_registers()); |
+ auto result = data()->fixed_double_live_ranges()[index]; |
+ if (result == nullptr) { |
+ result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); |
+ DCHECK(result->IsFixed()); |
+ result->set_kind(DOUBLE_REGISTERS); |
+ data()->SetLiveRangeAssignedRegister(result, index); |
+ data()->fixed_double_live_ranges()[index] = result; |
+ } |
+ return result; |
+} |
+ |
+ |
+LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
+ if (operand->IsUnallocated()) { |
+ return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
+ } else if (operand->IsConstant()) { |
+ return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); |
+ } else if (operand->IsRegister()) { |
+ return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); |
+ } else if (operand->IsDoubleRegister()) { |
+ return FixedDoubleLiveRangeFor( |
+ DoubleRegisterOperand::cast(operand)->index()); |
+ } else { |
+ return nullptr; |
+ } |
+} |
+ |
+ |
+void LiveRangeBuilder::Define(LifetimePosition position, |
+ InstructionOperand* operand, |
+ InstructionOperand* hint) { |
+ auto range = LiveRangeFor(operand); |
+ if (range == nullptr) return; |
+ |
+ if (range->IsEmpty() || range->Start().Value() > position.Value()) { |
+ // Can happen if there is a definition without use. |
+ range->AddUseInterval(position, position.NextStart(), allocation_zone()); |
+ range->AddUsePosition(position.NextStart(), nullptr, nullptr, |
+ allocation_zone()); |
+ } else { |
+ range->ShortenTo(position); |
+ } |
+ |
+ if (operand->IsUnallocated()) { |
+ auto unalloc_operand = UnallocatedOperand::cast(operand); |
+ range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
+ } |
+} |
+ |
+ |
+void LiveRangeBuilder::Use(LifetimePosition block_start, |
+ LifetimePosition position, |
+ InstructionOperand* operand, |
+ InstructionOperand* hint) { |
+ auto range = LiveRangeFor(operand); |
+ if (range == nullptr) return; |
+ if (operand->IsUnallocated()) { |
+ UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
+ range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
+ } |
+ range->AddUseInterval(block_start, position, allocation_zone()); |
+} |
+ |
+ |
bool LiveRangeBuilder::IsOutputRegisterOf(Instruction* instr, int index) { |
for (size_t i = 0; i < instr->OutputCount(); i++) { |
auto output = instr->OutputAt(i); |
@@ -1184,7 +1232,7 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
index--) { |
auto curr_position = |
LifetimePosition::InstructionFromInstructionIndex(index); |
- auto instr = InstructionAt(index); |
+ auto instr = code()->InstructionAt(index); |
DCHECK(instr != nullptr); |
DCHECK(curr_position.IsInstructionPosition()); |
// Process output, inputs, and temps of this instruction. |
@@ -1308,51 +1356,6 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
} |
-void LiveRangeBuilder::ResolvePhis(const InstructionBlock* block) { |
- for (auto phi : block->phis()) { |
- int phi_vreg = phi->virtual_register(); |
- auto map_value = new (allocation_zone()) |
- RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
- auto res = phi_map().insert(std::make_pair(phi_vreg, map_value)); |
- DCHECK(res.second); |
- USE(res); |
- auto& output = phi->output(); |
- for (size_t i = 0; i < phi->operands().size(); ++i) { |
- InstructionBlock* cur_block = |
- code()->InstructionBlockAt(block->predecessors()[i]); |
- UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); |
- auto move = data()->AddGapMove(cur_block->last_instruction_index(), |
- Instruction::END, input, output); |
- map_value->incoming_moves.push_back(move); |
- DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
- ->HasReferenceMap()); |
- } |
- auto live_range = LiveRangeFor(phi_vreg); |
- int gap_index = block->first_instruction_index(); |
- live_range->SpillAtDefinition(allocation_zone(), gap_index, &output); |
- live_range->SetSpillStartIndex(gap_index); |
- // We use the phi-ness of some nodes in some later heuristics. |
- live_range->set_is_phi(true); |
- live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
- } |
-} |
- |
- |
-void LiveRangeBuilder::MeetRegisterConstraints() { |
- for (auto block : code()->instruction_blocks()) { |
- MeetRegisterConstraints(block); |
- } |
-} |
- |
- |
-void LiveRangeBuilder::ResolvePhis() { |
- // Process the blocks in reverse order. |
- for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) { |
- ResolvePhis(block); |
- } |
-} |
- |
- |
void LiveRangeBuilder::BuildLiveRanges() { |
// Process the blocks in reverse order. |
for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; |
@@ -1374,7 +1377,7 @@ void LiveRangeBuilder::BuildLiveRanges() { |
live->Remove(phi_vreg); |
InstructionOperand* hint = nullptr; |
auto instr = GetLastInstruction( |
- code()->InstructionBlockAt(block->predecessors()[0])); |
+ code(), code()->InstructionBlockAt(block->predecessors()[0])); |
for (auto move : *instr->GetParallelMove(Instruction::END)) { |
auto& to = move->destination(); |
if (to.IsUnallocated() && |
@@ -1415,7 +1418,7 @@ void LiveRangeBuilder::BuildLiveRanges() { |
} |
} |
- for (auto range : live_ranges()) { |
+ for (auto range : data()->live_ranges()) { |
if (range == nullptr) continue; |
range->set_kind(RequiredRegisterKind(range->id())); |
// Give slots to all ranges with a non fixed slot use. |
@@ -1474,14 +1477,16 @@ LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, |
// TryAllocateFreeReg and AllocateBlockedReg assume this |
// when allocating local arrays. |
DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= |
- config()->num_general_registers()); |
+ this->data()->config()->num_general_registers()); |
} |
void LinearScanAllocator::AllocateRegisters() { |
DCHECK(unhandled_live_ranges().empty()); |
+ DCHECK(active_live_ranges().empty()); |
+ DCHECK(inactive_live_ranges().empty()); |
- for (auto range : live_ranges()) { |
+ for (auto range : data()->live_ranges()) { |
if (range == nullptr) continue; |
if (range->Kind() == mode_) { |
AddToUnhandledUnsorted(range); |
@@ -1490,9 +1495,6 @@ void LinearScanAllocator::AllocateRegisters() { |
SortUnhandled(); |
DCHECK(UnhandledIsSorted()); |
- DCHECK(active_live_ranges().empty()); |
- DCHECK(inactive_live_ranges().empty()); |
- |
auto& fixed_ranges = GetFixedRegisters(data(), mode_); |
for (auto current : fixed_ranges) { |
if (current != nullptr) { |
@@ -1565,17 +1567,14 @@ void LinearScanAllocator::AllocateRegisters() { |
AddToActive(current); |
} |
} |
- |
- active_live_ranges().clear(); |
- inactive_live_ranges().clear(); |
} |
const char* LinearScanAllocator::RegisterName(int allocation_index) const { |
if (mode_ == GENERAL_REGISTERS) { |
- return config()->general_register_name(allocation_index); |
+ return data()->config()->general_register_name(allocation_index); |
} else { |
- return config()->double_register_name(allocation_index); |
+ return data()->config()->double_register_name(allocation_index); |
} |
} |
@@ -1910,8 +1909,8 @@ bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) { |
if (range->IsChild() || !range->is_phi()) return false; |
DCHECK(!range->HasSpillOperand()); |
- auto lookup = phi_map().find(range->id()); |
- DCHECK(lookup != phi_map().end()); |
+ auto lookup = data()->phi_map().find(range->id()); |
+ DCHECK(lookup != data()->phi_map().end()); |
auto phi = lookup->second->phi; |
auto block = lookup->second->block; |
// Count the number of spilled operands. |
@@ -2190,7 +2189,7 @@ void ReferenceMapPopulator::PopulateReferenceMaps() { |
// Iterate over the first parts of multi-part live ranges. |
if (range->IsChild()) continue; |
// Skip non-reference values. |
- if (!IsReference(range->id())) continue; |
+ if (!data()->IsReference(range->id())) continue; |
// Skip empty live ranges. |
if (range->IsEmpty()) continue; |
@@ -2444,7 +2443,7 @@ void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, |
position = Instruction::START; |
} else { |
DCHECK(pred->SuccessorCount() == 1); |
- DCHECK(!data() |
+ DCHECK(!code() |
->InstructionAt(pred->last_instruction_index()) |
->HasReferenceMap()); |
gap_index = pred->last_instruction_index(); |