Index: src/compiler/register-allocator.cc |
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc |
index 20fae0cbce1b29d80300854ac7db34143ac4dfb1..a0cdec1cd71218584eeafff3b888fecaabe25711 100644 |
--- a/src/compiler/register-allocator.cc |
+++ b/src/compiler/register-allocator.cc |
@@ -169,8 +169,8 @@ void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
auto zone = sequence->zone(); |
for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
to_spill = to_spill->next) { |
- auto gap = sequence->GapAt(to_spill->gap_index); |
- auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone); |
+ auto instr = sequence->InstructionAt(to_spill->gap_index); |
+ auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); |
// Skip insertion if it's possible that the move exists already as a |
// constraint move from a fixed output register to a slot. |
if (might_be_duplicated) { |
@@ -264,8 +264,7 @@ bool LiveRange::CanBeSpilled(LifetimePosition pos) { |
// at the current or the immediate next position. |
auto use_pos = NextRegisterPosition(pos); |
if (use_pos == nullptr) return true; |
- return use_pos->pos().Value() > |
- pos.NextInstruction().InstructionEnd().Value(); |
+ return use_pos->pos().Value() > pos.NextStart().End().Value(); |
} |
@@ -685,10 +684,10 @@ void RegisterAllocator::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::FromInstructionIndex(block->first_instruction_index()); |
- auto end = LifetimePosition::FromInstructionIndex( |
- block->last_instruction_index()).NextInstruction(); |
+ 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(); |
@@ -780,15 +779,17 @@ LiveRange* RegisterAllocator::LiveRangeFor(int index) { |
} |
-GapInstruction* RegisterAllocator::GetLastGap(const InstructionBlock* block) { |
- int last_instruction = block->last_instruction_index(); |
- return code()->GapAt(last_instruction - 1); |
+Instruction* RegisterAllocator::GetLastInstruction( |
+ const InstructionBlock* block) { |
+ return code()->InstructionAt(block->last_instruction_index()); |
} |
LiveRange* RegisterAllocator::LiveRangeFor(InstructionOperand* operand) { |
if (operand->IsUnallocated()) { |
return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
+ } else if (operand->IsConstant()) { |
+ return LiveRangeFor(ConstantOperand::cast(operand)->index()); |
} else if (operand->IsRegister()) { |
return FixedLiveRangeFor(operand->index()); |
} else if (operand->IsDoubleRegister()) { |
@@ -807,9 +808,8 @@ 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(), local_zone()); |
- range->AddUsePosition(position.NextInstruction(), nullptr, nullptr, |
- local_zone()); |
+ range->AddUseInterval(position, position.NextStart(), local_zone()); |
+ range->AddUsePosition(position.NextStart(), nullptr, nullptr, local_zone()); |
} else { |
range->ShortenTo(position); |
} |
@@ -835,12 +835,11 @@ void RegisterAllocator::Use(LifetimePosition block_start, |
} |
-void RegisterAllocator::AddGapMove(int index, |
- GapInstruction::InnerPosition position, |
+void RegisterAllocator::AddGapMove(int index, Instruction::GapPosition position, |
InstructionOperand* from, |
InstructionOperand* to) { |
- auto gap = code()->GapAt(index); |
- auto move = gap->GetOrCreateParallelMove(position, code_zone()); |
+ auto instr = code()->InstructionAt(index); |
+ auto move = instr->GetOrCreateParallelMove(position, code_zone()); |
move->AddMove(from, to, code_zone()); |
} |
@@ -1024,8 +1023,8 @@ bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
LiveRange* op_range = LiveRangeFor(op); |
if (op_range->GetSpillRange() == nullptr) continue; |
auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
- auto pred_end = |
- LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
+ auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
+ pred->last_instruction_index()); |
while (op_range != nullptr && !op_range->CanCover(pred_end)) { |
op_range = op_range->next(); |
} |
@@ -1068,9 +1067,7 @@ bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
// If the range does not need register soon, spill it to the merged |
// spill range. |
auto next_pos = range->Start(); |
- if (code()->IsGapAt(next_pos.InstructionIndex())) { |
- next_pos = next_pos.NextInstruction(); |
- } |
+ if (next_pos.IsGapPosition()) next_pos = next_pos.NextStart(); |
auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
if (pos == nullptr) { |
auto spill_range = range->TopLevel()->HasSpillRange() |
@@ -1079,7 +1076,7 @@ bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
CHECK(first_op_spill->TryMerge(spill_range)); |
Spill(range); |
return true; |
- } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { |
+ } else if (pos->pos().Value() > range->Start().NextStart().Value()) { |
auto spill_range = range->TopLevel()->HasSpillRange() |
? range->TopLevel()->GetSpillRange() |
: AssignSpillRangeToLiveRange(range->TopLevel()); |
@@ -1097,19 +1094,11 @@ void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { |
int end = block->last_instruction_index(); |
DCHECK_NE(-1, start); |
for (int i = start; i <= end; ++i) { |
- if (code()->IsGapAt(i)) { |
- Instruction* instr = nullptr; |
- Instruction* prev_instr = nullptr; |
- if (i < end) instr = InstructionAt(i + 1); |
- if (i > start) prev_instr = InstructionAt(i - 1); |
- MeetConstraintsBetween(prev_instr, instr, i); |
- } |
+ MeetConstraintsBefore(i); |
+ if (i != end) MeetConstraintsAfter(i); |
} |
- |
// Meet register constraints for the instruction in the end. |
- if (!code()->IsGapAt(end)) { |
- MeetRegisterConstraintsForLastInstructionInBlock(block); |
- } |
+ MeetRegisterConstraintsForLastInstructionInBlock(block); |
} |
@@ -1138,14 +1127,12 @@ void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock( |
const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
DCHECK(successor->PredecessorCount() == 1); |
int gap_index = successor->first_instruction_index(); |
- DCHECK(code()->IsGapAt(gap_index)); |
- |
// Create an unconstrained operand for the same virtual register |
// and insert a gap move from the fixed output to the operand. |
UnallocatedOperand* output_copy = |
UnallocatedOperand(UnallocatedOperand::ANY, output_vreg) |
.Copy(code_zone()); |
- AddGapMove(gap_index, GapInstruction::START, output, output_copy); |
+ AddGapMove(gap_index, Instruction::START, output, output_copy); |
} |
} |
@@ -1162,101 +1149,90 @@ void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock( |
} |
-void RegisterAllocator::MeetConstraintsBetween(Instruction* first, |
- Instruction* second, |
- int gap_index) { |
- if (first != nullptr) { |
- // Handle fixed temporaries. |
- for (size_t i = 0; i < first->TempCount(); i++) { |
- auto temp = UnallocatedOperand::cast(first->TempAt(i)); |
- if (temp->HasFixedPolicy()) { |
- AllocateFixed(temp, gap_index - 1, false); |
- } |
- } |
- |
- // Handle constant/fixed output operands. |
- for (size_t i = 0; i < first->OutputCount(); i++) { |
- InstructionOperand* output = first->OutputAt(i); |
- if (output->IsConstant()) { |
- int output_vreg = output->index(); |
- auto range = LiveRangeFor(output_vreg); |
- range->SetSpillStartIndex(gap_index - 1); |
- range->SetSpillOperand(output); |
- } else { |
- auto first_output = UnallocatedOperand::cast(output); |
- auto range = LiveRangeFor(first_output->virtual_register()); |
- bool assigned = false; |
- if (first_output->HasFixedPolicy()) { |
- auto output_copy = first_output->CopyUnconstrained(code_zone()); |
- bool is_tagged = HasTaggedValue(first_output->virtual_register()); |
- AllocateFixed(first_output, gap_index, is_tagged); |
- |
- // This value is produced on the stack, we never need to spill it. |
- if (first_output->IsStackSlot()) { |
- DCHECK(first_output->index() < frame_->GetSpillSlotCount()); |
- range->SetSpillOperand(first_output); |
- range->SetSpillStartIndex(gap_index - 1); |
- assigned = true; |
- } |
- AddGapMove(gap_index, GapInstruction::START, first_output, |
- output_copy); |
- } |
- |
- // Make sure we add a gap move for spilling (if we have not done |
- // so already). |
- if (!assigned) { |
- range->SpillAtDefinition(local_zone(), gap_index, first_output); |
- range->SetSpillStartIndex(gap_index); |
- } |
- } |
- } |
+void RegisterAllocator::MeetConstraintsAfter(int instr_index) { |
+ auto first = InstructionAt(instr_index); |
+ // Handle fixed temporaries. |
+ for (size_t i = 0; i < first->TempCount(); i++) { |
+ auto temp = UnallocatedOperand::cast(first->TempAt(i)); |
+ if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); |
} |
+ // Handle constant/fixed output operands. |
+ for (size_t i = 0; i < first->OutputCount(); i++) { |
+ InstructionOperand* output = first->OutputAt(i); |
+ if (output->IsConstant()) { |
+ int output_vreg = output->index(); |
+ auto range = LiveRangeFor(output_vreg); |
+ range->SetSpillStartIndex(instr_index + 1); |
+ range->SetSpillOperand(output); |
+ continue; |
+ } |
+ auto first_output = UnallocatedOperand::cast(output); |
+ auto range = LiveRangeFor(first_output->virtual_register()); |
+ bool assigned = false; |
+ if (first_output->HasFixedPolicy()) { |
+ auto output_copy = first_output->CopyUnconstrained(code_zone()); |
+ bool is_tagged = HasTaggedValue(first_output->virtual_register()); |
+ AllocateFixed(first_output, instr_index, is_tagged); |
- if (second != nullptr) { |
- // Handle fixed input operands of second instruction. |
- for (size_t i = 0; i < second->InputCount(); i++) { |
- auto input = second->InputAt(i); |
- if (input->IsImmediate()) continue; // Ignore immediates. |
- auto cur_input = UnallocatedOperand::cast(input); |
- if (cur_input->HasFixedPolicy()) { |
- auto input_copy = cur_input->CopyUnconstrained(code_zone()); |
- bool is_tagged = HasTaggedValue(cur_input->virtual_register()); |
- AllocateFixed(cur_input, gap_index + 1, is_tagged); |
- AddGapMove(gap_index, GapInstruction::END, input_copy, cur_input); |
+ // This value is produced on the stack, we never need to spill it. |
+ if (first_output->IsStackSlot()) { |
+ DCHECK(first_output->index() < frame_->GetSpillSlotCount()); |
+ range->SetSpillOperand(first_output); |
+ range->SetSpillStartIndex(instr_index + 1); |
+ assigned = true; |
} |
+ AddGapMove(instr_index + 1, Instruction::START, first_output, |
+ output_copy); |
} |
- |
- // Handle "output same as input" for second instruction. |
- for (size_t i = 0; i < second->OutputCount(); i++) { |
- auto output = second->OutputAt(i); |
- if (!output->IsUnallocated()) continue; |
- auto second_output = UnallocatedOperand::cast(output); |
- if (second_output->HasSameAsInputPolicy()) { |
- DCHECK(i == 0); // Only valid for first output. |
- UnallocatedOperand* cur_input = |
- UnallocatedOperand::cast(second->InputAt(0)); |
- int output_vreg = second_output->virtual_register(); |
- int input_vreg = cur_input->virtual_register(); |
- |
- auto input_copy = cur_input->CopyUnconstrained(code_zone()); |
- cur_input->set_virtual_register(second_output->virtual_register()); |
- AddGapMove(gap_index, GapInstruction::END, input_copy, cur_input); |
- |
- if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) { |
- int index = gap_index + 1; |
- Instruction* instr = InstructionAt(index); |
- if (instr->HasPointerMap()) { |
- instr->pointer_map()->RecordPointer(input_copy, code_zone()); |
- } |
- } else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) { |
- // The input is assumed to immediately have a tagged representation, |
- // before the pointer map can be used. I.e. the pointer map at the |
- // instruction will include the output operand (whose value at the |
- // beginning of the instruction is equal to the input operand). If |
- // this is not desired, then the pointer map at this instruction needs |
- // to be adjusted manually. |
- } |
+ // Make sure we add a gap move for spilling (if we have not done |
+ // so already). |
+ if (!assigned) { |
+ range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); |
+ range->SetSpillStartIndex(instr_index + 1); |
+ } |
+ } |
+} |
+ |
+ |
+void RegisterAllocator::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++) { |
+ auto input = second->InputAt(i); |
+ if (input->IsImmediate()) continue; // Ignore immediates. |
+ auto cur_input = UnallocatedOperand::cast(input); |
+ if (cur_input->HasFixedPolicy()) { |
+ auto input_copy = cur_input->CopyUnconstrained(code_zone()); |
+ bool is_tagged = HasTaggedValue(cur_input->virtual_register()); |
+ AllocateFixed(cur_input, instr_index, is_tagged); |
+ AddGapMove(instr_index, Instruction::END, input_copy, cur_input); |
+ } |
+ } |
+ // Handle "output same as input" for second instruction. |
+ for (size_t i = 0; i < second->OutputCount(); i++) { |
+ auto output = second->OutputAt(i); |
+ if (!output->IsUnallocated()) continue; |
+ auto second_output = UnallocatedOperand::cast(output); |
+ if (!second_output->HasSameAsInputPolicy()) continue; |
+ DCHECK(i == 0); // Only valid for first output. |
+ UnallocatedOperand* cur_input = |
+ UnallocatedOperand::cast(second->InputAt(0)); |
+ int output_vreg = second_output->virtual_register(); |
+ int input_vreg = cur_input->virtual_register(); |
+ auto input_copy = cur_input->CopyUnconstrained(code_zone()); |
+ cur_input->set_virtual_register(second_output->virtual_register()); |
+ AddGapMove(instr_index, Instruction::END, input_copy, cur_input); |
+ if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) { |
+ if (second->HasPointerMap()) { |
+ second->pointer_map()->RecordPointer(input_copy, code_zone()); |
} |
+ } else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) { |
+ // The input is assumed to immediately have a tagged representation, |
+ // before the pointer map can be used. I.e. the pointer map at the |
+ // instruction will include the output operand (whose value at the |
+ // beginning of the instruction is equal to the input operand). If |
+ // this is not desired, then the pointer map at this instruction needs |
+ // to be adjusted manually. |
} |
} |
} |
@@ -1285,132 +1261,132 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, |
BitVector* live) { |
int block_start = block->first_instruction_index(); |
auto block_start_position = |
- LifetimePosition::FromInstructionIndex(block_start); |
+ LifetimePosition::GapFromInstructionIndex(block_start); |
for (int index = block->last_instruction_index(); index >= block_start; |
index--) { |
- auto curr_position = LifetimePosition::FromInstructionIndex(index); |
+ auto curr_position = |
+ LifetimePosition::InstructionFromInstructionIndex(index); |
auto instr = InstructionAt(index); |
DCHECK(instr != nullptr); |
- if (instr->IsGapMoves()) { |
- // Process the moves of the gap instruction, making their sources live. |
- auto gap = code()->GapAt(index); |
- const GapInstruction::InnerPosition kPositions[] = { |
- GapInstruction::END, GapInstruction::START}; |
- for (auto position : kPositions) { |
- auto move = gap->GetParallelMove(position); |
- if (move == nullptr) continue; |
- if (position == GapInstruction::END) { |
- curr_position = curr_position.InstructionEnd(); |
- } else { |
- curr_position = curr_position.InstructionStart(); |
- } |
- auto move_ops = move->move_operands(); |
- for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) { |
- auto from = cur->source(); |
- auto to = cur->destination(); |
- auto hint = to; |
- if (to->IsUnallocated()) { |
- int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
- auto to_range = LiveRangeFor(to_vreg); |
- if (to_range->is_phi()) { |
- DCHECK(!FLAG_turbo_delay_ssa_decon); |
- if (to_range->is_non_loop_phi()) { |
- hint = to_range->current_hint_operand(); |
- } |
- } else { |
- if (live->Contains(to_vreg)) { |
- Define(curr_position, to, from); |
- live->Remove(to_vreg); |
- } else { |
- cur->Eliminate(); |
- continue; |
- } |
- } |
- } else { |
- Define(curr_position, to, from); |
- } |
- Use(block_start_position, curr_position, from, hint); |
- if (from->IsUnallocated()) { |
- live->Add(UnallocatedOperand::cast(from)->virtual_register()); |
- } |
- } |
+ DCHECK(curr_position.IsInstructionPosition()); |
+ // Process output, inputs, and temps of this instruction. |
+ for (size_t i = 0; i < instr->OutputCount(); i++) { |
+ auto output = instr->OutputAt(i); |
+ if (output->IsUnallocated()) { |
+ // Unsupported. |
+ DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); |
+ int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); |
+ live->Remove(out_vreg); |
+ } else if (output->IsConstant()) { |
+ int out_vreg = output->index(); |
+ live->Remove(out_vreg); |
} |
- } else { |
- // Process output, inputs, and temps of this non-gap instruction. |
- for (size_t i = 0; i < instr->OutputCount(); i++) { |
- auto output = instr->OutputAt(i); |
- if (output->IsUnallocated()) { |
- // Unsupported. |
- DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); |
- int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); |
- live->Remove(out_vreg); |
- } else if (output->IsConstant()) { |
- int out_vreg = output->index(); |
- live->Remove(out_vreg); |
+ Define(curr_position, output, nullptr); |
+ } |
+ |
+ if (instr->ClobbersRegisters()) { |
+ for (int i = 0; i < config()->num_general_registers(); ++i) { |
+ if (!IsOutputRegisterOf(instr, i)) { |
+ auto range = FixedLiveRangeFor(i); |
+ range->AddUseInterval(curr_position, curr_position.End(), |
+ local_zone()); |
} |
- Define(curr_position, output, nullptr); |
} |
+ } |
- if (instr->ClobbersRegisters()) { |
- for (int i = 0; i < config()->num_general_registers(); ++i) { |
- if (!IsOutputRegisterOf(instr, i)) { |
- auto range = FixedLiveRangeFor(i); |
- range->AddUseInterval(curr_position, curr_position.InstructionEnd(), |
- local_zone()); |
- } |
+ if (instr->ClobbersDoubleRegisters()) { |
+ for (int i = 0; i < config()->num_aliased_double_registers(); ++i) { |
+ if (!IsOutputDoubleRegisterOf(instr, i)) { |
+ auto range = FixedDoubleLiveRangeFor(i); |
+ range->AddUseInterval(curr_position, curr_position.End(), |
+ local_zone()); |
} |
} |
+ } |
- if (instr->ClobbersDoubleRegisters()) { |
- for (int i = 0; i < config()->num_aliased_double_registers(); ++i) { |
- if (!IsOutputDoubleRegisterOf(instr, i)) { |
- auto range = FixedDoubleLiveRangeFor(i); |
- range->AddUseInterval(curr_position, curr_position.InstructionEnd(), |
- local_zone()); |
- } |
- } |
+ for (size_t i = 0; i < instr->InputCount(); i++) { |
+ auto input = instr->InputAt(i); |
+ if (input->IsImmediate()) continue; // Ignore immediates. |
+ LifetimePosition use_pos; |
+ if (input->IsUnallocated() && |
+ UnallocatedOperand::cast(input)->IsUsedAtStart()) { |
+ use_pos = curr_position; |
+ } else { |
+ use_pos = curr_position.End(); |
} |
- for (size_t i = 0; i < instr->InputCount(); i++) { |
- auto input = instr->InputAt(i); |
- if (input->IsImmediate()) continue; // Ignore immediates. |
- LifetimePosition use_pos; |
- if (input->IsUnallocated() && |
- UnallocatedOperand::cast(input)->IsUsedAtStart()) { |
- use_pos = curr_position; |
- } else { |
- use_pos = curr_position.InstructionEnd(); |
+ if (input->IsUnallocated()) { |
+ UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); |
+ int vreg = unalloc->virtual_register(); |
+ live->Add(vreg); |
+ if (unalloc->HasSlotPolicy()) { |
+ LiveRangeFor(vreg)->set_has_slot_use(true); |
} |
- |
- if (input->IsUnallocated()) { |
- UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); |
- int vreg = unalloc->virtual_register(); |
- live->Add(vreg); |
- if (unalloc->HasSlotPolicy()) { |
- LiveRangeFor(vreg)->set_has_slot_use(true); |
+ } |
+ Use(block_start_position, use_pos, input, nullptr); |
+ } |
+ |
+ for (size_t i = 0; i < instr->TempCount(); i++) { |
+ auto temp = instr->TempAt(i); |
+ // Unsupported. |
+ DCHECK_IMPLIES(temp->IsUnallocated(), |
+ !UnallocatedOperand::cast(temp)->HasSlotPolicy()); |
+ if (instr->ClobbersTemps()) { |
+ if (temp->IsRegister()) continue; |
+ if (temp->IsUnallocated()) { |
+ UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); |
+ if (temp_unalloc->HasFixedPolicy()) { |
+ continue; |
} |
} |
- Use(block_start_position, use_pos, input, nullptr); |
} |
- |
- for (size_t i = 0; i < instr->TempCount(); i++) { |
- auto temp = instr->TempAt(i); |
- // Unsupported. |
- DCHECK_IMPLIES(temp->IsUnallocated(), |
- !UnallocatedOperand::cast(temp)->HasSlotPolicy()); |
- if (instr->ClobbersTemps()) { |
- if (temp->IsRegister()) continue; |
- if (temp->IsUnallocated()) { |
- UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); |
- if (temp_unalloc->HasFixedPolicy()) { |
+ Use(block_start_position, curr_position.End(), temp, nullptr); |
+ Define(curr_position, temp, nullptr); |
+ } |
+ |
+ // Process the moves of the instruction's gaps, making their sources live. |
+ const Instruction::GapPosition kPositions[] = {Instruction::END, |
+ Instruction::START}; |
+ curr_position = curr_position.PrevStart(); |
+ DCHECK(curr_position.IsGapPosition()); |
+ for (auto position : kPositions) { |
+ auto move = instr->GetParallelMove(position); |
+ if (move == nullptr) continue; |
+ if (position == Instruction::END) { |
+ curr_position = curr_position.End(); |
+ } else { |
+ curr_position = curr_position.Start(); |
+ } |
+ auto move_ops = move->move_operands(); |
+ for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) { |
+ auto from = cur->source(); |
+ auto to = cur->destination(); |
+ auto hint = to; |
+ if (to->IsUnallocated()) { |
+ int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
+ auto to_range = LiveRangeFor(to_vreg); |
+ if (to_range->is_phi()) { |
+ DCHECK(!FLAG_turbo_delay_ssa_decon); |
+ if (to_range->is_non_loop_phi()) { |
+ hint = to_range->current_hint_operand(); |
+ } |
+ } else { |
+ if (live->Contains(to_vreg)) { |
+ Define(curr_position, to, from); |
+ live->Remove(to_vreg); |
+ } else { |
+ cur->Eliminate(); |
continue; |
} |
} |
+ } else { |
+ Define(curr_position, to, from); |
+ } |
+ Use(block_start_position, curr_position, from, hint); |
+ if (from->IsUnallocated()) { |
+ live->Add(UnallocatedOperand::cast(from)->virtual_register()); |
} |
- Use(block_start_position, curr_position.InstructionEnd(), temp, |
- nullptr); |
- Define(curr_position, temp, nullptr); |
} |
} |
} |
@@ -1429,7 +1405,7 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { |
for (size_t i = 0; i < phi->operands().size(); ++i) { |
InstructionBlock* cur_block = |
code()->InstructionBlockAt(block->predecessors()[i]); |
- AddGapMove(cur_block->last_instruction_index() - 1, GapInstruction::END, |
+ AddGapMove(cur_block->last_instruction_index(), Instruction::END, |
&phi->inputs()[i], &output); |
DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
->HasPointerMap()); |
@@ -1464,7 +1440,7 @@ void RegisterAllocator::ResolvePhis() { |
const InstructionBlock* RegisterAllocator::GetInstructionBlock( |
LifetimePosition pos) { |
- return code()->GetInstructionBlock(pos.InstructionIndex()); |
+ return code()->GetInstructionBlock(pos.ToInstructionIndex()); |
} |
@@ -1487,19 +1463,20 @@ void RegisterAllocator::ConnectRanges() { |
auto prev_operand = first_range->GetAssignedOperand(operand_cache()); |
auto cur_operand = second_range->GetAssignedOperand(operand_cache()); |
if (prev_operand->Equals(cur_operand)) continue; |
- int index = pos.InstructionIndex(); |
bool delay_insertion = false; |
- GapInstruction::InnerPosition gap_pos; |
- int gap_index = index; |
- if (code()->IsGapAt(index)) { |
- gap_pos = pos.IsInstructionStart() ? GapInstruction::START |
- : GapInstruction::END; |
+ Instruction::GapPosition gap_pos; |
+ int gap_index = pos.ToInstructionIndex(); |
+ if (pos.IsGapPosition()) { |
+ gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
} else { |
- gap_index = pos.IsInstructionStart() ? (index - 1) : (index + 1); |
- delay_insertion = gap_index < index; |
- gap_pos = delay_insertion ? GapInstruction::END : GapInstruction::START; |
+ if (pos.IsStart()) { |
+ delay_insertion = true; |
+ } else { |
+ gap_index++; |
+ } |
+ gap_pos = delay_insertion ? Instruction::END : Instruction::START; |
} |
- auto move = code()->GapAt(gap_index)->GetOrCreateParallelMove( |
+ auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( |
gap_pos, code_zone()); |
if (!delay_insertion) { |
move->AddMove(prev_operand, cur_operand, code_zone()); |
@@ -1612,24 +1589,24 @@ class LiveRangeBoundArray { |
} |
LiveRangeBound* FindPred(const InstructionBlock* pred) { |
- auto pred_end = |
- LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
+ auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
+ pred->last_instruction_index()); |
return Find(pred_end); |
} |
LiveRangeBound* FindSucc(const InstructionBlock* succ) { |
- auto succ_start = |
- LifetimePosition::FromInstructionIndex(succ->first_instruction_index()); |
+ auto succ_start = LifetimePosition::GapFromInstructionIndex( |
+ succ->first_instruction_index()); |
return Find(succ_start); |
} |
void Find(const InstructionBlock* block, const InstructionBlock* pred, |
FindResult* result) const { |
- auto pred_end = |
- LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
+ auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
+ pred->last_instruction_index()); |
auto bound = Find(pred_end); |
result->pred_cover_ = bound->range_; |
- auto cur_start = LifetimePosition::FromInstructionIndex( |
+ auto cur_start = LifetimePosition::GapFromInstructionIndex( |
block->first_instruction_index()); |
// Common case. |
if (bound->CanCover(cur_start)) { |
@@ -1735,15 +1712,15 @@ void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, |
InstructionOperand* pred_op) { |
if (pred_op->Equals(cur_op)) return; |
int gap_index; |
- GapInstruction::InnerPosition position; |
+ Instruction::GapPosition position; |
if (block->PredecessorCount() == 1) { |
gap_index = block->first_instruction_index(); |
- position = GapInstruction::START; |
+ position = Instruction::START; |
} else { |
DCHECK(pred->SuccessorCount() == 1); |
DCHECK(!InstructionAt(pred->last_instruction_index())->HasPointerMap()); |
- gap_index = pred->last_instruction_index() - 1; |
- position = GapInstruction::END; |
+ gap_index = pred->last_instruction_index(); |
+ position = Instruction::END; |
} |
AddGapMove(gap_index, position, pred_op, cur_op); |
} |
@@ -1771,10 +1748,9 @@ void RegisterAllocator::BuildLiveRanges() { |
if (!FLAG_turbo_delay_ssa_decon) { |
InstructionOperand* hint = nullptr; |
InstructionOperand* phi_operand = nullptr; |
- auto gap = |
- GetLastGap(code()->InstructionBlockAt(block->predecessors()[0])); |
- auto move = |
- gap->GetOrCreateParallelMove(GapInstruction::END, code_zone()); |
+ auto instr = GetLastInstruction( |
+ code()->InstructionBlockAt(block->predecessors()[0])); |
+ auto move = instr->GetParallelMove(Instruction::END); |
for (int j = 0; j < move->move_operands()->length(); ++j) { |
auto to = move->move_operands()->at(j).destination(); |
if (to->IsUnallocated() && |
@@ -1785,7 +1761,7 @@ void RegisterAllocator::BuildLiveRanges() { |
} |
} |
DCHECK(hint != nullptr); |
- auto block_start = LifetimePosition::FromInstructionIndex( |
+ auto block_start = LifetimePosition::GapFromInstructionIndex( |
block->first_instruction_index()); |
Define(block_start, phi_operand, hint); |
} |
@@ -1799,10 +1775,10 @@ void RegisterAllocator::BuildLiveRanges() { |
// Add a live range stretching from the first loop instruction to the last |
// for each value live on entry to the header. |
BitVector::Iterator iterator(live); |
- auto start = LifetimePosition::FromInstructionIndex( |
+ auto start = LifetimePosition::GapFromInstructionIndex( |
block->first_instruction_index()); |
- auto end = LifetimePosition::FromInstructionIndex( |
- code()->LastLoopInstructionIndex(block)).NextInstruction(); |
+ auto end = LifetimePosition::GapFromInstructionIndex( |
+ code()->LastLoopInstructionIndex(block)).NextFullStart(); |
while (!iterator.Done()) { |
int operand_index = iterator.Current(); |
auto range = LiveRangeFor(operand_index); |
@@ -1833,9 +1809,7 @@ void RegisterAllocator::BuildLiveRanges() { |
if (pos->type() == UsePositionType::kRequiresSlot) continue; |
UsePositionType new_type = UsePositionType::kAny; |
// Can't mark phis as needing a register. |
- if (!code() |
- ->InstructionAt(pos->pos().InstructionIndex()) |
- ->IsGapMoves()) { |
+ if (!pos->pos().IsGapPosition()) { |
new_type = UsePositionType::kRequiresRegister; |
} |
pos->set_type(new_type, true); |
@@ -1894,12 +1868,13 @@ void RegisterAllocator::PopulatePointerMaps() { |
if (range->IsEmpty()) continue; |
// Find the extent of the range and its children. |
- int start = range->Start().InstructionIndex(); |
+ int start = range->Start().ToInstructionIndex(); |
int end = 0; |
for (auto cur = range; cur != nullptr; cur = cur->next()) { |
auto this_end = cur->End(); |
- if (this_end.InstructionIndex() > end) end = this_end.InstructionIndex(); |
- DCHECK(cur->Start().InstructionIndex() >= start); |
+ if (this_end.ToInstructionIndex() > end) |
+ end = this_end.ToInstructionIndex(); |
+ DCHECK(cur->Start().ToInstructionIndex() >= start); |
} |
// Most of the ranges are in order, but not all. Keep an eye on when they |
@@ -1924,7 +1899,8 @@ void RegisterAllocator::PopulatePointerMaps() { |
// Advance to the next active range that covers the current |
// safe point position. |
- auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point); |
+ auto safe_point_pos = |
+ LifetimePosition::InstructionFromInstructionIndex(safe_point); |
auto cur = range; |
while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
cur = cur->next(); |
@@ -2014,8 +1990,8 @@ void RegisterAllocator::AllocateRegisters() { |
if (!current->HasNoSpillType()) { |
TRACE("Live range %d already has a spill operand\n", current->id()); |
auto next_pos = position; |
- if (code()->IsGapAt(next_pos.InstructionIndex())) { |
- next_pos = next_pos.NextInstruction(); |
+ if (next_pos.IsGapPosition()) { |
+ next_pos = next_pos.NextStart(); |
} |
auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); |
// If the range already has a spill operand and it doesn't need a |
@@ -2023,8 +1999,7 @@ void RegisterAllocator::AllocateRegisters() { |
if (pos == nullptr) { |
Spill(current); |
continue; |
- } else if (pos->pos().Value() > |
- current->Start().NextInstruction().Value()) { |
+ } else if (pos->pos().Value() > current->Start().NextStart().Value()) { |
// Do not spill live range eagerly if use position that can benefit from |
// the register is too close to the start of live range. |
SpillBetween(current, current->Start(), pos->pos()); |
@@ -2196,7 +2171,7 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) { |
for (auto cur_active : active_live_ranges()) { |
free_until_pos[cur_active->assigned_register()] = |
- LifetimePosition::FromInstructionIndex(0); |
+ LifetimePosition::GapFromInstructionIndex(0); |
} |
for (auto cur_inactive : inactive_live_ranges()) { |
@@ -2276,7 +2251,7 @@ void RegisterAllocator::AllocateBlockedReg(LiveRange* current) { |
int cur_reg = range->assigned_register(); |
if (range->IsFixed() || !range->CanBeSpilled(current->Start())) { |
block_pos[cur_reg] = use_pos[cur_reg] = |
- LifetimePosition::FromInstructionIndex(0); |
+ LifetimePosition::GapFromInstructionIndex(0); |
} else { |
auto next_use = |
range->NextUsePositionRegisterIsBeneficial(current->Start()); |
@@ -2320,8 +2295,8 @@ void RegisterAllocator::AllocateBlockedReg(LiveRange* current) { |
if (block_pos[reg].Value() < current->End().Value()) { |
// Register becomes blocked before the current range end. Split before that |
// position. |
- LiveRange* tail = SplitBetween(current, current->Start(), |
- block_pos[reg].InstructionStart()); |
+ LiveRange* tail = |
+ SplitBetween(current, current->Start(), block_pos[reg].Start()); |
AddToUnhandledSorted(tail); |
} |
@@ -2348,7 +2323,7 @@ static const InstructionBlock* GetContainingLoop( |
LifetimePosition RegisterAllocator::FindOptimalSpillingPos( |
LiveRange* range, LifetimePosition pos) { |
- auto block = GetInstructionBlock(pos.InstructionStart()); |
+ auto block = GetInstructionBlock(pos.Start()); |
auto loop_header = |
block->IsLoopHeader() ? block : GetContainingLoop(code(), block); |
@@ -2360,7 +2335,7 @@ LifetimePosition RegisterAllocator::FindOptimalSpillingPos( |
// 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::FromInstructionIndex( |
+ auto loop_start = LifetimePosition::GapFromInstructionIndex( |
loop_header->first_instruction_index()); |
if (range->Covers(loop_start)) { |
@@ -2427,9 +2402,9 @@ void RegisterAllocator::SplitAndSpillIntersecting(LiveRange* current) { |
bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) { |
- return pos.IsInstructionStart() && |
- code()->GetInstructionBlock(pos.InstructionIndex())->code_start() == |
- pos.InstructionIndex(); |
+ return pos.IsFullStart() && |
+ code()->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == |
+ pos.ToInstructionIndex(); |
} |
@@ -2442,9 +2417,9 @@ LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, |
// We can't properly connect liveranges if splitting occurred at the end |
// a block. |
- DCHECK(pos.IsInstructionStart() || |
- (code()->GetInstructionBlock(pos.InstructionIndex())) |
- ->last_instruction_index() != pos.InstructionIndex()); |
+ DCHECK(pos.IsStart() || pos.IsGapPosition() || |
+ (code()->GetInstructionBlock(pos.ToInstructionIndex())) |
+ ->last_instruction_index() != pos.ToInstructionIndex()); |
int vreg = GetVirtualRegister(); |
auto result = LiveRangeFor(vreg); |
@@ -2468,8 +2443,8 @@ LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, |
LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, |
LifetimePosition end) { |
- int start_instr = start.InstructionIndex(); |
- int end_instr = end.InstructionIndex(); |
+ int start_instr = start.ToInstructionIndex(); |
+ int end_instr = end.ToInstructionIndex(); |
DCHECK(start_instr <= end_instr); |
// We have no choice |
@@ -2497,7 +2472,7 @@ LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, |
// position unless end_block is a loop header itself. |
if (block == end_block && !end_block->IsLoopHeader()) return end; |
- return LifetimePosition::FromInstructionIndex( |
+ return LifetimePosition::GapFromInstructionIndex( |
block->first_instruction_index()); |
} |
@@ -2525,13 +2500,12 @@ void RegisterAllocator::SpillBetweenUntil(LiveRange* range, |
// The split result intersects with [start, end[. |
// Split it at position between ]start+1, end[, spill the middle part |
// and put the rest to unhandled. |
- auto third_part_end = end.PrevInstruction().InstructionEnd(); |
- if (IsBlockBoundary(end.InstructionStart())) { |
- third_part_end = end.InstructionStart(); |
+ auto third_part_end = end.PrevStart().End(); |
+ if (IsBlockBoundary(end.Start())) { |
+ third_part_end = end.Start(); |
} |
auto third_part = SplitBetween( |
- second_part, Max(second_part->Start().InstructionEnd(), until), |
- third_part_end); |
+ second_part, Max(second_part->Start().End(), until), third_part_end); |
DCHECK(third_part != second_part); |