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

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

Issue 17101028: Refactor load forwarding pass to use a Place abstraction. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_optimizer.h" 5 #include "vm/flow_graph_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/cha.h" 8 #include "vm/cha.h"
9 #include "vm/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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698