| 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" |
| 11 #include "src/compiler/node-matchers.h" | 11 #include "src/compiler/node-matchers.h" |
| 12 #include "src/compiler/node-properties.h" | 12 #include "src/compiler/node-properties.h" |
| 13 #include "src/zone-containers.h" | 13 #include "src/zone-containers.h" |
| 14 | 14 |
| 15 namespace v8 { | 15 namespace v8 { |
| 16 namespace internal { | 16 namespace internal { |
| 17 namespace compiler { | 17 namespace compiler { |
| 18 | 18 |
| 19 #define TRACE(...) \ | 19 #define TRACE(...) \ |
| 20 do { \ | 20 do { \ |
| 21 if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \ | 21 if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \ |
| 22 } while (false) | 22 } while (false) |
| 23 | 23 |
| 24 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; | |
| 25 enum Decision { kFalse, kUnknown, kTrue }; | 24 enum Decision { kFalse, kUnknown, kTrue }; |
| 26 | 25 |
| 27 class ReachabilityMarker : public NodeMarker<uint8_t> { | |
| 28 public: | |
| 29 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} | |
| 30 bool SetReachableFromEnd(Node* node) { | |
| 31 uint8_t before = Get(node); | |
| 32 Set(node, before | kFromEnd); | |
| 33 return before & kFromEnd; | |
| 34 } | |
| 35 bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; } | |
| 36 void Push(Node* node) { Set(node, Get(node) | kFwStack); } | |
| 37 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } | |
| 38 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } | |
| 39 | |
| 40 private: | |
| 41 enum Bit { kFromEnd = 1, kFwStack = 2 }; | |
| 42 }; | |
| 43 | |
| 44 | |
| 45 class ControlReducerImpl final : public AdvancedReducer { | 26 class ControlReducerImpl final : public AdvancedReducer { |
| 46 public: | 27 public: |
| 47 Zone* zone_; | 28 Zone* zone_; |
| 48 JSGraph* jsgraph_; | 29 JSGraph* jsgraph_; |
| 49 int max_phis_for_select_; | 30 int max_phis_for_select_; |
| 50 | 31 |
| 51 ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph) | 32 ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph) |
| 52 : AdvancedReducer(editor), | 33 : AdvancedReducer(editor), |
| 53 zone_(zone), | 34 zone_(zone), |
| 54 jsgraph_(jsgraph), | 35 jsgraph_(jsgraph), |
| 55 max_phis_for_select_(0) {} | 36 max_phis_for_select_(0) {} |
| 56 | 37 |
| 57 Graph* graph() { return jsgraph_->graph(); } | 38 Graph* graph() { return jsgraph_->graph(); } |
| 58 CommonOperatorBuilder* common() { return jsgraph_->common(); } | 39 CommonOperatorBuilder* common() { return jsgraph_->common(); } |
| 59 Node* dead() { return jsgraph_->DeadControl(); } | 40 Node* dead() { return jsgraph_->DeadControl(); } |
| 60 | 41 |
| 61 // Finish reducing the graph by trimming nodes. | |
| 62 bool Finish() final { | |
| 63 // TODO(bmeurer): Move this to the GraphReducer. | |
| 64 Trim(); | |
| 65 return true; | |
| 66 } | |
| 67 | |
| 68 void AddNodesReachableFromRoots(ReachabilityMarker& marked, | |
| 69 NodeVector& nodes) { | |
| 70 jsgraph_->GetCachedNodes(&nodes); // Consider cached nodes roots. | |
| 71 Node* end = graph()->end(); | |
| 72 marked.SetReachableFromEnd(end); | |
| 73 if (!end->IsDead()) nodes.push_back(end); // Consider end to be a root. | |
| 74 for (Node* node : nodes) marked.SetReachableFromEnd(node); | |
| 75 AddBackwardsReachableNodes(marked, nodes, 0); | |
| 76 } | |
| 77 | |
| 78 void AddBackwardsReachableNodes(ReachabilityMarker& marked, NodeVector& nodes, | |
| 79 size_t cursor) { | |
| 80 while (cursor < nodes.size()) { | |
| 81 Node* node = nodes[cursor++]; | |
| 82 for (Node* const input : node->inputs()) { | |
| 83 if (!marked.SetReachableFromEnd(input)) { | |
| 84 nodes.push_back(input); | |
| 85 } | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 void Trim() { | |
| 91 // Gather all nodes backwards-reachable from end through inputs. | |
| 92 ReachabilityMarker marked(graph()); | |
| 93 NodeVector nodes(zone_); | |
| 94 jsgraph_->GetCachedNodes(&nodes); | |
| 95 AddNodesReachableFromRoots(marked, nodes); | |
| 96 TrimNodes(marked, nodes); | |
| 97 } | |
| 98 | |
| 99 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) { | |
| 100 // Remove dead->live edges. | |
| 101 for (size_t j = 0; j < nodes.size(); j++) { | |
| 102 Node* node = nodes[j]; | |
| 103 for (Edge edge : node->use_edges()) { | |
| 104 Node* use = edge.from(); | |
| 105 if (!marked.IsReachableFromEnd(use)) { | |
| 106 TRACE("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(), | |
| 107 use->op()->mnemonic(), edge.index(), node->id(), | |
| 108 node->op()->mnemonic()); | |
| 109 edge.UpdateTo(NULL); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 #if DEBUG | |
| 114 // Verify that no inputs to live nodes are NULL. | |
| 115 for (Node* node : nodes) { | |
| 116 for (int index = 0; index < node->InputCount(); index++) { | |
| 117 Node* input = node->InputAt(index); | |
| 118 if (input == nullptr) { | |
| 119 std::ostringstream str; | |
| 120 str << "GraphError: node #" << node->id() << ":" << *node->op() | |
| 121 << "(input @" << index << ") == null"; | |
| 122 FATAL(str.str().c_str()); | |
| 123 } | |
| 124 if (input->opcode() == IrOpcode::kDead) { | |
| 125 std::ostringstream str; | |
| 126 str << "GraphError: node #" << node->id() << ":" << *node->op() | |
| 127 << "(input @" << index << ") == dead"; | |
| 128 FATAL(str.str().c_str()); | |
| 129 } | |
| 130 } | |
| 131 for (Node* use : node->uses()) { | |
| 132 CHECK(marked.IsReachableFromEnd(use)); | |
| 133 } | |
| 134 } | |
| 135 #endif | |
| 136 } | |
| 137 | |
| 138 //=========================================================================== | 42 //=========================================================================== |
| 139 // Reducer implementation: perform reductions on a node. | 43 // Reducer implementation: perform reductions on a node. |
| 140 //=========================================================================== | 44 //=========================================================================== |
| 141 Reduction Reduce(Node* node) override { | 45 Reduction Reduce(Node* node) override { |
| 142 if (node->op()->ControlInputCount() == 1 || | 46 if (node->op()->ControlInputCount() == 1 || |
| 143 node->opcode() == IrOpcode::kLoop) { | 47 node->opcode() == IrOpcode::kLoop) { |
| 144 // If a node has only one control input and it is dead, replace with dead. | 48 // If a node has only one control input and it is dead, replace with dead. |
| 145 Node* control = NodeProperties::GetControlInput(node); | 49 Node* control = NodeProperties::GetControlInput(node); |
| 146 if (control->opcode() == IrOpcode::kDead) { | 50 if (control->opcode() == IrOpcode::kDead) { |
| 147 TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); | 51 TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 node->ReplaceUses(replacement); | 340 node->ReplaceUses(replacement); |
| 437 } | 341 } |
| 438 void Revisit(Node* node) final {} | 342 void Revisit(Node* node) final {} |
| 439 void ReplaceWithValue(Node* node, Node* value, Node* effect, | 343 void ReplaceWithValue(Node* node, Node* value, Node* effect, |
| 440 Node* control) final {} | 344 Node* control) final {} |
| 441 }; | 345 }; |
| 442 | 346 |
| 443 } // namespace | 347 } // namespace |
| 444 | 348 |
| 445 | 349 |
| 446 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { | |
| 447 DummyEditor editor; | |
| 448 ControlReducerImpl impl(&editor, zone, jsgraph); | |
| 449 impl.Trim(); | |
| 450 } | |
| 451 | |
| 452 | |
| 453 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node, | 350 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node, |
| 454 int max_phis_for_select) { | 351 int max_phis_for_select) { |
| 455 Zone zone; | 352 Zone zone; |
| 456 DummyEditor editor; | 353 DummyEditor editor; |
| 457 ControlReducerImpl impl(&editor, &zone, jsgraph); | 354 ControlReducerImpl impl(&editor, &zone, jsgraph); |
| 458 impl.max_phis_for_select_ = max_phis_for_select; | 355 impl.max_phis_for_select_ = max_phis_for_select; |
| 459 return impl.ReduceMerge(node); | 356 return impl.ReduceMerge(node); |
| 460 } | 357 } |
| 461 | 358 |
| 462 | 359 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 478 case IrOpcode::kIfFalse: | 375 case IrOpcode::kIfFalse: |
| 479 return impl.ReduceIfProjection(node, kFalse); | 376 return impl.ReduceIfProjection(node, kFalse); |
| 480 default: | 377 default: |
| 481 return node; | 378 return node; |
| 482 } | 379 } |
| 483 } | 380 } |
| 484 | 381 |
| 485 } // namespace compiler | 382 } // namespace compiler |
| 486 } // namespace internal | 383 } // namespace internal |
| 487 } // namespace v8 | 384 } // namespace v8 |
| OLD | NEW |