[bigint] Move bitwise ops to src/bigint/
No asymptotic improvements, and none are planned either. Minor speedups (25-50%) through reduced overhead: accessing Digits is faster than working with Handle<BigInt>, and this implementation avoids allocating intermediate results. Bug: v8:11515 Change-Id: I2aab2b1c5c9cbb910800161b8514c497daf2b587 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3149453 Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#76793}
This commit is contained in:
parent
b757471c81
commit
fc6f621387
@ -2727,6 +2727,7 @@ filegroup(
|
|||||||
"src/bigint/bigint-internal.cc",
|
"src/bigint/bigint-internal.cc",
|
||||||
"src/bigint/bigint-internal.h",
|
"src/bigint/bigint-internal.h",
|
||||||
"src/bigint/bigint.h",
|
"src/bigint/bigint.h",
|
||||||
|
"src/bigint/bitwise.cc",
|
||||||
"src/bigint/digit-arithmetic.h",
|
"src/bigint/digit-arithmetic.h",
|
||||||
"src/bigint/div-barrett.cc",
|
"src/bigint/div-barrett.cc",
|
||||||
"src/bigint/div-burnikel.cc",
|
"src/bigint/div-burnikel.cc",
|
||||||
|
1
BUILD.gn
1
BUILD.gn
@ -5106,6 +5106,7 @@ v8_source_set("v8_bigint") {
|
|||||||
"src/bigint/bigint-internal.cc",
|
"src/bigint/bigint-internal.cc",
|
||||||
"src/bigint/bigint-internal.h",
|
"src/bigint/bigint-internal.h",
|
||||||
"src/bigint/bigint.h",
|
"src/bigint/bigint.h",
|
||||||
|
"src/bigint/bitwise.cc",
|
||||||
"src/bigint/digit-arithmetic.h",
|
"src/bigint/digit-arithmetic.h",
|
||||||
"src/bigint/div-burnikel.cc",
|
"src/bigint/div-burnikel.cc",
|
||||||
"src/bigint/div-helpers.cc",
|
"src/bigint/div-helpers.cc",
|
||||||
|
@ -227,12 +227,32 @@ void Add(RWDigits Z, Digits X, Digits Y);
|
|||||||
// Addition of signed integers. Returns true if the result is negative.
|
// Addition of signed integers. Returns true if the result is negative.
|
||||||
bool AddSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
bool AddSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
||||||
bool y_negative);
|
bool y_negative);
|
||||||
|
// Z := X + 1
|
||||||
|
void AddOne(RWDigits Z, Digits X);
|
||||||
|
|
||||||
// Z := X - Y. Requires X >= Y.
|
// Z := X - Y. Requires X >= Y.
|
||||||
void Subtract(RWDigits Z, Digits X, Digits Y);
|
void Subtract(RWDigits Z, Digits X, Digits Y);
|
||||||
// Subtraction of signed integers. Returns true if the result is negative.
|
// Subtraction of signed integers. Returns true if the result is negative.
|
||||||
bool SubtractSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
bool SubtractSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
||||||
bool y_negative);
|
bool y_negative);
|
||||||
|
// Z := X - 1
|
||||||
|
void SubtractOne(RWDigits Z, Digits X);
|
||||||
|
|
||||||
|
// The bitwise operations assume that negative BigInts are represented as
|
||||||
|
// sign+magnitude. Their behavior depends on the sign of the inputs: negative
|
||||||
|
// inputs perform an implicit conversion to two's complement representation.
|
||||||
|
// Z := X & Y
|
||||||
|
void BitwiseAnd_PosPos(RWDigits Z, Digits X, Digits Y);
|
||||||
|
// Call this for a BigInt x = (magnitude=X, negative=true).
|
||||||
|
void BitwiseAnd_NegNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
// Positive X, negative Y. Callers must swap arguments as needed.
|
||||||
|
void BitwiseAnd_PosNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseOr_PosPos(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseOr_NegNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseOr_PosNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseXor_PosPos(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseXor_NegNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
void BitwiseXor_PosNeg(RWDigits Z, Digits X, Digits Y);
|
||||||
|
|
||||||
enum class Status { kOk, kInterrupted };
|
enum class Status { kOk, kInterrupted };
|
||||||
|
|
||||||
@ -303,6 +323,28 @@ int ToStringResultLength(Digits X, int radix, bool sign);
|
|||||||
// In DEBUG builds, the result of {ToString} will be initialized to this value.
|
// In DEBUG builds, the result of {ToString} will be initialized to this value.
|
||||||
constexpr char kStringZapValue = '?';
|
constexpr char kStringZapValue = '?';
|
||||||
|
|
||||||
|
inline int BitwiseAnd_PosPos_ResultLength(int x_length, int y_length) {
|
||||||
|
return std::min(x_length, y_length);
|
||||||
|
}
|
||||||
|
inline int BitwiseAnd_NegNeg_ResultLength(int x_length, int y_length) {
|
||||||
|
// Result length growth example: -2 & -3 = -4 (2-bit inputs, 3-bit result).
|
||||||
|
return std::max(x_length, y_length) + 1;
|
||||||
|
}
|
||||||
|
inline int BitwiseAnd_PosNeg_ResultLength(int x_length) { return x_length; }
|
||||||
|
inline int BitwiseOrResultLength(int x_length, int y_length) {
|
||||||
|
return std::max(x_length, y_length);
|
||||||
|
}
|
||||||
|
inline int BitwiseXor_PosPos_ResultLength(int x_length, int y_length) {
|
||||||
|
return std::max(x_length, y_length);
|
||||||
|
}
|
||||||
|
inline int BitwiseXor_NegNeg_ResultLength(int x_length, int y_length) {
|
||||||
|
return std::max(x_length, y_length);
|
||||||
|
}
|
||||||
|
inline int BitwiseXor_PosNeg_ResultLength(int x_length, int y_length) {
|
||||||
|
// Result length growth example: 3 ^ -1 == -4 (2-bit inputs, 3-bit result).
|
||||||
|
return std::max(x_length, y_length) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Support for parsing BigInts from Strings, using an Accumulator object
|
// Support for parsing BigInts from Strings, using an Accumulator object
|
||||||
// for intermediate state.
|
// for intermediate state.
|
||||||
|
|
||||||
|
136
src/bigint/bitwise.cc
Normal file
136
src/bigint/bitwise.cc
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
#include "src/bigint/bigint-internal.h"
|
||||||
|
#include "src/bigint/digit-arithmetic.h"
|
||||||
|
#include "src/bigint/vector-arithmetic.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace bigint {
|
||||||
|
|
||||||
|
void BitwiseAnd_PosPos(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
DCHECK(Z.len() >= pairs);
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = X[i] & Y[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseAnd_NegNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// (-x) & (-y) == ~(x-1) & ~(y-1)
|
||||||
|
// == ~((x-1) | (y-1))
|
||||||
|
// == -(((x-1) | (y-1)) + 1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t x_borrow = 1;
|
||||||
|
digit_t y_borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) {
|
||||||
|
Z[i] = digit_sub(X[i], x_borrow, &x_borrow) |
|
||||||
|
digit_sub(Y[i], y_borrow, &y_borrow);
|
||||||
|
}
|
||||||
|
// (At least) one of the next two loops will perform zero iterations:
|
||||||
|
for (; i < X.len(); i++) Z[i] = digit_sub(X[i], x_borrow, &x_borrow);
|
||||||
|
for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], y_borrow, &y_borrow);
|
||||||
|
DCHECK(x_borrow == 0); // NOLINT(readability/check)
|
||||||
|
DCHECK(y_borrow == 0); // NOLINT(readability/check)
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
Add(Z, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseAnd_PosNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// x & (-y) == x & ~(y-1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = X[i] & ~digit_sub(Y[i], borrow, &borrow);
|
||||||
|
for (; i < X.len(); i++) Z[i] = X[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseOr_PosPos(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = X[i] | Y[i];
|
||||||
|
// (At least) one of the next two loops will perform zero iterations:
|
||||||
|
for (; i < X.len(); i++) Z[i] = X[i];
|
||||||
|
for (; i < Y.len(); i++) Z[i] = Y[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseOr_NegNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// (-x) | (-y) == ~(x-1) | ~(y-1)
|
||||||
|
// == ~((x-1) & (y-1))
|
||||||
|
// == -(((x-1) & (y-1)) + 1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t x_borrow = 1;
|
||||||
|
digit_t y_borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) {
|
||||||
|
Z[i] = digit_sub(X[i], x_borrow, &x_borrow) &
|
||||||
|
digit_sub(Y[i], y_borrow, &y_borrow);
|
||||||
|
}
|
||||||
|
// Any leftover borrows don't matter, the '&' would drop them anyway.
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
Add(Z, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseOr_PosNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = digit_sub(Y[i], borrow, &borrow) & ~X[i];
|
||||||
|
for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], borrow, &borrow);
|
||||||
|
DCHECK(borrow == 0); // NOLINT(readability/check)
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
Add(Z, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseXor_PosPos(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
int pairs = X.len();
|
||||||
|
if (Y.len() < X.len()) {
|
||||||
|
std::swap(X, Y);
|
||||||
|
pairs = X.len();
|
||||||
|
}
|
||||||
|
DCHECK(X.len() <= Y.len());
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = X[i] ^ Y[i];
|
||||||
|
for (; i < Y.len(); i++) Z[i] = Y[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseXor_NegNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t x_borrow = 1;
|
||||||
|
digit_t y_borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) {
|
||||||
|
Z[i] = digit_sub(X[i], x_borrow, &x_borrow) ^
|
||||||
|
digit_sub(Y[i], y_borrow, &y_borrow);
|
||||||
|
}
|
||||||
|
// (At least) one of the next two loops will perform zero iterations:
|
||||||
|
for (; i < X.len(); i++) Z[i] = digit_sub(X[i], x_borrow, &x_borrow);
|
||||||
|
for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], y_borrow, &y_borrow);
|
||||||
|
DCHECK(x_borrow == 0); // NOLINT(readability/check)
|
||||||
|
DCHECK(y_borrow == 0); // NOLINT(readability/check)
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitwiseXor_PosNeg(RWDigits Z, Digits X, Digits Y) {
|
||||||
|
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||||
|
int pairs = std::min(X.len(), Y.len());
|
||||||
|
digit_t borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < pairs; i++) Z[i] = X[i] ^ digit_sub(Y[i], borrow, &borrow);
|
||||||
|
// (At least) one of the next two loops will perform zero iterations:
|
||||||
|
for (; i < X.len(); i++) Z[i] = X[i];
|
||||||
|
for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], borrow, &borrow);
|
||||||
|
DCHECK(borrow == 0); // NOLINT(readability/check)
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
Add(Z, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bigint
|
||||||
|
} // namespace v8
|
@ -118,5 +118,22 @@ bool SubtractSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
|||||||
return !x_negative;
|
return !x_negative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddOne(RWDigits Z, Digits X) {
|
||||||
|
digit_t carry = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; carry > 0 && i < X.len(); i++) Z[i] = digit_add2(X[i], carry, &carry);
|
||||||
|
if (carry > 0) Z[i++] = carry;
|
||||||
|
for (; i < X.len(); i++) Z[i] = X[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubtractOne(RWDigits Z, Digits X) {
|
||||||
|
digit_t borrow = 1;
|
||||||
|
int i = 0;
|
||||||
|
for (; borrow > 0; i++) Z[i] = digit_sub(X[i], borrow, &borrow);
|
||||||
|
for (; i < X.len(); i++) Z[i] = X[i];
|
||||||
|
for (; i < Z.len(); i++) Z[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bigint
|
} // namespace bigint
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -81,16 +81,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal helpers.
|
// Internal helpers.
|
||||||
static MaybeHandle<MutableBigInt> BitwiseAnd(Isolate* isolate,
|
|
||||||
Handle<BigInt> x,
|
|
||||||
Handle<BigInt> y);
|
|
||||||
static MaybeHandle<MutableBigInt> BitwiseXor(Isolate* isolate,
|
|
||||||
Handle<BigInt> x,
|
|
||||||
Handle<BigInt> y);
|
|
||||||
static MaybeHandle<MutableBigInt> BitwiseOr(Isolate* isolate,
|
|
||||||
Handle<BigInt> x,
|
|
||||||
Handle<BigInt> y);
|
|
||||||
|
|
||||||
static Handle<BigInt> TruncateToNBits(Isolate* isolate, int n,
|
static Handle<BigInt> TruncateToNBits(Isolate* isolate, int n,
|
||||||
Handle<BigInt> x);
|
Handle<BigInt> x);
|
||||||
static Handle<BigInt> TruncateAndSubFromPowerOfTwo(Isolate* isolate, int n,
|
static Handle<BigInt> TruncateAndSubFromPowerOfTwo(Isolate* isolate, int n,
|
||||||
@ -102,29 +92,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
|||||||
MutableBigInt result_storage = MutableBigInt());
|
MutableBigInt result_storage = MutableBigInt());
|
||||||
static Handle<MutableBigInt> AbsoluteSubOne(Isolate* isolate,
|
static Handle<MutableBigInt> AbsoluteSubOne(Isolate* isolate,
|
||||||
Handle<BigIntBase> x);
|
Handle<BigIntBase> x);
|
||||||
static MaybeHandle<MutableBigInt> AbsoluteSubOne(Isolate* isolate,
|
|
||||||
Handle<BigIntBase> x,
|
|
||||||
int result_length);
|
|
||||||
|
|
||||||
enum ExtraDigitsHandling { kCopy, kSkip };
|
|
||||||
enum SymmetricOp { kSymmetric, kNotSymmetric };
|
|
||||||
static inline Handle<MutableBigInt> AbsoluteBitwiseOp(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage, ExtraDigitsHandling extra_digits,
|
|
||||||
SymmetricOp symmetric,
|
|
||||||
const std::function<digit_t(digit_t, digit_t)>& op);
|
|
||||||
static Handle<MutableBigInt> AbsoluteAnd(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage = MutableBigInt());
|
|
||||||
static Handle<MutableBigInt> AbsoluteAndNot(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage = MutableBigInt());
|
|
||||||
static Handle<MutableBigInt> AbsoluteOr(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage = MutableBigInt());
|
|
||||||
static Handle<MutableBigInt> AbsoluteXor(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage = MutableBigInt());
|
|
||||||
|
|
||||||
// Specialized helpers for shift operations.
|
// Specialized helpers for shift operations.
|
||||||
static MaybeHandle<BigInt> LeftShiftByAbsolute(Isolate* isolate,
|
static MaybeHandle<BigInt> LeftShiftByAbsolute(Isolate* isolate,
|
||||||
@ -146,7 +113,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
|||||||
static uint64_t GetRawBits(BigIntBase x, bool* lossless);
|
static uint64_t GetRawBits(BigIntBase x, bool* lossless);
|
||||||
|
|
||||||
// Digit arithmetic helpers.
|
// Digit arithmetic helpers.
|
||||||
static inline digit_t digit_add(digit_t a, digit_t b, digit_t* carry);
|
|
||||||
static inline digit_t digit_sub(digit_t a, digit_t b, digit_t* borrow);
|
static inline digit_t digit_sub(digit_t a, digit_t b, digit_t* borrow);
|
||||||
static inline bool digit_ismax(digit_t x) {
|
static inline bool digit_ismax(digit_t x) {
|
||||||
return static_cast<digit_t>(~x) == 0;
|
return static_cast<digit_t>(~x) == 0;
|
||||||
@ -406,7 +372,7 @@ MaybeHandle<BigInt> BigInt::BitwiseNot(Isolate* isolate, Handle<BigInt> x) {
|
|||||||
MaybeHandle<MutableBigInt> result;
|
MaybeHandle<MutableBigInt> result;
|
||||||
if (x->sign()) {
|
if (x->sign()) {
|
||||||
// ~(-x) == ~(~(x-1)) == x-1
|
// ~(-x) == ~(~(x-1)) == x-1
|
||||||
result = MutableBigInt::AbsoluteSubOne(isolate, x, x->length());
|
result = MutableBigInt::AbsoluteSubOne(isolate, x);
|
||||||
} else {
|
} else {
|
||||||
// ~x == -x-1 == -(x+1)
|
// ~x == -x-1 == -(x+1)
|
||||||
result = MutableBigInt::AbsoluteAddOne(isolate, x, true);
|
result = MutableBigInt::AbsoluteAddOne(isolate, x, true);
|
||||||
@ -673,96 +639,82 @@ bool BigInt::EqualToBigInt(BigInt x, BigInt y) {
|
|||||||
|
|
||||||
MaybeHandle<BigInt> BigInt::BitwiseAnd(Isolate* isolate, Handle<BigInt> x,
|
MaybeHandle<BigInt> BigInt::BitwiseAnd(Isolate* isolate, Handle<BigInt> x,
|
||||||
Handle<BigInt> y) {
|
Handle<BigInt> y) {
|
||||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseAnd(isolate, x, y));
|
bool x_sign = x->sign();
|
||||||
}
|
bool y_sign = y->sign();
|
||||||
|
Handle<MutableBigInt> result;
|
||||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseAnd(Isolate* isolate,
|
if (!x_sign && !y_sign) {
|
||||||
Handle<BigInt> x,
|
int result_length =
|
||||||
Handle<BigInt> y) {
|
bigint::BitwiseAnd_PosPos_ResultLength(x->length(), y->length());
|
||||||
if (!x->sign() && !y->sign()) {
|
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||||
return AbsoluteAnd(isolate, x, y);
|
bigint::BitwiseAnd_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
} else if (x->sign() && y->sign()) {
|
DCHECK(!result->sign());
|
||||||
int result_length = std::max(x->length(), y->length()) + 1;
|
} else if (x_sign && y_sign) {
|
||||||
// (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
|
int result_length =
|
||||||
// == -(((x-1) | (y-1)) + 1)
|
bigint::BitwiseAnd_NegNeg_ResultLength(x->length(), y->length());
|
||||||
Handle<MutableBigInt> result;
|
if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) {
|
||||||
if (!AbsoluteSubOne(isolate, x, result_length).ToHandle(&result)) {
|
return {};
|
||||||
return MaybeHandle<MutableBigInt>();
|
|
||||||
}
|
}
|
||||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
bigint::BitwiseAnd_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
result = AbsoluteOr(isolate, result, y_1, *result);
|
result->set_sign(true);
|
||||||
return AbsoluteAddOne(isolate, result, true, *result);
|
|
||||||
} else {
|
} else {
|
||||||
DCHECK(x->sign() != y->sign());
|
if (x_sign) std::swap(x, y);
|
||||||
// Assume that x is the positive BigInt.
|
int result_length = bigint::BitwiseAnd_PosNeg_ResultLength(x->length());
|
||||||
if (x->sign()) std::swap(x, y);
|
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||||
// x & (-y) == x & ~(y-1) == x &~ (y-1)
|
bigint::BitwiseAnd_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
DCHECK(!result->sign());
|
||||||
return AbsoluteAndNot(isolate, x, y_1);
|
|
||||||
}
|
}
|
||||||
|
return MutableBigInt::MakeImmutable(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<BigInt> BigInt::BitwiseXor(Isolate* isolate, Handle<BigInt> x,
|
MaybeHandle<BigInt> BigInt::BitwiseXor(Isolate* isolate, Handle<BigInt> x,
|
||||||
Handle<BigInt> y) {
|
Handle<BigInt> y) {
|
||||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseXor(isolate, x, y));
|
bool x_sign = x->sign();
|
||||||
}
|
bool y_sign = y->sign();
|
||||||
|
Handle<MutableBigInt> result;
|
||||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseXor(Isolate* isolate,
|
if (!x_sign && !y_sign) {
|
||||||
Handle<BigInt> x,
|
int result_length =
|
||||||
Handle<BigInt> y) {
|
bigint::BitwiseXor_PosPos_ResultLength(x->length(), y->length());
|
||||||
if (!x->sign() && !y->sign()) {
|
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||||
return AbsoluteXor(isolate, x, y);
|
bigint::BitwiseXor_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
} else if (x->sign() && y->sign()) {
|
DCHECK(!result->sign());
|
||||||
int result_length = std::max(x->length(), y->length());
|
} else if (x_sign && y_sign) {
|
||||||
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
|
int result_length =
|
||||||
Handle<MutableBigInt> result =
|
bigint::BitwiseXor_NegNeg_ResultLength(x->length(), y->length());
|
||||||
AbsoluteSubOne(isolate, x, result_length).ToHandleChecked();
|
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
bigint::BitwiseXor_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
return AbsoluteXor(isolate, result, y_1, *result);
|
DCHECK(!result->sign());
|
||||||
} else {
|
} else {
|
||||||
DCHECK(x->sign() != y->sign());
|
if (x_sign) std::swap(x, y);
|
||||||
int result_length = std::max(x->length(), y->length()) + 1;
|
int result_length =
|
||||||
// Assume that x is the positive BigInt.
|
bigint::BitwiseXor_PosNeg_ResultLength(x->length(), y->length());
|
||||||
if (x->sign()) std::swap(x, y);
|
if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) {
|
||||||
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
return {};
|
||||||
Handle<MutableBigInt> result;
|
|
||||||
if (!AbsoluteSubOne(isolate, y, result_length).ToHandle(&result)) {
|
|
||||||
return MaybeHandle<MutableBigInt>();
|
|
||||||
}
|
}
|
||||||
result = AbsoluteXor(isolate, result, x, *result);
|
bigint::BitwiseXor_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
return AbsoluteAddOne(isolate, result, true, *result);
|
result->set_sign(true);
|
||||||
}
|
}
|
||||||
|
return MutableBigInt::MakeImmutable(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<BigInt> BigInt::BitwiseOr(Isolate* isolate, Handle<BigInt> x,
|
MaybeHandle<BigInt> BigInt::BitwiseOr(Isolate* isolate, Handle<BigInt> x,
|
||||||
Handle<BigInt> y) {
|
Handle<BigInt> y) {
|
||||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseOr(isolate, x, y));
|
bool x_sign = x->sign();
|
||||||
}
|
bool y_sign = y->sign();
|
||||||
|
int result_length = bigint::BitwiseOrResultLength(x->length(), y->length());
|
||||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseOr(Isolate* isolate,
|
Handle<MutableBigInt> result =
|
||||||
Handle<BigInt> x,
|
MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||||
Handle<BigInt> y) {
|
if (!x_sign && !y_sign) {
|
||||||
int result_length = std::max(x->length(), y->length());
|
bigint::BitwiseOr_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
if (!x->sign() && !y->sign()) {
|
DCHECK(!result->sign());
|
||||||
return AbsoluteOr(isolate, x, y);
|
} else if (x_sign && y_sign) {
|
||||||
} else if (x->sign() && y->sign()) {
|
bigint::BitwiseOr_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
// (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
|
result->set_sign(true);
|
||||||
// == -(((x-1) & (y-1)) + 1)
|
|
||||||
Handle<MutableBigInt> result =
|
|
||||||
AbsoluteSubOne(isolate, x, result_length).ToHandleChecked();
|
|
||||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
|
||||||
result = AbsoluteAnd(isolate, result, y_1, *result);
|
|
||||||
return AbsoluteAddOne(isolate, result, true, *result);
|
|
||||||
} else {
|
} else {
|
||||||
DCHECK(x->sign() != y->sign());
|
if (x_sign) std::swap(x, y);
|
||||||
// Assume that x is the positive BigInt.
|
bigint::BitwiseOr_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||||
if (x->sign()) std::swap(x, y);
|
result->set_sign(true);
|
||||||
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
|
|
||||||
Handle<MutableBigInt> result =
|
|
||||||
AbsoluteSubOne(isolate, y, result_length).ToHandleChecked();
|
|
||||||
result = AbsoluteAndNot(isolate, result, x, *result);
|
|
||||||
return AbsoluteAddOne(isolate, result, true, *result);
|
|
||||||
}
|
}
|
||||||
|
return MutableBigInt::MakeImmutable(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<BigInt> BigInt::Increment(Isolate* isolate, Handle<BigInt> x) {
|
MaybeHandle<BigInt> BigInt::Increment(Isolate* isolate, Handle<BigInt> x) {
|
||||||
@ -1270,16 +1222,12 @@ MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteAddOne(
|
|||||||
} else {
|
} else {
|
||||||
DCHECK(result->length() == result_length);
|
DCHECK(result->length() == result_length);
|
||||||
}
|
}
|
||||||
digit_t carry = 1;
|
if (input_length == 0) {
|
||||||
for (int i = 0; i < input_length; i++) {
|
result->set_digit(0, 1);
|
||||||
digit_t new_carry = 0;
|
} else if (input_length == 1 && !will_overflow) {
|
||||||
result->set_digit(i, digit_add(x->digit(i), carry, &new_carry));
|
result->set_digit(0, x->digit(0) + 1);
|
||||||
carry = new_carry;
|
|
||||||
}
|
|
||||||
if (result_length > input_length) {
|
|
||||||
result->set_digit(input_length, carry);
|
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(carry, 0);
|
bigint::AddOne(GetRWDigits(result), GetDigits(x));
|
||||||
}
|
}
|
||||||
result->set_sign(sign);
|
result->set_sign(sign);
|
||||||
return result;
|
return result;
|
||||||
@ -1289,134 +1237,16 @@ MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteAddOne(
|
|||||||
Handle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate,
|
Handle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate,
|
||||||
Handle<BigIntBase> x) {
|
Handle<BigIntBase> x) {
|
||||||
DCHECK(!x->is_zero());
|
DCHECK(!x->is_zero());
|
||||||
// Requesting a result length identical to an existing BigInt's length
|
|
||||||
// cannot overflow the limit.
|
|
||||||
return AbsoluteSubOne(isolate, x, x->length()).ToHandleChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like the above, but you can specify that the allocated result should have
|
|
||||||
// length {result_length}, which must be at least as large as {x->length()}.
|
|
||||||
MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate,
|
|
||||||
Handle<BigIntBase> x,
|
|
||||||
int result_length) {
|
|
||||||
DCHECK(!x->is_zero());
|
|
||||||
DCHECK(result_length >= x->length());
|
|
||||||
Handle<MutableBigInt> result;
|
|
||||||
if (!New(isolate, result_length).ToHandle(&result)) {
|
|
||||||
return MaybeHandle<MutableBigInt>();
|
|
||||||
}
|
|
||||||
int length = x->length();
|
int length = x->length();
|
||||||
digit_t borrow = 1;
|
Handle<MutableBigInt> result = New(isolate, length).ToHandleChecked();
|
||||||
for (int i = 0; i < length; i++) {
|
if (length == 1) {
|
||||||
digit_t new_borrow = 0;
|
result->set_digit(0, x->digit(0) - 1);
|
||||||
result->set_digit(i, digit_sub(x->digit(i), borrow, &new_borrow));
|
|
||||||
borrow = new_borrow;
|
|
||||||
}
|
|
||||||
DCHECK_EQ(borrow, 0);
|
|
||||||
for (int i = length; i < result_length; i++) {
|
|
||||||
result->set_digit(i, borrow);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper for Absolute{And,AndNot,Or,Xor}.
|
|
||||||
// Performs the given binary {op} on digit pairs of {x} and {y}; when the
|
|
||||||
// end of the shorter of the two is reached, {extra_digits} configures how
|
|
||||||
// remaining digits in the longer input (if {symmetric} == kSymmetric, in
|
|
||||||
// {x} otherwise) are handled: copied to the result or ignored.
|
|
||||||
// If {result_storage} is non-nullptr, it will be used for the result and
|
|
||||||
// any extra digits in it will be zeroed out, otherwise a new BigInt (with
|
|
||||||
// the same length as the longer input) will be allocated.
|
|
||||||
// {result_storage} may alias {x} or {y} for in-place modification.
|
|
||||||
// Example:
|
|
||||||
// y: [ y2 ][ y1 ][ y0 ]
|
|
||||||
// x: [ x3 ][ x2 ][ x1 ][ x0 ]
|
|
||||||
// | | | |
|
|
||||||
// (kCopy) (op) (op) (op)
|
|
||||||
// | | | |
|
|
||||||
// v v v v
|
|
||||||
// result_storage: [ 0 ][ x3 ][ r2 ][ r1 ][ r0 ]
|
|
||||||
inline Handle<MutableBigInt> MutableBigInt::AbsoluteBitwiseOp(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage, ExtraDigitsHandling extra_digits,
|
|
||||||
SymmetricOp symmetric, const std::function<digit_t(digit_t, digit_t)>& op) {
|
|
||||||
int x_length = x->length();
|
|
||||||
int y_length = y->length();
|
|
||||||
int num_pairs = y_length;
|
|
||||||
if (x_length < y_length) {
|
|
||||||
num_pairs = x_length;
|
|
||||||
if (symmetric == kSymmetric) {
|
|
||||||
std::swap(x, y);
|
|
||||||
std::swap(x_length, y_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DCHECK(num_pairs == std::min(x_length, y_length));
|
|
||||||
Handle<MutableBigInt> result(result_storage, isolate);
|
|
||||||
int result_length = extra_digits == kCopy ? x_length : num_pairs;
|
|
||||||
if (result_storage.is_null()) {
|
|
||||||
result = New(isolate, result_length).ToHandleChecked();
|
|
||||||
} else {
|
} else {
|
||||||
DCHECK(result_storage.length() >= result_length);
|
bigint::SubtractOne(GetRWDigits(result), GetDigits(x));
|
||||||
result_length = result_storage.length();
|
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
for (; i < num_pairs; i++) {
|
|
||||||
result->set_digit(i, op(x->digit(i), y->digit(i)));
|
|
||||||
}
|
|
||||||
if (extra_digits == kCopy) {
|
|
||||||
for (; i < x_length; i++) {
|
|
||||||
result->set_digit(i, x->digit(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (; i < result_length; i++) {
|
|
||||||
result->set_digit(i, 0);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If {result_storage} is non-nullptr, it will be used for the result,
|
|
||||||
// otherwise a new BigInt of appropriate length will be allocated.
|
|
||||||
// {result_storage} may alias {x} or {y} for in-place modification.
|
|
||||||
Handle<MutableBigInt> MutableBigInt::AbsoluteAnd(Isolate* isolate,
|
|
||||||
Handle<BigIntBase> x,
|
|
||||||
Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage) {
|
|
||||||
return AbsoluteBitwiseOp(isolate, x, y, result_storage, kSkip, kSymmetric,
|
|
||||||
[](digit_t a, digit_t b) { return a & b; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If {result_storage} is non-nullptr, it will be used for the result,
|
|
||||||
// otherwise a new BigInt of appropriate length will be allocated.
|
|
||||||
// {result_storage} may alias {x} or {y} for in-place modification.
|
|
||||||
Handle<MutableBigInt> MutableBigInt::AbsoluteAndNot(
|
|
||||||
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage) {
|
|
||||||
return AbsoluteBitwiseOp(isolate, x, y, result_storage, kCopy, kNotSymmetric,
|
|
||||||
[](digit_t a, digit_t b) { return a & ~b; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If {result_storage} is non-nullptr, it will be used for the result,
|
|
||||||
// otherwise a new BigInt of appropriate length will be allocated.
|
|
||||||
// {result_storage} may alias {x} or {y} for in-place modification.
|
|
||||||
Handle<MutableBigInt> MutableBigInt::AbsoluteOr(Isolate* isolate,
|
|
||||||
Handle<BigIntBase> x,
|
|
||||||
Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage) {
|
|
||||||
return AbsoluteBitwiseOp(isolate, x, y, result_storage, kCopy, kSymmetric,
|
|
||||||
[](digit_t a, digit_t b) { return a | b; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If {result_storage} is non-nullptr, it will be used for the result,
|
|
||||||
// otherwise a new BigInt of appropriate length will be allocated.
|
|
||||||
// {result_storage} may alias {x} or {y} for in-place modification.
|
|
||||||
Handle<MutableBigInt> MutableBigInt::AbsoluteXor(Isolate* isolate,
|
|
||||||
Handle<BigIntBase> x,
|
|
||||||
Handle<BigIntBase> y,
|
|
||||||
MutableBigInt result_storage) {
|
|
||||||
return AbsoluteBitwiseOp(isolate, x, y, result_storage, kCopy, kSymmetric,
|
|
||||||
[](digit_t a, digit_t b) { return a ^ b; });
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeHandle<BigInt> MutableBigInt::LeftShiftByAbsolute(Isolate* isolate,
|
MaybeHandle<BigInt> MutableBigInt::LeftShiftByAbsolute(Isolate* isolate,
|
||||||
Handle<BigIntBase> x,
|
Handle<BigIntBase> x,
|
||||||
Handle<BigIntBase> y) {
|
Handle<BigIntBase> y) {
|
||||||
@ -1950,21 +1780,6 @@ using twodigit_t = uint64_t;
|
|||||||
using twodigit_t = __uint128_t;
|
using twodigit_t = __uint128_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// {carry} must point to an initialized digit_t and will either be incremented
|
|
||||||
// by one or left alone.
|
|
||||||
inline BigInt::digit_t MutableBigInt::digit_add(digit_t a, digit_t b,
|
|
||||||
digit_t* carry) {
|
|
||||||
#if HAVE_TWODIGIT_T
|
|
||||||
twodigit_t result = static_cast<twodigit_t>(a) + static_cast<twodigit_t>(b);
|
|
||||||
*carry += result >> kDigitBits;
|
|
||||||
return static_cast<digit_t>(result);
|
|
||||||
#else
|
|
||||||
digit_t result = a + b;
|
|
||||||
if (result < a) *carry += 1;
|
|
||||||
return result;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// {borrow} must point to an initialized digit_t and will either be incremented
|
// {borrow} must point to an initialized digit_t and will either be incremented
|
||||||
// by one or left alone.
|
// by one or left alone.
|
||||||
inline BigInt::digit_t MutableBigInt::digit_sub(digit_t a, digit_t b,
|
inline BigInt::digit_t MutableBigInt::digit_sub(digit_t a, digit_t b,
|
||||||
|
Loading…
Reference in New Issue
Block a user