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

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

Powered by Google App Engine
This is Rietveld 408576698