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 1180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 ASSERT(current_iterator()->Current() == call); | 1281 ASSERT(current_iterator()->Current() == call); |
1282 current_iterator()->RemoveCurrentFromGraph(); | 1282 current_iterator()->RemoveCurrentFromGraph(); |
1283 call->set_previous(NULL); | 1283 call->set_previous(NULL); |
1284 call->set_next(NULL); | 1284 call->set_next(NULL); |
1285 return true; | 1285 return true; |
1286 } | 1286 } |
1287 | 1287 |
1288 | 1288 |
1289 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1289 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
1290 | 1290 |
| 1291 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 1292 Token::Kind op_kind) { |
| 1293 const ICData& ic_data = *call->ic_data(); |
| 1294 ASSERT(ic_data.num_args_tested() == 2); |
| 1295 |
| 1296 ASSERT(call->ArgumentCount() == 2); |
| 1297 Definition* left = call->ArgumentAt(0); |
| 1298 Definition* right = call->ArgumentAt(1); |
| 1299 |
| 1300 intptr_t cid = kIllegalCid; |
| 1301 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1302 InsertBefore(call, |
| 1303 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 1304 call->env(), |
| 1305 Definition::kEffect); |
| 1306 InsertBefore(call, |
| 1307 new CheckSmiInstr(new Value(right), call->deopt_id()), |
| 1308 call->env(), |
| 1309 Definition::kEffect); |
| 1310 cid = kSmiCid; |
| 1311 } else if (HasTwoMintOrSmi(ic_data) && |
| 1312 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1313 cid = kMintCid; |
| 1314 } else if (HasTwoDoubleOrSmi(ic_data)) { |
| 1315 // Use double comparison. |
| 1316 if (SmiFitsInDouble()) { |
| 1317 cid = kDoubleCid; |
| 1318 } else { |
| 1319 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 1320 // We cannot use double comparison on two smis. Need polymorphic |
| 1321 // call. |
| 1322 return false; |
| 1323 } else { |
| 1324 InsertBefore(call, |
| 1325 new CheckEitherNonSmiInstr(new Value(left), |
| 1326 new Value(right), |
| 1327 call->deopt_id()), |
| 1328 call->env(), |
| 1329 Definition::kEffect); |
| 1330 cid = kDoubleCid; |
| 1331 } |
| 1332 } |
| 1333 } else { |
| 1334 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1335 // we can still emit the optimized Smi equality operation but need to add |
| 1336 // checks for null or Smi. |
| 1337 GrowableArray<intptr_t> smi_or_null(2); |
| 1338 smi_or_null.Add(kSmiCid); |
| 1339 smi_or_null.Add(kNullCid); |
| 1340 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, |
| 1341 smi_or_null, |
| 1342 smi_or_null)) { |
| 1343 const ICData& unary_checks_0 = |
| 1344 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 1345 AddCheckClass(left, |
| 1346 unary_checks_0, |
| 1347 call->deopt_id(), |
| 1348 call->env(), |
| 1349 call); |
| 1350 |
| 1351 const ICData& unary_checks_1 = |
| 1352 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1353 AddCheckClass(right, |
| 1354 unary_checks_1, |
| 1355 call->deopt_id(), |
| 1356 call->env(), |
| 1357 call); |
| 1358 cid = kSmiCid; |
| 1359 } else { |
| 1360 // Shortcut for equality with null. |
| 1361 ConstantInstr* right_const = right->AsConstant(); |
| 1362 ConstantInstr* left_const = left->AsConstant(); |
| 1363 if ((right_const != NULL && right_const->value().IsNull()) || |
| 1364 (left_const != NULL && left_const->value().IsNull())) { |
| 1365 StrictCompareInstr* comp = new StrictCompareInstr(call->token_pos(), |
| 1366 Token::kEQ_STRICT, |
| 1367 new Value(left), |
| 1368 new Value(right)); |
| 1369 ReplaceCall(call, comp); |
| 1370 return true; |
| 1371 } |
| 1372 return false; |
| 1373 } |
| 1374 } |
| 1375 ASSERT(cid != kIllegalCid); |
| 1376 EqualityCompareInstr* comp = new EqualityCompareInstr(call->token_pos(), |
| 1377 op_kind, |
| 1378 new Value(left), |
| 1379 new Value(right), |
| 1380 cid, |
| 1381 call->deopt_id()); |
| 1382 ReplaceCall(call, comp); |
| 1383 return true; |
| 1384 } |
| 1385 |
1291 | 1386 |
1292 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1387 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
1293 Token::Kind op_kind) { | 1388 Token::Kind op_kind) { |
1294 const ICData& ic_data = *call->ic_data(); | 1389 const ICData& ic_data = *call->ic_data(); |
1295 ASSERT(ic_data.num_args_tested() == 2); | 1390 ASSERT(ic_data.num_args_tested() == 2); |
1296 | 1391 |
1297 ASSERT(call->ArgumentCount() == 2); | 1392 ASSERT(call->ArgumentCount() == 2); |
1298 Definition* left = call->ArgumentAt(0); | 1393 Definition* left = call->ArgumentAt(0); |
1299 Definition* right = call->ArgumentAt(1); | 1394 Definition* right = call->ArgumentAt(1); |
1300 | 1395 |
(...skipping 1625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2926 if (prev.IsNull()) { | 3021 if (prev.IsNull()) { |
2927 prev = Bool::Get(is_subtype).raw(); | 3022 prev = Bool::Get(is_subtype).raw(); |
2928 } else { | 3023 } else { |
2929 if (is_subtype != prev.value()) return Bool::null(); | 3024 if (is_subtype != prev.value()) return Bool::null(); |
2930 } | 3025 } |
2931 } | 3026 } |
2932 return prev.raw(); | 3027 return prev.raw(); |
2933 } | 3028 } |
2934 | 3029 |
2935 | 3030 |
| 3031 static Definition* OriginalDefinition(Definition* defn) { |
| 3032 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { |
| 3033 if (defn->IsRedefinition()) { |
| 3034 defn = defn->AsRedefinition()->value()->definition(); |
| 3035 } else { |
| 3036 defn = defn->AsAssertAssignable()->value()->definition(); |
| 3037 } |
| 3038 } |
| 3039 return defn; |
| 3040 } |
| 3041 |
| 3042 |
2936 // TODO(srdjan): Use ICData to check if always true or false. | 3043 // TODO(srdjan): Use ICData to check if always true or false. |
2937 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 3044 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
2938 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 3045 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
2939 Definition* left = call->ArgumentAt(0); | 3046 Definition* left = call->ArgumentAt(0); |
2940 Definition* instantiator = call->ArgumentAt(1); | 3047 Definition* instantiator = call->ArgumentAt(1); |
2941 Definition* type_args = call->ArgumentAt(2); | 3048 Definition* type_args = call->ArgumentAt(2); |
2942 const AbstractType& type = | 3049 const AbstractType& type = |
2943 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 3050 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
2944 const bool negate = | 3051 const bool negate = Bool::Cast( |
2945 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); | 3052 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); |
2946 const ICData& unary_checks = | 3053 const ICData& unary_checks = |
2947 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 3054 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
2948 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 3055 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
2949 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 3056 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
2950 if (!as_bool.IsNull()) { | 3057 if (!as_bool.IsNull()) { |
2951 AddReceiverCheck(call); | 3058 AddReceiverCheck(call); |
2952 if (negate) { | 3059 if (negate) { |
2953 as_bool = Bool::Get(!as_bool.value()).raw(); | 3060 as_bool = Bool::Get(!as_bool.value()).raw(); |
2954 } | 3061 } |
2955 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | 3062 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3034 } | 3141 } |
3035 | 3142 |
3036 if (Token::IsTypeCastOperator(op_kind)) { | 3143 if (Token::IsTypeCastOperator(op_kind)) { |
3037 ReplaceWithTypeCast(instr); | 3144 ReplaceWithTypeCast(instr); |
3038 return; | 3145 return; |
3039 } | 3146 } |
3040 | 3147 |
3041 const ICData& unary_checks = | 3148 const ICData& unary_checks = |
3042 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 3149 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
3043 | 3150 |
3044 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && | 3151 intptr_t max_checks = (op_kind == Token::kEQ) |
| 3152 ? FLAG_max_equality_polymorphic_checks |
| 3153 : FLAG_max_polymorphic_checks; |
| 3154 if ((unary_checks.NumberOfChecks() > max_checks) && |
3045 InstanceCallNeedsClassCheck(instr)) { | 3155 InstanceCallNeedsClassCheck(instr)) { |
3046 // Too many checks, it will be megamorphic which needs unary checks. | 3156 // Too many checks, it will be megamorphic which needs unary checks. |
3047 instr->set_ic_data(&unary_checks); | 3157 instr->set_ic_data(&unary_checks); |
3048 return; | 3158 return; |
3049 } | 3159 } |
3050 | 3160 |
3051 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { | 3161 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { |
3052 return; | 3162 return; |
3053 } | 3163 } |
3054 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { | 3164 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { |
3055 return; | 3165 return; |
3056 } | 3166 } |
3057 | 3167 |
| 3168 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 3169 return; |
| 3170 } |
| 3171 |
3058 if (Token::IsRelationalOperator(op_kind) && | 3172 if (Token::IsRelationalOperator(op_kind) && |
3059 TryReplaceWithRelationalOp(instr, op_kind)) { | 3173 TryReplaceWithRelationalOp(instr, op_kind)) { |
3060 return; | 3174 return; |
3061 } | 3175 } |
3062 | 3176 |
3063 if (Token::IsBinaryOperator(op_kind) && | 3177 if (Token::IsBinaryOperator(op_kind) && |
3064 TryReplaceWithBinaryOp(instr, op_kind)) { | 3178 TryReplaceWithBinaryOp(instr, op_kind)) { |
3065 return; | 3179 return; |
3066 } | 3180 } |
3067 if (Token::IsPrefixOperator(op_kind) && | 3181 if (Token::IsPrefixOperator(op_kind) && |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3273 new Value(instr->ArgumentAt(1)), | 3387 new Value(instr->ArgumentAt(1)), |
3274 needs_store_barrier); | 3388 needs_store_barrier); |
3275 // Discard the environment from the original instruction because the store | 3389 // Discard the environment from the original instruction because the store |
3276 // can't deoptimize. | 3390 // can't deoptimize. |
3277 instr->RemoveEnvironment(); | 3391 instr->RemoveEnvironment(); |
3278 ReplaceCall(instr, store); | 3392 ReplaceCall(instr, store); |
3279 return true; | 3393 return true; |
3280 } | 3394 } |
3281 | 3395 |
3282 | 3396 |
3283 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( | |
3284 EqualityCompareInstr* compare) { | |
3285 // If one of the inputs is null this is a strict comparison. | |
3286 if (compare->left()->BindsToConstantNull() || | |
3287 compare->right()->BindsToConstantNull()) { | |
3288 return true; | |
3289 } | |
3290 | |
3291 if (compare->left()->Type()->IsNone()) { | |
3292 return false; // We might be running prior to any type propagation passes. | |
3293 } | |
3294 | |
3295 // Try resolving target function using propagated cid for the receiver. | |
3296 // If receiver is either null or has default equality operator then | |
3297 // we can convert such comparison to a strict one. | |
3298 const intptr_t receiver_cid = | |
3299 compare->left()->Type()->ToNullableCid(); | |
3300 | |
3301 if (receiver_cid == kDynamicCid) { | |
3302 return false; | |
3303 } | |
3304 | |
3305 const Class& receiver_class = Class::Handle( | |
3306 Isolate::Current()->class_table()->At(receiver_cid)); | |
3307 | |
3308 // Resolve equality operator. | |
3309 const intptr_t kNumArgs = 2; | |
3310 ArgumentsDescriptor args_desc( | |
3311 Array::Handle(ArgumentsDescriptor::New(kNumArgs))); | |
3312 const Function& function = Function::Handle( | |
3313 Resolver::ResolveDynamicForReceiverClass( | |
3314 receiver_class, | |
3315 Symbols::EqualOperator(), | |
3316 args_desc)); | |
3317 | |
3318 if (function.IsNull()) { | |
3319 return false; | |
3320 } | |
3321 | |
3322 // Default equality operator declared on the Object class just calls | |
3323 // identical. | |
3324 return (Class::Handle(function.Owner()).id() == kInstanceCid); | |
3325 } | |
3326 | |
3327 | |
3328 template <typename T> | |
3329 bool FlowGraphOptimizer::StrictifyEqualityCompare( | |
3330 EqualityCompareInstr* compare, | |
3331 T current_instruction) const { | |
3332 if (CanStrictifyEqualityCompare(compare)) { | |
3333 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
3334 Token::kEQ_STRICT : Token::kNE_STRICT; | |
3335 StrictCompareInstr* strict_comp = | |
3336 new StrictCompareInstr(compare->token_pos(), | |
3337 strict_kind, | |
3338 compare->left()->CopyWithType(), | |
3339 compare->right()->CopyWithType()); | |
3340 // Numbers override equality and are therefore not part of this conversion. | |
3341 strict_comp->set_needs_number_check(false); | |
3342 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
3343 return true; | |
3344 } | |
3345 return false; | |
3346 } | |
3347 | |
3348 | |
3349 // Returns true if we converted EqualityCompare to StrictCompare. | |
3350 template <typename T> | |
3351 bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData( | |
3352 EqualityCompareInstr* compare, | |
3353 const ICData& unary_ic_data, | |
3354 T current_instruction) { | |
3355 ASSERT(unary_ic_data.num_args_tested() == 1); | |
3356 if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | |
3357 // If possible classes do not override Object's equality then replace | |
3358 // with strict equality. | |
3359 Function& target = Function::Handle(); | |
3360 Class& targets_class = Class::Handle(); | |
3361 for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) { | |
3362 intptr_t cid = kIllegalCid; | |
3363 unary_ic_data.GetOneClassCheckAt(i, &cid, &target); | |
3364 targets_class = target.Owner(); | |
3365 if (targets_class.id() != kInstanceCid) { | |
3366 // Overriden equality operator. | |
3367 return false; | |
3368 } | |
3369 } | |
3370 AddCheckClass(compare->left()->definition(), | |
3371 unary_ic_data, | |
3372 compare->deopt_id(), | |
3373 current_instruction->env(), | |
3374 current_instruction); | |
3375 ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE)); | |
3376 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
3377 Token::kEQ_STRICT : Token::kNE_STRICT; | |
3378 StrictCompareInstr* strict_comp = | |
3379 new StrictCompareInstr(compare->token_pos(), | |
3380 strict_kind, | |
3381 compare->left()->Copy(), | |
3382 compare->right()->Copy()); | |
3383 // Numbers override equality and are therefore not part of this conversion. | |
3384 strict_comp->set_needs_number_check(false); | |
3385 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
3386 return true; | |
3387 } | |
3388 return false; | |
3389 } | |
3390 | |
3391 | |
3392 template <typename T> | |
3393 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, | |
3394 T current_instruction) { | |
3395 if (StrictifyEqualityCompare(comp, current_instruction)) { | |
3396 // Based on input types, equality converted to strict-equality. | |
3397 return; | |
3398 } | |
3399 | |
3400 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | |
3401 return; | |
3402 } | |
3403 | |
3404 const ICData& ic_data = *comp->ic_data(); | |
3405 ASSERT(ic_data.num_args_tested() == 2); | |
3406 ASSERT(comp->operation_cid() == kIllegalCid); | |
3407 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
3408 InsertBefore(current_instruction, | |
3409 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
3410 current_instruction->env(), | |
3411 Definition::kEffect); | |
3412 InsertBefore(current_instruction, | |
3413 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
3414 current_instruction->env(), | |
3415 Definition::kEffect); | |
3416 comp->set_operation_cid(kSmiCid); | |
3417 } else if (HasTwoMintOrSmi(ic_data) && | |
3418 FlowGraphCompiler::SupportsUnboxedMints()) { | |
3419 comp->set_operation_cid(kMintCid); | |
3420 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
3421 // Use double comparison. | |
3422 if (SmiFitsInDouble()) { | |
3423 comp->set_operation_cid(kDoubleCid); | |
3424 } else { | |
3425 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
3426 // We cannot use double comparison on two smis. | |
3427 ASSERT(comp->operation_cid() == kIllegalCid); | |
3428 } else { | |
3429 InsertBefore(current_instruction, | |
3430 new CheckEitherNonSmiInstr(comp->left()->Copy(), | |
3431 comp->right()->Copy(), | |
3432 comp->deopt_id()), | |
3433 current_instruction->env(), | |
3434 Definition::kEffect); | |
3435 comp->set_operation_cid(kDoubleCid); | |
3436 } | |
3437 } | |
3438 } | |
3439 | |
3440 if (comp->operation_cid() != kIllegalCid) { | |
3441 // Done. | |
3442 return; | |
3443 } | |
3444 | |
3445 const ICData& unary_checks_0 = | |
3446 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | |
3447 if (StrictifyEqualityCompareWithICData( | |
3448 comp, unary_checks_0, current_instruction)) { | |
3449 // Based on ICData, equality converted to strict-equality. | |
3450 return; | |
3451 } | |
3452 | |
3453 // Check if ICDData contains checks with Smi/Null combinations. In that case | |
3454 // we can still emit the optimized Smi equality operation but need to add | |
3455 // checks for null or Smi. | |
3456 // TODO(srdjan): Add it for Double and Mint. | |
3457 GrowableArray<intptr_t> smi_or_null(2); | |
3458 smi_or_null.Add(kSmiCid); | |
3459 smi_or_null.Add(kNullCid); | |
3460 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, | |
3461 smi_or_null, | |
3462 smi_or_null)) { | |
3463 AddCheckClass(comp->left()->definition(), | |
3464 unary_checks_0, | |
3465 comp->deopt_id(), | |
3466 current_instruction->env(), | |
3467 current_instruction); | |
3468 | |
3469 const ICData& unary_checks_1 = | |
3470 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
3471 AddCheckClass(comp->right()->definition(), | |
3472 unary_checks_1, | |
3473 comp->deopt_id(), | |
3474 current_instruction->env(), | |
3475 current_instruction); | |
3476 comp->set_operation_cid(kSmiCid); | |
3477 } | |
3478 } | |
3479 | |
3480 | |
3481 | |
3482 | |
3483 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | |
3484 HandleEqualityCompare(instr, instr); | |
3485 } | |
3486 | |
3487 | |
3488 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | |
3489 ComparisonInstr* comparison = instr->comparison(); | |
3490 if (comparison->IsEqualityCompare()) { | |
3491 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); | |
3492 } else { | |
3493 ASSERT(comparison->IsStrictCompare()); | |
3494 // Nothing to do. | |
3495 } | |
3496 } | |
3497 | |
3498 | |
3499 // Range analysis for smi values. | 3397 // Range analysis for smi values. |
3500 class RangeAnalysis : public ValueObject { | 3398 class RangeAnalysis : public ValueObject { |
3501 public: | 3399 public: |
3502 explicit RangeAnalysis(FlowGraph* flow_graph) | 3400 explicit RangeAnalysis(FlowGraph* flow_graph) |
3503 : flow_graph_(flow_graph), | 3401 : flow_graph_(flow_graph), |
3504 marked_defns_(NULL) { } | 3402 marked_defns_(NULL) { } |
3505 | 3403 |
3506 // Infer ranges for all values and remove overflow checks from binary smi | 3404 // Infer ranges for all values and remove overflow checks from binary smi |
3507 // operations when proven redundant. | 3405 // operations when proven redundant. |
3508 void Analyze(); | 3406 void Analyze(); |
(...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4594 return (kind_ == other->kind_) && | 4492 return (kind_ == other->kind_) && |
4595 (representation_ == other->representation_) && | 4493 (representation_ == other->representation_) && |
4596 (instance_ == other->instance_) && | 4494 (instance_ == other->instance_) && |
4597 SameField(other); | 4495 SameField(other); |
4598 } | 4496 } |
4599 | 4497 |
4600 // Create a zone allocated copy of this place. | 4498 // Create a zone allocated copy of this place. |
4601 static Place* Wrap(const Place& place); | 4499 static Place* Wrap(const Place& place); |
4602 | 4500 |
4603 private: | 4501 private: |
4604 static Definition* OriginalDefinition(Definition* defn) { | |
4605 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { | |
4606 if (defn->IsRedefinition()) { | |
4607 defn = defn->AsRedefinition()->value()->definition(); | |
4608 } else { | |
4609 defn = defn->AsAssertAssignable()->value()->definition(); | |
4610 } | |
4611 } | |
4612 return defn; | |
4613 } | |
4614 | |
4615 bool SameField(Place* other) const { | 4502 bool SameField(Place* other) const { |
4616 return (kind_ == kField) ? (field().raw() == other->field().raw()) | 4503 return (kind_ == kField) ? (field().raw() == other->field().raw()) |
4617 : (offset_in_bytes_ == other->offset_in_bytes_); | 4504 : (offset_in_bytes_ == other->offset_in_bytes_); |
4618 } | 4505 } |
4619 | 4506 |
4620 intptr_t FieldHashcode() const { | 4507 intptr_t FieldHashcode() const { |
4621 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) | 4508 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) |
4622 : offset_in_bytes_; | 4509 : offset_in_bytes_; |
4623 } | 4510 } |
4624 | 4511 |
(...skipping 1822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6447 return false; | 6334 return false; |
6448 } | 6335 } |
6449 } | 6336 } |
6450 | 6337 |
6451 | 6338 |
6452 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | 6339 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { |
6453 const Object& left = instr->left()->definition()->constant_value(); | 6340 const Object& left = instr->left()->definition()->constant_value(); |
6454 const Object& right = instr->right()->definition()->constant_value(); | 6341 const Object& right = instr->right()->definition()->constant_value(); |
6455 | 6342 |
6456 if (instr->left()->definition() == instr->right()->definition()) { | 6343 if (instr->left()->definition() == instr->right()->definition()) { |
6457 // Fold x == x, and x != x to true/false for numbers and checked strict | 6344 // Fold x == x, and x != x to true/false for numbers comparisons. |
6458 // comparisons. | 6345 if (RawObject::IsIntegerClassId(instr->operation_cid())) { |
6459 if (instr->IsCheckedStrictEqual() || | |
6460 RawObject::IsIntegerClassId(instr->operation_cid())) { | |
6461 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); | 6346 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); |
6462 } | 6347 } |
6463 } | 6348 } |
6464 | 6349 |
6465 if (IsNonConstant(left) || IsNonConstant(right)) { | 6350 if (IsNonConstant(left) || IsNonConstant(right)) { |
6466 SetValue(instr, non_constant_); | 6351 SetValue(instr, non_constant_); |
6467 } else if (IsConstant(left) && IsConstant(right)) { | 6352 } else if (IsConstant(left) && IsConstant(right)) { |
6468 if (left.IsInteger() && right.IsInteger()) { | 6353 if (left.IsInteger() && right.IsInteger()) { |
6469 const bool result = CompareIntegers(instr->kind(), | 6354 const bool result = CompareIntegers(instr->kind(), |
6470 Integer::Cast(left), | 6355 Integer::Cast(left), |
(...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7421 comparison->kind(), | 7306 comparison->kind(), |
7422 left, | 7307 left, |
7423 right); | 7308 right); |
7424 } else if (comparison->IsEqualityCompare()) { | 7309 } else if (comparison->IsEqualityCompare()) { |
7425 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); | 7310 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); |
7426 EqualityCompareInstr* new_equality_compare = | 7311 EqualityCompareInstr* new_equality_compare = |
7427 new EqualityCompareInstr(equality_compare->token_pos(), | 7312 new EqualityCompareInstr(equality_compare->token_pos(), |
7428 comparison->kind(), | 7313 comparison->kind(), |
7429 left, | 7314 left, |
7430 right, | 7315 right, |
7431 Object::null_array()); | 7316 equality_compare->operation_cid(), |
7432 new_equality_compare->set_ic_data(equality_compare->ic_data()); | 7317 equality_compare->deopt_id()); |
7433 new_equality_compare->set_operation_cid(equality_compare->operation_cid()); | |
7434 new_comparison = new_equality_compare; | 7318 new_comparison = new_equality_compare; |
7435 } else { | 7319 } else { |
7436 ASSERT(comparison->IsRelationalOp()); | 7320 ASSERT(comparison->IsRelationalOp()); |
7437 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); | 7321 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); |
7438 RelationalOpInstr* new_relational_op = | 7322 RelationalOpInstr* new_relational_op = |
7439 new RelationalOpInstr(relational_op->token_pos(), | 7323 new RelationalOpInstr(relational_op->token_pos(), |
7440 comparison->kind(), | 7324 comparison->kind(), |
7441 left, | 7325 left, |
7442 right, | 7326 right, |
7443 relational_op->operation_cid(), | 7327 relational_op->operation_cid(), |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7967 } | 7851 } |
7968 | 7852 |
7969 // Insert materializations at environment uses. | 7853 // Insert materializations at environment uses. |
7970 for (intptr_t i = 0; i < exits.length(); i++) { | 7854 for (intptr_t i = 0; i < exits.length(); i++) { |
7971 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7855 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
7972 } | 7856 } |
7973 } | 7857 } |
7974 | 7858 |
7975 | 7859 |
7976 } // namespace dart | 7860 } // namespace dart |
OLD | NEW |