| 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 |