blob: 9a6b121ffbd224d2fe0e8bfed002fcf4ce312039 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/graph-reducer.h"
6
7#include <functional>
8
9#include "src/compiler/graph-inl.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
Emily Bernier958fae72015-03-24 16:35:39 -040015enum class GraphReducer::State : uint8_t {
16 kUnvisited,
17 kRevisit,
18 kOnStack,
19 kVisited
20};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021
22
Emily Bernier958fae72015-03-24 16:35:39 -040023GraphReducer::GraphReducer(Graph* graph, Zone* zone)
24 : graph_(graph),
25 state_(graph, 4),
26 reducers_(zone),
27 revisit_(zone),
28 stack_(zone) {}
29
30
31void GraphReducer::AddReducer(Reducer* reducer) {
32 reducers_.push_back(reducer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033}
34
35
36void GraphReducer::ReduceNode(Node* node) {
Emily Bernier958fae72015-03-24 16:35:39 -040037 DCHECK(stack_.empty());
38 DCHECK(revisit_.empty());
39 Push(node);
40 for (;;) {
41 if (!stack_.empty()) {
42 // Process the node on the top of the stack, potentially pushing more or
43 // popping the node off the stack.
44 ReduceTop();
45 } else if (!revisit_.empty()) {
46 // If the stack becomes empty, revisit any nodes in the revisit queue.
47 Node* const node = revisit_.top();
48 revisit_.pop();
49 if (state_.Get(node) == State::kRevisit) {
50 // state can change while in queue.
51 Push(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052 }
Emily Bernier958fae72015-03-24 16:35:39 -040053 } else {
54 break;
55 }
56 }
57 DCHECK(revisit_.empty());
58 DCHECK(stack_.empty());
59}
60
61
62void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); }
63
64
65Reduction GraphReducer::Reduce(Node* const node) {
66 auto skip = reducers_.end();
67 for (auto i = reducers_.begin(); i != reducers_.end();) {
68 if (i != skip) {
69 Reduction reduction = (*i)->Reduce(node);
70 if (!reduction.Changed()) {
71 // No change from this reducer.
72 } else if (reduction.replacement() == node) {
73 // {replacement} == {node} represents an in-place reduction. Rerun
74 // all the other reducers for this node, as now there may be more
75 // opportunities for reduction.
76 skip = i;
77 i = reducers_.begin();
78 continue;
79 } else {
80 // {node} was replaced by another node.
81 return reduction;
82 }
83 }
84 ++i;
85 }
86 if (skip == reducers_.end()) {
87 // No change from any reducer.
88 return Reducer::NoChange();
89 }
90 // At least one reducer did some in-place reduction.
91 return Reducer::Changed(node);
92}
93
94
95void GraphReducer::ReduceTop() {
96 NodeState& entry = stack_.top();
97 Node* node = entry.node;
98 DCHECK(state_.Get(node) == State::kOnStack);
99
100 if (node->IsDead()) return Pop(); // Node was killed while on stack.
101
102 // Recurse on an input if necessary.
103 int start = entry.input_index < node->InputCount() ? entry.input_index : 0;
104 for (int i = start; i < node->InputCount(); i++) {
105 Node* input = node->InputAt(i);
106 entry.input_index = i + 1;
107 if (input != node && Recurse(input)) return;
108 }
109 for (int i = 0; i < start; i++) {
110 Node* input = node->InputAt(i);
111 entry.input_index = i + 1;
112 if (input != node && Recurse(input)) return;
113 }
114
115 // Remember the node count before reduction.
116 const int node_count = graph()->NodeCount();
117
118 // All inputs should be visited or on stack. Apply reductions to node.
119 Reduction reduction = Reduce(node);
120
121 // If there was no reduction, pop {node} and continue.
122 if (!reduction.Changed()) return Pop();
123
124 // Check if the reduction is an in-place update of the {node}.
125 Node* const replacement = reduction.replacement();
126 if (replacement == node) {
127 // In-place update of {node}, may need to recurse on an input.
128 for (int i = 0; i < node->InputCount(); ++i) {
129 Node* input = node->InputAt(i);
130 entry.input_index = i + 1;
131 if (input != node && Recurse(input)) return;
132 }
133 }
134
135 // After reducing the node, pop it off the stack.
136 Pop();
137
138 // Revisit all uses of the node.
139 for (Node* const use : node->uses()) {
140 // Don't revisit this node if it refers to itself.
141 if (use != node) Revisit(use);
142 }
143
144 // Check if we have a new replacement.
145 if (replacement != node) {
146 if (node == graph()->start()) graph()->SetStart(replacement);
147 if (node == graph()->end()) graph()->SetEnd(replacement);
148 // If {node} was replaced by an old node, unlink {node} and assume that
149 // {replacement} was already reduced and finish.
150 if (replacement->id() < node_count) {
151 node->ReplaceUses(replacement);
152 node->Kill();
153 } else {
154 // Otherwise {node} was replaced by a new node. Replace all old uses of
155 // {node} with {replacement}. New nodes created by this reduction can
156 // use {node}.
157 node->ReplaceUsesIf(
158 [node_count](Node* const node) { return node->id() < node_count; },
159 replacement);
160 // Unlink {node} if it's no longer used.
161 if (node->uses().empty()) {
162 node->Kill();
163 }
164
165 // If there was a replacement, reduce it after popping {node}.
166 Recurse(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 }
168 }
169}
170
171
Emily Bernier958fae72015-03-24 16:35:39 -0400172void GraphReducer::Pop() {
173 Node* node = stack_.top().node;
174 state_.Set(node, State::kVisited);
175 stack_.pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176}
177
178
Emily Bernier958fae72015-03-24 16:35:39 -0400179void GraphReducer::Push(Node* const node) {
180 DCHECK(state_.Get(node) != State::kOnStack);
181 state_.Set(node, State::kOnStack);
182 stack_.push({node, 0});
183}
184
185
186bool GraphReducer::Recurse(Node* node) {
187 if (state_.Get(node) > State::kRevisit) return false;
188 Push(node);
189 return true;
190}
191
192
193void GraphReducer::Revisit(Node* node) {
194 if (state_.Get(node) == State::kVisited) {
195 state_.Set(node, State::kRevisit);
196 revisit_.push(node);
197 }
198}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199
200} // namespace compiler
201} // namespace internal
202} // namespace v8