Skip to content

Commit ddbb7d7

Browse files
BridgeARdanbev
authored andcommitted
deps: cherry-pick 56f6a76 from upstream V8
Original commit message: [turbofan] Fix -0 check for subnormals. Previously we'd check `x` for -0 by testing `(1.0 / x) == -Infinity`, but this will yield the wrong results when `x` is a subnormal, i.e. really close to 0. In CSA we already perform bit checks to test for -0, so teach TurboFan to do the same for comparisons to -0 (via `Object.is`). We introduce a new NumberIsMinusZero simplified operator to handle the case where SimplifiedLowering already knows that the input is a number. Bug: chromium:903043, v8:6882 Change-Id: I0cb7c568029b461a92fc183104d5f359b4bfe7f4 Reviewed-on: https://chromium-review.googlesource.com/c/1328802 Commit-Queue: Benedikt Meurer <[email protected]> Reviewed-by: Sigurd Schneider <[email protected]> Cr-Commit-Position: refs/heads/master@{#57382} PR-URL: #25269 Refs: v8/v8@56f6a76 Fixes: #25268 Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Ujjwal Sharma <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e54d11e commit ddbb7d7

10 files changed

+100
-16
lines changed

common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
# Reset this number to 0 on major V8 upgrades.
4040
# Increment by one for each non-official patch applied to deps/v8.
41-
'v8_embedder_string': '-node.8',
41+
'v8_embedder_string': '-node.9',
4242

4343
##### V8 defaults for Node.js #####
4444

deps/v8/src/compiler/effect-control-linearizer.cc

+43-4
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
797797
case IrOpcode::kObjectIsMinusZero:
798798
result = LowerObjectIsMinusZero(node);
799799
break;
800+
case IrOpcode::kNumberIsMinusZero:
801+
result = LowerNumberIsMinusZero(node);
802+
break;
800803
case IrOpcode::kObjectIsNaN:
801804
result = LowerObjectIsNaN(node);
802805
break;
@@ -2543,6 +2546,14 @@ Node* EffectControlLinearizer::LowerObjectIsSafeInteger(Node* node) {
25432546
return done.PhiAt(0);
25442547
}
25452548

2549+
namespace {
2550+
2551+
const int64_t kMinusZeroBits = bit_cast<int64_t>(-0.0);
2552+
const int32_t kMinusZeroLoBits = static_cast<int32_t>(kMinusZeroBits);
2553+
const int32_t kMinusZeroHiBits = static_cast<int32_t>(kMinusZeroBits >> 32);
2554+
2555+
} // namespace
2556+
25462557
Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) {
25472558
Node* value = node->InputAt(0);
25482559
Node* zero = __ Int32Constant(0);
@@ -2559,15 +2570,43 @@ Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) {
25592570

25602571
// Check if {value} contains -0.
25612572
Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
2562-
__ Goto(&done,
2563-
__ Float64Equal(
2564-
__ Float64Div(__ Float64Constant(1.0), value_value),
2565-
__ Float64Constant(-std::numeric_limits<double>::infinity())));
2573+
if (machine()->Is64()) {
2574+
Node* value64 = __ BitcastFloat64ToInt64(value_value);
2575+
__ Goto(&done, __ Word64Equal(value64, __ Int64Constant(kMinusZeroBits)));
2576+
} else {
2577+
Node* value_lo = __ Float64ExtractLowWord32(value_value);
2578+
__ GotoIfNot(__ Word32Equal(value_lo, __ Int32Constant(kMinusZeroLoBits)),
2579+
&done, zero);
2580+
Node* value_hi = __ Float64ExtractHighWord32(value_value);
2581+
__ Goto(&done,
2582+
__ Word32Equal(value_hi, __ Int32Constant(kMinusZeroHiBits)));
2583+
}
25662584

25672585
__ Bind(&done);
25682586
return done.PhiAt(0);
25692587
}
25702588

2589+
Node* EffectControlLinearizer::LowerNumberIsMinusZero(Node* node) {
2590+
Node* value = node->InputAt(0);
2591+
2592+
if (machine()->Is64()) {
2593+
Node* value64 = __ BitcastFloat64ToInt64(value);
2594+
return __ Word64Equal(value64, __ Int64Constant(kMinusZeroBits));
2595+
} else {
2596+
auto done = __ MakeLabel(MachineRepresentation::kBit);
2597+
2598+
Node* value_lo = __ Float64ExtractLowWord32(value);
2599+
__ GotoIfNot(__ Word32Equal(value_lo, __ Int32Constant(kMinusZeroLoBits)),
2600+
&done, __ Int32Constant(0));
2601+
Node* value_hi = __ Float64ExtractHighWord32(value);
2602+
__ Goto(&done,
2603+
__ Word32Equal(value_hi, __ Int32Constant(kMinusZeroHiBits)));
2604+
2605+
__ Bind(&done);
2606+
return done.PhiAt(0);
2607+
}
2608+
}
2609+
25712610
Node* EffectControlLinearizer::LowerObjectIsNaN(Node* node) {
25722611
Node* value = node->InputAt(0);
25732612
Node* zero = __ Int32Constant(0);

deps/v8/src/compiler/effect-control-linearizer.h

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
106106
Node* LowerObjectIsConstructor(Node* node);
107107
Node* LowerObjectIsDetectableCallable(Node* node);
108108
Node* LowerObjectIsMinusZero(Node* node);
109+
Node* LowerNumberIsMinusZero(Node* node);
109110
Node* LowerObjectIsNaN(Node* node);
110111
Node* LowerNumberIsNaN(Node* node);
111112
Node* LowerObjectIsNonCallable(Node* node);

deps/v8/src/compiler/opcodes.h

+1
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@
417417
V(ObjectIsConstructor) \
418418
V(ObjectIsDetectableCallable) \
419419
V(ObjectIsMinusZero) \
420+
V(NumberIsMinusZero) \
420421
V(ObjectIsNaN) \
421422
V(NumberIsNaN) \
422423
V(ObjectIsNonCallable) \

deps/v8/src/compiler/simplified-lowering.cc

+1-11
Original file line numberDiff line numberDiff line change
@@ -3008,17 +3008,7 @@ class RepresentationSelector {
30083008
VisitUnop(node, UseInfo::TruncatingFloat64(),
30093009
MachineRepresentation::kBit);
30103010
if (lower()) {
3011-
// ObjectIsMinusZero(x:kRepFloat64)
3012-
// => Float64Equal(Float64Div(1.0,x),-Infinity)
3013-
Node* const input = node->InputAt(0);
3014-
node->ReplaceInput(
3015-
0, jsgraph_->graph()->NewNode(
3016-
lowering->machine()->Float64Div(),
3017-
lowering->jsgraph()->Float64Constant(1.0), input));
3018-
node->AppendInput(jsgraph_->zone(),
3019-
jsgraph_->Float64Constant(
3020-
-std::numeric_limits<double>::infinity()));
3021-
NodeProperties::ChangeOp(node, lowering->machine()->Float64Equal());
3011+
NodeProperties::ChangeOp(node, simplified()->NumberIsMinusZero());
30223012
}
30233013
} else {
30243014
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);

deps/v8/src/compiler/simplified-operator.cc

+1
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
745745
V(ObjectIsConstructor, Operator::kNoProperties, 1, 0) \
746746
V(ObjectIsDetectableCallable, Operator::kNoProperties, 1, 0) \
747747
V(ObjectIsMinusZero, Operator::kNoProperties, 1, 0) \
748+
V(NumberIsMinusZero, Operator::kNoProperties, 1, 0) \
748749
V(ObjectIsNaN, Operator::kNoProperties, 1, 0) \
749750
V(NumberIsNaN, Operator::kNoProperties, 1, 0) \
750751
V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \

deps/v8/src/compiler/simplified-operator.h

+1
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
719719
const Operator* ObjectIsConstructor();
720720
const Operator* ObjectIsDetectableCallable();
721721
const Operator* ObjectIsMinusZero();
722+
const Operator* NumberIsMinusZero();
722723
const Operator* ObjectIsNaN();
723724
const Operator* NumberIsNaN();
724725
const Operator* ObjectIsNonCallable();

deps/v8/src/compiler/typer.cc

+11
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ class Typer::Visitor : public Reducer {
290290
static Type ObjectIsConstructor(Type, Typer*);
291291
static Type ObjectIsDetectableCallable(Type, Typer*);
292292
static Type ObjectIsMinusZero(Type, Typer*);
293+
static Type NumberIsMinusZero(Type, Typer*);
293294
static Type ObjectIsNaN(Type, Typer*);
294295
static Type NumberIsNaN(Type, Typer*);
295296
static Type ObjectIsNonCallable(Type, Typer*);
@@ -597,6 +598,12 @@ Type Typer::Visitor::ObjectIsMinusZero(Type type, Typer* t) {
597598
return Type::Boolean();
598599
}
599600

601+
Type Typer::Visitor::NumberIsMinusZero(Type type, Typer* t) {
602+
if (type.Is(Type::MinusZero())) return t->singleton_true_;
603+
if (!type.Maybe(Type::MinusZero())) return t->singleton_false_;
604+
return Type::Boolean();
605+
}
606+
600607
Type Typer::Visitor::ObjectIsNaN(Type type, Typer* t) {
601608
if (type.Is(Type::NaN())) return t->singleton_true_;
602609
if (!type.Maybe(Type::NaN())) return t->singleton_false_;
@@ -2104,6 +2111,10 @@ Type Typer::Visitor::TypeObjectIsMinusZero(Node* node) {
21042111
return TypeUnaryOp(node, ObjectIsMinusZero);
21052112
}
21062113

2114+
Type Typer::Visitor::TypeNumberIsMinusZero(Node* node) {
2115+
return TypeUnaryOp(node, NumberIsMinusZero);
2116+
}
2117+
21072118
Type Typer::Visitor::TypeNumberIsFloat64Hole(Node* node) {
21082119
return Type::Boolean();
21092120
}

deps/v8/src/compiler/verifier.cc

+1
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
11881188
CheckValueInputIs(node, 0, Type::Number());
11891189
CheckTypeIs(node, Type::Boolean());
11901190
break;
1191+
case IrOpcode::kNumberIsMinusZero:
11911192
case IrOpcode::kNumberIsNaN:
11921193
CheckValueInputIs(node, 0, Type::Number());
11931194
CheckTypeIs(node, Type::Boolean());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --allow-natives-syntax
6+
7+
(function() {
8+
function foo() {
9+
const x = 1e-1;
10+
return Object.is(-0, x * (-1e-308));
11+
}
12+
13+
assertFalse(foo());
14+
assertFalse(foo());
15+
%OptimizeFunctionOnNextCall(foo);
16+
assertFalse(foo());
17+
})();
18+
19+
(function() {
20+
function foo(x) {
21+
return Object.is(-0, x * (-1e-308));
22+
}
23+
24+
assertFalse(foo(1e-1));
25+
assertFalse(foo(1e-1));
26+
%OptimizeFunctionOnNextCall(foo);
27+
assertFalse(foo(1e-1));
28+
})();
29+
30+
(function() {
31+
function foo(x) {
32+
return Object.is(-0, x);
33+
}
34+
35+
assertFalse(foo(1e-1 * (-1e-308)));
36+
assertFalse(foo(1e-1 * (-1e-308)));
37+
%OptimizeFunctionOnNextCall(foo);
38+
assertFalse(foo(1e-1 * (-1e-308)));
39+
})();

0 commit comments

Comments
 (0)