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

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: 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
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 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698