blob: 72f9ddd5066b8c381b6a49bc420717d1cedc4538 [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();
Nicolas Geoffray31596742014-11-24 15:28:45 +000032 // Set dead ahead of running through uses. The phi may have no use.
33 phi->SetDead();
David Brazdiled596192015-01-23 10:39:45 +000034 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
35 HUseListNode<HInstruction*>* current = use_it.Current();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010036 HInstruction* user = current->GetUser();
37 if (!user->IsPhi()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010038 worklist_.push_back(phi);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010039 phi->SetLive();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010040 break;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010041 }
42 }
43 }
44 }
45
46 // Process the worklist by propagating liveness to phi inputs.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010047 while (!worklist_.empty()) {
48 HPhi* phi = worklist_.back();
49 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010050 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
51 HInstruction* input = it.Current();
52 if (input->IsPhi() && input->AsPhi()->IsDead()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010053 worklist_.push_back(input->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010054 input->AsPhi()->SetLive();
55 }
56 }
57 }
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000058}
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010059
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +000060void SsaDeadPhiElimination::EliminateDeadPhis() {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010061 // Remove phis that are not live. Visit in post order so that phis
62 // that are not inputs of loop phis can be removed when they have
63 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010064 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
65 HBasicBlock* block = it.Current();
66 HInstruction* current = block->GetFirstPhi();
67 HInstruction* next = nullptr;
David Brazdil1abb4192015-02-17 18:33:36 +000068 HPhi* phi;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010069 while (current != nullptr) {
David Brazdil1abb4192015-02-17 18:33:36 +000070 phi = current->AsPhi();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010071 next = current->GetNext();
David Brazdil1abb4192015-02-17 18:33:36 +000072 if (phi->IsDead()) {
73 // Make sure the phi is only used by other dead phis.
74 if (kIsDebugBuild) {
75 for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done();
Andreas Gampe277ccbd2014-11-03 21:36:10 -080076 use_it.Advance()) {
David Brazdil1abb4192015-02-17 18:33:36 +000077 HInstruction* user = use_it.Current()->GetUser();
Nicolas Geoffray31596742014-11-24 15:28:45 +000078 DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
79 DCHECK(user->AsPhi()->IsDead()) << user->GetId();
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010080 }
81 }
David Brazdil1abb4192015-02-17 18:33:36 +000082 // Remove the phi from use lists of its inputs.
83 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
84 phi->RemoveAsUserOfInput(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010085 }
David Brazdil1abb4192015-02-17 18:33:36 +000086 // Remove the phi from environments that use it.
87 for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done();
88 use_it.Advance()) {
89 HUseListNode<HEnvironment*>* user_node = use_it.Current();
90 HEnvironment* user = user_node->GetUser();
91 user->SetRawEnvAt(user_node->GetIndex(), nullptr);
92 }
93 // Delete it from the instruction list.
94 block->RemovePhi(phi, /*ensure_safety=*/ false);
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010095 }
96 current = next;
97 }
98 }
99}
100
101void SsaRedundantPhiElimination::Run() {
David Brazdil77b022d2015-08-19 14:17:31 +0100102 // Add all phis in the worklist. Order does not matter for correctness, and
103 // neither will necessarily converge faster.
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100104 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
105 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800106 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100107 worklist_.push_back(inst_it.Current()->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100108 }
109 }
110
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100111 while (!worklist_.empty()) {
112 HPhi* phi = worklist_.back();
113 worklist_.pop_back();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100114
115 // If the phi has already been processed, continue.
116 if (!phi->IsInBlock()) {
117 continue;
118 }
119
David Brazdilffee3d32015-07-06 11:48:53 +0100120 if (phi->InputCount() == 0) {
121 DCHECK(phi->IsCatchPhi());
122 DCHECK(phi->IsDead());
123 continue;
124 }
125
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100126 // Find if the inputs of the phi are the same instruction.
127 HInstruction* candidate = phi->InputAt(0);
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100128 // A loop phi cannot have itself as the first phi. Note that this
129 // check relies on our simplification pass ensuring the pre-header
130 // block is first in the list of predecessors of the loop header.
Roland Levillain6b879dd2014-09-22 17:13:44 +0100131 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100132 DCHECK_NE(phi, candidate);
133
134 for (size_t i = 1; i < phi->InputCount(); ++i) {
135 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100136 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100137 // elimination.
138 if (input != candidate && input != phi) {
139 candidate = nullptr;
140 break;
141 }
142 }
143
144 // If the inputs are not the same, continue.
145 if (candidate == nullptr) {
146 continue;
147 }
148
David Brazdilffee3d32015-07-06 11:48:53 +0100149 // The candidate may not dominate a phi in a catch block.
150 if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) {
151 continue;
152 }
153
David Brazdil77b022d2015-08-19 14:17:31 +0100154 // Because we're updating the users of this phi, we may have new candidates
155 // for elimination. Add phis that use this phi to the worklist.
156 for (HUseIterator<HInstruction*> it(phi->GetUses()); !it.Done(); it.Advance()) {
157 HUseListNode<HInstruction*>* current = it.Current();
158 HInstruction* user = current->GetUser();
159 if (user->IsPhi()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100160 worklist_.push_back(user->AsPhi());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100161 }
162 }
David Brazdil77b022d2015-08-19 14:17:31 +0100163
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100164 phi->ReplaceWith(candidate);
165 phi->GetBlock()->RemovePhi(phi);
166 }
167}
168
169} // namespace art