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/base/bits.h" | 5 #include "src/base/bits.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 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 DCHECK(cont->IsSet()); | 893 DCHECK(cont->IsSet()); |
894 selector->Emit( | 894 selector->Emit( |
895 cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), | 895 cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), |
896 g.UseRegister(m.left().node()), g.UseRegister(m.right().node())); | 896 g.UseRegister(m.left().node()), g.UseRegister(m.right().node())); |
897 } | 897 } |
898 } | 898 } |
899 | 899 |
900 | 900 |
901 // Shared routine for multiple word compare operations. | 901 // Shared routine for multiple word compare operations. |
902 void VisitWordCompare(InstructionSelector* selector, Node* node, | 902 void VisitWordCompare(InstructionSelector* selector, Node* node, |
903 InstructionCode opcode, FlagsContinuation* cont, | 903 InstructionCode opcode, FlagsContinuation* cont) { |
904 bool commutative) { | |
905 ArmOperandGenerator g(selector); | 904 ArmOperandGenerator g(selector); |
906 Int32BinopMatcher m(node); | 905 Int32BinopMatcher m(node); |
907 InstructionOperand* inputs[5]; | 906 InstructionOperand* inputs[5]; |
908 size_t input_count = 0; | 907 size_t input_count = 0; |
909 InstructionOperand* outputs[1]; | 908 InstructionOperand* outputs[1]; |
910 size_t output_count = 0; | 909 size_t output_count = 0; |
911 | 910 |
912 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 911 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
913 &input_count, &inputs[1])) { | 912 &input_count, &inputs[1])) { |
914 inputs[0] = g.UseRegister(m.left().node()); | 913 inputs[0] = g.UseRegister(m.left().node()); |
915 input_count++; | 914 input_count++; |
916 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), | 915 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), |
917 &input_count, &inputs[1])) { | 916 &input_count, &inputs[1])) { |
918 if (!commutative) cont->Commute(); | 917 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
919 inputs[0] = g.UseRegister(m.right().node()); | 918 inputs[0] = g.UseRegister(m.right().node()); |
920 input_count++; | 919 input_count++; |
921 } else { | 920 } else { |
922 opcode |= AddressingModeField::encode(kMode_Operand2_R); | 921 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
923 inputs[input_count++] = g.UseRegister(m.left().node()); | 922 inputs[input_count++] = g.UseRegister(m.left().node()); |
924 inputs[input_count++] = g.UseRegister(m.right().node()); | 923 inputs[input_count++] = g.UseRegister(m.right().node()); |
925 } | 924 } |
926 | 925 |
927 if (cont->IsBranch()) { | 926 if (cont->IsBranch()) { |
928 inputs[input_count++] = g.Label(cont->true_block()); | 927 inputs[input_count++] = g.Label(cont->true_block()); |
929 inputs[input_count++] = g.Label(cont->false_block()); | 928 inputs[input_count++] = g.Label(cont->false_block()); |
930 } else { | 929 } else { |
931 DCHECK(cont->IsSet()); | 930 DCHECK(cont->IsSet()); |
932 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 931 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
933 } | 932 } |
934 | 933 |
935 DCHECK_NE(0, input_count); | 934 DCHECK_NE(0, input_count); |
936 DCHECK_GE(arraysize(inputs), input_count); | 935 DCHECK_GE(arraysize(inputs), input_count); |
937 DCHECK_GE(arraysize(outputs), output_count); | 936 DCHECK_GE(arraysize(outputs), output_count); |
938 | 937 |
939 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, | 938 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, |
940 outputs, input_count, inputs); | 939 outputs, input_count, inputs); |
941 if (cont->IsBranch()) instr->MarkAsControl(); | 940 if (cont->IsBranch()) instr->MarkAsControl(); |
942 } | 941 } |
943 | 942 |
944 | 943 |
945 void VisitWordCompare(InstructionSelector* selector, Node* node, | 944 void VisitWordCompare(InstructionSelector* selector, Node* node, |
946 FlagsContinuation* cont) { | 945 FlagsContinuation* cont) { |
947 VisitWordCompare(selector, node, kArmCmp, cont, false); | 946 VisitWordCompare(selector, node, kArmCmp, cont); |
948 } | 947 } |
949 | 948 |
950 | 949 |
951 void VisitWordTest(InstructionSelector* selector, Node* node, | 950 // Shared routine for word comparisons against zero. |
952 FlagsContinuation* cont) { | 951 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
953 ArmOperandGenerator g(selector); | 952 Node* value, FlagsContinuation* cont) { |
954 InstructionCode opcode = | 953 while (selector->CanCover(user, value)) { |
955 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); | |
956 if (cont->IsBranch()) { | |
957 selector->Emit(opcode, nullptr, g.UseRegister(node), g.UseRegister(node), | |
958 g.Label(cont->true_block()), | |
959 g.Label(cont->false_block()))->MarkAsControl(); | |
960 } else { | |
961 selector->Emit(opcode, g.DefineAsRegister(cont->result()), | |
962 g.UseRegister(node), g.UseRegister(node)); | |
963 } | |
964 } | |
965 | |
966 } // namespace | |
967 | |
968 | |
969 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, | |
970 BasicBlock* fbranch) { | |
971 ArmOperandGenerator g(this); | |
972 Node* user = branch; | |
973 Node* value = branch->InputAt(0); | |
974 | |
975 FlagsContinuation cont(kNotEqual, tbranch, fbranch); | |
976 | |
977 // If we can fall through to the true block, invert the branch. | |
978 if (IsNextInAssemblyOrder(tbranch)) { | |
979 cont.Negate(); | |
980 cont.SwapBlocks(); | |
981 } | |
982 | |
983 // Try to combine with comparisons against 0 by simply inverting the branch. | |
984 while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) { | |
985 Int32BinopMatcher m(value); | |
986 if (m.right().Is(0)) { | |
987 user = value; | |
988 value = m.left().node(); | |
989 cont.Negate(); | |
990 } else { | |
991 break; | |
992 } | |
993 } | |
994 | |
995 // Try to combine the branch with a comparison. | |
996 if (CanCover(user, value)) { | |
997 switch (value->opcode()) { | 954 switch (value->opcode()) { |
998 case IrOpcode::kWord32Equal: | 955 case IrOpcode::kWord32Equal: { |
999 cont.OverwriteAndNegateIfEqual(kEqual); | 956 // Combine with comparisons against 0 by simply inverting the |
1000 return VisitWordCompare(this, value, &cont); | 957 // continuation. |
| 958 Int32BinopMatcher m(value); |
| 959 if (m.right().Is(0)) { |
| 960 user = value; |
| 961 value = m.left().node(); |
| 962 cont->Negate(); |
| 963 continue; |
| 964 } |
| 965 cont->OverwriteAndNegateIfEqual(kEqual); |
| 966 return VisitWordCompare(selector, value, cont); |
| 967 } |
1001 case IrOpcode::kInt32LessThan: | 968 case IrOpcode::kInt32LessThan: |
1002 cont.OverwriteAndNegateIfEqual(kSignedLessThan); | 969 cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
1003 return VisitWordCompare(this, value, &cont); | 970 return VisitWordCompare(selector, value, cont); |
1004 case IrOpcode::kInt32LessThanOrEqual: | 971 case IrOpcode::kInt32LessThanOrEqual: |
1005 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); | 972 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
1006 return VisitWordCompare(this, value, &cont); | 973 return VisitWordCompare(selector, value, cont); |
1007 case IrOpcode::kUint32LessThan: | 974 case IrOpcode::kUint32LessThan: |
1008 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); | 975 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); |
1009 return VisitWordCompare(this, value, &cont); | 976 return VisitWordCompare(selector, value, cont); |
1010 case IrOpcode::kUint32LessThanOrEqual: | 977 case IrOpcode::kUint32LessThanOrEqual: |
1011 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); | 978 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
1012 return VisitWordCompare(this, value, &cont); | 979 return VisitWordCompare(selector, value, cont); |
1013 case IrOpcode::kFloat64Equal: | 980 case IrOpcode::kFloat64Equal: |
1014 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); | 981 cont->OverwriteAndNegateIfEqual(kUnorderedEqual); |
1015 return VisitFloat64Compare(this, value, &cont); | 982 return VisitFloat64Compare(selector, value, cont); |
1016 case IrOpcode::kFloat64LessThan: | 983 case IrOpcode::kFloat64LessThan: |
1017 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); | 984 cont->OverwriteAndNegateIfEqual(kUnorderedLessThan); |
1018 return VisitFloat64Compare(this, value, &cont); | 985 return VisitFloat64Compare(selector, value, cont); |
1019 case IrOpcode::kFloat64LessThanOrEqual: | 986 case IrOpcode::kFloat64LessThanOrEqual: |
1020 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); | 987 cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
1021 return VisitFloat64Compare(this, value, &cont); | 988 return VisitFloat64Compare(selector, value, cont); |
1022 case IrOpcode::kProjection: | 989 case IrOpcode::kProjection: |
1023 // Check if this is the overflow output projection of an | 990 // Check if this is the overflow output projection of an |
1024 // <Operation>WithOverflow node. | 991 // <Operation>WithOverflow node. |
1025 if (OpParameter<size_t>(value) == 1u) { | 992 if (OpParameter<size_t>(value) == 1u) { |
1026 // We cannot combine the <Operation>WithOverflow with this branch | 993 // We cannot combine the <Operation>WithOverflow with this branch |
1027 // unless the 0th projection (the use of the actual value of the | 994 // unless the 0th projection (the use of the actual value of the |
1028 // <Operation> is either NULL, which means there's no use of the | 995 // <Operation> is either NULL, which means there's no use of the |
1029 // actual value, or was already defined, which means it is scheduled | 996 // actual value, or was already defined, which means it is scheduled |
1030 // *AFTER* this branch). | 997 // *AFTER* this branch). |
1031 Node* node = value->InputAt(0); | 998 Node* const node = value->InputAt(0); |
1032 Node* result = node->FindProjection(0); | 999 Node* const result = node->FindProjection(0); |
1033 if (!result || IsDefined(result)) { | 1000 if (!result || selector->IsDefined(result)) { |
1034 switch (node->opcode()) { | 1001 switch (node->opcode()) { |
1035 case IrOpcode::kInt32AddWithOverflow: | 1002 case IrOpcode::kInt32AddWithOverflow: |
1036 cont.OverwriteAndNegateIfEqual(kOverflow); | 1003 cont->OverwriteAndNegateIfEqual(kOverflow); |
1037 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont); | 1004 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont); |
1038 case IrOpcode::kInt32SubWithOverflow: | 1005 case IrOpcode::kInt32SubWithOverflow: |
1039 cont.OverwriteAndNegateIfEqual(kOverflow); | 1006 cont->OverwriteAndNegateIfEqual(kOverflow); |
1040 return VisitBinop(this, node, kArmSub, kArmRsb, &cont); | 1007 return VisitBinop(selector, node, kArmSub, kArmRsb, cont); |
1041 default: | 1008 default: |
1042 break; | 1009 break; |
1043 } | 1010 } |
1044 } | 1011 } |
1045 } | 1012 } |
1046 break; | 1013 break; |
1047 case IrOpcode::kInt32Add: | 1014 case IrOpcode::kInt32Add: |
1048 return VisitWordCompare(this, value, kArmCmn, &cont, true); | 1015 return VisitWordCompare(selector, value, kArmCmn, cont); |
1049 case IrOpcode::kInt32Sub: | 1016 case IrOpcode::kInt32Sub: |
1050 return VisitWordCompare(this, value, kArmCmp, &cont, false); | 1017 return VisitWordCompare(selector, value, kArmCmp, cont); |
1051 case IrOpcode::kWord32And: | 1018 case IrOpcode::kWord32And: |
1052 return VisitWordCompare(this, value, kArmTst, &cont, true); | 1019 return VisitWordCompare(selector, value, kArmTst, cont); |
1053 case IrOpcode::kWord32Or: | 1020 case IrOpcode::kWord32Or: |
1054 return VisitBinop(this, value, kArmOrr, kArmOrr, &cont); | 1021 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont); |
1055 case IrOpcode::kWord32Xor: | 1022 case IrOpcode::kWord32Xor: |
1056 return VisitWordCompare(this, value, kArmTeq, &cont, true); | 1023 return VisitWordCompare(selector, value, kArmTeq, cont); |
1057 case IrOpcode::kWord32Sar: | 1024 case IrOpcode::kWord32Sar: |
1058 return VisitShift(this, value, TryMatchASR, &cont); | 1025 return VisitShift(selector, value, TryMatchASR, cont); |
1059 case IrOpcode::kWord32Shl: | 1026 case IrOpcode::kWord32Shl: |
1060 return VisitShift(this, value, TryMatchLSL, &cont); | 1027 return VisitShift(selector, value, TryMatchLSL, cont); |
1061 case IrOpcode::kWord32Shr: | 1028 case IrOpcode::kWord32Shr: |
1062 return VisitShift(this, value, TryMatchLSR, &cont); | 1029 return VisitShift(selector, value, TryMatchLSR, cont); |
1063 case IrOpcode::kWord32Ror: | 1030 case IrOpcode::kWord32Ror: |
1064 return VisitShift(this, value, TryMatchROR, &cont); | 1031 return VisitShift(selector, value, TryMatchROR, cont); |
1065 default: | 1032 default: |
1066 break; | 1033 break; |
1067 } | 1034 } |
| 1035 break; |
1068 } | 1036 } |
1069 | 1037 |
1070 // Branch could not be combined with a compare, emit compare against 0. | 1038 // Continuation could not be combined with a compare, emit compare against 0. |
1071 return VisitWordTest(this, value, &cont); | 1039 ArmOperandGenerator g(selector); |
| 1040 InstructionCode const opcode = |
| 1041 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); |
| 1042 InstructionOperand* const value_operand = g.UseRegister(value); |
| 1043 if (cont->IsBranch()) { |
| 1044 selector->Emit(opcode, nullptr, value_operand, value_operand, |
| 1045 g.Label(cont->true_block()), |
| 1046 g.Label(cont->false_block()))->MarkAsControl(); |
| 1047 } else { |
| 1048 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, |
| 1049 value_operand); |
| 1050 } |
| 1051 } |
| 1052 |
| 1053 } // namespace |
| 1054 |
| 1055 |
| 1056 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 1057 BasicBlock* fbranch) { |
| 1058 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 1059 if (IsNextInAssemblyOrder(tbranch)) { // We can fallthru to the true block. |
| 1060 cont.Negate(); |
| 1061 cont.SwapBlocks(); |
| 1062 } |
| 1063 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); |
1072 } | 1064 } |
1073 | 1065 |
1074 | 1066 |
1075 void InstructionSelector::VisitWord32Equal(Node* const node) { | 1067 void InstructionSelector::VisitWord32Equal(Node* const node) { |
1076 Node* const user = node; | |
1077 FlagsContinuation cont(kEqual, node); | 1068 FlagsContinuation cont(kEqual, node); |
1078 Int32BinopMatcher m(user); | 1069 Int32BinopMatcher m(node); |
1079 if (m.right().Is(0)) { | 1070 if (m.right().Is(0)) { |
1080 Node* const value = m.left().node(); | 1071 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); |
1081 if (CanCover(user, value)) { | |
1082 switch (value->opcode()) { | |
1083 case IrOpcode::kInt32Add: | |
1084 return VisitWordCompare(this, value, kArmCmn, &cont, true); | |
1085 case IrOpcode::kInt32Sub: | |
1086 return VisitWordCompare(this, value, kArmCmp, &cont, false); | |
1087 case IrOpcode::kWord32And: | |
1088 return VisitWordCompare(this, value, kArmTst, &cont, true); | |
1089 case IrOpcode::kWord32Or: | |
1090 return VisitBinop(this, value, kArmOrr, kArmOrr, &cont); | |
1091 case IrOpcode::kWord32Xor: | |
1092 return VisitWordCompare(this, value, kArmTeq, &cont, true); | |
1093 case IrOpcode::kWord32Sar: | |
1094 return VisitShift(this, value, TryMatchASR, &cont); | |
1095 case IrOpcode::kWord32Shl: | |
1096 return VisitShift(this, value, TryMatchLSL, &cont); | |
1097 case IrOpcode::kWord32Shr: | |
1098 return VisitShift(this, value, TryMatchLSR, &cont); | |
1099 case IrOpcode::kWord32Ror: | |
1100 return VisitShift(this, value, TryMatchROR, &cont); | |
1101 default: | |
1102 break; | |
1103 } | |
1104 return VisitWordTest(this, value, &cont); | |
1105 } | |
1106 } | 1072 } |
1107 VisitWordCompare(this, node, &cont); | 1073 VisitWordCompare(this, node, &cont); |
1108 } | 1074 } |
1109 | 1075 |
1110 | 1076 |
1111 void InstructionSelector::VisitInt32LessThan(Node* node) { | 1077 void InstructionSelector::VisitInt32LessThan(Node* node) { |
1112 FlagsContinuation cont(kSignedLessThan, node); | 1078 FlagsContinuation cont(kSignedLessThan, node); |
1113 VisitWordCompare(this, node, &cont); | 1079 VisitWordCompare(this, node, &cont); |
1114 } | 1080 } |
1115 | 1081 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1165 | 1131 |
1166 | 1132 |
1167 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { | 1133 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
1168 FlagsContinuation cont(kUnorderedLessThanOrEqual, node); | 1134 FlagsContinuation cont(kUnorderedLessThanOrEqual, node); |
1169 VisitFloat64Compare(this, node, &cont); | 1135 VisitFloat64Compare(this, node, &cont); |
1170 } | 1136 } |
1171 | 1137 |
1172 } // namespace compiler | 1138 } // namespace compiler |
1173 } // namespace internal | 1139 } // namespace internal |
1174 } // namespace v8 | 1140 } // namespace v8 |
OLD | NEW |