diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 5f195ab6a6..2705f29336 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -702,6 +702,8 @@ namespace internal { TFC(SameValue, Compare, 1) \ TFC(StrictEqual, Compare, 1) \ TFS(BitwiseNot, kValue) \ + TFS(Decrement, kValue) \ + TFS(Increment, kValue) \ TFS(Negate, kValue) \ \ /* Object */ \ diff --git a/src/builtins/builtins-number-gen.cc b/src/builtins/builtins-number-gen.cc index 2ea9b7bffd..23dc0f813a 100644 --- a/src/builtins/builtins-number-gen.cc +++ b/src/builtins/builtins-number-gen.cc @@ -771,6 +771,45 @@ TF_BUILTIN(BitwiseNot, NumberBuiltinsAssembler) { } } +TF_BUILTIN(Decrement, NumberBuiltinsAssembler) { + Node* context = Parameter(Descriptor::kContext); + VARIABLE(var_input, MachineRepresentation::kTagged); + Label do_number(this), do_bigint(this); + + UnaryOp(&var_input, &do_number, &do_number, nullptr, &do_bigint); + + BIND(&do_number); + { + TailCallBuiltin(Builtins::kSubtract, context, var_input.value(), + SmiConstant(1)); + } + + BIND(&do_bigint); + { + Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), + SmiConstant(Operation::kDecrement))); + } +} + +TF_BUILTIN(Increment, NumberBuiltinsAssembler) { + Node* context = Parameter(Descriptor::kContext); + VARIABLE(var_input, MachineRepresentation::kTagged); + Label do_number(this), do_bigint(this); + + UnaryOp(&var_input, &do_number, &do_number, nullptr, &do_bigint); + + BIND(&do_number); + { + TailCallBuiltin(Builtins::kAdd, context, var_input.value(), SmiConstant(1)); + } + + BIND(&do_bigint); + { + Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), + SmiConstant(Operation::kIncrement))); + } +} + TF_BUILTIN(Negate, NumberBuiltinsAssembler) { VARIABLE(var_input, MachineRepresentation::kTagged); VARIABLE(var_input_double, MachineRepresentation::kFloat64); diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index 7569d407c0..523448573d 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -2015,6 +2015,27 @@ void BytecodeGraphBuilder::VisitThrowSuperAlreadyCalledIfNotHole() { Runtime::kThrowSuperAlreadyCalledError); } +void BytecodeGraphBuilder::BuildUnaryOp(const Operator* op) { + PrepareEagerCheckpoint(); + Node* operand = environment()->LookupAccumulator(); + + FeedbackSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex)); + JSTypeHintLowering::LoweringResult lowering = + TryBuildSimplifiedUnaryOp(op, operand, slot); + if (lowering.IsExit()) return; + + Node* node = nullptr; + if (lowering.IsSideEffectFree()) { + node = lowering.value(); + } else { + DCHECK(!lowering.Changed()); + node = NewNode(op, operand); + } + + environment()->BindAccumulator(node, Environment::kAttachFrameState); +} + void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) { PrepareEagerCheckpoint(); Node* left = @@ -2084,48 +2105,19 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const { } void BytecodeGraphBuilder::VisitBitwiseNot() { - // TODO(neis): Define a BuildUnaryOp helper function. - PrepareEagerCheckpoint(); + BuildUnaryOp(javascript()->BitwiseNot()); +} - FeedbackSlot slot = feedback_vector()->ToSlot( - bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex)); - const Operator* op = javascript()->BitwiseNot(); - Node* operand = environment()->LookupAccumulator(); +void BytecodeGraphBuilder::VisitDec() { + BuildUnaryOp(javascript()->Decrement()); +} - JSTypeHintLowering::LoweringResult lowering = - TryBuildSimplifiedUnaryOp(op, operand, slot); - if (lowering.IsExit()) return; - Node* node = nullptr; - if (lowering.IsSideEffectFree()) { - node = lowering.value(); - } else { - DCHECK(!lowering.Changed()); - node = NewNode(op, operand); - } - - environment()->BindAccumulator(node, Environment::kAttachFrameState); +void BytecodeGraphBuilder::VisitInc() { + BuildUnaryOp(javascript()->Increment()); } void BytecodeGraphBuilder::VisitNegate() { - PrepareEagerCheckpoint(); - - FeedbackSlot slot = feedback_vector()->ToSlot( - bytecode_iterator().GetIndexOperand(kUnaryOperationHintIndex)); - const Operator* op = javascript()->Negate(); - Node* operand = environment()->LookupAccumulator(); - - JSTypeHintLowering::LoweringResult lowering = - TryBuildSimplifiedUnaryOp(op, operand, slot); - if (lowering.IsExit()) return; - Node* node = nullptr; - if (lowering.IsSideEffectFree()) { - node = lowering.value(); - } else { - DCHECK(!lowering.Changed()); - node = NewNode(op, operand); - } - - environment()->BindAccumulator(node, Environment::kAttachFrameState); + BuildUnaryOp(javascript()->Negate()); } void BytecodeGraphBuilder::VisitAdd() { @@ -2237,52 +2229,6 @@ void BytecodeGraphBuilder::VisitShiftRightLogicalSmi() { BuildBinaryOpWithImmediate(javascript()->ShiftRightLogical()); } -void BytecodeGraphBuilder::VisitInc() { - PrepareEagerCheckpoint(); - // Note: Use subtract -1 here instead of add 1 to ensure we always convert to - // a number, not a string. - Node* left = environment()->LookupAccumulator(); - Node* right = jsgraph()->Constant(-1); - const Operator* op = javascript()->Subtract(); - - FeedbackSlot slot = feedback_vector()->ToSlot( - bytecode_iterator().GetIndexOperand(kCountOperationHintIndex)); - JSTypeHintLowering::LoweringResult lowering = - TryBuildSimplifiedBinaryOp(op, left, right, slot); - if (lowering.IsExit()) return; - - Node* node = nullptr; - if (lowering.IsSideEffectFree()) { - node = lowering.value(); - } else { - DCHECK(!lowering.Changed()); - node = NewNode(op, left, right); - } - environment()->BindAccumulator(node, Environment::kAttachFrameState); -} - -void BytecodeGraphBuilder::VisitDec() { - PrepareEagerCheckpoint(); - Node* left = environment()->LookupAccumulator(); - Node* right = jsgraph()->OneConstant(); - const Operator* op = javascript()->Subtract(); - - FeedbackSlot slot = feedback_vector()->ToSlot( - bytecode_iterator().GetIndexOperand(kCountOperationHintIndex)); - JSTypeHintLowering::LoweringResult lowering = - TryBuildSimplifiedBinaryOp(op, left, right, slot); - if (lowering.IsExit()) return; - - Node* node = nullptr; - if (lowering.IsSideEffectFree()) { - node = lowering.value(); - } else { - DCHECK(!lowering.Changed()); - node = NewNode(op, left, right); - } - environment()->BindAccumulator(node, Environment::kAttachFrameState); -} - void BytecodeGraphBuilder::VisitLogicalNot() { Node* value = environment()->LookupAccumulator(); Node* node = NewNode(simplified()->BooleanNot(), value); diff --git a/src/compiler/bytecode-graph-builder.h b/src/compiler/bytecode-graph-builder.h index 737fb52a81..562c3ddaea 100644 --- a/src/compiler/bytecode-graph-builder.h +++ b/src/compiler/bytecode-graph-builder.h @@ -171,6 +171,7 @@ class BytecodeGraphBuilder { std::initializer_list args, int slot_id) { BuildCall(receiver_mode, args.begin(), args.size(), slot_id); } + void BuildUnaryOp(const Operator* op); void BuildBinaryOp(const Operator* op); void BuildBinaryOpWithImmediate(const Operator* op); void BuildCompareOp(const Operator* op); diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 3e75a4afab..e89ea28bbd 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -71,6 +71,8 @@ REPLACE_STUB_CALL(LessThanOrEqual) REPLACE_STUB_CALL(GreaterThan) REPLACE_STUB_CALL(GreaterThanOrEqual) REPLACE_STUB_CALL(BitwiseNot) +REPLACE_STUB_CALL(Decrement) +REPLACE_STUB_CALL(Increment) REPLACE_STUB_CALL(Negate) REPLACE_STUB_CALL(HasProperty) REPLACE_STUB_CALL(Equal) diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 13abf20dc6..d53dd52e59 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -578,6 +578,8 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { V(Divide, Operator::kNoProperties, 2, 1) \ V(Modulus, Operator::kNoProperties, 2, 1) \ V(BitwiseNot, Operator::kNoProperties, 1, 1) \ + V(Decrement, Operator::kNoProperties, 1, 1) \ + V(Increment, Operator::kNoProperties, 1, 1) \ V(Negate, Operator::kNoProperties, 1, 1) \ V(ToInteger, Operator::kNoProperties, 1, 1) \ V(ToLength, Operator::kNoProperties, 1, 1) \ diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index 50d1fcae98..97eeac598c 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -653,6 +653,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final const Operator* Modulus(); const Operator* BitwiseNot(); + const Operator* Decrement(); + const Operator* Increment(); const Operator* Negate(); const Operator* ToInteger(); diff --git a/src/compiler/js-type-hint-lowering.cc b/src/compiler/js-type-hint-lowering.cc index de6e712580..9318612f16 100644 --- a/src/compiler/js-type-hint-lowering.cc +++ b/src/compiler/js-type-hint-lowering.cc @@ -234,6 +234,25 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation( node = b.TryBuildNumberBinop(); break; } + case IrOpcode::kJSDecrement: { + // Lower to a speculative subtraction of 1 if we have some kind of Number + // feedback. + JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Subtract(), + operand, jsgraph()->SmiConstant(1), effect, + control, slot); + node = b.TryBuildNumberBinop(); + break; + } + case IrOpcode::kJSIncrement: { + // Lower to a speculative addition of 1 if we have some kind of Number + // feedback. + BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy. + JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Add(hint), + operand, jsgraph()->SmiConstant(1), effect, + control, slot); + node = b.TryBuildNumberBinop(); + break; + } case IrOpcode::kJSNegate: { // Lower to a speculative multiplication with -1 if we have some kind of // Number feedback. diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 3c0d8d1fc2..f159ead960 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -441,6 +441,37 @@ Reduction JSTypedLowering::ReduceJSBitwiseNot(Node* node) { return NoChange(); } +Reduction JSTypedLowering::ReduceJSDecrement(Node* node) { + Node* input = NodeProperties::GetValueInput(node, 0); + Type* input_type = NodeProperties::GetType(input); + if (input_type->Is(Type::PlainPrimitive())) { + // JSDecrement(x) => NumberSubtract(ToNumber(x), 1) + node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant()); + NodeProperties::ChangeOp(node, javascript()->Subtract()); + JSBinopReduction r(this, node); + r.ConvertInputsToNumber(); + DCHECK_EQ(simplified()->NumberSubtract(), r.NumberOp()); + return r.ChangeToPureOperator(r.NumberOp(), Type::Number()); + } + return NoChange(); +} + +Reduction JSTypedLowering::ReduceJSIncrement(Node* node) { + Node* input = NodeProperties::GetValueInput(node, 0); + Type* input_type = NodeProperties::GetType(input); + if (input_type->Is(Type::PlainPrimitive())) { + // JSIncrement(x) => NumberAdd(ToNumber(x), 1) + node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant()); + BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy. + NodeProperties::ChangeOp(node, javascript()->Add(hint)); + JSBinopReduction r(this, node); + r.ConvertInputsToNumber(); + DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp()); + return r.ChangeToPureOperator(r.NumberOp(), Type::Number()); + } + return NoChange(); +} + Reduction JSTypedLowering::ReduceJSNegate(Node* node) { Node* input = NodeProperties::GetValueInput(node, 0); Type* input_type = NodeProperties::GetType(input); @@ -2095,6 +2126,10 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceNumberBinop(node); case IrOpcode::kJSBitwiseNot: return ReduceJSBitwiseNot(node); + case IrOpcode::kJSDecrement: + return ReduceJSDecrement(node); + case IrOpcode::kJSIncrement: + return ReduceJSIncrement(node); case IrOpcode::kJSNegate: return ReduceJSNegate(node); case IrOpcode::kJSHasInPrototypeChain: diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index c11d7476b3..8b00c1d32c 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -41,6 +41,8 @@ class V8_EXPORT_PRIVATE JSTypedLowering final Reduction ReduceJSAdd(Node* node); Reduction ReduceJSBitwiseNot(Node* node); + Reduction ReduceJSDecrement(Node* node); + Reduction ReduceJSIncrement(Node* node); Reduction ReduceJSNegate(Node* node); Reduction ReduceJSComparison(Node* node); Reduction ReduceJSLoadNamed(Node* node); diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index d2966bf068..651635db18 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -127,6 +127,8 @@ #define JS_SIMPLE_UNOP_LIST(V) \ JS_CONVERSION_UNOP_LIST(V) \ V(JSBitwiseNot) \ + V(JSDecrement) \ + V(JSIncrement) \ V(JSNegate) #define JS_OBJECT_OP_LIST(V) \ diff --git a/src/compiler/operator-properties.cc b/src/compiler/operator-properties.cc index 96fa8de8c4..b6e8841393 100644 --- a/src/compiler/operator-properties.cc +++ b/src/compiler/operator-properties.cc @@ -111,6 +111,8 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { case IrOpcode::kJSDebugger: case IrOpcode::kJSGetSuperConstructor: case IrOpcode::kJSBitwiseNot: + case IrOpcode::kJSDecrement: + case IrOpcode::kJSIncrement: case IrOpcode::kJSNegate: return true; diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index b203f72924..342dd7d454 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -3046,6 +3046,8 @@ class RepresentationSelector { JS_OTHER_OP_LIST(OPCODE_CASE) #undef OPCODE_CASE case IrOpcode::kJSBitwiseNot: + case IrOpcode::kJSDecrement: + case IrOpcode::kJSIncrement: case IrOpcode::kJSNegate: case IrOpcode::kJSToInteger: case IrOpcode::kJSToLength: diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index f9993415e3..12b0090ee1 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -265,6 +265,8 @@ class Typer::Visitor : public Reducer { static Type* FalsifyUndefined(ComparisonOutcome, Typer*); static Type* BitwiseNot(Type*, Typer*); + static Type* Decrement(Type*, Typer*); + static Type* Increment(Type*, Typer*); static Type* Negate(Type*, Typer*); static Type* ToPrimitive(Type*, Typer*); @@ -435,6 +437,22 @@ Type* Typer::Visitor::BitwiseNot(Type* type, Typer* t) { return Type::Numeric(); } +Type* Typer::Visitor::Decrement(Type* type, Typer* t) { + type = ToNumeric(type, t); + if (type->Is(Type::Number())) { + return NumberSubtract(type, t->cache_.kSingletonOne, t); + } + return Type::Numeric(); +} + +Type* Typer::Visitor::Increment(Type* type, Typer* t) { + type = ToNumeric(type, t); + if (type->Is(Type::Number())) { + return NumberAdd(type, t->cache_.kSingletonOne, t); + } + return Type::Numeric(); +} + Type* Typer::Visitor::Negate(Type* type, Typer* t) { type = ToNumeric(type, t); if (type->Is(Type::Number())) { @@ -1092,6 +1110,14 @@ Type* Typer::Visitor::TypeJSBitwiseNot(Node* node) { return TypeUnaryOp(node, BitwiseNot); } +Type* Typer::Visitor::TypeJSDecrement(Node* node) { + return TypeUnaryOp(node, Decrement); +} + +Type* Typer::Visitor::TypeJSIncrement(Node* node) { + return TypeUnaryOp(node, Increment); +} + Type* Typer::Visitor::TypeJSNegate(Node* node) { return TypeUnaryOp(node, Negate); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 859029ed1d..6d856fd5ce 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -613,6 +613,8 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { break; case IrOpcode::kJSBitwiseNot: + case IrOpcode::kJSDecrement: + case IrOpcode::kJSIncrement: case IrOpcode::kJSNegate: // Type is Numeric. CheckTypeIs(node, Type::Numeric());