Commit fc6f6213 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

[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/+/3149453Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76793}
parent b757471c
......@@ -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",
......
......@@ -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.
......
// 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
This diff is collapsed.
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