%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/bigint/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/bigint/digit-arithmetic.h |
// 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.
// Helper functions that operate on individual digits.
#ifndef V8_BIGINT_DIGIT_ARITHMETIC_H_
#define V8_BIGINT_DIGIT_ARITHMETIC_H_
#include "src/bigint/bigint.h"
#include "src/bigint/util.h"
namespace v8 {
namespace bigint {
static constexpr int kHalfDigitBits = kDigitBits / 2;
static constexpr digit_t kHalfDigitBase = digit_t{1} << kHalfDigitBits;
static constexpr digit_t kHalfDigitMask = kHalfDigitBase - 1;
constexpr bool digit_ismax(digit_t x) { return static_cast<digit_t>(~x) == 0; }
// {carry} will be set to 0 or 1.
inline digit_t digit_add2(digit_t a, digit_t b, digit_t* carry) {
#if HAVE_TWODIGIT_T
twodigit_t result = twodigit_t{a} + b;
*carry = result >> kDigitBits;
return static_cast<digit_t>(result);
#else
digit_t result = a + b;
*carry = (result < a) ? 1 : 0;
return result;
#endif
}
// This compiles to slightly better machine code than repeated invocations
// of {digit_add2}.
inline digit_t digit_add3(digit_t a, digit_t b, digit_t c, digit_t* carry) {
#if HAVE_TWODIGIT_T
twodigit_t result = twodigit_t{a} + b + c;
*carry = result >> kDigitBits;
return static_cast<digit_t>(result);
#else
digit_t result = a + b;
*carry = (result < a) ? 1 : 0;
result += c;
if (result < c) *carry += 1;
return result;
#endif
}
// {borrow} will be set to 0 or 1.
inline digit_t digit_sub(digit_t a, digit_t b, digit_t* borrow) {
#if HAVE_TWODIGIT_T
twodigit_t result = twodigit_t{a} - b;
*borrow = (result >> kDigitBits) & 1;
return static_cast<digit_t>(result);
#else
digit_t result = a - b;
*borrow = (result > a) ? 1 : 0;
return result;
#endif
}
// {borrow_out} will be set to 0 or 1.
inline digit_t digit_sub2(digit_t a, digit_t b, digit_t borrow_in,
digit_t* borrow_out) {
#if HAVE_TWODIGIT_T
twodigit_t subtrahend = twodigit_t{b} + borrow_in;
twodigit_t result = twodigit_t{a} - subtrahend;
*borrow_out = (result >> kDigitBits) & 1;
return static_cast<digit_t>(result);
#else
digit_t result = a - b;
*borrow_out = (result > a) ? 1 : 0;
if (result < borrow_in) *borrow_out += 1;
result -= borrow_in;
return result;
#endif
}
// Returns the low half of the result. High half is in {high}.
inline digit_t digit_mul(digit_t a, digit_t b, digit_t* high) {
#if HAVE_TWODIGIT_T
twodigit_t result = twodigit_t{a} * b;
*high = result >> kDigitBits;
return static_cast<digit_t>(result);
#else
// Multiply in half-pointer-sized chunks.
// For inputs [AH AL]*[BH BL], the result is:
//
// [AL*BL] // r_low
// + [AL*BH] // r_mid1
// + [AH*BL] // r_mid2
// + [AH*BH] // r_high
// = [R4 R3 R2 R1] // high = [R4 R3], low = [R2 R1]
//
// Where of course we must be careful with carries between the columns.
digit_t a_low = a & kHalfDigitMask;
digit_t a_high = a >> kHalfDigitBits;
digit_t b_low = b & kHalfDigitMask;
digit_t b_high = b >> kHalfDigitBits;
digit_t r_low = a_low * b_low;
digit_t r_mid1 = a_low * b_high;
digit_t r_mid2 = a_high * b_low;
digit_t r_high = a_high * b_high;
digit_t carry = 0;
digit_t low = digit_add3(r_low, r_mid1 << kHalfDigitBits,
r_mid2 << kHalfDigitBits, &carry);
*high =
(r_mid1 >> kHalfDigitBits) + (r_mid2 >> kHalfDigitBits) + r_high + carry;
return low;
#endif
}
// Returns the quotient.
// quotient = (high << kDigitBits + low - remainder) / divisor
static inline digit_t digit_div(digit_t high, digit_t low, digit_t divisor,
digit_t* remainder) {
#if defined(DCHECK)
DCHECK(high < divisor);
DCHECK(divisor != 0);
#endif
#if __x86_64__ && (__GNUC__ || __clang__)
digit_t quotient;
digit_t rem;
__asm__("divq %[divisor]"
// Outputs: {quotient} will be in rax, {rem} in rdx.
: "=a"(quotient), "=d"(rem)
// Inputs: put {high} into rdx, {low} into rax, and {divisor} into
// any register or stack slot.
: "d"(high), "a"(low), [divisor] "rm"(divisor));
*remainder = rem;
return quotient;
#elif __i386__ && (__GNUC__ || __clang__)
digit_t quotient;
digit_t rem;
__asm__("divl %[divisor]"
// Outputs: {quotient} will be in eax, {rem} in edx.
: "=a"(quotient), "=d"(rem)
// Inputs: put {high} into edx, {low} into eax, and {divisor} into
// any register or stack slot.
: "d"(high), "a"(low), [divisor] "rm"(divisor));
*remainder = rem;
return quotient;
#else
// Adapted from Warren, Hacker's Delight, p. 152.
int s = CountLeadingZeros(divisor);
#if defined(DCHECK)
DCHECK(s != kDigitBits); // {divisor} is not 0.
#endif
divisor <<= s;
digit_t vn1 = divisor >> kHalfDigitBits;
digit_t vn0 = divisor & kHalfDigitMask;
// {s} can be 0. {low >> kDigitBits} would be undefined behavior, so
// we mask the shift amount with {kShiftMask}, and the result with
// {s_zero_mask} which is 0 if s == 0 and all 1-bits otherwise.
static_assert(sizeof(intptr_t) == sizeof(digit_t),
"intptr_t and digit_t must have the same size");
const int kShiftMask = kDigitBits - 1;
digit_t s_zero_mask =
static_cast<digit_t>(static_cast<intptr_t>(-s) >> (kDigitBits - 1));
digit_t un32 =
(high << s) | ((low >> ((kDigitBits - s) & kShiftMask)) & s_zero_mask);
digit_t un10 = low << s;
digit_t un1 = un10 >> kHalfDigitBits;
digit_t un0 = un10 & kHalfDigitMask;
digit_t q1 = un32 / vn1;
digit_t rhat = un32 - q1 * vn1;
while (q1 >= kHalfDigitBase || q1 * vn0 > rhat * kHalfDigitBase + un1) {
q1--;
rhat += vn1;
if (rhat >= kHalfDigitBase) break;
}
digit_t un21 = un32 * kHalfDigitBase + un1 - q1 * divisor;
digit_t q0 = un21 / vn1;
rhat = un21 - q0 * vn1;
while (q0 >= kHalfDigitBase || q0 * vn0 > rhat * kHalfDigitBase + un0) {
q0--;
rhat += vn1;
if (rhat >= kHalfDigitBase) break;
}
*remainder = (un21 * kHalfDigitBase + un0 - q0 * divisor) >> s;
return q1 * kHalfDigitBase + q0;
#endif
}
} // namespace bigint
} // namespace v8
#endif // V8_BIGINT_DIGIT_ARITHMETIC_H_