blob: 63aba88c2b21385a27623d42990fadcf643303f1 [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
David Brazdil809d70f2015-11-19 10:29:39 +000019#include "base/arena_containers.h"
20
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010021namespace art {
22
23void SsaDeadPhiElimination::Run() {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000024 MarkDeadPhis();
25 EliminateDeadPhis();
26}
27
28void SsaDeadPhiElimination::MarkDeadPhis() {
David Brazdil809d70f2015-11-19 10:29:39 +000029 // Phis are constructed live and should not be revived if previously marked
30 // dead. This algorithm temporarily breaks that invariant but we DCHECK that
31 // only phis which were initially live are revived.
32 ArenaSet<HPhi*> initially_live(graph_->GetArena()->Adapter());
33
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010034 // Add to the worklist phis referenced by non-phi instructions.
35 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
36 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080037 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
38 HPhi* phi = inst_it.Current()->AsPhi();
David Brazdil809d70f2015-11-19 10:29:39 +000039 if (phi->IsDead()) {
40 continue;
41 }
42
David Brazdild9510df2015-11-04 23:30:22 +000043 bool keep_alive = (graph_->IsDebuggable() && phi->HasEnvironmentUses());
44 if (!keep_alive) {
45 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
46 if (!use_it.Current()->GetUser()->IsPhi()) {
47 keep_alive = true;
48 break;
49 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010050 }
51 }
David Brazdil809d70f2015-11-19 10:29:39 +000052
David Brazdild9510df2015-11-04 23:30:22 +000053 if (keep_alive) {
David Brazdil809d70f2015-11-19 10:29:39 +000054 worklist_.push_back(phi);
55 } else {
56 phi->SetDead();
57 if (kIsDebugBuild) {
58 initially_live.insert(phi);
59 }
60 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010061 }
62 }
63
64 // Process the worklist by propagating liveness to phi inputs.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010065 while (!worklist_.empty()) {
66 HPhi* phi = worklist_.back();
67 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010068 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
David Brazdil809d70f2015-11-19 10:29:39 +000069 HPhi* input = it.Current()->AsPhi();
70 if (input != nullptr && input->IsDead()) {
71 // Input is a dead phi. Revive it and add to the worklist. We make sure
72 // that the phi was not dead initially (see definition of `initially_live`).
73 DCHECK(ContainsElement(initially_live, input));
74 input->SetLive();
75 worklist_.push_back(input);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010076 }
77 }
78 }
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000079}
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010080
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000081void SsaDeadPhiElimination::EliminateDeadPhis() {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010082 // Remove phis that are not live. Visit in post order so that phis
83 // that are not inputs of loop phis can be removed when they have
84 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010085 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
86 HBasicBlock* block = it.Current();
87 HInstruction* current = block->GetFirstPhi();
88 HInstruction* next = nullptr;
David Brazdil1abb4192015-02-17 18:33:36 +000089 HPhi* phi;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010090 while (current != nullptr) {
David Brazdil1abb4192015-02-17 18:33:36 +000091 phi = current->AsPhi();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010092 next = current->GetNext();
David Brazdil1abb4192015-02-17 18:33:36 +000093 if (phi->IsDead()) {
94 // Make sure the phi is only used by other dead phis.
95 if (kIsDebugBuild) {
96 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080097 use_it.Advance()) {
David Brazdil1abb4192015-02-17 18:33:36 +000098 HInstruction* user = use_it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +000099 DCHECK(user->IsLoopHeaderPhi());
100 DCHECK(user->AsPhi()->IsDead());
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100101 }
102 }
David Brazdil1abb4192015-02-17 18:33:36 +0000103 // Remove the phi from use lists of its inputs.
104 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
105 phi->RemoveAsUserOfInput(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100106 }
David Brazdil1abb4192015-02-17 18:33:36 +0000107 // Remove the phi from environments that use it.
108 for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
109 use_it.Advance()) {
110 HUseListNode<HEnvironment*>* user_node = use_it.Current();
111 HEnvironment* user = user_node->GetUser();
112 user->SetRawEnvAt(user_node->GetIndex(), nullptr);
113 }
114 // Delete it from the instruction list.
115 block->RemovePhi(phi, /*ensure_safety=*/ false);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100116 }
117 current = next;
118 }
119 }
120}
121
122void SsaRedundantPhiElimination::Run() {
David Brazdil77b022d2015-08-19 14:17:31 +0100123 // Add all phis in the worklist. Order does not matter for correctness, and
124 // neither will necessarily converge faster.
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100125 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
126 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800127 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100128 worklist_.push_back(inst_it.Current()->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100129 }
130 }
131
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100132 while (!worklist_.empty()) {
133 HPhi* phi = worklist_.back();
134 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100135
136 // If the phi has already been processed, continue.
137 if (!phi->IsInBlock()) {
138 continue;
139 }
140
David Brazdilffee3d32015-07-06 11:48:53 +0100141 if (phi->InputCount() == 0) {
David Brazdilffee3d32015-07-06 11:48:53 +0100142 DCHECK(phi->IsDead());
143 continue;
144 }
145
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100146 // Find if the inputs of the phi are the same instruction.
147 HInstruction* candidate = phi->InputAt(0);
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100148 // A loop phi cannot have itself as the first phi. Note that this
149 // check relies on our simplification pass ensuring the pre-header
150 // block is first in the list of predecessors of the loop header.
Roland Levillain6b879dd2014-09-22 17:13:44 +0100151 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100152 DCHECK_NE(phi, candidate);
153
154 for (size_t i = 1; i < phi->InputCount(); ++i) {
155 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100156 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100157 // elimination.
158 if (input != candidate && input != phi) {
159 candidate = nullptr;
160 break;
161 }
162 }
163
164 // If the inputs are not the same, continue.
165 if (candidate == nullptr) {
166 continue;
167 }
168
David Brazdilffee3d32015-07-06 11:48:53 +0100169 // The candidate may not dominate a phi in a catch block.
170 if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) {
171 continue;
172 }
173
David Brazdil77b022d2015-08-19 14:17:31 +0100174 // Because we're updating the users of this phi, we may have new candidates
175 // for elimination. Add phis that use this phi to the worklist.
176 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) {
177 HUseListNode<HInstruction*>* current = it.Current();
178 HInstruction* user = current->GetUser();
179 if (user->IsPhi()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100180 worklist_.push_back(user->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100181 }
182 }
David Brazdil77b022d2015-08-19 14:17:31 +0100183
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100184 phi->ReplaceWith(candidate);
185 phi->GetBlock()->RemovePhi(phi);
186 }
187}
188
189} // namespace art