| 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/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 26 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 27 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 27 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 28 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 28 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
| 29 DEFINE_FLAG(bool, trace_constant_propagation, false, | 29 DEFINE_FLAG(bool, trace_constant_propagation, false, |
| 30 "Print constant propagation and useless code elimination."); | 30 "Print constant propagation and useless code elimination."); |
| 31 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 31 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 32 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 32 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 33 DEFINE_FLAG(bool, truncating_left_shift, true, | 33 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 34 "Optimize left shift to truncate if possible"); | 34 "Optimize left shift to truncate if possible"); |
| 35 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 35 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 36 DEFINE_FLAG(bool, trace_load_optimization, false, |
| 37 "Print live sets for load optimization pass."); |
| 36 DECLARE_FLAG(bool, eliminate_type_checks); | 38 DECLARE_FLAG(bool, eliminate_type_checks); |
| 37 DECLARE_FLAG(bool, enable_type_checks); | 39 DECLARE_FLAG(bool, enable_type_checks); |
| 38 DECLARE_FLAG(bool, trace_type_check_elimination); | 40 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 39 | 41 |
| 40 | 42 |
| 41 // Optimize instance calls using ICData. | 43 // Optimize instance calls using ICData. |
| 42 void FlowGraphOptimizer::ApplyICData() { | 44 void FlowGraphOptimizer::ApplyICData() { |
| 43 VisitBlocks(); | 45 VisitBlocks(); |
| 44 } | 46 } |
| 45 | 47 |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 insert_before = | 408 insert_before = |
| 407 phi->block()->PredecessorAt(use->use_index())->last_instruction(); | 409 phi->block()->PredecessorAt(use->use_index())->last_instruction(); |
| 408 deopt_target = NULL; | 410 deopt_target = NULL; |
| 409 } else { | 411 } else { |
| 410 deopt_target = insert_before = use->instruction(); | 412 deopt_target = insert_before = use->instruction(); |
| 411 } | 413 } |
| 412 | 414 |
| 413 InsertConversion(from_rep, to_rep, use, insert_before, deopt_target); | 415 InsertConversion(from_rep, to_rep, use, insert_before, deopt_target); |
| 414 } | 416 } |
| 415 | 417 |
| 418 |
| 416 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { | 419 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
| 417 const Representation from_rep = def->representation(); | 420 const Representation from_rep = def->representation(); |
| 418 | 421 |
| 419 for (Value::Iterator it(def->input_use_list()); | 422 for (Value::Iterator it(def->input_use_list()); |
| 420 !it.Done(); | 423 !it.Done(); |
| 421 it.Advance()) { | 424 it.Advance()) { |
| 422 ConvertUse(it.Current(), from_rep); | 425 ConvertUse(it.Current(), from_rep); |
| 423 } | 426 } |
| 424 } | 427 } |
| 425 | 428 |
| (...skipping 3069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3495 current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); | 3498 current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); |
| 3496 | 3499 |
| 3497 phi->UpdateType(CompileType::FromCid(kSmiCid)); | 3500 phi->UpdateType(CompileType::FromCid(kSmiCid)); |
| 3498 } | 3501 } |
| 3499 | 3502 |
| 3500 | 3503 |
| 3501 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, | 3504 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, |
| 3502 intptr_t loop_header_index, | 3505 intptr_t loop_header_index, |
| 3503 Instruction* instr) { | 3506 Instruction* instr) { |
| 3504 return (sets != NULL) && | 3507 return (sets != NULL) && |
| 3505 instr->HasExprId() && | 3508 instr->HasPlaceId() && |
| 3506 ((*sets)[loop_header_index] != NULL) && | 3509 ((*sets)[loop_header_index] != NULL) && |
| 3507 (*sets)[loop_header_index]->Contains(instr->expr_id()); | 3510 (*sets)[loop_header_index]->Contains(instr->place_id()); |
| 3508 } | 3511 } |
| 3509 | 3512 |
| 3510 | 3513 |
| 3511 void LICM::Optimize() { | 3514 void LICM::Optimize() { |
| 3512 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = | 3515 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = |
| 3513 flow_graph()->loop_headers(); | 3516 flow_graph()->loop_headers(); |
| 3514 | 3517 |
| 3515 ZoneGrowableArray<BitVector*>* loop_invariant_loads = | 3518 ZoneGrowableArray<BitVector*>* loop_invariant_loads = |
| 3516 flow_graph()->loop_invariant_loads(); | 3519 flow_graph()->loop_invariant_loads(); |
| 3517 | 3520 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3627 kCurrentContextAlias = -1, | 3630 kCurrentContextAlias = -1, |
| 3628 kIndexesAlias = 0, | 3631 kIndexesAlias = 0, |
| 3629 kFirstFieldAlias = kIndexesAlias + 1, | 3632 kFirstFieldAlias = kIndexesAlias + 1, |
| 3630 kAliasBase = kCurrentContextAlias | 3633 kAliasBase = kCurrentContextAlias |
| 3631 }; | 3634 }; |
| 3632 | 3635 |
| 3633 const intptr_t alias_; | 3636 const intptr_t alias_; |
| 3634 }; | 3637 }; |
| 3635 | 3638 |
| 3636 | 3639 |
| 3637 // Set mapping alias to a list of loads sharing this alias. Additionally | 3640 // Place describes an abstract location (e.g. field) that IR can load |
| 3638 // carries a set of loads that can be aliased by side-effects, essentially | 3641 // from or store to. |
| 3642 class Place : public ValueObject { |
| 3643 public: |
| 3644 enum Kind { |
| 3645 kNone, |
| 3646 |
| 3647 // Field location. For instance fields is represented as a pair of a Field |
| 3648 // object and an instance (SSA definition) that is being accessed. |
| 3649 // For static fields instance is NULL. |
| 3650 kField, |
| 3651 |
| 3652 // VMField location. Represented as a pair of an instance (SSA definition) |
| 3653 // being accessed and offset to the field. |
| 3654 kVMField, |
| 3655 |
| 3656 // Indexed location. |
| 3657 kIndexed, |
| 3658 |
| 3659 // Current context. |
| 3660 kContext |
| 3661 }; |
| 3662 |
| 3663 Place(const Place& other) |
| 3664 : ValueObject(), |
| 3665 kind_(other.kind_), |
| 3666 instance_(other.instance_), |
| 3667 raw_selector_(other.raw_selector_), |
| 3668 id_(other.id_) { |
| 3669 } |
| 3670 |
| 3671 // Construct a place from instruction if instruction accesses any place. |
| 3672 // Otherwise constructs kNone place. |
| 3673 Place(Instruction* instr, bool* is_load) |
| 3674 : kind_(kNone), instance_(NULL), raw_selector_(0), id_(0) { |
| 3675 switch (instr->tag()) { |
| 3676 case Instruction::kLoadField: { |
| 3677 LoadFieldInstr* load_field = instr->AsLoadField(); |
| 3678 instance_ = load_field->instance()->definition(); |
| 3679 if (load_field->field() != NULL) { |
| 3680 kind_ = kField; |
| 3681 field_ = load_field->field(); |
| 3682 } else { |
| 3683 kind_ = kVMField; |
| 3684 offset_in_bytes_ = load_field->offset_in_bytes(); |
| 3685 } |
| 3686 *is_load = true; |
| 3687 break; |
| 3688 } |
| 3689 |
| 3690 case Instruction::kStoreInstanceField: { |
| 3691 StoreInstanceFieldInstr* store_instance_field = |
| 3692 instr->AsStoreInstanceField(); |
| 3693 kind_ = kField; |
| 3694 instance_ = store_instance_field->instance()->definition(); |
| 3695 field_ = &store_instance_field->field(); |
| 3696 break; |
| 3697 } |
| 3698 |
| 3699 case Instruction::kStoreVMField: { |
| 3700 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField(); |
| 3701 kind_ = kVMField; |
| 3702 instance_ = store_vm_field->dest()->definition(); |
| 3703 offset_in_bytes_ = store_vm_field->offset_in_bytes(); |
| 3704 break; |
| 3705 } |
| 3706 |
| 3707 case Instruction::kLoadStaticField: |
| 3708 kind_ = kField; |
| 3709 field_ = &instr->AsLoadStaticField()->StaticField(); |
| 3710 *is_load = true; |
| 3711 break; |
| 3712 |
| 3713 case Instruction::kStoreStaticField: |
| 3714 kind_ = kField; |
| 3715 field_ = &instr->AsStoreStaticField()->field(); |
| 3716 break; |
| 3717 |
| 3718 case Instruction::kLoadIndexed: { |
| 3719 LoadIndexedInstr* load_indexed = instr->AsLoadIndexed(); |
| 3720 kind_ = kIndexed; |
| 3721 instance_ = load_indexed->array()->definition(); |
| 3722 index_ = load_indexed->index()->definition(); |
| 3723 *is_load = true; |
| 3724 break; |
| 3725 } |
| 3726 |
| 3727 case Instruction::kStoreIndexed: { |
| 3728 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed(); |
| 3729 kind_ = kIndexed; |
| 3730 instance_ = store_indexed->array()->definition(); |
| 3731 index_ = store_indexed->index()->definition(); |
| 3732 break; |
| 3733 } |
| 3734 |
| 3735 case Instruction::kCurrentContext: |
| 3736 kind_ = kContext; |
| 3737 *is_load = true; |
| 3738 break; |
| 3739 |
| 3740 case Instruction::kChainContext: |
| 3741 case Instruction::kStoreContext: |
| 3742 kind_ = kContext; |
| 3743 break; |
| 3744 |
| 3745 default: |
| 3746 break; |
| 3747 } |
| 3748 } |
| 3749 |
| 3750 intptr_t id() const { return id_; } |
| 3751 void set_id(intptr_t id) { id_ = id; } |
| 3752 |
| 3753 Kind kind() const { return kind_; } |
| 3754 |
| 3755 Definition* instance() const { |
| 3756 ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed)); |
| 3757 return instance_; |
| 3758 } |
| 3759 |
| 3760 void set_instance(Definition* def) { |
| 3761 ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed)); |
| 3762 instance_ = def; |
| 3763 } |
| 3764 |
| 3765 const Field& field() const { |
| 3766 ASSERT(kind_ == kField); |
| 3767 return *field_; |
| 3768 } |
| 3769 |
| 3770 intptr_t offset_in_bytes() const { |
| 3771 ASSERT(kind_ == kVMField); |
| 3772 return offset_in_bytes_; |
| 3773 } |
| 3774 |
| 3775 Definition* index() const { |
| 3776 ASSERT(kind_ == kIndexed); |
| 3777 return index_; |
| 3778 } |
| 3779 |
| 3780 const char* ToCString() const { |
| 3781 switch (kind_) { |
| 3782 case kNone: |
| 3783 return "<none>"; |
| 3784 |
| 3785 case kField: { |
| 3786 const char* field_name = String::Handle(field().name()).ToCString(); |
| 3787 if (instance() == NULL) { |
| 3788 return field_name; |
| 3789 } |
| 3790 return Isolate::Current()->current_zone()->PrintToString( |
| 3791 "<v%"Pd".%s>", instance()->ssa_temp_index(), field_name); |
| 3792 } |
| 3793 |
| 3794 case kVMField: { |
| 3795 return Isolate::Current()->current_zone()->PrintToString( |
| 3796 "<v%"Pd"@%"Pd">", instance()->ssa_temp_index(), offset_in_bytes()); |
| 3797 } |
| 3798 |
| 3799 case kIndexed: { |
| 3800 return Isolate::Current()->current_zone()->PrintToString( |
| 3801 "<v%"Pd"[v%"Pd"]>", |
| 3802 instance()->ssa_temp_index(), |
| 3803 index()->ssa_temp_index()); |
| 3804 } |
| 3805 |
| 3806 case kContext: |
| 3807 return "<context>"; |
| 3808 } |
| 3809 UNREACHABLE(); |
| 3810 return "<?>"; |
| 3811 } |
| 3812 |
| 3813 bool IsFinalField() const { |
| 3814 return (kind() == kField) && field().is_final(); |
| 3815 } |
| 3816 |
| 3817 intptr_t Hashcode() const { |
| 3818 return (kind_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 + |
| 3819 FieldHashcode(); |
| 3820 } |
| 3821 |
| 3822 bool Equals(Place* other) const { |
| 3823 return (kind_ == other->kind_) && |
| 3824 (instance_ == other->instance_) && |
| 3825 SameField(other); |
| 3826 } |
| 3827 |
| 3828 // Create a zone allocated copy of this place. |
| 3829 static Place* Wrap(const Place& place); |
| 3830 |
| 3831 private: |
| 3832 bool SameField(Place* other) const { |
| 3833 return (kind_ == kField) ? (field().raw() == other->field().raw()) |
| 3834 : (offset_in_bytes_ == other->offset_in_bytes_); |
| 3835 } |
| 3836 |
| 3837 intptr_t FieldHashcode() const { |
| 3838 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) |
| 3839 : offset_in_bytes_; |
| 3840 } |
| 3841 |
| 3842 Kind kind_; |
| 3843 Definition* instance_; |
| 3844 union { |
| 3845 intptr_t raw_selector_; |
| 3846 const Field* field_; |
| 3847 intptr_t offset_in_bytes_; |
| 3848 Definition* index_; |
| 3849 }; |
| 3850 |
| 3851 intptr_t id_; |
| 3852 }; |
| 3853 |
| 3854 |
| 3855 class ZonePlace : public ZoneAllocated { |
| 3856 public: |
| 3857 explicit ZonePlace(const Place& place) : place_(place) { } |
| 3858 |
| 3859 Place* place() { return &place_; } |
| 3860 |
| 3861 private: |
| 3862 Place place_; |
| 3863 }; |
| 3864 |
| 3865 |
| 3866 Place* Place::Wrap(const Place& place) { |
| 3867 return (new ZonePlace(place))->place(); |
| 3868 } |
| 3869 |
| 3870 |
| 3871 class PhiPlaceMoves : public ZoneAllocated { |
| 3872 public: |
| 3873 void CreateOutgoingMove(BlockEntryInstr* block, intptr_t from, intptr_t to) { |
| 3874 const intptr_t block_num = block->preorder_number(); |
| 3875 while (moves_.length() <= block_num) { |
| 3876 moves_.Add(NULL); |
| 3877 } |
| 3878 |
| 3879 if (moves_[block_num] == NULL) { |
| 3880 moves_[block_num] = new ZoneGrowableArray<Move>(5); |
| 3881 } |
| 3882 |
| 3883 moves_[block_num]->Add(Move(from, to)); |
| 3884 } |
| 3885 |
| 3886 class Move { |
| 3887 public: |
| 3888 Move(intptr_t from, intptr_t to) : from_(from), to_(to) { } |
| 3889 |
| 3890 intptr_t from() const { return from_; } |
| 3891 intptr_t to() const { return to_; } |
| 3892 |
| 3893 private: |
| 3894 intptr_t from_; |
| 3895 intptr_t to_; |
| 3896 }; |
| 3897 |
| 3898 typedef const ZoneGrowableArray<Move>* MovesList; |
| 3899 |
| 3900 MovesList GetOutgoingMoves(BlockEntryInstr* block) const { |
| 3901 const intptr_t block_num = block->preorder_number(); |
| 3902 return (block_num < moves_.length()) ? |
| 3903 moves_[block_num] : NULL; |
| 3904 } |
| 3905 |
| 3906 private: |
| 3907 GrowableArray<ZoneGrowableArray<Move>* > moves_; |
| 3908 }; |
| 3909 |
| 3910 |
| 3911 // A map from aliases to a set of places sharing the alias. Additionally |
| 3912 // carries a set of places that can be aliased by side-effects, essentially |
| 3639 // those that are affected by calls. | 3913 // those that are affected by calls. |
| 3640 class AliasedSet : public ZoneAllocated { | 3914 class AliasedSet : public ZoneAllocated { |
| 3641 public: | 3915 public: |
| 3642 explicit AliasedSet(intptr_t max_expr_id) | 3916 explicit AliasedSet(ZoneGrowableArray<Place*>* places, |
| 3643 : max_expr_id_(max_expr_id), | 3917 PhiPlaceMoves* phi_moves) |
| 3918 : places_(*places), |
| 3919 phi_moves_(phi_moves), |
| 3644 sets_(), | 3920 sets_(), |
| 3645 // BitVector constructor throws if requested length is 0. | 3921 aliased_by_effects_(new BitVector(places->length())), |
| 3646 aliased_by_effects_(max_expr_id > 0 ? new BitVector(max_expr_id) | |
| 3647 : NULL), | |
| 3648 max_field_id_(0), | 3922 max_field_id_(0), |
| 3649 field_ids_() { } | 3923 field_ids_() { } |
| 3650 | 3924 |
| 3651 Alias ComputeAliasForLoad(Definition* defn) { | 3925 Alias ComputeAlias(Place* place) { |
| 3652 if (defn->IsLoadIndexed()) { | 3926 switch (place->kind()) { |
| 3653 // We are assuming that LoadField is never used to load the first word. | 3927 case Place::kIndexed: |
| 3654 return Alias::Indexes(); | 3928 return Alias::Indexes(); |
| 3655 } | 3929 case Place::kField: |
| 3656 | 3930 return Alias::Field( |
| 3657 LoadFieldInstr* load_field = defn->AsLoadField(); | 3931 GetInstanceFieldId(place->instance(), place->field())); |
| 3658 if (load_field != NULL) { | 3932 case Place::kVMField: |
| 3659 if (load_field->field() != NULL) { | 3933 return Alias::VMField(place->offset_in_bytes()); |
| 3660 Definition* instance = load_field->instance()->definition(); | 3934 case Place::kContext: |
| 3661 return Alias::Field(GetInstanceFieldId(instance, *load_field->field())); | 3935 return Alias::CurrentContext(); |
| 3662 } else { | 3936 case Place::kNone: |
| 3663 return Alias::VMField(load_field->offset_in_bytes()); | 3937 UNREACHABLE(); |
| 3664 } | |
| 3665 } | |
| 3666 | |
| 3667 if (defn->IsCurrentContext()) { | |
| 3668 return Alias::CurrentContext(); | |
| 3669 } | |
| 3670 | |
| 3671 LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField(); | |
| 3672 if (load_static_field != NULL) { | |
| 3673 return Alias::Field(GetFieldId(kAnyInstance, | |
| 3674 load_static_field->StaticField())); | |
| 3675 } | 3938 } |
| 3676 | 3939 |
| 3677 UNREACHABLE(); | 3940 UNREACHABLE(); |
| 3678 return Alias::None(); | 3941 return Alias::None(); |
| 3679 } | 3942 } |
| 3680 | 3943 |
| 3681 Alias ComputeAliasForStore(Instruction* instr) { | 3944 Alias ComputeAliasForStore(Instruction* instr) { |
| 3682 if (instr->IsStoreIndexed()) { | 3945 if (instr->IsStoreIndexed()) { |
| 3683 return Alias::Indexes(); | 3946 return Alias::Indexes(); |
| 3684 } | 3947 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3701 } | 3964 } |
| 3702 | 3965 |
| 3703 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField(); | 3966 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField(); |
| 3704 if (store_static_field != NULL) { | 3967 if (store_static_field != NULL) { |
| 3705 return Alias::Field(GetStaticFieldId(store_static_field->field())); | 3968 return Alias::Field(GetStaticFieldId(store_static_field->field())); |
| 3706 } | 3969 } |
| 3707 | 3970 |
| 3708 return Alias::None(); | 3971 return Alias::None(); |
| 3709 } | 3972 } |
| 3710 | 3973 |
| 3711 bool Contains(const Alias alias) { | 3974 BitVector* Get(const Alias alias) { |
| 3712 const intptr_t idx = alias.ToIndex(); | 3975 const intptr_t idx = alias.ToIndex(); |
| 3713 return (idx < sets_.length()) && (sets_[idx] != NULL); | 3976 return (idx < sets_.length()) ? sets_[idx] : NULL; |
| 3714 } | 3977 } |
| 3715 | 3978 |
| 3716 BitVector* Get(const Alias alias) { | 3979 void AddRepresentative(Place* place) { |
| 3717 ASSERT(Contains(alias)); | 3980 if (!place->IsFinalField()) { |
| 3718 return sets_[alias.ToIndex()]; | 3981 AddIdForAlias(ComputeAlias(place), place->id()); |
| 3719 } | 3982 if (!IsIndependentFromEffects(place)) { |
| 3720 | 3983 aliased_by_effects_->Add(place->id()); |
| 3721 void AddRepresentative(Definition* defn) { | 3984 } |
| 3722 AddIdForAlias(ComputeAliasForLoad(defn), defn->expr_id()); | |
| 3723 if (!IsIndependentFromEffects(defn)) { | |
| 3724 aliased_by_effects_->Add(defn->expr_id()); | |
| 3725 } | 3985 } |
| 3726 } | 3986 } |
| 3727 | 3987 |
| 3728 void AddIdForAlias(const Alias alias, intptr_t expr_id) { | 3988 void AddIdForAlias(const Alias alias, intptr_t place_id) { |
| 3729 const intptr_t idx = alias.ToIndex(); | 3989 const intptr_t idx = alias.ToIndex(); |
| 3730 | 3990 |
| 3731 while (sets_.length() <= idx) { | 3991 while (sets_.length() <= idx) { |
| 3732 sets_.Add(NULL); | 3992 sets_.Add(NULL); |
| 3733 } | 3993 } |
| 3734 | 3994 |
| 3735 if (sets_[idx] == NULL) { | 3995 if (sets_[idx] == NULL) { |
| 3736 sets_[idx] = new BitVector(max_expr_id_); | 3996 sets_[idx] = new BitVector(max_place_id()); |
| 3737 } | 3997 } |
| 3738 | 3998 |
| 3739 sets_[idx]->Add(expr_id); | 3999 sets_[idx]->Add(place_id); |
| 3740 } | 4000 } |
| 3741 | 4001 |
| 3742 intptr_t max_expr_id() const { return max_expr_id_; } | 4002 intptr_t max_place_id() const { return places().length(); } |
| 3743 bool IsEmpty() const { return max_expr_id_ == 0; } | 4003 bool IsEmpty() const { return max_place_id() == 0; } |
| 3744 | 4004 |
| 3745 BitVector* aliased_by_effects() const { return aliased_by_effects_; } | 4005 BitVector* aliased_by_effects() const { return aliased_by_effects_; } |
| 3746 | 4006 |
| 4007 const ZoneGrowableArray<Place*>& places() const { |
| 4008 return places_; |
| 4009 } |
| 4010 |
| 4011 void PrintSet(BitVector* set) { |
| 4012 bool comma = false; |
| 4013 for (BitVector::Iterator it(set); |
| 4014 !it.Done(); |
| 4015 it.Advance()) { |
| 4016 if (comma) { |
| 4017 OS::Print(", "); |
| 4018 } |
| 4019 OS::Print("%s", places_[it.Current()]->ToCString()); |
| 4020 comma = true; |
| 4021 } |
| 4022 } |
| 4023 |
| 4024 const PhiPlaceMoves* phi_moves() const { return phi_moves_; } |
| 4025 |
| 3747 private: | 4026 private: |
| 3748 // Get id assigned to the given field. Assign a new id if the field is seen | 4027 // Get id assigned to the given field. Assign a new id if the field is seen |
| 3749 // for the first time. | 4028 // for the first time. |
| 3750 intptr_t GetFieldId(intptr_t instance_id, const Field& field) { | 4029 intptr_t GetFieldId(intptr_t instance_id, const Field& field) { |
| 3751 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field)); | 4030 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field)); |
| 3752 if (id == 0) { | 4031 if (id == 0) { |
| 3753 id = ++max_field_id_; | 4032 id = ++max_field_id_; |
| 3754 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id)); | 4033 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id)); |
| 3755 } | 4034 } |
| 3756 return id; | 4035 return id; |
| 3757 } | 4036 } |
| 3758 | 4037 |
| 3759 enum { | 4038 enum { |
| 3760 kAnyInstance = -1 | 4039 kAnyInstance = -1 |
| 3761 }; | 4040 }; |
| 3762 | 4041 |
| 3763 // Get or create an identifier for an instance field belonging to the | 4042 // Get or create an identifier for an instance field belonging to the |
| 3764 // given instance. | 4043 // given instance. |
| 3765 // The space of identifiers assigned to instance fields is split into | 4044 // The space of identifiers assigned to instance fields is split into |
| 3766 // parts based on the instance that contains the field. | 4045 // parts based on the instance that contains the field. |
| 3767 // If compiler can prove that instance has a single SSA name in the compiled | 4046 // If compiler can prove that instance has a single SSA name in the compiled |
| 3768 // function then we use that SSA name to distinguish fields of this object | 4047 // function then we use that SSA name to distinguish fields of this object |
| 3769 // from the same fields in other objects. | 4048 // from the same fields in other objects. |
| 3770 // If multiple SSA names can point to the same object then we use | 4049 // If multiple SSA names can point to the same object then we use |
| 3771 // kAnyInstance instead of a concrete SSA name. | 4050 // kAnyInstance instead of a concrete SSA name. |
| 3772 intptr_t GetInstanceFieldId(Definition* defn, const Field& field) { | 4051 intptr_t GetInstanceFieldId(Definition* defn, const Field& field) { |
| 3773 ASSERT(!field.is_static()); | 4052 ASSERT(field.is_static() == (defn == NULL)); |
| 3774 | 4053 |
| 3775 intptr_t instance_id = kAnyInstance; | 4054 intptr_t instance_id = kAnyInstance; |
| 3776 | 4055 |
| 3777 AllocateObjectInstr* alloc = defn->AsAllocateObject(); | 4056 if (defn != NULL) { |
| 3778 if ((alloc != NULL) && !CanBeAliased(alloc)) { | 4057 AllocateObjectInstr* alloc = defn->AsAllocateObject(); |
| 3779 instance_id = alloc->ssa_temp_index(); | 4058 if ((alloc != NULL) && !CanBeAliased(alloc)) { |
| 3780 ASSERT(instance_id != kAnyInstance); | 4059 instance_id = alloc->ssa_temp_index(); |
| 4060 ASSERT(instance_id != kAnyInstance); |
| 4061 } |
| 3781 } | 4062 } |
| 3782 | 4063 |
| 3783 return GetFieldId(instance_id, field); | 4064 return GetFieldId(instance_id, field); |
| 3784 } | 4065 } |
| 3785 | 4066 |
| 3786 // Get or create an identifier for a static field. | 4067 // Get or create an identifier for a static field. |
| 3787 intptr_t GetStaticFieldId(const Field& field) { | 4068 intptr_t GetStaticFieldId(const Field& field) { |
| 3788 ASSERT(field.is_static()); | 4069 ASSERT(field.is_static()); |
| 3789 return GetFieldId(kAnyInstance, field); | 4070 return GetFieldId(kAnyInstance, field); |
| 3790 } | 4071 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3813 alloc->set_identity(escapes ? AllocateObjectInstr::kAliased | 4094 alloc->set_identity(escapes ? AllocateObjectInstr::kAliased |
| 3814 : AllocateObjectInstr::kNotAliased); | 4095 : AllocateObjectInstr::kNotAliased); |
| 3815 } | 4096 } |
| 3816 | 4097 |
| 3817 return alloc->identity() != AllocateObjectInstr::kNotAliased; | 4098 return alloc->identity() != AllocateObjectInstr::kNotAliased; |
| 3818 } | 4099 } |
| 3819 | 4100 |
| 3820 // Returns true if the given load is unaffected by external side-effects. | 4101 // Returns true if the given load is unaffected by external side-effects. |
| 3821 // This essentially means that no stores to the same location can | 4102 // This essentially means that no stores to the same location can |
| 3822 // occur in other functions. | 4103 // occur in other functions. |
| 3823 bool IsIndependentFromEffects(Definition* defn) { | 4104 bool IsIndependentFromEffects(Place* place) { |
| 3824 LoadFieldInstr* load_field = defn->AsLoadField(); | 4105 if (place->IsFinalField()) { |
| 3825 if (load_field != NULL) { | |
| 3826 // Note that we can't use LoadField's is_immutable attribute here because | 4106 // Note that we can't use LoadField's is_immutable attribute here because |
| 3827 // some VM-fields (those that have no corresponding Field object and | 4107 // some VM-fields (those that have no corresponding Field object and |
| 3828 // accessed through offset alone) can share offset but have different | 4108 // accessed through offset alone) can share offset but have different |
| 3829 // immutability properties. | 4109 // immutability properties. |
| 3830 // One example is the length property of growable and fixed size list. If | 4110 // One example is the length property of growable and fixed size list. If |
| 3831 // loads of these two properties occur in the same function for the same | 4111 // loads of these two properties occur in the same function for the same |
| 3832 // receiver then they will get the same expression number. However | 4112 // receiver then they will get the same expression number. However |
| 3833 // immutability of the length of fixed size list does not mean that | 4113 // immutability of the length of fixed size list does not mean that |
| 3834 // growable list also has immutable property. Thus we will make a | 4114 // growable list also has immutable property. Thus we will make a |
| 3835 // conservative assumption for the VM-properties. | 4115 // conservative assumption for the VM-properties. |
| 3836 // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with | 4116 // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with |
| 3837 // the same offset e.g. through recognized kind. | 4117 // the same offset e.g. through recognized kind. |
| 3838 if ((load_field->field() != NULL) && | 4118 return true; |
| 3839 (load_field->field()->is_final())) { | 4119 } |
| 3840 return true; | |
| 3841 } | |
| 3842 | 4120 |
| 3843 AllocateObjectInstr* alloc = | 4121 if (((place->kind() == Place::kField) || |
| 3844 load_field->instance()->definition()->AsAllocateObject(); | 4122 (place->kind() == Place::kVMField)) && |
| 4123 (place->instance() != NULL)) { |
| 4124 AllocateObjectInstr* alloc = place->instance()->AsAllocateObject(); |
| 3845 return (alloc != NULL) && !CanBeAliased(alloc); | 4125 return (alloc != NULL) && !CanBeAliased(alloc); |
| 3846 } | 4126 } |
| 3847 | 4127 |
| 3848 LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField(); | |
| 3849 if (load_static_field != NULL) { | |
| 3850 return load_static_field->StaticField().is_final(); | |
| 3851 } | |
| 3852 | |
| 3853 return false; | 4128 return false; |
| 3854 } | 4129 } |
| 3855 | 4130 |
| 3856 class FieldIdPair { | 4131 class FieldIdPair { |
| 3857 public: | 4132 public: |
| 3858 struct Key { | 4133 struct Key { |
| 3859 Key(intptr_t instance_id, const Field* field) | 4134 Key(intptr_t instance_id, const Field* field) |
| 3860 : instance_id_(instance_id), field_(field) { } | 4135 : instance_id_(instance_id), field_(field) { } |
| 3861 | 4136 |
| 3862 intptr_t instance_id_; | 4137 intptr_t instance_id_; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3883 static inline bool IsKeyEqual(Pair kv, Key key) { | 4158 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 3884 return (KeyOf(kv).field_->raw() == key.field_->raw()) && | 4159 return (KeyOf(kv).field_->raw() == key.field_->raw()) && |
| 3885 (KeyOf(kv).instance_id_ == key.instance_id_); | 4160 (KeyOf(kv).instance_id_ == key.instance_id_); |
| 3886 } | 4161 } |
| 3887 | 4162 |
| 3888 private: | 4163 private: |
| 3889 Key key_; | 4164 Key key_; |
| 3890 Value value_; | 4165 Value value_; |
| 3891 }; | 4166 }; |
| 3892 | 4167 |
| 3893 const intptr_t max_expr_id_; | 4168 const ZoneGrowableArray<Place*>& places_; |
| 4169 |
| 4170 const PhiPlaceMoves* phi_moves_; |
| 3894 | 4171 |
| 3895 // Maps alias index to a set of ssa indexes corresponding to loads with the | 4172 // Maps alias index to a set of ssa indexes corresponding to loads with the |
| 3896 // given alias. | 4173 // given alias. |
| 3897 GrowableArray<BitVector*> sets_; | 4174 GrowableArray<BitVector*> sets_; |
| 3898 | 4175 |
| 3899 BitVector* aliased_by_effects_; | 4176 BitVector* aliased_by_effects_; |
| 3900 | 4177 |
| 3901 // Table mapping static field to their id used during optimization pass. | 4178 // Table mapping static field to their id used during optimization pass. |
| 3902 intptr_t max_field_id_; | 4179 intptr_t max_field_id_; |
| 3903 DirectChainedHashMap<FieldIdPair> field_ids_; | 4180 DirectChainedHashMap<FieldIdPair> field_ids_; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3926 | 4203 |
| 3927 if (instr->IsStoreContext() || instr->IsChainContext()) { | 4204 if (instr->IsStoreContext() || instr->IsChainContext()) { |
| 3928 return instr->InputAt(0)->definition(); | 4205 return instr->InputAt(0)->definition(); |
| 3929 } | 4206 } |
| 3930 | 4207 |
| 3931 UNREACHABLE(); // Should only be called for supported store instructions. | 4208 UNREACHABLE(); // Should only be called for supported store instructions. |
| 3932 return NULL; | 4209 return NULL; |
| 3933 } | 4210 } |
| 3934 | 4211 |
| 3935 | 4212 |
| 3936 // KeyValueTrait used for numbering of loads. Allows to lookup loads | 4213 static bool IsPhiDependentPlace(Place* place) { |
| 3937 // corresponding to stores. | 4214 return ((place->kind() == Place::kField) || |
| 3938 class LoadKeyValueTrait { | 4215 (place->kind() == Place::kVMField)) && |
| 3939 public: | 4216 (place->instance() != NULL) && |
| 3940 typedef Definition* Value; | 4217 place->instance()->IsPhi(); |
| 3941 typedef Instruction* Key; | 4218 } |
| 3942 typedef Definition* Pair; | |
| 3943 | 4219 |
| 3944 static Key KeyOf(Pair kv) { | 4220 |
| 3945 return kv; | 4221 // For each place that depends on a phi ensure that equivalent places |
| 4222 // corresponding to phi input are numbered and record outgoing phi moves |
| 4223 // for each block which establish correspondence between phi dependent place |
| 4224 // and phi input's place that is flowing in. |
| 4225 static PhiPlaceMoves* ComputePhiMoves( |
| 4226 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, |
| 4227 ZoneGrowableArray<Place*>* places) { |
| 4228 PhiPlaceMoves* phi_moves = new PhiPlaceMoves(); |
| 4229 |
| 4230 for (intptr_t i = 0; i < places->length(); i++) { |
| 4231 Place* place = (*places)[i]; |
| 4232 |
| 4233 if (IsPhiDependentPlace(place)) { |
| 4234 PhiInstr* phi = place->instance()->AsPhi(); |
| 4235 BlockEntryInstr* block = phi->GetBlock(); |
| 4236 |
| 4237 if (FLAG_trace_optimization) { |
| 4238 OS::Print("phi dependent place %s\n", place->ToCString()); |
| 4239 } |
| 4240 |
| 4241 Place input_place(*place); |
| 4242 for (intptr_t j = 0; j < phi->InputCount(); j++) { |
| 4243 input_place.set_instance(phi->InputAt(j)->definition()); |
| 4244 |
| 4245 Place* result = map->Lookup(&input_place); |
| 4246 if (result == NULL) { |
| 4247 input_place.set_id(places->length()); |
| 4248 result = Place::Wrap(input_place); |
| 4249 map->Insert(result); |
| 4250 places->Add(result); |
| 4251 if (FLAG_trace_optimization) { |
| 4252 OS::Print(" adding place %s as %"Pd"\n", |
| 4253 result->ToCString(), |
| 4254 result->id()); |
| 4255 } |
| 4256 } |
| 4257 |
| 4258 phi_moves->CreateOutgoingMove(block->PredecessorAt(j), |
| 4259 result->id(), |
| 4260 place->id()); |
| 4261 } |
| 4262 } |
| 3946 } | 4263 } |
| 3947 | 4264 |
| 3948 static Value ValueOf(Pair kv) { | 4265 return phi_moves; |
| 3949 return kv; | 4266 } |
| 3950 } | |
| 3951 | 4267 |
| 3952 static inline intptr_t Hashcode(Key key) { | 4268 static AliasedSet* NumberPlaces( |
| 3953 intptr_t object = 0; | |
| 3954 intptr_t location = 0; | |
| 3955 | |
| 3956 if (key->IsLoadIndexed()) { | |
| 3957 LoadIndexedInstr* load_indexed = key->AsLoadIndexed(); | |
| 3958 object = load_indexed->array()->definition()->ssa_temp_index(); | |
| 3959 location = load_indexed->index()->definition()->ssa_temp_index(); | |
| 3960 } else if (key->IsStoreIndexed()) { | |
| 3961 StoreIndexedInstr* store_indexed = key->AsStoreIndexed(); | |
| 3962 object = store_indexed->array()->definition()->ssa_temp_index(); | |
| 3963 location = store_indexed->index()->definition()->ssa_temp_index(); | |
| 3964 } else if (key->IsLoadField()) { | |
| 3965 LoadFieldInstr* load_field = key->AsLoadField(); | |
| 3966 object = load_field->instance()->definition()->ssa_temp_index(); | |
| 3967 location = load_field->offset_in_bytes(); | |
| 3968 } else if (key->IsStoreInstanceField()) { | |
| 3969 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); | |
| 3970 object = store_field->instance()->definition()->ssa_temp_index(); | |
| 3971 location = store_field->field().Offset(); | |
| 3972 } else if (key->IsStoreVMField()) { | |
| 3973 StoreVMFieldInstr* store_field = key->AsStoreVMField(); | |
| 3974 object = store_field->dest()->definition()->ssa_temp_index(); | |
| 3975 location = store_field->offset_in_bytes(); | |
| 3976 } else if (key->IsLoadStaticField()) { | |
| 3977 LoadStaticFieldInstr* load_static_field = key->AsLoadStaticField(); | |
| 3978 object = String::Handle(load_static_field->StaticField().name()).Hash(); | |
| 3979 } else if (key->IsStoreStaticField()) { | |
| 3980 StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField(); | |
| 3981 object = String::Handle(store_static_field->field().name()).Hash(); | |
| 3982 } else { | |
| 3983 ASSERT(key->IsStoreContext() || | |
| 3984 key->IsCurrentContext() || | |
| 3985 key->IsChainContext()); | |
| 3986 } | |
| 3987 | |
| 3988 return object * 31 + location; | |
| 3989 } | |
| 3990 | |
| 3991 static inline bool IsKeyEqual(Pair kv, Key key) { | |
| 3992 if (kv->Equals(key)) return true; | |
| 3993 | |
| 3994 if (kv->IsLoadIndexed()) { | |
| 3995 if (key->IsStoreIndexed()) { | |
| 3996 LoadIndexedInstr* load_indexed = kv->AsLoadIndexed(); | |
| 3997 StoreIndexedInstr* store_indexed = key->AsStoreIndexed(); | |
| 3998 return load_indexed->array()->Equals(store_indexed->array()) && | |
| 3999 load_indexed->index()->Equals(store_indexed->index()); | |
| 4000 } | |
| 4001 return false; | |
| 4002 } | |
| 4003 | |
| 4004 if (kv->IsLoadStaticField()) { | |
| 4005 if (key->IsStoreStaticField()) { | |
| 4006 LoadStaticFieldInstr* load_static_field = kv->AsLoadStaticField(); | |
| 4007 StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField(); | |
| 4008 return load_static_field->StaticField().raw() == | |
| 4009 store_static_field->field().raw(); | |
| 4010 } | |
| 4011 return false; | |
| 4012 } | |
| 4013 | |
| 4014 if (kv->IsCurrentContext()) { | |
| 4015 return key->IsStoreContext() || key->IsChainContext(); | |
| 4016 } | |
| 4017 | |
| 4018 ASSERT(kv->IsLoadField()); | |
| 4019 LoadFieldInstr* load_field = kv->AsLoadField(); | |
| 4020 if (key->IsStoreVMField()) { | |
| 4021 StoreVMFieldInstr* store_field = key->AsStoreVMField(); | |
| 4022 return load_field->instance()->Equals(store_field->dest()) && | |
| 4023 (load_field->offset_in_bytes() == store_field->offset_in_bytes()); | |
| 4024 } else if (key->IsStoreInstanceField()) { | |
| 4025 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); | |
| 4026 return load_field->instance()->Equals(store_field->instance()) && | |
| 4027 (load_field->offset_in_bytes() == store_field->field().Offset()); | |
| 4028 } | |
| 4029 | |
| 4030 return false; | |
| 4031 } | |
| 4032 }; | |
| 4033 | |
| 4034 | |
| 4035 static AliasedSet* NumberLoadExpressions( | |
| 4036 FlowGraph* graph, | 4269 FlowGraph* graph, |
| 4037 DirectChainedHashMap<LoadKeyValueTrait>* map) { | 4270 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) { |
| 4038 intptr_t expr_id = 0; | |
| 4039 | |
| 4040 // Loads representing different expression ids will be collected and | 4271 // Loads representing different expression ids will be collected and |
| 4041 // used to build per offset kill sets. | 4272 // used to build per offset kill sets. |
| 4042 GrowableArray<Definition*> loads(10); | 4273 ZoneGrowableArray<Place*>* places = new ZoneGrowableArray<Place*>(10); |
| 4043 | 4274 |
| 4275 bool has_loads = false; |
| 4044 for (BlockIterator it = graph->reverse_postorder_iterator(); | 4276 for (BlockIterator it = graph->reverse_postorder_iterator(); |
| 4045 !it.Done(); | 4277 !it.Done(); |
| 4046 it.Advance()) { | 4278 it.Advance()) { |
| 4047 BlockEntryInstr* block = it.Current(); | 4279 BlockEntryInstr* block = it.Current(); |
| 4048 for (ForwardInstructionIterator instr_it(block); | 4280 for (ForwardInstructionIterator instr_it(block); |
| 4049 !instr_it.Done(); | 4281 !instr_it.Done(); |
| 4050 instr_it.Advance()) { | 4282 instr_it.Advance()) { |
| 4051 Definition* defn = instr_it.Current()->AsDefinition(); | 4283 Instruction* instr = instr_it.Current(); |
| 4052 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 4284 |
| 4285 Place place(instr, &has_loads); |
| 4286 if (place.kind() == Place::kNone) { |
| 4053 continue; | 4287 continue; |
| 4054 } | 4288 } |
| 4055 Definition* result = map->Lookup(defn); | 4289 |
| 4290 Place* result = map->Lookup(&place); |
| 4056 if (result == NULL) { | 4291 if (result == NULL) { |
| 4057 map->Insert(defn); | 4292 place.set_id(places->length()); |
| 4058 defn->set_expr_id(expr_id++); | 4293 result = Place::Wrap(place); |
| 4059 loads.Add(defn); | 4294 map->Insert(result); |
| 4060 } else { | 4295 places->Add(result); |
| 4061 defn->set_expr_id(result->expr_id()); | 4296 |
| 4297 if (FLAG_trace_optimization) { |
| 4298 OS::Print("numbering %s as %"Pd"\n", |
| 4299 result->ToCString(), |
| 4300 result->id()); |
| 4301 } |
| 4062 } | 4302 } |
| 4063 | 4303 |
| 4064 if (FLAG_trace_optimization) { | 4304 instr->set_place_id(result->id()); |
| 4065 OS::Print("load v%"Pd" is numbered as %"Pd"\n", | |
| 4066 defn->ssa_temp_index(), | |
| 4067 defn->expr_id()); | |
| 4068 } | |
| 4069 } | 4305 } |
| 4070 } | 4306 } |
| 4071 | 4307 |
| 4308 if (!has_loads) { |
| 4309 return NULL; |
| 4310 } |
| 4311 |
| 4312 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); |
| 4313 |
| 4072 // Build aliasing sets mapping aliases to loads. | 4314 // Build aliasing sets mapping aliases to loads. |
| 4073 AliasedSet* aliased_set = new AliasedSet(expr_id); | 4315 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); |
| 4074 for (intptr_t i = 0; i < loads.length(); i++) { | 4316 for (intptr_t i = 0; i < places->length(); i++) { |
| 4075 Definition* defn = loads[i]; | 4317 Place* place = (*places)[i]; |
| 4076 aliased_set->AddRepresentative(defn); | 4318 aliased_set->AddRepresentative(place); |
| 4077 } | 4319 } |
| 4320 |
| 4078 return aliased_set; | 4321 return aliased_set; |
| 4079 } | 4322 } |
| 4080 | 4323 |
| 4081 | 4324 |
| 4082 class LoadOptimizer : public ValueObject { | 4325 class LoadOptimizer : public ValueObject { |
| 4083 public: | 4326 public: |
| 4084 LoadOptimizer(FlowGraph* graph, | 4327 LoadOptimizer(FlowGraph* graph, |
| 4085 AliasedSet* aliased_set, | 4328 AliasedSet* aliased_set, |
| 4086 DirectChainedHashMap<LoadKeyValueTrait>* map) | 4329 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) |
| 4087 : graph_(graph), | 4330 : graph_(graph), |
| 4088 map_(map), | 4331 map_(map), |
| 4089 aliased_set_(aliased_set), | 4332 aliased_set_(aliased_set), |
| 4090 in_(graph_->preorder().length()), | 4333 in_(graph_->preorder().length()), |
| 4091 out_(graph_->preorder().length()), | 4334 out_(graph_->preorder().length()), |
| 4092 gen_(graph_->preorder().length()), | 4335 gen_(graph_->preorder().length()), |
| 4093 kill_(graph_->preorder().length()), | 4336 kill_(graph_->preorder().length()), |
| 4094 exposed_values_(graph_->preorder().length()), | 4337 exposed_values_(graph_->preorder().length()), |
| 4095 out_values_(graph_->preorder().length()), | 4338 out_values_(graph_->preorder().length()), |
| 4096 phis_(5), | 4339 phis_(5), |
| 4097 worklist_(5), | 4340 worklist_(5), |
| 4098 in_worklist_(NULL), | 4341 in_worklist_(NULL), |
| 4099 forwarded_(false) { | 4342 forwarded_(false) { |
| 4100 const intptr_t num_blocks = graph_->preorder().length(); | 4343 const intptr_t num_blocks = graph_->preorder().length(); |
| 4101 for (intptr_t i = 0; i < num_blocks; i++) { | 4344 for (intptr_t i = 0; i < num_blocks; i++) { |
| 4102 out_.Add(new BitVector(aliased_set_->max_expr_id())); | 4345 out_.Add(NULL); |
| 4103 gen_.Add(new BitVector(aliased_set_->max_expr_id())); | 4346 gen_.Add(new BitVector(aliased_set_->max_place_id())); |
| 4104 kill_.Add(new BitVector(aliased_set_->max_expr_id())); | 4347 kill_.Add(new BitVector(aliased_set_->max_place_id())); |
| 4105 in_.Add(new BitVector(aliased_set_->max_expr_id())); | 4348 in_.Add(new BitVector(aliased_set_->max_place_id())); |
| 4106 | 4349 |
| 4107 exposed_values_.Add(NULL); | 4350 exposed_values_.Add(NULL); |
| 4108 out_values_.Add(NULL); | 4351 out_values_.Add(NULL); |
| 4109 } | 4352 } |
| 4110 } | 4353 } |
| 4111 | 4354 |
| 4112 static bool OptimizeGraph(FlowGraph* graph) { | 4355 static bool OptimizeGraph(FlowGraph* graph) { |
| 4113 ASSERT(FLAG_load_cse); | 4356 ASSERT(FLAG_load_cse); |
| 4357 if (FLAG_trace_load_optimization) { |
| 4358 FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph); |
| 4359 } |
| 4114 | 4360 |
| 4115 DirectChainedHashMap<LoadKeyValueTrait> map; | 4361 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
| 4116 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map); | 4362 AliasedSet* aliased_set = NumberPlaces(graph, &map); |
| 4117 if (!aliased_set->IsEmpty()) { | 4363 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
| 4118 // If any loads were forwarded return true from Optimize to run load | 4364 // If any loads were forwarded return true from Optimize to run load |
| 4119 // forwarding again. This will allow to forward chains of loads. | 4365 // forwarding again. This will allow to forward chains of loads. |
| 4120 // This is especially important for context variables as they are built | 4366 // This is especially important for context variables as they are built |
| 4121 // as loads from loaded context. | 4367 // as loads from loaded context. |
| 4122 // TODO(vegorov): renumber newly discovered congruences during the | 4368 // TODO(vegorov): renumber newly discovered congruences during the |
| 4123 // forwarding to forward chains without running whole pass twice. | 4369 // forwarding to forward chains without running whole pass twice. |
| 4124 LoadOptimizer load_optimizer(graph, aliased_set, &map); | 4370 LoadOptimizer load_optimizer(graph, aliased_set, &map); |
| 4125 return load_optimizer.Optimize(); | 4371 return load_optimizer.Optimize(); |
| 4126 } | 4372 } |
| 4127 return false; | 4373 return false; |
| 4128 } | 4374 } |
| 4129 | 4375 |
| 4130 private: | 4376 private: |
| 4131 bool Optimize() { | 4377 bool Optimize() { |
| 4132 ComputeInitialSets(); | 4378 ComputeInitialSets(); |
| 4379 ComputeOutSets(); |
| 4133 ComputeOutValues(); | 4380 ComputeOutValues(); |
| 4134 if (graph_->is_licm_allowed()) { | 4381 if (graph_->is_licm_allowed()) { |
| 4135 MarkLoopInvariantLoads(); | 4382 MarkLoopInvariantLoads(); |
| 4136 } | 4383 } |
| 4137 ForwardLoads(); | 4384 ForwardLoads(); |
| 4138 EmitPhis(); | 4385 EmitPhis(); |
| 4386 |
| 4387 if (FLAG_trace_load_optimization) { |
| 4388 FlowGraphPrinter::PrintGraph("After LoadOptimizer", graph_); |
| 4389 } |
| 4390 |
| 4139 return forwarded_; | 4391 return forwarded_; |
| 4140 } | 4392 } |
| 4141 | 4393 |
| 4142 // Compute sets of loads generated and killed by each block. | 4394 // Compute sets of loads generated and killed by each block. |
| 4143 // Additionally compute upwards exposed and generated loads for each block. | 4395 // Additionally compute upwards exposed and generated loads for each block. |
| 4144 // Exposed loads are those that can be replaced if a corresponding | 4396 // Exposed loads are those that can be replaced if a corresponding |
| 4145 // reaching load will be found. | 4397 // reaching load will be found. |
| 4146 // Loads that are locally redundant will be replaced as we go through | 4398 // Loads that are locally redundant will be replaced as we go through |
| 4147 // instructions. | 4399 // instructions. |
| 4148 void ComputeInitialSets() { | 4400 void ComputeInitialSets() { |
| 4401 BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id()); |
| 4402 |
| 4149 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 4403 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 4150 !block_it.Done(); | 4404 !block_it.Done(); |
| 4151 block_it.Advance()) { | 4405 block_it.Advance()) { |
| 4152 BlockEntryInstr* block = block_it.Current(); | 4406 BlockEntryInstr* block = block_it.Current(); |
| 4153 const intptr_t preorder_number = block->preorder_number(); | 4407 const intptr_t preorder_number = block->preorder_number(); |
| 4154 | 4408 |
| 4155 BitVector* kill = kill_[preorder_number]; | 4409 BitVector* kill = kill_[preorder_number]; |
| 4156 BitVector* gen = gen_[preorder_number]; | 4410 BitVector* gen = gen_[preorder_number]; |
| 4157 | 4411 |
| 4158 ZoneGrowableArray<Definition*>* exposed_values = NULL; | 4412 ZoneGrowableArray<Definition*>* exposed_values = NULL; |
| 4159 ZoneGrowableArray<Definition*>* out_values = NULL; | 4413 ZoneGrowableArray<Definition*>* out_values = NULL; |
| 4160 | 4414 |
| 4161 for (ForwardInstructionIterator instr_it(block); | 4415 for (ForwardInstructionIterator instr_it(block); |
| 4162 !instr_it.Done(); | 4416 !instr_it.Done(); |
| 4163 instr_it.Advance()) { | 4417 instr_it.Advance()) { |
| 4164 Instruction* instr = instr_it.Current(); | 4418 Instruction* instr = instr_it.Current(); |
| 4165 | 4419 |
| 4166 const Alias alias = aliased_set_->ComputeAliasForStore(instr); | 4420 const Alias alias = aliased_set_->ComputeAliasForStore(instr); |
| 4167 if (!alias.IsNone()) { | 4421 if (!alias.IsNone()) { |
| 4168 // Interfering stores kill only loads from the same offset. | 4422 // Interfering stores kill only loads from the same offset. |
| 4169 if (aliased_set_->Contains(alias)) { | 4423 BitVector* killed = aliased_set_->Get(alias); |
| 4170 BitVector* killed = aliased_set_->Get(alias); | 4424 |
| 4425 if (killed != NULL) { |
| 4171 kill->AddAll(killed); | 4426 kill->AddAll(killed); |
| 4172 // There is no need to clear out_values when clearing GEN set | 4427 // There is no need to clear out_values when clearing GEN set |
| 4173 // because only those values that are in the GEN set | 4428 // because only those values that are in the GEN set |
| 4174 // will ever be used. | 4429 // will ever be used. |
| 4175 gen->RemoveAll(killed); | 4430 gen->RemoveAll(killed); |
| 4431 } |
| 4176 | 4432 |
| 4177 // Only forward stores to normal arrays and float64 arrays | 4433 // Only forward stores to normal arrays and float64 arrays |
| 4178 // to loads because other array stores (intXX/uintXX/float32) | 4434 // to loads because other array stores (intXX/uintXX/float32) |
| 4179 // may implicitly convert the value stored. | 4435 // may implicitly convert the value stored. |
| 4180 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); | 4436 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); |
| 4181 if (array_store == NULL || | 4437 if (array_store == NULL || |
| 4182 array_store->class_id() == kArrayCid || | 4438 array_store->class_id() == kArrayCid || |
| 4183 array_store->class_id() == kTypedDataFloat64ArrayCid) { | 4439 array_store->class_id() == kTypedDataFloat64ArrayCid) { |
| 4184 Definition* load = map_->Lookup(instr); | 4440 bool is_load = false; |
| 4185 if (load != NULL) { | 4441 Place store_place(instr, &is_load); |
| 4186 // Store has a corresponding numbered load. Try forwarding | 4442 ASSERT(!is_load); |
| 4187 // stored value to it. | 4443 Place* place = map_->Lookup(&store_place); |
| 4188 gen->Add(load->expr_id()); | 4444 if (place != NULL) { |
| 4189 if (out_values == NULL) out_values = CreateBlockOutValues(); | 4445 // Store has a corresponding numbered place that might have a |
| 4190 (*out_values)[load->expr_id()] = GetStoredValue(instr); | 4446 // load. Try forwarding stored value to it. |
| 4191 } | 4447 gen->Add(place->id()); |
| 4448 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 4449 (*out_values)[place->id()] = GetStoredValue(instr); |
| 4192 } | 4450 } |
| 4193 } | 4451 } |
| 4452 |
| 4194 ASSERT(!instr->IsDefinition() || | 4453 ASSERT(!instr->IsDefinition() || |
| 4195 !IsLoadEliminationCandidate(instr->AsDefinition())); | 4454 !IsLoadEliminationCandidate(instr->AsDefinition())); |
| 4196 continue; | 4455 continue; |
| 4197 } | 4456 } |
| 4198 | 4457 |
| 4199 // If instruction has effects then kill all loads affected. | 4458 // If instruction has effects then kill all loads affected. |
| 4200 if (!instr->Effects().IsNone()) { | 4459 if (!instr->Effects().IsNone()) { |
| 4201 kill->AddAll(aliased_set_->aliased_by_effects()); | 4460 kill->AddAll(aliased_set_->aliased_by_effects()); |
| 4202 // There is no need to clear out_values when removing values from GEN | 4461 // There is no need to clear out_values when removing values from GEN |
| 4203 // set because only those values that are in the GEN set | 4462 // set because only those values that are in the GEN set |
| (...skipping 29 matching lines...) Expand all Loading... |
| 4233 use != NULL; | 4492 use != NULL; |
| 4234 use = use->next_use()) { | 4493 use = use->next_use()) { |
| 4235 // Look for all immediate loads from this object. | 4494 // Look for all immediate loads from this object. |
| 4236 if (use->use_index() != 0) { | 4495 if (use->use_index() != 0) { |
| 4237 continue; | 4496 continue; |
| 4238 } | 4497 } |
| 4239 | 4498 |
| 4240 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 4499 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
| 4241 if (load != NULL) { | 4500 if (load != NULL) { |
| 4242 // Found a load. Initialize current value of the field to null. | 4501 // Found a load. Initialize current value of the field to null. |
| 4243 gen->Add(load->expr_id()); | 4502 gen->Add(load->place_id()); |
| 4244 if (out_values == NULL) out_values = CreateBlockOutValues(); | 4503 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 4245 (*out_values)[load->expr_id()] = graph_->constant_null(); | 4504 (*out_values)[load->place_id()] = graph_->constant_null(); |
| 4246 } | 4505 } |
| 4247 } | 4506 } |
| 4248 continue; | 4507 continue; |
| 4249 } | 4508 } |
| 4250 | 4509 |
| 4251 if (!IsLoadEliminationCandidate(defn)) { | 4510 if (!IsLoadEliminationCandidate(defn)) { |
| 4252 continue; | 4511 continue; |
| 4253 } | 4512 } |
| 4254 | 4513 |
| 4255 const intptr_t expr_id = defn->expr_id(); | 4514 const intptr_t place_id = defn->place_id(); |
| 4256 if (gen->Contains(expr_id)) { | 4515 if (gen->Contains(place_id)) { |
| 4257 // This is a locally redundant load. | 4516 // This is a locally redundant load. |
| 4258 ASSERT((out_values != NULL) && ((*out_values)[expr_id] != NULL)); | 4517 ASSERT((out_values != NULL) && ((*out_values)[place_id] != NULL)); |
| 4259 | 4518 |
| 4260 Definition* replacement = (*out_values)[expr_id]; | 4519 Definition* replacement = (*out_values)[place_id]; |
| 4261 EnsureSSATempIndex(graph_, defn, replacement); | 4520 EnsureSSATempIndex(graph_, defn, replacement); |
| 4262 if (FLAG_trace_optimization) { | 4521 if (FLAG_trace_optimization) { |
| 4263 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", | 4522 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", |
| 4264 defn->ssa_temp_index(), | 4523 defn->ssa_temp_index(), |
| 4265 replacement->ssa_temp_index()); | 4524 replacement->ssa_temp_index()); |
| 4266 } | 4525 } |
| 4267 | 4526 |
| 4268 defn->ReplaceUsesWith(replacement); | 4527 defn->ReplaceUsesWith(replacement); |
| 4269 instr_it.RemoveCurrentFromGraph(); | 4528 instr_it.RemoveCurrentFromGraph(); |
| 4270 forwarded_ = true; | 4529 forwarded_ = true; |
| 4271 continue; | 4530 continue; |
| 4272 } else if (!kill->Contains(expr_id)) { | 4531 } else if (!kill->Contains(place_id)) { |
| 4273 // This is an exposed load: it is the first representative of a | 4532 // This is an exposed load: it is the first representative of a |
| 4274 // given expression id and it is not killed on the path from | 4533 // given expression id and it is not killed on the path from |
| 4275 // the block entry. | 4534 // the block entry. |
| 4276 if (exposed_values == NULL) { | 4535 if (exposed_values == NULL) { |
| 4277 static const intptr_t kMaxExposedValuesInitialSize = 5; | 4536 static const intptr_t kMaxExposedValuesInitialSize = 5; |
| 4278 exposed_values = new ZoneGrowableArray<Definition*>( | 4537 exposed_values = new ZoneGrowableArray<Definition*>( |
| 4279 Utils::Minimum(kMaxExposedValuesInitialSize, | 4538 Utils::Minimum(kMaxExposedValuesInitialSize, |
| 4280 aliased_set_->max_expr_id())); | 4539 aliased_set_->max_place_id())); |
| 4281 } | 4540 } |
| 4282 | 4541 |
| 4283 exposed_values->Add(defn); | 4542 exposed_values->Add(defn); |
| 4284 } | 4543 } |
| 4285 | 4544 |
| 4286 gen->Add(expr_id); | 4545 gen->Add(place_id); |
| 4287 | 4546 |
| 4288 if (out_values == NULL) out_values = CreateBlockOutValues(); | 4547 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 4289 (*out_values)[expr_id] = defn; | 4548 (*out_values)[place_id] = defn; |
| 4290 } | 4549 } |
| 4291 | 4550 |
| 4292 out_[preorder_number]->CopyFrom(gen); | 4551 PhiPlaceMoves::MovesList phi_moves = |
| 4552 aliased_set_->phi_moves()->GetOutgoingMoves(block); |
| 4553 if (phi_moves != NULL) { |
| 4554 PerformPhiMoves(phi_moves, gen, forwarded_loads); |
| 4555 } |
| 4556 |
| 4293 exposed_values_[preorder_number] = exposed_values; | 4557 exposed_values_[preorder_number] = exposed_values; |
| 4294 out_values_[preorder_number] = out_values; | 4558 out_values_[preorder_number] = out_values; |
| 4295 } | 4559 } |
| 4296 } | 4560 } |
| 4297 | 4561 |
| 4298 // Compute OUT sets and corresponding out_values mappings by propagating them | 4562 static void PerformPhiMoves(PhiPlaceMoves::MovesList phi_moves, |
| 4299 // iteratively until fix point is reached. | 4563 BitVector* out, |
| 4300 // No replacement is done at this point and thus any out_value[expr_id] is | 4564 BitVector* forwarded_loads) { |
| 4301 // changed at most once: from NULL to an actual value. | 4565 forwarded_loads->Clear(); |
| 4302 // When merging incoming loads we might need to create a phi. | 4566 |
| 4303 // These phis are not inserted at the graph immediately because some of them | 4567 for (intptr_t i = 0; i < phi_moves->length(); i++) { |
| 4304 // might become redundant after load forwarding is done. | 4568 const intptr_t from = (*phi_moves)[i].from(); |
| 4305 void ComputeOutValues() { | 4569 const intptr_t to = (*phi_moves)[i].to(); |
| 4306 BitVector* temp = new BitVector(aliased_set_->max_expr_id()); | 4570 if (from == to) continue; |
| 4571 |
| 4572 if (out->Contains(from)) { |
| 4573 forwarded_loads->Add(to); |
| 4574 } |
| 4575 } |
| 4576 |
| 4577 for (intptr_t i = 0; i < phi_moves->length(); i++) { |
| 4578 const intptr_t from = (*phi_moves)[i].from(); |
| 4579 const intptr_t to = (*phi_moves)[i].to(); |
| 4580 if (from == to) continue; |
| 4581 |
| 4582 out->Remove(to); |
| 4583 } |
| 4584 |
| 4585 out->AddAll(forwarded_loads); |
| 4586 } |
| 4587 |
| 4588 // Compute OUT sets by propagating them iteratively until fix point |
| 4589 // is reached. |
| 4590 void ComputeOutSets() { |
| 4591 BitVector* temp = new BitVector(aliased_set_->max_place_id()); |
| 4592 BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id()); |
| 4307 | 4593 |
| 4308 bool changed = true; | 4594 bool changed = true; |
| 4309 while (changed) { | 4595 while (changed) { |
| 4310 changed = false; | 4596 changed = false; |
| 4311 | 4597 |
| 4312 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 4598 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 4313 !block_it.Done(); | 4599 !block_it.Done(); |
| 4314 block_it.Advance()) { | 4600 block_it.Advance()) { |
| 4315 BlockEntryInstr* block = block_it.Current(); | 4601 BlockEntryInstr* block = block_it.Current(); |
| 4316 | 4602 |
| 4317 const intptr_t preorder_number = block->preorder_number(); | 4603 const intptr_t preorder_number = block->preorder_number(); |
| 4318 | 4604 |
| 4319 BitVector* block_in = in_[preorder_number]; | 4605 BitVector* block_in = in_[preorder_number]; |
| 4320 BitVector* block_out = out_[preorder_number]; | 4606 BitVector* block_out = out_[preorder_number]; |
| 4321 BitVector* block_kill = kill_[preorder_number]; | 4607 BitVector* block_kill = kill_[preorder_number]; |
| 4322 BitVector* block_gen = gen_[preorder_number]; | 4608 BitVector* block_gen = gen_[preorder_number]; |
| 4323 | 4609 |
| 4324 if (FLAG_trace_optimization) { | |
| 4325 OS::Print("B%"Pd"", block->block_id()); | |
| 4326 block_in->Print(); | |
| 4327 block_out->Print(); | |
| 4328 block_kill->Print(); | |
| 4329 block_gen->Print(); | |
| 4330 OS::Print("\n"); | |
| 4331 } | |
| 4332 | |
| 4333 ZoneGrowableArray<Definition*>* block_out_values = | |
| 4334 out_values_[preorder_number]; | |
| 4335 | |
| 4336 // Compute block_in as the intersection of all out(p) where p | 4610 // Compute block_in as the intersection of all out(p) where p |
| 4337 // is a predecessor of the current block. | 4611 // is a predecessor of the current block. |
| 4338 if (block->IsGraphEntry()) { | 4612 if (block->IsGraphEntry()) { |
| 4339 temp->Clear(); | 4613 temp->Clear(); |
| 4340 } else { | 4614 } else { |
| 4341 // TODO(vegorov): this can be optimized for the case of a single | |
| 4342 // predecessor. | |
| 4343 // TODO(vegorov): this can be reordered to reduce amount of operations | |
| 4344 // temp->CopyFrom(first_predecessor) | |
| 4345 temp->SetAll(); | 4615 temp->SetAll(); |
| 4346 ASSERT(block->PredecessorCount() > 0); | 4616 ASSERT(block->PredecessorCount() > 0); |
| 4347 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 4617 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 4348 BlockEntryInstr* pred = block->PredecessorAt(i); | 4618 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 4349 BitVector* pred_out = out_[pred->preorder_number()]; | 4619 BitVector* pred_out = out_[pred->preorder_number()]; |
| 4350 temp->Intersect(pred_out); | 4620 if (pred_out != NULL) { |
| 4621 temp->Intersect(pred_out); |
| 4622 } |
| 4351 } | 4623 } |
| 4352 } | 4624 } |
| 4353 | 4625 |
| 4354 if (!temp->Equals(*block_in)) { | 4626 if (!temp->Equals(*block_in) || (block_out == NULL)) { |
| 4355 // If IN set has changed propagate the change to OUT set. | 4627 // If IN set has changed propagate the change to OUT set. |
| 4356 block_in->CopyFrom(temp); | 4628 block_in->CopyFrom(temp); |
| 4357 if (block_out->KillAndAdd(block_kill, block_in)) { | |
| 4358 // If OUT set has changed then we have new values available out of | |
| 4359 // the block. Compute these values creating phi where necessary. | |
| 4360 for (BitVector::Iterator it(block_out); | |
| 4361 !it.Done(); | |
| 4362 it.Advance()) { | |
| 4363 const intptr_t expr_id = it.Current(); | |
| 4364 | 4629 |
| 4365 if (block_out_values == NULL) { | 4630 temp->RemoveAll(block_kill); |
| 4366 out_values_[preorder_number] = block_out_values = | 4631 temp->AddAll(block_gen); |
| 4367 CreateBlockOutValues(); | |
| 4368 } | |
| 4369 | 4632 |
| 4370 if ((*block_out_values)[expr_id] == NULL) { | 4633 PhiPlaceMoves::MovesList phi_moves = |
| 4371 ASSERT(block->PredecessorCount() > 0); | 4634 aliased_set_->phi_moves()->GetOutgoingMoves(block); |
| 4372 (*block_out_values)[expr_id] = | 4635 if (phi_moves != NULL) { |
| 4373 MergeIncomingValues(block, expr_id); | 4636 PerformPhiMoves(phi_moves, temp, forwarded_loads); |
| 4374 } | 4637 } |
| 4638 |
| 4639 if ((block_out == NULL) || !block_out->Equals(*temp)) { |
| 4640 if (block_out == NULL) { |
| 4641 block_out = out_[preorder_number] = |
| 4642 new BitVector(aliased_set_->max_place_id()); |
| 4375 } | 4643 } |
| 4644 block_out->CopyFrom(temp); |
| 4376 changed = true; | 4645 changed = true; |
| 4377 } | 4646 } |
| 4378 } | 4647 } |
| 4379 | |
| 4380 if (FLAG_trace_optimization) { | |
| 4381 OS::Print("after B%"Pd"", block->block_id()); | |
| 4382 block_in->Print(); | |
| 4383 block_out->Print(); | |
| 4384 block_kill->Print(); | |
| 4385 block_gen->Print(); | |
| 4386 OS::Print("\n"); | |
| 4387 } | |
| 4388 } | 4648 } |
| 4389 } | 4649 } |
| 4390 } | 4650 } |
| 4391 | 4651 |
| 4652 // Compute out_values mappings by propagating them in reverse postorder once |
| 4653 // through the graph. Generate phis on back edges where eager merge is |
| 4654 // impossible. |
| 4655 // No replacement is done at this point and thus any out_value[place_id] is |
| 4656 // changed at most once: from NULL to an actual value. |
| 4657 // When merging incoming loads we might need to create a phi. |
| 4658 // These phis are not inserted at the graph immediately because some of them |
| 4659 // might become redundant after load forwarding is done. |
| 4660 void ComputeOutValues() { |
| 4661 GrowableArray<PhiInstr*> pending_phis(5); |
| 4662 ZoneGrowableArray<Definition*>* temp_forwarded_values = NULL; |
| 4663 |
| 4664 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 4665 !block_it.Done(); |
| 4666 block_it.Advance()) { |
| 4667 BlockEntryInstr* block = block_it.Current(); |
| 4668 |
| 4669 const bool can_merge_eagerly = CanMergeEagerly(block); |
| 4670 |
| 4671 const intptr_t preorder_number = block->preorder_number(); |
| 4672 |
| 4673 ZoneGrowableArray<Definition*>* block_out_values = |
| 4674 out_values_[preorder_number]; |
| 4675 |
| 4676 |
| 4677 // If OUT set has changed then we have new values available out of |
| 4678 // the block. Compute these values creating phi where necessary. |
| 4679 for (BitVector::Iterator it(out_[preorder_number]); |
| 4680 !it.Done(); |
| 4681 it.Advance()) { |
| 4682 const intptr_t place_id = it.Current(); |
| 4683 |
| 4684 if (block_out_values == NULL) { |
| 4685 out_values_[preorder_number] = block_out_values = |
| 4686 CreateBlockOutValues(); |
| 4687 } |
| 4688 |
| 4689 if ((*block_out_values)[place_id] == NULL) { |
| 4690 ASSERT(block->PredecessorCount() > 0); |
| 4691 Definition* in_value = can_merge_eagerly ? |
| 4692 MergeIncomingValues(block, place_id) : NULL; |
| 4693 if ((in_value == NULL) && |
| 4694 (in_[preorder_number]->Contains(place_id))) { |
| 4695 PhiInstr* phi = new PhiInstr(block->AsJoinEntry(), |
| 4696 block->PredecessorCount()); |
| 4697 phi->set_place_id(place_id); |
| 4698 pending_phis.Add(phi); |
| 4699 in_value = phi; |
| 4700 } |
| 4701 (*block_out_values)[place_id] = in_value; |
| 4702 } |
| 4703 } |
| 4704 |
| 4705 // If the block has outgoing phi moves perform them. Use temporary list |
| 4706 // of values to ensure that cyclic moves are performed correctly. |
| 4707 PhiPlaceMoves::MovesList phi_moves = |
| 4708 aliased_set_->phi_moves()->GetOutgoingMoves(block); |
| 4709 if ((phi_moves != NULL) && (block_out_values != NULL)) { |
| 4710 if (temp_forwarded_values == NULL) { |
| 4711 temp_forwarded_values = CreateBlockOutValues(); |
| 4712 } |
| 4713 |
| 4714 for (intptr_t i = 0; i < phi_moves->length(); i++) { |
| 4715 const intptr_t from = (*phi_moves)[i].from(); |
| 4716 const intptr_t to = (*phi_moves)[i].to(); |
| 4717 if (from == to) continue; |
| 4718 |
| 4719 (*temp_forwarded_values)[to] = (*block_out_values)[from]; |
| 4720 } |
| 4721 |
| 4722 for (intptr_t i = 0; i < phi_moves->length(); i++) { |
| 4723 const intptr_t from = (*phi_moves)[i].from(); |
| 4724 const intptr_t to = (*phi_moves)[i].to(); |
| 4725 if (from == to) continue; |
| 4726 |
| 4727 (*block_out_values)[to] = (*temp_forwarded_values)[to]; |
| 4728 } |
| 4729 } |
| 4730 |
| 4731 if (FLAG_trace_load_optimization) { |
| 4732 OS::Print("B%"Pd"\n", block->block_id()); |
| 4733 OS::Print(" IN: "); |
| 4734 aliased_set_->PrintSet(in_[preorder_number]); |
| 4735 OS::Print("\n"); |
| 4736 |
| 4737 OS::Print(" KILL: "); |
| 4738 aliased_set_->PrintSet(kill_[preorder_number]); |
| 4739 OS::Print("\n"); |
| 4740 |
| 4741 OS::Print(" OUT: "); |
| 4742 aliased_set_->PrintSet(out_[preorder_number]); |
| 4743 OS::Print("\n"); |
| 4744 } |
| 4745 } |
| 4746 |
| 4747 // All blocks were visited. Fill pending phis with inputs |
| 4748 // that flow on back edges. |
| 4749 for (intptr_t i = 0; i < pending_phis.length(); i++) { |
| 4750 FillPhiInputs(pending_phis[i]); |
| 4751 } |
| 4752 } |
| 4753 |
| 4754 bool CanMergeEagerly(BlockEntryInstr* block) { |
| 4755 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 4756 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 4757 if (pred->postorder_number() < block->postorder_number()) { |
| 4758 return false; |
| 4759 } |
| 4760 } |
| 4761 return true; |
| 4762 } |
| 4763 |
| 4392 void MarkLoopInvariantLoads() { | 4764 void MarkLoopInvariantLoads() { |
| 4393 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = | 4765 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = |
| 4394 graph_->loop_headers(); | 4766 graph_->loop_headers(); |
| 4395 | 4767 |
| 4396 ZoneGrowableArray<BitVector*>* invariant_loads = | 4768 ZoneGrowableArray<BitVector*>* invariant_loads = |
| 4397 new ZoneGrowableArray<BitVector*>(loop_headers.length()); | 4769 new ZoneGrowableArray<BitVector*>(loop_headers.length()); |
| 4398 | 4770 |
| 4399 for (intptr_t i = 0; i < loop_headers.length(); i++) { | 4771 for (intptr_t i = 0; i < loop_headers.length(); i++) { |
| 4400 BlockEntryInstr* header = loop_headers[i]; | 4772 BlockEntryInstr* header = loop_headers[i]; |
| 4401 BlockEntryInstr* pre_header = FindPreHeader(header); | 4773 BlockEntryInstr* pre_header = FindPreHeader(header); |
| 4402 if (pre_header == NULL) { | 4774 if (pre_header == NULL) { |
| 4403 invariant_loads->Add(NULL); | 4775 invariant_loads->Add(NULL); |
| 4404 continue; | 4776 continue; |
| 4405 } | 4777 } |
| 4406 | 4778 |
| 4407 BitVector* loop_gen = new BitVector(aliased_set_->max_expr_id()); | 4779 BitVector* loop_gen = new BitVector(aliased_set_->max_place_id()); |
| 4408 for (BitVector::Iterator loop_it(header->loop_info()); | 4780 for (BitVector::Iterator loop_it(header->loop_info()); |
| 4409 !loop_it.Done(); | 4781 !loop_it.Done(); |
| 4410 loop_it.Advance()) { | 4782 loop_it.Advance()) { |
| 4411 const intptr_t preorder_number = loop_it.Current(); | 4783 const intptr_t preorder_number = loop_it.Current(); |
| 4412 loop_gen->AddAll(gen_[preorder_number]); | 4784 loop_gen->AddAll(gen_[preorder_number]); |
| 4413 } | 4785 } |
| 4414 | 4786 |
| 4415 for (BitVector::Iterator loop_it(header->loop_info()); | 4787 for (BitVector::Iterator loop_it(header->loop_info()); |
| 4416 !loop_it.Done(); | 4788 !loop_it.Done(); |
| 4417 loop_it.Advance()) { | 4789 loop_it.Advance()) { |
| 4418 const intptr_t preorder_number = loop_it.Current(); | 4790 const intptr_t preorder_number = loop_it.Current(); |
| 4419 loop_gen->RemoveAll(kill_[preorder_number]); | 4791 loop_gen->RemoveAll(kill_[preorder_number]); |
| 4420 } | 4792 } |
| 4421 | 4793 |
| 4422 if (FLAG_trace_optimization) { | 4794 if (FLAG_trace_optimization) { |
| 4423 for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) { | 4795 for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) { |
| 4424 OS::Print("load %"Pd" is loop invariant for B%"Pd"\n", | 4796 OS::Print("place %s is loop invariant for B%"Pd"\n", |
| 4425 it.Current(), | 4797 aliased_set_->places()[it.Current()]->ToCString(), |
| 4426 header->block_id()); | 4798 header->block_id()); |
| 4427 } | 4799 } |
| 4428 } | 4800 } |
| 4429 | 4801 |
| 4430 invariant_loads->Add(loop_gen); | 4802 invariant_loads->Add(loop_gen); |
| 4431 } | 4803 } |
| 4432 | 4804 |
| 4433 graph_->set_loop_invariant_loads(invariant_loads); | 4805 graph_->set_loop_invariant_loads(invariant_loads); |
| 4434 } | 4806 } |
| 4435 | 4807 |
| 4436 // Compute incoming value for the given expression id. | 4808 // Compute incoming value for the given expression id. |
| 4437 // Will create a phi if different values are incoming from multiple | 4809 // Will create a phi if different values are incoming from multiple |
| 4438 // predecessors. | 4810 // predecessors. |
| 4439 Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t expr_id) { | 4811 Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t place_id) { |
| 4440 // First check if the same value is coming in from all predecessors. | 4812 // First check if the same value is coming in from all predecessors. |
| 4813 static Definition* const kDifferentValuesMarker = |
| 4814 reinterpret_cast<Definition*>(-1); |
| 4441 Definition* incoming = NULL; | 4815 Definition* incoming = NULL; |
| 4442 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 4816 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 4443 BlockEntryInstr* pred = block->PredecessorAt(i); | 4817 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 4444 ZoneGrowableArray<Definition*>* pred_out_values = | 4818 ZoneGrowableArray<Definition*>* pred_out_values = |
| 4445 out_values_[pred->preorder_number()]; | 4819 out_values_[pred->preorder_number()]; |
| 4446 if (incoming == NULL) { | 4820 if ((pred_out_values == NULL) || ((*pred_out_values)[place_id] == NULL)) { |
| 4447 incoming = (*pred_out_values)[expr_id]; | 4821 return NULL; |
| 4448 } else if (incoming != (*pred_out_values)[expr_id]) { | 4822 } else if (incoming == NULL) { |
| 4449 incoming = NULL; | 4823 incoming = (*pred_out_values)[place_id]; |
| 4450 break; | 4824 } else if (incoming != (*pred_out_values)[place_id]) { |
| 4825 incoming = kDifferentValuesMarker; |
| 4451 } | 4826 } |
| 4452 } | 4827 } |
| 4453 | 4828 |
| 4454 if (incoming != NULL) { | 4829 if (incoming != kDifferentValuesMarker) { |
| 4830 ASSERT(incoming != NULL); |
| 4455 return incoming; | 4831 return incoming; |
| 4456 } | 4832 } |
| 4457 | 4833 |
| 4458 // Incoming values are different. Phi is required to merge. | 4834 // Incoming values are different. Phi is required to merge. |
| 4459 PhiInstr* phi = new PhiInstr( | 4835 PhiInstr* phi = new PhiInstr( |
| 4460 block->AsJoinEntry(), block->PredecessorCount()); | 4836 block->AsJoinEntry(), block->PredecessorCount()); |
| 4837 phi->set_place_id(place_id); |
| 4838 FillPhiInputs(phi); |
| 4839 return phi; |
| 4840 } |
| 4841 |
| 4842 void FillPhiInputs(PhiInstr* phi) { |
| 4843 BlockEntryInstr* block = phi->GetBlock(); |
| 4844 const intptr_t place_id = phi->place_id(); |
| 4461 | 4845 |
| 4462 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 4846 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 4463 BlockEntryInstr* pred = block->PredecessorAt(i); | 4847 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 4464 ZoneGrowableArray<Definition*>* pred_out_values = | 4848 ZoneGrowableArray<Definition*>* pred_out_values = |
| 4465 out_values_[pred->preorder_number()]; | 4849 out_values_[pred->preorder_number()]; |
| 4466 ASSERT((*pred_out_values)[expr_id] != NULL); | 4850 ASSERT((*pred_out_values)[place_id] != NULL); |
| 4467 | 4851 |
| 4468 // Sets of outgoing values are not linked into use lists so | 4852 // Sets of outgoing values are not linked into use lists so |
| 4469 // they might contain values that were replaced and removed | 4853 // they might contain values that were replaced and removed |
| 4470 // from the graph by this iteration. | 4854 // from the graph by this iteration. |
| 4471 // To prevent using them we additionally mark definitions themselves | 4855 // To prevent using them we additionally mark definitions themselves |
| 4472 // as replaced and store a pointer to the replacement. | 4856 // as replaced and store a pointer to the replacement. |
| 4473 Definition* replacement = (*pred_out_values)[expr_id]->Replacement(); | 4857 Definition* replacement = (*pred_out_values)[place_id]->Replacement(); |
| 4474 Value* input = new Value(replacement); | 4858 Value* input = new Value(replacement); |
| 4475 phi->SetInputAt(i, input); | 4859 phi->SetInputAt(i, input); |
| 4476 replacement->AddInputUse(input); | 4860 replacement->AddInputUse(input); |
| 4477 } | 4861 } |
| 4478 | 4862 |
| 4479 phi->set_ssa_temp_index(graph_->alloc_ssa_temp_index()); | 4863 phi->set_ssa_temp_index(graph_->alloc_ssa_temp_index()); |
| 4480 phis_.Add(phi); // Postpone phi insertion until after load forwarding. | 4864 phis_.Add(phi); // Postpone phi insertion until after load forwarding. |
| 4481 | 4865 |
| 4482 return phi; | 4866 if (FLAG_trace_load_optimization) { |
| 4867 OS::Print("created pending phi %s for %s at B%"Pd"\n", |
| 4868 phi->ToCString(), |
| 4869 aliased_set_->places()[place_id]->ToCString(), |
| 4870 block->block_id()); |
| 4871 } |
| 4483 } | 4872 } |
| 4484 | 4873 |
| 4485 // Iterate over basic blocks and replace exposed loads with incoming | 4874 // Iterate over basic blocks and replace exposed loads with incoming |
| 4486 // values. | 4875 // values. |
| 4487 void ForwardLoads() { | 4876 void ForwardLoads() { |
| 4488 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 4877 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 4489 !block_it.Done(); | 4878 !block_it.Done(); |
| 4490 block_it.Advance()) { | 4879 block_it.Advance()) { |
| 4491 BlockEntryInstr* block = block_it.Current(); | 4880 BlockEntryInstr* block = block_it.Current(); |
| 4492 | 4881 |
| 4493 ZoneGrowableArray<Definition*>* loads = | 4882 ZoneGrowableArray<Definition*>* loads = |
| 4494 exposed_values_[block->preorder_number()]; | 4883 exposed_values_[block->preorder_number()]; |
| 4495 if (loads == NULL) continue; // No exposed loads. | 4884 if (loads == NULL) continue; // No exposed loads. |
| 4496 | 4885 |
| 4497 BitVector* in = in_[block->preorder_number()]; | 4886 BitVector* in = in_[block->preorder_number()]; |
| 4498 | 4887 |
| 4499 for (intptr_t i = 0; i < loads->length(); i++) { | 4888 for (intptr_t i = 0; i < loads->length(); i++) { |
| 4500 Definition* load = (*loads)[i]; | 4889 Definition* load = (*loads)[i]; |
| 4501 if (!in->Contains(load->expr_id())) continue; // No incoming value. | 4890 if (!in->Contains(load->place_id())) continue; // No incoming value. |
| 4502 | 4891 |
| 4503 Definition* replacement = MergeIncomingValues(block, load->expr_id()); | 4892 Definition* replacement = MergeIncomingValues(block, load->place_id()); |
| 4893 ASSERT(replacement != NULL); |
| 4504 | 4894 |
| 4505 // Sets of outgoing values are not linked into use lists so | 4895 // Sets of outgoing values are not linked into use lists so |
| 4506 // they might contain values that were replace and removed | 4896 // they might contain values that were replace and removed |
| 4507 // from the graph by this iteration. | 4897 // from the graph by this iteration. |
| 4508 // To prevent using them we additionally mark definitions themselves | 4898 // To prevent using them we additionally mark definitions themselves |
| 4509 // as replaced and store a pointer to the replacement. | 4899 // as replaced and store a pointer to the replacement. |
| 4510 replacement = replacement->Replacement(); | 4900 replacement = replacement->Replacement(); |
| 4511 | 4901 |
| 4512 if (load != replacement) { | 4902 if (load != replacement) { |
| 4513 EnsureSSATempIndex(graph_, load, replacement); | 4903 EnsureSSATempIndex(graph_, load, replacement); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4573 // All phis in the worklist are redundant and have the same computed | 4963 // All phis in the worklist are redundant and have the same computed |
| 4574 // value on all code paths. | 4964 // value on all code paths. |
| 4575 ASSERT(value != NULL); | 4965 ASSERT(value != NULL); |
| 4576 for (intptr_t i = 0; i < worklist_.length(); i++) { | 4966 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 4577 worklist_[i]->ReplaceUsesWith(value); | 4967 worklist_[i]->ReplaceUsesWith(value); |
| 4578 } | 4968 } |
| 4579 | 4969 |
| 4580 return true; | 4970 return true; |
| 4581 } | 4971 } |
| 4582 | 4972 |
| 4973 bool AddPhiPairToWorklist(PhiInstr* a, PhiInstr* b) { |
| 4974 // Can't compare two phis from different blocks. |
| 4975 if (a->block() != b->block()) { |
| 4976 return false; |
| 4977 } |
| 4978 |
| 4979 // If a is already in the worklist check if it is being compared to b. |
| 4980 // Give up if it is not. |
| 4981 if (in_worklist_->Contains(a->ssa_temp_index())) { |
| 4982 for (intptr_t i = 0; i < worklist_.length(); i += 2) { |
| 4983 if (a == worklist_[i]) { |
| 4984 return (b == worklist_[i + 1]); |
| 4985 } |
| 4986 } |
| 4987 UNREACHABLE(); |
| 4988 } |
| 4989 |
| 4990 worklist_.Add(a); |
| 4991 worklist_.Add(b); |
| 4992 in_worklist_->Add(a->ssa_temp_index()); |
| 4993 return true; |
| 4994 } |
| 4995 |
| 4996 // Replace the given phi with another if they are equal. |
| 4997 // Returns true if succeeds. |
| 4998 bool ReplacePhiWith(PhiInstr* phi, PhiInstr* replacement) { |
| 4999 ASSERT(phi->InputCount() == replacement->InputCount()); |
| 5000 ASSERT(phi->block() == replacement->block()); |
| 5001 |
| 5002 worklist_.Clear(); |
| 5003 if (in_worklist_ == NULL) { |
| 5004 in_worklist_ = new BitVector(graph_->current_ssa_temp_index()); |
| 5005 } else { |
| 5006 in_worklist_->Clear(); |
| 5007 } |
| 5008 |
| 5009 // During the comparison worklist contains pairs of phis to be compared. |
| 5010 AddPhiPairToWorklist(phi, replacement); |
| 5011 |
| 5012 // Process the worklist. It might grow during each comparison step. |
| 5013 for (intptr_t i = 0; i < worklist_.length(); i += 2) { |
| 5014 PhiInstr* a = worklist_[i]; |
| 5015 PhiInstr* b = worklist_[i + 1]; |
| 5016 |
| 5017 // Compare phi inputs. |
| 5018 for (intptr_t j = 0; j < a->InputCount(); j++) { |
| 5019 Definition* inputA = a->InputAt(j)->definition(); |
| 5020 Definition* inputB = b->InputAt(j)->definition(); |
| 5021 |
| 5022 if (inputA != inputB) { |
| 5023 // If inputs are unequal by they are phis then add them to |
| 5024 // the worklist for recursive comparison. |
| 5025 if (inputA->IsPhi() && inputB->IsPhi() && |
| 5026 AddPhiPairToWorklist(inputA->AsPhi(), inputB->AsPhi())) { |
| 5027 continue; |
| 5028 } |
| 5029 return false; // Not equal. |
| 5030 } |
| 5031 } |
| 5032 } |
| 5033 |
| 5034 // At this point worklist contains pairs of equal phis. Replace the first |
| 5035 // phi in the pair with the second. |
| 5036 for (intptr_t i = 0; i < worklist_.length(); i += 2) { |
| 5037 PhiInstr* a = worklist_[i]; |
| 5038 PhiInstr* b = worklist_[i + 1]; |
| 5039 a->ReplaceUsesWith(b); |
| 5040 if (a->is_alive()) { |
| 5041 a->mark_dead(); |
| 5042 a->block()->RemovePhi(a); |
| 5043 } |
| 5044 } |
| 5045 |
| 5046 return true; |
| 5047 } |
| 5048 |
| 5049 // Insert the given phi into the graph. Attempt to find an equal one in the |
| 5050 // target block first. |
| 5051 // Returns true if the phi was inserted and false if it was replaced. |
| 5052 bool EmitPhi(PhiInstr* phi) { |
| 5053 for (PhiIterator it(phi->block()); !it.Done(); it.Advance()) { |
| 5054 if (ReplacePhiWith(phi, it.Current())) { |
| 5055 return false; |
| 5056 } |
| 5057 } |
| 5058 |
| 5059 phi->mark_alive(); |
| 5060 phi->block()->InsertPhi(phi); |
| 5061 return true; |
| 5062 } |
| 5063 |
| 4583 // Phis have not yet been inserted into the graph but they have uses of | 5064 // Phis have not yet been inserted into the graph but they have uses of |
| 4584 // their inputs. Insert the non-redundant ones and clear the input uses | 5065 // their inputs. Insert the non-redundant ones and clear the input uses |
| 4585 // of the redundant ones. | 5066 // of the redundant ones. |
| 4586 void EmitPhis() { | 5067 void EmitPhis() { |
| 5068 // First eliminate all redundant phis. |
| 4587 for (intptr_t i = 0; i < phis_.length(); i++) { | 5069 for (intptr_t i = 0; i < phis_.length(); i++) { |
| 4588 PhiInstr* phi = phis_[i]; | 5070 PhiInstr* phi = phis_[i]; |
| 4589 if (phi->HasUses() && !EliminateRedundantPhi(phi)) { | 5071 if (!phi->HasUses() || EliminateRedundantPhi(phi)) { |
| 4590 phi->mark_alive(); | |
| 4591 phi->block()->InsertPhi(phi); | |
| 4592 } else { | |
| 4593 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) { | 5072 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) { |
| 4594 phi->InputAt(j)->RemoveFromUseList(); | 5073 phi->InputAt(j)->RemoveFromUseList(); |
| 4595 } | 5074 } |
| 5075 phis_[i] = NULL; |
| 5076 } |
| 5077 } |
| 5078 |
| 5079 // Now emit phis or replace them with equal phis already present in the |
| 5080 // graph. |
| 5081 for (intptr_t i = 0; i < phis_.length(); i++) { |
| 5082 PhiInstr* phi = phis_[i]; |
| 5083 if ((phi != NULL) && (!phi->HasUses() || !EmitPhi(phi))) { |
| 5084 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) { |
| 5085 phi->InputAt(j)->RemoveFromUseList(); |
| 5086 } |
| 4596 } | 5087 } |
| 4597 } | 5088 } |
| 4598 } | 5089 } |
| 4599 | 5090 |
| 4600 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { | 5091 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { |
| 4601 ZoneGrowableArray<Definition*>* out = | 5092 ZoneGrowableArray<Definition*>* out = |
| 4602 new ZoneGrowableArray<Definition*>(aliased_set_->max_expr_id()); | 5093 new ZoneGrowableArray<Definition*>(aliased_set_->max_place_id()); |
| 4603 for (intptr_t i = 0; i < aliased_set_->max_expr_id(); i++) { | 5094 for (intptr_t i = 0; i < aliased_set_->max_place_id(); i++) { |
| 4604 out->Add(NULL); | 5095 out->Add(NULL); |
| 4605 } | 5096 } |
| 4606 return out; | 5097 return out; |
| 4607 } | 5098 } |
| 4608 | 5099 |
| 4609 FlowGraph* graph_; | 5100 FlowGraph* graph_; |
| 4610 DirectChainedHashMap<LoadKeyValueTrait>* map_; | 5101 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_; |
| 4611 | 5102 |
| 4612 // Mapping between field offsets in words and expression ids of loads from | 5103 // Mapping between field offsets in words and expression ids of loads from |
| 4613 // that offset. | 5104 // that offset. |
| 4614 AliasedSet* aliased_set_; | 5105 AliasedSet* aliased_set_; |
| 4615 | 5106 |
| 4616 // Per block sets of expression ids for loads that are: incoming (available | 5107 // Per block sets of expression ids for loads that are: incoming (available |
| 4617 // on the entry), outgoing (available on the exit), generated and killed. | 5108 // on the entry), outgoing (available on the exit), generated and killed. |
| 4618 GrowableArray<BitVector*> in_; | 5109 GrowableArray<BitVector*> in_; |
| 4619 GrowableArray<BitVector*> out_; | 5110 GrowableArray<BitVector*> out_; |
| 4620 GrowableArray<BitVector*> gen_; | 5111 GrowableArray<BitVector*> gen_; |
| (...skipping 1950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6571 | 7062 |
| 6572 // Insert materializations at environment uses. | 7063 // Insert materializations at environment uses. |
| 6573 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7064 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 6574 for (intptr_t i = 0; i < exits.length(); i++) { | 7065 for (intptr_t i = 0; i < exits.length(); i++) { |
| 6575 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7066 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 6576 } | 7067 } |
| 6577 } | 7068 } |
| 6578 | 7069 |
| 6579 | 7070 |
| 6580 } // namespace dart | 7071 } // namespace dart |
| OLD | NEW |