| 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 |