Chromium Code Reviews| 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 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1070 new LoadIndexedInstr(new Value(array), | 1070 new LoadIndexedInstr(new Value(array), |
| 1071 new Value(index), | 1071 new Value(index), |
| 1072 index_scale, | 1072 index_scale, |
| 1073 array_cid, | 1073 array_cid, |
| 1074 deopt_id); | 1074 deopt_id); |
| 1075 ReplaceCall(call, array_op); | 1075 ReplaceCall(call, array_op); |
| 1076 return true; | 1076 return true; |
| 1077 } | 1077 } |
| 1078 | 1078 |
| 1079 | 1079 |
| 1080 static bool SmiFitsInDouble() { return kSmiBits < 53; } | |
| 1081 | |
| 1082 | |
| 1083 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | |
| 1084 Token::Kind op_kind) { | |
| 1085 const ICData& ic_data = *call->ic_data(); | |
| 1086 ASSERT(ic_data.num_args_tested() == 2); | |
| 1087 | |
| 1088 ASSERT(call->ArgumentCount() == 2); | |
| 1089 Definition* left = call->ArgumentAt(0); | |
| 1090 Definition* right = call->ArgumentAt(1); | |
| 1091 | |
| 1092 intptr_t cid = kIllegalCid; | |
| 1093 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
| 1094 InsertBefore(call, | |
| 1095 new CheckSmiInstr(new Value(left), call->deopt_id()), | |
| 1096 call->env(), | |
| 1097 Definition::kEffect); | |
| 1098 InsertBefore(call, | |
| 1099 new CheckSmiInstr(new Value(right), call->deopt_id()), | |
| 1100 call->env(), | |
| 1101 Definition::kEffect); | |
| 1102 cid = kSmiCid; | |
| 1103 } else if (HasTwoMintOrSmi(ic_data) && | |
| 1104 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 1105 cid = kMintCid; | |
| 1106 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
| 1107 // Use double comparison. | |
| 1108 if (SmiFitsInDouble()) { | |
| 1109 cid = kDoubleCid; | |
| 1110 } else { | |
| 1111 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
| 1112 // We cannot use double comparison on two Smi-s. Need polymorphic | |
|
Kevin Millikin (Google)
2013/09/03 13:23:55
I see that you didn't write this comment in this c
Florian Schneider
2013/09/03 13:55:06
Done.
| |
| 1113 // call. | |
| 1114 return false; | |
| 1115 } else { | |
| 1116 InsertBefore(call, | |
| 1117 new CheckEitherNonSmiInstr(new Value(left), | |
| 1118 new Value(right), | |
| 1119 call->deopt_id()), | |
| 1120 call->env(), | |
| 1121 Definition::kEffect); | |
| 1122 cid = kDoubleCid; | |
| 1123 } | |
| 1124 } | |
| 1125 } else { | |
| 1126 return false; | |
| 1127 } | |
| 1128 ASSERT(cid != kIllegalCid); | |
| 1129 RelationalOpInstr* comp = new RelationalOpInstr(call->token_pos(), | |
| 1130 op_kind, | |
| 1131 new Value(left), | |
| 1132 new Value(right), | |
| 1133 cid, | |
| 1134 call->deopt_id()); | |
| 1135 ReplaceCall(call, comp); | |
| 1136 return true; | |
| 1137 } | |
| 1138 | |
| 1139 | |
| 1080 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 1140 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 1081 Token::Kind op_kind) { | 1141 Token::Kind op_kind) { |
| 1082 intptr_t operands_type = kIllegalCid; | 1142 intptr_t operands_type = kIllegalCid; |
| 1083 ASSERT(call->HasICData()); | 1143 ASSERT(call->HasICData()); |
| 1084 const ICData& ic_data = *call->ic_data(); | 1144 const ICData& ic_data = *call->ic_data(); |
| 1085 switch (op_kind) { | 1145 switch (op_kind) { |
| 1086 case Token::kADD: | 1146 case Token::kADD: |
| 1087 case Token::kSUB: | 1147 case Token::kSUB: |
| 1088 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1148 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1089 // Don't generate smi code if the IC data is marked because | 1149 // Don't generate smi code if the IC data is marked because |
| (...skipping 1513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2603 instr->set_ic_data(&unary_checks); | 2663 instr->set_ic_data(&unary_checks); |
| 2604 return; | 2664 return; |
| 2605 } | 2665 } |
| 2606 | 2666 |
| 2607 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { | 2667 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { |
| 2608 return; | 2668 return; |
| 2609 } | 2669 } |
| 2610 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { | 2670 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { |
| 2611 return; | 2671 return; |
| 2612 } | 2672 } |
| 2673 | |
| 2674 if (Token::IsRelationalOperator(op_kind) && | |
| 2675 TryReplaceWithRelationalOp(instr, op_kind)) { | |
| 2676 return; | |
| 2677 } | |
| 2678 | |
| 2613 if (Token::IsBinaryOperator(op_kind) && | 2679 if (Token::IsBinaryOperator(op_kind) && |
| 2614 TryReplaceWithBinaryOp(instr, op_kind)) { | 2680 TryReplaceWithBinaryOp(instr, op_kind)) { |
| 2615 return; | 2681 return; |
| 2616 } | 2682 } |
| 2617 if (Token::IsPrefixOperator(op_kind) && | 2683 if (Token::IsPrefixOperator(op_kind) && |
| 2618 TryReplaceWithUnaryOp(instr, op_kind)) { | 2684 TryReplaceWithUnaryOp(instr, op_kind)) { |
| 2619 return; | 2685 return; |
| 2620 } | 2686 } |
| 2621 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | 2687 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { |
| 2622 return; | 2688 return; |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2806 new Value(instr->ArgumentAt(1)), | 2872 new Value(instr->ArgumentAt(1)), |
| 2807 needs_store_barrier); | 2873 needs_store_barrier); |
| 2808 // Discard the environment from the original instruction because the store | 2874 // Discard the environment from the original instruction because the store |
| 2809 // can't deoptimize. | 2875 // can't deoptimize. |
| 2810 instr->RemoveEnvironment(); | 2876 instr->RemoveEnvironment(); |
| 2811 ReplaceCall(instr, store); | 2877 ReplaceCall(instr, store); |
| 2812 return true; | 2878 return true; |
| 2813 } | 2879 } |
| 2814 | 2880 |
| 2815 | 2881 |
| 2816 static bool SmiFitsInDouble() { return kSmiBits < 53; } | |
| 2817 | |
| 2818 | |
| 2819 void FlowGraphOptimizer::HandleComparison(ComparisonInstr* comp, | |
| 2820 const ICData& ic_data, | |
| 2821 Instruction* current_instruction) { | |
| 2822 ASSERT(ic_data.num_args_tested() == 2); | |
| 2823 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 2824 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
| 2825 InsertBefore(current_instruction, | |
| 2826 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
| 2827 current_instruction->env(), | |
| 2828 Definition::kEffect); | |
| 2829 InsertBefore(current_instruction, | |
| 2830 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
| 2831 current_instruction->env(), | |
| 2832 Definition::kEffect); | |
| 2833 comp->set_operation_cid(kSmiCid); | |
| 2834 } else if (HasTwoMintOrSmi(ic_data) && | |
| 2835 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 2836 comp->set_operation_cid(kMintCid); | |
| 2837 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
| 2838 // Use double comparison. | |
| 2839 if (SmiFitsInDouble()) { | |
| 2840 comp->set_operation_cid(kDoubleCid); | |
| 2841 } else { | |
| 2842 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
| 2843 // We cannot use double comparison on two Smi-s. | |
| 2844 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 2845 } else { | |
| 2846 InsertBefore(current_instruction, | |
| 2847 new CheckEitherNonSmiInstr(comp->left()->Copy(), | |
| 2848 comp->right()->Copy(), | |
| 2849 comp->deopt_id()), | |
| 2850 current_instruction->env(), | |
| 2851 Definition::kEffect); | |
| 2852 comp->set_operation_cid(kDoubleCid); | |
| 2853 } | |
| 2854 } | |
| 2855 } else { | |
| 2856 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 2857 } | |
| 2858 } | |
| 2859 | |
| 2860 | |
| 2861 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { | |
| 2862 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | |
| 2863 return; | |
| 2864 } | |
| 2865 HandleComparison(comp, *comp->ic_data(), current_iterator()->Current()); | |
| 2866 } | |
| 2867 | |
| 2868 | |
| 2869 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { | |
| 2870 HandleRelationalOp(instr); | |
| 2871 } | |
| 2872 | |
| 2873 | |
| 2874 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( | 2882 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( |
| 2875 EqualityCompareInstr* compare) { | 2883 EqualityCompareInstr* compare) { |
| 2876 // If one of the inputs is null this is a strict comparison. | 2884 // If one of the inputs is null this is a strict comparison. |
| 2877 if (compare->left()->BindsToConstantNull() || | 2885 if (compare->left()->BindsToConstantNull() || |
| 2878 compare->right()->BindsToConstantNull()) { | 2886 compare->right()->BindsToConstantNull()) { |
| 2879 return true; | 2887 return true; |
| 2880 } | 2888 } |
| 2881 | 2889 |
| 2882 if (compare->left()->Type()->IsNone()) { | 2890 if (compare->left()->Type()->IsNone()) { |
| 2883 return false; // We might be running prior to any type propagation passes. | 2891 return false; // We might be running prior to any type propagation passes. |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2986 if (StrictifyEqualityCompare(comp, current_instruction)) { | 2994 if (StrictifyEqualityCompare(comp, current_instruction)) { |
| 2987 // Based on input types, equality converted to strict-equality. | 2995 // Based on input types, equality converted to strict-equality. |
| 2988 return; | 2996 return; |
| 2989 } | 2997 } |
| 2990 | 2998 |
| 2991 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 2999 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 2992 return; | 3000 return; |
| 2993 } | 3001 } |
| 2994 | 3002 |
| 2995 const ICData& ic_data = *comp->ic_data(); | 3003 const ICData& ic_data = *comp->ic_data(); |
| 2996 HandleComparison(comp, ic_data, current_instruction); | 3004 ASSERT(ic_data.num_args_tested() == 2); |
| 3005 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 3006 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
| 3007 InsertBefore(current_instruction, | |
| 3008 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
| 3009 current_instruction->env(), | |
| 3010 Definition::kEffect); | |
| 3011 InsertBefore(current_instruction, | |
| 3012 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
| 3013 current_instruction->env(), | |
| 3014 Definition::kEffect); | |
| 3015 comp->set_operation_cid(kSmiCid); | |
| 3016 } else if (HasTwoMintOrSmi(ic_data) && | |
| 3017 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 3018 comp->set_operation_cid(kMintCid); | |
| 3019 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
| 3020 // Use double comparison. | |
| 3021 if (SmiFitsInDouble()) { | |
| 3022 comp->set_operation_cid(kDoubleCid); | |
| 3023 } else { | |
| 3024 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
| 3025 // We cannot use double comparison on two Smi-s. | |
| 3026 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 3027 } else { | |
| 3028 InsertBefore(current_instruction, | |
| 3029 new CheckEitherNonSmiInstr(comp->left()->Copy(), | |
| 3030 comp->right()->Copy(), | |
| 3031 comp->deopt_id()), | |
| 3032 current_instruction->env(), | |
| 3033 Definition::kEffect); | |
| 3034 comp->set_operation_cid(kDoubleCid); | |
| 3035 } | |
| 3036 } | |
| 3037 } | |
| 2997 | 3038 |
| 2998 if (comp->operation_cid() != kIllegalCid) { | 3039 if (comp->operation_cid() != kIllegalCid) { |
| 2999 // Done. | 3040 // Done. |
| 3000 return; | 3041 return; |
| 3001 } | 3042 } |
| 3002 | 3043 |
| 3003 const ICData& unary_checks_0 = | 3044 const ICData& unary_checks_0 = |
| 3004 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 3045 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 3005 if (StrictifyEqualityCompareWithICData( | 3046 if (StrictifyEqualityCompareWithICData( |
| 3006 comp, unary_checks_0, current_instruction)) { | 3047 comp, unary_checks_0, current_instruction)) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3038 | 3079 |
| 3039 | 3080 |
| 3040 | 3081 |
| 3041 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 3082 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 3042 HandleEqualityCompare(instr, instr); | 3083 HandleEqualityCompare(instr, instr); |
| 3043 } | 3084 } |
| 3044 | 3085 |
| 3045 | 3086 |
| 3046 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | 3087 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| 3047 ComparisonInstr* comparison = instr->comparison(); | 3088 ComparisonInstr* comparison = instr->comparison(); |
| 3048 if (comparison->IsRelationalOp()) { | 3089 if (comparison->IsEqualityCompare()) { |
| 3049 HandleRelationalOp(comparison->AsRelationalOp()); | |
| 3050 } else if (comparison->IsEqualityCompare()) { | |
| 3051 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); | 3090 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); |
| 3052 } else { | 3091 } else { |
| 3053 ASSERT(comparison->IsStrictCompare()); | 3092 ASSERT(comparison->IsStrictCompare()); |
| 3054 // Nothing to do. | 3093 // Nothing to do. |
| 3055 } | 3094 } |
| 3056 } | 3095 } |
| 3057 | 3096 |
| 3058 | 3097 |
| 3059 static bool MayBeBoxableNumber(intptr_t cid) { | 3098 static bool MayBeBoxableNumber(intptr_t cid) { |
| 3060 return (cid == kDynamicCid) || | 3099 return (cid == kDynamicCid) || |
| (...skipping 3879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6940 new_equality_compare->set_operation_cid(equality_compare->operation_cid()); | 6979 new_equality_compare->set_operation_cid(equality_compare->operation_cid()); |
| 6941 new_comparison = new_equality_compare; | 6980 new_comparison = new_equality_compare; |
| 6942 } else { | 6981 } else { |
| 6943 ASSERT(comparison->IsRelationalOp()); | 6982 ASSERT(comparison->IsRelationalOp()); |
| 6944 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); | 6983 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); |
| 6945 RelationalOpInstr* new_relational_op = | 6984 RelationalOpInstr* new_relational_op = |
| 6946 new RelationalOpInstr(relational_op->token_pos(), | 6985 new RelationalOpInstr(relational_op->token_pos(), |
| 6947 comparison->kind(), | 6986 comparison->kind(), |
| 6948 left, | 6987 left, |
| 6949 right, | 6988 right, |
| 6950 Object::null_array()); | 6989 relational_op->operation_cid(), |
| 6951 new_relational_op->set_ic_data(relational_op->ic_data()); | 6990 relational_op->deopt_id()); |
| 6952 new_relational_op->set_operation_cid(relational_op->operation_cid()); | |
| 6953 new_comparison = new_relational_op; | 6991 new_comparison = new_relational_op; |
| 6954 } | 6992 } |
| 6955 return new BranchInstr(new_comparison, branch->is_checked()); | 6993 return new BranchInstr(new_comparison, branch->is_checked()); |
| 6956 } | 6994 } |
| 6957 | 6995 |
| 6958 | 6996 |
| 6959 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { | 6997 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { |
| 6960 // Optimize some branches that test the value of a phi. When it is safe | 6998 // Optimize some branches that test the value of a phi. When it is safe |
| 6961 // to do so, push the branch to each of the predecessor blocks. This is | 6999 // to do so, push the branch to each of the predecessor blocks. This is |
| 6962 // an optimization when (a) it can avoid materializing a boolean object at | 7000 // an optimization when (a) it can avoid materializing a boolean object at |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7475 } | 7513 } |
| 7476 | 7514 |
| 7477 // Insert materializations at environment uses. | 7515 // Insert materializations at environment uses. |
| 7478 for (intptr_t i = 0; i < exits.length(); i++) { | 7516 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7479 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7517 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7480 } | 7518 } |
| 7481 } | 7519 } |
| 7482 | 7520 |
| 7483 | 7521 |
| 7484 } // namespace dart | 7522 } // namespace dart |
| OLD | NEW |