Index: src/compiler/operation-typer.cc |
diff --git a/src/compiler/operation-typer.cc b/src/compiler/operation-typer.cc |
index 53c2770864864de5294d62403dfc8110677143da..ac9a9a06f6bde85a573085d77deeda6f4fbeb6c7 100644 |
--- a/src/compiler/operation-typer.cc |
+++ b/src/compiler/operation-typer.cc |
@@ -192,12 +192,13 @@ Type* OperationTyper::AddRanger(double lhs_min, double lhs_max, double rhs_min, |
return type; |
} |
-Type* OperationTyper::SubtractRanger(RangeType* lhs, RangeType* rhs) { |
+Type* OperationTyper::SubtractRanger(double lhs_min, double lhs_max, |
+ double rhs_min, double rhs_max) { |
double results[4]; |
- results[0] = lhs->Min() - rhs->Min(); |
- results[1] = lhs->Min() - rhs->Max(); |
- results[2] = lhs->Max() - rhs->Min(); |
- results[3] = lhs->Max() - rhs->Max(); |
+ results[0] = lhs_min - rhs_min; |
+ results[1] = lhs_min - rhs_max; |
+ results[2] = lhs_max - rhs_min; |
+ results[3] = lhs_max - rhs_max; |
// Since none of the inputs can be -0, the result cannot be -0. |
// However, it can be nan (the subtraction of two infinities of same sign). |
// On the other hand, if none of the "results" above is nan, then the actual |
@@ -207,9 +208,9 @@ Type* OperationTyper::SubtractRanger(RangeType* lhs, RangeType* rhs) { |
if (std::isnan(results[i])) ++nans; |
} |
if (nans == 4) return Type::NaN(); // [inf..inf] - [inf..inf] (all same sign) |
- Type* range = |
+ Type* type = |
Type::Range(array_min(results, 4), array_max(results, 4), zone()); |
- return nans == 0 ? range : Type::Union(range, Type::NaN(), zone()); |
+ return nans == 0 ? type : Type::Union(type, Type::NaN(), zone()); |
// Examples: |
// [-inf, +inf] - [-inf, +inf] = [-inf, +inf] \/ NaN |
// [-inf, -inf] - [-inf, -inf] = NaN |
@@ -544,14 +545,41 @@ Type* OperationTyper::NumberSubtract(Type* lhs, Type* rhs) { |
return Type::None(); |
} |
- lhs = Rangify(lhs); |
- rhs = Rangify(rhs); |
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
- if (lhs->IsRange() && rhs->IsRange()) { |
- return SubtractRanger(lhs->AsRange(), rhs->AsRange()); |
+ // Subtraction can return NaN if either input can be NaN or we try to |
+ // compute the sum of two infinities of opposite sign. |
+ bool maybe_nan = lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN()); |
+ |
+ // Subtraction can yield minus zero if {lhs} can be minus zero and {rhs} |
+ // can be zero. |
+ bool maybe_minuszero = false; |
+ if (lhs->Maybe(Type::MinusZero())) { |
+ lhs = Type::Union(lhs, cache_.kSingletonZero, zone()); |
+ maybe_minuszero = rhs->Maybe(cache_.kSingletonZero); |
} |
- // TODO(neis): Deal with numeric bitsets here and elsewhere. |
- return Type::Number(); |
+ if (rhs->Maybe(Type::MinusZero())) { |
+ rhs = Type::Union(rhs, cache_.kSingletonZero, zone()); |
+ } |
+ |
+ // We can give more precise types for integers. |
+ Type* type = Type::None(); |
+ lhs = Type::Intersect(lhs, Type::PlainNumber(), zone()); |
+ rhs = Type::Intersect(rhs, Type::PlainNumber(), zone()); |
+ if (lhs->IsInhabited() && rhs->IsInhabited()) { |
+ if (lhs->Is(cache_.kInteger) && rhs->Is(cache_.kInteger)) { |
+ type = SubtractRanger(lhs->Min(), lhs->Max(), rhs->Min(), rhs->Max()); |
+ } else { |
+ if ((lhs->Maybe(infinity_) && rhs->Maybe(infinity_)) || |
+ (rhs->Maybe(minus_infinity_) && lhs->Maybe(minus_infinity_))) { |
+ maybe_nan = true; |
+ } |
+ type = Type::PlainNumber(); |
+ } |
+ } |
+ |
+ // Take into account the -0 and NaN information computed earlier. |
+ if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone()); |
+ if (maybe_nan) type = Type::Union(type, Type::NaN(), zone()); |
+ return type; |
} |
Type* OperationTyper::NumberMultiply(Type* lhs, Type* rhs) { |