| 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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
| 8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/flow_graph_allocator.h" | 11 #include "vm/flow_graph_allocator.h" |
| 12 #include "vm/flow_graph_builder.h" | 12 #include "vm/flow_graph_builder.h" |
| 13 #include "vm/flow_graph_compiler.h" | 13 #include "vm/flow_graph_compiler.h" |
| 14 #include "vm/flow_graph_optimizer.h" | 14 #include "vm/flow_graph_optimizer.h" |
| 15 #include "vm/flow_graph_range_analysis.h" |
| 15 #include "vm/locations.h" | 16 #include "vm/locations.h" |
| 16 #include "vm/object.h" | 17 #include "vm/object.h" |
| 17 #include "vm/object_store.h" | 18 #include "vm/object_store.h" |
| 18 #include "vm/os.h" | 19 #include "vm/os.h" |
| 19 #include "vm/resolver.h" | 20 #include "vm/resolver.h" |
| 20 #include "vm/scopes.h" | 21 #include "vm/scopes.h" |
| 21 #include "vm/stub_code.h" | 22 #include "vm/stub_code.h" |
| 22 #include "vm/symbols.h" | 23 #include "vm/symbols.h" |
| 23 | 24 |
| 24 #include "vm/il_printer.h" | 25 #include "vm/il_printer.h" |
| (...skipping 2550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2575 intptr_t use_index = instr->env()->Length(); // Start index after inner. | 2576 intptr_t use_index = instr->env()->Length(); // Start index after inner. |
| 2576 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 2577 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
| 2577 Value* value = it.CurrentValue(); | 2578 Value* value = it.CurrentValue(); |
| 2578 value->set_instruction(instr); | 2579 value->set_instruction(instr); |
| 2579 value->set_use_index(use_index++); | 2580 value->set_use_index(use_index++); |
| 2580 value->definition()->AddEnvUse(value); | 2581 value->definition()->AddEnvUse(value); |
| 2581 } | 2582 } |
| 2582 } | 2583 } |
| 2583 | 2584 |
| 2584 | 2585 |
| 2585 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, int64_t offs) { | |
| 2586 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | |
| 2587 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | |
| 2588 } | |
| 2589 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | |
| 2590 } | |
| 2591 | |
| 2592 | |
| 2593 RangeBoundary RangeBoundary::LowerBound() const { | |
| 2594 if (IsInfinity()) { | |
| 2595 return NegativeInfinity(); | |
| 2596 } | |
| 2597 if (IsConstant()) return *this; | |
| 2598 return Add(Range::ConstantMin(symbol()->range()), | |
| 2599 RangeBoundary::FromConstant(offset_), | |
| 2600 NegativeInfinity()); | |
| 2601 } | |
| 2602 | |
| 2603 | |
| 2604 RangeBoundary RangeBoundary::UpperBound() const { | |
| 2605 if (IsInfinity()) { | |
| 2606 return PositiveInfinity(); | |
| 2607 } | |
| 2608 if (IsConstant()) return *this; | |
| 2609 return Add(Range::ConstantMax(symbol()->range()), | |
| 2610 RangeBoundary::FromConstant(offset_), | |
| 2611 PositiveInfinity()); | |
| 2612 } | |
| 2613 | |
| 2614 | |
| 2615 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | |
| 2616 const RangeBoundary& b, | |
| 2617 const RangeBoundary& overflow) { | |
| 2618 if (a.IsInfinity() || b.IsInfinity()) return overflow; | |
| 2619 | |
| 2620 ASSERT(a.IsConstant() && b.IsConstant()); | |
| 2621 if (Utils::WillAddOverflow(a.ConstantValue(), b.ConstantValue())) { | |
| 2622 return overflow; | |
| 2623 } | |
| 2624 | |
| 2625 int64_t result = a.ConstantValue() + b.ConstantValue(); | |
| 2626 | |
| 2627 return RangeBoundary::FromConstant(result); | |
| 2628 } | |
| 2629 | |
| 2630 | |
| 2631 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a, | |
| 2632 const RangeBoundary& b, | |
| 2633 const RangeBoundary& overflow) { | |
| 2634 if (a.IsInfinity() || b.IsInfinity()) return overflow; | |
| 2635 ASSERT(a.IsConstant() && b.IsConstant()); | |
| 2636 if (Utils::WillSubOverflow(a.ConstantValue(), b.ConstantValue())) { | |
| 2637 return overflow; | |
| 2638 } | |
| 2639 | |
| 2640 int64_t result = a.ConstantValue() - b.ConstantValue(); | |
| 2641 | |
| 2642 return RangeBoundary::FromConstant(result); | |
| 2643 } | |
| 2644 | |
| 2645 | |
| 2646 bool RangeBoundary::SymbolicAdd(const RangeBoundary& a, | |
| 2647 const RangeBoundary& b, | |
| 2648 RangeBoundary* result) { | |
| 2649 if (a.IsSymbol() && b.IsConstant()) { | |
| 2650 if (Utils::WillAddOverflow(a.offset(), b.ConstantValue())) { | |
| 2651 return false; | |
| 2652 } | |
| 2653 | |
| 2654 const int64_t offset = a.offset() + b.ConstantValue(); | |
| 2655 | |
| 2656 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
| 2657 return true; | |
| 2658 } else if (b.IsSymbol() && a.IsConstant()) { | |
| 2659 return SymbolicAdd(b, a, result); | |
| 2660 } | |
| 2661 return false; | |
| 2662 } | |
| 2663 | |
| 2664 | |
| 2665 bool RangeBoundary::SymbolicSub(const RangeBoundary& a, | |
| 2666 const RangeBoundary& b, | |
| 2667 RangeBoundary* result) { | |
| 2668 if (a.IsSymbol() && b.IsConstant()) { | |
| 2669 if (Utils::WillSubOverflow(a.offset(), b.ConstantValue())) { | |
| 2670 return false; | |
| 2671 } | |
| 2672 | |
| 2673 const int64_t offset = a.offset() - b.ConstantValue(); | |
| 2674 | |
| 2675 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
| 2676 return true; | |
| 2677 } | |
| 2678 return false; | |
| 2679 } | |
| 2680 | |
| 2681 | |
| 2682 static Definition* UnwrapConstraint(Definition* defn) { | |
| 2683 while (defn->IsConstraint()) { | |
| 2684 defn = defn->AsConstraint()->value()->definition(); | |
| 2685 } | |
| 2686 return defn; | |
| 2687 } | |
| 2688 | |
| 2689 | |
| 2690 static bool AreEqualDefinitions(Definition* a, Definition* b) { | |
| 2691 a = UnwrapConstraint(a); | |
| 2692 b = UnwrapConstraint(b); | |
| 2693 return (a == b) || | |
| 2694 (a->AllowsCSE() && | |
| 2695 a->Dependencies().IsNone() && | |
| 2696 b->AllowsCSE() && | |
| 2697 b->Dependencies().IsNone() && | |
| 2698 a->Equals(b)); | |
| 2699 } | |
| 2700 | |
| 2701 | |
| 2702 // Returns true if two range boundaries refer to the same symbol. | |
| 2703 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | |
| 2704 return a.IsSymbol() && b.IsSymbol() && | |
| 2705 AreEqualDefinitions(a.symbol(), b.symbol()); | |
| 2706 } | |
| 2707 | |
| 2708 | |
| 2709 bool RangeBoundary::Equals(const RangeBoundary& other) const { | |
| 2710 if (IsConstant() && other.IsConstant()) { | |
| 2711 return ConstantValue() == other.ConstantValue(); | |
| 2712 } else if (IsInfinity() && other.IsInfinity()) { | |
| 2713 return kind() == other.kind(); | |
| 2714 } else if (IsSymbol() && other.IsSymbol()) { | |
| 2715 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); | |
| 2716 } else if (IsUnknown() && other.IsUnknown()) { | |
| 2717 return true; | |
| 2718 } | |
| 2719 return false; | |
| 2720 } | |
| 2721 | |
| 2722 | |
| 2723 RangeBoundary RangeBoundary::Shl(const RangeBoundary& value_boundary, | |
| 2724 int64_t shift_count, | |
| 2725 const RangeBoundary& overflow) { | |
| 2726 ASSERT(value_boundary.IsConstant()); | |
| 2727 ASSERT(shift_count >= 0); | |
| 2728 int64_t limit = 64 - shift_count; | |
| 2729 int64_t value = value_boundary.ConstantValue(); | |
| 2730 | |
| 2731 if ((value == 0) || | |
| 2732 (shift_count == 0) || | |
| 2733 ((limit > 0) && Utils::IsInt(static_cast<int>(limit), value))) { | |
| 2734 // Result stays in 64 bit range. | |
| 2735 int64_t result = value << shift_count; | |
| 2736 return RangeBoundary(result); | |
| 2737 } | |
| 2738 | |
| 2739 return overflow; | |
| 2740 } | |
| 2741 | |
| 2742 | |
| 2743 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, | |
| 2744 const RangeBoundary& overflow) { | |
| 2745 if (a.IsConstant() || a.IsInfinity()) { | |
| 2746 return a; | |
| 2747 } | |
| 2748 | |
| 2749 int64_t offset = a.offset(); | |
| 2750 Definition* symbol = a.symbol(); | |
| 2751 | |
| 2752 bool changed; | |
| 2753 do { | |
| 2754 changed = false; | |
| 2755 if (symbol->IsConstraint()) { | |
| 2756 symbol = symbol->AsConstraint()->value()->definition(); | |
| 2757 changed = true; | |
| 2758 } else if (symbol->IsBinarySmiOp()) { | |
| 2759 BinarySmiOpInstr* op = symbol->AsBinarySmiOp(); | |
| 2760 Definition* left = op->left()->definition(); | |
| 2761 Definition* right = op->right()->definition(); | |
| 2762 switch (op->op_kind()) { | |
| 2763 case Token::kADD: | |
| 2764 if (right->IsConstant()) { | |
| 2765 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value(); | |
| 2766 if (Utils::WillAddOverflow(offset, rhs)) { | |
| 2767 return overflow; | |
| 2768 } | |
| 2769 offset += rhs; | |
| 2770 symbol = left; | |
| 2771 changed = true; | |
| 2772 } else if (left->IsConstant()) { | |
| 2773 int64_t rhs = Smi::Cast(left->AsConstant()->value()).Value(); | |
| 2774 if (Utils::WillAddOverflow(offset, rhs)) { | |
| 2775 return overflow; | |
| 2776 } | |
| 2777 offset += rhs; | |
| 2778 symbol = right; | |
| 2779 changed = true; | |
| 2780 } | |
| 2781 break; | |
| 2782 | |
| 2783 case Token::kSUB: | |
| 2784 if (right->IsConstant()) { | |
| 2785 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value(); | |
| 2786 if (Utils::WillSubOverflow(offset, rhs)) { | |
| 2787 return overflow; | |
| 2788 } | |
| 2789 offset -= rhs; | |
| 2790 symbol = left; | |
| 2791 changed = true; | |
| 2792 } | |
| 2793 break; | |
| 2794 | |
| 2795 default: | |
| 2796 break; | |
| 2797 } | |
| 2798 } | |
| 2799 } while (changed); | |
| 2800 | |
| 2801 return RangeBoundary::FromDefinition(symbol, offset); | |
| 2802 } | |
| 2803 | |
| 2804 | |
| 2805 static bool CanonicalizeMaxBoundary(RangeBoundary* a) { | |
| 2806 if (!a->IsSymbol()) return false; | |
| 2807 | |
| 2808 Range* range = a->symbol()->range(); | |
| 2809 if ((range == NULL) || !range->max().IsSymbol()) return false; | |
| 2810 | |
| 2811 | |
| 2812 if (Utils::WillAddOverflow(range->max().offset(), a->offset())) { | |
| 2813 *a = RangeBoundary::PositiveInfinity(); | |
| 2814 return true; | |
| 2815 } | |
| 2816 | |
| 2817 const int64_t offset = range->max().offset() + a->offset(); | |
| 2818 | |
| 2819 | |
| 2820 *a = CanonicalizeBoundary( | |
| 2821 RangeBoundary::FromDefinition(range->max().symbol(), offset), | |
| 2822 RangeBoundary::PositiveInfinity()); | |
| 2823 | |
| 2824 return true; | |
| 2825 } | |
| 2826 | |
| 2827 | |
| 2828 static bool CanonicalizeMinBoundary(RangeBoundary* a) { | |
| 2829 if (!a->IsSymbol()) return false; | |
| 2830 | |
| 2831 Range* range = a->symbol()->range(); | |
| 2832 if ((range == NULL) || !range->min().IsSymbol()) return false; | |
| 2833 | |
| 2834 if (Utils::WillAddOverflow(range->min().offset(), a->offset())) { | |
| 2835 *a = RangeBoundary::NegativeInfinity(); | |
| 2836 return true; | |
| 2837 } | |
| 2838 | |
| 2839 const int64_t offset = range->min().offset() + a->offset(); | |
| 2840 | |
| 2841 *a = CanonicalizeBoundary( | |
| 2842 RangeBoundary::FromDefinition(range->min().symbol(), offset), | |
| 2843 RangeBoundary::NegativeInfinity()); | |
| 2844 | |
| 2845 return true; | |
| 2846 } | |
| 2847 | |
| 2848 | |
| 2849 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b, | |
| 2850 RangeSize size) { | |
| 2851 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity())); | |
| 2852 ASSERT(!a.IsUnknown() || !b.IsUnknown()); | |
| 2853 if (a.IsUnknown() && !b.IsUnknown()) { | |
| 2854 return b; | |
| 2855 } | |
| 2856 if (!a.IsUnknown() && b.IsUnknown()) { | |
| 2857 return a; | |
| 2858 } | |
| 2859 if (size == kRangeBoundarySmi) { | |
| 2860 if (a.IsSmiMaximumOrAbove() && !b.IsSmiMaximumOrAbove()) { | |
| 2861 return b; | |
| 2862 } | |
| 2863 if (!a.IsSmiMaximumOrAbove() && b.IsSmiMaximumOrAbove()) { | |
| 2864 return a; | |
| 2865 } | |
| 2866 } else { | |
| 2867 ASSERT(size == kRangeBoundaryInt64); | |
| 2868 if (a.IsMaximumOrAbove() && !b.IsMaximumOrAbove()) { | |
| 2869 return b; | |
| 2870 } | |
| 2871 if (!a.IsMaximumOrAbove() && b.IsMaximumOrAbove()) { | |
| 2872 return a; | |
| 2873 } | |
| 2874 } | |
| 2875 | |
| 2876 if (a.Equals(b)) { | |
| 2877 return b; | |
| 2878 } | |
| 2879 | |
| 2880 { | |
| 2881 RangeBoundary canonical_a = | |
| 2882 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity()); | |
| 2883 RangeBoundary canonical_b = | |
| 2884 CanonicalizeBoundary(b, RangeBoundary::PositiveInfinity()); | |
| 2885 do { | |
| 2886 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
| 2887 a = canonical_a; | |
| 2888 b = canonical_b; | |
| 2889 break; | |
| 2890 } | |
| 2891 } while (CanonicalizeMaxBoundary(&canonical_a) || | |
| 2892 CanonicalizeMaxBoundary(&canonical_b)); | |
| 2893 } | |
| 2894 | |
| 2895 if (DependOnSameSymbol(a, b)) { | |
| 2896 return (a.offset() <= b.offset()) ? a : b; | |
| 2897 } | |
| 2898 | |
| 2899 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue(); | |
| 2900 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue(); | |
| 2901 | |
| 2902 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | |
| 2903 } | |
| 2904 | |
| 2905 | |
| 2906 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b, | |
| 2907 RangeSize size) { | |
| 2908 ASSERT(!(a.IsPositiveInfinity() || b.IsPositiveInfinity())); | |
| 2909 ASSERT(!a.IsUnknown() || !b.IsUnknown()); | |
| 2910 if (a.IsUnknown() && !b.IsUnknown()) { | |
| 2911 return b; | |
| 2912 } | |
| 2913 if (!a.IsUnknown() && b.IsUnknown()) { | |
| 2914 return a; | |
| 2915 } | |
| 2916 if (size == kRangeBoundarySmi) { | |
| 2917 if (a.IsSmiMinimumOrBelow() && !b.IsSmiMinimumOrBelow()) { | |
| 2918 return b; | |
| 2919 } | |
| 2920 if (!a.IsSmiMinimumOrBelow() && b.IsSmiMinimumOrBelow()) { | |
| 2921 return a; | |
| 2922 } | |
| 2923 } else { | |
| 2924 ASSERT(size == kRangeBoundaryInt64); | |
| 2925 if (a.IsMinimumOrBelow() && !b.IsMinimumOrBelow()) { | |
| 2926 return b; | |
| 2927 } | |
| 2928 if (!a.IsMinimumOrBelow() && b.IsMinimumOrBelow()) { | |
| 2929 return a; | |
| 2930 } | |
| 2931 } | |
| 2932 if (a.Equals(b)) { | |
| 2933 return b; | |
| 2934 } | |
| 2935 | |
| 2936 { | |
| 2937 RangeBoundary canonical_a = | |
| 2938 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity()); | |
| 2939 RangeBoundary canonical_b = | |
| 2940 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity()); | |
| 2941 | |
| 2942 do { | |
| 2943 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
| 2944 a = canonical_a; | |
| 2945 b = canonical_b; | |
| 2946 break; | |
| 2947 } | |
| 2948 } while (CanonicalizeMinBoundary(&canonical_a) || | |
| 2949 CanonicalizeMinBoundary(&canonical_b)); | |
| 2950 } | |
| 2951 | |
| 2952 if (DependOnSameSymbol(a, b)) { | |
| 2953 return (a.offset() <= b.offset()) ? b : a; | |
| 2954 } | |
| 2955 | |
| 2956 const int64_t max_a = a.LowerBound().Clamp(size).ConstantValue(); | |
| 2957 const int64_t max_b = b.LowerBound().Clamp(size).ConstantValue(); | |
| 2958 | |
| 2959 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | |
| 2960 } | |
| 2961 | |
| 2962 | |
| 2963 int64_t RangeBoundary::ConstantValue() const { | |
| 2964 ASSERT(IsConstant()); | |
| 2965 return value_; | |
| 2966 } | |
| 2967 | |
| 2968 | |
| 2969 void Definition::InferRange() { | |
| 2970 if (Type()->ToCid() == kSmiCid) { | |
| 2971 if (range_ == NULL) { | |
| 2972 range_ = Range::UnknownSmi(); | |
| 2973 } | |
| 2974 } else if (IsMintDefinition()) { | |
| 2975 if (range_ == NULL) { | |
| 2976 range_ = Range::Unknown(); | |
| 2977 } | |
| 2978 } else { | |
| 2979 // Only Smi and Mint supported. | |
| 2980 UNREACHABLE(); | |
| 2981 } | |
| 2982 } | |
| 2983 | |
| 2984 | |
| 2985 void ConstantInstr::InferRange() { | |
| 2986 if (value_.IsSmi()) { | |
| 2987 if (range_ == NULL) { | |
| 2988 int64_t value = Smi::Cast(value_).Value(); | |
| 2989 range_ = new Range(RangeBoundary::FromConstant(value), | |
| 2990 RangeBoundary::FromConstant(value)); | |
| 2991 } | |
| 2992 } else if (value_.IsMint()) { | |
| 2993 if (range_ == NULL) { | |
| 2994 int64_t value = Mint::Cast(value_).value(); | |
| 2995 range_ = new Range(RangeBoundary::FromConstant(value), | |
| 2996 RangeBoundary::FromConstant(value)); | |
| 2997 } | |
| 2998 } else { | |
| 2999 // Only Smi and Mint supported. | |
| 3000 UNREACHABLE(); | |
| 3001 } | |
| 3002 } | |
| 3003 | |
| 3004 | |
| 3005 void UnboxIntegerInstr::InferRange() { | |
| 3006 if (range_ == NULL) { | |
| 3007 Definition* unboxed = value()->definition(); | |
| 3008 ASSERT(unboxed != NULL); | |
| 3009 Range* range = unboxed->range(); | |
| 3010 if (range == NULL) { | |
| 3011 range_ = Range::Unknown(); | |
| 3012 return; | |
| 3013 } | |
| 3014 range_ = new Range(range->min(), range->max()); | |
| 3015 } | |
| 3016 } | |
| 3017 | |
| 3018 | |
| 3019 void ConstraintInstr::InferRange() { | |
| 3020 Range* value_range = value()->definition()->range(); | |
| 3021 | |
| 3022 // Only constraining smi values. | |
| 3023 ASSERT(value()->IsSmiValue()); | |
| 3024 | |
| 3025 RangeBoundary min; | |
| 3026 RangeBoundary max; | |
| 3027 | |
| 3028 { | |
| 3029 RangeBoundary value_min = (value_range == NULL) ? | |
| 3030 RangeBoundary() : value_range->min(); | |
| 3031 RangeBoundary constraint_min = constraint()->min(); | |
| 3032 min = RangeBoundary::Max(value_min, constraint_min, | |
| 3033 RangeBoundary::kRangeBoundarySmi); | |
| 3034 } | |
| 3035 | |
| 3036 ASSERT(!min.IsUnknown()); | |
| 3037 | |
| 3038 { | |
| 3039 RangeBoundary value_max = (value_range == NULL) ? | |
| 3040 RangeBoundary() : value_range->max(); | |
| 3041 RangeBoundary constraint_max = constraint()->max(); | |
| 3042 max = RangeBoundary::Min(value_max, constraint_max, | |
| 3043 RangeBoundary::kRangeBoundarySmi); | |
| 3044 } | |
| 3045 | |
| 3046 ASSERT(!max.IsUnknown()); | |
| 3047 | |
| 3048 range_ = new Range(min, max); | |
| 3049 | |
| 3050 // Mark branches that generate unsatisfiable constraints as constant. | |
| 3051 if (target() != NULL && range_->IsUnsatisfiable()) { | |
| 3052 BranchInstr* branch = | |
| 3053 target()->PredecessorAt(0)->last_instruction()->AsBranch(); | |
| 3054 if (target() == branch->true_successor()) { | |
| 3055 // True unreachable. | |
| 3056 if (FLAG_trace_constant_propagation) { | |
| 3057 OS::Print("Range analysis: True unreachable (B%" Pd ")\n", | |
| 3058 branch->true_successor()->block_id()); | |
| 3059 } | |
| 3060 branch->set_constant_target(branch->false_successor()); | |
| 3061 } else { | |
| 3062 ASSERT(target() == branch->false_successor()); | |
| 3063 // False unreachable. | |
| 3064 if (FLAG_trace_constant_propagation) { | |
| 3065 OS::Print("Range analysis: False unreachable (B%" Pd ")\n", | |
| 3066 branch->false_successor()->block_id()); | |
| 3067 } | |
| 3068 branch->set_constant_target(branch->true_successor()); | |
| 3069 } | |
| 3070 } | |
| 3071 } | |
| 3072 | |
| 3073 | |
| 3074 void LoadFieldInstr::InferRange() { | |
| 3075 if ((range_ == NULL) && | |
| 3076 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) || | |
| 3077 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) { | |
| 3078 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3079 RangeBoundary::FromConstant(Array::kMaxElements)); | |
| 3080 return; | |
| 3081 } | |
| 3082 if ((range_ == NULL) && | |
| 3083 (recognized_kind() == MethodRecognizer::kTypedDataLength)) { | |
| 3084 range_ = new Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi()); | |
| 3085 return; | |
| 3086 } | |
| 3087 if ((range_ == NULL) && | |
| 3088 (recognized_kind() == MethodRecognizer::kStringBaseLength)) { | |
| 3089 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3090 RangeBoundary::FromConstant(String::kMaxElements)); | |
| 3091 return; | |
| 3092 } | |
| 3093 Definition::InferRange(); | |
| 3094 } | |
| 3095 | |
| 3096 | |
| 3097 | |
| 3098 void LoadIndexedInstr::InferRange() { | |
| 3099 switch (class_id()) { | |
| 3100 case kTypedDataInt8ArrayCid: | |
| 3101 range_ = new Range(RangeBoundary::FromConstant(-128), | |
| 3102 RangeBoundary::FromConstant(127)); | |
| 3103 break; | |
| 3104 case kTypedDataUint8ArrayCid: | |
| 3105 case kTypedDataUint8ClampedArrayCid: | |
| 3106 case kExternalTypedDataUint8ArrayCid: | |
| 3107 case kExternalTypedDataUint8ClampedArrayCid: | |
| 3108 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3109 RangeBoundary::FromConstant(255)); | |
| 3110 break; | |
| 3111 case kTypedDataInt16ArrayCid: | |
| 3112 range_ = new Range(RangeBoundary::FromConstant(-32768), | |
| 3113 RangeBoundary::FromConstant(32767)); | |
| 3114 break; | |
| 3115 case kTypedDataUint16ArrayCid: | |
| 3116 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3117 RangeBoundary::FromConstant(65535)); | |
| 3118 break; | |
| 3119 case kTypedDataInt32ArrayCid: | |
| 3120 if (Typed32BitIsSmi()) { | |
| 3121 range_ = Range::UnknownSmi(); | |
| 3122 } else { | |
| 3123 range_ = new Range(RangeBoundary::FromConstant(kMinInt32), | |
| 3124 RangeBoundary::FromConstant(kMaxInt32)); | |
| 3125 } | |
| 3126 break; | |
| 3127 case kTypedDataUint32ArrayCid: | |
| 3128 if (Typed32BitIsSmi()) { | |
| 3129 range_ = Range::UnknownSmi(); | |
| 3130 } else { | |
| 3131 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3132 RangeBoundary::FromConstant(kMaxUint32)); | |
| 3133 } | |
| 3134 break; | |
| 3135 case kOneByteStringCid: | |
| 3136 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3137 RangeBoundary::FromConstant(0xFF)); | |
| 3138 break; | |
| 3139 case kTwoByteStringCid: | |
| 3140 range_ = new Range(RangeBoundary::FromConstant(0), | |
| 3141 RangeBoundary::FromConstant(0xFFFF)); | |
| 3142 break; | |
| 3143 default: | |
| 3144 Definition::InferRange(); | |
| 3145 break; | |
| 3146 } | |
| 3147 } | |
| 3148 | |
| 3149 | |
| 3150 void IfThenElseInstr::InferRange() { | |
| 3151 const intptr_t min = Utils::Minimum(if_true_, if_false_); | |
| 3152 const intptr_t max = Utils::Maximum(if_true_, if_false_); | |
| 3153 range_ = new Range(RangeBoundary::FromConstant(min), | |
| 3154 RangeBoundary::FromConstant(max)); | |
| 3155 } | |
| 3156 | |
| 3157 | |
| 3158 static bool BindsToSmiConstant(Value* value) { | 2586 static bool BindsToSmiConstant(Value* value) { |
| 3159 return value->BindsToConstant() && value->BoundConstant().IsSmi(); | 2587 return value->BindsToConstant() && value->BoundConstant().IsSmi(); |
| 3160 } | 2588 } |
| 3161 | 2589 |
| 3162 | 2590 |
| 3163 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, | 2591 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, |
| 3164 Value* new_right) { | 2592 Value* new_right) { |
| 3165 return new EqualityCompareInstr(token_pos(), | 2593 return new EqualityCompareInstr(token_pos(), |
| 3166 kind(), | 2594 kind(), |
| 3167 new_left, | 2595 new_left, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3239 && !comparison->AsStrictCompare()->needs_number_check(); | 2667 && !comparison->AsStrictCompare()->needs_number_check(); |
| 3240 } | 2668 } |
| 3241 if (comparison->operation_cid() != kSmiCid) { | 2669 if (comparison->operation_cid() != kSmiCid) { |
| 3242 // Non-smi comparisons are not supported by if-conversion. | 2670 // Non-smi comparisons are not supported by if-conversion. |
| 3243 return false; | 2671 return false; |
| 3244 } | 2672 } |
| 3245 return is_smi_result; | 2673 return is_smi_result; |
| 3246 } | 2674 } |
| 3247 | 2675 |
| 3248 | 2676 |
| 3249 void PhiInstr::InferRange() { | |
| 3250 RangeBoundary new_min; | |
| 3251 RangeBoundary new_max; | |
| 3252 | |
| 3253 ASSERT(Type()->ToCid() == kSmiCid); | |
| 3254 | |
| 3255 for (intptr_t i = 0; i < InputCount(); i++) { | |
| 3256 Range* input_range = InputAt(i)->definition()->range(); | |
| 3257 if (input_range == NULL) { | |
| 3258 range_ = Range::UnknownSmi(); | |
| 3259 return; | |
| 3260 } | |
| 3261 | |
| 3262 if (new_min.IsUnknown()) { | |
| 3263 new_min = Range::ConstantMin(input_range); | |
| 3264 } else { | |
| 3265 new_min = RangeBoundary::Min(new_min, | |
| 3266 Range::ConstantMinSmi(input_range), | |
| 3267 RangeBoundary::kRangeBoundarySmi); | |
| 3268 } | |
| 3269 | |
| 3270 if (new_max.IsUnknown()) { | |
| 3271 new_max = Range::ConstantMax(input_range); | |
| 3272 } else { | |
| 3273 new_max = RangeBoundary::Max(new_max, | |
| 3274 Range::ConstantMaxSmi(input_range), | |
| 3275 RangeBoundary::kRangeBoundarySmi); | |
| 3276 } | |
| 3277 } | |
| 3278 | |
| 3279 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); | |
| 3280 if (new_min.IsUnknown()) { | |
| 3281 range_ = Range::UnknownSmi(); | |
| 3282 return; | |
| 3283 } | |
| 3284 | |
| 3285 range_ = new Range(new_min, new_max); | |
| 3286 } | |
| 3287 | |
| 3288 | |
| 3289 bool PhiInstr::IsRedundant() const { | 2677 bool PhiInstr::IsRedundant() const { |
| 3290 ASSERT(InputCount() > 1); | 2678 ASSERT(InputCount() > 1); |
| 3291 Definition* first = InputAt(0)->definition(); | 2679 Definition* first = InputAt(0)->definition(); |
| 3292 for (intptr_t i = 1; i < InputCount(); ++i) { | 2680 for (intptr_t i = 1; i < InputCount(); ++i) { |
| 3293 Definition* def = InputAt(i)->definition(); | 2681 Definition* def = InputAt(i)->definition(); |
| 3294 if (def != first) return false; | 2682 if (def != first) return false; |
| 3295 } | 2683 } |
| 3296 return true; | 2684 return true; |
| 3297 } | 2685 } |
| 3298 | 2686 |
| 3299 | 2687 |
| 3300 static bool IsArrayLength(Definition* defn) { | |
| 3301 if (defn == NULL) { | |
| 3302 return false; | |
| 3303 } | |
| 3304 LoadFieldInstr* load = defn->AsLoadField(); | |
| 3305 return (load != NULL) && load->IsImmutableLengthLoad(); | |
| 3306 } | |
| 3307 | |
| 3308 | |
| 3309 void BinarySmiOpInstr::InferRange() { | |
| 3310 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | |
| 3311 // right and a non-constant on the left. | |
| 3312 Definition* left_defn = left()->definition(); | |
| 3313 | |
| 3314 Range* left_range = left_defn->range(); | |
| 3315 Range* right_range = right()->definition()->range(); | |
| 3316 | |
| 3317 if ((left_range == NULL) || (right_range == NULL)) { | |
| 3318 range_ = Range::UnknownSmi(); | |
| 3319 return; | |
| 3320 } | |
| 3321 | |
| 3322 Range* possible_range = Range::BinaryOp(op_kind(), | |
| 3323 left_range, | |
| 3324 right_range, | |
| 3325 left_defn); | |
| 3326 | |
| 3327 if ((range_ == NULL) && (possible_range == NULL)) { | |
| 3328 // Initialize. | |
| 3329 range_ = Range::UnknownSmi(); | |
| 3330 return; | |
| 3331 } | |
| 3332 | |
| 3333 if (possible_range == NULL) { | |
| 3334 // Nothing new. | |
| 3335 return; | |
| 3336 } | |
| 3337 | |
| 3338 range_ = possible_range; | |
| 3339 | |
| 3340 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); | |
| 3341 // Calculate overflowed status before clamping. | |
| 3342 const bool overflowed = range_->min().LowerBound().OverflowedSmi() || | |
| 3343 range_->max().UpperBound().OverflowedSmi(); | |
| 3344 set_overflow(overflowed); | |
| 3345 | |
| 3346 // Clamp value to be within smi range. | |
| 3347 range_->Clamp(RangeBoundary::kRangeBoundarySmi); | |
| 3348 } | |
| 3349 | |
| 3350 | |
| 3351 void BinaryMintOpInstr::InferRange() { | |
| 3352 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | |
| 3353 // the right and a non-constant on the left. | |
| 3354 Definition* left_defn = left()->definition(); | |
| 3355 | |
| 3356 Range* left_range = left_defn->range(); | |
| 3357 Range* right_range = right()->definition()->range(); | |
| 3358 | |
| 3359 if ((left_range == NULL) || (right_range == NULL)) { | |
| 3360 range_ = Range::Unknown(); | |
| 3361 return; | |
| 3362 } | |
| 3363 | |
| 3364 Range* possible_range = Range::BinaryOp(op_kind(), | |
| 3365 left_range, | |
| 3366 right_range, | |
| 3367 left_defn); | |
| 3368 | |
| 3369 if ((range_ == NULL) && (possible_range == NULL)) { | |
| 3370 // Initialize. | |
| 3371 range_ = Range::Unknown(); | |
| 3372 return; | |
| 3373 } | |
| 3374 | |
| 3375 if (possible_range == NULL) { | |
| 3376 // Nothing new. | |
| 3377 return; | |
| 3378 } | |
| 3379 | |
| 3380 range_ = possible_range; | |
| 3381 | |
| 3382 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); | |
| 3383 | |
| 3384 // Calculate overflowed status before clamping. | |
| 3385 const bool overflowed = range_->min().LowerBound().OverflowedMint() || | |
| 3386 range_->max().UpperBound().OverflowedMint(); | |
| 3387 set_can_overflow(overflowed); | |
| 3388 | |
| 3389 // Clamp value to be within mint range. | |
| 3390 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); | |
| 3391 } | |
| 3392 | |
| 3393 | |
| 3394 void ShiftMintOpInstr::InferRange() { | |
| 3395 Definition* left_defn = left()->definition(); | |
| 3396 | |
| 3397 Range* left_range = left_defn->range(); | |
| 3398 Range* right_range = right()->definition()->range(); | |
| 3399 | |
| 3400 if ((left_range == NULL) || (right_range == NULL)) { | |
| 3401 range_ = Range::Unknown(); | |
| 3402 return; | |
| 3403 } | |
| 3404 | |
| 3405 Range* possible_range = Range::BinaryOp(op_kind(), | |
| 3406 left_range, | |
| 3407 right_range, | |
| 3408 left_defn); | |
| 3409 | |
| 3410 if ((range_ == NULL) && (possible_range == NULL)) { | |
| 3411 // Initialize. | |
| 3412 range_ = Range::Unknown(); | |
| 3413 return; | |
| 3414 } | |
| 3415 | |
| 3416 if (possible_range == NULL) { | |
| 3417 // Nothing new. | |
| 3418 return; | |
| 3419 } | |
| 3420 | |
| 3421 range_ = possible_range; | |
| 3422 | |
| 3423 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); | |
| 3424 | |
| 3425 // Calculate overflowed status before clamping. | |
| 3426 const bool overflowed = range_->min().LowerBound().OverflowedMint() || | |
| 3427 range_->max().UpperBound().OverflowedMint(); | |
| 3428 set_can_overflow(overflowed); | |
| 3429 | |
| 3430 // Clamp value to be within mint range. | |
| 3431 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); | |
| 3432 } | |
| 3433 | |
| 3434 | |
| 3435 void BoxIntegerInstr::InferRange() { | |
| 3436 Range* input_range = value()->definition()->range(); | |
| 3437 if (input_range != NULL) { | |
| 3438 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && | |
| 3439 !input_range->max().UpperBound().OverflowedSmi(); | |
| 3440 set_is_smi(is_smi); | |
| 3441 // The output range is the same as the input range. | |
| 3442 range_ = input_range; | |
| 3443 } | |
| 3444 } | |
| 3445 | |
| 3446 | |
| 3447 bool Range::IsPositive() const { | |
| 3448 if (min().IsNegativeInfinity()) { | |
| 3449 return false; | |
| 3450 } | |
| 3451 if (min().LowerBound().ConstantValue() < 0) { | |
| 3452 return false; | |
| 3453 } | |
| 3454 if (max().IsPositiveInfinity()) { | |
| 3455 return true; | |
| 3456 } | |
| 3457 return max().UpperBound().ConstantValue() >= 0; | |
| 3458 } | |
| 3459 | |
| 3460 | |
| 3461 bool Range::OnlyLessThanOrEqualTo(int64_t val) const { | |
| 3462 if (max().IsPositiveInfinity()) { | |
| 3463 // Cannot be true. | |
| 3464 return false; | |
| 3465 } | |
| 3466 if (max().UpperBound().ConstantValue() > val) { | |
| 3467 // Not true. | |
| 3468 return false; | |
| 3469 } | |
| 3470 return true; | |
| 3471 } | |
| 3472 | |
| 3473 | |
| 3474 bool Range::OnlyGreaterThanOrEqualTo(int64_t val) const { | |
| 3475 if (min().IsNegativeInfinity()) { | |
| 3476 return false; | |
| 3477 } | |
| 3478 if (min().LowerBound().ConstantValue() < val) { | |
| 3479 return false; | |
| 3480 } | |
| 3481 return true; | |
| 3482 } | |
| 3483 | |
| 3484 | |
| 3485 // Inclusive. | |
| 3486 bool Range::IsWithin(int64_t min_int, int64_t max_int) const { | |
| 3487 RangeBoundary lower_min = min().LowerBound(); | |
| 3488 if (lower_min.IsNegativeInfinity() || (lower_min.ConstantValue() < min_int)) { | |
| 3489 return false; | |
| 3490 } | |
| 3491 RangeBoundary upper_max = max().UpperBound(); | |
| 3492 if (upper_max.IsPositiveInfinity() || (upper_max.ConstantValue() > max_int)) { | |
| 3493 return false; | |
| 3494 } | |
| 3495 return true; | |
| 3496 } | |
| 3497 | |
| 3498 | |
| 3499 bool Range::Overlaps(int64_t min_int, int64_t max_int) const { | |
| 3500 RangeBoundary lower = min().LowerBound(); | |
| 3501 RangeBoundary upper = max().UpperBound(); | |
| 3502 const int64_t this_min = lower.IsNegativeInfinity() ? | |
| 3503 RangeBoundary::kMin : lower.ConstantValue(); | |
| 3504 const int64_t this_max = upper.IsPositiveInfinity() ? | |
| 3505 RangeBoundary::kMax : upper.ConstantValue(); | |
| 3506 if ((this_min <= min_int) && (min_int <= this_max)) return true; | |
| 3507 if ((this_min <= max_int) && (max_int <= this_max)) return true; | |
| 3508 if ((min_int < this_min) && (max_int > this_max)) return true; | |
| 3509 return false; | |
| 3510 } | |
| 3511 | |
| 3512 | |
| 3513 bool Range::IsUnsatisfiable() const { | |
| 3514 // Infinity case: [+inf, ...] || [..., -inf] | |
| 3515 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { | |
| 3516 return true; | |
| 3517 } | |
| 3518 // Constant case: For example [0, -1]. | |
| 3519 if (Range::ConstantMin(this).ConstantValue() > | |
| 3520 Range::ConstantMax(this).ConstantValue()) { | |
| 3521 return true; | |
| 3522 } | |
| 3523 // Symbol case: For example [v+1, v]. | |
| 3524 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { | |
| 3525 return true; | |
| 3526 } | |
| 3527 return false; | |
| 3528 } | |
| 3529 | |
| 3530 | |
| 3531 void Range::Clamp(RangeBoundary::RangeSize size) { | |
| 3532 min_ = min_.Clamp(size); | |
| 3533 max_ = max_.Clamp(size); | |
| 3534 } | |
| 3535 | |
| 3536 | |
| 3537 void Range::Shl(const Range* left, | |
| 3538 const Range* right, | |
| 3539 RangeBoundary* result_min, | |
| 3540 RangeBoundary* result_max) { | |
| 3541 ASSERT(left != NULL); | |
| 3542 ASSERT(right != NULL); | |
| 3543 ASSERT(result_min != NULL); | |
| 3544 ASSERT(result_max != NULL); | |
| 3545 RangeBoundary left_max = Range::ConstantMax(left); | |
| 3546 RangeBoundary left_min = Range::ConstantMin(left); | |
| 3547 // A negative shift count always deoptimizes (and throws), so the minimum | |
| 3548 // shift count is zero. | |
| 3549 int64_t right_max = Utils::Maximum(Range::ConstantMax(right).ConstantValue(), | |
| 3550 static_cast<int64_t>(0)); | |
| 3551 int64_t right_min = Utils::Maximum(Range::ConstantMin(right).ConstantValue(), | |
| 3552 static_cast<int64_t>(0)); | |
| 3553 | |
| 3554 *result_min = RangeBoundary::Shl( | |
| 3555 left_min, | |
| 3556 left_min.ConstantValue() > 0 ? right_min : right_max, | |
| 3557 left_min.ConstantValue() > 0 | |
| 3558 ? RangeBoundary::PositiveInfinity() | |
| 3559 : RangeBoundary::NegativeInfinity()); | |
| 3560 | |
| 3561 *result_max = RangeBoundary::Shl( | |
| 3562 left_max, | |
| 3563 left_max.ConstantValue() > 0 ? right_max : right_min, | |
| 3564 left_max.ConstantValue() > 0 | |
| 3565 ? RangeBoundary::PositiveInfinity() | |
| 3566 : RangeBoundary::NegativeInfinity()); | |
| 3567 } | |
| 3568 | |
| 3569 | |
| 3570 void Range::Shr(const Range* left, | |
| 3571 const Range* right, | |
| 3572 RangeBoundary* result_min, | |
| 3573 RangeBoundary* result_max) { | |
| 3574 RangeBoundary left_max = Range::ConstantMax(left); | |
| 3575 RangeBoundary left_min = Range::ConstantMin(left); | |
| 3576 // A negative shift count always deoptimizes (and throws), so the minimum | |
| 3577 // shift count is zero. | |
| 3578 int64_t right_max = Utils::Maximum(Range::ConstantMax(right).ConstantValue(), | |
| 3579 static_cast<int64_t>(0)); | |
| 3580 int64_t right_min = Utils::Maximum(Range::ConstantMin(right).ConstantValue(), | |
| 3581 static_cast<int64_t>(0)); | |
| 3582 | |
| 3583 *result_min = RangeBoundary::Shr( | |
| 3584 left_min, | |
| 3585 left_min.ConstantValue() > 0 ? right_max : right_min); | |
| 3586 | |
| 3587 *result_max = RangeBoundary::Shr( | |
| 3588 left_max, | |
| 3589 left_max.ConstantValue() > 0 ? right_min : right_max); | |
| 3590 } | |
| 3591 | |
| 3592 | |
| 3593 bool Range::And(const Range* left_range, | |
| 3594 const Range* right_range, | |
| 3595 RangeBoundary* result_min, | |
| 3596 RangeBoundary* result_max) { | |
| 3597 ASSERT(left_range != NULL); | |
| 3598 ASSERT(right_range != NULL); | |
| 3599 ASSERT(result_min != NULL); | |
| 3600 ASSERT(result_max != NULL); | |
| 3601 | |
| 3602 if (Range::ConstantMin(right_range).ConstantValue() >= 0) { | |
| 3603 *result_min = RangeBoundary::FromConstant(0); | |
| 3604 *result_max = Range::ConstantMax(right_range); | |
| 3605 return true; | |
| 3606 } | |
| 3607 | |
| 3608 if (Range::ConstantMin(left_range).ConstantValue() >= 0) { | |
| 3609 *result_min = RangeBoundary::FromConstant(0); | |
| 3610 *result_max = Range::ConstantMax(left_range); | |
| 3611 return true; | |
| 3612 } | |
| 3613 | |
| 3614 return false; | |
| 3615 } | |
| 3616 | |
| 3617 | |
| 3618 void Range::Add(const Range* left_range, | |
| 3619 const Range* right_range, | |
| 3620 RangeBoundary* result_min, | |
| 3621 RangeBoundary* result_max, | |
| 3622 Definition* left_defn) { | |
| 3623 ASSERT(left_range != NULL); | |
| 3624 ASSERT(right_range != NULL); | |
| 3625 ASSERT(result_min != NULL); | |
| 3626 ASSERT(result_max != NULL); | |
| 3627 | |
| 3628 RangeBoundary left_min = | |
| 3629 IsArrayLength(left_defn) ? | |
| 3630 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | |
| 3631 | |
| 3632 RangeBoundary left_max = | |
| 3633 IsArrayLength(left_defn) ? | |
| 3634 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | |
| 3635 | |
| 3636 if (!RangeBoundary::SymbolicAdd(left_min, right_range->min(), result_min)) { | |
| 3637 *result_min = RangeBoundary::Add(left_range->min().LowerBound(), | |
| 3638 right_range->min().LowerBound(), | |
| 3639 RangeBoundary::NegativeInfinity()); | |
| 3640 } | |
| 3641 if (!RangeBoundary::SymbolicAdd(left_max, right_range->max(), result_max)) { | |
| 3642 *result_max = RangeBoundary::Add(right_range->max().UpperBound(), | |
| 3643 left_range->max().UpperBound(), | |
| 3644 RangeBoundary::PositiveInfinity()); | |
| 3645 } | |
| 3646 } | |
| 3647 | |
| 3648 | |
| 3649 void Range::Sub(const Range* left_range, | |
| 3650 const Range* right_range, | |
| 3651 RangeBoundary* result_min, | |
| 3652 RangeBoundary* result_max, | |
| 3653 Definition* left_defn) { | |
| 3654 ASSERT(left_range != NULL); | |
| 3655 ASSERT(right_range != NULL); | |
| 3656 ASSERT(result_min != NULL); | |
| 3657 ASSERT(result_max != NULL); | |
| 3658 | |
| 3659 RangeBoundary left_min = | |
| 3660 IsArrayLength(left_defn) ? | |
| 3661 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | |
| 3662 | |
| 3663 RangeBoundary left_max = | |
| 3664 IsArrayLength(left_defn) ? | |
| 3665 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | |
| 3666 | |
| 3667 if (!RangeBoundary::SymbolicSub(left_min, right_range->max(), result_min)) { | |
| 3668 *result_min = RangeBoundary::Sub(left_range->min().LowerBound(), | |
| 3669 right_range->max().UpperBound(), | |
| 3670 RangeBoundary::NegativeInfinity()); | |
| 3671 } | |
| 3672 if (!RangeBoundary::SymbolicSub(left_max, right_range->min(), result_max)) { | |
| 3673 *result_max = RangeBoundary::Sub(left_range->max().UpperBound(), | |
| 3674 right_range->min().LowerBound(), | |
| 3675 RangeBoundary::PositiveInfinity()); | |
| 3676 } | |
| 3677 } | |
| 3678 | |
| 3679 | |
| 3680 bool Range::Mul(const Range* left_range, | |
| 3681 const Range* right_range, | |
| 3682 RangeBoundary* result_min, | |
| 3683 RangeBoundary* result_max) { | |
| 3684 ASSERT(left_range != NULL); | |
| 3685 ASSERT(right_range != NULL); | |
| 3686 ASSERT(result_min != NULL); | |
| 3687 ASSERT(result_max != NULL); | |
| 3688 | |
| 3689 const int64_t left_max = ConstantAbsMax(left_range); | |
| 3690 const int64_t right_max = ConstantAbsMax(right_range); | |
| 3691 if ((left_max <= -kSmiMin) && (right_max <= -kSmiMin) && | |
| 3692 ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) { | |
| 3693 // Product of left and right max values stays in 64 bit range. | |
| 3694 const int64_t mul_max = left_max * right_max; | |
| 3695 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { | |
| 3696 const int64_t r_min = | |
| 3697 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; | |
| 3698 *result_min = RangeBoundary::FromConstant(r_min); | |
| 3699 const int64_t r_max = | |
| 3700 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; | |
| 3701 *result_max = RangeBoundary::FromConstant(r_max); | |
| 3702 return true; | |
| 3703 } | |
| 3704 } | |
| 3705 return false; | |
| 3706 } | |
| 3707 | |
| 3708 | |
| 3709 // Both the a and b ranges are >= 0. | |
| 3710 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | |
| 3711 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); | |
| 3712 } | |
| 3713 | |
| 3714 | |
| 3715 // Both the a and b ranges are <= 0. | |
| 3716 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | |
| 3717 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); | |
| 3718 } | |
| 3719 | |
| 3720 | |
| 3721 // Return the maximum absolute value included in range. | |
| 3722 int64_t Range::ConstantAbsMax(const Range* range) { | |
| 3723 if (range == NULL) { | |
| 3724 return RangeBoundary::kMax; | |
| 3725 } | |
| 3726 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); | |
| 3727 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); | |
| 3728 return Utils::Maximum(abs_min, abs_max); | |
| 3729 } | |
| 3730 | |
| 3731 | |
| 3732 Range* Range::BinaryOp(const Token::Kind op, | |
| 3733 const Range* left_range, | |
| 3734 const Range* right_range, | |
| 3735 Definition* left_defn) { | |
| 3736 ASSERT(left_range != NULL); | |
| 3737 ASSERT(right_range != NULL); | |
| 3738 | |
| 3739 // Both left and right ranges are finite. | |
| 3740 ASSERT(left_range->IsFinite()); | |
| 3741 ASSERT(right_range->IsFinite()); | |
| 3742 | |
| 3743 RangeBoundary min; | |
| 3744 RangeBoundary max; | |
| 3745 ASSERT(min.IsUnknown() && max.IsUnknown()); | |
| 3746 | |
| 3747 switch (op) { | |
| 3748 case Token::kADD: | |
| 3749 Range::Add(left_range, right_range, &min, &max, left_defn); | |
| 3750 break; | |
| 3751 case Token::kSUB: | |
| 3752 Range::Sub(left_range, right_range, &min, &max, left_defn); | |
| 3753 break; | |
| 3754 case Token::kMUL: { | |
| 3755 if (!Range::Mul(left_range, right_range, &min, &max)) { | |
| 3756 return NULL; | |
| 3757 } | |
| 3758 break; | |
| 3759 } | |
| 3760 case Token::kSHL: { | |
| 3761 Range::Shl(left_range, right_range, &min, &max); | |
| 3762 break; | |
| 3763 } | |
| 3764 case Token::kSHR: { | |
| 3765 Range::Shr(left_range, right_range, &min, &max); | |
| 3766 break; | |
| 3767 } | |
| 3768 case Token::kBIT_AND: | |
| 3769 if (!Range::And(left_range, right_range, &min, &max)) { | |
| 3770 return NULL; | |
| 3771 } | |
| 3772 break; | |
| 3773 default: | |
| 3774 return NULL; | |
| 3775 break; | |
| 3776 } | |
| 3777 | |
| 3778 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | |
| 3779 | |
| 3780 return new Range(min, max); | |
| 3781 } | |
| 3782 | |
| 3783 | |
| 3784 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 2688 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
| 3785 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 2689 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
| 3786 } | 2690 } |
| 3787 | 2691 |
| 3788 | 2692 |
| 3789 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { | |
| 3790 Range* index_range = index()->definition()->range(); | |
| 3791 | |
| 3792 // Range of the index is unknown can't decide if the check is redundant. | |
| 3793 if (index_range == NULL) { | |
| 3794 return false; | |
| 3795 } | |
| 3796 | |
| 3797 // Range of the index is not positive. Check can't be redundant. | |
| 3798 if (Range::ConstantMinSmi(index_range).ConstantValue() < 0) { | |
| 3799 return false; | |
| 3800 } | |
| 3801 | |
| 3802 RangeBoundary max = CanonicalizeBoundary(index_range->max(), | |
| 3803 RangeBoundary::PositiveInfinity()); | |
| 3804 | |
| 3805 if (max.OverflowedSmi()) { | |
| 3806 return false; | |
| 3807 } | |
| 3808 | |
| 3809 | |
| 3810 RangeBoundary max_upper = max.UpperBound(); | |
| 3811 RangeBoundary length_lower = length.LowerBound(); | |
| 3812 | |
| 3813 if (max_upper.OverflowedSmi() || length_lower.OverflowedSmi()) { | |
| 3814 return false; | |
| 3815 } | |
| 3816 | |
| 3817 // Try to compare constant boundaries. | |
| 3818 if (max_upper.ConstantValue() < length_lower.ConstantValue()) { | |
| 3819 return true; | |
| 3820 } | |
| 3821 | |
| 3822 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); | |
| 3823 if (length.OverflowedSmi()) { | |
| 3824 return false; | |
| 3825 } | |
| 3826 | |
| 3827 // Try symbolic comparison. | |
| 3828 do { | |
| 3829 if (DependOnSameSymbol(max, length)) return max.offset() < length.offset(); | |
| 3830 } while (CanonicalizeMaxBoundary(&max) || CanonicalizeMinBoundary(&length)); | |
| 3831 | |
| 3832 // Failed to prove that maximum is bounded with array length. | |
| 3833 return false; | |
| 3834 } | |
| 3835 | |
| 3836 | |
| 3837 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { | 2693 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { |
| 3838 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) ? | 2694 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) ? |
| 3839 NULL : this; | 2695 NULL : this; |
| 3840 } | 2696 } |
| 3841 | 2697 |
| 3842 | 2698 |
| 3843 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { | 2699 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { |
| 3844 if (RawObject::IsExternalTypedDataClassId(class_id)) { | 2700 if (RawObject::IsExternalTypedDataClassId(class_id)) { |
| 3845 return ExternalTypedData::length_offset(); | 2701 return ExternalTypedData::length_offset(); |
| 3846 } | 2702 } |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4106 case Token::kTRUNCDIV: return 0; | 2962 case Token::kTRUNCDIV: return 0; |
| 4107 case Token::kMOD: return 1; | 2963 case Token::kMOD: return 1; |
| 4108 default: UNIMPLEMENTED(); return -1; | 2964 default: UNIMPLEMENTED(); return -1; |
| 4109 } | 2965 } |
| 4110 } | 2966 } |
| 4111 | 2967 |
| 4112 | 2968 |
| 4113 #undef __ | 2969 #undef __ |
| 4114 | 2970 |
| 4115 } // namespace dart | 2971 } // namespace dart |
| OLD | NEW |