Chromium Code Reviews| 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 973 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 984 const ZoneList<MoveOperands>* move_operands = move->move_operands(); | 984 const ZoneList<MoveOperands>* move_operands = move->move_operands(); |
| 985 for (int i = 0; i < move_operands->length(); ++i) { | 985 for (int i = 0; i < move_operands->length(); ++i) { |
| 986 MoveOperands* cur = &move_operands->at(i); | 986 MoveOperands* cur = &move_operands->at(i); |
| 987 if (cur->IsIgnored()) continue; | 987 if (cur->IsIgnored()) continue; |
| 988 InstructionOperand* from = cur->source(); | 988 InstructionOperand* from = cur->source(); |
| 989 InstructionOperand* to = cur->destination(); | 989 InstructionOperand* to = cur->destination(); |
| 990 InstructionOperand* hint = to; | 990 InstructionOperand* hint = to; |
| 991 if (to->IsUnallocated()) { | 991 if (to->IsUnallocated()) { |
| 992 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); | 992 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
| 993 LiveRange* to_range = LiveRangeFor(to_vreg); | 993 LiveRange* to_range = LiveRangeFor(to_vreg); |
| 994 // TODO(dcarney): this in no longer reachable. | |
|
Jarin
2014/11/19 15:43:04
How about DCHECK(!to_range->is_phi()), then?
dcarney
2014/11/19 15:55:48
i just nuked all the is_phi stuff instead
| |
| 994 if (to_range->is_phi()) { | 995 if (to_range->is_phi()) { |
| 995 if (to_range->is_non_loop_phi()) { | 996 if (to_range->is_non_loop_phi()) { |
| 996 hint = to_range->current_hint_operand(); | 997 hint = to_range->current_hint_operand(); |
| 997 } | 998 } |
| 998 } else { | 999 } else { |
| 999 if (live->Contains(to_vreg)) { | 1000 if (live->Contains(to_vreg)) { |
| 1000 Define(curr_position, to, from); | 1001 Define(curr_position, to, from); |
| 1001 live->Remove(to_vreg); | 1002 live->Remove(to_vreg); |
| 1002 } else { | 1003 } else { |
| 1003 cur->Eliminate(); | 1004 cur->Eliminate(); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1075 } | 1076 } |
| 1076 } | 1077 } |
| 1077 Use(block_start_position, curr_position.InstructionEnd(), temp, NULL); | 1078 Use(block_start_position, curr_position.InstructionEnd(), temp, NULL); |
| 1078 Define(curr_position, temp, NULL); | 1079 Define(curr_position, temp, NULL); |
| 1079 } | 1080 } |
| 1080 } | 1081 } |
| 1081 } | 1082 } |
| 1082 } | 1083 } |
| 1083 | 1084 |
| 1084 | 1085 |
| 1085 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { | 1086 void RegisterAllocator::ProcessPhis(const InstructionBlock* block) { |
| 1086 for (auto phi : block->phis()) { | 1087 for (auto phi : block->phis()) { |
| 1087 UnallocatedOperand* phi_operand = | 1088 auto output = phi->output(); |
| 1088 new (code_zone()) UnallocatedOperand(UnallocatedOperand::NONE); | |
| 1089 int phi_vreg = phi->virtual_register(); | 1089 int phi_vreg = phi->virtual_register(); |
| 1090 phi_operand->set_virtual_register(phi_vreg); | |
| 1091 | |
| 1092 for (size_t i = 0; i < phi->operands().size(); ++i) { | |
| 1093 UnallocatedOperand* operand = | |
| 1094 new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY); | |
| 1095 operand->set_virtual_register(phi->operands()[i]); | |
| 1096 InstructionBlock* cur_block = | |
| 1097 code()->InstructionBlockAt(block->predecessors()[i]); | |
| 1098 // The gap move must be added without any special processing as in | |
| 1099 // the AddConstraintsGapMove. | |
| 1100 code()->AddGapMove(cur_block->last_instruction_index() - 1, operand, | |
| 1101 phi_operand); | |
| 1102 | |
| 1103 Instruction* branch = InstructionAt(cur_block->last_instruction_index()); | |
| 1104 DCHECK(!branch->HasPointerMap()); | |
| 1105 USE(branch); | |
| 1106 } | |
| 1107 | |
| 1108 LiveRange* live_range = LiveRangeFor(phi_vreg); | 1090 LiveRange* live_range = LiveRangeFor(phi_vreg); |
| 1109 BlockStartInstruction* block_start = | 1091 BlockStartInstruction* block_start = |
| 1110 code()->GetBlockStart(block->rpo_number()); | 1092 code()->GetBlockStart(block->rpo_number()); |
| 1111 block_start->GetOrCreateParallelMove(GapInstruction::START, code_zone()) | 1093 block_start->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()) |
| 1112 ->AddMove(phi_operand, live_range->GetSpillOperand(), code_zone()); | 1094 ->AddMove(output, live_range->GetSpillOperand(), code_zone()); |
| 1113 live_range->SetSpillStartIndex(block->first_instruction_index()); | 1095 live_range->SetSpillStartIndex(block->first_instruction_index()); |
| 1114 | |
| 1115 // We use the phi-ness of some nodes in some later heuristics. | 1096 // We use the phi-ness of some nodes in some later heuristics. |
| 1116 live_range->set_is_phi(true); | 1097 live_range->set_is_phi(true); |
| 1117 if (!block->IsLoopHeader()) { | 1098 if (!block->IsLoopHeader()) { |
| 1118 live_range->set_is_non_loop_phi(true); | 1099 live_range->set_is_non_loop_phi(true); |
| 1119 } | 1100 } |
| 1120 } | 1101 } |
| 1121 } | 1102 } |
| 1122 | 1103 |
| 1123 | 1104 |
| 1124 void RegisterAllocator::MeetRegisterConstraints() { | 1105 void RegisterAllocator::MeetRegisterConstraints() { |
| 1125 for (auto block : code()->instruction_blocks()) { | 1106 for (auto block : code()->instruction_blocks()) { |
| 1107 ProcessPhis(block); | |
| 1126 MeetRegisterConstraints(block); | 1108 MeetRegisterConstraints(block); |
| 1127 if (!AllocationOk()) return; | |
| 1128 } | 1109 } |
| 1129 } | 1110 } |
| 1130 | 1111 |
| 1131 | |
| 1132 void RegisterAllocator::ResolvePhis() { | |
| 1133 // Process the blocks in reverse order. | |
| 1134 for (auto i = code()->instruction_blocks().rbegin(); | |
| 1135 i != code()->instruction_blocks().rend(); ++i) { | |
| 1136 ResolvePhis(*i); | |
| 1137 } | |
| 1138 } | |
| 1139 | |
| 1140 | 1112 |
| 1141 ParallelMove* RegisterAllocator::GetConnectingParallelMove( | 1113 ParallelMove* RegisterAllocator::GetConnectingParallelMove( |
| 1142 LifetimePosition pos) { | 1114 LifetimePosition pos) { |
| 1143 int index = pos.InstructionIndex(); | 1115 int index = pos.InstructionIndex(); |
| 1144 if (code()->IsGapAt(index)) { | 1116 if (code()->IsGapAt(index)) { |
| 1145 GapInstruction* gap = code()->GapAt(index); | 1117 GapInstruction* gap = code()->GapAt(index); |
| 1146 return gap->GetOrCreateParallelMove( | 1118 return gap->GetOrCreateParallelMove( |
| 1147 pos.IsInstructionStart() ? GapInstruction::START : GapInstruction::END, | 1119 pos.IsInstructionStart() ? GapInstruction::START : GapInstruction::END, |
| 1148 code_zone()); | 1120 code_zone()); |
| 1149 } | 1121 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1259 if (bound->start_.Value() <= position.Value()) { | 1231 if (bound->start_.Value() <= position.Value()) { |
| 1260 if (position.Value() < bound->end_.Value()) return bound; | 1232 if (position.Value() < bound->end_.Value()) return bound; |
| 1261 DCHECK(left_index < current_index); | 1233 DCHECK(left_index < current_index); |
| 1262 left_index = current_index; | 1234 left_index = current_index; |
| 1263 } else { | 1235 } else { |
| 1264 right_index = current_index; | 1236 right_index = current_index; |
| 1265 } | 1237 } |
| 1266 } | 1238 } |
| 1267 } | 1239 } |
| 1268 | 1240 |
| 1241 LiveRangeBound* FindPred(const InstructionBlock* pred) { | |
| 1242 const LifetimePosition pred_end = | |
| 1243 LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); | |
| 1244 return Find(pred_end); | |
| 1245 } | |
| 1246 | |
| 1247 LiveRangeBound* FindSucc(const InstructionBlock* succ) { | |
| 1248 const LifetimePosition succ_start = | |
| 1249 LifetimePosition::FromInstructionIndex(succ->first_instruction_index()); | |
| 1250 return Find(succ_start); | |
| 1251 } | |
| 1252 | |
| 1269 void Find(const InstructionBlock* block, const InstructionBlock* pred, | 1253 void Find(const InstructionBlock* block, const InstructionBlock* pred, |
| 1270 FindResult* result) const { | 1254 FindResult* result) const { |
| 1271 const LifetimePosition pred_end = | 1255 const LifetimePosition pred_end = |
| 1272 LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); | 1256 LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); |
| 1273 LiveRangeBound* bound = Find(pred_end); | 1257 LiveRangeBound* bound = Find(pred_end); |
| 1274 result->pred_cover_ = bound->range_; | 1258 result->pred_cover_ = bound->range_; |
| 1275 const LifetimePosition cur_start = LifetimePosition::FromInstructionIndex( | 1259 const LifetimePosition cur_start = LifetimePosition::FromInstructionIndex( |
| 1276 block->first_instruction_index()); | 1260 block->first_instruction_index()); |
| 1277 // Common case. | 1261 // Common case. |
| 1278 if (bound->CanCover(cur_start)) { | 1262 if (bound->CanCover(cur_start)) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1323 }; | 1307 }; |
| 1324 | 1308 |
| 1325 } // namespace | 1309 } // namespace |
| 1326 | 1310 |
| 1327 | 1311 |
| 1328 void RegisterAllocator::ResolveControlFlow() { | 1312 void RegisterAllocator::ResolveControlFlow() { |
| 1329 // Lazily linearize live ranges in memory for fast lookup. | 1313 // Lazily linearize live ranges in memory for fast lookup. |
| 1330 LiveRangeFinder finder(*this); | 1314 LiveRangeFinder finder(*this); |
| 1331 for (auto block : code()->instruction_blocks()) { | 1315 for (auto block : code()->instruction_blocks()) { |
| 1332 if (CanEagerlyResolveControlFlow(block)) continue; | 1316 if (CanEagerlyResolveControlFlow(block)) continue; |
| 1317 /* resolve phis */ | |
|
Jarin
2014/11/19 15:43:04
// style comment?
dcarney
2014/11/19 15:55:48
Done.
| |
| 1318 for (auto phi : block->phis()) { | |
| 1319 // TODO(dcarney): optimize this - no need to CreateAssignedOperand here | |
| 1320 // and in ResolveControlFlow. | |
| 1321 auto* block_bound = | |
|
Jarin
2014/11/19 15:43:04
Yeah, this would deserve some comment and/or clean
dcarney
2014/11/19 15:55:48
cleaned up
| |
| 1322 finder.ArrayFor(phi->virtual_register())->FindSucc(block); | |
| 1323 auto phi_output = block_bound->range_->CreateAssignedOperand(code_zone()); | |
| 1324 phi->output()->ConvertTo(phi_output->kind(), phi_output->index()); | |
| 1325 size_t pred_index = 0; | |
| 1326 for (auto pred : block->predecessors()) { | |
| 1327 const InstructionBlock* pred_block = code()->InstructionBlockAt(pred); | |
| 1328 auto* pred_bound = | |
| 1329 finder.ArrayFor(phi->operands()[pred_index])->FindPred(pred_block); | |
| 1330 phi->inputs()[pred_index] = | |
| 1331 pred_bound->range_->CreateAssignedOperand(code_zone()); | |
| 1332 ResolveControlFlow(block, block_bound->range_, pred_block, | |
| 1333 pred_bound->range_); | |
| 1334 pred_index++; | |
| 1335 } | |
| 1336 } | |
| 1333 BitVector* live = live_in_sets_[block->rpo_number().ToInt()]; | 1337 BitVector* live = live_in_sets_[block->rpo_number().ToInt()]; |
| 1334 BitVector::Iterator iterator(live); | 1338 BitVector::Iterator iterator(live); |
| 1335 while (!iterator.Done()) { | 1339 while (!iterator.Done()) { |
| 1336 LiveRangeBoundArray* array = finder.ArrayFor(iterator.Current()); | 1340 auto* array = finder.ArrayFor(iterator.Current()); |
| 1337 for (auto pred : block->predecessors()) { | 1341 for (auto pred : block->predecessors()) { |
| 1338 FindResult result; | 1342 FindResult result; |
| 1339 const InstructionBlock* pred_block = code()->InstructionBlockAt(pred); | 1343 const auto* pred_block = code()->InstructionBlockAt(pred); |
| 1340 array->Find(block, pred_block, &result); | 1344 array->Find(block, pred_block, &result); |
| 1341 if (result.cur_cover_ == result.pred_cover_ || | 1345 if (result.cur_cover_ == result.pred_cover_ || |
| 1342 result.cur_cover_->IsSpilled()) | 1346 result.cur_cover_->IsSpilled()) |
| 1343 continue; | 1347 continue; |
| 1344 ResolveControlFlow(block, result.cur_cover_, pred_block, | 1348 ResolveControlFlow(block, result.cur_cover_, pred_block, |
| 1345 result.pred_cover_); | 1349 result.pred_cover_); |
| 1346 } | 1350 } |
| 1347 iterator.Advance(); | 1351 iterator.Advance(); |
| 1348 } | 1352 } |
| 1349 } | 1353 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1388 | 1392 |
| 1389 // Process the instructions in reverse order, generating and killing | 1393 // Process the instructions in reverse order, generating and killing |
| 1390 // live values. | 1394 // live values. |
| 1391 ProcessInstructions(block, live); | 1395 ProcessInstructions(block, live); |
| 1392 // All phi output operands are killed by this block. | 1396 // All phi output operands are killed by this block. |
| 1393 for (auto phi : block->phis()) { | 1397 for (auto phi : block->phis()) { |
| 1394 // The live range interval already ends at the first instruction of the | 1398 // The live range interval already ends at the first instruction of the |
| 1395 // block. | 1399 // block. |
| 1396 int phi_vreg = phi->virtual_register(); | 1400 int phi_vreg = phi->virtual_register(); |
| 1397 live->Remove(phi_vreg); | 1401 live->Remove(phi_vreg); |
| 1398 | |
| 1399 InstructionOperand* hint = NULL; | |
| 1400 InstructionOperand* phi_operand = NULL; | |
| 1401 GapInstruction* gap = | |
| 1402 GetLastGap(code()->InstructionBlockAt(block->predecessors()[0])); | |
| 1403 | |
| 1404 // TODO(titzer): no need to create the parallel move if it doesn't exit. | |
| 1405 ParallelMove* move = | |
| 1406 gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()); | |
| 1407 for (int j = 0; j < move->move_operands()->length(); ++j) { | |
| 1408 InstructionOperand* to = move->move_operands()->at(j).destination(); | |
| 1409 if (to->IsUnallocated() && | |
| 1410 UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) { | |
| 1411 hint = move->move_operands()->at(j).source(); | |
| 1412 phi_operand = to; | |
| 1413 break; | |
| 1414 } | |
| 1415 } | |
| 1416 DCHECK(hint != NULL); | |
| 1417 | |
| 1418 LifetimePosition block_start = LifetimePosition::FromInstructionIndex( | |
| 1419 block->first_instruction_index()); | |
| 1420 Define(block_start, phi_operand, hint); | |
| 1421 } | 1402 } |
| 1422 | 1403 |
| 1423 // Now live is live_in for this block except not including values live | 1404 // Now live is live_in for this block except not including values live |
| 1424 // out on backward successor edges. | 1405 // out on backward successor edges. |
| 1425 live_in_sets_[block_id] = live; | 1406 live_in_sets_[block_id] = live; |
| 1426 | 1407 |
| 1427 if (block->IsLoopHeader()) { | 1408 if (block->IsLoopHeader()) { |
| 1428 // Add a live range stretching from the first loop instruction to the last | 1409 // Add a live range stretching from the first loop instruction to the last |
| 1429 // for each value live on entry to the header. | 1410 // for each value live on entry to the header. |
| 1430 BitVector::Iterator iterator(live); | 1411 BitVector::Iterator iterator(live); |
| (...skipping 845 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2276 } else { | 2257 } else { |
| 2277 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2258 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2278 assigned_registers_->Add(reg); | 2259 assigned_registers_->Add(reg); |
| 2279 } | 2260 } |
| 2280 range->set_assigned_register(reg, code_zone()); | 2261 range->set_assigned_register(reg, code_zone()); |
| 2281 } | 2262 } |
| 2282 | 2263 |
| 2283 } | 2264 } |
| 2284 } | 2265 } |
| 2285 } // namespace v8::internal::compiler | 2266 } // namespace v8::internal::compiler |
| OLD | NEW |