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

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 820883004: Move ConstantPropagator from flow_graph_optimizer.cc/.h into separate files. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698