Revert "[turbofan] Improve NumberMultiply typing rule."
This reverts commit 585b4eef6a
.
Reason for revert: Speculative, crbug 906567.
Original change's description:
> [turbofan] Improve NumberMultiply typing rule.
>
> The NumberMultiply typing rule gave up in the presence of NaN inputs,
> but we can still infer useful ranges here and just union the result
> of that with the NaN propagation (similar for MinusZero propagation).
> This way we can still makes sense of these ranges at the uses.
>
> Bug: v8:8015
> Change-Id: Ic4c5e8edc6c68776ff3baca9628ad7de0f8e2a92
> Reviewed-on: https://chromium-review.googlesource.com/c/1261143
> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#56539}
TBR=sigurds@chromium.org,bmeurer@chromium.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: v8:8015
Change-Id: I3c652bafbbc0e5d1ad4ff288264fd4f4cbf71330
Reviewed-on: https://chromium-review.googlesource.com/c/1340253
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57602}
This commit is contained in:
parent
72823c8cfc
commit
858fc3f695
@ -221,36 +221,31 @@ Type OperationTyper::SubtractRanger(double lhs_min, double lhs_max,
|
||||
// [m, +inf] - [-inf, n] = [-inf, +inf] \/ NaN
|
||||
}
|
||||
|
||||
Type OperationTyper::MultiplyRanger(double lhs_min, double lhs_max,
|
||||
double rhs_min, double rhs_max) {
|
||||
Type OperationTyper::MultiplyRanger(Type lhs, Type rhs) {
|
||||
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;
|
||||
// If the result may be nan, we give up on calculating a precise type,
|
||||
// because the discontinuity makes it too complicated. Note that even if
|
||||
// none of the "results" above is nan, the actual result may still be, so we
|
||||
// have to do a different check:
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (std::isnan(results[i])) {
|
||||
return cache_.kIntegerOrMinusZeroOrNaN;
|
||||
}
|
||||
}
|
||||
double min = array_min(results, 4);
|
||||
double max = array_max(results, 4);
|
||||
Type type = Type::Range(min, max, zone());
|
||||
if (min <= 0.0 && 0.0 <= max && (lhs_min < 0.0 || rhs_min < 0.0)) {
|
||||
type = Type::Union(type, Type::MinusZero(), zone());
|
||||
}
|
||||
// 0 * V8_INFINITY is NaN, regardless of sign
|
||||
if (((lhs_min == -V8_INFINITY || lhs_max == V8_INFINITY) &&
|
||||
(rhs_min <= 0.0 && 0.0 <= rhs_max)) ||
|
||||
((rhs_min == -V8_INFINITY || rhs_max == V8_INFINITY) &&
|
||||
(lhs_min <= 0.0 && 0.0 <= lhs_max))) {
|
||||
type = Type::Union(type, Type::NaN(), zone());
|
||||
}
|
||||
return type;
|
||||
double lmin = lhs.AsRange()->Min();
|
||||
double lmax = lhs.AsRange()->Max();
|
||||
double rmin = rhs.AsRange()->Min();
|
||||
double rmax = rhs.AsRange()->Max();
|
||||
results[0] = lmin * rmin;
|
||||
results[1] = lmin * rmax;
|
||||
results[2] = lmax * rmin;
|
||||
results[3] = lmax * rmax;
|
||||
// If the result may be nan, we give up on calculating a precise type, because
|
||||
// the discontinuity makes it too complicated. Note that even if none of the
|
||||
// "results" above is nan, the actual result may still be, so we have to do a
|
||||
// different check:
|
||||
bool maybe_nan = (lhs.Maybe(cache_.kSingletonZero) &&
|
||||
(rmin == -V8_INFINITY || rmax == +V8_INFINITY)) ||
|
||||
(rhs.Maybe(cache_.kSingletonZero) &&
|
||||
(lmin == -V8_INFINITY || lmax == +V8_INFINITY));
|
||||
if (maybe_nan) return cache_.kIntegerOrMinusZeroOrNaN; // Giving up.
|
||||
bool maybe_minuszero = (lhs.Maybe(cache_.kSingletonZero) && rmin < 0) ||
|
||||
(rhs.Maybe(cache_.kSingletonZero) && lmin < 0);
|
||||
Type range =
|
||||
Type::Range(array_min(results, 4), array_max(results, 4), zone());
|
||||
return maybe_minuszero ? Type::Union(range, Type::MinusZero(), zone())
|
||||
: range;
|
||||
}
|
||||
|
||||
Type OperationTyper::ConvertReceiver(Type type) {
|
||||
@ -690,44 +685,14 @@ Type OperationTyper::NumberMultiply(Type lhs, Type rhs) {
|
||||
DCHECK(rhs.Is(Type::Number()));
|
||||
|
||||
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
|
||||
|
||||
lhs = Rangify(lhs);
|
||||
rhs = Rangify(rhs);
|
||||
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
|
||||
|
||||
// Multiplication propagates NaN:
|
||||
// NaN * x = NaN (regardless of sign of x)
|
||||
// 0 * Infinity = NaN (regardless of signs)
|
||||
bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN()) ||
|
||||
(lhs.Maybe(cache_.kZeroish) &&
|
||||
(rhs.Min() == -V8_INFINITY || rhs.Max() == V8_INFINITY)) ||
|
||||
(rhs.Maybe(cache_.kZeroish) &&
|
||||
(lhs.Min() == -V8_INFINITY || lhs.Max() == V8_INFINITY));
|
||||
lhs = Type::Intersect(lhs, Type::OrderedNumber(), zone());
|
||||
DCHECK(!lhs.IsNone());
|
||||
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
|
||||
DCHECK(!rhs.IsNone());
|
||||
|
||||
// Try to rule out -0.
|
||||
bool maybe_minuszero = lhs.Maybe(Type::MinusZero()) ||
|
||||
rhs.Maybe(Type::MinusZero()) ||
|
||||
(lhs.Maybe(cache_.kZeroish) && rhs.Min() < 0.0) ||
|
||||
(rhs.Maybe(cache_.kZeroish) && lhs.Min() < 0.0);
|
||||
if (lhs.Maybe(Type::MinusZero())) {
|
||||
lhs = Type::Union(lhs, cache_.kSingletonZero, zone());
|
||||
lhs = Type::Intersect(lhs, Type::PlainNumber(), zone());
|
||||
if (lhs.IsRange() && rhs.IsRange()) {
|
||||
return MultiplyRanger(lhs, rhs);
|
||||
}
|
||||
if (rhs.Maybe(Type::MinusZero())) {
|
||||
rhs = Type::Union(rhs, cache_.kSingletonZero, zone());
|
||||
rhs = Type::Intersect(rhs, Type::PlainNumber(), zone());
|
||||
}
|
||||
|
||||
// Compute the effective type, utilizing range information if possible.
|
||||
Type type = (lhs.Is(cache_.kInteger) && rhs.Is(cache_.kInteger))
|
||||
? MultiplyRanger(lhs.Min(), lhs.Max(), rhs.Min(), rhs.Max())
|
||||
: Type::OrderedNumber();
|
||||
|
||||
// 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;
|
||||
return Type::Number();
|
||||
}
|
||||
|
||||
Type OperationTyper::NumberDivide(Type lhs, Type rhs) {
|
||||
|
@ -87,8 +87,7 @@ class V8_EXPORT_PRIVATE OperationTyper {
|
||||
double rhs_max);
|
||||
Type SubtractRanger(double lhs_min, double lhs_max, double rhs_min,
|
||||
double rhs_max);
|
||||
Type MultiplyRanger(double lhs_min, double lhs_max, double rhs_min,
|
||||
double rhs_max);
|
||||
Type MultiplyRanger(Type lhs, Type rhs);
|
||||
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
|
@ -1,59 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --opt
|
||||
|
||||
// Test the extreme case where -0 is produced by rounding errors.
|
||||
(function() {
|
||||
function bar(x) {
|
||||
return 1e-308 * x;
|
||||
}
|
||||
bar(1);
|
||||
|
||||
function foo() {
|
||||
return Object.is(-0, bar(-1e-308));
|
||||
}
|
||||
|
||||
assertTrue(foo());
|
||||
assertTrue(foo());
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertTrue(foo());
|
||||
})();
|
||||
|
||||
// Test that multiplication of integer by 0 produces the correct results.
|
||||
(function() {
|
||||
function foo(x) {
|
||||
return 0 * Math.round(x);
|
||||
}
|
||||
|
||||
assertEquals(0, foo(0.1));
|
||||
assertEquals(-0, foo(-0.1));
|
||||
assertEquals(NaN, foo(NaN));
|
||||
assertEquals(NaN, foo(Infinity));
|
||||
assertEquals(NaN, foo(-Infinity));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertEquals(0, foo(0.1));
|
||||
assertEquals(-0, foo(-0.1));
|
||||
assertEquals(NaN, foo(NaN));
|
||||
assertEquals(NaN, foo(Infinity));
|
||||
assertEquals(NaN, foo(-Infinity));
|
||||
})();
|
||||
|
||||
// Test that multiplication properly preserves -0 and NaN, and doesn't
|
||||
// cut it short incorrectly.
|
||||
(function() {
|
||||
function foo(x, y) {
|
||||
x = Math.sign(x);
|
||||
y = Math.sign(y);
|
||||
return Math.min(x * y, 0);
|
||||
}
|
||||
|
||||
assertEquals(0, foo(1, 0));
|
||||
assertEquals(-0, foo(1, -0));
|
||||
assertEquals(NaN, foo(NaN, -0));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertEquals(0, foo(1, 0));
|
||||
assertEquals(-0, foo(1, -0));
|
||||
assertEquals(NaN, foo(NaN, -0));
|
||||
})();
|
Loading…
Reference in New Issue
Block a user