Index: runtime/vm/flow_graph_optimizer.cc |
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
index f8288dd332d0ea839083709e48534daaa1e558e6..491c930dacb5654025d90691faf7be92b00f4510 100644 |
--- a/runtime/vm/flow_graph_optimizer.cc |
+++ b/runtime/vm/flow_graph_optimizer.cc |
@@ -3075,7 +3075,9 @@ void LICM::Optimize() { |
!it.Done(); |
it.Advance()) { |
Instruction* current = it.Current(); |
- if (!current->IsPushArgument() && !current->AffectedBySideEffect()) { |
+ if (!current->IsPushArgument() && |
+ current->AllowsCSE() && |
+ flow_graph()->block_effects()->CanBeMovedTo(current, pre_header)) { |
bool inputs_loop_invariant = true; |
for (int i = 0; i < current->InputCount(); ++i) { |
Definition* input_def = current->InputAt(i)->definition(); |
@@ -3106,7 +3108,7 @@ static bool IsLoadEliminationCandidate(Definition* def) { |
// Immutable loads (not affected by side effects) are handled |
// in the DominatorBasedCSE pass. |
// TODO(fschneider): Extend to other load instructions. |
- return (def->IsLoadField() && def->AffectedBySideEffect()) |
+ return (def->IsLoadField() && !def->Dependencies().IsNone()) |
|| def->IsLoadIndexed() |
|| def->IsLoadStaticField() |
|| def->IsCurrentContext(); |
@@ -3585,7 +3587,7 @@ class LoadOptimizer : public ValueObject { |
} |
// Other instructions with side effects kill all loads. |
- if (instr->HasSideEffect()) { |
+ if (!instr->Effects().IsNone()) { |
kill->SetAll(); |
// There is no need to clear out_values when clearing GEN set |
// because only those values that are in the GEN set |
@@ -3946,6 +3948,56 @@ class LoadOptimizer : public ValueObject { |
}; |
+class CSEInstructionMap : public ValueObject { |
+ public: |
+ // Right now CSE and LICM track a single effect: possible externalization of |
+ // strings. |
+ // Other effects like modifications of fields are tracked in a separate load |
+ // forwarding pass via Alias structure. |
+ COMPILE_ASSERT(EffectSet::kLastEffect == 1, single_effect_is_tracked); |
+ |
+ CSEInstructionMap() : independent_(), dependent_() { } |
+ explicit CSEInstructionMap(const CSEInstructionMap& other) |
+ : ValueObject(), |
+ independent_(other.independent_), |
+ dependent_(other.dependent_) { |
+ } |
+ |
+ void RemoveAffected(EffectSet effects) { |
+ if (!effects.IsNone()) { |
+ dependent_.Clear(); |
+ } |
+ } |
+ |
+ Instruction* Lookup(Instruction* other) const { |
+ return GetMapFor(other)->Lookup(other); |
+ } |
+ |
+ void Insert(Instruction* instr) { |
+ return GetMapFor(instr)->Insert(instr); |
+ } |
+ |
+ private: |
+ typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; |
+ |
+ Map* GetMapFor(Instruction* instr) { |
+ return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
+ } |
+ |
+ const Map* GetMapFor(Instruction* instr) const { |
+ return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
+ } |
+ |
+ // All computations that are not affected by any side-effect. |
+ // Majority of computations are not affected by anything and will be in |
+ // this map. |
+ Map independent_; |
+ |
+ // All computations that are affected by side effect. |
+ Map dependent_; |
+}; |
+ |
+ |
bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
bool changed = false; |
if (FLAG_load_cse) { |
@@ -3964,7 +4016,7 @@ bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
} |
} |
- DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; |
+ CSEInstructionMap map; |
changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; |
return changed; |
@@ -3974,19 +4026,29 @@ bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
bool DominatorBasedCSE::OptimizeRecursive( |
FlowGraph* graph, |
BlockEntryInstr* block, |
- DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { |
+ CSEInstructionMap* map) { |
bool changed = false; |
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
Instruction* current = it.Current(); |
- if (current->AffectedBySideEffect()) continue; |
- Instruction* replacement = map->Lookup(current); |
- if (replacement == NULL) { |
+ if (current->AllowsCSE()) { |
+ Instruction* replacement = map->Lookup(current); |
+ if ((replacement != NULL) && |
+ graph->block_effects()->IsAvailableAt(replacement, block)) { |
+ // Replace current with lookup result. |
+ ReplaceCurrentInstruction(&it, current, replacement, graph); |
+ changed = true; |
+ continue; |
+ } |
+ |
+ // For simplicity we assume that instruction either does not depend on |
+ // anything or does not affect anything. If this is not the case then |
+ // we should first remove affected instructions from the map and |
+ // then add instruction to the map so that it does not kill itself. |
+ ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); |
map->Insert(current); |
- continue; |
} |
- // Replace current with lookup result. |
- ReplaceCurrentInstruction(&it, current, replacement, graph); |
- changed = true; |
+ |
+ map->RemoveAffected(current->Effects()); |
} |
// Process children in the dominator tree recursively. |
@@ -3995,7 +4057,7 @@ bool DominatorBasedCSE::OptimizeRecursive( |
BlockEntryInstr* child = block->dominated_blocks()[i]; |
if (i < num_children - 1) { |
// Copy map. |
- DirectChainedHashMap<PointerKeyValueTrait<Instruction> > child_map(*map); |
+ CSEInstructionMap child_map(*map); |
changed = OptimizeRecursive(graph, child, &child_map) || changed; |
} else { |
// Reuse map for the last child. |