ssa_phi_elimination.cc revision 604c6e4764edb2fd244e9f47626868cda5644a7a
1/*
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?
29        worklist_.Add(phi);
30        phi->SetLive();
31        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
58  // 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).
61  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()) {
68        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        }
79        block->RemovePhi(current->AsPhi());
80      }
81      current = next;
82    }
83  }
84}
85
86static bool LoopPreHeaderIsFirstPredecessor(HBasicBlock* block) {
87  return block->GetPredecessors().Get(0) == block->GetLoopInformation()->GetPreHeader();
88}
89
90void SsaRedundantPhiElimination::Run() {
91  // Add all phis in the worklist.
92  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
93    HBasicBlock* block = it.Current();
94    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
95      worklist_.Add(it.Current()->AsPhi());
96    }
97  }
98
99  while (!worklist_.IsEmpty()) {
100    HPhi* phi = worklist_.Pop();
101
102    // If the phi has already been processed, continue.
103    if (!phi->IsInBlock()) {
104      continue;
105    }
106
107    // Find if the inputs of the phi are the same instruction.
108    HInstruction* candidate = phi->InputAt(0);
109    // A loop phi cannot have itself as the first phi. Note that this
110    // check relies on our simplification pass ensuring the pre-header
111    // block is first in the list of predecessors of the loop header.
112    DCHECK(!phi->IsLoopHeaderPhi() || LoopPreHeaderIsFirstPredecessor(phi->GetBlock()));
113    DCHECK_NE(phi, candidate);
114
115    for (size_t i = 1; i < phi->InputCount(); ++i) {
116      HInstruction* input = phi->InputAt(i);
117      // For a loop phi, if the input is the phi, the phi is still candidate for
118      // elimination.
119      if (input != candidate && input != phi) {
120        candidate = nullptr;
121        break;
122      }
123    }
124
125    // If the inputs are not the same, continue.
126    if (candidate == nullptr) {
127      continue;
128    }
129
130    if (phi->IsInLoop()) {
131      // Because we're updating the users of this phi, we may have new
132      // phis candidate for elimination if this phi is in a loop. Add phis that
133      // used this phi to the worklist.
134      for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
135        HUseListNode<HInstruction>* current = it.Current();
136        HInstruction* user = current->GetUser();
137        if (user->IsPhi()) {
138          worklist_.Add(user->AsPhi());
139        }
140      }
141    }
142    phi->ReplaceWith(candidate);
143    phi->GetBlock()->RemovePhi(phi);
144  }
145}
146
147}  // namespace art
148