Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: src/compiler/control-reducer.cc

Issue 1030623003: [turbofan] Fix control reducer bug with walking non-control edges during ConnectNTL phase. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-469605.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-469605.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698