diff options
| author | 2017-06-22 11:56:01 +0100 | |
|---|---|---|
| committer | 2017-06-22 17:51:38 +0000 | |
| commit | 565cd4e9861d44c1b24b4b2054446edf3118cbba (patch) | |
| tree | 99e6abb0184683a01b76b2aa366ab5def16159d1 /compiler/optimizing/loop_optimization.cc | |
| parent | cd3d23c17b00ddc9768b3c60886d92a93f2d331a (diff) | |
Fix loop optimization in the presence of environment uses.
We should not remove instructions that have deoptimize as
users, or that have environment uses in a debuggable setup.
bug: 62536525
bug: 33775412
Test: 656-loop-deopt
(cherry picked from commit 1a0a519c82044ec3e6d3910ff0602b11292de47a)
Change-Id: I213dc85ac644619b041f0fa408e112352efcef2d
Diffstat (limited to 'compiler/optimizing/loop_optimization.cc')
| -rw-r--r-- | compiler/optimizing/loop_optimization.cc | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 8f52812007..d5e105951b 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -344,6 +344,23 @@ void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) { // Optimization. // +bool HLoopOptimization::CanRemoveCycle() { + for (HInstruction* i : *iset_) { + // We can never remove instructions that have environment + // uses when we compile 'debuggable'. + if (i->HasEnvironmentUses() && graph_->IsDebuggable()) { + return false; + } + // A deoptimization should never have an environment input removed. + for (const HUseListNode<HEnvironment*>& use : i->GetEnvUses()) { + if (use.GetUser()->GetHolder()->IsDeoptimize()) { + return false; + } + } + } + return true; +} + void HLoopOptimization::SimplifyInduction(LoopNode* node) { HBasicBlock* header = node->loop_info->GetHeader(); HBasicBlock* preheader = node->loop_info->GetPreHeader(); @@ -357,10 +374,15 @@ void HLoopOptimization::SimplifyInduction(LoopNode* node) { iset_->clear(); // prepare phi induction if (TrySetPhiInduction(phi, /*restrict_uses*/ true) && TryAssignLastValue(node->loop_info, phi, preheader, /*collect_loop_uses*/ false)) { - for (HInstruction* i : *iset_) { - RemoveFromCycle(i); + // Note that it's ok to have replaced uses after the loop with the last value, without + // being able to remove the cycle. Environment uses (which are the reason we may not be + // able to remove the cycle) within the loop will still hold the right value. + if (CanRemoveCycle()) { + for (HInstruction* i : *iset_) { + RemoveFromCycle(i); + } + simplified_ = true; } - simplified_ = true; } } } @@ -1350,11 +1372,10 @@ bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info, return true; } -bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction, HBasicBlock* block) { - // Try to replace outside uses with the last value. Environment uses can consume this - // value too, since any first true use is outside the loop (although this may imply - // that de-opting may look "ahead" a bit on the phi value). If there are only environment - // uses, the value is dropped altogether, since the computations have no effect. +bool HLoopOptimization::TryReplaceWithLastValue(HLoopInformation* loop_info, + HInstruction* instruction, + HBasicBlock* block) { + // Try to replace outside uses with the last value. if (induction_range_.CanGenerateLastValue(instruction)) { HInstruction* replacement = induction_range_.GenerateLastValue(instruction, graph_, block); const HUseList<HInstruction*>& uses = instruction->GetUses(); @@ -1363,6 +1384,11 @@ bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction, HBasi size_t index = it->GetIndex(); ++it; // increment before replacing if (iset_->find(user) == iset_->end()) { // not excluded? + if (kIsDebugBuild) { + // We have checked earlier in 'IsOnlyUsedAfterLoop' that the use is after the loop. + HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation(); + CHECK(other_loop_info == nullptr || !other_loop_info->IsIn(*loop_info)); + } user->ReplaceInput(replacement, index); induction_range_.Replace(user, instruction, replacement); // update induction } @@ -1373,9 +1399,13 @@ bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction, HBasi size_t index = it->GetIndex(); ++it; // increment before replacing if (iset_->find(user->GetHolder()) == iset_->end()) { // not excluded? - user->RemoveAsUserOfInput(index); - user->SetRawEnvAt(index, replacement); - replacement->AddEnvUseAt(user, index); + HLoopInformation* other_loop_info = user->GetHolder()->GetBlock()->GetLoopInformation(); + // Only update environment uses after the loop. + if (other_loop_info == nullptr || !other_loop_info->IsIn(*loop_info)) { + user->RemoveAsUserOfInput(index); + user->SetRawEnvAt(index, replacement); + replacement->AddEnvUseAt(user, index); + } } } induction_simplication_count_++; @@ -1394,7 +1424,7 @@ bool HLoopOptimization::TryAssignLastValue(HLoopInformation* loop_info, int32_t use_count = 0; return IsOnlyUsedAfterLoop(loop_info, instruction, collect_loop_uses, &use_count) && (use_count == 0 || - (!IsEarlyExit(loop_info) && TryReplaceWithLastValue(instruction, block))); + (!IsEarlyExit(loop_info) && TryReplaceWithLastValue(loop_info, instruction, block))); } void HLoopOptimization::RemoveDeadInstructions(const HInstructionList& list) { |