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 2447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2458 | 2458 |
2459 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { | 2459 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { |
2460 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | 2460 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
2461 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | 2461 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
2462 } | 2462 } |
2463 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | 2463 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
2464 } | 2464 } |
2465 | 2465 |
2466 | 2466 |
2467 RangeBoundary RangeBoundary::LowerBound() const { | 2467 RangeBoundary RangeBoundary::LowerBound() const { |
2468 if (IsNegativeInfinity()) return *this; | 2468 if (IsInfinity()) { |
2469 return NegativeInfinity(); | |
2470 } | |
2469 if (IsConstant()) return *this; | 2471 if (IsConstant()) return *this; |
2470 return Add(Range::ConstantMin(symbol()->range()), | 2472 return Add(Range::ConstantMin(symbol()->range()), |
2471 RangeBoundary::FromConstant(offset_), | 2473 RangeBoundary::FromConstant(offset_), |
2472 NegativeInfinity()); | 2474 NegativeInfinity()); |
2473 } | 2475 } |
2474 | 2476 |
2475 | 2477 |
2476 RangeBoundary RangeBoundary::UpperBound() const { | 2478 RangeBoundary RangeBoundary::UpperBound() const { |
2477 if (IsPositiveInfinity()) return *this; | 2479 if (IsInfinity()) { |
2480 return PositiveInfinity(); | |
2481 } | |
2478 if (IsConstant()) return *this; | 2482 if (IsConstant()) return *this; |
2479 return Add(Range::ConstantMax(symbol()->range()), | 2483 return Add(Range::ConstantMax(symbol()->range()), |
2480 RangeBoundary::FromConstant(offset_), | 2484 RangeBoundary::FromConstant(offset_), |
2481 PositiveInfinity()); | 2485 PositiveInfinity()); |
2482 } | 2486 } |
2483 | 2487 |
2484 | 2488 |
2489 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | |
2490 const RangeBoundary& b, | |
2491 const RangeBoundary& overflow) { | |
2492 if (a.IsInfinity() || b.IsInfinity()) { | |
2493 // In that case that a or b is +/- inf, return the overflow boundary. | |
2494 return overflow; | |
2495 } | |
2496 ASSERT(a.IsConstant() && b.IsConstant()); | |
2497 | |
2498 intptr_t result = a.ConstantValue() + b.ConstantValue(); | |
2499 if (!Smi::IsValid(result)) { | |
2500 return overflow; | |
2501 } | |
2502 return RangeBoundary::FromConstant(result); | |
2503 } | |
2504 | |
2505 | |
2506 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a, | |
2507 const RangeBoundary& b, | |
2508 const RangeBoundary& overflow) { | |
2509 if (a.IsInfinity() || b.IsInfinity()) { | |
2510 // In that case that a or b is +/- inf, return the overflow boundary. | |
2511 return overflow; | |
2512 } | |
2513 ASSERT(a.IsConstant() && b.IsConstant()); | |
2514 | |
2515 intptr_t result = a.ConstantValue() - b.ConstantValue(); | |
2516 if (!Smi::IsValid(result)) { | |
2517 return overflow; | |
2518 } | |
2519 return RangeBoundary::FromConstant(result); | |
2520 } | |
2521 | |
2522 | |
2523 bool RangeBoundary::SymbolicAdd(const RangeBoundary& a, | |
2524 const RangeBoundary& b, | |
2525 RangeBoundary* result) { | |
2526 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2527 const intptr_t offset = a.offset() + b.ConstantValue(); | |
2528 if (!Smi::IsValid(offset)) return false; | |
2529 | |
2530 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2531 return true; | |
2532 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { | |
2533 const intptr_t offset = b.offset() + a.ConstantValue(); | |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
return SymbolicAdd(b, a, result); to avoid duplica
Cutch
2014/06/13 22:45:22
Done.
| |
2534 if (!Smi::IsValid(offset)) return false; | |
2535 | |
2536 *result = RangeBoundary::FromDefinition(b.symbol(), offset); | |
2537 return true; | |
2538 } | |
2539 return false; | |
2540 } | |
2541 | |
2542 | |
2543 bool RangeBoundary::SymbolicSub(const RangeBoundary& a, | |
2544 const RangeBoundary& b, | |
2545 RangeBoundary* result) { | |
2546 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2547 const intptr_t offset = a.offset() - b.ConstantValue(); | |
2548 if (!Smi::IsValid(offset)) return false; | |
2549 | |
2550 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2551 return true; | |
2552 } | |
2553 return false; | |
2554 } | |
2555 | |
2556 | |
2485 static Definition* UnwrapConstraint(Definition* defn) { | 2557 static Definition* UnwrapConstraint(Definition* defn) { |
2486 while (defn->IsConstraint()) { | 2558 while (defn->IsConstraint()) { |
2487 defn = defn->AsConstraint()->value()->definition(); | 2559 defn = defn->AsConstraint()->value()->definition(); |
2488 } | 2560 } |
2489 return defn; | 2561 return defn; |
2490 } | 2562 } |
2491 | 2563 |
2492 | 2564 |
2493 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 2565 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
2494 a = UnwrapConstraint(a); | 2566 a = UnwrapConstraint(a); |
2495 b = UnwrapConstraint(b); | 2567 b = UnwrapConstraint(b); |
2496 return (a == b) || | 2568 return (a == b) || |
2497 (a->AllowsCSE() && | 2569 (a->AllowsCSE() && |
2498 a->Dependencies().IsNone() && | 2570 a->Dependencies().IsNone() && |
2499 b->AllowsCSE() && | 2571 b->AllowsCSE() && |
2500 b->Dependencies().IsNone() && | 2572 b->Dependencies().IsNone() && |
2501 a->Equals(b)); | 2573 a->Equals(b)); |
2502 } | 2574 } |
2503 | 2575 |
2504 | 2576 |
2505 // Returns true if two range boundaries refer to the same symbol. | 2577 // Returns true if two range boundaries refer to the same symbol. |
2506 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 2578 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
2507 return a.IsSymbol() && b.IsSymbol() && | 2579 return a.IsSymbol() && b.IsSymbol() && |
2508 AreEqualDefinitions(a.symbol(), b.symbol()); | 2580 AreEqualDefinitions(a.symbol(), b.symbol()); |
2509 } | 2581 } |
2510 | 2582 |
2511 | 2583 |
2512 // Returns true if range has a least specific minimum value. | 2584 bool RangeBoundary::Equals(const RangeBoundary& other) const { |
2513 static bool IsMinSmi(Range* range) { | 2585 if (IsConstant() && other.IsConstant()) { |
2514 return (range == NULL) || | 2586 return ConstantValue() == other.ConstantValue(); |
2515 (range->min().IsConstant() && | 2587 } else if (IsInfinity() && other.IsInfinity()) { |
2516 (range->min().value() <= Smi::kMinValue)); | 2588 return kind() == other.kind(); |
2517 } | 2589 } else if (IsSymbol() && other.IsSymbol()) { |
2518 | 2590 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); |
2519 | |
2520 // Returns true if range has a least specific maximium value. | |
2521 static bool IsMaxSmi(Range* range) { | |
2522 return (range == NULL) || | |
2523 (range->max().IsConstant() && | |
2524 (range->max().value() >= Smi::kMaxValue)); | |
2525 } | |
2526 | |
2527 | |
2528 // Returns true if two range boundaries can be proven to be equal. | |
2529 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
2530 if (a.IsConstant() && b.IsConstant()) { | |
2531 return a.value() == b.value(); | |
2532 } else if (a.IsSymbol() && b.IsSymbol()) { | |
2533 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); | |
2534 } else { | |
2535 return false; | |
2536 } | 2591 } |
2592 return false; | |
2537 } | 2593 } |
2538 | 2594 |
2539 | 2595 |
2540 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, | 2596 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, |
2541 const RangeBoundary& overflow) { | 2597 const RangeBoundary& overflow) { |
2542 if (a.IsConstant() || a.IsNegativeInfinity() || a.IsPositiveInfinity()) { | 2598 if (a.IsConstant() || a.IsInfinity()) { |
2543 return a; | 2599 return a; |
2544 } | 2600 } |
2545 | 2601 |
2546 intptr_t offset = a.offset(); | 2602 intptr_t offset = a.offset(); |
2547 Definition* symbol = a.symbol(); | 2603 Definition* symbol = a.symbol(); |
2548 | 2604 |
2549 bool changed; | 2605 bool changed; |
2550 do { | 2606 do { |
2551 changed = false; | 2607 changed = false; |
2552 if (symbol->IsConstraint()) { | 2608 if (symbol->IsConstraint()) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2624 | 2680 |
2625 *a = CanonicalizeBoundary( | 2681 *a = CanonicalizeBoundary( |
2626 RangeBoundary::FromDefinition(range->min().symbol(), offset), | 2682 RangeBoundary::FromDefinition(range->min().symbol(), offset), |
2627 RangeBoundary::NegativeInfinity()); | 2683 RangeBoundary::NegativeInfinity()); |
2628 | 2684 |
2629 return true; | 2685 return true; |
2630 } | 2686 } |
2631 | 2687 |
2632 | 2688 |
2633 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { | 2689 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { |
2690 // Infinity cases. | |
2691 if (a.IsNegativeInfinity() || b.IsNegativeInfinity()) { | |
2692 return NegativeInfinity(); | |
2693 } | |
2694 if (a.IsPositiveInfinity()) { | |
2695 return b; | |
2696 } | |
2697 if (b.IsPositiveInfinity()) { | |
2698 return a; | |
2699 } | |
2700 | |
2701 // Equality case. | |
2702 if (a.Equals(b)) { | |
2703 return a; | |
2704 } | |
2705 | |
2634 if (DependOnSameSymbol(a, b)) { | 2706 if (DependOnSameSymbol(a, b)) { |
2635 return (a.offset() <= b.offset()) ? a : b; | 2707 return (a.offset() <= b.offset()) ? a : b; |
2636 } | 2708 } |
2637 | 2709 |
2638 const intptr_t min_a = a.LowerBound().Clamp().value(); | 2710 const intptr_t min_a = a.LowerBound().Clamp().ConstantValue(); |
2639 const intptr_t min_b = b.LowerBound().Clamp().value(); | 2711 const intptr_t min_b = b.LowerBound().Clamp().ConstantValue(); |
2640 | 2712 |
2641 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | 2713 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
2642 } | 2714 } |
2643 | 2715 |
2644 | 2716 |
2645 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { | 2717 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { |
2646 if (DependOnSameSymbol(a, b)) { | 2718 // Infinity cases. |
2647 return (a.offset() >= b.offset()) ? a : b; | 2719 if (a.IsPositiveInfinity() || b.IsPositiveInfinity()) { |
2720 return RangeBoundary::PositiveInfinity(); | |
2721 } | |
2722 if (a.IsNegativeInfinity()) { | |
2723 return b; | |
2724 } | |
2725 if (b.IsNegativeInfinity()) { | |
2726 return a; | |
2727 } | |
2728 // Equality case. | |
2729 if (a.Equals(b)) { | |
2730 return a; | |
2648 } | 2731 } |
2649 | 2732 |
2650 const intptr_t max_a = a.UpperBound().Clamp().value(); | 2733 if (DependOnSameSymbol(a, b)) { |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
I would move loop that tries to Canonicalize bound
| |
2651 const intptr_t max_b = b.UpperBound().Clamp().value(); | 2734 return (a.offset() <= b.offset()) ? b : a; |
2735 } | |
2736 | |
2737 const intptr_t max_a = a.UpperBound().Clamp().ConstantValue(); | |
2738 const intptr_t max_b = b.UpperBound().Clamp().ConstantValue(); | |
2652 | 2739 |
2653 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 2740 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
2654 } | 2741 } |
2655 | 2742 |
2656 | 2743 |
2744 intptr_t RangeBoundary::ConstantValue() const { | |
2745 ASSERT(IsConstant()); | |
2746 return value_; | |
2747 } | |
2748 | |
2749 | |
2657 void Definition::InferRange() { | 2750 void Definition::InferRange() { |
2658 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. | 2751 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. |
2659 if (range_ == NULL) { | 2752 if (range_ == NULL) { |
2660 range_ = Range::Unknown(); | 2753 range_ = Range::Unknown(); |
2661 } | 2754 } |
2662 } | 2755 } |
2663 | 2756 |
2664 | 2757 |
2665 void ConstantInstr::InferRange() { | 2758 void ConstantInstr::InferRange() { |
2666 ASSERT(value_.IsSmi()); | 2759 ASSERT(value_.IsSmi()); |
2667 if (range_ == NULL) { | 2760 if (range_ == NULL) { |
2668 intptr_t value = Smi::Cast(value_).Value(); | 2761 intptr_t value = Smi::Cast(value_).Value(); |
2669 range_ = new Range(RangeBoundary::FromConstant(value), | 2762 range_ = new Range(RangeBoundary::FromConstant(value), |
2670 RangeBoundary::FromConstant(value)); | 2763 RangeBoundary::FromConstant(value)); |
2671 } | 2764 } |
2672 } | 2765 } |
2673 | 2766 |
2674 | 2767 |
2675 void ConstraintInstr::InferRange() { | 2768 void ConstraintInstr::InferRange() { |
2676 Range* value_range = value()->definition()->range(); | 2769 Range* value_range = value()->definition()->range(); |
2677 | 2770 |
2678 RangeBoundary min; | 2771 RangeBoundary min; |
2679 RangeBoundary max; | 2772 RangeBoundary max; |
2680 | 2773 |
2681 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { | 2774 if (Range::IncludesNegativeInfinity(value_range) && |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
I would expect this code to actually use RangeBoun
| |
2775 !Range::IncludesNegativeInfinity(constraint())) { | |
2682 min = constraint()->min(); | 2776 min = constraint()->min(); |
2683 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { | 2777 } else if (Range::IncludesNegativeInfinity(constraint()) && |
2778 !Range::IncludesNegativeInfinity(value_range)) { | |
2684 min = value_range->min(); | 2779 min = value_range->min(); |
2685 } else if ((value_range != NULL) && | 2780 } else if ((value_range != NULL) && |
2686 IsEqual(constraint()->min(), value_range->min())) { | 2781 constraint()->min().Equals(value_range->min())) { |
2687 min = constraint()->min(); | 2782 min = constraint()->min(); |
2688 } else { | 2783 } else { |
2689 if (value_range != NULL) { | 2784 if (value_range != NULL) { |
2690 RangeBoundary canonical_a = | 2785 RangeBoundary canonical_a = |
2691 CanonicalizeBoundary(constraint()->min(), | 2786 CanonicalizeBoundary(constraint()->min(), |
2692 RangeBoundary::NegativeInfinity()); | 2787 RangeBoundary::NegativeInfinity()); |
2693 RangeBoundary canonical_b = | 2788 RangeBoundary canonical_b = |
2694 CanonicalizeBoundary(value_range->min(), | 2789 CanonicalizeBoundary(value_range->min(), |
2695 RangeBoundary::NegativeInfinity()); | 2790 RangeBoundary::NegativeInfinity()); |
2696 | 2791 |
2697 do { | 2792 do { |
2698 if (DependOnSameSymbol(canonical_a, canonical_b)) { | 2793 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
2699 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b | 2794 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b |
2700 : canonical_a; | 2795 : canonical_a; |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
I agree this should have break.
| |
2701 } | 2796 } |
2702 } while (CanonicalizeMinBoundary(&canonical_a) || | 2797 } while (CanonicalizeMinBoundary(&canonical_a) || |
2703 CanonicalizeMinBoundary(&canonical_b)); | 2798 CanonicalizeMinBoundary(&canonical_b)); |
2704 } | 2799 } |
2705 | 2800 |
2706 if (min.IsUnknown()) { | 2801 if (min.IsUnknown()) { |
2707 min = RangeBoundary::Max(Range::ConstantMin(value_range), | 2802 min = RangeBoundary::Max(Range::ConstantMin(value_range), |
2708 Range::ConstantMin(constraint())); | 2803 Range::ConstantMin(constraint())); |
2709 } | 2804 } |
2710 } | 2805 } |
2711 | 2806 |
2712 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { | 2807 if (Range::IncludesPositiveInfinity(value_range) && |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
I would expect this to be replaced by RangeBoundar
Cutch
2014/06/13 22:45:22
Done.
| |
2808 !Range::IncludesPositiveInfinity(constraint())) { | |
2713 max = constraint()->max(); | 2809 max = constraint()->max(); |
2714 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { | 2810 } else if (Range::IncludesPositiveInfinity(constraint()) && |
2811 !Range::IncludesPositiveInfinity(value_range)) { | |
2715 max = value_range->max(); | 2812 max = value_range->max(); |
2716 } else if ((value_range != NULL) && | 2813 } else if ((value_range != NULL) && |
2717 IsEqual(constraint()->max(), value_range->max())) { | 2814 constraint()->max().Equals(value_range->max())) { |
2718 max = constraint()->max(); | 2815 max = constraint()->max(); |
2719 } else { | 2816 } else { |
2720 if (value_range != NULL) { | 2817 if (value_range != NULL) { |
2721 RangeBoundary canonical_b = | 2818 RangeBoundary canonical_b = |
2722 CanonicalizeBoundary(value_range->max(), | 2819 CanonicalizeBoundary(value_range->max(), |
2723 RangeBoundary::PositiveInfinity()); | 2820 RangeBoundary::PositiveInfinity()); |
2724 RangeBoundary canonical_a = | 2821 RangeBoundary canonical_a = |
2725 CanonicalizeBoundary(constraint()->max(), | 2822 CanonicalizeBoundary(constraint()->max(), |
2726 RangeBoundary::PositiveInfinity()); | 2823 RangeBoundary::PositiveInfinity()); |
2727 | 2824 |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2964 ASSERT(InputCount() > 1); | 3061 ASSERT(InputCount() > 1); |
2965 Definition* first = InputAt(0)->definition(); | 3062 Definition* first = InputAt(0)->definition(); |
2966 for (intptr_t i = 1; i < InputCount(); ++i) { | 3063 for (intptr_t i = 1; i < InputCount(); ++i) { |
2967 Definition* def = InputAt(i)->definition(); | 3064 Definition* def = InputAt(i)->definition(); |
2968 if (def != first) return false; | 3065 if (def != first) return false; |
2969 } | 3066 } |
2970 return true; | 3067 return true; |
2971 } | 3068 } |
2972 | 3069 |
2973 | 3070 |
2974 static bool SymbolicSub(const RangeBoundary& a, | |
2975 const RangeBoundary& b, | |
2976 RangeBoundary* result) { | |
2977 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2978 const intptr_t offset = a.offset() - b.value(); | |
2979 if (!Smi::IsValid(offset)) return false; | |
2980 | |
2981 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2982 return true; | |
2983 } | |
2984 return false; | |
2985 } | |
2986 | |
2987 | |
2988 static bool SymbolicAdd(const RangeBoundary& a, | |
2989 const RangeBoundary& b, | |
2990 RangeBoundary* result) { | |
2991 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2992 const intptr_t offset = a.offset() + b.value(); | |
2993 if (!Smi::IsValid(offset)) return false; | |
2994 | |
2995 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2996 return true; | |
2997 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { | |
2998 const intptr_t offset = b.offset() + a.value(); | |
2999 if (!Smi::IsValid(offset)) return false; | |
3000 | |
3001 *result = RangeBoundary::FromDefinition(b.symbol(), offset); | |
3002 return true; | |
3003 } | |
3004 return false; | |
3005 } | |
3006 | |
3007 | |
3008 static bool IsArrayLength(Definition* defn) { | 3071 static bool IsArrayLength(Definition* defn) { |
3009 LoadFieldInstr* load = defn->AsLoadField(); | 3072 LoadFieldInstr* load = defn->AsLoadField(); |
3010 return (load != NULL) && load->IsImmutableLengthLoad(); | 3073 return (load != NULL) && load->IsImmutableLengthLoad(); |
3011 } | 3074 } |
3012 | 3075 |
3013 | 3076 |
3014 static int64_t ConstantAbsMax(const Range* range) { | |
3015 if (range == NULL) return Smi::kMaxValue; | |
3016 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).value()); | |
3017 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).value()); | |
3018 return abs_min > abs_max ? abs_min : abs_max; | |
3019 } | |
3020 | |
3021 | |
3022 static bool OnlyPositiveOrZero(const Range* a, const Range* b) { | |
3023 if ((a == NULL) || (b == NULL)) return false; | |
3024 if (Range::ConstantMin(a).value() < 0) return false; | |
3025 if (Range::ConstantMin(b).value() < 0) return false; | |
3026 return true; | |
3027 } | |
3028 | |
3029 | |
3030 static bool OnlyNegativeOrZero(const Range* a, const Range* b) { | |
3031 if ((a == NULL) || (b == NULL)) return false; | |
3032 if (Range::ConstantMax(a).value() > 0) return false; | |
3033 if (Range::ConstantMax(b).value() > 0) return false; | |
3034 return true; | |
3035 } | |
3036 | |
3037 | |
3038 void BinarySmiOpInstr::InferRange() { | 3077 void BinarySmiOpInstr::InferRange() { |
3039 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 3078 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
3040 // right and a non-constant on the left. | 3079 // right and a non-constant on the left. |
3041 Definition* left_defn = left()->definition(); | 3080 Definition* left_defn = left()->definition(); |
3042 | 3081 |
3043 Range* left_range = left_defn->range(); | 3082 Range* left_range = left_defn->range(); |
3044 Range* right_range = right()->definition()->range(); | 3083 Range* right_range = right()->definition()->range(); |
3045 | 3084 |
3046 if ((left_range == NULL) || (right_range == NULL)) { | 3085 if ((left_range == NULL) || (right_range == NULL)) { |
3047 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 3086 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
3048 return; | 3087 return; |
3049 } | 3088 } |
3050 | 3089 |
3051 RangeBoundary left_min = | 3090 RangeBoundary left_min = |
3052 IsArrayLength(left_defn) ? | 3091 IsArrayLength(left_defn) ? |
3053 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | 3092 RangeBoundary::FromDefinition(left_defn) : left_range->min(); |
3054 | 3093 |
3055 RangeBoundary left_max = | 3094 RangeBoundary left_max = |
3056 IsArrayLength(left_defn) ? | 3095 IsArrayLength(left_defn) ? |
3057 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | 3096 RangeBoundary::FromDefinition(left_defn) : left_range->max(); |
3058 | 3097 |
3059 RangeBoundary min; | 3098 // Only update overflow state for +, -, and cases where we already have a |
3060 RangeBoundary max; | 3099 // range. |
3061 switch (op_kind()) { | 3100 bool should_update_overflow = (op_kind() == Token::kADD) || |
3062 case Token::kADD: | 3101 (op_kind() == Token::kSUB) || |
3063 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | 3102 (range_ != NULL); |
3064 min = | |
3065 RangeBoundary::Add(Range::ConstantMin(left_range), | |
3066 Range::ConstantMin(right_range), | |
3067 RangeBoundary::NegativeInfinity()); | |
3068 } | |
3069 | 3103 |
3070 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | 3104 range_ = Range::BinaryOp(op_kind(), |
3071 max = | 3105 left_min, |
3072 RangeBoundary::Add(Range::ConstantMax(right_range), | 3106 left_max, |
3073 Range::ConstantMax(left_range), | 3107 left_range, |
3074 RangeBoundary::PositiveInfinity()); | 3108 right_range, |
3075 } | 3109 range_); |
3076 break; | 3110 if (range_ == NULL) { |
3077 | 3111 // No range information. |
3078 case Token::kSUB: | 3112 return; |
3079 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
3080 min = | |
3081 RangeBoundary::Sub(Range::ConstantMin(left_range), | |
3082 Range::ConstantMax(right_range), | |
3083 RangeBoundary::NegativeInfinity()); | |
3084 } | |
3085 | |
3086 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
3087 max = | |
3088 RangeBoundary::Sub(Range::ConstantMax(left_range), | |
3089 Range::ConstantMin(right_range), | |
3090 RangeBoundary::PositiveInfinity()); | |
3091 } | |
3092 break; | |
3093 | |
3094 case Token::kMUL: { | |
3095 const int64_t left_max = ConstantAbsMax(left_range); | |
3096 const int64_t right_max = ConstantAbsMax(right_range); | |
3097 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
3098 // Product of left and right max values stays in 64 bit range. | |
3099 const int64_t result_max = left_max * right_max; | |
3100 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3101 const intptr_t r_min = | |
3102 OnlyPositiveOrZero(left_range, right_range) ? 0 : -result_max; | |
3103 min = RangeBoundary::FromConstant(r_min); | |
3104 const intptr_t r_max = | |
3105 OnlyNegativeOrZero(left_range, right_range) ? 0 : result_max; | |
3106 max = RangeBoundary::FromConstant(r_max); | |
3107 break; | |
3108 } | |
3109 } | |
3110 if (range_ == NULL) { | |
3111 range_ = Range::Unknown(); | |
3112 } | |
3113 return; | |
3114 } | |
3115 case Token::kBIT_AND: | |
3116 if (Range::ConstantMin(right_range).value() >= 0) { | |
3117 min = RangeBoundary::FromConstant(0); | |
3118 max = Range::ConstantMax(right_range); | |
3119 break; | |
3120 } | |
3121 if (Range::ConstantMin(left_range).value() >= 0) { | |
3122 min = RangeBoundary::FromConstant(0); | |
3123 max = Range::ConstantMax(left_range); | |
3124 break; | |
3125 } | |
3126 | |
3127 if (range_ == NULL) { | |
3128 range_ = Range::Unknown(); | |
3129 } | |
3130 return; | |
3131 | |
3132 default: | |
3133 if (range_ == NULL) { | |
3134 range_ = Range::Unknown(); | |
3135 } | |
3136 return; | |
3137 } | 3113 } |
3138 | 3114 |
3139 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | 3115 if (!should_update_overflow) { |
3140 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); | 3116 return; |
3117 } | |
3141 | 3118 |
3142 if (min.IsConstant()) min.Clamp(); | 3119 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
3143 if (max.IsConstant()) max.Clamp(); | 3120 const bool overflowed = range_->min().LowerBound().Overflowed() || |
3144 | 3121 range_->max().UpperBound().Overflowed(); |
3145 range_ = new Range(min, max); | 3122 set_overflow(overflowed); |
3146 } | 3123 } |
3147 | 3124 |
3148 | 3125 |
3149 bool Range::IsPositive() const { | 3126 bool Range::IsPositive() const { |
3150 if (min().IsNegativeInfinity()) { | 3127 if (min().IsNegativeInfinity()) { |
3151 return false; | 3128 return false; |
3152 } | 3129 } |
3153 if (min().LowerBound().value() < 0) { | 3130 if (min().LowerBound().ConstantValue() < 0) { |
3154 return false; | 3131 return false; |
3155 } | 3132 } |
3156 if (max().IsPositiveInfinity()) { | 3133 if (max().IsPositiveInfinity()) { |
3157 return true; | 3134 return true; |
3158 } | 3135 } |
3159 return max().UpperBound().value() >= 0; | 3136 return max().UpperBound().ConstantValue() >= 0; |
3160 } | 3137 } |
3161 | 3138 |
3162 | 3139 |
3163 bool Range::IsNegative() const { | 3140 bool Range::IsNegative() const { |
3164 if (max().IsPositiveInfinity()) { | 3141 if (max().IsPositiveInfinity()) { |
3165 return false; | 3142 return false; |
3166 } | 3143 } |
3167 if (max().UpperBound().value() >= 0) { | 3144 if (max().UpperBound().ConstantValue() >= 0) { |
3168 return false; | 3145 return false; |
3169 } | 3146 } |
3170 if (min().IsNegativeInfinity()) { | 3147 if (min().IsNegativeInfinity()) { |
3171 return true; | 3148 return true; |
3172 } | 3149 } |
3173 return min().LowerBound().value() < 0; | 3150 return min().LowerBound().ConstantValue() < 0; |
3174 } | 3151 } |
3175 | 3152 |
3176 | 3153 |
3177 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { | 3154 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { |
3178 if (max().IsPositiveInfinity()) { | 3155 if (max().IsPositiveInfinity()) { |
3179 // Cannot be true. | 3156 // Cannot be true. |
3180 return false; | 3157 return false; |
3181 } | 3158 } |
3182 if (max().UpperBound().value() > val) { | 3159 if (max().UpperBound().ConstantValue() > val) { |
3183 // Not true. | 3160 // Not true. |
3184 return false; | 3161 return false; |
3185 } | 3162 } |
3186 if (!min().IsNegativeInfinity()) { | 3163 if (!min().IsNegativeInfinity()) { |
3187 if (min().LowerBound().value() > val) { | 3164 if (min().LowerBound().ConstantValue() > val) { |
3188 // Lower bound is > value. | 3165 // Lower bound is > value. |
3189 return false; | 3166 return false; |
3190 } | 3167 } |
3191 } | 3168 } |
3192 return true; | 3169 return true; |
3193 } | 3170 } |
3194 | 3171 |
3195 | 3172 |
3173 bool Range::OnlyGreaterThanOrEqualTo(intptr_t val) const { | |
3174 if (min().IsNegativeInfinity()) { | |
3175 return false; | |
3176 } | |
3177 if (min().LowerBound().ConstantValue() < val) { | |
3178 return false; | |
3179 } | |
3180 if (!max().IsPositiveInfinity()) { | |
3181 if (max().UpperBound().ConstantValue() < val) { | |
Vyacheslav Egorov (Google)
2014/06/13 11:50:21
min().LowerBound().ConstantValue() >= val && max()
| |
3182 return false; | |
3183 } | |
3184 } | |
3185 return true; | |
3186 } | |
3187 | |
3188 | |
3196 // Inclusive. | 3189 // Inclusive. |
3197 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { | 3190 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { |
3198 RangeBoundary lower_min = min().LowerBound(); | 3191 RangeBoundary lower_min = min().LowerBound(); |
3199 if (lower_min.IsNegativeInfinity() || (lower_min.value() < min_int)) { | 3192 if (lower_min.IsNegativeInfinity() || (lower_min.ConstantValue() < min_int)) { |
3200 return false; | 3193 return false; |
3201 } | 3194 } |
3202 RangeBoundary upper_max = max().UpperBound(); | 3195 RangeBoundary upper_max = max().UpperBound(); |
3203 if (upper_max.IsPositiveInfinity() || (upper_max.value() > max_int)) { | 3196 if (upper_max.IsPositiveInfinity() || (upper_max.ConstantValue() > max_int)) { |
3204 return false; | 3197 return false; |
3205 } | 3198 } |
3206 return true; | 3199 return true; |
3207 } | 3200 } |
3208 | 3201 |
3209 | 3202 |
3210 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { | 3203 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { |
3211 const intptr_t this_min = min().IsNegativeInfinity() ? | 3204 RangeBoundary lower = min().LowerBound(); |
3212 kIntptrMin : min().LowerBound().value(); | 3205 RangeBoundary upper = max().UpperBound(); |
3213 const intptr_t this_max = max().IsPositiveInfinity() ? | 3206 const intptr_t this_min = lower.IsNegativeInfinity() ? |
3214 kIntptrMax : max().UpperBound().value(); | 3207 RangeBoundary::kMin : lower.ConstantValue(); |
3208 const intptr_t this_max = upper.IsPositiveInfinity() ? | |
3209 RangeBoundary::kMax : upper.ConstantValue(); | |
3215 if ((this_min <= min_int) && (min_int <= this_max)) return true; | 3210 if ((this_min <= min_int) && (min_int <= this_max)) return true; |
3216 if ((this_min <= max_int) && (max_int <= this_max)) return true; | 3211 if ((this_min <= max_int) && (max_int <= this_max)) return true; |
3217 if ((min_int < this_min) && (max_int > this_max)) return true; | 3212 if ((min_int < this_min) && (max_int > this_max)) return true; |
3218 return false; | 3213 return false; |
3219 } | 3214 } |
3220 | 3215 |
3221 | 3216 |
3222 bool Range::IsUnsatisfiable() const { | 3217 bool Range::IsUnsatisfiable() const { |
3223 // Infinity case: [+inf, ...] || [..., -inf] | 3218 // Infinity case: [+inf, ...] || [..., -inf] |
3224 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { | 3219 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { |
3225 return true; | 3220 return true; |
3226 } | 3221 } |
3227 // Constant case: For example [0, -1]. | 3222 // Constant case: For example [0, -1]. |
3228 if (Range::ConstantMin(this).value() > Range::ConstantMax(this).value()) { | 3223 if (Range::ConstantMin(this).ConstantValue() > |
3224 Range::ConstantMax(this).ConstantValue()) { | |
3229 return true; | 3225 return true; |
3230 } | 3226 } |
3231 // Symbol case: For example [v+1, v]. | 3227 // Symbol case: For example [v+1, v]. |
3232 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { | 3228 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { |
3233 return true; | 3229 return true; |
3234 } | 3230 } |
3235 return false; | 3231 return false; |
3236 } | 3232 } |
3237 | 3233 |
3238 | 3234 |
3235 // Returns true if range is at or below the minimum smi value. | |
3236 bool Range::IncludesNegativeInfinity(const Range* range) { | |
3237 return (range == NULL) || range->min().IsNegativeInfinity(); | |
3238 } | |
3239 | |
3240 | |
3241 // Returns true if range is at or above the maximum smi value. | |
3242 bool Range::IncludesPositiveInfinity(const Range* range) { | |
3243 return (range == NULL) || range->max().IsPositiveInfinity(); | |
3244 } | |
3245 | |
3246 | |
3247 // Both the a and b ranges are >= 0. | |
3248 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | |
3249 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); | |
3250 } | |
3251 | |
3252 | |
3253 // Both the a and b ranges are <= 0. | |
3254 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | |
3255 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); | |
3256 } | |
3257 | |
3258 | |
3259 // Return the maximum absolute value included in range. | |
3260 int64_t Range::ConstantAbsMax(const Range* range) { | |
3261 if (range == NULL) { | |
3262 return RangeBoundary::kMax; | |
3263 } | |
3264 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); | |
3265 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); | |
3266 return Utils::Maximum(abs_min, abs_max); | |
3267 } | |
3268 | |
3269 | |
3270 Range* Range::BinaryOp(const Token::Kind op, | |
3271 const RangeBoundary& left_min, | |
3272 const RangeBoundary& left_max, | |
3273 const Range* left_range, | |
3274 const Range* right_range, | |
3275 const Range* original_range) { | |
3276 ASSERT(left_range != NULL); | |
3277 ASSERT(right_range != NULL); | |
3278 RangeBoundary min; | |
3279 RangeBoundary max; | |
3280 switch (op) { | |
3281 case Token::kADD: | |
3282 if (!RangeBoundary::SymbolicAdd(left_min, right_range->min(), &min)) { | |
3283 min = RangeBoundary::Add(left_range->min().LowerBound(), | |
3284 right_range->min().LowerBound(), | |
3285 RangeBoundary::NegativeInfinity()); | |
3286 } | |
3287 if (!RangeBoundary::SymbolicAdd(left_max, right_range->max(), &max)) { | |
3288 max = RangeBoundary::Add(right_range->max().UpperBound(), | |
3289 left_range->max().UpperBound(), | |
3290 RangeBoundary::PositiveInfinity()); | |
3291 } | |
3292 break; | |
3293 case Token::kSUB: | |
3294 if (!RangeBoundary::SymbolicSub(left_min, right_range->max(), &min)) { | |
3295 min = RangeBoundary::Sub(left_range->min().LowerBound(), | |
3296 right_range->max().UpperBound(), | |
3297 RangeBoundary::NegativeInfinity()); | |
3298 } | |
3299 if (!RangeBoundary::SymbolicSub(left_max, right_range->min(), &max)) { | |
3300 max = RangeBoundary::Sub(left_range->max().UpperBound(), | |
3301 right_range->min().LowerBound(), | |
3302 RangeBoundary::PositiveInfinity()); | |
3303 } | |
3304 break; | |
3305 case Token::kMUL: { | |
3306 const int64_t left_max = ConstantAbsMax(left_range); | |
3307 const int64_t right_max = ConstantAbsMax(right_range); | |
3308 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
3309 // Product of left and right max values stays in 64 bit range. | |
3310 const int64_t result_max = left_max * right_max; | |
3311 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3312 const intptr_t r_min = | |
3313 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -result_max; | |
3314 min = RangeBoundary::FromConstant(r_min); | |
3315 const intptr_t r_max = | |
3316 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : result_max; | |
3317 max = RangeBoundary::FromConstant(r_max); | |
3318 break; | |
3319 } | |
3320 } | |
3321 if (original_range == NULL) { | |
3322 return Range::Unknown(); | |
3323 } | |
3324 break; | |
3325 } | |
3326 case Token::kBIT_AND: | |
3327 if (Range::ConstantMin(right_range).ConstantValue() >= 0) { | |
3328 min = RangeBoundary::FromConstant(0); | |
3329 max = Range::ConstantMax(right_range); | |
3330 break; | |
3331 } | |
3332 if (Range::ConstantMin(left_range).ConstantValue() >= 0) { | |
3333 min = RangeBoundary::FromConstant(0); | |
3334 max = Range::ConstantMax(left_range); | |
3335 break; | |
3336 } | |
3337 if (original_range == NULL) { | |
3338 return Range::Unknown(); | |
3339 } | |
3340 break; | |
3341 default: | |
3342 if (original_range == NULL) { | |
3343 return Range::Unknown(); | |
3344 } | |
3345 return const_cast<Range*>(original_range); | |
3346 } | |
3347 | |
3348 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | |
3349 | |
3350 return new Range(min, max); | |
3351 } | |
3352 | |
3353 | |
3239 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3354 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
3240 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3355 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
3241 } | 3356 } |
3242 | 3357 |
3243 | 3358 |
3244 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { | 3359 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { |
3245 Range* index_range = index()->definition()->range(); | 3360 Range* index_range = index()->definition()->range(); |
3246 | 3361 |
3247 // Range of the index is unknown can't decide if the check is redundant. | 3362 // Range of the index is unknown can't decide if the check is redundant. |
3248 if (index_range == NULL) { | 3363 if (index_range == NULL) { |
3249 return false; | 3364 return false; |
3250 } | 3365 } |
3251 | 3366 |
3252 // Range of the index is not positive. Check can't be redundant. | 3367 // Range of the index is not positive. Check can't be redundant. |
3253 if (Range::ConstantMin(index_range).value() < 0) { | 3368 if (Range::ConstantMin(index_range).ConstantValue() < 0) { |
3254 return false; | 3369 return false; |
3255 } | 3370 } |
3256 | 3371 |
3257 RangeBoundary max = CanonicalizeBoundary(index_range->max(), | 3372 RangeBoundary max = CanonicalizeBoundary(index_range->max(), |
3258 RangeBoundary::PositiveInfinity()); | 3373 RangeBoundary::PositiveInfinity()); |
3259 | 3374 |
3260 if (max.Overflowed()) { | 3375 if (max.Overflowed()) { |
3261 return false; | 3376 return false; |
3262 } | 3377 } |
3263 | 3378 |
3264 | 3379 |
3265 RangeBoundary max_upper = max.UpperBound(); | 3380 RangeBoundary max_upper = max.UpperBound(); |
3266 RangeBoundary length_lower = length.LowerBound(); | 3381 RangeBoundary length_lower = length.LowerBound(); |
3267 | 3382 |
3268 if (max_upper.Overflowed() || length_lower.Overflowed()) { | 3383 if (max_upper.Overflowed() || length_lower.Overflowed()) { |
3269 return false; | 3384 return false; |
3270 } | 3385 } |
3271 | 3386 |
3272 // Try to compare constant boundaries. | 3387 // Try to compare constant boundaries. |
3273 if (max_upper.value() < length_lower.value()) { | 3388 if (max_upper.ConstantValue() < length_lower.ConstantValue()) { |
3274 return true; | 3389 return true; |
3275 } | 3390 } |
3276 | 3391 |
3277 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); | 3392 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); |
3278 if (length.Overflowed()) { | 3393 if (length.Overflowed()) { |
3279 return false; | 3394 return false; |
3280 } | 3395 } |
3281 | 3396 |
3282 // Try symbolic comparison. | 3397 // Try symbolic comparison. |
3283 do { | 3398 do { |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3561 case Token::kTRUNCDIV: return 0; | 3676 case Token::kTRUNCDIV: return 0; |
3562 case Token::kMOD: return 1; | 3677 case Token::kMOD: return 1; |
3563 default: UNIMPLEMENTED(); return -1; | 3678 default: UNIMPLEMENTED(); return -1; |
3564 } | 3679 } |
3565 } | 3680 } |
3566 | 3681 |
3567 | 3682 |
3568 #undef __ | 3683 #undef __ |
3569 | 3684 |
3570 } // namespace dart | 3685 } // namespace dart |
OLD | NEW |