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