Commit d93fd41a authored by epertoso's avatar epertoso Committed by Commit bot

[turbofan] Introduces the SpeculativeNumberShiftLeft opcode.

Typed lowering now produces SpeculativeNumberShiftLeft for JSShiftLeft if the type feedback is kSignedSmall or kSigned32.

BUG=v8:4583
LOG=n

Review-Url: https://codereview.chromium.org/2150553002
Cr-Commit-Position: refs/heads/master@{#37762}
parent 5abc73a1
......@@ -583,6 +583,27 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
return r.ChangeToPureOperator(intOp, Type::Integral32());
}
Reduction JSTypedLowering::ReduceShiftLeft(Node* node) {
if (flags() & kDisableIntegerBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kSigned32 ||
feedback == BinaryOperationHints::kSignedSmall) {
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberShiftLeft(feedback), Type::Signed32());
}
// If deoptimization is enabled we rely on type feedback.
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
r.ConvertInputsToUI32(kSigned, kUnsigned);
return r.ChangeToPureOperator(simplified()->NumberShiftLeft(),
Type::Number());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
Signedness left_signedness,
......@@ -1939,7 +1960,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSBitwiseAnd:
return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
case IrOpcode::kJSShiftLeft:
return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
return ReduceShiftLeft(node);
case IrOpcode::kJSShiftRight:
return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
case IrOpcode::kJSShiftRightLogical:
......
......@@ -84,6 +84,7 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSSubtract(Node* node);
Reduction ReduceJSDivide(Node* node);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
Reduction ReduceShiftLeft(Node* node);
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
const Operator* shift_op);
......
......@@ -220,6 +220,7 @@
V(NumberBitwiseXor) \
V(NumberBitwiseAnd) \
V(NumberShiftLeft) \
V(SpeculativeNumberShiftLeft) \
V(NumberShiftRight) \
V(NumberShiftRightLogical) \
V(NumberImul) \
......
......@@ -100,6 +100,31 @@ UseInfo UseInfoForBasePointer(const ElementAccess& access) {
return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
}
void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsControlEdge(edge)) {
edge.UpdateTo(control);
} else if (NodeProperties::IsEffectEdge(edge)) {
edge.UpdateTo(effect);
} else {
DCHECK(NodeProperties::IsValueEdge(edge));
}
}
}
void ChangeToPureOp(Node* node, const Operator* new_op) {
if (node->op()->EffectInputCount() > 0) {
DCHECK_LT(0, node->op()->ControlInputCount());
// Disconnect the node from effect and control chains.
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control);
node->TrimInputCount(new_op->ValueInputCount());
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
}
NodeProperties::ChangeOp(node, new_op);
}
#ifdef DEBUG
// Helpers for monotonicity checking.
......@@ -1048,33 +1073,6 @@ class RepresentationSelector {
return jsgraph_->simplified();
}
void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsControlEdge(edge)) {
edge.UpdateTo(control);
} else if (NodeProperties::IsEffectEdge(edge)) {
edge.UpdateTo(effect);
} else {
DCHECK(NodeProperties::IsValueEdge(edge));
}
}
}
void ChangeToPureOp(Node* node, const Operator* new_op) {
if (node->op()->EffectInputCount() > 0) {
DCHECK_LT(0, node->op()->ControlInputCount());
// Disconnect the node from effect and control chains.
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control);
node->TrimInputCount(new_op->ValueInputCount());
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
}
NodeProperties::ChangeOp(node, new_op);
}
void ChangeToInt32OverflowOp(Node* node) {
NodeProperties::ChangeOp(node, Int32OverflowOp(node));
}
......@@ -1561,6 +1559,40 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kSpeculativeNumberShiftLeft: {
if (BothInputsAre(node, Type::NumberOrOddball())) {
Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, UseInfo::TruncatingWord32(),
UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
}
return;
}
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
Type* rhs_type = GetUpperBound(node->InputAt(1));
if (truncation.TruncatesToWord32()) {
VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(),
rhs_type);
}
} else {
VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(),
rhs_type);
}
}
return;
}
UNREACHABLE();
}
case IrOpcode::kNumberShiftRight: {
Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, UseInfo::TruncatingWord32(),
......@@ -3237,7 +3269,8 @@ void SimplifiedLowering::DoShift(Node* node, Operator const* op,
node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
jsgraph()->Int32Constant(0x1f)));
}
NodeProperties::ChangeOp(node, op);
DCHECK(op->HasProperty(Operator::kPure));
ChangeToPureOp(node, op);
}
void SimplifiedLowering::DoStringToNumber(Node* node) {
......
......@@ -217,7 +217,8 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
op->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
op->opcode() == IrOpcode::kSpeculativeNumberMultiply ||
op->opcode() == IrOpcode::kSpeculativeNumberDivide ||
op->opcode() == IrOpcode::kSpeculativeNumberModulus);
op->opcode() == IrOpcode::kSpeculativeNumberModulus ||
op->opcode() == IrOpcode::kSpeculativeNumberShiftLeft);
return OpParameter<BinaryOperationHints::Hint>(op);
}
......@@ -309,7 +310,8 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(SpeculativeNumberSubtract) \
V(SpeculativeNumberDivide) \
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberModulus)
V(SpeculativeNumberModulus) \
V(SpeculativeNumberShiftLeft)
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
......
......@@ -214,6 +214,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* SpeculativeNumberMultiply(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberDivide(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberModulus(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberShiftLeft(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThan(CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThanOrEqual(
......
......@@ -1556,6 +1556,10 @@ Type* Typer::Visitor::TypeSpeculativeNumberModulus(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberShiftLeft(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberMultiply(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberDivide(Node* node) { return Type::Number(); }
......
......@@ -697,6 +697,9 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned32());
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kSpeculativeNumberShiftLeft:
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kNumberShiftRightLogical:
// (Unsigned32, Unsigned32) -> Unsigned32
CheckValueInputIs(node, 0, Type::Unsigned32());
......
......@@ -56,3 +56,14 @@
assertEquals(1, f3(0, 1));
assertEquals(1.5, f3(1, 1));
})();
(function ShiftLeftSmis() {
function f4(a, b) {
return a << b;
}
assertEquals(24, f4(3, 3));
assertEquals(40, f4(5, 3));
%OptimizeFunctionOnNextCall(f4);
assertEquals(64, f4(4, 4));
})();
......@@ -887,12 +887,31 @@ TEST_F(JSTypedLoweringTest, JSSubtractSmis) {
lhs, rhs, effect, control));
}
// -----------------------------------------------------------------------------
// JSShiftLeft
TEST_F(JSTypedLoweringTest, JSShiftLeftSmis) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftLeft(hints), lhs, rhs, UndefinedConstant(),
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftLeft(BinaryOperationHints::kSignedSmall,
lhs, rhs, effect, control));
}
// -----------------------------------------------------------------------------
// JSInstanceOf
// Test that instanceOf is reduced if and only if the right-hand side is a
// function constant. Functional correctness is ensured elsewhere.
TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithoutSmiCheck) {
Node* const context = Parameter(Type::Any());
Node* const frame_state = EmptyFrameState();
......
......@@ -2050,6 +2050,16 @@ Matcher<Node*> IsSpeculativeNumberSubtract(
rhs_matcher, effect_matcher, control_matcher));
}
Matcher<Node*> IsSpeculativeNumberShiftLeft(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(new IsSpeculativeBinopMatcher(
IrOpcode::kSpeculativeNumberShiftLeft, hint_matcher, lhs_matcher,
rhs_matcher, effect_matcher, control_matcher));
}
Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
......
......@@ -212,6 +212,11 @@ Matcher<Node*> IsSpeculativeNumberSubtract(
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsSpeculativeNumberShiftLeft(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_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