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" |
11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
12 #include "vm/hash_map.h" | 12 #include "vm/hash_map.h" |
13 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
14 #include "vm/intermediate_language.h" | 14 #include "vm/intermediate_language.h" |
15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
16 #include "vm/parser.h" | 16 #include "vm/parser.h" |
17 #include "vm/resolver.h" | 17 #include "vm/resolver.h" |
18 #include "vm/scopes.h" | 18 #include "vm/scopes.h" |
19 #include "vm/stack_frame.h" | 19 #include "vm/stack_frame.h" |
20 #include "vm/symbols.h" | 20 #include "vm/symbols.h" |
21 | 21 |
22 namespace dart { | 22 namespace dart { |
23 | 23 |
24 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 24 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
25 "Eliminate redundant bounds checks."); | 25 "Eliminate redundant bounds checks."); |
26 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 26 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
27 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 27 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
28 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 28 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 29 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
| 30 "Maximum number of polymorphic checks in equality operator," |
| 31 " otherwise use megamorphic dispatch."); |
29 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 32 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
30 DEFINE_FLAG(bool, trace_constant_propagation, false, | 33 DEFINE_FLAG(bool, trace_constant_propagation, false, |
31 "Print constant propagation and useless code elimination."); | 34 "Print constant propagation and useless code elimination."); |
32 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 35 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
33 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 36 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
34 DEFINE_FLAG(bool, truncating_left_shift, true, | 37 DEFINE_FLAG(bool, truncating_left_shift, true, |
35 "Optimize left shift to truncate if possible"); | 38 "Optimize left shift to truncate if possible"); |
36 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 39 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
37 DEFINE_FLAG(bool, trace_load_optimization, false, | 40 DEFINE_FLAG(bool, trace_load_optimization, false, |
38 "Print live sets for load optimization pass."); | 41 "Print live sets for load optimization pass."); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } | 81 } |
79 } | 82 } |
80 } else if (instr->IsPolymorphicInstanceCall()) { | 83 } else if (instr->IsPolymorphicInstanceCall()) { |
81 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); | 84 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); |
82 } else if (instr->IsStrictCompare()) { | 85 } else if (instr->IsStrictCompare()) { |
83 VisitStrictCompare(instr->AsStrictCompare()); | 86 VisitStrictCompare(instr->AsStrictCompare()); |
84 } else if (instr->IsBranch()) { | 87 } else if (instr->IsBranch()) { |
85 ComparisonInstr* compare = instr->AsBranch()->comparison(); | 88 ComparisonInstr* compare = instr->AsBranch()->comparison(); |
86 if (compare->IsStrictCompare()) { | 89 if (compare->IsStrictCompare()) { |
87 VisitStrictCompare(compare->AsStrictCompare()); | 90 VisitStrictCompare(compare->AsStrictCompare()); |
88 } else if (compare->IsEqualityCompare()) { | |
89 StrictifyEqualityCompare(compare->AsEqualityCompare(), | |
90 instr->AsBranch()); | |
91 } | 91 } |
92 } | 92 } |
93 } | 93 } |
94 current_iterator_ = NULL; | 94 current_iterator_ = NULL; |
95 } | 95 } |
96 } | 96 } |
97 | 97 |
98 | 98 |
99 // Attempt to build ICData for call using propagated class-ids. | 99 // Attempt to build ICData for call using propagated class-ids. |
100 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 100 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
(...skipping 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1267 ASSERT(current_iterator()->Current() == call); | 1267 ASSERT(current_iterator()->Current() == call); |
1268 current_iterator()->RemoveCurrentFromGraph(); | 1268 current_iterator()->RemoveCurrentFromGraph(); |
1269 call->set_previous(NULL); | 1269 call->set_previous(NULL); |
1270 call->set_next(NULL); | 1270 call->set_next(NULL); |
1271 return true; | 1271 return true; |
1272 } | 1272 } |
1273 | 1273 |
1274 | 1274 |
1275 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1275 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
1276 | 1276 |
| 1277 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 1278 Token::Kind op_kind) { |
| 1279 const ICData& ic_data = *call->ic_data(); |
| 1280 ASSERT(ic_data.num_args_tested() == 2); |
| 1281 |
| 1282 ASSERT(call->ArgumentCount() == 2); |
| 1283 Definition* left = call->ArgumentAt(0); |
| 1284 Definition* right = call->ArgumentAt(1); |
| 1285 |
| 1286 intptr_t cid = kIllegalCid; |
| 1287 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1288 InsertBefore(call, |
| 1289 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 1290 call->env(), |
| 1291 Definition::kEffect); |
| 1292 InsertBefore(call, |
| 1293 new CheckSmiInstr(new Value(right), call->deopt_id()), |
| 1294 call->env(), |
| 1295 Definition::kEffect); |
| 1296 cid = kSmiCid; |
| 1297 } else if (HasTwoMintOrSmi(ic_data) && |
| 1298 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1299 cid = kMintCid; |
| 1300 } else if (HasTwoDoubleOrSmi(ic_data)) { |
| 1301 // Use double comparison. |
| 1302 if (SmiFitsInDouble()) { |
| 1303 cid = kDoubleCid; |
| 1304 } else { |
| 1305 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 1306 // We cannot use double comparison on two smis. Need polymorphic |
| 1307 // call. |
| 1308 return false; |
| 1309 } else { |
| 1310 InsertBefore(call, |
| 1311 new CheckEitherNonSmiInstr(new Value(left), |
| 1312 new Value(right), |
| 1313 call->deopt_id()), |
| 1314 call->env(), |
| 1315 Definition::kEffect); |
| 1316 cid = kDoubleCid; |
| 1317 } |
| 1318 } |
| 1319 } else { |
| 1320 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1321 // we can still emit the optimized Smi equality operation but need to add |
| 1322 // checks for null or Smi. |
| 1323 GrowableArray<intptr_t> smi_or_null(2); |
| 1324 smi_or_null.Add(kSmiCid); |
| 1325 smi_or_null.Add(kNullCid); |
| 1326 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, |
| 1327 smi_or_null, |
| 1328 smi_or_null)) { |
| 1329 const ICData& unary_checks_0 = |
| 1330 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 1331 AddCheckClass(left, |
| 1332 unary_checks_0, |
| 1333 call->deopt_id(), |
| 1334 call->env(), |
| 1335 call); |
| 1336 |
| 1337 const ICData& unary_checks_1 = |
| 1338 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1339 AddCheckClass(right, |
| 1340 unary_checks_1, |
| 1341 call->deopt_id(), |
| 1342 call->env(), |
| 1343 call); |
| 1344 cid = kSmiCid; |
| 1345 } else { |
| 1346 // Shortcut for equality with null. |
| 1347 ConstantInstr* right_const = right->AsConstant(); |
| 1348 ConstantInstr* left_const = left->AsConstant(); |
| 1349 if ((right_const != NULL && right_const->value().IsNull()) || |
| 1350 (left_const != NULL && left_const->value().IsNull())) { |
| 1351 StrictCompareInstr* comp = new StrictCompareInstr(call->token_pos(), |
| 1352 Token::kEQ_STRICT, |
| 1353 new Value(left), |
| 1354 new Value(right)); |
| 1355 ReplaceCall(call, comp); |
| 1356 return true; |
| 1357 } |
| 1358 return false; |
| 1359 } |
| 1360 } |
| 1361 ASSERT(cid != kIllegalCid); |
| 1362 EqualityCompareInstr* comp = new EqualityCompareInstr(call->token_pos(), |
| 1363 op_kind, |
| 1364 new Value(left), |
| 1365 new Value(right), |
| 1366 cid, |
| 1367 call->deopt_id()); |
| 1368 ReplaceCall(call, comp); |
| 1369 return true; |
| 1370 } |
| 1371 |
1277 | 1372 |
1278 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1373 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
1279 Token::Kind op_kind) { | 1374 Token::Kind op_kind) { |
1280 const ICData& ic_data = *call->ic_data(); | 1375 const ICData& ic_data = *call->ic_data(); |
1281 ASSERT(ic_data.num_args_tested() == 2); | 1376 ASSERT(ic_data.num_args_tested() == 2); |
1282 | 1377 |
1283 ASSERT(call->ArgumentCount() == 2); | 1378 ASSERT(call->ArgumentCount() == 2); |
1284 Definition* left = call->ArgumentAt(0); | 1379 Definition* left = call->ArgumentAt(0); |
1285 Definition* right = call->ArgumentAt(1); | 1380 Definition* right = call->ArgumentAt(1); |
1286 | 1381 |
(...skipping 1560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2847 if (prev.IsNull()) { | 2942 if (prev.IsNull()) { |
2848 prev = Bool::Get(is_subtype).raw(); | 2943 prev = Bool::Get(is_subtype).raw(); |
2849 } else { | 2944 } else { |
2850 if (is_subtype != prev.value()) return Bool::null(); | 2945 if (is_subtype != prev.value()) return Bool::null(); |
2851 } | 2946 } |
2852 } | 2947 } |
2853 return prev.raw(); | 2948 return prev.raw(); |
2854 } | 2949 } |
2855 | 2950 |
2856 | 2951 |
| 2952 static Definition* OriginalDefinition(Definition* defn) { |
| 2953 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { |
| 2954 if (defn->IsRedefinition()) { |
| 2955 defn = defn->AsRedefinition()->value()->definition(); |
| 2956 } else { |
| 2957 defn = defn->AsAssertAssignable()->value()->definition(); |
| 2958 } |
| 2959 } |
| 2960 return defn; |
| 2961 } |
| 2962 |
| 2963 |
2857 // TODO(srdjan): Use ICData to check if always true or false. | 2964 // TODO(srdjan): Use ICData to check if always true or false. |
2858 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2965 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
2859 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2966 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
2860 Definition* left = call->ArgumentAt(0); | 2967 Definition* left = call->ArgumentAt(0); |
2861 Definition* instantiator = call->ArgumentAt(1); | 2968 Definition* instantiator = call->ArgumentAt(1); |
2862 Definition* type_args = call->ArgumentAt(2); | 2969 Definition* type_args = call->ArgumentAt(2); |
2863 const AbstractType& type = | 2970 const AbstractType& type = |
2864 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 2971 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
2865 const bool negate = | 2972 const bool negate = Bool::Cast( |
2866 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); | 2973 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); |
2867 const ICData& unary_checks = | 2974 const ICData& unary_checks = |
2868 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 2975 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
2869 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 2976 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
2870 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 2977 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
2871 if (!as_bool.IsNull()) { | 2978 if (!as_bool.IsNull()) { |
2872 AddReceiverCheck(call); | 2979 AddReceiverCheck(call); |
2873 if (negate) { | 2980 if (negate) { |
2874 as_bool = Bool::Get(!as_bool.value()).raw(); | 2981 as_bool = Bool::Get(!as_bool.value()).raw(); |
2875 } | 2982 } |
2876 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | 2983 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2955 } | 3062 } |
2956 | 3063 |
2957 if (Token::IsTypeCastOperator(op_kind)) { | 3064 if (Token::IsTypeCastOperator(op_kind)) { |
2958 ReplaceWithTypeCast(instr); | 3065 ReplaceWithTypeCast(instr); |
2959 return; | 3066 return; |
2960 } | 3067 } |
2961 | 3068 |
2962 const ICData& unary_checks = | 3069 const ICData& unary_checks = |
2963 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 3070 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
2964 | 3071 |
2965 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && | 3072 intptr_t max_checks = (op_kind == Token::kEQ) |
| 3073 ? FLAG_max_equality_polymorphic_checks |
| 3074 : FLAG_max_polymorphic_checks; |
| 3075 if ((unary_checks.NumberOfChecks() > max_checks) && |
2966 InstanceCallNeedsClassCheck(instr)) { | 3076 InstanceCallNeedsClassCheck(instr)) { |
2967 // Too many checks, it will be megamorphic which needs unary checks. | 3077 // Too many checks, it will be megamorphic which needs unary checks. |
2968 instr->set_ic_data(&unary_checks); | 3078 instr->set_ic_data(&unary_checks); |
2969 return; | 3079 return; |
2970 } | 3080 } |
2971 | 3081 |
2972 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { | 3082 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { |
2973 return; | 3083 return; |
2974 } | 3084 } |
2975 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { | 3085 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { |
2976 return; | 3086 return; |
2977 } | 3087 } |
2978 | 3088 |
| 3089 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 3090 return; |
| 3091 } |
| 3092 |
2979 if (Token::IsRelationalOperator(op_kind) && | 3093 if (Token::IsRelationalOperator(op_kind) && |
2980 TryReplaceWithRelationalOp(instr, op_kind)) { | 3094 TryReplaceWithRelationalOp(instr, op_kind)) { |
2981 return; | 3095 return; |
2982 } | 3096 } |
2983 | 3097 |
2984 if (Token::IsBinaryOperator(op_kind) && | 3098 if (Token::IsBinaryOperator(op_kind) && |
2985 TryReplaceWithBinaryOp(instr, op_kind)) { | 3099 TryReplaceWithBinaryOp(instr, op_kind)) { |
2986 return; | 3100 return; |
2987 } | 3101 } |
2988 if (Token::IsPrefixOperator(op_kind) && | 3102 if (Token::IsPrefixOperator(op_kind) && |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3183 new Value(instr->ArgumentAt(1)), | 3297 new Value(instr->ArgumentAt(1)), |
3184 needs_store_barrier); | 3298 needs_store_barrier); |
3185 // Discard the environment from the original instruction because the store | 3299 // Discard the environment from the original instruction because the store |
3186 // can't deoptimize. | 3300 // can't deoptimize. |
3187 instr->RemoveEnvironment(); | 3301 instr->RemoveEnvironment(); |
3188 ReplaceCall(instr, store); | 3302 ReplaceCall(instr, store); |
3189 return true; | 3303 return true; |
3190 } | 3304 } |
3191 | 3305 |
3192 | 3306 |
3193 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( | |
3194 EqualityCompareInstr* compare) { | |
3195 // If one of the inputs is null this is a strict comparison. | |
3196 if (compare->left()->BindsToConstantNull() || | |
3197 compare->right()->BindsToConstantNull()) { | |
3198 return true; | |
3199 } | |
3200 | |
3201 if (compare->left()->Type()->IsNone()) { | |
3202 return false; // We might be running prior to any type propagation passes. | |
3203 } | |
3204 | |
3205 // Try resolving target function using propagated cid for the receiver. | |
3206 // If receiver is either null or has default equality operator then | |
3207 // we can convert such comparison to a strict one. | |
3208 const intptr_t receiver_cid = | |
3209 compare->left()->Type()->ToNullableCid(); | |
3210 | |
3211 if (receiver_cid == kDynamicCid) { | |
3212 return false; | |
3213 } | |
3214 | |
3215 const Class& receiver_class = Class::Handle( | |
3216 Isolate::Current()->class_table()->At(receiver_cid)); | |
3217 | |
3218 // Resolve equality operator. | |
3219 const intptr_t kNumArgs = 2; | |
3220 ArgumentsDescriptor args_desc( | |
3221 Array::Handle(ArgumentsDescriptor::New(kNumArgs))); | |
3222 const Function& function = Function::Handle( | |
3223 Resolver::ResolveDynamicForReceiverClass( | |
3224 receiver_class, | |
3225 Symbols::EqualOperator(), | |
3226 args_desc)); | |
3227 | |
3228 if (function.IsNull()) { | |
3229 return false; | |
3230 } | |
3231 | |
3232 // Default equality operator declared on the Object class just calls | |
3233 // identical. | |
3234 return (Class::Handle(function.Owner()).id() == kInstanceCid); | |
3235 } | |
3236 | |
3237 | |
3238 template <typename T> | |
3239 bool FlowGraphOptimizer::StrictifyEqualityCompare( | |
3240 EqualityCompareInstr* compare, | |
3241 T current_instruction) const { | |
3242 if (CanStrictifyEqualityCompare(compare)) { | |
3243 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
3244 Token::kEQ_STRICT : Token::kNE_STRICT; | |
3245 StrictCompareInstr* strict_comp = | |
3246 new StrictCompareInstr(compare->token_pos(), | |
3247 strict_kind, | |
3248 compare->left()->CopyWithType(), | |
3249 compare->right()->CopyWithType()); | |
3250 // Numbers override equality and are therefore not part of this conversion. | |
3251 strict_comp->set_needs_number_check(false); | |
3252 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
3253 return true; | |
3254 } | |
3255 return false; | |
3256 } | |
3257 | |
3258 | |
3259 // Returns true if we converted EqualityCompare to StrictCompare. | |
3260 template <typename T> | |
3261 bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData( | |
3262 EqualityCompareInstr* compare, | |
3263 const ICData& unary_ic_data, | |
3264 T current_instruction) { | |
3265 ASSERT(unary_ic_data.num_args_tested() == 1); | |
3266 if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | |
3267 // If possible classes do not override Object's equality then replace | |
3268 // with strict equality. | |
3269 Function& target = Function::Handle(); | |
3270 Class& targets_class = Class::Handle(); | |
3271 for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) { | |
3272 intptr_t cid = kIllegalCid; | |
3273 unary_ic_data.GetOneClassCheckAt(i, &cid, &target); | |
3274 targets_class = target.Owner(); | |
3275 if (targets_class.id() != kInstanceCid) { | |
3276 // Overriden equality operator. | |
3277 return false; | |
3278 } | |
3279 } | |
3280 AddCheckClass(compare->left()->definition(), | |
3281 unary_ic_data, | |
3282 compare->deopt_id(), | |
3283 current_instruction->env(), | |
3284 current_instruction); | |
3285 ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE)); | |
3286 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
3287 Token::kEQ_STRICT : Token::kNE_STRICT; | |
3288 StrictCompareInstr* strict_comp = | |
3289 new StrictCompareInstr(compare->token_pos(), | |
3290 strict_kind, | |
3291 compare->left()->Copy(), | |
3292 compare->right()->Copy()); | |
3293 // Numbers override equality and are therefore not part of this conversion. | |
3294 strict_comp->set_needs_number_check(false); | |
3295 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
3296 return true; | |
3297 } | |
3298 return false; | |
3299 } | |
3300 | |
3301 | |
3302 template <typename T> | |
3303 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, | |
3304 T current_instruction) { | |
3305 if (StrictifyEqualityCompare(comp, current_instruction)) { | |
3306 // Based on input types, equality converted to strict-equality. | |
3307 return; | |
3308 } | |
3309 | |
3310 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | |
3311 return; | |
3312 } | |
3313 | |
3314 const ICData& ic_data = *comp->ic_data(); | |
3315 ASSERT(ic_data.num_args_tested() == 2); | |
3316 ASSERT(comp->operation_cid() == kIllegalCid); | |
3317 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
3318 InsertBefore(current_instruction, | |
3319 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
3320 current_instruction->env(), | |
3321 Definition::kEffect); | |
3322 InsertBefore(current_instruction, | |
3323 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
3324 current_instruction->env(), | |
3325 Definition::kEffect); | |
3326 comp->set_operation_cid(kSmiCid); | |
3327 } else if (HasTwoMintOrSmi(ic_data) && | |
3328 FlowGraphCompiler::SupportsUnboxedMints()) { | |
3329 comp->set_operation_cid(kMintCid); | |
3330 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
3331 // Use double comparison. | |
3332 if (SmiFitsInDouble()) { | |
3333 comp->set_operation_cid(kDoubleCid); | |
3334 } else { | |
3335 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
3336 // We cannot use double comparison on two smis. | |
3337 ASSERT(comp->operation_cid() == kIllegalCid); | |
3338 } else { | |
3339 InsertBefore(current_instruction, | |
3340 new CheckEitherNonSmiInstr(comp->left()->Copy(), | |
3341 comp->right()->Copy(), | |
3342 comp->deopt_id()), | |
3343 current_instruction->env(), | |
3344 Definition::kEffect); | |
3345 comp->set_operation_cid(kDoubleCid); | |
3346 } | |
3347 } | |
3348 } | |
3349 | |
3350 if (comp->operation_cid() != kIllegalCid) { | |
3351 // Done. | |
3352 return; | |
3353 } | |
3354 | |
3355 const ICData& unary_checks_0 = | |
3356 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | |
3357 if (StrictifyEqualityCompareWithICData( | |
3358 comp, unary_checks_0, current_instruction)) { | |
3359 // Based on ICData, equality converted to strict-equality. | |
3360 return; | |
3361 } | |
3362 | |
3363 // Check if ICDData contains checks with Smi/Null combinations. In that case | |
3364 // we can still emit the optimized Smi equality operation but need to add | |
3365 // checks for null or Smi. | |
3366 // TODO(srdjan): Add it for Double and Mint. | |
3367 GrowableArray<intptr_t> smi_or_null(2); | |
3368 smi_or_null.Add(kSmiCid); | |
3369 smi_or_null.Add(kNullCid); | |
3370 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, | |
3371 smi_or_null, | |
3372 smi_or_null)) { | |
3373 AddCheckClass(comp->left()->definition(), | |
3374 unary_checks_0, | |
3375 comp->deopt_id(), | |
3376 current_instruction->env(), | |
3377 current_instruction); | |
3378 | |
3379 const ICData& unary_checks_1 = | |
3380 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
3381 AddCheckClass(comp->right()->definition(), | |
3382 unary_checks_1, | |
3383 comp->deopt_id(), | |
3384 current_instruction->env(), | |
3385 current_instruction); | |
3386 comp->set_operation_cid(kSmiCid); | |
3387 } | |
3388 } | |
3389 | |
3390 | |
3391 | |
3392 | |
3393 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | |
3394 HandleEqualityCompare(instr, instr); | |
3395 } | |
3396 | |
3397 | |
3398 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | |
3399 ComparisonInstr* comparison = instr->comparison(); | |
3400 if (comparison->IsEqualityCompare()) { | |
3401 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); | |
3402 } else { | |
3403 ASSERT(comparison->IsStrictCompare()); | |
3404 // Nothing to do. | |
3405 } | |
3406 } | |
3407 | |
3408 | |
3409 // Range analysis for smi values. | 3307 // Range analysis for smi values. |
3410 class RangeAnalysis : public ValueObject { | 3308 class RangeAnalysis : public ValueObject { |
3411 public: | 3309 public: |
3412 explicit RangeAnalysis(FlowGraph* flow_graph) | 3310 explicit RangeAnalysis(FlowGraph* flow_graph) |
3413 : flow_graph_(flow_graph), | 3311 : flow_graph_(flow_graph), |
3414 marked_defns_(NULL) { } | 3312 marked_defns_(NULL) { } |
3415 | 3313 |
3416 // Infer ranges for all values and remove overflow checks from binary smi | 3314 // Infer ranges for all values and remove overflow checks from binary smi |
3417 // operations when proven redundant. | 3315 // operations when proven redundant. |
3418 void Analyze(); | 3316 void Analyze(); |
(...skipping 1075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4494 return (kind_ == other->kind_) && | 4392 return (kind_ == other->kind_) && |
4495 (representation_ == other->representation_) && | 4393 (representation_ == other->representation_) && |
4496 (instance_ == other->instance_) && | 4394 (instance_ == other->instance_) && |
4497 SameField(other); | 4395 SameField(other); |
4498 } | 4396 } |
4499 | 4397 |
4500 // Create a zone allocated copy of this place. | 4398 // Create a zone allocated copy of this place. |
4501 static Place* Wrap(const Place& place); | 4399 static Place* Wrap(const Place& place); |
4502 | 4400 |
4503 private: | 4401 private: |
4504 static Definition* OriginalDefinition(Definition* defn) { | |
4505 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { | |
4506 if (defn->IsRedefinition()) { | |
4507 defn = defn->AsRedefinition()->value()->definition(); | |
4508 } else { | |
4509 defn = defn->AsAssertAssignable()->value()->definition(); | |
4510 } | |
4511 } | |
4512 return defn; | |
4513 } | |
4514 | |
4515 bool SameField(Place* other) const { | 4402 bool SameField(Place* other) const { |
4516 return (kind_ == kField) ? (field().raw() == other->field().raw()) | 4403 return (kind_ == kField) ? (field().raw() == other->field().raw()) |
4517 : (offset_in_bytes_ == other->offset_in_bytes_); | 4404 : (offset_in_bytes_ == other->offset_in_bytes_); |
4518 } | 4405 } |
4519 | 4406 |
4520 intptr_t FieldHashcode() const { | 4407 intptr_t FieldHashcode() const { |
4521 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) | 4408 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) |
4522 : offset_in_bytes_; | 4409 : offset_in_bytes_; |
4523 } | 4410 } |
4524 | 4411 |
(...skipping 1822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6347 return false; | 6234 return false; |
6348 } | 6235 } |
6349 } | 6236 } |
6350 | 6237 |
6351 | 6238 |
6352 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | 6239 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { |
6353 const Object& left = instr->left()->definition()->constant_value(); | 6240 const Object& left = instr->left()->definition()->constant_value(); |
6354 const Object& right = instr->right()->definition()->constant_value(); | 6241 const Object& right = instr->right()->definition()->constant_value(); |
6355 | 6242 |
6356 if (instr->left()->definition() == instr->right()->definition()) { | 6243 if (instr->left()->definition() == instr->right()->definition()) { |
6357 // Fold x == x, and x != x to true/false for numbers and checked strict | 6244 // Fold x == x, and x != x to true/false for numbers comparisons. |
6358 // comparisons. | 6245 if (RawObject::IsIntegerClassId(instr->operation_cid())) { |
6359 if (instr->IsCheckedStrictEqual() || | |
6360 RawObject::IsIntegerClassId(instr->operation_cid())) { | |
6361 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); | 6246 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); |
6362 } | 6247 } |
6363 } | 6248 } |
6364 | 6249 |
6365 if (IsNonConstant(left) || IsNonConstant(right)) { | 6250 if (IsNonConstant(left) || IsNonConstant(right)) { |
6366 SetValue(instr, non_constant_); | 6251 SetValue(instr, non_constant_); |
6367 } else if (IsConstant(left) && IsConstant(right)) { | 6252 } else if (IsConstant(left) && IsConstant(right)) { |
6368 if (left.IsInteger() && right.IsInteger()) { | 6253 if (left.IsInteger() && right.IsInteger()) { |
6369 const bool result = CompareIntegers(instr->kind(), | 6254 const bool result = CompareIntegers(instr->kind(), |
6370 Integer::Cast(left), | 6255 Integer::Cast(left), |
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7319 comparison->kind(), | 7204 comparison->kind(), |
7320 left, | 7205 left, |
7321 right); | 7206 right); |
7322 } else if (comparison->IsEqualityCompare()) { | 7207 } else if (comparison->IsEqualityCompare()) { |
7323 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); | 7208 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); |
7324 EqualityCompareInstr* new_equality_compare = | 7209 EqualityCompareInstr* new_equality_compare = |
7325 new EqualityCompareInstr(equality_compare->token_pos(), | 7210 new EqualityCompareInstr(equality_compare->token_pos(), |
7326 comparison->kind(), | 7211 comparison->kind(), |
7327 left, | 7212 left, |
7328 right, | 7213 right, |
7329 Object::null_array()); | 7214 equality_compare->operation_cid(), |
7330 new_equality_compare->set_ic_data(equality_compare->ic_data()); | 7215 equality_compare->deopt_id()); |
7331 new_equality_compare->set_operation_cid(equality_compare->operation_cid()); | |
7332 new_comparison = new_equality_compare; | 7216 new_comparison = new_equality_compare; |
7333 } else { | 7217 } else { |
7334 ASSERT(comparison->IsRelationalOp()); | 7218 ASSERT(comparison->IsRelationalOp()); |
7335 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); | 7219 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); |
7336 RelationalOpInstr* new_relational_op = | 7220 RelationalOpInstr* new_relational_op = |
7337 new RelationalOpInstr(relational_op->token_pos(), | 7221 new RelationalOpInstr(relational_op->token_pos(), |
7338 comparison->kind(), | 7222 comparison->kind(), |
7339 left, | 7223 left, |
7340 right, | 7224 right, |
7341 relational_op->operation_cid(), | 7225 relational_op->operation_cid(), |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7865 } | 7749 } |
7866 | 7750 |
7867 // Insert materializations at environment uses. | 7751 // Insert materializations at environment uses. |
7868 for (intptr_t i = 0; i < exits.length(); i++) { | 7752 for (intptr_t i = 0; i < exits.length(); i++) { |
7869 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7753 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
7870 } | 7754 } |
7871 } | 7755 } |
7872 | 7756 |
7873 | 7757 |
7874 } // namespace dart | 7758 } // namespace dart |
OLD | NEW |