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

[turbofan] Fix optimized lowering of Math.imul.

We eagerly inserted Int32Mul for Math.imul during builtin lowering and
messed up with the types, which confused the representation selection.
This adds a proper NumberImul operator, and fixes the builtin reducer to
do the right thing according to the spec.

R=mstarzinger@chromium.org
BUG=v8:5006
LOG=n

Review-Url: https://codereview.chromium.org/1971163002
Cr-Commit-Position: refs/heads/master@{#36219}
parent 83b9e1be
...@@ -117,13 +117,15 @@ Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { ...@@ -117,13 +117,15 @@ Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
return NoChange(); return NoChange();
} }
// ES6 section 20.2.2.19 Math.imul ( x, y )
// ES6 draft 08-24-14, section 20.2.2.19.
Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchTwo(Type::Integral32(), Type::Integral32())) { if (r.InputsMatchTwo(Type::Number(), Type::Number())) {
// Math.imul(a:int32, b:int32) -> Int32Mul(a, b) // Math.imul(a:number, b:number) -> NumberImul(NumberToUint32(a),
Node* value = graph()->NewNode(machine()->Int32Mul(), r.left(), r.right()); // 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);
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
......
...@@ -186,6 +186,7 @@ ...@@ -186,6 +186,7 @@
V(NumberShiftLeft) \ V(NumberShiftLeft) \
V(NumberShiftRight) \ V(NumberShiftRight) \
V(NumberShiftRightLogical) \ V(NumberShiftRightLogical) \
V(NumberImul) \
V(NumberClz32) \ V(NumberClz32) \
V(NumberCeil) \ V(NumberCeil) \
V(NumberFloor) \ V(NumberFloor) \
......
...@@ -491,6 +491,8 @@ const Operator* RepresentationChanger::Uint32OperatorFor( ...@@ -491,6 +491,8 @@ const Operator* RepresentationChanger::Uint32OperatorFor(
return machine()->Uint32LessThanOrEqual(); return machine()->Uint32LessThanOrEqual();
case IrOpcode::kNumberClz32: case IrOpcode::kNumberClz32:
return machine()->Word32Clz(); return machine()->Word32Clz();
case IrOpcode::kNumberImul:
return machine()->Int32Mul();
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
......
...@@ -1043,6 +1043,12 @@ class RepresentationSelector { ...@@ -1043,6 +1043,12 @@ class RepresentationSelector {
if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node)); if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
break; break;
} }
case IrOpcode::kNumberImul: {
VisitBinop(node, UseInfo::TruncatingWord32(),
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
break;
}
case IrOpcode::kNumberCeil: { case IrOpcode::kNumberCeil: {
VisitUnop(node, UseInfo::TruncatingFloat64(), VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64); MachineRepresentation::kFloat64);
......
...@@ -189,6 +189,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) { ...@@ -189,6 +189,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
V(NumberShiftLeft, Operator::kNoProperties, 2) \ V(NumberShiftLeft, Operator::kNoProperties, 2) \
V(NumberShiftRight, Operator::kNoProperties, 2) \ V(NumberShiftRight, Operator::kNoProperties, 2) \
V(NumberShiftRightLogical, Operator::kNoProperties, 2) \ V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
V(NumberImul, Operator::kCommutative, 2) \
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) \
......
...@@ -146,6 +146,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -146,6 +146,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberShiftLeft(); const Operator* NumberShiftLeft();
const Operator* NumberShiftRight(); const Operator* NumberShiftRight();
const Operator* NumberShiftRightLogical(); const Operator* NumberShiftRightLogical();
const Operator* NumberImul();
const Operator* NumberClz32(); const Operator* NumberClz32();
const Operator* NumberCeil(); const Operator* NumberCeil();
const Operator* NumberFloor(); const Operator* NumberFloor();
......
...@@ -1745,6 +1745,8 @@ Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) { ...@@ -1745,6 +1745,8 @@ Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) {
return Type::Unsigned32(); return Type::Unsigned32();
} }
Type* Typer::Visitor::TypeNumberImul(Node* node) { return Type::Signed32(); }
Type* Typer::Visitor::TypeNumberClz32(Node* node) { Type* Typer::Visitor::TypeNumberClz32(Node* node) {
return typer_->cache_.kZeroToThirtyTwo; return typer_->cache_.kZeroToThirtyTwo;
} }
......
...@@ -700,6 +700,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -700,6 +700,12 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned32()); CheckValueInputIs(node, 1, Type::Unsigned32());
CheckUpperIs(node, Type::Unsigned32()); CheckUpperIs(node, Type::Unsigned32());
break; break;
case IrOpcode::kNumberImul:
// (Unsigned32, Unsigned32) -> Signed32
CheckValueInputIs(node, 0, Type::Unsigned32());
CheckValueInputIs(node, 1, Type::Unsigned32());
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kNumberClz32: case IrOpcode::kNumberClz32:
// Unsigned32 -> Unsigned32 // Unsigned32 -> Unsigned32
CheckValueInputIs(node, 0, Type::Unsigned32()); CheckValueInputIs(node, 0, Type::Unsigned32());
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function foo(x) { return Math.imul(x|0, 2); }
print(foo(1));
print(foo(1));
%OptimizeFunctionOnNextCall(foo);
print(foo(1));
...@@ -149,8 +149,8 @@ TEST_F(JSBuiltinReducerTest, MathImul) { ...@@ -149,8 +149,8 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
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) { TRACED_FOREACH(Type*, t0, kNumberTypes) {
TRACED_FOREACH(Type*, t1, kIntegral32Types) { TRACED_FOREACH(Type*, t1, kNumberTypes) {
Node* p0 = Parameter(t0, 0); Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1); Node* p1 = Parameter(t1, 1);
Node* call = graph()->NewNode(javascript()->CallFunction(4), function, Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
...@@ -159,7 +159,8 @@ TEST_F(JSBuiltinReducerTest, MathImul) { ...@@ -159,7 +159,8 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
Reduction r = Reduce(call); Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); EXPECT_THAT(r.replacement(),
IsNumberImul(IsNumberToUint32(p0), IsNumberToUint32(p1)));
} }
} }
} }
......
...@@ -2196,6 +2196,7 @@ IS_BINOP_MATCHER(NumberMultiply) ...@@ -2196,6 +2196,7 @@ IS_BINOP_MATCHER(NumberMultiply)
IS_BINOP_MATCHER(NumberShiftLeft) IS_BINOP_MATCHER(NumberShiftLeft)
IS_BINOP_MATCHER(NumberShiftRight) IS_BINOP_MATCHER(NumberShiftRight)
IS_BINOP_MATCHER(NumberShiftRightLogical) IS_BINOP_MATCHER(NumberShiftRightLogical)
IS_BINOP_MATCHER(NumberImul)
IS_BINOP_MATCHER(Word32And) IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Or) IS_BINOP_MATCHER(Word32Or)
IS_BINOP_MATCHER(Word32Xor) IS_BINOP_MATCHER(Word32Xor)
......
...@@ -209,6 +209,8 @@ Matcher<Node*> IsNumberShiftRight(const Matcher<Node*>& lhs_matcher, ...@@ -209,6 +209,8 @@ Matcher<Node*> IsNumberShiftRight(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberShiftRightLogical(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberShiftRightLogical(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_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,
const Matcher<Node*>& control_matcher); const Matcher<Node*>& control_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