Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 27307005: Change == into an instance call to allow polymorphic inlining of ==. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased, addressed comments Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698