Commit ed0039a7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Unify the PlainPrimitive as Number treatment.

Now that we have the PlainPrimitiveToNumber operator(s), we can unify
all the places where we expect a number, but can also safely handle any
plain-primitive (via ToNumber truncation).

Drive-by-fix: Also handle Math.min consistently with Math.max.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2064953004
Cr-Commit-Position: refs/heads/master@{#36984}
parent 05a663e6
...@@ -91,41 +91,28 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph) ...@@ -91,41 +91,28 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph)
jsgraph_(jsgraph), jsgraph_(jsgraph),
type_cache_(TypeCache::Get()) {} type_cache_(TypeCache::Get()) {}
// ECMA-262, section 15.8.2.11. // ES6 section 20.2.2.6 Math.atan ( x )
Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchZero()) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.max() -> -Infinity // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
return Replace(jsgraph()->Constant(-V8_INFINITY)); Node* input = ToNumber(r.GetJSCallInput(0));
} Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
if (r.InputsMatchOne(Type::Number())) {
// Math.max(a:number) -> a
return Replace(r.left());
}
if (r.InputsMatchAll(Type::Integral32())) {
// Math.max(a:int32, b:int32, ...)
Node* value = r.GetJSCallInput(0);
for (int i = 1; i < r.GetJSCallArity(); i++) {
Node* const input = r.GetJSCallInput(i);
value = graph()->NewNode(
common()->Select(MachineRepresentation::kNone),
graph()->NewNode(simplified()->NumberLessThan(), input, value), value,
input);
}
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.19 Math.imul ( x, y ) // ES6 section 20.2.2.8 Math.atan2 ( y, x )
Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchTwo(Type::Number(), Type::Number())) { if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
// Math.imul(a:number, b:number) -> NumberImul(NumberToUint32(a), // Math.atan2(a:plain-primitive,
// NumberToUint32(b)) // b:plain-primitive) -> NumberAtan2(ToNumber(a),
Node* a = graph()->NewNode(simplified()->NumberToUint32(), r.left()); // ToNumber(b))
Node* b = graph()->NewNode(simplified()->NumberToUint32(), r.right()); Node* left = ToNumber(r.left());
Node* value = graph()->NewNode(simplified()->NumberImul(), a, b); Node* right = ToNumber(r.right());
Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -134,9 +121,10 @@ Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { ...@@ -134,9 +121,10 @@ Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
// ES6 section 20.2.2.10 Math.ceil ( x ) // ES6 section 20.2.2.10 Math.ceil ( x )
Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.ceil(a:number) -> NumberCeil(a) // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
Node* value = graph()->NewNode(simplified()->NumberCeil(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -145,84 +133,127 @@ Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { ...@@ -145,84 +133,127 @@ Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
// ES6 section 20.2.2.11 Math.clz32 ( x ) // ES6 section 20.2.2.11 Math.clz32 ( x )
Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) { Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Unsigned32())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.clz32(a:unsigned32) -> NumberClz32(a) // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
Node* value = graph()->NewNode(simplified()->NumberClz32(), r.left()); Node* input = ToUint32(r.GetJSCallInput(0));
return Replace(value); Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
}
if (r.InputsMatchOne(Type::Number())) {
// Math.clz32(a:number) -> NumberClz32(NumberToUint32(a))
Node* value = graph()->NewNode(
simplified()->NumberClz32(),
graph()->NewNode(simplified()->NumberToUint32(), r.left()));
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 draft 08-24-14, section 20.2.2.16. // ES6 section 20.2.2.16 Math.floor ( x )
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) { Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.floor(a:number) -> NumberFloor(a) // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
Node* value = graph()->NewNode(simplified()->NumberFloor(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 draft 08-24-14, section 20.2.2.17. // ES6 section 20.2.2.17 Math.fround ( x )
Reduction JSBuiltinReducer::ReduceMathFround(Node* node) { Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::NumberOrUndefined())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.fround(a:number) -> TruncateFloat64ToFloat32(a) // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
Node* value = Node* input = ToNumber(r.GetJSCallInput(0));
graph()->NewNode(machine()->TruncateFloat64ToFloat32(), r.left()); Node* value = graph()->NewNode(simplified()->NumberFround(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.6 Math.atan ( x ) // ES6 section 20.2.2.19 Math.imul ( x, y )
Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) { Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
// Math.atan(a:number) -> NumberAtan(a) // Math.imul(a:plain-primitive,
Node* value = graph()->NewNode(simplified()->NumberAtan(), r.left()); // b:plain-primitive) -> NumberImul(ToUint32(a),
// ToUint32(b))
Node* left = ToUint32(r.left());
Node* right = ToUint32(r.right());
Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.8 Math.atan2 ( y, x ) // ES6 section 20.2.2.20 Math.log ( x )
Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) { Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchTwo(Type::Number(), Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.atan2(a:number, b:number) -> NumberAtan2(a, b) // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
Node* value = Node* input = ToNumber(r.GetJSCallInput(0));
graph()->NewNode(simplified()->NumberAtan2(), r.left(), r.right()); Node* value = graph()->NewNode(simplified()->NumberLog(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.20 Math.log ( x ) // ES6 section 20.2.2.21 Math.log1p ( x )
Reduction JSBuiltinReducer::ReduceMathLog(Node* node) { Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.log(a:number) -> NumberLog(a) // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
Node* value = graph()->NewNode(simplified()->NumberLog(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.21 Math.log1p ( x ) // ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) { Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchZero()) {
// Math.log1p(a:number) -> NumberLog1p(a) // Math.max() -> -Infinity
Node* value = graph()->NewNode(simplified()->NumberLog1p(), r.left()); return Replace(jsgraph()->Constant(-V8_INFINITY));
}
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.max(a:plain-primitive) -> ToNumber(a)
Node* value = ToNumber(r.GetJSCallInput(0));
return Replace(value);
}
if (r.InputsMatchAll(Type::Integral32())) {
// Math.max(a:int32, b:int32, ...)
Node* value = r.GetJSCallInput(0);
for (int i = 1; i < r.GetJSCallArity(); i++) {
Node* const input = r.GetJSCallInput(i);
value = graph()->NewNode(
common()->Select(MachineRepresentation::kNone),
graph()->NewNode(simplified()->NumberLessThan(), input, value), value,
input);
}
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchZero()) {
// Math.min() -> Infinity
return Replace(jsgraph()->Constant(V8_INFINITY));
}
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.min(a:plain-primitive) -> ToNumber(a)
Node* value = ToNumber(r.GetJSCallInput(0));
return Replace(value);
}
if (r.InputsMatchAll(Type::Integral32())) {
// Math.min(a:int32, b:int32, ...)
Node* value = r.GetJSCallInput(0);
for (int i = 1; i < r.GetJSCallArity(); i++) {
Node* const input = r.GetJSCallInput(i);
value = graph()->NewNode(
common()->Select(MachineRepresentation::kNone),
graph()->NewNode(simplified()->NumberLessThan(), input, value), input,
value);
}
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -231,9 +262,10 @@ Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) { ...@@ -231,9 +262,10 @@ Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
// ES6 section 20.2.2.28 Math.round ( x ) // ES6 section 20.2.2.28 Math.round ( x )
Reduction JSBuiltinReducer::ReduceMathRound(Node* node) { Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.round(a:number) -> NumberRound(a) // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
Node* value = graph()->NewNode(simplified()->NumberRound(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberRound(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -242,9 +274,10 @@ Reduction JSBuiltinReducer::ReduceMathRound(Node* node) { ...@@ -242,9 +274,10 @@ Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
// ES6 section 20.2.2.32 Math.sqrt ( x ) // ES6 section 20.2.2.32 Math.sqrt ( x )
Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) { Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.sqrt(a:number) -> Float64Sqrt(a) // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
Node* value = graph()->NewNode(machine()->Float64Sqrt(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -253,9 +286,10 @@ Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) { ...@@ -253,9 +286,10 @@ Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
// ES6 section 20.2.2.35 Math.trunc ( x ) // ES6 section 20.2.2.35 Math.trunc ( x )
Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.trunc(a:number) -> NumberTrunc(a) // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
Node* value = graph()->NewNode(simplified()->NumberTrunc(), r.left()); Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -264,10 +298,10 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { ...@@ -264,10 +298,10 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) { if (r.InputsMatchOne(Type::PlainPrimitive())) {
// String.fromCharCode(a:number) -> StringFromCharCode(a) // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
Node* value = Node* input = ToNumber(r.GetJSCallInput(0));
graph()->NewNode(simplified()->StringFromCharCode(), r.left()); Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
...@@ -280,11 +314,11 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -280,11 +314,11 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
// Dispatch according to the BuiltinFunctionId if present. // Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange(); if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) { switch (r.GetBuiltinFunctionId()) {
case kMathMax: case kMathAtan:
reduction = ReduceMathMax(node); reduction = ReduceMathAtan(node);
break; break;
case kMathImul: case kMathAtan2:
reduction = ReduceMathImul(node); reduction = ReduceMathAtan2(node);
break; break;
case kMathClz32: case kMathClz32:
reduction = ReduceMathClz32(node); reduction = ReduceMathClz32(node);
...@@ -298,11 +332,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -298,11 +332,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathFround: case kMathFround:
reduction = ReduceMathFround(node); reduction = ReduceMathFround(node);
break; break;
case kMathAtan: case kMathImul:
reduction = ReduceMathAtan(node); reduction = ReduceMathImul(node);
break;
case kMathAtan2:
reduction = ReduceMathAtan2(node);
break; break;
case kMathLog: case kMathLog:
reduction = ReduceMathLog(node); reduction = ReduceMathLog(node);
...@@ -310,6 +341,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -310,6 +341,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathLog1p: case kMathLog1p:
reduction = ReduceMathLog1p(node); reduction = ReduceMathLog1p(node);
break; break;
case kMathMax:
reduction = ReduceMathMax(node);
break;
case kMathMin:
reduction = ReduceMathMin(node);
break;
case kMathRound: case kMathRound:
reduction = ReduceMathRound(node); reduction = ReduceMathRound(node);
break; break;
...@@ -333,6 +370,18 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -333,6 +370,18 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return reduction; return reduction;
} }
Node* JSBuiltinReducer::ToNumber(Node* input) {
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::Number())) return input;
return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
}
Node* JSBuiltinReducer::ToUint32(Node* input) {
input = ToNumber(input);
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::Unsigned32())) return input;
return graph()->NewNode(simplified()->NumberToUint32(), input);
}
Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
...@@ -345,11 +394,6 @@ CommonOperatorBuilder* JSBuiltinReducer::common() const { ...@@ -345,11 +394,6 @@ CommonOperatorBuilder* JSBuiltinReducer::common() const {
} }
MachineOperatorBuilder* JSBuiltinReducer::machine() const {
return jsgraph()->machine();
}
SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
return jsgraph()->simplified(); return jsgraph()->simplified();
} }
......
...@@ -18,7 +18,6 @@ namespace compiler { ...@@ -18,7 +18,6 @@ namespace compiler {
// Forward declarations. // Forward declarations.
class CommonOperatorBuilder; class CommonOperatorBuilder;
class JSGraph; class JSGraph;
class MachineOperatorBuilder;
class SimplifiedOperatorBuilder; class SimplifiedOperatorBuilder;
...@@ -30,27 +29,29 @@ class JSBuiltinReducer final : public AdvancedReducer { ...@@ -30,27 +29,29 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
private: private:
Reduction ReduceFunctionCall(Node* node); Reduction ReduceMathAtan(Node* node);
Reduction ReduceMathMax(Node* node); Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathImul(Node* node);
Reduction ReduceMathCeil(Node* node); Reduction ReduceMathCeil(Node* node);
Reduction ReduceMathClz32(Node* node); Reduction ReduceMathClz32(Node* node);
Reduction ReduceMathFloor(Node* node); Reduction ReduceMathFloor(Node* node);
Reduction ReduceMathFround(Node* node); Reduction ReduceMathFround(Node* node);
Reduction ReduceMathAtan(Node* node); Reduction ReduceMathImul(Node* node);
Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathLog(Node* node); Reduction ReduceMathLog(Node* node);
Reduction ReduceMathLog1p(Node* node); Reduction ReduceMathLog1p(Node* node);
Reduction ReduceMathMax(Node* node);
Reduction ReduceMathMin(Node* node);
Reduction ReduceMathRound(Node* node); Reduction ReduceMathRound(Node* node);
Reduction ReduceMathSqrt(Node* node); Reduction ReduceMathSqrt(Node* node);
Reduction ReduceMathTrunc(Node* node); Reduction ReduceMathTrunc(Node* node);
Reduction ReduceStringFromCharCode(Node* node); Reduction ReduceStringFromCharCode(Node* node);
Node* ToNumber(Node* value);
Node* ToUint32(Node* value);
Graph* graph() const; Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const; Isolate* isolate() const;
CommonOperatorBuilder* common() const; CommonOperatorBuilder* common() const;
MachineOperatorBuilder* machine() const;
SimplifiedOperatorBuilder* simplified() const; SimplifiedOperatorBuilder* simplified() const;
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
......
...@@ -45,7 +45,7 @@ class JSBinopReduction final { ...@@ -45,7 +45,7 @@ class JSBinopReduction final {
return BinaryOperationHints::kAny; return BinaryOperationHints::kAny;
} }
void ConvertInputsToNumberOrUndefined(Node* frame_state) { void ConvertInputsToNumber(Node* frame_state) {
// To convert the inputs to numbers, we have to provide frame states // To convert the inputs to numbers, we have to provide frame states
// for lazy bailouts in the ToNumber conversions. // for lazy bailouts in the ToNumber conversions.
// We use a little hack here: we take the frame state before the binary // We use a little hack here: we take the frame state before the binary
...@@ -64,11 +64,11 @@ class JSBinopReduction final { ...@@ -64,11 +64,11 @@ class JSBinopReduction final {
ConvertBothInputsToNumber(&left_input, &right_input, frame_state); ConvertBothInputsToNumber(&left_input, &right_input, frame_state);
} else { } else {
left_input = left_is_primitive left_input = left_is_primitive
? ConvertPlainPrimitiveToNumberOrUndefined(left()) ? ConvertPlainPrimitiveToNumber(left())
: ConvertSingleInputToNumber( : ConvertSingleInputToNumber(
left(), CreateFrameStateForLeftInput(frame_state)); left(), CreateFrameStateForLeftInput(frame_state));
right_input = right_is_primitive right_input = right_is_primitive
? ConvertPlainPrimitiveToNumberOrUndefined(right()) ? ConvertPlainPrimitiveToNumber(right())
: ConvertSingleInputToNumber( : ConvertSingleInputToNumber(
right(), CreateFrameStateForRightInput( right(), CreateFrameStateForRightInput(
frame_state, left_input)); frame_state, left_input));
...@@ -281,12 +281,12 @@ class JSBinopReduction final { ...@@ -281,12 +281,12 @@ class JSBinopReduction final {
frame_state->InputAt(kFrameStateOuterStateInput)); frame_state->InputAt(kFrameStateOuterStateInput));
} }
Node* ConvertPlainPrimitiveToNumberOrUndefined(Node* node) { Node* ConvertPlainPrimitiveToNumber(Node* node) {
DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
// Avoid inserting too many eager ToNumber() operations. // Avoid inserting too many eager ToNumber() operations.
Reduction const reduction = lowering_->ReduceJSToNumberInput(node); Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
if (reduction.Changed()) return reduction.replacement(); if (reduction.Changed()) return reduction.replacement();
if (NodeProperties::GetType(node)->Is(Type::NumberOrUndefined())) { if (NodeProperties::GetType(node)->Is(Type::Number())) {
return node; return node;
} }
return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node); return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
...@@ -409,16 +409,16 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -409,16 +409,16 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
return r.ChangeToSpeculativeOperator( return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(feedback)); simplified()->SpeculativeNumberAdd(feedback));
} }
if (r.BothInputsAre(Type::NumberOrUndefined())) { if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y) // JSAdd(x:number, y:number) => NumberAdd(x, y)
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
} }
if (r.NeitherInputCanBe(Type::StringOrReceiver())) { if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
} }
if (r.OneInputIs(Type::String())) { if (r.OneInputIs(Type::String())) {
...@@ -468,7 +468,7 @@ Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { ...@@ -468,7 +468,7 @@ Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
simplified()->SpeculativeNumberSubtract(feedback)); simplified()->SpeculativeNumberSubtract(feedback));
} }
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number()); return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
} }
...@@ -476,7 +476,7 @@ Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { ...@@ -476,7 +476,7 @@ Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange(); if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number()); return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number());
} }
...@@ -484,7 +484,7 @@ Reduction JSTypedLowering::ReduceJSDivide(Node* node) { ...@@ -484,7 +484,7 @@ Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange(); if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number()); return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number());
} }
...@@ -494,7 +494,7 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { ...@@ -494,7 +494,7 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
r.ConvertInputsToUI32(kSigned, kSigned); r.ConvertInputsToUI32(kSigned, kSigned);
return r.ChangeToPureOperator(intOp, Type::Integral32()); return r.ChangeToPureOperator(intOp, Type::Integral32());
} }
...@@ -507,7 +507,7 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node, ...@@ -507,7 +507,7 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
r.ConvertInputsToUI32(left_signedness, kUnsigned); r.ConvertInputsToUI32(left_signedness, kUnsigned);
return r.ChangeToPureOperator(shift_op); return r.ChangeToPureOperator(shift_op);
} }
...@@ -553,7 +553,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -553,7 +553,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
} else { } else {
// TODO(turbofan): mixed signed/unsigned int32 comparisons. // TODO(turbofan): mixed signed/unsigned int32 comparisons.
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumber(frame_state);
less_than = simplified()->NumberLessThan(); less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual(); less_than_or_equal = simplified()->NumberLessThanOrEqual();
} }
...@@ -722,7 +722,7 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { ...@@ -722,7 +722,7 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
if (r.BothInputsAre(Type::String())) { if (r.BothInputsAre(Type::String())) {
return r.ChangeToPureOperator(simplified()->StringEqual(), invert); return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
} }
if (r.BothInputsAre(Type::NumberOrUndefined())) { if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
} }
// TODO(turbofan): js-typed-lowering of StrictEqual(mixed types) // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
...@@ -1073,7 +1073,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { ...@@ -1073,7 +1073,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
// Convert to a number first. // Convert to a number first.
if (!value_type->Is(Type::NumberOrUndefined())) { if (!value_type->Is(Type::Number())) {
Reduction number_reduction = ReduceJSToNumberInput(value); Reduction number_reduction = ReduceJSToNumberInput(value);
if (number_reduction.Changed()) { if (number_reduction.Changed()) {
value = number_reduction.replacement(); value = number_reduction.replacement();
......
...@@ -197,11 +197,13 @@ ...@@ -197,11 +197,13 @@
V(NumberClz32) \ V(NumberClz32) \
V(NumberCeil) \ V(NumberCeil) \
V(NumberFloor) \ V(NumberFloor) \
V(NumberFround) \
V(NumberAtan) \ V(NumberAtan) \
V(NumberAtan2) \ V(NumberAtan2) \
V(NumberLog) \ V(NumberLog) \
V(NumberLog1p) \ V(NumberLog1p) \
V(NumberRound) \ V(NumberRound) \
V(NumberSqrt) \
V(NumberTrunc) \ V(NumberTrunc) \
V(NumberToInt32) \ V(NumberToInt32) \
V(NumberToUint32) \ V(NumberToUint32) \
......
...@@ -663,10 +663,14 @@ const Operator* RepresentationChanger::Float64OperatorFor( ...@@ -663,10 +663,14 @@ const Operator* RepresentationChanger::Float64OperatorFor(
return machine()->Float64Atan(); return machine()->Float64Atan();
case IrOpcode::kNumberAtan2: case IrOpcode::kNumberAtan2:
return machine()->Float64Atan2(); return machine()->Float64Atan2();
case IrOpcode::kNumberFround:
return machine()->TruncateFloat64ToFloat32();
case IrOpcode::kNumberLog: case IrOpcode::kNumberLog:
return machine()->Float64Log(); return machine()->Float64Log();
case IrOpcode::kNumberLog1p: case IrOpcode::kNumberLog1p:
return machine()->Float64Log1p(); return machine()->Float64Log1p();
case IrOpcode::kNumberSqrt:
return machine()->Float64Sqrt();
case IrOpcode::kNumberSilenceNaN: case IrOpcode::kNumberSilenceNaN:
return machine()->Float64SilenceNaN(); return machine()->Float64SilenceNaN();
default: default:
......
...@@ -611,16 +611,17 @@ class RepresentationSelector { ...@@ -611,16 +611,17 @@ class RepresentationSelector {
Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); } Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
bool InputIs(Node* node, Type* type) {
DCHECK_EQ(1, node->InputCount());
return GetUpperBound(node->InputAt(0))->Is(type);
}
bool BothInputsAreSigned32(Node* node) { bool BothInputsAreSigned32(Node* node) {
DCHECK_EQ(2, node->InputCount()); return BothInputsAre(node, Type::Signed32());
return GetUpperBound(node->InputAt(0))->Is(Type::Signed32()) &&
GetUpperBound(node->InputAt(1))->Is(Type::Signed32());
} }
bool BothInputsAreUnsigned32(Node* node) { bool BothInputsAreUnsigned32(Node* node) {
DCHECK_EQ(2, node->InputCount()); return BothInputsAre(node, Type::Unsigned32());
return GetUpperBound(node->InputAt(0))->Is(Type::Unsigned32()) &&
GetUpperBound(node->InputAt(1))->Is(Type::Unsigned32());
} }
bool BothInputsAre(Node* node, Type* type) { bool BothInputsAre(Node* node, Type* type) {
...@@ -1393,6 +1394,12 @@ class RepresentationSelector { ...@@ -1393,6 +1394,12 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, lowering->Float64Floor(node)); if (lower()) DeferReplacement(node, lowering->Float64Floor(node));
return; return;
} }
case IrOpcode::kNumberFround: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat32);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberAtan2: { case IrOpcode::kNumberAtan2: {
VisitBinop(node, UseInfo::TruncatingFloat64(), VisitBinop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64); MachineRepresentation::kFloat64);
...@@ -1413,6 +1420,12 @@ class RepresentationSelector { ...@@ -1413,6 +1420,12 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, lowering->Float64Round(node)); if (lower()) DeferReplacement(node, lowering->Float64Round(node));
return; return;
} }
case IrOpcode::kNumberSqrt: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberTrunc: { case IrOpcode::kNumberTrunc: {
VisitUnop(node, UseInfo::TruncatingFloat64(), VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64); MachineRepresentation::kFloat64);
...@@ -1683,21 +1696,36 @@ class RepresentationSelector { ...@@ -1683,21 +1696,36 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kPlainPrimitiveToNumber: case IrOpcode::kPlainPrimitiveToNumber:
ProcessInput(node, 0, UseInfo::AnyTagged());
if (truncation.TruncatesToWord32()) { if (truncation.TruncatesToWord32()) {
SetOutput(node, MachineRepresentation::kWord32); // TODO(jarin): Extend this to Number \/ Oddball
if (InputIs(node, Type::NumberOrUndefined())) {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kWord32);
if (lower()) { if (lower()) {
NodeProperties::ChangeOp(node, NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToWord32()); simplified()->PlainPrimitiveToWord32());
} }
}
} else if (truncation.TruncatesToFloat64()) { } else if (truncation.TruncatesToFloat64()) {
SetOutput(node, MachineRepresentation::kFloat64); // TODO(jarin): Extend this to Number \/ Oddball
if (InputIs(node, Type::NumberOrUndefined())) {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kFloat64);
if (lower()) { if (lower()) {
NodeProperties::ChangeOp(node, NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToFloat64()); simplified()->PlainPrimitiveToFloat64());
} }
}
} else { } else {
SetOutput(node, MachineRepresentation::kTagged); VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
} }
return; return;
case IrOpcode::kObjectIsCallable: case IrOpcode::kObjectIsCallable:
......
...@@ -204,11 +204,13 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) { ...@@ -204,11 +204,13 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
V(NumberClz32, Operator::kNoProperties, 1) \ V(NumberClz32, Operator::kNoProperties, 1) \
V(NumberCeil, Operator::kNoProperties, 1) \ V(NumberCeil, Operator::kNoProperties, 1) \
V(NumberFloor, Operator::kNoProperties, 1) \ V(NumberFloor, Operator::kNoProperties, 1) \
V(NumberFround, Operator::kNoProperties, 1) \
V(NumberAtan, Operator::kNoProperties, 1) \ V(NumberAtan, Operator::kNoProperties, 1) \
V(NumberAtan2, Operator::kNoProperties, 2) \ V(NumberAtan2, Operator::kNoProperties, 2) \
V(NumberLog, Operator::kNoProperties, 1) \ V(NumberLog, Operator::kNoProperties, 1) \
V(NumberLog1p, Operator::kNoProperties, 1) \ V(NumberLog1p, Operator::kNoProperties, 1) \
V(NumberRound, Operator::kNoProperties, 1) \ V(NumberRound, Operator::kNoProperties, 1) \
V(NumberSqrt, Operator::kNoProperties, 1) \
V(NumberTrunc, Operator::kNoProperties, 1) \ V(NumberTrunc, Operator::kNoProperties, 1) \
V(NumberToInt32, Operator::kNoProperties, 1) \ V(NumberToInt32, Operator::kNoProperties, 1) \
V(NumberToUint32, Operator::kNoProperties, 1) \ V(NumberToUint32, Operator::kNoProperties, 1) \
...@@ -217,9 +219,9 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) { ...@@ -217,9 +219,9 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
V(NumberConvertHoleNaN, Operator::kNoProperties, 1) \ V(NumberConvertHoleNaN, Operator::kNoProperties, 1) \
V(StringFromCharCode, Operator::kNoProperties, 1) \ V(StringFromCharCode, Operator::kNoProperties, 1) \
V(StringToNumber, Operator::kNoProperties, 1) \ V(StringToNumber, Operator::kNoProperties, 1) \
V(PlainPrimitiveToNumber, Operator::kNoWrite, 1) \ V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
V(PlainPrimitiveToWord32, Operator::kNoWrite, 1) \ V(PlainPrimitiveToWord32, Operator::kNoProperties, 1) \
V(PlainPrimitiveToFloat64, Operator::kNoWrite, 1) \ V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1) \
V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1) \ V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \ V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \ V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
......
...@@ -154,11 +154,13 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -154,11 +154,13 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberClz32(); const Operator* NumberClz32();
const Operator* NumberCeil(); const Operator* NumberCeil();
const Operator* NumberFloor(); const Operator* NumberFloor();
const Operator* NumberFround();
const Operator* NumberAtan(); const Operator* NumberAtan();
const Operator* NumberAtan2(); const Operator* NumberAtan2();
const Operator* NumberLog(); const Operator* NumberLog();
const Operator* NumberLog1p(); const Operator* NumberLog1p();
const Operator* NumberRound(); const Operator* NumberRound();
const Operator* NumberSqrt();
const Operator* NumberTrunc(); const Operator* NumberTrunc();
const Operator* NumberToInt32(); const Operator* NumberToInt32();
const Operator* NumberToUint32(); const Operator* NumberToUint32();
......
...@@ -1788,6 +1788,8 @@ Type* Typer::Visitor::TypeNumberFloor(Node* node) { ...@@ -1788,6 +1788,8 @@ Type* Typer::Visitor::TypeNumberFloor(Node* node) {
return TypeUnaryOp(node, NumberFloor); return TypeUnaryOp(node, NumberFloor);
} }
Type* Typer::Visitor::TypeNumberFround(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtan(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberAtan(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtan2(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberAtan2(Node* node) { return Type::Number(); }
...@@ -1800,6 +1802,8 @@ Type* Typer::Visitor::TypeNumberRound(Node* node) { ...@@ -1800,6 +1802,8 @@ Type* Typer::Visitor::TypeNumberRound(Node* node) {
return TypeUnaryOp(node, NumberRound); return TypeUnaryOp(node, NumberRound);
} }
Type* Typer::Visitor::TypeNumberSqrt(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberTrunc(Node* node) { Type* Typer::Visitor::TypeNumberTrunc(Node* node) {
return TypeUnaryOp(node, NumberTrunc); return TypeUnaryOp(node, NumberTrunc);
} }
...@@ -1902,7 +1906,7 @@ Type* Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) { ...@@ -1902,7 +1906,7 @@ Type* Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
Type* Typer::Visitor::TypeTruncateTaggedToFloat64(Node* node) { Type* Typer::Visitor::TypeTruncateTaggedToFloat64(Node* node) {
Type* arg = Operand(node, 0); Type* arg = Operand(node, 0);
DCHECK(arg->Is(Type::NumberOrUndefined())); DCHECK(arg->Is(Type::NumberOrOddball()));
return ChangeRepresentation(arg, Type::UntaggedFloat64(), zone()); return ChangeRepresentation(arg, Type::UntaggedFloat64(), zone());
} }
......
...@@ -675,16 +675,16 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -675,16 +675,16 @@ void Verifier::Visitor::Check(Node* node) {
CheckUpperIs(node, Type::Number()); CheckUpperIs(node, Type::Number());
break; break;
case IrOpcode::kNumberEqual: case IrOpcode::kNumberEqual:
// (NumberOrUndefined, NumberOrUndefined) -> Boolean // (Number, Number) -> Boolean
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::NumberOrUndefined()); CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean()); CheckUpperIs(node, Type::Boolean());
break; break;
case IrOpcode::kNumberLessThan: case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kNumberLessThanOrEqual:
// (Number, Number) -> Boolean // (Number, Number) -> Boolean
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::NumberOrUndefined()); CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean()); CheckUpperIs(node, Type::Boolean());
break; break;
case IrOpcode::kSpeculativeNumberAdd: case IrOpcode::kSpeculativeNumberAdd:
...@@ -695,16 +695,15 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -695,16 +695,15 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kNumberMultiply: case IrOpcode::kNumberMultiply:
case IrOpcode::kNumberDivide: case IrOpcode::kNumberDivide:
// (Number, Number) -> Number // (Number, Number) -> Number
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::NumberOrUndefined()); CheckValueInputIs(node, 1, Type::Number());
// CheckUpperIs(node, Type::Number()); CheckUpperIs(node, Type::Number());
break; break;
case IrOpcode::kNumberModulus: case IrOpcode::kNumberModulus:
// (Number, Number) -> Number // (Number, Number) -> Number
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number()); CheckValueInputIs(node, 1, Type::Number());
// TODO(rossberg): activate once we retype after opcode changes. CheckUpperIs(node, Type::Number());
// CheckUpperIs(node, Type::Number());
break; break;
case IrOpcode::kNumberBitwiseOr: case IrOpcode::kNumberBitwiseOr:
case IrOpcode::kNumberBitwiseXor: case IrOpcode::kNumberBitwiseXor:
...@@ -746,10 +745,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -746,10 +745,12 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kNumberCeil: case IrOpcode::kNumberCeil:
case IrOpcode::kNumberFloor: case IrOpcode::kNumberFloor:
case IrOpcode::kNumberFround:
case IrOpcode::kNumberAtan: case IrOpcode::kNumberAtan:
case IrOpcode::kNumberLog: case IrOpcode::kNumberLog:
case IrOpcode::kNumberLog1p: case IrOpcode::kNumberLog1p:
case IrOpcode::kNumberRound: case IrOpcode::kNumberRound:
case IrOpcode::kNumberSqrt:
case IrOpcode::kNumberTrunc: case IrOpcode::kNumberTrunc:
// Number -> Number // Number -> Number
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
...@@ -757,12 +758,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -757,12 +758,12 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kNumberToInt32: case IrOpcode::kNumberToInt32:
// Number -> Signed32 // Number -> Signed32
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Signed32()); CheckUpperIs(node, Type::Signed32());
break; break;
case IrOpcode::kNumberToUint32: case IrOpcode::kNumberToUint32:
// Number -> Unsigned32 // Number -> Unsigned32
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Unsigned32()); CheckUpperIs(node, Type::Unsigned32());
break; break;
case IrOpcode::kNumberIsHoleNaN: case IrOpcode::kNumberIsHoleNaN:
...@@ -851,7 +852,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -851,7 +852,7 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
} }
case IrOpcode::kChangeTaggedToFloat64: { case IrOpcode::kChangeTaggedToFloat64: {
// Number /\ Tagged -> Number /\ UntaggedFloat64 // NumberOrUndefined /\ Tagged -> Number /\ UntaggedFloat64
// TODO(neis): Activate once ChangeRepresentation works in typer. // TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Number(), Type::Tagged()); // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64()); // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
...@@ -970,7 +971,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -970,7 +971,7 @@ void Verifier::Visitor::Check(Node* node) {
CheckNotTyped(node); CheckNotTyped(node);
break; break;
case IrOpcode::kNumberSilenceNaN: case IrOpcode::kNumberSilenceNaN:
CheckValueInputIs(node, 0, Type::NumberOrUndefined()); CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number()); CheckUpperIs(node, Type::Number());
break; break;
......
...@@ -219,6 +219,7 @@ namespace internal { ...@@ -219,6 +219,7 @@ namespace internal {
V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \ V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \
V(NullOrUndefined, kNull | kUndefined) \ V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \ V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \
V(NumberOrSimdOrString, kNumber | kSimd | kString) \ V(NumberOrSimdOrString, kNumber | kSimd | kString) \
V(NumberOrString, kNumber | kString) \ V(NumberOrString, kNumber | kString) \
V(NumberOrUndefined, kNumber | kUndefined) \ V(NumberOrUndefined, kNumber | kUndefined) \
......
...@@ -87,28 +87,93 @@ Type* const kNumberTypes[] = { ...@@ -87,28 +87,93 @@ Type* const kNumberTypes[] = {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.max // Math.atan
TEST_F(JSBuiltinReducerTest, MathAtanWithNumber) {
Node* function = MathFunction("atan");
TEST_F(JSBuiltinReducerTest, MathMax0) { Node* effect = graph()->start();
Node* function = MathFunction("max"); 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()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAtan(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathAtanWithPlainPrimitive) {
Node* function = MathFunction("atan");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
Node* call = graph()->NewNode(javascript()->CallFunction(2), function, Node* p0 = Parameter(Type::PlainPrimitive(), 0);
UndefinedConstant(), context, frame_state, Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control); effect, control);
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); EXPECT_THAT(r.replacement(), IsNumberAtan(IsPlainPrimitiveToNumber(p0)));
} }
// -----------------------------------------------------------------------------
// Math.atan2
TEST_F(JSBuiltinReducerTest, MathMax1) { TEST_F(JSBuiltinReducerTest, MathAtan2WithNumber) {
Node* function = MathFunction("max"); Node* function = MathFunction("atan2");
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);
TRACED_FOREACH(Type*, t1, kNumberTypes) {
Node* p1 = Parameter(t1, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context,
frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAtan2(p0, p1));
}
}
}
TEST_F(JSBuiltinReducerTest, MathAtan2WithPlainPrimitive) {
Node* function = MathFunction("atan2");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* p1 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context,
frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAtan2(IsPlainPrimitiveToNumber(p0),
IsPlainPrimitiveToNumber(p1)));
}
// -----------------------------------------------------------------------------
// Math.ceil
TEST_F(JSBuiltinReducerTest, MathCeilWithNumber) {
Node* function = MathFunction("ceil");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -122,50 +187,190 @@ TEST_F(JSBuiltinReducerTest, MathMax1) { ...@@ -122,50 +187,190 @@ TEST_F(JSBuiltinReducerTest, MathMax1) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), p0); EXPECT_THAT(r.replacement(), IsNumberCeil(p0));
} }
} }
TEST_F(JSBuiltinReducerTest, MathCeilWithPlainPrimitive) {
Node* function = MathFunction("ceil");
TEST_F(JSBuiltinReducerTest, MathMax2) { Node* effect = graph()->start();
Node* function = MathFunction("max"); Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberCeil(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.clz32
TEST_F(JSBuiltinReducerTest, MathClz32WithUnsigned32) {
Node* function = MathFunction("clz32");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kIntegral32Types) { Node* p0 = Parameter(Type::Unsigned32(), 0);
TRACED_FOREACH(Type*, t1, kIntegral32Types) { Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberClz32(p0));
}
TEST_F(JSBuiltinReducerTest, MathClz32WithNumber) {
Node* function = MathFunction("clz32");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Number(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberClz32(IsNumberToUint32(p0)));
}
TEST_F(JSBuiltinReducerTest, MathClz32WithPlainPrimitive) {
Node* function = MathFunction("clz32");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberClz32(IsNumberToUint32(IsPlainPrimitiveToNumber(p0))));
}
// -----------------------------------------------------------------------------
// Math.floor
TEST_F(JSBuiltinReducerTest, MathFloorWithNumber) {
Node* function = MathFunction("floor");
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* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1); Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
Node* call = graph()->NewNode(javascript()->CallFunction(4), function, UndefinedConstant(), p0, context, frame_state,
UndefinedConstant(), p0, p1, context, effect, control);
frame_state, effect, control);
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone, EXPECT_THAT(r.replacement(), IsNumberFloor(p0));
IsNumberLessThan(p1, p0), p0, p1));
} }
}
TEST_F(JSBuiltinReducerTest, MathFloorWithPlainPrimitive) {
Node* function = MathFunction("floor");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberFloor(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.fround
TEST_F(JSBuiltinReducerTest, MathFroundWithNumber) {
Node* function = MathFunction("fround");
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()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberFround(p0));
} }
} }
TEST_F(JSBuiltinReducerTest, MathFroundWithPlainPrimitive) {
Node* function = MathFunction("fround");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberFround(IsPlainPrimitiveToNumber(p0)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.imul // Math.imul
TEST_F(JSBuiltinReducerTest, MathImulWithUnsigned32) {
Node* function = MathFunction("imul");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Unsigned32(), 0);
Node* p1 = Parameter(Type::Unsigned32(), 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context,
frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberImul(p0, p1));
}
TEST_F(JSBuiltinReducerTest, MathImul) { TEST_F(JSBuiltinReducerTest, MathImulWithNumber) {
Node* function = MathFunction("imul"); Node* function = MathFunction("imul");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(Type::Number(), 0);
TRACED_FOREACH(Type*, t1, kNumberTypes) { Node* p1 = Parameter(Type::Number(), 1);
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function, Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context, UndefinedConstant(), p0, p1, context,
frame_state, effect, control); frame_state, effect, control);
...@@ -174,17 +379,72 @@ TEST_F(JSBuiltinReducerTest, MathImul) { ...@@ -174,17 +379,72 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(r.replacement(),
IsNumberImul(IsNumberToUint32(p0), IsNumberToUint32(p1))); IsNumberImul(IsNumberToUint32(p0), IsNumberToUint32(p1)));
}
}
} }
TEST_F(JSBuiltinReducerTest, MathImulWithPlainPrimitive) {
Node* function = MathFunction("imul");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* p1 = Parameter(Type::PlainPrimitive(), 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context,
frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberImul(IsNumberToUint32(IsPlainPrimitiveToNumber(p0)),
IsNumberToUint32(IsPlainPrimitiveToNumber(p1))));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.fround // Math.log
TEST_F(JSBuiltinReducerTest, MathLogWithNumber) {
Node* function = MathFunction("log");
TEST_F(JSBuiltinReducerTest, MathFround) { Node* effect = graph()->start();
Node* function = MathFunction("fround"); 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()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathLogWithPlainPrimitive) {
Node* function = MathFunction("log");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.log1p
TEST_F(JSBuiltinReducerTest, MathLog1pWithNumber) {
Node* function = MathFunction("log1p");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -198,15 +458,48 @@ TEST_F(JSBuiltinReducerTest, MathFround) { ...@@ -198,15 +458,48 @@ TEST_F(JSBuiltinReducerTest, MathFround) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0)); EXPECT_THAT(r.replacement(), IsNumberLog1p(p0));
} }
} }
TEST_F(JSBuiltinReducerTest, MathLog1pWithPlainPrimitive) {
Node* function = MathFunction("log1p");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog1p(IsPlainPrimitiveToNumber(p0)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.atan // Math.max
TEST_F(JSBuiltinReducerTest, MathAtan) { TEST_F(JSBuiltinReducerTest, MathMaxWithNoArguments) {
Node* function = MathFunction("atan"); Node* function = MathFunction("max");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* call = graph()->NewNode(javascript()->CallFunction(2), function,
UndefinedConstant(), context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
}
TEST_F(JSBuiltinReducerTest, MathMaxWithNumber) {
Node* function = MathFunction("max");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -220,15 +513,71 @@ TEST_F(JSBuiltinReducerTest, MathAtan) { ...@@ -220,15 +513,71 @@ TEST_F(JSBuiltinReducerTest, MathAtan) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAtan(p0)); EXPECT_THAT(r.replacement(), p0);
}
}
TEST_F(JSBuiltinReducerTest, MathMaxWithPlainPrimitive) {
Node* function = MathFunction("max");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsPlainPrimitiveToNumber(p0));
}
TEST_F(JSBuiltinReducerTest, MathMaxWithIntegral32) {
Node* function = MathFunction("max");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kIntegral32Types) {
TRACED_FOREACH(Type*, t1, kIntegral32Types) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context,
frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone,
IsNumberLessThan(p1, p0), p0, p1));
}
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.atan2 // Math.min
TEST_F(JSBuiltinReducerTest, MathAtan2) { TEST_F(JSBuiltinReducerTest, MathMinWithNoArguments) {
Node* function = MathFunction("atan2"); Node* function = MathFunction("min");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* call = graph()->NewNode(javascript()->CallFunction(2), function,
UndefinedConstant(), context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberConstant(V8_INFINITY));
}
TEST_F(JSBuiltinReducerTest, MathMinWithNumber) {
Node* function = MathFunction("min");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -236,24 +585,61 @@ TEST_F(JSBuiltinReducerTest, MathAtan2) { ...@@ -236,24 +585,61 @@ TEST_F(JSBuiltinReducerTest, MathAtan2) {
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) { TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0); Node* p0 = Parameter(t0, 0);
TRACED_FOREACH(Type*, t1, kNumberTypes) { Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
Node* p1 = Parameter(t1, 0); UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), p0);
}
}
TEST_F(JSBuiltinReducerTest, MathMinWithPlainPrimitive) {
Node* function = MathFunction("min");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsPlainPrimitiveToNumber(p0));
}
TEST_F(JSBuiltinReducerTest, MathMinWithIntegral32) {
Node* function = MathFunction("min");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kIntegral32Types) {
TRACED_FOREACH(Type*, t1, kIntegral32Types) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function, Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
UndefinedConstant(), p0, p1, context, UndefinedConstant(), p0, p1, context,
frame_state, effect, control); frame_state, effect, control);
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberAtan2(p0, p1)); EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone,
IsNumberLessThan(p1, p0), p1, p0));
} }
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.log // Math.round
TEST_F(JSBuiltinReducerTest, MathLog) { TEST_F(JSBuiltinReducerTest, MathRoundWithNumber) {
Node* function = MathFunction("log"); Node* function = MathFunction("round");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -267,15 +653,32 @@ TEST_F(JSBuiltinReducerTest, MathLog) { ...@@ -267,15 +653,32 @@ TEST_F(JSBuiltinReducerTest, MathLog) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog(p0)); EXPECT_THAT(r.replacement(), IsNumberRound(p0));
} }
} }
TEST_F(JSBuiltinReducerTest, MathRoundWithPlainPrimitive) {
Node* function = MathFunction("round");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberRound(IsPlainPrimitiveToNumber(p0)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.log1p // Math.sqrt
TEST_F(JSBuiltinReducerTest, MathLog1p) { TEST_F(JSBuiltinReducerTest, MathSqrtWithNumber) {
Node* function = MathFunction("log1p"); Node* function = MathFunction("sqrt");
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
...@@ -289,14 +692,70 @@ TEST_F(JSBuiltinReducerTest, MathLog1p) { ...@@ -289,14 +692,70 @@ TEST_F(JSBuiltinReducerTest, MathLog1p) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog1p(p0)); EXPECT_THAT(r.replacement(), IsNumberSqrt(p0));
} }
} }
TEST_F(JSBuiltinReducerTest, MathSqrtWithPlainPrimitive) {
Node* function = MathFunction("sqrt");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberSqrt(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.trunc
TEST_F(JSBuiltinReducerTest, MathTruncWithNumber) {
Node* function = MathFunction("trunc");
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()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberTrunc(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathTruncWithPlainPrimitive) {
Node* function = MathFunction("trunc");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberTrunc(IsPlainPrimitiveToNumber(p0)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// String.fromCharCode // String.fromCharCode
TEST_F(JSBuiltinReducerTest, StringFromCharCode) { TEST_F(JSBuiltinReducerTest, StringFromCharCodeWithNumber) {
Node* function = StringFunction("fromCharCode"); Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start(); Node* effect = graph()->start();
...@@ -315,6 +774,24 @@ TEST_F(JSBuiltinReducerTest, StringFromCharCode) { ...@@ -315,6 +774,24 @@ TEST_F(JSBuiltinReducerTest, StringFromCharCode) {
} }
} }
TEST_F(JSBuiltinReducerTest, StringFromCharCodeWithPlainPrimitive) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsStringFromCharCode(IsPlainPrimitiveToNumber(p0)));
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -2311,8 +2311,15 @@ IS_UNOP_MATCHER(Float64RoundTiesAway) ...@@ -2311,8 +2311,15 @@ IS_UNOP_MATCHER(Float64RoundTiesAway)
IS_UNOP_MATCHER(Float64ExtractLowWord32) IS_UNOP_MATCHER(Float64ExtractLowWord32)
IS_UNOP_MATCHER(Float64ExtractHighWord32) IS_UNOP_MATCHER(Float64ExtractHighWord32)
IS_UNOP_MATCHER(NumberAtan) IS_UNOP_MATCHER(NumberAtan)
IS_UNOP_MATCHER(NumberCeil)
IS_UNOP_MATCHER(NumberClz32)
IS_UNOP_MATCHER(NumberFloor)
IS_UNOP_MATCHER(NumberFround)
IS_UNOP_MATCHER(NumberLog) IS_UNOP_MATCHER(NumberLog)
IS_UNOP_MATCHER(NumberLog1p) IS_UNOP_MATCHER(NumberLog1p)
IS_UNOP_MATCHER(NumberRound)
IS_UNOP_MATCHER(NumberSqrt)
IS_UNOP_MATCHER(NumberTrunc)
IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(PlainPrimitiveToNumber) IS_UNOP_MATCHER(PlainPrimitiveToNumber)
......
...@@ -227,8 +227,15 @@ Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher, ...@@ -227,8 +227,15 @@ Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsNumberAtan(const Matcher<Node*>& value_matcher); Matcher<Node*> IsNumberAtan(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberCeil(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberClz32(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberFloor(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberFround(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher); Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberLog1p(const Matcher<Node*>& value_matcher); Matcher<Node*> IsNumberLog1p(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberRound(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberSqrt(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberTrunc(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsStringFromCharCode(const Matcher<Node*>& value_matcher); Matcher<Node*> IsStringFromCharCode(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher, Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher,
const Matcher<Node*>& effect_matcher, const Matcher<Node*>& effect_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