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/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
7 #include "src/compiler/node-properties-inl.h" | 7 #include "src/compiler/node-properties-inl.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
571 temps); | 571 temps); |
572 } | 572 } |
573 | 573 |
574 | 574 |
575 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 575 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
576 IA32OperandGenerator g(this); | 576 IA32OperandGenerator g(this); |
577 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 577 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
578 } | 578 } |
579 | 579 |
580 | 580 |
581 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | 581 void InstructionSelector::VisitCall(Node* node) { |
582 FlagsContinuation* cont) { | 582 IA32OperandGenerator g(this); |
583 VisitBinop(this, node, kIA32Add, cont); | 583 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node); |
| 584 |
| 585 FrameStateDescriptor* frame_state_descriptor = NULL; |
| 586 |
| 587 if (descriptor->NeedsFrameState()) { |
| 588 frame_state_descriptor = |
| 589 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount())); |
| 590 } |
| 591 |
| 592 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 593 |
| 594 // Compute InstructionOperands for inputs and outputs. |
| 595 InitializeCallBuffer(node, &buffer, true, true); |
| 596 |
| 597 // Push any stack arguments. |
| 598 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); |
| 599 input != buffer.pushed_nodes.rend(); input++) { |
| 600 // TODO(titzer): handle pushing double parameters. |
| 601 Emit(kIA32Push, NULL, |
| 602 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); |
| 603 } |
| 604 |
| 605 // Select the appropriate opcode based on the call type. |
| 606 InstructionCode opcode; |
| 607 switch (descriptor->kind()) { |
| 608 case CallDescriptor::kCallCodeObject: { |
| 609 opcode = kArchCallCodeObject; |
| 610 break; |
| 611 } |
| 612 case CallDescriptor::kCallJSFunction: |
| 613 opcode = kArchCallJSFunction; |
| 614 break; |
| 615 default: |
| 616 UNREACHABLE(); |
| 617 return; |
| 618 } |
| 619 opcode |= MiscField::encode(descriptor->flags()); |
| 620 |
| 621 // Emit the call instruction. |
| 622 Instruction* call_instr = |
| 623 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), |
| 624 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
| 625 call_instr->MarkAsCall(); |
584 } | 626 } |
585 | 627 |
586 | 628 |
587 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
588 FlagsContinuation* cont) { | |
589 VisitBinop(this, node, kIA32Sub, cont); | |
590 } | |
591 | |
592 | |
593 // Shared routine for multiple compare operations. | 629 // Shared routine for multiple compare operations. |
594 static inline void VisitCompare(InstructionSelector* selector, | 630 static inline void VisitCompare(InstructionSelector* selector, |
595 InstructionCode opcode, | 631 InstructionCode opcode, |
596 InstructionOperand* left, | 632 InstructionOperand* left, |
597 InstructionOperand* right, | 633 InstructionOperand* right, |
598 FlagsContinuation* cont) { | 634 FlagsContinuation* cont) { |
599 IA32OperandGenerator g(selector); | 635 IA32OperandGenerator g(selector); |
600 if (cont->IsBranch()) { | 636 if (cont->IsBranch()) { |
601 selector->Emit(cont->Encode(opcode), NULL, left, right, | 637 selector->Emit(cont->Encode(opcode), NULL, left, right, |
602 g.Label(cont->true_block()), | 638 g.Label(cont->true_block()), |
(...skipping 20 matching lines...) Expand all Loading... |
623 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); | 659 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); |
624 } else if (g.CanBeImmediate(left)) { | 660 } else if (g.CanBeImmediate(left)) { |
625 if (!commutative) cont->Commute(); | 661 if (!commutative) cont->Commute(); |
626 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); | 662 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); |
627 } else { | 663 } else { |
628 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); | 664 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); |
629 } | 665 } |
630 } | 666 } |
631 | 667 |
632 | 668 |
633 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { | 669 static void VisitWordTest(InstructionSelector* selector, Node* node, |
634 switch (node->opcode()) { | 670 FlagsContinuation* cont) { |
635 case IrOpcode::kInt32Sub: | 671 IA32OperandGenerator g(selector); |
636 return VisitWordCompare(this, node, kIA32Cmp, cont, false); | 672 VisitCompare(selector, kIA32Test, g.Use(node), g.TempImmediate(-1), cont); |
637 case IrOpcode::kWord32And: | |
638 return VisitWordCompare(this, node, kIA32Test, cont, true); | |
639 default: | |
640 break; | |
641 } | |
642 | |
643 IA32OperandGenerator g(this); | |
644 VisitCompare(this, kIA32Test, g.Use(node), g.TempImmediate(-1), cont); | |
645 } | 673 } |
646 | 674 |
647 | 675 |
648 void InstructionSelector::VisitWord32Compare(Node* node, | 676 // Shared routine for multiple float compare operations. |
649 FlagsContinuation* cont) { | 677 static void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
650 VisitWordCompare(this, node, kIA32Cmp, cont, false); | 678 FlagsContinuation* cont) { |
| 679 IA32OperandGenerator g(selector); |
| 680 Node* left = node->InputAt(0); |
| 681 Node* right = node->InputAt(1); |
| 682 VisitCompare(selector, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), |
| 683 cont); |
651 } | 684 } |
652 | 685 |
653 | 686 |
654 void InstructionSelector::VisitFloat64Compare(Node* node, | 687 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
655 FlagsContinuation* cont) { | 688 BasicBlock* fbranch) { |
656 IA32OperandGenerator g(this); | 689 OperandGenerator g(this); |
657 Node* left = node->InputAt(0); | 690 Node* user = branch; |
658 Node* right = node->InputAt(1); | 691 Node* value = branch->InputAt(0); |
659 VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont); | 692 |
| 693 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 694 |
| 695 // If we can fall through to the true block, invert the branch. |
| 696 if (IsNextInAssemblyOrder(tbranch)) { |
| 697 cont.Negate(); |
| 698 cont.SwapBlocks(); |
| 699 } |
| 700 |
| 701 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 702 while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) { |
| 703 Int32BinopMatcher m(value); |
| 704 if (m.right().Is(0)) { |
| 705 user = value; |
| 706 value = m.left().node(); |
| 707 cont.Negate(); |
| 708 } else { |
| 709 break; |
| 710 } |
| 711 } |
| 712 |
| 713 // Try to combine the branch with a comparison. |
| 714 if (CanCover(user, value)) { |
| 715 switch (value->opcode()) { |
| 716 case IrOpcode::kWord32Equal: |
| 717 cont.OverwriteAndNegateIfEqual(kEqual); |
| 718 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 719 case IrOpcode::kInt32LessThan: |
| 720 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 721 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 722 case IrOpcode::kInt32LessThanOrEqual: |
| 723 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 724 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 725 case IrOpcode::kUint32LessThan: |
| 726 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 727 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 728 case IrOpcode::kUint32LessThanOrEqual: |
| 729 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 730 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 731 case IrOpcode::kFloat64Equal: |
| 732 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 733 return VisitFloat64Compare(this, value, &cont); |
| 734 case IrOpcode::kFloat64LessThan: |
| 735 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 736 return VisitFloat64Compare(this, value, &cont); |
| 737 case IrOpcode::kFloat64LessThanOrEqual: |
| 738 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 739 return VisitFloat64Compare(this, value, &cont); |
| 740 case IrOpcode::kProjection: |
| 741 // Check if this is the overflow output projection of an |
| 742 // <Operation>WithOverflow node. |
| 743 if (OpParameter<size_t>(value) == 1u) { |
| 744 // We cannot combine the <Operation>WithOverflow with this branch |
| 745 // unless the 0th projection (the use of the actual value of the |
| 746 // <Operation> is either NULL, which means there's no use of the |
| 747 // actual value, or was already defined, which means it is scheduled |
| 748 // *AFTER* this branch). |
| 749 Node* node = value->InputAt(0); |
| 750 Node* result = node->FindProjection(0); |
| 751 if (result == NULL || IsDefined(result)) { |
| 752 switch (node->opcode()) { |
| 753 case IrOpcode::kInt32AddWithOverflow: |
| 754 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 755 return VisitBinop(this, node, kIA32Add, &cont); |
| 756 case IrOpcode::kInt32SubWithOverflow: |
| 757 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 758 return VisitBinop(this, node, kIA32Sub, &cont); |
| 759 default: |
| 760 break; |
| 761 } |
| 762 } |
| 763 } |
| 764 break; |
| 765 case IrOpcode::kInt32Sub: |
| 766 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 767 case IrOpcode::kWord32And: |
| 768 return VisitWordCompare(this, value, kIA32Test, &cont, true); |
| 769 default: |
| 770 break; |
| 771 } |
| 772 } |
| 773 |
| 774 // Branch could not be combined with a compare, emit compare against 0. |
| 775 VisitWordTest(this, value, &cont); |
660 } | 776 } |
661 | 777 |
662 | 778 |
663 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 779 void InstructionSelector::VisitWord32Equal(Node* const node) { |
664 BasicBlock* deoptimization) { | 780 Node* const user = node; |
665 IA32OperandGenerator g(this); | 781 FlagsContinuation cont(kEqual, node); |
666 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 782 Int32BinopMatcher m(user); |
| 783 if (m.right().Is(0)) { |
| 784 Node* const value = m.left().node(); |
| 785 if (CanCover(user, value)) { |
| 786 switch (value->opcode()) { |
| 787 case IrOpcode::kInt32Sub: |
| 788 return VisitWordCompare(this, value, kIA32Cmp, &cont, false); |
| 789 case IrOpcode::kWord32And: |
| 790 return VisitWordCompare(this, value, kIA32Test, &cont, true); |
| 791 default: |
| 792 break; |
| 793 } |
| 794 return VisitWordTest(this, value, &cont); |
| 795 } |
| 796 } |
| 797 return VisitWordCompare(this, node, kIA32Cmp, &cont, false); |
| 798 } |
667 | 799 |
668 FrameStateDescriptor* frame_state_descriptor = NULL; | |
669 | 800 |
670 if (descriptor->NeedsFrameState()) { | 801 void InstructionSelector::VisitInt32LessThan(Node* node) { |
671 frame_state_descriptor = | 802 FlagsContinuation cont(kSignedLessThan, node); |
672 GetFrameStateDescriptor(call->InputAt(descriptor->InputCount())); | 803 return VisitWordCompare(this, node, kIA32Cmp, &cont, false); |
| 804 } |
| 805 |
| 806 |
| 807 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { |
| 808 FlagsContinuation cont(kSignedLessThanOrEqual, node); |
| 809 return VisitWordCompare(this, node, kIA32Cmp, &cont, false); |
| 810 } |
| 811 |
| 812 |
| 813 void InstructionSelector::VisitUint32LessThan(Node* node) { |
| 814 FlagsContinuation cont(kUnsignedLessThan, node); |
| 815 return VisitWordCompare(this, node, kIA32Cmp, &cont, false); |
| 816 } |
| 817 |
| 818 |
| 819 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { |
| 820 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
| 821 return VisitWordCompare(this, node, kIA32Cmp, &cont, false); |
| 822 } |
| 823 |
| 824 |
| 825 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 826 if (Node* ovf = node->FindProjection(1)) { |
| 827 FlagsContinuation cont(kOverflow, ovf); |
| 828 return VisitBinop(this, node, kIA32Add, &cont); |
673 } | 829 } |
| 830 FlagsContinuation cont; |
| 831 VisitBinop(this, node, kIA32Add, &cont); |
| 832 } |
674 | 833 |
675 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | |
676 | 834 |
677 // Compute InstructionOperands for inputs and outputs. | 835 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
678 InitializeCallBuffer(call, &buffer, true, true); | 836 if (Node* ovf = node->FindProjection(1)) { |
| 837 FlagsContinuation cont(kOverflow, ovf); |
| 838 return VisitBinop(this, node, kIA32Sub, &cont); |
| 839 } |
| 840 FlagsContinuation cont; |
| 841 VisitBinop(this, node, kIA32Sub, &cont); |
| 842 } |
679 | 843 |
680 // Push any stack arguments. | |
681 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); | |
682 input != buffer.pushed_nodes.rend(); input++) { | |
683 // TODO(titzer): handle pushing double parameters. | |
684 Emit(kIA32Push, NULL, | |
685 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); | |
686 } | |
687 | 844 |
688 // Select the appropriate opcode based on the call type. | 845 void InstructionSelector::VisitFloat64Equal(Node* node) { |
689 InstructionCode opcode; | 846 FlagsContinuation cont(kUnorderedEqual, node); |
690 switch (descriptor->kind()) { | 847 VisitFloat64Compare(this, node, &cont); |
691 case CallDescriptor::kCallCodeObject: { | 848 } |
692 opcode = kArchCallCodeObject; | |
693 break; | |
694 } | |
695 case CallDescriptor::kCallJSFunction: | |
696 opcode = kArchCallJSFunction; | |
697 break; | |
698 default: | |
699 UNREACHABLE(); | |
700 return; | |
701 } | |
702 opcode |= MiscField::encode(descriptor->flags()); | |
703 | 849 |
704 // Emit the call instruction. | |
705 Instruction* call_instr = | |
706 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), | |
707 buffer.instruction_args.size(), &buffer.instruction_args.front()); | |
708 | 850 |
709 call_instr->MarkAsCall(); | 851 void InstructionSelector::VisitFloat64LessThan(Node* node) { |
710 if (deoptimization != NULL) { | 852 FlagsContinuation cont(kUnorderedLessThan, node); |
711 DCHECK(continuation != NULL); | 853 VisitFloat64Compare(this, node, &cont); |
712 call_instr->MarkAsControl(); | 854 } |
713 } | 855 |
| 856 |
| 857 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
| 858 FlagsContinuation cont(kUnorderedLessThanOrEqual, node); |
| 859 VisitFloat64Compare(this, node, &cont); |
714 } | 860 } |
715 | 861 |
716 } // namespace compiler | 862 } // namespace compiler |
717 } // namespace internal | 863 } // namespace internal |
718 } // namespace v8 | 864 } // namespace v8 |
OLD | NEW |