[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}
This commit is contained in:
bmeurer 2016-06-14 22:43:36 -07:00 committed by Commit bot
parent 05a663e605
commit ed0039a72e
14 changed files with 864 additions and 284 deletions

View File

@ -91,16 +91,131 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph)
jsgraph_(jsgraph),
type_cache_(TypeCache::Get()) {}
// ECMA-262, section 15.8.2.11.
// ES6 section 20.2.2.6 Math.atan ( x )
Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.8 Math.atan2 ( y, x )
Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
// Math.atan2(a:plain-primitive,
// b:plain-primitive) -> NumberAtan2(ToNumber(a),
// ToNumber(b))
Node* left = ToNumber(r.left());
Node* right = ToNumber(r.right());
Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.10 Math.ceil ( x )
Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.11 Math.clz32 ( x )
Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
Node* input = ToUint32(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.16 Math.floor ( x )
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.17 Math.fround ( x )
Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberFround(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.19 Math.imul ( x, y )
Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
// Math.imul(a:plain-primitive,
// 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 NoChange();
}
// ES6 section 20.2.2.20 Math.log ( x )
Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberLog(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.21 Math.log1p ( x )
Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchZero()) {
// Math.max() -> -Infinity
return Replace(jsgraph()->Constant(-V8_INFINITY));
}
if (r.InputsMatchOne(Type::Number())) {
// Math.max(a:number) -> a
return Replace(r.left());
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, ...)
@ -117,112 +232,28 @@ Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
return NoChange();
}
// ES6 section 20.2.2.19 Math.imul ( x, y )
Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchTwo(Type::Number(), Type::Number())) {
// Math.imul(a:number, b:number) -> NumberImul(NumberToUint32(a),
// NumberToUint32(b))
Node* a = graph()->NewNode(simplified()->NumberToUint32(), r.left());
Node* b = graph()->NewNode(simplified()->NumberToUint32(), r.right());
Node* value = graph()->NewNode(simplified()->NumberImul(), a, b);
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);
}
return NoChange();
}
// ES6 section 20.2.2.10 Math.ceil ( x )
Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.ceil(a:number) -> NumberCeil(a)
Node* value = graph()->NewNode(simplified()->NumberCeil(), r.left());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.11 Math.clz32 ( x )
Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Unsigned32())) {
// Math.clz32(a:unsigned32) -> NumberClz32(a)
Node* value = graph()->NewNode(simplified()->NumberClz32(), r.left());
return Replace(value);
}
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 NoChange();
}
// ES6 draft 08-24-14, section 20.2.2.16.
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.floor(a:number) -> NumberFloor(a)
Node* value = graph()->NewNode(simplified()->NumberFloor(), r.left());
return Replace(value);
}
return NoChange();
}
// ES6 draft 08-24-14, section 20.2.2.17.
Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::NumberOrUndefined())) {
// Math.fround(a:number) -> TruncateFloat64ToFloat32(a)
Node* value =
graph()->NewNode(machine()->TruncateFloat64ToFloat32(), r.left());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.6 Math.atan ( x )
Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.atan(a:number) -> NumberAtan(a)
Node* value = graph()->NewNode(simplified()->NumberAtan(), r.left());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.8 Math.atan2 ( y, x )
Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchTwo(Type::Number(), Type::Number())) {
// Math.atan2(a:number, b:number) -> NumberAtan2(a, b)
Node* value =
graph()->NewNode(simplified()->NumberAtan2(), r.left(), r.right());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.20 Math.log ( x )
Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.log(a:number) -> NumberLog(a)
Node* value = graph()->NewNode(simplified()->NumberLog(), r.left());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.21 Math.log1p ( x )
Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.log1p(a:number) -> NumberLog1p(a)
Node* value = graph()->NewNode(simplified()->NumberLog1p(), r.left());
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 NoChange();
@ -231,9 +262,10 @@ Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
// ES6 section 20.2.2.28 Math.round ( x )
Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.round(a:number) -> NumberRound(a)
Node* value = graph()->NewNode(simplified()->NumberRound(), r.left());
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberRound(), input);
return Replace(value);
}
return NoChange();
@ -242,9 +274,10 @@ Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
// ES6 section 20.2.2.32 Math.sqrt ( x )
Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.sqrt(a:number) -> Float64Sqrt(a)
Node* value = graph()->NewNode(machine()->Float64Sqrt(), r.left());
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
return Replace(value);
}
return NoChange();
@ -253,9 +286,10 @@ Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
// ES6 section 20.2.2.35 Math.trunc ( x )
Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Math.trunc(a:number) -> NumberTrunc(a)
Node* value = graph()->NewNode(simplified()->NumberTrunc(), r.left());
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
return Replace(value);
}
return NoChange();
@ -264,10 +298,10 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// String.fromCharCode(a:number) -> StringFromCharCode(a)
Node* value =
graph()->NewNode(simplified()->StringFromCharCode(), r.left());
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
return Replace(value);
}
return NoChange();
@ -280,11 +314,11 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
case kMathMax:
reduction = ReduceMathMax(node);
case kMathAtan:
reduction = ReduceMathAtan(node);
break;
case kMathImul:
reduction = ReduceMathImul(node);
case kMathAtan2:
reduction = ReduceMathAtan2(node);
break;
case kMathClz32:
reduction = ReduceMathClz32(node);
@ -298,11 +332,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathFround:
reduction = ReduceMathFround(node);
break;
case kMathAtan:
reduction = ReduceMathAtan(node);
break;
case kMathAtan2:
reduction = ReduceMathAtan2(node);
case kMathImul:
reduction = ReduceMathImul(node);
break;
case kMathLog:
reduction = ReduceMathLog(node);
@ -310,6 +341,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathLog1p:
reduction = ReduceMathLog1p(node);
break;
case kMathMax:
reduction = ReduceMathMax(node);
break;
case kMathMin:
reduction = ReduceMathMin(node);
break;
case kMathRound:
reduction = ReduceMathRound(node);
break;
@ -333,6 +370,18 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
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(); }
@ -345,11 +394,6 @@ CommonOperatorBuilder* JSBuiltinReducer::common() const {
}
MachineOperatorBuilder* JSBuiltinReducer::machine() const {
return jsgraph()->machine();
}
SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
return jsgraph()->simplified();
}

View File

@ -18,7 +18,6 @@ namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class JSGraph;
class MachineOperatorBuilder;
class SimplifiedOperatorBuilder;
@ -30,27 +29,29 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction Reduce(Node* node) final;
private:
Reduction ReduceFunctionCall(Node* node);
Reduction ReduceMathMax(Node* node);
Reduction ReduceMathImul(Node* node);
Reduction ReduceMathAtan(Node* node);
Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathCeil(Node* node);
Reduction ReduceMathClz32(Node* node);
Reduction ReduceMathFloor(Node* node);
Reduction ReduceMathFround(Node* node);
Reduction ReduceMathAtan(Node* node);
Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathImul(Node* node);
Reduction ReduceMathLog(Node* node);
Reduction ReduceMathLog1p(Node* node);
Reduction ReduceMathMax(Node* node);
Reduction ReduceMathMin(Node* node);
Reduction ReduceMathRound(Node* node);
Reduction ReduceMathSqrt(Node* node);
Reduction ReduceMathTrunc(Node* node);
Reduction ReduceStringFromCharCode(Node* node);
Node* ToNumber(Node* value);
Node* ToUint32(Node* value);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
CommonOperatorBuilder* common() const;
MachineOperatorBuilder* machine() const;
SimplifiedOperatorBuilder* simplified() const;
JSGraph* const jsgraph_;

View File

@ -45,7 +45,7 @@ class JSBinopReduction final {
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
// for lazy bailouts in the ToNumber conversions.
// We use a little hack here: we take the frame state before the binary
@ -64,11 +64,11 @@ class JSBinopReduction final {
ConvertBothInputsToNumber(&left_input, &right_input, frame_state);
} else {
left_input = left_is_primitive
? ConvertPlainPrimitiveToNumberOrUndefined(left())
? ConvertPlainPrimitiveToNumber(left())
: ConvertSingleInputToNumber(
left(), CreateFrameStateForLeftInput(frame_state));
right_input = right_is_primitive
? ConvertPlainPrimitiveToNumberOrUndefined(right())
? ConvertPlainPrimitiveToNumber(right())
: ConvertSingleInputToNumber(
right(), CreateFrameStateForRightInput(
frame_state, left_input));
@ -281,12 +281,12 @@ class JSBinopReduction final {
frame_state->InputAt(kFrameStateOuterStateInput));
}
Node* ConvertPlainPrimitiveToNumberOrUndefined(Node* node) {
Node* ConvertPlainPrimitiveToNumber(Node* node) {
DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
// Avoid inserting too many eager ToNumber() operations.
Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
if (reduction.Changed()) return reduction.replacement();
if (NodeProperties::GetType(node)->Is(Type::NumberOrUndefined())) {
if (NodeProperties::GetType(node)->Is(Type::Number())) {
return node;
}
return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
@ -409,16 +409,16 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(feedback));
}
if (r.BothInputsAre(Type::NumberOrUndefined())) {
if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y)
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
if (r.OneInputIs(Type::String())) {
@ -468,7 +468,7 @@ Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
simplified()->SpeculativeNumberSubtract(feedback));
}
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
}
@ -476,7 +476,7 @@ Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number());
}
@ -484,7 +484,7 @@ Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number());
}
@ -494,7 +494,7 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
r.ConvertInputsToUI32(kSigned, kSigned);
return r.ChangeToPureOperator(intOp, Type::Integral32());
}
@ -507,7 +507,7 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
r.ConvertInputsToUI32(left_signedness, kUnsigned);
return r.ChangeToPureOperator(shift_op);
}
@ -553,7 +553,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
} else {
// TODO(turbofan): mixed signed/unsigned int32 comparisons.
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
r.ConvertInputsToNumber(frame_state);
less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual();
}
@ -722,7 +722,7 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
if (r.BothInputsAre(Type::String())) {
return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
}
if (r.BothInputsAre(Type::NumberOrUndefined())) {
if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
}
// TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
@ -1073,7 +1073,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Convert to a number first.
if (!value_type->Is(Type::NumberOrUndefined())) {
if (!value_type->Is(Type::Number())) {
Reduction number_reduction = ReduceJSToNumberInput(value);
if (number_reduction.Changed()) {
value = number_reduction.replacement();

View File

@ -197,11 +197,13 @@
V(NumberClz32) \
V(NumberCeil) \
V(NumberFloor) \
V(NumberFround) \
V(NumberAtan) \
V(NumberAtan2) \
V(NumberLog) \
V(NumberLog1p) \
V(NumberRound) \
V(NumberSqrt) \
V(NumberTrunc) \
V(NumberToInt32) \
V(NumberToUint32) \

View File

@ -663,10 +663,14 @@ const Operator* RepresentationChanger::Float64OperatorFor(
return machine()->Float64Atan();
case IrOpcode::kNumberAtan2:
return machine()->Float64Atan2();
case IrOpcode::kNumberFround:
return machine()->TruncateFloat64ToFloat32();
case IrOpcode::kNumberLog:
return machine()->Float64Log();
case IrOpcode::kNumberLog1p:
return machine()->Float64Log1p();
case IrOpcode::kNumberSqrt:
return machine()->Float64Sqrt();
case IrOpcode::kNumberSilenceNaN:
return machine()->Float64SilenceNaN();
default:

View File

@ -611,16 +611,17 @@ class RepresentationSelector {
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) {
DCHECK_EQ(2, node->InputCount());
return GetUpperBound(node->InputAt(0))->Is(Type::Signed32()) &&
GetUpperBound(node->InputAt(1))->Is(Type::Signed32());
return BothInputsAre(node, Type::Signed32());
}
bool BothInputsAreUnsigned32(Node* node) {
DCHECK_EQ(2, node->InputCount());
return GetUpperBound(node->InputAt(0))->Is(Type::Unsigned32()) &&
GetUpperBound(node->InputAt(1))->Is(Type::Unsigned32());
return BothInputsAre(node, Type::Unsigned32());
}
bool BothInputsAre(Node* node, Type* type) {
@ -1393,6 +1394,12 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, lowering->Float64Floor(node));
return;
}
case IrOpcode::kNumberFround: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat32);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberAtan2: {
VisitBinop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
@ -1413,6 +1420,12 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, lowering->Float64Round(node));
return;
}
case IrOpcode::kNumberSqrt: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberTrunc: {
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
@ -1683,21 +1696,36 @@ class RepresentationSelector {
return;
}
case IrOpcode::kPlainPrimitiveToNumber:
ProcessInput(node, 0, UseInfo::AnyTagged());
if (truncation.TruncatesToWord32()) {
SetOutput(node, MachineRepresentation::kWord32);
if (lower()) {
NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToWord32());
// 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()) {
NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToWord32());
}
}
} else if (truncation.TruncatesToFloat64()) {
SetOutput(node, MachineRepresentation::kFloat64);
if (lower()) {
NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToFloat64());
// 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()) {
NodeProperties::ChangeOp(node,
simplified()->PlainPrimitiveToFloat64());
}
}
} else {
SetOutput(node, MachineRepresentation::kTagged);
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
}
return;
case IrOpcode::kObjectIsCallable:

View File

@ -204,11 +204,13 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
V(NumberClz32, Operator::kNoProperties, 1) \
V(NumberCeil, Operator::kNoProperties, 1) \
V(NumberFloor, Operator::kNoProperties, 1) \
V(NumberFround, Operator::kNoProperties, 1) \
V(NumberAtan, Operator::kNoProperties, 1) \
V(NumberAtan2, Operator::kNoProperties, 2) \
V(NumberLog, Operator::kNoProperties, 1) \
V(NumberLog1p, Operator::kNoProperties, 1) \
V(NumberRound, Operator::kNoProperties, 1) \
V(NumberSqrt, Operator::kNoProperties, 1) \
V(NumberTrunc, Operator::kNoProperties, 1) \
V(NumberToInt32, Operator::kNoProperties, 1) \
V(NumberToUint32, Operator::kNoProperties, 1) \
@ -217,9 +219,9 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
V(NumberConvertHoleNaN, Operator::kNoProperties, 1) \
V(StringFromCharCode, Operator::kNoProperties, 1) \
V(StringToNumber, Operator::kNoProperties, 1) \
V(PlainPrimitiveToNumber, Operator::kNoWrite, 1) \
V(PlainPrimitiveToWord32, Operator::kNoWrite, 1) \
V(PlainPrimitiveToFloat64, Operator::kNoWrite, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1) \
V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \

View File

@ -154,11 +154,13 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberClz32();
const Operator* NumberCeil();
const Operator* NumberFloor();
const Operator* NumberFround();
const Operator* NumberAtan();
const Operator* NumberAtan2();
const Operator* NumberLog();
const Operator* NumberLog1p();
const Operator* NumberRound();
const Operator* NumberSqrt();
const Operator* NumberTrunc();
const Operator* NumberToInt32();
const Operator* NumberToUint32();

View File

@ -1788,6 +1788,8 @@ Type* Typer::Visitor::TypeNumberFloor(Node* node) {
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::TypeNumberAtan2(Node* node) { return Type::Number(); }
@ -1800,6 +1802,8 @@ Type* Typer::Visitor::TypeNumberRound(Node* node) {
return TypeUnaryOp(node, NumberRound);
}
Type* Typer::Visitor::TypeNumberSqrt(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberTrunc(Node* node) {
return TypeUnaryOp(node, NumberTrunc);
}
@ -1902,7 +1906,7 @@ Type* Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
Type* Typer::Visitor::TypeTruncateTaggedToFloat64(Node* node) {
Type* arg = Operand(node, 0);
DCHECK(arg->Is(Type::NumberOrUndefined()));
DCHECK(arg->Is(Type::NumberOrOddball()));
return ChangeRepresentation(arg, Type::UntaggedFloat64(), zone());
}

View File

@ -675,16 +675,16 @@ void Verifier::Visitor::Check(Node* node) {
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberEqual:
// (NumberOrUndefined, NumberOrUndefined) -> Boolean
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 1, Type::NumberOrUndefined());
// (Number, Number) -> Boolean
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual:
// (Number, Number) -> Boolean
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 1, Type::NumberOrUndefined());
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kSpeculativeNumberAdd:
@ -695,16 +695,15 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kNumberMultiply:
case IrOpcode::kNumberDivide:
// (Number, Number) -> Number
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 1, Type::NumberOrUndefined());
// CheckUpperIs(node, Type::Number());
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberModulus:
// (Number, Number) -> Number
CheckValueInputIs(node, 0, 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;
case IrOpcode::kNumberBitwiseOr:
case IrOpcode::kNumberBitwiseXor:
@ -746,10 +745,12 @@ void Verifier::Visitor::Check(Node* node) {
break;
case IrOpcode::kNumberCeil:
case IrOpcode::kNumberFloor:
case IrOpcode::kNumberFround:
case IrOpcode::kNumberAtan:
case IrOpcode::kNumberLog:
case IrOpcode::kNumberLog1p:
case IrOpcode::kNumberRound:
case IrOpcode::kNumberSqrt:
case IrOpcode::kNumberTrunc:
// Number -> Number
CheckValueInputIs(node, 0, Type::Number());
@ -757,12 +758,12 @@ void Verifier::Visitor::Check(Node* node) {
break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kNumberToUint32:
// Number -> Unsigned32
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Unsigned32());
break;
case IrOpcode::kNumberIsHoleNaN:
@ -851,7 +852,7 @@ void Verifier::Visitor::Check(Node* node) {
break;
}
case IrOpcode::kChangeTaggedToFloat64: {
// Number /\ Tagged -> Number /\ UntaggedFloat64
// NumberOrUndefined /\ Tagged -> Number /\ UntaggedFloat64
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
@ -970,7 +971,7 @@ void Verifier::Visitor::Check(Node* node) {
CheckNotTyped(node);
break;
case IrOpcode::kNumberSilenceNaN:
CheckValueInputIs(node, 0, Type::NumberOrUndefined());
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number());
break;

View File

@ -219,6 +219,7 @@ namespace internal {
V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \
V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \
V(NumberOrSimdOrString, kNumber | kSimd | kString) \
V(NumberOrString, kNumber | kString) \
V(NumberOrUndefined, kNumber | kUndefined) \

View File

@ -86,11 +86,403 @@ Type* const kNumberTypes[] = {
} // namespace
// -----------------------------------------------------------------------------
// Math.atan
TEST_F(JSBuiltinReducerTest, MathAtanWithNumber) {
Node* function = MathFunction("atan");
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(), IsNumberAtan(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathAtanWithPlainPrimitive) {
Node* function = MathFunction("atan");
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(), IsNumberAtan(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.atan2
TEST_F(JSBuiltinReducerTest, MathAtan2WithNumber) {
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* 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(), IsNumberCeil(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathCeilWithPlainPrimitive) {
Node* function = MathFunction("ceil");
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(), IsNumberCeil(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.clz32
TEST_F(JSBuiltinReducerTest, MathClz32WithUnsigned32) {
Node* function = MathFunction("clz32");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Unsigned32(), 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(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* 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(p0));
}
}
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
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, MathImulWithNumber) {
Node* function = MathFunction("imul");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Number(), 0);
Node* p1 = Parameter(Type::Number(), 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(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.log
TEST_F(JSBuiltinReducerTest, MathLogWithNumber) {
Node* function = MathFunction("log");
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(), 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* 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(), 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.max
TEST_F(JSBuiltinReducerTest, MathMax0) {
TEST_F(JSBuiltinReducerTest, MathMaxWithNoArguments) {
Node* function = MathFunction("max");
Node* effect = graph()->start();
@ -106,8 +498,7 @@ TEST_F(JSBuiltinReducerTest, MathMax0) {
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
}
TEST_F(JSBuiltinReducerTest, MathMax1) {
TEST_F(JSBuiltinReducerTest, MathMaxWithNumber) {
Node* function = MathFunction("max");
Node* effect = graph()->start();
@ -126,8 +517,24 @@ TEST_F(JSBuiltinReducerTest, MathMax1) {
}
}
TEST_F(JSBuiltinReducerTest, MathMaxWithPlainPrimitive) {
Node* function = MathFunction("max");
TEST_F(JSBuiltinReducerTest, MathMax2) {
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();
@ -150,20 +557,70 @@ TEST_F(JSBuiltinReducerTest, MathMax2) {
}
}
// -----------------------------------------------------------------------------
// Math.imul
// Math.min
TEST_F(JSBuiltinReducerTest, MathMinWithNoArguments) {
Node* function = MathFunction("min");
TEST_F(JSBuiltinReducerTest, MathImul) {
Node* function = MathFunction("imul");
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* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
TRACED_FOREACH(Type*, t1, 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(), 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,
@ -172,88 +629,17 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberImul(IsNumberToUint32(p0), IsNumberToUint32(p1)));
}
}
}
// -----------------------------------------------------------------------------
// Math.fround
TEST_F(JSBuiltinReducerTest, MathFround) {
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(), IsTruncateFloat64ToFloat32(p0));
}
}
// -----------------------------------------------------------------------------
// Math.atan
TEST_F(JSBuiltinReducerTest, MathAtan) {
Node* function = MathFunction("atan");
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(), IsNumberAtan(p0));
}
}
// -----------------------------------------------------------------------------
// Math.atan2
TEST_F(JSBuiltinReducerTest, MathAtan2) {
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));
EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone,
IsNumberLessThan(p1, p0), p1, p0));
}
}
}
// -----------------------------------------------------------------------------
// Math.log
// Math.round
TEST_F(JSBuiltinReducerTest, MathLog) {
Node* function = MathFunction("log");
TEST_F(JSBuiltinReducerTest, MathRoundWithNumber) {
Node* function = MathFunction("round");
Node* effect = graph()->start();
Node* control = graph()->start();
@ -267,15 +653,32 @@ TEST_F(JSBuiltinReducerTest, MathLog) {
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberLog(p0));
EXPECT_THAT(r.replacement(), IsNumberRound(p0));
}
}
// -----------------------------------------------------------------------------
// Math.log1p
TEST_F(JSBuiltinReducerTest, MathRoundWithPlainPrimitive) {
Node* function = MathFunction("round");
TEST_F(JSBuiltinReducerTest, MathLog1p) {
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(), IsNumberRound(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.sqrt
TEST_F(JSBuiltinReducerTest, MathSqrtWithNumber) {
Node* function = MathFunction("sqrt");
Node* effect = graph()->start();
Node* control = graph()->start();
@ -289,14 +692,70 @@ TEST_F(JSBuiltinReducerTest, MathLog1p) {
Reduction r = Reduce(call);
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
TEST_F(JSBuiltinReducerTest, StringFromCharCode) {
TEST_F(JSBuiltinReducerTest, StringFromCharCodeWithNumber) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
@ -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 internal
} // namespace v8

View File

@ -2311,8 +2311,15 @@ IS_UNOP_MATCHER(Float64RoundTiesAway)
IS_UNOP_MATCHER(Float64ExtractLowWord32)
IS_UNOP_MATCHER(Float64ExtractHighWord32)
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(NumberLog1p)
IS_UNOP_MATCHER(NumberRound)
IS_UNOP_MATCHER(NumberSqrt)
IS_UNOP_MATCHER(NumberTrunc)
IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(PlainPrimitiveToNumber)

View File

@ -227,8 +227,15 @@ Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsNumberAtan(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_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*> 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*> IsAllocate(const Matcher<Node*>& size_matcher,
const Matcher<Node*>& effect_matcher,