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