Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 } | 84 } |
| 85 blocked_cpu_registers_[SPREG] = true; | 85 blocked_cpu_registers_[SPREG] = true; |
| 86 blocked_cpu_registers_[FPREG] = true; | 86 blocked_cpu_registers_[FPREG] = true; |
| 87 | 87 |
| 88 // FpuTMP is used as scratch by optimized code and parallel move resolver. | 88 // FpuTMP is used as scratch by optimized code and parallel move resolver. |
| 89 blocked_fpu_registers_[FpuTMP] = true; | 89 blocked_fpu_registers_[FpuTMP] = true; |
| 90 } | 90 } |
| 91 | 91 |
| 92 | 92 |
| 93 // Remove environments from the instructions which can't deoptimize. | 93 // Remove environments from the instructions which can't deoptimize. |
| 94 // Replace dead phis uses with null values in environments. | 94 void FlowGraphAllocator::EliminateEnvironments() { |
| 95 void FlowGraphAllocator::EliminateEnvironmentUses() { | |
| 96 ConstantInstr* constant_null = | |
| 97 postorder_.Last()->AsGraphEntry()->constant_null(); | |
| 98 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 95 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 99 BlockEntryInstr* block = block_order_[i]; | 96 BlockEntryInstr* block = block_order_[i]; |
| 100 if (block->IsJoinEntry()) block->AsJoinEntry()->RemoveDeadPhis(); | |
| 101 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 97 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 102 Instruction* current = it.Current(); | 98 Instruction* current = it.Current(); |
| 103 if (current->CanDeoptimize()) { | 99 if (!current->CanDeoptimize()) current->RemoveEnvironment(); |
| 104 ASSERT(current->env() != NULL); | |
| 105 for (Environment::DeepIterator it(current->env()); | |
| 106 !it.Done(); | |
| 107 it.Advance()) { | |
| 108 Value* use = it.CurrentValue(); | |
| 109 Definition* def = use->definition(); | |
| 110 PushArgumentInstr* push_argument = def->AsPushArgument(); | |
| 111 if ((push_argument != NULL) && push_argument->WasEliminated()) { | |
| 112 it.SetCurrentValue(push_argument->value()->Copy()); | |
|
Vyacheslav Egorov (Google)
2013/02/27 21:53:02
What happened to this special PushArgument handlin
Kevin Millikin (Google)
2013/02/28 08:12:02
It was already obsolete after a previous change, w
| |
| 113 continue; | |
| 114 } | |
| 115 | |
| 116 PhiInstr* phi = def->AsPhi(); | |
| 117 if ((phi != NULL) && !phi->is_alive()) { | |
| 118 it.SetCurrentValue(new Value(constant_null)); | |
| 119 continue; | |
| 120 } | |
| 121 } | |
| 122 } else { | |
| 123 current->RemoveEnvironment(); | |
| 124 } | |
| 125 } | 100 } |
| 126 } | 101 } |
| 127 } | 102 } |
| 128 | 103 |
| 129 | 104 |
| 130 void FlowGraphAllocator::ComputeInitialSets() { | 105 void FlowGraphAllocator::ComputeInitialSets() { |
| 131 const intptr_t block_count = postorder_.length(); | 106 const intptr_t block_count = postorder_.length(); |
| 132 for (intptr_t i = 0; i < block_count; i++) { | 107 for (intptr_t i = 0; i < block_count; i++) { |
| 133 BlockEntryInstr* block = postorder_[i]; | 108 BlockEntryInstr* block = postorder_[i]; |
| 134 | 109 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 !value->BindsToConstant()) { | 145 !value->BindsToConstant()) { |
| 171 live_in->Add(value->definition()->ssa_temp_index()); | 146 live_in->Add(value->definition()->ssa_temp_index()); |
| 172 } | 147 } |
| 173 } | 148 } |
| 174 } | 149 } |
| 175 } | 150 } |
| 176 | 151 |
| 177 // Handle phis. | 152 // Handle phis. |
| 178 if (block->IsJoinEntry()) { | 153 if (block->IsJoinEntry()) { |
| 179 JoinEntryInstr* join = block->AsJoinEntry(); | 154 JoinEntryInstr* join = block->AsJoinEntry(); |
| 180 if (join->phis() != NULL) { | 155 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 181 for (intptr_t j = 0; j < join->phis()->length(); j++) { | 156 PhiInstr* phi = it.Current(); |
| 182 PhiInstr* phi = (*join->phis())[j]; | 157 ASSERT(phi != NULL); |
| 183 if (phi == NULL) continue; | 158 kill->Add(phi->ssa_temp_index()); |
| 159 live_in->Remove(phi->ssa_temp_index()); | |
| 184 | 160 |
| 185 kill->Add(phi->ssa_temp_index()); | 161 // If a phi input is not defined by the corresponding predecessor it |
| 186 live_in->Remove(phi->ssa_temp_index()); | 162 // must be marked live-in for that predecessor. |
| 163 for (intptr_t k = 0; k < phi->InputCount(); k++) { | |
| 164 Value* val = phi->InputAt(k); | |
| 165 if (val->BindsToConstant()) continue; | |
| 187 | 166 |
| 188 // If phi-operand is not defined by a predecessor it must be marked | 167 BlockEntryInstr* pred = block->PredecessorAt(k); |
| 189 // live-in for a predecessor. | 168 const intptr_t use = val->definition()->ssa_temp_index(); |
| 190 for (intptr_t k = 0; k < phi->InputCount(); k++) { | 169 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 191 Value* val = phi->InputAt(k); | 170 live_in_[pred->postorder_number()]->Add(use); |
| 192 if (val->BindsToConstant()) continue; | |
| 193 | |
| 194 BlockEntryInstr* pred = block->PredecessorAt(k); | |
| 195 const intptr_t use = val->definition()->ssa_temp_index(); | |
| 196 if (!kill_[pred->postorder_number()]->Contains(use)) { | |
| 197 live_in_[pred->postorder_number()]->Add(use); | |
| 198 } | |
| 199 } | 171 } |
| 200 } | 172 } |
| 201 } | 173 } |
| 202 } | 174 } |
| 203 } | 175 } |
| 204 | 176 |
| 205 // Process initial definitions, ie, constants and incoming parameters. | 177 // Process initial definitions, ie, constants and incoming parameters. |
| 206 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 178 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 207 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 179 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 208 intptr_t vreg = (*graph_entry->initial_definitions())[i]->ssa_temp_index(); | 180 intptr_t vreg = (*graph_entry->initial_definitions())[i]->ssa_temp_index(); |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 689 const intptr_t pos = goto_instr->lifetime_position(); | 661 const intptr_t pos = goto_instr->lifetime_position(); |
| 690 | 662 |
| 691 JoinEntryInstr* join = goto_instr->successor(); | 663 JoinEntryInstr* join = goto_instr->successor(); |
| 692 ASSERT(join != NULL); | 664 ASSERT(join != NULL); |
| 693 | 665 |
| 694 // Search for the index of the current block in the predecessors of | 666 // Search for the index of the current block in the predecessors of |
| 695 // the join. | 667 // the join. |
| 696 const intptr_t pred_idx = join->IndexOfPredecessor(block); | 668 const intptr_t pred_idx = join->IndexOfPredecessor(block); |
| 697 | 669 |
| 698 // Record the corresponding phi input use for each phi. | 670 // Record the corresponding phi input use for each phi. |
| 699 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | |
| 700 intptr_t move_idx = 0; | 671 intptr_t move_idx = 0; |
| 701 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { | 672 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 702 PhiInstr* phi = (*phis)[phi_idx]; | 673 PhiInstr* phi = it.Current(); |
| 703 if (phi == NULL) continue; | |
| 704 | |
| 705 Value* val = phi->InputAt(pred_idx); | 674 Value* val = phi->InputAt(pred_idx); |
| 706 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); | 675 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); |
| 707 | 676 |
| 708 ConstantInstr* constant = val->definition()->AsConstant(); | 677 ConstantInstr* constant = val->definition()->AsConstant(); |
| 709 if (constant != NULL) { | 678 if (constant != NULL) { |
| 710 move->set_src(Location::Constant(constant->value())); | 679 move->set_src(Location::Constant(constant->value())); |
| 711 move_idx++; | 680 move_idx++; |
| 712 continue; | 681 continue; |
| 713 } | 682 } |
| 714 | 683 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 737 | 706 |
| 738 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 707 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { |
| 739 // If this block is a join we need to add destinations of phi | 708 // If this block is a join we need to add destinations of phi |
| 740 // resolution moves to phi's live range so that register allocator will | 709 // resolution moves to phi's live range so that register allocator will |
| 741 // fill them with moves. | 710 // fill them with moves. |
| 742 JoinEntryInstr* join = block->AsJoinEntry(); | 711 JoinEntryInstr* join = block->AsJoinEntry(); |
| 743 if (join == NULL) return; | 712 if (join == NULL) return; |
| 744 | 713 |
| 745 // All uses are recorded at the start position in the block. | 714 // All uses are recorded at the start position in the block. |
| 746 const intptr_t pos = join->start_pos(); | 715 const intptr_t pos = join->start_pos(); |
| 747 | |
| 748 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | |
| 749 if (phis == NULL) return; | |
| 750 | |
| 751 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); | 716 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); |
| 752 | |
| 753 intptr_t move_idx = 0; | 717 intptr_t move_idx = 0; |
| 754 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { | 718 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 755 PhiInstr* phi = (*phis)[phi_idx]; | 719 PhiInstr* phi = it.Current(); |
| 756 if (phi == NULL) continue; | 720 ASSERT(phi != NULL); |
| 757 | |
| 758 const intptr_t vreg = phi->ssa_temp_index(); | 721 const intptr_t vreg = phi->ssa_temp_index(); |
| 759 ASSERT(vreg != -1); | 722 ASSERT(vreg >= 0); |
| 760 | 723 |
| 761 // Expected shape of live range: | 724 // Expected shape of live range: |
| 762 // | 725 // |
| 763 // B | 726 // B |
| 764 // phi [-------- | 727 // phi [-------- |
| 765 // | 728 // |
| 766 LiveRange* range = GetLiveRange(vreg); | 729 LiveRange* range = GetLiveRange(vreg); |
| 767 range->DefineAt(pos); // Shorten live range. | 730 range->DefineAt(pos); // Shorten live range. |
| 768 | 731 |
| 769 if (is_loop_header) range->mark_loop_phi(); | 732 if (is_loop_header) range->mark_loop_phi(); |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1176 } | 1139 } |
| 1177 | 1140 |
| 1178 // Create parallel moves in join predecessors. This must be done after | 1141 // Create parallel moves in join predecessors. This must be done after |
| 1179 // all instructions are numbered. | 1142 // all instructions are numbered. |
| 1180 for (intptr_t i = block_count - 1; i >= 0; i--) { | 1143 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| 1181 BlockEntryInstr* block = postorder_[i]; | 1144 BlockEntryInstr* block = postorder_[i]; |
| 1182 | 1145 |
| 1183 // For join entry predecessors create phi resolution moves if | 1146 // For join entry predecessors create phi resolution moves if |
| 1184 // necessary. They will be populated by the register allocator. | 1147 // necessary. They will be populated by the register allocator. |
| 1185 JoinEntryInstr* join = block->AsJoinEntry(); | 1148 JoinEntryInstr* join = block->AsJoinEntry(); |
| 1186 if ((join != NULL) && (join->phi_count() > 0)) { | 1149 if ((join != NULL) && |
| 1187 const intptr_t phi_count = join->phi_count(); | 1150 (join->phis() != NULL) && |
| 1151 !join->phis()->is_empty()) { | |
| 1152 const intptr_t phi_count = join->phis()->length(); | |
| 1188 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 1153 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 1189 // Insert the move between the last two instructions of the | 1154 // Insert the move between the last two instructions of the |
| 1190 // predecessor block (all such blocks have at least two instructions: | 1155 // predecessor block (all such blocks have at least two instructions: |
| 1191 // the block entry and goto instructions.) | 1156 // the block entry and goto instructions.) |
| 1192 Instruction* last = block->PredecessorAt(i)->last_instruction(); | 1157 Instruction* last = block->PredecessorAt(i)->last_instruction(); |
| 1193 ASSERT(last->IsGoto()); | 1158 ASSERT(last->IsGoto()); |
| 1194 | 1159 |
| 1195 ParallelMoveInstr* move = last->AsGoto()->GetParallelMove(); | 1160 ParallelMoveInstr* move = last->AsGoto()->GetParallelMove(); |
| 1196 | 1161 |
| 1197 // Populate the ParallelMove with empty moves. | 1162 // Populate the ParallelMove with empty moves. |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1749 (free_until >= loop_header->last_block()->end_pos()) && | 1714 (free_until >= loop_header->last_block()->end_pos()) && |
| 1750 loop_header->backedge_interference()->Contains(unallocated->vreg())) { | 1715 loop_header->backedge_interference()->Contains(unallocated->vreg())) { |
| 1751 ASSERT(static_cast<intptr_t>(kNumberOfFpuRegisters) <= | 1716 ASSERT(static_cast<intptr_t>(kNumberOfFpuRegisters) <= |
| 1752 kNumberOfCpuRegisters); | 1717 kNumberOfCpuRegisters); |
| 1753 bool used_on_backedge[kNumberOfCpuRegisters] = { false }; | 1718 bool used_on_backedge[kNumberOfCpuRegisters] = { false }; |
| 1754 | 1719 |
| 1755 for (PhiIterator it(loop_header->entry()->AsJoinEntry()); | 1720 for (PhiIterator it(loop_header->entry()->AsJoinEntry()); |
| 1756 !it.Done(); | 1721 !it.Done(); |
| 1757 it.Advance()) { | 1722 it.Advance()) { |
| 1758 PhiInstr* phi = it.Current(); | 1723 PhiInstr* phi = it.Current(); |
| 1759 if (phi->is_alive()) { | 1724 ASSERT(phi->is_alive()); |
| 1760 const intptr_t phi_vreg = phi->ssa_temp_index(); | 1725 const intptr_t phi_vreg = phi->ssa_temp_index(); |
| 1761 LiveRange* range = GetLiveRange(phi_vreg); | 1726 LiveRange* range = GetLiveRange(phi_vreg); |
| 1762 if (range->assigned_location().kind() == register_kind_) { | 1727 if (range->assigned_location().kind() == register_kind_) { |
| 1763 const intptr_t reg = range->assigned_location().register_code(); | 1728 const intptr_t reg = range->assigned_location().register_code(); |
| 1764 | 1729 |
| 1765 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { | 1730 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { |
| 1766 used_on_backedge[reg] = true; | 1731 used_on_backedge[reg] = true; |
| 1767 } | |
| 1768 } | 1732 } |
| 1769 } | 1733 } |
| 1770 } | 1734 } |
| 1771 | 1735 |
| 1772 if (used_on_backedge[candidate]) { | 1736 if (used_on_backedge[candidate]) { |
| 1773 TRACE_ALLOC(OS::Print( | 1737 TRACE_ALLOC(OS::Print( |
| 1774 "considering %s for v%"Pd": has interference on the back edge" | 1738 "considering %s for v%"Pd": has interference on the back edge" |
| 1775 " {loop [%"Pd", %"Pd")}\n", | 1739 " {loop [%"Pd", %"Pd")}\n", |
| 1776 MakeRegisterLocation(candidate, Location::kDouble).Name(), | 1740 MakeRegisterLocation(candidate, Location::kDouble).Name(), |
| 1777 unallocated->vreg(), | 1741 unallocated->vreg(), |
| (...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2439 mint_values_->Add(defn->ssa_temp_index()); | 2403 mint_values_->Add(defn->ssa_temp_index()); |
| 2440 } | 2404 } |
| 2441 } | 2405 } |
| 2442 } | 2406 } |
| 2443 } | 2407 } |
| 2444 | 2408 |
| 2445 | 2409 |
| 2446 void FlowGraphAllocator::AllocateRegisters() { | 2410 void FlowGraphAllocator::AllocateRegisters() { |
| 2447 CollectRepresentations(); | 2411 CollectRepresentations(); |
| 2448 | 2412 |
| 2449 EliminateEnvironmentUses(); | 2413 EliminateEnvironments(); |
| 2450 | 2414 |
| 2451 AnalyzeLiveness(); | 2415 AnalyzeLiveness(); |
| 2452 | 2416 |
| 2453 NumberInstructions(); | 2417 NumberInstructions(); |
| 2454 | 2418 |
| 2455 DiscoverLoops(); | 2419 DiscoverLoops(); |
| 2456 | 2420 |
| 2457 BuildLiveRanges(); | 2421 BuildLiveRanges(); |
| 2458 | 2422 |
| 2459 if (FLAG_print_ssa_liveness) { | 2423 if (FLAG_print_ssa_liveness) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2511 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2475 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2512 function.ToFullyQualifiedCString()); | 2476 function.ToFullyQualifiedCString()); |
| 2513 FlowGraphPrinter printer(flow_graph_, true); | 2477 FlowGraphPrinter printer(flow_graph_, true); |
| 2514 printer.PrintBlocks(); | 2478 printer.PrintBlocks(); |
| 2515 OS::Print("----------------------------------------------\n"); | 2479 OS::Print("----------------------------------------------\n"); |
| 2516 } | 2480 } |
| 2517 } | 2481 } |
| 2518 | 2482 |
| 2519 | 2483 |
| 2520 } // namespace dart | 2484 } // namespace dart |
| OLD | NEW |