Commit c4ada3de authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Propagate kIdentifyZeros correctly for modulus.

For NumberModulus and SpeculativeNumberModulus there's no observable
difference between 0 and -0 for the right hand side, since both of them
result in NaN (in general the sign of the right hand side is ignored
for modulus in JavaScript). For the left hand side we can just propagate
the zero identification part of the truncation, since we only care about
-0 on the left hand side if the use nodes care about -0 too.

This further improves the Kraken/audio-oscillator test from around 67ms
to 64ms.

Bug: v8:8015, v8:8178
Change-Id: I1f51d42f7df08aaa28a9b0ddd3177df6b76be98c
Reviewed-on: https://chromium-review.googlesource.com/c/1260024
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56372}
parent 1d2a8e96
......@@ -1440,17 +1440,24 @@ class RepresentationSelector {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
// If the result is truncated, we only need to check the inputs.
// For the left hand side we just propagate the identify zeros
// mode of the {truncation}; and for modulus the sign of the
// right hand side doesn't matter anyways, so in particular there's
// no observable difference between a 0 and a -0 then.
UseInfo const lhs_use = CheckedUseInfoAsWord32FromHint(
hint, VectorSlotPair(), truncation.identify_zeros());
UseInfo const rhs_use = CheckedUseInfoAsWord32FromHint(
hint, VectorSlotPair(), kIdentifyZeros);
if (truncation.IsUsedAsWord32()) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32);
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
} else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Unsigned32());
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
Type::Unsigned32());
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
} else {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
Type::Signed32());
if (lower()) ChangeToInt32OverflowOp(node);
}
return;
......@@ -1460,10 +1467,7 @@ class RepresentationSelector {
TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
(truncation.IsUsedAsWord32() ||
NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
// We can only promise Float64 truncation here, as the decision is
// based on the feedback types of the inputs.
VisitBinop(node,
UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Number());
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
return;
......@@ -1472,19 +1476,23 @@ class RepresentationSelector {
TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
(truncation.IsUsedAsWord32() ||
NodeProperties::GetType(node).Is(Type::Signed32()))) {
// We can only promise Float64 truncation here, as the decision is
// based on the feedback types of the inputs.
VisitBinop(node,
UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Number());
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
return;
}
// default case => Float64Mod
VisitBinop(node,
UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
VectorSlotPair()),
MachineRepresentation::kFloat64, Type::Number());
// For the left hand side we just propagate the identify zeros
// mode of the {truncation}; and for modulus the sign of the
// right hand side doesn't matter anyways, so in particular there's
// no observable difference between a 0 and a -0 then.
UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
truncation.identify_zeros(), VectorSlotPair());
UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
kIdentifyZeros, VectorSlotPair());
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
Type::Number());
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
}
......@@ -2027,7 +2035,14 @@ class RepresentationSelector {
return;
}
// => Float64Mod
VisitFloat64Binop(node);
// For the left hand side we just propagate the identify zeros
// mode of the {truncation}; and for modulus the sign of the
// right hand side doesn't matter anyways, so in particular there's
// no observable difference between a 0 and a -0 then.
UseInfo const lhs_use =
UseInfo::TruncatingFloat64(truncation.identify_zeros());
UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
}
......
......@@ -176,3 +176,81 @@
assertEquals(-0, foo(-2, 2));
assertUnoptimized(foo);
})();
// Test that NumberModulus passes kIdentifiesZero to the
// left hand side input when the result doesn't care about
// 0 vs -0, even when the inputs are outside Signed32.
(function() {
function foo(x) {
return (x * -2) % (2 ** 32) === 0;
}
assertFalse(foo(2));
assertFalse(foo(1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(2));
assertFalse(foo(1));
// Now `foo` should stay optimized even if `x * -2` would
// produce -0, aka when we pass a zero value for `x`.
assertTrue(foo(0));
assertOptimized(foo);
})();
// Test that NumberModulus passes kIdentifiesZero to the
// right hand side input, even when the inputs are outside
// the Signed32 range.
(function() {
function foo(x) {
return (2 ** 32) % (x * -2);
}
assertEquals(0, foo(1));
assertEquals(0, foo(1));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(1));
// Now `foo` should stay optimized even if `x * -2` would
// produce -0, aka when we pass a zero value for `x`.
assertEquals(NaN, foo(0));
assertOptimized(foo);
})();
// Test that SpeculativeNumberModulus passes kIdentifiesZero
// to the right hand side input, even when feedback is consumed.
(function() {
function foo(x, y) {
return (x % (y * -2)) | 0;
}
assertEquals(0, foo(2, 1));
assertEquals(-1, foo(-3, 1));
%OptimizeFunctionOnNextCall(foo);
assertEquals(0, foo(2, 1));
assertEquals(-1, foo(-3, 1));
assertOptimized(foo);
// Now `foo` should stay optimized even if `y * -2` would
// produce -0, aka when we pass a zero value for `y`.
assertEquals(0, foo(2, 0));
assertOptimized(foo);
})();
// Test that SpeculativeNumberModulus passes kIdentifiesZero
// to the left hand side input, even when feedback is consumed.
(function() {
function foo(x, y) {
return ((x * -2) % y) | 0;
}
assertEquals(-2, foo(1, 3));
assertEquals(-2, foo(1, 3));
%OptimizeFunctionOnNextCall(foo);
assertEquals(-2, foo(1, 3));
assertOptimized(foo);
// Now `foo` should stay optimized even if `x * -2` would
// produce -0, aka when we pass a zero value for `x`.
assertEquals(0, foo(0, 2));
assertOptimized(foo);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment