blob: 947b23588fcdf993d86b73bb0667db129edb74e2 [file] [log] [blame]
//===-- A class to manipulate wide integers. --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_UINT_H
#define LLVM_LIBC_SRC___SUPPORT_UINT_H
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/bit.h" // countl_zero
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/integer_utils.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/math_extras.h" // SumCarry, DiffBorrow
#include "src/__support/number_pair.h"
#include <stddef.h> // For size_t
#include <stdint.h>
namespace LIBC_NAMESPACE::cpp {
template <size_t Bits, bool Signed> struct BigInt {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in BigInt should be a multiple of 64.");
LIBC_INLINE_VAR static constexpr size_t WORDCOUNT = Bits / 64;
cpp::array<uint64_t, WORDCOUNT> val{};
LIBC_INLINE_VAR static constexpr uint64_t MASK32 = 0xFFFFFFFFu;
LIBC_INLINE static constexpr uint64_t low(uint64_t v) { return v & MASK32; }
LIBC_INLINE static constexpr uint64_t high(uint64_t v) {
return (v >> 32) & MASK32;
}
LIBC_INLINE constexpr BigInt() = default;
LIBC_INLINE constexpr BigInt(const BigInt<Bits, Signed> &other) = default;
template <size_t OtherBits, bool OtherSigned>
LIBC_INLINE constexpr BigInt(const BigInt<OtherBits, OtherSigned> &other) {
if (OtherBits >= Bits) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] = other[i];
} else {
size_t i = 0;
for (; i < OtherBits / 64; ++i)
val[i] = other[i];
uint64_t sign = 0;
if constexpr (Signed && OtherSigned) {
sign = static_cast<uint64_t>(
-static_cast<int64_t>(other[OtherBits / 64 - 1] >> 63));
}
for (; i < WORDCOUNT; ++i)
val[i] = sign;
}
}
// Construct a BigInt from a C array.
template <size_t N, enable_if_t<N <= WORDCOUNT, int> = 0>
LIBC_INLINE constexpr BigInt(const uint64_t (&nums)[N]) {
size_t min_wordcount = N < WORDCOUNT ? N : WORDCOUNT;
size_t i = 0;
for (; i < min_wordcount; ++i)
val[i] = nums[i];
// If nums doesn't completely fill val, then fill the rest with zeroes.
for (; i < WORDCOUNT; ++i)
val[i] = 0;
}
// Initialize the first word to |v| and the rest to 0.
template <typename T,
typename = cpp::enable_if_t<is_integral_v<T> && sizeof(T) <= 16>>
LIBC_INLINE constexpr BigInt(T v) {
val[0] = static_cast<uint64_t>(v);
if constexpr (Bits == 64)
return;
// Bits is at least 128.
size_t i = 1;
if constexpr (sizeof(T) == 16) {
val[1] = static_cast<uint64_t>(v >> 64);
i = 2;
}
uint64_t sign = (Signed && (v < 0)) ? 0xffff'ffff'ffff'ffff : 0;
for (; i < WORDCOUNT; ++i) {
val[i] = sign;
}
}
LIBC_INLINE constexpr explicit BigInt(
const cpp::array<uint64_t, WORDCOUNT> &words) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] = words[i];
}
template <typename T> LIBC_INLINE constexpr explicit operator T() const {
return to<T>();
}
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> && sizeof(T) <= 8 && !cpp::is_same_v<T, bool>, T>
to() const {
return static_cast<T>(val[0]);
}
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> && sizeof(T) == 16, T>
to() const {
// T is 128-bit.
T lo = static_cast<T>(val[0]);
if constexpr (Bits == 64) {
if constexpr (Signed) {
// Extend sign for negative numbers.
return (val[0] >> 63) ? ((T(-1) << 64) + lo) : lo;
} else {
return lo;
}
} else {
return static_cast<T>((static_cast<T>(val[1]) << 64) + lo);
}
}
LIBC_INLINE constexpr explicit operator bool() const { return !is_zero(); }
LIBC_INLINE BigInt<Bits, Signed> &
operator=(const BigInt<Bits, Signed> &other) = default;
LIBC_INLINE constexpr bool is_zero() const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
if (val[i] != 0)
return false;
}
return true;
}
// Add x to this number and store the result in this number.
// Returns the carry value produced by the addition operation.
LIBC_INLINE constexpr uint64_t add(const BigInt<Bits, Signed> &x) {
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry_const(val[i], x.val[i], s.carry);
val[i] = s.sum;
}
return s.carry;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator+(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry(val[i], other.val[i], s.carry);
result.val[i] = s.sum;
}
return result;
}
// This will only apply when initializing a variable from constant values, so
// it will always use the constexpr version of add_with_carry.
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator+(BigInt<Bits, Signed> &&other) const {
BigInt<Bits, Signed> result;
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
s = add_with_carry_const(val[i], other.val[i], s.carry);
result.val[i] = s.sum;
}
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator+=(const BigInt<Bits, Signed> &other) {
add(other); // Returned carry value is ignored.
return *this;
}
// Subtract x to this number and store the result in this number.
// Returns the carry value produced by the subtraction operation.
LIBC_INLINE constexpr uint64_t sub(const BigInt<Bits, Signed> &x) {
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow_const(val[i], x.val[i], d.borrow);
val[i] = d.diff;
}
return d.borrow;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator-(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow(val[i], other.val[i], d.borrow);
result.val[i] = d.diff;
}
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator-(BigInt<Bits, Signed> &&other) const {
BigInt<Bits, Signed> result;
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
d = sub_with_borrow_const(val[i], other.val[i], d.borrow);
result.val[i] = d.diff;
}
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator-=(const BigInt<Bits, Signed> &other) {
// TODO(lntue): Set overflow flag / errno when carry is true.
sub(other);
return *this;
}
// Multiply this number with x and store the result in this number. It is
// implemented using the long multiplication algorithm by splitting the
// 64-bit words of this number and |x| in to 32-bit halves but peforming
// the operations using 64-bit numbers. This ensures that we don't lose the
// carry bits.
// Returns the carry value produced by the multiplication operation.
LIBC_INLINE constexpr uint64_t mul(uint64_t x) {
BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
for (size_t i = 0; i < WORDCOUNT; ++i) {
NumberPair<uint64_t> prod = full_mul(val[i], x);
BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
val[i] = partial_sum.val[0];
partial_sum.val[0] = partial_sum.val[1];
partial_sum.val[1] = carry;
carry = 0;
}
return partial_sum.val[1];
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator*(const BigInt<Bits, Signed> &other) const {
if constexpr (Signed) {
BigInt<Bits, false> a(*this);
BigInt<Bits, false> b(other);
bool a_neg = (a.val[WORDCOUNT - 1] >> 63);
bool b_neg = (b.val[WORDCOUNT - 1] >> 63);
if (a_neg)
a = -a;
if (b_neg)
b = -b;
BigInt<Bits, false> prod = a * b;
if (a_neg != b_neg)
prod = -prod;
return static_cast<BigInt<Bits, true>>(prod);
} else {
if constexpr (WORDCOUNT == 1) {
return {val[0] * other.val[0]};
} else {
BigInt<Bits, Signed> result(0);
BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
for (size_t i = 0; i < WORDCOUNT; ++i) {
for (size_t j = 0; j <= i; j++) {
NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
result.val[i] = partial_sum.val[0];
partial_sum.val[0] = partial_sum.val[1];
partial_sum.val[1] = carry;
carry = 0;
}
return result;
}
}
}
// Return the full product, only unsigned for now.
template <size_t OtherBits>
LIBC_INLINE constexpr BigInt<Bits + OtherBits, Signed>
ful_mul(const BigInt<OtherBits, Signed> &other) const {
BigInt<Bits + OtherBits, Signed> result(0);
BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
constexpr size_t OTHER_WORDCOUNT = BigInt<OtherBits, Signed>::WORDCOUNT;
for (size_t i = 0; i <= WORDCOUNT + OTHER_WORDCOUNT - 2; ++i) {
const size_t lower_idx =
i < OTHER_WORDCOUNT ? 0 : i - OTHER_WORDCOUNT + 1;
const size_t upper_idx = i < WORDCOUNT ? i : WORDCOUNT - 1;
for (size_t j = lower_idx; j <= upper_idx; ++j) {
NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
result.val[i] = partial_sum.val[0];
partial_sum.val[0] = partial_sum.val[1];
partial_sum.val[1] = carry;
carry = 0;
}
result.val[WORDCOUNT + OTHER_WORDCOUNT - 1] = partial_sum.val[0];
return result;
}
// Fast hi part of the full product. The normal product `operator*` returns
// `Bits` least significant bits of the full product, while this function will
// approximate `Bits` most significant bits of the full product with errors
// bounded by:
// 0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= WORDCOUNT - 1.
//
// An example usage of this is to quickly (but less accurately) compute the
// product of (normalized) mantissas of floating point numbers:
// (mant_1, mant_2) -> quick_mul_hi -> normalize leading bit
// is much more efficient than:
// (mant_1, mant_2) -> ful_mul -> normalize leading bit
// -> convert back to same Bits width by shifting/rounding,
// especially for higher precisions.
//
// Performance summary:
// Number of 64-bit x 64-bit -> 128-bit multiplications performed.
// Bits WORDCOUNT ful_mul quick_mul_hi Error bound
// 128 2 4 3 1
// 196 3 9 6 2
// 256 4 16 10 3
// 512 8 64 36 7
LIBC_INLINE constexpr BigInt<Bits, Signed>
quick_mul_hi(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result(0);
BigInt<128, Signed> partial_sum(0);
uint64_t carry = 0;
// First round of accumulation for those at WORDCOUNT - 1 in the full
// product.
for (size_t i = 0; i < WORDCOUNT; ++i) {
NumberPair<uint64_t> prod =
full_mul(val[i], other.val[WORDCOUNT - 1 - i]);
BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
for (size_t i = WORDCOUNT; i < 2 * WORDCOUNT - 1; ++i) {
partial_sum.val[0] = partial_sum.val[1];
partial_sum.val[1] = carry;
carry = 0;
for (size_t j = i - WORDCOUNT + 1; j < WORDCOUNT; ++j) {
NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
BigInt<128, Signed> tmp({prod.lo, prod.hi});
carry += partial_sum.add(tmp);
}
result.val[i - WORDCOUNT] = partial_sum.val[0];
}
result.val[WORDCOUNT - 1] = partial_sum.val[1];
return result;
}
// pow takes a power and sets this to its starting value to that power. Zero
// to the zeroth power returns 1.
LIBC_INLINE constexpr void pow_n(uint64_t power) {
BigInt<Bits, Signed> result = 1;
BigInt<Bits, Signed> cur_power = *this;
while (power > 0) {
if ((power % 2) > 0) {
result = result * cur_power;
}
power = power >> 1;
cur_power *= cur_power;
}
*this = result;
}
// TODO: Make division work correctly for signed integers.
// div takes another BigInt of the same size and divides this by it. The value
// of this will be set to the quotient, and the return value is the remainder.
LIBC_INLINE constexpr optional<BigInt<Bits, Signed>>
div(const BigInt<Bits, Signed> &other) {
BigInt<Bits, Signed> remainder(0);
if (*this < other) {
remainder = *this;
*this = BigInt<Bits, Signed>(0);
return remainder;
}
if (other == 1) {
return remainder;
}
if (other == 0) {
return nullopt;
}
BigInt<Bits, Signed> quotient(0);
BigInt<Bits, Signed> subtractor = other;
int cur_bit = static_cast<int>(subtractor.clz() - this->clz());
subtractor.shift_left(cur_bit);
for (; cur_bit >= 0 && *this > 0; --cur_bit, subtractor.shift_right(1)) {
if (*this >= subtractor) {
this->sub(subtractor);
quotient = quotient | (BigInt<Bits, Signed>(1) << cur_bit);
}
}
remainder = *this;
*this = quotient;
return remainder;
}
// Efficiently perform BigInt / (x * 2^e), where x is a 32-bit unsigned
// integer, and return the remainder. The main idea is as follow:
// Let q = y / (x * 2^e) be the quotient, and
// r = y % (x * 2^e) be the remainder.
// First, notice that:
// r % (2^e) = y % (2^e),
// so we just need to focus on all the bits of y that is >= 2^e.
// To speed up the shift-and-add steps, we only use x as the divisor, and
// performing 32-bit shiftings instead of bit-by-bit shiftings.
// Since the remainder of each division step < x < 2^32, the computation of
// each step is now properly contained within uint64_t.
// And finally we perform some extra alignment steps for the remaining bits.
LIBC_INLINE constexpr optional<BigInt<Bits, Signed>>
div_uint32_times_pow_2(uint32_t x, size_t e) {
BigInt<Bits, Signed> remainder(0);
if (x == 0) {
return nullopt;
}
if (e >= Bits) {
remainder = *this;
*this = BigInt<Bits, false>(0);
return remainder;
}
BigInt<Bits, Signed> quotient(0);
uint64_t x64 = static_cast<uint64_t>(x);
// lower64 = smallest multiple of 64 that is >= e.
size_t lower64 = ((e >> 6) + ((e & 63) != 0)) << 6;
// lower_pos is the index of the closest 64-bit chunk >= 2^e.
size_t lower_pos = lower64 / 64;
// Keep track of current remainder mod x * 2^(32*i)
uint64_t rem = 0;
// pos is the index of the current 64-bit chunk that we are processing.
size_t pos = WORDCOUNT;
for (size_t q_pos = WORDCOUNT - lower_pos; q_pos > 0; --q_pos) {
// q_pos is 1 + the index of the current 64-bit chunk of the quotient
// being processed.
// Performing the division / modulus with divisor:
// x * 2^(64*q_pos - 32),
// i.e. using the upper 32-bit of the current 64-bit chunk.
rem <<= 32;
rem += val[--pos] >> 32;
uint64_t q_tmp = rem / x64;
rem %= x64;
// Performing the division / modulus with divisor:
// x * 2^(64*(q_pos - 1)),
// i.e. using the lower 32-bit of the current 64-bit chunk.
rem <<= 32;
rem += val[pos] & MASK32;
quotient.val[q_pos - 1] = (q_tmp << 32) + rem / x64;
rem %= x64;
}
// So far, what we have is:
// quotient = y / (x * 2^lower64), and
// rem = (y % (x * 2^lower64)) / 2^lower64.
// If (lower64 > e), we will need to perform an extra adjustment of the
// quotient and remainder, namely:
// y / (x * 2^e) = [ y / (x * 2^lower64) ] * 2^(lower64 - e) +
// + (rem * 2^(lower64 - e)) / x
// (y % (x * 2^e)) / 2^e = (rem * 2^(lower64 - e)) % x
size_t last_shift = lower64 - e;
if (last_shift > 0) {
// quotient * 2^(lower64 - e)
quotient <<= last_shift;
uint64_t q_tmp = 0;
uint64_t d = val[--pos];
if (last_shift >= 32) {
// The shifting (rem * 2^(lower64 - e)) might overflow uint64_t, so we
// perform a 32-bit shift first.
rem <<= 32;
rem += d >> 32;
d &= MASK32;
q_tmp = rem / x64;
rem %= x64;
last_shift -= 32;
} else {
// Only use the upper 32-bit of the current 64-bit chunk.
d >>= 32;
}
if (last_shift > 0) {
rem <<= 32;
rem += d;
q_tmp <<= last_shift;
x64 <<= 32 - last_shift;
q_tmp += rem / x64;
rem %= x64;
}
quotient.val[0] += q_tmp;
if (lower64 - e <= 32) {
// The remainder rem * 2^(lower64 - e) might overflow to the higher
// 64-bit chunk.
if (pos < WORDCOUNT - 1) {
remainder[pos + 1] = rem >> 32;
}
remainder[pos] = (rem << 32) + (val[pos] & MASK32);
} else {
remainder[pos] = rem;
}
} else {
remainder[pos] = rem;
}
// Set the remaining lower bits of the remainder.
for (; pos > 0; --pos) {
remainder[pos - 1] = val[pos - 1];
}
*this = quotient;
return remainder;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator/(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result(*this);
result.div(other);
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator/=(const BigInt<Bits, Signed> &other) {
div(other);
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator%(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result(*this);
return *result.div(other);
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator*=(const BigInt<Bits, Signed> &other) {
*this = *this * other;
return *this;
}
LIBC_INLINE constexpr uint64_t clz() {
uint64_t leading_zeroes = 0;
for (size_t i = WORDCOUNT; i > 0; --i) {
if (val[i - 1] == 0) {
leading_zeroes += sizeof(uint64_t) * 8;
} else {
leading_zeroes += countl_zero(val[i - 1]);
break;
}
}
return leading_zeroes;
}
LIBC_INLINE constexpr void shift_left(size_t s) {
#ifdef __SIZEOF_INT128__
if constexpr (Bits == 128) {
// Use builtin 128 bits if available;
if (s >= 128) {
val[0] = 0;
val[1] = 0;
return;
}
__uint128_t tmp = __uint128_t(val[0]) + (__uint128_t(val[1]) << 64);
tmp <<= s;
val[0] = uint64_t(tmp);
val[1] = uint64_t(tmp >> 64);
return;
}
#endif // __SIZEOF_INT128__
if (LIBC_UNLIKELY(s == 0))
return;
const size_t drop = s / 64; // Number of words to drop
const size_t shift = s % 64; // Bits to shift in the remaining words.
size_t i = WORDCOUNT;
if (drop < WORDCOUNT) {
i = WORDCOUNT - 1;
if (shift > 0) {
for (size_t j = WORDCOUNT - 1 - drop; j > 0; --i, --j) {
val[i] = (val[j] << shift) | (val[j - 1] >> (64 - shift));
}
val[i] = val[0] << shift;
} else {
for (size_t j = WORDCOUNT - 1 - drop; j > 0; --i, --j) {
val[i] = val[j];
}
val[i] = val[0];
}
}
for (size_t j = 0; j < i; ++j) {
val[j] = 0;
}
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator<<(size_t s) const {
BigInt<Bits, Signed> result(*this);
result.shift_left(s);
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &operator<<=(size_t s) {
shift_left(s);
return *this;
}
LIBC_INLINE constexpr void shift_right(size_t s) {
#ifdef __SIZEOF_INT128__
if constexpr (Bits == 128) {
// Use builtin 128 bits if available;
if (s >= 128) {
val[0] = 0;
val[1] = 0;
return;
}
__uint128_t tmp = __uint128_t(val[0]) + (__uint128_t(val[1]) << 64);
if constexpr (Signed) {
tmp = static_cast<__uint128_t>(static_cast<__int128_t>(tmp) >> s);
} else {
tmp >>= s;
}
val[0] = uint64_t(tmp);
val[1] = uint64_t(tmp >> 64);
return;
}
#endif // __SIZEOF_INT128__
if (LIBC_UNLIKELY(s == 0))
return;
const size_t drop = s / 64; // Number of words to drop
const size_t shift = s % 64; // Bit shift in the remaining words.
size_t i = 0;
uint64_t sign = Signed ? (val[WORDCOUNT - 1] >> 63) : 0;
if (drop < WORDCOUNT) {
if (shift > 0) {
for (size_t j = drop; j < WORDCOUNT - 1; ++i, ++j) {
val[i] = (val[j] >> shift) | (val[j + 1] << (64 - shift));
}
if constexpr (Signed) {
val[i] = static_cast<uint64_t>(
static_cast<int64_t>(val[WORDCOUNT - 1]) >> shift);
} else {
val[i] = val[WORDCOUNT - 1] >> shift;
}
++i;
} else {
for (size_t j = drop; j < WORDCOUNT; ++i, ++j) {
val[i] = val[j];
}
}
}
for (; i < WORDCOUNT; ++i) {
val[i] = sign;
}
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator>>(size_t s) const {
BigInt<Bits, Signed> result(*this);
result.shift_right(s);
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &operator>>=(size_t s) {
shift_right(s);
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator&(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] & other.val[i];
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator&=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] &= other.val[i];
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator|(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] | other.val[i];
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator|=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] |= other.val[i];
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed>
operator^(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = val[i] ^ other.val[i];
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &
operator^=(const BigInt<Bits, Signed> &other) {
for (size_t i = 0; i < WORDCOUNT; ++i)
val[i] ^= other.val[i];
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator~() const {
BigInt<Bits, Signed> result;
for (size_t i = 0; i < WORDCOUNT; ++i)
result.val[i] = ~val[i];
return result;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator-() const {
BigInt<Bits, Signed> result = ~(*this);
result.add(BigInt<Bits, Signed>(1));
return result;
}
LIBC_INLINE constexpr bool
operator==(const BigInt<Bits, Signed> &other) const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
if (val[i] != other.val[i])
return false;
}
return true;
}
LIBC_INLINE constexpr bool
operator!=(const BigInt<Bits, Signed> &other) const {
for (size_t i = 0; i < WORDCOUNT; ++i) {
if (val[i] != other.val[i])
return true;
}
return false;
}
LIBC_INLINE constexpr bool
operator>(const BigInt<Bits, Signed> &other) const {
if constexpr (Signed) {
// Check for different signs;
bool a_sign = val[WORDCOUNT - 1] >> 63;
bool b_sign = other.val[WORDCOUNT - 1] >> 63;
if (a_sign != b_sign) {
return b_sign;
}
}
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
if (word > other_word)
return true;
else if (word < other_word)
return false;
}
// Equal
return false;
}
LIBC_INLINE constexpr bool
operator>=(const BigInt<Bits, Signed> &other) const {
if constexpr (Signed) {
// Check for different signs;
bool a_sign = val[WORDCOUNT - 1] >> 63;
bool b_sign = other.val[WORDCOUNT - 1] >> 63;
if (a_sign != b_sign) {
return b_sign;
}
}
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
if (word > other_word)
return true;
else if (word < other_word)
return false;
}
// Equal
return true;
}
LIBC_INLINE constexpr bool
operator<(const BigInt<Bits, Signed> &other) const {
if constexpr (Signed) {
// Check for different signs;
bool a_sign = val[WORDCOUNT - 1] >> 63;
bool b_sign = other.val[WORDCOUNT - 1] >> 63;
if (a_sign != b_sign) {
return a_sign;
}
}
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
if (word > other_word)
return false;
else if (word < other_word)
return true;
}
// Equal
return false;
}
LIBC_INLINE constexpr bool
operator<=(const BigInt<Bits, Signed> &other) const {
if constexpr (Signed) {
// Check for different signs;
bool a_sign = val[WORDCOUNT - 1] >> 63;
bool b_sign = other.val[WORDCOUNT - 1] >> 63;
if (a_sign != b_sign) {
return a_sign;
}
}
for (size_t i = WORDCOUNT; i > 0; --i) {
uint64_t word = val[i - 1];
uint64_t other_word = other.val[i - 1];
if (word > other_word)
return false;
else if (word < other_word)
return true;
}
// Equal
return true;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &operator++() {
BigInt<Bits, Signed> one(1);
add(one);
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator++(int) {
BigInt<Bits, Signed> oldval(*this);
BigInt<Bits, Signed> one(1);
add(one);
return oldval;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> &operator--() {
BigInt<Bits, Signed> one(1);
sub(one);
return *this;
}
LIBC_INLINE constexpr BigInt<Bits, Signed> operator--(int) {
BigInt<Bits, Signed> oldval(*this);
BigInt<Bits, Signed> one(1);
sub(one);
return oldval;
}
// Return the i-th 64-bit word of the number.
LIBC_INLINE constexpr const uint64_t &operator[](size_t i) const {
return val[i];
}
// Return the i-th 64-bit word of the number.
LIBC_INLINE constexpr uint64_t &operator[](size_t i) { return val[i]; }
LIBC_INLINE uint64_t *data() { return val; }
LIBC_INLINE const uint64_t *data() const { return val; }
};
template <size_t Bits> using UInt = BigInt<Bits, false>;
template <size_t Bits> using Int = BigInt<Bits, true>;
// Provides limits of U/Int<128>.
template <> class numeric_limits<UInt<128>> {
public:
LIBC_INLINE static constexpr UInt<128> max() {
return UInt<128>({0xffff'ffff'ffff'ffff, 0xffff'ffff'ffff'ffff});
}
LIBC_INLINE static constexpr UInt<128> min() { return UInt<128>(0); }
LIBC_INLINE_VAR static constexpr int digits = 128;
};
template <> class numeric_limits<Int<128>> {
public:
LIBC_INLINE static constexpr Int<128> max() {
return Int<128>({0xffff'ffff'ffff'ffff, 0x7fff'ffff'ffff'ffff});
}
LIBC_INLINE static constexpr Int<128> min() {
return Int<128>({0, 0x8000'0000'0000'0000});
}
LIBC_INLINE_VAR static constexpr int digits = 128;
};
// Provides is_integral of U/Int<128>, U/Int<192>, U/Int<256>.
template <size_t Bits, bool Signed>
struct is_integral<BigInt<Bits, Signed>> : cpp::true_type {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in BigInt should be a multiple of 64.");
};
// Provides is_unsigned of UInt<128>, UInt<192>, UInt<256>.
template <size_t Bits> struct is_unsigned<UInt<Bits>> : public cpp::true_type {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in UInt should be a multiple of 64.");
};
template <size_t Bits>
struct make_unsigned<Int<Bits>> : type_identity<UInt<Bits>> {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in Int should be a multiple of 64.");
};
template <size_t Bits>
struct make_unsigned<UInt<Bits>> : type_identity<UInt<Bits>> {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in Int should be a multiple of 64.");
};
template <size_t Bits>
struct make_signed<Int<Bits>> : type_identity<Int<Bits>> {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in Int should be a multiple of 64.");
};
template <size_t Bits>
struct make_signed<UInt<Bits>> : type_identity<Int<Bits>> {
static_assert(Bits > 0 && Bits % 64 == 0,
"Number of bits in Int should be a multiple of 64.");
};
namespace internal {
template <typename T> struct is_custom_uint : cpp::false_type {};
template <size_t Bits> struct is_custom_uint<UInt<Bits>> : cpp::true_type {};
} // namespace internal
// bit_cast to UInt
// Note: The standard scheme for SFINAE selection is to have exactly one
// function instanciation valid at a time. This is usually done by having a
// predicate in one function and the negated predicate in the other one.
// e.g.
// template<typename = cpp::enable_if_t< is_custom_uint<To>::value == true> ...
// template<typename = cpp::enable_if_t< is_custom_uint<To>::value == false> ...
//
// Unfortunately this would make the default 'cpp::bit_cast' aware of
// 'is_custom_uint' (or any other customization). To prevent exposing all
// customizations in the original function, we create a different function with
// four 'typename's instead of three - otherwise it would be considered as a
// redeclaration of the same function leading to "error: template parameter
// redefines default argument".
template <typename To, typename From,
typename = cpp::enable_if_t<sizeof(To) == sizeof(From) &&
cpp::is_trivially_copyable<To>::value &&
cpp::is_trivially_copyable<From>::value>,
typename = cpp::enable_if_t<internal::is_custom_uint<To>::value>>
LIBC_INLINE constexpr To bit_cast(const From &from) {
To out;
using Storage = decltype(out.val);
out.val = cpp::bit_cast<Storage>(from);
return out;
}
// bit_cast from UInt
template <
typename To, size_t Bits,
typename = cpp::enable_if_t<sizeof(To) == sizeof(UInt<Bits>) &&
cpp::is_trivially_constructible<To>::value &&
cpp::is_trivially_copyable<To>::value &&
cpp::is_trivially_copyable<UInt<Bits>>::value>>
LIBC_INLINE constexpr To bit_cast(const UInt<Bits> &from) {
return cpp::bit_cast<To>(from.val);
}
} // namespace LIBC_NAMESPACE::cpp
#endif // LLVM_LIBC_SRC___SUPPORT_UINT_H