[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.h",
|
||||
"src/bigint/bigint.h",
|
||||
"src/bigint/bitwise.cc",
|
||||
"src/bigint/digit-arithmetic.h",
|
||||
"src/bigint/div-barrett.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.h",
|
||||
"src/bigint/bigint.h",
|
||||
"src/bigint/bitwise.cc",
|
||||
"src/bigint/digit-arithmetic.h",
|
||||
"src/bigint/div-burnikel.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.
|
||||
bool AddSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
||||
bool y_negative);
|
||||
// Z := X + 1
|
||||
void AddOne(RWDigits Z, Digits X);
|
||||
|
||||
// Z := X - Y. Requires X >= Y.
|
||||
void Subtract(RWDigits Z, Digits X, Digits Y);
|
||||
// Subtraction of signed integers. Returns true if the result is negative.
|
||||
bool SubtractSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
|
||||
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 };
|
||||
|
||||
@ -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.
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 v8
|
||||
|
@ -81,16 +81,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
||||
}
|
||||
|
||||
// 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,
|
||||
Handle<BigInt> x);
|
||||
static Handle<BigInt> TruncateAndSubFromPowerOfTwo(Isolate* isolate, int n,
|
||||
@ -102,29 +92,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
||||
MutableBigInt result_storage = MutableBigInt());
|
||||
static Handle<MutableBigInt> AbsoluteSubOne(Isolate* isolate,
|
||||
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.
|
||||
static MaybeHandle<BigInt> LeftShiftByAbsolute(Isolate* isolate,
|
||||
@ -146,7 +113,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
|
||||
static uint64_t GetRawBits(BigIntBase x, bool* lossless);
|
||||
|
||||
// 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 bool digit_ismax(digit_t x) {
|
||||
return static_cast<digit_t>(~x) == 0;
|
||||
@ -406,7 +372,7 @@ MaybeHandle<BigInt> BigInt::BitwiseNot(Isolate* isolate, Handle<BigInt> x) {
|
||||
MaybeHandle<MutableBigInt> result;
|
||||
if (x->sign()) {
|
||||
// ~(-x) == ~(~(x-1)) == x-1
|
||||
result = MutableBigInt::AbsoluteSubOne(isolate, x, x->length());
|
||||
result = MutableBigInt::AbsoluteSubOne(isolate, x);
|
||||
} else {
|
||||
// ~x == -x-1 == -(x+1)
|
||||
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,
|
||||
Handle<BigInt> y) {
|
||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseAnd(isolate, x, y));
|
||||
}
|
||||
|
||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseAnd(Isolate* isolate,
|
||||
Handle<BigInt> x,
|
||||
Handle<BigInt> y) {
|
||||
if (!x->sign() && !y->sign()) {
|
||||
return AbsoluteAnd(isolate, x, y);
|
||||
} else if (x->sign() && y->sign()) {
|
||||
int result_length = std::max(x->length(), y->length()) + 1;
|
||||
// (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
|
||||
// == -(((x-1) | (y-1)) + 1)
|
||||
Handle<MutableBigInt> result;
|
||||
if (!AbsoluteSubOne(isolate, x, result_length).ToHandle(&result)) {
|
||||
return MaybeHandle<MutableBigInt>();
|
||||
bool x_sign = x->sign();
|
||||
bool y_sign = y->sign();
|
||||
Handle<MutableBigInt> result;
|
||||
if (!x_sign && !y_sign) {
|
||||
int result_length =
|
||||
bigint::BitwiseAnd_PosPos_ResultLength(x->length(), y->length());
|
||||
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||
bigint::BitwiseAnd_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
DCHECK(!result->sign());
|
||||
} else if (x_sign && y_sign) {
|
||||
int result_length =
|
||||
bigint::BitwiseAnd_NegNeg_ResultLength(x->length(), y->length());
|
||||
if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) {
|
||||
return {};
|
||||
}
|
||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
||||
result = AbsoluteOr(isolate, result, y_1, *result);
|
||||
return AbsoluteAddOne(isolate, result, true, *result);
|
||||
bigint::BitwiseAnd_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
result->set_sign(true);
|
||||
} else {
|
||||
DCHECK(x->sign() != y->sign());
|
||||
// Assume that x is the positive BigInt.
|
||||
if (x->sign()) std::swap(x, y);
|
||||
// x & (-y) == x & ~(y-1) == x &~ (y-1)
|
||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
||||
return AbsoluteAndNot(isolate, x, y_1);
|
||||
if (x_sign) std::swap(x, y);
|
||||
int result_length = bigint::BitwiseAnd_PosNeg_ResultLength(x->length());
|
||||
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||
bigint::BitwiseAnd_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
DCHECK(!result->sign());
|
||||
}
|
||||
return MutableBigInt::MakeImmutable(result);
|
||||
}
|
||||
|
||||
MaybeHandle<BigInt> BigInt::BitwiseXor(Isolate* isolate, Handle<BigInt> x,
|
||||
Handle<BigInt> y) {
|
||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseXor(isolate, x, y));
|
||||
}
|
||||
|
||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseXor(Isolate* isolate,
|
||||
Handle<BigInt> x,
|
||||
Handle<BigInt> y) {
|
||||
if (!x->sign() && !y->sign()) {
|
||||
return AbsoluteXor(isolate, x, y);
|
||||
} else if (x->sign() && y->sign()) {
|
||||
int result_length = std::max(x->length(), y->length());
|
||||
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
|
||||
Handle<MutableBigInt> result =
|
||||
AbsoluteSubOne(isolate, x, result_length).ToHandleChecked();
|
||||
Handle<MutableBigInt> y_1 = AbsoluteSubOne(isolate, y);
|
||||
return AbsoluteXor(isolate, result, y_1, *result);
|
||||
bool x_sign = x->sign();
|
||||
bool y_sign = y->sign();
|
||||
Handle<MutableBigInt> result;
|
||||
if (!x_sign && !y_sign) {
|
||||
int result_length =
|
||||
bigint::BitwiseXor_PosPos_ResultLength(x->length(), y->length());
|
||||
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||
bigint::BitwiseXor_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
DCHECK(!result->sign());
|
||||
} else if (x_sign && y_sign) {
|
||||
int result_length =
|
||||
bigint::BitwiseXor_NegNeg_ResultLength(x->length(), y->length());
|
||||
result = MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||
bigint::BitwiseXor_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
DCHECK(!result->sign());
|
||||
} else {
|
||||
DCHECK(x->sign() != y->sign());
|
||||
int result_length = std::max(x->length(), y->length()) + 1;
|
||||
// Assume that x is the positive BigInt.
|
||||
if (x->sign()) std::swap(x, y);
|
||||
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||
Handle<MutableBigInt> result;
|
||||
if (!AbsoluteSubOne(isolate, y, result_length).ToHandle(&result)) {
|
||||
return MaybeHandle<MutableBigInt>();
|
||||
if (x_sign) std::swap(x, y);
|
||||
int result_length =
|
||||
bigint::BitwiseXor_PosNeg_ResultLength(x->length(), y->length());
|
||||
if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) {
|
||||
return {};
|
||||
}
|
||||
result = AbsoluteXor(isolate, result, x, *result);
|
||||
return AbsoluteAddOne(isolate, result, true, *result);
|
||||
bigint::BitwiseXor_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
result->set_sign(true);
|
||||
}
|
||||
return MutableBigInt::MakeImmutable(result);
|
||||
}
|
||||
|
||||
MaybeHandle<BigInt> BigInt::BitwiseOr(Isolate* isolate, Handle<BigInt> x,
|
||||
Handle<BigInt> y) {
|
||||
return MutableBigInt::MakeImmutable(MutableBigInt::BitwiseOr(isolate, x, y));
|
||||
}
|
||||
|
||||
MaybeHandle<MutableBigInt> MutableBigInt::BitwiseOr(Isolate* isolate,
|
||||
Handle<BigInt> x,
|
||||
Handle<BigInt> y) {
|
||||
int result_length = std::max(x->length(), y->length());
|
||||
if (!x->sign() && !y->sign()) {
|
||||
return AbsoluteOr(isolate, x, y);
|
||||
} else if (x->sign() && y->sign()) {
|
||||
// (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
|
||||
// == -(((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);
|
||||
bool x_sign = x->sign();
|
||||
bool y_sign = y->sign();
|
||||
int result_length = bigint::BitwiseOrResultLength(x->length(), y->length());
|
||||
Handle<MutableBigInt> result =
|
||||
MutableBigInt::New(isolate, result_length).ToHandleChecked();
|
||||
if (!x_sign && !y_sign) {
|
||||
bigint::BitwiseOr_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
DCHECK(!result->sign());
|
||||
} else if (x_sign && y_sign) {
|
||||
bigint::BitwiseOr_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
result->set_sign(true);
|
||||
} else {
|
||||
DCHECK(x->sign() != y->sign());
|
||||
// Assume that x is the positive BigInt.
|
||||
if (x->sign()) std::swap(x, y);
|
||||
// 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);
|
||||
if (x_sign) std::swap(x, y);
|
||||
bigint::BitwiseOr_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y));
|
||||
result->set_sign(true);
|
||||
}
|
||||
return MutableBigInt::MakeImmutable(result);
|
||||
}
|
||||
|
||||
MaybeHandle<BigInt> BigInt::Increment(Isolate* isolate, Handle<BigInt> x) {
|
||||
@ -1270,16 +1222,12 @@ MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteAddOne(
|
||||
} else {
|
||||
DCHECK(result->length() == result_length);
|
||||
}
|
||||
digit_t carry = 1;
|
||||
for (int i = 0; i < input_length; i++) {
|
||||
digit_t new_carry = 0;
|
||||
result->set_digit(i, digit_add(x->digit(i), carry, &new_carry));
|
||||
carry = new_carry;
|
||||
}
|
||||
if (result_length > input_length) {
|
||||
result->set_digit(input_length, carry);
|
||||
if (input_length == 0) {
|
||||
result->set_digit(0, 1);
|
||||
} else if (input_length == 1 && !will_overflow) {
|
||||
result->set_digit(0, x->digit(0) + 1);
|
||||
} else {
|
||||
DCHECK_EQ(carry, 0);
|
||||
bigint::AddOne(GetRWDigits(result), GetDigits(x));
|
||||
}
|
||||
result->set_sign(sign);
|
||||
return result;
|
||||
@ -1289,134 +1237,16 @@ MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteAddOne(
|
||||
Handle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate,
|
||||
Handle<BigIntBase> x) {
|
||||
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();
|
||||
digit_t borrow = 1;
|
||||
for (int i = 0; i < length; i++) {
|
||||
digit_t new_borrow = 0;
|
||||
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();
|
||||
Handle<MutableBigInt> result = New(isolate, length).ToHandleChecked();
|
||||
if (length == 1) {
|
||||
result->set_digit(0, x->digit(0) - 1);
|
||||
} else {
|
||||
DCHECK(result_storage.length() >= result_length);
|
||||
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);
|
||||
bigint::SubtractOne(GetRWDigits(result), GetDigits(x));
|
||||
}
|
||||
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,
|
||||
Handle<BigIntBase> x,
|
||||
Handle<BigIntBase> y) {
|
||||
@ -1950,21 +1780,6 @@ using twodigit_t = uint64_t;
|
||||
using twodigit_t = __uint128_t;
|
||||
#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
|
||||
// by one or left alone.
|
||||
inline BigInt::digit_t MutableBigInt::digit_sub(digit_t a, digit_t b,
|
||||
|
Loading…
Reference in New Issue
Block a user