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 16 matching lines...) Expand all Loading... |
27 } while (0) | 27 } while (0) |
28 #else | 28 #else |
29 #define TRACE_ALLOC(statement) | 29 #define TRACE_ALLOC(statement) |
30 #endif | 30 #endif |
31 | 31 |
32 | 32 |
33 static const intptr_t kNoVirtualRegister = -1; | 33 static const intptr_t kNoVirtualRegister = -1; |
34 static const intptr_t kTempVirtualRegister = -2; | 34 static const intptr_t kTempVirtualRegister = -2; |
35 static const intptr_t kIllegalPosition = -1; | 35 static const intptr_t kIllegalPosition = -1; |
36 static const intptr_t kMaxPosition = 0x7FFFFFFF; | 36 static const intptr_t kMaxPosition = 0x7FFFFFFF; |
| 37 static const intptr_t kPairVirtualRegisterOffset = 1; |
| 38 |
| 39 // Definitions which have pair representations |
| 40 // (kPairOfTagged or kPairOfUnboxedDouble) use two virtual register names. |
| 41 // At SSA index allocation time each definition reserves two SSA indexes, |
| 42 // the second index is only used for pairs. This function maps from the first |
| 43 // SSA index to the second. |
| 44 static intptr_t ToSecondPairVreg(intptr_t vreg) { |
| 45 // Map vreg to its pair vreg. |
| 46 return vreg + kPairVirtualRegisterOffset; |
| 47 } |
| 48 |
37 | 49 |
38 static intptr_t MinPosition(intptr_t a, intptr_t b) { | 50 static intptr_t MinPosition(intptr_t a, intptr_t b) { |
39 return (a < b) ? a : b; | 51 return (a < b) ? a : b; |
40 } | 52 } |
41 | 53 |
42 | 54 |
43 static bool IsInstructionStartPosition(intptr_t pos) { | 55 static bool IsInstructionStartPosition(intptr_t pos) { |
44 return (pos & 1) == 0; | 56 return (pos & 1) == 0; |
45 } | 57 } |
46 | 58 |
(...skipping 20 matching lines...) Expand all Loading... |
67 block_order_(flow_graph.reverse_postorder()), | 79 block_order_(flow_graph.reverse_postorder()), |
68 postorder_(flow_graph.postorder()), | 80 postorder_(flow_graph.postorder()), |
69 liveness_(flow_graph), | 81 liveness_(flow_graph), |
70 vreg_count_(flow_graph.max_virtual_register_number()), | 82 vreg_count_(flow_graph.max_virtual_register_number()), |
71 live_ranges_(flow_graph.max_virtual_register_number()), | 83 live_ranges_(flow_graph.max_virtual_register_number()), |
72 cpu_regs_(), | 84 cpu_regs_(), |
73 fpu_regs_(), | 85 fpu_regs_(), |
74 blocked_cpu_registers_(), | 86 blocked_cpu_registers_(), |
75 blocked_fpu_registers_(), | 87 blocked_fpu_registers_(), |
76 cpu_spill_slot_count_(0) { | 88 cpu_spill_slot_count_(0) { |
77 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 89 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 90 live_ranges_.Add(NULL); |
| 91 } |
78 for (intptr_t i = 0; i < vreg_count_; i++) { | 92 for (intptr_t i = 0; i < vreg_count_; i++) { |
79 value_representations_.Add(kNoRepresentation); | 93 value_representations_.Add(kNoRepresentation); |
80 } | 94 } |
81 | 95 |
82 // All registers are marked as "not blocked" (array initialized to false). | 96 // All registers are marked as "not blocked" (array initialized to false). |
83 // Mark the unavailable ones as "blocked" (true). | 97 // Mark the unavailable ones as "blocked" (true). |
84 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { | 98 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { |
85 blocked_cpu_registers_[i] = true; | 99 blocked_cpu_registers_[i] = true; |
86 } | 100 } |
87 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { | 101 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { |
(...skipping 19 matching lines...) Expand all Loading... |
107 for (intptr_t i = 0; i < block_count; i++) { | 121 for (intptr_t i = 0; i < block_count; i++) { |
108 BlockEntryInstr* block = postorder_[i]; | 122 BlockEntryInstr* block = postorder_[i]; |
109 | 123 |
110 BitVector* kill = kill_[i]; | 124 BitVector* kill = kill_[i]; |
111 BitVector* live_in = live_in_[i]; | 125 BitVector* live_in = live_in_[i]; |
112 | 126 |
113 // Iterate backwards starting at the last instruction. | 127 // Iterate backwards starting at the last instruction. |
114 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 128 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
115 Instruction* current = it.Current(); | 129 Instruction* current = it.Current(); |
116 | 130 |
| 131 // Initialize location summary for instruction. |
| 132 current->InitializeLocationSummary(true); // Optimizing. |
| 133 LocationSummary* locs = current->locs(); |
| 134 |
117 // Handle definitions. | 135 // Handle definitions. |
118 Definition* current_def = current->AsDefinition(); | 136 Definition* current_def = current->AsDefinition(); |
119 if ((current_def != NULL) && current_def->HasSSATemp()) { | 137 if ((current_def != NULL) && current_def->HasSSATemp()) { |
120 kill->Add(current_def->ssa_temp_index()); | 138 kill->Add(current_def->ssa_temp_index()); |
121 live_in->Remove(current_def->ssa_temp_index()); | 139 live_in->Remove(current_def->ssa_temp_index()); |
| 140 if (current_def->HasPairRepresentation()) { |
| 141 kill->Add(ToSecondPairVreg(current_def->ssa_temp_index())); |
| 142 live_in->Remove(ToSecondPairVreg(current_def->ssa_temp_index())); |
| 143 } |
122 } | 144 } |
123 | 145 |
124 // Handle uses. | 146 // Handle uses. |
125 current->InitializeLocationSummary(true); // Optimizing. | |
126 LocationSummary* locs = current->locs(); | |
127 ASSERT(locs->input_count() == current->InputCount()); | 147 ASSERT(locs->input_count() == current->InputCount()); |
128 for (intptr_t j = 0; j < current->InputCount(); j++) { | 148 for (intptr_t j = 0; j < current->InputCount(); j++) { |
129 Value* input = current->InputAt(j); | 149 Value* input = current->InputAt(j); |
130 const intptr_t use = input->definition()->ssa_temp_index(); | |
131 | 150 |
132 ASSERT(!locs->in(j).IsConstant() || input->BindsToConstant()); | 151 ASSERT(!locs->in(j).IsConstant() || input->BindsToConstant()); |
133 if (locs->in(j).IsConstant()) continue; | 152 if (locs->in(j).IsConstant()) continue; |
134 | 153 |
135 live_in->Add(use); | 154 live_in->Add(input->definition()->ssa_temp_index()); |
| 155 if (input->definition()->HasPairRepresentation()) { |
| 156 live_in->Add(ToSecondPairVreg(input->definition()->ssa_temp_index())); |
| 157 } |
136 } | 158 } |
137 | 159 |
138 // Add non-argument uses from the deoptimization environment (pushed | 160 // Add non-argument uses from the deoptimization environment (pushed |
139 // arguments are not allocated by the register allocator). | 161 // arguments are not allocated by the register allocator). |
140 if (current->env() != NULL) { | 162 if (current->env() != NULL) { |
141 for (Environment::DeepIterator env_it(current->env()); | 163 for (Environment::DeepIterator env_it(current->env()); |
142 !env_it.Done(); | 164 !env_it.Done(); |
143 env_it.Advance()) { | 165 env_it.Advance()) { |
144 Definition* defn = env_it.CurrentValue()->definition(); | 166 Definition* defn = env_it.CurrentValue()->definition(); |
145 if (defn->IsMaterializeObject()) { | 167 if (defn->IsMaterializeObject()) { |
146 // MaterializeObject instruction is not in the graph. | 168 // MaterializeObject instruction is not in the graph. |
147 // Treat its inputs as part of the environment. | 169 // Treat its inputs as part of the environment. |
148 for (intptr_t i = 0; i < defn->InputCount(); i++) { | 170 for (intptr_t i = 0; i < defn->InputCount(); i++) { |
149 if (!defn->InputAt(i)->BindsToConstant()) { | 171 if (!defn->InputAt(i)->BindsToConstant()) { |
150 live_in->Add(defn->InputAt(i)->definition()->ssa_temp_index()); | 172 intptr_t idx = defn->InputAt(i)->definition()->ssa_temp_index(); |
| 173 live_in->Add(idx); |
151 } | 174 } |
152 } | 175 } |
153 } else if (!defn->IsPushArgument() && !defn->IsConstant()) { | 176 } else if (!defn->IsPushArgument() && !defn->IsConstant()) { |
154 live_in->Add(defn->ssa_temp_index()); | 177 live_in->Add(defn->ssa_temp_index()); |
| 178 if (defn->HasPairRepresentation()) { |
| 179 live_in->Add(ToSecondPairVreg(defn->ssa_temp_index())); |
| 180 } |
155 } | 181 } |
156 } | 182 } |
157 } | 183 } |
158 } | 184 } |
159 | 185 |
160 // Handle phis. | 186 // Handle phis. |
161 if (block->IsJoinEntry()) { | 187 if (block->IsJoinEntry()) { |
162 JoinEntryInstr* join = block->AsJoinEntry(); | 188 JoinEntryInstr* join = block->AsJoinEntry(); |
163 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 189 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 190 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
164 PhiInstr* phi = it.Current(); | 191 PhiInstr* phi = it.Current(); |
165 ASSERT(phi != NULL); | 192 ASSERT(phi != NULL); |
166 kill->Add(phi->ssa_temp_index()); | 193 kill->Add(phi->ssa_temp_index()); |
167 live_in->Remove(phi->ssa_temp_index()); | 194 live_in->Remove(phi->ssa_temp_index()); |
168 | 195 |
169 // If a phi input is not defined by the corresponding predecessor it | 196 // If a phi input is not defined by the corresponding predecessor it |
170 // must be marked live-in for that predecessor. | 197 // must be marked live-in for that predecessor. |
171 for (intptr_t k = 0; k < phi->InputCount(); k++) { | 198 for (intptr_t k = 0; k < phi->InputCount(); k++) { |
172 Value* val = phi->InputAt(k); | 199 Value* val = phi->InputAt(k); |
173 if (val->BindsToConstant()) continue; | 200 if (val->BindsToConstant()) continue; |
174 | 201 |
175 BlockEntryInstr* pred = block->PredecessorAt(k); | 202 BlockEntryInstr* pred = block->PredecessorAt(k); |
176 const intptr_t use = val->definition()->ssa_temp_index(); | 203 const intptr_t use = val->definition()->ssa_temp_index(); |
177 if (!kill_[pred->postorder_number()]->Contains(use)) { | 204 if (!kill_[pred->postorder_number()]->Contains(use)) { |
178 live_in_[pred->postorder_number()]->Add(use); | 205 live_in_[pred->postorder_number()]->Add(use); |
179 } | 206 } |
180 } | 207 } |
181 } | 208 } |
182 } else if (block->IsCatchBlockEntry()) { | 209 } else if (block->IsCatchBlockEntry()) { |
183 // Process initial definitions. | 210 // Process initial definitions. |
184 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); | 211 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); |
185 for (intptr_t i = 0; | 212 for (intptr_t i = 0; |
186 i < catch_entry->initial_definitions()->length(); | 213 i < catch_entry->initial_definitions()->length(); |
187 i++) { | 214 i++) { |
188 intptr_t vreg = | 215 Definition* def = (*catch_entry->initial_definitions())[i]; |
189 (*catch_entry->initial_definitions())[i]->ssa_temp_index(); | 216 const intptr_t vreg = def->ssa_temp_index(); |
190 kill_[catch_entry->postorder_number()]->Add(vreg); | 217 kill_[catch_entry->postorder_number()]->Add(vreg); |
191 live_in_[catch_entry->postorder_number()]->Remove(vreg); | 218 live_in_[catch_entry->postorder_number()]->Remove(vreg); |
192 } | 219 } |
193 } | 220 } |
194 } | 221 } |
195 | 222 |
196 // Process initial definitions, ie, constants and incoming parameters. | 223 // Process initial definitions, ie, constants and incoming parameters. |
197 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { | 224 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { |
198 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); | 225 Definition* def = (*graph_entry_->initial_definitions())[i]; |
| 226 const intptr_t vreg = def->ssa_temp_index(); |
199 kill_[graph_entry_->postorder_number()]->Add(vreg); | 227 kill_[graph_entry_->postorder_number()]->Add(vreg); |
200 live_in_[graph_entry_->postorder_number()]->Remove(vreg); | 228 live_in_[graph_entry_->postorder_number()]->Remove(vreg); |
201 } | 229 } |
202 | 230 |
203 // Update initial live_in sets to match live_out sets. Has to be | 231 // Update initial live_in sets to match live_out sets. Has to be |
204 // done in a separate path because of backwards branches. | 232 // done in a separate path because of backwards branches. |
205 for (intptr_t i = 0; i < block_count; i++) { | 233 for (intptr_t i = 0; i < block_count; i++) { |
206 UpdateLiveIn(*postorder_[i]); | 234 UpdateLiveIn(*postorder_[i]); |
207 } | 235 } |
208 } | 236 } |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 return Location::kRegister; | 628 return Location::kRegister; |
601 } | 629 } |
602 } | 630 } |
603 | 631 |
604 | 632 |
605 static Location::Kind RegisterKindForResult(Instruction* instr) { | 633 static Location::Kind RegisterKindForResult(Instruction* instr) { |
606 if ((instr->representation() == kUnboxedDouble) || | 634 if ((instr->representation() == kUnboxedDouble) || |
607 (instr->representation() == kUnboxedMint) || | 635 (instr->representation() == kUnboxedMint) || |
608 (instr->representation() == kUnboxedFloat32x4) || | 636 (instr->representation() == kUnboxedFloat32x4) || |
609 (instr->representation() == kUnboxedInt32x4) || | 637 (instr->representation() == kUnboxedInt32x4) || |
610 (instr->representation() == kUnboxedFloat64x2)) { | 638 (instr->representation() == kUnboxedFloat64x2) || |
| 639 (instr->representation() == kPairOfUnboxedDouble)) { |
611 return Location::kFpuRegister; | 640 return Location::kFpuRegister; |
612 } else { | 641 } else { |
613 return Location::kRegister; | 642 return Location::kRegister; |
614 } | 643 } |
615 } | 644 } |
616 | 645 |
617 | 646 |
618 // | 647 // |
619 // When describing shape of live ranges in comments below we are going to use | 648 // When describing shape of live ranges in comments below we are going to use |
620 // the following notation: | 649 // the following notation: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 JoinEntryInstr* join = goto_instr->successor(); | 688 JoinEntryInstr* join = goto_instr->successor(); |
660 ASSERT(join != NULL); | 689 ASSERT(join != NULL); |
661 | 690 |
662 // Search for the index of the current block in the predecessors of | 691 // Search for the index of the current block in the predecessors of |
663 // the join. | 692 // the join. |
664 const intptr_t pred_idx = join->IndexOfPredecessor(block); | 693 const intptr_t pred_idx = join->IndexOfPredecessor(block); |
665 | 694 |
666 // Record the corresponding phi input use for each phi. | 695 // Record the corresponding phi input use for each phi. |
667 intptr_t move_idx = 0; | 696 intptr_t move_idx = 0; |
668 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 697 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 698 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
669 PhiInstr* phi = it.Current(); | 699 PhiInstr* phi = it.Current(); |
670 Value* val = phi->InputAt(pred_idx); | 700 Value* val = phi->InputAt(pred_idx); |
671 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); | 701 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); |
672 | 702 |
673 ConstantInstr* constant = val->definition()->AsConstant(); | 703 ConstantInstr* constant = val->definition()->AsConstant(); |
674 if (constant != NULL) { | 704 if (constant != NULL) { |
675 move->set_src(Location::Constant(constant->value())); | 705 move->set_src(Location::Constant(constant->value())); |
676 move_idx++; | 706 move_idx++; |
677 continue; | 707 continue; |
678 } | 708 } |
(...skipping 23 matching lines...) Expand all Loading... |
702 | 732 |
703 void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) { | 733 void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) { |
704 // For join blocks we need to add destinations of phi resolution moves | 734 // For join blocks we need to add destinations of phi resolution moves |
705 // to phi's live range so that register allocator will fill them with moves. | 735 // to phi's live range so that register allocator will fill them with moves. |
706 | 736 |
707 // All uses are recorded at the start position in the block. | 737 // All uses are recorded at the start position in the block. |
708 const intptr_t pos = join->start_pos(); | 738 const intptr_t pos = join->start_pos(); |
709 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); | 739 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); |
710 intptr_t move_idx = 0; | 740 intptr_t move_idx = 0; |
711 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 741 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 742 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
712 PhiInstr* phi = it.Current(); | 743 PhiInstr* phi = it.Current(); |
713 ASSERT(phi != NULL); | 744 ASSERT(phi != NULL); |
714 const intptr_t vreg = phi->ssa_temp_index(); | 745 const intptr_t vreg = phi->ssa_temp_index(); |
715 ASSERT(vreg >= 0); | 746 ASSERT(vreg >= 0); |
716 | 747 |
717 // Expected shape of live range: | 748 // Expected shape of live range: |
718 // | 749 // |
719 // B | 750 // B |
720 // phi [-------- | 751 // phi [-------- |
721 // | 752 // |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 MaterializeObjectInstr* mat = def->AsMaterializeObject(); | 820 MaterializeObjectInstr* mat = def->AsMaterializeObject(); |
790 if (mat != NULL) { | 821 if (mat != NULL) { |
791 // MaterializeObject itself produces no value. But its uses | 822 // MaterializeObject itself produces no value. But its uses |
792 // are treated as part of the environment: allocated locations | 823 // are treated as part of the environment: allocated locations |
793 // will be used when building deoptimization data. | 824 // will be used when building deoptimization data. |
794 locations[i] = Location::NoLocation(); | 825 locations[i] = Location::NoLocation(); |
795 ProcessMaterializationUses(block, block_start_pos, use_pos, mat); | 826 ProcessMaterializationUses(block, block_start_pos, use_pos, mat); |
796 continue; | 827 continue; |
797 } | 828 } |
798 | 829 |
799 const intptr_t vreg = def->ssa_temp_index(); | 830 LiveRange* range = GetLiveRange(def->ssa_temp_index()); |
800 LiveRange* range = GetLiveRange(vreg); | |
801 range->AddUseInterval(block_start_pos, use_pos); | 831 range->AddUseInterval(block_start_pos, use_pos); |
802 range->AddUse(use_pos, &locations[i]); | 832 range->AddUse(use_pos, &locations[i]); |
| 833 |
| 834 if (def->HasPairRepresentation()) { |
| 835 LiveRange* range = |
| 836 GetLiveRange(ToSecondPairVreg(def->ssa_temp_index())); |
| 837 range->AddUseInterval(block_start_pos, use_pos); |
| 838 range->AddUse(use_pos, &locations[i]); |
| 839 } |
803 } | 840 } |
804 | 841 |
805 env->set_locations(locations); | 842 env->set_locations(locations); |
806 env = env->outer(); | 843 env = env->outer(); |
807 } | 844 } |
808 } | 845 } |
809 | 846 |
810 | 847 |
811 void FlowGraphAllocator::ProcessMaterializationUses( | 848 void FlowGraphAllocator::ProcessMaterializationUses( |
812 BlockEntryInstr* block, | 849 BlockEntryInstr* block, |
(...skipping 14 matching lines...) Expand all Loading... |
827 Definition* def = mat->InputAt(i)->definition(); | 864 Definition* def = mat->InputAt(i)->definition(); |
828 | 865 |
829 ConstantInstr* constant = def->AsConstant(); | 866 ConstantInstr* constant = def->AsConstant(); |
830 if (constant != NULL) { | 867 if (constant != NULL) { |
831 locations[i] = Location::Constant(constant->value()); | 868 locations[i] = Location::Constant(constant->value()); |
832 continue; | 869 continue; |
833 } | 870 } |
834 | 871 |
835 locations[i] = Location::Any(); | 872 locations[i] = Location::Any(); |
836 | 873 |
837 const intptr_t vreg = def->ssa_temp_index(); | 874 LiveRange* range = GetLiveRange(def->ssa_temp_index()); |
838 LiveRange* range = GetLiveRange(vreg); | |
839 range->AddUseInterval(block_start_pos, use_pos); | 875 range->AddUseInterval(block_start_pos, use_pos); |
840 range->AddUse(use_pos, &locations[i]); | 876 range->AddUse(use_pos, &locations[i]); |
| 877 if (def->HasPairRepresentation()) { |
| 878 LiveRange* range = GetLiveRange(ToSecondPairVreg(def->ssa_temp_index())); |
| 879 range->AddUseInterval(block_start_pos, use_pos); |
| 880 range->AddUse(use_pos, &locations[i]); |
| 881 } |
841 } | 882 } |
842 | 883 |
843 mat->set_locations(locations); | 884 mat->set_locations(locations); |
844 } | 885 } |
845 | 886 |
846 | 887 |
| 888 void FlowGraphAllocator::ProcessOneInput(BlockEntryInstr* block, |
| 889 intptr_t pos, |
| 890 Location* in_ref, |
| 891 Value* input, |
| 892 intptr_t vreg) { |
| 893 ASSERT(in_ref != NULL); |
| 894 ASSERT(!in_ref->IsPairLocation()); |
| 895 ASSERT(input != NULL); |
| 896 ASSERT(block != NULL); |
| 897 LiveRange* range = GetLiveRange(vreg); |
| 898 if (in_ref->IsMachineRegister()) { |
| 899 // Input is expected in a fixed register. Expected shape of |
| 900 // live ranges: |
| 901 // |
| 902 // j' i i' |
| 903 // value --* |
| 904 // register [-----) |
| 905 // |
| 906 MoveOperands* move = |
| 907 AddMoveAt(pos - 1, *in_ref, Location::Any()); |
| 908 BlockLocation(*in_ref, pos - 1, pos + 1); |
| 909 range->AddUseInterval(block->start_pos(), pos - 1); |
| 910 range->AddHintedUse(pos - 1, move->src_slot(), in_ref); |
| 911 } else if (in_ref->IsUnallocated()) { |
| 912 if (in_ref->policy() == Location::kWritableRegister) { |
| 913 // Writable unallocated input. Expected shape of |
| 914 // live ranges: |
| 915 // |
| 916 // j' i i' |
| 917 // value --* |
| 918 // temp [------) |
| 919 MoveOperands* move = AddMoveAt(pos - 1, |
| 920 Location::RequiresRegister(), |
| 921 Location::PrefersRegister()); |
| 922 |
| 923 // Add uses to the live range of the input. |
| 924 range->AddUseInterval(block->start_pos(), pos - 1); |
| 925 range->AddUse(pos - 1, move->src_slot()); |
| 926 |
| 927 // Create live range for the temporary. |
| 928 LiveRange* temp = MakeLiveRangeForTemporary(); |
| 929 temp->AddUseInterval(pos - 1, pos + 1); |
| 930 temp->AddHintedUse(pos - 1, in_ref, move->src_slot()); |
| 931 temp->AddUse(pos + 1, move->dest_slot()); |
| 932 *in_ref = Location::RequiresRegister(); |
| 933 CompleteRange(temp, RegisterKindFromPolicy(*in_ref)); |
| 934 } else { |
| 935 // Normal unallocated input. Expected shape of |
| 936 // live ranges: |
| 937 // |
| 938 // i i' |
| 939 // value -----* |
| 940 // |
| 941 range->AddUseInterval(block->start_pos(), pos + 1); |
| 942 range->AddUse(pos + 1, in_ref); |
| 943 } |
| 944 } else { |
| 945 ASSERT(in_ref->IsConstant()); |
| 946 } |
| 947 } |
| 948 |
| 949 |
| 950 void FlowGraphAllocator::ProcessOneOutput(BlockEntryInstr* block, |
| 951 Instruction* current, |
| 952 intptr_t pos, |
| 953 Location* out, |
| 954 Definition* def, |
| 955 intptr_t vreg, |
| 956 bool output_same_as_first_input, |
| 957 Location* in_ref, |
| 958 Definition* input, |
| 959 intptr_t input_vreg, |
| 960 BitVector* interference_set) { |
| 961 ASSERT(out != NULL); |
| 962 ASSERT(!out->IsPairLocation()); |
| 963 ASSERT(def != NULL); |
| 964 ASSERT(block != NULL); |
| 965 |
| 966 LiveRange* range = vreg >= 0 ? |
| 967 GetLiveRange(vreg) : MakeLiveRangeForTemporary(); |
| 968 |
| 969 // Process output and finalize its liverange. |
| 970 if (out->IsMachineRegister()) { |
| 971 // Fixed output location. Expected shape of live range: |
| 972 // |
| 973 // i i' j j' |
| 974 // register [--) |
| 975 // output [------- |
| 976 // |
| 977 BlockLocation(*out, pos, pos + 1); |
| 978 |
| 979 if (range->vreg() == kTempVirtualRegister) return; |
| 980 |
| 981 // We need to emit move connecting fixed register with another location |
| 982 // that will be allocated for this output's live range. |
| 983 // Special case: fixed output followed by a fixed input last use. |
| 984 UsePosition* use = range->first_use(); |
| 985 |
| 986 // If the value has no uses we don't need to allocate it. |
| 987 if (use == NULL) return; |
| 988 |
| 989 if (use->pos() == (pos + 1)) { |
| 990 ASSERT(use->location_slot()->IsUnallocated()); |
| 991 *(use->location_slot()) = *out; |
| 992 |
| 993 // Remove first use. It was allocated. |
| 994 range->set_first_use(range->first_use()->next()); |
| 995 } |
| 996 |
| 997 // Shorten live range to the point of definition, this might make the range |
| 998 // empty (if the only use immediately follows). If range is not empty add |
| 999 // move from a fixed register to an unallocated location. |
| 1000 range->DefineAt(pos + 1); |
| 1001 if (range->Start() == range->End()) return; |
| 1002 |
| 1003 MoveOperands* move = AddMoveAt(pos + 1, Location::Any(), *out); |
| 1004 range->AddHintedUse(pos + 1, move->dest_slot(), out); |
| 1005 } else if (output_same_as_first_input) { |
| 1006 ASSERT(in_ref != NULL); |
| 1007 ASSERT(input != NULL); |
| 1008 // Output register will contain a value of the first input at instruction's |
| 1009 // start. Expected shape of live ranges: |
| 1010 // |
| 1011 // i i' |
| 1012 // input #0 --* |
| 1013 // output [---- |
| 1014 // |
| 1015 ASSERT(in_ref->Equals(Location::RequiresRegister()) || |
| 1016 in_ref->Equals(Location::RequiresFpuRegister())); |
| 1017 |
| 1018 // TODO(johnmccutchan): Without this I get allocated a register instead |
| 1019 // of an FPU register. Figure out why. |
| 1020 |
| 1021 *out = *in_ref; |
| 1022 // Create move that will copy value between input and output. |
| 1023 MoveOperands* move = AddMoveAt(pos, |
| 1024 Location::RequiresRegister(), |
| 1025 Location::Any()); |
| 1026 |
| 1027 // Add uses to the live range of the input. |
| 1028 LiveRange* input_range = GetLiveRange(input_vreg); |
| 1029 input_range->AddUseInterval(block->start_pos(), pos); |
| 1030 input_range->AddUse(pos, move->src_slot()); |
| 1031 |
| 1032 // Shorten output live range to the point of definition and add both input |
| 1033 // and output uses slots to be filled by allocator. |
| 1034 range->DefineAt(pos); |
| 1035 range->AddHintedUse(pos, out, move->src_slot()); |
| 1036 range->AddUse(pos, move->dest_slot()); |
| 1037 range->AddUse(pos, in_ref); |
| 1038 |
| 1039 if ((interference_set != NULL) && |
| 1040 (range->vreg() >= 0) && |
| 1041 interference_set->Contains(range->vreg())) { |
| 1042 interference_set->Add(input->ssa_temp_index()); |
| 1043 } |
| 1044 } else { |
| 1045 // Normal unallocated location that requires a register. Expected shape of |
| 1046 // live range: |
| 1047 // |
| 1048 // i i' |
| 1049 // output [------- |
| 1050 // |
| 1051 ASSERT(out->Equals(Location::RequiresRegister()) || |
| 1052 out->Equals(Location::RequiresFpuRegister())); |
| 1053 |
| 1054 // Shorten live range to the point of definition and add use to be filled by |
| 1055 // allocator. |
| 1056 range->DefineAt(pos); |
| 1057 range->AddUse(pos, out); |
| 1058 } |
| 1059 |
| 1060 AssignSafepoints(range); |
| 1061 CompleteRange(range, RegisterKindForResult(current)); |
| 1062 } |
| 1063 |
| 1064 |
847 // Create and update live ranges corresponding to instruction's inputs, | 1065 // Create and update live ranges corresponding to instruction's inputs, |
848 // temporaries and output. | 1066 // temporaries and output. |
849 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block, | 1067 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block, |
850 Instruction* current, | 1068 Instruction* current, |
851 BitVector* interference_set) { | 1069 BitVector* interference_set) { |
852 LocationSummary* locs = current->locs(); | 1070 LocationSummary* locs = current->locs(); |
853 | 1071 |
854 Definition* def = current->AsDefinition(); | 1072 Definition* def = current->AsDefinition(); |
855 if ((def != NULL) && (def->AsConstant() != NULL)) { | 1073 if ((def != NULL) && (def->AsConstant() != NULL)) { |
| 1074 ASSERT(!def->HasPairRepresentation()); |
856 LiveRange* range = (def->ssa_temp_index() != -1) ? | 1075 LiveRange* range = (def->ssa_temp_index() != -1) ? |
857 GetLiveRange(def->ssa_temp_index()) : NULL; | 1076 GetLiveRange(def->ssa_temp_index()) : NULL; |
858 | 1077 |
859 // Drop definitions of constants that have no uses. | 1078 // Drop definitions of constants that have no uses. |
860 if ((range == NULL) || (range->first_use() == NULL)) { | 1079 if ((range == NULL) || (range->first_use() == NULL)) { |
861 locs->set_out(0, Location::NoLocation()); | 1080 locs->set_out(0, Location::NoLocation()); |
862 return; | 1081 return; |
863 } | 1082 } |
864 | 1083 |
865 // If this constant has only unconstrained uses convert them all | 1084 // If this constant has only unconstrained uses convert them all |
866 // to use the constant directly and drop this definition. | 1085 // to use the constant directly and drop this definition. |
867 // TODO(vegorov): improve allocation when we have enough registers to keep | 1086 // TODO(vegorov): improve allocation when we have enough registers to keep |
868 // constants used in the loop in them. | 1087 // constants used in the loop in them. |
869 if (HasOnlyUnconstrainedUses(range)) { | 1088 if (HasOnlyUnconstrainedUses(range)) { |
870 const Object& value = def->AsConstant()->value(); | 1089 const Object& value = def->AsConstant()->value(); |
871 range->set_assigned_location(Location::Constant(value)); | 1090 range->set_assigned_location(Location::Constant(value)); |
872 range->set_spill_slot(Location::Constant(value)); | 1091 range->set_spill_slot(Location::Constant(value)); |
873 range->finger()->Initialize(range); | 1092 range->finger()->Initialize(range); |
874 ConvertAllUses(range); | 1093 ConvertAllUses(range); |
875 | 1094 |
876 locs->set_out(0, Location::NoLocation()); | 1095 locs->set_out(0, Location::NoLocation()); |
877 return; | 1096 return; |
878 } | 1097 } |
879 } | 1098 } |
880 | 1099 |
881 const intptr_t pos = current->lifetime_position(); | 1100 const intptr_t pos = current->lifetime_position(); |
882 ASSERT(IsInstructionStartPosition(pos)); | 1101 ASSERT(IsInstructionStartPosition(pos)); |
883 | 1102 |
884 // Number of input locations and number of input operands have to agree. | |
885 ASSERT(locs->input_count() == current->InputCount()); | 1103 ASSERT(locs->input_count() == current->InputCount()); |
886 | 1104 |
887 // Normalize same-as-first-input output if input is specified as | 1105 // Normalize same-as-first-input output if input is specified as |
888 // fixed register. | 1106 // fixed register. |
889 if (locs->out(0).IsUnallocated() && | 1107 if (locs->out(0).IsUnallocated() && |
890 (locs->out(0).policy() == Location::kSameAsFirstInput) && | 1108 (locs->out(0).policy() == Location::kSameAsFirstInput) && |
891 (locs->in(0).IsMachineRegister())) { | 1109 (locs->in(0).IsMachineRegister())) { |
892 locs->set_out(0, locs->in(0)); | 1110 locs->set_out(0, locs->in(0)); |
893 } | 1111 } |
894 | 1112 |
895 const bool output_same_as_first_input = | 1113 const bool output_same_as_first_input = |
896 locs->out(0).IsUnallocated() && | 1114 locs->out(0).IsUnallocated() && |
897 (locs->out(0).policy() == Location::kSameAsFirstInput); | 1115 (locs->out(0).policy() == Location::kSameAsFirstInput); |
898 | 1116 |
899 // Add uses from the deoptimization environment. | 1117 // Add uses from the deoptimization environment. |
900 if (current->env() != NULL) ProcessEnvironmentUses(block, current); | 1118 if (current->env() != NULL) ProcessEnvironmentUses(block, current); |
901 | 1119 |
902 // Process inputs. | 1120 // Process inputs. |
903 // Skip the first input if output is specified with kSameAsFirstInput policy, | 1121 // Skip the first input if output is specified with kSameAsFirstInput policy, |
904 // they will be processed together at the very end. | 1122 // they will be processed together at the very end. |
905 for (intptr_t j = output_same_as_first_input ? 1 : 0; | 1123 { |
906 j < current->InputCount(); | 1124 for (intptr_t j = output_same_as_first_input ? 1 : 0; |
907 j++) { | 1125 j < locs->input_count(); |
908 Value* input = current->InputAt(j); | 1126 j++) { |
909 const intptr_t vreg = input->definition()->ssa_temp_index(); | 1127 // Determine if we are dealing with a value pair, and if so, whether |
910 LiveRange* range = GetLiveRange(vreg); | 1128 // the location is the first register or second register. |
911 | 1129 Value* input = current->InputAt(j); |
912 Location* in_ref = locs->in_slot(j); | 1130 Location* in_ref = locs->in_slot(j); |
913 | 1131 if (in_ref->IsPairLocation()) { |
914 if (in_ref->IsMachineRegister()) { | 1132 ASSERT(input->definition()->HasPairRepresentation()); |
915 // Input is expected in a fixed register. Expected shape of | 1133 PairLocation* pair = in_ref->AsPairLocation(); |
916 // live ranges: | 1134 const intptr_t vreg = input->definition()->ssa_temp_index(); |
917 // | 1135 // Each element of the pair is assigned it's own virtual register number |
918 // j' i i' | 1136 // and is allocated its own LiveRange. |
919 // value --* | 1137 ProcessOneInput(block, pos, pair->SlotAt(0), |
920 // register [-----) | 1138 input, vreg); |
921 // | 1139 ProcessOneInput(block, pos, pair->SlotAt(1), input, |
922 MoveOperands* move = | 1140 ToSecondPairVreg(vreg)); |
923 AddMoveAt(pos - 1, *in_ref, Location::Any()); | |
924 BlockLocation(*in_ref, pos - 1, pos + 1); | |
925 range->AddUseInterval(block->start_pos(), pos - 1); | |
926 range->AddHintedUse(pos - 1, move->src_slot(), in_ref); | |
927 } else if (in_ref->IsUnallocated()) { | |
928 if (in_ref->policy() == Location::kWritableRegister) { | |
929 // Writable unallocated input. Expected shape of | |
930 // live ranges: | |
931 // | |
932 // i i' | |
933 // value --* | |
934 // temp [--) | |
935 MoveOperands* move = AddMoveAt(pos, | |
936 Location::RequiresRegister(), | |
937 Location::PrefersRegister()); | |
938 | |
939 // Add uses to the live range of the input. | |
940 range->AddUseInterval(block->start_pos(), pos); | |
941 range->AddUse(pos, move->src_slot()); | |
942 | |
943 // Create live range for the temporary. | |
944 LiveRange* temp = MakeLiveRangeForTemporary(); | |
945 temp->AddUseInterval(pos, pos + 1); | |
946 temp->AddHintedUse(pos, in_ref, move->src_slot()); | |
947 temp->AddUse(pos, move->dest_slot()); | |
948 *in_ref = Location::RequiresRegister(); | |
949 CompleteRange(temp, RegisterKindFromPolicy(*in_ref)); | |
950 } else { | 1141 } else { |
951 // Normal unallocated input. Expected shape of | 1142 ProcessOneInput(block, pos, in_ref, input, |
952 // live ranges: | 1143 input->definition()->ssa_temp_index()); |
953 // | |
954 // i i' | |
955 // value -----* | |
956 // | |
957 range->AddUseInterval(block->start_pos(), pos + 1); | |
958 range->AddUse(pos + 1, in_ref); | |
959 } | 1144 } |
960 } else { | |
961 ASSERT(in_ref->IsConstant()); | |
962 } | 1145 } |
963 } | 1146 } |
964 | 1147 |
965 // Process temps. | 1148 // Process temps. |
966 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 1149 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
967 // Expected shape of live range: | 1150 // Expected shape of live range: |
968 // | 1151 // |
969 // i i' | 1152 // i i' |
970 // [--) | 1153 // [--) |
971 // | 1154 // |
972 | 1155 |
973 Location temp = locs->temp(j); | 1156 Location temp = locs->temp(j); |
| 1157 // We do not support pair locations for temporaries. |
| 1158 ASSERT(!temp.IsPairLocation()); |
974 if (temp.IsMachineRegister()) { | 1159 if (temp.IsMachineRegister()) { |
975 BlockLocation(temp, pos, pos + 1); | 1160 BlockLocation(temp, pos, pos + 1); |
976 } else if (temp.IsUnallocated()) { | 1161 } else if (temp.IsUnallocated()) { |
977 LiveRange* range = MakeLiveRangeForTemporary(); | 1162 LiveRange* range = MakeLiveRangeForTemporary(); |
978 range->AddUseInterval(pos, pos + 1); | 1163 range->AddUseInterval(pos, pos + 1); |
979 range->AddUse(pos, locs->temp_slot(j)); | 1164 range->AddUse(pos, locs->temp_slot(j)); |
980 CompleteRange(range, RegisterKindFromPolicy(temp)); | 1165 CompleteRange(range, RegisterKindFromPolicy(temp)); |
981 } else { | 1166 } else { |
982 UNREACHABLE(); | 1167 UNREACHABLE(); |
983 } | 1168 } |
(...skipping 19 matching lines...) Expand all Loading... |
1003 pos, | 1188 pos, |
1004 pos + 1); | 1189 pos + 1); |
1005 } | 1190 } |
1006 | 1191 |
1007 | 1192 |
1008 #if defined(DEBUG) | 1193 #if defined(DEBUG) |
1009 // Verify that temps, inputs and output were specified as fixed | 1194 // Verify that temps, inputs and output were specified as fixed |
1010 // locations. Every register is blocked now so attempt to | 1195 // locations. Every register is blocked now so attempt to |
1011 // allocate will not succeed. | 1196 // allocate will not succeed. |
1012 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 1197 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| 1198 ASSERT(!locs->temp(j).IsPairLocation()); |
1013 ASSERT(!locs->temp(j).IsUnallocated()); | 1199 ASSERT(!locs->temp(j).IsUnallocated()); |
1014 } | 1200 } |
1015 | 1201 |
1016 for (intptr_t j = 0; j < locs->input_count(); j++) { | 1202 for (intptr_t j = 0; j < locs->input_count(); j++) { |
1017 ASSERT(!locs->in(j).IsUnallocated()); | 1203 if (locs->in(j).IsPairLocation()) { |
| 1204 PairLocation* pair = locs->in_slot(j)->AsPairLocation(); |
| 1205 ASSERT(!pair->At(0).IsUnallocated()); |
| 1206 ASSERT(!pair->At(1).IsUnallocated()); |
| 1207 } else { |
| 1208 ASSERT(!locs->in(j).IsUnallocated()); |
| 1209 } |
1018 } | 1210 } |
1019 | 1211 |
1020 ASSERT(!locs->out(0).IsUnallocated()); | 1212 if (locs->out(0).IsPairLocation()) { |
| 1213 PairLocation* pair = locs->out_slot(0)->AsPairLocation(); |
| 1214 ASSERT(!pair->At(0).IsUnallocated()); |
| 1215 ASSERT(!pair->At(1).IsUnallocated()); |
| 1216 } else { |
| 1217 ASSERT(!locs->out(0).IsUnallocated()); |
| 1218 } |
1021 #endif | 1219 #endif |
1022 } | 1220 } |
1023 | 1221 |
1024 if (locs->can_call()) { | 1222 if (locs->can_call()) { |
1025 safepoints_.Add(current); | 1223 safepoints_.Add(current); |
1026 } | 1224 } |
1027 | 1225 |
1028 if (def == NULL) { | 1226 if (def == NULL) { |
1029 ASSERT(locs->out(0).IsInvalid()); | 1227 ASSERT(locs->out(0).IsInvalid()); |
1030 return; | 1228 return; |
1031 } | 1229 } |
1032 | 1230 |
1033 if (locs->out(0).IsInvalid()) { | 1231 if (locs->out(0).IsInvalid()) { |
1034 ASSERT(def->ssa_temp_index() < 0); | 1232 ASSERT(def->ssa_temp_index() < 0); |
1035 return; | 1233 return; |
1036 } | 1234 } |
1037 | 1235 |
1038 // We might have a definition without use. We do not assign SSA index to | 1236 ASSERT(locs->output_count() == 1); |
1039 // such definitions. | |
1040 LiveRange* range = (def->ssa_temp_index() >= 0) ? | |
1041 GetLiveRange(def->ssa_temp_index()) : | |
1042 MakeLiveRangeForTemporary(); | |
1043 Location* out = locs->out_slot(0); | 1237 Location* out = locs->out_slot(0); |
1044 | 1238 if (out->IsPairLocation()) { |
1045 // Process output and finalize its liverange. | 1239 ASSERT(def->HasPairRepresentation()); |
1046 if (out->IsMachineRegister()) { | 1240 PairLocation* pair = out->AsPairLocation(); |
1047 // Fixed output location. Expected shape of live range: | 1241 if (output_same_as_first_input) { |
1048 // | 1242 ASSERT(locs->in_slot(0)->IsPairLocation()); |
1049 // i i' j j' | 1243 PairLocation* in_pair = locs->in_slot(0)->AsPairLocation(); |
1050 // register [--) | 1244 Definition* input = current->InputAt(0)->definition(); |
1051 // output [------- | 1245 ASSERT(input->HasPairRepresentation()); |
1052 // | 1246 // Each element of the pair is assigned it's own virtual register number |
1053 BlockLocation(*out, pos, pos + 1); | 1247 // and is allocated its own LiveRange. |
1054 | 1248 ProcessOneOutput(block, current, pos, // BlockEntry, Instruction, seq. |
1055 if (range->vreg() == kTempVirtualRegister) return; | 1249 pair->SlotAt(0), def, // (output) Location, Definition. |
1056 | 1250 def->ssa_temp_index(), // (output) virtual register. |
1057 // We need to emit move connecting fixed register with another location | 1251 true, // output mapped to first input. |
1058 // that will be allocated for this output's live range. | 1252 in_pair->SlotAt(0), input, // (input) Location, Def. |
1059 // Special case: fixed output followed by a fixed input last use. | 1253 input->ssa_temp_index(), // (input) virtual register. |
1060 UsePosition* use = range->first_use(); | 1254 interference_set); |
1061 | 1255 ProcessOneOutput(block, current, pos, |
1062 // If the value has no uses we don't need to allocate it. | 1256 pair->SlotAt(1), def, |
1063 if (use == NULL) return; | 1257 ToSecondPairVreg(def->ssa_temp_index()), |
1064 | 1258 true, |
1065 if (use->pos() == (pos + 1)) { | 1259 in_pair->SlotAt(1), input, |
1066 ASSERT(use->location_slot()->IsUnallocated()); | 1260 ToSecondPairVreg(input->ssa_temp_index()), |
1067 *(use->location_slot()) = *out; | 1261 interference_set); |
1068 | 1262 } else { |
1069 // Remove first use. It was allocated. | 1263 // Each element of the pair is assigned it's own virtual register number |
1070 range->set_first_use(range->first_use()->next()); | 1264 // and is allocated its own LiveRange. |
1071 } | 1265 ProcessOneOutput(block, current, pos, |
1072 | 1266 pair->SlotAt(0), def, |
1073 // Shorten live range to the point of definition, this might make the range | 1267 def->ssa_temp_index(), |
1074 // empty (if the only use immediately follows). If range is not empty add | 1268 false, // output is not mapped to first input. |
1075 // move from a fixed register to an unallocated location. | 1269 NULL, NULL, -1, // First input not needed. |
1076 range->DefineAt(pos + 1); | 1270 interference_set); |
1077 if (range->Start() == range->End()) return; | 1271 ProcessOneOutput(block, current, pos, |
1078 | 1272 pair->SlotAt(1), def, |
1079 MoveOperands* move = AddMoveAt(pos + 1, Location::Any(), *out); | 1273 ToSecondPairVreg(def->ssa_temp_index()), |
1080 range->AddHintedUse(pos + 1, move->dest_slot(), out); | 1274 false, |
1081 } else if (output_same_as_first_input) { | 1275 NULL, NULL, -1, |
1082 // Output register will contain a value of the first input at instruction's | 1276 interference_set); |
1083 // start. Expected shape of live ranges: | |
1084 // | |
1085 // i i' | |
1086 // input #0 --* | |
1087 // output [---- | |
1088 // | |
1089 ASSERT(locs->in(0).Equals(Location::RequiresRegister()) || | |
1090 locs->in(0).Equals(Location::RequiresFpuRegister())); | |
1091 | |
1092 // Create move that will copy value between input and output. | |
1093 locs->set_out(0, Location::RequiresRegister()); | |
1094 MoveOperands* move = AddMoveAt(pos, | |
1095 Location::RequiresRegister(), | |
1096 Location::Any()); | |
1097 | |
1098 // Add uses to the live range of the input. | |
1099 Definition* input = current->InputAt(0)->definition(); | |
1100 LiveRange* input_range = | |
1101 GetLiveRange(input->ssa_temp_index()); | |
1102 input_range->AddUseInterval(block->start_pos(), pos); | |
1103 input_range->AddUse(pos, move->src_slot()); | |
1104 | |
1105 // Shorten output live range to the point of definition and add both input | |
1106 // and output uses slots to be filled by allocator. | |
1107 range->DefineAt(pos); | |
1108 range->AddHintedUse(pos, out, move->src_slot()); | |
1109 range->AddUse(pos, move->dest_slot()); | |
1110 range->AddUse(pos, locs->in_slot(0)); | |
1111 | |
1112 if ((interference_set != NULL) && | |
1113 (range->vreg() >= 0) && | |
1114 interference_set->Contains(range->vreg())) { | |
1115 interference_set->Add(input->ssa_temp_index()); | |
1116 } | 1277 } |
1117 } else { | 1278 } else { |
1118 // Normal unallocated location that requires a register. Expected shape of | 1279 if (output_same_as_first_input) { |
1119 // live range: | 1280 Location* in_ref = locs->in_slot(0); |
1120 // | 1281 Definition* input = current->InputAt(0)->definition(); |
1121 // i i' | 1282 ASSERT(!in_ref->IsPairLocation()); |
1122 // output [------- | 1283 ProcessOneOutput(block, current, pos, // BlockEntry, Instruction, seq. |
1123 // | 1284 out, def, // (output) Location, Definition. |
1124 ASSERT(locs->out(0).Equals(Location::RequiresRegister()) || | 1285 def->ssa_temp_index(), // (output) virtual register. |
1125 locs->out(0).Equals(Location::RequiresFpuRegister())); | 1286 true, // output mapped to first input. |
1126 | 1287 in_ref, input, // (input) Location, Def. |
1127 // Shorten live range to the point of definition and add use to be filled by | 1288 input->ssa_temp_index(), // (input) virtual register. |
1128 // allocator. | 1289 interference_set); |
1129 range->DefineAt(pos); | 1290 } else { |
1130 range->AddUse(pos, out); | 1291 ProcessOneOutput(block, current, pos, |
| 1292 out, def, |
| 1293 def->ssa_temp_index(), |
| 1294 false, // output is not mapped to first input. |
| 1295 NULL, NULL, -1, // First input not needed. |
| 1296 interference_set); |
| 1297 } |
1131 } | 1298 } |
1132 | |
1133 AssignSafepoints(range); | |
1134 CompleteRange(range, RegisterKindForResult(current)); | |
1135 } | 1299 } |
1136 | 1300 |
1137 | 1301 |
1138 static ParallelMoveInstr* CreateParallelMoveBefore(Instruction* instr, | 1302 static ParallelMoveInstr* CreateParallelMoveBefore(Instruction* instr, |
1139 intptr_t pos) { | 1303 intptr_t pos) { |
1140 ASSERT(pos > 0); | 1304 ASSERT(pos > 0); |
1141 Instruction* prev = instr->previous(); | 1305 Instruction* prev = instr->previous(); |
1142 ParallelMoveInstr* move = prev->AsParallelMove(); | 1306 ParallelMoveInstr* move = prev->AsParallelMove(); |
1143 if ((move == NULL) || (move->lifetime_position() != pos)) { | 1307 if ((move == NULL) || (move->lifetime_position() != pos)) { |
1144 move = new ParallelMoveInstr(); | 1308 move = new ParallelMoveInstr(); |
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1711 const intptr_t pos = FirstIntersection( | 1875 const intptr_t pos = FirstIntersection( |
1712 unallocated->finger()->first_pending_use_interval(), | 1876 unallocated->finger()->first_pending_use_interval(), |
1713 allocated_head); | 1877 allocated_head); |
1714 if (pos < intersection) intersection = pos; | 1878 if (pos < intersection) intersection = pos; |
1715 } | 1879 } |
1716 return intersection; | 1880 return intersection; |
1717 } | 1881 } |
1718 | 1882 |
1719 | 1883 |
1720 void ReachingDefs::AddPhi(PhiInstr* phi) { | 1884 void ReachingDefs::AddPhi(PhiInstr* phi) { |
| 1885 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
1721 if (phi->reaching_defs() == NULL) { | 1886 if (phi->reaching_defs() == NULL) { |
1722 phi->set_reaching_defs( | 1887 phi->set_reaching_defs( |
1723 new BitVector(flow_graph_.max_virtual_register_number())); | 1888 new BitVector(flow_graph_.max_virtual_register_number())); |
1724 | 1889 |
1725 // Compute initial set reaching defs set. | 1890 // Compute initial set reaching defs set. |
1726 bool depends_on_phi = false; | 1891 bool depends_on_phi = false; |
1727 for (intptr_t i = 0; i < phi->InputCount(); i++) { | 1892 for (intptr_t i = 0; i < phi->InputCount(); i++) { |
1728 Definition* input = phi->InputAt(i)->definition(); | 1893 Definition* input = phi->InputAt(i)->definition(); |
1729 if (input->IsPhi()) { | 1894 if (input->IsPhi()) { |
1730 depends_on_phi = true; | 1895 depends_on_phi = true; |
1731 } | 1896 } |
1732 phi->reaching_defs()->Add(input->ssa_temp_index()); | 1897 phi->reaching_defs()->Add(input->ssa_temp_index()); |
1733 } | 1898 } |
1734 | 1899 |
1735 // If this phi depends on another phi then we need fix point iteration. | 1900 // If this phi depends on another phi then we need fix point iteration. |
1736 if (depends_on_phi) phis_.Add(phi); | 1901 if (depends_on_phi) phis_.Add(phi); |
1737 } | 1902 } |
1738 } | 1903 } |
1739 | 1904 |
1740 | 1905 |
1741 void ReachingDefs::Compute() { | 1906 void ReachingDefs::Compute() { |
1742 // Transitively collect all phis that are used by the given phi. | 1907 // Transitively collect all phis that are used by the given phi. |
1743 for (intptr_t i = 0; i < phis_.length(); i++) { | 1908 for (intptr_t i = 0; i < phis_.length(); i++) { |
| 1909 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
1744 PhiInstr* phi = phis_[i]; | 1910 PhiInstr* phi = phis_[i]; |
1745 | 1911 |
1746 // Add all phis that affect this phi to the list. | 1912 // Add all phis that affect this phi to the list. |
1747 for (intptr_t i = 0; i < phi->InputCount(); i++) { | 1913 for (intptr_t i = 0; i < phi->InputCount(); i++) { |
1748 PhiInstr* input_phi = phi->InputAt(i)->definition()->AsPhi(); | 1914 PhiInstr* input_phi = phi->InputAt(i)->definition()->AsPhi(); |
1749 if (input_phi != NULL) { | 1915 if (input_phi != NULL) { |
1750 AddPhi(input_phi); | 1916 AddPhi(input_phi); |
1751 } | 1917 } |
1752 } | 1918 } |
1753 } | 1919 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1837 (loop_header != NULL) && | 2003 (loop_header != NULL) && |
1838 (free_until >= loop_header->last_block()->end_pos()) && | 2004 (free_until >= loop_header->last_block()->end_pos()) && |
1839 loop_header->backedge_interference()->Contains(unallocated->vreg())) { | 2005 loop_header->backedge_interference()->Contains(unallocated->vreg())) { |
1840 ASSERT(static_cast<intptr_t>(kNumberOfFpuRegisters) <= | 2006 ASSERT(static_cast<intptr_t>(kNumberOfFpuRegisters) <= |
1841 kNumberOfCpuRegisters); | 2007 kNumberOfCpuRegisters); |
1842 bool used_on_backedge[kNumberOfCpuRegisters] = { false }; | 2008 bool used_on_backedge[kNumberOfCpuRegisters] = { false }; |
1843 | 2009 |
1844 for (PhiIterator it(loop_header->entry()->AsJoinEntry()); | 2010 for (PhiIterator it(loop_header->entry()->AsJoinEntry()); |
1845 !it.Done(); | 2011 !it.Done(); |
1846 it.Advance()) { | 2012 it.Advance()) { |
| 2013 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
1847 PhiInstr* phi = it.Current(); | 2014 PhiInstr* phi = it.Current(); |
1848 ASSERT(phi->is_alive()); | 2015 ASSERT(phi->is_alive()); |
1849 const intptr_t phi_vreg = phi->ssa_temp_index(); | 2016 const intptr_t phi_vreg = phi->ssa_temp_index(); |
1850 LiveRange* range = GetLiveRange(phi_vreg); | 2017 LiveRange* range = GetLiveRange(phi_vreg); |
1851 if (range->assigned_location().kind() == register_kind_) { | 2018 if (range->assigned_location().kind() == register_kind_) { |
1852 const intptr_t reg = range->assigned_location().register_code(); | 2019 const intptr_t reg = range->assigned_location().register_code(); |
1853 | 2020 |
1854 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { | 2021 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { |
1855 used_on_backedge[reg] = true; | 2022 used_on_backedge[reg] = true; |
1856 } | 2023 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1901 registers_[candidate].Add(unallocated); | 2068 registers_[candidate].Add(unallocated); |
1902 unallocated->set_assigned_location(MakeRegisterLocation(candidate)); | 2069 unallocated->set_assigned_location(MakeRegisterLocation(candidate)); |
1903 | 2070 |
1904 return true; | 2071 return true; |
1905 } | 2072 } |
1906 | 2073 |
1907 | 2074 |
1908 bool FlowGraphAllocator::RangeHasOnlyUnconstrainedUsesInLoop(LiveRange* range, | 2075 bool FlowGraphAllocator::RangeHasOnlyUnconstrainedUsesInLoop(LiveRange* range, |
1909 intptr_t loop_id) { | 2076 intptr_t loop_id) { |
1910 if (range->vreg() >= 0) { | 2077 if (range->vreg() >= 0) { |
1911 return GetLiveRange(range->vreg())->HasOnlyUnconstrainedUsesInLoop(loop_id); | 2078 LiveRange* parent = GetLiveRange(range->vreg()); |
| 2079 return parent->HasOnlyUnconstrainedUsesInLoop(loop_id); |
1912 } | 2080 } |
1913 return false; | 2081 return false; |
1914 } | 2082 } |
1915 | 2083 |
1916 | 2084 |
1917 bool FlowGraphAllocator::IsCheapToEvictRegisterInLoop(BlockInfo* loop, | 2085 bool FlowGraphAllocator::IsCheapToEvictRegisterInLoop(BlockInfo* loop, |
1918 intptr_t reg) { | 2086 intptr_t reg) { |
1919 const intptr_t loop_start = loop->entry()->start_pos(); | 2087 const intptr_t loop_start = loop->entry()->start_pos(); |
1920 const intptr_t loop_end = loop->last_block()->end_pos(); | 2088 const intptr_t loop_end = loop->last_block()->end_pos(); |
1921 | 2089 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1982 const intptr_t register_use_pos = | 2150 const intptr_t register_use_pos = |
1983 (register_use != NULL) ? register_use->pos() | 2151 (register_use != NULL) ? register_use->pos() |
1984 : unallocated->Start(); | 2152 : unallocated->Start(); |
1985 if (free_until < register_use_pos) { | 2153 if (free_until < register_use_pos) { |
1986 // Can't acquire free register. Spill until we really need one. | 2154 // Can't acquire free register. Spill until we really need one. |
1987 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); | 2155 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); |
1988 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 2156 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
1989 return; | 2157 return; |
1990 } | 2158 } |
1991 | 2159 |
| 2160 ASSERT(candidate != kNoRegister); |
| 2161 |
1992 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 2162 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
1993 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); | 2163 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); |
1994 TRACE_ALLOC(OS::Print(" to live range v%" Pd " until %" Pd "\n", | 2164 TRACE_ALLOC(OS::Print(" to live range v%" Pd " until %" Pd "\n", |
1995 unallocated->vreg(), blocked_at)); | 2165 unallocated->vreg(), blocked_at)); |
1996 | 2166 |
1997 if (blocked_at < unallocated->End()) { | 2167 if (blocked_at < unallocated->End()) { |
1998 // Register is blocked before the end of the live range. Split the range | 2168 // Register is blocked before the end of the live range. Split the range |
1999 // at latest at blocked_at position. | 2169 // at latest at blocked_at position. |
2000 LiveRange* tail = SplitBetween(unallocated, | 2170 LiveRange* tail = SplitBetween(unallocated, |
2001 unallocated->Start(), | 2171 unallocated->Start(), |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2492 } | 2662 } |
2493 } | 2663 } |
2494 | 2664 |
2495 | 2665 |
2496 void FlowGraphAllocator::CollectRepresentations() { | 2666 void FlowGraphAllocator::CollectRepresentations() { |
2497 // Parameters. | 2667 // Parameters. |
2498 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 2668 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
2499 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { | 2669 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { |
2500 Definition* def = (*graph_entry->initial_definitions())[i]; | 2670 Definition* def = (*graph_entry->initial_definitions())[i]; |
2501 value_representations_[def->ssa_temp_index()] = def->representation(); | 2671 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2672 ASSERT(!def->HasPairRepresentation()); |
2502 } | 2673 } |
2503 | 2674 |
2504 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); | 2675 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
2505 !it.Done(); | 2676 !it.Done(); |
2506 it.Advance()) { | 2677 it.Advance()) { |
2507 BlockEntryInstr* block = it.Current(); | 2678 BlockEntryInstr* block = it.Current(); |
2508 | 2679 |
2509 // Catch entry. | 2680 // Catch entry. |
2510 if (block->IsCatchBlockEntry()) { | 2681 if (block->IsCatchBlockEntry()) { |
2511 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); | 2682 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); |
2512 for (intptr_t i = 0; | 2683 for (intptr_t i = 0; |
2513 i < catch_entry->initial_definitions()->length(); | 2684 i < catch_entry->initial_definitions()->length(); |
2514 ++i) { | 2685 ++i) { |
2515 Definition* def = (*catch_entry->initial_definitions())[i]; | 2686 Definition* def = (*catch_entry->initial_definitions())[i]; |
2516 value_representations_[def->ssa_temp_index()] = def->representation(); | 2687 value_representations_[def->ssa_temp_index()] = def->representation(); |
2517 } | 2688 } |
2518 } | 2689 } |
2519 // Phis. | 2690 // Phis. |
2520 if (block->IsJoinEntry()) { | 2691 if (block->IsJoinEntry()) { |
2521 JoinEntryInstr* join = block->AsJoinEntry(); | 2692 JoinEntryInstr* join = block->AsJoinEntry(); |
2522 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 2693 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 2694 // TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation. |
2523 PhiInstr* phi = it.Current(); | 2695 PhiInstr* phi = it.Current(); |
2524 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { | 2696 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { |
2525 value_representations_[phi->ssa_temp_index()] = phi->representation(); | 2697 value_representations_[phi->ssa_temp_index()] = phi->representation(); |
2526 } | 2698 } |
2527 } | 2699 } |
2528 } | 2700 } |
2529 // Normal instructions. | 2701 // Normal instructions. |
2530 for (ForwardInstructionIterator instr_it(block); | 2702 for (ForwardInstructionIterator instr_it(block); |
2531 !instr_it.Done(); | 2703 !instr_it.Done(); |
2532 instr_it.Advance()) { | 2704 instr_it.Advance()) { |
2533 Definition* def = instr_it.Current()->AsDefinition(); | 2705 Definition* def = instr_it.Current()->AsDefinition(); |
2534 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { | 2706 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { |
2535 value_representations_[def->ssa_temp_index()] = def->representation(); | 2707 const intptr_t vreg = def->ssa_temp_index(); |
| 2708 value_representations_[vreg] = def->representation(); |
| 2709 if (def->HasPairRepresentation()) { |
| 2710 value_representations_[ToSecondPairVreg(vreg)] = def->representation(); |
| 2711 } |
2536 } | 2712 } |
2537 } | 2713 } |
2538 } | 2714 } |
2539 } | 2715 } |
2540 | 2716 |
2541 | 2717 |
2542 void FlowGraphAllocator::AllocateRegisters() { | 2718 void FlowGraphAllocator::AllocateRegisters() { |
2543 CollectRepresentations(); | 2719 CollectRepresentations(); |
2544 | 2720 |
2545 liveness_.Analyze(); | 2721 liveness_.Analyze(); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2605 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2781 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
2606 function.ToFullyQualifiedCString()); | 2782 function.ToFullyQualifiedCString()); |
2607 FlowGraphPrinter printer(flow_graph_, true); | 2783 FlowGraphPrinter printer(flow_graph_, true); |
2608 printer.PrintBlocks(); | 2784 printer.PrintBlocks(); |
2609 OS::Print("----------------------------------------------\n"); | 2785 OS::Print("----------------------------------------------\n"); |
2610 } | 2786 } |
2611 } | 2787 } |
2612 | 2788 |
2613 | 2789 |
2614 } // namespace dart | 2790 } // namespace dart |
OLD | NEW |