| 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/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 // Returns false if the ICData contains anything other than the 4 combinations | 596 // Returns false if the ICData contains anything other than the 4 combinations |
| 597 // of Mint and Smi for the receiver and argument classes. | 597 // of Mint and Smi for the receiver and argument classes. |
| 598 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 598 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
| 599 GrowableArray<intptr_t> class_ids(2); | 599 GrowableArray<intptr_t> class_ids(2); |
| 600 class_ids.Add(kSmiCid); | 600 class_ids.Add(kSmiCid); |
| 601 class_ids.Add(kMintCid); | 601 class_ids.Add(kMintCid); |
| 602 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 602 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 603 } | 603 } |
| 604 | 604 |
| 605 | 605 |
| 606 // Returns false if the ICData contains anything other than the 4 combinations |
| 607 // of Double and Smi for the receiver and argument classes. |
| 608 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { |
| 609 GrowableArray<intptr_t> class_ids(2); |
| 610 class_ids.Add(kSmiCid); |
| 611 class_ids.Add(kDoubleCid); |
| 612 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 613 } |
| 614 |
| 615 |
| 606 static bool HasOnlyOneDouble(const ICData& ic_data) { | 616 static bool HasOnlyOneDouble(const ICData& ic_data) { |
| 607 return (ic_data.NumberOfChecks() == 1) | 617 return (ic_data.NumberOfChecks() == 1) |
| 608 && ic_data.HasReceiverClassId(kDoubleCid); | 618 && ic_data.HasReceiverClassId(kDoubleCid); |
| 609 } | 619 } |
| 610 | 620 |
| 611 | 621 |
| 612 static bool ShouldSpecializeForDouble(const ICData& ic_data) { | 622 static bool ShouldSpecializeForDouble(const ICData& ic_data) { |
| 613 // Unboxed double operation can't handle case of two smis. | 623 // Unboxed double operation can't handle case of two smis. |
| 614 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 624 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 615 return false; | 625 return false; |
| (...skipping 2022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2638 new Value(instr->ArgumentAt(1)), | 2648 new Value(instr->ArgumentAt(1)), |
| 2639 needs_store_barrier); | 2649 needs_store_barrier); |
| 2640 // Discard the environment from the original instruction because the store | 2650 // Discard the environment from the original instruction because the store |
| 2641 // can't deoptimize. | 2651 // can't deoptimize. |
| 2642 instr->RemoveEnvironment(); | 2652 instr->RemoveEnvironment(); |
| 2643 ReplaceCall(instr, store); | 2653 ReplaceCall(instr, store); |
| 2644 return true; | 2654 return true; |
| 2645 } | 2655 } |
| 2646 | 2656 |
| 2647 | 2657 |
| 2658 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 2659 |
| 2660 |
| 2661 void FlowGraphOptimizer::HandleComparison(ComparisonInstr* comp, |
| 2662 const ICData& ic_data, |
| 2663 Instruction* current_instruction) { |
| 2664 ASSERT(ic_data.num_args_tested() == 2); |
| 2665 ASSERT(comp->operation_cid() == kIllegalCid); |
| 2666 Instruction* instr = current_iterator()->Current(); |
| 2667 if (HasOnlyTwoSmis(ic_data)) { |
| 2668 InsertBefore(instr, |
| 2669 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 2670 instr->env(), |
| 2671 Definition::kEffect); |
| 2672 InsertBefore(instr, |
| 2673 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 2674 instr->env(), |
| 2675 Definition::kEffect); |
| 2676 comp->set_operation_cid(kSmiCid); |
| 2677 } else if (HasTwoMintOrSmi(ic_data) && |
| 2678 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 2679 comp->set_operation_cid(kMintCid); |
| 2680 } else if (HasTwoDoubleOrSmi(ic_data)) { |
| 2681 // Use double comparison. |
| 2682 if (SmiFitsInDouble()) { |
| 2683 comp->set_operation_cid(kDoubleCid); |
| 2684 } else { |
| 2685 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 2686 // We cannot use double comparison on two Smi-s. |
| 2687 ASSERT(comp->operation_cid() == kIllegalCid); |
| 2688 } else { |
| 2689 InsertBefore(instr, |
| 2690 new CheckEitherNonSmiInstr(comp->left()->Copy(), |
| 2691 comp->right()->Copy(), |
| 2692 comp->deopt_id()), |
| 2693 instr->env(), |
| 2694 Definition::kEffect); |
| 2695 comp->set_operation_cid(kDoubleCid); |
| 2696 } |
| 2697 } |
| 2698 } else { |
| 2699 ASSERT(comp->operation_cid() == kIllegalCid); |
| 2700 } |
| 2701 } |
| 2702 |
| 2703 |
| 2648 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { | 2704 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { |
| 2649 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 2705 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 2650 return; | 2706 return; |
| 2651 } | 2707 } |
| 2652 const ICData& ic_data = *comp->ic_data(); | 2708 HandleComparison(comp, *comp->ic_data(), current_iterator()->Current()); |
| 2653 Instruction* instr = current_iterator()->Current(); | |
| 2654 if (ic_data.NumberOfChecks() == 1) { | |
| 2655 ASSERT(ic_data.HasOneTarget()); | |
| 2656 if (HasOnlyTwoSmis(ic_data)) { | |
| 2657 InsertBefore(instr, | |
| 2658 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
| 2659 instr->env(), | |
| 2660 Definition::kEffect); | |
| 2661 InsertBefore(instr, | |
| 2662 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
| 2663 instr->env(), | |
| 2664 Definition::kEffect); | |
| 2665 comp->set_operands_class_id(kSmiCid); | |
| 2666 } else if (ShouldSpecializeForDouble(ic_data)) { | |
| 2667 comp->set_operands_class_id(kDoubleCid); | |
| 2668 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | |
| 2669 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 2670 comp->set_operands_class_id(kMintCid); | |
| 2671 } else { | |
| 2672 ASSERT(comp->operands_class_id() == kIllegalCid); | |
| 2673 } | |
| 2674 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | |
| 2675 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 2676 comp->set_operands_class_id(kMintCid); | |
| 2677 } | |
| 2678 } | 2709 } |
| 2679 | 2710 |
| 2680 | 2711 |
| 2681 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { | 2712 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { |
| 2682 HandleRelationalOp(instr); | 2713 HandleRelationalOp(instr); |
| 2683 } | 2714 } |
| 2684 | 2715 |
| 2685 | 2716 |
| 2686 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( | 2717 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( |
| 2687 EqualityCompareInstr* compare) { | 2718 EqualityCompareInstr* compare) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2751 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, | 2782 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, |
| 2752 T current_instruction) { | 2783 T current_instruction) { |
| 2753 if (StrictifyEqualityCompare(comp, current_instruction)) { | 2784 if (StrictifyEqualityCompare(comp, current_instruction)) { |
| 2754 return; | 2785 return; |
| 2755 } | 2786 } |
| 2756 | 2787 |
| 2757 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 2788 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 2758 return; | 2789 return; |
| 2759 } | 2790 } |
| 2760 | 2791 |
| 2761 ASSERT(comp->ic_data()->num_args_tested() == 2); | 2792 const ICData& ic_data = *comp->ic_data(); |
| 2762 if (comp->ic_data()->NumberOfChecks() == 1) { | 2793 HandleComparison(comp, ic_data, current_instruction); |
| 2763 GrowableArray<intptr_t> class_ids; | |
| 2764 Function& target = Function::Handle(); | |
| 2765 comp->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 2766 // TODO(srdjan): allow for mixed mode int/double comparison. | |
| 2767 | 2794 |
| 2768 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { | 2795 if (comp->operation_cid() != kIllegalCid) { |
| 2769 InsertBefore(current_instruction, | |
| 2770 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
| 2771 current_instruction->env(), | |
| 2772 Definition::kEffect); | |
| 2773 InsertBefore(current_instruction, | |
| 2774 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
| 2775 current_instruction->env(), | |
| 2776 Definition::kEffect); | |
| 2777 comp->set_receiver_class_id(kSmiCid); | |
| 2778 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { | |
| 2779 comp->set_receiver_class_id(kDoubleCid); | |
| 2780 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | |
| 2781 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 2782 comp->set_receiver_class_id(kMintCid); | |
| 2783 } else { | |
| 2784 ASSERT(comp->receiver_class_id() == kIllegalCid); | |
| 2785 } | |
| 2786 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | |
| 2787 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 2788 comp->set_receiver_class_id(kMintCid); | |
| 2789 } | |
| 2790 | |
| 2791 if (comp->receiver_class_id() != kIllegalCid) { | |
| 2792 // Done. | 2796 // Done. |
| 2793 return; | 2797 return; |
| 2794 } | 2798 } |
| 2795 | 2799 |
| 2796 // Check if ICDData contains checks with Smi/Null combinations. In that case | 2800 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 2797 // we can still emit the optimized Smi equality operation but need to add | 2801 // we can still emit the optimized Smi equality operation but need to add |
| 2798 // checks for null or Smi. | 2802 // checks for null or Smi. |
| 2799 // TODO(srdjan): Add it for Double and Mint. | 2803 // TODO(srdjan): Add it for Double and Mint. |
| 2800 GrowableArray<intptr_t> smi_or_null(2); | 2804 GrowableArray<intptr_t> smi_or_null(2); |
| 2801 smi_or_null.Add(kSmiCid); | 2805 smi_or_null.Add(kSmiCid); |
| 2802 smi_or_null.Add(kNullCid); | 2806 smi_or_null.Add(kNullCid); |
| 2803 if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(), | 2807 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, |
| 2804 smi_or_null, | 2808 smi_or_null, |
| 2805 smi_or_null)) { | 2809 smi_or_null)) { |
| 2806 const ICData& unary_checks_0 = | 2810 const ICData& unary_checks_0 = |
| 2807 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 2811 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 2808 AddCheckClass(comp->left()->definition(), | 2812 AddCheckClass(comp->left()->definition(), |
| 2809 unary_checks_0, | 2813 unary_checks_0, |
| 2810 comp->deopt_id(), | 2814 comp->deopt_id(), |
| 2811 current_instruction->env(), | 2815 current_instruction->env(), |
| 2812 current_instruction); | 2816 current_instruction); |
| 2813 | 2817 |
| 2814 const ICData& unary_checks_1 = | 2818 const ICData& unary_checks_1 = |
| 2815 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | 2819 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 2816 AddCheckClass(comp->right()->definition(), | 2820 AddCheckClass(comp->right()->definition(), |
| 2817 unary_checks_1, | 2821 unary_checks_1, |
| 2818 comp->deopt_id(), | 2822 comp->deopt_id(), |
| 2819 current_instruction->env(), | 2823 current_instruction->env(), |
| 2820 current_instruction); | 2824 current_instruction); |
| 2821 comp->set_receiver_class_id(kSmiCid); | 2825 comp->set_operation_cid(kSmiCid); |
| 2822 } | 2826 } |
| 2823 } | 2827 } |
| 2824 | 2828 |
| 2825 | 2829 |
| 2826 | 2830 |
| 2827 | 2831 |
| 2828 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 2832 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 2829 HandleEqualityCompare(instr, instr); | 2833 HandleEqualityCompare(instr, instr); |
| 2830 } | 2834 } |
| 2831 | 2835 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3131 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); | 3135 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); |
| 3132 RenameDominatedUses(defn, constraint, constraint); | 3136 RenameDominatedUses(defn, constraint, constraint); |
| 3133 constraints_.Add(constraint); | 3137 constraints_.Add(constraint); |
| 3134 return constraint; | 3138 return constraint; |
| 3135 } | 3139 } |
| 3136 | 3140 |
| 3137 | 3141 |
| 3138 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { | 3142 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { |
| 3139 BranchInstr* branch = use->instruction()->AsBranch(); | 3143 BranchInstr* branch = use->instruction()->AsBranch(); |
| 3140 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | 3144 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); |
| 3141 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | 3145 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) { |
| 3142 // Found comparison of two smis. Constrain defn at true and false | 3146 // Found comparison of two smis. Constrain defn at true and false |
| 3143 // successors using the other operand as a boundary. | 3147 // successors using the other operand as a boundary. |
| 3144 Definition* boundary; | 3148 Definition* boundary; |
| 3145 Token::Kind op_kind; | 3149 Token::Kind op_kind; |
| 3146 if (use->use_index() == 0) { // Left operand. | 3150 if (use->use_index() == 0) { // Left operand. |
| 3147 boundary = rel_op->InputAt(1)->definition(); | 3151 boundary = rel_op->InputAt(1)->definition(); |
| 3148 op_kind = rel_op->kind(); | 3152 op_kind = rel_op->kind(); |
| 3149 } else { | 3153 } else { |
| 3150 ASSERT(use->use_index() == 1); // Right operand. | 3154 ASSERT(use->use_index() == 1); // Right operand. |
| 3151 boundary = rel_op->InputAt(0)->definition(); | 3155 boundary = rel_op->InputAt(0)->definition(); |
| (...skipping 2622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5774 | 5778 |
| 5775 | 5779 |
| 5776 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | 5780 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 5777 const Object& left = instr->left()->definition()->constant_value(); | 5781 const Object& left = instr->left()->definition()->constant_value(); |
| 5778 const Object& right = instr->right()->definition()->constant_value(); | 5782 const Object& right = instr->right()->definition()->constant_value(); |
| 5779 | 5783 |
| 5780 if (instr->left()->definition() == instr->right()->definition()) { | 5784 if (instr->left()->definition() == instr->right()->definition()) { |
| 5781 // Fold x == x, and x != x to true/false for numbers and checked strict | 5785 // Fold x == x, and x != x to true/false for numbers and checked strict |
| 5782 // comparisons. | 5786 // comparisons. |
| 5783 if (instr->IsCheckedStrictEqual() || | 5787 if (instr->IsCheckedStrictEqual() || |
| 5784 RawObject::IsIntegerClassId(instr->receiver_class_id())) { | 5788 RawObject::IsIntegerClassId(instr->operation_cid())) { |
| 5785 return SetValue(instr, | 5789 return SetValue(instr, |
| 5786 (instr->kind() == Token::kEQ) | 5790 (instr->kind() == Token::kEQ) |
| 5787 ? Bool::True() | 5791 ? Bool::True() |
| 5788 : Bool::False()); | 5792 : Bool::False()); |
| 5789 } | 5793 } |
| 5790 } | 5794 } |
| 5791 | 5795 |
| 5792 if (IsNonConstant(left) || IsNonConstant(right)) { | 5796 if (IsNonConstant(left) || IsNonConstant(right)) { |
| 5793 SetValue(instr, non_constant_); | 5797 SetValue(instr, non_constant_); |
| 5794 } else if (IsConstant(left) && IsConstant(right)) { | 5798 } else if (IsConstant(left) && IsConstant(right)) { |
| (...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7244 | 7248 |
| 7245 // Insert materializations at environment uses. | 7249 // Insert materializations at environment uses. |
| 7246 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7250 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7247 for (intptr_t i = 0; i < exits.length(); i++) { | 7251 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7248 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7252 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 7249 } | 7253 } |
| 7250 } | 7254 } |
| 7251 | 7255 |
| 7252 | 7256 |
| 7253 } // namespace dart | 7257 } // namespace dart |
| OLD | NEW |