Index: runtime/vm/flow_graph_optimizer.cc |
=================================================================== |
--- runtime/vm/flow_graph_optimizer.cc (revision 35649) |
+++ runtime/vm/flow_graph_optimizer.cc (working copy) |
@@ -7169,6 +7169,7 @@ |
cp.Analyze(); |
cp.VisitBranches(); |
cp.Transform(); |
+ cp.EliminateRedundantBranches(); |
} |
@@ -8443,6 +8444,85 @@ |
} |
+static bool IsEmptyBlock(BlockEntryInstr* block) { |
+ return block->next()->IsGoto() && |
+ (!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)); |
+} |
+ |
+ |
+// Traverses a chain of empty blocks and returns the first reachable non-empty |
+// block that is not dominated by the start block. The empty blocks are added |
+// to the supplied bit vector. |
+static BlockEntryInstr* FindFirstNonEmptySuccessor( |
+ TargetEntryInstr* block, |
+ BitVector* empty_blocks) { |
+ BlockEntryInstr* current = block; |
+ while (IsEmptyBlock(current) && block->Dominates(current)) { |
+ ASSERT(!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)); |
+ empty_blocks->Add(current->preorder_number()); |
+ current = current->next()->AsGoto()->successor(); |
+ } |
+ return current; |
+} |
+ |
+ |
+void ConstantPropagator::EliminateRedundantBranches() { |
+ // Canonicalize branches that have no side-effects and where true- and |
+ // false-targets are the same. |
+ bool changed = false; |
+ BitVector* empty_blocks = new BitVector(graph_->preorder().length()); |
+ for (BlockIterator b = graph_->postorder_iterator(); |
+ !b.Done(); |
+ b.Advance()) { |
+ BlockEntryInstr* block = b.Current(); |
+ BranchInstr* branch = block->last_instruction()->AsBranch(); |
+ empty_blocks->Clear(); |
+ if ((branch != NULL) && branch->Effects().IsNone()) { |
+ ASSERT(branch->previous() != NULL); // Not already eliminated. |
+ BlockEntryInstr* if_true = |
+ FindFirstNonEmptySuccessor(branch->true_successor(), empty_blocks); |
+ BlockEntryInstr* if_false = |
+ FindFirstNonEmptySuccessor(branch->false_successor(), empty_blocks); |
+ if (if_true == if_false) { |
+ // Replace the branch with a jump to the common successor. |
+ // Drop the comparison, which does not have side effects |
+ JoinEntryInstr* join = if_true->AsJoinEntry(); |
+ if (join->phis() == NULL) { |
+ GotoInstr* jump = new GotoInstr(if_true->AsJoinEntry()); |
+ jump->InheritDeoptTarget(branch); |
+ |
+ Instruction* previous = branch->previous(); |
+ branch->set_previous(NULL); |
+ previous->LinkTo(jump); |
+ |
+ // Remove uses from branch and all the empty blocks that |
+ // are now unreachable. |
+ branch->UnuseAllInputs(); |
+ for (BitVector::Iterator it(empty_blocks); !it.Done(); it.Advance()) { |
+ BlockEntryInstr* empty_block = graph_->preorder()[it.Current()]; |
+ empty_block->ClearAllInstructions(); |
+ } |
+ |
+ changed = true; |
+ |
+ if (FLAG_trace_constant_propagation) { |
+ OS::Print("Eliminated branch in B%"Pd" common target B%"Pd"\n", |
+ block->block_id(), join->block_id()); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ if (changed) { |
+ graph_->DiscoverBlocks(); |
+ // TODO(fschneider): Update dominator tree in place instead of recomputing. |
+ GrowableArray<BitVector*> dominance_frontier; |
+ graph_->ComputeDominators(&dominance_frontier); |
+ } |
+} |
+ |
+ |
void ConstantPropagator::Transform() { |
if (FLAG_trace_constant_propagation) { |
OS::Print("\n==== Before constant propagation ====\n"); |
@@ -8460,24 +8540,16 @@ |
!b.Done(); |
b.Advance()) { |
BlockEntryInstr* block = b.Current(); |
- JoinEntryInstr* join = block->AsJoinEntry(); |
if (!reachable_->Contains(block->preorder_number())) { |
if (FLAG_trace_constant_propagation) { |
OS::Print("Unreachable B%" Pd "\n", block->block_id()); |
} |
// Remove all uses in unreachable blocks. |
- if (join != NULL) { |
- for (PhiIterator it(join); !it.Done(); it.Advance()) { |
- it.Current()->UnuseAllInputs(); |
- } |
- } |
- block->UnuseAllInputs(); |
- for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
- it.Current()->UnuseAllInputs(); |
- } |
+ block->ClearAllInstructions(); |
continue; |
} |
+ JoinEntryInstr* join = block->AsJoinEntry(); |
if (join != NULL) { |
// Remove phi inputs corresponding to unreachable predecessor blocks. |
// Predecessors will be recomputed (in block id order) after removing |