Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: runtime/vm/intermediate_language.cc

Issue 328503003: Extend Range analysis to 64-bit range and mint operations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698