[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: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#62684}
This commit is contained in:
parent
e3b2697e60
commit
1b2b1a67d2
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user