blob: 65675dc2736367a81fc9604bfe8fa503491fed0c [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();
27 if (phi->HasEnvironmentUses()) {
28 // TODO: Do we want to keep that phi alive?
Nicolas Geoffray39468442014-09-02 15:17:15 +010029 worklist_.Add(phi);
30 phi->SetLive();
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010031 continue;
32 }
33 for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
34 HUseListNode<HInstruction>* current = it.Current();
35 HInstruction* user = current->GetUser();
36 if (!user->IsPhi()) {
37 worklist_.Add(phi);
38 phi->SetLive();
39 } else {
40 phi->SetDead();
41 }
42 }
43 }
44 }
45
46 // Process the worklist by propagating liveness to phi inputs.
47 while (!worklist_.IsEmpty()) {
48 HPhi* phi = worklist_.Pop();
49 for (HInputIterator it(phi); !it.Done(); it.Advance()) {
50 HInstruction* input = it.Current();
51 if (input->IsPhi() && input->AsPhi()->IsDead()) {
52 worklist_.Add(input->AsPhi());
53 input->AsPhi()->SetLive();
54 }
55 }
56 }
57
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010058 // Remove phis that are not live. Visit in post order so that phis
59 // that are not inputs of loop phis can be removed when they have
60 // no users left (dead phis might use dead phis).
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010061 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
62 HBasicBlock* block = it.Current();
63 HInstruction* current = block->GetFirstPhi();
64 HInstruction* next = nullptr;
65 while (current != nullptr) {
66 next = current->GetNext();
67 if (current->AsPhi()->IsDead()) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010068 if (current->HasUses()) {
69 for (HUseIterator<HInstruction> it(current->GetUses()); !it.Done(); it.Advance()) {
70 HUseListNode<HInstruction>* user_node = it.Current();
71 HInstruction* user = user_node->GetUser();
72 DCHECK(user->IsLoopHeaderPhi());
73 DCHECK(user->AsPhi()->IsDead());
74 // Just put itself as an input. The phi will be removed in this loop anyway.
75 user->SetRawInputAt(user_node->GetIndex(), user);
76 current->RemoveUser(user, user_node->GetIndex());
77 }
78 }
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +010079 block->RemovePhi(current->AsPhi());
80 }
81 current = next;
82 }
83 }
84}
85
86void SsaRedundantPhiElimination::Run() {
87 // Add all phis in the worklist.
88 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
89 HBasicBlock* block = it.Current();
90 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
91 worklist_.Add(it.Current()->AsPhi());
92 }
93 }
94
95 while (!worklist_.IsEmpty()) {
96 HPhi* phi = worklist_.Pop();
97
98 // If the phi has already been processed, continue.
99 if (!phi->IsInBlock()) {
100 continue;
101 }
102
103 // Find if the inputs of the phi are the same instruction.
104 HInstruction* candidate = phi->InputAt(0);
105 // A loop phi cannot have itself as the first phi.
106 DCHECK_NE(phi, candidate);
107
108 for (size_t i = 1; i < phi->InputCount(); ++i) {
109 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100110 // For a loop phi, if the input is the phi, the phi is still candidate for
Nicolas Geoffray7dc206a2014-07-11 09:49:49 +0100111 // elimination.
112 if (input != candidate && input != phi) {
113 candidate = nullptr;
114 break;
115 }
116 }
117
118 // If the inputs are not the same, continue.
119 if (candidate == nullptr) {
120 continue;
121 }
122
123 if (phi->IsInLoop()) {
124 // Because we're updating the users of this phi, we may have new
125 // phis candidate for elimination if this phi is in a loop. Add phis that
126 // used this phi to the worklist.
127 for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
128 HUseListNode<HInstruction>* current = it.Current();
129 HInstruction* user = current->GetUser();
130 if (user->IsPhi()) {
131 worklist_.Add(user->AsPhi());
132 }
133 }
134 }
135 phi->ReplaceWith(candidate);
136 phi->GetBlock()->RemovePhi(phi);
137 }
138}
139
140} // namespace art