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