Chromium Code Reviews| Index: runtime/vm/flow_graph_optimizer.cc |
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
| index dc706fb19f158f616617e002052997c5bd041804..5183750c77222d7fb3a3bf252394ec53233a5c2f 100644 |
| --- a/runtime/vm/flow_graph_optimizer.cc |
| +++ b/runtime/vm/flow_graph_optimizer.cc |
| @@ -23,6 +23,8 @@ DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| DECLARE_FLAG(bool, trace_type_check_elimination); |
| DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| +DEFINE_FLAG(bool, trace_constant_propagation, false, |
| + "Print constant propagation and useless code elimination."); |
| void FlowGraphOptimizer::ApplyICData() { |
| VisitBlocks(); |
| @@ -2425,6 +2427,35 @@ void ConstantPropagator::VisitBranch(BranchInstr* instr) { |
| // -------------------------------------------------------------------------- |
| +// Analysis of non-definition instructions. They do not have values so they |
| +// cannot have constant values. |
| +void ConstantPropagator::VisitStoreContext(StoreContextInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitChainContext(ChainContextInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCatchEntry(CatchEntryInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCheckStackOverflow( |
| + CheckStackOverflowInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCheckClass(CheckClassInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCheckEitherNonSmi( |
| + CheckEitherNonSmiInstr* instr) { } |
| + |
| + |
| +void ConstantPropagator::VisitCheckArrayBound(CheckArrayBoundInstr* instr) { } |
| + |
| + |
| +// -------------------------------------------------------------------------- |
| // 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. |
| @@ -2488,11 +2519,6 @@ void ConstantPropagator::VisitCurrentContext(CurrentContextInstr* instr) { |
| } |
| -void ConstantPropagator::VisitStoreContext(StoreContextInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitClosureCall(ClosureCallInstr* instr) { |
| SetValue(instr, non_constant_); |
| } |
| @@ -2515,11 +2541,13 @@ void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) { |
| void ConstantPropagator::VisitLoadLocal(LoadLocalInstr* instr) { |
| + // Instruction is eliminated when translating to SSA. |
| UNREACHABLE(); |
| } |
| void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { |
| + // Instruction is eliminated when translating to SSA. |
| UNREACHABLE(); |
| } |
| @@ -2668,21 +2696,11 @@ void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) { |
| } |
| -void ConstantPropagator::VisitChainContext(ChainContextInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) { |
| SetValue(instr, non_constant_); |
| } |
| -void ConstantPropagator::VisitCatchEntry(CatchEntryInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) { |
| const Object& left = instr->left()->definition()->constant_value(); |
| const Object& right = instr->right()->definition()->constant_value(); |
| @@ -2690,15 +2708,31 @@ void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) { |
| SetValue(instr, non_constant_); |
| } else if (IsConstant(left) && IsConstant(right)) { |
| if (left.IsSmi() && right.IsSmi()) { |
| + const Smi& left_smi = Smi::Cast(left); |
| + const Smi& right_smi = Smi::Cast(right); |
| switch (instr->op_kind()) { |
| case Token::kADD: |
| case Token::kSUB: |
| case Token::kMUL: |
| case Token::kTRUNCDIV: |
| case Token::kMOD: { |
| - const Object& result = |
| - Integer::ZoneHandle(Smi::Cast(left).BinaryOp(instr->op_kind(), |
| - Smi::Cast(right))); |
| + const Object& result = Integer::ZoneHandle( |
| + left_smi.ArithmeticOp(instr->op_kind(), right_smi)); |
| + SetValue(instr, result); |
| + break; |
| + } |
| + case Token::kSHL: |
| + case Token::kSHR: { |
| + const Object& result = Integer::ZoneHandle( |
| + left_smi.ShiftOp(instr->op_kind(), right_smi)); |
| + SetValue(instr, result); |
| + break; |
| + } |
| + case Token::kBIT_AND: |
| + case Token::kBIT_OR: |
| + case Token::kBIT_XOR: { |
| + const Object& result = Integer::ZoneHandle( |
| + left_smi.BitOp(instr->op_kind(), right_smi)); |
| SetValue(instr, result); |
| break; |
| } |
| @@ -2737,12 +2771,6 @@ void ConstantPropagator::VisitUnarySmiOp(UnarySmiOpInstr* instr) { |
| } |
| -void ConstantPropagator::VisitCheckStackOverflow( |
| - CheckStackOverflowInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitDoubleToDouble(DoubleToDoubleInstr* instr) { |
| const Object& value = instr->value()->definition()->constant_value(); |
| if (IsNonConstant(value)) { |
| @@ -2760,16 +2788,6 @@ void ConstantPropagator::VisitSmiToDouble(SmiToDoubleInstr* instr) { |
| } |
| -void ConstantPropagator::VisitCheckClass(CheckClassInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| -void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { |
| - // Nothing to do. Has no value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitConstant(ConstantInstr* instr) { |
| SetValue(instr, instr->value()); |
| } |
| @@ -2781,11 +2799,6 @@ void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { |
| } |
| -void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::VisitUnboxedDoubleBinaryOp( |
| UnboxedDoubleBinaryOpInstr* instr) { |
| const Object& left = instr->left()->definition()->constant_value(); |
| @@ -2832,11 +2845,6 @@ void ConstantPropagator::VisitBoxDouble(BoxDoubleInstr* instr) { |
| } |
| -void ConstantPropagator::VisitCheckArrayBound(CheckArrayBoundInstr* instr) { |
| - // Nothing to do. Not a value. |
| -} |
| - |
| - |
| void ConstantPropagator::Analyze() { |
| GraphEntryInstr* entry = graph_->graph_entry(); |
| reachable_->Add(entry->preorder_number()); |
| @@ -2863,6 +2871,12 @@ void ConstantPropagator::Analyze() { |
| void ConstantPropagator::Transform() { |
| + if (FLAG_trace_constant_propagation) { |
| + OS::Print("\n==== Before constant propagation ====\n"); |
| + FlowGraphPrinter printer(*graph_); |
| + printer.PrintBlocks(); |
| + } |
| + |
| // 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 |
| @@ -2872,6 +2886,9 @@ void ConstantPropagator::Transform() { |
| b.Advance()) { |
| BlockEntryInstr* block = b.Current(); |
| if (!reachable_->Contains(block->preorder_number())) { |
| + if (FLAG_trace_constant_propagation) { |
| + OS::Print("Unreachable B%"Pd"\n", block->block_id()); |
| + } |
| continue; |
| } |
| @@ -2909,17 +2926,23 @@ void ConstantPropagator::Transform() { |
| for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) { |
| Definition* defn = i.Current()->AsDefinition(); |
| - if (defn != NULL && 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. |
| + // Replace constant-valued instructions without observable side |
| + // effects. Do this for smis only to avoid having to copy other |
| + // objects into the heap's old generation. |
|
Florian Schneider
2012/09/24 11:36:17
Maybe add a TODO to extend the analysis for bool-v
Kevin Millikin (Google)
2012/09/24 12:23:46
Done.
|
| + if ((defn != NULL) && |
| + defn->constant_value().IsSmi() && |
| + !defn->IsConstant() && |
| + !defn->IsPushArgument() && |
| + !defn->IsStoreIndexed() && |
| + !defn->IsStoreInstanceField() && |
| + !defn->IsStoreStaticField() && |
| + !defn->IsStoreVMField()) { |
| + if (FLAG_trace_constant_propagation) { |
| + OS::Print("Constant v%"Pd" = %s\n", |
| + defn->ssa_temp_index(), |
| + defn->constant_value().ToCString()); |
| } |
| + i.ReplaceCurrentWith(new ConstantInstr(defn->constant_value())); |
| } |
| } |
| @@ -2953,10 +2976,6 @@ void ConstantPropagator::Transform() { |
| // 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); |
| @@ -2971,6 +2990,12 @@ void ConstantPropagator::Transform() { |
| GrowableArray<BitVector*> dominance_frontier; |
| graph_->ComputeDominators(&dominance_frontier); |
| graph_->ComputeUseLists(); |
| + |
| + if (FLAG_trace_constant_propagation) { |
| + OS::Print("\n==== After constant propagation ====\n"); |
| + FlowGraphPrinter printer(*graph_); |
| + printer.PrintBlocks(); |
| + } |
| } |