diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc index 517b67ffe6..d7321d580c 100644 --- a/src/compiler/effect-control-linearizer.cc +++ b/src/compiler/effect-control-linearizer.cc @@ -170,6 +170,7 @@ class EffectControlLinearizer { Node* LowerStringLessThan(Node* node); Node* LowerStringLessThanOrEqual(Node* node); Node* LowerSpeculativeBigIntAdd(Node* node, Node* frame_state); + Node* LowerSpeculativeBigIntNegate(Node* node, Node* frame_state); Node* LowerCheckFloat64Hole(Node* node, Node* frame_state); Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state); Node* LowerConvertTaggedHoleToUndefined(Node* node); @@ -1176,6 +1177,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, case IrOpcode::kSpeculativeBigIntAdd: result = LowerSpeculativeBigIntAdd(node, frame_state); break; + case IrOpcode::kSpeculativeBigIntNegate: + result = LowerSpeculativeBigIntNegate(node, frame_state); + break; case IrOpcode::kNumberIsFloat64Hole: result = LowerNumberIsFloat64Hole(node); break; @@ -4272,6 +4276,21 @@ Node* EffectControlLinearizer::LowerSpeculativeBigIntAdd(Node* node, return value; } +Node* EffectControlLinearizer::LowerSpeculativeBigIntNegate(Node* node, + Node* frame_state) { + Callable const callable = + Builtins::CallableFor(isolate(), Builtins::kBigIntUnaryMinus); + auto call_descriptor = Linkage::GetStubCallDescriptor( + graph()->zone(), callable.descriptor(), + callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags, + Operator::kFoldable | Operator::kNoThrow); + Node* value = + __ Call(call_descriptor, jsgraph()->HeapConstant(callable.code()), + node->InputAt(0), __ NoContextConstant()); + + return value; +} + Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state) { // If we reach this point w/o eliminating the {node} that's marked diff --git a/src/compiler/js-type-hint-lowering.cc b/src/compiler/js-type-hint-lowering.cc index 76ba289a26..f3696bcc48 100644 --- a/src/compiler/js-type-hint-lowering.cc +++ b/src/compiler/js-type-hint-lowering.cc @@ -308,6 +308,15 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation( operand, jsgraph()->SmiConstant(-1), effect, control, slot); node = b.TryBuildNumberBinop(); + if (!node) { + FeedbackNexus nexus(feedback_vector(), slot); + if (nexus.GetBinaryOperationFeedback() == + BinaryOperationHint::kBigInt) { + const Operator* op = jsgraph()->simplified()->SpeculativeBigIntNegate( + BigIntOperationHint::kBigInt); + node = jsgraph()->graph()->NewNode(op, operand, effect, control); + } + } break; } default: diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 536fcbddcf..e06915011b 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -475,6 +475,7 @@ V(DateNow) #define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) V(SpeculativeBigIntAdd) +#define SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(V) V(SpeculativeBigIntNegate) #define SIMPLIFIED_OP_LIST(V) \ SIMPLIFIED_CHANGE_OP_LIST(V) \ @@ -485,6 +486,7 @@ SIMPLIFIED_NUMBER_UNOP_LIST(V) \ SIMPLIFIED_BIGINT_UNOP_LIST(V) \ SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) \ + SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(V) \ SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) \ SIMPLIFIED_OTHER_OP_LIST(V) diff --git a/src/compiler/operation-typer.cc b/src/compiler/operation-typer.cc index 517a194104..34f77dcfcd 100644 --- a/src/compiler/operation-typer.cc +++ b/src/compiler/operation-typer.cc @@ -1125,6 +1125,11 @@ Type OperationTyper::SpeculativeBigIntAdd(Type lhs, Type rhs) { return Type::BigInt(); } +Type OperationTyper::SpeculativeBigIntNegate(Type type) { + if (type.IsNone()) return type; + return Type::BigInt(); +} + Type OperationTyper::SpeculativeToNumber(Type type) { return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone())); } diff --git a/src/compiler/operation-typer.h b/src/compiler/operation-typer.h index 16603a75fd..41d15fbfba 100644 --- a/src/compiler/operation-typer.h +++ b/src/compiler/operation-typer.h @@ -45,6 +45,7 @@ class V8_EXPORT_PRIVATE OperationTyper { SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD) SIMPLIFIED_BIGINT_UNOP_LIST(DECLARE_METHOD) SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_METHOD) + SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(DECLARE_METHOD) DECLARE_METHOD(ConvertReceiver) #undef DECLARE_METHOD diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 0b368fc242..24740ba2a2 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -748,21 +748,32 @@ class RepresentationSelector { !GetUpperBound(node->InputAt(1)).Maybe(type); } + void ChangeToDeadValue(Node* node, Node* effect, Node* control) { + DCHECK(TypeOf(node).IsNone()); + // If the node is unreachable, insert an Unreachable node and mark the + // value dead. + // TODO(jarin,tebbi) Find a way to unify/merge this insertion with + // InsertUnreachableIfNecessary. + Node* unreachable = effect = + graph()->NewNode(jsgraph_->common()->Unreachable(), effect, control); + const Operator* dead_value = + jsgraph_->common()->DeadValue(GetInfo(node)->representation()); + node->ReplaceInput(0, unreachable); + node->TrimInputCount(dead_value->ValueInputCount()); + ReplaceEffectControlUses(node, effect, control); + NodeProperties::ChangeOp(node, dead_value); + } + void ChangeToPureOp(Node* node, const Operator* new_op) { DCHECK(new_op->HasProperty(Operator::kPure)); + DCHECK_EQ(new_op->ValueInputCount(), node->op()->ValueInputCount()); if (node->op()->EffectInputCount() > 0) { DCHECK_LT(0, node->op()->ControlInputCount()); Node* control = NodeProperties::GetControlInput(node); Node* effect = NodeProperties::GetEffectInput(node); if (TypeOf(node).IsNone()) { - // If the node is unreachable, insert an Unreachable node and mark the - // value dead. - // TODO(jarin,tebbi) Find a way to unify/merge this insertion with - // InsertUnreachableIfNecessary. - Node* unreachable = effect = graph()->NewNode( - jsgraph_->common()->Unreachable(), effect, control); - new_op = jsgraph_->common()->DeadValue(GetInfo(node)->representation()); - node->ReplaceInput(0, unreachable); + ChangeToDeadValue(node, effect, control); + return; } // Rewire the effect and control chains. node->TrimInputCount(new_op->ValueInputCount()); @@ -773,6 +784,30 @@ class RepresentationSelector { NodeProperties::ChangeOp(node, new_op); } + void ChangeUnaryToPureBinaryOp(Node* node, const Operator* new_op, + int new_input_index, Node* new_input) { + DCHECK(new_op->HasProperty(Operator::kPure)); + DCHECK_EQ(new_op->ValueInputCount(), 2); + DCHECK_EQ(node->op()->ValueInputCount(), 1); + DCHECK_LE(0, new_input_index); + DCHECK_LE(new_input_index, 1); + if (node->op()->EffectInputCount() > 0) { + DCHECK_LT(0, node->op()->ControlInputCount()); + Node* control = NodeProperties::GetControlInput(node); + Node* effect = NodeProperties::GetEffectInput(node); + if (TypeOf(node).IsNone()) { + ChangeToDeadValue(node, effect, control); + return; + } + node->TrimInputCount(node->op()->ValueInputCount()); + ReplaceEffectControlUses(node, effect, control); + } else { + DCHECK_EQ(0, node->op()->ControlInputCount()); + } + node->InsertInput(jsgraph_->zone(), new_input_index, new_input); + NodeProperties::ChangeOp(node, new_op); + } + // Converts input {index} of {node} according to given UseInfo {use}, // assuming the type of the input is {input_type}. If {input_type} is null, // it takes the input from the input node {TypeOf(node->InputAt(index))}. @@ -2679,6 +2714,22 @@ class RepresentationSelector { } return; } + case IrOpcode::kSpeculativeBigIntNegate: { + if (truncation.IsUsedAsWord64()) { + VisitUnop(node, + UseInfo::CheckedBigIntTruncatingWord64(VectorSlotPair{}), + MachineRepresentation::kWord64); + if (lower()) { + ChangeUnaryToPureBinaryOp(node, lowering->machine()->Int64Sub(), 0, + jsgraph_->Int64Constant(0)); + } + } else { + VisitUnop(node, + UseInfo::CheckedBigIntAsTaggedPointer(VectorSlotPair{}), + MachineRepresentation::kTaggedPointer); + } + return; + } case IrOpcode::kStringConcat: { // TODO(turbofan): We currently depend on having this first length input // to make sure that the overflow check is properly scheduled before the diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index 4878ff6af4..26d853e795 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -1442,6 +1442,14 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntAdd( "SpeculativeBigIntAdd", 2, 1, 1, 1, 1, 0, hint); } +const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntNegate( + BigIntOperationHint hint) { + return new (zone()) Operator1( + IrOpcode::kSpeculativeBigIntNegate, + Operator::kFoldable | Operator::kNoThrow, "SpeculativeBigIntNegate", 1, 1, + 1, 1, 1, 0, hint); +} + const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber( NumberOperationHint hint, const VectorSlotPair& feedback) { if (!feedback.IsValid()) { diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index 2df2397ce3..31df53b778 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -659,6 +659,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final const Operator* SpeculativeNumberEqual(NumberOperationHint hint); const Operator* SpeculativeBigIntAdd(BigIntOperationHint hint); + const Operator* SpeculativeBigIntNegate(BigIntOperationHint hint); const Operator* BigIntAsUintN(int bits); const Operator* ReferenceEqual(); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 6f8dc21a4e..e259b30ecf 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -101,6 +101,7 @@ class Typer::Visitor : public Reducer { SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE) SIMPLIFIED_BIGINT_UNOP_LIST(DECLARE_CASE) SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE) + SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(DECLARE_CASE) #undef DECLARE_CASE #define DECLARE_CASE(x) case IrOpcode::k##x: @@ -169,6 +170,7 @@ class Typer::Visitor : public Reducer { SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE) SIMPLIFIED_BIGINT_UNOP_LIST(DECLARE_CASE) SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE) + SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(DECLARE_CASE) #undef DECLARE_CASE #define DECLARE_CASE(x) case IrOpcode::k##x: @@ -282,6 +284,7 @@ class Typer::Visitor : public Reducer { SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD) SIMPLIFIED_BIGINT_UNOP_LIST(DECLARE_METHOD) SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_METHOD) + SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(DECLARE_METHOD) #undef DECLARE_METHOD #define DECLARE_METHOD(Name) \ static Type Name(Type lhs, Type rhs, Typer* t) { \ diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 755418eec4..4cba07ea8e 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -979,6 +979,9 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { case IrOpcode::kSpeculativeBigIntAdd: CheckTypeIs(node, Type::BigInt()); break; + case IrOpcode::kSpeculativeBigIntNegate: + CheckTypeIs(node, Type::BigInt()); + break; case IrOpcode::kBigIntAsUintN: CheckValueInputIs(node, 0, Type::BigInt()); CheckTypeIs(node, Type::BigInt());