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

Unified Diff: runtime/vm/flow_graph_optimizer.cc

Issue 10949020: Reapply "Initial implementation of sparse conditional constant propagation." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase to HEAD. Created 8 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: runtime/vm/flow_graph_optimizer.cc
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 69ce617a95a4153ed5c243bc22bf836ddad0e42a..750aa86005828711fccfab4de93abe37097f57ad 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -9,6 +9,7 @@
#include "vm/flow_graph_builder.h"
#include "vm/hash_map.h"
#include "vm/il_printer.h"
+#include "vm/intermediate_language.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/scopes.h"
@@ -1769,4 +1770,700 @@ void DominatorBasedCSE::OptimizeRecursive(
}
+ConstantPropagator::ConstantPropagator(
+ FlowGraph* graph,
+ const GrowableArray<BlockEntryInstr*>& ignored)
+ : FlowGraphVisitor(ignored),
+ graph_(graph),
+ unknown_(Object::ZoneHandle(Object::transition_sentinel())),
+ non_constant_(Object::ZoneHandle(Object::sentinel())),
+ reachable_(new BitVector(graph->preorder().length())),
+ definition_marks_(new BitVector(graph->max_virtual_register_number())),
+ block_worklist_(),
+ definition_worklist_() {}
+
+
+void ConstantPropagator::Optimize(FlowGraph* graph) {
+ GrowableArray<BlockEntryInstr*> ignored;
+ ConstantPropagator cp(graph, ignored);
+ cp.Analyze();
+ cp.Transform();
+}
+
+
+void ConstantPropagator::SetReachable(BlockEntryInstr* block) {
+ if (!reachable_->Contains(block->preorder_number())) {
+ reachable_->Add(block->preorder_number());
+ block_worklist_.Add(block);
+ }
+}
+
+
+void ConstantPropagator::SetValue(Definition* definition, const Object& value) {
+ // We would like to assert we only go up (toward non-constant) in the lattice.
+ //
+ // ASSERT(IsUnknown(definition->constant_value()) ||
+ // IsNonConstant(value) ||
+ // (definition->constant_value().raw() == value.raw()));
+ //
+ // But the final disjunct is not true (e.g., mint or double constants are
+ // heap-allocated and so not necessarily pointer-equal on each iteration).
+ if (definition->constant_value().raw() != value.raw()) {
+ definition->constant_value() = value.raw();
+ if (definition->input_use_list() != NULL) {
+ ASSERT(definition->HasSSATemp());
+ if (!definition_marks_->Contains(definition->ssa_temp_index())) {
+ definition_worklist_.Add(definition);
+ definition_marks_->Add(definition->ssa_temp_index());
+ }
+ }
+ }
+}
+
+
+// Compute the join of two values in the lattice, assign it to the first.
+void ConstantPropagator::Join(Object* left, const Object& right) {
+ // Join(non-constant, X) = non-constant
+ // Join(X, unknown) = X
+ if (IsNonConstant(*left) || IsUnknown(right)) return;
+
+ // Join(unknown, X) = X
+ // Join(X, non-constant) = non-constant
+ if (IsUnknown(*left) || IsNonConstant(right)) {
+ *left = right.raw();
+ return;
+ }
+
+ // Join(X, X) = X
+ // TODO(kmillikin): support equality for doubles, mints, etc.
+ if (left->raw() == right.raw()) return;
+
+ // Join(X, Y) = non-constant
+ *left = non_constant_.raw();
+}
+
+
+// --------------------------------------------------------------------------
+// Analysis of blocks. Called at most once per block. The block is already
+// marked as reachable. All instructions in the block are analyzed.
+void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) {
+ const GrowableArray<Definition*>& defs = *block->initial_definitions();
+ for (intptr_t i = 0; i < defs.length(); ++i) {
+ defs[i]->Accept(this);
+ }
+ ASSERT(ForwardInstructionIterator(block).Done());
+
+ SetReachable(block->normal_entry());
+}
+
+
+void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) {
+ ZoneGrowableArray<PhiInstr*>* phis = block->phis();
+ if (phis != NULL) {
+ for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) {
+ PhiInstr* phi = (*phis)[phi_idx];
+ if (phi == NULL) continue;
+ phi->Accept(this);
+ }
+ }
+
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ it.Current()->Accept(this);
+ }
+}
+
+
+void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) {
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ it.Current()->Accept(this);
+ }
+}
+
+
+void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) {
+ // Parallel moves have not yet been inserted in the graph.
+ UNREACHABLE();
+}
+
+
+// --------------------------------------------------------------------------
+// Analysis of control instructions. Unconditional successors are
+// reachable. Conditional successors are reachable depending on the
+// constant value of the condition.
+void ConstantPropagator::VisitReturn(ReturnInstr* instr) {
+ // Nothing to do.
+}
+
+
+void ConstantPropagator::VisitThrow(ThrowInstr* instr) {
+ // Nothing to do.
+}
+
+
+void ConstantPropagator::VisitReThrow(ReThrowInstr* instr) {
+ // Nothing to do.
+}
+
+
+void ConstantPropagator::VisitGoto(GotoInstr* instr) {
+ SetReachable(instr->successor());
+}
+
+
+void ConstantPropagator::VisitBranch(BranchInstr* instr) {
+ instr->comparison()->Accept(this);
+ const Object& value = instr->comparison()->constant_value();
+ if (IsNonConstant(value)) {
+ SetReachable(instr->true_successor());
+ SetReachable(instr->false_successor());
+ } else if (value.raw() == Bool::True()) {
+ SetReachable(instr->true_successor());
+ } else if (!IsUnknown(value)) { // Any other constant.
+ SetReachable(instr->false_successor());
+ }
+}
+
+
+// --------------------------------------------------------------------------
+// Analysis of definitions. Compute the constant value. If it has changed
+// and the definition has input uses, add the definition to the definition
+// worklist so that the used can be processed.
+void ConstantPropagator::VisitPhi(PhiInstr* instr) {
+ // Compute the join over all the reachable predecessor values.
+ JoinEntryInstr* block = instr->block();
+ Object& value = Object::ZoneHandle(Unknown());
+ for (intptr_t pred_idx = 0; pred_idx < instr->InputCount(); ++pred_idx) {
+ if (reachable_->Contains(
+ block->PredecessorAt(pred_idx)->preorder_number())) {
+ Join(&value,
+ instr->InputAt(pred_idx)->definition()->constant_value());
+ }
+ }
+ SetValue(instr, value);
+}
+
+
+void ConstantPropagator::VisitParameter(ParameterInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) {
+ SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
+void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // We are ignoring the instantiator and instantiator_type_arguments, but
+ // still monotonic and safe.
+ // TODO(kmillikin): Handle constants.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitAssertBoolean(AssertBooleanInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle assertion.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitArgumentDefinitionTest(
+ ArgumentDefinitionTestInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitCurrentContext(CurrentContextInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitStoreContext(StoreContextInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitClosureCall(ClosureCallInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitInstanceCall(InstanceCallInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitPolymorphicInstanceCall(
+ PolymorphicInstanceCallInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitLoadLocal(LoadLocalInstr* instr) {
+ UNREACHABLE();
+}
+
+
+void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) {
+ UNREACHABLE();
+}
+
+
+void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ bool result = (left.raw() == right.raw());
+ if (instr->kind() == Token::kNE_STRICT) result = !result;
+ SetValue(instr, Bool::ZoneHandle(Bool::Get(result)));
+ }
+}
+
+
+void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ // TODO(kmillikin): Handle equality comparison of constants.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitRelationalOp(RelationalOpInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ // TODO(kmillikin): Handle relational comparison of constants.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) {
+ SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
+void ConstantPropagator::VisitStoreInstanceField(
+ StoreInstanceFieldInstr* instr) {
+ SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
+void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitStoreStaticField(StoreStaticFieldInstr* instr) {
+ SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
+void ConstantPropagator::VisitBooleanNegate(BooleanNegateInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ SetValue(instr, Bool::ZoneHandle(Bool::Get(value.raw() != Bool::True())));
+ }
+}
+
+
+void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle instanceof on constants.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitCreateArray(CreateArrayInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitCreateClosure(CreateClosureInstr* instr) {
+ // TODO(kmillikin): Treat closures as constants.
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitAllocateObject(AllocateObjectInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitAllocateObjectWithBoundsCheck(
+ AllocateObjectWithBoundsCheckInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitStoreVMField(StoreVMFieldInstr* instr) {
+ SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
+void ConstantPropagator::VisitInstantiateTypeArguments(
+ InstantiateTypeArgumentsInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitExtractConstructorTypeArguments(
+ ExtractConstructorTypeArgumentsInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitExtractConstructorInstantiator(
+ ExtractConstructorInstantiatorInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitChainContext(ChainContextInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitCatchEntry(CatchEntryInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ if (left.IsSmi() && right.IsSmi()) {
+ switch (instr->op_kind()) {
+ case Token::kADD:
+ case Token::kSUB:
+ case Token::kMUL:
+ case Token::kTRUNCDIV:
+ case Token::kMOD: {
+ const Object& result =
+ Integer::ZoneHandle(Integer::BinaryOp(instr->op_kind(),
+ Smi::Cast(left),
+ Smi::Cast(right)));
+ SetValue(instr, result);
+ break;
+ }
+ default:
+ // TODO(kmillikin): support other smi operations.
+ SetValue(instr, non_constant_);
+ }
+ } else {
+ // TODO(kmillikin): support other types.
+ SetValue(instr, non_constant_);
+ }
+ }
+}
+
+
+void ConstantPropagator::VisitBinaryMintOp(BinaryMintOpInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ // TODO(kmillikin): Handle binary operations.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitUnarySmiOp(UnarySmiOpInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle unary operations.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitCheckStackOverflow(
+ CheckStackOverflowInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitDoubleToDouble(DoubleToDoubleInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle conversion.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitSmiToDouble(SmiToDoubleInstr* instr) {
+ // TODO(kmillikin): Handle conversion.
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitCheckClass(CheckClassInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle check.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle check.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitConstant(ConstantInstr* instr) {
+ SetValue(instr, instr->value());
+}
+
+
+void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ // TODO(kmillikin): Handle check.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitUnboxedDoubleBinaryOp(
+ UnboxedDoubleBinaryOpInstr* instr) {
+ const Object& left = instr->left()->definition()->constant_value();
+ const Object& right = instr->right()->definition()->constant_value();
+ if (IsNonConstant(left) || IsNonConstant(right)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(left) && IsConstant(right)) {
+ // TODO(kmillikin): Handle binary operation.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitMathSqrt(MathSqrtInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle sqrt.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitUnboxDouble(UnboxDoubleInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle conversion.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitBoxDouble(BoxDoubleInstr* instr) {
+ const Object& value = instr->value()->definition()->constant_value();
+ if (IsNonConstant(value)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(value)) {
+ // TODO(kmillikin): Handle conversion.
+ SetValue(instr, non_constant_);
+ }
+}
+
+
+void ConstantPropagator::VisitCheckArrayBound(CheckArrayBoundInstr* instr) {
+ // TODO(kmillikin): Handle checks.
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::Analyze() {
+ GraphEntryInstr* entry = graph_->graph_entry();
+ reachable_->Add(entry->preorder_number());
+ block_worklist_.Add(entry);
+
+ while (true) {
+ if (block_worklist_.is_empty()) {
+ if (definition_worklist_.is_empty()) break;
+ Definition* definition = definition_worklist_.Last();
+ definition_worklist_.RemoveLast();
+ definition_marks_->Remove(definition->ssa_temp_index());
+ Value* use = definition->input_use_list();
+ while (use != NULL) {
+ use->instruction()->Accept(this);
+ use = use->next_use();
+ }
+ } else {
+ BlockEntryInstr* block = block_worklist_.Last();
+ block_worklist_.RemoveLast();
+ block->Accept(this);
+ }
+ }
+}
+
+
+void ConstantPropagator::Transform() {
+ // We will recompute dominators, block ordering, block ids, block last
+ // instructions, previous pointers, predecessors, etc. after eliminating
+ // unreachable code. We do not maintain those properties during the
+ // transformation.
+ for (BlockIterator b = graph_->reverse_postorder_iterator();
+ !b.Done();
+ b.Advance()) {
+ BlockEntryInstr* block = b.Current();
+ if (!reachable_->Contains(block->preorder_number())) {
+ continue;
+ }
+ for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) {
+ Definition* defn = i.Current()->AsDefinition();
+ BranchInstr* branch = i.Current()->AsBranch();
+ if (defn != NULL) {
+ if (IsConstant(defn->constant_value())) {
+ if (!defn->IsConstant() &&
+ !defn->IsPushArgument() &&
+ !defn->IsStoreLocal() &&
+ !defn->IsStoreIndexed() &&
+ !defn->IsStoreInstanceField() &&
+ !defn->IsStoreStaticField() &&
+ !defn->IsStoreVMField()) {
+ // TODO(kmillikin): propagate constants to replace instructions
+ // without side effects.
+ }
+ }
+ } else if (branch != NULL) {
+ TargetEntryInstr* if_true = branch->true_successor();
+ TargetEntryInstr* if_false = branch->false_successor();
+ JoinEntryInstr* join = NULL;
+ Instruction* next = NULL;
+
+ if (!reachable_->Contains(if_true->preorder_number())) {
+ ASSERT(reachable_->Contains(if_false->preorder_number()));
+ ASSERT(branch->comparison()->IsStrictCompare());
+ ASSERT(if_false->parallel_move() == NULL);
+ ASSERT(if_false->loop_info() == NULL);
+ join = new JoinEntryInstr(if_false->try_index());
+ next = if_false->next();
+ } else if (!reachable_->Contains(if_false->preorder_number())) {
+ ASSERT(branch->comparison()->IsStrictCompare());
+ ASSERT(if_true->parallel_move() == NULL);
+ ASSERT(if_true->loop_info() == NULL);
+ join = new JoinEntryInstr(if_true->try_index());
+ next = if_true->next();
+ }
+
+ if (join != NULL) {
+ // Replace the branch with a jump to the reachable successor.
+ // Drop the comparison, which does not have side effects as long
+ // as it is a strict compare (the only one we can determine is
+ // constant with the current analysis).
+ GotoInstr* jump = new GotoInstr(join);
+ // Removing the branch from the graph will leave the iterator in a
+ // state where current is detached from the graph. Since current
+ // has no successors and neither does its replacement, that's
+ // safe.
+ Instruction* previous = branch->previous();
+ branch->set_previous(NULL);
+ previous->set_next(jump);
+ // Replace the false target entry with the new join entry. We will
+ // recompute the dominators after this pass.
+ join->set_next(next);
+ }
+ }
+ }
+ }
+ graph_->DiscoverBlocks();
+ GrowableArray<BitVector*> dominance_frontier;
+ graph_->ComputeDominators(&dominance_frontier);
+
+ // Garbage collect phi inputs corresponding to unreachable predecessors.
+ // This is required because we assume that predecessor and phi indexes
+ // align. Note that this does not necessarily eliminate all useless phis
+ // (e.g., it does not eliminate phis that were originally inserted solely
+ // due to an assignment on the now-unreachable path).
+ for (BlockIterator it = graph_->reverse_postorder_iterator();
+ !it.Done();
+ it.Advance()) {
+ JoinEntryInstr* join = it.Current()->AsJoinEntry();
+ if (join != NULL) join->EliminateUnreachablePhiInputs();
+ }
+
+ graph_->ComputeUseLists();
+}
+
+
} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698