| Index: runtime/vm/intermediate_language.cc
|
| diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
|
| index a87ac3a481585ad10e8d3a879a85a8b51bf8b772..198fbec962df72528c6d5d4ef72187adb5b486f4 100644
|
| --- a/runtime/vm/intermediate_language.cc
|
| +++ b/runtime/vm/intermediate_language.cc
|
| @@ -1233,14 +1233,13 @@ bool BinarySmiOpInstr::CanDeoptimize() const {
|
| case Token::kSHR: {
|
| // Can't deopt if shift-count is known positive.
|
| Range* right_range = this->right()->definition()->range();
|
| - return (right_range == NULL)
|
| - || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
|
| + return (right_range == NULL) || right_range->IsNegative();
|
| }
|
| case Token::kSHL: {
|
| Range* right_range = this->right()->definition()->range();
|
| if ((right_range != NULL) && is_truncating()) {
|
| // Can deoptimize if right can be negative.
|
| - return !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
|
| + return right_range->IsNegative();
|
| }
|
| return true;
|
| }
|
| @@ -2444,18 +2443,20 @@ RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) {
|
|
|
|
|
| RangeBoundary RangeBoundary::LowerBound() const {
|
| + if (IsNegativeInfinity()) return *this;
|
| if (IsConstant()) return *this;
|
| return Add(Range::ConstantMin(symbol()->range()),
|
| RangeBoundary::FromConstant(offset_),
|
| - OverflowedMinSmi());
|
| + NegativeInfinity());
|
| }
|
|
|
|
|
| RangeBoundary RangeBoundary::UpperBound() const {
|
| + if (IsPositiveInfinity()) return *this;
|
| if (IsConstant()) return *this;
|
| return Add(Range::ConstantMax(symbol()->range()),
|
| RangeBoundary::FromConstant(offset_),
|
| - OverflowedMaxSmi());
|
| + PositiveInfinity());
|
| }
|
|
|
|
|
| @@ -2516,7 +2517,9 @@ static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) {
|
|
|
| static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a,
|
| const RangeBoundary& overflow) {
|
| - if (a.IsConstant()) return a;
|
| + if (a.IsConstant() || a.IsNegativeInfinity() || a.IsPositiveInfinity()) {
|
| + return a;
|
| + }
|
|
|
| intptr_t offset = a.offset();
|
| Definition* symbol = a.symbol();
|
| @@ -2573,13 +2576,13 @@ static bool CanonicalizeMaxBoundary(RangeBoundary* a) {
|
| const intptr_t offset = range->max().offset() + a->offset();
|
|
|
| if (!Smi::IsValid(offset)) {
|
| - *a = RangeBoundary::OverflowedMaxSmi();
|
| + *a = RangeBoundary::PositiveInfinity();
|
| return true;
|
| }
|
|
|
| *a = CanonicalizeBoundary(
|
| RangeBoundary::FromDefinition(range->max().symbol(), offset),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
|
|
| return true;
|
| }
|
| @@ -2593,13 +2596,13 @@ static bool CanonicalizeMinBoundary(RangeBoundary* a) {
|
|
|
| const intptr_t offset = range->min().offset() + a->offset();
|
| if (!Smi::IsValid(offset)) {
|
| - *a = RangeBoundary::OverflowedMinSmi();
|
| + *a = RangeBoundary::NegativeInfinity();
|
| return true;
|
| }
|
|
|
| *a = CanonicalizeBoundary(
|
| RangeBoundary::FromDefinition(range->min().symbol(), offset),
|
| - RangeBoundary::OverflowedMinSmi());
|
| + RangeBoundary::NegativeInfinity());
|
|
|
| return true;
|
| }
|
| @@ -2664,10 +2667,10 @@ void ConstraintInstr::InferRange() {
|
| if (value_range != NULL) {
|
| RangeBoundary canonical_a =
|
| CanonicalizeBoundary(constraint()->min(),
|
| - RangeBoundary::OverflowedMinSmi());
|
| + RangeBoundary::NegativeInfinity());
|
| RangeBoundary canonical_b =
|
| CanonicalizeBoundary(value_range->min(),
|
| - RangeBoundary::OverflowedMinSmi());
|
| + RangeBoundary::NegativeInfinity());
|
|
|
| do {
|
| if (DependOnSameSymbol(canonical_a, canonical_b)) {
|
| @@ -2695,10 +2698,10 @@ void ConstraintInstr::InferRange() {
|
| if (value_range != NULL) {
|
| RangeBoundary canonical_b =
|
| CanonicalizeBoundary(value_range->max(),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
| RangeBoundary canonical_a =
|
| CanonicalizeBoundary(constraint()->max(),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
|
|
| do {
|
| if (DependOnSameSymbol(canonical_a, canonical_b)) {
|
| @@ -3039,14 +3042,14 @@ void BinarySmiOpInstr::InferRange() {
|
| min =
|
| RangeBoundary::Add(Range::ConstantMin(left_range),
|
| Range::ConstantMin(right_range),
|
| - RangeBoundary::OverflowedMinSmi());
|
| + RangeBoundary::NegativeInfinity());
|
| }
|
|
|
| if (!SymbolicAdd(left_max, right_range->max(), &max)) {
|
| max =
|
| RangeBoundary::Add(Range::ConstantMax(right_range),
|
| Range::ConstantMax(left_range),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
| }
|
| break;
|
|
|
| @@ -3055,14 +3058,14 @@ void BinarySmiOpInstr::InferRange() {
|
| min =
|
| RangeBoundary::Sub(Range::ConstantMin(left_range),
|
| Range::ConstantMax(right_range),
|
| - RangeBoundary::OverflowedMinSmi());
|
| + RangeBoundary::NegativeInfinity());
|
| }
|
|
|
| if (!SymbolicSub(left_max, right_range->min(), &max)) {
|
| max =
|
| RangeBoundary::Sub(Range::ConstantMax(left_range),
|
| Range::ConstantMin(right_range),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
| }
|
| break;
|
|
|
| @@ -3121,17 +3124,70 @@ void BinarySmiOpInstr::InferRange() {
|
| }
|
|
|
|
|
| +bool Range::IsPositive() const {
|
| + if (min().IsNegativeInfinity()) {
|
| + return false;
|
| + }
|
| + if (min().LowerBound().value() < 0) {
|
| + return false;
|
| + }
|
| + if (max().IsPositiveInfinity()) {
|
| + return true;
|
| + }
|
| + return max().UpperBound().value() >= 0;
|
| +}
|
| +
|
| +
|
| +bool Range::IsNegative() const {
|
| + if (max().IsPositiveInfinity()) {
|
| + return false;
|
| + }
|
| + if (max().UpperBound().value() >= 0) {
|
| + return false;
|
| + }
|
| + if (min().IsNegativeInfinity()) {
|
| + return true;
|
| + }
|
| + return min().LowerBound().value() < 0;
|
| +}
|
| +
|
| +
|
| +bool Range::OnlyLessThanOrEqualTo(intptr_t val) const {
|
| + if (max().IsPositiveInfinity()) {
|
| + // Cannot be true.
|
| + return false;
|
| + }
|
| + if (max().UpperBound().value() > val) {
|
| + // Not true.
|
| + return false;
|
| + }
|
| + if (!min().IsNegativeInfinity()) {
|
| + if (min().LowerBound().value() > val) {
|
| + // Lower bound is > value.
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| // Inclusive.
|
| bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const {
|
| - if (min().LowerBound().value() < min_int) return false;
|
| - if (max().UpperBound().value() > max_int) return false;
|
| + if (min().IsNegativeInfinity() || (min().LowerBound().value() < min_int)) {
|
| + return false;
|
| + }
|
| + if (max().IsPositiveInfinity() || (max().UpperBound().value() > max_int)) {
|
| + return false;
|
| + }
|
| return true;
|
| }
|
|
|
|
|
| bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const {
|
| - const intptr_t this_min = min().LowerBound().value();
|
| - const intptr_t this_max = max().UpperBound().value();
|
| + const intptr_t this_min = min().IsNegativeInfinity() ?
|
| + kIntptrMin : min().LowerBound().value();
|
| + const intptr_t this_max = max().IsPositiveInfinity() ?
|
| + kIntptrMax : max().UpperBound().value();
|
| if ((this_min <= min_int) && (min_int <= this_max)) return true;
|
| if ((this_min <= max_int) && (max_int <= this_max)) return true;
|
| if ((min_int < this_min) && (max_int > this_max)) return true;
|
| @@ -3140,6 +3196,10 @@ bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const {
|
|
|
|
|
| bool Range::IsUnsatisfiable() const {
|
| + // Infinity case: [+inf, ...] || [..., -inf]
|
| + if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) {
|
| + return true;
|
| + }
|
| // Constant case: For example [0, -1].
|
| if (Range::ConstantMin(this).value() > Range::ConstantMax(this).value()) {
|
| return true;
|
| @@ -3171,18 +3231,26 @@ bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) {
|
| }
|
|
|
| RangeBoundary max = CanonicalizeBoundary(index_range->max(),
|
| - RangeBoundary::OverflowedMaxSmi());
|
| + RangeBoundary::PositiveInfinity());
|
|
|
| if (max.Overflowed()) {
|
| return false;
|
| }
|
|
|
| +
|
| + RangeBoundary max_upper = max.UpperBound();
|
| + RangeBoundary length_lower = length.LowerBound();
|
| +
|
| + if (max_upper.Overflowed() || length_lower.Overflowed()) {
|
| + return false;
|
| + }
|
| +
|
| // Try to compare constant boundaries.
|
| - if (max.UpperBound().value() < length.LowerBound().value()) {
|
| + if (max_upper.value() < length_lower.value()) {
|
| return true;
|
| }
|
|
|
| - length = CanonicalizeBoundary(length, RangeBoundary::OverflowedMaxSmi());
|
| + length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity());
|
| if (length.Overflowed()) {
|
| return false;
|
| }
|
|
|