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 
19 namespace art {
20 
Run()21 void SsaDeadPhiElimination::Run() {
22   MarkDeadPhis();
23   EliminateDeadPhis();
24 }
25 
MarkDeadPhis()26 void 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 
EliminateDeadPhis()59 void 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     HPhi* phi;
68     while (current != nullptr) {
69       phi = current->AsPhi();
70       next = current->GetNext();
71       if (phi->IsDead()) {
72         // Make sure the phi is only used by other dead phis.
73         if (kIsDebugBuild) {
74           for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
75                use_it.Advance()) {
76             HInstruction* user = use_it.Current()->GetUser();
77             DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
78             DCHECK(user->AsPhi()->IsDead()) << user->GetId();
79           }
80         }
81         // Remove the phi from use lists of its inputs.
82         for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
83           phi->RemoveAsUserOfInput(i);
84         }
85         // Remove the phi from environments that use it.
86         for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
87              use_it.Advance()) {
88           HUseListNode<HEnvironment*>* user_node = use_it.Current();
89           HEnvironment* user = user_node->GetUser();
90           user->SetRawEnvAt(user_node->GetIndex(), nullptr);
91         }
92         // Delete it from the instruction list.
93         block->RemovePhi(phi, /*ensure_safety=*/ false);
94       }
95       current = next;
96     }
97   }
98 }
99 
Run()100 void SsaRedundantPhiElimination::Run() {
101   // Add all phis in the worklist.
102   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
103     HBasicBlock* block = it.Current();
104     for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
105       worklist_.Add(inst_it.Current()->AsPhi());
106     }
107   }
108 
109   while (!worklist_.IsEmpty()) {
110     HPhi* phi = worklist_.Pop();
111 
112     // If the phi has already been processed, continue.
113     if (!phi->IsInBlock()) {
114       continue;
115     }
116 
117     // Find if the inputs of the phi are the same instruction.
118     HInstruction* candidate = phi->InputAt(0);
119     // A loop phi cannot have itself as the first phi. Note that this
120     // check relies on our simplification pass ensuring the pre-header
121     // block is first in the list of predecessors of the loop header.
122     DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
123     DCHECK_NE(phi, candidate);
124 
125     for (size_t i = 1; i < phi->InputCount(); ++i) {
126       HInstruction* input = phi->InputAt(i);
127       // For a loop phi, if the input is the phi, the phi is still candidate for
128       // elimination.
129       if (input != candidate && input != phi) {
130         candidate = nullptr;
131         break;
132       }
133     }
134 
135     // If the inputs are not the same, continue.
136     if (candidate == nullptr) {
137       continue;
138     }
139 
140     if (phi->IsInLoop()) {
141       // Because we're updating the users of this phi, we may have new
142       // phis candidate for elimination if this phi is in a loop. Add phis that
143       // used this phi to the worklist.
144       for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) {
145         HUseListNode<HInstruction*>* current = it.Current();
146         HInstruction* user = current->GetUser();
147         if (user->IsPhi()) {
148           worklist_.Add(user->AsPhi());
149         }
150       }
151     }
152     phi->ReplaceWith(candidate);
153     phi->GetBlock()->RemovePhi(phi);
154   }
155 }
156 
157 }  // namespace art
158