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:
Georg Neis 2018-11-19 11:40:52 +00:00 committed by Commit Bot
parent 72823c8cfc
commit 858fc3f695
3 changed files with 31 additions and 126 deletions

View File

@ -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) {

View File

@ -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_; }

View File

@ -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));
})();