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 : public ValueObject { |
| 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 explicit CSEInstructionMap(const CSEInstructionMap& other) |
| 3961 : ValueObject(), |
| 3962 independent_(other.independent_), |
| 3963 dependent_(other.dependent_) { |
| 3964 } |
| 3965 |
| 3966 void RemoveAffected(EffectSet effects) { |
| 3967 if (!effects.IsNone()) { |
| 3968 dependent_.Clear(); |
| 3969 } |
| 3970 } |
| 3971 |
| 3972 Instruction* Lookup(Instruction* other) const { |
| 3973 return GetMapFor(other)->Lookup(other); |
| 3974 } |
| 3975 |
| 3976 void Insert(Instruction* instr) { |
| 3977 return GetMapFor(instr)->Insert(instr); |
| 3978 } |
| 3979 |
| 3980 private: |
| 3981 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; |
| 3982 |
| 3983 Map* GetMapFor(Instruction* instr) { |
| 3984 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
| 3985 } |
| 3986 |
| 3987 const Map* GetMapFor(Instruction* instr) const { |
| 3988 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
| 3989 } |
| 3990 |
| 3991 // All computations that are not affected by any side-effect. |
| 3992 // Majority of computations are not affected by anything and will be in |
| 3993 // this map. |
| 3994 Map independent_; |
| 3995 |
| 3996 // All computations that are affected by side effect. |
| 3997 Map dependent_; |
| 3998 }; |
| 3999 |
| 4000 |
3949 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { | 4001 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
3950 bool changed = false; | 4002 bool changed = false; |
3951 if (FLAG_load_cse) { | 4003 if (FLAG_load_cse) { |
3952 GrowableArray<BitVector*> kill_by_offs(10); | 4004 GrowableArray<BitVector*> kill_by_offs(10); |
3953 DirectChainedHashMap<LoadKeyValueTrait> map; | 4005 DirectChainedHashMap<LoadKeyValueTrait> map; |
3954 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map); | 4006 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map); |
3955 if (!aliased_set->IsEmpty()) { | 4007 if (!aliased_set->IsEmpty()) { |
3956 // If any loads were forwarded return true from Optimize to run load | 4008 // If any loads were forwarded return true from Optimize to run load |
3957 // forwarding again. This will allow to forward chains of loads. | 4009 // forwarding again. This will allow to forward chains of loads. |
3958 // This is especially important for context variables as they are built | 4010 // This is especially important for context variables as they are built |
3959 // as loads from loaded context. | 4011 // as loads from loaded context. |
3960 // TODO(vegorov): renumber newly discovered congruences during the | 4012 // TODO(vegorov): renumber newly discovered congruences during the |
3961 // forwarding to forward chains without running whole pass twice. | 4013 // forwarding to forward chains without running whole pass twice. |
3962 LoadOptimizer load_optimizer(graph, aliased_set, &map); | 4014 LoadOptimizer load_optimizer(graph, aliased_set, &map); |
3963 changed = load_optimizer.Optimize() || changed; | 4015 changed = load_optimizer.Optimize() || changed; |
3964 } | 4016 } |
3965 } | 4017 } |
3966 | 4018 |
3967 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; | 4019 CSEInstructionMap map; |
3968 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; | 4020 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; |
3969 | 4021 |
3970 return changed; | 4022 return changed; |
3971 } | 4023 } |
3972 | 4024 |
3973 | 4025 |
3974 bool DominatorBasedCSE::OptimizeRecursive( | 4026 bool DominatorBasedCSE::OptimizeRecursive( |
3975 FlowGraph* graph, | 4027 FlowGraph* graph, |
3976 BlockEntryInstr* block, | 4028 BlockEntryInstr* block, |
3977 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { | 4029 CSEInstructionMap* map) { |
3978 bool changed = false; | 4030 bool changed = false; |
3979 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4031 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
3980 Instruction* current = it.Current(); | 4032 Instruction* current = it.Current(); |
3981 if (current->AffectedBySideEffect()) continue; | 4033 if (current->AllowsCSE()) { |
3982 Instruction* replacement = map->Lookup(current); | 4034 Instruction* replacement = map->Lookup(current); |
3983 if (replacement == NULL) { | 4035 if ((replacement != NULL) && |
| 4036 graph->block_effects()->IsAvailableAt(replacement, block)) { |
| 4037 // Replace current with lookup result. |
| 4038 ReplaceCurrentInstruction(&it, current, replacement, graph); |
| 4039 changed = true; |
| 4040 continue; |
| 4041 } |
| 4042 |
| 4043 // For simplicity we assume that instruction either does not depend on |
| 4044 // anything or does not affect anything. If this is not the case then |
| 4045 // we should first remove affected instructions from the map and |
| 4046 // then add instruction to the map so that it does not kill itself. |
| 4047 ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); |
3984 map->Insert(current); | 4048 map->Insert(current); |
3985 continue; | |
3986 } | 4049 } |
3987 // Replace current with lookup result. | 4050 |
3988 ReplaceCurrentInstruction(&it, current, replacement, graph); | 4051 map->RemoveAffected(current->Effects()); |
3989 changed = true; | |
3990 } | 4052 } |
3991 | 4053 |
3992 // Process children in the dominator tree recursively. | 4054 // Process children in the dominator tree recursively. |
3993 intptr_t num_children = block->dominated_blocks().length(); | 4055 intptr_t num_children = block->dominated_blocks().length(); |
3994 for (intptr_t i = 0; i < num_children; ++i) { | 4056 for (intptr_t i = 0; i < num_children; ++i) { |
3995 BlockEntryInstr* child = block->dominated_blocks()[i]; | 4057 BlockEntryInstr* child = block->dominated_blocks()[i]; |
3996 if (i < num_children - 1) { | 4058 if (i < num_children - 1) { |
3997 // Copy map. | 4059 // Copy map. |
3998 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > child_map(*map); | 4060 CSEInstructionMap child_map(*map); |
3999 changed = OptimizeRecursive(graph, child, &child_map) || changed; | 4061 changed = OptimizeRecursive(graph, child, &child_map) || changed; |
4000 } else { | 4062 } else { |
4001 // Reuse map for the last child. | 4063 // Reuse map for the last child. |
4002 changed = OptimizeRecursive(graph, child, map) || changed; | 4064 changed = OptimizeRecursive(graph, child, map) || changed; |
4003 } | 4065 } |
4004 } | 4066 } |
4005 return changed; | 4067 return changed; |
4006 } | 4068 } |
4007 | 4069 |
4008 | 4070 |
(...skipping 1374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5383 if (changed) { | 5445 if (changed) { |
5384 // We may have changed the block order and the dominator tree. | 5446 // We may have changed the block order and the dominator tree. |
5385 flow_graph->DiscoverBlocks(); | 5447 flow_graph->DiscoverBlocks(); |
5386 GrowableArray<BitVector*> dominance_frontier; | 5448 GrowableArray<BitVector*> dominance_frontier; |
5387 flow_graph->ComputeDominators(&dominance_frontier); | 5449 flow_graph->ComputeDominators(&dominance_frontier); |
5388 } | 5450 } |
5389 } | 5451 } |
5390 | 5452 |
5391 | 5453 |
5392 } // namespace dart | 5454 } // namespace dart |
OLD | NEW |