blob: 4eda0f375750b2befe9751fc875198b4b405fada [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() {
22 // Add to the worklist phis referenced by non-phi instructions.
23 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
24 HBasicBlock* block = it.Current();
25 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
26 HPhi* phi = it.Current()->AsPhi();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010027 for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
28 HUseListNode<HInstruction>* current = it.Current();
29 HInstruction* user = current->GetUser();
30 if (!user->IsPhi()) {
31 worklist_.Add(phi);
32 phi->SetLive();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010033 break;
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010034 } else {
35 phi->SetDead();
36 }
37 }
38 }
39 }
40
41 // Process the worklist by propagating liveness to phi inputs.
42 while (!worklist_.IsEmpty()) {
43 HPhi* phi = worklist_.Pop();
44 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
45 HInstruction* input = it.Current();
46 if (input->IsPhi() && input->AsPhi()->IsDead()) {
47 worklist_.Add(input->AsPhi());
48 input->AsPhi()->SetLive();
49 }
50 }
51 }
52
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010053 // Remove phis that are not live. Visit in post order so that phis
54 // that are not inputs of loop phis can be removed when they have
55 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010056 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
57 HBasicBlock* block = it.Current();
58 HInstruction* current = block->GetFirstPhi();
59 HInstruction* next = nullptr;
60 while (current != nullptr) {
61 next = current->GetNext();
62 if (current->AsPhi()->IsDead()) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010063 if (current->HasUses()) {
64 for (HUseIterator<HInstruction> it(current->GetUses()); !it.Done(); it.Advance()) {
65 HUseListNode<HInstruction>* user_node = it.Current();
66 HInstruction* user = user_node->GetUser();
67 DCHECK(user->IsLoopHeaderPhi());
68 DCHECK(user->AsPhi()->IsDead());
69 // Just put itself as an input. The phi will be removed in this loop anyway.
70 user->SetRawInputAt(user_node->GetIndex(), user);
71 current->RemoveUser(user, user_node->GetIndex());
72 }
73 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010074 if (current->HasEnvironmentUses()) {
75 for (HUseIterator<HEnvironment> it(current->GetEnvUses()); !it.Done(); it.Advance()) {
76 HUseListNode<HEnvironment>* user_node = it.Current();
77 HEnvironment* user = user_node->GetUser();
78 user->SetRawEnvAt(user_node->GetIndex(), nullptr);
79 current->RemoveEnvironmentUser(user, user_node->GetIndex());
80 }
81 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010082 block->RemovePhi(current->AsPhi());
83 }
84 current = next;
85 }
86 }
87}
88
89void SsaRedundantPhiElimination::Run() {
90 // Add all phis in the worklist.
91 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
92 HBasicBlock* block = it.Current();
93 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
94 worklist_.Add(it.Current()->AsPhi());
95 }
96 }
97
98 while (!worklist_.IsEmpty()) {
99 HPhi* phi = worklist_.Pop();
100
101 // If the phi has already been processed, continue.
102 if (!phi->IsInBlock()) {
103 continue;
104 }
105
106 // Find if the inputs of the phi are the same instruction.
107 HInstruction* candidate = phi->InputAt(0);
Nicolas Geoffray604c6e42014-09-17 12:08:44 +0100108 // A loop phi cannot have itself as the first phi. Note that this
109 // check relies on our simplification pass ensuring the pre-header
110 // block is first in the list of predecessors of the loop header.
Roland Levillain6b879dd2014-09-22 17:13:44 +0100111 DCHECK(!phi->IsLoopHeaderPhi() || phi->GetBlock()->IsLoopPreHeaderFirstPredecessor());
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100112 DCHECK_NE(phi, candidate);
113
114 for (size_t i = 1; i < phi->InputCount(); ++i) {
115 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100116 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100117 // elimination.
118 if (input != candidate && input != phi) {
119 candidate = nullptr;
120 break;
121 }
122 }
123
124 // If the inputs are not the same, continue.
125 if (candidate == nullptr) {
126 continue;
127 }
128
129 if (phi->IsInLoop()) {
130 // Because we're updating the users of this phi, we may have new
131 // phis candidate for elimination if this phi is in a loop. Add phis that
132 // used this phi to the worklist.
133 for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
134 HUseListNode<HInstruction>* current = it.Current();
135 HInstruction* user = current->GetUser();
136 if (user->IsPhi()) {
137 worklist_.Add(user->AsPhi());
138 }
139 }
140 }
141 phi->ReplaceWith(candidate);
142 phi->GetBlock()->RemovePhi(phi);
143 }
144}
145
146} // namespace art