%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/bigint/ |
Current File : /home/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_