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