OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/linkage.h" | 5 #include "src/compiler/linkage.h" |
6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
7 #include "src/string-stream.h" | 7 #include "src/string-stream.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 current_hint_operand_(nullptr), | 133 current_hint_operand_(nullptr), |
134 spill_start_index_(kMaxInt), | 134 spill_start_index_(kMaxInt), |
135 spill_type_(SpillType::kNoSpillType), | 135 spill_type_(SpillType::kNoSpillType), |
136 spill_operand_(nullptr), | 136 spill_operand_(nullptr), |
137 spills_at_definition_(nullptr) {} | 137 spills_at_definition_(nullptr) {} |
138 | 138 |
139 | 139 |
140 void LiveRange::set_assigned_register(int reg) { | 140 void LiveRange::set_assigned_register(int reg) { |
141 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 141 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
142 assigned_register_ = reg; | 142 assigned_register_ = reg; |
143 // TODO(dcarney): stop aliasing hint operands. | |
144 ConvertUsesToOperand(GetAssignedOperand(), nullptr); | |
145 } | 143 } |
146 | 144 |
147 | 145 |
148 void LiveRange::MakeSpilled() { | 146 void LiveRange::MakeSpilled() { |
149 DCHECK(!IsSpilled()); | 147 DCHECK(!IsSpilled()); |
150 DCHECK(!TopLevel()->HasNoSpillType()); | 148 DCHECK(!TopLevel()->HasNoSpillType()); |
151 spilled_ = true; | 149 spilled_ = true; |
152 assigned_register_ = kInvalidAssignment; | 150 assigned_register_ = kInvalidAssignment; |
153 } | 151 } |
154 | 152 |
(...skipping 13 matching lines...) Expand all Loading... |
168 DCHECK(!IsChild()); | 166 DCHECK(!IsChild()); |
169 auto zone = sequence->zone(); | 167 auto zone = sequence->zone(); |
170 for (auto to_spill = spills_at_definition_; to_spill != nullptr; | 168 for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
171 to_spill = to_spill->next) { | 169 to_spill = to_spill->next) { |
172 auto instr = sequence->InstructionAt(to_spill->gap_index); | 170 auto instr = sequence->InstructionAt(to_spill->gap_index); |
173 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); | 171 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); |
174 // Skip insertion if it's possible that the move exists already as a | 172 // Skip insertion if it's possible that the move exists already as a |
175 // constraint move from a fixed output register to a slot. | 173 // constraint move from a fixed output register to a slot. |
176 if (might_be_duplicated) { | 174 if (might_be_duplicated) { |
177 bool found = false; | 175 bool found = false; |
178 auto move_ops = move->move_operands(); | 176 for (auto move_op : *move) { |
179 for (auto move_op = move_ops->begin(); move_op != move_ops->end(); | |
180 ++move_op) { | |
181 if (move_op->IsEliminated()) continue; | 177 if (move_op->IsEliminated()) continue; |
182 if (move_op->source()->Equals(to_spill->operand) && | 178 if (move_op->source() == *to_spill->operand && |
183 move_op->destination()->Equals(op)) { | 179 move_op->destination() == *op) { |
184 found = true; | 180 found = true; |
185 break; | 181 break; |
186 } | 182 } |
187 } | 183 } |
188 if (found) continue; | 184 if (found) continue; |
189 } | 185 } |
190 move->AddMove(to_spill->operand, op, zone); | 186 move->AddMove(*to_spill->operand, *op); |
191 } | 187 } |
192 } | 188 } |
193 | 189 |
194 | 190 |
195 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 191 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
196 DCHECK(HasNoSpillType()); | 192 DCHECK(HasNoSpillType()); |
197 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); | 193 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); |
198 spill_type_ = SpillType::kSpillOperand; | 194 spill_type_ = SpillType::kSpillOperand; |
199 spill_operand_ = operand; | 195 spill_operand_ = operand; |
200 } | 196 } |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 auto range = LiveRangeFor(operand); | 792 auto range = LiveRangeFor(operand); |
797 if (range == nullptr) return; | 793 if (range == nullptr) return; |
798 if (operand->IsUnallocated()) { | 794 if (operand->IsUnallocated()) { |
799 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); | 795 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
800 range->AddUsePosition(position, unalloc_operand, hint, local_zone()); | 796 range->AddUsePosition(position, unalloc_operand, hint, local_zone()); |
801 } | 797 } |
802 range->AddUseInterval(block_start, position, local_zone()); | 798 range->AddUseInterval(block_start, position, local_zone()); |
803 } | 799 } |
804 | 800 |
805 | 801 |
806 void RegisterAllocator::AddGapMove(int index, Instruction::GapPosition position, | 802 MoveOperands* RegisterAllocator::AddGapMove(int index, |
807 InstructionOperand* from, | 803 Instruction::GapPosition position, |
808 InstructionOperand* to) { | 804 const InstructionOperand& from, |
| 805 const InstructionOperand& to) { |
809 auto instr = code()->InstructionAt(index); | 806 auto instr = code()->InstructionAt(index); |
810 auto move = instr->GetOrCreateParallelMove(position, code_zone()); | 807 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); |
811 move->AddMove(from, to, code_zone()); | 808 return moves->AddMove(from, to); |
812 } | 809 } |
813 | 810 |
814 | 811 |
815 static bool AreUseIntervalsIntersecting(UseInterval* interval1, | 812 static bool AreUseIntervalsIntersecting(UseInterval* interval1, |
816 UseInterval* interval2) { | 813 UseInterval* interval2) { |
817 while (interval1 != nullptr && interval2 != nullptr) { | 814 while (interval1 != nullptr && interval2 != nullptr) { |
818 if (interval1->start().Value() < interval2->start().Value()) { | 815 if (interval1->start().Value() < interval2->start().Value()) { |
819 if (interval1->end().Value() > interval2->start().Value()) { | 816 if (interval1->end().Value() > interval2->start().Value()) { |
820 return true; | 817 return true; |
821 } | 818 } |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 | 950 |
954 void RegisterAllocator::CommitAssignment() { | 951 void RegisterAllocator::CommitAssignment() { |
955 for (auto range : live_ranges()) { | 952 for (auto range : live_ranges()) { |
956 if (range == nullptr || range->IsEmpty()) continue; | 953 if (range == nullptr || range->IsEmpty()) continue; |
957 InstructionOperand* spill_operand = nullptr; | 954 InstructionOperand* spill_operand = nullptr; |
958 if (!range->TopLevel()->HasNoSpillType()) { | 955 if (!range->TopLevel()->HasNoSpillType()) { |
959 spill_operand = range->TopLevel()->GetSpillOperand(); | 956 spill_operand = range->TopLevel()->GetSpillOperand(); |
960 } | 957 } |
961 auto assigned = range->GetAssignedOperand(); | 958 auto assigned = range->GetAssignedOperand(); |
962 range->ConvertUsesToOperand(assigned, spill_operand); | 959 range->ConvertUsesToOperand(assigned, spill_operand); |
| 960 if (range->is_phi()) AssignPhiInput(range, assigned); |
963 if (!range->IsChild() && spill_operand != nullptr) { | 961 if (!range->IsChild() && spill_operand != nullptr) { |
964 range->CommitSpillsAtDefinition(code(), spill_operand, | 962 range->CommitSpillsAtDefinition(code(), spill_operand, |
965 range->has_slot_use()); | 963 range->has_slot_use()); |
966 } | 964 } |
967 } | 965 } |
968 } | 966 } |
969 | 967 |
970 | 968 |
971 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 969 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
972 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); | 970 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); |
973 spill_ranges().push_back(spill_range); | 971 spill_ranges().push_back(spill_range); |
974 return spill_range; | 972 return spill_range; |
975 } | 973 } |
976 | 974 |
977 | 975 |
978 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 976 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
979 if (range->IsChild() || !range->is_phi()) return false; | 977 if (range->IsChild() || !range->is_phi()) return false; |
980 DCHECK(!range->HasSpillOperand()); | 978 DCHECK(!range->HasSpillOperand()); |
981 | 979 |
982 auto lookup = phi_map_.find(range->id()); | 980 auto lookup = phi_map_.find(range->id()); |
983 DCHECK(lookup != phi_map_.end()); | 981 DCHECK(lookup != phi_map_.end()); |
984 auto phi = lookup->second.phi; | 982 auto phi = lookup->second->phi; |
985 auto block = lookup->second.block; | 983 auto block = lookup->second->block; |
986 // Count the number of spilled operands. | 984 // Count the number of spilled operands. |
987 size_t spilled_count = 0; | 985 size_t spilled_count = 0; |
988 LiveRange* first_op = nullptr; | 986 LiveRange* first_op = nullptr; |
989 for (size_t i = 0; i < phi->operands().size(); i++) { | 987 for (size_t i = 0; i < phi->operands().size(); i++) { |
990 int op = phi->operands()[i]; | 988 int op = phi->operands()[i]; |
991 LiveRange* op_range = LiveRangeFor(op); | 989 LiveRange* op_range = LiveRangeFor(op); |
992 if (op_range->GetSpillRange() == nullptr) continue; | 990 if (op_range->GetSpillRange() == nullptr) continue; |
993 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); | 991 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
994 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | 992 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
995 pred->last_instruction_index()); | 993 pred->last_instruction_index()); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 range->SetSpillStartIndex(end); | 1089 range->SetSpillStartIndex(end); |
1092 assigned = true; | 1090 assigned = true; |
1093 } | 1091 } |
1094 | 1092 |
1095 for (auto succ : block->successors()) { | 1093 for (auto succ : block->successors()) { |
1096 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1094 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
1097 DCHECK(successor->PredecessorCount() == 1); | 1095 DCHECK(successor->PredecessorCount() == 1); |
1098 int gap_index = successor->first_instruction_index(); | 1096 int gap_index = successor->first_instruction_index(); |
1099 // Create an unconstrained operand for the same virtual register | 1097 // Create an unconstrained operand for the same virtual register |
1100 // and insert a gap move from the fixed output to the operand. | 1098 // and insert a gap move from the fixed output to the operand. |
1101 UnallocatedOperand* output_copy = | 1099 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); |
1102 UnallocatedOperand(UnallocatedOperand::ANY, output_vreg) | 1100 AddGapMove(gap_index, Instruction::START, *output, output_copy); |
1103 .Copy(code_zone()); | |
1104 AddGapMove(gap_index, Instruction::START, output, output_copy); | |
1105 } | 1101 } |
1106 } | 1102 } |
1107 | 1103 |
1108 if (!assigned) { | 1104 if (!assigned) { |
1109 for (auto succ : block->successors()) { | 1105 for (auto succ : block->successors()) { |
1110 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1106 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
1111 DCHECK(successor->PredecessorCount() == 1); | 1107 DCHECK(successor->PredecessorCount() == 1); |
1112 int gap_index = successor->first_instruction_index(); | 1108 int gap_index = successor->first_instruction_index(); |
1113 range->SpillAtDefinition(local_zone(), gap_index, output); | 1109 range->SpillAtDefinition(local_zone(), gap_index, output); |
1114 range->SetSpillStartIndex(gap_index); | 1110 range->SetSpillStartIndex(gap_index); |
(...skipping 17 matching lines...) Expand all Loading... |
1132 int output_vreg = ConstantOperand::cast(output)->virtual_register(); | 1128 int output_vreg = ConstantOperand::cast(output)->virtual_register(); |
1133 auto range = LiveRangeFor(output_vreg); | 1129 auto range = LiveRangeFor(output_vreg); |
1134 range->SetSpillStartIndex(instr_index + 1); | 1130 range->SetSpillStartIndex(instr_index + 1); |
1135 range->SetSpillOperand(output); | 1131 range->SetSpillOperand(output); |
1136 continue; | 1132 continue; |
1137 } | 1133 } |
1138 auto first_output = UnallocatedOperand::cast(output); | 1134 auto first_output = UnallocatedOperand::cast(output); |
1139 auto range = LiveRangeFor(first_output->virtual_register()); | 1135 auto range = LiveRangeFor(first_output->virtual_register()); |
1140 bool assigned = false; | 1136 bool assigned = false; |
1141 if (first_output->HasFixedPolicy()) { | 1137 if (first_output->HasFixedPolicy()) { |
1142 auto output_copy = first_output->CopyUnconstrained(code_zone()); | 1138 int output_vreg = first_output->virtual_register(); |
1143 bool is_tagged = HasTaggedValue(first_output->virtual_register()); | 1139 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); |
| 1140 bool is_tagged = HasTaggedValue(output_vreg); |
1144 AllocateFixed(first_output, instr_index, is_tagged); | 1141 AllocateFixed(first_output, instr_index, is_tagged); |
1145 | 1142 |
1146 // This value is produced on the stack, we never need to spill it. | 1143 // This value is produced on the stack, we never need to spill it. |
1147 if (first_output->IsStackSlot()) { | 1144 if (first_output->IsStackSlot()) { |
1148 DCHECK(StackSlotOperand::cast(first_output)->index() < | 1145 DCHECK(StackSlotOperand::cast(first_output)->index() < |
1149 frame_->GetSpillSlotCount()); | 1146 frame_->GetSpillSlotCount()); |
1150 range->SetSpillOperand(StackSlotOperand::cast(first_output)); | 1147 range->SetSpillOperand(StackSlotOperand::cast(first_output)); |
1151 range->SetSpillStartIndex(instr_index + 1); | 1148 range->SetSpillStartIndex(instr_index + 1); |
1152 assigned = true; | 1149 assigned = true; |
1153 } | 1150 } |
1154 AddGapMove(instr_index + 1, Instruction::START, first_output, | 1151 AddGapMove(instr_index + 1, Instruction::START, *first_output, |
1155 output_copy); | 1152 output_copy); |
1156 } | 1153 } |
1157 // Make sure we add a gap move for spilling (if we have not done | 1154 // Make sure we add a gap move for spilling (if we have not done |
1158 // so already). | 1155 // so already). |
1159 if (!assigned) { | 1156 if (!assigned) { |
1160 range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); | 1157 range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); |
1161 range->SetSpillStartIndex(instr_index + 1); | 1158 range->SetSpillStartIndex(instr_index + 1); |
1162 } | 1159 } |
1163 } | 1160 } |
1164 } | 1161 } |
1165 | 1162 |
1166 | 1163 |
1167 void RegisterAllocator::MeetConstraintsBefore(int instr_index) { | 1164 void RegisterAllocator::MeetConstraintsBefore(int instr_index) { |
1168 auto second = InstructionAt(instr_index); | 1165 auto second = InstructionAt(instr_index); |
1169 // Handle fixed input operands of second instruction. | 1166 // Handle fixed input operands of second instruction. |
1170 for (size_t i = 0; i < second->InputCount(); i++) { | 1167 for (size_t i = 0; i < second->InputCount(); i++) { |
1171 auto input = second->InputAt(i); | 1168 auto input = second->InputAt(i); |
1172 if (input->IsImmediate()) continue; // Ignore immediates. | 1169 if (input->IsImmediate()) continue; // Ignore immediates. |
1173 auto cur_input = UnallocatedOperand::cast(input); | 1170 auto cur_input = UnallocatedOperand::cast(input); |
1174 if (cur_input->HasFixedPolicy()) { | 1171 if (cur_input->HasFixedPolicy()) { |
1175 auto input_copy = cur_input->CopyUnconstrained(code_zone()); | 1172 int input_vreg = cur_input->virtual_register(); |
1176 bool is_tagged = HasTaggedValue(cur_input->virtual_register()); | 1173 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); |
| 1174 bool is_tagged = HasTaggedValue(input_vreg); |
1177 AllocateFixed(cur_input, instr_index, is_tagged); | 1175 AllocateFixed(cur_input, instr_index, is_tagged); |
1178 AddGapMove(instr_index, Instruction::END, input_copy, cur_input); | 1176 AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); |
1179 } | 1177 } |
1180 } | 1178 } |
1181 // Handle "output same as input" for second instruction. | 1179 // Handle "output same as input" for second instruction. |
1182 for (size_t i = 0; i < second->OutputCount(); i++) { | 1180 for (size_t i = 0; i < second->OutputCount(); i++) { |
1183 auto output = second->OutputAt(i); | 1181 auto output = second->OutputAt(i); |
1184 if (!output->IsUnallocated()) continue; | 1182 if (!output->IsUnallocated()) continue; |
1185 auto second_output = UnallocatedOperand::cast(output); | 1183 auto second_output = UnallocatedOperand::cast(output); |
1186 if (!second_output->HasSameAsInputPolicy()) continue; | 1184 if (!second_output->HasSameAsInputPolicy()) continue; |
1187 DCHECK(i == 0); // Only valid for first output. | 1185 DCHECK(i == 0); // Only valid for first output. |
1188 UnallocatedOperand* cur_input = | 1186 UnallocatedOperand* cur_input = |
1189 UnallocatedOperand::cast(second->InputAt(0)); | 1187 UnallocatedOperand::cast(second->InputAt(0)); |
1190 int output_vreg = second_output->virtual_register(); | 1188 int output_vreg = second_output->virtual_register(); |
1191 int input_vreg = cur_input->virtual_register(); | 1189 int input_vreg = cur_input->virtual_register(); |
1192 auto input_copy = cur_input->CopyUnconstrained(code_zone()); | 1190 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); |
1193 cur_input->set_virtual_register(second_output->virtual_register()); | 1191 cur_input->set_virtual_register(second_output->virtual_register()); |
1194 AddGapMove(instr_index, Instruction::END, input_copy, cur_input); | 1192 AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); |
1195 if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) { | 1193 if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) { |
1196 if (second->HasReferenceMap()) { | 1194 if (second->HasReferenceMap()) { |
1197 second->reference_map()->RecordReference(*input_copy); | 1195 second->reference_map()->RecordReference(input_copy); |
1198 } | 1196 } |
1199 } else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) { | 1197 } else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) { |
1200 // The input is assumed to immediately have a tagged representation, | 1198 // The input is assumed to immediately have a tagged representation, |
1201 // before the pointer map can be used. I.e. the pointer map at the | 1199 // before the pointer map can be used. I.e. the pointer map at the |
1202 // instruction will include the output operand (whose value at the | 1200 // instruction will include the output operand (whose value at the |
1203 // beginning of the instruction is equal to the input operand). If | 1201 // beginning of the instruction is equal to the input operand). If |
1204 // this is not desired, then the pointer map at this instruction needs | 1202 // this is not desired, then the pointer map at this instruction needs |
1205 // to be adjusted manually. | 1203 // to be adjusted manually. |
1206 } | 1204 } |
1207 } | 1205 } |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1324 curr_position = curr_position.PrevStart(); | 1322 curr_position = curr_position.PrevStart(); |
1325 DCHECK(curr_position.IsGapPosition()); | 1323 DCHECK(curr_position.IsGapPosition()); |
1326 for (auto position : kPositions) { | 1324 for (auto position : kPositions) { |
1327 auto move = instr->GetParallelMove(position); | 1325 auto move = instr->GetParallelMove(position); |
1328 if (move == nullptr) continue; | 1326 if (move == nullptr) continue; |
1329 if (position == Instruction::END) { | 1327 if (position == Instruction::END) { |
1330 curr_position = curr_position.End(); | 1328 curr_position = curr_position.End(); |
1331 } else { | 1329 } else { |
1332 curr_position = curr_position.Start(); | 1330 curr_position = curr_position.Start(); |
1333 } | 1331 } |
1334 auto move_ops = move->move_operands(); | 1332 for (auto cur : *move) { |
1335 for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) { | 1333 auto& from = cur->source(); |
1336 auto from = cur->source(); | 1334 auto& to = cur->destination(); |
1337 auto to = cur->destination(); | 1335 auto hint = &to; |
1338 auto hint = to; | 1336 if (to.IsUnallocated()) { |
1339 if (to->IsUnallocated()) { | 1337 int to_vreg = UnallocatedOperand::cast(to).virtual_register(); |
1340 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); | |
1341 auto to_range = LiveRangeFor(to_vreg); | 1338 auto to_range = LiveRangeFor(to_vreg); |
1342 if (to_range->is_phi()) { | 1339 if (to_range->is_phi()) { |
1343 if (to_range->is_non_loop_phi()) { | 1340 if (to_range->is_non_loop_phi()) { |
1344 hint = to_range->current_hint_operand(); | 1341 hint = to_range->current_hint_operand(); |
1345 } | 1342 } |
1346 } else { | 1343 } else { |
1347 if (live->Contains(to_vreg)) { | 1344 if (live->Contains(to_vreg)) { |
1348 Define(curr_position, to, from); | 1345 Define(curr_position, &to, &from); |
1349 live->Remove(to_vreg); | 1346 live->Remove(to_vreg); |
1350 } else { | 1347 } else { |
1351 cur->Eliminate(); | 1348 cur->Eliminate(); |
1352 continue; | 1349 continue; |
1353 } | 1350 } |
1354 } | 1351 } |
1355 } else { | 1352 } else { |
1356 Define(curr_position, to, from); | 1353 Define(curr_position, &to, &from); |
1357 } | 1354 } |
1358 Use(block_start_position, curr_position, from, hint); | 1355 Use(block_start_position, curr_position, &from, hint); |
1359 if (from->IsUnallocated()) { | 1356 if (from.IsUnallocated()) { |
1360 live->Add(UnallocatedOperand::cast(from)->virtual_register()); | 1357 live->Add(UnallocatedOperand::cast(from).virtual_register()); |
1361 } | 1358 } |
1362 } | 1359 } |
1363 } | 1360 } |
1364 } | 1361 } |
1365 } | 1362 } |
1366 | 1363 |
1367 | 1364 |
1368 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { | 1365 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { |
1369 for (auto phi : block->phis()) { | 1366 for (auto phi : block->phis()) { |
1370 int phi_vreg = phi->virtual_register(); | 1367 int phi_vreg = phi->virtual_register(); |
1371 auto res = | 1368 auto map_value = new (local_zone()) PhiMapValue(phi, block, local_zone()); |
1372 phi_map_.insert(std::make_pair(phi_vreg, PhiMapValue(phi, block))); | 1369 auto res = phi_map_.insert(std::make_pair(phi_vreg, map_value)); |
1373 DCHECK(res.second); | 1370 DCHECK(res.second); |
1374 USE(res); | 1371 USE(res); |
1375 auto& output = phi->output(); | 1372 auto& output = phi->output(); |
1376 for (size_t i = 0; i < phi->operands().size(); ++i) { | 1373 for (size_t i = 0; i < phi->operands().size(); ++i) { |
1377 InstructionBlock* cur_block = | 1374 InstructionBlock* cur_block = |
1378 code()->InstructionBlockAt(block->predecessors()[i]); | 1375 code()->InstructionBlockAt(block->predecessors()[i]); |
1379 AddGapMove(cur_block->last_instruction_index(), Instruction::END, | 1376 UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); |
1380 &phi->inputs()[i], &output); | 1377 auto move = AddGapMove(cur_block->last_instruction_index(), |
| 1378 Instruction::END, input, output); |
| 1379 map_value->incoming_moves.push_back(move); |
1381 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1380 DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
1382 ->HasReferenceMap()); | 1381 ->HasReferenceMap()); |
1383 } | 1382 } |
1384 auto live_range = LiveRangeFor(phi_vreg); | 1383 auto live_range = LiveRangeFor(phi_vreg); |
1385 int gap_index = block->first_instruction_index(); | 1384 int gap_index = block->first_instruction_index(); |
1386 live_range->SpillAtDefinition(local_zone(), gap_index, &output); | 1385 live_range->SpillAtDefinition(local_zone(), gap_index, &output); |
1387 live_range->SetSpillStartIndex(gap_index); | 1386 live_range->SetSpillStartIndex(gap_index); |
1388 // We use the phi-ness of some nodes in some later heuristics. | 1387 // We use the phi-ness of some nodes in some later heuristics. |
1389 live_range->set_is_phi(true); | 1388 live_range->set_is_phi(true); |
1390 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1389 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
1391 } | 1390 } |
1392 } | 1391 } |
1393 | 1392 |
1394 | 1393 |
| 1394 void RegisterAllocator::AssignPhiInput(LiveRange* range, |
| 1395 const InstructionOperand& assignment) { |
| 1396 DCHECK(range->is_phi()); |
| 1397 auto it = phi_map_.find(range->id()); |
| 1398 DCHECK(it != phi_map_.end()); |
| 1399 for (auto move : it->second->incoming_moves) { |
| 1400 move->set_destination(assignment); |
| 1401 } |
| 1402 } |
| 1403 |
| 1404 |
1395 void RegisterAllocator::MeetRegisterConstraints() { | 1405 void RegisterAllocator::MeetRegisterConstraints() { |
1396 for (auto block : code()->instruction_blocks()) { | 1406 for (auto block : code()->instruction_blocks()) { |
1397 MeetRegisterConstraints(block); | 1407 MeetRegisterConstraints(block); |
1398 } | 1408 } |
1399 } | 1409 } |
1400 | 1410 |
1401 | 1411 |
1402 void RegisterAllocator::ResolvePhis() { | 1412 void RegisterAllocator::ResolvePhis() { |
1403 // Process the blocks in reverse order. | 1413 // Process the blocks in reverse order. |
1404 for (auto i = code()->instruction_blocks().rbegin(); | 1414 for (auto i = code()->instruction_blocks().rbegin(); |
1405 i != code()->instruction_blocks().rend(); ++i) { | 1415 i != code()->instruction_blocks().rend(); ++i) { |
1406 ResolvePhis(*i); | 1416 ResolvePhis(*i); |
1407 } | 1417 } |
1408 } | 1418 } |
1409 | 1419 |
1410 | 1420 |
1411 const InstructionBlock* RegisterAllocator::GetInstructionBlock( | 1421 const InstructionBlock* RegisterAllocator::GetInstructionBlock( |
1412 LifetimePosition pos) { | 1422 LifetimePosition pos) { |
1413 return code()->GetInstructionBlock(pos.ToInstructionIndex()); | 1423 return code()->GetInstructionBlock(pos.ToInstructionIndex()); |
1414 } | 1424 } |
1415 | 1425 |
1416 | 1426 |
1417 void RegisterAllocator::ConnectRanges() { | 1427 void RegisterAllocator::ConnectRanges() { |
1418 ZoneMap<std::pair<ParallelMove*, InstructionOperand*>, InstructionOperand*> | 1428 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> |
1419 delayed_insertion_map(local_zone()); | 1429 delayed_insertion_map(local_zone()); |
1420 for (auto first_range : live_ranges()) { | 1430 for (auto first_range : live_ranges()) { |
1421 if (first_range == nullptr || first_range->IsChild()) continue; | 1431 if (first_range == nullptr || first_range->IsChild()) continue; |
1422 for (auto second_range = first_range->next(); second_range != nullptr; | 1432 for (auto second_range = first_range->next(); second_range != nullptr; |
1423 first_range = second_range, second_range = second_range->next()) { | 1433 first_range = second_range, second_range = second_range->next()) { |
1424 auto pos = second_range->Start(); | 1434 auto pos = second_range->Start(); |
1425 // Add gap move if the two live ranges touch and there is no block | 1435 // Add gap move if the two live ranges touch and there is no block |
1426 // boundary. | 1436 // boundary. |
1427 if (second_range->IsSpilled()) continue; | 1437 if (second_range->IsSpilled()) continue; |
1428 if (first_range->End().Value() != pos.Value()) continue; | 1438 if (first_range->End().Value() != pos.Value()) continue; |
1429 if (IsBlockBoundary(pos) && | 1439 if (IsBlockBoundary(pos) && |
1430 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { | 1440 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { |
1431 continue; | 1441 continue; |
1432 } | 1442 } |
1433 auto prev = first_range->GetAssignedOperand(); | 1443 auto prev_operand = first_range->GetAssignedOperand(); |
1434 auto cur = second_range->GetAssignedOperand(); | 1444 auto cur_operand = second_range->GetAssignedOperand(); |
1435 if (prev == cur) continue; | 1445 if (prev_operand == cur_operand) continue; |
1436 bool delay_insertion = false; | 1446 bool delay_insertion = false; |
1437 Instruction::GapPosition gap_pos; | 1447 Instruction::GapPosition gap_pos; |
1438 int gap_index = pos.ToInstructionIndex(); | 1448 int gap_index = pos.ToInstructionIndex(); |
1439 if (pos.IsGapPosition()) { | 1449 if (pos.IsGapPosition()) { |
1440 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; | 1450 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
1441 } else { | 1451 } else { |
1442 if (pos.IsStart()) { | 1452 if (pos.IsStart()) { |
1443 delay_insertion = true; | 1453 delay_insertion = true; |
1444 } else { | 1454 } else { |
1445 gap_index++; | 1455 gap_index++; |
1446 } | 1456 } |
1447 gap_pos = delay_insertion ? Instruction::END : Instruction::START; | 1457 gap_pos = delay_insertion ? Instruction::END : Instruction::START; |
1448 } | 1458 } |
1449 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( | 1459 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( |
1450 gap_pos, code_zone()); | 1460 gap_pos, code_zone()); |
1451 auto prev_operand = InstructionOperand::New(code_zone(), prev); | |
1452 auto cur_operand = InstructionOperand::New(code_zone(), cur); | |
1453 if (!delay_insertion) { | 1461 if (!delay_insertion) { |
1454 move->AddMove(prev_operand, cur_operand, code_zone()); | 1462 move->AddMove(prev_operand, cur_operand); |
1455 } else { | 1463 } else { |
1456 delayed_insertion_map.insert( | 1464 delayed_insertion_map.insert( |
1457 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); | 1465 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); |
1458 } | 1466 } |
1459 } | 1467 } |
1460 } | 1468 } |
1461 if (delayed_insertion_map.empty()) return; | 1469 if (delayed_insertion_map.empty()) return; |
1462 // Insert all the moves which should occur after the stored move. | 1470 // Insert all the moves which should occur after the stored move. |
1463 ZoneVector<MoveOperands> to_insert(local_zone()); | 1471 ZoneVector<MoveOperands*> to_insert(local_zone()); |
1464 ZoneVector<MoveOperands*> to_eliminate(local_zone()); | 1472 ZoneVector<MoveOperands*> to_eliminate(local_zone()); |
1465 to_insert.reserve(4); | 1473 to_insert.reserve(4); |
1466 to_eliminate.reserve(4); | 1474 to_eliminate.reserve(4); |
1467 auto move = delayed_insertion_map.begin()->first.first; | 1475 auto moves = delayed_insertion_map.begin()->first.first; |
1468 for (auto it = delayed_insertion_map.begin();; ++it) { | 1476 for (auto it = delayed_insertion_map.begin();; ++it) { |
1469 bool done = it == delayed_insertion_map.end(); | 1477 bool done = it == delayed_insertion_map.end(); |
1470 if (done || it->first.first != move) { | 1478 if (done || it->first.first != moves) { |
1471 // Commit the MoveOperands for current ParallelMove. | 1479 // Commit the MoveOperands for current ParallelMove. |
1472 for (auto move_ops : to_eliminate) { | 1480 for (auto move : to_eliminate) { |
1473 move_ops->Eliminate(); | 1481 move->Eliminate(); |
1474 } | 1482 } |
1475 for (auto move_ops : to_insert) { | 1483 for (auto move : to_insert) { |
1476 move->AddMove(move_ops.source(), move_ops.destination(), code_zone()); | 1484 moves->push_back(move); |
1477 } | 1485 } |
1478 if (done) break; | 1486 if (done) break; |
1479 // Reset state. | 1487 // Reset state. |
1480 to_eliminate.clear(); | 1488 to_eliminate.clear(); |
1481 to_insert.clear(); | 1489 to_insert.clear(); |
1482 move = it->first.first; | 1490 moves = it->first.first; |
1483 } | 1491 } |
1484 // Gather all MoveOperands for a single ParallelMove. | 1492 // Gather all MoveOperands for a single ParallelMove. |
1485 MoveOperands move_ops(it->first.second, it->second); | 1493 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); |
1486 auto eliminate = move->PrepareInsertAfter(&move_ops); | 1494 auto eliminate = moves->PrepareInsertAfter(move); |
1487 to_insert.push_back(move_ops); | 1495 to_insert.push_back(move); |
1488 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 1496 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
1489 } | 1497 } |
1490 } | 1498 } |
1491 | 1499 |
1492 | 1500 |
1493 bool RegisterAllocator::CanEagerlyResolveControlFlow( | 1501 bool RegisterAllocator::CanEagerlyResolveControlFlow( |
1494 const InstructionBlock* block) const { | 1502 const InstructionBlock* block) const { |
1495 if (block->PredecessorCount() != 1) return false; | 1503 if (block->PredecessorCount() != 1) return false; |
1496 return block->predecessors()[0].IsNext(block->rpo_number()); | 1504 return block->predecessors()[0].IsNext(block->rpo_number()); |
1497 } | 1505 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1643 for (auto pred : block->predecessors()) { | 1651 for (auto pred : block->predecessors()) { |
1644 FindResult result; | 1652 FindResult result; |
1645 const auto* pred_block = code()->InstructionBlockAt(pred); | 1653 const auto* pred_block = code()->InstructionBlockAt(pred); |
1646 array->Find(block, pred_block, &result); | 1654 array->Find(block, pred_block, &result); |
1647 if (result.cur_cover_ == result.pred_cover_ || | 1655 if (result.cur_cover_ == result.pred_cover_ || |
1648 result.cur_cover_->IsSpilled()) | 1656 result.cur_cover_->IsSpilled()) |
1649 continue; | 1657 continue; |
1650 auto pred_op = result.pred_cover_->GetAssignedOperand(); | 1658 auto pred_op = result.pred_cover_->GetAssignedOperand(); |
1651 auto cur_op = result.cur_cover_->GetAssignedOperand(); | 1659 auto cur_op = result.cur_cover_->GetAssignedOperand(); |
1652 if (pred_op == cur_op) continue; | 1660 if (pred_op == cur_op) continue; |
1653 auto pred_ptr = InstructionOperand::New(code_zone(), pred_op); | 1661 ResolveControlFlow(block, cur_op, pred_block, pred_op); |
1654 auto cur_ptr = InstructionOperand::New(code_zone(), cur_op); | |
1655 ResolveControlFlow(block, cur_ptr, pred_block, pred_ptr); | |
1656 } | 1662 } |
1657 iterator.Advance(); | 1663 iterator.Advance(); |
1658 } | 1664 } |
1659 } | 1665 } |
1660 } | 1666 } |
1661 | 1667 |
1662 | 1668 |
1663 void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, | 1669 void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, |
1664 InstructionOperand* cur_op, | 1670 const InstructionOperand& cur_op, |
1665 const InstructionBlock* pred, | 1671 const InstructionBlock* pred, |
1666 InstructionOperand* pred_op) { | 1672 const InstructionOperand& pred_op) { |
1667 DCHECK(!pred_op->Equals(cur_op)); | 1673 DCHECK(pred_op != cur_op); |
1668 int gap_index; | 1674 int gap_index; |
1669 Instruction::GapPosition position; | 1675 Instruction::GapPosition position; |
1670 if (block->PredecessorCount() == 1) { | 1676 if (block->PredecessorCount() == 1) { |
1671 gap_index = block->first_instruction_index(); | 1677 gap_index = block->first_instruction_index(); |
1672 position = Instruction::START; | 1678 position = Instruction::START; |
1673 } else { | 1679 } else { |
1674 DCHECK(pred->SuccessorCount() == 1); | 1680 DCHECK(pred->SuccessorCount() == 1); |
1675 DCHECK(!InstructionAt(pred->last_instruction_index())->HasReferenceMap()); | 1681 DCHECK(!InstructionAt(pred->last_instruction_index())->HasReferenceMap()); |
1676 gap_index = pred->last_instruction_index(); | 1682 gap_index = pred->last_instruction_index(); |
1677 position = Instruction::END; | 1683 position = Instruction::END; |
(...skipping 15 matching lines...) Expand all Loading... |
1693 // Process the instructions in reverse order, generating and killing | 1699 // Process the instructions in reverse order, generating and killing |
1694 // live values. | 1700 // live values. |
1695 ProcessInstructions(block, live); | 1701 ProcessInstructions(block, live); |
1696 // All phi output operands are killed by this block. | 1702 // All phi output operands are killed by this block. |
1697 for (auto phi : block->phis()) { | 1703 for (auto phi : block->phis()) { |
1698 // The live range interval already ends at the first instruction of the | 1704 // The live range interval already ends at the first instruction of the |
1699 // block. | 1705 // block. |
1700 int phi_vreg = phi->virtual_register(); | 1706 int phi_vreg = phi->virtual_register(); |
1701 live->Remove(phi_vreg); | 1707 live->Remove(phi_vreg); |
1702 InstructionOperand* hint = nullptr; | 1708 InstructionOperand* hint = nullptr; |
1703 InstructionOperand* phi_operand = nullptr; | |
1704 auto instr = GetLastInstruction( | 1709 auto instr = GetLastInstruction( |
1705 code()->InstructionBlockAt(block->predecessors()[0])); | 1710 code()->InstructionBlockAt(block->predecessors()[0])); |
1706 auto move = instr->GetParallelMove(Instruction::END); | 1711 for (auto move : *instr->GetParallelMove(Instruction::END)) { |
1707 for (int j = 0; j < move->move_operands()->length(); ++j) { | 1712 auto& to = move->destination(); |
1708 auto to = move->move_operands()->at(j).destination(); | 1713 if (to.IsUnallocated() && |
1709 if (to->IsUnallocated() && | 1714 UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { |
1710 UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) { | 1715 hint = &move->source(); |
1711 hint = move->move_operands()->at(j).source(); | |
1712 phi_operand = to; | |
1713 break; | 1716 break; |
1714 } | 1717 } |
1715 } | 1718 } |
1716 DCHECK(hint != nullptr); | 1719 DCHECK(hint != nullptr); |
1717 auto block_start = LifetimePosition::GapFromInstructionIndex( | 1720 auto block_start = LifetimePosition::GapFromInstructionIndex( |
1718 block->first_instruction_index()); | 1721 block->first_instruction_index()); |
1719 Define(block_start, phi_operand, hint); | 1722 Define(block_start, &phi->output(), hint); |
1720 } | 1723 } |
1721 | 1724 |
1722 // Now live is live_in for this block except not including values live | 1725 // Now live is live_in for this block except not including values live |
1723 // out on backward successor edges. | 1726 // out on backward successor edges. |
1724 live_in_sets_[block_id] = live; | 1727 live_in_sets_[block_id] = live; |
1725 | 1728 |
1726 if (block->IsLoopHeader()) { | 1729 if (block->IsLoopHeader()) { |
1727 // Add a live range stretching from the first loop instruction to the last | 1730 // Add a live range stretching from the first loop instruction to the last |
1728 // for each value live on entry to the header. | 1731 // for each value live on entry to the header. |
1729 BitVector::Iterator iterator(live); | 1732 BitVector::Iterator iterator(live); |
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2500 | 2503 |
2501 void RegisterAllocator::SetLiveRangeAssignedRegister(LiveRange* range, | 2504 void RegisterAllocator::SetLiveRangeAssignedRegister(LiveRange* range, |
2502 int reg) { | 2505 int reg) { |
2503 if (range->Kind() == DOUBLE_REGISTERS) { | 2506 if (range->Kind() == DOUBLE_REGISTERS) { |
2504 assigned_double_registers_->Add(reg); | 2507 assigned_double_registers_->Add(reg); |
2505 } else { | 2508 } else { |
2506 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2509 DCHECK(range->Kind() == GENERAL_REGISTERS); |
2507 assigned_registers_->Add(reg); | 2510 assigned_registers_->Add(reg); |
2508 } | 2511 } |
2509 range->set_assigned_register(reg); | 2512 range->set_assigned_register(reg); |
| 2513 auto assignment = range->GetAssignedOperand(); |
| 2514 // TODO(dcarney): stop aliasing hint operands. |
| 2515 range->ConvertUsesToOperand(assignment, nullptr); |
| 2516 if (range->is_phi()) AssignPhiInput(range, assignment); |
2510 } | 2517 } |
2511 | 2518 |
2512 } // namespace compiler | 2519 } // namespace compiler |
2513 } // namespace internal | 2520 } // namespace internal |
2514 } // namespace v8 | 2521 } // namespace v8 |
OLD | NEW |