blob: c6993f3acab624ca97af343e8912f0a141f61331 [file] [log] [blame]
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +01001/*
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() {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000022 MarkDeadPhis();
23 EliminateDeadPhis();
24}
25
26void SsaDeadPhiElimination::MarkDeadPhis() {
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010027 // Add to the worklist phis referenced by non-phi instructions.
28 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
29 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080030 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
31 HPhi* phi = inst_it.Current()->AsPhi();
David Brazdil1749e2c2015-09-28 13:49:59 +010032 if (phi->IsDead()) {
33 // Phis are constructed live so this one was proven conflicting.
34 continue;
35 }
36
37 bool is_live = false;
38 if (graph_->IsDebuggable() && phi->HasEnvironmentUses()) {
39 is_live = true;
40 } else {
41 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
42 if (!use_it.Current()->GetUser()->IsPhi()) {
43 is_live = true;
44 break;
45 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010046 }
47 }
David Brazdil1749e2c2015-09-28 13:49:59 +010048
49 if (is_live) {
50 worklist_.push_back(phi);
51 } else {
52 phi->SetDead();
53 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010054 }
55 }
56
57 // Process the worklist by propagating liveness to phi inputs.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010058 while (!worklist_.empty()) {
59 HPhi* phi = worklist_.back();
60 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010061 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
62 HInstruction* input = it.Current();
63 if (input->IsPhi() && input->AsPhi()->IsDead()) {
David Brazdil1749e2c2015-09-28 13:49:59 +010064 // If we revive a phi it must have been live at the beginning of
65 // the pass but had no non-phi uses of its own.
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010066 input->AsPhi()->SetLive();
David Brazdil1749e2c2015-09-28 13:49:59 +010067 worklist_.push_back(input->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010068 }
69 }
70 }
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000071}
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010072
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000073void SsaDeadPhiElimination::EliminateDeadPhis() {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010074 // Remove phis that are not live. Visit in post order so that phis
75 // that are not inputs of loop phis can be removed when they have
76 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010077 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
78 HBasicBlock* block = it.Current();
79 HInstruction* current = block->GetFirstPhi();
80 HInstruction* next = nullptr;
David Brazdil1abb4192015-02-17 18:33:36 +000081 HPhi* phi;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010082 while (current != nullptr) {
David Brazdil1abb4192015-02-17 18:33:36 +000083 phi = current->AsPhi();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010084 next = current->GetNext();
David Brazdil1abb4192015-02-17 18:33:36 +000085 if (phi->IsDead()) {
86 // Make sure the phi is only used by other dead phis.
87 if (kIsDebugBuild) {
88 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080089 use_it.Advance()) {
David Brazdil1abb4192015-02-17 18:33:36 +000090 HInstruction* user = use_it.Current()->GetUser();
David Brazdil1749e2c2015-09-28 13:49:59 +010091 DCHECK(user->IsPhi());
92 DCHECK(user->AsPhi()->IsDead());
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010093 }
94 }
David Brazdil1abb4192015-02-17 18:33:36 +000095 // Remove the phi from use lists of its inputs.
96 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
97 phi->RemoveAsUserOfInput(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010098 }
David Brazdil1abb4192015-02-17 18:33:36 +000099 // Remove the phi from environments that use it.
100 for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
101 use_it.Advance()) {
102 HUseListNode<HEnvironment*>* user_node = use_it.Current();
103 HEnvironment* user = user_node->GetUser();
104 user->SetRawEnvAt(user_node->GetIndex(), nullptr);
105 }
106 // Delete it from the instruction list.
107 block->RemovePhi(phi, /*ensure_safety=*/ false);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100108 }
109 current = next;
110 }
111 }
112}
113
114void SsaRedundantPhiElimination::Run() {
David Brazdil77b022d2015-08-19 14:17:31 +0100115 // Add all phis in the worklist. Order does not matter for correctness, and
116 // neither will necessarily converge faster.
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100117 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
118 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800119 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100120 worklist_.push_back(inst_it.Current()->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100121 }
122 }
123
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100124 while (!worklist_.empty()) {
125 HPhi* phi = worklist_.back();
126 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100127
128 // If the phi has already been processed, continue.
129 if (!phi->IsInBlock()) {
130 continue;
131 }
132
David Brazdilffee3d32015-07-06 11:48:53 +0100133 if (phi->InputCount() == 0) {
134 DCHECK(phi->IsCatchPhi());
135 DCHECK(phi->IsDead());
136 continue;
137 }
138
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100139 // Find if the inputs of the phi are the same instruction.
140 HInstruction* candidate = phi->InputAt(0);
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100141 // A loop phi cannot have itself as the first phi. Note that this
142 // check relies on our simplification pass ensuring the pre-header
143 // block is first in the list of predecessors of the loop header.
Roland Levillain6b879dd2014-09-22 17:13:44 +0100144 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100145 DCHECK_NE(phi, candidate);
146
147 for (size_t i = 1; i < phi->InputCount(); ++i) {
148 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100149 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100150 // elimination.
151 if (input != candidate && input != phi) {
152 candidate = nullptr;
153 break;
154 }
155 }
156
157 // If the inputs are not the same, continue.
158 if (candidate == nullptr) {
159 continue;
160 }
161
David Brazdilffee3d32015-07-06 11:48:53 +0100162 // The candidate may not dominate a phi in a catch block.
163 if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) {
164 continue;
165 }
166
David Brazdil77b022d2015-08-19 14:17:31 +0100167 // Because we're updating the users of this phi, we may have new candidates
168 // for elimination. Add phis that use this phi to the worklist.
169 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) {
170 HUseListNode<HInstruction*>* current = it.Current();
171 HInstruction* user = current->GetUser();
172 if (user->IsPhi()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100173 worklist_.push_back(user->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100174 }
175 }
David Brazdil77b022d2015-08-19 14:17:31 +0100176
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100177 phi->ReplaceWith(candidate);
178 phi->GetBlock()->RemovePhi(phi);
179 }
180}
181
182} // namespace art