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 |