[turbofan] Handle some arithmetic ops in early lowering.

This handles all arithmetic binary operations except addition during the
early type-hint lowering (i.e. during graph construction). We still use
static type information to potentially further reduce the speculative
operations down to pure operations during the typed lowering phase.

R=bmeurer@chromium.org

Change-Id: I8b93fd7c46ec8e5b81234a49624d503520c3d082
Reviewed-on: https://chromium-review.googlesource.com/443105
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43218}
This commit is contained in:
Michael Starzinger 2017-02-15 16:07:39 +01:00 committed by Commit Bot
parent 693b741f6d
commit 67d087d577
10 changed files with 112 additions and 92 deletions

View File

@ -2769,16 +2769,16 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op,
js_op = javascript()->Add(hint);
break;
case Token::SUB:
js_op = javascript()->Subtract(hint);
js_op = javascript()->Subtract();
break;
case Token::MUL:
js_op = javascript()->Multiply(hint);
js_op = javascript()->Multiply();
break;
case Token::DIV:
js_op = javascript()->Divide(hint);
js_op = javascript()->Divide();
break;
case Token::MOD:
js_op = javascript()->Modulus(hint);
js_op = javascript()->Modulus();
break;
default:
UNREACHABLE();

View File

@ -1557,23 +1557,17 @@ void BytecodeGraphBuilder::VisitAdd() {
}
void BytecodeGraphBuilder::VisitSub() {
BuildBinaryOp(javascript()->Subtract(
GetBinaryOperationHint(kBinaryOperationHintIndex)));
BuildBinaryOp(javascript()->Subtract());
}
void BytecodeGraphBuilder::VisitMul() {
BuildBinaryOp(javascript()->Multiply(
GetBinaryOperationHint(kBinaryOperationHintIndex)));
BuildBinaryOp(javascript()->Multiply());
}
void BytecodeGraphBuilder::VisitDiv() {
BuildBinaryOp(
javascript()->Divide(GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitDiv() { BuildBinaryOp(javascript()->Divide()); }
void BytecodeGraphBuilder::VisitMod() {
BuildBinaryOp(
javascript()->Modulus(GetBinaryOperationHint(kBinaryOperationHintIndex)));
BuildBinaryOp(javascript()->Modulus());
}
void BytecodeGraphBuilder::VisitBitwiseOr() {
@ -1605,10 +1599,10 @@ void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* op) {
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* right = jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0));
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kBinaryOperationSmiHintIndex));
Node* node = nullptr;
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kBinaryOperationSmiHintIndex));
if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
node = simplified;
} else {
@ -1624,8 +1618,7 @@ void BytecodeGraphBuilder::VisitAddSmi() {
}
void BytecodeGraphBuilder::VisitSubSmi() {
BuildBinaryOpWithImmediate(javascript()->Subtract(
GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
BuildBinaryOpWithImmediate(javascript()->Subtract());
}
void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
@ -1648,19 +1641,37 @@ void BytecodeGraphBuilder::VisitInc() {
PrepareEagerCheckpoint();
// Note: Use subtract -1 here instead of add 1 to ensure we always convert to
// a number, not a string.
const Operator* js_op =
javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
jsgraph()->Constant(-1));
Node* left = environment()->LookupAccumulator();
Node* right = jsgraph()->Constant(-1);
const Operator* op = javascript()->Subtract();
Node* node = nullptr;
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
node = simplified;
} else {
node = NewNode(op, left, right);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitDec() {
PrepareEagerCheckpoint();
const Operator* js_op =
javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
jsgraph()->OneConstant());
Node* left = environment()->LookupAccumulator();
Node* right = jsgraph()->OneConstant();
const Operator* op = javascript()->Subtract();
Node* node = nullptr;
FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
node = simplified;
} else {
node = NewNode(op, left, right);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}

View File

@ -545,6 +545,10 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(ShiftLeft, Operator::kNoProperties, 2, 1) \
V(ShiftRight, Operator::kNoProperties, 2, 1) \
V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \
V(Subtract, Operator::kNoProperties, 2, 1) \
V(Multiply, Operator::kNoProperties, 2, 1) \
V(Divide, Operator::kNoProperties, 2, 1) \
V(Modulus, Operator::kNoProperties, 2, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \
@ -568,12 +572,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(Debugger, Operator::kNoProperties, 0, 0) \
V(GetSuperConstructor, Operator::kNoWrite, 1, 1)
#define BINARY_OP_LIST(V) \
V(Add) \
V(Subtract) \
V(Multiply) \
V(Divide) \
V(Modulus)
#define BINARY_OP_LIST(V) V(Add)
#define COMPARE_OP_LIST(V) \
V(Equal, Operator::kNoProperties) \

View File

@ -579,10 +579,10 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ShiftRight();
const Operator* ShiftRightLogical();
const Operator* Add(BinaryOperationHint hint);
const Operator* Subtract(BinaryOperationHint hint);
const Operator* Multiply(BinaryOperationHint hint);
const Operator* Divide(BinaryOperationHint hint);
const Operator* Modulus(BinaryOperationHint hint);
const Operator* Subtract();
const Operator* Multiply();
const Operator* Divide();
const Operator* Modulus();
const Operator* ToBoolean(ToBooleanHints hints);
const Operator* ToInteger();

View File

@ -127,7 +127,11 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical: {
case IrOpcode::kJSShiftRightLogical:
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: {
JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
NumberOperationHint hint;
if (b.GetBinaryNumberOperationHint(&hint)) {
@ -137,10 +141,6 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
break;
}
case IrOpcode::kJSAdd:
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
// TODO(mstarzinger): Implement speculative lowering.
break;
default:

View File

@ -370,6 +370,25 @@ class JSBinopReduction final {
return nullptr;
}
const Operator* NumberOpFromSpeculativeNumberOp() {
switch (node_->opcode()) {
case IrOpcode::kSpeculativeNumberAdd:
return simplified()->NumberAdd();
case IrOpcode::kSpeculativeNumberSubtract:
return simplified()->NumberSubtract();
case IrOpcode::kSpeculativeNumberMultiply:
return simplified()->NumberMultiply();
case IrOpcode::kSpeculativeNumberDivide:
return simplified()->NumberDivide();
case IrOpcode::kSpeculativeNumberModulus:
return simplified()->NumberModulus();
default:
break;
}
UNREACHABLE();
return nullptr;
}
const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
switch (node_->opcode()) {
case IrOpcode::kJSAdd:
@ -632,16 +651,6 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::NumberOrOddball())) {
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
}
return r.ChangeToSpeculativeOperator(r.SpeculativeNumberOp(hint),
Type::Number());
}
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
@ -650,6 +659,18 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
return NoChange();
}
Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::NumberOrOddball())) {
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
Type::Number());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::PlainPrimitive()) ||
@ -2473,6 +2494,13 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSGeneratorRestoreContinuation(node);
case IrOpcode::kJSGeneratorRestoreRegister:
return ReduceJSGeneratorRestoreRegister(node);
// TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
// fooling anyone. Consider moving this into a separate reducer.
case IrOpcode::kSpeculativeNumberSubtract:
case IrOpcode::kSpeculativeNumberMultiply:
case IrOpcode::kSpeculativeNumberDivide:
case IrOpcode::kSpeculativeNumberModulus:
return ReduceSpeculativeNumberBinop(node);
default:
break;
}

View File

@ -84,6 +84,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceInt32Binop(Node* node);
Reduction ReduceUI32Shift(Node* node, Signedness signedness);
Reduction ReduceCreateConsString(Node* node);
Reduction ReduceSpeculativeNumberBinop(Node* node);
Factory* factory() const;
Graph* graph() const;

View File

@ -264,11 +264,11 @@ TEST(AddNumber1) {
TEST(NumberBinops) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
R.javascript.Modulus(R.binop_hints), R.simplified.NumberModulus(),
R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(), R.simplified.NumberSubtract(),
R.javascript.Multiply(), R.simplified.NumberMultiply(),
R.javascript.Divide(), R.simplified.NumberDivide(),
R.javascript.Modulus(), R.simplified.NumberModulus(),
};
for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
@ -899,13 +899,13 @@ TEST(RemovePureNumberBinopEffects) {
R.simplified.NumberEqual(),
R.javascript.Add(R.binop_hints),
R.simplified.NumberAdd(),
R.javascript.Subtract(R.binop_hints),
R.javascript.Subtract(),
R.simplified.NumberSubtract(),
R.javascript.Multiply(R.binop_hints),
R.javascript.Multiply(),
R.simplified.NumberMultiply(),
R.javascript.Divide(R.binop_hints),
R.javascript.Divide(),
R.simplified.NumberDivide(),
R.javascript.Modulus(R.binop_hints),
R.javascript.Modulus(),
R.simplified.NumberModulus(),
R.javascript.LessThan(R.compare_hints),
R.simplified.NumberLessThan(),
@ -931,8 +931,8 @@ TEST(OrderNumberBinopEffects1) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Subtract(), R.simplified.NumberSubtract(),
R.javascript.Multiply(), R.simplified.NumberMultiply(),
};
for (size_t j = 0; j < arraysize(ops); j += 2) {
@ -956,9 +956,9 @@ TEST(OrderNumberBinopEffects2) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(), R.simplified.NumberSubtract(),
R.javascript.Multiply(), R.simplified.NumberMultiply(),
};
for (size_t j = 0; j < arraysize(ops); j += 2) {

View File

@ -717,25 +717,6 @@ TEST_F(JSTypedLoweringTest, JSAddSmis) {
rhs, effect, control));
}
// -----------------------------------------------------------------------------
// JSSubtract
TEST_F(JSTypedLoweringTest, JSSubtractSmis) {
BinaryOperationHint const hint = BinaryOperationHint::kSignedSmall;
Node* lhs = Parameter(Type::Number(), 0);
Node* rhs = Parameter(Type::Number(), 1);
Node* context = Parameter(Type::Any(), 2);
Node* frame_state = EmptyFrameState();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->Subtract(hint), lhs, rhs,
context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberSubtract(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -245,22 +245,22 @@ TEST_F(TyperTest, TypeJSAdd) {
TEST_F(TyperTest, TypeJSSubtract) {
TestBinaryArithOp(javascript_.Subtract(hints_), std::minus<double>());
TestBinaryArithOp(javascript_.Subtract(), std::minus<double>());
}
TEST_F(TyperTest, TypeJSMultiply) {
TestBinaryArithOp(javascript_.Multiply(hints_), std::multiplies<double>());
TestBinaryArithOp(javascript_.Multiply(), std::multiplies<double>());
}
TEST_F(TyperTest, TypeJSDivide) {
TestBinaryArithOp(javascript_.Divide(hints_), std::divides<double>());
TestBinaryArithOp(javascript_.Divide(), std::divides<double>());
}
TEST_F(TyperTest, TypeJSModulus) {
TestBinaryArithOp(javascript_.Modulus(hints_), modulo);
TestBinaryArithOp(javascript_.Modulus(), modulo);
}
@ -366,6 +366,10 @@ TEST_BINARY_MONOTONICITY(BitwiseAnd)
TEST_BINARY_MONOTONICITY(ShiftLeft)
TEST_BINARY_MONOTONICITY(ShiftRight)
TEST_BINARY_MONOTONICITY(ShiftRightLogical)
TEST_BINARY_MONOTONICITY(Subtract)
TEST_BINARY_MONOTONICITY(Multiply)
TEST_BINARY_MONOTONICITY(Divide)
TEST_BINARY_MONOTONICITY(Modulus)
#undef TEST_BINARY_MONOTONICITY
#define TEST_BINARY_MONOTONICITY(name) \
@ -373,10 +377,6 @@ TEST_BINARY_MONOTONICITY(ShiftRightLogical)
TestBinaryMonotonicity(javascript_.name(BinaryOperationHint::kAny)); \
}
TEST_BINARY_MONOTONICITY(Add)
TEST_BINARY_MONOTONICITY(Subtract)
TEST_BINARY_MONOTONICITY(Multiply)
TEST_BINARY_MONOTONICITY(Divide)
TEST_BINARY_MONOTONICITY(Modulus)
#undef TEST_BINARY_MONOTONICITY
} // namespace compiler