blob: a3219dcc38b58e01702510aa1e17ba7ffb3e9dda [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
Alex Light68289a52015-12-15 17:30:30 -080043 bool has_non_phi_use = false;
44 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
45 if (!use_it.Current()->GetUser()->IsPhi()) {
46 has_non_phi_use = true;
47 break;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010048 }
49 }
David Brazdil809d70f2015-11-19 10:29:39 +000050
Alex Light68289a52015-12-15 17:30:30 -080051 if (has_non_phi_use) {
David Brazdil809d70f2015-11-19 10:29:39 +000052 worklist_.push_back(phi);
53 } else {
54 phi->SetDead();
55 if (kIsDebugBuild) {
56 initially_live.insert(phi);
57 }
58 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010059 }
60 }
61
62 // Process the worklist by propagating liveness to phi inputs.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010063 while (!worklist_.empty()) {
64 HPhi* phi = worklist_.back();
65 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010066 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
David Brazdil809d70f2015-11-19 10:29:39 +000067 HPhi* input = it.Current()->AsPhi();
68 if (input != nullptr && input->IsDead()) {
69 // Input is a dead phi. Revive it and add to the worklist. We make sure
70 // that the phi was not dead initially (see definition of `initially_live`).
71 DCHECK(ContainsElement(initially_live, input));
72 input->SetLive();
73 worklist_.push_back(input);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010074 }
75 }
76 }
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000077}
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010078
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000079void SsaDeadPhiElimination::EliminateDeadPhis() {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010080 // Remove phis that are not live. Visit in post order so that phis
81 // that are not inputs of loop phis can be removed when they have
82 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010083 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
84 HBasicBlock* block = it.Current();
85 HInstruction* current = block->GetFirstPhi();
86 HInstruction* next = nullptr;
David Brazdil1abb4192015-02-17 18:33:36 +000087 HPhi* phi;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010088 while (current != nullptr) {
David Brazdil1abb4192015-02-17 18:33:36 +000089 phi = current->AsPhi();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010090 next = current->GetNext();
David Brazdil1abb4192015-02-17 18:33:36 +000091 if (phi->IsDead()) {
92 // Make sure the phi is only used by other dead phis.
93 if (kIsDebugBuild) {
94 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080095 use_it.Advance()) {
David Brazdil1abb4192015-02-17 18:33:36 +000096 HInstruction* user = use_it.Current()->GetUser();
Alex Light68289a52015-12-15 17:30:30 -080097 DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
98 DCHECK(user->AsPhi()->IsDead()) << user->GetId();
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010099 }
100 }
David Brazdil1abb4192015-02-17 18:33:36 +0000101 // Remove the phi from use lists of its inputs.
102 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
103 phi->RemoveAsUserOfInput(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100104 }
David Brazdil1abb4192015-02-17 18:33:36 +0000105 // Remove the phi from environments that use it.
106 for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
107 use_it.Advance()) {
108 HUseListNode<HEnvironment*>* user_node = use_it.Current();
109 HEnvironment* user = user_node->GetUser();
110 user->SetRawEnvAt(user_node->GetIndex(), nullptr);
111 }
112 // Delete it from the instruction list.
113 block->RemovePhi(phi, /*ensure_safety=*/ false);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100114 }
115 current = next;
116 }
117 }
118}
119
120void SsaRedundantPhiElimination::Run() {
David Brazdil77b022d2015-08-19 14:17:31 +0100121 // Add all phis in the worklist. Order does not matter for correctness, and
122 // neither will necessarily converge faster.
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100123 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
124 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800125 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100126 worklist_.push_back(inst_it.Current()->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100127 }
128 }
129
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100130 while (!worklist_.empty()) {
131 HPhi* phi = worklist_.back();
132 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100133
134 // If the phi has already been processed, continue.
135 if (!phi->IsInBlock()) {
136 continue;
137 }
138
David Brazdilffee3d32015-07-06 11:48:53 +0100139 if (phi->InputCount() == 0) {
David Brazdilffee3d32015-07-06 11:48:53 +0100140 DCHECK(phi->IsDead());
141 continue;
142 }
143
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100144 // Find if the inputs of the phi are the same instruction.
145 HInstruction* candidate = phi->InputAt(0);
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100146 // A loop phi cannot have itself as the first phi. Note that this
147 // check relies on our simplification pass ensuring the pre-header
148 // block is first in the list of predecessors of the loop header.
Roland Levillain6b879dd2014-09-22 17:13:44 +0100149 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100150 DCHECK_NE(phi, candidate);
151
152 for (size_t i = 1; i < phi->InputCount(); ++i) {
153 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100154 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100155 // elimination.
156 if (input != candidate && input != phi) {
157 candidate = nullptr;
158 break;
159 }
160 }
161
162 // If the inputs are not the same, continue.
163 if (candidate == nullptr) {
164 continue;
165 }
166
David Brazdilffee3d32015-07-06 11:48:53 +0100167 // The candidate may not dominate a phi in a catch block.
168 if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) {
169 continue;
170 }
171
David Brazdil77b022d2015-08-19 14:17:31 +0100172 // Because we're updating the users of this phi, we may have new candidates
173 // for elimination. Add phis that use this phi to the worklist.
174 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) {
175 HUseListNode<HInstruction*>* current = it.Current();
176 HInstruction* user = current->GetUser();
177 if (user->IsPhi()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100178 worklist_.push_back(user->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100179 }
180 }
David Brazdil77b022d2015-08-19 14:17:31 +0100181
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100182 phi->ReplaceWith(candidate);
183 phi->GetBlock()->RemovePhi(phi);
184 }
185}
186
187} // namespace art