[turbofan] Handle arithmetic addition in early lowering.

This handles arithmetic addition operations during the early type-hint
lowering (i.e. during graph construction). The string addition case is
still handled by {JSTypedLowering} as it needs static type information.

R=bmeurer@chromium.org

Change-Id: I9df47dfc5bf7613c51f6d803ab43d5d3f6c21be8
Reviewed-on: https://chromium-review.googlesource.com/443185
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43235}
This commit is contained in:
Michael Starzinger 2017-02-15 16:56:21 +01:00 committed by Commit Bot
parent c0fe56e63d
commit 9d53d16bcf
7 changed files with 28 additions and 64 deletions

View File

@ -1942,8 +1942,9 @@ void BytecodeGraphBuilder::VisitForInStep() {
PrepareEagerCheckpoint();
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall), index,
jsgraph()->OneConstant());
index = NewNode(
simplified()->SpeculativeNumberAdd(NumberOperationHint::kSignedSmall),
index, jsgraph()->OneConstant());
environment()->BindAccumulator(index, Environment::kAttachFrameState);
}

View File

@ -518,11 +518,7 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
}
BinaryOperationHint BinaryOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract ||
op->opcode() == IrOpcode::kJSMultiply ||
op->opcode() == IrOpcode::kJSDivide ||
op->opcode() == IrOpcode::kJSModulus);
DCHECK_EQ(IrOpcode::kJSAdd, op->opcode());
return OpParameter<BinaryOperationHint>(op);
}

View File

@ -128,6 +128,7 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
case IrOpcode::kJSAdd:
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
@ -140,9 +141,6 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
}
break;
}
case IrOpcode::kJSAdd:
// TODO(mstarzinger): Implement speculative lowering.
break;
default:
UNREACHABLE();
break;

View File

@ -30,30 +30,6 @@ class JSBinopReduction final {
JSBinopReduction(JSTypedLowering* lowering, Node* node)
: lowering_(lowering), node_(node) {}
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
DCHECK_NE(0, node_->op()->ControlOutputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node_->op()));
switch (BinaryOperationHintOf(node_->op())) {
case BinaryOperationHint::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case BinaryOperationHint::kSigned32:
*hint = NumberOperationHint::kSigned32;
return true;
case BinaryOperationHint::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
case BinaryOperationHint::kAny:
case BinaryOperationHint::kNone:
case BinaryOperationHint::kString:
break;
}
}
return false;
}
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
@ -113,6 +89,7 @@ class JSBinopReduction final {
// minimum length.
bool ShouldCreateConsString() {
DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
DCHECK(OneInputIs(Type::String()));
if (BothInputsAre(Type::String()) ||
((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) &&
BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) {
@ -590,20 +567,22 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
}
}
Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) {
// SpeculativeNumberAdd(x:-string, y:-string) =>
// NumberAdd(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(hint), Type::Number());
}
if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y)
r.ConvertInputsToNumber();
@ -2496,6 +2475,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSGeneratorRestoreRegister(node);
// TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
// fooling anyone. Consider moving this into a separate reducer.
case IrOpcode::kSpeculativeNumberAdd:
return ReduceSpeculativeNumberAdd(node);
case IrOpcode::kSpeculativeNumberSubtract:
case IrOpcode::kSpeculativeNumberMultiply:
case IrOpcode::kSpeculativeNumberDivide:

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 ReduceSpeculativeNumberAdd(Node* node);
Reduction ReduceSpeculativeNumberBinop(Node* node);
Factory* factory() const;

View File

@ -1187,8 +1187,11 @@ class RepresentationSelector {
// ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can
// only eliminate an unused speculative number operation if we know that
// the inputs are PlainPrimitive, which excludes everything that's might
// have side effects or throws during a ToNumber conversion.
if (BothInputsAre(node, Type::PlainPrimitive())) {
// have side effects or throws during a ToNumber conversion. We are only
// allowed to perform a number addition if neither input is a String, even
// if the value is never used, so we further limit to NumberOrOddball in
// order to explicitly exclude String inputs.
if (BothInputsAre(node, Type::NumberOrOddball())) {
if (truncation.IsUnused()) return VisitUnused(node);
}

View File

@ -701,22 +701,6 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) {
lhs, rhs, context, frame_state, effect, control));
}
TEST_F(JSTypedLoweringTest, JSAddSmis) {
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()->Add(hint), lhs, rhs,
context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberAdd(NumberOperationHint::kSignedSmall, lhs,
rhs, effect, control));
}
} // namespace compiler
} // namespace internal
} // namespace v8