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/generic-node-inl.h" | 5 #include "src/compiler/generic-node-inl.h" |
6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 temps); | 698 temps); |
699 } | 699 } |
700 | 700 |
701 | 701 |
702 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 702 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
703 X64OperandGenerator g(this); | 703 X64OperandGenerator g(this); |
704 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 704 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
705 } | 705 } |
706 | 706 |
707 | 707 |
708 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | 708 void InstructionSelector::VisitCall(Node* node) { |
709 FlagsContinuation* cont) { | 709 X64OperandGenerator g(this); |
710 VisitBinop(this, node, kX64Add32, cont); | 710 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node); |
| 711 |
| 712 FrameStateDescriptor* frame_state_descriptor = NULL; |
| 713 if (descriptor->NeedsFrameState()) { |
| 714 frame_state_descriptor = GetFrameStateDescriptor( |
| 715 node->InputAt(static_cast<int>(descriptor->InputCount()))); |
| 716 } |
| 717 |
| 718 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 719 |
| 720 // Compute InstructionOperands for inputs and outputs. |
| 721 InitializeCallBuffer(node, &buffer, true, true); |
| 722 |
| 723 // Push any stack arguments. |
| 724 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); |
| 725 input != buffer.pushed_nodes.rend(); input++) { |
| 726 // TODO(titzer): handle pushing double parameters. |
| 727 Emit(kX64Push, NULL, |
| 728 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); |
| 729 } |
| 730 |
| 731 // Select the appropriate opcode based on the call type. |
| 732 InstructionCode opcode; |
| 733 switch (descriptor->kind()) { |
| 734 case CallDescriptor::kCallCodeObject: { |
| 735 opcode = kArchCallCodeObject; |
| 736 break; |
| 737 } |
| 738 case CallDescriptor::kCallJSFunction: |
| 739 opcode = kArchCallJSFunction; |
| 740 break; |
| 741 default: |
| 742 UNREACHABLE(); |
| 743 return; |
| 744 } |
| 745 opcode |= MiscField::encode(descriptor->flags()); |
| 746 |
| 747 // Emit the call instruction. |
| 748 Instruction* call_instr = |
| 749 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), |
| 750 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
| 751 call_instr->MarkAsCall(); |
711 } | 752 } |
712 | 753 |
713 | 754 |
714 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
715 FlagsContinuation* cont) { | |
716 VisitBinop(this, node, kX64Sub32, cont); | |
717 } | |
718 | |
719 | |
720 // Shared routine for multiple compare operations. | 755 // Shared routine for multiple compare operations. |
721 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 756 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
722 InstructionOperand* left, InstructionOperand* right, | 757 InstructionOperand* left, InstructionOperand* right, |
723 FlagsContinuation* cont) { | 758 FlagsContinuation* cont) { |
724 X64OperandGenerator g(selector); | 759 X64OperandGenerator g(selector); |
725 opcode = cont->Encode(opcode); | 760 opcode = cont->Encode(opcode); |
726 if (cont->IsBranch()) { | 761 if (cont->IsBranch()) { |
727 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), | 762 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), |
728 g.Label(cont->false_block()))->MarkAsControl(); | 763 g.Label(cont->false_block()))->MarkAsControl(); |
729 } else { | 764 } else { |
(...skipping 16 matching lines...) Expand all Loading... |
746 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); | 781 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); |
747 } else if (g.CanBeImmediate(left)) { | 782 } else if (g.CanBeImmediate(left)) { |
748 if (!commutative) cont->Commute(); | 783 if (!commutative) cont->Commute(); |
749 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); | 784 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); |
750 } else { | 785 } else { |
751 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); | 786 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); |
752 } | 787 } |
753 } | 788 } |
754 | 789 |
755 | 790 |
756 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { | 791 static void VisitWordTest(InstructionSelector* selector, Node* node, |
757 switch (node->opcode()) { | 792 InstructionCode opcode, FlagsContinuation* cont) { |
758 case IrOpcode::kInt32Sub: | 793 X64OperandGenerator g(selector); |
759 return VisitWordCompare(this, node, kX64Cmp32, cont, false); | 794 VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(-1), cont); |
760 case IrOpcode::kWord32And: | 795 } |
761 return VisitWordCompare(this, node, kX64Test32, cont, true); | 796 |
762 default: | 797 |
763 break; | 798 static void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
764 } | 799 FlagsContinuation* cont) { |
765 | 800 X64OperandGenerator g(selector); |
766 X64OperandGenerator g(this); | |
767 VisitCompare(this, kX64Test32, g.Use(node), g.TempImmediate(-1), cont); | |
768 } | |
769 | |
770 | |
771 void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) { | |
772 switch (node->opcode()) { | |
773 case IrOpcode::kInt64Sub: | |
774 return VisitWordCompare(this, node, kX64Cmp, cont, false); | |
775 case IrOpcode::kWord64And: | |
776 return VisitWordCompare(this, node, kX64Test, cont, true); | |
777 default: | |
778 break; | |
779 } | |
780 | |
781 X64OperandGenerator g(this); | |
782 VisitCompare(this, kX64Test, g.Use(node), g.TempImmediate(-1), cont); | |
783 } | |
784 | |
785 | |
786 void InstructionSelector::VisitWord32Compare(Node* node, | |
787 FlagsContinuation* cont) { | |
788 VisitWordCompare(this, node, kX64Cmp32, cont, false); | |
789 } | |
790 | |
791 | |
792 void InstructionSelector::VisitWord64Compare(Node* node, | |
793 FlagsContinuation* cont) { | |
794 VisitWordCompare(this, node, kX64Cmp, cont, false); | |
795 } | |
796 | |
797 | |
798 void InstructionSelector::VisitFloat64Compare(Node* node, | |
799 FlagsContinuation* cont) { | |
800 X64OperandGenerator g(this); | |
801 Node* left = node->InputAt(0); | 801 Node* left = node->InputAt(0); |
802 Node* right = node->InputAt(1); | 802 Node* right = node->InputAt(1); |
803 VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont); | 803 VisitCompare(selector, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), |
804 } | 804 cont); |
805 | 805 } |
806 | 806 |
807 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 807 |
808 BasicBlock* deoptimization) { | 808 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
809 X64OperandGenerator g(this); | 809 BasicBlock* fbranch) { |
810 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 810 OperandGenerator g(this); |
811 | 811 Node* user = branch; |
812 FrameStateDescriptor* frame_state_descriptor = NULL; | 812 Node* value = branch->InputAt(0); |
813 if (descriptor->NeedsFrameState()) { | 813 |
814 frame_state_descriptor = GetFrameStateDescriptor( | 814 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
815 call->InputAt(static_cast<int>(descriptor->InputCount()))); | 815 |
816 } | 816 // If we can fall through to the true block, invert the branch. |
817 | 817 if (IsNextInAssemblyOrder(tbranch)) { |
818 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 818 cont.Negate(); |
819 | 819 cont.SwapBlocks(); |
820 // Compute InstructionOperands for inputs and outputs. | 820 } |
821 InitializeCallBuffer(call, &buffer, true, true); | 821 |
822 | 822 // Try to combine with comparisons against 0 by simply inverting the branch. |
823 // Push any stack arguments. | 823 while (CanCover(user, value)) { |
824 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); | 824 if (value->opcode() == IrOpcode::kWord32Equal) { |
825 input != buffer.pushed_nodes.rend(); input++) { | 825 Int32BinopMatcher m(value); |
826 // TODO(titzer): handle pushing double parameters. | 826 if (m.right().Is(0)) { |
827 Emit(kX64Push, NULL, | 827 user = value; |
828 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); | 828 value = m.left().node(); |
829 } | 829 cont.Negate(); |
830 | 830 } else { |
831 // Select the appropriate opcode based on the call type. | 831 break; |
832 InstructionCode opcode; | 832 } |
833 switch (descriptor->kind()) { | 833 } else if (value->opcode() == IrOpcode::kWord64Equal) { |
834 case CallDescriptor::kCallCodeObject: { | 834 Int64BinopMatcher m(value); |
835 opcode = kArchCallCodeObject; | 835 if (m.right().Is(0)) { |
| 836 user = value; |
| 837 value = m.left().node(); |
| 838 cont.Negate(); |
| 839 } else { |
| 840 break; |
| 841 } |
| 842 } else { |
836 break; | 843 break; |
837 } | 844 } |
838 case CallDescriptor::kCallJSFunction: | 845 } |
839 opcode = kArchCallJSFunction; | 846 |
840 break; | 847 // Try to combine the branch with a comparison. |
841 default: | 848 if (CanCover(user, value)) { |
842 UNREACHABLE(); | 849 switch (value->opcode()) { |
843 return; | 850 case IrOpcode::kWord32Equal: |
844 } | 851 cont.OverwriteAndNegateIfEqual(kEqual); |
845 opcode |= MiscField::encode(descriptor->flags()); | 852 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
846 | 853 case IrOpcode::kInt32LessThan: |
847 // Emit the call instruction. | 854 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
848 Instruction* call_instr = | 855 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
849 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), | 856 case IrOpcode::kInt32LessThanOrEqual: |
850 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 857 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
851 | 858 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
852 call_instr->MarkAsCall(); | 859 case IrOpcode::kUint32LessThan: |
853 if (deoptimization != NULL) { | 860 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
854 DCHECK(continuation != NULL); | 861 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
855 call_instr->MarkAsControl(); | 862 case IrOpcode::kUint32LessThanOrEqual: |
856 } | 863 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 864 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
| 865 case IrOpcode::kWord64Equal: |
| 866 cont.OverwriteAndNegateIfEqual(kEqual); |
| 867 return VisitWordCompare(this, value, kX64Cmp, &cont, false); |
| 868 case IrOpcode::kInt64LessThan: |
| 869 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 870 return VisitWordCompare(this, value, kX64Cmp, &cont, false); |
| 871 case IrOpcode::kInt64LessThanOrEqual: |
| 872 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 873 return VisitWordCompare(this, value, kX64Cmp, &cont, false); |
| 874 case IrOpcode::kUint64LessThan: |
| 875 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 876 return VisitWordCompare(this, value, kX64Cmp, &cont, false); |
| 877 case IrOpcode::kFloat64Equal: |
| 878 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 879 return VisitFloat64Compare(this, value, &cont); |
| 880 case IrOpcode::kFloat64LessThan: |
| 881 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 882 return VisitFloat64Compare(this, value, &cont); |
| 883 case IrOpcode::kFloat64LessThanOrEqual: |
| 884 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 885 return VisitFloat64Compare(this, value, &cont); |
| 886 case IrOpcode::kProjection: |
| 887 // Check if this is the overflow output projection of an |
| 888 // <Operation>WithOverflow node. |
| 889 if (OpParameter<size_t>(value) == 1u) { |
| 890 // We cannot combine the <Operation>WithOverflow with this branch |
| 891 // unless the 0th projection (the use of the actual value of the |
| 892 // <Operation> is either NULL, which means there's no use of the |
| 893 // actual value, or was already defined, which means it is scheduled |
| 894 // *AFTER* this branch). |
| 895 Node* node = value->InputAt(0); |
| 896 Node* result = node->FindProjection(0); |
| 897 if (result == NULL || IsDefined(result)) { |
| 898 switch (node->opcode()) { |
| 899 case IrOpcode::kInt32AddWithOverflow: |
| 900 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 901 return VisitBinop(this, node, kX64Add32, &cont); |
| 902 case IrOpcode::kInt32SubWithOverflow: |
| 903 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 904 return VisitBinop(this, node, kX64Sub32, &cont); |
| 905 default: |
| 906 break; |
| 907 } |
| 908 } |
| 909 } |
| 910 break; |
| 911 case IrOpcode::kInt32Sub: |
| 912 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
| 913 case IrOpcode::kWord32And: |
| 914 return VisitWordCompare(this, value, kX64Test32, &cont, true); |
| 915 default: |
| 916 break; |
| 917 } |
| 918 } |
| 919 |
| 920 // Branch could not be combined with a compare, emit compare against 0. |
| 921 VisitWordTest(this, value, kX64Test32, &cont); |
| 922 } |
| 923 |
| 924 |
| 925 void InstructionSelector::VisitWord32Equal(Node* const node) { |
| 926 Node* const user = node; |
| 927 FlagsContinuation cont(kEqual, node); |
| 928 Int32BinopMatcher m(user); |
| 929 if (m.right().Is(0)) { |
| 930 Node* const value = m.left().node(); |
| 931 if (CanCover(user, value)) { |
| 932 switch (value->opcode()) { |
| 933 case IrOpcode::kInt32Sub: |
| 934 return VisitWordCompare(this, value, kX64Cmp32, &cont, false); |
| 935 case IrOpcode::kWord32And: |
| 936 return VisitWordCompare(this, value, kX64Test32, &cont, true); |
| 937 default: |
| 938 break; |
| 939 } |
| 940 return VisitWordTest(this, value, kX64Test32, &cont); |
| 941 } |
| 942 } |
| 943 VisitWordCompare(this, node, kX64Cmp32, &cont, false); |
| 944 } |
| 945 |
| 946 |
| 947 void InstructionSelector::VisitInt32LessThan(Node* node) { |
| 948 FlagsContinuation cont(kSignedLessThan, node); |
| 949 VisitWordCompare(this, node, kX64Cmp32, &cont, false); |
| 950 } |
| 951 |
| 952 |
| 953 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { |
| 954 FlagsContinuation cont(kSignedLessThanOrEqual, node); |
| 955 VisitWordCompare(this, node, kX64Cmp32, &cont, false); |
| 956 } |
| 957 |
| 958 |
| 959 void InstructionSelector::VisitUint32LessThan(Node* node) { |
| 960 FlagsContinuation cont(kUnsignedLessThan, node); |
| 961 VisitWordCompare(this, node, kX64Cmp32, &cont, false); |
| 962 } |
| 963 |
| 964 |
| 965 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { |
| 966 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
| 967 VisitWordCompare(this, node, kX64Cmp32, &cont, false); |
| 968 } |
| 969 |
| 970 |
| 971 void InstructionSelector::VisitWord64Equal(Node* const node) { |
| 972 Node* const user = node; |
| 973 FlagsContinuation cont(kEqual, node); |
| 974 Int64BinopMatcher m(user); |
| 975 if (m.right().Is(0)) { |
| 976 Node* const value = m.left().node(); |
| 977 if (CanCover(user, value)) { |
| 978 switch (value->opcode()) { |
| 979 case IrOpcode::kInt64Sub: |
| 980 return VisitWordCompare(this, value, kX64Cmp, &cont, false); |
| 981 case IrOpcode::kWord64And: |
| 982 return VisitWordCompare(this, value, kX64Test, &cont, true); |
| 983 default: |
| 984 break; |
| 985 } |
| 986 return VisitWordTest(this, value, kX64Test, &cont); |
| 987 } |
| 988 } |
| 989 VisitWordCompare(this, node, kX64Cmp, &cont, false); |
| 990 } |
| 991 |
| 992 |
| 993 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 994 if (Node* ovf = node->FindProjection(1)) { |
| 995 FlagsContinuation cont(kOverflow, ovf); |
| 996 VisitBinop(this, node, kX64Add32, &cont); |
| 997 } |
| 998 FlagsContinuation cont; |
| 999 VisitBinop(this, node, kX64Add32, &cont); |
| 1000 } |
| 1001 |
| 1002 |
| 1003 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 1004 if (Node* ovf = node->FindProjection(1)) { |
| 1005 FlagsContinuation cont(kOverflow, ovf); |
| 1006 return VisitBinop(this, node, kX64Sub32, &cont); |
| 1007 } |
| 1008 FlagsContinuation cont; |
| 1009 VisitBinop(this, node, kX64Sub32, &cont); |
| 1010 } |
| 1011 |
| 1012 |
| 1013 void InstructionSelector::VisitInt64LessThan(Node* node) { |
| 1014 FlagsContinuation cont(kSignedLessThan, node); |
| 1015 VisitWordCompare(this, node, kX64Cmp, &cont, false); |
| 1016 } |
| 1017 |
| 1018 |
| 1019 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { |
| 1020 FlagsContinuation cont(kSignedLessThanOrEqual, node); |
| 1021 VisitWordCompare(this, node, kX64Cmp, &cont, false); |
| 1022 } |
| 1023 |
| 1024 |
| 1025 void InstructionSelector::VisitUint64LessThan(Node* node) { |
| 1026 FlagsContinuation cont(kUnsignedLessThan, node); |
| 1027 VisitWordCompare(this, node, kX64Cmp, &cont, false); |
| 1028 } |
| 1029 |
| 1030 |
| 1031 void InstructionSelector::VisitFloat64Equal(Node* node) { |
| 1032 FlagsContinuation cont(kUnorderedEqual, node); |
| 1033 VisitFloat64Compare(this, node, &cont); |
| 1034 } |
| 1035 |
| 1036 |
| 1037 void InstructionSelector::VisitFloat64LessThan(Node* node) { |
| 1038 FlagsContinuation cont(kUnorderedLessThan, node); |
| 1039 VisitFloat64Compare(this, node, &cont); |
| 1040 } |
| 1041 |
| 1042 |
| 1043 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
| 1044 FlagsContinuation cont(kUnorderedLessThanOrEqual, node); |
| 1045 VisitFloat64Compare(this, node, &cont); |
857 } | 1046 } |
858 | 1047 |
859 } // namespace compiler | 1048 } // namespace compiler |
860 } // namespace internal | 1049 } // namespace internal |
861 } // namespace v8 | 1050 } // namespace v8 |
OLD | NEW |