| 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 | 12 |
| 13 #define TRACE(...) \ | 13 #define TRACE(...) \ |
| 14 do { \ | 14 do { \ |
| 15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ | 15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ |
| 16 } while (false) | 16 } while (false) |
| 17 | 17 |
| 18 | 18 |
| 19 const float GreedyAllocator::kAllocatedRangeMultiplier = 10.0; | 19 const float GreedyAllocator::kAllocatedRangeMultiplier = 10.0; |
| 20 | 20 |
| 21 | 21 |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 void UpdateOperands(LiveRange* range, RegisterAllocationData* data) { | 24 |
| 25 void UpdateOperands(TopLevelLiveRange* range, RegisterAllocationData* data) { |
| 25 int reg_id = range->assigned_register(); | 26 int reg_id = range->assigned_register(); |
| 26 range->SetUseHints(reg_id); | 27 range->SetUseHints(reg_id); |
| 27 if (range->IsTopLevel() && range->TopLevel()->is_phi()) { | 28 if (range->is_phi()) { |
| 28 data->GetPhiMapValueFor(range->TopLevel())->set_assigned_register(reg_id); | 29 data->GetPhiMapValueFor(range)->set_assigned_register(reg_id); |
| 29 } | 30 } |
| 30 } | 31 } |
| 31 | 32 |
| 32 | 33 |
| 33 LiveRange* Split(LiveRange* range, RegisterAllocationData* data, | 34 LiveRange* Split(LiveRange* range, RegisterAllocationData* data, |
| 34 LifetimePosition pos) { | 35 LifetimePosition pos) { |
| 35 DCHECK(range->Start() < pos && pos < range->End()); | 36 DCHECK(range->Start() < pos && pos < range->End()); |
| 36 DCHECK(pos.IsStart() || pos.IsGapPosition() || | 37 DCHECK(pos.IsStart() || pos.IsGapPosition() || |
| 37 (data->code() | 38 (data->code() |
| 38 ->GetInstructionBlock(pos.ToInstructionIndex()) | 39 ->GetInstructionBlock(pos.ToInstructionIndex()) |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 TRACE("Assigning register %s to live range %d:%d\n", RegisterName(reg_id), | 133 TRACE("Assigning register %s to live range %d:%d\n", RegisterName(reg_id), |
| 133 range->TopLevel()->vreg(), range->relative_id()); | 134 range->TopLevel()->vreg(), range->relative_id()); |
| 134 | 135 |
| 135 DCHECK(!range->HasRegisterAssigned()); | 136 DCHECK(!range->HasRegisterAssigned()); |
| 136 | 137 |
| 137 AllocateRegisterToRange(reg_id, range); | 138 AllocateRegisterToRange(reg_id, range); |
| 138 | 139 |
| 139 TRACE("Assigning %s to range %d%d.\n", RegisterName(reg_id), | 140 TRACE("Assigning %s to range %d%d.\n", RegisterName(reg_id), |
| 140 range->TopLevel()->vreg(), range->relative_id()); | 141 range->TopLevel()->vreg(), range->relative_id()); |
| 141 range->set_assigned_register(reg_id); | 142 range->set_assigned_register(reg_id); |
| 142 UpdateOperands(range, data()); | |
| 143 } | 143 } |
| 144 | 144 |
| 145 | 145 |
| 146 void GreedyAllocator::PreallocateFixedRanges() { | 146 void GreedyAllocator::PreallocateFixedRanges() { |
| 147 allocations_.resize(num_registers()); | 147 allocations_.resize(num_registers()); |
| 148 for (int i = 0; i < num_registers(); i++) { | 148 for (int i = 0; i < num_registers(); i++) { |
| 149 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone()); | 149 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone()); |
| 150 } | 150 } |
| 151 | 151 |
| 152 for (LiveRange* fixed_range : GetFixedRegisters()) { | 152 for (LiveRange* fixed_range : GetFixedRegisters()) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 182 } | 182 } |
| 183 | 183 |
| 184 | 184 |
| 185 void GreedyAllocator::TryAllocateLiveRange(LiveRange* range) { | 185 void GreedyAllocator::TryAllocateLiveRange(LiveRange* range) { |
| 186 // TODO(mtrofin): once we introduce groups, we'll want to first try and | 186 // TODO(mtrofin): once we introduce groups, we'll want to first try and |
| 187 // allocate at the preferred register. | 187 // allocate at the preferred register. |
| 188 TRACE("Attempting to allocate live range %d:%d.\n", range->TopLevel()->vreg(), | 188 TRACE("Attempting to allocate live range %d:%d.\n", range->TopLevel()->vreg(), |
| 189 range->relative_id()); | 189 range->relative_id()); |
| 190 int free_reg = -1; | 190 int free_reg = -1; |
| 191 int evictable_reg = -1; | 191 int evictable_reg = -1; |
| 192 int hinted_reg = -1; | |
| 193 | |
| 194 EnsureValidRangeWeight(range); | 192 EnsureValidRangeWeight(range); |
| 195 DCHECK(range->weight() != LiveRange::kInvalidWeight); | 193 DCHECK(range->weight() != LiveRange::kInvalidWeight); |
| 196 | 194 |
| 197 // Can we allocate at the hinted register? | 195 float smallest_weight = LiveRange::kMaxWeight; |
| 198 if (range->FirstHintPosition(&hinted_reg) != nullptr) { | 196 |
| 199 DCHECK(hinted_reg >= 0); | 197 // Seek either the first free register, or, from the set of registers |
| 200 float max_conflict_weight = GetMaximumConflictingWeight(hinted_reg, range); | 198 // where the maximum conflict is lower than the candidate's weight, the one |
| 199 // with the smallest such weight. |
| 200 for (int i = 0; i < num_registers(); i++) { |
| 201 float max_conflict_weight = GetMaximumConflictingWeight(i, range); |
| 201 if (max_conflict_weight == LiveRange::kInvalidWeight) { | 202 if (max_conflict_weight == LiveRange::kInvalidWeight) { |
| 202 free_reg = hinted_reg; | 203 free_reg = i; |
| 203 } else if (max_conflict_weight < range->weight()) { | 204 break; |
| 204 evictable_reg = hinted_reg; | 205 } |
| 206 if (max_conflict_weight < range->weight() && |
| 207 max_conflict_weight < smallest_weight) { |
| 208 smallest_weight = max_conflict_weight; |
| 209 evictable_reg = i; |
| 205 } | 210 } |
| 206 } | 211 } |
| 207 | 212 |
| 208 if (free_reg < 0 && evictable_reg < 0) { | |
| 209 // There was no hinted reg, or we cannot allocate there. | |
| 210 float smallest_weight = LiveRange::kMaxWeight; | |
| 211 | |
| 212 // Seek either the first free register, or, from the set of registers | |
| 213 // where the maximum conflict is lower than the candidate's weight, the one | |
| 214 // with the smallest such weight. | |
| 215 for (int i = 0; i < num_registers(); i++) { | |
| 216 // Skip unnecessarily re-visiting the hinted register, if any. | |
| 217 if (i == hinted_reg) continue; | |
| 218 float max_conflict_weight = GetMaximumConflictingWeight(i, range); | |
| 219 if (max_conflict_weight == LiveRange::kInvalidWeight) { | |
| 220 free_reg = i; | |
| 221 break; | |
| 222 } | |
| 223 if (max_conflict_weight < range->weight() && | |
| 224 max_conflict_weight < smallest_weight) { | |
| 225 smallest_weight = max_conflict_weight; | |
| 226 evictable_reg = i; | |
| 227 } | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 // We have a free register, so we use it. | 213 // We have a free register, so we use it. |
| 232 if (free_reg >= 0) { | 214 if (free_reg >= 0) { |
| 233 TRACE("Found free register %s for live range %d:%d.\n", | 215 TRACE("Found free register %s for live range %d:%d.\n", |
| 234 RegisterName(free_reg), range->TopLevel()->vreg(), | 216 RegisterName(free_reg), range->TopLevel()->vreg(), |
| 235 range->relative_id()); | 217 range->relative_id()); |
| 236 AssignRangeToRegister(free_reg, range); | 218 AssignRangeToRegister(free_reg, range); |
| 237 return; | 219 return; |
| 238 } | 220 } |
| 239 | 221 |
| 240 // We found a register to perform evictions, so we evict and allocate our | 222 // We found a register to perform evictions, so we evict and allocate our |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 | 297 |
| 316 SplitAndSpillRangesDefinedByMemoryOperand(); | 298 SplitAndSpillRangesDefinedByMemoryOperand(); |
| 317 PreallocateFixedRanges(); | 299 PreallocateFixedRanges(); |
| 318 ScheduleAllocationCandidates(); | 300 ScheduleAllocationCandidates(); |
| 319 | 301 |
| 320 while (!scheduler().empty()) { | 302 while (!scheduler().empty()) { |
| 321 AllocationCandidate candidate = scheduler().GetNext(); | 303 AllocationCandidate candidate = scheduler().GetNext(); |
| 322 TryAllocateCandidate(candidate); | 304 TryAllocateCandidate(candidate); |
| 323 } | 305 } |
| 324 | 306 |
| 307 |
| 308 // We do not rely on the hint mechanism used by LinearScan, so no need to |
| 309 // actively update/reset operands until the end. |
| 310 for (auto range : data()->live_ranges()) { |
| 311 if (CanProcessRange(range) && range->HasRegisterAssigned()) { |
| 312 UpdateOperands(range, data()); |
| 313 } |
| 314 } |
| 315 |
| 325 for (size_t i = 0; i < allocations_.size(); ++i) { | 316 for (size_t i = 0; i < allocations_.size(); ++i) { |
| 326 if (!allocations_[i]->empty()) { | 317 if (!allocations_[i]->empty()) { |
| 327 data()->MarkAllocated(mode(), static_cast<int>(i)); | 318 data()->MarkAllocated(mode(), static_cast<int>(i)); |
| 328 } | 319 } |
| 329 } | 320 } |
| 330 allocations_.clear(); | 321 allocations_.clear(); |
| 331 | 322 |
| 332 TRACE("End allocating function %s with the Greedy Allocator\n", | 323 TRACE("End allocating function %s with the Greedy Allocator\n", |
| 333 data()->debug_name()); | 324 data()->debug_name()); |
| 334 } | 325 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 scheduler().Schedule(range); | 384 scheduler().Schedule(range); |
| 394 return; | 385 return; |
| 395 } | 386 } |
| 396 SpillRangeAsLastResort(range); | 387 SpillRangeAsLastResort(range); |
| 397 } | 388 } |
| 398 | 389 |
| 399 | 390 |
| 400 } // namespace compiler | 391 } // namespace compiler |
| 401 } // namespace internal | 392 } // namespace internal |
| 402 } // namespace v8 | 393 } // namespace v8 |
| OLD | NEW |