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 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ | 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ |
6 #define VM_INTERMEDIATE_LANGUAGE_H_ | 6 #define VM_INTERMEDIATE_LANGUAGE_H_ |
7 | 7 |
8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
9 #include "vm/ast.h" | 9 #include "vm/ast.h" |
10 #include "vm/growable_array.h" | 10 #include "vm/growable_array.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 class Definition; | 25 class Definition; |
26 class Environment; | 26 class Environment; |
27 class FlowGraph; | 27 class FlowGraph; |
28 class FlowGraphBuilder; | 28 class FlowGraphBuilder; |
29 class FlowGraphCompiler; | 29 class FlowGraphCompiler; |
30 class FlowGraphVisitor; | 30 class FlowGraphVisitor; |
31 class Instruction; | 31 class Instruction; |
32 class LocalVariable; | 32 class LocalVariable; |
33 class ParsedFunction; | 33 class ParsedFunction; |
34 class Range; | 34 class Range; |
| 35 class RangeBoundary; |
35 | 36 |
36 | 37 |
37 // TODO(srdjan): Unify with INTRINSIC_LIST. | 38 // TODO(srdjan): Unify with INTRINSIC_LIST. |
38 // (class-name, function-name, recognized enum, fingerprint). | 39 // (class-name, function-name, recognized enum, fingerprint). |
39 // See intrinsifier for fingerprint computation. | 40 // See intrinsifier for fingerprint computation. |
40 #define RECOGNIZED_LIST(V) \ | 41 #define RECOGNIZED_LIST(V) \ |
41 V(::, identical, ObjectIdentical, 496869842) \ | 42 V(::, identical, ObjectIdentical, 496869842) \ |
42 V(ClassID, getID, ClassIDgetID, 1322490980) \ | 43 V(ClassID, getID, ClassIDgetID, 1322490980) \ |
43 V(Object, ==, ObjectEquals, 1068471689) \ | 44 V(Object, ==, ObjectEquals, 1068471689) \ |
44 V(Object, Object., ObjectConstructor, 1066669787) \ | 45 V(Object, Object., ObjectConstructor, 1066669787) \ |
(...skipping 2511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2556 virtual EffectSet Dependencies() const { return EffectSet::None(); } | 2557 virtual EffectSet Dependencies() const { return EffectSet::None(); } |
2557 virtual EffectSet Effects() const { return EffectSet::None(); } | 2558 virtual EffectSet Effects() const { return EffectSet::None(); } |
2558 | 2559 |
2559 virtual bool MayThrow() const { return false; } | 2560 virtual bool MayThrow() const { return false; } |
2560 | 2561 |
2561 private: | 2562 private: |
2562 DISALLOW_COPY_AND_ASSIGN(RedefinitionInstr); | 2563 DISALLOW_COPY_AND_ASSIGN(RedefinitionInstr); |
2563 }; | 2564 }; |
2564 | 2565 |
2565 | 2566 |
2566 class RangeBoundary : public ValueObject { | |
2567 public: | |
2568 enum Kind { | |
2569 kUnknown, | |
2570 kNegativeInfinity, | |
2571 kPositiveInfinity, | |
2572 kSymbol, | |
2573 kConstant, | |
2574 }; | |
2575 | |
2576 enum RangeSize { | |
2577 kRangeBoundarySmi, | |
2578 kRangeBoundaryInt64, | |
2579 }; | |
2580 | |
2581 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { } | |
2582 | |
2583 RangeBoundary(const RangeBoundary& other) | |
2584 : ValueObject(), | |
2585 kind_(other.kind_), | |
2586 value_(other.value_), | |
2587 offset_(other.offset_) { } | |
2588 | |
2589 explicit RangeBoundary(int64_t val) | |
2590 : kind_(kConstant), value_(val), offset_(0) { } | |
2591 | |
2592 RangeBoundary& operator=(const RangeBoundary& other) { | |
2593 kind_ = other.kind_; | |
2594 value_ = other.value_; | |
2595 offset_ = other.offset_; | |
2596 return *this; | |
2597 } | |
2598 | |
2599 static const int64_t kMin = kMinInt64; | |
2600 static const int64_t kMax = kMaxInt64; | |
2601 | |
2602 // Construct a RangeBoundary for a constant value. | |
2603 static RangeBoundary FromConstant(int64_t val) { | |
2604 return RangeBoundary(val); | |
2605 } | |
2606 | |
2607 // Construct a RangeBoundary for -inf. | |
2608 static RangeBoundary NegativeInfinity() { | |
2609 return RangeBoundary(kNegativeInfinity, 0, 0); | |
2610 } | |
2611 | |
2612 // Construct a RangeBoundary for +inf. | |
2613 static RangeBoundary PositiveInfinity() { | |
2614 return RangeBoundary(kPositiveInfinity, 0, 0); | |
2615 } | |
2616 | |
2617 // Construct a RangeBoundary from a definition and offset. | |
2618 static RangeBoundary FromDefinition(Definition* defn, int64_t offs = 0); | |
2619 | |
2620 // Construct a RangeBoundary for the constant MinSmi value. | |
2621 static RangeBoundary MinSmi() { | |
2622 return FromConstant(Smi::kMinValue); | |
2623 } | |
2624 | |
2625 // Construct a RangeBoundary for the constant MaxSmi value. | |
2626 static RangeBoundary MaxSmi() { | |
2627 return FromConstant(Smi::kMaxValue); | |
2628 } | |
2629 | |
2630 // Construct a RangeBoundary for the constant kMin value. | |
2631 static RangeBoundary MinConstant() { | |
2632 return FromConstant(kMin); | |
2633 } | |
2634 | |
2635 // Construct a RangeBoundary for the constant kMax value. | |
2636 static RangeBoundary MaxConstant() { | |
2637 return FromConstant(kMax); | |
2638 } | |
2639 | |
2640 // Calculate the minimum of a and b within the given range. | |
2641 static RangeBoundary Min(RangeBoundary a, RangeBoundary b, RangeSize size); | |
2642 static RangeBoundary Max(RangeBoundary a, RangeBoundary b, RangeSize size); | |
2643 | |
2644 // Returns true when this is a constant that is outside of Smi range. | |
2645 bool OverflowedSmi() const { | |
2646 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); | |
2647 } | |
2648 | |
2649 // Returns true if this outside mint range. | |
2650 bool OverflowedMint() const { | |
2651 return IsInfinity(); | |
2652 } | |
2653 | |
2654 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type. | |
2655 RangeBoundary Clamp(RangeSize size) const { | |
2656 if (IsNegativeInfinity()) { | |
2657 return (size == kRangeBoundaryInt64) ? MinConstant() : MinSmi(); | |
2658 } | |
2659 if (IsPositiveInfinity()) { | |
2660 return (size == kRangeBoundaryInt64) ? MaxConstant() : MaxSmi(); | |
2661 } | |
2662 if ((size == kRangeBoundarySmi) && IsConstant()) { | |
2663 if (ConstantValue() <= Smi::kMinValue) { | |
2664 return MinSmi(); | |
2665 } | |
2666 if (ConstantValue() >= Smi::kMaxValue) { | |
2667 return MaxSmi(); | |
2668 } | |
2669 } | |
2670 // If this range is a symbolic range, we do not clamp it. | |
2671 // This could lead to some imprecision later on. | |
2672 return *this; | |
2673 } | |
2674 | |
2675 | |
2676 bool IsSmiMinimumOrBelow() const { | |
2677 return IsNegativeInfinity() || | |
2678 (IsConstant() && (ConstantValue() <= Smi::kMinValue)); | |
2679 } | |
2680 | |
2681 bool IsSmiMaximumOrAbove() const { | |
2682 return IsPositiveInfinity() || | |
2683 (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); | |
2684 } | |
2685 | |
2686 bool IsMinimumOrBelow() const { | |
2687 return IsNegativeInfinity() || (IsConstant() && (ConstantValue() == kMin)); | |
2688 } | |
2689 | |
2690 bool IsMaximumOrAbove() const { | |
2691 return IsPositiveInfinity() || (IsConstant() && (ConstantValue() == kMax)); | |
2692 } | |
2693 | |
2694 intptr_t kind() const { | |
2695 return kind_; | |
2696 } | |
2697 | |
2698 // Kind tests. | |
2699 bool IsUnknown() const { return kind_ == kUnknown; } | |
2700 bool IsConstant() const { return kind_ == kConstant; } | |
2701 bool IsSymbol() const { return kind_ == kSymbol; } | |
2702 bool IsNegativeInfinity() const { return kind_ == kNegativeInfinity; } | |
2703 bool IsPositiveInfinity() const { return kind_ == kPositiveInfinity; } | |
2704 bool IsInfinity() const { | |
2705 return IsNegativeInfinity() || IsPositiveInfinity(); | |
2706 } | |
2707 bool IsConstantOrInfinity() const { | |
2708 return IsConstant() || IsInfinity(); | |
2709 } | |
2710 | |
2711 // Returns the value of a kConstant RangeBoundary. | |
2712 int64_t ConstantValue() const; | |
2713 | |
2714 // Returns the Definition associated with a kSymbol RangeBoundary. | |
2715 Definition* symbol() const { | |
2716 ASSERT(IsSymbol()); | |
2717 return reinterpret_cast<Definition*>(value_); | |
2718 } | |
2719 | |
2720 // Offset from symbol. | |
2721 int64_t offset() const { | |
2722 return offset_; | |
2723 } | |
2724 | |
2725 // Computes the LowerBound of this. Three cases: | |
2726 // IsInfinity() -> NegativeInfinity(). | |
2727 // IsConstant() -> value(). | |
2728 // IsSymbol() -> lower bound computed from definition + offset. | |
2729 RangeBoundary LowerBound() const; | |
2730 | |
2731 // Computes the UpperBound of this. Three cases: | |
2732 // IsInfinity() -> PositiveInfinity(). | |
2733 // IsConstant() -> value(). | |
2734 // IsSymbol() -> upper bound computed from definition + offset. | |
2735 RangeBoundary UpperBound() const; | |
2736 | |
2737 void PrintTo(BufferFormatter* f) const; | |
2738 const char* ToCString() const; | |
2739 | |
2740 static RangeBoundary Add(const RangeBoundary& a, | |
2741 const RangeBoundary& b, | |
2742 const RangeBoundary& overflow); | |
2743 | |
2744 static RangeBoundary Sub(const RangeBoundary& a, | |
2745 const RangeBoundary& b, | |
2746 const RangeBoundary& overflow); | |
2747 | |
2748 static RangeBoundary Shl(const RangeBoundary& value_boundary, | |
2749 int64_t shift_count, | |
2750 const RangeBoundary& overflow); | |
2751 | |
2752 static RangeBoundary Shr(const RangeBoundary& value_boundary, | |
2753 int64_t shift_count) { | |
2754 ASSERT(value_boundary.IsConstant()); | |
2755 ASSERT(shift_count >= 0); | |
2756 int64_t value = static_cast<int64_t>(value_boundary.ConstantValue()); | |
2757 int64_t result = value >> shift_count; | |
2758 return RangeBoundary(result); | |
2759 } | |
2760 | |
2761 // Attempts to calculate a + b when: | |
2762 // a is a symbol and b is a constant OR | |
2763 // a is a constant and b is a symbol | |
2764 // returns true if it succeeds, output is in result. | |
2765 static bool SymbolicAdd(const RangeBoundary& a, | |
2766 const RangeBoundary& b, | |
2767 RangeBoundary* result); | |
2768 | |
2769 // Attempts to calculate a - b when: | |
2770 // a is a symbol and b is a constant | |
2771 // returns true if it succeeds, output is in result. | |
2772 static bool SymbolicSub(const RangeBoundary& a, | |
2773 const RangeBoundary& b, | |
2774 RangeBoundary* result); | |
2775 | |
2776 bool Equals(const RangeBoundary& other) const; | |
2777 | |
2778 private: | |
2779 RangeBoundary(Kind kind, int64_t value, int64_t offset) | |
2780 : kind_(kind), value_(value), offset_(offset) { } | |
2781 | |
2782 Kind kind_; | |
2783 int64_t value_; | |
2784 int64_t offset_; | |
2785 }; | |
2786 | |
2787 | |
2788 class Range : public ZoneAllocated { | |
2789 public: | |
2790 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { } | |
2791 | |
2792 static Range* Unknown() { | |
2793 return new Range(RangeBoundary::MinConstant(), | |
2794 RangeBoundary::MaxConstant()); | |
2795 } | |
2796 | |
2797 static Range* UnknownSmi() { | |
2798 return new Range(RangeBoundary::MinSmi(), | |
2799 RangeBoundary::MaxSmi()); | |
2800 } | |
2801 | |
2802 void PrintTo(BufferFormatter* f) const; | |
2803 static const char* ToCString(const Range* range); | |
2804 | |
2805 const RangeBoundary& min() const { return min_; } | |
2806 const RangeBoundary& max() const { return max_; } | |
2807 | |
2808 static RangeBoundary ConstantMinSmi(const Range* range) { | |
2809 if (range == NULL) { | |
2810 return RangeBoundary::MinSmi(); | |
2811 } | |
2812 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi); | |
2813 } | |
2814 | |
2815 static RangeBoundary ConstantMaxSmi(const Range* range) { | |
2816 if (range == NULL) { | |
2817 return RangeBoundary::MaxSmi(); | |
2818 } | |
2819 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundarySmi); | |
2820 } | |
2821 | |
2822 static RangeBoundary ConstantMin(const Range* range) { | |
2823 if (range == NULL) { | |
2824 return RangeBoundary::MinConstant(); | |
2825 } | |
2826 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundaryInt64); | |
2827 } | |
2828 | |
2829 static RangeBoundary ConstantMax(const Range* range) { | |
2830 if (range == NULL) { | |
2831 return RangeBoundary::MaxConstant(); | |
2832 } | |
2833 return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundaryInt64); | |
2834 } | |
2835 | |
2836 // [0, +inf] | |
2837 bool IsPositive() const; | |
2838 | |
2839 // [-inf, val]. | |
2840 bool OnlyLessThanOrEqualTo(int64_t val) const; | |
2841 | |
2842 // [val, +inf]. | |
2843 bool OnlyGreaterThanOrEqualTo(int64_t val) const; | |
2844 | |
2845 // Inclusive. | |
2846 bool IsWithin(int64_t min_int, int64_t max_int) const; | |
2847 | |
2848 // Inclusive. | |
2849 bool Overlaps(int64_t min_int, int64_t max_int) const; | |
2850 | |
2851 bool IsUnsatisfiable() const; | |
2852 | |
2853 bool IsFinite() const { | |
2854 return !min_.IsInfinity() && !max_.IsInfinity(); | |
2855 } | |
2856 | |
2857 // Clamp this to be within size. | |
2858 void Clamp(RangeBoundary::RangeSize size); | |
2859 | |
2860 static void Add(const Range* left_range, | |
2861 const Range* right_range, | |
2862 RangeBoundary* min, | |
2863 RangeBoundary* max, | |
2864 Definition* left_defn); | |
2865 | |
2866 static void Sub(const Range* left_range, | |
2867 const Range* right_range, | |
2868 RangeBoundary* min, | |
2869 RangeBoundary* max, | |
2870 Definition* left_defn); | |
2871 | |
2872 static bool Mul(const Range* left_range, | |
2873 const Range* right_range, | |
2874 RangeBoundary* min, | |
2875 RangeBoundary* max); | |
2876 static void Shr(const Range* left_range, | |
2877 const Range* right_range, | |
2878 RangeBoundary* min, | |
2879 RangeBoundary* max); | |
2880 | |
2881 static void Shl(const Range* left_range, | |
2882 const Range* right_range, | |
2883 RangeBoundary* min, | |
2884 RangeBoundary* max); | |
2885 | |
2886 static bool And(const Range* left_range, | |
2887 const Range* right_range, | |
2888 RangeBoundary* min, | |
2889 RangeBoundary* max); | |
2890 | |
2891 | |
2892 // Both the a and b ranges are >= 0. | |
2893 static bool OnlyPositiveOrZero(const Range& a, const Range& b); | |
2894 | |
2895 // Both the a and b ranges are <= 0. | |
2896 static bool OnlyNegativeOrZero(const Range& a, const Range& b); | |
2897 | |
2898 // Return the maximum absolute value included in range. | |
2899 static int64_t ConstantAbsMax(const Range* range); | |
2900 | |
2901 static Range* BinaryOp(const Token::Kind op, | |
2902 const Range* left_range, | |
2903 const Range* right_range, | |
2904 Definition* left_defn); | |
2905 | |
2906 private: | |
2907 RangeBoundary min_; | |
2908 RangeBoundary max_; | |
2909 }; | |
2910 | |
2911 | |
2912 class ConstraintInstr : public TemplateDefinition<2> { | 2567 class ConstraintInstr : public TemplateDefinition<2> { |
2913 public: | 2568 public: |
2914 ConstraintInstr(Value* value, Range* constraint) | 2569 ConstraintInstr(Value* value, Range* constraint) |
2915 : constraint_(constraint), | 2570 : constraint_(constraint), |
2916 target_(NULL) { | 2571 target_(NULL) { |
2917 SetInputAt(0, value); | 2572 SetInputAt(0, value); |
2918 } | 2573 } |
2919 | 2574 |
2920 DECLARE_INSTRUCTION(Constraint) | 2575 DECLARE_INSTRUCTION(Constraint) |
2921 | 2576 |
(...skipping 5157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8079 | 7734 |
8080 Value* length() const { return inputs_[kLengthPos]; } | 7735 Value* length() const { return inputs_[kLengthPos]; } |
8081 Value* index() const { return inputs_[kIndexPos]; } | 7736 Value* index() const { return inputs_[kIndexPos]; } |
8082 | 7737 |
8083 DECLARE_INSTRUCTION(CheckArrayBound) | 7738 DECLARE_INSTRUCTION(CheckArrayBound) |
8084 | 7739 |
8085 virtual intptr_t ArgumentCount() const { return 0; } | 7740 virtual intptr_t ArgumentCount() const { return 0; } |
8086 | 7741 |
8087 virtual bool CanDeoptimize() const { return true; } | 7742 virtual bool CanDeoptimize() const { return true; } |
8088 | 7743 |
8089 bool IsRedundant(RangeBoundary length); | 7744 bool IsRedundant(const RangeBoundary& length); |
8090 | 7745 |
8091 virtual Instruction* Canonicalize(FlowGraph* flow_graph); | 7746 virtual Instruction* Canonicalize(FlowGraph* flow_graph); |
8092 | 7747 |
8093 // Returns the length offset for array and string types. | 7748 // Returns the length offset for array and string types. |
8094 static intptr_t LengthOffsetFor(intptr_t class_id); | 7749 static intptr_t LengthOffsetFor(intptr_t class_id); |
8095 | 7750 |
8096 static bool IsFixedLengthArrayType(intptr_t class_id); | 7751 static bool IsFixedLengthArrayType(intptr_t class_id); |
8097 | 7752 |
8098 virtual bool AllowsCSE() const { return true; } | 7753 virtual bool AllowsCSE() const { return true; } |
8099 virtual EffectSet Effects() const { return EffectSet::None(); } | 7754 virtual EffectSet Effects() const { return EffectSet::None(); } |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8629 ForwardInstructionIterator* current_iterator_; | 8284 ForwardInstructionIterator* current_iterator_; |
8630 | 8285 |
8631 private: | 8286 private: |
8632 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); | 8287 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); |
8633 }; | 8288 }; |
8634 | 8289 |
8635 | 8290 |
8636 } // namespace dart | 8291 } // namespace dart |
8637 | 8292 |
8638 #endif // VM_INTERMEDIATE_LANGUAGE_H_ | 8293 #endif // VM_INTERMEDIATE_LANGUAGE_H_ |
OLD | NEW |