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" |
(...skipping 2445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2456 | 2456 |
2457 | 2457 |
2458 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { | 2458 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { |
2459 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | 2459 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
2460 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | 2460 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
2461 } | 2461 } |
2462 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | 2462 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
2463 } | 2463 } |
2464 | 2464 |
2465 | 2465 |
2466 RangeBoundary RangeBoundary::LowerBound() const { | 2466 RangeBoundary RangeBoundary::LowerBound() const { |
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
I don't think having PositiveInfinity.LowerBound()
| |
2467 if (IsNegativeInfinity()) return *this; | 2467 if (IsConstantOrInfinity()) return *this; |
2468 if (IsConstant()) return *this; | |
2469 return Add(Range::ConstantMin(symbol()->range()), | 2468 return Add(Range::ConstantMin(symbol()->range()), |
2470 RangeBoundary::FromConstant(offset_), | 2469 RangeBoundary::FromConstant(offset_), |
2471 NegativeInfinity()); | 2470 NegativeInfinity()); |
2472 } | 2471 } |
2473 | 2472 |
2474 | 2473 |
2475 RangeBoundary RangeBoundary::UpperBound() const { | 2474 RangeBoundary RangeBoundary::UpperBound() const { |
2476 if (IsPositiveInfinity()) return *this; | 2475 if (IsConstantOrInfinity()) return *this; |
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
Ditto.
| |
2477 if (IsConstant()) return *this; | |
2478 return Add(Range::ConstantMax(symbol()->range()), | 2476 return Add(Range::ConstantMax(symbol()->range()), |
2479 RangeBoundary::FromConstant(offset_), | 2477 RangeBoundary::FromConstant(offset_), |
2480 PositiveInfinity()); | 2478 PositiveInfinity()); |
2481 } | 2479 } |
2482 | 2480 |
2483 | 2481 |
2482 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | |
2483 const RangeBoundary& b, | |
2484 const RangeBoundary& overflow) { | |
2485 ASSERT(a.IsConstantOrInfinity() && b.IsConstantOrInfinity()); | |
2486 | |
2487 intptr_t result = a.Value() + b.Value(); | |
2488 if (!Smi::IsValid(result)) { | |
2489 return overflow; | |
2490 } | |
2491 return RangeBoundary::FromConstant(result); | |
2492 } | |
2493 | |
2494 | |
2495 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a, | |
2496 const RangeBoundary& b, | |
2497 const RangeBoundary& overflow) { | |
2498 ASSERT(a.IsConstantOrInfinity() && b.IsConstantOrInfinity()); | |
2499 | |
2500 intptr_t result = a.Value() - b.Value(); | |
2501 if (!Smi::IsValid(result)) { | |
2502 return overflow; | |
2503 } | |
2504 return RangeBoundary::FromConstant(result); | |
2505 } | |
2506 | |
2507 | |
2484 static Definition* UnwrapConstraint(Definition* defn) { | 2508 static Definition* UnwrapConstraint(Definition* defn) { |
2485 while (defn->IsConstraint()) { | 2509 while (defn->IsConstraint()) { |
2486 defn = defn->AsConstraint()->value()->definition(); | 2510 defn = defn->AsConstraint()->value()->definition(); |
2487 } | 2511 } |
2488 return defn; | 2512 return defn; |
2489 } | 2513 } |
2490 | 2514 |
2491 | 2515 |
2492 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 2516 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
2493 a = UnwrapConstraint(a); | 2517 a = UnwrapConstraint(a); |
2494 b = UnwrapConstraint(b); | 2518 b = UnwrapConstraint(b); |
2495 return (a == b) || | 2519 return (a == b) || |
2496 (a->AllowsCSE() && | 2520 (a->AllowsCSE() && |
2497 a->Dependencies().IsNone() && | 2521 a->Dependencies().IsNone() && |
2498 b->AllowsCSE() && | 2522 b->AllowsCSE() && |
2499 b->Dependencies().IsNone() && | 2523 b->Dependencies().IsNone() && |
2500 a->Equals(b)); | 2524 a->Equals(b)); |
2501 } | 2525 } |
2502 | 2526 |
2503 | 2527 |
2504 // Returns true if two range boundaries refer to the same symbol. | 2528 // Returns true if two range boundaries refer to the same symbol. |
2505 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 2529 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
2506 return a.IsSymbol() && b.IsSymbol() && | 2530 return a.IsSymbol() && b.IsSymbol() && |
2507 AreEqualDefinitions(a.symbol(), b.symbol()); | 2531 AreEqualDefinitions(a.symbol(), b.symbol()); |
2508 } | 2532 } |
2509 | 2533 |
2510 | 2534 |
2511 // Returns true if range has a least specific minimum value. | 2535 bool RangeBoundary::Equals(const RangeBoundary& other) const { |
2512 static bool IsMinSmi(Range* range) { | 2536 if (IsConstant() && other.IsConstant()) { |
2513 return (range == NULL) || | 2537 return Value() == other.Value(); |
2514 (range->min().IsConstant() && | 2538 } else if (IsInfinity() && other.IsInfinity()) { |
2515 (range->min().value() <= Smi::kMinValue)); | 2539 return Value() == other.Value(); |
2516 } | 2540 } else if (IsSymbol() && other.IsSymbol()) { |
2517 | 2541 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); |
2518 | |
2519 // Returns true if range has a least specific maximium value. | |
2520 static bool IsMaxSmi(Range* range) { | |
2521 return (range == NULL) || | |
2522 (range->max().IsConstant() && | |
2523 (range->max().value() >= Smi::kMaxValue)); | |
2524 } | |
2525 | |
2526 | |
2527 // Returns true if two range boundaries can be proven to be equal. | |
2528 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
2529 if (a.IsConstant() && b.IsConstant()) { | |
2530 return a.value() == b.value(); | |
2531 } else if (a.IsSymbol() && b.IsSymbol()) { | |
2532 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); | |
2533 } else { | |
2534 return false; | |
2535 } | 2542 } |
2543 return false; | |
2536 } | 2544 } |
2537 | 2545 |
2538 | 2546 |
2539 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, | 2547 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, |
2540 const RangeBoundary& overflow) { | 2548 const RangeBoundary& overflow) { |
2541 if (a.IsConstant() || a.IsNegativeInfinity() || a.IsPositiveInfinity()) { | 2549 if (a.IsConstant() || a.IsInfinity()) { |
2542 return a; | 2550 return a; |
2543 } | 2551 } |
2544 | 2552 |
2545 intptr_t offset = a.offset(); | 2553 intptr_t offset = a.offset(); |
2546 Definition* symbol = a.symbol(); | 2554 Definition* symbol = a.symbol(); |
2547 | 2555 |
2548 bool changed; | 2556 bool changed; |
2549 do { | 2557 do { |
2550 changed = false; | 2558 changed = false; |
2551 if (symbol->IsConstraint()) { | 2559 if (symbol->IsConstraint()) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2627 | 2635 |
2628 return true; | 2636 return true; |
2629 } | 2637 } |
2630 | 2638 |
2631 | 2639 |
2632 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { | 2640 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { |
2633 if (DependOnSameSymbol(a, b)) { | 2641 if (DependOnSameSymbol(a, b)) { |
2634 return (a.offset() <= b.offset()) ? a : b; | 2642 return (a.offset() <= b.offset()) ? a : b; |
2635 } | 2643 } |
2636 | 2644 |
2637 const intptr_t min_a = a.LowerBound().Clamp().value(); | 2645 const intptr_t min_a = a.LowerBound().Clamp().Value(); |
2638 const intptr_t min_b = b.LowerBound().Clamp().value(); | 2646 const intptr_t min_b = b.LowerBound().Clamp().Value(); |
2639 | 2647 |
2640 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | 2648 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
2641 } | 2649 } |
2642 | 2650 |
2643 | 2651 |
2644 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { | 2652 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { |
2645 if (DependOnSameSymbol(a, b)) { | 2653 if (DependOnSameSymbol(a, b)) { |
2646 return (a.offset() >= b.offset()) ? a : b; | 2654 return (a.offset() >= b.offset()) ? a : b; |
2647 } | 2655 } |
2648 | 2656 |
2649 const intptr_t max_a = a.UpperBound().Clamp().value(); | 2657 const intptr_t max_a = a.UpperBound().Clamp().Value(); |
2650 const intptr_t max_b = b.UpperBound().Clamp().value(); | 2658 const intptr_t max_b = b.UpperBound().Clamp().Value(); |
2651 | 2659 |
2652 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 2660 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
2653 } | 2661 } |
2654 | 2662 |
2655 | 2663 |
2664 intptr_t RangeBoundary::Value() const { | |
Florian Schneider
2014/06/11 10:41:00
maybe add ASSERT(kind_ == kConstant);
Cutch
2014/06/13 04:24:25
Done.
| |
2665 if (IsNegativeInfinity()) { | |
2666 return kMin; | |
Florian Schneider
2014/06/11 10:41:00
I'm not sure this is ideal to return kMin/kMax. A
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
I second Florian here. Let's prohibit asking a val
Cutch
2014/06/13 04:24:26
Done.
| |
2667 } | |
2668 if (IsPositiveInfinity()) { | |
2669 return kMax; | |
Florian Schneider
2014/06/11 10:41:00
UNREACHABLE()?
Cutch
2014/06/13 04:24:25
Done.
| |
2670 } | |
2671 ASSERT(IsConstant()); | |
2672 return value_; | |
2673 } | |
2674 | |
2675 | |
2656 void Definition::InferRange() { | 2676 void Definition::InferRange() { |
2657 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. | 2677 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. |
2658 if (range_ == NULL) { | 2678 if (range_ == NULL) { |
2659 range_ = Range::Unknown(); | 2679 range_ = Range::Unknown(); |
2660 } | 2680 } |
2661 } | 2681 } |
2662 | 2682 |
2663 | 2683 |
2664 void ConstantInstr::InferRange() { | 2684 void ConstantInstr::InferRange() { |
2665 ASSERT(value_.IsSmi()); | 2685 ASSERT(value_.IsSmi()); |
2666 if (range_ == NULL) { | 2686 if (range_ == NULL) { |
2667 intptr_t value = Smi::Cast(value_).Value(); | 2687 intptr_t value = Smi::Cast(value_).Value(); |
2668 range_ = new Range(RangeBoundary::FromConstant(value), | 2688 range_ = new Range(RangeBoundary::FromConstant(value), |
2669 RangeBoundary::FromConstant(value)); | 2689 RangeBoundary::FromConstant(value)); |
2670 } | 2690 } |
2671 } | 2691 } |
2672 | 2692 |
2673 | 2693 |
2674 void ConstraintInstr::InferRange() { | 2694 void ConstraintInstr::InferRange() { |
2675 Range* value_range = value()->definition()->range(); | 2695 Range* value_range = value()->definition()->range(); |
2676 | 2696 |
2677 RangeBoundary min; | 2697 RangeBoundary min; |
2678 RangeBoundary max; | 2698 RangeBoundary max; |
2679 | 2699 |
2680 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { | 2700 if (Range::IsSmiMinimumOrUnderflow(value_range) && |
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
for simplicity I suggest we make this code differe
Vyacheslav Egorov (Google)
2014/06/11 20:06:37
I wonder if this code will become better if we int
Cutch
2014/06/13 04:24:25
I've extended Min and Max to handle infinities but
Cutch
2014/06/13 04:24:25
Done.
| |
2701 !Range::IsSmiMinimumOrUnderflow(constraint())) { | |
2681 min = constraint()->min(); | 2702 min = constraint()->min(); |
2682 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { | 2703 } else if (Range::IsSmiMinimumOrUnderflow(constraint()) && |
2704 !Range::IsSmiMinimumOrUnderflow(value_range)) { | |
2683 min = value_range->min(); | 2705 min = value_range->min(); |
2684 } else if ((value_range != NULL) && | 2706 } else if ((value_range != NULL) && |
2685 IsEqual(constraint()->min(), value_range->min())) { | 2707 constraint()->min().Equals(value_range->min())) { |
2686 min = constraint()->min(); | 2708 min = constraint()->min(); |
2687 } else { | 2709 } else { |
2688 if (value_range != NULL) { | 2710 if (value_range != NULL) { |
2689 RangeBoundary canonical_a = | 2711 RangeBoundary canonical_a = |
2690 CanonicalizeBoundary(constraint()->min(), | 2712 CanonicalizeBoundary(constraint()->min(), |
2691 RangeBoundary::NegativeInfinity()); | 2713 RangeBoundary::NegativeInfinity()); |
2692 RangeBoundary canonical_b = | 2714 RangeBoundary canonical_b = |
2693 CanonicalizeBoundary(value_range->min(), | 2715 CanonicalizeBoundary(value_range->min(), |
2694 RangeBoundary::NegativeInfinity()); | 2716 RangeBoundary::NegativeInfinity()); |
2695 | 2717 |
2696 do { | 2718 do { |
2697 if (DependOnSameSymbol(canonical_a, canonical_b)) { | 2719 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
2698 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b | 2720 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b |
2699 : canonical_a; | 2721 : canonical_a; |
2700 } | 2722 } |
2701 } while (CanonicalizeMinBoundary(&canonical_a) || | 2723 } while (CanonicalizeMinBoundary(&canonical_a) || |
2702 CanonicalizeMinBoundary(&canonical_b)); | 2724 CanonicalizeMinBoundary(&canonical_b)); |
2703 } | 2725 } |
2704 | 2726 |
2705 if (min.IsUnknown()) { | 2727 if (min.IsUnknown()) { |
2706 min = RangeBoundary::Max(Range::ConstantMin(value_range), | 2728 min = RangeBoundary::Max(Range::ConstantMin(value_range), |
2707 Range::ConstantMin(constraint())); | 2729 Range::ConstantMin(constraint())); |
2708 } | 2730 } |
2709 } | 2731 } |
2710 | 2732 |
2711 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { | 2733 if (Range::IsSmiMaximumOrOverflow(value_range) && |
2734 !Range::IsSmiMaximumOrOverflow(constraint())) { | |
2712 max = constraint()->max(); | 2735 max = constraint()->max(); |
2713 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { | 2736 } else if (Range::IsSmiMaximumOrOverflow(constraint()) && |
2737 !Range::IsSmiMaximumOrOverflow(value_range)) { | |
2714 max = value_range->max(); | 2738 max = value_range->max(); |
2715 } else if ((value_range != NULL) && | 2739 } else if ((value_range != NULL) && |
2716 IsEqual(constraint()->max(), value_range->max())) { | 2740 constraint()->max().Equals(value_range->max())) { |
2717 max = constraint()->max(); | 2741 max = constraint()->max(); |
2718 } else { | 2742 } else { |
2719 if (value_range != NULL) { | 2743 if (value_range != NULL) { |
2720 RangeBoundary canonical_b = | 2744 RangeBoundary canonical_b = |
2721 CanonicalizeBoundary(value_range->max(), | 2745 CanonicalizeBoundary(value_range->max(), |
2722 RangeBoundary::PositiveInfinity()); | 2746 RangeBoundary::PositiveInfinity()); |
2723 RangeBoundary canonical_a = | 2747 RangeBoundary canonical_a = |
2724 CanonicalizeBoundary(constraint()->max(), | 2748 CanonicalizeBoundary(constraint()->max(), |
2725 RangeBoundary::PositiveInfinity()); | 2749 RangeBoundary::PositiveInfinity()); |
2726 | 2750 |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2963 ASSERT(InputCount() > 1); | 2987 ASSERT(InputCount() > 1); |
2964 Definition* first = InputAt(0)->definition(); | 2988 Definition* first = InputAt(0)->definition(); |
2965 for (intptr_t i = 1; i < InputCount(); ++i) { | 2989 for (intptr_t i = 1; i < InputCount(); ++i) { |
2966 Definition* def = InputAt(i)->definition(); | 2990 Definition* def = InputAt(i)->definition(); |
2967 if (def != first) return false; | 2991 if (def != first) return false; |
2968 } | 2992 } |
2969 return true; | 2993 return true; |
2970 } | 2994 } |
2971 | 2995 |
2972 | 2996 |
2973 static bool SymbolicSub(const RangeBoundary& a, | 2997 static bool SymbolicSub(const RangeBoundary& a, |
Vyacheslav Egorov (Google)
2014/06/11 20:06:36
This funciton should be moved to RangeBoundary?
Cutch
2014/06/13 04:24:25
Done.
| |
2974 const RangeBoundary& b, | 2998 const RangeBoundary& b, |
2975 RangeBoundary* result) { | 2999 RangeBoundary* result) { |
2976 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | 3000 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
2977 const intptr_t offset = a.offset() - b.value(); | 3001 const intptr_t offset = a.offset() - b.Value(); |
2978 if (!Smi::IsValid(offset)) return false; | 3002 if (!Smi::IsValid(offset)) return false; |
2979 | 3003 |
2980 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | 3004 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
2981 return true; | 3005 return true; |
2982 } | 3006 } |
2983 return false; | 3007 return false; |
2984 } | 3008 } |
2985 | 3009 |
2986 | 3010 |
2987 static bool SymbolicAdd(const RangeBoundary& a, | 3011 static bool SymbolicAdd(const RangeBoundary& a, |
2988 const RangeBoundary& b, | 3012 const RangeBoundary& b, |
2989 RangeBoundary* result) { | 3013 RangeBoundary* result) { |
2990 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | 3014 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
2991 const intptr_t offset = a.offset() + b.value(); | 3015 const intptr_t offset = a.offset() + b.Value(); |
2992 if (!Smi::IsValid(offset)) return false; | 3016 if (!Smi::IsValid(offset)) return false; |
2993 | 3017 |
2994 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | 3018 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
2995 return true; | 3019 return true; |
2996 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { | 3020 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { |
2997 const intptr_t offset = b.offset() + a.value(); | 3021 const intptr_t offset = b.offset() + a.Value(); |
2998 if (!Smi::IsValid(offset)) return false; | 3022 if (!Smi::IsValid(offset)) return false; |
2999 | 3023 |
3000 *result = RangeBoundary::FromDefinition(b.symbol(), offset); | 3024 *result = RangeBoundary::FromDefinition(b.symbol(), offset); |
3001 return true; | 3025 return true; |
3002 } | 3026 } |
3003 return false; | 3027 return false; |
3004 } | 3028 } |
3005 | 3029 |
3006 | 3030 |
3007 static bool IsArrayLength(Definition* defn) { | 3031 static bool IsArrayLength(Definition* defn) { |
3008 LoadFieldInstr* load = defn->AsLoadField(); | 3032 LoadFieldInstr* load = defn->AsLoadField(); |
3009 return (load != NULL) && load->IsImmutableLengthLoad(); | 3033 return (load != NULL) && load->IsImmutableLengthLoad(); |
3010 } | 3034 } |
3011 | 3035 |
3012 | 3036 |
3013 static int64_t ConstantAbsMax(const Range* range) { | |
3014 if (range == NULL) return Smi::kMaxValue; | |
3015 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).value()); | |
3016 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).value()); | |
3017 return abs_min > abs_max ? abs_min : abs_max; | |
3018 } | |
3019 | |
3020 | |
3021 static bool OnlyPositiveOrZero(const Range* a, const Range* b) { | |
3022 if ((a == NULL) || (b == NULL)) return false; | |
3023 if (Range::ConstantMin(a).value() < 0) return false; | |
3024 if (Range::ConstantMin(b).value() < 0) return false; | |
3025 return true; | |
3026 } | |
3027 | |
3028 | |
3029 static bool OnlyNegativeOrZero(const Range* a, const Range* b) { | |
3030 if ((a == NULL) || (b == NULL)) return false; | |
3031 if (Range::ConstantMax(a).value() > 0) return false; | |
3032 if (Range::ConstantMax(b).value() > 0) return false; | |
3033 return true; | |
3034 } | |
3035 | |
3036 | |
3037 void BinarySmiOpInstr::InferRange() { | 3037 void BinarySmiOpInstr::InferRange() { |
3038 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 3038 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
3039 // right and a non-constant on the left. | 3039 // right and a non-constant on the left. |
3040 Definition* left_defn = left()->definition(); | 3040 Definition* left_defn = left()->definition(); |
3041 | 3041 |
3042 Range* left_range = left_defn->range(); | 3042 Range* left_range = left_defn->range(); |
3043 Range* right_range = right()->definition()->range(); | 3043 Range* right_range = right()->definition()->range(); |
3044 | 3044 |
3045 if ((left_range == NULL) || (right_range == NULL)) { | 3045 if ((left_range == NULL) || (right_range == NULL)) { |
3046 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 3046 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
3047 return; | 3047 return; |
3048 } | 3048 } |
3049 | 3049 |
3050 RangeBoundary left_min = | 3050 RangeBoundary left_min = |
3051 IsArrayLength(left_defn) ? | 3051 IsArrayLength(left_defn) ? |
3052 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | 3052 RangeBoundary::FromDefinition(left_defn) : left_range->min(); |
3053 | 3053 |
3054 RangeBoundary left_max = | 3054 RangeBoundary left_max = |
3055 IsArrayLength(left_defn) ? | 3055 IsArrayLength(left_defn) ? |
3056 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | 3056 RangeBoundary::FromDefinition(left_defn) : left_range->max(); |
3057 | 3057 |
3058 RangeBoundary min; | 3058 // If we had no range information before, we do not update the overflow state. |
3059 RangeBoundary max; | 3059 bool should_update_overflow = range_ != NULL; |
Vyacheslav Egorov (Google)
2014/06/11 20:06:37
I don't understand the reasoning behind this lack
Cutch
2014/06/13 04:24:26
I've updated the predicate to include the + and -
| |
3060 switch (op_kind()) { | |
3061 case Token::kADD: | |
3062 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | |
3063 min = | |
3064 RangeBoundary::Add(Range::ConstantMin(left_range), | |
3065 Range::ConstantMin(right_range), | |
3066 RangeBoundary::NegativeInfinity()); | |
3067 } | |
3068 | 3060 |
3069 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | 3061 range_ = Range::BinaryOp(op_kind(), |
3070 max = | 3062 left_min, |
3071 RangeBoundary::Add(Range::ConstantMax(right_range), | 3063 left_max, |
3072 Range::ConstantMax(left_range), | 3064 left_range, |
3073 RangeBoundary::PositiveInfinity()); | 3065 right_range, |
3074 } | 3066 range_); |
3075 break; | 3067 if (range_ == NULL) { |
3076 | 3068 // No range information. |
3077 case Token::kSUB: | 3069 return; |
3078 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
3079 min = | |
3080 RangeBoundary::Sub(Range::ConstantMin(left_range), | |
3081 Range::ConstantMax(right_range), | |
3082 RangeBoundary::NegativeInfinity()); | |
3083 } | |
3084 | |
3085 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
3086 max = | |
3087 RangeBoundary::Sub(Range::ConstantMax(left_range), | |
3088 Range::ConstantMin(right_range), | |
3089 RangeBoundary::PositiveInfinity()); | |
3090 } | |
3091 break; | |
3092 | |
3093 case Token::kMUL: { | |
3094 const int64_t left_max = ConstantAbsMax(left_range); | |
3095 const int64_t right_max = ConstantAbsMax(right_range); | |
3096 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
3097 // Product of left and right max values stays in 64 bit range. | |
3098 const int64_t result_max = left_max * right_max; | |
3099 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3100 const intptr_t r_min = | |
3101 OnlyPositiveOrZero(left_range, right_range) ? 0 : -result_max; | |
3102 min = RangeBoundary::FromConstant(r_min); | |
3103 const intptr_t r_max = | |
3104 OnlyNegativeOrZero(left_range, right_range) ? 0 : result_max; | |
3105 max = RangeBoundary::FromConstant(r_max); | |
3106 break; | |
3107 } | |
3108 } | |
3109 if (range_ == NULL) { | |
3110 range_ = Range::Unknown(); | |
3111 } | |
3112 return; | |
3113 } | |
3114 case Token::kBIT_AND: | |
3115 if (Range::ConstantMin(right_range).value() >= 0) { | |
3116 min = RangeBoundary::FromConstant(0); | |
3117 max = Range::ConstantMax(right_range); | |
3118 break; | |
3119 } | |
3120 if (Range::ConstantMin(left_range).value() >= 0) { | |
3121 min = RangeBoundary::FromConstant(0); | |
3122 max = Range::ConstantMax(left_range); | |
3123 break; | |
3124 } | |
3125 | |
3126 if (range_ == NULL) { | |
3127 range_ = Range::Unknown(); | |
3128 } | |
3129 return; | |
3130 | |
3131 default: | |
3132 if (range_ == NULL) { | |
3133 range_ = Range::Unknown(); | |
3134 } | |
3135 return; | |
3136 } | 3070 } |
3137 | 3071 |
3138 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | 3072 if (!should_update_overflow) { |
3139 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); | 3073 return; |
3074 } | |
3140 | 3075 |
3141 if (min.IsConstant()) min.Clamp(); | 3076 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
3142 if (max.IsConstant()) max.Clamp(); | 3077 const bool overflowed = range_->min().LowerBound().Overflowed() || |
3143 | 3078 range_->max().UpperBound().Overflowed(); |
3144 range_ = new Range(min, max); | 3079 set_overflow(overflowed); |
3145 } | 3080 } |
3146 | 3081 |
3147 | 3082 |
3148 bool Range::IsPositive() const { | 3083 bool Range::IsPositive() const { |
3149 if (min().IsNegativeInfinity()) { | 3084 if (min().IsNegativeInfinity()) { |
3150 return false; | 3085 return false; |
3151 } | 3086 } |
3152 if (min().LowerBound().value() < 0) { | 3087 if (min().LowerBound().Value() < 0) { |
3153 return false; | 3088 return false; |
3154 } | 3089 } |
3155 if (max().IsPositiveInfinity()) { | 3090 if (max().IsPositiveInfinity()) { |
3156 return true; | 3091 return true; |
3157 } | 3092 } |
3158 return max().UpperBound().value() >= 0; | 3093 return max().UpperBound().Value() >= 0; |
3159 } | 3094 } |
3160 | 3095 |
3161 | 3096 |
3162 bool Range::IsNegative() const { | 3097 bool Range::IsNegative() const { |
3163 if (max().IsPositiveInfinity()) { | 3098 if (max().IsPositiveInfinity()) { |
3164 return false; | 3099 return false; |
3165 } | 3100 } |
3166 if (max().UpperBound().value() >= 0) { | 3101 if (max().UpperBound().Value() >= 0) { |
3167 return false; | 3102 return false; |
3168 } | 3103 } |
3169 if (min().IsNegativeInfinity()) { | 3104 if (min().IsNegativeInfinity()) { |
3170 return true; | 3105 return true; |
3171 } | 3106 } |
3172 return min().LowerBound().value() < 0; | 3107 return min().LowerBound().Value() < 0; |
3173 } | 3108 } |
3174 | 3109 |
3175 | 3110 |
3176 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { | 3111 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { |
3177 if (max().IsPositiveInfinity()) { | 3112 if (max().IsPositiveInfinity()) { |
3178 // Cannot be true. | 3113 // Cannot be true. |
3179 return false; | 3114 return false; |
3180 } | 3115 } |
3181 if (max().UpperBound().value() > val) { | 3116 if (max().UpperBound().Value() > val) { |
3182 // Not true. | 3117 // Not true. |
3183 return false; | 3118 return false; |
3184 } | 3119 } |
3185 if (!min().IsNegativeInfinity()) { | 3120 if (!min().IsNegativeInfinity()) { |
3186 if (min().LowerBound().value() > val) { | 3121 if (min().LowerBound().Value() > val) { |
3187 // Lower bound is > value. | 3122 // Lower bound is > value. |
3188 return false; | 3123 return false; |
3189 } | 3124 } |
3190 } | 3125 } |
3191 return true; | 3126 return true; |
3192 } | 3127 } |
3193 | 3128 |
3194 | 3129 |
3195 // Inclusive. | 3130 // Inclusive. |
3196 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { | 3131 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { |
3197 RangeBoundary lower_min = min().LowerBound(); | 3132 RangeBoundary lower_min = min().LowerBound(); |
3198 if (lower_min.IsNegativeInfinity() || (lower_min.value() < min_int)) { | 3133 if (lower_min.IsNegativeInfinity() || (lower_min.Value() < min_int)) { |
3199 return false; | 3134 return false; |
3200 } | 3135 } |
3201 RangeBoundary upper_max = max().UpperBound(); | 3136 RangeBoundary upper_max = max().UpperBound(); |
3202 if (upper_max.IsPositiveInfinity() || (upper_max.value() > max_int)) { | 3137 if (upper_max.IsPositiveInfinity() || (upper_max.Value() > max_int)) { |
3203 return false; | 3138 return false; |
3204 } | 3139 } |
3205 return true; | 3140 return true; |
3206 } | 3141 } |
3207 | 3142 |
3208 | 3143 |
3209 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { | 3144 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { |
3210 const intptr_t this_min = min().IsNegativeInfinity() ? | 3145 const intptr_t this_min = min().LowerBound().Value(); |
3211 kIntptrMin : min().LowerBound().value(); | 3146 const intptr_t this_max = max().UpperBound().Value(); |
3212 const intptr_t this_max = max().IsPositiveInfinity() ? | |
3213 kIntptrMax : max().UpperBound().value(); | |
3214 if ((this_min <= min_int) && (min_int <= this_max)) return true; | 3147 if ((this_min <= min_int) && (min_int <= this_max)) return true; |
3215 if ((this_min <= max_int) && (max_int <= this_max)) return true; | 3148 if ((this_min <= max_int) && (max_int <= this_max)) return true; |
3216 if ((min_int < this_min) && (max_int > this_max)) return true; | 3149 if ((min_int < this_min) && (max_int > this_max)) return true; |
3217 return false; | 3150 return false; |
3218 } | 3151 } |
3219 | 3152 |
3220 | 3153 |
3221 bool Range::IsUnsatisfiable() const { | 3154 bool Range::IsUnsatisfiable() const { |
3222 // Infinity case: [+inf, ...] || [..., -inf] | 3155 // Infinity case: [+inf, ...] || [..., -inf] |
3223 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { | 3156 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { |
3224 return true; | 3157 return true; |
3225 } | 3158 } |
3226 // Constant case: For example [0, -1]. | 3159 // Constant case: For example [0, -1]. |
3227 if (Range::ConstantMin(this).value() > Range::ConstantMax(this).value()) { | 3160 if (Range::ConstantMin(this).Value() > Range::ConstantMax(this).Value()) { |
3228 return true; | 3161 return true; |
3229 } | 3162 } |
3230 // Symbol case: For example [v+1, v]. | 3163 // Symbol case: For example [v+1, v]. |
3231 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { | 3164 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { |
3232 return true; | 3165 return true; |
3233 } | 3166 } |
3234 return false; | 3167 return false; |
3235 } | 3168 } |
3236 | 3169 |
3237 | 3170 |
3171 // Returns true if range is at or below the minimum smi value. | |
3172 bool Range::IsSmiMinimumOrUnderflow(const Range* range) { | |
3173 return (range == NULL) || | |
3174 ((range->min().IsConstant() || range->min().IsInfinity()) && | |
Florian Schneider
2014/06/11 10:41:00
IsNegativeInfinity()?
| |
3175 (range->min().Value() <= Smi::kMinValue)); | |
Florian Schneider
2014/06/11 10:41:00
Same comment as below.
| |
3176 } | |
3177 | |
3178 // Returns true if range is at or above the maximum smi value. | |
3179 bool Range::IsSmiMaximumOrOverflow(const Range* range) { | |
3180 return (range == NULL) || | |
3181 ((range->max().IsConstant() || range->max().IsInfinity()) && | |
Florian Schneider
2014/06/11 10:41:00
IsPositiveInfinity?
| |
3182 (range->max().Value() >= Smi::kMaxValue)); | |
Florian Schneider
2014/06/11 10:41:00
This is a piece of code that gets hard to read bec
| |
3183 } | |
3184 | |
3185 | |
3186 // Both the a and b ranges are >= 0. | |
3187 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | |
Vyacheslav Egorov (Google)
2014/06/11 20:06:36
It feels like we have some kind of duplication her
Cutch
2014/06/13 04:24:25
Done.
| |
3188 if (Range::ConstantMin(&a).Value() < 0) { | |
3189 return false; | |
3190 } | |
3191 if (Range::ConstantMin(&b).Value() < 0) { | |
3192 return false; | |
3193 } | |
3194 return true; | |
3195 } | |
3196 | |
3197 | |
3198 // Both the a and b ranges are <= 0. | |
3199 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | |
3200 if (Range::ConstantMax(&a).Value() > 0) { | |
3201 return false; | |
3202 } | |
3203 if (Range::ConstantMax(&b).Value() > 0) { | |
3204 return false; | |
3205 } | |
3206 return true; | |
3207 } | |
3208 | |
3209 | |
3210 // Return the maximum absolute value included in range. | |
3211 int64_t Range::ConstantAbsMax(const Range* range) { | |
3212 if (range == NULL) { | |
3213 return RangeBoundary::kMax; | |
3214 } | |
3215 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).Value()); | |
3216 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).Value()); | |
3217 return Utils::Maximum(abs_min, abs_max); | |
3218 } | |
3219 | |
3220 | |
3221 Range* Range::BinaryOp(const Token::Kind op, | |
3222 const RangeBoundary& left_min, | |
3223 const RangeBoundary& left_max, | |
3224 const Range* left_range, | |
3225 const Range* right_range, | |
3226 const Range* original_range) { | |
3227 ASSERT(left_range != NULL); | |
3228 ASSERT(right_range != NULL); | |
3229 RangeBoundary min; | |
3230 RangeBoundary max; | |
3231 switch (op) { | |
3232 case Token::kADD: | |
3233 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | |
3234 min = RangeBoundary::Add(Range::ConstantMin(left_range), | |
3235 Range::ConstantMin(right_range), | |
3236 RangeBoundary::NegativeInfinity()); | |
3237 } | |
3238 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | |
3239 max = RangeBoundary::Add(Range::ConstantMax(right_range), | |
3240 Range::ConstantMax(left_range), | |
3241 RangeBoundary::PositiveInfinity()); | |
3242 } | |
3243 break; | |
3244 case Token::kSUB: | |
3245 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
3246 min = RangeBoundary::Sub(Range::ConstantMin(left_range), | |
3247 Range::ConstantMax(right_range), | |
3248 RangeBoundary::NegativeInfinity()); | |
3249 } | |
3250 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
3251 max = RangeBoundary::Sub(Range::ConstantMax(left_range), | |
3252 Range::ConstantMin(right_range), | |
3253 RangeBoundary::PositiveInfinity()); | |
3254 } | |
3255 break; | |
3256 case Token::kMUL: { | |
3257 const int64_t left_max = ConstantAbsMax(left_range); | |
3258 const int64_t right_max = ConstantAbsMax(right_range); | |
3259 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
3260 // Product of left and right max values stays in 64 bit range. | |
3261 const int64_t result_max = left_max * right_max; | |
3262 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3263 const intptr_t r_min = | |
3264 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -result_max; | |
3265 min = RangeBoundary::FromConstant(r_min); | |
3266 const intptr_t r_max = | |
3267 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : result_max; | |
3268 max = RangeBoundary::FromConstant(r_max); | |
3269 break; | |
3270 } | |
3271 } | |
3272 if (original_range == NULL) { | |
3273 return Range::Unknown(); | |
3274 } | |
3275 break; | |
3276 } | |
3277 case Token::kBIT_AND: | |
3278 if (Range::ConstantMin(right_range).Value() >= 0) { | |
3279 min = RangeBoundary::FromConstant(0); | |
3280 max = Range::ConstantMax(right_range); | |
3281 break; | |
3282 } | |
3283 if (Range::ConstantMin(left_range).Value() >= 0) { | |
3284 min = RangeBoundary::FromConstant(0); | |
3285 max = Range::ConstantMax(left_range); | |
3286 break; | |
3287 } | |
3288 if (original_range == NULL) { | |
3289 return Range::Unknown(); | |
3290 } | |
3291 break; | |
3292 default: | |
3293 if (original_range == NULL) { | |
3294 return Range::Unknown(); | |
3295 } | |
3296 return const_cast<Range*>(original_range); | |
3297 } | |
3298 | |
3299 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | |
3300 | |
3301 return new Range(min, max); | |
3302 } | |
3303 | |
3304 | |
3238 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3305 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
3239 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3306 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
3240 } | 3307 } |
3241 | 3308 |
3242 | 3309 |
3243 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { | 3310 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { |
3244 Range* index_range = index()->definition()->range(); | 3311 Range* index_range = index()->definition()->range(); |
3245 | 3312 |
3246 // Range of the index is unknown can't decide if the check is redundant. | 3313 // Range of the index is unknown can't decide if the check is redundant. |
3247 if (index_range == NULL) { | 3314 if (index_range == NULL) { |
3248 return false; | 3315 return false; |
3249 } | 3316 } |
3250 | 3317 |
3251 // Range of the index is not positive. Check can't be redundant. | 3318 // Range of the index is not positive. Check can't be redundant. |
3252 if (Range::ConstantMin(index_range).value() < 0) { | 3319 if (Range::ConstantMin(index_range).Value() < 0) { |
3253 return false; | 3320 return false; |
3254 } | 3321 } |
3255 | 3322 |
3256 RangeBoundary max = CanonicalizeBoundary(index_range->max(), | 3323 RangeBoundary max = CanonicalizeBoundary(index_range->max(), |
3257 RangeBoundary::PositiveInfinity()); | 3324 RangeBoundary::PositiveInfinity()); |
3258 | 3325 |
3259 if (max.Overflowed()) { | 3326 if (max.Overflowed()) { |
3260 return false; | 3327 return false; |
3261 } | 3328 } |
3262 | 3329 |
3263 | 3330 |
3264 RangeBoundary max_upper = max.UpperBound(); | 3331 RangeBoundary max_upper = max.UpperBound(); |
3265 RangeBoundary length_lower = length.LowerBound(); | 3332 RangeBoundary length_lower = length.LowerBound(); |
3266 | 3333 |
3267 if (max_upper.Overflowed() || length_lower.Overflowed()) { | 3334 if (max_upper.Overflowed() || length_lower.Overflowed()) { |
3268 return false; | 3335 return false; |
3269 } | 3336 } |
3270 | 3337 |
3271 // Try to compare constant boundaries. | 3338 // Try to compare constant boundaries. |
3272 if (max_upper.value() < length_lower.value()) { | 3339 if (max_upper.Value() < length_lower.Value()) { |
3273 return true; | 3340 return true; |
3274 } | 3341 } |
3275 | 3342 |
3276 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); | 3343 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); |
3277 if (length.Overflowed()) { | 3344 if (length.Overflowed()) { |
3278 return false; | 3345 return false; |
3279 } | 3346 } |
3280 | 3347 |
3281 // Try symbolic comparison. | 3348 // Try symbolic comparison. |
3282 do { | 3349 do { |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3560 case Token::kTRUNCDIV: return 0; | 3627 case Token::kTRUNCDIV: return 0; |
3561 case Token::kMOD: return 1; | 3628 case Token::kMOD: return 1; |
3562 default: UNIMPLEMENTED(); return -1; | 3629 default: UNIMPLEMENTED(); return -1; |
3563 } | 3630 } |
3564 } | 3631 } |
3565 | 3632 |
3566 | 3633 |
3567 #undef __ | 3634 #undef __ |
3568 | 3635 |
3569 } // namespace dart | 3636 } // namespace dart |
OLD | NEW |