ssa_phi_elimination.cc revision d6138ef1ea13d07ae555542f8898b30d89e9ac9a
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_.Add(phi); 39 phi->SetLive(); 40 break; 41 } 42 } 43 } 44 } 45 46 // Process the worklist by propagating liveness to phi inputs. 47 while (!worklist_.IsEmpty()) { 48 HPhi* phi = worklist_.Pop(); 49 for (HInputIterator it(phi); !it.Done(); it.Advance()) { 50 HInstruction* input = it.Current(); 51 if (input->IsPhi() && input->AsPhi()->IsDead()) { 52 worklist_.Add(input->AsPhi()); 53 input->AsPhi()->SetLive(); 54 } 55 } 56 } 57} 58 59void SsaDeadPhiElimination::EliminateDeadPhis() { 60 // Remove phis that are not live. Visit in post order so that phis 61 // that are not inputs of loop phis can be removed when they have 62 // no users left (dead phis might use dead phis). 63 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 64 HBasicBlock* block = it.Current(); 65 HInstruction* current = block->GetFirstPhi(); 66 HInstruction* next = nullptr; 67 while (current != nullptr) { 68 next = current->GetNext(); 69 if (current->AsPhi()->IsDead()) { 70 if (current->HasUses()) { 71 for (HUseIterator<HInstruction*> use_it(current->GetUses()); !use_it.Done(); 72 use_it.Advance()) { 73 HUseListNode<HInstruction*>* user_node = use_it.Current(); 74 HInstruction* user = user_node->GetUser(); 75 DCHECK(user->IsLoopHeaderPhi()) << user->GetId(); 76 DCHECK(user->AsPhi()->IsDead()) << user->GetId(); 77 // Just put itself as an input. The phi will be removed in this loop anyway. 78 user->SetRawInputAt(user_node->GetIndex(), user); 79 current->RemoveUser(user, user_node->GetIndex()); 80 } 81 } 82 if (current->HasEnvironmentUses()) { 83 for (HUseIterator<HEnvironment*> use_it(current->GetEnvUses()); !use_it.Done(); 84 use_it.Advance()) { 85 HUseListNode<HEnvironment*>* user_node = use_it.Current(); 86 HEnvironment* user = user_node->GetUser(); 87 user->SetRawEnvAt(user_node->GetIndex(), nullptr); 88 current->RemoveEnvironmentUser(user_node); 89 } 90 } 91 block->RemovePhi(current->AsPhi()); 92 } 93 current = next; 94 } 95 } 96} 97 98void SsaRedundantPhiElimination::Run() { 99 // Add all phis in the worklist. 100 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 101 HBasicBlock* block = it.Current(); 102 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) { 103 worklist_.Add(inst_it.Current()->AsPhi()); 104 } 105 } 106 107 while (!worklist_.IsEmpty()) { 108 HPhi* phi = worklist_.Pop(); 109 110 // If the phi has already been processed, continue. 111 if (!phi->IsInBlock()) { 112 continue; 113 } 114 115 // Find if the inputs of the phi are the same instruction. 116 HInstruction* candidate = phi->InputAt(0); 117 // A loop phi cannot have itself as the first phi. Note that this 118 // check relies on our simplification pass ensuring the pre-header 119 // block is first in the list of predecessors of the loop header. 120 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor()); 121 DCHECK_NE(phi, candidate); 122 123 for (size_t i = 1; i < phi->InputCount(); ++i) { 124 HInstruction* input = phi->InputAt(i); 125 // For a loop phi, if the input is the phi, the phi is still candidate for 126 // elimination. 127 if (input != candidate && input != phi) { 128 candidate = nullptr; 129 break; 130 } 131 } 132 133 // If the inputs are not the same, continue. 134 if (candidate == nullptr) { 135 continue; 136 } 137 138 if (phi->IsInLoop()) { 139 // Because we're updating the users of this phi, we may have new 140 // phis candidate for elimination if this phi is in a loop. Add phis that 141 // used this phi to the worklist. 142 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) { 143 HUseListNode<HInstruction*>* current = it.Current(); 144 HInstruction* user = current->GetUser(); 145 if (user->IsPhi()) { 146 worklist_.Add(user->AsPhi()); 147 } 148 } 149 } 150 phi->ReplaceWith(candidate); 151 phi->GetBlock()->RemovePhi(phi); 152 } 153} 154 155} // namespace art 156