Commit 8a94f074 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Move Number.isInteger to JSCallReducer

This also adds ObjectIsInteger and NumberIsInteger
operators.

Bug: v8:7340, v8:7250
Change-Id: I8067276d12c8532931f90e6397f8435362c2f9af
Reviewed-on: https://chromium-review.googlesource.com/951602Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51991}
parent 163f8069
...@@ -872,6 +872,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -872,6 +872,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kObjectIsFiniteNumber: case IrOpcode::kObjectIsFiniteNumber:
result = LowerObjectIsFiniteNumber(node); result = LowerObjectIsFiniteNumber(node);
break; break;
case IrOpcode::kNumberIsInteger:
result = LowerNumberIsInteger(node);
break;
case IrOpcode::kObjectIsInteger:
result = LowerObjectIsInteger(node);
break;
case IrOpcode::kCheckFloat64Hole: case IrOpcode::kCheckFloat64Hole:
result = LowerCheckFloat64Hole(node, frame_state); result = LowerCheckFloat64Hole(node, frame_state);
break; break;
...@@ -2169,15 +2175,15 @@ Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) { ...@@ -2169,15 +2175,15 @@ Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) {
auto done = __ MakeLabel(MachineRepresentation::kBit); auto done = __ MakeLabel(MachineRepresentation::kBit);
// Check if {value} is a Smi. // Check if {object} is a Smi.
__ GotoIf(ObjectIsSmi(object), &done, one); __ GotoIf(ObjectIsSmi(object), &done, one);
// Check if {value} is a HeapNumber. // Check if {object} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), object); Node* value_map = __ LoadField(AccessBuilder::ForMap(), object);
__ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done, __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
zero); zero);
// Value is a HeapNumber. // {object} is a HeapNumber.
Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object); Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object);
Node* diff = __ Float64Sub(value, value); Node* diff = __ Float64Sub(value, value);
Node* check = __ Float64Equal(diff, diff); Node* check = __ Float64Equal(diff, diff);
...@@ -2187,6 +2193,40 @@ Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) { ...@@ -2187,6 +2193,40 @@ Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) {
return done.PhiAt(0); return done.PhiAt(0);
} }
Node* EffectControlLinearizer::LowerNumberIsInteger(Node* node) {
Node* number = node->InputAt(0);
Node* trunc = BuildFloat64RoundTruncate(number);
Node* diff = __ Float64Sub(number, trunc);
Node* check = __ Float64Equal(diff, __ Float64Constant(0));
return check;
}
Node* EffectControlLinearizer::LowerObjectIsInteger(Node* node) {
Node* object = node->InputAt(0);
Node* zero = __ Int32Constant(0);
Node* one = __ Int32Constant(1);
auto done = __ MakeLabel(MachineRepresentation::kBit);
// Check if {object} is a Smi.
__ GotoIf(ObjectIsSmi(object), &done, one);
// Check if {object} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), object);
__ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// {object} is a HeapNumber.
Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), object);
Node* trunc = BuildFloat64RoundTruncate(value);
Node* diff = __ Float64Sub(value, trunc);
Node* check = __ Float64Equal(diff, __ Float64Constant(0));
__ Goto(&done, check);
__ Bind(&done);
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) { Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) {
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
Node* zero = __ Int32Constant(0); Node* zero = __ Int32Constant(0);
...@@ -4218,9 +4258,8 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundUp(Node* node) { ...@@ -4218,9 +4258,8 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundUp(Node* node) {
} }
Node* EffectControlLinearizer::BuildFloat64RoundDown(Node* value) { Node* EffectControlLinearizer::BuildFloat64RoundDown(Node* value) {
Node* round_down = __ Float64RoundDown(value); if (machine()->Float64RoundDown().IsSupported()) {
if (round_down != nullptr) { return __ Float64RoundDown(value);
return round_down;
} }
Node* const input = value; Node* const input = value;
...@@ -4364,14 +4403,10 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node) { ...@@ -4364,14 +4403,10 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node) {
return Just(done.PhiAt(0)); return Just(done.PhiAt(0));
} }
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) { Node* EffectControlLinearizer::BuildFloat64RoundTruncate(Node* input) {
// Nothing to be done if a fast hardware instruction is available.
if (machine()->Float64RoundTruncate().IsSupported()) { if (machine()->Float64RoundTruncate().IsSupported()) {
return Nothing<Node*>(); return __ Float64RoundTruncate(input);
} }
Node* const input = node->InputAt(0);
// General case for trunc. // General case for trunc.
// //
// if 0.0 < input then // if 0.0 < input then
...@@ -4452,7 +4487,17 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) { ...@@ -4452,7 +4487,17 @@ Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) {
__ Goto(&done, input); __ Goto(&done, input);
} }
__ Bind(&done); __ Bind(&done);
return Just(done.PhiAt(0)); return done.PhiAt(0);
}
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) {
// Nothing to be done if a fast hardware instruction is available.
if (machine()->Float64RoundTruncate().IsSupported()) {
return Nothing<Node*>();
}
Node* const input = node->InputAt(0);
return Just(BuildFloat64RoundTruncate(input));
} }
Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) { Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) {
......
...@@ -107,6 +107,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -107,6 +107,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerNumberIsFloat64Hole(Node* node); Node* LowerNumberIsFloat64Hole(Node* node);
Node* LowerNumberIsFinite(Node* node); Node* LowerNumberIsFinite(Node* node);
Node* LowerObjectIsFiniteNumber(Node* node); Node* LowerObjectIsFiniteNumber(Node* node);
Node* LowerNumberIsInteger(Node* node);
Node* LowerObjectIsInteger(Node* node);
Node* LowerArgumentsFrame(Node* node); Node* LowerArgumentsFrame(Node* node);
Node* LowerArgumentsLength(Node* node); Node* LowerArgumentsLength(Node* node);
Node* LowerNewDoubleElements(Node* node); Node* LowerNewDoubleElements(Node* node);
...@@ -169,6 +171,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -169,6 +171,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* value, Node* value,
Node* frame_state); Node* frame_state);
Node* BuildFloat64RoundDown(Node* value); Node* BuildFloat64RoundDown(Node* value);
Node* BuildFloat64RoundTruncate(Node* input);
Node* ComputeIntegerHash(Node* value); Node* ComputeIntegerHash(Node* value);
Node* LowerStringComparison(Callable const& callable, Node* node); Node* LowerStringComparison(Callable const& callable, Node* node);
Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind); Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind);
......
...@@ -86,10 +86,13 @@ CHECKED_ASSEMBLER_MACH_BINOP_LIST(CHECKED_BINOP_DEF) ...@@ -86,10 +86,13 @@ CHECKED_ASSEMBLER_MACH_BINOP_LIST(CHECKED_BINOP_DEF)
#undef CHECKED_BINOP_DEF #undef CHECKED_BINOP_DEF
Node* GraphAssembler::Float64RoundDown(Node* value) { Node* GraphAssembler::Float64RoundDown(Node* value) {
if (machine()->Float64RoundDown().IsSupported()) { CHECK(machine()->Float64RoundDown().IsSupported());
return graph()->NewNode(machine()->Float64RoundDown().op(), value); return graph()->NewNode(machine()->Float64RoundDown().op(), value);
} }
return nullptr;
Node* GraphAssembler::Float64RoundTruncate(Node* value) {
CHECK(machine()->Float64RoundTruncate().IsSupported());
return graph()->NewNode(machine()->Float64RoundTruncate().op(), value);
} }
Node* GraphAssembler::Projection(int index, Node* value) { Node* GraphAssembler::Projection(int index, Node* value) {
......
...@@ -196,6 +196,7 @@ class GraphAssembler { ...@@ -196,6 +196,7 @@ class GraphAssembler {
Node* Unreachable(); Node* Unreachable();
Node* Float64RoundDown(Node* value); Node* Float64RoundDown(Node* value);
Node* Float64RoundTruncate(Node* value);
Node* ToNumber(Node* value); Node* ToNumber(Node* value);
Node* BitcastWordToTagged(Node* value); Node* BitcastWordToTagged(Node* value);
......
...@@ -754,22 +754,6 @@ Reduction JSBuiltinReducer::ReduceMapHas(Node* node) { ...@@ -754,22 +754,6 @@ Reduction JSBuiltinReducer::ReduceMapHas(Node* node) {
return Replace(value); return Replace(value);
} }
// ES6 section 20.1.2.3 Number.isInteger ( number )
Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0)
// where x' = NumberTrunc(x)
Node* input = r.GetJSCallInput(0);
Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input);
Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc);
Node* value = graph()->NewNode(simplified()->NumberEqual(), diff,
jsgraph()->ZeroConstant());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.1.2.4 Number.isNaN ( number ) // ES6 section 20.1.2.4 Number.isNaN ( number )
Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) { Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
...@@ -982,8 +966,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -982,8 +966,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceCollectionIteratorNext( return ReduceCollectionIteratorNext(
node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(), node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(),
FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE); FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE);
case kNumberIsInteger:
reduction = ReduceNumberIsInteger(node);
break; break;
case kNumberIsNaN: case kNumberIsNaN:
reduction = ReduceNumberIsNaN(node); reduction = ReduceNumberIsNaN(node);
......
...@@ -57,7 +57,6 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final ...@@ -57,7 +57,6 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction ReduceGlobalIsNaN(Node* node); Reduction ReduceGlobalIsNaN(Node* node);
Reduction ReduceMapHas(Node* node); Reduction ReduceMapHas(Node* node);
Reduction ReduceMapGet(Node* node); Reduction ReduceMapGet(Node* node);
Reduction ReduceNumberIsInteger(Node* node);
Reduction ReduceNumberIsNaN(Node* node); Reduction ReduceNumberIsNaN(Node* node);
Reduction ReduceNumberIsSafeInteger(Node* node); Reduction ReduceNumberIsSafeInteger(Node* node);
Reduction ReduceNumberParseInt(Node* node); Reduction ReduceNumberParseInt(Node* node);
......
...@@ -3426,6 +3426,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node, ...@@ -3426,6 +3426,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
jsgraph()->Constant(V8_INFINITY)); jsgraph()->Constant(V8_INFINITY));
case Builtins::kNumberIsFinite: case Builtins::kNumberIsFinite:
return ReduceNumberIsFinite(node); return ReduceNumberIsFinite(node);
case Builtins::kNumberIsInteger:
return ReduceNumberIsInteger(node);
case Builtins::kReturnReceiver: case Builtins::kReturnReceiver:
return ReduceReturnReceiver(node); return ReduceReturnReceiver(node);
case Builtins::kStringPrototypeIndexOf: case Builtins::kStringPrototypeIndexOf:
...@@ -5894,6 +5896,19 @@ Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) { ...@@ -5894,6 +5896,19 @@ Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) {
return Replace(value); return Replace(value);
} }
// ES #sec-number.isfinite
Reduction JSCallReducer::ReduceNumberIsInteger(Node* node) {
if (node->op()->ValueInputCount() < 3) {
Node* value = jsgraph()->FalseConstant();
ReplaceWithValue(node, value);
return Replace(value);
}
Node* input = NodeProperties::GetValueInput(node, 2);
Node* value = graph()->NewNode(simplified()->ObjectIsInteger(), input);
ReplaceWithValue(node, value);
return Replace(value);
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
......
...@@ -151,6 +151,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer { ...@@ -151,6 +151,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceMathMinMax(Node* node, const Operator* op, Node* empty_value); Reduction ReduceMathMinMax(Node* node, const Operator* op, Node* empty_value);
Reduction ReduceNumberIsFinite(Node* node); Reduction ReduceNumberIsFinite(Node* node);
Reduction ReduceNumberIsInteger(Node* node);
// Returns the updated {to} node, and updates control and effect along the // Returns the updated {to} node, and updates control and effect along the
// way. // way.
......
...@@ -386,6 +386,8 @@ ...@@ -386,6 +386,8 @@
V(NumberIsFloat64Hole) \ V(NumberIsFloat64Hole) \
V(NumberIsFinite) \ V(NumberIsFinite) \
V(ObjectIsFiniteNumber) \ V(ObjectIsFiniteNumber) \
V(NumberIsInteger) \
V(ObjectIsInteger) \
V(ObjectIsArrayBufferView) \ V(ObjectIsArrayBufferView) \
V(ObjectIsBigInt) \ V(ObjectIsBigInt) \
V(ObjectIsCallable) \ V(ObjectIsCallable) \
......
...@@ -2771,6 +2771,36 @@ class RepresentationSelector { ...@@ -2771,6 +2771,36 @@ class RepresentationSelector {
case IrOpcode::kNumberIsFinite: { case IrOpcode::kNumberIsFinite: {
UNREACHABLE(); UNREACHABLE();
} }
case IrOpcode::kObjectIsInteger: {
Type* const input_type = GetUpperBound(node->InputAt(0));
// Ranges are always integers.
if (input_type->IsRange()) {
VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
if (lower()) {
DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
}
} else if (!input_type->Maybe(Type::Number())) {
VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
if (lower()) {
DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
}
} else if (input_type->Is(Type::Number())) {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kBit);
if (lower()) {
NodeProperties::ChangeOp(node,
lowering->simplified()->NumberIsInteger());
}
} else {
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
}
return;
}
case IrOpcode::kNumberIsInteger: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kBit);
return;
}
case IrOpcode::kObjectIsMinusZero: { case IrOpcode::kObjectIsMinusZero: {
Type* const input_type = GetUpperBound(node->InputAt(0)); Type* const input_type = GetUpperBound(node->InputAt(0));
if (input_type->Is(Type::MinusZero())) { if (input_type->Is(Type::MinusZero())) {
......
...@@ -711,6 +711,8 @@ bool operator==(CheckMinusZeroParameters const& lhs, ...@@ -711,6 +711,8 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(NumberIsFloat64Hole, Operator::kNoProperties, 1, 0) \ V(NumberIsFloat64Hole, Operator::kNoProperties, 1, 0) \
V(NumberIsFinite, Operator::kNoProperties, 1, 0) \ V(NumberIsFinite, Operator::kNoProperties, 1, 0) \
V(ObjectIsFiniteNumber, Operator::kNoProperties, 1, 0) \ V(ObjectIsFiniteNumber, Operator::kNoProperties, 1, 0) \
V(NumberIsInteger, Operator::kNoProperties, 1, 0) \
V(ObjectIsInteger, Operator::kNoProperties, 1, 0) \
V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \ V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \
V(SameValue, Operator::kCommutative, 2, 0) \ V(SameValue, Operator::kCommutative, 2, 0) \
V(ReferenceEqual, Operator::kCommutative, 2, 0) \ V(ReferenceEqual, Operator::kCommutative, 2, 0) \
......
...@@ -624,6 +624,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -624,6 +624,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* NumberIsFloat64Hole(); const Operator* NumberIsFloat64Hole();
const Operator* NumberIsFinite(); const Operator* NumberIsFinite();
const Operator* ObjectIsFiniteNumber(); const Operator* ObjectIsFiniteNumber();
const Operator* NumberIsInteger();
const Operator* ObjectIsInteger();
const Operator* ArgumentsFrame(); const Operator* ArgumentsFrame();
const Operator* ArgumentsLength(int formal_parameter_count, const Operator* ArgumentsLength(int formal_parameter_count,
......
...@@ -2182,6 +2182,12 @@ Type* Typer::Visitor::TypeObjectIsFiniteNumber(Node* node) { ...@@ -2182,6 +2182,12 @@ Type* Typer::Visitor::TypeObjectIsFiniteNumber(Node* node) {
return Type::Boolean(); return Type::Boolean();
} }
Type* Typer::Visitor::TypeNumberIsInteger(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeObjectIsInteger(Node* node) {
return Type::Boolean();
}
Type* Typer::Visitor::TypeObjectIsNaN(Node* node) { Type* Typer::Visitor::TypeObjectIsNaN(Node* node) {
return TypeUnaryOp(node, ObjectIsNaN); return TypeUnaryOp(node, ObjectIsNaN);
} }
......
...@@ -1174,6 +1174,14 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -1174,6 +1174,14 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::Any()); CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::Boolean()); CheckTypeIs(node, Type::Boolean());
break; break;
case IrOpcode::kNumberIsInteger:
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kObjectIsInteger:
CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kFindOrderedHashMapEntry: case IrOpcode::kFindOrderedHashMapEntry:
CheckValueInputIs(node, 0, Type::Any()); CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::SignedSmall()); CheckTypeIs(node, Type::SignedSmall());
......
...@@ -12,6 +12,9 @@ function test(f) { ...@@ -12,6 +12,9 @@ function test(f) {
assertTrue(f(Number.MIN_SAFE_INTEGER - 13)); assertTrue(f(Number.MIN_SAFE_INTEGER - 13));
assertTrue(f(Number.MAX_SAFE_INTEGER)); assertTrue(f(Number.MAX_SAFE_INTEGER));
assertTrue(f(Number.MAX_SAFE_INTEGER + 23)); assertTrue(f(Number.MAX_SAFE_INTEGER + 23));
assertTrue(f(0));
assertTrue(f(-1));
assertTrue(f(123456));
assertFalse(f(Number.NaN)); assertFalse(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY)); assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY)); assertFalse(f(Number.NEGATIVE_INFINITY));
...@@ -28,3 +31,32 @@ test(f); ...@@ -28,3 +31,32 @@ test(f);
test(f); test(f);
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
test(f); test(f);
function test2(f) {
assertTrue(f(0));
assertFalse(f(Number.MIN_VALUE));
assertTrue(f(Number.MAX_VALUE));
assertTrue(f(Number.MIN_SAFE_INTEGER));
assertTrue(f(Number.MIN_SAFE_INTEGER - 13));
assertTrue(f(Number.MAX_SAFE_INTEGER));
assertTrue(f(Number.MAX_SAFE_INTEGER + 23));
assertTrue(f(0));
assertTrue(f(-1));
assertTrue(f(123456));
assertFalse(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY));
assertFalse(f(1 / 0));
assertFalse(f(-1 / 0));
assertFalse(f(Number.EPSILON));
}
function f2(x) {
return Number.isInteger(x);
}
test2(f2);
test2(f2);
%OptimizeFunctionOnNextCall(f2);
test2(f2);
...@@ -195,31 +195,6 @@ TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithPlainPrimitive) { ...@@ -195,31 +195,6 @@ TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithPlainPrimitive) {
IsPlainPrimitiveToNumber(p0)))); IsPlainPrimitiveToNumber(p0))));
} }
// -----------------------------------------------------------------------------
// Number.isInteger
TEST_F(JSBuiltinReducerTest, NumberIsIntegerWithNumber) {
Node* function = NumberFunction("isInteger");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call =
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(),
p0, context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberEqual(IsNumberSubtract(p0, IsNumberTrunc(p0)),
IsNumberConstant(0.0)));
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Number.isNaN // Number.isNaN
......
...@@ -471,6 +471,26 @@ TEST_F(JSCallReducerTest, NumberIsFinite) { ...@@ -471,6 +471,26 @@ TEST_F(JSCallReducerTest, NumberIsFinite) {
EXPECT_THAT(r.replacement(), IsObjectIsFiniteNumber(p0)); EXPECT_THAT(r.replacement(), IsObjectIsFiniteNumber(p0));
} }
// -----------------------------------------------------------------------------
// Number.isInteger
TEST_F(JSCallReducerTest, NumberIsIntegerWithNumber) {
Node* function = NumberFunction("isInteger");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Any(), 0);
Node* call =
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(), p0,
context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsObjectIsInteger(p0));
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -2181,6 +2181,7 @@ IS_UNOP_MATCHER(NumberToInt32) ...@@ -2181,6 +2181,7 @@ IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(PlainPrimitiveToNumber) IS_UNOP_MATCHER(PlainPrimitiveToNumber)
IS_UNOP_MATCHER(ObjectIsFiniteNumber) IS_UNOP_MATCHER(ObjectIsFiniteNumber)
IS_UNOP_MATCHER(ObjectIsInteger)
IS_UNOP_MATCHER(ObjectIsNaN) IS_UNOP_MATCHER(ObjectIsNaN)
IS_UNOP_MATCHER(ObjectIsReceiver) IS_UNOP_MATCHER(ObjectIsReceiver)
IS_UNOP_MATCHER(ObjectIsSmi) IS_UNOP_MATCHER(ObjectIsSmi)
......
...@@ -312,6 +312,7 @@ Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher, ...@@ -312,6 +312,7 @@ Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
const Matcher<Node*>& control_matcher); const Matcher<Node*>& control_matcher);
Matcher<Node*> IsObjectIsFiniteNumber(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsFiniteNumber(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsObjectIsInteger(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsObjectIsNaN(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsNaN(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsObjectIsReceiver(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsReceiver(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsObjectIsSmi(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsSmi(const Matcher<Node*>& value_matcher);
......
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