| 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 21 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { | 33 static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { |
| 34 auto it = std::find(v->begin(), v->end(), range); | 34 auto it = std::find(v->begin(), v->end(), range); |
| 35 DCHECK(it != v->end()); | 35 DCHECK(it != v->end()); |
| 36 v->erase(it); | 36 v->erase(it); |
| 37 } | 37 } |
| 38 | 38 |
| 39 | 39 |
| 40 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 40 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
| 41 InstructionOperand* hint) | 41 InstructionOperand* hint) |
| 42 : operand_(operand), | 42 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { |
| 43 hint_(hint), | 43 bool register_beneficial = true; |
| 44 pos_(pos), | 44 UsePositionType type = UsePositionType::kAny; |
| 45 next_(nullptr), | |
| 46 requires_reg_(false), | |
| 47 register_beneficial_(true) { | |
| 48 if (operand_ != nullptr && operand_->IsUnallocated()) { | 45 if (operand_ != nullptr && operand_->IsUnallocated()) { |
| 49 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); | 46 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); |
| 50 requires_reg_ = unalloc->HasRegisterPolicy(); | 47 if (unalloc->HasRegisterPolicy()) { |
| 51 register_beneficial_ = !unalloc->HasAnyPolicy(); | 48 type = UsePositionType::kRequiresRegister; |
| 49 } else if (unalloc->HasSlotPolicy()) { |
| 50 type = UsePositionType::kRequiresSlot; |
| 51 register_beneficial = false; |
| 52 } else { |
| 53 register_beneficial = !unalloc->HasAnyPolicy(); |
| 54 } |
| 52 } | 55 } |
| 56 flags_ = TypeField::encode(type) | |
| 57 RegisterBeneficialField::encode(register_beneficial); |
| 53 DCHECK(pos_.IsValid()); | 58 DCHECK(pos_.IsValid()); |
| 54 } | 59 } |
| 55 | 60 |
| 56 | 61 |
| 57 bool UsePosition::HasHint() const { | 62 bool UsePosition::HasHint() const { |
| 58 return hint_ != nullptr && !hint_->IsUnallocated(); | 63 return hint_ != nullptr && !hint_->IsUnallocated(); |
| 59 } | 64 } |
| 60 | 65 |
| 61 | 66 |
| 62 bool UsePosition::RequiresRegister() const { return requires_reg_; } | 67 void UsePosition::set_type(UsePositionType type, bool register_beneficial) { |
| 63 | 68 DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial); |
| 64 | 69 flags_ = TypeField::encode(type) | |
| 65 bool UsePosition::RegisterIsBeneficial() const { return register_beneficial_; } | 70 RegisterBeneficialField::encode(register_beneficial); |
| 71 } |
| 66 | 72 |
| 67 | 73 |
| 68 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { | 74 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { |
| 69 DCHECK(Contains(pos) && pos.Value() != start().Value()); | 75 DCHECK(Contains(pos) && pos.Value() != start().Value()); |
| 70 auto after = new (zone) UseInterval(pos, end_); | 76 auto after = new (zone) UseInterval(pos, end_); |
| 71 after->next_ = next_; | 77 after->next_ = next_; |
| 72 next_ = after; | 78 next_ = after; |
| 73 end_ = pos; | 79 end_ = pos; |
| 74 } | 80 } |
| 75 | 81 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 return false; | 116 return false; |
| 111 } | 117 } |
| 112 | 118 |
| 113 | 119 |
| 114 #endif | 120 #endif |
| 115 | 121 |
| 116 | 122 |
| 117 LiveRange::LiveRange(int id, Zone* zone) | 123 LiveRange::LiveRange(int id, Zone* zone) |
| 118 : id_(id), | 124 : id_(id), |
| 119 spilled_(false), | 125 spilled_(false), |
| 126 has_slot_use_(false), |
| 120 is_phi_(false), | 127 is_phi_(false), |
| 121 is_non_loop_phi_(false), | 128 is_non_loop_phi_(false), |
| 122 kind_(UNALLOCATED_REGISTERS), | 129 kind_(UNALLOCATED_REGISTERS), |
| 123 assigned_register_(kInvalidAssignment), | 130 assigned_register_(kInvalidAssignment), |
| 124 last_interval_(nullptr), | 131 last_interval_(nullptr), |
| 125 first_interval_(nullptr), | 132 first_interval_(nullptr), |
| 126 first_pos_(nullptr), | 133 first_pos_(nullptr), |
| 127 parent_(nullptr), | 134 parent_(nullptr), |
| 128 next_(nullptr), | 135 next_(nullptr), |
| 129 current_interval_(nullptr), | 136 current_interval_(nullptr), |
| 130 last_processed_use_(nullptr), | 137 last_processed_use_(nullptr), |
| 131 current_hint_operand_(nullptr), | 138 current_hint_operand_(nullptr), |
| 132 spill_start_index_(kMaxInt), | 139 spill_start_index_(kMaxInt), |
| 133 spill_type_(SpillType::kNoSpillType), | 140 spill_type_(SpillType::kNoSpillType), |
| 134 spill_operand_(nullptr), | 141 spill_operand_(nullptr), |
| 135 spills_at_definition_(nullptr) {} | 142 spills_at_definition_(nullptr) {} |
| 136 | 143 |
| 137 | 144 |
| 138 void LiveRange::set_assigned_register(int reg, | 145 void LiveRange::set_assigned_register(int reg, |
| 139 InstructionOperandCache* operand_cache) { | 146 InstructionOperandCache* operand_cache) { |
| 140 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 147 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
| 141 assigned_register_ = reg; | 148 assigned_register_ = reg; |
| 142 // TODO(dcarney): stop aliasing hint operands. | 149 // TODO(dcarney): stop aliasing hint operands. |
| 143 ConvertUsesToOperand(GetAssignedOperand(operand_cache)); | 150 ConvertUsesToOperand(GetAssignedOperand(operand_cache), nullptr); |
| 144 } | 151 } |
| 145 | 152 |
| 146 | 153 |
| 147 void LiveRange::MakeSpilled() { | 154 void LiveRange::MakeSpilled() { |
| 148 DCHECK(!IsSpilled()); | 155 DCHECK(!IsSpilled()); |
| 149 DCHECK(!TopLevel()->HasNoSpillType()); | 156 DCHECK(!TopLevel()->HasNoSpillType()); |
| 150 spilled_ = true; | 157 spilled_ = true; |
| 151 assigned_register_ = kInvalidAssignment; | 158 assigned_register_ = kInvalidAssignment; |
| 152 } | 159 } |
| 153 | 160 |
| 154 | 161 |
| 155 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, | 162 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, |
| 156 InstructionOperand* operand) { | 163 InstructionOperand* operand) { |
| 157 DCHECK(HasNoSpillType()); | 164 DCHECK(HasNoSpillType()); |
| 158 spills_at_definition_ = new (zone) | 165 spills_at_definition_ = new (zone) |
| 159 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | 166 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
| 160 } | 167 } |
| 161 | 168 |
| 162 | 169 |
| 163 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, | 170 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
| 164 InstructionOperand* op) { | 171 InstructionOperand* op, |
| 165 auto to_spill = TopLevel()->spills_at_definition_; | 172 bool might_be_duplicated) { |
| 166 if (to_spill == nullptr) return; | 173 DCHECK(!IsChild()); |
| 167 auto zone = sequence->zone(); | 174 auto zone = sequence->zone(); |
| 168 for (; to_spill != nullptr; to_spill = to_spill->next) { | 175 for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
| 176 to_spill = to_spill->next) { |
| 169 auto gap = sequence->GapAt(to_spill->gap_index); | 177 auto gap = sequence->GapAt(to_spill->gap_index); |
| 170 auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone); | 178 auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone); |
| 179 // Skip insertion if it's possible that the move exists already as a |
| 180 // constraint move from a fixed output register to a slot. |
| 181 if (might_be_duplicated) { |
| 182 bool found = false; |
| 183 auto move_ops = move->move_operands(); |
| 184 for (auto move_op = move_ops->begin(); move_op != move_ops->end(); |
| 185 ++move_op) { |
| 186 if (move_op->IsEliminated()) continue; |
| 187 if (move_op->source()->Equals(to_spill->operand) && |
| 188 move_op->destination()->Equals(op)) { |
| 189 found = true; |
| 190 break; |
| 191 } |
| 192 } |
| 193 if (found) continue; |
| 194 } |
| 171 move->AddMove(to_spill->operand, op, zone); | 195 move->AddMove(to_spill->operand, op, zone); |
| 172 } | 196 } |
| 173 TopLevel()->spills_at_definition_ = nullptr; | |
| 174 } | 197 } |
| 175 | 198 |
| 176 | 199 |
| 177 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 200 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
| 178 DCHECK(HasNoSpillType()); | 201 DCHECK(HasNoSpillType()); |
| 179 DCHECK(!operand->IsUnallocated()); | 202 DCHECK(!operand->IsUnallocated()); |
| 180 spill_type_ = SpillType::kSpillOperand; | 203 spill_type_ = SpillType::kSpillOperand; |
| 181 spill_operand_ = operand; | 204 spill_operand_ = operand; |
| 182 } | 205 } |
| 183 | 206 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 while (pos != nullptr && pos->pos().Value() < start.Value()) { | 250 while (pos != nullptr && pos->pos().Value() < start.Value()) { |
| 228 if (pos->RegisterIsBeneficial()) prev = pos; | 251 if (pos->RegisterIsBeneficial()) prev = pos; |
| 229 pos = pos->next(); | 252 pos = pos->next(); |
| 230 } | 253 } |
| 231 return prev; | 254 return prev; |
| 232 } | 255 } |
| 233 | 256 |
| 234 | 257 |
| 235 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) { | 258 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) { |
| 236 UsePosition* pos = NextUsePosition(start); | 259 UsePosition* pos = NextUsePosition(start); |
| 237 while (pos != nullptr && !pos->RequiresRegister()) { | 260 while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) { |
| 238 pos = pos->next(); | 261 pos = pos->next(); |
| 239 } | 262 } |
| 240 return pos; | 263 return pos; |
| 241 } | 264 } |
| 242 | 265 |
| 243 | 266 |
| 244 bool LiveRange::CanBeSpilled(LifetimePosition pos) { | 267 bool LiveRange::CanBeSpilled(LifetimePosition pos) { |
| 245 // We cannot spill a live range that has a use requiring a register | 268 // We cannot spill a live range that has a use requiring a register |
| 246 // at the current or the immediate next position. | 269 // at the current or the immediate next position. |
| 247 auto use_pos = NextRegisterPosition(pos); | 270 auto use_pos = NextRegisterPosition(pos); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 use_pos->next_ = prev->next_; | 525 use_pos->next_ = prev->next_; |
| 503 prev->next_ = use_pos; | 526 prev->next_ = use_pos; |
| 504 } | 527 } |
| 505 | 528 |
| 506 if (prev_hint == nullptr && use_pos->HasHint()) { | 529 if (prev_hint == nullptr && use_pos->HasHint()) { |
| 507 current_hint_operand_ = hint; | 530 current_hint_operand_ = hint; |
| 508 } | 531 } |
| 509 } | 532 } |
| 510 | 533 |
| 511 | 534 |
| 512 void LiveRange::ConvertUsesToOperand(InstructionOperand* op) { | 535 void LiveRange::ConvertUsesToOperand(InstructionOperand* op, |
| 513 auto use_pos = first_pos(); | 536 InstructionOperand* spill_op) { |
| 514 while (use_pos != nullptr) { | 537 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
| 515 DCHECK(Start().Value() <= use_pos->pos().Value() && | 538 DCHECK(Start().Value() <= pos->pos().Value() && |
| 516 use_pos->pos().Value() <= End().Value()); | 539 pos->pos().Value() <= End().Value()); |
| 517 | 540 if (!pos->HasOperand()) { |
| 518 if (use_pos->HasOperand()) { | 541 continue; |
| 519 DCHECK(op->IsRegister() || op->IsDoubleRegister() || | |
| 520 !use_pos->RequiresRegister()); | |
| 521 use_pos->operand()->ConvertTo(op->kind(), op->index()); | |
| 522 } | 542 } |
| 523 use_pos = use_pos->next(); | 543 switch (pos->type()) { |
| 544 case UsePositionType::kRequiresSlot: |
| 545 if (spill_op != nullptr) { |
| 546 pos->operand()->ConvertTo(spill_op->kind(), spill_op->index()); |
| 547 } |
| 548 break; |
| 549 case UsePositionType::kRequiresRegister: |
| 550 DCHECK(op->IsRegister() || op->IsDoubleRegister()); |
| 551 // Fall through. |
| 552 case UsePositionType::kAny: |
| 553 pos->operand()->ConvertTo(op->kind(), op->index()); |
| 554 break; |
| 555 } |
| 524 } | 556 } |
| 525 } | 557 } |
| 526 | 558 |
| 527 | 559 |
| 528 bool LiveRange::CanCover(LifetimePosition position) const { | 560 bool LiveRange::CanCover(LifetimePosition position) const { |
| 529 if (IsEmpty()) return false; | 561 if (IsEmpty()) return false; |
| 530 return Start().Value() <= position.Value() && | 562 return Start().Value() <= position.Value() && |
| 531 position.Value() < End().Value(); | 563 position.Value() < End().Value(); |
| 532 } | 564 } |
| 533 | 565 |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 : InstructionOperand::STACK_SLOT; | 982 : InstructionOperand::STACK_SLOT; |
| 951 auto op = InstructionOperand::New(code_zone(), op_kind, index); | 983 auto op = InstructionOperand::New(code_zone(), op_kind, index); |
| 952 range->SetOperand(op); | 984 range->SetOperand(op); |
| 953 } | 985 } |
| 954 } | 986 } |
| 955 | 987 |
| 956 | 988 |
| 957 void RegisterAllocator::CommitAssignment() { | 989 void RegisterAllocator::CommitAssignment() { |
| 958 for (auto range : live_ranges()) { | 990 for (auto range : live_ranges()) { |
| 959 if (range == nullptr || range->IsEmpty()) continue; | 991 if (range == nullptr || range->IsEmpty()) continue; |
| 960 // Register assignments were committed in set_assigned_register. | |
| 961 if (range->HasRegisterAssigned()) continue; | |
| 962 auto assigned = range->GetAssignedOperand(operand_cache()); | 992 auto assigned = range->GetAssignedOperand(operand_cache()); |
| 963 range->ConvertUsesToOperand(assigned); | 993 InstructionOperand* spill_operand = nullptr; |
| 964 if (range->IsSpilled()) { | 994 if (!range->TopLevel()->HasNoSpillType()) { |
| 965 range->CommitSpillsAtDefinition(code(), assigned); | 995 spill_operand = range->TopLevel()->GetSpillOperand(); |
| 996 } |
| 997 range->ConvertUsesToOperand(assigned, spill_operand); |
| 998 if (!range->IsChild() && spill_operand != nullptr) { |
| 999 range->CommitSpillsAtDefinition(code(), spill_operand, |
| 1000 range->has_slot_use()); |
| 966 } | 1001 } |
| 967 } | 1002 } |
| 968 } | 1003 } |
| 969 | 1004 |
| 970 | 1005 |
| 971 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 1006 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
| 972 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); | 1007 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); |
| 973 spill_ranges().push_back(spill_range); | 1008 spill_ranges().push_back(spill_range); |
| 974 return spill_range; | 1009 return spill_range; |
| 975 } | 1010 } |
| 976 | 1011 |
| 977 | 1012 |
| 978 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 1013 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
| 979 if (range->IsChild() || !range->is_phi()) return false; | 1014 if (range->IsChild() || !range->is_phi()) return false; |
| 980 DCHECK(range->HasNoSpillType()); | 1015 DCHECK(!range->HasSpillOperand()); |
| 981 | 1016 |
| 982 auto lookup = phi_map_.find(range->id()); | 1017 auto lookup = phi_map_.find(range->id()); |
| 983 DCHECK(lookup != phi_map_.end()); | 1018 DCHECK(lookup != phi_map_.end()); |
| 984 auto phi = lookup->second.phi; | 1019 auto phi = lookup->second.phi; |
| 985 auto block = lookup->second.block; | 1020 auto block = lookup->second.block; |
| 986 // Count the number of spilled operands. | 1021 // Count the number of spilled operands. |
| 987 size_t spilled_count = 0; | 1022 size_t spilled_count = 0; |
| 988 LiveRange* first_op = nullptr; | 1023 LiveRange* first_op = nullptr; |
| 989 for (size_t i = 0; i < phi->operands().size(); i++) { | 1024 for (size_t i = 0; i < phi->operands().size(); i++) { |
| 990 int op = phi->operands()[i]; | 1025 int op = phi->operands()[i]; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 } | 1068 } |
| 1034 | 1069 |
| 1035 // If the range does not need register soon, spill it to the merged | 1070 // If the range does not need register soon, spill it to the merged |
| 1036 // spill range. | 1071 // spill range. |
| 1037 auto next_pos = range->Start(); | 1072 auto next_pos = range->Start(); |
| 1038 if (code()->IsGapAt(next_pos.InstructionIndex())) { | 1073 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
| 1039 next_pos = next_pos.NextInstruction(); | 1074 next_pos = next_pos.NextInstruction(); |
| 1040 } | 1075 } |
| 1041 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | 1076 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
| 1042 if (pos == nullptr) { | 1077 if (pos == nullptr) { |
| 1043 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | 1078 auto spill_range = range->TopLevel()->HasSpillRange() |
| 1079 ? range->TopLevel()->GetSpillRange() |
| 1080 : AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1044 CHECK(first_op_spill->TryMerge(spill_range)); | 1081 CHECK(first_op_spill->TryMerge(spill_range)); |
| 1045 Spill(range); | 1082 Spill(range); |
| 1046 return true; | 1083 return true; |
| 1047 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { | 1084 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { |
| 1048 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | 1085 auto spill_range = range->TopLevel()->HasSpillRange() |
| 1086 ? range->TopLevel()->GetSpillRange() |
| 1087 : AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1049 CHECK(first_op_spill->TryMerge(spill_range)); | 1088 CHECK(first_op_spill->TryMerge(spill_range)); |
| 1050 SpillBetween(range, range->Start(), pos->pos()); | 1089 SpillBetween(range, range->Start(), pos->pos()); |
| 1051 DCHECK(UnhandledIsSorted()); | 1090 DCHECK(UnhandledIsSorted()); |
| 1052 return true; | 1091 return true; |
| 1053 } | 1092 } |
| 1054 return false; | 1093 return false; |
| 1055 } | 1094 } |
| 1056 | 1095 |
| 1057 | 1096 |
| 1058 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { | 1097 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1297 if (from->IsUnallocated()) { | 1336 if (from->IsUnallocated()) { |
| 1298 live->Add(UnallocatedOperand::cast(from)->virtual_register()); | 1337 live->Add(UnallocatedOperand::cast(from)->virtual_register()); |
| 1299 } | 1338 } |
| 1300 } | 1339 } |
| 1301 } | 1340 } |
| 1302 } else { | 1341 } else { |
| 1303 // Process output, inputs, and temps of this non-gap instruction. | 1342 // Process output, inputs, and temps of this non-gap instruction. |
| 1304 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1343 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1305 auto output = instr->OutputAt(i); | 1344 auto output = instr->OutputAt(i); |
| 1306 if (output->IsUnallocated()) { | 1345 if (output->IsUnallocated()) { |
| 1346 // Unsupported. |
| 1347 DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); |
| 1307 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); | 1348 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); |
| 1308 live->Remove(out_vreg); | 1349 live->Remove(out_vreg); |
| 1309 } else if (output->IsConstant()) { | 1350 } else if (output->IsConstant()) { |
| 1310 int out_vreg = output->index(); | 1351 int out_vreg = output->index(); |
| 1311 live->Remove(out_vreg); | 1352 live->Remove(out_vreg); |
| 1312 } | 1353 } |
| 1313 Define(curr_position, output, nullptr); | 1354 Define(curr_position, output, nullptr); |
| 1314 } | 1355 } |
| 1315 | 1356 |
| 1316 if (instr->ClobbersRegisters()) { | 1357 if (instr->ClobbersRegisters()) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1337 auto input = instr->InputAt(i); | 1378 auto input = instr->InputAt(i); |
| 1338 if (input->IsImmediate()) continue; // Ignore immediates. | 1379 if (input->IsImmediate()) continue; // Ignore immediates. |
| 1339 LifetimePosition use_pos; | 1380 LifetimePosition use_pos; |
| 1340 if (input->IsUnallocated() && | 1381 if (input->IsUnallocated() && |
| 1341 UnallocatedOperand::cast(input)->IsUsedAtStart()) { | 1382 UnallocatedOperand::cast(input)->IsUsedAtStart()) { |
| 1342 use_pos = curr_position; | 1383 use_pos = curr_position; |
| 1343 } else { | 1384 } else { |
| 1344 use_pos = curr_position.InstructionEnd(); | 1385 use_pos = curr_position.InstructionEnd(); |
| 1345 } | 1386 } |
| 1346 | 1387 |
| 1388 if (input->IsUnallocated()) { |
| 1389 UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); |
| 1390 int vreg = unalloc->virtual_register(); |
| 1391 live->Add(vreg); |
| 1392 if (unalloc->HasSlotPolicy()) { |
| 1393 LiveRangeFor(vreg)->set_has_slot_use(true); |
| 1394 } |
| 1395 } |
| 1347 Use(block_start_position, use_pos, input, nullptr); | 1396 Use(block_start_position, use_pos, input, nullptr); |
| 1348 if (input->IsUnallocated()) { | |
| 1349 live->Add(UnallocatedOperand::cast(input)->virtual_register()); | |
| 1350 } | |
| 1351 } | 1397 } |
| 1352 | 1398 |
| 1353 for (size_t i = 0; i < instr->TempCount(); i++) { | 1399 for (size_t i = 0; i < instr->TempCount(); i++) { |
| 1354 auto temp = instr->TempAt(i); | 1400 auto temp = instr->TempAt(i); |
| 1401 // Unsupported. |
| 1402 DCHECK_IMPLIES(temp->IsUnallocated(), |
| 1403 !UnallocatedOperand::cast(temp)->HasSlotPolicy()); |
| 1355 if (instr->ClobbersTemps()) { | 1404 if (instr->ClobbersTemps()) { |
| 1356 if (temp->IsRegister()) continue; | 1405 if (temp->IsRegister()) continue; |
| 1357 if (temp->IsUnallocated()) { | 1406 if (temp->IsUnallocated()) { |
| 1358 UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); | 1407 UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); |
| 1359 if (temp_unalloc->HasFixedPolicy()) { | 1408 if (temp_unalloc->HasFixedPolicy()) { |
| 1360 continue; | 1409 continue; |
| 1361 } | 1410 } |
| 1362 } | 1411 } |
| 1363 } | 1412 } |
| 1364 Use(block_start_position, curr_position.InstructionEnd(), temp, | 1413 Use(block_start_position, curr_position.InstructionEnd(), temp, |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1766 for (int i = block->rpo_number().ToInt() + 1; | 1815 for (int i = block->rpo_number().ToInt() + 1; |
| 1767 i < block->loop_end().ToInt(); ++i) { | 1816 i < block->loop_end().ToInt(); ++i) { |
| 1768 live_in_sets_[i]->Union(*live); | 1817 live_in_sets_[i]->Union(*live); |
| 1769 } | 1818 } |
| 1770 } | 1819 } |
| 1771 } | 1820 } |
| 1772 | 1821 |
| 1773 for (auto range : live_ranges()) { | 1822 for (auto range : live_ranges()) { |
| 1774 if (range == nullptr) continue; | 1823 if (range == nullptr) continue; |
| 1775 range->kind_ = RequiredRegisterKind(range->id()); | 1824 range->kind_ = RequiredRegisterKind(range->id()); |
| 1825 // Give slots to all ranges with a non fixed slot use. |
| 1826 if (range->has_slot_use() && range->HasNoSpillType()) { |
| 1827 AssignSpillRangeToLiveRange(range); |
| 1828 } |
| 1776 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1829 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
| 1777 // live ranges, every use requires the constant to be in a register. | 1830 // live ranges, every use requires the constant to be in a register. |
| 1778 // Without this hack, all uses with "any" policy would get the constant | 1831 // Without this hack, all uses with "any" policy would get the constant |
| 1779 // operand assigned. | 1832 // operand assigned. |
| 1780 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1833 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
| 1781 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { | 1834 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { |
| 1782 pos->register_beneficial_ = true; | 1835 if (pos->type() == UsePositionType::kRequiresSlot) continue; |
| 1783 // TODO(dcarney): should the else case assert requires_reg_ == false? | 1836 UsePositionType new_type = UsePositionType::kAny; |
| 1784 // Can't mark phis as needing a register. | 1837 // Can't mark phis as needing a register. |
| 1785 if (!code() | 1838 if (!code() |
| 1786 ->InstructionAt(pos->pos().InstructionIndex()) | 1839 ->InstructionAt(pos->pos().InstructionIndex()) |
| 1787 ->IsGapMoves()) { | 1840 ->IsGapMoves()) { |
| 1788 pos->requires_reg_ = true; | 1841 new_type = UsePositionType::kRequiresRegister; |
| 1789 } | 1842 } |
| 1843 pos->set_type(new_type, true); |
| 1790 } | 1844 } |
| 1791 } | 1845 } |
| 1792 } | 1846 } |
| 1793 } | 1847 } |
| 1794 | 1848 |
| 1795 | 1849 |
| 1796 bool RegisterAllocator::ExistsUseWithoutDefinition() { | 1850 bool RegisterAllocator::ExistsUseWithoutDefinition() { |
| 1797 bool found = false; | 1851 bool found = false; |
| 1798 BitVector::Iterator iterator(live_in_sets_[0]); | 1852 BitVector::Iterator iterator(live_in_sets_[0]); |
| 1799 while (!iterator.Done()) { | 1853 while (!iterator.Done()) { |
| (...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2528 } else { | 2582 } else { |
| 2529 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2583 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2530 assigned_registers_->Add(reg); | 2584 assigned_registers_->Add(reg); |
| 2531 } | 2585 } |
| 2532 range->set_assigned_register(reg, operand_cache()); | 2586 range->set_assigned_register(reg, operand_cache()); |
| 2533 } | 2587 } |
| 2534 | 2588 |
| 2535 } // namespace compiler | 2589 } // namespace compiler |
| 2536 } // namespace internal | 2590 } // namespace internal |
| 2537 } // namespace v8 | 2591 } // namespace v8 |
| OLD | NEW |