OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |