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

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

Issue 14021016: Track side-effect free paths in the graph to allow CSE and LICM for instructions that depend on som… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 7 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 | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.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 3057 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698