Commit 1b2b1a67 authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

[turbofan] Speculative BigIntNegate

This CL adds a speculative operator for BigInt negation that is
lowered to the respective builtin call and is optimized to native
64 bit machine operations if truncated. In particular, this change
allows negative BigInt constants (e.g. -5n) to be lowered.

Bug: v8:9407
Change-Id: Ia98fd6dee18a31ce56efbe537f4352b1582539e7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1695463
Commit-Queue: Nico Hartmann <nicohartmann@google.com>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62684}
parent e3b2697e
......@@ -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
......
......@@ -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:
......
......@@ -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)
......
......@@ -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()));
}
......
......@@ -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
......
......@@ -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
......
......@@ -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<BigIntOperationHint>(
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()) {
......
......@@ -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();
......
......@@ -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) { \
......
......@@ -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());
......
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