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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 | 49 |
50 class ControlReducerImpl { | 50 class ControlReducerImpl { |
51 public: | 51 public: |
52 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, | 52 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, |
53 CommonOperatorBuilder* common) | 53 CommonOperatorBuilder* common) |
54 : zone_(zone), | 54 : zone_(zone), |
55 jsgraph_(jsgraph), | 55 jsgraph_(jsgraph), |
56 common_(common), | 56 common_(common), |
57 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), | 57 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), |
58 stack_(zone_), | 58 stack_(zone_), |
59 revisit_(zone_) {} | 59 revisit_(zone_), |
| 60 max_phis_for_select_(0) {} |
60 | 61 |
61 Zone* zone_; | 62 Zone* zone_; |
62 JSGraph* jsgraph_; | 63 JSGraph* jsgraph_; |
63 CommonOperatorBuilder* common_; | 64 CommonOperatorBuilder* common_; |
64 ZoneVector<VisitState> state_; | 65 ZoneVector<VisitState> state_; |
65 ZoneDeque<Node*> stack_; | 66 ZoneDeque<Node*> stack_; |
66 ZoneDeque<Node*> revisit_; | 67 ZoneDeque<Node*> revisit_; |
| 68 int max_phis_for_select_; |
67 | 69 |
68 void Reduce() { | 70 void Reduce() { |
69 Push(graph()->end()); | 71 Push(graph()->end()); |
70 do { | 72 do { |
71 // Process the node on the top of the stack, potentially pushing more | 73 // Process the node on the top of the stack, potentially pushing more |
72 // or popping the node off the stack. | 74 // or popping the node off the stack. |
73 ReduceTop(); | 75 ReduceTop(); |
74 // If the stack becomes empty, revisit any nodes in the revisit queue. | 76 // If the stack becomes empty, revisit any nodes in the revisit queue. |
75 // If no nodes in the revisit queue, try removing dead loops. | 77 // If no nodes in the revisit queue, try removing dead loops. |
76 // If no dead loops, then finish. | 78 // If no dead loops, then finish. |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 } | 531 } |
530 index++; | 532 index++; |
531 } | 533 } |
532 | 534 |
533 TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(), | 535 TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(), |
534 node->op()->mnemonic(), live, index); | 536 node->op()->mnemonic(), live, index); |
535 | 537 |
536 if (live == 0) return dead(); // no remaining inputs. | 538 if (live == 0) return dead(); // no remaining inputs. |
537 | 539 |
538 // Gather phis and effect phis to be edited. | 540 // Gather phis and effect phis to be edited. |
539 ZoneVector<Node*> phis(zone_); | 541 NodeVector phis(zone_); |
540 for (Node* const use : node->uses()) { | 542 for (Node* const use : node->uses()) { |
541 if (NodeProperties::IsPhi(use)) phis.push_back(use); | 543 if (NodeProperties::IsPhi(use)) phis.push_back(use); |
542 } | 544 } |
543 | 545 |
544 if (live == 1) { | 546 if (live == 1) { |
545 // All phis are redundant. Replace them with their live input. | 547 // All phis are redundant. Replace them with their live input. |
546 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); | 548 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); |
547 // The merge itself is redundant. | 549 // The merge itself is redundant. |
548 return node->InputAt(live_index); | 550 return node->InputAt(live_index); |
549 } | 551 } |
550 | 552 |
551 DCHECK_LE(2, live); | 553 DCHECK_LE(2, live); |
552 | 554 |
553 if (live < node->InputCount()) { | 555 if (live < node->InputCount()) { |
554 // Edit phis in place, removing dead inputs and revisiting them. | 556 // Edit phis in place, removing dead inputs and revisiting them. |
555 for (Node* const phi : phis) { | 557 for (Node* const phi : phis) { |
556 TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(), | 558 TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(), |
557 phi->op()->mnemonic(), live); | 559 phi->op()->mnemonic(), live); |
558 RemoveDeadInputs(node, phi); | 560 RemoveDeadInputs(node, phi); |
559 Revisit(phi); | 561 Revisit(phi); |
560 } | 562 } |
561 // Edit the merge in place, removing dead inputs. | 563 // Edit the merge in place, removing dead inputs. |
562 RemoveDeadInputs(node, node); | 564 RemoveDeadInputs(node, node); |
563 } | 565 } |
564 | 566 |
565 DCHECK_EQ(live, node->InputCount()); | 567 DCHECK_EQ(live, node->InputCount()); |
566 | 568 |
567 // Check if it's an unused diamond. | 569 // Try to remove dead diamonds or introduce selects. |
568 if (live == 2 && phis.empty()) { | 570 if (live == 2 && CheckPhisForSelect(phis)) { |
569 DiamondMatcher matcher(node); | 571 DiamondMatcher matcher(node); |
570 if (matcher.Matched() && matcher.IfProjectionsAreOwned()) { | 572 if (matcher.Matched() && matcher.IfProjectionsAreOwned()) { |
571 // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes | 573 // Dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
572 // have uses except for the Merge and the Merge has no Phi or | 574 // have uses except for the Merge. Remove the branch if there |
573 // EffectPhi uses, so replace the Merge with the control input of the | 575 // are no phis or replace phis with selects. |
574 // diamond. | 576 Node* control = NodeProperties::GetControlInput(matcher.Branch()); |
575 TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", | 577 if (phis.size() == 0) { |
576 matcher.Branch()->id(), matcher.IfTrue()->id(), | 578 // No phis. Remove the branch altogether. |
577 matcher.IfFalse()->id()); | 579 TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", |
578 // TODO(turbofan): replace single-phi diamonds with selects. | 580 matcher.Branch()->id(), matcher.IfTrue()->id(), |
579 return NodeProperties::GetControlInput(matcher.Branch()); | 581 matcher.IfFalse()->id()); |
| 582 return control; |
| 583 } else { |
| 584 // A small number of phis. Replace with selects. |
| 585 Node* cond = matcher.Branch()->InputAt(0); |
| 586 for (Node* phi : phis) { |
| 587 Node* select = graph()->NewNode( |
| 588 common_->Select(OpParameter<MachineType>(phi), |
| 589 BranchHintOf(matcher.Branch()->op())), |
| 590 cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi)); |
| 591 TRACE(" MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n", |
| 592 matcher.Branch()->id(), matcher.IfTrue()->id(), |
| 593 matcher.IfFalse()->id(), select->id()); |
| 594 ReplaceNode(phi, select); |
| 595 } |
| 596 return control; |
| 597 } |
580 } | 598 } |
581 } | 599 } |
582 | 600 |
583 return node; | 601 return node; |
584 } | 602 } |
585 | 603 |
| 604 bool CheckPhisForSelect(const NodeVector& phis) { |
| 605 if (phis.size() > static_cast<size_t>(max_phis_for_select_)) return false; |
| 606 for (Node* phi : phis) { |
| 607 if (phi->opcode() != IrOpcode::kPhi) return false; // no EffectPhis. |
| 608 } |
| 609 return true; |
| 610 } |
| 611 |
586 // Reduce if projections if the branch has a constant input. | 612 // Reduce if projections if the branch has a constant input. |
587 Node* ReduceIfProjection(Node* node, Decision decision) { | 613 Node* ReduceIfProjection(Node* node, Decision decision) { |
588 Node* branch = node->InputAt(0); | 614 Node* branch = node->InputAt(0); |
589 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 615 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
590 Decision result = DecideCondition(branch->InputAt(0)); | 616 Decision result = DecideCondition(branch->InputAt(0)); |
591 if (result == decision) { | 617 if (result == decision) { |
592 // Fold a branch by replacing IfTrue/IfFalse with the branch control. | 618 // Fold a branch by replacing IfTrue/IfFalse with the branch control. |
593 TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 619 TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
594 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 620 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
595 return branch->InputAt(1); | 621 return branch->InputAt(1); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
631 } | 657 } |
632 node->ReplaceUses(replacement); | 658 node->ReplaceUses(replacement); |
633 node->Kill(); | 659 node->Kill(); |
634 } | 660 } |
635 | 661 |
636 Graph* graph() { return jsgraph_->graph(); } | 662 Graph* graph() { return jsgraph_->graph(); } |
637 }; | 663 }; |
638 | 664 |
639 | 665 |
640 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, | 666 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, |
641 CommonOperatorBuilder* common) { | 667 CommonOperatorBuilder* common, |
| 668 int max_phis_for_select) { |
642 ControlReducerImpl impl(zone, jsgraph, common); | 669 ControlReducerImpl impl(zone, jsgraph, common); |
| 670 impl.max_phis_for_select_ = max_phis_for_select; |
643 impl.Reduce(); | 671 impl.Reduce(); |
644 } | 672 } |
645 | 673 |
646 | 674 |
647 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { | 675 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { |
648 ControlReducerImpl impl(zone, jsgraph, NULL); | 676 ControlReducerImpl impl(zone, jsgraph, NULL); |
649 impl.Trim(); | 677 impl.Trim(); |
650 } | 678 } |
651 | 679 |
652 | 680 |
653 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, | 681 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, |
654 CommonOperatorBuilder* common, Node* node) { | 682 CommonOperatorBuilder* common, Node* node, |
| 683 int max_phis_for_select) { |
655 Zone zone; | 684 Zone zone; |
656 ControlReducerImpl impl(&zone, jsgraph, common); | 685 ControlReducerImpl impl(&zone, jsgraph, common); |
| 686 impl.max_phis_for_select_ = max_phis_for_select; |
657 return impl.ReduceMerge(node); | 687 return impl.ReduceMerge(node); |
658 } | 688 } |
659 | 689 |
660 | 690 |
661 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, | 691 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, |
662 CommonOperatorBuilder* common, | 692 CommonOperatorBuilder* common, |
663 Node* node) { | 693 Node* node) { |
664 Zone zone; | 694 Zone zone; |
665 ControlReducerImpl impl(&zone, jsgraph, common); | 695 ControlReducerImpl impl(&zone, jsgraph, common); |
666 return impl.ReducePhi(node); | 696 return impl.ReducePhi(node); |
(...skipping 10 matching lines...) Expand all Loading... |
677 return impl.ReduceIfProjection(node, kTrue); | 707 return impl.ReduceIfProjection(node, kTrue); |
678 case IrOpcode::kIfFalse: | 708 case IrOpcode::kIfFalse: |
679 return impl.ReduceIfProjection(node, kFalse); | 709 return impl.ReduceIfProjection(node, kFalse); |
680 default: | 710 default: |
681 return node; | 711 return node; |
682 } | 712 } |
683 } | 713 } |
684 } | 714 } |
685 } | 715 } |
686 } // namespace v8::internal::compiler | 716 } // namespace v8::internal::compiler |
OLD | NEW |