| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/hydrogen.h" | 7 #include "src/hydrogen.h" |
| 8 #include "src/lithium-inl.h" | 8 #include "src/lithium-inl.h" |
| 9 #include "src/lithium-allocator-inl.h" | 9 #include "src/lithium-allocator-inl.h" |
| 10 #include "src/string-stream.h" | 10 #include "src/string-stream.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 assigned_register_(kInvalidAssignment), | 102 assigned_register_(kInvalidAssignment), |
| 103 last_interval_(NULL), | 103 last_interval_(NULL), |
| 104 first_interval_(NULL), | 104 first_interval_(NULL), |
| 105 first_pos_(NULL), | 105 first_pos_(NULL), |
| 106 parent_(NULL), | 106 parent_(NULL), |
| 107 next_(NULL), | 107 next_(NULL), |
| 108 current_interval_(NULL), | 108 current_interval_(NULL), |
| 109 last_processed_use_(NULL), | 109 last_processed_use_(NULL), |
| 110 current_hint_operand_(NULL), | 110 current_hint_operand_(NULL), |
| 111 spill_operand_(new (zone) LOperand()), | 111 spill_operand_(new (zone) LOperand()), |
| 112 spill_start_index_(kMaxInt), | 112 spill_start_index_(kMaxInt) {} |
| 113 spill_range_(NULL) {} | |
| 114 | 113 |
| 115 | 114 |
| 116 void LiveRange::set_assigned_register(int reg, Zone* zone) { | 115 void LiveRange::set_assigned_register(int reg, Zone* zone) { |
| 117 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 116 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
| 118 assigned_register_ = reg; | 117 assigned_register_ = reg; |
| 119 ConvertOperands(zone); | 118 ConvertOperands(zone); |
| 120 } | 119 } |
| 121 | 120 |
| 122 | 121 |
| 123 void LiveRange::MakeSpilled(Zone* zone) { | 122 void LiveRange::MakeSpilled(Zone* zone) { |
| 124 DCHECK(!IsSpilled()); | 123 DCHECK(!IsSpilled()); |
| 125 DCHECK(TopLevel()->HasAllocatedSpillOperand()); | 124 DCHECK(TopLevel()->HasAllocatedSpillOperand()); |
| 126 spilled_ = true; | 125 spilled_ = true; |
| 127 assigned_register_ = kInvalidAssignment; | 126 assigned_register_ = kInvalidAssignment; |
| 128 if (spill_range_ == NULL) { | 127 ConvertOperands(zone); |
| 129 ConvertOperands(zone); | |
| 130 } | |
| 131 } | 128 } |
| 132 | 129 |
| 133 | 130 |
| 134 bool LiveRange::HasAllocatedSpillOperand() const { | 131 bool LiveRange::HasAllocatedSpillOperand() const { |
| 135 DCHECK(spill_operand_ != NULL); | 132 DCHECK(spill_operand_ != NULL); |
| 136 return !spill_operand_->IsIgnored() || spill_range_ != NULL; | 133 return !spill_operand_->IsIgnored(); |
| 137 } | 134 } |
| 138 | 135 |
| 139 | 136 |
| 140 void LiveRange::SetSpillOperand(LOperand* operand) { | 137 void LiveRange::SetSpillOperand(LOperand* operand) { |
| 141 DCHECK(!operand->IsUnallocated()); | 138 DCHECK(!operand->IsUnallocated()); |
| 142 DCHECK(spill_operand_ != NULL); | 139 DCHECK(spill_operand_ != NULL); |
| 143 DCHECK(spill_operand_->IsIgnored()); | 140 DCHECK(spill_operand_->IsIgnored()); |
| 144 spill_operand_->ConvertTo(operand->kind(), operand->index()); | 141 spill_operand_->ConvertTo(operand->kind(), operand->index()); |
| 145 } | 142 } |
| 146 | 143 |
| 147 | 144 |
| 148 void LiveRange::CommitSpillOperand(LOperand* operand) { | |
| 149 DCHECK(spill_range_ != NULL); | |
| 150 DCHECK(!IsChild()); | |
| 151 spill_range_ = NULL; | |
| 152 SetSpillOperand(operand); | |
| 153 for (LiveRange* range = this; range != NULL; range = range->next()) { | |
| 154 if (range->IsSpilled()) { | |
| 155 range->ConvertUsesToOperand(operand); | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 | |
| 161 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { | 145 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { |
| 162 UsePosition* use_pos = last_processed_use_; | 146 UsePosition* use_pos = last_processed_use_; |
| 163 if (use_pos == NULL) use_pos = first_pos(); | 147 if (use_pos == NULL) use_pos = first_pos(); |
| 164 while (use_pos != NULL && use_pos->pos().Value() < start.Value()) { | 148 while (use_pos != NULL && use_pos->pos().Value() < start.Value()) { |
| 165 use_pos = use_pos->next(); | 149 use_pos = use_pos->next(); |
| 166 } | 150 } |
| 167 last_processed_use_ = use_pos; | 151 last_processed_use_ = use_pos; |
| 168 return use_pos; | 152 return use_pos; |
| 169 } | 153 } |
| 170 | 154 |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 use_pos->next_ = prev->next_; | 439 use_pos->next_ = prev->next_; |
| 456 prev->next_ = use_pos; | 440 prev->next_ = use_pos; |
| 457 } | 441 } |
| 458 | 442 |
| 459 if (prev_hint == NULL && use_pos->HasHint()) { | 443 if (prev_hint == NULL && use_pos->HasHint()) { |
| 460 current_hint_operand_ = hint; | 444 current_hint_operand_ = hint; |
| 461 } | 445 } |
| 462 } | 446 } |
| 463 | 447 |
| 464 | 448 |
| 465 void LiveRange::ConvertUsesToOperand(LOperand* op) { | 449 void LiveRange::ConvertOperands(Zone* zone) { |
| 450 LOperand* op = CreateAssignedOperand(zone); |
| 466 UsePosition* use_pos = first_pos(); | 451 UsePosition* use_pos = first_pos(); |
| 467 while (use_pos != NULL) { | 452 while (use_pos != NULL) { |
| 468 DCHECK(Start().Value() <= use_pos->pos().Value() && | 453 DCHECK(Start().Value() <= use_pos->pos().Value() && |
| 469 use_pos->pos().Value() <= End().Value()); | 454 use_pos->pos().Value() <= End().Value()); |
| 470 | 455 |
| 471 if (use_pos->HasOperand()) { | 456 if (use_pos->HasOperand()) { |
| 472 DCHECK(op->IsRegister() || op->IsDoubleRegister() || | 457 DCHECK(op->IsRegister() || op->IsDoubleRegister() || |
| 473 !use_pos->RequiresRegister()); | 458 !use_pos->RequiresRegister()); |
| 474 use_pos->operand()->ConvertTo(op->kind(), op->index()); | 459 use_pos->operand()->ConvertTo(op->kind(), op->index()); |
| 475 } | 460 } |
| 476 use_pos = use_pos->next(); | 461 use_pos = use_pos->next(); |
| 477 } | 462 } |
| 478 } | 463 } |
| 479 | 464 |
| 480 | 465 |
| 481 void LiveRange::ConvertOperands(Zone* zone) { | |
| 482 LOperand* op = CreateAssignedOperand(zone); | |
| 483 ConvertUsesToOperand(op); | |
| 484 } | |
| 485 | |
| 486 | |
| 487 bool LiveRange::CanCover(LifetimePosition position) const { | 466 bool LiveRange::CanCover(LifetimePosition position) const { |
| 488 if (IsEmpty()) return false; | 467 if (IsEmpty()) return false; |
| 489 return Start().Value() <= position.Value() && | 468 return Start().Value() <= position.Value() && |
| 490 position.Value() < End().Value(); | 469 position.Value() < End().Value(); |
| 491 } | 470 } |
| 492 | 471 |
| 493 | 472 |
| 494 bool LiveRange::Covers(LifetimePosition position) { | 473 bool LiveRange::Covers(LifetimePosition position) { |
| 495 if (!CanCover(position)) return false; | 474 if (!CanCover(position)) return false; |
| 496 UseInterval* start_search = FirstSearchIntervalForPosition(position); | 475 UseInterval* start_search = FirstSearchIntervalForPosition(position); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 : zone_(graph->isolate()), | 514 : zone_(graph->isolate()), |
| 536 chunk_(NULL), | 515 chunk_(NULL), |
| 537 live_in_sets_(graph->blocks()->length(), zone()), | 516 live_in_sets_(graph->blocks()->length(), zone()), |
| 538 live_ranges_(num_values * 2, zone()), | 517 live_ranges_(num_values * 2, zone()), |
| 539 fixed_live_ranges_(NULL), | 518 fixed_live_ranges_(NULL), |
| 540 fixed_double_live_ranges_(NULL), | 519 fixed_double_live_ranges_(NULL), |
| 541 unhandled_live_ranges_(num_values * 2, zone()), | 520 unhandled_live_ranges_(num_values * 2, zone()), |
| 542 active_live_ranges_(8, zone()), | 521 active_live_ranges_(8, zone()), |
| 543 inactive_live_ranges_(8, zone()), | 522 inactive_live_ranges_(8, zone()), |
| 544 reusable_slots_(8, zone()), | 523 reusable_slots_(8, zone()), |
| 545 spill_ranges_(8, zone()), | |
| 546 next_virtual_register_(num_values), | 524 next_virtual_register_(num_values), |
| 547 first_artificial_register_(num_values), | 525 first_artificial_register_(num_values), |
| 548 mode_(UNALLOCATED_REGISTERS), | 526 mode_(UNALLOCATED_REGISTERS), |
| 549 num_registers_(-1), | 527 num_registers_(-1), |
| 550 graph_(graph), | 528 graph_(graph), |
| 551 has_osr_entry_(false), | 529 has_osr_entry_(false), |
| 552 allocation_ok_(true) {} | 530 allocation_ok_(true) {} |
| 553 | 531 |
| 554 | 532 |
| 555 void LAllocator::InitializeLivenessAnalysis() { | 533 void LAllocator::InitializeLivenessAnalysis() { |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1031 index = index - 1; | 1009 index = index - 1; |
| 1032 } | 1010 } |
| 1033 } | 1011 } |
| 1034 | 1012 |
| 1035 | 1013 |
| 1036 void LAllocator::ResolvePhis(HBasicBlock* block) { | 1014 void LAllocator::ResolvePhis(HBasicBlock* block) { |
| 1037 const ZoneList<HPhi*>* phis = block->phis(); | 1015 const ZoneList<HPhi*>* phis = block->phis(); |
| 1038 for (int i = 0; i < phis->length(); ++i) { | 1016 for (int i = 0; i < phis->length(); ++i) { |
| 1039 HPhi* phi = phis->at(i); | 1017 HPhi* phi = phis->at(i); |
| 1040 LUnallocated* phi_operand = | 1018 LUnallocated* phi_operand = |
| 1041 new (chunk()->zone()) LUnallocated(LUnallocated::ANY); | 1019 new (chunk()->zone()) LUnallocated(LUnallocated::NONE); |
| 1042 phi_operand->set_virtual_register(phi->id()); | 1020 phi_operand->set_virtual_register(phi->id()); |
| 1043 for (int j = 0; j < phi->OperandCount(); ++j) { | 1021 for (int j = 0; j < phi->OperandCount(); ++j) { |
| 1044 HValue* op = phi->OperandAt(j); | 1022 HValue* op = phi->OperandAt(j); |
| 1045 LOperand* operand = NULL; | 1023 LOperand* operand = NULL; |
| 1046 if (op->IsConstant() && op->EmitAtUses()) { | 1024 if (op->IsConstant() && op->EmitAtUses()) { |
| 1047 HConstant* constant = HConstant::cast(op); | 1025 HConstant* constant = HConstant::cast(op); |
| 1048 operand = chunk_->DefineConstantOperand(constant); | 1026 operand = chunk_->DefineConstantOperand(constant); |
| 1049 } else { | 1027 } else { |
| 1050 DCHECK(!op->EmitAtUses()); | 1028 DCHECK(!op->EmitAtUses()); |
| 1051 LUnallocated* unalloc = | 1029 LUnallocated* unalloc = |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 new(chunk->zone()) BitVector(DoubleRegister::NumAllocatableRegisters(), | 1076 new(chunk->zone()) BitVector(DoubleRegister::NumAllocatableRegisters(), |
| 1099 chunk->zone()); | 1077 chunk->zone()); |
| 1100 MeetRegisterConstraints(); | 1078 MeetRegisterConstraints(); |
| 1101 if (!AllocationOk()) return false; | 1079 if (!AllocationOk()) return false; |
| 1102 ResolvePhis(); | 1080 ResolvePhis(); |
| 1103 BuildLiveRanges(); | 1081 BuildLiveRanges(); |
| 1104 AllocateGeneralRegisters(); | 1082 AllocateGeneralRegisters(); |
| 1105 if (!AllocationOk()) return false; | 1083 if (!AllocationOk()) return false; |
| 1106 AllocateDoubleRegisters(); | 1084 AllocateDoubleRegisters(); |
| 1107 if (!AllocationOk()) return false; | 1085 if (!AllocationOk()) return false; |
| 1108 ReuseSpillSlots(); | |
| 1109 PopulatePointerMaps(); | 1086 PopulatePointerMaps(); |
| 1110 ConnectRanges(); | 1087 ConnectRanges(); |
| 1111 ResolveControlFlow(); | 1088 ResolveControlFlow(); |
| 1112 return true; | 1089 return true; |
| 1113 } | 1090 } |
| 1114 | 1091 |
| 1115 | 1092 |
| 1116 static bool AreUseIntervalsIntersecting(UseInterval* interval1, | |
| 1117 UseInterval* interval2) { | |
| 1118 while (interval1 != NULL && interval2 != NULL) { | |
| 1119 if (interval1->start().Value() < interval2->start().Value()) { | |
| 1120 if (interval1->end().Value() > interval2->start().Value()) { | |
| 1121 return true; | |
| 1122 } | |
| 1123 interval1 = interval1->next(); | |
| 1124 } else { | |
| 1125 if (interval2->end().Value() > interval1->start().Value()) { | |
| 1126 return true; | |
| 1127 } | |
| 1128 interval2 = interval2->next(); | |
| 1129 } | |
| 1130 } | |
| 1131 return false; | |
| 1132 } | |
| 1133 | |
| 1134 | |
| 1135 SpillRange::SpillRange(LiveRange* range, int id, Zone* zone) | |
| 1136 : id_(id), live_ranges_(1, zone), end_position_(range->End()) { | |
| 1137 UseInterval* src = range->first_interval(); | |
| 1138 UseInterval* result = NULL; | |
| 1139 UseInterval* node = NULL; | |
| 1140 // Copy the nodes | |
| 1141 while (src != NULL) { | |
| 1142 UseInterval* new_node = new (zone) UseInterval(src->start(), src->end()); | |
| 1143 if (result == NULL) { | |
| 1144 result = new_node; | |
| 1145 } else { | |
| 1146 node->set_next(new_node); | |
| 1147 } | |
| 1148 node = new_node; | |
| 1149 src = src->next(); | |
| 1150 } | |
| 1151 use_interval_ = result; | |
| 1152 live_ranges_.Add(range, zone); | |
| 1153 DCHECK(range->GetSpillRange() == NULL); | |
| 1154 range->SetSpillRange(this); | |
| 1155 } | |
| 1156 | |
| 1157 | |
| 1158 bool SpillRange::IsIntersectingWith(SpillRange* other) { | |
| 1159 if (End().Value() <= other->use_interval_->start().Value() || | |
| 1160 other->End().Value() <= use_interval_->start().Value()) { | |
| 1161 return false; | |
| 1162 } | |
| 1163 return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); | |
| 1164 } | |
| 1165 | |
| 1166 | |
| 1167 bool SpillRange::TryMerge(SpillRange* other, Zone* zone) { | |
| 1168 if (Kind() == other->Kind() && | |
| 1169 !AreUseIntervalsIntersecting(use_interval_, other->use_interval_)) { | |
| 1170 if (End().Value() < other->End().Value()) { | |
| 1171 end_position_ = other->End(); | |
| 1172 } | |
| 1173 | |
| 1174 MergeDisjointIntervals(other->use_interval_, zone); | |
| 1175 other->use_interval_ = NULL; | |
| 1176 | |
| 1177 for (int i = 0; i < other->live_ranges_.length(); i++) { | |
| 1178 DCHECK(other->live_ranges_.at(i)->GetSpillRange() == other); | |
| 1179 other->live_ranges_.at(i)->SetSpillRange(this); | |
| 1180 } | |
| 1181 | |
| 1182 live_ranges_.AddAll(other->live_ranges_, zone); | |
| 1183 other->live_ranges_.Clear(); | |
| 1184 | |
| 1185 return true; | |
| 1186 } | |
| 1187 return false; | |
| 1188 } | |
| 1189 | |
| 1190 | |
| 1191 void SpillRange::SetOperand(LOperand* op) { | |
| 1192 for (int i = 0; i < live_ranges_.length(); i++) { | |
| 1193 DCHECK(live_ranges_.at(i)->GetSpillRange() == this); | |
| 1194 live_ranges_.at(i)->CommitSpillOperand(op); | |
| 1195 } | |
| 1196 } | |
| 1197 | |
| 1198 | |
| 1199 void SpillRange::MergeDisjointIntervals(UseInterval* other, Zone* zone) { | |
| 1200 UseInterval* tail = NULL; | |
| 1201 UseInterval* current = use_interval_; | |
| 1202 while (other != NULL) { | |
| 1203 // Make sure the 'current' list starts first | |
| 1204 if (current == NULL || current->start().Value() > other->start().Value()) { | |
| 1205 std::swap(current, other); | |
| 1206 } | |
| 1207 | |
| 1208 // Check disjointness | |
| 1209 DCHECK(other == NULL || current->end().Value() <= other->start().Value()); | |
| 1210 | |
| 1211 // Append the 'current' node to the result accumulator and move forward | |
| 1212 if (tail == NULL) { | |
| 1213 use_interval_ = current; | |
| 1214 } else { | |
| 1215 tail->set_next(current); | |
| 1216 } | |
| 1217 tail = current; | |
| 1218 current = current->next(); | |
| 1219 } | |
| 1220 // Other list is empty => we are done | |
| 1221 } | |
| 1222 | |
| 1223 | |
| 1224 void LAllocator::ReuseSpillSlots() { | |
| 1225 // Merge disjoint spill ranges | |
| 1226 for (int i = 0; i < spill_ranges_.length(); i++) { | |
| 1227 SpillRange* range = spill_ranges_.at(i); | |
| 1228 if (!range->IsEmpty()) { | |
| 1229 for (int j = i + 1; j < spill_ranges_.length(); j++) { | |
| 1230 SpillRange* other = spill_ranges_.at(j); | |
| 1231 if (!other->IsEmpty()) { | |
| 1232 range->TryMerge(spill_ranges_.at(j), zone()); | |
| 1233 } | |
| 1234 } | |
| 1235 } | |
| 1236 } | |
| 1237 | |
| 1238 // Allocate slots for the merged spill ranges. | |
| 1239 for (int i = 0; i < spill_ranges_.length(); i++) { | |
| 1240 SpillRange* range = spill_ranges_.at(i); | |
| 1241 if (!range->IsEmpty()) { | |
| 1242 LOperand* op = chunk_->GetNextSpillSlot(range->Kind()); | |
| 1243 range->SetOperand(op); | |
| 1244 } | |
| 1245 } | |
| 1246 } | |
| 1247 | |
| 1248 | |
| 1249 void LAllocator::MeetRegisterConstraints() { | 1093 void LAllocator::MeetRegisterConstraints() { |
| 1250 LAllocatorPhase phase("L_Register constraints", this); | 1094 LAllocatorPhase phase("L_Register constraints", this); |
| 1251 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); | 1095 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); |
| 1252 for (int i = 0; i < blocks->length(); ++i) { | 1096 for (int i = 0; i < blocks->length(); ++i) { |
| 1253 HBasicBlock* block = blocks->at(i); | 1097 HBasicBlock* block = blocks->at(i); |
| 1254 MeetRegisterConstraints(block); | 1098 MeetRegisterConstraints(block); |
| 1255 if (!AllocationOk()) return; | 1099 if (!AllocationOk()) return; |
| 1256 } | 1100 } |
| 1257 } | 1101 } |
| 1258 | 1102 |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1629 | 1473 |
| 1630 | 1474 |
| 1631 void LAllocator::AllocateDoubleRegisters() { | 1475 void LAllocator::AllocateDoubleRegisters() { |
| 1632 LAllocatorPhase phase("L_Allocate double registers", this); | 1476 LAllocatorPhase phase("L_Allocate double registers", this); |
| 1633 num_registers_ = DoubleRegister::NumAllocatableRegisters(); | 1477 num_registers_ = DoubleRegister::NumAllocatableRegisters(); |
| 1634 mode_ = DOUBLE_REGISTERS; | 1478 mode_ = DOUBLE_REGISTERS; |
| 1635 AllocateRegisters(); | 1479 AllocateRegisters(); |
| 1636 } | 1480 } |
| 1637 | 1481 |
| 1638 | 1482 |
| 1639 bool LAllocator::TryReuseSpillForPhi(LiveRange* range) { | |
| 1640 DCHECK(!range->HasAllocatedSpillOperand()); | |
| 1641 if (range->IsChild()) { | |
| 1642 return false; | |
| 1643 } | |
| 1644 HValue* instr = graph_->LookupValue(range->id()); | |
| 1645 if (instr == NULL || !instr->IsPhi()) { | |
| 1646 return false; | |
| 1647 } | |
| 1648 | |
| 1649 // Count the number of spilled operands. | |
| 1650 HPhi* phi = HPhi::cast(instr); | |
| 1651 int spilled_count = 0; | |
| 1652 LiveRange* first_op = NULL; | |
| 1653 for (int i = 0; i < phi->OperandCount(); i++) { | |
| 1654 HValue* op = phi->OperandAt(i); | |
| 1655 LiveRange* op_range = LiveRangeFor(op->id()); | |
| 1656 if (op_range->GetSpillRange() != NULL) { | |
| 1657 HBasicBlock* pred = instr->block()->predecessors()->at(i); | |
| 1658 LifetimePosition pred_end = LifetimePosition::FromInstructionIndex( | |
| 1659 pred->last_instruction_index()); | |
| 1660 while (op_range != NULL && !op_range->CanCover(pred_end)) { | |
| 1661 op_range = op_range->next(); | |
| 1662 } | |
| 1663 if (op_range != NULL && op_range->IsSpilled()) { | |
| 1664 spilled_count++; | |
| 1665 if (first_op == NULL) { | |
| 1666 first_op = op_range->TopLevel(); | |
| 1667 } | |
| 1668 } | |
| 1669 } | |
| 1670 } | |
| 1671 | |
| 1672 // Only continue if more than half of the operands are spilled. | |
| 1673 if (spilled_count * 2 <= phi->OperandCount()) { | |
| 1674 return false; | |
| 1675 } | |
| 1676 | |
| 1677 // Try to merge the spilled operands and count the number of merged spilled | |
| 1678 // operands. | |
| 1679 DCHECK(first_op != NULL); | |
| 1680 SpillRange* first_op_spill = first_op->GetSpillRange(); | |
| 1681 int num_merged = 1; | |
| 1682 for (int i = 1; i < phi->OperandCount(); i++) { | |
| 1683 HValue* op = phi->OperandAt(i); | |
| 1684 LiveRange* op_range = LiveRangeFor(op->id()); | |
| 1685 SpillRange* op_spill = op_range->GetSpillRange(); | |
| 1686 if (op_spill != NULL) { | |
| 1687 if (op_spill->id() == first_op_spill->id() || | |
| 1688 first_op_spill->TryMerge(op_spill, zone())) { | |
| 1689 num_merged++; | |
| 1690 } | |
| 1691 } | |
| 1692 } | |
| 1693 | |
| 1694 // Only continue if enough operands could be merged to the | |
| 1695 // same spill slot. | |
| 1696 if (num_merged * 2 <= phi->OperandCount() || | |
| 1697 AreUseIntervalsIntersecting(first_op_spill->interval(), | |
| 1698 range->first_interval())) { | |
| 1699 return false; | |
| 1700 } | |
| 1701 | |
| 1702 // If the range does not need register soon, spill it to the merged | |
| 1703 // spill range. | |
| 1704 LifetimePosition next_pos = range->Start(); | |
| 1705 if (IsGapAt(next_pos.InstructionIndex())) { | |
| 1706 next_pos = next_pos.NextInstruction(); | |
| 1707 } | |
| 1708 UsePosition* pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | |
| 1709 if (pos == NULL) { | |
| 1710 SpillRange* spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | |
| 1711 CHECK(first_op_spill->TryMerge(spill_range, zone())); | |
| 1712 Spill(range); | |
| 1713 return true; | |
| 1714 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { | |
| 1715 SpillRange* spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | |
| 1716 CHECK(first_op_spill->TryMerge(spill_range, zone())); | |
| 1717 SpillBetween(range, range->Start(), pos->pos()); | |
| 1718 if (!AllocationOk()) return false; | |
| 1719 DCHECK(UnhandledIsSorted()); | |
| 1720 return true; | |
| 1721 } | |
| 1722 | |
| 1723 return false; | |
| 1724 } | |
| 1725 | |
| 1726 | |
| 1727 SpillRange* LAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | |
| 1728 int spill_id = spill_ranges_.length(); | |
| 1729 SpillRange* spill_range = new (zone()) SpillRange(range, spill_id, zone()); | |
| 1730 spill_ranges_.Add(spill_range, zone()); | |
| 1731 return spill_range; | |
| 1732 } | |
| 1733 | |
| 1734 | |
| 1735 void LAllocator::AllocateRegisters() { | 1483 void LAllocator::AllocateRegisters() { |
| 1736 DCHECK(unhandled_live_ranges_.is_empty()); | 1484 DCHECK(unhandled_live_ranges_.is_empty()); |
| 1737 | 1485 |
| 1738 for (int i = 0; i < live_ranges_.length(); ++i) { | 1486 for (int i = 0; i < live_ranges_.length(); ++i) { |
| 1739 if (live_ranges_[i] != NULL) { | 1487 if (live_ranges_[i] != NULL) { |
| 1740 if (live_ranges_[i]->Kind() == mode_) { | 1488 if (live_ranges_[i]->Kind() == mode_) { |
| 1741 AddToUnhandledUnsorted(live_ranges_[i]); | 1489 AddToUnhandledUnsorted(live_ranges_[i]); |
| 1742 } | 1490 } |
| 1743 } | 1491 } |
| 1744 } | 1492 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1794 current->Start().NextInstruction().Value()) { | 1542 current->Start().NextInstruction().Value()) { |
| 1795 // Do not spill live range eagerly if use position that can benefit from | 1543 // Do not spill live range eagerly if use position that can benefit from |
| 1796 // the register is too close to the start of live range. | 1544 // the register is too close to the start of live range. |
| 1797 SpillBetween(current, current->Start(), pos->pos()); | 1545 SpillBetween(current, current->Start(), pos->pos()); |
| 1798 if (!AllocationOk()) return; | 1546 if (!AllocationOk()) return; |
| 1799 DCHECK(UnhandledIsSorted()); | 1547 DCHECK(UnhandledIsSorted()); |
| 1800 continue; | 1548 continue; |
| 1801 } | 1549 } |
| 1802 } | 1550 } |
| 1803 | 1551 |
| 1804 if (TryReuseSpillForPhi(current)) { | |
| 1805 continue; | |
| 1806 } | |
| 1807 if (!AllocationOk()) return; | |
| 1808 | |
| 1809 for (int i = 0; i < active_live_ranges_.length(); ++i) { | 1552 for (int i = 0; i < active_live_ranges_.length(); ++i) { |
| 1810 LiveRange* cur_active = active_live_ranges_.at(i); | 1553 LiveRange* cur_active = active_live_ranges_.at(i); |
| 1811 if (cur_active->End().Value() <= position.Value()) { | 1554 if (cur_active->End().Value() <= position.Value()) { |
| 1812 ActiveToHandled(cur_active); | 1555 ActiveToHandled(cur_active); |
| 1813 --i; // The live range was removed from the list of active live ranges. | 1556 --i; // The live range was removed from the list of active live ranges. |
| 1814 } else if (!cur_active->Covers(position)) { | 1557 } else if (!cur_active->Covers(position)) { |
| 1815 ActiveToInactive(cur_active); | 1558 ActiveToInactive(cur_active); |
| 1816 --i; // The live range was removed from the list of active live ranges. | 1559 --i; // The live range was removed from the list of active live ranges. |
| 1817 } | 1560 } |
| 1818 } | 1561 } |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1949 int len = unhandled_live_ranges_.length(); | 1692 int len = unhandled_live_ranges_.length(); |
| 1950 for (int i = 1; i < len; i++) { | 1693 for (int i = 1; i < len; i++) { |
| 1951 LiveRange* a = unhandled_live_ranges_.at(i - 1); | 1694 LiveRange* a = unhandled_live_ranges_.at(i - 1); |
| 1952 LiveRange* b = unhandled_live_ranges_.at(i); | 1695 LiveRange* b = unhandled_live_ranges_.at(i); |
| 1953 if (a->Start().Value() < b->Start().Value()) return false; | 1696 if (a->Start().Value() < b->Start().Value()) return false; |
| 1954 } | 1697 } |
| 1955 return true; | 1698 return true; |
| 1956 } | 1699 } |
| 1957 | 1700 |
| 1958 | 1701 |
| 1702 void LAllocator::FreeSpillSlot(LiveRange* range) { |
| 1703 // Check that we are the last range. |
| 1704 if (range->next() != NULL) return; |
| 1705 |
| 1706 if (!range->TopLevel()->HasAllocatedSpillOperand()) return; |
| 1707 |
| 1708 int index = range->TopLevel()->GetSpillOperand()->index(); |
| 1709 if (index >= 0) { |
| 1710 reusable_slots_.Add(range, zone()); |
| 1711 } |
| 1712 } |
| 1713 |
| 1714 |
| 1715 LOperand* LAllocator::TryReuseSpillSlot(LiveRange* range) { |
| 1716 if (reusable_slots_.is_empty()) return NULL; |
| 1717 if (reusable_slots_.first()->End().Value() > |
| 1718 range->TopLevel()->Start().Value()) { |
| 1719 return NULL; |
| 1720 } |
| 1721 LOperand* result = reusable_slots_.first()->TopLevel()->GetSpillOperand(); |
| 1722 reusable_slots_.Remove(0); |
| 1723 return result; |
| 1724 } |
| 1725 |
| 1726 |
| 1959 void LAllocator::ActiveToHandled(LiveRange* range) { | 1727 void LAllocator::ActiveToHandled(LiveRange* range) { |
| 1960 DCHECK(active_live_ranges_.Contains(range)); | 1728 DCHECK(active_live_ranges_.Contains(range)); |
| 1961 active_live_ranges_.RemoveElement(range); | 1729 active_live_ranges_.RemoveElement(range); |
| 1962 TraceAlloc("Moving live range %d from active to handled\n", range->id()); | 1730 TraceAlloc("Moving live range %d from active to handled\n", range->id()); |
| 1731 FreeSpillSlot(range); |
| 1963 } | 1732 } |
| 1964 | 1733 |
| 1965 | 1734 |
| 1966 void LAllocator::ActiveToInactive(LiveRange* range) { | 1735 void LAllocator::ActiveToInactive(LiveRange* range) { |
| 1967 DCHECK(active_live_ranges_.Contains(range)); | 1736 DCHECK(active_live_ranges_.Contains(range)); |
| 1968 active_live_ranges_.RemoveElement(range); | 1737 active_live_ranges_.RemoveElement(range); |
| 1969 inactive_live_ranges_.Add(range, zone()); | 1738 inactive_live_ranges_.Add(range, zone()); |
| 1970 TraceAlloc("Moving live range %d from active to inactive\n", range->id()); | 1739 TraceAlloc("Moving live range %d from active to inactive\n", range->id()); |
| 1971 } | 1740 } |
| 1972 | 1741 |
| 1973 | 1742 |
| 1974 void LAllocator::InactiveToHandled(LiveRange* range) { | 1743 void LAllocator::InactiveToHandled(LiveRange* range) { |
| 1975 DCHECK(inactive_live_ranges_.Contains(range)); | 1744 DCHECK(inactive_live_ranges_.Contains(range)); |
| 1976 inactive_live_ranges_.RemoveElement(range); | 1745 inactive_live_ranges_.RemoveElement(range); |
| 1977 TraceAlloc("Moving live range %d from inactive to handled\n", range->id()); | 1746 TraceAlloc("Moving live range %d from inactive to handled\n", range->id()); |
| 1747 FreeSpillSlot(range); |
| 1978 } | 1748 } |
| 1979 | 1749 |
| 1980 | 1750 |
| 1981 void LAllocator::InactiveToActive(LiveRange* range) { | 1751 void LAllocator::InactiveToActive(LiveRange* range) { |
| 1982 DCHECK(inactive_live_ranges_.Contains(range)); | 1752 DCHECK(inactive_live_ranges_.Contains(range)); |
| 1983 inactive_live_ranges_.RemoveElement(range); | 1753 inactive_live_ranges_.RemoveElement(range); |
| 1984 active_live_ranges_.Add(range, zone()); | 1754 active_live_ranges_.Add(range, zone()); |
| 1985 TraceAlloc("Moving live range %d from inactive to active\n", range->id()); | 1755 TraceAlloc("Moving live range %d from inactive to active\n", range->id()); |
| 1986 } | 1756 } |
| 1987 | 1757 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 } | 1821 } |
| 2052 | 1822 |
| 2053 if (pos.Value() < current->End().Value()) { | 1823 if (pos.Value() < current->End().Value()) { |
| 2054 // Register reg is available at the range start but becomes blocked before | 1824 // Register reg is available at the range start but becomes blocked before |
| 2055 // the range end. Split current at position where it becomes blocked. | 1825 // the range end. Split current at position where it becomes blocked. |
| 2056 LiveRange* tail = SplitRangeAt(current, pos); | 1826 LiveRange* tail = SplitRangeAt(current, pos); |
| 2057 if (!AllocationOk()) return false; | 1827 if (!AllocationOk()) return false; |
| 2058 AddToUnhandledSorted(tail); | 1828 AddToUnhandledSorted(tail); |
| 2059 } | 1829 } |
| 2060 | 1830 |
| 1831 |
| 2061 // Register reg is available at the range start and is free until | 1832 // Register reg is available at the range start and is free until |
| 2062 // the range end. | 1833 // the range end. |
| 2063 DCHECK(pos.Value() >= current->End().Value()); | 1834 DCHECK(pos.Value() >= current->End().Value()); |
| 2064 TraceAlloc("Assigning free reg %s to live range %d\n", | 1835 TraceAlloc("Assigning free reg %s to live range %d\n", |
| 2065 RegisterName(reg), | 1836 RegisterName(reg), |
| 2066 current->id()); | 1837 current->id()); |
| 2067 SetLiveRangeAssignedRegister(current, reg); | 1838 SetLiveRangeAssignedRegister(current, reg); |
| 2068 | 1839 |
| 2069 return true; | 1840 return true; |
| 2070 } | 1841 } |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2358 } | 2129 } |
| 2359 } | 2130 } |
| 2360 | 2131 |
| 2361 | 2132 |
| 2362 void LAllocator::Spill(LiveRange* range) { | 2133 void LAllocator::Spill(LiveRange* range) { |
| 2363 DCHECK(!range->IsSpilled()); | 2134 DCHECK(!range->IsSpilled()); |
| 2364 TraceAlloc("Spilling live range %d\n", range->id()); | 2135 TraceAlloc("Spilling live range %d\n", range->id()); |
| 2365 LiveRange* first = range->TopLevel(); | 2136 LiveRange* first = range->TopLevel(); |
| 2366 | 2137 |
| 2367 if (!first->HasAllocatedSpillOperand()) { | 2138 if (!first->HasAllocatedSpillOperand()) { |
| 2368 AssignSpillRangeToLiveRange(first); | 2139 LOperand* op = TryReuseSpillSlot(range); |
| 2140 if (op == NULL) op = chunk_->GetNextSpillSlot(range->Kind()); |
| 2141 first->SetSpillOperand(op); |
| 2369 } | 2142 } |
| 2370 range->MakeSpilled(chunk()->zone()); | 2143 range->MakeSpilled(chunk()->zone()); |
| 2371 } | 2144 } |
| 2372 | 2145 |
| 2373 | 2146 |
| 2374 int LAllocator::RegisterCount() const { | 2147 int LAllocator::RegisterCount() const { |
| 2375 return num_registers_; | 2148 return num_registers_; |
| 2376 } | 2149 } |
| 2377 | 2150 |
| 2378 | 2151 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2412 isolate()->GetHTracer()->TraceLiveRanges(name(), allocator_); | 2185 isolate()->GetHTracer()->TraceLiveRanges(name(), allocator_); |
| 2413 } | 2186 } |
| 2414 | 2187 |
| 2415 #ifdef DEBUG | 2188 #ifdef DEBUG |
| 2416 if (allocator_ != NULL) allocator_->Verify(); | 2189 if (allocator_ != NULL) allocator_->Verify(); |
| 2417 #endif | 2190 #endif |
| 2418 } | 2191 } |
| 2419 | 2192 |
| 2420 | 2193 |
| 2421 } } // namespace v8::internal | 2194 } } // namespace v8::internal |
| OLD | NEW |