v8/test/mjsunit/compiler/number-modulus.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

179 lines
5.6 KiB
JavaScript
Raw Normal View History

// 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 --noalways-opt
// Test that NumberModulus with Number feedback works if only in the
// end SimplifiedLowering figures out that the inputs to this operation
// are actually Unsigned32.
(function() {
// We need a separately polluted % with NumberOrOddball feedback.
function bar(x) { return x % 2; }
bar(undefined); // The % feedback is now NumberOrOddball.
// Now just use the gadget above in a way that only after RETYPE
// in SimplifiedLowering we find out that the `x` is actually in
// Unsigned32 range (based on taking the SignedSmall feedback on
// the + operator).
function foo(x) {
x = (x >>> 0) + 1;
return bar(x) | 0;
}
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
assertOptimized(foo);
})();
// Test that NumberModulus with Number feedback works if only in the
// end SimplifiedLowering figures out that the inputs to this operation
// are actually Signed32.
(function() {
// We need a separately polluted % with NumberOrOddball feedback.
function bar(x) { return x % 2; }
bar(undefined); // The % feedback is now NumberOrOddball.
// Now just use the gadget above in a way that only after RETYPE
// in SimplifiedLowering we find out that the `x` is actually in
// Signed32 range (based on taking the SignedSmall feedback on
// the + operator).
function foo(x) {
x = (x | 0) + 1;
return bar(x) | 0;
}
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
assertOptimized(foo);
})();
// Test that SpeculativeNumberModulus with Number feedback works if
// only in the end SimplifiedLowering figures out that the inputs to
// this operation are actually Unsigned32.
(function() {
// We need to use an object literal here to make sure that the
// SpeculativeNumberModulus is not turned into a NumberModulus
// early during JSTypedLowering.
function bar(x) { return {x}.x % 2; }
bar(undefined); // The % feedback is now NumberOrOddball.
// Now just use the gadget above in a way that only after RETYPE
// in SimplifiedLowering we find out that the `x` is actually in
// Unsigned32 range (based on taking the SignedSmall feedback on
// the + operator).
function foo(x) {
x = (x >>> 0) + 1;
return bar(x) | 0;
}
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
assertOptimized(foo);
})();
// Test that SpeculativeNumberModulus with Number feedback works if
// only in the end SimplifiedLowering figures out that the inputs to
// this operation are actually Signed32.
(function() {
// We need to use an object literal here to make sure that the
// SpeculativeNumberModulus is not turned into a NumberModulus
// early during JSTypedLowering.
function bar(x) { return {x}.x % 2; }
bar(undefined); // The % feedback is now NumberOrOddball.
// Now just use the gadget above in a way that only after RETYPE
// in SimplifiedLowering we find out that the `x` is actually in
// Signed32 range (based on taking the SignedSmall feedback on
// the + operator).
function foo(x) {
x = (x | 0) + 1;
return bar(x) | 0;
}
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(1));
assertEquals(1, foo(2));
assertEquals(0, foo(3));
assertEquals(1, foo(4));
assertOptimized(foo);
})();
[turbofan] Unify handling of zeros. Following up on the earlier work regarding redundant Smi checks in https://chromium-review.googlesource.com/c/v8/v8/+/1246181, it was noticed that the handling of the 0 and -0 and how some operations identify these is not really consistent, but was still rather ad-hoc. This change tries to unify the handling a bit by making sure that all number comparisons generally pass truncations that identify zeros, since for the number comparisons in JavaScript there's no difference between 0 and -0. In the same spirit NumberAbs and NumberToBoolean should also pass these truncations, since they also don't care about the differences between 0 and -0. Adjust NumberCeil, NumberFloor, NumberTrunc, NumberMin and NumberMax to pass along any incoming kIdentifiesZeros truncation, since these operations also don't really care whether the inputs can be -0 if the use nodes don't care. Also utilize the kIdentifiesZeros truncation for NumberModulus with Signed32 inputs, because it's kind of common to do something like `x % 2 === 0`, where it doesn't really matter whether `x % 2` would eventually produce a negative zero (since that would still be considered true for the sake of the comparison). This also adds a whole lot of tests to ensure that not only are these optimizations correct, but also that we do indeed perform them. Drive-by-fix: The `NumberAbs(x)` would incorrectly lower to just `x` for PositiveIntegerOrMinusZeroOrNaN inputs, which was obviously wrong in case of -0. This was fixed as well, and an appropriate test was added. The reason for the unification is that with the introduction of Word64 for CheckBounds (which is necessary to support large TypedArrays and DataViews) we can no longer safely pass Word32 truncations for the interesting cases, since the index might be outside the Signed32 or Unsigned32 ranges, but we still identify 0 and -0 for the sake of the bounds check, and so it's important that this is handled consistently to not regress performance on TypedArrays and DataViews accesses. Bug: v8:8015, v8:8178 Change-Id: Ia1d32f1b726754cea1e5793105d9423d84a6393a Reviewed-on: https://chromium-review.googlesource.com/1246172 Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#56325}
2018-09-26 20:14:42 +00:00
// Test that NumberModulus works in the case where TurboFan
// can infer that the output is Signed32 \/ MinusZero, and
// there's a truncation on the result that identifies zeros
// (via the SpeculativeNumberEqual).
(function() {
// We need a separately polluted % with NumberOrOddball feedback.
function bar(x) { return x % 2; }
bar(undefined); // The % feedback is now NumberOrOddball.
// Now we just use the gadget above on an `x` that is known
// to be in Signed32 range and compare it to 0, which passes
// a truncation that identifies zeros.
function foo(x) {
if (bar(x | 0) == 0) return 0;
return 1;
}
assertEquals(0, foo(2));
assertEquals(1, foo(1));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(2));
assertEquals(1, foo(1));
assertOptimized(foo);
// Now `foo` should stay optimized even if `x % 2` would
// produce -0, aka when we pass a negative value for `x`.
assertEquals(0, foo(-2));
assertEquals(1, foo(-1));
assertOptimized(foo);
})();
// Test that CheckedInt32Mod handles the slow-path (when
// the left hand side is negative) correctly.
(function() {
// We need a SpeculativeNumberModulus with SignedSmall feedback.
function foo(x, y) {
return x % y;
}
assertEquals(0, foo(2, 1));
assertEquals(0, foo(2, 2));
assertEquals(-1, foo(-3, 2));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(2, 1));
assertEquals(0, foo(2, 2));
assertEquals(-1, foo(-3, 2));
assertOptimized(foo);
// Now `foo` should deoptimize if the result is -0.
assertEquals(-0, foo(-2, 2));
assertUnoptimized(foo);
})();