| Index: src/compiler/register-allocator.cc
|
| diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
|
| index 283603a44e1728e6a9c8ae82b79fa053415a5c73..3e1ac629417d6f5c8a66ccd425fc5f323df8730c 100644
|
| --- a/src/compiler/register-allocator.cc
|
| +++ b/src/compiler/register-allocator.cc
|
| @@ -100,6 +100,8 @@ bool LiveRange::HasOverlap(UseInterval* target) const {
|
| LiveRange::LiveRange(int id, Zone* zone)
|
| : id_(id),
|
| spilled_(false),
|
| + is_phi_(false),
|
| + is_non_loop_phi_(false),
|
| kind_(UNALLOCATED_REGISTERS),
|
| assigned_register_(kInvalidAssignment),
|
| last_interval_(NULL),
|
| @@ -1163,12 +1165,20 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
| InstructionOperand* hint = to;
|
| if (to->IsUnallocated()) {
|
| int to_vreg = UnallocatedOperand::cast(to)->virtual_register();
|
| - if (live->Contains(to_vreg)) {
|
| - Define(curr_position, to, from);
|
| - live->Remove(to_vreg);
|
| + LiveRange* 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 {
|
| - cur->Eliminate();
|
| - continue;
|
| + if (live->Contains(to_vreg)) {
|
| + Define(curr_position, to, from);
|
| + live->Remove(to_vreg);
|
| + } else {
|
| + cur->Eliminate();
|
| + continue;
|
| + }
|
| }
|
| } else {
|
| Define(curr_position, to, from);
|
| @@ -1248,28 +1258,53 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
| }
|
|
|
|
|
| -void RegisterAllocator::ProcessPhis(const InstructionBlock* block) {
|
| +void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
|
| for (auto phi : block->phis()) {
|
| auto output = phi->output();
|
| int phi_vreg = phi->virtual_register();
|
| + if (!FLAG_turbo_delay_ssa_decon) {
|
| + for (size_t i = 0; i < phi->operands().size(); ++i) {
|
| + InstructionBlock* cur_block =
|
| + code()->InstructionBlockAt(block->predecessors()[i]);
|
| + // The gap move must be added without any special processing as in
|
| + // the AddConstraintsGapMove.
|
| + code()->AddGapMove(cur_block->last_instruction_index() - 1,
|
| + phi->inputs()[i], output);
|
| + DCHECK(!InstructionAt(cur_block->last_instruction_index())
|
| + ->HasPointerMap());
|
| + }
|
| + }
|
| LiveRange* live_range = LiveRangeFor(phi_vreg);
|
| BlockStartInstruction* block_start =
|
| code()->GetBlockStart(block->rpo_number());
|
| block_start->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone())
|
| ->AddMove(output, live_range->GetSpillOperand(), code_zone());
|
| live_range->SetSpillStartIndex(block->first_instruction_index());
|
| + // We use the phi-ness of some nodes in some later heuristics.
|
| + live_range->set_is_phi(true);
|
| + if (!block->IsLoopHeader()) {
|
| + live_range->set_is_non_loop_phi(true);
|
| + }
|
| }
|
| }
|
|
|
|
|
| void RegisterAllocator::MeetRegisterConstraints() {
|
| for (auto block : code()->instruction_blocks()) {
|
| - ProcessPhis(block);
|
| MeetRegisterConstraints(block);
|
| }
|
| }
|
|
|
|
|
| +void RegisterAllocator::ResolvePhis() {
|
| + // Process the blocks in reverse order.
|
| + for (auto i = code()->instruction_blocks().rbegin();
|
| + i != code()->instruction_blocks().rend(); ++i) {
|
| + ResolvePhis(*i);
|
| + }
|
| +}
|
| +
|
| +
|
| ParallelMove* RegisterAllocator::GetConnectingParallelMove(
|
| LifetimePosition pos) {
|
| int index = pos.InstructionIndex();
|
| @@ -1474,21 +1509,24 @@ void RegisterAllocator::ResolveControlFlow() {
|
| LiveRangeFinder finder(*this);
|
| for (auto block : code()->instruction_blocks()) {
|
| if (CanEagerlyResolveControlFlow(block)) continue;
|
| - // resolve phis
|
| - for (auto phi : block->phis()) {
|
| - auto* block_bound =
|
| - finder.ArrayFor(phi->virtual_register())->FindSucc(block);
|
| - auto phi_output = block_bound->range_->CreateAssignedOperand(code_zone());
|
| - phi->output()->ConvertTo(phi_output->kind(), phi_output->index());
|
| - size_t pred_index = 0;
|
| - for (auto pred : block->predecessors()) {
|
| - const InstructionBlock* pred_block = code()->InstructionBlockAt(pred);
|
| - auto* pred_bound =
|
| - finder.ArrayFor(phi->operands()[pred_index])->FindPred(pred_block);
|
| - auto pred_op = pred_bound->range_->CreateAssignedOperand(code_zone());
|
| - phi->inputs()[pred_index] = pred_op;
|
| - ResolveControlFlow(block, phi_output, pred_block, pred_op);
|
| - pred_index++;
|
| + if (FLAG_turbo_delay_ssa_decon) {
|
| + // resolve phis
|
| + for (auto phi : block->phis()) {
|
| + auto* block_bound =
|
| + finder.ArrayFor(phi->virtual_register())->FindSucc(block);
|
| + auto phi_output =
|
| + block_bound->range_->CreateAssignedOperand(code_zone());
|
| + phi->output()->ConvertTo(phi_output->kind(), phi_output->index());
|
| + size_t pred_index = 0;
|
| + for (auto pred : block->predecessors()) {
|
| + const InstructionBlock* pred_block = code()->InstructionBlockAt(pred);
|
| + auto* pred_bound = finder.ArrayFor(phi->operands()[pred_index])
|
| + ->FindPred(pred_block);
|
| + auto pred_op = pred_bound->range_->CreateAssignedOperand(code_zone());
|
| + phi->inputs()[pred_index] = pred_op;
|
| + ResolveControlFlow(block, phi_output, pred_block, pred_op);
|
| + pred_index++;
|
| + }
|
| }
|
| }
|
| BitVector* live = live_in_sets_[block->rpo_number().ToInt()];
|
| @@ -1556,6 +1594,27 @@ void RegisterAllocator::BuildLiveRanges() {
|
| // block.
|
| int phi_vreg = phi->virtual_register();
|
| live->Remove(phi_vreg);
|
| + if (!FLAG_turbo_delay_ssa_decon) {
|
| + InstructionOperand* hint = NULL;
|
| + InstructionOperand* phi_operand = NULL;
|
| + GapInstruction* gap =
|
| + GetLastGap(code()->InstructionBlockAt(block->predecessors()[0]));
|
| + ParallelMove* move =
|
| + gap->GetOrCreateParallelMove(GapInstruction::START, code_zone());
|
| + for (int j = 0; j < move->move_operands()->length(); ++j) {
|
| + InstructionOperand* to = move->move_operands()->at(j).destination();
|
| + if (to->IsUnallocated() &&
|
| + UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) {
|
| + hint = move->move_operands()->at(j).source();
|
| + phi_operand = to;
|
| + break;
|
| + }
|
| + }
|
| + DCHECK(hint != NULL);
|
| + LifetimePosition block_start = LifetimePosition::FromInstructionIndex(
|
| + block->first_instruction_index());
|
| + Define(block_start, phi_operand, hint);
|
| + }
|
| }
|
|
|
| // Now live is live_in for this block except not including values live
|
| @@ -1600,7 +1659,13 @@ void RegisterAllocator::BuildLiveRanges() {
|
| for (UsePosition* pos = range->first_pos(); pos != NULL;
|
| pos = pos->next_) {
|
| pos->register_beneficial_ = true;
|
| - pos->requires_reg_ = true;
|
| + // TODO(dcarney): should the else case assert requires_reg_ == false?
|
| + // Can't mark phis as needing a register.
|
| + if (!code()
|
| + ->InstructionAt(pos->pos().InstructionIndex())
|
| + ->IsGapMoves()) {
|
| + pos->requires_reg_ = true;
|
| + }
|
| }
|
| }
|
| }
|
|
|