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

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 2445 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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