| 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 | 67 |
| 68 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { | 68 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { |
| 69 DCHECK(Contains(pos) && pos.Value() != start().Value()); | 69 DCHECK(Contains(pos) && pos.Value() != start().Value()); |
| 70 auto after = new (zone) UseInterval(pos, end_); | 70 auto after = new (zone) UseInterval(pos, end_); |
| 71 after->next_ = next_; | 71 after->next_ = next_; |
| 72 next_ = after; | 72 next_ = after; |
| 73 end_ = pos; | 73 end_ = pos; |
| 74 } | 74 } |
| 75 | 75 |
| 76 | 76 |
| 77 struct LiveRange::SpillAtDefinitionList : ZoneObject { | |
| 78 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, | |
| 79 SpillAtDefinitionList* next) | |
| 80 : gap_index(gap_index), operand(operand), next(next) {} | |
| 81 const int gap_index; | |
| 82 InstructionOperand* const operand; | |
| 83 SpillAtDefinitionList* const next; | |
| 84 }; | |
| 85 | |
| 86 | |
| 87 #ifdef DEBUG | 77 #ifdef DEBUG |
| 88 | 78 |
| 89 | 79 |
| 90 void LiveRange::Verify() const { | 80 void LiveRange::Verify() const { |
| 91 UsePosition* cur = first_pos_; | 81 UsePosition* cur = first_pos_; |
| 92 while (cur != nullptr) { | 82 while (cur != nullptr) { |
| 93 DCHECK(Start().Value() <= cur->pos().Value() && | 83 DCHECK(Start().Value() <= cur->pos().Value() && |
| 94 cur->pos().Value() <= End().Value()); | 84 cur->pos().Value() <= End().Value()); |
| 95 cur = cur->next(); | 85 cur = cur->next(); |
| 96 } | 86 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 122 kind_(UNALLOCATED_REGISTERS), | 112 kind_(UNALLOCATED_REGISTERS), |
| 123 assigned_register_(kInvalidAssignment), | 113 assigned_register_(kInvalidAssignment), |
| 124 last_interval_(nullptr), | 114 last_interval_(nullptr), |
| 125 first_interval_(nullptr), | 115 first_interval_(nullptr), |
| 126 first_pos_(nullptr), | 116 first_pos_(nullptr), |
| 127 parent_(nullptr), | 117 parent_(nullptr), |
| 128 next_(nullptr), | 118 next_(nullptr), |
| 129 current_interval_(nullptr), | 119 current_interval_(nullptr), |
| 130 last_processed_use_(nullptr), | 120 last_processed_use_(nullptr), |
| 131 current_hint_operand_(nullptr), | 121 current_hint_operand_(nullptr), |
| 122 spill_operand_(new (zone) InstructionOperand()), |
| 132 spill_start_index_(kMaxInt), | 123 spill_start_index_(kMaxInt), |
| 133 spill_type_(SpillType::kNoSpillType), | 124 spill_range_(nullptr) {} |
| 134 spill_operand_(nullptr), | |
| 135 spills_at_definition_(nullptr) {} | |
| 136 | 125 |
| 137 | 126 |
| 138 void LiveRange::set_assigned_register(int reg, Zone* zone) { | 127 void LiveRange::set_assigned_register(int reg, Zone* zone) { |
| 139 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 128 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
| 140 assigned_register_ = reg; | 129 assigned_register_ = reg; |
| 141 // TODO(dcarney): stop aliasing hint operands. | 130 if (spill_range_ == nullptr) { |
| 142 ConvertUsesToOperand(CreateAssignedOperand(zone)); | 131 ConvertOperands(zone); |
| 132 } |
| 143 } | 133 } |
| 144 | 134 |
| 145 | 135 |
| 146 void LiveRange::MakeSpilled() { | 136 void LiveRange::MakeSpilled(Zone* zone) { |
| 147 DCHECK(!IsSpilled()); | 137 DCHECK(!IsSpilled()); |
| 148 DCHECK(!TopLevel()->HasNoSpillType()); | 138 DCHECK(TopLevel()->HasAllocatedSpillOperand()); |
| 149 spilled_ = true; | 139 spilled_ = true; |
| 150 assigned_register_ = kInvalidAssignment; | 140 assigned_register_ = kInvalidAssignment; |
| 141 ConvertOperands(zone); |
| 151 } | 142 } |
| 152 | 143 |
| 153 | 144 |
| 154 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, | 145 bool LiveRange::HasAllocatedSpillOperand() const { |
| 155 InstructionOperand* operand) { | 146 DCHECK(spill_operand_ != nullptr); |
| 156 DCHECK(HasNoSpillType()); | 147 return !spill_operand_->IsIgnored() || spill_range_ != nullptr; |
| 157 spills_at_definition_ = new (zone) | |
| 158 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | |
| 159 } | |
| 160 | |
| 161 | |
| 162 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, | |
| 163 InstructionOperand* op) { | |
| 164 auto to_spill = TopLevel()->spills_at_definition_; | |
| 165 if (to_spill == nullptr) return; | |
| 166 auto zone = sequence->zone(); | |
| 167 for (; to_spill != nullptr; to_spill = to_spill->next) { | |
| 168 auto gap = sequence->GapAt(to_spill->gap_index); | |
| 169 auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone); | |
| 170 move->AddMove(to_spill->operand, op, zone); | |
| 171 } | |
| 172 TopLevel()->spills_at_definition_ = nullptr; | |
| 173 } | 148 } |
| 174 | 149 |
| 175 | 150 |
| 176 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 151 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
| 177 DCHECK(HasNoSpillType()); | |
| 178 DCHECK(!operand->IsUnallocated()); | 152 DCHECK(!operand->IsUnallocated()); |
| 179 spill_type_ = SpillType::kSpillOperand; | 153 DCHECK(spill_operand_ != nullptr); |
| 180 spill_operand_ = operand; | 154 DCHECK(spill_operand_->IsIgnored()); |
| 181 } | 155 spill_operand_->ConvertTo(operand->kind(), operand->index()); |
| 182 | |
| 183 | |
| 184 void LiveRange::SetSpillRange(SpillRange* spill_range) { | |
| 185 DCHECK(HasNoSpillType() || HasSpillRange()); | |
| 186 DCHECK_NE(spill_range, nullptr); | |
| 187 spill_type_ = SpillType::kSpillRange; | |
| 188 spill_range_ = spill_range; | |
| 189 } | 156 } |
| 190 | 157 |
| 191 | 158 |
| 192 void LiveRange::CommitSpillOperand(InstructionOperand* operand) { | 159 void LiveRange::CommitSpillOperand(InstructionOperand* operand) { |
| 193 DCHECK(HasSpillRange()); | 160 DCHECK(spill_range_ != nullptr); |
| 194 DCHECK(!operand->IsUnallocated()); | |
| 195 DCHECK(!IsChild()); | 161 DCHECK(!IsChild()); |
| 196 spill_type_ = SpillType::kSpillOperand; | 162 spill_range_ = nullptr; |
| 197 spill_operand_ = operand; | 163 SetSpillOperand(operand); |
| 164 for (auto range = this; range != nullptr; range = range->next()) { |
| 165 if (range->IsSpilled()) { |
| 166 range->ConvertUsesToOperand(operand); |
| 167 } |
| 168 } |
| 198 } | 169 } |
| 199 | 170 |
| 200 | 171 |
| 201 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { | 172 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { |
| 202 UsePosition* use_pos = last_processed_use_; | 173 UsePosition* use_pos = last_processed_use_; |
| 203 if (use_pos == nullptr) use_pos = first_pos(); | 174 if (use_pos == nullptr) use_pos = first_pos(); |
| 204 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { | 175 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { |
| 205 use_pos = use_pos->next(); | 176 use_pos = use_pos->next(); |
| 206 } | 177 } |
| 207 last_processed_use_ = use_pos; | 178 last_processed_use_ = use_pos; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 switch (Kind()) { | 228 switch (Kind()) { |
| 258 case GENERAL_REGISTERS: | 229 case GENERAL_REGISTERS: |
| 259 op = RegisterOperand::Create(assigned_register(), zone); | 230 op = RegisterOperand::Create(assigned_register(), zone); |
| 260 break; | 231 break; |
| 261 case DOUBLE_REGISTERS: | 232 case DOUBLE_REGISTERS: |
| 262 op = DoubleRegisterOperand::Create(assigned_register(), zone); | 233 op = DoubleRegisterOperand::Create(assigned_register(), zone); |
| 263 break; | 234 break; |
| 264 default: | 235 default: |
| 265 UNREACHABLE(); | 236 UNREACHABLE(); |
| 266 } | 237 } |
| 267 } else { | 238 } else if (IsSpilled()) { |
| 268 DCHECK(IsSpilled()); | |
| 269 DCHECK(!HasRegisterAssigned()); | 239 DCHECK(!HasRegisterAssigned()); |
| 270 op = TopLevel()->GetSpillOperand(); | 240 op = TopLevel()->GetSpillOperand(); |
| 271 DCHECK(!op->IsUnallocated()); | 241 DCHECK(!op->IsUnallocated()); |
| 242 } else { |
| 243 UnallocatedOperand* unalloc = |
| 244 new (zone) UnallocatedOperand(UnallocatedOperand::NONE); |
| 245 unalloc->set_virtual_register(id_); |
| 246 op = unalloc; |
| 272 } | 247 } |
| 273 return op; | 248 return op; |
| 274 } | 249 } |
| 275 | 250 |
| 276 | 251 |
| 277 UseInterval* LiveRange::FirstSearchIntervalForPosition( | 252 UseInterval* LiveRange::FirstSearchIntervalForPosition( |
| 278 LifetimePosition position) const { | 253 LifetimePosition position) const { |
| 279 if (current_interval_ == nullptr) return first_interval_; | 254 if (current_interval_ == nullptr) return first_interval_; |
| 280 if (current_interval_->start().Value() > position.Value()) { | 255 if (current_interval_->start().Value() > position.Value()) { |
| 281 current_interval_ = nullptr; | 256 current_interval_ = nullptr; |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 if (use_pos->HasOperand()) { | 475 if (use_pos->HasOperand()) { |
| 501 DCHECK(op->IsRegister() || op->IsDoubleRegister() || | 476 DCHECK(op->IsRegister() || op->IsDoubleRegister() || |
| 502 !use_pos->RequiresRegister()); | 477 !use_pos->RequiresRegister()); |
| 503 use_pos->operand()->ConvertTo(op->kind(), op->index()); | 478 use_pos->operand()->ConvertTo(op->kind(), op->index()); |
| 504 } | 479 } |
| 505 use_pos = use_pos->next(); | 480 use_pos = use_pos->next(); |
| 506 } | 481 } |
| 507 } | 482 } |
| 508 | 483 |
| 509 | 484 |
| 485 void LiveRange::ConvertOperands(Zone* zone) { |
| 486 ConvertUsesToOperand(CreateAssignedOperand(zone)); |
| 487 } |
| 488 |
| 489 |
| 510 bool LiveRange::CanCover(LifetimePosition position) const { | 490 bool LiveRange::CanCover(LifetimePosition position) const { |
| 511 if (IsEmpty()) return false; | 491 if (IsEmpty()) return false; |
| 512 return Start().Value() <= position.Value() && | 492 return Start().Value() <= position.Value() && |
| 513 position.Value() < End().Value(); | 493 position.Value() < End().Value(); |
| 514 } | 494 } |
| 515 | 495 |
| 516 | 496 |
| 517 bool LiveRange::Covers(LifetimePosition position) { | 497 bool LiveRange::Covers(LifetimePosition position) { |
| 518 if (!CanCover(position)) return false; | 498 if (!CanCover(position)) return false; |
| 519 auto start_search = FirstSearchIntervalForPosition(position); | 499 auto start_search = FirstSearchIntervalForPosition(position); |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 result = new_node; | 810 result = new_node; |
| 831 } else { | 811 } else { |
| 832 node->set_next(new_node); | 812 node->set_next(new_node); |
| 833 } | 813 } |
| 834 node = new_node; | 814 node = new_node; |
| 835 src = src->next(); | 815 src = src->next(); |
| 836 } | 816 } |
| 837 use_interval_ = result; | 817 use_interval_ = result; |
| 838 live_ranges().push_back(range); | 818 live_ranges().push_back(range); |
| 839 end_position_ = node->end(); | 819 end_position_ = node->end(); |
| 840 DCHECK(!range->HasSpillRange()); | 820 DCHECK(range->GetSpillRange() == nullptr); |
| 841 range->SetSpillRange(this); | 821 range->SetSpillRange(this); |
| 842 } | 822 } |
| 843 | 823 |
| 844 | 824 |
| 845 bool SpillRange::IsIntersectingWith(SpillRange* other) const { | 825 bool SpillRange::IsIntersectingWith(SpillRange* other) const { |
| 846 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || | 826 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || |
| 847 this->End().Value() <= other->use_interval_->start().Value() || | 827 this->End().Value() <= other->use_interval_->start().Value() || |
| 848 other->End().Value() <= this->use_interval_->start().Value()) { | 828 other->End().Value() <= this->use_interval_->start().Value()) { |
| 849 return false; | 829 return false; |
| 850 } | 830 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 914 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
| 935 auto op_kind = kind == DOUBLE_REGISTERS | 915 auto op_kind = kind == DOUBLE_REGISTERS |
| 936 ? InstructionOperand::DOUBLE_STACK_SLOT | 916 ? InstructionOperand::DOUBLE_STACK_SLOT |
| 937 : InstructionOperand::STACK_SLOT; | 917 : InstructionOperand::STACK_SLOT; |
| 938 auto op = new (code_zone()) InstructionOperand(op_kind, index); | 918 auto op = new (code_zone()) InstructionOperand(op_kind, index); |
| 939 range->SetOperand(op); | 919 range->SetOperand(op); |
| 940 } | 920 } |
| 941 } | 921 } |
| 942 | 922 |
| 943 | 923 |
| 944 void RegisterAllocator::CommitAssignment() { | |
| 945 for (auto range : live_ranges()) { | |
| 946 if (range == nullptr || range->IsEmpty()) continue; | |
| 947 // Register assignments were committed in set_assigned_register. | |
| 948 if (range->HasRegisterAssigned()) continue; | |
| 949 auto assigned = range->CreateAssignedOperand(code_zone()); | |
| 950 range->ConvertUsesToOperand(assigned); | |
| 951 if (range->IsSpilled()) { | |
| 952 range->CommitSpillsAtDefinition(code(), assigned); | |
| 953 } | |
| 954 } | |
| 955 } | |
| 956 | |
| 957 | |
| 958 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 924 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
| 959 DCHECK(FLAG_turbo_reuse_spill_slots); | 925 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 960 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); | 926 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); |
| 961 spill_ranges().push_back(spill_range); | 927 spill_ranges().push_back(spill_range); |
| 962 return spill_range; | 928 return spill_range; |
| 963 } | 929 } |
| 964 | 930 |
| 965 | 931 |
| 966 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 932 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
| 967 DCHECK(FLAG_turbo_reuse_spill_slots); | 933 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 968 DCHECK(range->HasNoSpillType()); | 934 DCHECK(!range->HasAllocatedSpillOperand()); |
| 969 if (range->IsChild() || !range->is_phi()) return false; | 935 if (range->IsChild() || !range->is_phi()) return false; |
| 970 | 936 |
| 971 auto lookup = phi_map_.find(range->id()); | 937 auto lookup = phi_map_.find(range->id()); |
| 972 DCHECK(lookup != phi_map_.end()); | 938 DCHECK(lookup != phi_map_.end()); |
| 973 auto phi = lookup->second.phi; | 939 auto phi = lookup->second.phi; |
| 974 auto block = lookup->second.block; | 940 auto block = lookup->second.block; |
| 975 // Count the number of spilled operands. | 941 // Count the number of spilled operands. |
| 976 size_t spilled_count = 0; | 942 size_t spilled_count = 0; |
| 977 LiveRange* first_op = nullptr; | 943 LiveRange* first_op = nullptr; |
| 978 for (size_t i = 0; i < phi->operands().size(); i++) { | 944 for (size_t i = 0; i < phi->operands().size(); i++) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1102 | 1068 |
| 1103 code()->AddGapMove(gap_index, output, output_copy); | 1069 code()->AddGapMove(gap_index, output, output_copy); |
| 1104 } | 1070 } |
| 1105 } | 1071 } |
| 1106 | 1072 |
| 1107 if (!assigned) { | 1073 if (!assigned) { |
| 1108 for (auto succ : block->successors()) { | 1074 for (auto succ : block->successors()) { |
| 1109 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1075 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
| 1110 DCHECK(successor->PredecessorCount() == 1); | 1076 DCHECK(successor->PredecessorCount() == 1); |
| 1111 int gap_index = successor->first_instruction_index() + 1; | 1077 int gap_index = successor->first_instruction_index() + 1; |
| 1112 range->SpillAtDefinition(local_zone(), gap_index, output); | |
| 1113 range->SetSpillStartIndex(gap_index); | 1078 range->SetSpillStartIndex(gap_index); |
| 1079 |
| 1080 // This move to spill operand is not a real use. Liveness analysis |
| 1081 // and splitting of live ranges do not account for it. |
| 1082 // Thus it should be inserted to a lifetime position corresponding to |
| 1083 // the instruction end. |
| 1084 auto gap = code()->GapAt(gap_index); |
| 1085 auto move = |
| 1086 gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()); |
| 1087 move->AddMove(output, range->GetSpillOperand(), code_zone()); |
| 1114 } | 1088 } |
| 1115 } | 1089 } |
| 1116 } | 1090 } |
| 1117 } | 1091 } |
| 1118 | 1092 |
| 1119 | 1093 |
| 1120 void RegisterAllocator::MeetConstraintsBetween(Instruction* first, | 1094 void RegisterAllocator::MeetConstraintsBetween(Instruction* first, |
| 1121 Instruction* second, | 1095 Instruction* second, |
| 1122 int gap_index) { | 1096 int gap_index) { |
| 1123 if (first != nullptr) { | 1097 if (first != nullptr) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1152 range->SetSpillOperand(first_output); | 1126 range->SetSpillOperand(first_output); |
| 1153 range->SetSpillStartIndex(gap_index - 1); | 1127 range->SetSpillStartIndex(gap_index - 1); |
| 1154 assigned = true; | 1128 assigned = true; |
| 1155 } | 1129 } |
| 1156 code()->AddGapMove(gap_index, first_output, output_copy); | 1130 code()->AddGapMove(gap_index, first_output, output_copy); |
| 1157 } | 1131 } |
| 1158 | 1132 |
| 1159 // Make sure we add a gap move for spilling (if we have not done | 1133 // Make sure we add a gap move for spilling (if we have not done |
| 1160 // so already). | 1134 // so already). |
| 1161 if (!assigned) { | 1135 if (!assigned) { |
| 1162 range->SpillAtDefinition(local_zone(), gap_index, first_output); | |
| 1163 range->SetSpillStartIndex(gap_index); | 1136 range->SetSpillStartIndex(gap_index); |
| 1137 |
| 1138 // This move to spill operand is not a real use. Liveness analysis |
| 1139 // and splitting of live ranges do not account for it. |
| 1140 // Thus it should be inserted to a lifetime position corresponding to |
| 1141 // the instruction end. |
| 1142 auto gap = code()->GapAt(gap_index); |
| 1143 auto move = |
| 1144 gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()); |
| 1145 move->AddMove(first_output, range->GetSpillOperand(), code_zone()); |
| 1164 } | 1146 } |
| 1165 } | 1147 } |
| 1166 } | 1148 } |
| 1167 } | 1149 } |
| 1168 | 1150 |
| 1169 if (second != nullptr) { | 1151 if (second != nullptr) { |
| 1170 // Handle fixed input operands of second instruction. | 1152 // Handle fixed input operands of second instruction. |
| 1171 for (size_t i = 0; i < second->InputCount(); i++) { | 1153 for (size_t i = 0; i < second->InputCount(); i++) { |
| 1172 auto input = second->InputAt(i); | 1154 auto input = second->InputAt(i); |
| 1173 if (input->IsImmediate()) continue; // Ignore immediates. | 1155 if (input->IsImmediate()) continue; // Ignore immediates. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1249 if (instr->IsGapMoves()) { | 1231 if (instr->IsGapMoves()) { |
| 1250 // Process the moves of the gap instruction, making their sources live. | 1232 // Process the moves of the gap instruction, making their sources live. |
| 1251 auto gap = code()->GapAt(index); | 1233 auto gap = code()->GapAt(index); |
| 1252 | 1234 |
| 1253 // TODO(titzer): no need to create the parallel move if it doesn't exist. | 1235 // TODO(titzer): no need to create the parallel move if it doesn't exist. |
| 1254 auto move = | 1236 auto move = |
| 1255 gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()); | 1237 gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()); |
| 1256 const ZoneList<MoveOperands>* move_operands = move->move_operands(); | 1238 const ZoneList<MoveOperands>* move_operands = move->move_operands(); |
| 1257 for (int i = 0; i < move_operands->length(); ++i) { | 1239 for (int i = 0; i < move_operands->length(); ++i) { |
| 1258 auto cur = &move_operands->at(i); | 1240 auto cur = &move_operands->at(i); |
| 1241 if (cur->IsIgnored()) continue; |
| 1259 auto from = cur->source(); | 1242 auto from = cur->source(); |
| 1260 auto to = cur->destination(); | 1243 auto to = cur->destination(); |
| 1261 auto hint = to; | 1244 auto hint = to; |
| 1262 if (to->IsUnallocated()) { | 1245 if (to->IsUnallocated()) { |
| 1263 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); | 1246 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
| 1264 auto to_range = LiveRangeFor(to_vreg); | 1247 auto to_range = LiveRangeFor(to_vreg); |
| 1265 if (to_range->is_phi()) { | 1248 if (to_range->is_phi()) { |
| 1266 DCHECK(!FLAG_turbo_delay_ssa_decon); | 1249 DCHECK(!FLAG_turbo_delay_ssa_decon); |
| 1267 if (to_range->is_non_loop_phi()) { | 1250 if (to_range->is_non_loop_phi()) { |
| 1268 hint = to_range->current_hint_operand(); | 1251 hint = to_range->current_hint_operand(); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1371 code()->InstructionBlockAt(block->predecessors()[i]); | 1354 code()->InstructionBlockAt(block->predecessors()[i]); |
| 1372 // The gap move must be added without any special processing as in | 1355 // The gap move must be added without any special processing as in |
| 1373 // the AddConstraintsGapMove. | 1356 // the AddConstraintsGapMove. |
| 1374 code()->AddGapMove(cur_block->last_instruction_index() - 1, | 1357 code()->AddGapMove(cur_block->last_instruction_index() - 1, |
| 1375 phi->inputs()[i], output); | 1358 phi->inputs()[i], output); |
| 1376 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1359 DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
| 1377 ->HasPointerMap()); | 1360 ->HasPointerMap()); |
| 1378 } | 1361 } |
| 1379 } | 1362 } |
| 1380 auto live_range = LiveRangeFor(phi_vreg); | 1363 auto live_range = LiveRangeFor(phi_vreg); |
| 1381 int gap_index = block->first_instruction_index(); | 1364 auto block_start = code()->GetBlockStart(block->rpo_number()); |
| 1382 live_range->SpillAtDefinition(local_zone(), gap_index, output); | 1365 block_start->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()) |
| 1383 live_range->SetSpillStartIndex(gap_index); | 1366 ->AddMove(output, live_range->GetSpillOperand(), code_zone()); |
| 1367 live_range->SetSpillStartIndex(block->first_instruction_index()); |
| 1384 // We use the phi-ness of some nodes in some later heuristics. | 1368 // We use the phi-ness of some nodes in some later heuristics. |
| 1385 live_range->set_is_phi(true); | 1369 live_range->set_is_phi(true); |
| 1386 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1370 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
| 1387 } | 1371 } |
| 1388 } | 1372 } |
| 1389 | 1373 |
| 1390 | 1374 |
| 1391 void RegisterAllocator::MeetRegisterConstraints() { | 1375 void RegisterAllocator::MeetRegisterConstraints() { |
| 1392 for (auto block : code()->instruction_blocks()) { | 1376 for (auto block : code()->instruction_blocks()) { |
| 1393 MeetRegisterConstraints(block); | 1377 MeetRegisterConstraints(block); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1732 } | 1716 } |
| 1733 } | 1717 } |
| 1734 | 1718 |
| 1735 for (auto range : live_ranges()) { | 1719 for (auto range : live_ranges()) { |
| 1736 if (range == nullptr) continue; | 1720 if (range == nullptr) continue; |
| 1737 range->kind_ = RequiredRegisterKind(range->id()); | 1721 range->kind_ = RequiredRegisterKind(range->id()); |
| 1738 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1722 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
| 1739 // live ranges, every use requires the constant to be in a register. | 1723 // live ranges, every use requires the constant to be in a register. |
| 1740 // Without this hack, all uses with "any" policy would get the constant | 1724 // Without this hack, all uses with "any" policy would get the constant |
| 1741 // operand assigned. | 1725 // operand assigned. |
| 1742 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1726 if (range->HasAllocatedSpillOperand() && |
| 1727 range->GetSpillOperand()->IsConstant()) { |
| 1743 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { | 1728 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { |
| 1744 pos->register_beneficial_ = true; | 1729 pos->register_beneficial_ = true; |
| 1745 // TODO(dcarney): should the else case assert requires_reg_ == false? | 1730 // TODO(dcarney): should the else case assert requires_reg_ == false? |
| 1746 // Can't mark phis as needing a register. | 1731 // Can't mark phis as needing a register. |
| 1747 if (!code() | 1732 if (!code() |
| 1748 ->InstructionAt(pos->pos().InstructionIndex()) | 1733 ->InstructionAt(pos->pos().InstructionIndex()) |
| 1749 ->IsGapMoves()) { | 1734 ->IsGapMoves()) { |
| 1750 pos->requires_reg_ = true; | 1735 pos->requires_reg_ = true; |
| 1751 } | 1736 } |
| 1752 } | 1737 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1836 // safe point position. | 1821 // safe point position. |
| 1837 auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point); | 1822 auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point); |
| 1838 auto cur = range; | 1823 auto cur = range; |
| 1839 while (cur != nullptr && !cur->Covers(safe_point_pos)) { | 1824 while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
| 1840 cur = cur->next(); | 1825 cur = cur->next(); |
| 1841 } | 1826 } |
| 1842 if (cur == nullptr) continue; | 1827 if (cur == nullptr) continue; |
| 1843 | 1828 |
| 1844 // Check if the live range is spilled and the safe point is after | 1829 // Check if the live range is spilled and the safe point is after |
| 1845 // the spill position. | 1830 // the spill position. |
| 1846 if (range->HasSpillOperand() && | 1831 if (range->HasAllocatedSpillOperand() && |
| 1847 safe_point >= range->spill_start_index() && | 1832 safe_point >= range->spill_start_index() && |
| 1848 !range->GetSpillOperand()->IsConstant()) { | 1833 !range->GetSpillOperand()->IsConstant()) { |
| 1849 TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n", | 1834 TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n", |
| 1850 range->id(), range->spill_start_index(), safe_point); | 1835 range->id(), range->spill_start_index(), safe_point); |
| 1851 map->RecordPointer(range->GetSpillOperand(), code_zone()); | 1836 map->RecordPointer(range->GetSpillOperand(), code_zone()); |
| 1852 } | 1837 } |
| 1853 | 1838 |
| 1854 if (!cur->IsSpilled()) { | 1839 if (!cur->IsSpilled()) { |
| 1855 TraceAlloc( | 1840 TraceAlloc( |
| 1856 "Pointer in register for range %d (start at %d) " | 1841 "Pointer in register for range %d (start at %d) " |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1916 auto current = unhandled_live_ranges().back(); | 1901 auto current = unhandled_live_ranges().back(); |
| 1917 unhandled_live_ranges().pop_back(); | 1902 unhandled_live_ranges().pop_back(); |
| 1918 DCHECK(UnhandledIsSorted()); | 1903 DCHECK(UnhandledIsSorted()); |
| 1919 auto position = current->Start(); | 1904 auto position = current->Start(); |
| 1920 #ifdef DEBUG | 1905 #ifdef DEBUG |
| 1921 allocation_finger_ = position; | 1906 allocation_finger_ = position; |
| 1922 #endif | 1907 #endif |
| 1923 TraceAlloc("Processing interval %d start=%d\n", current->id(), | 1908 TraceAlloc("Processing interval %d start=%d\n", current->id(), |
| 1924 position.Value()); | 1909 position.Value()); |
| 1925 | 1910 |
| 1926 if (!current->HasNoSpillType()) { | 1911 if (current->HasAllocatedSpillOperand()) { |
| 1927 TraceAlloc("Live range %d already has a spill operand\n", current->id()); | 1912 TraceAlloc("Live range %d already has a spill operand\n", current->id()); |
| 1928 auto next_pos = position; | 1913 auto next_pos = position; |
| 1929 if (code()->IsGapAt(next_pos.InstructionIndex())) { | 1914 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
| 1930 next_pos = next_pos.NextInstruction(); | 1915 next_pos = next_pos.NextInstruction(); |
| 1931 } | 1916 } |
| 1932 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); | 1917 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); |
| 1933 // If the range already has a spill operand and it doesn't need a | 1918 // If the range already has a spill operand and it doesn't need a |
| 1934 // register immediately, split it and spill the first part of the range. | 1919 // register immediately, split it and spill the first part of the range. |
| 1935 if (pos == nullptr) { | 1920 if (pos == nullptr) { |
| 1936 Spill(current); | 1921 Spill(current); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2081 if (a->Start().Value() < b->Start().Value()) return false; | 2066 if (a->Start().Value() < b->Start().Value()) return false; |
| 2082 } | 2067 } |
| 2083 return true; | 2068 return true; |
| 2084 } | 2069 } |
| 2085 | 2070 |
| 2086 | 2071 |
| 2087 void RegisterAllocator::FreeSpillSlot(LiveRange* range) { | 2072 void RegisterAllocator::FreeSpillSlot(LiveRange* range) { |
| 2088 DCHECK(!FLAG_turbo_reuse_spill_slots); | 2073 DCHECK(!FLAG_turbo_reuse_spill_slots); |
| 2089 // Check that we are the last range. | 2074 // Check that we are the last range. |
| 2090 if (range->next() != nullptr) return; | 2075 if (range->next() != nullptr) return; |
| 2091 if (!range->TopLevel()->HasSpillOperand()) return; | 2076 if (!range->TopLevel()->HasAllocatedSpillOperand()) return; |
| 2092 auto spill_operand = range->TopLevel()->GetSpillOperand(); | 2077 auto spill_operand = range->TopLevel()->GetSpillOperand(); |
| 2093 if (spill_operand->IsConstant()) return; | 2078 if (spill_operand->IsConstant()) return; |
| 2094 if (spill_operand->index() >= 0) { | 2079 if (spill_operand->index() >= 0) { |
| 2095 reusable_slots().push_back(range); | 2080 reusable_slots().push_back(range); |
| 2096 } | 2081 } |
| 2097 } | 2082 } |
| 2098 | 2083 |
| 2099 | 2084 |
| 2100 InstructionOperand* RegisterAllocator::TryReuseSpillSlot(LiveRange* range) { | 2085 InstructionOperand* RegisterAllocator::TryReuseSpillSlot(LiveRange* range) { |
| 2101 DCHECK(!FLAG_turbo_reuse_spill_slots); | 2086 DCHECK(!FLAG_turbo_reuse_spill_slots); |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2496 // Nothing to spill. Just put it to unhandled as whole. | 2481 // Nothing to spill. Just put it to unhandled as whole. |
| 2497 AddToUnhandledSorted(second_part); | 2482 AddToUnhandledSorted(second_part); |
| 2498 } | 2483 } |
| 2499 } | 2484 } |
| 2500 | 2485 |
| 2501 | 2486 |
| 2502 void RegisterAllocator::Spill(LiveRange* range) { | 2487 void RegisterAllocator::Spill(LiveRange* range) { |
| 2503 DCHECK(!range->IsSpilled()); | 2488 DCHECK(!range->IsSpilled()); |
| 2504 TraceAlloc("Spilling live range %d\n", range->id()); | 2489 TraceAlloc("Spilling live range %d\n", range->id()); |
| 2505 auto first = range->TopLevel(); | 2490 auto first = range->TopLevel(); |
| 2506 if (first->HasNoSpillType()) { | 2491 if (!first->HasAllocatedSpillOperand()) { |
| 2507 if (FLAG_turbo_reuse_spill_slots) { | 2492 if (FLAG_turbo_reuse_spill_slots) { |
| 2508 AssignSpillRangeToLiveRange(first); | 2493 AssignSpillRangeToLiveRange(first); |
| 2509 } else { | 2494 } else { |
| 2510 auto op = TryReuseSpillSlot(range); | 2495 auto op = TryReuseSpillSlot(range); |
| 2511 if (op == nullptr) { | 2496 if (op == nullptr) { |
| 2512 // Allocate a new operand referring to the spill slot. | 2497 // Allocate a new operand referring to the spill slot. |
| 2513 RegisterKind kind = range->Kind(); | 2498 RegisterKind kind = range->Kind(); |
| 2514 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 2499 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
| 2515 auto op_kind = kind == DOUBLE_REGISTERS | 2500 if (kind == DOUBLE_REGISTERS) { |
| 2516 ? InstructionOperand::DOUBLE_STACK_SLOT | 2501 op = DoubleStackSlotOperand::Create(index, local_zone()); |
| 2517 : InstructionOperand::STACK_SLOT; | 2502 } else { |
| 2518 op = new (code_zone()) InstructionOperand(op_kind, index); | 2503 DCHECK(kind == GENERAL_REGISTERS); |
| 2504 op = StackSlotOperand::Create(index, local_zone()); |
| 2505 } |
| 2519 } | 2506 } |
| 2520 first->SetSpillOperand(op); | 2507 first->SetSpillOperand(op); |
| 2521 } | 2508 } |
| 2522 } | 2509 } |
| 2523 range->MakeSpilled(); | 2510 range->MakeSpilled(code_zone()); |
| 2524 } | 2511 } |
| 2525 | 2512 |
| 2526 | 2513 |
| 2527 int RegisterAllocator::RegisterCount() const { return num_registers_; } | 2514 int RegisterAllocator::RegisterCount() const { return num_registers_; } |
| 2528 | 2515 |
| 2529 | 2516 |
| 2530 #ifdef DEBUG | 2517 #ifdef DEBUG |
| 2531 | 2518 |
| 2532 | 2519 |
| 2533 void RegisterAllocator::Verify() const { | 2520 void RegisterAllocator::Verify() const { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2547 } else { | 2534 } else { |
| 2548 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2535 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2549 assigned_registers_->Add(reg); | 2536 assigned_registers_->Add(reg); |
| 2550 } | 2537 } |
| 2551 range->set_assigned_register(reg, code_zone()); | 2538 range->set_assigned_register(reg, code_zone()); |
| 2552 } | 2539 } |
| 2553 | 2540 |
| 2554 } // namespace compiler | 2541 } // namespace compiler |
| 2555 } // namespace internal | 2542 } // namespace internal |
| 2556 } // namespace v8 | 2543 } // namespace v8 |
| OLD | NEW |