OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 3057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3068 if (pre_header == NULL) continue; | 3068 if (pre_header == NULL) continue; |
3069 | 3069 |
3070 for (BitVector::Iterator loop_it(header->loop_info()); | 3070 for (BitVector::Iterator loop_it(header->loop_info()); |
3071 !loop_it.Done(); | 3071 !loop_it.Done(); |
3072 loop_it.Advance()) { | 3072 loop_it.Advance()) { |
3073 BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()]; | 3073 BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()]; |
3074 for (ForwardInstructionIterator it(block); | 3074 for (ForwardInstructionIterator it(block); |
3075 !it.Done(); | 3075 !it.Done(); |
3076 it.Advance()) { | 3076 it.Advance()) { |
3077 Instruction* current = it.Current(); | 3077 Instruction* current = it.Current(); |
3078 if (!current->IsPushArgument() && !current->AffectedBySideEffect()) { | 3078 if (!current->IsPushArgument() && |
3079 current->AllowsCSE() && | |
3080 flow_graph()->block_effects()->CanBeMovedTo(current, pre_header)) { | |
3079 bool inputs_loop_invariant = true; | 3081 bool inputs_loop_invariant = true; |
3080 for (int i = 0; i < current->InputCount(); ++i) { | 3082 for (int i = 0; i < current->InputCount(); ++i) { |
3081 Definition* input_def = current->InputAt(i)->definition(); | 3083 Definition* input_def = current->InputAt(i)->definition(); |
3082 if (!input_def->GetBlock()->Dominates(pre_header)) { | 3084 if (!input_def->GetBlock()->Dominates(pre_header)) { |
3083 inputs_loop_invariant = false; | 3085 inputs_loop_invariant = false; |
3084 break; | 3086 break; |
3085 } | 3087 } |
3086 } | 3088 } |
3087 if (inputs_loop_invariant && | 3089 if (inputs_loop_invariant && |
3088 !current->IsAssertAssignable() && | 3090 !current->IsAssertAssignable() && |
(...skipping 10 matching lines...) Expand all Loading... | |
3099 } | 3101 } |
3100 } | 3102 } |
3101 } | 3103 } |
3102 } | 3104 } |
3103 | 3105 |
3104 | 3106 |
3105 static bool IsLoadEliminationCandidate(Definition* def) { | 3107 static bool IsLoadEliminationCandidate(Definition* def) { |
3106 // Immutable loads (not affected by side effects) are handled | 3108 // Immutable loads (not affected by side effects) are handled |
3107 // in the DominatorBasedCSE pass. | 3109 // in the DominatorBasedCSE pass. |
3108 // TODO(fschneider): Extend to other load instructions. | 3110 // TODO(fschneider): Extend to other load instructions. |
3109 return (def->IsLoadField() && def->AffectedBySideEffect()) | 3111 return (def->IsLoadField() && !def->Dependencies().IsNone()) |
3110 || def->IsLoadIndexed() | 3112 || def->IsLoadIndexed() |
3111 || def->IsLoadStaticField() | 3113 || def->IsLoadStaticField() |
3112 || def->IsCurrentContext(); | 3114 || def->IsCurrentContext(); |
3113 } | 3115 } |
3114 | 3116 |
3115 | 3117 |
3116 // Alias represents a family of locations. It is used to capture aliasing | 3118 // Alias represents a family of locations. It is used to capture aliasing |
3117 // between stores and loads. Store can alias another load or store if and only | 3119 // between stores and loads. Store can alias another load or store if and only |
3118 // if they have the same alias. | 3120 // if they have the same alias. |
3119 class Alias : public ValueObject { | 3121 class Alias : public ValueObject { |
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3578 (*out_values)[load->expr_id()] = GetStoredValue(instr); | 3580 (*out_values)[load->expr_id()] = GetStoredValue(instr); |
3579 } | 3581 } |
3580 } | 3582 } |
3581 } | 3583 } |
3582 ASSERT(!instr->IsDefinition() || | 3584 ASSERT(!instr->IsDefinition() || |
3583 !IsLoadEliminationCandidate(instr->AsDefinition())); | 3585 !IsLoadEliminationCandidate(instr->AsDefinition())); |
3584 continue; | 3586 continue; |
3585 } | 3587 } |
3586 | 3588 |
3587 // Other instructions with side effects kill all loads. | 3589 // Other instructions with side effects kill all loads. |
3588 if (instr->HasSideEffect()) { | 3590 if (!instr->Effects().IsNone()) { |
3589 kill->SetAll(); | 3591 kill->SetAll(); |
3590 // There is no need to clear out_values when clearing GEN set | 3592 // There is no need to clear out_values when clearing GEN set |
3591 // because only those values that are in the GEN set | 3593 // because only those values that are in the GEN set |
3592 // will ever be used. | 3594 // will ever be used. |
3593 gen->Clear(); | 3595 gen->Clear(); |
3594 continue; | 3596 continue; |
3595 } | 3597 } |
3596 | 3598 |
3597 Definition* defn = instr->AsDefinition(); | 3599 Definition* defn = instr->AsDefinition(); |
3598 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 3600 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3939 GrowableArray<PhiInstr*> worklist_; | 3941 GrowableArray<PhiInstr*> worklist_; |
3940 BitVector* in_worklist_; | 3942 BitVector* in_worklist_; |
3941 | 3943 |
3942 // True if any load was eliminated. | 3944 // True if any load was eliminated. |
3943 bool forwarded_; | 3945 bool forwarded_; |
3944 | 3946 |
3945 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); | 3947 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); |
3946 }; | 3948 }; |
3947 | 3949 |
3948 | 3950 |
3951 class CSEInstructionMap { | |
srdjan
2013/04/29 17:16:26
: public ValueObject
Vyacheslav Egorov (Google)
2013/04/30 14:01:33
Done.
| |
3952 public: | |
3953 // Right now CSE and LICM track a single effect: possible externalization of | |
3954 // strings. | |
3955 // Other effects like modifications of fields are tracked in a separate load | |
3956 // forwarding pass via Alias structure. | |
3957 COMPILE_ASSERT(EffectSet::kLastEffect == 1, single_effect_is_tracked); | |
3958 | |
3959 CSEInstructionMap() : independent_(), dependent_() { } | |
3960 CSEInstructionMap(const CSEInstructionMap& other) | |
srdjan
2013/04/29 17:16:26
explicit
Vyacheslav Egorov (Google)
2013/04/30 14:01:33
Done.
| |
3961 : independent_(other.independent_), dependent_(other.dependent_) { } | |
3962 | |
3963 void RemoveAffected(EffectSet effects) { | |
3964 if (!effects.IsNone()) { | |
3965 dependent_.Clear(); | |
3966 } | |
3967 } | |
3968 | |
3969 Instruction* Lookup(Instruction* other) const { | |
3970 return GetMapFor(other)->Lookup(other); | |
3971 } | |
3972 | |
3973 void Insert(Instruction* instr) { | |
3974 return GetMapFor(instr)->Insert(instr); | |
3975 } | |
3976 | |
3977 private: | |
3978 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; | |
3979 | |
3980 Map* GetMapFor(Instruction* instr) { | |
3981 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | |
3982 } | |
3983 | |
3984 const Map* GetMapFor(Instruction* instr) const { | |
3985 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | |
3986 } | |
3987 | |
3988 // All computations that are not affected by any side-effect. | |
3989 // Majority of computations are not affected by anything and will be in | |
3990 // this map. | |
3991 Map independent_; | |
3992 | |
3993 // All computations that are affected by side effect. | |
3994 Map dependent_; | |
3995 }; | |
3996 | |
3997 | |
3949 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { | 3998 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
3950 bool changed = false; | 3999 bool changed = false; |
3951 if (FLAG_load_cse) { | 4000 if (FLAG_load_cse) { |
3952 GrowableArray<BitVector*> kill_by_offs(10); | 4001 GrowableArray<BitVector*> kill_by_offs(10); |
3953 DirectChainedHashMap<LoadKeyValueTrait> map; | 4002 DirectChainedHashMap<LoadKeyValueTrait> map; |
3954 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map); | 4003 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map); |
3955 if (!aliased_set->IsEmpty()) { | 4004 if (!aliased_set->IsEmpty()) { |
3956 // If any loads were forwarded return true from Optimize to run load | 4005 // If any loads were forwarded return true from Optimize to run load |
3957 // forwarding again. This will allow to forward chains of loads. | 4006 // forwarding again. This will allow to forward chains of loads. |
3958 // This is especially important for context variables as they are built | 4007 // This is especially important for context variables as they are built |
3959 // as loads from loaded context. | 4008 // as loads from loaded context. |
3960 // TODO(vegorov): renumber newly discovered congruences during the | 4009 // TODO(vegorov): renumber newly discovered congruences during the |
3961 // forwarding to forward chains without running whole pass twice. | 4010 // forwarding to forward chains without running whole pass twice. |
3962 LoadOptimizer load_optimizer(graph, aliased_set, &map); | 4011 LoadOptimizer load_optimizer(graph, aliased_set, &map); |
3963 changed = load_optimizer.Optimize() || changed; | 4012 changed = load_optimizer.Optimize() || changed; |
3964 } | 4013 } |
3965 } | 4014 } |
3966 | 4015 |
3967 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; | 4016 CSEInstructionMap map; |
3968 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; | 4017 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; |
3969 | 4018 |
3970 return changed; | 4019 return changed; |
3971 } | 4020 } |
3972 | 4021 |
3973 | 4022 |
3974 bool DominatorBasedCSE::OptimizeRecursive( | 4023 bool DominatorBasedCSE::OptimizeRecursive( |
3975 FlowGraph* graph, | 4024 FlowGraph* graph, |
3976 BlockEntryInstr* block, | 4025 BlockEntryInstr* block, |
3977 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { | 4026 CSEInstructionMap* map) { |
3978 bool changed = false; | 4027 bool changed = false; |
3979 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4028 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
3980 Instruction* current = it.Current(); | 4029 Instruction* current = it.Current(); |
3981 if (current->AffectedBySideEffect()) continue; | 4030 if (current->AllowsCSE()) { |
3982 Instruction* replacement = map->Lookup(current); | 4031 Instruction* replacement = map->Lookup(current); |
3983 if (replacement == NULL) { | 4032 if ((replacement != NULL) && |
4033 graph->block_effects()->IsAvailableAt(replacement, block)) { | |
4034 // Replace current with lookup result. | |
4035 ReplaceCurrentInstruction(&it, current, replacement, graph); | |
4036 changed = true; | |
4037 continue; | |
4038 } | |
4039 | |
4040 // For simplicity we assume that instruction either does not depend on | |
4041 // anything or does not affect anything. If this is not the case then | |
4042 // we should first remove affected instructions from the map and | |
4043 // then add instruction to the map so that it does not kill itself. | |
4044 ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); | |
3984 map->Insert(current); | 4045 map->Insert(current); |
3985 continue; | |
3986 } | 4046 } |
3987 // Replace current with lookup result. | 4047 |
3988 ReplaceCurrentInstruction(&it, current, replacement, graph); | 4048 map->RemoveAffected(current->Effects()); |
3989 changed = true; | |
3990 } | 4049 } |
3991 | 4050 |
3992 // Process children in the dominator tree recursively. | 4051 // Process children in the dominator tree recursively. |
3993 intptr_t num_children = block->dominated_blocks().length(); | 4052 intptr_t num_children = block->dominated_blocks().length(); |
3994 for (intptr_t i = 0; i < num_children; ++i) { | 4053 for (intptr_t i = 0; i < num_children; ++i) { |
3995 BlockEntryInstr* child = block->dominated_blocks()[i]; | 4054 BlockEntryInstr* child = block->dominated_blocks()[i]; |
3996 if (i < num_children - 1) { | 4055 if (i < num_children - 1) { |
3997 // Copy map. | 4056 // Copy map. |
3998 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > child_map(*map); | 4057 CSEInstructionMap child_map(*map); |
3999 changed = OptimizeRecursive(graph, child, &child_map) || changed; | 4058 changed = OptimizeRecursive(graph, child, &child_map) || changed; |
4000 } else { | 4059 } else { |
4001 // Reuse map for the last child. | 4060 // Reuse map for the last child. |
4002 changed = OptimizeRecursive(graph, child, map) || changed; | 4061 changed = OptimizeRecursive(graph, child, map) || changed; |
4003 } | 4062 } |
4004 } | 4063 } |
4005 return changed; | 4064 return changed; |
4006 } | 4065 } |
4007 | 4066 |
4008 | 4067 |
(...skipping 1374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5383 if (changed) { | 5442 if (changed) { |
5384 // We may have changed the block order and the dominator tree. | 5443 // We may have changed the block order and the dominator tree. |
5385 flow_graph->DiscoverBlocks(); | 5444 flow_graph->DiscoverBlocks(); |
5386 GrowableArray<BitVector*> dominance_frontier; | 5445 GrowableArray<BitVector*> dominance_frontier; |
5387 flow_graph->ComputeDominators(&dominance_frontier); | 5446 flow_graph->ComputeDominators(&dominance_frontier); |
5388 } | 5447 } |
5389 } | 5448 } |
5390 | 5449 |
5391 | 5450 |
5392 } // namespace dart | 5451 } // namespace dart |
OLD | NEW |