| OLD | NEW |
| 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/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 DEFINE_FLAG(int, getter_setter_ratio, 13, | 27 DEFINE_FLAG(int, getter_setter_ratio, 13, |
| 28 "Ratio of getter/setter usage used for double field unboxing heuristics"); | 28 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
| 29 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 29 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 30 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); | 30 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); |
| 31 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 31 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 32 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 32 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 33 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | 33 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
| 34 "Maximum number of polymorphic checks in equality operator," | 34 "Maximum number of polymorphic checks in equality operator," |
| 35 " otherwise use megamorphic dispatch."); | 35 " otherwise use megamorphic dispatch."); |
| 36 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | |
| 37 DEFINE_FLAG(bool, trace_constant_propagation, false, | |
| 38 "Print constant propagation and useless code elimination."); | |
| 39 DEFINE_FLAG(bool, trace_load_optimization, false, | 36 DEFINE_FLAG(bool, trace_load_optimization, false, |
| 40 "Print live sets for load optimization pass."); | 37 "Print live sets for load optimization pass."); |
| 41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 38 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 42 DEFINE_FLAG(bool, truncating_left_shift, true, | 39 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 43 "Optimize left shift to truncate if possible"); | 40 "Optimize left shift to truncate if possible"); |
| 44 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 41 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 45 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) | 42 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) |
| 46 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); | 43 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); |
| 47 #endif | 44 #endif |
| 48 DECLARE_FLAG(bool, enable_type_checks); | 45 DECLARE_FLAG(bool, enable_type_checks); |
| (...skipping 7444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7493 changed = OptimizeRecursive(graph, child, &child_map) || changed; | 7490 changed = OptimizeRecursive(graph, child, &child_map) || changed; |
| 7494 } else { | 7491 } else { |
| 7495 // Reuse map for the last child. | 7492 // Reuse map for the last child. |
| 7496 changed = OptimizeRecursive(graph, child, map) || changed; | 7493 changed = OptimizeRecursive(graph, child, map) || changed; |
| 7497 } | 7494 } |
| 7498 } | 7495 } |
| 7499 return changed; | 7496 return changed; |
| 7500 } | 7497 } |
| 7501 | 7498 |
| 7502 | 7499 |
| 7503 ConstantPropagator::ConstantPropagator( | |
| 7504 FlowGraph* graph, | |
| 7505 const GrowableArray<BlockEntryInstr*>& ignored) | |
| 7506 : FlowGraphVisitor(ignored), | |
| 7507 graph_(graph), | |
| 7508 unknown_(Object::unknown_constant()), | |
| 7509 non_constant_(Object::non_constant()), | |
| 7510 reachable_(new(graph->isolate()) BitVector( | |
| 7511 graph->isolate(), graph->preorder().length())), | |
| 7512 marked_phis_(new(graph->isolate()) BitVector( | |
| 7513 graph->isolate(), graph->max_virtual_register_number())), | |
| 7514 block_worklist_(), | |
| 7515 definition_worklist_(graph, 10) {} | |
| 7516 | |
| 7517 | |
| 7518 void ConstantPropagator::Optimize(FlowGraph* graph) { | |
| 7519 GrowableArray<BlockEntryInstr*> ignored; | |
| 7520 ConstantPropagator cp(graph, ignored); | |
| 7521 cp.Analyze(); | |
| 7522 cp.Transform(); | |
| 7523 } | |
| 7524 | |
| 7525 | |
| 7526 void ConstantPropagator::OptimizeBranches(FlowGraph* graph) { | |
| 7527 GrowableArray<BlockEntryInstr*> ignored; | |
| 7528 ConstantPropagator cp(graph, ignored); | |
| 7529 cp.Analyze(); | |
| 7530 cp.Transform(); | |
| 7531 cp.EliminateRedundantBranches(); | |
| 7532 } | |
| 7533 | |
| 7534 | |
| 7535 void ConstantPropagator::SetReachable(BlockEntryInstr* block) { | |
| 7536 if (!reachable_->Contains(block->preorder_number())) { | |
| 7537 reachable_->Add(block->preorder_number()); | |
| 7538 block_worklist_.Add(block); | |
| 7539 } | |
| 7540 } | |
| 7541 | |
| 7542 | |
| 7543 bool ConstantPropagator::SetValue(Definition* definition, const Object& value) { | |
| 7544 // We would like to assert we only go up (toward non-constant) in the lattice. | |
| 7545 // | |
| 7546 // ASSERT(IsUnknown(definition->constant_value()) || | |
| 7547 // IsNonConstant(value) || | |
| 7548 // (definition->constant_value().raw() == value.raw())); | |
| 7549 // | |
| 7550 // But the final disjunct is not true (e.g., mint or double constants are | |
| 7551 // heap-allocated and so not necessarily pointer-equal on each iteration). | |
| 7552 if (definition->constant_value().raw() != value.raw()) { | |
| 7553 definition->constant_value() = value.raw(); | |
| 7554 if (definition->input_use_list() != NULL) { | |
| 7555 definition_worklist_.Add(definition); | |
| 7556 } | |
| 7557 return true; | |
| 7558 } | |
| 7559 return false; | |
| 7560 } | |
| 7561 | |
| 7562 | |
| 7563 // Compute the join of two values in the lattice, assign it to the first. | |
| 7564 void ConstantPropagator::Join(Object* left, const Object& right) { | |
| 7565 // Join(non-constant, X) = non-constant | |
| 7566 // Join(X, unknown) = X | |
| 7567 if (IsNonConstant(*left) || IsUnknown(right)) return; | |
| 7568 | |
| 7569 // Join(unknown, X) = X | |
| 7570 // Join(X, non-constant) = non-constant | |
| 7571 if (IsUnknown(*left) || IsNonConstant(right)) { | |
| 7572 *left = right.raw(); | |
| 7573 return; | |
| 7574 } | |
| 7575 | |
| 7576 // Join(X, X) = X | |
| 7577 // TODO(kmillikin): support equality for doubles, mints, etc. | |
| 7578 if (left->raw() == right.raw()) return; | |
| 7579 | |
| 7580 // Join(X, Y) = non-constant | |
| 7581 *left = non_constant_.raw(); | |
| 7582 } | |
| 7583 | |
| 7584 | |
| 7585 // -------------------------------------------------------------------------- | |
| 7586 // Analysis of blocks. Called at most once per block. The block is already | |
| 7587 // marked as reachable. All instructions in the block are analyzed. | |
| 7588 void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) { | |
| 7589 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | |
| 7590 for (intptr_t i = 0; i < defs.length(); ++i) { | |
| 7591 defs[i]->Accept(this); | |
| 7592 } | |
| 7593 ASSERT(ForwardInstructionIterator(block).Done()); | |
| 7594 | |
| 7595 // TODO(fschneider): Improve this approximation. The catch entry is only | |
| 7596 // reachable if a call in the try-block is reachable. | |
| 7597 for (intptr_t i = 0; i < block->SuccessorCount(); ++i) { | |
| 7598 SetReachable(block->SuccessorAt(i)); | |
| 7599 } | |
| 7600 } | |
| 7601 | |
| 7602 | |
| 7603 void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) { | |
| 7604 // Phis are visited when visiting Goto at a predecessor. See VisitGoto. | |
| 7605 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 7606 it.Current()->Accept(this); | |
| 7607 } | |
| 7608 } | |
| 7609 | |
| 7610 | |
| 7611 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { | |
| 7612 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 7613 it.Current()->Accept(this); | |
| 7614 } | |
| 7615 } | |
| 7616 | |
| 7617 | |
| 7618 void ConstantPropagator::VisitIndirectEntry(IndirectEntryInstr* block) { | |
| 7619 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 7620 it.Current()->Accept(this); | |
| 7621 } | |
| 7622 } | |
| 7623 | |
| 7624 | |
| 7625 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { | |
| 7626 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | |
| 7627 for (intptr_t i = 0; i < defs.length(); ++i) { | |
| 7628 defs[i]->Accept(this); | |
| 7629 } | |
| 7630 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 7631 it.Current()->Accept(this); | |
| 7632 } | |
| 7633 } | |
| 7634 | |
| 7635 | |
| 7636 void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) { | |
| 7637 // Parallel moves have not yet been inserted in the graph. | |
| 7638 UNREACHABLE(); | |
| 7639 } | |
| 7640 | |
| 7641 | |
| 7642 // -------------------------------------------------------------------------- | |
| 7643 // Analysis of control instructions. Unconditional successors are | |
| 7644 // reachable. Conditional successors are reachable depending on the | |
| 7645 // constant value of the condition. | |
| 7646 void ConstantPropagator::VisitReturn(ReturnInstr* instr) { | |
| 7647 // Nothing to do. | |
| 7648 } | |
| 7649 | |
| 7650 | |
| 7651 void ConstantPropagator::VisitThrow(ThrowInstr* instr) { | |
| 7652 // Nothing to do. | |
| 7653 } | |
| 7654 | |
| 7655 | |
| 7656 void ConstantPropagator::VisitReThrow(ReThrowInstr* instr) { | |
| 7657 // Nothing to do. | |
| 7658 } | |
| 7659 | |
| 7660 | |
| 7661 void ConstantPropagator::VisitGoto(GotoInstr* instr) { | |
| 7662 SetReachable(instr->successor()); | |
| 7663 | |
| 7664 // Phi value depends on the reachability of a predecessor. We have | |
| 7665 // to revisit phis every time a predecessor becomes reachable. | |
| 7666 for (PhiIterator it(instr->successor()); !it.Done(); it.Advance()) { | |
| 7667 it.Current()->Accept(this); | |
| 7668 } | |
| 7669 } | |
| 7670 | |
| 7671 | |
| 7672 void ConstantPropagator::VisitIndirectGoto(IndirectGotoInstr* instr) { | |
| 7673 for (intptr_t i = 0; i < instr->SuccessorCount(); i++) { | |
| 7674 SetReachable(instr->SuccessorAt(i)); | |
| 7675 } | |
| 7676 } | |
| 7677 | |
| 7678 | |
| 7679 void ConstantPropagator::VisitBranch(BranchInstr* instr) { | |
| 7680 instr->comparison()->Accept(this); | |
| 7681 | |
| 7682 // The successors may be reachable, but only if this instruction is. (We | |
| 7683 // might be analyzing it because the constant value of one of its inputs | |
| 7684 // has changed.) | |
| 7685 if (reachable_->Contains(instr->GetBlock()->preorder_number())) { | |
| 7686 if (instr->constant_target() != NULL) { | |
| 7687 ASSERT((instr->constant_target() == instr->true_successor()) || | |
| 7688 (instr->constant_target() == instr->false_successor())); | |
| 7689 SetReachable(instr->constant_target()); | |
| 7690 } else { | |
| 7691 const Object& value = instr->comparison()->constant_value(); | |
| 7692 if (IsNonConstant(value)) { | |
| 7693 SetReachable(instr->true_successor()); | |
| 7694 SetReachable(instr->false_successor()); | |
| 7695 } else if (value.raw() == Bool::True().raw()) { | |
| 7696 SetReachable(instr->true_successor()); | |
| 7697 } else if (!IsUnknown(value)) { // Any other constant. | |
| 7698 SetReachable(instr->false_successor()); | |
| 7699 } | |
| 7700 } | |
| 7701 } | |
| 7702 } | |
| 7703 | |
| 7704 | |
| 7705 // -------------------------------------------------------------------------- | |
| 7706 // Analysis of non-definition instructions. They do not have values so they | |
| 7707 // cannot have constant values. | |
| 7708 void ConstantPropagator::VisitCheckStackOverflow( | |
| 7709 CheckStackOverflowInstr* instr) { } | |
| 7710 | |
| 7711 | |
| 7712 void ConstantPropagator::VisitCheckClass(CheckClassInstr* instr) { } | |
| 7713 | |
| 7714 | |
| 7715 void ConstantPropagator::VisitCheckClassId(CheckClassIdInstr* instr) { } | |
| 7716 | |
| 7717 | |
| 7718 void ConstantPropagator::VisitGuardFieldClass(GuardFieldClassInstr* instr) { } | |
| 7719 | |
| 7720 | |
| 7721 void ConstantPropagator::VisitGuardFieldLength(GuardFieldLengthInstr* instr) { } | |
| 7722 | |
| 7723 | |
| 7724 void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { } | |
| 7725 | |
| 7726 | |
| 7727 void ConstantPropagator::VisitCheckEitherNonSmi( | |
| 7728 CheckEitherNonSmiInstr* instr) { } | |
| 7729 | |
| 7730 | |
| 7731 void ConstantPropagator::VisitCheckArrayBound(CheckArrayBoundInstr* instr) { } | |
| 7732 | |
| 7733 | |
| 7734 void ConstantPropagator::VisitDeoptimize(DeoptimizeInstr* instr) { | |
| 7735 // TODO(vegorov) remove all code after DeoptimizeInstr as dead. | |
| 7736 } | |
| 7737 | |
| 7738 | |
| 7739 Definition* ConstantPropagator::UnwrapPhi(Definition* defn) { | |
| 7740 if (defn->IsPhi()) { | |
| 7741 JoinEntryInstr* block = defn->AsPhi()->block(); | |
| 7742 | |
| 7743 Definition* input = NULL; | |
| 7744 for (intptr_t i = 0; i < defn->InputCount(); ++i) { | |
| 7745 if (reachable_->Contains(block->PredecessorAt(i)->preorder_number())) { | |
| 7746 if (input == NULL) { | |
| 7747 input = defn->InputAt(i)->definition(); | |
| 7748 } else { | |
| 7749 return defn; | |
| 7750 } | |
| 7751 } | |
| 7752 } | |
| 7753 | |
| 7754 return input; | |
| 7755 } | |
| 7756 | |
| 7757 return defn; | |
| 7758 } | |
| 7759 | |
| 7760 | |
| 7761 void ConstantPropagator::MarkPhi(Definition* phi) { | |
| 7762 ASSERT(phi->IsPhi()); | |
| 7763 marked_phis_->Add(phi->ssa_temp_index()); | |
| 7764 } | |
| 7765 | |
| 7766 | |
| 7767 // -------------------------------------------------------------------------- | |
| 7768 // Analysis of definitions. Compute the constant value. If it has changed | |
| 7769 // and the definition has input uses, add the definition to the definition | |
| 7770 // worklist so that the used can be processed. | |
| 7771 void ConstantPropagator::VisitPhi(PhiInstr* instr) { | |
| 7772 // Compute the join over all the reachable predecessor values. | |
| 7773 JoinEntryInstr* block = instr->block(); | |
| 7774 Object& value = Object::ZoneHandle(I, Unknown()); | |
| 7775 for (intptr_t pred_idx = 0; pred_idx < instr->InputCount(); ++pred_idx) { | |
| 7776 if (reachable_->Contains( | |
| 7777 block->PredecessorAt(pred_idx)->preorder_number())) { | |
| 7778 Join(&value, | |
| 7779 instr->InputAt(pred_idx)->definition()->constant_value()); | |
| 7780 } | |
| 7781 } | |
| 7782 if (!SetValue(instr, value) && | |
| 7783 marked_phis_->Contains(instr->ssa_temp_index())) { | |
| 7784 marked_phis_->Remove(instr->ssa_temp_index()); | |
| 7785 definition_worklist_.Add(instr); | |
| 7786 } | |
| 7787 } | |
| 7788 | |
| 7789 | |
| 7790 void ConstantPropagator::VisitRedefinition(RedefinitionInstr* instr) { | |
| 7791 SetValue(instr, instr->value()->definition()->constant_value()); | |
| 7792 } | |
| 7793 | |
| 7794 | |
| 7795 void ConstantPropagator::VisitParameter(ParameterInstr* instr) { | |
| 7796 SetValue(instr, non_constant_); | |
| 7797 } | |
| 7798 | |
| 7799 | |
| 7800 void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) { | |
| 7801 SetValue(instr, instr->value()->definition()->constant_value()); | |
| 7802 } | |
| 7803 | |
| 7804 | |
| 7805 void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) { | |
| 7806 const Object& value = instr->value()->definition()->constant_value(); | |
| 7807 if (IsNonConstant(value)) { | |
| 7808 SetValue(instr, non_constant_); | |
| 7809 } else if (IsConstant(value)) { | |
| 7810 // We are ignoring the instantiator and instantiator_type_arguments, but | |
| 7811 // still monotonic and safe. | |
| 7812 if (instr->value()->Type()->IsAssignableTo(instr->dst_type())) { | |
| 7813 SetValue(instr, value); | |
| 7814 } else { | |
| 7815 SetValue(instr, non_constant_); | |
| 7816 } | |
| 7817 } | |
| 7818 } | |
| 7819 | |
| 7820 | |
| 7821 void ConstantPropagator::VisitAssertBoolean(AssertBooleanInstr* instr) { | |
| 7822 const Object& value = instr->value()->definition()->constant_value(); | |
| 7823 if (IsNonConstant(value)) { | |
| 7824 SetValue(instr, non_constant_); | |
| 7825 } else if (IsConstant(value)) { | |
| 7826 if (value.IsBool()) { | |
| 7827 SetValue(instr, value); | |
| 7828 } else { | |
| 7829 SetValue(instr, non_constant_); | |
| 7830 } | |
| 7831 } | |
| 7832 } | |
| 7833 | |
| 7834 | |
| 7835 void ConstantPropagator::VisitCurrentContext(CurrentContextInstr* instr) { | |
| 7836 SetValue(instr, non_constant_); | |
| 7837 } | |
| 7838 | |
| 7839 | |
| 7840 void ConstantPropagator::VisitClosureCall(ClosureCallInstr* instr) { | |
| 7841 SetValue(instr, non_constant_); | |
| 7842 } | |
| 7843 | |
| 7844 | |
| 7845 void ConstantPropagator::VisitInstanceCall(InstanceCallInstr* instr) { | |
| 7846 SetValue(instr, non_constant_); | |
| 7847 } | |
| 7848 | |
| 7849 | |
| 7850 void ConstantPropagator::VisitPolymorphicInstanceCall( | |
| 7851 PolymorphicInstanceCallInstr* instr) { | |
| 7852 SetValue(instr, non_constant_); | |
| 7853 } | |
| 7854 | |
| 7855 | |
| 7856 void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) { | |
| 7857 SetValue(instr, non_constant_); | |
| 7858 } | |
| 7859 | |
| 7860 | |
| 7861 void ConstantPropagator::VisitLoadLocal(LoadLocalInstr* instr) { | |
| 7862 // Instruction is eliminated when translating to SSA. | |
| 7863 UNREACHABLE(); | |
| 7864 } | |
| 7865 | |
| 7866 | |
| 7867 void ConstantPropagator::VisitPushTemp(PushTempInstr* instr) { | |
| 7868 // Instruction is eliminated when translating to SSA. | |
| 7869 UNREACHABLE(); | |
| 7870 } | |
| 7871 | |
| 7872 | |
| 7873 void ConstantPropagator::VisitDropTemps(DropTempsInstr* instr) { | |
| 7874 // Instruction is eliminated when translating to SSA. | |
| 7875 UNREACHABLE(); | |
| 7876 } | |
| 7877 | |
| 7878 | |
| 7879 void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { | |
| 7880 // Instruction is eliminated when translating to SSA. | |
| 7881 UNREACHABLE(); | |
| 7882 } | |
| 7883 | |
| 7884 | |
| 7885 void ConstantPropagator::VisitIfThenElse(IfThenElseInstr* instr) { | |
| 7886 instr->comparison()->Accept(this); | |
| 7887 const Object& value = instr->comparison()->constant_value(); | |
| 7888 if (IsNonConstant(value)) { | |
| 7889 SetValue(instr, non_constant_); | |
| 7890 } else if (IsConstant(value)) { | |
| 7891 ASSERT(!value.IsNull()); | |
| 7892 ASSERT(value.IsBool()); | |
| 7893 bool result = Bool::Cast(value).value(); | |
| 7894 SetValue(instr, | |
| 7895 Smi::Handle(I, Smi::New( | |
| 7896 result ? instr->if_true() : instr->if_false()))); | |
| 7897 } | |
| 7898 } | |
| 7899 | |
| 7900 | |
| 7901 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { | |
| 7902 Definition* left_defn = instr->left()->definition(); | |
| 7903 Definition* right_defn = instr->right()->definition(); | |
| 7904 | |
| 7905 Definition* unwrapped_left_defn = UnwrapPhi(left_defn); | |
| 7906 Definition* unwrapped_right_defn = UnwrapPhi(right_defn); | |
| 7907 if (unwrapped_left_defn == unwrapped_right_defn) { | |
| 7908 // Fold x === x, and x !== x to true/false. | |
| 7909 SetValue(instr, Bool::Get(instr->kind() == Token::kEQ_STRICT)); | |
| 7910 if (unwrapped_left_defn != left_defn) { | |
| 7911 MarkPhi(left_defn); | |
| 7912 } | |
| 7913 if (unwrapped_right_defn != right_defn) { | |
| 7914 MarkPhi(right_defn); | |
| 7915 } | |
| 7916 return; | |
| 7917 } | |
| 7918 | |
| 7919 const Object& left = left_defn->constant_value(); | |
| 7920 const Object& right = right_defn->constant_value(); | |
| 7921 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 7922 // TODO(vegorov): incorporate nullability information into the lattice. | |
| 7923 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || | |
| 7924 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { | |
| 7925 bool result = left.IsNull() ? instr->right()->Type()->IsNull() | |
| 7926 : instr->left()->Type()->IsNull(); | |
| 7927 if (instr->kind() == Token::kNE_STRICT) { | |
| 7928 result = !result; | |
| 7929 } | |
| 7930 SetValue(instr, Bool::Get(result)); | |
| 7931 } else { | |
| 7932 const intptr_t left_cid = instr->left()->Type()->ToCid(); | |
| 7933 const intptr_t right_cid = instr->right()->Type()->ToCid(); | |
| 7934 // If exact classes (cids) are known and they differ, the result | |
| 7935 // of strict compare can be computed. | |
| 7936 if ((left_cid != kDynamicCid) && (right_cid != kDynamicCid) && | |
| 7937 (left_cid != right_cid)) { | |
| 7938 const bool result = (instr->kind() != Token::kEQ_STRICT); | |
| 7939 SetValue(instr, Bool::Get(result)); | |
| 7940 } else { | |
| 7941 SetValue(instr, non_constant_); | |
| 7942 } | |
| 7943 } | |
| 7944 } else if (IsConstant(left) && IsConstant(right)) { | |
| 7945 bool result = (left.raw() == right.raw()); | |
| 7946 if (instr->kind() == Token::kNE_STRICT) { | |
| 7947 result = !result; | |
| 7948 } | |
| 7949 SetValue(instr, Bool::Get(result)); | |
| 7950 } | |
| 7951 } | |
| 7952 | |
| 7953 | |
| 7954 static bool CompareIntegers(Token::Kind kind, | |
| 7955 const Integer& left, | |
| 7956 const Integer& right) { | |
| 7957 const int result = left.CompareWith(right); | |
| 7958 switch (kind) { | |
| 7959 case Token::kEQ: return (result == 0); | |
| 7960 case Token::kNE: return (result != 0); | |
| 7961 case Token::kLT: return (result < 0); | |
| 7962 case Token::kGT: return (result > 0); | |
| 7963 case Token::kLTE: return (result <= 0); | |
| 7964 case Token::kGTE: return (result >= 0); | |
| 7965 default: | |
| 7966 UNREACHABLE(); | |
| 7967 return false; | |
| 7968 } | |
| 7969 } | |
| 7970 | |
| 7971 | |
| 7972 void ConstantPropagator::VisitTestSmi(TestSmiInstr* instr) { | |
| 7973 const Object& left = instr->left()->definition()->constant_value(); | |
| 7974 const Object& right = instr->right()->definition()->constant_value(); | |
| 7975 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 7976 SetValue(instr, non_constant_); | |
| 7977 } else if (IsConstant(left) && IsConstant(right)) { | |
| 7978 if (left.IsInteger() && right.IsInteger()) { | |
| 7979 const bool result = CompareIntegers( | |
| 7980 instr->kind(), | |
| 7981 Integer::Handle(I, Integer::Cast(left).BitOp(Token::kBIT_AND, | |
| 7982 Integer::Cast(right))), | |
| 7983 Smi::Handle(I, Smi::New(0))); | |
| 7984 SetValue(instr, result ? Bool::True() : Bool::False()); | |
| 7985 } else { | |
| 7986 SetValue(instr, non_constant_); | |
| 7987 } | |
| 7988 } | |
| 7989 } | |
| 7990 | |
| 7991 | |
| 7992 void ConstantPropagator::VisitTestCids(TestCidsInstr* instr) { | |
| 7993 SetValue(instr, non_constant_); | |
| 7994 } | |
| 7995 | |
| 7996 | |
| 7997 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | |
| 7998 Definition* left_defn = instr->left()->definition(); | |
| 7999 Definition* right_defn = instr->right()->definition(); | |
| 8000 | |
| 8001 if (RawObject::IsIntegerClassId(instr->operation_cid())) { | |
| 8002 // Fold x == x, and x != x to true/false for numbers comparisons. | |
| 8003 Definition* unwrapped_left_defn = UnwrapPhi(left_defn); | |
| 8004 Definition* unwrapped_right_defn = UnwrapPhi(right_defn); | |
| 8005 if (unwrapped_left_defn == unwrapped_right_defn) { | |
| 8006 // Fold x === x, and x !== x to true/false. | |
| 8007 SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); | |
| 8008 if (unwrapped_left_defn != left_defn) { | |
| 8009 MarkPhi(left_defn); | |
| 8010 } | |
| 8011 if (unwrapped_right_defn != right_defn) { | |
| 8012 MarkPhi(right_defn); | |
| 8013 } | |
| 8014 return; | |
| 8015 } | |
| 8016 } | |
| 8017 | |
| 8018 const Object& left = left_defn->constant_value(); | |
| 8019 const Object& right = right_defn->constant_value(); | |
| 8020 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 8021 SetValue(instr, non_constant_); | |
| 8022 } else if (IsConstant(left) && IsConstant(right)) { | |
| 8023 if (left.IsInteger() && right.IsInteger()) { | |
| 8024 const bool result = CompareIntegers(instr->kind(), | |
| 8025 Integer::Cast(left), | |
| 8026 Integer::Cast(right)); | |
| 8027 SetValue(instr, Bool::Get(result)); | |
| 8028 } else if (left.IsString() && right.IsString()) { | |
| 8029 const bool result = String::Cast(left).Equals(String::Cast(right)); | |
| 8030 SetValue(instr, Bool::Get((instr->kind() == Token::kEQ) == result)); | |
| 8031 } else { | |
| 8032 SetValue(instr, non_constant_); | |
| 8033 } | |
| 8034 } | |
| 8035 } | |
| 8036 | |
| 8037 | |
| 8038 void ConstantPropagator::VisitRelationalOp(RelationalOpInstr* instr) { | |
| 8039 const Object& left = instr->left()->definition()->constant_value(); | |
| 8040 const Object& right = instr->right()->definition()->constant_value(); | |
| 8041 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 8042 SetValue(instr, non_constant_); | |
| 8043 } else if (IsConstant(left) && IsConstant(right)) { | |
| 8044 if (left.IsInteger() && right.IsInteger()) { | |
| 8045 const bool result = CompareIntegers(instr->kind(), | |
| 8046 Integer::Cast(left), | |
| 8047 Integer::Cast(right)); | |
| 8048 SetValue(instr, Bool::Get(result)); | |
| 8049 } else if (left.IsDouble() && right.IsDouble()) { | |
| 8050 // TODO(srdjan): Implement. | |
| 8051 SetValue(instr, non_constant_); | |
| 8052 } else { | |
| 8053 SetValue(instr, non_constant_); | |
| 8054 } | |
| 8055 } | |
| 8056 } | |
| 8057 | |
| 8058 | |
| 8059 void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) { | |
| 8060 SetValue(instr, non_constant_); | |
| 8061 } | |
| 8062 | |
| 8063 | |
| 8064 void ConstantPropagator::VisitDebugStepCheck(DebugStepCheckInstr* instr) { | |
| 8065 // Nothing to do. | |
| 8066 } | |
| 8067 | |
| 8068 | |
| 8069 void ConstantPropagator::VisitStringFromCharCode( | |
| 8070 StringFromCharCodeInstr* instr) { | |
| 8071 const Object& o = instr->char_code()->definition()->constant_value(); | |
| 8072 if (o.IsNull() || IsNonConstant(o)) { | |
| 8073 SetValue(instr, non_constant_); | |
| 8074 } else if (IsConstant(o)) { | |
| 8075 const intptr_t ch_code = Smi::Cast(o).Value(); | |
| 8076 ASSERT(ch_code >= 0); | |
| 8077 if (ch_code < Symbols::kMaxOneCharCodeSymbol) { | |
| 8078 RawString** table = Symbols::PredefinedAddress(); | |
| 8079 SetValue(instr, String::ZoneHandle(I, table[ch_code])); | |
| 8080 } else { | |
| 8081 SetValue(instr, non_constant_); | |
| 8082 } | |
| 8083 } | |
| 8084 } | |
| 8085 | |
| 8086 | |
| 8087 void ConstantPropagator::VisitStringToCharCode(StringToCharCodeInstr* instr) { | |
| 8088 const Object& o = instr->str()->definition()->constant_value(); | |
| 8089 if (o.IsNull() || IsNonConstant(o)) { | |
| 8090 SetValue(instr, non_constant_); | |
| 8091 } else if (IsConstant(o)) { | |
| 8092 const String& str = String::Cast(o); | |
| 8093 const intptr_t result = | |
| 8094 (str.Length() == 1) ? static_cast<intptr_t>(str.CharAt(0)) : -1; | |
| 8095 SetValue(instr, Smi::ZoneHandle(I, Smi::New(result))); | |
| 8096 } | |
| 8097 } | |
| 8098 | |
| 8099 | |
| 8100 void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) { | |
| 8101 SetValue(instr, non_constant_); | |
| 8102 } | |
| 8103 | |
| 8104 | |
| 8105 void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) { | |
| 8106 const Object& array_obj = instr->array()->definition()->constant_value(); | |
| 8107 const Object& index_obj = instr->index()->definition()->constant_value(); | |
| 8108 if (IsNonConstant(array_obj) || IsNonConstant(index_obj)) { | |
| 8109 SetValue(instr, non_constant_); | |
| 8110 } else if (IsConstant(array_obj) && IsConstant(index_obj)) { | |
| 8111 // Need index to be Smi and array to be either String or an immutable array. | |
| 8112 if (!index_obj.IsSmi()) { | |
| 8113 // Should not occur. | |
| 8114 SetValue(instr, non_constant_); | |
| 8115 return; | |
| 8116 } | |
| 8117 const intptr_t index = Smi::Cast(index_obj).Value(); | |
| 8118 if (index >= 0) { | |
| 8119 if (array_obj.IsString()) { | |
| 8120 const String& str = String::Cast(array_obj); | |
| 8121 if (str.Length() > index) { | |
| 8122 SetValue(instr, Smi::Handle(I, | |
| 8123 Smi::New(static_cast<intptr_t>(str.CharAt(index))))); | |
| 8124 return; | |
| 8125 } | |
| 8126 } else if (array_obj.IsArray()) { | |
| 8127 const Array& a = Array::Cast(array_obj); | |
| 8128 if ((a.Length() > index) && a.IsImmutable()) { | |
| 8129 Instance& result = Instance::Handle(I); | |
| 8130 result ^= a.At(index); | |
| 8131 SetValue(instr, result); | |
| 8132 return; | |
| 8133 } | |
| 8134 } | |
| 8135 } | |
| 8136 SetValue(instr, non_constant_); | |
| 8137 } | |
| 8138 } | |
| 8139 | |
| 8140 | |
| 8141 void ConstantPropagator::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | |
| 8142 // TODO(zerny): Implement constant propagation. | |
| 8143 SetValue(instr, non_constant_); | |
| 8144 } | |
| 8145 | |
| 8146 | |
| 8147 void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) { | |
| 8148 SetValue(instr, instr->value()->definition()->constant_value()); | |
| 8149 } | |
| 8150 | |
| 8151 | |
| 8152 void ConstantPropagator::VisitStoreInstanceField( | |
| 8153 StoreInstanceFieldInstr* instr) { | |
| 8154 SetValue(instr, instr->value()->definition()->constant_value()); | |
| 8155 } | |
| 8156 | |
| 8157 | |
| 8158 void ConstantPropagator::VisitInitStaticField(InitStaticFieldInstr* instr) { | |
| 8159 // Nothing to do. | |
| 8160 } | |
| 8161 | |
| 8162 | |
| 8163 void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) { | |
| 8164 const Field& field = instr->StaticField(); | |
| 8165 ASSERT(field.is_static()); | |
| 8166 if (field.is_final()) { | |
| 8167 Instance& obj = Instance::Handle(I, field.value()); | |
| 8168 ASSERT(obj.raw() != Object::sentinel().raw()); | |
| 8169 ASSERT(obj.raw() != Object::transition_sentinel().raw()); | |
| 8170 if (obj.IsSmi() || obj.IsOld()) { | |
| 8171 SetValue(instr, obj); | |
| 8172 return; | |
| 8173 } | |
| 8174 } | |
| 8175 SetValue(instr, non_constant_); | |
| 8176 } | |
| 8177 | |
| 8178 | |
| 8179 void ConstantPropagator::VisitStoreStaticField(StoreStaticFieldInstr* instr) { | |
| 8180 SetValue(instr, instr->value()->definition()->constant_value()); | |
| 8181 } | |
| 8182 | |
| 8183 | |
| 8184 void ConstantPropagator::VisitBooleanNegate(BooleanNegateInstr* instr) { | |
| 8185 const Object& value = instr->value()->definition()->constant_value(); | |
| 8186 if (IsNonConstant(value)) { | |
| 8187 SetValue(instr, non_constant_); | |
| 8188 } else if (IsConstant(value)) { | |
| 8189 bool val = value.raw() != Bool::True().raw(); | |
| 8190 SetValue(instr, Bool::Get(val)); | |
| 8191 } | |
| 8192 } | |
| 8193 | |
| 8194 | |
| 8195 void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) { | |
| 8196 const Definition* def = instr->value()->definition(); | |
| 8197 const Object& value = def->constant_value(); | |
| 8198 if (IsNonConstant(value)) { | |
| 8199 const AbstractType& checked_type = instr->type(); | |
| 8200 intptr_t value_cid = instr->value()->Type()->ToCid(); | |
| 8201 Representation rep = def->representation(); | |
| 8202 if ((checked_type.IsFloat32x4Type() && (rep == kUnboxedFloat32x4)) || | |
| 8203 (checked_type.IsInt32x4Type() && (rep == kUnboxedInt32x4)) || | |
| 8204 (checked_type.IsDoubleType() && (rep == kUnboxedDouble) && | |
| 8205 CanUnboxDouble()) || | |
| 8206 (checked_type.IsIntType() && (rep == kUnboxedMint))) { | |
| 8207 // Ensure that compile time type matches representation. | |
| 8208 ASSERT(((rep == kUnboxedFloat32x4) && (value_cid == kFloat32x4Cid)) || | |
| 8209 ((rep == kUnboxedInt32x4) && (value_cid == kInt32x4Cid)) || | |
| 8210 ((rep == kUnboxedDouble) && (value_cid == kDoubleCid)) || | |
| 8211 ((rep == kUnboxedMint) && (value_cid == kMintCid))); | |
| 8212 // The representation guarantees the type check to be true. | |
| 8213 SetValue(instr, instr->negate_result() ? Bool::False() : Bool::True()); | |
| 8214 } else { | |
| 8215 SetValue(instr, non_constant_); | |
| 8216 } | |
| 8217 } else if (IsConstant(value)) { | |
| 8218 // TODO(kmillikin): Handle instanceof on constants. | |
| 8219 SetValue(instr, non_constant_); | |
| 8220 } | |
| 8221 } | |
| 8222 | |
| 8223 | |
| 8224 void ConstantPropagator::VisitCreateArray(CreateArrayInstr* instr) { | |
| 8225 SetValue(instr, non_constant_); | |
| 8226 } | |
| 8227 | |
| 8228 | |
| 8229 void ConstantPropagator::VisitAllocateObject(AllocateObjectInstr* instr) { | |
| 8230 SetValue(instr, non_constant_); | |
| 8231 } | |
| 8232 | |
| 8233 | |
| 8234 void ConstantPropagator::VisitLoadUntagged(LoadUntaggedInstr* instr) { | |
| 8235 SetValue(instr, non_constant_); | |
| 8236 } | |
| 8237 | |
| 8238 | |
| 8239 void ConstantPropagator::VisitLoadClassId(LoadClassIdInstr* instr) { | |
| 8240 intptr_t cid = instr->object()->Type()->ToCid(); | |
| 8241 if (cid != kDynamicCid) { | |
| 8242 SetValue(instr, Smi::ZoneHandle(I, Smi::New(cid))); | |
| 8243 return; | |
| 8244 } | |
| 8245 const Object& object = instr->object()->definition()->constant_value(); | |
| 8246 if (IsConstant(object)) { | |
| 8247 SetValue(instr, Smi::ZoneHandle(I, Smi::New(object.GetClassId()))); | |
| 8248 return; | |
| 8249 } | |
| 8250 SetValue(instr, non_constant_); | |
| 8251 } | |
| 8252 | |
| 8253 | |
| 8254 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) { | |
| 8255 Value* instance = instr->instance(); | |
| 8256 if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) && | |
| 8257 instance->definition()->OriginalDefinition()->IsCreateArray()) { | |
| 8258 Value* num_elements = instance->definition()->OriginalDefinition() | |
| 8259 ->AsCreateArray()->num_elements(); | |
| 8260 if (num_elements->BindsToConstant() && | |
| 8261 num_elements->BoundConstant().IsSmi()) { | |
| 8262 intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); | |
| 8263 const Object& result = Smi::ZoneHandle(I, Smi::New(length)); | |
| 8264 SetValue(instr, result); | |
| 8265 return; | |
| 8266 } | |
| 8267 } | |
| 8268 | |
| 8269 if (instr->IsImmutableLengthLoad()) { | |
| 8270 ConstantInstr* constant = | |
| 8271 instance->definition()->OriginalDefinition()->AsConstant(); | |
| 8272 if (constant != NULL) { | |
| 8273 if (constant->value().IsString()) { | |
| 8274 SetValue(instr, Smi::ZoneHandle(I, | |
| 8275 Smi::New(String::Cast(constant->value()).Length()))); | |
| 8276 return; | |
| 8277 } | |
| 8278 if (constant->value().IsArray()) { | |
| 8279 SetValue(instr, Smi::ZoneHandle(I, | |
| 8280 Smi::New(Array::Cast(constant->value()).Length()))); | |
| 8281 return; | |
| 8282 } | |
| 8283 } | |
| 8284 } | |
| 8285 SetValue(instr, non_constant_); | |
| 8286 } | |
| 8287 | |
| 8288 | |
| 8289 void ConstantPropagator::VisitInstantiateType(InstantiateTypeInstr* instr) { | |
| 8290 const Object& object = | |
| 8291 instr->instantiator()->definition()->constant_value(); | |
| 8292 if (IsNonConstant(object)) { | |
| 8293 SetValue(instr, non_constant_); | |
| 8294 return; | |
| 8295 } | |
| 8296 if (IsConstant(object)) { | |
| 8297 if (instr->type().IsTypeParameter()) { | |
| 8298 if (object.IsNull()) { | |
| 8299 SetValue(instr, Type::ZoneHandle(I, Type::DynamicType())); | |
| 8300 return; | |
| 8301 } | |
| 8302 // We could try to instantiate the type parameter and return it if no | |
| 8303 // malformed error is reported. | |
| 8304 } | |
| 8305 SetValue(instr, non_constant_); | |
| 8306 } | |
| 8307 } | |
| 8308 | |
| 8309 | |
| 8310 void ConstantPropagator::VisitInstantiateTypeArguments( | |
| 8311 InstantiateTypeArgumentsInstr* instr) { | |
| 8312 const Object& object = | |
| 8313 instr->instantiator()->definition()->constant_value(); | |
| 8314 if (IsNonConstant(object)) { | |
| 8315 SetValue(instr, non_constant_); | |
| 8316 return; | |
| 8317 } | |
| 8318 if (IsConstant(object)) { | |
| 8319 const intptr_t len = instr->type_arguments().Length(); | |
| 8320 if (instr->type_arguments().IsRawInstantiatedRaw(len) && | |
| 8321 object.IsNull()) { | |
| 8322 SetValue(instr, object); | |
| 8323 return; | |
| 8324 } | |
| 8325 if (instr->type_arguments().IsUninstantiatedIdentity() || | |
| 8326 instr->type_arguments().CanShareInstantiatorTypeArguments( | |
| 8327 instr->instantiator_class())) { | |
| 8328 SetValue(instr, object); | |
| 8329 return; | |
| 8330 } | |
| 8331 SetValue(instr, non_constant_); | |
| 8332 } | |
| 8333 } | |
| 8334 | |
| 8335 | |
| 8336 void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) { | |
| 8337 SetValue(instr, non_constant_); | |
| 8338 } | |
| 8339 | |
| 8340 | |
| 8341 void ConstantPropagator::VisitAllocateUninitializedContext( | |
| 8342 AllocateUninitializedContextInstr* instr) { | |
| 8343 SetValue(instr, non_constant_); | |
| 8344 } | |
| 8345 | |
| 8346 | |
| 8347 void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) { | |
| 8348 SetValue(instr, non_constant_); | |
| 8349 } | |
| 8350 | |
| 8351 | |
| 8352 void ConstantPropagator::VisitBinaryIntegerOp(BinaryIntegerOpInstr* binary_op) { | |
| 8353 const Object& left = binary_op->left()->definition()->constant_value(); | |
| 8354 const Object& right = binary_op->right()->definition()->constant_value(); | |
| 8355 if (IsConstant(left) && IsConstant(right)) { | |
| 8356 if (left.IsInteger() && right.IsInteger()) { | |
| 8357 const Integer& left_int = Integer::Cast(left); | |
| 8358 const Integer& right_int = Integer::Cast(right); | |
| 8359 const Integer& result = | |
| 8360 Integer::Handle(I, binary_op->Evaluate(left_int, right_int)); | |
| 8361 if (!result.IsNull()) { | |
| 8362 SetValue(binary_op, Integer::ZoneHandle(I, result.raw())); | |
| 8363 return; | |
| 8364 } | |
| 8365 } | |
| 8366 } | |
| 8367 | |
| 8368 SetValue(binary_op, non_constant_); | |
| 8369 } | |
| 8370 | |
| 8371 | |
| 8372 void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) { | |
| 8373 VisitBinaryIntegerOp(instr); | |
| 8374 } | |
| 8375 | |
| 8376 | |
| 8377 void ConstantPropagator::VisitBinaryInt32Op(BinaryInt32OpInstr* instr) { | |
| 8378 VisitBinaryIntegerOp(instr); | |
| 8379 } | |
| 8380 | |
| 8381 | |
| 8382 void ConstantPropagator::VisitBinaryUint32Op(BinaryUint32OpInstr* instr) { | |
| 8383 VisitBinaryIntegerOp(instr); | |
| 8384 } | |
| 8385 | |
| 8386 | |
| 8387 void ConstantPropagator::VisitShiftUint32Op(ShiftUint32OpInstr* instr) { | |
| 8388 VisitBinaryIntegerOp(instr); | |
| 8389 } | |
| 8390 | |
| 8391 | |
| 8392 void ConstantPropagator::VisitBinaryMintOp(BinaryMintOpInstr* instr) { | |
| 8393 VisitBinaryIntegerOp(instr); | |
| 8394 } | |
| 8395 | |
| 8396 | |
| 8397 void ConstantPropagator::VisitShiftMintOp(ShiftMintOpInstr* instr) { | |
| 8398 VisitBinaryIntegerOp(instr); | |
| 8399 } | |
| 8400 | |
| 8401 | |
| 8402 void ConstantPropagator::VisitBoxInt64(BoxInt64Instr* instr) { | |
| 8403 // TODO(kmillikin): Handle box operation. | |
| 8404 SetValue(instr, non_constant_); | |
| 8405 } | |
| 8406 | |
| 8407 | |
| 8408 void ConstantPropagator::VisitUnboxInt64(UnboxInt64Instr* instr) { | |
| 8409 // TODO(kmillikin): Handle unbox operation. | |
| 8410 SetValue(instr, non_constant_); | |
| 8411 } | |
| 8412 | |
| 8413 | |
| 8414 void ConstantPropagator::VisitUnaryMintOp(UnaryMintOpInstr* instr) { | |
| 8415 // TODO(kmillikin): Handle unary operations. | |
| 8416 SetValue(instr, non_constant_); | |
| 8417 } | |
| 8418 | |
| 8419 | |
| 8420 void ConstantPropagator::VisitUnarySmiOp(UnarySmiOpInstr* instr) { | |
| 8421 const Object& value = instr->value()->definition()->constant_value(); | |
| 8422 if (IsNonConstant(value)) { | |
| 8423 SetValue(instr, non_constant_); | |
| 8424 } else if (IsConstant(value)) { | |
| 8425 // TODO(kmillikin): Handle unary operations. | |
| 8426 SetValue(instr, non_constant_); | |
| 8427 } | |
| 8428 } | |
| 8429 | |
| 8430 | |
| 8431 void ConstantPropagator::VisitUnaryDoubleOp(UnaryDoubleOpInstr* instr) { | |
| 8432 const Object& value = instr->value()->definition()->constant_value(); | |
| 8433 if (IsNonConstant(value)) { | |
| 8434 SetValue(instr, non_constant_); | |
| 8435 } else if (IsConstant(value)) { | |
| 8436 // TODO(kmillikin): Handle unary operations. | |
| 8437 SetValue(instr, non_constant_); | |
| 8438 } | |
| 8439 } | |
| 8440 | |
| 8441 | |
| 8442 void ConstantPropagator::VisitSmiToDouble(SmiToDoubleInstr* instr) { | |
| 8443 const Object& value = instr->value()->definition()->constant_value(); | |
| 8444 if (IsConstant(value) && value.IsInteger()) { | |
| 8445 SetValue(instr, Double::Handle(I, | |
| 8446 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld))); | |
| 8447 } else if (IsNonConstant(value)) { | |
| 8448 SetValue(instr, non_constant_); | |
| 8449 } | |
| 8450 } | |
| 8451 | |
| 8452 | |
| 8453 void ConstantPropagator::VisitMintToDouble(MintToDoubleInstr* instr) { | |
| 8454 const Object& value = instr->value()->definition()->constant_value(); | |
| 8455 if (IsConstant(value) && value.IsInteger()) { | |
| 8456 SetValue(instr, Double::Handle(I, | |
| 8457 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld))); | |
| 8458 } else if (IsNonConstant(value)) { | |
| 8459 SetValue(instr, non_constant_); | |
| 8460 } | |
| 8461 } | |
| 8462 | |
| 8463 | |
| 8464 void ConstantPropagator::VisitInt32ToDouble(Int32ToDoubleInstr* instr) { | |
| 8465 const Object& value = instr->value()->definition()->constant_value(); | |
| 8466 if (IsConstant(value) && value.IsInteger()) { | |
| 8467 SetValue(instr, Double::Handle(I, | |
| 8468 Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld))); | |
| 8469 } else if (IsNonConstant(value)) { | |
| 8470 SetValue(instr, non_constant_); | |
| 8471 } | |
| 8472 } | |
| 8473 | |
| 8474 | |
| 8475 void ConstantPropagator::VisitDoubleToInteger(DoubleToIntegerInstr* instr) { | |
| 8476 // TODO(kmillikin): Handle conversion. | |
| 8477 SetValue(instr, non_constant_); | |
| 8478 } | |
| 8479 | |
| 8480 | |
| 8481 void ConstantPropagator::VisitDoubleToSmi(DoubleToSmiInstr* instr) { | |
| 8482 // TODO(kmillikin): Handle conversion. | |
| 8483 SetValue(instr, non_constant_); | |
| 8484 } | |
| 8485 | |
| 8486 | |
| 8487 void ConstantPropagator::VisitDoubleToDouble(DoubleToDoubleInstr* instr) { | |
| 8488 // TODO(kmillikin): Handle conversion. | |
| 8489 SetValue(instr, non_constant_); | |
| 8490 } | |
| 8491 | |
| 8492 | |
| 8493 void ConstantPropagator::VisitDoubleToFloat(DoubleToFloatInstr* instr) { | |
| 8494 // TODO(kmillikin): Handle conversion. | |
| 8495 SetValue(instr, non_constant_); | |
| 8496 } | |
| 8497 | |
| 8498 | |
| 8499 void ConstantPropagator::VisitFloatToDouble(FloatToDoubleInstr* instr) { | |
| 8500 // TODO(kmillikin): Handle conversion. | |
| 8501 SetValue(instr, non_constant_); | |
| 8502 } | |
| 8503 | |
| 8504 | |
| 8505 void ConstantPropagator::VisitInvokeMathCFunction( | |
| 8506 InvokeMathCFunctionInstr* instr) { | |
| 8507 // TODO(kmillikin): Handle conversion. | |
| 8508 SetValue(instr, non_constant_); | |
| 8509 } | |
| 8510 | |
| 8511 | |
| 8512 void ConstantPropagator::VisitMergedMath(MergedMathInstr* instr) { | |
| 8513 // TODO(srdjan): Handle merged instruction. | |
| 8514 SetValue(instr, non_constant_); | |
| 8515 } | |
| 8516 | |
| 8517 | |
| 8518 void ConstantPropagator::VisitExtractNthOutput(ExtractNthOutputInstr* instr) { | |
| 8519 SetValue(instr, non_constant_); | |
| 8520 } | |
| 8521 | |
| 8522 | |
| 8523 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { | |
| 8524 SetValue(instr, instr->value()); | |
| 8525 } | |
| 8526 | |
| 8527 | |
| 8528 void ConstantPropagator::VisitUnboxedConstant(UnboxedConstantInstr* instr) { | |
| 8529 SetValue(instr, instr->value()); | |
| 8530 } | |
| 8531 | |
| 8532 | |
| 8533 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { | |
| 8534 // Should not be used outside of range analysis. | |
| 8535 UNREACHABLE(); | |
| 8536 } | |
| 8537 | |
| 8538 | |
| 8539 void ConstantPropagator::VisitMaterializeObject(MaterializeObjectInstr* instr) { | |
| 8540 // Should not be used outside of allocation elimination pass. | |
| 8541 UNREACHABLE(); | |
| 8542 } | |
| 8543 | |
| 8544 | |
| 8545 static bool IsIntegerOrDouble(const Object& value) { | |
| 8546 return value.IsInteger() || value.IsDouble(); | |
| 8547 } | |
| 8548 | |
| 8549 | |
| 8550 static double ToDouble(const Object& value) { | |
| 8551 return value.IsInteger() ? Integer::Cast(value).AsDoubleValue() | |
| 8552 : Double::Cast(value).value(); | |
| 8553 } | |
| 8554 | |
| 8555 | |
| 8556 void ConstantPropagator::VisitBinaryDoubleOp( | |
| 8557 BinaryDoubleOpInstr* instr) { | |
| 8558 const Object& left = instr->left()->definition()->constant_value(); | |
| 8559 const Object& right = instr->right()->definition()->constant_value(); | |
| 8560 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 8561 SetValue(instr, non_constant_); | |
| 8562 } else if (left.IsInteger() && right.IsInteger()) { | |
| 8563 SetValue(instr, non_constant_); | |
| 8564 } else if (IsIntegerOrDouble(left) && IsIntegerOrDouble(right)) { | |
| 8565 const double left_val = ToDouble(left); | |
| 8566 const double right_val = ToDouble(right); | |
| 8567 double result_val = 0.0; | |
| 8568 switch (instr->op_kind()) { | |
| 8569 case Token::kADD: | |
| 8570 result_val = left_val + right_val; | |
| 8571 break; | |
| 8572 case Token::kSUB: | |
| 8573 result_val = left_val - right_val; | |
| 8574 break; | |
| 8575 case Token::kMUL: | |
| 8576 result_val = left_val * right_val; | |
| 8577 break; | |
| 8578 case Token::kDIV: | |
| 8579 result_val = left_val / right_val; | |
| 8580 break; | |
| 8581 default: | |
| 8582 UNREACHABLE(); | |
| 8583 } | |
| 8584 const Double& result = Double::ZoneHandle(Double::NewCanonical(result_val)); | |
| 8585 SetValue(instr, result); | |
| 8586 } | |
| 8587 } | |
| 8588 | |
| 8589 | |
| 8590 void ConstantPropagator::VisitBinaryFloat32x4Op( | |
| 8591 BinaryFloat32x4OpInstr* instr) { | |
| 8592 const Object& left = instr->left()->definition()->constant_value(); | |
| 8593 const Object& right = instr->right()->definition()->constant_value(); | |
| 8594 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 8595 SetValue(instr, non_constant_); | |
| 8596 } else if (IsConstant(left) && IsConstant(right)) { | |
| 8597 // TODO(kmillikin): Handle binary operation. | |
| 8598 SetValue(instr, non_constant_); | |
| 8599 } | |
| 8600 } | |
| 8601 | |
| 8602 | |
| 8603 void ConstantPropagator::VisitFloat32x4Constructor( | |
| 8604 Float32x4ConstructorInstr* instr) { | |
| 8605 SetValue(instr, non_constant_); | |
| 8606 } | |
| 8607 | |
| 8608 | |
| 8609 void ConstantPropagator::VisitSimd32x4Shuffle(Simd32x4ShuffleInstr* instr) { | |
| 8610 SetValue(instr, non_constant_); | |
| 8611 } | |
| 8612 | |
| 8613 | |
| 8614 void ConstantPropagator::VisitSimd32x4ShuffleMix( | |
| 8615 Simd32x4ShuffleMixInstr* instr) { | |
| 8616 SetValue(instr, non_constant_); | |
| 8617 } | |
| 8618 | |
| 8619 | |
| 8620 void ConstantPropagator::VisitSimd32x4GetSignMask( | |
| 8621 Simd32x4GetSignMaskInstr* instr) { | |
| 8622 SetValue(instr, non_constant_); | |
| 8623 } | |
| 8624 | |
| 8625 | |
| 8626 void ConstantPropagator::VisitFloat32x4Zero(Float32x4ZeroInstr* instr) { | |
| 8627 SetValue(instr, non_constant_); | |
| 8628 } | |
| 8629 | |
| 8630 | |
| 8631 void ConstantPropagator::VisitFloat32x4Splat(Float32x4SplatInstr* instr) { | |
| 8632 SetValue(instr, non_constant_); | |
| 8633 } | |
| 8634 | |
| 8635 | |
| 8636 void ConstantPropagator::VisitFloat32x4Comparison( | |
| 8637 Float32x4ComparisonInstr* instr) { | |
| 8638 SetValue(instr, non_constant_); | |
| 8639 } | |
| 8640 | |
| 8641 | |
| 8642 void ConstantPropagator::VisitFloat32x4MinMax(Float32x4MinMaxInstr* instr) { | |
| 8643 SetValue(instr, non_constant_); | |
| 8644 } | |
| 8645 | |
| 8646 | |
| 8647 void ConstantPropagator::VisitFloat32x4Scale(Float32x4ScaleInstr* instr) { | |
| 8648 SetValue(instr, non_constant_); | |
| 8649 } | |
| 8650 | |
| 8651 | |
| 8652 void ConstantPropagator::VisitFloat32x4Sqrt(Float32x4SqrtInstr* instr) { | |
| 8653 SetValue(instr, non_constant_); | |
| 8654 } | |
| 8655 | |
| 8656 | |
| 8657 void ConstantPropagator::VisitFloat32x4ZeroArg(Float32x4ZeroArgInstr* instr) { | |
| 8658 SetValue(instr, non_constant_); | |
| 8659 } | |
| 8660 | |
| 8661 | |
| 8662 void ConstantPropagator::VisitFloat32x4Clamp(Float32x4ClampInstr* instr) { | |
| 8663 SetValue(instr, non_constant_); | |
| 8664 } | |
| 8665 | |
| 8666 | |
| 8667 void ConstantPropagator::VisitFloat32x4With(Float32x4WithInstr* instr) { | |
| 8668 SetValue(instr, non_constant_); | |
| 8669 } | |
| 8670 | |
| 8671 | |
| 8672 void ConstantPropagator::VisitFloat32x4ToInt32x4( | |
| 8673 Float32x4ToInt32x4Instr* instr) { | |
| 8674 SetValue(instr, non_constant_); | |
| 8675 } | |
| 8676 | |
| 8677 | |
| 8678 void ConstantPropagator::VisitInt32x4Constructor( | |
| 8679 Int32x4ConstructorInstr* instr) { | |
| 8680 SetValue(instr, non_constant_); | |
| 8681 } | |
| 8682 | |
| 8683 | |
| 8684 void ConstantPropagator::VisitInt32x4BoolConstructor( | |
| 8685 Int32x4BoolConstructorInstr* instr) { | |
| 8686 SetValue(instr, non_constant_); | |
| 8687 } | |
| 8688 | |
| 8689 | |
| 8690 void ConstantPropagator::VisitInt32x4GetFlag(Int32x4GetFlagInstr* instr) { | |
| 8691 SetValue(instr, non_constant_); | |
| 8692 } | |
| 8693 | |
| 8694 | |
| 8695 void ConstantPropagator::VisitInt32x4SetFlag(Int32x4SetFlagInstr* instr) { | |
| 8696 SetValue(instr, non_constant_); | |
| 8697 } | |
| 8698 | |
| 8699 | |
| 8700 void ConstantPropagator::VisitInt32x4Select(Int32x4SelectInstr* instr) { | |
| 8701 SetValue(instr, non_constant_); | |
| 8702 } | |
| 8703 | |
| 8704 | |
| 8705 void ConstantPropagator::VisitInt32x4ToFloat32x4( | |
| 8706 Int32x4ToFloat32x4Instr* instr) { | |
| 8707 SetValue(instr, non_constant_); | |
| 8708 } | |
| 8709 | |
| 8710 | |
| 8711 void ConstantPropagator::VisitBinaryInt32x4Op(BinaryInt32x4OpInstr* instr) { | |
| 8712 SetValue(instr, non_constant_); | |
| 8713 } | |
| 8714 | |
| 8715 | |
| 8716 void ConstantPropagator::VisitSimd64x2Shuffle(Simd64x2ShuffleInstr* instr) { | |
| 8717 SetValue(instr, non_constant_); | |
| 8718 } | |
| 8719 | |
| 8720 | |
| 8721 void ConstantPropagator::VisitBinaryFloat64x2Op(BinaryFloat64x2OpInstr* instr) { | |
| 8722 SetValue(instr, non_constant_); | |
| 8723 } | |
| 8724 | |
| 8725 | |
| 8726 void ConstantPropagator::VisitFloat32x4ToFloat64x2( | |
| 8727 Float32x4ToFloat64x2Instr* instr) { | |
| 8728 SetValue(instr, non_constant_); | |
| 8729 } | |
| 8730 | |
| 8731 | |
| 8732 void ConstantPropagator::VisitFloat64x2ToFloat32x4( | |
| 8733 Float64x2ToFloat32x4Instr* instr) { | |
| 8734 SetValue(instr, non_constant_); | |
| 8735 } | |
| 8736 | |
| 8737 | |
| 8738 void ConstantPropagator::VisitFloat64x2Zero( | |
| 8739 Float64x2ZeroInstr* instr) { | |
| 8740 SetValue(instr, non_constant_); | |
| 8741 } | |
| 8742 | |
| 8743 | |
| 8744 void ConstantPropagator::VisitFloat64x2Splat( | |
| 8745 Float64x2SplatInstr* instr) { | |
| 8746 SetValue(instr, non_constant_); | |
| 8747 } | |
| 8748 | |
| 8749 | |
| 8750 void ConstantPropagator::VisitFloat64x2Constructor( | |
| 8751 Float64x2ConstructorInstr* instr) { | |
| 8752 SetValue(instr, non_constant_); | |
| 8753 } | |
| 8754 | |
| 8755 | |
| 8756 void ConstantPropagator::VisitFloat64x2ZeroArg(Float64x2ZeroArgInstr* instr) { | |
| 8757 // TODO(johnmccutchan): Implement constant propagation. | |
| 8758 SetValue(instr, non_constant_); | |
| 8759 } | |
| 8760 | |
| 8761 | |
| 8762 void ConstantPropagator::VisitFloat64x2OneArg(Float64x2OneArgInstr* instr) { | |
| 8763 // TODO(johnmccutchan): Implement constant propagation. | |
| 8764 SetValue(instr, non_constant_); | |
| 8765 } | |
| 8766 | |
| 8767 | |
| 8768 void ConstantPropagator::VisitMathUnary(MathUnaryInstr* instr) { | |
| 8769 const Object& value = instr->value()->definition()->constant_value(); | |
| 8770 if (IsNonConstant(value)) { | |
| 8771 SetValue(instr, non_constant_); | |
| 8772 } else if (IsConstant(value)) { | |
| 8773 // TODO(kmillikin): Handle Math's unary operations (sqrt, cos, sin). | |
| 8774 SetValue(instr, non_constant_); | |
| 8775 } | |
| 8776 } | |
| 8777 | |
| 8778 | |
| 8779 void ConstantPropagator::VisitMathMinMax(MathMinMaxInstr* instr) { | |
| 8780 const Object& left = instr->left()->definition()->constant_value(); | |
| 8781 const Object& right = instr->right()->definition()->constant_value(); | |
| 8782 if (IsNonConstant(left) || IsNonConstant(right)) { | |
| 8783 SetValue(instr, non_constant_); | |
| 8784 } else if (IsConstant(left) && IsConstant(right)) { | |
| 8785 // TODO(srdjan): Handle min and max. | |
| 8786 SetValue(instr, non_constant_); | |
| 8787 } | |
| 8788 } | |
| 8789 | |
| 8790 | |
| 8791 void ConstantPropagator::VisitCaseInsensitiveCompareUC16( | |
| 8792 CaseInsensitiveCompareUC16Instr *instr) { | |
| 8793 SetValue(instr, non_constant_); | |
| 8794 } | |
| 8795 | |
| 8796 | |
| 8797 void ConstantPropagator::VisitUnbox(UnboxInstr* instr) { | |
| 8798 const Object& value = instr->value()->definition()->constant_value(); | |
| 8799 if (IsNonConstant(value)) { | |
| 8800 SetValue(instr, non_constant_); | |
| 8801 } else if (IsConstant(value)) { | |
| 8802 // TODO(kmillikin): Handle conversion. | |
| 8803 SetValue(instr, non_constant_); | |
| 8804 } | |
| 8805 } | |
| 8806 | |
| 8807 | |
| 8808 void ConstantPropagator::VisitBox(BoxInstr* instr) { | |
| 8809 const Object& value = instr->value()->definition()->constant_value(); | |
| 8810 if (IsNonConstant(value)) { | |
| 8811 SetValue(instr, non_constant_); | |
| 8812 } else if (IsConstant(value)) { | |
| 8813 // TODO(kmillikin): Handle conversion. | |
| 8814 SetValue(instr, non_constant_); | |
| 8815 } | |
| 8816 } | |
| 8817 | |
| 8818 | |
| 8819 void ConstantPropagator::VisitBoxUint32(BoxUint32Instr* instr) { | |
| 8820 // TODO(kmillikin): Handle box operation. | |
| 8821 SetValue(instr, non_constant_); | |
| 8822 } | |
| 8823 | |
| 8824 | |
| 8825 void ConstantPropagator::VisitUnboxUint32(UnboxUint32Instr* instr) { | |
| 8826 // TODO(kmillikin): Handle unbox operation. | |
| 8827 SetValue(instr, non_constant_); | |
| 8828 } | |
| 8829 | |
| 8830 | |
| 8831 void ConstantPropagator::VisitBoxInt32(BoxInt32Instr* instr) { | |
| 8832 // TODO(kmillikin): Handle box operation. | |
| 8833 SetValue(instr, non_constant_); | |
| 8834 } | |
| 8835 | |
| 8836 | |
| 8837 void ConstantPropagator::VisitUnboxInt32(UnboxInt32Instr* instr) { | |
| 8838 // TODO(kmillikin): Handle unbox operation. | |
| 8839 SetValue(instr, non_constant_); | |
| 8840 } | |
| 8841 | |
| 8842 | |
| 8843 void ConstantPropagator::VisitUnboxedIntConverter( | |
| 8844 UnboxedIntConverterInstr* instr) { | |
| 8845 SetValue(instr, non_constant_); | |
| 8846 } | |
| 8847 | |
| 8848 | |
| 8849 void ConstantPropagator::VisitUnaryUint32Op(UnaryUint32OpInstr* instr) { | |
| 8850 // TODO(kmillikin): Handle unary operations. | |
| 8851 SetValue(instr, non_constant_); | |
| 8852 } | |
| 8853 | |
| 8854 | |
| 8855 void ConstantPropagator::Analyze() { | |
| 8856 GraphEntryInstr* entry = graph_->graph_entry(); | |
| 8857 reachable_->Add(entry->preorder_number()); | |
| 8858 block_worklist_.Add(entry); | |
| 8859 | |
| 8860 while (true) { | |
| 8861 if (block_worklist_.is_empty()) { | |
| 8862 if (definition_worklist_.IsEmpty()) break; | |
| 8863 Definition* definition = definition_worklist_.RemoveLast(); | |
| 8864 Value* use = definition->input_use_list(); | |
| 8865 while (use != NULL) { | |
| 8866 use->instruction()->Accept(this); | |
| 8867 use = use->next_use(); | |
| 8868 } | |
| 8869 } else { | |
| 8870 BlockEntryInstr* block = block_worklist_.RemoveLast(); | |
| 8871 block->Accept(this); | |
| 8872 } | |
| 8873 } | |
| 8874 } | |
| 8875 | |
| 8876 | |
| 8877 static bool IsEmptyBlock(BlockEntryInstr* block) { | |
| 8878 return block->next()->IsGoto() && | |
| 8879 (!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)) && | |
| 8880 !block->IsIndirectEntry(); | |
| 8881 } | |
| 8882 | |
| 8883 | |
| 8884 // Traverses a chain of empty blocks and returns the first reachable non-empty | |
| 8885 // block that is not dominated by the start block. The empty blocks are added | |
| 8886 // to the supplied bit vector. | |
| 8887 static BlockEntryInstr* FindFirstNonEmptySuccessor( | |
| 8888 TargetEntryInstr* block, | |
| 8889 BitVector* empty_blocks) { | |
| 8890 BlockEntryInstr* current = block; | |
| 8891 while (IsEmptyBlock(current) && block->Dominates(current)) { | |
| 8892 ASSERT(!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)); | |
| 8893 empty_blocks->Add(current->preorder_number()); | |
| 8894 current = current->next()->AsGoto()->successor(); | |
| 8895 } | |
| 8896 return current; | |
| 8897 } | |
| 8898 | |
| 8899 | |
| 8900 void ConstantPropagator::EliminateRedundantBranches() { | |
| 8901 // Canonicalize branches that have no side-effects and where true- and | |
| 8902 // false-targets are the same. | |
| 8903 bool changed = false; | |
| 8904 BitVector* empty_blocks = new(I) BitVector(I, graph_->preorder().length()); | |
| 8905 for (BlockIterator b = graph_->postorder_iterator(); | |
| 8906 !b.Done(); | |
| 8907 b.Advance()) { | |
| 8908 BlockEntryInstr* block = b.Current(); | |
| 8909 BranchInstr* branch = block->last_instruction()->AsBranch(); | |
| 8910 empty_blocks->Clear(); | |
| 8911 if ((branch != NULL) && branch->Effects().IsNone()) { | |
| 8912 ASSERT(branch->previous() != NULL); // Not already eliminated. | |
| 8913 BlockEntryInstr* if_true = | |
| 8914 FindFirstNonEmptySuccessor(branch->true_successor(), empty_blocks); | |
| 8915 BlockEntryInstr* if_false = | |
| 8916 FindFirstNonEmptySuccessor(branch->false_successor(), empty_blocks); | |
| 8917 if (if_true == if_false) { | |
| 8918 // Replace the branch with a jump to the common successor. | |
| 8919 // Drop the comparison, which does not have side effects | |
| 8920 JoinEntryInstr* join = if_true->AsJoinEntry(); | |
| 8921 if (join->phis() == NULL) { | |
| 8922 GotoInstr* jump = new(I) GotoInstr(if_true->AsJoinEntry()); | |
| 8923 jump->InheritDeoptTarget(I, branch); | |
| 8924 | |
| 8925 Instruction* previous = branch->previous(); | |
| 8926 branch->set_previous(NULL); | |
| 8927 previous->LinkTo(jump); | |
| 8928 | |
| 8929 // Remove uses from branch and all the empty blocks that | |
| 8930 // are now unreachable. | |
| 8931 branch->UnuseAllInputs(); | |
| 8932 for (BitVector::Iterator it(empty_blocks); !it.Done(); it.Advance()) { | |
| 8933 BlockEntryInstr* empty_block = graph_->preorder()[it.Current()]; | |
| 8934 empty_block->ClearAllInstructions(); | |
| 8935 } | |
| 8936 | |
| 8937 changed = true; | |
| 8938 | |
| 8939 if (FLAG_trace_constant_propagation) { | |
| 8940 OS::Print("Eliminated branch in B%" Pd " common target B%" Pd "\n", | |
| 8941 block->block_id(), join->block_id()); | |
| 8942 } | |
| 8943 } | |
| 8944 } | |
| 8945 } | |
| 8946 } | |
| 8947 | |
| 8948 if (changed) { | |
| 8949 graph_->DiscoverBlocks(); | |
| 8950 // TODO(fschneider): Update dominator tree in place instead of recomputing. | |
| 8951 GrowableArray<BitVector*> dominance_frontier; | |
| 8952 graph_->ComputeDominators(&dominance_frontier); | |
| 8953 } | |
| 8954 } | |
| 8955 | |
| 8956 | |
| 8957 void ConstantPropagator::Transform() { | |
| 8958 if (FLAG_trace_constant_propagation) { | |
| 8959 OS::Print("\n==== Before constant propagation ====\n"); | |
| 8960 FlowGraphPrinter printer(*graph_); | |
| 8961 printer.PrintBlocks(); | |
| 8962 } | |
| 8963 | |
| 8964 // We will recompute dominators, block ordering, block ids, block last | |
| 8965 // instructions, previous pointers, predecessors, etc. after eliminating | |
| 8966 // unreachable code. We do not maintain those properties during the | |
| 8967 // transformation. | |
| 8968 for (BlockIterator b = graph_->reverse_postorder_iterator(); | |
| 8969 !b.Done(); | |
| 8970 b.Advance()) { | |
| 8971 BlockEntryInstr* block = b.Current(); | |
| 8972 if (!reachable_->Contains(block->preorder_number())) { | |
| 8973 if (FLAG_trace_constant_propagation) { | |
| 8974 OS::Print("Unreachable B%" Pd "\n", block->block_id()); | |
| 8975 } | |
| 8976 // Remove all uses in unreachable blocks. | |
| 8977 block->ClearAllInstructions(); | |
| 8978 continue; | |
| 8979 } | |
| 8980 | |
| 8981 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 8982 if (join != NULL) { | |
| 8983 // Remove phi inputs corresponding to unreachable predecessor blocks. | |
| 8984 // Predecessors will be recomputed (in block id order) after removing | |
| 8985 // unreachable code so we merely have to keep the phi inputs in order. | |
| 8986 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | |
| 8987 if ((phis != NULL) && !phis->is_empty()) { | |
| 8988 intptr_t pred_count = join->PredecessorCount(); | |
| 8989 intptr_t live_count = 0; | |
| 8990 for (intptr_t pred_idx = 0; pred_idx < pred_count; ++pred_idx) { | |
| 8991 if (reachable_->Contains( | |
| 8992 join->PredecessorAt(pred_idx)->preorder_number())) { | |
| 8993 if (live_count < pred_idx) { | |
| 8994 for (PhiIterator it(join); !it.Done(); it.Advance()) { | |
| 8995 PhiInstr* phi = it.Current(); | |
| 8996 ASSERT(phi != NULL); | |
| 8997 phi->SetInputAt(live_count, phi->InputAt(pred_idx)); | |
| 8998 } | |
| 8999 } | |
| 9000 ++live_count; | |
| 9001 } else { | |
| 9002 for (PhiIterator it(join); !it.Done(); it.Advance()) { | |
| 9003 PhiInstr* phi = it.Current(); | |
| 9004 ASSERT(phi != NULL); | |
| 9005 phi->InputAt(pred_idx)->RemoveFromUseList(); | |
| 9006 } | |
| 9007 } | |
| 9008 } | |
| 9009 if (live_count < pred_count) { | |
| 9010 intptr_t to_idx = 0; | |
| 9011 for (intptr_t from_idx = 0; from_idx < phis->length(); ++from_idx) { | |
| 9012 PhiInstr* phi = (*phis)[from_idx]; | |
| 9013 ASSERT(phi != NULL); | |
| 9014 if (FLAG_remove_redundant_phis && (live_count == 1)) { | |
| 9015 Value* input = phi->InputAt(0); | |
| 9016 phi->ReplaceUsesWith(input->definition()); | |
| 9017 input->RemoveFromUseList(); | |
| 9018 } else { | |
| 9019 phi->inputs_.TruncateTo(live_count); | |
| 9020 (*phis)[to_idx++] = phi; | |
| 9021 } | |
| 9022 } | |
| 9023 if (to_idx == 0) { | |
| 9024 join->phis_ = NULL; | |
| 9025 } else { | |
| 9026 phis->TruncateTo(to_idx); | |
| 9027 } | |
| 9028 } | |
| 9029 } | |
| 9030 } | |
| 9031 | |
| 9032 for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) { | |
| 9033 Definition* defn = i.Current()->AsDefinition(); | |
| 9034 // Replace constant-valued instructions without observable side | |
| 9035 // effects. Do this for smis only to avoid having to copy other | |
| 9036 // objects into the heap's old generation. | |
| 9037 if ((defn != NULL) && | |
| 9038 IsConstant(defn->constant_value()) && | |
| 9039 (defn->constant_value().IsSmi() || defn->constant_value().IsOld()) && | |
| 9040 !defn->IsConstant() && | |
| 9041 !defn->IsPushArgument() && | |
| 9042 !defn->IsStoreIndexed() && | |
| 9043 !defn->IsStoreInstanceField() && | |
| 9044 !defn->IsStoreStaticField()) { | |
| 9045 if (FLAG_trace_constant_propagation) { | |
| 9046 OS::Print("Constant v%" Pd " = %s\n", | |
| 9047 defn->ssa_temp_index(), | |
| 9048 defn->constant_value().ToCString()); | |
| 9049 } | |
| 9050 ConstantInstr* constant = graph_->GetConstant(defn->constant_value()); | |
| 9051 defn->ReplaceUsesWith(constant); | |
| 9052 i.RemoveCurrentFromGraph(); | |
| 9053 } | |
| 9054 } | |
| 9055 | |
| 9056 // Replace branches where one target is unreachable with jumps. | |
| 9057 BranchInstr* branch = block->last_instruction()->AsBranch(); | |
| 9058 if (branch != NULL) { | |
| 9059 TargetEntryInstr* if_true = branch->true_successor(); | |
| 9060 TargetEntryInstr* if_false = branch->false_successor(); | |
| 9061 JoinEntryInstr* join = NULL; | |
| 9062 Instruction* next = NULL; | |
| 9063 | |
| 9064 if (!reachable_->Contains(if_true->preorder_number())) { | |
| 9065 ASSERT(reachable_->Contains(if_false->preorder_number())); | |
| 9066 ASSERT(if_false->parallel_move() == NULL); | |
| 9067 ASSERT(if_false->loop_info() == NULL); | |
| 9068 join = new(I) JoinEntryInstr(if_false->block_id(), | |
| 9069 if_false->try_index()); | |
| 9070 join->InheritDeoptTarget(I, if_false); | |
| 9071 if_false->UnuseAllInputs(); | |
| 9072 next = if_false->next(); | |
| 9073 } else if (!reachable_->Contains(if_false->preorder_number())) { | |
| 9074 ASSERT(if_true->parallel_move() == NULL); | |
| 9075 ASSERT(if_true->loop_info() == NULL); | |
| 9076 join = new(I) JoinEntryInstr(if_true->block_id(), | |
| 9077 if_true->try_index()); | |
| 9078 join->InheritDeoptTarget(I, if_true); | |
| 9079 if_true->UnuseAllInputs(); | |
| 9080 next = if_true->next(); | |
| 9081 } | |
| 9082 | |
| 9083 if (join != NULL) { | |
| 9084 // Replace the branch with a jump to the reachable successor. | |
| 9085 // Drop the comparison, which does not have side effects as long | |
| 9086 // as it is a strict compare (the only one we can determine is | |
| 9087 // constant with the current analysis). | |
| 9088 GotoInstr* jump = new(I) GotoInstr(join); | |
| 9089 jump->InheritDeoptTarget(I, branch); | |
| 9090 | |
| 9091 Instruction* previous = branch->previous(); | |
| 9092 branch->set_previous(NULL); | |
| 9093 previous->LinkTo(jump); | |
| 9094 | |
| 9095 // Replace the false target entry with the new join entry. We will | |
| 9096 // recompute the dominators after this pass. | |
| 9097 join->LinkTo(next); | |
| 9098 branch->UnuseAllInputs(); | |
| 9099 } | |
| 9100 } | |
| 9101 } | |
| 9102 | |
| 9103 graph_->DiscoverBlocks(); | |
| 9104 graph_->MergeBlocks(); | |
| 9105 GrowableArray<BitVector*> dominance_frontier; | |
| 9106 graph_->ComputeDominators(&dominance_frontier); | |
| 9107 | |
| 9108 if (FLAG_trace_constant_propagation) { | |
| 9109 OS::Print("\n==== After constant propagation ====\n"); | |
| 9110 FlowGraphPrinter printer(*graph_); | |
| 9111 printer.PrintBlocks(); | |
| 9112 } | |
| 9113 } | |
| 9114 | |
| 9115 | |
| 9116 // Returns true if the given phi has a single input use and | 7500 // Returns true if the given phi has a single input use and |
| 9117 // is used in the environments either at the corresponding block entry or | 7501 // is used in the environments either at the corresponding block entry or |
| 9118 // at the same instruction where input use is. | 7502 // at the same instruction where input use is. |
| 9119 static bool PhiHasSingleUse(PhiInstr* phi, Value* use) { | 7503 static bool PhiHasSingleUse(PhiInstr* phi, Value* use) { |
| 9120 if ((use->next_use() != NULL) || (phi->input_use_list() != use)) { | 7504 if ((use->next_use() != NULL) || (phi->input_use_list() != use)) { |
| 9121 return false; | 7505 return false; |
| 9122 } | 7506 } |
| 9123 | 7507 |
| 9124 BlockEntryInstr* block = phi->block(); | 7508 BlockEntryInstr* block = phi->block(); |
| 9125 for (Value* env_use = phi->env_use_list(); | 7509 for (Value* env_use = phi->env_use_list(); |
| (...skipping 952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10078 | 8462 |
| 10079 // Insert materializations at environment uses. | 8463 // Insert materializations at environment uses. |
| 10080 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8464 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 10081 CreateMaterializationAt( | 8465 CreateMaterializationAt( |
| 10082 exits_collector_.exits()[i], alloc, *slots); | 8466 exits_collector_.exits()[i], alloc, *slots); |
| 10083 } | 8467 } |
| 10084 } | 8468 } |
| 10085 | 8469 |
| 10086 | 8470 |
| 10087 } // namespace dart | 8471 } // namespace dart |
| OLD | NEW |