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" |
11 #include "src/compiler/node-properties.h" | 11 #include "src/compiler/node-properties.h" |
12 #include "src/zone-containers.h" | 12 #include "src/zone-containers.h" |
13 | 13 |
14 #define TRACE(...) \ | |
Michael Starzinger
2015/03/17 17:08:07
nit: Can we move it into the namespaces for consis
titzer
2015/03/17 17:32:42
Done.
| |
15 do { \ | |
16 if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \ | |
17 } while (false) | |
18 | |
14 namespace v8 { | 19 namespace v8 { |
15 namespace internal { | 20 namespace internal { |
16 namespace compiler { | 21 namespace compiler { |
17 | 22 |
18 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; | 23 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; |
19 enum Decision { kFalse, kUnknown, kTrue }; | 24 enum Decision { kFalse, kUnknown, kTrue }; |
20 | 25 |
21 class ReachabilityMarker : public NodeMarker<uint8_t> { | 26 class ReachabilityMarker : public NodeMarker<uint8_t> { |
22 public: | 27 public: |
23 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} | 28 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} |
(...skipping 11 matching lines...) Expand all Loading... | |
35 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } | 40 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } |
36 void Push(Node* node) { Set(node, Get(node) | kFwStack); } | 41 void Push(Node* node) { Set(node, Get(node) | kFwStack); } |
37 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } | 42 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } |
38 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } | 43 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } |
39 | 44 |
40 private: | 45 private: |
41 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; | 46 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; |
42 }; | 47 }; |
43 | 48 |
44 | 49 |
45 #define TRACE(x) \ | |
46 if (FLAG_trace_turbo_reduction) PrintF x | |
47 | |
48 class ControlReducerImpl { | 50 class ControlReducerImpl { |
49 public: | 51 public: |
50 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, | 52 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, |
51 CommonOperatorBuilder* common) | 53 CommonOperatorBuilder* common) |
52 : zone_(zone), | 54 : zone_(zone), |
53 jsgraph_(jsgraph), | 55 jsgraph_(jsgraph), |
54 common_(common), | 56 common_(common), |
55 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), | 57 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), |
56 stack_(zone_), | 58 stack_(zone_), |
57 revisit_(zone_) {} | 59 revisit_(zone_) {} |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
105 marked.SetReachableFromStart(start); | 107 marked.SetReachableFromStart(start); |
106 | 108 |
107 // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid | 109 // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid |
108 // O(n^2) traversal. | 110 // O(n^2) traversal. |
109 typedef std::pair<Node*, Node::Uses::const_iterator> FwIter; | 111 typedef std::pair<Node*, Node::Uses::const_iterator> FwIter; |
110 ZoneVector<FwIter> fw_stack(zone_); | 112 ZoneVector<FwIter> fw_stack(zone_); |
111 fw_stack.push_back(FwIter(start, start->uses().begin())); | 113 fw_stack.push_back(FwIter(start, start->uses().begin())); |
112 | 114 |
113 while (!fw_stack.empty()) { | 115 while (!fw_stack.empty()) { |
114 Node* node = fw_stack.back().first; | 116 Node* node = fw_stack.back().first; |
115 TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic())); | 117 TRACE("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()); |
116 bool pop = true; | 118 bool pop = true; |
117 while (fw_stack.back().second != node->uses().end()) { | 119 while (fw_stack.back().second != node->uses().end()) { |
118 Node* succ = *(fw_stack.back().second); | 120 Node* succ = *(fw_stack.back().second); |
119 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { | 121 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { |
120 // {succ} is on stack and not reachable from end. | 122 // {succ} is on stack and not reachable from end. |
121 Node* added = ConnectNTL(succ); | 123 Node* added = ConnectNTL(succ); |
122 nodes.push_back(added); | 124 nodes.push_back(added); |
123 marked.SetReachableFromEnd(added); | 125 marked.SetReachableFromEnd(added); |
124 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); | 126 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); |
125 | 127 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
158 if (node->op()->ControlOutputCount() > 0 && | 160 if (node->op()->ControlOutputCount() > 0 && |
159 !marked.IsReachableFromStart(node)) { | 161 !marked.IsReachableFromStart(node)) { |
160 ReplaceNode(node, dead()); // uses will be added to revisit queue. | 162 ReplaceNode(node, dead()); // uses will be added to revisit queue. |
161 } | 163 } |
162 } | 164 } |
163 return TryRevisit(); // try to push a node onto the stack. | 165 return TryRevisit(); // try to push a node onto the stack. |
164 } | 166 } |
165 | 167 |
166 // Connect {loop}, the header of a non-terminating loop, to the end node. | 168 // Connect {loop}, the header of a non-terminating loop, to the end node. |
167 Node* ConnectNTL(Node* loop) { | 169 Node* ConnectNTL(Node* loop) { |
168 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); | 170 TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); |
169 | 171 |
170 Node* always = graph()->NewNode(common_->Always()); | 172 Node* always = graph()->NewNode(common_->Always()); |
171 // Mark the node as visited so that we can revisit later. | 173 // Mark the node as visited so that we can revisit later. |
172 MarkAsVisited(always); | 174 MarkAsVisited(always); |
173 | 175 |
174 Node* branch = graph()->NewNode(common_->Branch(), always, loop); | 176 Node* branch = graph()->NewNode(common_->Branch(), always, loop); |
175 // Mark the node as visited so that we can revisit later. | 177 // Mark the node as visited so that we can revisit later. |
176 MarkAsVisited(branch); | 178 MarkAsVisited(branch); |
177 | 179 |
178 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); | 180 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 TrimNodes(marked, nodes); | 275 TrimNodes(marked, nodes); |
274 } | 276 } |
275 | 277 |
276 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) { | 278 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) { |
277 // Remove dead->live edges. | 279 // Remove dead->live edges. |
278 for (size_t j = 0; j < nodes.size(); j++) { | 280 for (size_t j = 0; j < nodes.size(); j++) { |
279 Node* node = nodes[j]; | 281 Node* node = nodes[j]; |
280 for (Edge edge : node->use_edges()) { | 282 for (Edge edge : node->use_edges()) { |
281 Node* use = edge.from(); | 283 Node* use = edge.from(); |
282 if (!marked.IsReachableFromEnd(use)) { | 284 if (!marked.IsReachableFromEnd(use)) { |
283 TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(), | 285 TRACE("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(), |
284 use->op()->mnemonic(), edge.index(), node->id(), | 286 use->op()->mnemonic(), edge.index(), node->id(), |
285 node->op()->mnemonic())); | 287 node->op()->mnemonic()); |
286 edge.UpdateTo(NULL); | 288 edge.UpdateTo(NULL); |
287 } | 289 } |
288 } | 290 } |
289 } | 291 } |
290 #if DEBUG | 292 #if DEBUG |
291 // Verify that no inputs to live nodes are NULL. | 293 // Verify that no inputs to live nodes are NULL. |
292 for (Node* node : nodes) { | 294 for (Node* node : nodes) { |
293 for (int index = 0; index < node->InputCount(); index++) { | 295 for (int index = 0; index < node->InputCount(); index++) { |
294 Node* input = node->InputAt(index); | 296 Node* input = node->InputAt(index); |
295 if (input == nullptr) { | 297 if (input == nullptr) { |
(...skipping 19 matching lines...) Expand all Loading... | |
315 // Reduce the node on the top of the stack. | 317 // Reduce the node on the top of the stack. |
316 // If an input {i} is not yet visited or needs to be revisited, push {i} onto | 318 // If an input {i} is not yet visited or needs to be revisited, push {i} onto |
317 // the stack and return. Otherwise, all inputs are visited, so apply | 319 // the stack and return. Otherwise, all inputs are visited, so apply |
318 // reductions for {node} and pop it off the stack. | 320 // reductions for {node} and pop it off the stack. |
319 void ReduceTop() { | 321 void ReduceTop() { |
320 size_t height = stack_.size(); | 322 size_t height = stack_.size(); |
321 Node* node = stack_.back(); | 323 Node* node = stack_.back(); |
322 | 324 |
323 if (node->IsDead()) return Pop(); // Node was killed while on stack. | 325 if (node->IsDead()) return Pop(); // Node was killed while on stack. |
324 | 326 |
325 TRACE(("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic())); | 327 TRACE("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic()); |
326 | 328 |
327 // Recurse on an input if necessary. | 329 // Recurse on an input if necessary. |
328 for (Node* const input : node->inputs()) { | 330 for (Node* const input : node->inputs()) { |
329 DCHECK(input); | 331 DCHECK(input); |
330 if (Recurse(input)) return; | 332 if (Recurse(input)) return; |
331 } | 333 } |
332 | 334 |
333 // All inputs should be visited or on stack. Apply reductions to node. | 335 // All inputs should be visited or on stack. Apply reductions to node. |
334 Node* replacement = ReduceNode(node); | 336 Node* replacement = ReduceNode(node); |
335 if (replacement != node) ReplaceNode(node, replacement); | 337 if (replacement != node) ReplaceNode(node, replacement); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
367 DCHECK_GE(pos, 0); | 369 DCHECK_GE(pos, 0); |
368 DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]); | 370 DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]); |
369 state_[stack_[pos]->id()] = kVisited; | 371 state_[stack_[pos]->id()] = kVisited; |
370 stack_.pop_back(); | 372 stack_.pop_back(); |
371 } | 373 } |
372 | 374 |
373 // Queue a node to be revisited if it has been visited once already. | 375 // Queue a node to be revisited if it has been visited once already. |
374 void Revisit(Node* node) { | 376 void Revisit(Node* node) { |
375 size_t id = static_cast<size_t>(node->id()); | 377 size_t id = static_cast<size_t>(node->id()); |
376 if (id < state_.size() && state_[id] == kVisited) { | 378 if (id < state_.size() && state_[id] == kVisited) { |
377 TRACE((" Revisit #%d:%s\n", node->id(), node->op()->mnemonic())); | 379 TRACE(" Revisit #%d:%s\n", node->id(), node->op()->mnemonic()); |
378 state_[id] = kRevisit; | 380 state_[id] = kRevisit; |
379 revisit_.push_back(node); | 381 revisit_.push_back(node); |
380 } | 382 } |
381 } | 383 } |
382 | 384 |
383 // Mark {node} as visited. | 385 // Mark {node} as visited. |
384 void MarkAsVisited(Node* node) { | 386 void MarkAsVisited(Node* node) { |
385 size_t id = static_cast<size_t>(node->id()); | 387 size_t id = static_cast<size_t>(node->id()); |
386 EnsureStateSize(id); | 388 EnsureStateSize(id); |
387 state_[id] = kVisited; | 389 state_[id] = kVisited; |
388 } | 390 } |
389 | 391 |
390 Node* dead() { return jsgraph_->DeadControl(); } | 392 Node* dead() { return jsgraph_->DeadControl(); } |
391 | 393 |
392 //=========================================================================== | 394 //=========================================================================== |
393 // Reducer implementation: perform reductions on a node. | 395 // Reducer implementation: perform reductions on a node. |
394 //=========================================================================== | 396 //=========================================================================== |
395 Node* ReduceNode(Node* node) { | 397 Node* ReduceNode(Node* node) { |
396 if (node->op()->ControlInputCount() == 1 || | 398 if (node->op()->ControlInputCount() == 1 || |
397 node->opcode() == IrOpcode::kLoop) { | 399 node->opcode() == IrOpcode::kLoop) { |
398 // If a node has only one control input and it is dead, replace with dead. | 400 // If a node has only one control input and it is dead, replace with dead. |
399 Node* control = NodeProperties::GetControlInput(node); | 401 Node* control = NodeProperties::GetControlInput(node); |
400 if (control->opcode() == IrOpcode::kDead) { | 402 if (control->opcode() == IrOpcode::kDead) { |
401 TRACE(("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic())); | 403 TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); |
402 return control; | 404 return control; |
403 } | 405 } |
404 } | 406 } |
405 | 407 |
406 // Reduce branches, phis, and merges. | 408 // Reduce branches, phis, and merges. |
407 switch (node->opcode()) { | 409 switch (node->opcode()) { |
408 case IrOpcode::kBranch: | 410 case IrOpcode::kBranch: |
409 return ReduceBranch(node); | 411 return ReduceBranch(node); |
410 case IrOpcode::kIfTrue: | 412 case IrOpcode::kIfTrue: |
411 return ReduceIfTrue(node); | 413 return ReduceIfTrue(node); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
500 int index = 0; | 502 int index = 0; |
501 int live_index = 0; | 503 int live_index = 0; |
502 for (Node* const input : node->inputs()) { | 504 for (Node* const input : node->inputs()) { |
503 if (input->opcode() != IrOpcode::kDead) { | 505 if (input->opcode() != IrOpcode::kDead) { |
504 live++; | 506 live++; |
505 live_index = index; | 507 live_index = index; |
506 } | 508 } |
507 index++; | 509 index++; |
508 } | 510 } |
509 | 511 |
510 TRACE(("ReduceMerge: #%d:%s (%d live)\n", node->id(), | 512 TRACE("ReduceMerge: #%d:%s (%d live)\n", node->id(), node->op()->mnemonic(), |
511 node->op()->mnemonic(), live)); | 513 live); |
512 | 514 |
513 if (live == 0) return dead(); // no remaining inputs. | 515 if (live == 0) return dead(); // no remaining inputs. |
514 | 516 |
515 // Gather phis and effect phis to be edited. | 517 // Gather phis and effect phis to be edited. |
516 ZoneVector<Node*> phis(zone_); | 518 ZoneVector<Node*> phis(zone_); |
517 for (Node* const use : node->uses()) { | 519 for (Node* const use : node->uses()) { |
518 if (NodeProperties::IsPhi(use)) phis.push_back(use); | 520 if (NodeProperties::IsPhi(use)) phis.push_back(use); |
519 } | 521 } |
520 | 522 |
521 if (live == 1) { | 523 if (live == 1) { |
522 // All phis are redundant. Replace them with their live input. | 524 // All phis are redundant. Replace them with their live input. |
523 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); | 525 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); |
524 // The merge itself is redundant. | 526 // The merge itself is redundant. |
525 return node->InputAt(live_index); | 527 return node->InputAt(live_index); |
526 } | 528 } |
527 | 529 |
528 DCHECK_LE(2, live); | 530 DCHECK_LE(2, live); |
529 | 531 |
530 if (live < node->InputCount()) { | 532 if (live < node->InputCount()) { |
531 // Edit phis in place, removing dead inputs and revisiting them. | 533 // Edit phis in place, removing dead inputs and revisiting them. |
532 for (Node* const phi : phis) { | 534 for (Node* const phi : phis) { |
533 TRACE((" PhiInMerge: #%d:%s (%d live)\n", phi->id(), | 535 TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(), |
534 phi->op()->mnemonic(), live)); | 536 phi->op()->mnemonic(), live); |
535 RemoveDeadInputs(node, phi); | 537 RemoveDeadInputs(node, phi); |
536 Revisit(phi); | 538 Revisit(phi); |
537 } | 539 } |
538 // Edit the merge in place, removing dead inputs. | 540 // Edit the merge in place, removing dead inputs. |
539 RemoveDeadInputs(node, node); | 541 RemoveDeadInputs(node, node); |
540 } | 542 } |
541 | 543 |
542 DCHECK_EQ(live, node->InputCount()); | 544 DCHECK_EQ(live, node->InputCount()); |
543 | 545 |
544 // Check if it's an unused diamond. | 546 // Check if it's an unused diamond. |
545 if (live == 2 && phis.empty()) { | 547 if (live == 2 && phis.empty()) { |
546 Node* node0 = node->InputAt(0); | 548 Node* node0 = node->InputAt(0); |
547 Node* node1 = node->InputAt(1); | 549 Node* node1 = node->InputAt(1); |
548 if (((node0->opcode() == IrOpcode::kIfTrue && | 550 if (((node0->opcode() == IrOpcode::kIfTrue && |
549 node1->opcode() == IrOpcode::kIfFalse) || | 551 node1->opcode() == IrOpcode::kIfFalse) || |
550 (node1->opcode() == IrOpcode::kIfTrue && | 552 (node1->opcode() == IrOpcode::kIfTrue && |
551 node0->opcode() == IrOpcode::kIfFalse)) && | 553 node0->opcode() == IrOpcode::kIfFalse)) && |
552 node0->OwnedBy(node) && node1->OwnedBy(node)) { | 554 node0->OwnedBy(node) && node1->OwnedBy(node)) { |
553 Node* branch0 = NodeProperties::GetControlInput(node0); | 555 Node* branch0 = NodeProperties::GetControlInput(node0); |
554 Node* branch1 = NodeProperties::GetControlInput(node1); | 556 Node* branch1 = NodeProperties::GetControlInput(node1); |
555 if (branch0 == branch1) { | 557 if (branch0 == branch1) { |
556 // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes | 558 // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
557 // have users except for the Merge and the Merge has no Phi or | 559 // have users except for the Merge and the Merge has no Phi or |
558 // EffectPhi uses, so replace the Merge with the control input of the | 560 // EffectPhi uses, so replace the Merge with the control input of the |
559 // diamond. | 561 // diamond. |
560 TRACE((" DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(), | 562 TRACE(" DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(), |
561 node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(), | 563 node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(), |
562 branch0->id(), branch0->op()->mnemonic())); | 564 branch0->id(), branch0->op()->mnemonic()); |
563 return NodeProperties::GetControlInput(branch0); | 565 return NodeProperties::GetControlInput(branch0); |
564 } | 566 } |
565 } | 567 } |
566 } | 568 } |
567 | 569 |
568 return node; | 570 return node; |
569 } | 571 } |
570 | 572 |
571 // Reduce branches if they have constant inputs. | 573 // Reduce branches if they have constant inputs. |
572 Node* ReduceIfTrue(Node* node) { | 574 Node* ReduceIfTrue(Node* node) { |
573 Node* branch = node->InputAt(0); | 575 Node* branch = node->InputAt(0); |
574 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 576 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
575 Decision result = DecideCondition(branch->InputAt(0)); | 577 Decision result = DecideCondition(branch->InputAt(0)); |
576 if (result == kTrue) { | 578 if (result == kTrue) { |
577 // fold a true branch by replacing IfTrue with the branch control. | 579 // fold a true branch by replacing IfTrue with the branch control. |
578 TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 580 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
579 branch->op()->mnemonic(), node->id(), node->op()->mnemonic())); | 581 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
580 return branch->InputAt(1); | 582 return branch->InputAt(1); |
581 } | 583 } |
582 return result == kUnknown ? node : dead(); | 584 return result == kUnknown ? node : dead(); |
583 } | 585 } |
584 | 586 |
585 // Reduce branches if they have constant inputs. | 587 // Reduce branches if they have constant inputs. |
586 Node* ReduceIfFalse(Node* node) { | 588 Node* ReduceIfFalse(Node* node) { |
587 Node* branch = node->InputAt(0); | 589 Node* branch = node->InputAt(0); |
588 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 590 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
589 Decision result = DecideCondition(branch->InputAt(0)); | 591 Decision result = DecideCondition(branch->InputAt(0)); |
590 if (result == kFalse) { | 592 if (result == kFalse) { |
591 // fold a false branch by replacing IfFalse with the branch control. | 593 // fold a false branch by replacing IfFalse with the branch control. |
592 TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 594 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
593 branch->op()->mnemonic(), node->id(), node->op()->mnemonic())); | 595 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
594 return branch->InputAt(1); | 596 return branch->InputAt(1); |
595 } | 597 } |
596 return result == kUnknown ? node : dead(); | 598 return result == kUnknown ? node : dead(); |
597 } | 599 } |
598 | 600 |
599 // Remove inputs to {node} corresponding to the dead inputs to {merge} | 601 // Remove inputs to {node} corresponding to the dead inputs to {merge} |
600 // and compact the remaining inputs, updating the operator. | 602 // and compact the remaining inputs, updating the operator. |
601 void RemoveDeadInputs(Node* merge, Node* node) { | 603 void RemoveDeadInputs(Node* merge, Node* node) { |
602 int live = 0; | 604 int live = 0; |
603 for (int i = 0; i < merge->InputCount(); i++) { | 605 for (int i = 0; i < merge->InputCount(); i++) { |
(...skipping 11 matching lines...) Expand all Loading... | |
615 } | 617 } |
616 DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); | 618 DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); |
617 DCHECK_NE(total, node->InputCount()); | 619 DCHECK_NE(total, node->InputCount()); |
618 node->TrimInputCount(total); | 620 node->TrimInputCount(total); |
619 node->set_op(common_->ResizeMergeOrPhi(node->op(), live)); | 621 node->set_op(common_->ResizeMergeOrPhi(node->op(), live)); |
620 } | 622 } |
621 | 623 |
622 // Replace uses of {node} with {replacement} and revisit the uses. | 624 // Replace uses of {node} with {replacement} and revisit the uses. |
623 void ReplaceNode(Node* node, Node* replacement) { | 625 void ReplaceNode(Node* node, Node* replacement) { |
624 if (node == replacement) return; | 626 if (node == replacement) return; |
625 TRACE((" Replace: #%d:%s with #%d:%s\n", node->id(), | 627 TRACE(" Replace: #%d:%s with #%d:%s\n", node->id(), node->op()->mnemonic(), |
626 node->op()->mnemonic(), replacement->id(), | 628 replacement->id(), replacement->op()->mnemonic()); |
627 replacement->op()->mnemonic())); | |
628 for (Node* const use : node->uses()) { | 629 for (Node* const use : node->uses()) { |
629 // Don't revisit this node if it refers to itself. | 630 // Don't revisit this node if it refers to itself. |
630 if (use != node) Revisit(use); | 631 if (use != node) Revisit(use); |
631 } | 632 } |
632 node->ReplaceUses(replacement); | 633 node->ReplaceUses(replacement); |
633 node->Kill(); | 634 node->Kill(); |
634 } | 635 } |
635 | 636 |
636 Graph* graph() { return jsgraph_->graph(); } | 637 Graph* graph() { return jsgraph_->graph(); } |
637 }; | 638 }; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
677 return impl.ReduceIfTrue(node); | 678 return impl.ReduceIfTrue(node); |
678 case IrOpcode::kIfFalse: | 679 case IrOpcode::kIfFalse: |
679 return impl.ReduceIfFalse(node); | 680 return impl.ReduceIfFalse(node); |
680 default: | 681 default: |
681 return node; | 682 return node; |
682 } | 683 } |
683 } | 684 } |
684 } | 685 } |
685 } | 686 } |
686 } // namespace v8::internal::compiler | 687 } // namespace v8::internal::compiler |
OLD | NEW |