Commit e3002216 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Implement bitwise binary ops

Bug: v8:6791
Change-Id: Id889823ff2cf20cf504010ffce3283f0d75bf72f
Reviewed-on: https://chromium-review.googlesource.com/699420Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48295}
parent 841ca52c
......@@ -163,15 +163,72 @@ bool BigInt::Equal(BigInt* x, BigInt* y) {
}
Handle<BigInt> BigInt::BitwiseAnd(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
Handle<BigInt> result;
if (!x->sign() && !y->sign()) {
result = AbsoluteAnd(x, y);
} else if (x->sign() && y->sign()) {
int result_length = Max(x->length(), y->length()) + 1;
// (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
// == -(((x-1) | (y-1)) + 1)
result = AbsoluteSubOne(x, result_length);
result = AbsoluteOr(result, AbsoluteSubOne(y, y->length()), *result);
result = AbsoluteAddOne(result, true, *result);
} 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)
result = AbsoluteAndNot(x, AbsoluteSubOne(y, y->length()));
}
result->RightTrim();
return result;
}
Handle<BigInt> BigInt::BitwiseXor(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
Handle<BigInt> result;
if (!x->sign() && !y->sign()) {
result = AbsoluteXor(x, y);
} else if (x->sign() && y->sign()) {
int result_length = Max(x->length(), y->length());
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
result = AbsoluteSubOne(x, result_length);
result = AbsoluteXor(result, AbsoluteSubOne(y, y->length()), *result);
} else {
DCHECK(x->sign() != y->sign());
int result_length = 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)
result = AbsoluteSubOne(y, result_length);
result = AbsoluteXor(result, x, *result);
result = AbsoluteAddOne(result, true, *result);
}
result->RightTrim();
return result;
}
Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
Handle<BigInt> result;
int result_length = Max(x->length(), y->length());
if (!x->sign() && !y->sign()) {
result = AbsoluteOr(x, y);
} else if (x->sign() && y->sign()) {
// (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
// == -(((x-1) & (y-1)) + 1)
result = AbsoluteSubOne(x, result_length);
result = AbsoluteAnd(result, AbsoluteSubOne(y, y->length()), *result);
result = AbsoluteAddOne(result, true, *result);
} 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)
result = AbsoluteSubOne(y, result_length);
result = AbsoluteAndNot(result, x, *result);
result = AbsoluteAddOne(result, true, *result);
}
result->RightTrim();
return result;
}
MaybeHandle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
......@@ -275,6 +332,142 @@ Handle<BigInt> BigInt::AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
return result;
}
// Adds 1 to the absolute value of {x}, stores the result in {result_storage}
// and sets its sign to {sign}.
// {result_storage} and {x} may refer to the same BigInt for in-place
// modification.
Handle<BigInt> BigInt::AbsoluteAddOne(Handle<BigInt> x, bool sign,
BigInt* result_storage) {
DCHECK(result_storage != nullptr);
int input_length = x->length();
int result_length = result_storage->length();
Isolate* isolate = x->GetIsolate();
Handle<BigInt> result(result_storage, isolate);
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);
} else {
DCHECK(carry == 0);
}
result->set_sign(sign);
return result;
}
// Subtracts 1 from the absolute value of {x}. {x} must not be zero.
// Allocates a new BigInt of length {result_length} for the result;
// {result_length} must be at least as large as {x->length()}.
Handle<BigInt> BigInt::AbsoluteSubOne(Handle<BigInt> x, int result_length) {
DCHECK(!x->is_zero());
DCHECK(result_length >= x->length());
Handle<BigInt> result =
x->GetIsolate()->factory()->NewBigIntRaw(result_length);
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(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 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<BigInt> BigInt::AbsoluteBitwiseOp(
Handle<BigInt> x, Handle<BigInt> y, BigInt* result_storage,
ExtraDigitsHandling extra_digits,
std::function<digit_t(digit_t, digit_t)> op) {
int x_length = x->length();
int y_length = y->length();
if (x_length < y_length) {
return AbsoluteBitwiseOp(y, x, result_storage, extra_digits, op);
}
Isolate* isolate = x->GetIsolate();
Handle<BigInt> result(result_storage, isolate);
int result_length = extra_digits == kCopy ? x_length : y_length;
if (result_storage == nullptr) {
result = isolate->factory()->NewBigIntRaw(result_length);
} else {
DCHECK(result_storage->length() >= result_length);
result_length = result_storage->length();
}
int i = 0;
for (; i < y_length; 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;
}
// 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<BigInt> BigInt::AbsoluteAnd(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage) {
return AbsoluteBitwiseOp(x, y, result_storage, kSkip,
[](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<BigInt> BigInt::AbsoluteAndNot(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage) {
return AbsoluteBitwiseOp(x, y, result_storage, kCopy,
[](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<BigInt> BigInt::AbsoluteOr(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage) {
return AbsoluteBitwiseOp(x, y, result_storage, kCopy,
[](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<BigInt> BigInt::AbsoluteXor(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage) {
return AbsoluteBitwiseOp(x, y, result_storage, kCopy,
[](digit_t a, digit_t b) { return a ^ b; });
}
// Returns a positive value if abs(x) > abs(y), a negative value if
// abs(x) < abs(y), or zero if abs(x) == abs(y).
int BigInt::AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y) {
int diff = x->length() - y->length();
if (diff != 0) return diff;
......
......@@ -101,8 +101,24 @@ class BigInt : public HeapObject {
bool result_sign);
static Handle<BigInt> AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
bool result_sign);
// Returns a positive value if abs(x) > abs(y), a negative value if
// abs(x) < abs(y), or zero if abs(x) == abs(y).
static Handle<BigInt> AbsoluteAddOne(Handle<BigInt> x, bool sign,
BigInt* result_storage);
static Handle<BigInt> AbsoluteSubOne(Handle<BigInt> x, int result_length);
enum ExtraDigitsHandling { kCopy, kSkip };
static inline Handle<BigInt> AbsoluteBitwiseOp(
Handle<BigInt> x, Handle<BigInt> y, BigInt* result_storage,
ExtraDigitsHandling extra_digits,
std::function<digit_t(digit_t, digit_t)> op);
static Handle<BigInt> AbsoluteAnd(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage = nullptr);
static Handle<BigInt> AbsoluteAndNot(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage = nullptr);
static Handle<BigInt> AbsoluteOr(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage = nullptr);
static Handle<BigInt> AbsoluteXor(Handle<BigInt> x, Handle<BigInt> y,
BigInt* result_storage = nullptr);
static int AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y);
static void MultiplyAccumulate(Handle<BigInt> multiplicand,
......@@ -139,6 +155,9 @@ class BigInt : public HeapObject {
static inline digit_t digit_mul(digit_t a, digit_t b, digit_t* high);
static inline digit_t digit_div(digit_t high, digit_t low, digit_t divisor,
digit_t* remainder);
static inline bool digit_ismax(digit_t x) {
return static_cast<digit_t>(~x) == 0;
}
class LengthBits : public BitField<int, 0, kMaxLengthBits> {};
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};
......
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