| 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/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/node-marker.h" | 9 #include "src/compiler/node-marker.h" |
| 10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 ReachabilityMarker marked(graph()); | 99 ReachabilityMarker marked(graph()); |
| 100 NodeVector nodes(zone_); | 100 NodeVector nodes(zone_); |
| 101 AddNodesReachableFromEnd(marked, nodes); | 101 AddNodesReachableFromEnd(marked, nodes); |
| 102 | 102 |
| 103 // Walk forward through control nodes, looking for back edges to nodes | 103 // Walk forward through control nodes, looking for back edges to nodes |
| 104 // that are not connected to end. Those are non-terminating loops (NTLs). | 104 // that are not connected to end. Those are non-terminating loops (NTLs). |
| 105 Node* start = graph()->start(); | 105 Node* start = graph()->start(); |
| 106 marked.Push(start); | 106 marked.Push(start); |
| 107 marked.SetReachableFromStart(start); | 107 marked.SetReachableFromStart(start); |
| 108 | 108 |
| 109 // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid | 109 // We use a stack of (Node, Node::UseEdges::iterator) pairs to avoid |
| 110 // O(n^2) traversal. | 110 // O(n^2) traversal. |
| 111 typedef std::pair<Node*, Node::Uses::const_iterator> FwIter; | 111 typedef std::pair<Node*, Node::UseEdges::iterator> FwIter; |
| 112 ZoneVector<FwIter> fw_stack(zone_); | 112 ZoneVector<FwIter> fw_stack(zone_); |
| 113 fw_stack.push_back(FwIter(start, start->uses().begin())); | 113 fw_stack.push_back(FwIter(start, start->use_edges().begin())); |
| 114 | 114 |
| 115 while (!fw_stack.empty()) { | 115 while (!fw_stack.empty()) { |
| 116 Node* node = fw_stack.back().first; | 116 Node* node = fw_stack.back().first; |
| 117 TRACE("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()); | 117 TRACE("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 118 bool pop = true; | 118 bool pop = true; |
| 119 while (fw_stack.back().second != node->uses().end()) { | 119 while (fw_stack.back().second != node->use_edges().end()) { |
| 120 Node* succ = *(fw_stack.back().second); | 120 Edge edge = *(fw_stack.back().second); |
| 121 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { | 121 if (NodeProperties::IsControlEdge(edge) && |
| 122 // {succ} is on stack and not reachable from end. | 122 edge.from()->op()->ControlOutputCount() > 0) { |
| 123 Node* added = ConnectNTL(succ); | 123 // Only walk control edges to control nodes. |
| 124 nodes.push_back(added); | 124 Node* succ = edge.from(); |
| 125 marked.SetReachableFromEnd(added); | |
| 126 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); | |
| 127 | 125 |
| 128 // Reset the use iterators for the entire stack. | 126 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { |
| 129 for (size_t i = 0; i < fw_stack.size(); i++) { | 127 // {succ} is on stack and not reachable from end. |
| 130 FwIter& iter = fw_stack[i]; | 128 Node* added = ConnectNTL(succ); |
| 131 fw_stack[i] = FwIter(iter.first, iter.first->uses().begin()); | 129 nodes.push_back(added); |
| 130 marked.SetReachableFromEnd(added); |
| 131 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); |
| 132 |
| 133 // Reset the use iterators for the entire stack. |
| 134 for (size_t i = 0; i < fw_stack.size(); i++) { |
| 135 FwIter& iter = fw_stack[i]; |
| 136 fw_stack[i] = FwIter(iter.first, iter.first->use_edges().begin()); |
| 137 } |
| 138 pop = false; // restart traversing successors of this node. |
| 139 break; |
| 132 } | 140 } |
| 133 pop = false; // restart traversing successors of this node. | 141 if (!marked.IsReachableFromStart(succ)) { |
| 134 break; | 142 // {succ} is not yet reached from start. |
| 135 } | 143 marked.Push(succ); |
| 136 if (succ->op()->ControlOutputCount() > 0 && | 144 marked.SetReachableFromStart(succ); |
| 137 !marked.IsReachableFromStart(succ)) { | 145 fw_stack.push_back(FwIter(succ, succ->use_edges().begin())); |
| 138 // {succ} is a control node and not yet reached from start. | 146 pop = false; // "recurse" into successor control node. |
| 139 marked.Push(succ); | 147 break; |
| 140 marked.SetReachableFromStart(succ); | 148 } |
| 141 fw_stack.push_back(FwIter(succ, succ->uses().begin())); | |
| 142 pop = false; // "recurse" into successor control node. | |
| 143 break; | |
| 144 } | 149 } |
| 145 ++fw_stack.back().second; | 150 ++fw_stack.back().second; |
| 146 } | 151 } |
| 147 if (pop) { | 152 if (pop) { |
| 148 marked.Pop(node); | 153 marked.Pop(node); |
| 149 fw_stack.pop_back(); | 154 fw_stack.pop_back(); |
| 150 } | 155 } |
| 151 } | 156 } |
| 152 | 157 |
| 153 // Trim references from dead nodes to live nodes first. | 158 // Trim references from dead nodes to live nodes first. |
| 154 jsgraph_->GetCachedNodes(&nodes); | 159 jsgraph_->GetCachedNodes(&nodes); |
| 155 TrimNodes(marked, nodes); | 160 TrimNodes(marked, nodes); |
| 156 | 161 |
| 157 // Any control nodes not reachable from start are dead, even loops. | 162 // Any control nodes not reachable from start are dead, even loops. |
| 158 for (size_t i = 0; i < nodes.size(); i++) { | 163 for (size_t i = 0; i < nodes.size(); i++) { |
| 159 Node* node = nodes[i]; | 164 Node* node = nodes[i]; |
| 160 if (node->op()->ControlOutputCount() > 0 && | 165 if (node->op()->ControlOutputCount() > 0 && |
| 161 !marked.IsReachableFromStart(node)) { | 166 !marked.IsReachableFromStart(node)) { |
| 162 ReplaceNode(node, dead()); // uses will be added to revisit queue. | 167 ReplaceNode(node, dead()); // uses will be added to revisit queue. |
| 163 } | 168 } |
| 164 } | 169 } |
| 165 return TryRevisit(); // try to push a node onto the stack. | 170 return TryRevisit(); // try to push a node onto the stack. |
| 166 } | 171 } |
| 167 | 172 |
| 168 // Connect {loop}, the header of a non-terminating loop, to the end node. | 173 // Connect {loop}, the header of a non-terminating loop, to the end node. |
| 169 Node* ConnectNTL(Node* loop) { | 174 Node* ConnectNTL(Node* loop) { |
| 170 TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); | 175 TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); |
| 176 DCHECK_EQ(IrOpcode::kLoop, loop->opcode()); |
| 171 | 177 |
| 172 Node* always = graph()->NewNode(common_->Always()); | 178 Node* always = graph()->NewNode(common_->Always()); |
| 173 // Mark the node as visited so that we can revisit later. | 179 // Mark the node as visited so that we can revisit later. |
| 174 MarkAsVisited(always); | 180 MarkAsVisited(always); |
| 175 | 181 |
| 176 Node* branch = graph()->NewNode(common_->Branch(), always, loop); | 182 Node* branch = graph()->NewNode(common_->Branch(), always, loop); |
| 177 // Mark the node as visited so that we can revisit later. | 183 // Mark the node as visited so that we can revisit later. |
| 178 MarkAsVisited(branch); | 184 MarkAsVisited(branch); |
| 179 | 185 |
| 180 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); | 186 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 int index = 0; | 508 int index = 0; |
| 503 int live_index = 0; | 509 int live_index = 0; |
| 504 for (Node* const input : node->inputs()) { | 510 for (Node* const input : node->inputs()) { |
| 505 if (input->opcode() != IrOpcode::kDead) { | 511 if (input->opcode() != IrOpcode::kDead) { |
| 506 live++; | 512 live++; |
| 507 live_index = index; | 513 live_index = index; |
| 508 } | 514 } |
| 509 index++; | 515 index++; |
| 510 } | 516 } |
| 511 | 517 |
| 512 TRACE("ReduceMerge: #%d:%s (%d live)\n", node->id(), node->op()->mnemonic(), | 518 TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(), |
| 513 live); | 519 node->op()->mnemonic(), live, index); |
| 514 | 520 |
| 515 if (live == 0) return dead(); // no remaining inputs. | 521 if (live == 0) return dead(); // no remaining inputs. |
| 516 | 522 |
| 517 // Gather phis and effect phis to be edited. | 523 // Gather phis and effect phis to be edited. |
| 518 ZoneVector<Node*> phis(zone_); | 524 ZoneVector<Node*> phis(zone_); |
| 519 for (Node* const use : node->uses()) { | 525 for (Node* const use : node->uses()) { |
| 520 if (NodeProperties::IsPhi(use)) phis.push_back(use); | 526 if (NodeProperties::IsPhi(use)) phis.push_back(use); |
| 521 } | 527 } |
| 522 | 528 |
| 523 if (live == 1) { | 529 if (live == 1) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 return node; | 576 return node; |
| 571 } | 577 } |
| 572 | 578 |
| 573 // Reduce branches if they have constant inputs. | 579 // Reduce branches if they have constant inputs. |
| 574 Node* ReduceIfTrue(Node* node) { | 580 Node* ReduceIfTrue(Node* node) { |
| 575 Node* branch = node->InputAt(0); | 581 Node* branch = node->InputAt(0); |
| 576 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 582 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 577 Decision result = DecideCondition(branch->InputAt(0)); | 583 Decision result = DecideCondition(branch->InputAt(0)); |
| 578 if (result == kTrue) { | 584 if (result == kTrue) { |
| 579 // fold a true branch by replacing IfTrue with the branch control. | 585 // fold a true branch by replacing IfTrue with the branch control. |
| 580 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 586 TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
| 581 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 587 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 582 return branch->InputAt(1); | 588 return branch->InputAt(1); |
| 583 } | 589 } |
| 584 return result == kUnknown ? node : dead(); | 590 return result == kUnknown ? node : dead(); |
| 585 } | 591 } |
| 586 | 592 |
| 587 // Reduce branches if they have constant inputs. | 593 // Reduce branches if they have constant inputs. |
| 588 Node* ReduceIfFalse(Node* node) { | 594 Node* ReduceIfFalse(Node* node) { |
| 589 Node* branch = node->InputAt(0); | 595 Node* branch = node->InputAt(0); |
| 590 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 596 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 591 Decision result = DecideCondition(branch->InputAt(0)); | 597 Decision result = DecideCondition(branch->InputAt(0)); |
| 592 if (result == kFalse) { | 598 if (result == kFalse) { |
| 593 // fold a false branch by replacing IfFalse with the branch control. | 599 // fold a false branch by replacing IfFalse with the branch control. |
| 594 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 600 TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
| 595 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 601 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 596 return branch->InputAt(1); | 602 return branch->InputAt(1); |
| 597 } | 603 } |
| 598 return result == kUnknown ? node : dead(); | 604 return result == kUnknown ? node : dead(); |
| 599 } | 605 } |
| 600 | 606 |
| 601 // Remove inputs to {node} corresponding to the dead inputs to {merge} | 607 // Remove inputs to {node} corresponding to the dead inputs to {merge} |
| 602 // and compact the remaining inputs, updating the operator. | 608 // and compact the remaining inputs, updating the operator. |
| 603 void RemoveDeadInputs(Node* merge, Node* node) { | 609 void RemoveDeadInputs(Node* merge, Node* node) { |
| 604 int live = 0; | 610 int live = 0; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 return impl.ReduceIfTrue(node); | 684 return impl.ReduceIfTrue(node); |
| 679 case IrOpcode::kIfFalse: | 685 case IrOpcode::kIfFalse: |
| 680 return impl.ReduceIfFalse(node); | 686 return impl.ReduceIfFalse(node); |
| 681 default: | 687 default: |
| 682 return node; | 688 return node; |
| 683 } | 689 } |
| 684 } | 690 } |
| 685 } | 691 } |
| 686 } | 692 } |
| 687 } // namespace v8::internal::compiler | 693 } // namespace v8::internal::compiler |
| OLD | NEW |