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 |