| Index: src/compiler/greedy-allocator.cc
|
| diff --git a/src/compiler/greedy-allocator.cc b/src/compiler/greedy-allocator.cc
|
| index 444130aa1ea806e2647d7d375f4395384e6e5528..d6f48a2716e2be223b05c46c526dcbc4ca5a7a79 100644
|
| --- a/src/compiler/greedy-allocator.cc
|
| +++ b/src/compiler/greedy-allocator.cc
|
| @@ -390,9 +390,94 @@ void GreedyAllocator::SpillRangeAsLastResort(LiveRange* range) {
|
| }
|
|
|
|
|
| +LiveRange* GreedyAllocator::GetRemainderAfterSplittingAroundFirstCall(
|
| + LiveRange* range) {
|
| + LiveRange* ret = range;
|
| + for (UseInterval* interval = range->first_interval(); interval != nullptr;
|
| + interval = interval->next()) {
|
| + LifetimePosition start = interval->start();
|
| + LifetimePosition end = interval->end();
|
| + // If the interval starts at instruction end, then the first instruction
|
| + // in the interval is the next one.
|
| + int first_full_instruction = (start.IsGapPosition() || start.IsStart())
|
| + ? start.ToInstructionIndex()
|
| + : start.ToInstructionIndex() + 1;
|
| + // If the interval ends in a gap or at instruction start, then the last
|
| + // instruction is the previous one.
|
| + int last_full_instruction = (end.IsGapPosition() || end.IsStart())
|
| + ? end.ToInstructionIndex() - 1
|
| + : end.ToInstructionIndex();
|
| +
|
| + for (int instruction_index = first_full_instruction;
|
| + instruction_index <= last_full_instruction; ++instruction_index) {
|
| + if (!code()->InstructionAt(instruction_index)->IsCall()) continue;
|
| +
|
| + LifetimePosition before =
|
| + GetSplitPositionForInstruction(range, instruction_index);
|
| + LiveRange* second_part =
|
| + before.IsValid() ? Split(range, data(), before) : range;
|
| +
|
| + if (range != second_part) scheduler().Schedule(range);
|
| +
|
| + LifetimePosition after =
|
| + FindSplitPositionAfterCall(second_part, instruction_index);
|
| +
|
| + if (after.IsValid()) {
|
| + ret = Split(second_part, data(), after);
|
| + } else {
|
| + ret = nullptr;
|
| + }
|
| + Spill(second_part);
|
| + return ret;
|
| + }
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +
|
| +bool GreedyAllocator::TrySplitAroundCalls(LiveRange* range) {
|
| + bool modified = false;
|
| +
|
| + while (range != nullptr) {
|
| + LiveRange* remainder = GetRemainderAfterSplittingAroundFirstCall(range);
|
| + // If we performed no modification, we're done.
|
| + if (remainder == range) {
|
| + break;
|
| + }
|
| + // We performed a modification.
|
| + modified = true;
|
| + range = remainder;
|
| + }
|
| + // If we have a remainder and we made modifications, it means the remainder
|
| + // has no calls and we should schedule it for further processing. If we made
|
| + // no modifications, we will just return false, because we want the algorithm
|
| + // to make progress by trying some other heuristic.
|
| + if (modified && range != nullptr) {
|
| + DCHECK(!range->spilled());
|
| + DCHECK(!range->HasRegisterAssigned());
|
| + scheduler().Schedule(range);
|
| + }
|
| + return modified;
|
| +}
|
| +
|
| +
|
| +LifetimePosition GreedyAllocator::FindSplitPositionAfterCall(
|
| + const LiveRange* range, int call_index) {
|
| + LifetimePosition after_call =
|
| + Max(range->Start(),
|
| + LifetimePosition::GapFromInstructionIndex(call_index + 1));
|
| + UsePosition* next_use = range->NextRegisterPosition(after_call);
|
| + if (!next_use) return LifetimePosition::Invalid();
|
| +
|
| + LifetimePosition split_pos = FindOptimalSplitPos(after_call, next_use->pos());
|
| + split_pos =
|
| + GetSplitPositionForInstruction(range, split_pos.ToInstructionIndex());
|
| + return split_pos;
|
| +}
|
| +
|
| +
|
| void GreedyAllocator::SplitOrSpillBlockedRange(LiveRange* range) {
|
| - // TODO(mtrofin): replace the call below with the entry point selecting
|
| - // heuristics, once they exist, out of which GLRSP is the last one.
|
| + if (TrySplitAroundCalls(range)) return;
|
| auto pos = GetLastResortSplitPosition(range, code());
|
| if (pos.IsValid()) {
|
| LiveRange* tail = Split(range, data(), pos);
|
|
|