Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/compiler/control-reducer.cc

Issue 767743003: [turbofan] NodeMarker in ControlReducer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Use uint8_t. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/common-operator.h" 5 #include "src/compiler/common-operator.h"
6 #include "src/compiler/control-reducer.h" 6 #include "src/compiler/control-reducer.h"
7 #include "src/compiler/graph.h" 7 #include "src/compiler/graph.h"
8 #include "src/compiler/js-graph.h" 8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/node-matchers.h" 9 #include "src/compiler/node-matchers.h"
10 #include "src/compiler/node-properties-inl.h" 10 #include "src/compiler/node-properties-inl.h"
11 #include "src/zone-containers.h" 11 #include "src/zone-containers.h"
12 12
13 namespace v8 { 13 namespace v8 {
14 namespace internal { 14 namespace internal {
15 namespace compiler { 15 namespace compiler {
16 16
17 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; 17 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 };
18 enum Reachability { kFromStart = 8 };
19 enum Decision { kFalse, kUnknown, kTrue }; 18 enum Decision { kFalse, kUnknown, kTrue };
20 19
20 class ReachabilityMarker : public NodeMarker<uint8_t> {
21 public:
22 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {}
23 bool SetReachableFromEnd(Node* node) {
24 uint8_t before = Get(node);
25 Set(node, before | kFromEnd);
26 return before & kFromEnd;
27 }
28 bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; }
29 bool SetReachableFromStart(Node* node) {
30 uint8_t before = Get(node);
31 Set(node, before | kFromStart);
32 return before & kFromStart;
33 }
34 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; }
35 void Push(Node* node) { Set(node, Get(node) | kFwStack); }
36 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); }
37 bool IsOnStack(Node* node) { return Get(node) & kFwStack; }
38
39 private:
40 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 };
41 };
42
43
21 #define TRACE(x) \ 44 #define TRACE(x) \
22 if (FLAG_trace_turbo_reduction) PrintF x 45 if (FLAG_trace_turbo_reduction) PrintF x
23 46
24 class ControlReducerImpl { 47 class ControlReducerImpl {
25 public: 48 public:
26 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, 49 ControlReducerImpl(Zone* zone, JSGraph* jsgraph,
27 CommonOperatorBuilder* common) 50 CommonOperatorBuilder* common)
28 : zone_(zone), 51 : zone_(zone),
29 jsgraph_(jsgraph), 52 jsgraph_(jsgraph),
30 common_(common), 53 common_(common),
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 return false; 88 return false;
66 } 89 }
67 90
68 // Repair the graph after the possible creation of non-terminating or dead 91 // Repair the graph after the possible creation of non-terminating or dead
69 // loops. Removing dead loops can produce more opportunities for reduction. 92 // loops. Removing dead loops can produce more opportunities for reduction.
70 bool RepairAndRemoveLoops() { 93 bool RepairAndRemoveLoops() {
71 // TODO(turbofan): we can skip this if the graph has no loops, but 94 // TODO(turbofan): we can skip this if the graph has no loops, but
72 // we have to be careful about proper loop detection during reduction. 95 // we have to be careful about proper loop detection during reduction.
73 96
74 // Gather all nodes backwards-reachable from end (through inputs). 97 // Gather all nodes backwards-reachable from end (through inputs).
75 state_.assign(graph()->NodeCount(), kUnvisited); 98 ReachabilityMarker marked(graph());
76 NodeVector nodes(zone_); 99 NodeVector nodes(zone_);
77 AddNodesReachableFromEnd(nodes); 100 AddNodesReachableFromEnd(marked, nodes);
78 101
79 // Walk forward through control nodes, looking for back edges to nodes 102 // Walk forward through control nodes, looking for back edges to nodes
80 // that are not connected to end. Those are non-terminating loops (NTLs). 103 // that are not connected to end. Those are non-terminating loops (NTLs).
81 Node* start = graph()->start(); 104 Node* start = graph()->start();
82 ZoneVector<byte> fw_reachability(graph()->NodeCount(), 0, zone_); 105 marked.Push(start);
83 fw_reachability[start->id()] = kFromStart | kOnStack; 106 marked.SetReachableFromStart(start);
84 107
85 // We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal. 108 // We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal.
86 typedef std::pair<Node*, UseIter> FwIter; 109 typedef std::pair<Node*, UseIter> FwIter;
87 ZoneDeque<FwIter> fw_stack(zone_); 110 ZoneDeque<FwIter> fw_stack(zone_);
88 fw_stack.push_back(FwIter(start, start->uses().begin())); 111 fw_stack.push_back(FwIter(start, start->uses().begin()));
89 112
90 while (!fw_stack.empty()) { 113 while (!fw_stack.empty()) {
91 Node* node = fw_stack.back().first; 114 Node* node = fw_stack.back().first;
92 TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic())); 115 TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()));
93 bool pop = true; 116 bool pop = true;
94 while (fw_stack.back().second != node->uses().end()) { 117 while (fw_stack.back().second != node->uses().end()) {
95 Node* succ = *(fw_stack.back().second); 118 Node* succ = *(fw_stack.back().second);
96 byte reach = fw_reachability[succ->id()]; 119 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) {
97 if ((reach & kOnStack) != 0 && state_[succ->id()] != kVisited) {
98 // {succ} is on stack and not reachable from end. 120 // {succ} is on stack and not reachable from end.
99 ConnectNTL(nodes, succ); 121 Node* added = ConnectNTL(succ);
100 fw_reachability.resize(graph()->NodeCount(), 0); 122 nodes.push_back(added);
123 marked.SetReachableFromEnd(added);
124 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
125
101 // The use list of {succ} might have changed. 126 // The use list of {succ} might have changed.
102 fw_stack[fw_stack.size() - 1] = FwIter(succ, succ->uses().begin()); 127 fw_stack[fw_stack.size() - 1] = FwIter(succ, succ->uses().begin());
103 pop = false; // restart traversing successors of this node. 128 pop = false; // restart traversing successors of this node.
104 break; 129 break;
105 } 130 }
106 if ((reach & kFromStart) == 0 && 131 if (IrOpcode::IsControlOpcode(succ->opcode()) &&
107 IrOpcode::IsControlOpcode(succ->opcode())) { 132 !marked.IsReachableFromStart(succ)) {
108 // {succ} is a control node and not yet reached from start. 133 // {succ} is a control node and not yet reached from start.
109 fw_reachability[succ->id()] |= kFromStart | kOnStack; 134 marked.Push(succ);
135 marked.SetReachableFromStart(succ);
110 fw_stack.push_back(FwIter(succ, succ->uses().begin())); 136 fw_stack.push_back(FwIter(succ, succ->uses().begin()));
111 pop = false; // "recurse" into successor control node. 137 pop = false; // "recurse" into successor control node.
112 break; 138 break;
113 } 139 }
114 ++fw_stack.back().second; 140 ++fw_stack.back().second;
115 } 141 }
116 if (pop) { 142 if (pop) {
117 fw_reachability[node->id()] &= ~kOnStack; 143 marked.Pop(node);
118 fw_stack.pop_back(); 144 fw_stack.pop_back();
119 } 145 }
120 } 146 }
121 147
122 // Trim references from dead nodes to live nodes first. 148 // Trim references from dead nodes to live nodes first.
123 jsgraph_->GetCachedNodes(&nodes); 149 jsgraph_->GetCachedNodes(&nodes);
124 TrimNodes(nodes); 150 TrimNodes(marked, nodes);
125 151
126 // Any control nodes not reachable from start are dead, even loops. 152 // Any control nodes not reachable from start are dead, even loops.
127 for (size_t i = 0; i < nodes.size(); i++) { 153 for (size_t i = 0; i < nodes.size(); i++) {
128 Node* node = nodes[i]; 154 Node* node = nodes[i];
129 byte reach = fw_reachability[node->id()]; 155 if (IrOpcode::IsControlOpcode(node->opcode()) &&
130 if ((reach & kFromStart) == 0 && 156 !marked.IsReachableFromStart(node)) {
131 IrOpcode::IsControlOpcode(node->opcode())) {
132 ReplaceNode(node, dead()); // uses will be added to revisit queue. 157 ReplaceNode(node, dead()); // uses will be added to revisit queue.
133 } 158 }
134 } 159 }
135 return TryRevisit(); // try to push a node onto the stack. 160 return TryRevisit(); // try to push a node onto the stack.
136 } 161 }
137 162
138 // Connect {loop}, the header of a non-terminating loop, to the end node. 163 // Connect {loop}, the header of a non-terminating loop, to the end node.
139 void ConnectNTL(NodeVector& nodes, Node* loop) { 164 Node* ConnectNTL(Node* loop) {
140 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); 165 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()));
141 166
142 if (loop->opcode() != IrOpcode::kTerminate) { 167 if (loop->opcode() != IrOpcode::kTerminate) {
143 // Insert a {Terminate} node if the loop has effects. 168 // Insert a {Terminate} node if the loop has effects.
144 ZoneDeque<Node*> effects(zone_); 169 ZoneDeque<Node*> effects(zone_);
145 for (Node* const use : loop->uses()) { 170 for (Node* const use : loop->uses()) {
146 if (use->opcode() == IrOpcode::kEffectPhi) effects.push_back(use); 171 if (use->opcode() == IrOpcode::kEffectPhi) effects.push_back(use);
147 } 172 }
148 int count = static_cast<int>(effects.size()); 173 int count = static_cast<int>(effects.size());
149 if (count > 0) { 174 if (count > 0) {
(...skipping 16 matching lines...) Expand all
166 } else if (merge->opcode() != IrOpcode::kMerge) { 191 } else if (merge->opcode() != IrOpcode::kMerge) {
167 // Introduce a final merge node for {end->InputAt(0)} and {loop}. 192 // Introduce a final merge node for {end->InputAt(0)} and {loop}.
168 merge = graph()->NewNode(common_->Merge(2), merge, loop); 193 merge = graph()->NewNode(common_->Merge(2), merge, loop);
169 end->ReplaceInput(0, merge); 194 end->ReplaceInput(0, merge);
170 to_add = merge; 195 to_add = merge;
171 } else { 196 } else {
172 // Append a new input to the final merge at the end. 197 // Append a new input to the final merge at the end.
173 merge->AppendInput(graph()->zone(), loop); 198 merge->AppendInput(graph()->zone(), loop);
174 merge->set_op(common_->Merge(merge->InputCount())); 199 merge->set_op(common_->Merge(merge->InputCount()));
175 } 200 }
176 nodes.push_back(to_add); 201 return to_add;
177 state_.resize(graph()->NodeCount(), kUnvisited);
178 state_[to_add->id()] = kVisited;
179 AddBackwardsReachableNodes(nodes, nodes.size() - 1);
180 } 202 }
181 203
182 void AddNodesReachableFromEnd(NodeVector& nodes) { 204 void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) {
183 Node* end = graph()->end(); 205 Node* end = graph()->end();
184 state_[end->id()] = kVisited; 206 marked.SetReachableFromEnd(end);
185 if (!end->IsDead()) { 207 if (!end->IsDead()) {
186 nodes.push_back(end); 208 nodes.push_back(end);
187 AddBackwardsReachableNodes(nodes, nodes.size() - 1); 209 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
188 } 210 }
189 } 211 }
190 212
191 void AddBackwardsReachableNodes(NodeVector& nodes, size_t cursor) { 213 void AddBackwardsReachableNodes(ReachabilityMarker& marked, NodeVector& nodes,
214 size_t cursor) {
192 while (cursor < nodes.size()) { 215 while (cursor < nodes.size()) {
193 Node* node = nodes[cursor++]; 216 Node* node = nodes[cursor++];
194 for (Node* const input : node->inputs()) { 217 for (Node* const input : node->inputs()) {
195 if (state_[input->id()] != kVisited) { 218 if (!marked.SetReachableFromEnd(input)) {
196 state_[input->id()] = kVisited;
197 nodes.push_back(input); 219 nodes.push_back(input);
198 } 220 }
199 } 221 }
200 } 222 }
201 } 223 }
202 224
203 void Trim() { 225 void Trim() {
204 // Gather all nodes backwards-reachable from end through inputs. 226 // Gather all nodes backwards-reachable from end through inputs.
205 state_.assign(graph()->NodeCount(), kUnvisited); 227 ReachabilityMarker marked(graph());
206 NodeVector nodes(zone_); 228 NodeVector nodes(zone_);
207 AddNodesReachableFromEnd(nodes); 229 AddNodesReachableFromEnd(marked, nodes);
208 230
209 // Process cached nodes in the JSGraph too. 231 // Process cached nodes in the JSGraph too.
210 jsgraph_->GetCachedNodes(&nodes); 232 jsgraph_->GetCachedNodes(&nodes);
211 TrimNodes(nodes); 233 TrimNodes(marked, nodes);
212 } 234 }
213 235
214 void TrimNodes(NodeVector& nodes) { 236 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) {
215 // Remove dead->live edges. 237 // Remove dead->live edges.
216 for (size_t j = 0; j < nodes.size(); j++) { 238 for (size_t j = 0; j < nodes.size(); j++) {
217 Node* node = nodes[j]; 239 Node* node = nodes[j];
218 for (UseIter i = node->uses().begin(); i != node->uses().end();) { 240 for (UseIter i = node->uses().begin(); i != node->uses().end();) {
219 size_t id = static_cast<size_t>((*i)->id()); 241 if (!marked.IsReachableFromEnd(*i)) {
220 if (state_[id] != kVisited) {
221 TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", (*i)->id(), 242 TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", (*i)->id(),
222 (*i)->op()->mnemonic(), i.index(), node->id(), 243 (*i)->op()->mnemonic(), i.index(), node->id(),
223 node->op()->mnemonic())); 244 node->op()->mnemonic()));
224 i.UpdateToAndIncrement(NULL); 245 i.UpdateToAndIncrement(NULL);
225 } else { 246 } else {
226 ++i; 247 ++i;
227 } 248 }
228 } 249 }
229 } 250 }
230 #if DEBUG 251 #if DEBUG
231 // Verify that no inputs to live nodes are NULL. 252 // Verify that no inputs to live nodes are NULL.
232 for (size_t j = 0; j < nodes.size(); j++) { 253 for (size_t j = 0; j < nodes.size(); j++) {
233 Node* node = nodes[j]; 254 Node* node = nodes[j];
234 for (Node* const input : node->inputs()) { 255 for (Node* const input : node->inputs()) {
235 CHECK_NE(NULL, input); 256 CHECK_NE(NULL, input);
236 } 257 }
237 for (Node* const use : node->uses()) { 258 for (Node* const use : node->uses()) {
238 size_t id = static_cast<size_t>(use->id()); 259 CHECK(marked.IsReachableFromEnd(use));
239 CHECK_EQ(kVisited, state_[id]);
240 } 260 }
241 } 261 }
242 #endif 262 #endif
243 } 263 }
244 264
245 // Reduce the node on the top of the stack. 265 // Reduce the node on the top of the stack.
246 // If an input {i} is not yet visited or needs to be revisited, push {i} onto 266 // If an input {i} is not yet visited or needs to be revisited, push {i} onto
247 // the stack and return. Otherwise, all inputs are visited, so apply 267 // the stack and return. Otherwise, all inputs are visited, so apply
248 // reductions for {node} and pop it off the stack. 268 // reductions for {node} and pop it off the stack.
249 void ReduceTop() { 269 void ReduceTop() {
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 } 532 }
513 533
514 Graph* graph() { return jsgraph_->graph(); } 534 Graph* graph() { return jsgraph_->graph(); }
515 }; 535 };
516 536
517 537
518 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, 538 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph,
519 CommonOperatorBuilder* common) { 539 CommonOperatorBuilder* common) {
520 ControlReducerImpl impl(zone, jsgraph, common); 540 ControlReducerImpl impl(zone, jsgraph, common);
521 impl.Reduce(); 541 impl.Reduce();
522 impl.Trim();
523 } 542 }
524 543
525 544
526 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { 545 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) {
527 ControlReducerImpl impl(zone, jsgraph, NULL); 546 ControlReducerImpl impl(zone, jsgraph, NULL);
528 impl.Trim(); 547 impl.Trim();
529 } 548 }
530 549
531 550
532 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, 551 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph,
(...skipping 17 matching lines...) Expand all
550 Node* ControlReducer::ReduceBranchForTesting(JSGraph* jsgraph, 569 Node* ControlReducer::ReduceBranchForTesting(JSGraph* jsgraph,
551 CommonOperatorBuilder* common, 570 CommonOperatorBuilder* common,
552 Node* node) { 571 Node* node) {
553 Zone zone(jsgraph->graph()->zone()->isolate()); 572 Zone zone(jsgraph->graph()->zone()->isolate());
554 ControlReducerImpl impl(&zone, jsgraph, common); 573 ControlReducerImpl impl(&zone, jsgraph, common);
555 return impl.ReduceBranch(node); 574 return impl.ReduceBranch(node);
556 } 575 }
557 } 576 }
558 } 577 }
559 } // namespace v8::internal::compiler 578 } // namespace v8::internal::compiler
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698