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

[turbofan] Support BigIntBitwiseAnd

Bug: v8:9407
Change-Id: I159b2ce338ab55d8171b0892a6942c9a5144d632
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3842156Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Qifan Pan <panq@google.com>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82622}
parent 35fd638c
......@@ -77,6 +77,45 @@ class BigIntBuiltinsAssembler : public CodeStubAssembler {
return success;
}
void CppBitwiseAndPosPosAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference>
mutable_big_int_bitwise_and_pos_pos_and_canonicalize = ExternalConstant(
ExternalReference::
mutable_big_int_bitwise_and_pp_and_canonicalize_function());
CallCFunction(mutable_big_int_bitwise_and_pos_pos_and_canonicalize,
MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y));
}
void CppBitwiseAndNegNegAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference>
mutable_big_int_bitwise_and_neg_neg_and_canonicalize = ExternalConstant(
ExternalReference::
mutable_big_int_bitwise_and_nn_and_canonicalize_function());
CallCFunction(mutable_big_int_bitwise_and_neg_neg_and_canonicalize,
MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y));
}
void CppBitwiseAndPosNegAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference>
mutable_big_int_bitwise_and_pos_neg_and_canonicalize = ExternalConstant(
ExternalReference::
mutable_big_int_bitwise_and_pn_and_canonicalize_function());
CallCFunction(mutable_big_int_bitwise_and_pos_neg_and_canonicalize,
MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y));
}
TNode<Int32T> CppAbsoluteCompare(TNode<BigInt> x, TNode<BigInt> y) {
TNode<ExternalReference> mutable_big_int_absolute_compare =
ExternalConstant(
......
......@@ -15,6 +15,12 @@ extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppAbsoluteMulAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): bool;
extern macro BigIntBuiltinsAssembler::CppBitwiseAndPosPosAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppBitwiseAndNegNegAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppBitwiseAndPosNegAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare(
BigIntBase, BigIntBase): int32;
......@@ -241,10 +247,10 @@ builtin BigIntMultiplyNoThrow(implicit context: Context)(
return BigIntMultiplyImpl(x, y) otherwise BigIntTooBig,
TerminationRequested;
} label BigIntTooBig {
// Smi sentinal 0 is used to signal BigIntTooBig exception.
// Smi sentinel 0 is used to signal BigIntTooBig exception.
return Convert<Smi>(0);
} label TerminationRequested {
// Smi sentinal 1 is used to signal TerminateExecution exception.
// Smi sentinel 1 is used to signal TerminateExecution exception.
return Convert<Smi>(1);
}
}
......@@ -266,6 +272,73 @@ builtin BigIntMultiply(implicit context: Context)(
}
}
macro BigIntBitwiseAndImpl(implicit context: Context)(
x: BigInt, y: BigInt): BigInt labels BigIntTooBig {
const xlength = ReadBigIntLength(x);
const ylength = ReadBigIntLength(y);
// case: 0n & y
if (xlength == 0) {
return x;
}
// case: x & 0n
if (ylength == 0) {
return y;
}
const xsign = ReadBigIntSign(x);
const ysign = ReadBigIntSign(y);
if (xsign == kPositiveSign && ysign == kPositiveSign) {
const resultLength = (xlength < ylength) ? xlength : ylength;
const result = AllocateEmptyBigIntNoThrow(kPositiveSign, resultLength)
otherwise unreachable;
CppBitwiseAndPosPosAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
} else if (xsign == kNegativeSign && ysign == kNegativeSign) {
const resultLength = ((xlength > ylength) ? xlength : ylength) + 1;
const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength)
otherwise BigIntTooBig;
CppBitwiseAndNegNegAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
} else if (xsign == kPositiveSign && ysign == kNegativeSign) {
const result = AllocateEmptyBigIntNoThrow(kPositiveSign, xlength)
otherwise unreachable;
CppBitwiseAndPosNegAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
} else {
const result = AllocateEmptyBigIntNoThrow(kPositiveSign, ylength)
otherwise unreachable;
CppBitwiseAndPosNegAndCanonicalize(result, y, x);
return Convert<BigInt>(result);
}
}
builtin BigIntBitwiseAndNoThrow(implicit context: Context)(
x: BigInt, y: BigInt): Numeric {
try {
return BigIntBitwiseAndImpl(x, y) otherwise BigIntTooBig;
} label BigIntTooBig {
// Smi sentinel 0 is used to signal BigIntTooBig exception.
return Convert<Smi>(0);
}
}
builtin BigIntBitwiseAnd(implicit context: Context)(
xNum: Numeric, yNum: Numeric): BigInt {
try {
const x = Cast<BigInt>(xNum) otherwise MixedTypes;
const y = Cast<BigInt>(yNum) otherwise MixedTypes;
return BigIntBitwiseAndImpl(x, y) otherwise BigIntTooBig;
} label MixedTypes {
ThrowTypeError(MessageTemplate::kBigIntMixedTypes);
} label BigIntTooBig {
ThrowRangeError(MessageTemplate::kBigIntTooBig);
}
}
builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt {
const length = ReadBigIntLength(bigint);
......
......@@ -311,6 +311,7 @@ transitioning javascript builtin NumberParseInt(
}
extern builtin NonNumberToNumeric(implicit context: Context)(JSAny): Numeric;
extern builtin BitwiseAnd(implicit context: Context)(Number, Number): Number;
extern builtin BitwiseXor(implicit context: Context)(Number, Number): Number;
extern builtin Subtract(implicit context: Context)(Number, Number): Number;
extern builtin Add(implicit context: Context)(Number, Number): Number;
......@@ -751,8 +752,14 @@ builtin ShiftRightLogical(implicit context: Context)(
}
builtin BitwiseAnd(implicit context: Context)(
left: JSAny, right: JSAny): Object {
return Generate_BitwiseBinaryOp(Operation::kBitwiseAnd, left, right, context);
left: JSAny, right: JSAny): Numeric {
try {
BinaryOp1(left, right) otherwise Number, AtLeastOneBigInt;
} label Number(left: Number, right: Number) {
tail BitwiseAnd(left, right);
} label AtLeastOneBigInt(left: Numeric, right: Numeric) {
tail bigint::BigIntBitwiseAnd(left, right);
}
}
builtin BitwiseOr(implicit context: Context)(
......
......@@ -1042,6 +1042,15 @@ 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_bitwise_and_pp_and_canonicalize_function,
MutableBigInt_BitwiseAndPosPosAndCanonicalize)
FUNCTION_REFERENCE(mutable_big_int_bitwise_and_nn_and_canonicalize_function,
MutableBigInt_BitwiseAndNegNegAndCanonicalize)
FUNCTION_REFERENCE(mutable_big_int_bitwise_and_pn_and_canonicalize_function,
MutableBigInt_BitwiseAndPosNegAndCanonicalize)
FUNCTION_REFERENCE(check_object_type, CheckObjectType)
#ifdef V8_INTL_SUPPORT
......
......@@ -178,6 +178,12 @@ class StatsCounter;
"MutableBigInt_AbsoluteSubAndCanonicalize") \
V(mutable_big_int_absolute_mul_and_canonicalize_function, \
"MutableBigInt_AbsoluteMulAndCanonicalize") \
V(mutable_big_int_bitwise_and_pp_and_canonicalize_function, \
"MutableBigInt_BitwiseAndPosPosAndCanonicalize") \
V(mutable_big_int_bitwise_and_nn_and_canonicalize_function, \
"MutableBigInt_BitwiseAndNegNegAndCanonicalize") \
V(mutable_big_int_bitwise_and_pn_and_canonicalize_function, \
"MutableBigInt_BitwiseAndPosNegAndCanonicalize") \
V(new_deoptimizer_function, "Deoptimizer::New()") \
V(orderedhashmap_gethash_raw, "orderedhashmap_gethash_raw") \
V(printf_function, "printf") \
......
......@@ -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* LowerBigIntBitwiseAnd(Node* node, Node* frame_state);
Node* LowerBigIntNegate(Node* node);
Node* LowerCheckFloat64Hole(Node* node, Node* frame_state);
Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state);
......@@ -1241,6 +1242,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kBigIntMultiply:
result = LowerBigIntMultiply(node, frame_state);
break;
case IrOpcode::kBigIntBitwiseAnd:
result = LowerBigIntBitwiseAnd(node, frame_state);
break;
case IrOpcode::kBigIntNegate:
result = LowerBigIntNegate(node);
break;
......@@ -4389,6 +4393,27 @@ Node* EffectControlLinearizer::LowerBigIntMultiply(Node* node,
return value;
}
Node* EffectControlLinearizer::LowerBigIntBitwiseAnd(Node* node,
Node* frame_state) {
Node* lhs = node->InputAt(0);
Node* rhs = node->InputAt(1);
Callable const callable =
Builtins::CallableFor(isolate(), Builtin::kBigIntBitwiseAndNoThrow);
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());
// Check for exception sentinel: Smi is returned to signal BigIntTooBig.
__ DeoptimizeIf(DeoptimizeReason::kBigIntTooBig, FeedbackSource{},
ObjectIsSmi(value), frame_state);
return value;
}
Node* EffectControlLinearizer::LowerBigIntNegate(Node* node) {
Callable const callable =
Builtins::CallableFor(isolate(), Builtin::kBigIntUnaryMinus);
......
......@@ -158,6 +158,8 @@ class JSSpeculativeBinopBuilder final {
return simplified()->SpeculativeBigIntSubtract(hint);
case IrOpcode::kJSMultiply:
return simplified()->SpeculativeBigIntMultiply(hint);
case IrOpcode::kJSBitwiseAnd:
return simplified()->SpeculativeBigIntBitwiseAnd(hint);
default:
break;
}
......@@ -405,7 +407,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
}
if (op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract ||
op->opcode() == IrOpcode::kJSMultiply) {
op->opcode() == IrOpcode::kJSMultiply ||
op->opcode() == IrOpcode::kJSBitwiseAnd) {
if (Node* node = b.TryBuildBigIntBinop()) {
return LoweringResult::SideEffectFree(node, node, control);
}
......
......@@ -335,7 +335,8 @@
#define SIMPLIFIED_BIGINT_BINOP_LIST(V) \
V(BigIntAdd) \
V(BigIntSubtract) \
V(BigIntMultiply)
V(BigIntMultiply) \
V(BigIntBitwiseAnd)
#define SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
V(SpeculativeNumberAdd) \
......@@ -500,7 +501,8 @@
#define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) \
V(SpeculativeBigIntAdd) \
V(SpeculativeBigIntSubtract) \
V(SpeculativeBigIntMultiply)
V(SpeculativeBigIntMultiply) \
V(SpeculativeBigIntBitwiseAnd)
#define SIMPLIFIED_SPECULATIVE_BIGINT_UNOP_LIST(V) \
V(SpeculativeBigIntAsIntN) \
......
......@@ -1152,6 +1152,14 @@ Type OperationTyper::BigIntMultiply(Type lhs, Type rhs) {
return Type::BigInt();
}
Type OperationTyper::BigIntBitwiseAnd(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::BigIntNegate(Type type) {
DCHECK(type.Is(Type::BigInt()));
......@@ -1174,6 +1182,11 @@ Type OperationTyper::SpeculativeBigIntMultiply(Type lhs, Type rhs) {
return Type::BigInt();
}
Type OperationTyper::SpeculativeBigIntBitwiseAnd(Type lhs, Type rhs) {
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
return Type::BigInt();
}
Type OperationTyper::SpeculativeBigIntNegate(Type type) {
if (type.IsNone()) return type;
return Type::BigInt();
......
......@@ -3236,6 +3236,24 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kSpeculativeBigIntBitwiseAnd: {
if (truncation.IsUsedAsWord64()) {
VisitBinop<T>(
node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
MachineRepresentation::kWord64);
if (lower<T>()) {
ChangeToPureOp(node, lowering->machine()->Word64And());
}
} else {
VisitBinop<T>(node,
UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
MachineRepresentation::kTaggedPointer);
if (lower<T>()) {
ChangeOp(node, lowering->simplified()->BigIntBitwiseAnd());
}
}
return;
}
case IrOpcode::kSpeculativeBigIntNegate: {
if (truncation.IsUsedAsWord64()) {
VisitUnop<T>(node,
......
......@@ -805,6 +805,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(BigIntBitwiseAnd, Operator::kNoProperties, 2, 1) \
V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringCodePointAt, Operator::kNoProperties, 2, 1) \
V(StringFromCodePointAt, Operator::kNoProperties, 2, 1) \
......@@ -1627,6 +1628,14 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntMultiply(
1, 1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntBitwiseAnd(
BigIntOperationHint hint) {
return zone()->New<Operator1<BigIntOperationHint>>(
IrOpcode::kSpeculativeBigIntBitwiseAnd,
Operator::kFoldable | Operator::kNoThrow, "SpeculativeBigIntBitwiseAnd",
2, 1, 1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntNegate(
BigIntOperationHint hint) {
return zone()->New<Operator1<BigIntOperationHint>>(
......
......@@ -779,6 +779,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* BigIntAdd();
const Operator* BigIntSubtract();
const Operator* BigIntMultiply();
const Operator* BigIntBitwiseAnd();
const Operator* BigIntNegate();
const Operator* SpeculativeSafeIntegerAdd(NumberOperationHint hint);
......@@ -804,6 +805,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* SpeculativeBigIntAdd(BigIntOperationHint hint);
const Operator* SpeculativeBigIntSubtract(BigIntOperationHint hint);
const Operator* SpeculativeBigIntMultiply(BigIntOperationHint hint);
const Operator* SpeculativeBigIntBitwiseAnd(BigIntOperationHint hint);
const Operator* SpeculativeBigIntNegate(BigIntOperationHint hint);
const Operator* SpeculativeBigIntAsIntN(int bits,
const FeedbackSource& feedback);
......
......@@ -968,6 +968,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kSpeculativeBigIntAdd:
case IrOpcode::kSpeculativeBigIntSubtract:
case IrOpcode::kSpeculativeBigIntMultiply:
case IrOpcode::kSpeculativeBigIntBitwiseAnd:
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kSpeculativeBigIntNegate:
......@@ -981,6 +982,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kBigIntAdd:
case IrOpcode::kBigIntSubtract:
case IrOpcode::kBigIntMultiply:
case IrOpcode::kBigIntBitwiseAnd:
CheckValueInputIs(node, 0, Type::BigInt());
CheckValueInputIs(node, 1, Type::BigInt());
CheckTypeIs(node, Type::BigInt());
......
......@@ -1647,5 +1647,38 @@ bool MutableBigInt_AbsoluteMulAndCanonicalize(Address result_addr,
return true;
}
void MutableBigInt_BitwiseAndPosPosAndCanonicalize(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));
bigint::BitwiseAnd_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
MutableBigInt::Canonicalize(result);
}
void MutableBigInt_BitwiseAndNegNegAndCanonicalize(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));
bigint::BitwiseAnd_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
MutableBigInt::Canonicalize(result);
}
void MutableBigInt_BitwiseAndPosNegAndCanonicalize(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));
bigint::BitwiseAnd_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
MutableBigInt::Canonicalize(result);
}
} // namespace internal
} // namespace v8
......@@ -28,6 +28,15 @@ void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
bool MutableBigInt_AbsoluteMulAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
void MutableBigInt_BitwiseAndPosPosAndCanonicalize(Address result_addr,
Address x_addr,
Address y_addr);
void MutableBigInt_BitwiseAndNegNegAndCanonicalize(Address result_addr,
Address x_addr,
Address y_addr);
void MutableBigInt_BitwiseAndPosNegAndCanonicalize(Address result_addr,
Address x_addr,
Address y_addr);
class BigInt;
class ValueDeserializer;
......
// 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 TestBitwiseAnd(a, b) {
return a & b;
}
function OptimizeAndTest(fn) {
%PrepareFunctionForOptimization(fn);
assertEquals(0b1000n, fn(0b1100n, 0b1010n));
assertEquals(-0b1000n, fn(-0b100n, -0b110n));
assertEquals(0b1000n, fn(-0b100n, 0b1010n));
assertEquals(0b1000n, fn(0b1100n, -0b110n));
// The result grows out of one digit
assertEquals(-(2n ** 64n), fn(-(2n ** 63n + 1n), -(2n ** 63n)));
%OptimizeFunctionOnNextCall(fn);
fn(0b1100n, 0b1010n);
assertOptimized(fn);
assertEquals(0b1000n, fn(0b1100n, 0b1010n));
assertEquals(-0b1000n, fn(-0b100n, -0b110n));
assertEquals(0b1000n, fn(-0b100n, 0b1010n));
assertEquals(0b1000n, fn(0b1100n, -0b110n));
// The result grows out of one digit
assertEquals(-(2n ** 64n), fn(-(2n ** 63n + 1n), -(2n ** 63n)));
assertEquals(0b1000, fn(0b1100, 0b1010));
assertUnoptimized(fn);
}
OptimizeAndTest(TestBitwiseAnd);
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