ssa_phi_elimination.cc revision 2aaa4b5532d30c4e65d8892b556400bb61f9dc8c
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ssa_phi_elimination.h" 18 19namespace art { 20 21void SsaDeadPhiElimination::Run() { 22 MarkDeadPhis(); 23 EliminateDeadPhis(); 24} 25 26void SsaDeadPhiElimination::MarkDeadPhis() { 27 // Add to the worklist phis referenced by non-phi instructions. 28 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 29 HBasicBlock* block = it.Current(); 30 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) { 31 HPhi* phi = inst_it.Current()->AsPhi(); 32 // Set dead ahead of running through uses. The phi may have no use. 33 phi->SetDead(); 34 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) { 35 HUseListNode<HInstruction*>* current = use_it.Current(); 36 HInstruction* user = current->GetUser(); 37 if (!user->IsPhi()) { 38 worklist_.push_back(phi); 39 phi->SetLive(); 40 break; 41 } 42 } 43 } 44 } 45 46 // Process the worklist by propagating liveness to phi inputs. 47 while (!worklist_.empty()) { 48 HPhi* phi = worklist_.back(); 49 worklist_.pop_back(); 50 for (HInputIterator it(phi); !it.Done(); it.Advance()) { 51 HInstruction* input = it.Current(); 52 if (input->IsPhi() && input->AsPhi()->IsDead()) { 53 worklist_.push_back(input->AsPhi()); 54 input->AsPhi()->SetLive(); 55 } 56 } 57 } 58} 59 60void SsaDeadPhiElimination::EliminateDeadPhis() { 61 // Remove phis that are not live. Visit in post order so that phis 62 // that are not inputs of loop phis can be removed when they have 63 // no users left (dead phis might use dead phis). 64 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 65 HBasicBlock* block = it.Current(); 66 HInstruction* current = block->GetFirstPhi(); 67 HInstruction* next = nullptr; 68 HPhi* phi; 69 while (current != nullptr) { 70 phi = current->AsPhi(); 71 next = current->GetNext(); 72 if (phi->IsDead()) { 73 // Make sure the phi is only used by other dead phis. 74 if (kIsDebugBuild) { 75 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); 76 use_it.Advance()) { 77 HInstruction* user = use_it.Current()->GetUser(); 78 DCHECK(user->IsLoopHeaderPhi()) << user->GetId(); 79 DCHECK(user->AsPhi()->IsDead()) << user->GetId(); 80 } 81 } 82 // Remove the phi from use lists of its inputs. 83 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { 84 phi->RemoveAsUserOfInput(i); 85 } 86 // Remove the phi from environments that use it. 87 for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done(); 88 use_it.Advance()) { 89 HUseListNode<HEnvironment*>* user_node = use_it.Current(); 90 HEnvironment* user = user_node->GetUser(); 91 user->SetRawEnvAt(user_node->GetIndex(), nullptr); 92 } 93 // Delete it from the instruction list. 94 block->RemovePhi(phi, /*ensure_safety=*/ false); 95 } 96 current = next; 97 } 98 } 99} 100 101void SsaRedundantPhiElimination::Run() { 102 // Add all phis in the worklist. Order does not matter for correctness, and 103 // neither will necessarily converge faster. 104 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 105 HBasicBlock* block = it.Current(); 106 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) { 107 worklist_.push_back(inst_it.Current()->AsPhi()); 108 } 109 } 110 111 while (!worklist_.empty()) { 112 HPhi* phi = worklist_.back(); 113 worklist_.pop_back(); 114 115 // If the phi has already been processed, continue. 116 if (!phi->IsInBlock()) { 117 continue; 118 } 119 120 if (phi->InputCount() == 0) { 121 DCHECK(phi->IsCatchPhi()); 122 DCHECK(phi->IsDead()); 123 continue; 124 } 125 126 // Find if the inputs of the phi are the same instruction. 127 HInstruction* candidate = phi->InputAt(0); 128 // A loop phi cannot have itself as the first phi. Note that this 129 // check relies on our simplification pass ensuring the pre-header 130 // block is first in the list of predecessors of the loop header. 131 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor()); 132 DCHECK_NE(phi, candidate); 133 134 for (size_t i = 1; i < phi->InputCount(); ++i) { 135 HInstruction* input = phi->InputAt(i); 136 // For a loop phi, if the input is the phi, the phi is still candidate for 137 // elimination. 138 if (input != candidate && input != phi) { 139 candidate = nullptr; 140 break; 141 } 142 } 143 144 // If the inputs are not the same, continue. 145 if (candidate == nullptr) { 146 continue; 147 } 148 149 // The candidate may not dominate a phi in a catch block. 150 if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) { 151 continue; 152 } 153 154 // Because we're updating the users of this phi, we may have new candidates 155 // for elimination. Add phis that use this phi to the worklist. 156 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) { 157 HUseListNode<HInstruction*>* current = it.Current(); 158 HInstruction* user = current->GetUser(); 159 if (user->IsPhi()) { 160 worklist_.push_back(user->AsPhi()); 161 } 162 } 163 164 phi->ReplaceWith(candidate); 165 phi->GetBlock()->RemovePhi(phi); 166 } 167} 168 169} // namespace art 170