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

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

Issue 1155683004: [turbofan] Connect loops to end via Terminate during graph building. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Also remove redundant EffectPhis now. Created 5 years, 6 months 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 | « src/compiler/common-operator.cc ('k') | src/compiler/js-inlining.cc » ('j') | 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/graph-reducer.h" 8 #include "src/compiler/graph-reducer.h"
9 #include "src/compiler/js-graph.h" 9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/node-marker.h" 10 #include "src/compiler/node-marker.h"
(...skipping 15 matching lines...) Expand all
26 26
27 class ReachabilityMarker : public NodeMarker<uint8_t> { 27 class ReachabilityMarker : public NodeMarker<uint8_t> {
28 public: 28 public:
29 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} 29 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {}
30 bool SetReachableFromEnd(Node* node) { 30 bool SetReachableFromEnd(Node* node) {
31 uint8_t before = Get(node); 31 uint8_t before = Get(node);
32 Set(node, before | kFromEnd); 32 Set(node, before | kFromEnd);
33 return before & kFromEnd; 33 return before & kFromEnd;
34 } 34 }
35 bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; } 35 bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; }
36 bool SetReachableFromStart(Node* node) {
37 uint8_t before = Get(node);
38 Set(node, before | kFromStart);
39 return before & kFromStart;
40 }
41 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; }
42 void Push(Node* node) { Set(node, Get(node) | kFwStack); } 36 void Push(Node* node) { Set(node, Get(node) | kFwStack); }
43 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } 37 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); }
44 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } 38 bool IsOnStack(Node* node) { return Get(node) & kFwStack; }
45 39
46 private: 40 private:
47 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; 41 enum Bit { kFromEnd = 1, kFwStack = 2 };
48 }; 42 };
49 43
50 44
51 class ControlReducerImpl final : public AdvancedReducer { 45 class ControlReducerImpl final : public AdvancedReducer {
52 public: 46 public:
53 Zone* zone_; 47 Zone* zone_;
54 JSGraph* jsgraph_; 48 JSGraph* jsgraph_;
55 int max_phis_for_select_; 49 int max_phis_for_select_;
56 50
57 ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph) 51 ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph)
58 : AdvancedReducer(editor), 52 : AdvancedReducer(editor),
59 zone_(zone), 53 zone_(zone),
60 jsgraph_(jsgraph), 54 jsgraph_(jsgraph),
61 max_phis_for_select_(0) {} 55 max_phis_for_select_(0) {}
62 56
63 Graph* graph() { return jsgraph_->graph(); } 57 Graph* graph() { return jsgraph_->graph(); }
64 CommonOperatorBuilder* common() { return jsgraph_->common(); } 58 CommonOperatorBuilder* common() { return jsgraph_->common(); }
65 Node* dead() { return jsgraph_->DeadControl(); } 59 Node* dead() { return jsgraph_->DeadControl(); }
66 60
67 // Finish reducing the graph by trimming nodes and/or connecting NTLs. 61 // Finish reducing the graph by trimming nodes.
68 bool Finish() final { 62 bool Finish() final {
69 bool done = true; 63 // TODO(bmeurer): Move this to the GraphReducer.
70 // Gather all nodes backwards-reachable from end (through inputs). 64 Trim();
71 ReachabilityMarker marked(graph()); 65 return true;
72 NodeVector nodes(zone_);
73 AddNodesReachableFromRoots(marked, nodes);
74
75 // Walk forward through control nodes, looking for back edges to nodes
76 // that are not connected to end. Those are non-terminating loops (NTLs).
77 Node* start = graph()->start();
78 marked.Push(start);
79 marked.SetReachableFromStart(start);
80
81 // We use a stack of (Node, Node::UseEdges::iterator) pairs to avoid
82 // O(n^2) traversal.
83 typedef std::pair<Node*, Node::UseEdges::iterator> FwIter;
84 ZoneVector<FwIter> fw_stack(zone_);
85 fw_stack.push_back(FwIter(start, start->use_edges().begin()));
86
87 while (!fw_stack.empty()) {
88 Node* node = fw_stack.back().first;
89 TRACE("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic());
90 bool pop = true;
91 while (fw_stack.back().second != node->use_edges().end()) {
92 Edge edge = *(fw_stack.back().second);
93 Node* succ = edge.from();
94 if (NodeProperties::IsControlEdge(edge) &&
95 succ->op()->ControlOutputCount() > 0) {
96 // Only walk control edges to control nodes.
97 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) {
98 // {succ} is on stack and not reachable from end.
99 Node* added = ConnectNTL(succ);
100 nodes.push_back(added);
101 marked.SetReachableFromEnd(added);
102 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
103
104 // Reset the use iterators for the entire stack.
105 for (size_t i = 0; i < fw_stack.size(); i++) {
106 FwIter& iter = fw_stack[i];
107 fw_stack[i] = FwIter(iter.first, iter.first->use_edges().begin());
108 }
109 pop = false; // restart traversing successors of this node.
110 break;
111 }
112 if (!marked.IsReachableFromStart(succ)) {
113 // {succ} is not yet reached from start.
114 marked.SetReachableFromStart(succ);
115 if (succ->opcode() != IrOpcode::kOsrLoopEntry) {
116 // Skip OsrLoopEntry; forms a confusing irredducible loop.
117 marked.Push(succ);
118 fw_stack.push_back(FwIter(succ, succ->use_edges().begin()));
119 pop = false; // "recurse" into successor control node.
120 break;
121 }
122 }
123 }
124 ++fw_stack.back().second;
125 }
126 if (pop) {
127 marked.Pop(node);
128 fw_stack.pop_back();
129 }
130 }
131
132 // Trim references from dead nodes to live nodes first.
133 TrimNodes(marked, nodes);
134
135 // Any control nodes not reachable from start are dead, even loops.
136 for (size_t i = 0; i < nodes.size(); i++) {
137 Node* node = nodes[i];
138 if (node->op()->ControlOutputCount() > 0 &&
139 !marked.IsReachableFromStart(node) &&
140 node->opcode() != IrOpcode::kDead) {
141 TRACE("Dead: #%d:%s\n", node->id(), node->op()->mnemonic());
142 node->ReplaceUses(dead());
143 done = false;
144 }
145 }
146
147 return done;
148 }
149
150 // Connect {loop}, the header of a non-terminating loop, to the end node.
151 Node* ConnectNTL(Node* loop) {
152 TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic());
153 DCHECK_EQ(IrOpcode::kLoop, loop->opcode());
154
155 // Collect all loop effects.
156 NodeVector effects(zone_);
157 for (auto edge : loop->use_edges()) {
158 DCHECK_EQ(loop, edge.to());
159 DCHECK(NodeProperties::IsControlEdge(edge));
160 switch (edge.from()->opcode()) {
161 case IrOpcode::kPhi:
162 break;
163 case IrOpcode::kEffectPhi:
164 effects.push_back(edge.from());
165 break;
166 default:
167 break;
168 }
169 }
170
171 // Compute effects for the Return.
172 Node* effect = graph()->start();
173 int const effects_count = static_cast<int>(effects.size());
174 if (effects_count == 1) {
175 effect = effects[0];
176 } else if (effects_count > 1) {
177 effect = graph()->NewNode(common()->EffectSet(effects_count),
178 effects_count, &effects.front());
179 }
180
181 // Add a terminate to connect the NTL to the end.
182 Node* terminate = graph()->NewNode(common()->Terminate(), effect, loop);
183
184 Node* end = graph()->end();
185 if (end->opcode() == IrOpcode::kDead) {
186 // End is actually the dead node. Make a new end.
187 end = graph()->NewNode(common()->End(1), terminate);
188 graph()->SetEnd(end);
189 return end;
190 }
191 // Append a new input to the end.
192 end->AppendInput(graph()->zone(), terminate);
193 end->set_op(common()->End(end->InputCount()));
194 return terminate;
195 } 66 }
196 67
197 void AddNodesReachableFromRoots(ReachabilityMarker& marked, 68 void AddNodesReachableFromRoots(ReachabilityMarker& marked,
198 NodeVector& nodes) { 69 NodeVector& nodes) {
199 jsgraph_->GetCachedNodes(&nodes); // Consider cached nodes roots. 70 jsgraph_->GetCachedNodes(&nodes); // Consider cached nodes roots.
200 Node* end = graph()->end(); 71 Node* end = graph()->end();
201 marked.SetReachableFromEnd(end); 72 marked.SetReachableFromEnd(end);
202 if (!end->IsDead()) nodes.push_back(end); // Consider end to be a root. 73 if (!end->IsDead()) nodes.push_back(end); // Consider end to be a root.
203 for (Node* node : nodes) marked.SetReachableFromEnd(node); 74 for (Node* node : nodes) marked.SetReachableFromEnd(node);
204 AddBackwardsReachableNodes(marked, nodes, 0); 75 AddBackwardsReachableNodes(marked, nodes, 0);
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 if (result == kFalse) return fvalue; 230 if (result == kFalse) return fvalue;
360 return node; 231 return node;
361 } 232 }
362 233
363 // Reduce redundant phis. 234 // Reduce redundant phis.
364 Node* ReducePhi(Node* node) { 235 Node* ReducePhi(Node* node) {
365 int n = node->InputCount(); 236 int n = node->InputCount();
366 if (n <= 1) return dead(); // No non-control inputs. 237 if (n <= 1) return dead(); // No non-control inputs.
367 if (n == 2) return node->InputAt(0); // Only one non-control input. 238 if (n == 2) return node->InputAt(0); // Only one non-control input.
368 239
369 // Never remove an effect phi from a (potentially non-terminating) loop.
370 // Otherwise, we might end up eliminating effect nodes, such as calls,
371 // before the loop.
372 if (node->opcode() == IrOpcode::kEffectPhi &&
373 NodeProperties::GetControlInput(node)->opcode() == IrOpcode::kLoop) {
374 return node;
375 }
376
377 Node* replacement = NULL; 240 Node* replacement = NULL;
378 auto const inputs = node->inputs(); 241 auto const inputs = node->inputs();
379 for (auto it = inputs.begin(); n > 1; --n, ++it) { 242 for (auto it = inputs.begin(); n > 1; --n, ++it) {
380 Node* input = *it; 243 Node* input = *it;
381 if (input->opcode() == IrOpcode::kDead) continue; // ignore dead inputs. 244 if (input->opcode() == IrOpcode::kDead) continue; // ignore dead inputs.
382 if (input != node && input != replacement) { // non-redundant input. 245 if (input != node && input != replacement) { // non-redundant input.
383 if (replacement != NULL) return node; 246 if (replacement != NULL) return node;
384 replacement = input; 247 replacement = input;
385 } 248 }
386 } 249 }
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 case IrOpcode::kIfFalse: 483 case IrOpcode::kIfFalse:
621 return impl.ReduceIfProjection(node, kFalse); 484 return impl.ReduceIfProjection(node, kFalse);
622 default: 485 default:
623 return node; 486 return node;
624 } 487 }
625 } 488 }
626 489
627 } // namespace compiler 490 } // namespace compiler
628 } // namespace internal 491 } // namespace internal
629 } // namespace v8 492 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/common-operator.cc ('k') | src/compiler/js-inlining.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698