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 |