Commit 6fb86b97 authored by Qifan Pan's avatar Qifan Pan Committed by V8 LUCI CQ

[turbofan] Support BigIntDivide

Bug: v8:9407
Change-Id: I29f8f5ec68f09e8631b59d3a6a2926bab3b3bcd3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3845638Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Qifan Pan <panq@google.com>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82741}
parent 9e1ecccf
......@@ -389,6 +389,7 @@ extern enum MessageTemplate {
kSymbolIteratorInvalid,
kPropertyNotFunction,
kBigIntTooBig,
kBigIntDivZero,
kNotTypedArray,
kDetachedOperation,
kBadSortComparisonFunction,
......
......@@ -77,6 +77,20 @@ class BigIntBuiltinsAssembler : public CodeStubAssembler {
return success;
}
TNode<BoolT> CppAbsoluteDivAndCanonicalize(TNode<BigInt> result,
TNode<BigInt> x, TNode<BigInt> y) {
TNode<ExternalReference> mutable_big_int_absolute_div_and_canonicalize =
ExternalConstant(
ExternalReference::
mutable_big_int_absolute_div_and_canonicalize_function());
TNode<BoolT> success = UncheckedCast<BoolT>(CallCFunction(
mutable_big_int_absolute_div_and_canonicalize, MachineType::Bool(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y)));
return success;
}
void CppBitwiseAndPosPosAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference>
......
......@@ -15,6 +15,8 @@ extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppAbsoluteMulAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): bool;
extern macro BigIntBuiltinsAssembler::CppAbsoluteDivAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): bool;
extern macro BigIntBuiltinsAssembler::CppBitwiseAndPosPosAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppBitwiseAndNegNegAndCanonicalize(
......@@ -272,6 +274,73 @@ builtin BigIntMultiply(implicit context: Context)(
}
}
macro BigIntDivideImpl(implicit context: Context)(x: BigInt, y: BigInt):
BigInt labels BigIntDivZero, TerminationRequested {
const xlength = ReadBigIntLength(x);
const ylength = ReadBigIntLength(y);
// case: x / 0n
if (ylength == 0) {
goto BigIntDivZero;
}
// case: x / y, where x < y
if (MutableBigIntAbsoluteCompare(x, y) < 0) {
const zero = AllocateEmptyBigInt(kPositiveSign, 0);
return Convert<BigInt>(zero);
}
// case: x / 1n
const xsign = ReadBigIntSign(x);
const ysign = ReadBigIntSign(y);
const resultSign = (xsign != ysign) ? kNegativeSign : kPositiveSign;
if (ylength == 1 && LoadBigIntDigit(y, 0) == 1) {
return resultSign == xsign ? x : BigIntUnaryMinus(x);
}
// case: x / y
let resultLength = xlength - ylength + 1;
// This implies a *very* conservative estimate that kBarrettThreshold > 10.
if (ylength > 10) resultLength++;
const result = AllocateEmptyBigIntNoThrow(resultSign, resultLength)
otherwise unreachable;
if (!CppAbsoluteDivAndCanonicalize(result, x, y)) {
goto TerminationRequested;
}
return Convert<BigInt>(result);
}
builtin BigIntDivideNoThrow(implicit context: Context)(
x: BigInt, y: BigInt): Numeric {
try {
return BigIntDivideImpl(x, y) otherwise BigIntDivZero, TerminationRequested;
} label BigIntDivZero {
// Smi sentinel 0 is used to signal BigIntDivZero exception.
return Convert<Smi>(0);
} label TerminationRequested {
// Smi sentinel 1 is used to signal TerminateExecution exception.
return Convert<Smi>(1);
}
}
builtin BigIntDivide(implicit context: Context)(
xNum: Numeric, yNum: Numeric): BigInt {
try {
const x = Cast<BigInt>(xNum) otherwise MixedTypes;
const y = Cast<BigInt>(yNum) otherwise MixedTypes;
return BigIntDivideImpl(x, y) otherwise BigIntDivZero, TerminationRequested;
} label MixedTypes {
ThrowTypeError(MessageTemplate::kBigIntMixedTypes);
} label BigIntDivZero {
ThrowRangeError(MessageTemplate::kBigIntDivZero);
} label TerminationRequested {
TerminateExecution();
}
}
macro BigIntBitwiseAndImpl(implicit context: Context)(
x: BigInt, y: BigInt): BigInt labels BigIntTooBig {
const xlength = ReadBigIntLength(x);
......
......@@ -654,8 +654,7 @@ builtin Divide(implicit context: Context)(left: JSAny, right: JSAny): Numeric {
} label Float64s(left: float64, right: float64) {
return AllocateHeapNumberWithValue(left / right);
} label AtLeastOneBigInt(left: Numeric, right: Numeric) {
tail runtime::BigIntBinaryOp(
context, left, right, SmiTag<Operation>(Operation::kDivide));
tail bigint::BigIntDivide(left, right);
}
}
......
......@@ -1051,6 +1051,9 @@ FUNCTION_REFERENCE(mutable_big_int_absolute_sub_and_canonicalize_function,
FUNCTION_REFERENCE(mutable_big_int_absolute_mul_and_canonicalize_function,
MutableBigInt_AbsoluteMulAndCanonicalize)
FUNCTION_REFERENCE(mutable_big_int_absolute_div_and_canonicalize_function,
MutableBigInt_AbsoluteDivAndCanonicalize)
FUNCTION_REFERENCE(mutable_big_int_bitwise_and_pp_and_canonicalize_function,
MutableBigInt_BitwiseAndPosPosAndCanonicalize)
......
......@@ -178,6 +178,8 @@ class StatsCounter;
"MutableBigInt_AbsoluteSubAndCanonicalize") \
V(mutable_big_int_absolute_mul_and_canonicalize_function, \
"MutableBigInt_AbsoluteMulAndCanonicalize") \
V(mutable_big_int_absolute_div_and_canonicalize_function, \
"MutableBigInt_AbsoluteDivAndCanonicalize") \
V(mutable_big_int_bitwise_and_pp_and_canonicalize_function, \
"MutableBigInt_BitwiseAndPosPosAndCanonicalize") \
V(mutable_big_int_bitwise_and_nn_and_canonicalize_function, \
......
......@@ -175,6 +175,7 @@ class EffectControlLinearizer {
Node* LowerBigIntAdd(Node* node, Node* frame_state);
Node* LowerBigIntSubtract(Node* node, Node* frame_state);
Node* LowerBigIntMultiply(Node* node, Node* frame_state);
Node* LowerBigIntDivide(Node* node, Node* frame_state);
Node* LowerBigIntBitwiseAnd(Node* node, Node* frame_state);
Node* LowerBigIntNegate(Node* node);
Node* LowerCheckFloat64Hole(Node* node, Node* frame_state);
......@@ -1242,6 +1243,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kBigIntMultiply:
result = LowerBigIntMultiply(node, frame_state);
break;
case IrOpcode::kBigIntDivide:
result = LowerBigIntDivide(node, frame_state);
break;
case IrOpcode::kBigIntBitwiseAnd:
result = LowerBigIntBitwiseAnd(node, frame_state);
break;
......@@ -4393,6 +4397,50 @@ Node* EffectControlLinearizer::LowerBigIntMultiply(Node* node,
return value;
}
Node* EffectControlLinearizer::LowerBigIntDivide(Node* node,
Node* frame_state) {
Node* lhs = node->InputAt(0);
Node* rhs = node->InputAt(1);
Callable const callable =
Builtins::CallableFor(isolate(), Builtin::kBigIntDivideNoThrow);
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
Operator::kFoldable | Operator::kNoThrow);
Node* value = __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs,
rhs, __ NoContextConstant());
auto if_termreq = __ MakeDeferredLabel();
auto done = __ MakeLabel();
// Check for exception sentinel
// - Smi 0 is returned to signal BigIntDivZero
// - Smi 1 is returned to signal TerminationRequested
__ GotoIf(__ TaggedEqual(value, __ SmiConstant(1)), &if_termreq);
__ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, FeedbackSource{},
ObjectIsSmi(value), frame_state);
__ Goto(&done);
__ Bind(&if_termreq);
{
Runtime::FunctionId id = Runtime::kTerminateExecution;
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
graph()->zone(), id, 0, Operator::kNoDeopt,
CallDescriptor::kNeedsFrameState);
__ Call(call_descriptor, __ CEntryStubConstant(1),
__ ExternalConstant(ExternalReference::Create(id)),
__ Int32Constant(0), __ NoContextConstant(), frame_state);
__ Goto(&done);
}
__ Bind(&done);
return value;
}
Node* EffectControlLinearizer::LowerBigIntBitwiseAnd(Node* node,
Node* frame_state) {
Node* lhs = node->InputAt(0);
......
......@@ -6,6 +6,7 @@
#include "src/compiler/js-graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/type-hints.h"
......@@ -158,6 +159,8 @@ class JSSpeculativeBinopBuilder final {
return simplified()->SpeculativeBigIntSubtract(hint);
case IrOpcode::kJSMultiply:
return simplified()->SpeculativeBigIntMultiply(hint);
case IrOpcode::kJSDivide:
return simplified()->SpeculativeBigIntDivide(hint);
case IrOpcode::kJSBitwiseAnd:
return simplified()->SpeculativeBigIntBitwiseAnd(hint);
default:
......@@ -408,6 +411,7 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
if (op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract ||
op->opcode() == IrOpcode::kJSMultiply ||
op->opcode() == IrOpcode::kJSDivide ||
op->opcode() == IrOpcode::kJSBitwiseAnd) {
if (Node* node = b.TryBuildBigIntBinop()) {
return LoweringResult::SideEffectFree(node, node, control);
......
......@@ -336,6 +336,7 @@
V(BigIntAdd) \
V(BigIntSubtract) \
V(BigIntMultiply) \
V(BigIntDivide) \
V(BigIntBitwiseAnd)
#define SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
......@@ -502,6 +503,7 @@
V(SpeculativeBigIntAdd) \
V(SpeculativeBigIntSubtract) \
V(SpeculativeBigIntMultiply) \
V(SpeculativeBigIntDivide) \
V(SpeculativeBigIntBitwiseAnd)
#define SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(V) \
......
......@@ -1152,6 +1152,14 @@ Type OperationTyper::BigIntMultiply(Type lhs, Type rhs) {
return Type::BigInt();
}
Type OperationTyper::BigIntDivide(Type lhs, Type rhs) {
DCHECK(lhs.Is(Type::BigInt()));
DCHECK(rhs.Is(Type::BigInt()));
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
return Type::BigInt();
}
Type OperationTyper::BigIntBitwiseAnd(Type lhs, Type rhs) {
DCHECK(lhs.Is(Type::BigInt()));
DCHECK(rhs.Is(Type::BigInt()));
......@@ -1182,6 +1190,11 @@ Type OperationTyper::SpeculativeBigIntMultiply(Type lhs, Type rhs) {
return Type::BigInt();
}
Type OperationTyper::SpeculativeBigIntDivide(Type lhs, Type rhs) {
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
return Type::BigInt();
}
Type OperationTyper::SpeculativeBigIntBitwiseAnd(Type lhs, Type rhs) {
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
return Type::BigInt();
......
......@@ -3254,6 +3254,15 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kSpeculativeBigIntDivide: {
VisitBinop<T>(node,
UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
MachineRepresentation::kTaggedPointer);
if (lower<T>()) {
ChangeOp(node, lowering->simplified()->BigIntDivide());
}
return;
}
case IrOpcode::kSpeculativeBigIntNegate: {
if (truncation.IsUsedAsWord64()) {
VisitUnop<T>(node,
......
......@@ -809,6 +809,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(BigIntAdd, Operator::kNoProperties, 2, 1) \
V(BigIntSubtract, Operator::kNoProperties, 2, 1) \
V(BigIntMultiply, Operator::kNoProperties, 2, 1) \
V(BigIntDivide, Operator::kNoProperties, 2, 1) \
V(BigIntBitwiseAnd, Operator::kNoProperties, 2, 1) \
V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringCodePointAt, Operator::kNoProperties, 2, 1) \
......@@ -1632,6 +1633,14 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntMultiply(
1, 1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntDivide(
BigIntOperationHint hint) {
return zone()->New<Operator1<BigIntOperationHint>>(
IrOpcode::kSpeculativeBigIntDivide,
Operator::kFoldable | Operator::kNoThrow, "SpeculativeBigIntDivide", 2, 1,
1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntBitwiseAnd(
BigIntOperationHint hint) {
return zone()->New<Operator1<BigIntOperationHint>>(
......
......@@ -787,6 +787,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* BigIntAdd();
const Operator* BigIntSubtract();
const Operator* BigIntMultiply();
const Operator* BigIntDivide();
const Operator* BigIntBitwiseAnd();
const Operator* BigIntNegate();
......@@ -813,6 +814,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* SpeculativeBigIntAdd(BigIntOperationHint hint);
const Operator* SpeculativeBigIntSubtract(BigIntOperationHint hint);
const Operator* SpeculativeBigIntMultiply(BigIntOperationHint hint);
const Operator* SpeculativeBigIntDivide(BigIntOperationHint hint);
const Operator* SpeculativeBigIntBitwiseAnd(BigIntOperationHint hint);
const Operator* SpeculativeBigIntNegate(BigIntOperationHint hint);
const Operator* SpeculativeBigIntAsIntN(int bits,
......
......@@ -968,6 +968,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kSpeculativeBigIntAdd:
case IrOpcode::kSpeculativeBigIntSubtract:
case IrOpcode::kSpeculativeBigIntMultiply:
case IrOpcode::kSpeculativeBigIntDivide:
case IrOpcode::kSpeculativeBigIntBitwiseAnd:
CheckTypeIs(node, Type::BigInt());
break;
......@@ -982,6 +983,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kBigIntAdd:
case IrOpcode::kBigIntSubtract:
case IrOpcode::kBigIntMultiply:
case IrOpcode::kBigIntDivide:
case IrOpcode::kBigIntBitwiseAnd:
CheckValueInputIs(node, 0, Type::BigInt());
CheckValueInputIs(node, 1, Type::BigInt());
......
......@@ -1647,6 +1647,30 @@ bool MutableBigInt_AbsoluteMulAndCanonicalize(Address result_addr,
return true;
}
bool MutableBigInt_AbsoluteDivAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr) {
BigInt x = BigInt::cast(Object(x_addr));
BigInt y = BigInt::cast(Object(y_addr));
MutableBigInt result = MutableBigInt::cast(Object(result_addr));
DCHECK_GE(result.length(),
bigint::DivideResultLength(GetDigits(x), GetDigits(y)));
Isolate* isolate;
if (!GetIsolateFromHeapObject(x, &isolate)) {
// We should always get the isolate from the BigInt.
UNREACHABLE();
}
bigint::Status status = isolate->bigint_processor()->Divide(
GetRWDigits(result), GetDigits(x), GetDigits(y));
if (status == bigint::Status::kInterrupted) {
return false;
}
MutableBigInt::Canonicalize(result);
return true;
}
void MutableBigInt_BitwiseAndPosPosAndCanonicalize(Address result_addr,
Address x_addr,
Address y_addr) {
......
......@@ -28,6 +28,8 @@ void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
bool MutableBigInt_AbsoluteMulAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
bool MutableBigInt_AbsoluteDivAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
void MutableBigInt_BitwiseAndPosPosAndCanonicalize(Address result_addr,
Address x_addr,
Address y_addr);
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turbofan --no-always-turbofan
function OptimizeAndTest() {
function fn(a, b) {
return a / b;
}
%PrepareFunctionForOptimization(fn);
assertEquals(0n, fn(3n, 4n));
assertEquals(3n, fn(3n, 1n));
assertEquals(4n, fn(30n, 7n));
%OptimizeFunctionOnNextCall(fn);
assertEquals(0n, fn(3n, 4n));
assertEquals(3n, fn(3n, 1n));
assertEquals(4n, fn(30n, 7n));
assertOptimized(fn);
assertEquals(5, fn(30, 6));
assertUnoptimized(fn);
}
function OptimizeAndTestDivZero() {
function fn(a, b) {
return a / b;
}
%PrepareFunctionForOptimization(fn);
assertEquals(0n, fn(3n, 4n));
assertEquals(4n, fn(30n, 7n));
%OptimizeFunctionOnNextCall(fn);
assertEquals(4n, fn(30n, 7n));
assertOptimized(fn);
assertThrows(() => fn(3n, 0n), RangeError);
assertUnoptimized(fn);
}
OptimizeAndTest();
OptimizeAndTestDivZero();
......@@ -259,6 +259,22 @@ TEST_F(ThreadTerminationTest, TerminateBigIntDivision) {
"fail();");
}
TEST_F(ThreadTerminationTest, TerminateOptimizedBigIntDivision) {
i::FLAG_allow_natives_syntax = true;
TestTerminatingFromCurrentThread(
"function foo(a, b) { return a / b; }"
"%PrepareFunctionForOptimization(foo);"
"foo(3n, 2n);"
"foo(3n, 2n);"
"%OptimizeFunctionOnNextCall(foo);"
"foo(3n, 2n);"
"var a = 2n ** 2222222n;"
"var b = 3n ** 333333n;"
"terminate();"
"foo(a, b);"
"fail();");
}
TEST_F(ThreadTerminationTest, TerminateBigIntToString) {
TestTerminatingFromCurrentThread(
"var a = 2n ** 2222222n;"
......
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