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