Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/flow_graph_builder.h" | 7 #include "vm/flow_graph_builder.h" |
| 8 #include "vm/hash_map.h" | |
| 8 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 9 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
| 10 #include "vm/parser.h" | 11 #include "vm/parser.h" |
| 11 #include "vm/scopes.h" | 12 #include "vm/scopes.h" |
| 12 #include "vm/symbols.h" | 13 #include "vm/symbols.h" |
| 13 | 14 |
| 14 namespace dart { | 15 namespace dart { |
| 15 | 16 |
| 16 DECLARE_FLAG(bool, eliminate_type_checks); | 17 DECLARE_FLAG(bool, eliminate_type_checks); |
| 17 DECLARE_FLAG(bool, enable_type_checks); | 18 DECLARE_FLAG(bool, enable_type_checks); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 if ((class_ids[0] == receiver_class_id) && | 75 if ((class_ids[0] == receiver_class_id) && |
| 75 (class_ids[1] == argument_class_id)) { | 76 (class_ids[1] == argument_class_id)) { |
| 76 return true; | 77 return true; |
| 77 } | 78 } |
| 78 } | 79 } |
| 79 return false; | 80 return false; |
| 80 } | 81 } |
| 81 | 82 |
| 82 | 83 |
| 83 static bool ClassIdIsOneOf(intptr_t class_id, | 84 static bool ClassIdIsOneOf(intptr_t class_id, |
| 84 GrowableArray<intptr_t>* class_ids) { | 85 const GrowableArray<intptr_t>& class_ids) { |
| 85 for (intptr_t i = 0; i < class_ids->length(); i++) { | 86 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 86 if ((*class_ids)[i] == class_id) { | 87 if (class_ids[i] == class_id) { |
| 87 return true; | 88 return true; |
| 88 } | 89 } |
| 89 } | 90 } |
| 90 return false; | 91 return false; |
| 91 } | 92 } |
| 92 | 93 |
| 93 | 94 |
| 94 static bool ICDataHasOnlyReceiverArgumentClassIds( | 95 static bool ICDataHasOnlyReceiverArgumentClassIds( |
| 95 const ICData& ic_data, | 96 const ICData& ic_data, |
| 96 GrowableArray<intptr_t>* receiver_class_ids, | 97 const GrowableArray<intptr_t>& receiver_class_ids, |
| 97 GrowableArray<intptr_t>* argument_class_ids) { | 98 const GrowableArray<intptr_t>& argument_class_ids) { |
| 98 if (ic_data.num_args_tested() != 2) return false; | 99 if (ic_data.num_args_tested() != 2) return false; |
| 99 | 100 |
| 100 Function& target = Function::Handle(); | 101 Function& target = Function::Handle(); |
| 101 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 102 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 102 GrowableArray<intptr_t> class_ids; | 103 GrowableArray<intptr_t> class_ids; |
| 103 ic_data.GetCheckAt(i, &class_ids, &target); | 104 ic_data.GetCheckAt(i, &class_ids, &target); |
| 104 ASSERT(class_ids.length() == 2); | 105 ASSERT(class_ids.length() == 2); |
| 105 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || | 106 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || |
| 106 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { | 107 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { |
| 107 return false; | 108 return false; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 118 | 119 |
| 119 static bool HasOnlyTwoSmi(const ICData& ic_data) { | 120 static bool HasOnlyTwoSmi(const ICData& ic_data) { |
| 120 return (ic_data.NumberOfChecks() == 1) && | 121 return (ic_data.NumberOfChecks() == 1) && |
| 121 ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid); | 122 ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid); |
| 122 } | 123 } |
| 123 | 124 |
| 124 | 125 |
| 125 // Returns false if the ICData contains anything other than the 4 combinations | 126 // Returns false if the ICData contains anything other than the 4 combinations |
| 126 // of Mint and Smi for the receiver and argument classes. | 127 // of Mint and Smi for the receiver and argument classes. |
| 127 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 128 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
| 128 GrowableArray<intptr_t> class_ids; | 129 GrowableArray<intptr_t> class_ids(2); |
| 129 class_ids.Add(kSmiCid); | 130 class_ids.Add(kSmiCid); |
| 130 class_ids.Add(kMintCid); | 131 class_ids.Add(kMintCid); |
| 131 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, &class_ids, &class_ids); | 132 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 132 } | 133 } |
| 133 | 134 |
| 134 | 135 |
| 135 static bool HasOneDouble(const ICData& ic_data) { | 136 static bool HasOneDouble(const ICData& ic_data) { |
| 136 return ICDataHasReceiverClassId(ic_data, kDoubleCid); | 137 return ICDataHasReceiverClassId(ic_data, kDoubleCid); |
| 137 } | 138 } |
| 138 | 139 |
| 139 | 140 |
| 140 static bool HasOnlyTwoDouble(const ICData& ic_data) { | 141 static bool HasOnlyTwoDouble(const ICData& ic_data) { |
| 141 return (ic_data.NumberOfChecks() == 1) && | 142 return (ic_data.NumberOfChecks() == 1) && |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 if (target.kind() == RawFunction::kImplicitGetter) { | 357 if (target.kind() == RawFunction::kImplicitGetter) { |
| 357 if (!HasOneTarget(ic_data)) { | 358 if (!HasOneTarget(ic_data)) { |
| 358 // TODO(srdjan): Implement for mutiple targets. | 359 // TODO(srdjan): Implement for mutiple targets. |
| 359 return false; | 360 return false; |
| 360 } | 361 } |
| 361 // Inline implicit instance getter. | 362 // Inline implicit instance getter. |
| 362 const String& field_name = | 363 const String& field_name = |
| 363 String::Handle(Field::NameFromGetter(comp->function_name())); | 364 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 364 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 365 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 365 ASSERT(!field.IsNull()); | 366 ASSERT(!field.IsNull()); |
| 366 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 367 |
| 367 field, comp->ArgumentAt(0)->value(), comp); | 368 LoadInstanceFieldComp* load; |
| 368 load->set_ic_data(comp->ic_data()); | 369 if (!use_ssa_) { |
| 370 load = new LoadInstanceFieldComp( | |
| 371 field, comp->ArgumentAt(0)->value(), comp); | |
| 372 load->set_ic_data(comp->ic_data()); | |
| 373 } else { | |
|
srdjan
2012/08/17 22:30:22
The code below is probably going to be quite commo
Florian Schneider
2012/08/20 12:09:37
Yes, this will be similar for inserting other chec
| |
| 374 CheckClassComp* check = | |
| 375 new CheckClassComp(comp->ArgumentAt(0)->value(), comp); | |
|
srdjan
2012/08/17 22:30:22
You may want to check if the CheckClassComp is nee
Florian Schneider
2012/08/20 12:09:37
I'll add a TODO. The only thing required for that
| |
| 376 const ICData& unary_checks = | |
| 377 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | |
| 378 check->set_ic_data(&unary_checks); | |
| 379 BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check); | |
| 380 ASSERT(instr->env() != NULL); // Always the case with SSA. | |
| 381 check_instr->set_env( | |
| 382 new Environment(instr->env()->values(), | |
| 383 instr->env()->fixed_parameter_count())); | |
| 384 check_instr->InsertBefore(instr); | |
| 385 load = new LoadInstanceFieldComp( | |
| 386 field, comp->ArgumentAt(0)->value(), NULL); | |
| 387 } | |
| 369 instr->set_computation(load); | 388 instr->set_computation(load); |
| 370 RemovePushArguments(comp); | 389 RemovePushArguments(comp); |
| 371 return true; | 390 return true; |
| 372 } | 391 } |
| 373 | 392 |
| 374 // Not an implicit getter. | 393 // Not an implicit getter. |
| 375 MethodRecognizer::Kind recognized_kind = | 394 MethodRecognizer::Kind recognized_kind = |
| 376 MethodRecognizer::RecognizeKind(target); | 395 MethodRecognizer::RecognizeKind(target); |
| 377 | 396 |
| 378 // VM objects length getter. | 397 // VM objects length getter. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 482 } | 501 } |
| 483 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { | 502 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { |
| 484 return; | 503 return; |
| 485 } | 504 } |
| 486 if (TryInlineInstanceMethod(instr, comp)) { | 505 if (TryInlineInstanceMethod(instr, comp)) { |
| 487 return; | 506 return; |
| 488 } | 507 } |
| 489 const intptr_t kMaxChecks = 4; | 508 const intptr_t kMaxChecks = 4; |
| 490 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { | 509 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { |
| 491 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); | 510 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); |
| 492 ICData& unary_checks = | 511 const ICData& unary_checks = |
| 493 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 512 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 494 call->set_ic_data(&unary_checks); | 513 call->set_ic_data(&unary_checks); |
| 495 instr->set_computation(call); | 514 instr->set_computation(call); |
| 496 } | 515 } |
| 497 } | 516 } |
| 498 // An instance call without ICData should continue calling via IC calls | 517 // An instance call without ICData should continue calling via IC calls |
| 499 // which should trigger reoptimization of optimized code. | 518 // which should trigger reoptimization of optimized code. |
| 500 } | 519 } |
| 501 | 520 |
| 502 | 521 |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 861 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 880 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 862 LocationSummary* locs = it.Current()->locs(); | 881 LocationSummary* locs = it.Current()->locs(); |
| 863 if ((locs != NULL) && locs->can_call()) { | 882 if ((locs != NULL) && locs->can_call()) { |
| 864 is_leaf_ = false; | 883 is_leaf_ = false; |
| 865 return; | 884 return; |
| 866 } | 885 } |
| 867 } | 886 } |
| 868 } | 887 } |
| 869 } | 888 } |
| 870 | 889 |
| 890 | |
| 891 void LocalCSE::Optimize() { | |
| 892 for (intptr_t i = 0; i < blocks_.length(); ++i) { | |
| 893 BlockEntryInstr* entry = blocks_[i]; | |
| 894 DirectChainedHashMap<BindInstr> map; | |
| 895 ASSERT(map.IsEmpty()); | |
| 896 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | |
| 897 BindInstr* instr = it.Current()->AsBind(); | |
| 898 if (instr == NULL || instr->computation()->HasSideEffect()) continue; | |
| 899 BindInstr* result = map.Lookup(instr); | |
| 900 if (result == NULL) { | |
| 901 map.Insert(instr); | |
| 902 continue; | |
| 903 } | |
| 904 // Replace current with lookup result. | |
| 905 instr->ReplaceUsesWith(result); | |
| 906 it.RemoveCurrentFromGraph(); | |
| 907 if (FLAG_trace_optimization) { | |
| 908 OS::Print("Replacing v%d with v%d\n", | |
| 909 instr->ssa_temp_index(), | |
| 910 result->ssa_temp_index()); | |
| 911 } | |
| 912 } | |
| 913 } | |
| 914 } | |
| 915 | |
| 916 | |
| 871 } // namespace dart | 917 } // namespace dart |
| OLD | NEW |