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

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

Issue 258563004: Copy of Issue 231383002 after hard disk crash: First step in improving instance of test for a fixed… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 8 months 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/cpu.h" 9 #include "vm/cpu.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 3655 matching lines...) Expand 10 before | Expand all | Expand 10 after
3666 intptr_t view_cid) { 3666 intptr_t view_cid) {
3667 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || 3667 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) ||
3668 (view_cid == kTypedDataInt32x4ArrayCid); 3668 (view_cid == kTypedDataInt32x4ArrayCid);
3669 if (simd_view && !ShouldInlineSimd()) { 3669 if (simd_view && !ShouldInlineSimd()) {
3670 return false; 3670 return false;
3671 } 3671 }
3672 return TryReplaceInstanceCallWithInline(call); 3672 return TryReplaceInstanceCallWithInline(call);
3673 } 3673 }
3674 3674
3675 3675
3676 // Returns a Boolean constant if all classes in ic_data yield the same type-test 3676 // If type tests specified by 'ic_data' do not depend on type arguments,
3677 // result and the type tests do not depend on type arguments. Otherwise return 3677 // return mapping cid->result in 'results' (i : cid; i + 1: result).
3678 // Bool::null(). 3678 // If all tests yield the same result, return it otherwise return Bool::null.
3679 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, 3679 // If no mapping is possible, 'results' is empty.
3680 const AbstractType& type) const { 3680 // An instance-of test returning all same results can be converted to a class
3681 // check.
3682 RawBool* FlowGraphOptimizer::InstanceOfAsBool(
3683 const ICData& ic_data,
3684 const AbstractType& type,
3685 ZoneGrowableArray<intptr_t>* results) const {
3686 results->Clear();
Florian Schneider 2014/04/28 15:41:01 Is results reused somewhere? Maybe just ASSERT(re
srdjan 2014/04/28 15:44:58 Done.
3681 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. 3687 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only.
3682 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { 3688 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
3683 return Bool::null(); 3689 return Bool::null();
3684 } 3690 }
3685 const Class& type_class = Class::Handle(type.type_class()); 3691 const Class& type_class = Class::Handle(type.type_class());
3686 const intptr_t num_type_args = type_class.NumTypeArguments(); 3692 const intptr_t num_type_args = type_class.NumTypeArguments();
3687 if (num_type_args > 0) { 3693 if (num_type_args > 0) {
3688 // Only raw types can be directly compared, thus disregarding type 3694 // Only raw types can be directly compared, thus disregarding type
3689 // arguments. 3695 // arguments.
3690 const intptr_t num_type_params = type_class.NumTypeParameters(); 3696 const intptr_t num_type_params = type_class.NumTypeParameters();
3691 const intptr_t from_index = num_type_args - num_type_params; 3697 const intptr_t from_index = num_type_args - num_type_params;
3692 const TypeArguments& type_arguments = 3698 const TypeArguments& type_arguments =
3693 TypeArguments::Handle(type.arguments()); 3699 TypeArguments::Handle(type.arguments());
3694 const bool is_raw_type = type_arguments.IsNull() || 3700 const bool is_raw_type = type_arguments.IsNull() ||
3695 type_arguments.IsRaw(from_index, num_type_params); 3701 type_arguments.IsRaw(from_index, num_type_params);
3696 if (!is_raw_type) { 3702 if (!is_raw_type) {
3697 // Unknown result. 3703 // Unknown result.
3698 return Bool::null(); 3704 return Bool::null();
3699 } 3705 }
3700 } 3706 }
3707
3701 const ClassTable& class_table = *Isolate::Current()->class_table(); 3708 const ClassTable& class_table = *Isolate::Current()->class_table();
3702 Bool& prev = Bool::Handle(); 3709 Bool& prev = Bool::Handle();
3703 Class& cls = Class::Handle(); 3710 Class& cls = Class::Handle();
3711
3712 bool results_differ = false;
3704 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { 3713 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
3705 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); 3714 cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
3706 if (cls.NumTypeArguments() > 0) return Bool::null(); 3715 if (cls.NumTypeArguments() > 0) {
3716 return Bool::null();
3717 }
3707 const bool is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), 3718 const bool is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(),
3708 type_class, 3719 type_class,
3709 TypeArguments::Handle(), 3720 TypeArguments::Handle(),
3710 NULL); 3721 NULL);
3722 results->Add(cls.id());
3723 results->Add(is_subtype);
3711 if (prev.IsNull()) { 3724 if (prev.IsNull()) {
3712 prev = Bool::Get(is_subtype).raw(); 3725 prev = Bool::Get(is_subtype).raw();
3713 } else { 3726 } else {
3714 if (is_subtype != prev.value()) return Bool::null(); 3727 if (is_subtype != prev.value()) {
3728 results_differ = true;
3729 }
3715 } 3730 }
3716 } 3731 }
3717 return prev.raw(); 3732 return results_differ ? Bool::null() : prev.raw();
3718 } 3733 }
3719 3734
3720 3735
3721 static Definition* OriginalDefinition(Definition* defn) { 3736 static Definition* OriginalDefinition(Definition* defn) {
3722 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { 3737 while (defn->IsRedefinition() || defn->IsAssertAssignable()) {
3723 if (defn->IsRedefinition()) { 3738 if (defn->IsRedefinition()) {
3724 defn = defn->AsRedefinition()->value()->definition(); 3739 defn = defn->AsRedefinition()->value()->definition();
3725 } else { 3740 } else {
3726 defn = defn->AsAssertAssignable()->value()->definition(); 3741 defn = defn->AsAssertAssignable()->value()->definition();
3727 } 3742 }
(...skipping 24 matching lines...) Expand all
3752 const TypeArguments& type_arguments = 3767 const TypeArguments& type_arguments =
3753 TypeArguments::Handle(type.arguments()); 3768 TypeArguments::Handle(type.arguments());
3754 const bool is_raw_type = type_arguments.IsNull() || 3769 const bool is_raw_type = type_arguments.IsNull() ||
3755 type_arguments.IsRaw(from_index, num_type_params); 3770 type_arguments.IsRaw(from_index, num_type_params);
3756 return is_raw_type; 3771 return is_raw_type;
3757 } 3772 }
3758 return true; 3773 return true;
3759 } 3774 }
3760 3775
3761 3776
3777 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
3778 intptr_t test_cid) {
3779 for (intptr_t i = 0; i < results.length(); i += 2) {
3780 if (results[i] == test_cid) return true;
3781 }
3782 return false;
3783 }
3784
3785
3786 static void TryAddTest(ZoneGrowableArray<intptr_t>* results,
3787 intptr_t test_cid,
3788 bool result) {
3789 if (!CidTestResultsContains(*results, test_cid)) {
3790 results->Add(test_cid);
3791 results->Add(result);
3792 }
3793 }
3794
3795
3796 // Tries to add cid tests to 'results' so that no deoptimization is
3797 // necessary.
3798 // TODO(srdjan): Do also for other than 'int' type.
3799 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
3800 const AbstractType& type) {
3801 ASSERT(results->length() >= 2); // At least on eentry.
3802 const ClassTable& class_table = *Isolate::Current()->class_table();
3803 if ((*results)[0] != kSmiCid) {
3804 const Class& cls = Class::Handle(class_table.At(kSmiCid));
3805 const Class& type_class = Class::Handle(type.type_class());
3806 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(),
3807 type_class,
3808 TypeArguments::Handle(),
3809 NULL);
3810 results->Add((*results)[results->length() - 2]);
3811 results->Add((*results)[results->length() - 2]);
3812 for (intptr_t i = results->length() - 3; i > 1; --i) {
3813 (*results)[i] = (*results)[i - 2];
3814 }
3815 (*results)[0] = kSmiCid;
3816 (*results)[1] = smi_is_subtype;
3817 }
3818
3819 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
3820 ASSERT(results->length() >= 2);
3821 // const Class& type_class = Class::Handle(type.type_class())
Florian Schneider 2014/04/28 15:41:01 Remove commented-out code.
srdjan 2014/04/28 15:44:58 Done.
3822 if (type.IsIntType()) {
3823 ASSERT((*results)[0] == kSmiCid);
3824 TryAddTest(results, kMintCid, true);
3825 TryAddTest(results, kBigintCid, true);
3826 // Cannot deoptimize since all tests returning true have been added.
3827 return false;
3828 }
3829
3830 return true; // May deoptimize since we have not identified all 'true' tests.
3831 }
3832
3833
3762 // TODO(srdjan): Use ICData to check if always true or false. 3834 // TODO(srdjan): Use ICData to check if always true or false.
3763 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { 3835 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
3764 ASSERT(Token::IsTypeTestOperator(call->token_kind())); 3836 ASSERT(Token::IsTypeTestOperator(call->token_kind()));
3765 Definition* left = call->ArgumentAt(0); 3837 Definition* left = call->ArgumentAt(0);
3766 Definition* instantiator = call->ArgumentAt(1); 3838 Definition* instantiator = call->ArgumentAt(1);
3767 Definition* type_args = call->ArgumentAt(2); 3839 Definition* type_args = call->ArgumentAt(2);
3768 const AbstractType& type = 3840 const AbstractType& type =
3769 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); 3841 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
3770 const bool negate = Bool::Cast( 3842 const bool negate = Bool::Cast(
3771 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); 3843 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value();
3772 const ICData& unary_checks = 3844 const ICData& unary_checks =
3773 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); 3845 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
3774 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { 3846 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
3775 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); 3847 ZoneGrowableArray<intptr_t>* results =
3776 if (!as_bool.IsNull()) { 3848 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
3849 Bool& as_bool =
3850 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results));
3851 if (as_bool.IsNull()) {
3852 if (results->length() == unary_checks.NumberOfChecks() * 2) {
3853 const bool can_deopt = TryExpandTestCidsResult(results, type);
3854 TestCidsInstr* test_cids = new TestCidsInstr(
3855 call->token_pos(),
3856 negate ? Token::kISNOT : Token::kIS,
3857 new Value(left),
3858 *results,
3859 can_deopt ? call->deopt_id() : Isolate::kNoDeoptId);
3860 // Remove type.
3861 ReplaceCall(call, test_cids);
3862 return;
3863 }
3864 } else {
3865 // TODO(srdjan): Use TestCidsInstr also for this case.
3866 // One result only.
3777 AddReceiverCheck(call); 3867 AddReceiverCheck(call);
3778 if (negate) { 3868 if (negate) {
3779 as_bool = Bool::Get(!as_bool.value()).raw(); 3869 as_bool = Bool::Get(!as_bool.value()).raw();
3780 } 3870 }
3781 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); 3871 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
3782 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 3872 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
3783 PushArgumentInstr* push = call->PushArgumentAt(i); 3873 PushArgumentInstr* push = call->PushArgumentAt(i);
3784 push->ReplaceUsesWith(push->value()->definition()); 3874 push->ReplaceUsesWith(push->value()->definition());
3785 push->RemoveFromGraph(); 3875 push->RemoveFromGraph();
3786 } 3876 }
(...skipping 29 matching lines...) Expand all
3816 new Value(left), 3906 new Value(left),
3817 new Value(instantiator), 3907 new Value(instantiator),
3818 new Value(type_args), 3908 new Value(type_args),
3819 type, 3909 type,
3820 negate, 3910 negate,
3821 call->deopt_id()); 3911 call->deopt_id());
3822 ReplaceCall(call, instance_of); 3912 ReplaceCall(call, instance_of);
3823 } 3913 }
3824 3914
3825 3915
3916 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
3826 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 3917 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
3827 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 3918 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
3828 Definition* left = call->ArgumentAt(0); 3919 Definition* left = call->ArgumentAt(0);
3829 Definition* instantiator = call->ArgumentAt(1); 3920 Definition* instantiator = call->ArgumentAt(1);
3830 Definition* type_args = call->ArgumentAt(2); 3921 Definition* type_args = call->ArgumentAt(2);
3831 const AbstractType& type = 3922 const AbstractType& type =
3832 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); 3923 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
3833 ASSERT(!type.IsMalformedOrMalbounded()); 3924 ASSERT(!type.IsMalformedOrMalbounded());
3834 const ICData& unary_checks = 3925 const ICData& unary_checks =
3835 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); 3926 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
3836 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { 3927 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
3837 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); 3928 ZoneGrowableArray<intptr_t>* results =
3929 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
3930 const Bool& as_bool =
3931 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results));
3838 if (as_bool.raw() == Bool::True().raw()) { 3932 if (as_bool.raw() == Bool::True().raw()) {
3839 AddReceiverCheck(call); 3933 AddReceiverCheck(call);
3840 // Remove the original push arguments. 3934 // Remove the original push arguments.
3841 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 3935 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
3842 PushArgumentInstr* push = call->PushArgumentAt(i); 3936 PushArgumentInstr* push = call->PushArgumentAt(i);
3843 push->ReplaceUsesWith(push->value()->definition()); 3937 push->ReplaceUsesWith(push->value()->definition());
3844 push->RemoveFromGraph(); 3938 push->RemoveFromGraph();
3845 } 3939 }
3846 // Remove call, replace it with 'left'. 3940 // Remove call, replace it with 'left'.
3847 call->ReplaceUsesWith(left); 3941 call->ReplaceUsesWith(left);
(...skipping 3568 matching lines...) Expand 10 before | Expand all | Expand 10 after
7416 Integer::Cast(right))), 7510 Integer::Cast(right))),
7417 Smi::Handle(Smi::New(0))); 7511 Smi::Handle(Smi::New(0)));
7418 SetValue(instr, result ? Bool::True() : Bool::False()); 7512 SetValue(instr, result ? Bool::True() : Bool::False());
7419 } else { 7513 } else {
7420 SetValue(instr, non_constant_); 7514 SetValue(instr, non_constant_);
7421 } 7515 }
7422 } 7516 }
7423 } 7517 }
7424 7518
7425 7519
7520 void ConstantPropagator::VisitTestCids(TestCidsInstr* instr) {
7521 SetValue(instr, non_constant_);
7522 }
7523
7524
7426 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { 7525 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
7427 const Object& left = instr->left()->definition()->constant_value(); 7526 const Object& left = instr->left()->definition()->constant_value();
7428 const Object& right = instr->right()->definition()->constant_value(); 7527 const Object& right = instr->right()->definition()->constant_value();
7429 7528
7430 if (instr->left()->definition() == instr->right()->definition()) { 7529 if (instr->left()->definition() == instr->right()->definition()) {
7431 // Fold x == x, and x != x to true/false for numbers comparisons. 7530 // Fold x == x, and x != x to true/false for numbers comparisons.
7432 if (RawObject::IsIntegerClassId(instr->operation_cid())) { 7531 if (RawObject::IsIntegerClassId(instr->operation_cid())) {
7433 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); 7532 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ));
7434 } 7533 }
7435 } 7534 }
(...skipping 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after
8499 // These are the branches produced by inlining in a test context. Also, 8598 // These are the branches produced by inlining in a test context. Also,
8500 // the phi has no other uses so they can simply be eliminated. The block 8599 // the phi has no other uses so they can simply be eliminated. The block
8501 // has no other phis and no instructions intervening between the phi and 8600 // has no other phis and no instructions intervening between the phi and
8502 // branch so the block can simply be eliminated. 8601 // branch so the block can simply be eliminated.
8503 BranchInstr* branch = block->last_instruction()->AsBranch(); 8602 BranchInstr* branch = block->last_instruction()->AsBranch();
8504 ASSERT(branch != NULL); 8603 ASSERT(branch != NULL);
8505 ComparisonInstr* comparison = branch->comparison(); 8604 ComparisonInstr* comparison = branch->comparison();
8506 Value* left = comparison->left(); 8605 Value* left = comparison->left();
8507 PhiInstr* phi = left->definition()->AsPhi(); 8606 PhiInstr* phi = left->definition()->AsPhi();
8508 Value* right = comparison->right(); 8607 Value* right = comparison->right();
8509 ConstantInstr* constant = right->definition()->AsConstant(); 8608 ConstantInstr* constant =
8609 (right == NULL) ? NULL : right->definition()->AsConstant();
8510 return (phi != NULL) && 8610 return (phi != NULL) &&
8511 (constant != NULL) && 8611 (constant != NULL) &&
8512 (phi->GetBlock() == block) && 8612 (phi->GetBlock() == block) &&
8513 PhiHasSingleUse(phi, left) && 8613 PhiHasSingleUse(phi, left) &&
8514 (block->next() == branch) && 8614 (block->next() == branch) &&
8515 (block->phis()->length() == 1); 8615 (block->phis()->length() == 1);
8516 } 8616 }
8517 8617
8518 8618
8519 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { 8619 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) {
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
9053 } 9153 }
9054 9154
9055 // Insert materializations at environment uses. 9155 // Insert materializations at environment uses.
9056 for (intptr_t i = 0; i < exits.length(); i++) { 9156 for (intptr_t i = 0; i < exits.length(); i++) {
9057 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); 9157 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots);
9058 } 9158 }
9059 } 9159 }
9060 9160
9061 9161
9062 } // namespace dart 9162 } // 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