Chromium Code Reviews| 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 { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 33 DCHECK(pos.IsStart() || pos.IsGapPosition() || | 33 DCHECK(pos.IsStart() || pos.IsGapPosition() || |
| 34 (data->code() | 34 (data->code() |
| 35 ->GetInstructionBlock(pos.ToInstructionIndex()) | 35 ->GetInstructionBlock(pos.ToInstructionIndex()) |
| 36 ->last_instruction_index() != pos.ToInstructionIndex())); | 36 ->last_instruction_index() != pos.ToInstructionIndex())); |
| 37 LiveRange* result = data->NewChildRangeFor(range); | 37 LiveRange* result = data->NewChildRangeFor(range); |
| 38 range->SplitAt(pos, result, data->allocation_zone()); | 38 range->SplitAt(pos, result, data->allocation_zone()); |
| 39 return result; | 39 return result; |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 void SpillToStackSlot(LiveRange* range, RegisterAllocationData* data) { | |
| 44 DCHECK(!range->spilled()); | |
| 45 TRACE("Spilling live range %d\n", range->id()); | |
| 46 auto first = range->TopLevel(); | |
| 47 if (first->HasNoSpillType()) { | |
| 48 data->AssignSpillRangeToLiveRange(first); | |
| 49 } | |
| 50 range->Spill(); | |
| 51 } | |
| 52 | |
| 53 | |
| 43 // TODO(mtrofin): explain why splitting in gap START is always OK. | 54 // TODO(mtrofin): explain why splitting in gap START is always OK. |
| 44 LifetimePosition GetSplitPositionForInstruction(const LiveRange* range, | 55 LifetimePosition GetSplitPositionForInstruction(const LiveRange* range, |
| 45 const InstructionSequence* code, | 56 const InstructionSequence* code, |
| 46 int instruction_index) { | 57 int instruction_index) { |
| 47 LifetimePosition ret = LifetimePosition::Invalid(); | 58 LifetimePosition ret = LifetimePosition::Invalid(); |
| 48 | 59 |
| 49 ret = LifetimePosition::GapFromInstructionIndex(instruction_index); | 60 ret = LifetimePosition::GapFromInstructionIndex(instruction_index); |
| 50 if (range->Start() >= ret || ret >= range->End()) { | 61 if (range->Start() >= ret || ret >= range->End()) { |
| 51 return LifetimePosition::Invalid(); | 62 return LifetimePosition::Invalid(); |
| 52 } | 63 } |
| 53 return ret; | 64 return ret; |
| 54 } | 65 } |
| 55 | 66 |
| 56 | 67 |
| 57 int GetFirstGapIndex(const UseInterval* interval) { | 68 int GetFirstGapIndex(const UseInterval* interval) { |
| 58 LifetimePosition start = interval->start(); | 69 LifetimePosition start = interval->start(); |
| 59 int ret = start.ToInstructionIndex(); | 70 int ret = start.ToInstructionIndex(); |
| 60 return ret; | 71 return ret; |
| 61 } | 72 } |
| 62 | 73 |
| 63 | 74 |
| 64 int GetLastGapIndex(const UseInterval* interval) { | 75 int GetLastGapIndex(const UseInterval* interval) { |
| 65 LifetimePosition end = interval->end(); | 76 LifetimePosition end = interval->end(); |
| 66 return end.ToInstructionIndex(); | 77 return end.ToInstructionIndex(); |
| 67 } | 78 } |
| 68 | 79 |
| 69 | 80 |
| 81 // Split before a call that requires parameters on stack, and spill until | |
| 82 // the first position requiring the parameter back in a register. | |
| 83 bool TrySplittingAroundCalls(LiveRange* range, RegisterAllocationData* data, | |
| 84 AllocationScheduler* scheduler) { | |
| 85 for (auto use = range->first_pos(); use != nullptr; use = use->next()) { | |
| 86 int index = use->pos().ToInstructionIndex(); | |
| 87 auto instr = data->code()->InstructionAt(index); | |
|
Jarin
2015/07/22 12:59:35
Expand 'auto', please.
| |
| 88 if (!instr->IsCall()) continue; | |
|
Jarin
2015/07/22 12:59:35
This does not really work because live ranges can
Mircea Trofin
2015/07/23 02:20:04
I see. OK, so we need to iterate over each instruc
| |
| 89 if (use->type() != UsePositionType::kRequiresSlot) continue; | |
| 90 | |
| 91 LifetimePosition at_call = | |
| 92 GetSplitPositionForInstruction(range, data->code(), index); | |
| 93 if (!at_call.IsValid()) continue; | |
| 94 LiveRange* call_part = Split(range, data, at_call); | |
| 95 scheduler->Schedule(range); | |
| 96 | |
| 97 use = use->next(); | |
| 98 LifetimePosition next_split = LifetimePosition::Invalid(); | |
| 99 for (; use != nullptr && !next_split.IsValid(); use = use->next()) { | |
| 100 next_split = GetSplitPositionForInstruction( | |
| 101 call_part, data->code(), use->pos().ToInstructionIndex()); | |
| 102 } | |
|
Jarin
2015/07/22 12:59:35
Why do we have the loop here? Cannot it happen tha
Mircea Trofin
2015/07/23 02:20:04
If we fall on to a different block, that's fine, c
| |
| 103 if (next_split.IsValid()) { | |
| 104 LiveRange* keep = Split(call_part, data, next_split); | |
| 105 scheduler->Schedule(keep); | |
| 106 } | |
| 107 | |
| 108 SpillToStackSlot(call_part, data); | |
| 109 return true; | |
| 110 } | |
| 111 return false; | |
| 112 } | |
| 113 | |
| 114 | |
| 70 // Basic heuristic for advancing the algorithm, if any other splitting heuristic | 115 // Basic heuristic for advancing the algorithm, if any other splitting heuristic |
| 71 // failed. | 116 // failed. |
| 72 LifetimePosition GetLastResortSplitPosition(const LiveRange* range, | 117 LifetimePosition GetLastResortSplitPosition(const LiveRange* range, |
| 73 const InstructionSequence* code) { | 118 const InstructionSequence* code) { |
| 74 if (range->first_interval()->next() != nullptr) { | 119 if (range->first_interval()->next() != nullptr) { |
| 75 return range->first_interval()->next()->start(); | 120 return range->first_interval()->next()->start(); |
| 76 } | 121 } |
| 77 | 122 |
| 78 UseInterval* interval = range->first_interval(); | 123 UseInterval* interval = range->first_interval(); |
| 79 int first = GetFirstGapIndex(interval); | 124 int first = GetFirstGapIndex(interval); |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 LifetimePosition start = range->Start(); | 282 LifetimePosition start = range->Start(); |
| 238 TRACE("Live range %d is defined by a spill operand.\n", range->id()); | 283 TRACE("Live range %d is defined by a spill operand.\n", range->id()); |
| 239 auto next_pos = start; | 284 auto next_pos = start; |
| 240 if (next_pos.IsGapPosition()) { | 285 if (next_pos.IsGapPosition()) { |
| 241 next_pos = next_pos.NextStart(); | 286 next_pos = next_pos.NextStart(); |
| 242 } | 287 } |
| 243 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | 288 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
| 244 // If the range already has a spill operand and it doesn't need a | 289 // If the range already has a spill operand and it doesn't need a |
| 245 // register immediately, split it and spill the first part of the range. | 290 // register immediately, split it and spill the first part of the range. |
| 246 if (pos == nullptr) { | 291 if (pos == nullptr) { |
| 247 Spill(range); | 292 SpillToStackSlot(range, data()); |
| 248 } else if (pos->pos() > range->Start().NextStart()) { | 293 } else if (pos->pos() > range->Start().NextStart()) { |
| 249 // Do not spill live range eagerly if use position that can benefit from | 294 // Do not spill live range eagerly if use position that can benefit from |
| 250 // the register is too close to the start of live range. | 295 // the register is too close to the start of live range. |
| 251 auto split_pos = pos->pos(); | 296 auto split_pos = GetSplitPositionForInstruction( |
| 252 if (data()->IsBlockBoundary(split_pos.Start())) { | 297 range, code(), pos->pos().ToInstructionIndex()); |
| 253 split_pos = split_pos.Start(); | 298 if (split_pos.IsValid()) { |
| 254 } else { | 299 Split(range, data(), split_pos); |
| 255 split_pos = split_pos.PrevStart().End(); | 300 SpillToStackSlot(range, data()); |
| 256 } | 301 } |
| 257 Split(range, data(), split_pos); | |
| 258 Spill(range); | |
| 259 } | 302 } |
| 260 } | 303 } |
| 261 } | 304 } |
| 262 | 305 |
| 263 | 306 |
| 264 void GreedyAllocator::AllocateRegisters() { | 307 void GreedyAllocator::AllocateRegisters() { |
| 265 CHECK(scheduler().empty()); | 308 CHECK(scheduler().empty()); |
| 266 CHECK(allocations_.empty()); | 309 CHECK(allocations_.empty()); |
| 267 | 310 |
| 268 TRACE("Begin allocating function %s with the Greedy Allocator\n", | 311 TRACE("Begin allocating function %s with the Greedy Allocator\n", |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 } | 362 } |
| 320 range->set_weight(use_count / static_cast<float>(range->GetSize())); | 363 range->set_weight(use_count / static_cast<float>(range->GetSize())); |
| 321 } | 364 } |
| 322 | 365 |
| 323 | 366 |
| 324 void GreedyAllocator::SpillRangeAsLastResort(LiveRange* range) { | 367 void GreedyAllocator::SpillRangeAsLastResort(LiveRange* range) { |
| 325 LifetimePosition start = range->Start(); | 368 LifetimePosition start = range->Start(); |
| 326 CHECK(range->CanBeSpilled(start)); | 369 CHECK(range->CanBeSpilled(start)); |
| 327 | 370 |
| 328 DCHECK(range->NextRegisterPosition(start) == nullptr); | 371 DCHECK(range->NextRegisterPosition(start) == nullptr); |
| 329 Spill(range); | 372 SpillToStackSlot(range, data()); |
| 330 } | 373 } |
| 331 | 374 |
| 332 | 375 |
| 333 void GreedyAllocator::SplitOrSpillBlockedRange(LiveRange* range) { | 376 void GreedyAllocator::SplitOrSpillBlockedRange(LiveRange* range) { |
| 377 if (TrySplittingAroundCalls(range, data(), &scheduler())) return; | |
| 378 | |
| 334 // TODO(mtrofin): replace the call below with the entry point selecting | 379 // TODO(mtrofin): replace the call below with the entry point selecting |
| 335 // heuristics, once they exist, out of which GLRSP is the last one. | 380 // heuristics, once they exist, out of which GLRSP is the last one. |
| 336 auto pos = GetLastResortSplitPosition(range, code()); | 381 auto pos = GetLastResortSplitPosition(range, code()); |
| 337 if (pos.IsValid()) { | 382 if (pos.IsValid()) { |
| 338 LiveRange* tail = Split(range, data(), pos); | 383 LiveRange* tail = Split(range, data(), pos); |
| 339 DCHECK(tail != range); | 384 DCHECK(tail != range); |
| 340 scheduler().Schedule(tail); | 385 scheduler().Schedule(tail); |
| 341 scheduler().Schedule(range); | 386 scheduler().Schedule(range); |
| 342 return; | 387 return; |
| 343 } | 388 } |
| 344 SpillRangeAsLastResort(range); | 389 SpillRangeAsLastResort(range); |
| 345 } | 390 } |
| 346 | 391 |
| 347 | 392 |
| 348 } // namespace compiler | 393 } // namespace compiler |
| 349 } // namespace internal | 394 } // namespace internal |
| 350 } // namespace v8 | 395 } // namespace v8 |
| OLD | NEW |