OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/greedy-allocator.h" | 5 #include "src/compiler/greedy-allocator.h" |
6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
7 | 7 |
8 namespace v8 { | 8 namespace v8 { |
9 namespace internal { | 9 namespace internal { |
10 namespace compiler { | 10 namespace compiler { |
11 | 11 |
12 #define TRACE(...) \ | 12 #define TRACE(...) \ |
13 do { \ | 13 do { \ |
14 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ | 14 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ |
15 } while (false) | 15 } while (false) |
16 | 16 |
17 | 17 |
| 18 const float GreedyAllocator::kAllocatedRangeMultiplier = 10.0; |
| 19 |
| 20 |
18 namespace { | 21 namespace { |
19 | 22 |
20 | 23 |
21 void UpdateOperands(LiveRange* range, RegisterAllocationData* data) { | 24 void UpdateOperands(LiveRange* range, RegisterAllocationData* data) { |
22 int reg_id = range->assigned_register(); | 25 int reg_id = range->assigned_register(); |
23 range->SetUseHints(reg_id); | 26 range->SetUseHints(reg_id); |
24 if (range->is_phi()) { | 27 if (range->is_phi()) { |
25 data->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id); | 28 data->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id); |
26 } | 29 } |
27 } | 30 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 allocations_(local_zone), | 127 allocations_(local_zone), |
125 scheduler_(local_zone) {} | 128 scheduler_(local_zone) {} |
126 | 129 |
127 | 130 |
128 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { | 131 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { |
129 TRACE("Assigning register %s to live range %d\n", RegisterName(reg_id), | 132 TRACE("Assigning register %s to live range %d\n", RegisterName(reg_id), |
130 range->id()); | 133 range->id()); |
131 | 134 |
132 DCHECK(!range->HasRegisterAssigned()); | 135 DCHECK(!range->HasRegisterAssigned()); |
133 | 136 |
134 current_allocations(reg_id)->AllocateRange(range); | 137 AllocateRegisterToRange(reg_id, range); |
135 | 138 |
136 TRACE("Assigning %s to range %d\n", RegisterName(reg_id), range->id()); | 139 TRACE("Assigning %s to range %d\n", RegisterName(reg_id), range->id()); |
137 range->set_assigned_register(reg_id); | 140 range->set_assigned_register(reg_id); |
138 | |
139 DCHECK(current_allocations(reg_id)->VerifyAllocationsAreValid()); | |
140 } | 141 } |
141 | 142 |
142 | 143 |
143 void GreedyAllocator::PreallocateFixedRanges() { | 144 void GreedyAllocator::PreallocateFixedRanges() { |
144 allocations_.resize(num_registers()); | 145 allocations_.resize(num_registers()); |
145 for (int i = 0; i < num_registers(); i++) { | 146 for (int i = 0; i < num_registers(); i++) { |
146 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone()); | 147 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone()); |
147 } | 148 } |
148 | 149 |
149 for (LiveRange* fixed_range : GetFixedRegisters()) { | 150 for (LiveRange* fixed_range : GetFixedRegisters()) { |
150 if (fixed_range != nullptr) { | 151 if (fixed_range != nullptr) { |
151 DCHECK_EQ(mode(), fixed_range->kind()); | 152 DCHECK_EQ(mode(), fixed_range->kind()); |
152 DCHECK(fixed_range->IsFixed()); | 153 DCHECK(fixed_range->IsFixed()); |
153 | 154 |
154 int reg_nr = fixed_range->assigned_register(); | 155 int reg_nr = fixed_range->assigned_register(); |
155 EnsureValidRangeWeight(fixed_range); | 156 EnsureValidRangeWeight(fixed_range); |
156 current_allocations(reg_nr)->AllocateRange(fixed_range); | 157 AllocateRegisterToRange(reg_nr, fixed_range); |
157 } | 158 } |
158 } | 159 } |
159 } | 160 } |
160 | 161 |
161 | 162 |
162 void GreedyAllocator::ScheduleAllocationCandidates() { | 163 void GreedyAllocator::ScheduleAllocationCandidates() { |
163 for (auto range : data()->live_ranges()) { | 164 for (auto range : data()->live_ranges()) { |
164 if (CanProcessRange(range) && !range->spilled()) { | 165 if (CanProcessRange(range) && !range->spilled()) { |
165 scheduler().Schedule(range); | 166 scheduler().Schedule(range); |
166 } | 167 } |
(...skipping 16 matching lines...) Expand all Loading... |
183 int evictable_reg = -1; | 184 int evictable_reg = -1; |
184 EnsureValidRangeWeight(range); | 185 EnsureValidRangeWeight(range); |
185 DCHECK(range->weight() != LiveRange::kInvalidWeight); | 186 DCHECK(range->weight() != LiveRange::kInvalidWeight); |
186 | 187 |
187 float smallest_weight = LiveRange::kMaxWeight; | 188 float smallest_weight = LiveRange::kMaxWeight; |
188 | 189 |
189 // Seek either the first free register, or, from the set of registers | 190 // Seek either the first free register, or, from the set of registers |
190 // where the maximum conflict is lower than the candidate's weight, the one | 191 // where the maximum conflict is lower than the candidate's weight, the one |
191 // with the smallest such weight. | 192 // with the smallest such weight. |
192 for (int i = 0; i < num_registers(); i++) { | 193 for (int i = 0; i < num_registers(); i++) { |
193 float max_conflict_weight = | 194 float max_conflict_weight = GetMaximumConflictingWeight(i, range); |
194 current_allocations(i)->GetMaximumConflictingWeight(range); | |
195 if (max_conflict_weight == LiveRange::kInvalidWeight) { | 195 if (max_conflict_weight == LiveRange::kInvalidWeight) { |
196 free_reg = i; | 196 free_reg = i; |
197 break; | 197 break; |
198 } | 198 } |
199 if (max_conflict_weight < range->weight() && | 199 if (max_conflict_weight < range->weight() && |
200 max_conflict_weight < smallest_weight) { | 200 max_conflict_weight < smallest_weight) { |
201 smallest_weight = max_conflict_weight; | 201 smallest_weight = max_conflict_weight; |
202 evictable_reg = i; | 202 evictable_reg = i; |
203 } | 203 } |
204 } | 204 } |
205 | 205 |
206 // We have a free register, so we use it. | 206 // We have a free register, so we use it. |
207 if (free_reg >= 0) { | 207 if (free_reg >= 0) { |
208 TRACE("Found free register %s for live range %d\n", RegisterName(free_reg), | 208 TRACE("Found free register %s for live range %d\n", RegisterName(free_reg), |
209 range->id()); | 209 range->id()); |
210 AssignRangeToRegister(free_reg, range); | 210 AssignRangeToRegister(free_reg, range); |
211 return; | 211 return; |
212 } | 212 } |
213 | 213 |
214 // We found a register to perform evictions, so we evict and allocate our | 214 // We found a register to perform evictions, so we evict and allocate our |
215 // candidate. | 215 // candidate. |
216 if (evictable_reg >= 0) { | 216 if (evictable_reg >= 0) { |
217 TRACE("Found evictable register %s for live range %d\n", | 217 TRACE("Found evictable register %s for live range %d\n", |
218 RegisterName(free_reg), range->id()); | 218 RegisterName(free_reg), range->id()); |
219 current_allocations(evictable_reg) | 219 EvictAndRescheduleConflicts(evictable_reg, range); |
220 ->EvictAndRescheduleConflicts(range, &scheduler()); | |
221 AssignRangeToRegister(evictable_reg, range); | 220 AssignRangeToRegister(evictable_reg, range); |
222 return; | 221 return; |
223 } | 222 } |
224 | 223 |
225 // The range needs to be split or spilled. | 224 // The range needs to be split or spilled. |
226 SplitOrSpillBlockedRange(range); | 225 SplitOrSpillBlockedRange(range); |
227 } | 226 } |
228 | 227 |
229 | 228 |
| 229 void GreedyAllocator::EvictAndRescheduleConflicts(unsigned reg_id, |
| 230 const LiveRange* range) { |
| 231 current_allocations(reg_id)->RemoveConflicts(range, [this](LiveRange* range) { |
| 232 DCHECK(range->HasRegisterAssigned()); |
| 233 CHECK(!range->IsFixed()); |
| 234 range->UnsetAssignedRegister(); |
| 235 UpdateWeightAtEviction(range); |
| 236 scheduler().Schedule(range); |
| 237 TRACE("Evicted range %d.\n", range->id()); |
| 238 }); |
| 239 } |
| 240 |
| 241 |
230 void GreedyAllocator::SplitAndSpillRangesDefinedByMemoryOperand() { | 242 void GreedyAllocator::SplitAndSpillRangesDefinedByMemoryOperand() { |
231 size_t initial_range_count = data()->live_ranges().size(); | 243 size_t initial_range_count = data()->live_ranges().size(); |
232 for (size_t i = 0; i < initial_range_count; ++i) { | 244 for (size_t i = 0; i < initial_range_count; ++i) { |
233 auto range = data()->live_ranges()[i]; | 245 auto range = data()->live_ranges()[i]; |
234 if (!CanProcessRange(range)) continue; | 246 if (!CanProcessRange(range)) continue; |
235 if (range->HasNoSpillType()) continue; | 247 if (range->HasNoSpillType()) continue; |
236 | 248 |
237 LifetimePosition start = range->Start(); | 249 LifetimePosition start = range->Start(); |
238 TRACE("Live range %d is defined by a spill operand.\n", range->id()); | 250 TRACE("Live range %d is defined by a spill operand.\n", range->id()); |
239 auto next_pos = start; | 251 auto next_pos = start; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 data()->MarkAllocated(mode(), static_cast<int>(i)); | 303 data()->MarkAllocated(mode(), static_cast<int>(i)); |
292 } | 304 } |
293 } | 305 } |
294 allocations_.clear(); | 306 allocations_.clear(); |
295 | 307 |
296 TRACE("End allocating function %s with the Greedy Allocator\n", | 308 TRACE("End allocating function %s with the Greedy Allocator\n", |
297 data()->debug_name()); | 309 data()->debug_name()); |
298 } | 310 } |
299 | 311 |
300 | 312 |
| 313 float GreedyAllocator::GetMaximumConflictingWeight( |
| 314 unsigned reg_id, const LiveRange* range) const { |
| 315 float ret = LiveRange::kInvalidWeight; |
| 316 |
| 317 current_allocations(reg_id) |
| 318 ->VisitConflicts(range, [&ret](const LiveRange* conflict) { |
| 319 DCHECK_NE(conflict->weight(), LiveRange::kInvalidWeight); |
| 320 ret = Max(ret, conflict->weight()); |
| 321 return (ret != LiveRange::kMaxWeight); |
| 322 }); |
| 323 |
| 324 return ret; |
| 325 } |
| 326 |
| 327 |
301 void GreedyAllocator::EnsureValidRangeWeight(LiveRange* range) { | 328 void GreedyAllocator::EnsureValidRangeWeight(LiveRange* range) { |
302 // The live range weight will be invalidated when ranges are created or split. | 329 // The live range weight will be invalidated when ranges are created or split. |
303 // Otherwise, it is consistently updated when the range is allocated or | 330 // Otherwise, it is consistently updated when the range is allocated or |
304 // unallocated. | 331 // unallocated. |
305 if (range->weight() != LiveRange::kInvalidWeight) return; | 332 if (range->weight() != LiveRange::kInvalidWeight) return; |
306 | 333 |
307 if (range->IsFixed()) { | 334 if (range->IsFixed()) { |
308 range->set_weight(LiveRange::kMaxWeight); | 335 range->set_weight(LiveRange::kMaxWeight); |
309 return; | 336 return; |
310 } | 337 } |
(...skipping 30 matching lines...) Expand all Loading... |
341 scheduler().Schedule(range); | 368 scheduler().Schedule(range); |
342 return; | 369 return; |
343 } | 370 } |
344 SpillRangeAsLastResort(range); | 371 SpillRangeAsLastResort(range); |
345 } | 372 } |
346 | 373 |
347 | 374 |
348 } // namespace compiler | 375 } // namespace compiler |
349 } // namespace internal | 376 } // namespace internal |
350 } // namespace v8 | 377 } // namespace v8 |
OLD | NEW |