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 |