| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 if (ic_data.NumberOfChecks() == 1) { | 585 if (ic_data.NumberOfChecks() == 1) { |
| 586 return ic_data.HasReceiverClassId(kSmiCid) | 586 return ic_data.HasReceiverClassId(kSmiCid) |
| 587 || ic_data.HasReceiverClassId(kMintCid); | 587 || ic_data.HasReceiverClassId(kMintCid); |
| 588 } | 588 } |
| 589 return (ic_data.NumberOfChecks() == 2) | 589 return (ic_data.NumberOfChecks() == 2) |
| 590 && ic_data.HasReceiverClassId(kSmiCid) | 590 && ic_data.HasReceiverClassId(kSmiCid) |
| 591 && ic_data.HasReceiverClassId(kMintCid); | 591 && ic_data.HasReceiverClassId(kMintCid); |
| 592 } | 592 } |
| 593 | 593 |
| 594 | 594 |
| 595 static bool HasOnlyTwoSmis(const ICData& ic_data) { | 595 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { |
| 596 return (ic_data.NumberOfChecks() == 1) && | 596 return (ic_data.NumberOfChecks() == 1) && |
| 597 ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid); | 597 ICDataHasReceiverArgumentClassIds(ic_data, cid, cid); |
| 598 } | |
| 599 | |
| 600 static bool HasOnlyTwoFloat32x4s(const ICData& ic_data) { | |
| 601 return (ic_data.NumberOfChecks() == 1) && | |
| 602 ICDataHasReceiverArgumentClassIds(ic_data, kFloat32x4Cid, kFloat32x4Cid); | |
| 603 } | |
| 604 | |
| 605 static bool HasOnlyTwoUint32x4s(const ICData& ic_data) { | |
| 606 return (ic_data.NumberOfChecks() == 1) && | |
| 607 ICDataHasReceiverArgumentClassIds(ic_data, kUint32x4Cid, kUint32x4Cid); | |
| 608 } | 598 } |
| 609 | 599 |
| 610 // Returns false if the ICData contains anything other than the 4 combinations | 600 // Returns false if the ICData contains anything other than the 4 combinations |
| 611 // of Mint and Smi for the receiver and argument classes. | 601 // of Mint and Smi for the receiver and argument classes. |
| 612 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 602 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
| 613 GrowableArray<intptr_t> class_ids(2); | 603 GrowableArray<intptr_t> class_ids(2); |
| 614 class_ids.Add(kSmiCid); | 604 class_ids.Add(kSmiCid); |
| 615 class_ids.Add(kMintCid); | 605 class_ids.Add(kMintCid); |
| 616 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 606 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 617 } | 607 } |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 | 1013 |
| 1024 | 1014 |
| 1025 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 1015 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 1026 Token::Kind op_kind) { | 1016 Token::Kind op_kind) { |
| 1027 intptr_t operands_type = kIllegalCid; | 1017 intptr_t operands_type = kIllegalCid; |
| 1028 ASSERT(call->HasICData()); | 1018 ASSERT(call->HasICData()); |
| 1029 const ICData& ic_data = *call->ic_data(); | 1019 const ICData& ic_data = *call->ic_data(); |
| 1030 switch (op_kind) { | 1020 switch (op_kind) { |
| 1031 case Token::kADD: | 1021 case Token::kADD: |
| 1032 case Token::kSUB: | 1022 case Token::kSUB: |
| 1033 if (HasOnlyTwoSmis(ic_data)) { | 1023 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1034 // Don't generate smi code if the IC data is marked because | 1024 // Don't generate smi code if the IC data is marked because |
| 1035 // of an overflow. | 1025 // of an overflow. |
| 1036 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) | 1026 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) |
| 1037 ? kMintCid | 1027 ? kMintCid |
| 1038 : kSmiCid; | 1028 : kSmiCid; |
| 1039 } else if (HasTwoMintOrSmi(ic_data) && | 1029 } else if (HasTwoMintOrSmi(ic_data) && |
| 1040 FlowGraphCompiler::SupportsUnboxedMints()) { | 1030 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1041 // Don't generate mint code if the IC data is marked because of an | 1031 // Don't generate mint code if the IC data is marked because of an |
| 1042 // overflow. | 1032 // overflow. |
| 1043 if (ic_data.deopt_reason() == kDeoptBinaryMintOp) return false; | 1033 if (ic_data.deopt_reason() == kDeoptBinaryMintOp) return false; |
| 1044 operands_type = kMintCid; | 1034 operands_type = kMintCid; |
| 1045 } else if (ShouldSpecializeForDouble(ic_data)) { | 1035 } else if (ShouldSpecializeForDouble(ic_data)) { |
| 1046 operands_type = kDoubleCid; | 1036 operands_type = kDoubleCid; |
| 1047 } else if (HasOnlyTwoFloat32x4s(ic_data)) { | 1037 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { |
| 1048 operands_type = kFloat32x4Cid; | 1038 operands_type = kFloat32x4Cid; |
| 1049 } else { | 1039 } else { |
| 1050 return false; | 1040 return false; |
| 1051 } | 1041 } |
| 1052 break; | 1042 break; |
| 1053 case Token::kMUL: | 1043 case Token::kMUL: |
| 1054 if (HasOnlyTwoSmis(ic_data)) { | 1044 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1055 // Don't generate smi code if the IC data is marked because of an | 1045 // Don't generate smi code if the IC data is marked because of an |
| 1056 // overflow. | 1046 // overflow. |
| 1057 // TODO(fschneider): Add unboxed mint multiplication. | 1047 // TODO(fschneider): Add unboxed mint multiplication. |
| 1058 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; | 1048 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; |
| 1059 operands_type = kSmiCid; | 1049 operands_type = kSmiCid; |
| 1060 } else if (ShouldSpecializeForDouble(ic_data)) { | 1050 } else if (ShouldSpecializeForDouble(ic_data)) { |
| 1061 operands_type = kDoubleCid; | 1051 operands_type = kDoubleCid; |
| 1062 } else if (HasOnlyTwoFloat32x4s(ic_data)) { | 1052 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { |
| 1063 operands_type = kFloat32x4Cid; | 1053 operands_type = kFloat32x4Cid; |
| 1064 } else { | 1054 } else { |
| 1065 return false; | 1055 return false; |
| 1066 } | 1056 } |
| 1067 break; | 1057 break; |
| 1068 case Token::kDIV: | 1058 case Token::kDIV: |
| 1069 if (ShouldSpecializeForDouble(ic_data) || HasOnlyTwoSmis(ic_data)) { | 1059 if (ShouldSpecializeForDouble(ic_data) || |
| 1060 HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1070 operands_type = kDoubleCid; | 1061 operands_type = kDoubleCid; |
| 1071 } else if (HasOnlyTwoFloat32x4s(ic_data)) { | 1062 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { |
| 1072 operands_type = kFloat32x4Cid; | 1063 operands_type = kFloat32x4Cid; |
| 1073 } else { | 1064 } else { |
| 1074 return false; | 1065 return false; |
| 1075 } | 1066 } |
| 1076 break; | 1067 break; |
| 1077 case Token::kMOD: | 1068 case Token::kMOD: |
| 1078 if (HasOnlyTwoSmis(ic_data)) { | 1069 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1079 operands_type = kSmiCid; | 1070 operands_type = kSmiCid; |
| 1080 } else { | 1071 } else { |
| 1081 return false; | 1072 return false; |
| 1082 } | 1073 } |
| 1083 break; | 1074 break; |
| 1084 case Token::kBIT_AND: | 1075 case Token::kBIT_AND: |
| 1085 case Token::kBIT_OR: | 1076 case Token::kBIT_OR: |
| 1086 case Token::kBIT_XOR: | 1077 case Token::kBIT_XOR: |
| 1087 if (HasOnlyTwoSmis(ic_data)) { | 1078 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1088 operands_type = kSmiCid; | 1079 operands_type = kSmiCid; |
| 1089 } else if (HasTwoMintOrSmi(ic_data)) { | 1080 } else if (HasTwoMintOrSmi(ic_data)) { |
| 1090 operands_type = kMintCid; | 1081 operands_type = kMintCid; |
| 1091 } else if (HasOnlyTwoUint32x4s(ic_data)) { | 1082 } else if (HasOnlyTwoOf(ic_data, kUint32x4Cid)) { |
| 1092 operands_type = kUint32x4Cid; | 1083 operands_type = kUint32x4Cid; |
| 1093 } else { | 1084 } else { |
| 1094 return false; | 1085 return false; |
| 1095 } | 1086 } |
| 1096 break; | 1087 break; |
| 1097 case Token::kSHR: | 1088 case Token::kSHR: |
| 1098 case Token::kSHL: | 1089 case Token::kSHL: |
| 1099 if (HasOnlyTwoSmis(ic_data)) { | 1090 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1100 // Left shift may overflow from smi into mint or big ints. | 1091 // Left shift may overflow from smi into mint or big ints. |
| 1101 // Don't generate smi code if the IC data is marked because | 1092 // Don't generate smi code if the IC data is marked because |
| 1102 // of an overflow. | 1093 // of an overflow. |
| 1103 if (ic_data.deopt_reason() == kDeoptShiftMintOp) return false; | 1094 if (ic_data.deopt_reason() == kDeoptShiftMintOp) return false; |
| 1104 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) | 1095 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) |
| 1105 ? kMintCid | 1096 ? kMintCid |
| 1106 : kSmiCid; | 1097 : kSmiCid; |
| 1107 } else if (HasTwoMintOrSmi(ic_data) && | 1098 } else if (HasTwoMintOrSmi(ic_data) && |
| 1108 HasOnlyOneSmi(ICData::Handle( | 1099 HasOnlyOneSmi(ICData::Handle( |
| 1109 ic_data.AsUnaryClassChecksForArgNr(1)))) { | 1100 ic_data.AsUnaryClassChecksForArgNr(1)))) { |
| 1110 // Don't generate mint code if the IC data is marked because of an | 1101 // Don't generate mint code if the IC data is marked because of an |
| 1111 // overflow. | 1102 // overflow. |
| 1112 if (ic_data.deopt_reason() == kDeoptShiftMintOp) return false; | 1103 if (ic_data.deopt_reason() == kDeoptShiftMintOp) return false; |
| 1113 // Check for smi/mint << smi or smi/mint >> smi. | 1104 // Check for smi/mint << smi or smi/mint >> smi. |
| 1114 operands_type = kMintCid; | 1105 operands_type = kMintCid; |
| 1115 } else { | 1106 } else { |
| 1116 return false; | 1107 return false; |
| 1117 } | 1108 } |
| 1118 break; | 1109 break; |
| 1119 case Token::kTRUNCDIV: | 1110 case Token::kTRUNCDIV: |
| 1120 if (HasOnlyTwoSmis(ic_data)) { | 1111 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1121 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; | 1112 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; |
| 1122 operands_type = kSmiCid; | 1113 operands_type = kSmiCid; |
| 1123 } else { | 1114 } else { |
| 1124 return false; | 1115 return false; |
| 1125 } | 1116 } |
| 1126 break; | 1117 break; |
| 1127 default: | 1118 default: |
| 1128 UNREACHABLE(); | 1119 UNREACHABLE(); |
| 1129 } | 1120 } |
| 1130 | 1121 |
| (...skipping 1639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2770 | 2761 |
| 2771 | 2762 |
| 2772 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 2763 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 2773 | 2764 |
| 2774 | 2765 |
| 2775 void FlowGraphOptimizer::HandleComparison(ComparisonInstr* comp, | 2766 void FlowGraphOptimizer::HandleComparison(ComparisonInstr* comp, |
| 2776 const ICData& ic_data, | 2767 const ICData& ic_data, |
| 2777 Instruction* current_instruction) { | 2768 Instruction* current_instruction) { |
| 2778 ASSERT(ic_data.num_args_tested() == 2); | 2769 ASSERT(ic_data.num_args_tested() == 2); |
| 2779 ASSERT(comp->operation_cid() == kIllegalCid); | 2770 ASSERT(comp->operation_cid() == kIllegalCid); |
| 2780 if (HasOnlyTwoSmis(ic_data)) { | 2771 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 2781 InsertBefore(current_instruction, | 2772 InsertBefore(current_instruction, |
| 2782 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 2773 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 2783 current_instruction->env(), | 2774 current_instruction->env(), |
| 2784 Definition::kEffect); | 2775 Definition::kEffect); |
| 2785 InsertBefore(current_instruction, | 2776 InsertBefore(current_instruction, |
| 2786 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 2777 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 2787 current_instruction->env(), | 2778 current_instruction->env(), |
| 2788 Definition::kEffect); | 2779 Definition::kEffect); |
| 2789 comp->set_operation_cid(kSmiCid); | 2780 comp->set_operation_cid(kSmiCid); |
| 2790 } else if (HasTwoMintOrSmi(ic_data) && | 2781 } else if (HasTwoMintOrSmi(ic_data) && |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2884 strict_kind, | 2875 strict_kind, |
| 2885 compare->left()->CopyWithType(), | 2876 compare->left()->CopyWithType(), |
| 2886 compare->right()->CopyWithType()); | 2877 compare->right()->CopyWithType()); |
| 2887 current_instruction->ReplaceWith(strict_comp, current_iterator()); | 2878 current_instruction->ReplaceWith(strict_comp, current_iterator()); |
| 2888 return true; | 2879 return true; |
| 2889 } | 2880 } |
| 2890 return false; | 2881 return false; |
| 2891 } | 2882 } |
| 2892 | 2883 |
| 2893 | 2884 |
| 2885 // Returns true if we converted EqualityCompare to StrictCompare. |
| 2886 template <typename T> |
| 2887 bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData( |
| 2888 EqualityCompareInstr* compare, |
| 2889 const ICData& unary_ic_data, |
| 2890 T current_instruction) { |
| 2891 ASSERT(unary_ic_data.num_args_tested() == 1); |
| 2892 if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 2893 // If possible classes do not override Object's equality then replace |
| 2894 // with strict equality. |
| 2895 Function& target = Function::Handle(); |
| 2896 Class& targets_class = Class::Handle(); |
| 2897 for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) { |
| 2898 intptr_t cid = kIllegalCid; |
| 2899 unary_ic_data.GetOneClassCheckAt(i, &cid, &target); |
| 2900 targets_class = target.Owner(); |
| 2901 if (targets_class.id() != kInstanceCid) { |
| 2902 // Overriden equality operator. |
| 2903 return false; |
| 2904 } |
| 2905 } |
| 2906 AddCheckClass(compare->left()->definition(), |
| 2907 unary_ic_data, |
| 2908 compare->deopt_id(), |
| 2909 current_instruction->env(), |
| 2910 current_instruction); |
| 2911 ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE)); |
| 2912 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? |
| 2913 Token::kEQ_STRICT : Token::kNE_STRICT; |
| 2914 StrictCompareInstr* strict_comp = |
| 2915 new StrictCompareInstr(compare->token_pos(), |
| 2916 strict_kind, |
| 2917 compare->left()->Copy(), |
| 2918 compare->right()->Copy()); |
| 2919 current_instruction->ReplaceWith(strict_comp, current_iterator()); |
| 2920 return true; |
| 2921 } |
| 2922 return false; |
| 2923 } |
| 2924 |
| 2925 |
| 2894 template <typename T> | 2926 template <typename T> |
| 2895 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, | 2927 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, |
| 2896 T current_instruction) { | 2928 T current_instruction) { |
| 2897 if (StrictifyEqualityCompare(comp, current_instruction)) { | 2929 if (StrictifyEqualityCompare(comp, current_instruction)) { |
| 2930 // Based on input types, equality converted to strict-equality. |
| 2898 return; | 2931 return; |
| 2899 } | 2932 } |
| 2900 | 2933 |
| 2901 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 2934 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 2902 return; | 2935 return; |
| 2903 } | 2936 } |
| 2904 | 2937 |
| 2905 const ICData& ic_data = *comp->ic_data(); | 2938 const ICData& ic_data = *comp->ic_data(); |
| 2906 HandleComparison(comp, ic_data, current_instruction); | 2939 HandleComparison(comp, ic_data, current_instruction); |
| 2907 | 2940 |
| 2908 if (comp->operation_cid() != kIllegalCid) { | 2941 if (comp->operation_cid() != kIllegalCid) { |
| 2909 // Done. | 2942 // Done. |
| 2910 return; | 2943 return; |
| 2911 } | 2944 } |
| 2912 | 2945 |
| 2946 const ICData& unary_checks_0 = |
| 2947 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 2948 if (StrictifyEqualityCompareWithICData( |
| 2949 comp, unary_checks_0, current_instruction)) { |
| 2950 // Based on ICData, equality converted to strict-equality. |
| 2951 return; |
| 2952 } |
| 2953 |
| 2913 // Check if ICDData contains checks with Smi/Null combinations. In that case | 2954 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 2914 // we can still emit the optimized Smi equality operation but need to add | 2955 // we can still emit the optimized Smi equality operation but need to add |
| 2915 // checks for null or Smi. | 2956 // checks for null or Smi. |
| 2916 // TODO(srdjan): Add it for Double and Mint. | 2957 // TODO(srdjan): Add it for Double and Mint. |
| 2917 GrowableArray<intptr_t> smi_or_null(2); | 2958 GrowableArray<intptr_t> smi_or_null(2); |
| 2918 smi_or_null.Add(kSmiCid); | 2959 smi_or_null.Add(kSmiCid); |
| 2919 smi_or_null.Add(kNullCid); | 2960 smi_or_null.Add(kNullCid); |
| 2920 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, | 2961 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, |
| 2921 smi_or_null, | 2962 smi_or_null, |
| 2922 smi_or_null)) { | 2963 smi_or_null)) { |
| 2923 const ICData& unary_checks_0 = | |
| 2924 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | |
| 2925 AddCheckClass(comp->left()->definition(), | 2964 AddCheckClass(comp->left()->definition(), |
| 2926 unary_checks_0, | 2965 unary_checks_0, |
| 2927 comp->deopt_id(), | 2966 comp->deopt_id(), |
| 2928 current_instruction->env(), | 2967 current_instruction->env(), |
| 2929 current_instruction); | 2968 current_instruction); |
| 2930 | 2969 |
| 2931 const ICData& unary_checks_1 = | 2970 const ICData& unary_checks_1 = |
| 2932 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | 2971 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 2933 AddCheckClass(comp->right()->definition(), | 2972 AddCheckClass(comp->right()->definition(), |
| 2934 unary_checks_1, | 2973 unary_checks_1, |
| (...skipping 4431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7366 | 7405 |
| 7367 // Insert materializations at environment uses. | 7406 // Insert materializations at environment uses. |
| 7368 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7407 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7369 for (intptr_t i = 0; i < exits.length(); i++) { | 7408 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7370 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7409 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 7371 } | 7410 } |
| 7372 } | 7411 } |
| 7373 | 7412 |
| 7374 | 7413 |
| 7375 } // namespace dart | 7414 } // namespace dart |
| OLD | NEW |