[turbofan] Add missing -0 support for NumberMax/NumberMin typing.

The typing rules for NumberMax and NumberMin didn't properly deal with
-0 up until now, leading to suboptimal typing, i.e. for a simple case
like

  Math.max(Math.round(x), 1)

TurboFan was unable to figure out that the result is definitely going
to be a positive integer in the range [1,inf] or NaN (assuming that
NumberOrOddball feedback is used for the value x).

Bug: v8:8015
Change-Id: I06e14a9c9b0b813eb214ace7749fcc6ab36bb66a
Reviewed-on: https://chromium-review.googlesource.com/1199304
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55570}
This commit is contained in:
Benedikt Meurer 2018-09-02 21:19:37 +02:00 committed by Commit Bot
parent a9e3d9c7ec
commit fa54dff255
3 changed files with 90 additions and 4 deletions

View File

@ -999,7 +999,6 @@ Type OperationTyper::NumberMax(Type lhs, Type rhs) {
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
Type type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone());
}
@ -1007,10 +1006,17 @@ Type OperationTyper::NumberMax(Type lhs, Type rhs) {
DCHECK(!lhs.IsNone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
DCHECK(!rhs.IsNone());
if (lhs.Is(cache_.kInteger) && rhs.Is(cache_.kInteger)) {
if (lhs.Is(cache_.kIntegerOrMinusZero) &&
rhs.Is(cache_.kIntegerOrMinusZero)) {
// TODO(turbofan): This could still be improved in ruling out -0 when
// one of the inputs' min is 0.
double max = std::max(lhs.Max(), rhs.Max());
double min = std::max(lhs.Min(), rhs.Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
if (min <= 0.0 && 0.0 <= max &&
(lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero()))) {
type = Type::Union(type, Type::MinusZero(), zone());
}
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}
@ -1025,7 +1031,6 @@ Type OperationTyper::NumberMin(Type lhs, Type rhs) {
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
Type type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone());
}
@ -1033,10 +1038,15 @@ Type OperationTyper::NumberMin(Type lhs, Type rhs) {
DCHECK(!lhs.IsNone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
DCHECK(!rhs.IsNone());
if (lhs.Is(cache_.kInteger) && rhs.Is(cache_.kInteger)) {
if (lhs.Is(cache_.kIntegerOrMinusZero) &&
rhs.Is(cache_.kIntegerOrMinusZero)) {
double max = std::min(lhs.Max(), rhs.Max());
double min = std::min(lhs.Min(), rhs.Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
if (min <= 0.0 && 0.0 <= max &&
(lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero()))) {
type = Type::Union(type, Type::MinusZero(), zone());
}
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}

View File

@ -0,0 +1,38 @@
// 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
// Test the case where TurboFan can statically rule out -0 from the
// Math.max type.
(function() {
function foo(x) {
// Arrange x such that TurboFan infers type [-inf, inf] \/ MinusZero.
x = +x;
x = Math.round(x);
return Object.is(-0, Math.max(1, x))
}
assertFalse(foo(-0));
assertFalse(foo(-1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-0));
assertFalse(foo(-1));
})();
// Test the case where -0 is ruled out because it's strictly less than +0.
(function() {
function foo(x) {
// Arrange x such that TurboFan infers type [-inf, inf] \/ MinusZero.
x = +x;
x = Math.round(x);
return Object.is(-0, Math.max(0, x))
}
assertFalse(foo(-0));
assertFalse(foo(-1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-0));
assertFalse(foo(-1));
})();

38
test/mjsunit/compiler/math-min.js vendored Normal file
View File

@ -0,0 +1,38 @@
// 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
// Test the case where TurboFan can statically rule out -0 from the
// Math.min type.
(function() {
function foo(x) {
// Arrange x such that TurboFan infers type [-inf, inf] \/ MinusZero.
x = +x;
x = Math.round(x);
return Object.is(-0, Math.min(-1, x))
}
assertFalse(foo(-0));
assertFalse(foo(-1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-0));
assertFalse(foo(-1));
})();
// Test the case where +0 is ruled out because it's strictly greater than -0.
(function() {
function foo(x) {
// Arrange x such that TurboFan infers type [-inf, inf] \/ MinusZero.
x = +x;
x = Math.round(x);
return Object.is(+0, Math.min(-0, x))
}
assertFalse(foo(-0));
assertFalse(foo(-1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-0));
assertFalse(foo(-1));
})();