Index: src/compiler/register-allocator.cc |
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc |
index 28007d47fa11aadc60c0781e3793d76a13d39880..966128ac7221423691e48734de1f89c6fdc8992d 100644 |
--- a/src/compiler/register-allocator.cc |
+++ b/src/compiler/register-allocator.cc |
@@ -65,12 +65,37 @@ Instruction* GetLastInstruction(InstructionSequence* code, |
return code->InstructionAt(block->last_instruction_index()); |
} |
+ |
+bool IsOutputRegisterOf(Instruction* instr, int index) { |
+ for (size_t i = 0; i < instr->OutputCount(); i++) { |
+ auto output = instr->OutputAt(i); |
+ if (output->IsRegister() && |
+ RegisterOperand::cast(output)->index() == index) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
+bool IsOutputDoubleRegisterOf(Instruction* instr, int index) { |
+ for (size_t i = 0; i < instr->OutputCount(); i++) { |
+ auto output = instr->OutputAt(i); |
+ if (output->IsDoubleRegister() && |
+ DoubleRegisterOperand::cast(output)->index() == index) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
} // namespace |
UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
- InstructionOperand* hint) |
- : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { |
+ void* hint, UsePositionHintType hint_type) |
+ : operand_(operand), hint_(hint), next_(nullptr), pos_(pos), flags_(0) { |
+ DCHECK_IMPLIES(hint == nullptr, hint_type == UsePositionHintType::kNone); |
bool register_beneficial = true; |
UsePositionType type = UsePositionType::kAny; |
if (operand_ != nullptr && operand_->IsUnallocated()) { |
@@ -84,14 +109,81 @@ UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
register_beneficial = !unalloc->HasAnyPolicy(); |
} |
} |
- flags_ = TypeField::encode(type) | |
- RegisterBeneficialField::encode(register_beneficial); |
+ flags_ = TypeField::encode(type) | HintTypeField::encode(hint_type) | |
+ RegisterBeneficialField::encode(register_beneficial) | |
+ AssignedRegisterField::encode(kUnassignedRegister); |
DCHECK(pos_.IsValid()); |
} |
bool UsePosition::HasHint() const { |
- return hint_ != nullptr && !hint_->IsUnallocated(); |
+ int hint_register; |
+ return HintRegister(&hint_register); |
+} |
+ |
+ |
+bool UsePosition::HintRegister(int* register_index) const { |
+ if (hint_ == nullptr) return false; |
+ switch (HintTypeField::decode(flags_)) { |
+ case UsePositionHintType::kNone: |
+ case UsePositionHintType::kUnresolved: |
+ return false; |
+ case UsePositionHintType::kUsePos: { |
+ auto use_pos = reinterpret_cast<UsePosition*>(hint_); |
+ int assigned_register = AssignedRegisterField::decode(use_pos->flags_); |
+ if (assigned_register == kUnassignedRegister) return false; |
+ *register_index = assigned_register; |
+ return true; |
+ } |
+ case UsePositionHintType::kOperand: { |
+ auto operand = reinterpret_cast<InstructionOperand*>(hint_); |
+ int assigned_register = AllocatedOperand::cast(operand)->index(); |
+ *register_index = assigned_register; |
+ return true; |
+ } |
+ case UsePositionHintType::kPhi: { |
+ auto phi = reinterpret_cast<RegisterAllocationData::PhiMapValue*>(hint_); |
+ int assigned_register = phi->assigned_register(); |
+ if (assigned_register == kUnassignedRegister) return false; |
+ *register_index = assigned_register; |
+ return true; |
+ } |
+ } |
+ UNREACHABLE(); |
+ return false; |
+} |
+ |
+ |
+UsePositionHintType UsePosition::HintTypeForOperand( |
+ const InstructionOperand& op) { |
+ switch (op.kind()) { |
+ case InstructionOperand::CONSTANT: |
+ case InstructionOperand::IMMEDIATE: |
+ return UsePositionHintType::kNone; |
+ case InstructionOperand::UNALLOCATED: |
+ return UsePositionHintType::kUnresolved; |
+ case InstructionOperand::ALLOCATED: |
+ switch (AllocatedOperand::cast(op).allocated_kind()) { |
+ case AllocatedOperand::REGISTER: |
+ case AllocatedOperand::DOUBLE_REGISTER: |
+ return UsePositionHintType::kOperand; |
+ case AllocatedOperand::STACK_SLOT: |
+ case AllocatedOperand::DOUBLE_STACK_SLOT: |
+ return UsePositionHintType::kNone; |
+ } |
+ case InstructionOperand::INVALID: |
+ break; |
+ } |
+ UNREACHABLE(); |
+ return UsePositionHintType::kNone; |
+} |
+ |
+ |
+void UsePosition::ResolveHint(UsePosition* use_pos) { |
+ DCHECK_NOT_NULL(use_pos); |
+ if (HintTypeField::decode(flags_) != UsePositionHintType::kUnresolved) return; |
+ hint_ = use_pos; |
+ flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); |
} |
@@ -129,7 +221,7 @@ LiveRange::LiveRange(int id) |
is_phi_(false), |
is_non_loop_phi_(false), |
kind_(UNALLOCATED_REGISTERS), |
- assigned_register_(kInvalidAssignment), |
+ assigned_register_(kUnassignedRegister), |
last_interval_(nullptr), |
first_interval_(nullptr), |
first_pos_(nullptr), |
@@ -137,7 +229,7 @@ LiveRange::LiveRange(int id) |
next_(nullptr), |
current_interval_(nullptr), |
last_processed_use_(nullptr), |
- current_hint_operand_(nullptr), |
+ current_hint_position_(nullptr), |
spill_start_index_(kMaxInt), |
spill_type_(SpillType::kNoSpillType), |
spill_operand_(nullptr), |
@@ -165,11 +257,17 @@ void LiveRange::set_assigned_register(int reg) { |
} |
+void LiveRange::UnsetAssignedRegister() { |
+ DCHECK(HasRegisterAssigned() && !IsSpilled()); |
+ assigned_register_ = kUnassignedRegister; |
+} |
+ |
+ |
void LiveRange::MakeSpilled() { |
DCHECK(!IsSpilled()); |
DCHECK(!TopLevel()->HasNoSpillType()); |
spilled_ = true; |
- assigned_register_ = kInvalidAssignment; |
+ assigned_register_ = kUnassignedRegister; |
} |
@@ -210,6 +308,14 @@ void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
} |
+UsePosition* LiveRange::FirstHintPosition(int* register_index) const { |
+ for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { |
+ if (pos->HintRegister(register_index)) return pos; |
+ } |
+ return nullptr; |
+} |
+ |
+ |
void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
DCHECK(HasNoSpillType()); |
DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); |
@@ -494,11 +600,9 @@ void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end, |
} |
-void LiveRange::AddUsePosition(LifetimePosition pos, |
- InstructionOperand* operand, |
- InstructionOperand* hint, Zone* zone) { |
+void LiveRange::AddUsePosition(UsePosition* use_pos) { |
+ auto pos = use_pos->pos(); |
TRACE("Add to live range %d use position %d\n", id_, pos.value()); |
- auto use_pos = new (zone) UsePosition(pos, operand, hint); |
UsePosition* prev_hint = nullptr; |
UsePosition* prev = nullptr; |
auto current = first_pos_; |
@@ -517,7 +621,7 @@ void LiveRange::AddUsePosition(LifetimePosition pos, |
} |
if (prev_hint == nullptr && use_pos->HasHint()) { |
- current_hint_operand_ = hint; |
+ current_hint_position_ = use_pos; |
} |
} |
@@ -526,9 +630,7 @@ void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
InstructionOperand* spill_op) { |
for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
DCHECK(Start() <= pos->pos() && pos->pos() <= End()); |
- if (!pos->HasOperand()) { |
- continue; |
- } |
+ if (!pos->HasOperand()) continue; |
switch (pos->type()) { |
case UsePositionType::kRequiresSlot: |
if (spill_op != nullptr) { |
@@ -546,6 +648,21 @@ void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
} |
+void LiveRange::SetUseHints(int register_index) { |
+ for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
+ if (!pos->HasOperand()) continue; |
+ switch (pos->type()) { |
+ case UsePositionType::kRequiresSlot: |
+ break; |
+ case UsePositionType::kRequiresRegister: |
+ case UsePositionType::kAny: |
+ pos->set_assigned_register(register_index); |
+ break; |
+ } |
+ } |
+} |
+ |
+ |
bool LiveRange::CanCover(LifetimePosition position) const { |
if (IsEmpty()) return false; |
return Start() <= position && position < End(); |
@@ -702,6 +819,31 @@ void SpillRange::MergeDisjointIntervals(UseInterval* other) { |
} |
+RegisterAllocationData::PhiMapValue::PhiMapValue(PhiInstruction* phi, |
+ const InstructionBlock* block, |
+ Zone* zone) |
+ : phi_(phi), |
+ block_(block), |
+ incoming_operands_(zone), |
+ assigned_register_(kUnassignedRegister) { |
+ incoming_operands_.reserve(phi->operands().size()); |
+} |
+ |
+ |
+void RegisterAllocationData::PhiMapValue::AddOperand( |
+ InstructionOperand* operand) { |
+ incoming_operands_.push_back(operand); |
+} |
+ |
+ |
+void RegisterAllocationData::PhiMapValue::CommitAssignment( |
+ const InstructionOperand& assigned) { |
+ for (auto operand : incoming_operands_) { |
+ InstructionOperand::ReplaceWith(operand, &assigned); |
+ } |
+} |
+ |
+ |
RegisterAllocationData::RegisterAllocationData( |
const RegisterConfiguration* config, Zone* zone, Frame* frame, |
InstructionSequence* code, const char* debug_name) |
@@ -757,19 +899,28 @@ MoveOperands* RegisterAllocationData::AddGapMove( |
} |
-void RegisterAllocationData::AssignPhiInput( |
- LiveRange* range, const InstructionOperand& assignment) { |
- DCHECK(range->is_phi()); |
- auto it = phi_map().find(range->id()); |
- DCHECK(it != phi_map().end()); |
- for (auto move : it->second->incoming_moves) { |
- move->set_destination(assignment); |
- } |
+LiveRange* RegisterAllocationData::NewLiveRange(int index) { |
+ return new (allocation_zone()) LiveRange(index); |
} |
-LiveRange* RegisterAllocationData::NewLiveRange(int index) { |
- return new (allocation_zone()) LiveRange(index); |
+RegisterAllocationData::PhiMapValue* RegisterAllocationData::InitializePhiMap( |
+ const InstructionBlock* block, PhiInstruction* phi) { |
+ auto map_value = new (allocation_zone()) |
+ RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
+ auto res = |
+ phi_map_.insert(std::make_pair(phi->virtual_register(), map_value)); |
+ DCHECK(res.second); |
+ USE(res); |
+ return map_value; |
+} |
+ |
+ |
+RegisterAllocationData::PhiMapValue* RegisterAllocationData::GetPhiMapValueFor( |
+ int virtual_register) { |
+ auto it = phi_map_.find(virtual_register); |
+ DCHECK(it != phi_map_.end()); |
+ return it->second; |
} |
@@ -803,19 +954,13 @@ SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( |
} |
-void RegisterAllocationData::SetLiveRangeAssignedRegister(LiveRange* range, |
- int reg) { |
- if (range->Kind() == DOUBLE_REGISTERS) { |
- assigned_double_registers_->Add(reg); |
+void RegisterAllocationData::MarkAllocated(RegisterKind kind, int index) { |
+ if (kind == DOUBLE_REGISTERS) { |
+ assigned_double_registers_->Add(index); |
} else { |
- DCHECK(range->Kind() == GENERAL_REGISTERS); |
- assigned_registers_->Add(reg); |
+ DCHECK(kind == GENERAL_REGISTERS); |
+ assigned_registers_->Add(index); |
} |
- range->set_assigned_register(reg); |
- auto assignment = range->GetAssignedOperand(); |
- // TODO(dcarney): stop aliasing hint operands. |
- range->ConvertUsesToOperand(assignment, nullptr); |
- if (range->is_phi()) AssignPhiInput(range, assignment); |
} |
@@ -1022,19 +1167,16 @@ void ConstraintBuilder::ResolvePhis() { |
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 map_value = data()->InitializePhiMap(block, phi); |
auto& output = phi->output(); |
+ // Map the destination operands, so the commitment phase can find them. |
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); |
+ map_value->AddOperand(&move->destination()); |
DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
->HasReferenceMap()); |
} |
@@ -1049,8 +1191,9 @@ void ConstraintBuilder::ResolvePhis(const InstructionBlock* block) { |
} |
-LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data) |
- : data_(data) {} |
+LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data, |
+ Zone* local_zone) |
+ : data_(data), phi_hints_(local_zone) {} |
BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { |
@@ -1109,7 +1252,8 @@ LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
result = data()->NewLiveRange(FixedLiveRangeID(index)); |
DCHECK(result->IsFixed()); |
result->set_kind(GENERAL_REGISTERS); |
- data()->SetLiveRangeAssignedRegister(result, index); |
+ result->set_assigned_register(index); |
+ data()->MarkAllocated(GENERAL_REGISTERS, index); |
data()->fixed_live_ranges()[index] = result; |
} |
return result; |
@@ -1123,7 +1267,8 @@ LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); |
DCHECK(result->IsFixed()); |
result->set_kind(DOUBLE_REGISTERS); |
- data()->SetLiveRangeAssignedRegister(result, index); |
+ result->set_assigned_register(index); |
+ data()->MarkAllocated(DOUBLE_REGISTERS, index); |
data()->fixed_double_live_ranges()[index] = result; |
} |
return result; |
@@ -1146,60 +1291,49 @@ LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
} |
-void LiveRangeBuilder::Define(LifetimePosition position, |
- InstructionOperand* operand, |
- InstructionOperand* hint) { |
+UsePosition* LiveRangeBuilder::NewUsePosition(LifetimePosition pos, |
+ InstructionOperand* operand, |
+ void* hint, |
+ UsePositionHintType hint_type) { |
+ return new (allocation_zone()) UsePosition(pos, operand, hint, hint_type); |
+} |
+ |
+ |
+UsePosition* LiveRangeBuilder::Define(LifetimePosition position, |
+ InstructionOperand* operand, void* hint, |
+ UsePositionHintType hint_type) { |
auto range = LiveRangeFor(operand); |
- if (range == nullptr) return; |
+ if (range == nullptr) return nullptr; |
if (range->IsEmpty() || range->Start() > position) { |
// Can happen if there is a definition without use. |
range->AddUseInterval(position, position.NextStart(), allocation_zone()); |
- range->AddUsePosition(position.NextStart(), nullptr, nullptr, |
- allocation_zone()); |
+ range->AddUsePosition(NewUsePosition(position.NextStart())); |
} else { |
range->ShortenTo(position); |
} |
- |
- if (operand->IsUnallocated()) { |
- auto unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
- } |
+ if (!operand->IsUnallocated()) return nullptr; |
+ auto unalloc_operand = UnallocatedOperand::cast(operand); |
+ auto use_pos = NewUsePosition(position, unalloc_operand, hint, hint_type); |
+ range->AddUsePosition(use_pos); |
+ return use_pos; |
} |
-void LiveRangeBuilder::Use(LifetimePosition block_start, |
- LifetimePosition position, |
- InstructionOperand* operand, |
- InstructionOperand* hint) { |
+UsePosition* LiveRangeBuilder::Use(LifetimePosition block_start, |
+ LifetimePosition position, |
+ InstructionOperand* operand, void* hint, |
+ UsePositionHintType hint_type) { |
auto range = LiveRangeFor(operand); |
- if (range == nullptr) return; |
+ if (range == nullptr) return nullptr; |
+ UsePosition* use_pos = nullptr; |
if (operand->IsUnallocated()) { |
UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
- range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
+ use_pos = NewUsePosition(position, unalloc_operand, hint, hint_type); |
+ range->AddUsePosition(use_pos); |
} |
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); |
- if (output->IsRegister() && RegisterOperand::cast(output)->index() == index) |
- return true; |
- } |
- return false; |
-} |
- |
- |
-bool LiveRangeBuilder::IsOutputDoubleRegisterOf(Instruction* instr, int index) { |
- for (size_t i = 0; i < instr->OutputCount(); i++) { |
- auto output = instr->OutputAt(i); |
- if (output->IsDoubleRegister() && |
- DoubleRegisterOperand::cast(output)->index() == index) |
- return true; |
- } |
- return false; |
+ return use_pos; |
} |
@@ -1228,7 +1362,7 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
int out_vreg = ConstantOperand::cast(output)->virtual_register(); |
live->Remove(out_vreg); |
} |
- Define(curr_position, output, nullptr); |
+ Define(curr_position, output); |
} |
if (instr->ClobbersRegisters()) { |
@@ -1270,7 +1404,7 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
LiveRangeFor(vreg)->set_has_slot_use(true); |
} |
} |
- Use(block_start_position, use_pos, input, nullptr); |
+ Use(block_start_position, use_pos, input); |
} |
for (size_t i = 0; i < instr->TempCount(); i++) { |
@@ -1287,8 +1421,8 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
} |
} |
} |
- Use(block_start_position, curr_position.End(), temp, nullptr); |
- Define(curr_position, temp, nullptr); |
+ Use(block_start_position, curr_position.End(), temp); |
+ Define(curr_position, temp); |
} |
// Process the moves of the instruction's gaps, making their sources live. |
@@ -1307,17 +1441,27 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
for (auto cur : *move) { |
auto& from = cur->source(); |
auto& to = cur->destination(); |
- auto hint = &to; |
+ void* hint = &to; |
+ UsePositionHintType hint_type = UsePosition::HintTypeForOperand(to); |
+ UsePosition* to_use = nullptr; |
+ int phi_vreg = -1; |
if (to.IsUnallocated()) { |
int to_vreg = UnallocatedOperand::cast(to).virtual_register(); |
auto to_range = LiveRangeFor(to_vreg); |
if (to_range->is_phi()) { |
+ phi_vreg = to_vreg; |
if (to_range->is_non_loop_phi()) { |
- hint = to_range->current_hint_operand(); |
+ hint = to_range->current_hint_position(); |
+ hint_type = hint == nullptr ? UsePositionHintType::kNone |
+ : UsePositionHintType::kUsePos; |
+ } else { |
+ hint_type = UsePositionHintType::kPhi; |
+ hint = data()->GetPhiMapValueFor(to_vreg); |
} |
} else { |
if (live->Contains(to_vreg)) { |
- Define(curr_position, &to, &from); |
+ to_use = Define(curr_position, &to, &from, |
+ UsePosition::HintTypeForOperand(from)); |
live->Remove(to_vreg); |
} else { |
cur->Eliminate(); |
@@ -1325,18 +1469,81 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
} |
} |
} else { |
- Define(curr_position, &to, &from); |
+ Define(curr_position, &to); |
} |
- Use(block_start_position, curr_position, &from, hint); |
+ auto from_use = |
+ Use(block_start_position, curr_position, &from, hint, hint_type); |
+ // Mark range live. |
if (from.IsUnallocated()) { |
live->Add(UnallocatedOperand::cast(from).virtual_register()); |
} |
+ // Resolve use position hints just created. |
+ if (to_use != nullptr && from_use != nullptr) { |
+ to_use->ResolveHint(from_use); |
+ from_use->ResolveHint(to_use); |
+ } |
+ DCHECK_IMPLIES(to_use != nullptr, to_use->IsResolved()); |
+ DCHECK_IMPLIES(from_use != nullptr, from_use->IsResolved()); |
+ // Potentially resolve phi hint. |
+ if (phi_vreg != -1) ResolvePhiHint(&from, from_use); |
} |
} |
} |
} |
+void LiveRangeBuilder::ProcessPhis(const InstructionBlock* block, |
+ BitVector* live) { |
+ for (auto phi : block->phis()) { |
+ // The live range interval already ends at the first instruction of the |
+ // block. |
+ int phi_vreg = phi->virtual_register(); |
+ live->Remove(phi_vreg); |
+ InstructionOperand* hint = nullptr; |
+ auto instr = GetLastInstruction( |
+ code(), code()->InstructionBlockAt(block->predecessors()[0])); |
+ for (auto move : *instr->GetParallelMove(Instruction::END)) { |
+ auto& to = move->destination(); |
+ if (to.IsUnallocated() && |
+ UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { |
+ hint = &move->source(); |
+ break; |
+ } |
+ } |
+ DCHECK(hint != nullptr); |
+ auto block_start = LifetimePosition::GapFromInstructionIndex( |
+ block->first_instruction_index()); |
+ auto use_pos = Define(block_start, &phi->output(), hint, |
+ UsePosition::HintTypeForOperand(*hint)); |
+ MapPhiHint(hint, use_pos); |
+ } |
+} |
+ |
+ |
+void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, |
+ BitVector* live) { |
+ DCHECK(block->IsLoopHeader()); |
+ // 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::GapFromInstructionIndex( |
+ block->first_instruction_index()); |
+ auto end = LifetimePosition::GapFromInstructionIndex( |
+ code()->LastLoopInstructionIndex(block)).NextFullStart(); |
+ while (!iterator.Done()) { |
+ int operand_index = iterator.Current(); |
+ auto range = LiveRangeFor(operand_index); |
+ range->EnsureInterval(start, end, allocation_zone()); |
+ iterator.Advance(); |
+ } |
+ // Insert all values into the live in sets of all blocks in the loop. |
+ for (int i = block->rpo_number().ToInt() + 1; i < block->loop_end().ToInt(); |
+ ++i) { |
+ live_in_sets()[i]->Union(*live); |
+ } |
+} |
+ |
+ |
void LiveRangeBuilder::BuildLiveRanges() { |
// Process the blocks in reverse order. |
for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; |
@@ -1346,59 +1553,17 @@ void LiveRangeBuilder::BuildLiveRanges() { |
// Initially consider all live_out values live for the entire block. We |
// will shorten these intervals if necessary. |
AddInitialIntervals(block, live); |
- |
// Process the instructions in reverse order, generating and killing |
// live values. |
ProcessInstructions(block, live); |
// All phi output operands are killed by this block. |
- for (auto phi : block->phis()) { |
- // The live range interval already ends at the first instruction of the |
- // block. |
- int phi_vreg = phi->virtual_register(); |
- live->Remove(phi_vreg); |
- InstructionOperand* hint = nullptr; |
- auto instr = GetLastInstruction( |
- code(), code()->InstructionBlockAt(block->predecessors()[0])); |
- for (auto move : *instr->GetParallelMove(Instruction::END)) { |
- auto& to = move->destination(); |
- if (to.IsUnallocated() && |
- UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { |
- hint = &move->source(); |
- break; |
- } |
- } |
- DCHECK(hint != nullptr); |
- auto block_start = LifetimePosition::GapFromInstructionIndex( |
- block->first_instruction_index()); |
- Define(block_start, &phi->output(), hint); |
- } |
- |
+ ProcessPhis(block, live); |
// Now live is live_in for this block except not including values live |
// out on backward successor edges. |
+ if (block->IsLoopHeader()) ProcessLoopHeader(block, live); |
live_in_sets()[block_id] = live; |
- |
- if (block->IsLoopHeader()) { |
- // 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::GapFromInstructionIndex( |
- block->first_instruction_index()); |
- auto end = LifetimePosition::GapFromInstructionIndex( |
- code()->LastLoopInstructionIndex(block)).NextFullStart(); |
- while (!iterator.Done()) { |
- int operand_index = iterator.Current(); |
- auto range = LiveRangeFor(operand_index); |
- range->EnsureInterval(start, end, allocation_zone()); |
- iterator.Advance(); |
- } |
- // Insert all values into the live in sets of all blocks in the loop. |
- for (int i = block->rpo_number().ToInt() + 1; |
- i < block->loop_end().ToInt(); ++i) { |
- live_in_sets()[i]->Union(*live); |
- } |
- } |
} |
- |
+ // Postprocess the ranges. |
for (auto range : data()->live_ranges()) { |
if (range == nullptr) continue; |
range->set_kind(RequiredRegisterKind(range->id())); |
@@ -1422,13 +1587,30 @@ void LiveRangeBuilder::BuildLiveRanges() { |
} |
} |
} |
- |
#ifdef DEBUG |
Verify(); |
#endif |
} |
+void LiveRangeBuilder::MapPhiHint(InstructionOperand* operand, |
+ UsePosition* use_pos) { |
+ DCHECK(!use_pos->IsResolved()); |
+ auto res = phi_hints_.insert(std::make_pair(operand, use_pos)); |
+ DCHECK(res.second); |
+ USE(res); |
+} |
+ |
+ |
+void LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, |
+ UsePosition* use_pos) { |
+ auto it = phi_hints_.find(operand); |
+ if (it == phi_hints_.end()) return; |
+ DCHECK(!it->second->IsResolved()); |
+ it->second->ResolveHint(use_pos); |
+} |
+ |
+ |
RegisterKind LiveRangeBuilder::RequiredRegisterKind( |
int virtual_register) const { |
return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS |
@@ -1437,6 +1619,9 @@ RegisterKind LiveRangeBuilder::RequiredRegisterKind( |
void LiveRangeBuilder::Verify() const { |
+ for (auto& hint : phi_hints_) { |
+ CHECK(hint.second->IsResolved()); |
+ } |
for (auto current : data()->live_ranges()) { |
if (current != nullptr) current->Verify(); |
} |
@@ -1677,6 +1862,17 @@ const char* LinearScanAllocator::RegisterName(int allocation_index) const { |
} |
+void LinearScanAllocator::SetLiveRangeAssignedRegister(LiveRange* range, |
+ int reg) { |
+ data()->MarkAllocated(range->Kind(), reg); |
+ range->set_assigned_register(reg); |
+ range->SetUseHints(reg); |
+ if (range->is_phi()) { |
+ data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg); |
+ } |
+} |
+ |
+ |
void LinearScanAllocator::AddToActive(LiveRange* range) { |
TRACE("Add live range %d to active\n", range->id()); |
active_live_ranges().push_back(range); |
@@ -1792,18 +1988,17 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) { |
free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); |
} |
- auto hint = current->FirstHint(); |
- if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { |
- int register_index = AllocatedOperand::cast(hint)->index(); |
+ int hint_register; |
+ if (current->FirstHintPosition(&hint_register) != nullptr) { |
TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", |
- RegisterName(register_index), free_until_pos[register_index].value(), |
+ RegisterName(hint_register), free_until_pos[hint_register].value(), |
current->id(), current->End().value()); |
// The desired register is free until the end of the current live range. |
- if (free_until_pos[register_index] >= current->End()) { |
+ if (free_until_pos[hint_register] >= current->End()) { |
TRACE("Assigning preferred reg %s to live range %d\n", |
- RegisterName(register_index), current->id()); |
- data()->SetLiveRangeAssignedRegister(current, register_index); |
+ RegisterName(hint_register), current->id()); |
+ SetLiveRangeAssignedRegister(current, hint_register); |
return true; |
} |
} |
@@ -1835,7 +2030,7 @@ bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) { |
DCHECK(pos >= current->End()); |
TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), |
current->id()); |
- data()->SetLiveRangeAssignedRegister(current, reg); |
+ SetLiveRangeAssignedRegister(current, reg); |
return true; |
} |
@@ -1914,7 +2109,7 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { |
DCHECK(block_pos[reg] >= current->End()); |
TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), |
current->id()); |
- data()->SetLiveRangeAssignedRegister(current, reg); |
+ SetLiveRangeAssignedRegister(current, reg); |
// This register was not free. Thus we need to find and spill |
// parts of active and inactive live regions that use the same register |
@@ -1974,11 +2169,9 @@ void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) { |
bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) { |
if (range->IsChild() || !range->is_phi()) return false; |
DCHECK(!range->HasSpillOperand()); |
- |
- auto lookup = data()->phi_map().find(range->id()); |
- DCHECK(lookup != data()->phi_map().end()); |
- auto phi = lookup->second->phi; |
- auto block = lookup->second->block; |
+ auto phi_map_value = data()->GetPhiMapValueFor(range->id()); |
+ auto phi = phi_map_value->phi(); |
+ auto block = phi_map_value->block(); |
// Count the number of spilled operands. |
size_t spilled_count = 0; |
LiveRange* first_op = nullptr; |
@@ -2199,13 +2392,18 @@ void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { |
return; |
} |
range->set_assigned_register(reg_id); |
+ range->SetUseHints(reg_id); |
+ if (range->is_phi()) { |
+ data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id); |
+ } |
} |
float GreedyAllocator::CalculateSpillWeight(LiveRange* range) { |
if (range->IsFixed()) return std::numeric_limits<float>::max(); |
- if (range->FirstHint() != nullptr && range->FirstHint()->IsRegister()) { |
+ int hint_register; |
+ if (range->FirstHintPosition(&hint_register) != nullptr) { |
return std::numeric_limits<float>::max(); |
} |
@@ -2237,6 +2435,11 @@ float GreedyAllocator::CalculateMaxSpillWeight( |
void GreedyAllocator::Evict(LiveRange* range) { |
bool removed = allocations_[range->assigned_register()]->Remove(range); |
CHECK(removed); |
+ range->UnsetUseHints(); |
+ range->UnsetAssignedRegister(); |
+ if (range->is_phi()) { |
+ data()->GetPhiMapValueFor(range->id())->UnsetAssignedRegister(); |
+ } |
} |
@@ -2405,13 +2608,11 @@ void GreedyAllocator::AllocateRegisters() { |
} |
} |
- BitVector* assigned_registers = new (zone) BitVector(num_registers(), zone); |
for (size_t i = 0; i < allocations_.size(); ++i) { |
if (!allocations_[i]->IsEmpty()) { |
- assigned_registers->Add(static_cast<int>(i)); |
+ data()->MarkAllocated(mode(), static_cast<int>(i)); |
} |
} |
- data()->frame()->SetAllocatedRegisters(assigned_registers); |
} |
@@ -2472,7 +2673,9 @@ void OperandAssigner::CommitAssignment() { |
} |
auto assigned = range->GetAssignedOperand(); |
range->ConvertUsesToOperand(assigned, spill_operand); |
- if (range->is_phi()) data()->AssignPhiInput(range, assigned); |
+ if (range->is_phi()) { |
+ data()->GetPhiMapValueFor(range->id())->CommitAssignment(assigned); |
+ } |
if (!range->IsChild() && spill_operand != nullptr) { |
range->CommitSpillsAtDefinition(data()->code(), spill_operand, |
range->has_slot_use()); |