xref: /llvm-project/libc/src/__support/big_int.h (revision 7302c8dbe71b7c03b73a35a21fa4b415fa1f4505)
109efe848SGuillaume Chatelet //===-- A class to manipulate wide integers. --------------------*- C++ -*-===//
209efe848SGuillaume Chatelet //
309efe848SGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409efe848SGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information.
509efe848SGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609efe848SGuillaume Chatelet //
709efe848SGuillaume Chatelet //===----------------------------------------------------------------------===//
809efe848SGuillaume Chatelet 
921895a84SOleksandr T. #ifndef LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
1021895a84SOleksandr T. #define LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
1109efe848SGuillaume Chatelet 
1209efe848SGuillaume Chatelet #include "src/__support/CPP/array.h"
1309efe848SGuillaume Chatelet #include "src/__support/CPP/bit.h" // countl_zero
1409efe848SGuillaume Chatelet #include "src/__support/CPP/limits.h"
1509efe848SGuillaume Chatelet #include "src/__support/CPP/optional.h"
1609efe848SGuillaume Chatelet #include "src/__support/CPP/type_traits.h"
1709efe848SGuillaume Chatelet #include "src/__support/macros/attributes.h" // LIBC_INLINE
185ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
1909efe848SGuillaume Chatelet #include "src/__support/macros/optimization.h"        // LIBC_UNLIKELY
2009efe848SGuillaume Chatelet #include "src/__support/macros/properties/compiler.h" // LIBC_COMPILER_IS_CLANG
2109efe848SGuillaume Chatelet #include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128, LIBC_TYPES_HAS_INT64
2209efe848SGuillaume Chatelet #include "src/__support/math_extras.h" // add_with_carry, sub_with_borrow
2309efe848SGuillaume Chatelet #include "src/__support/number_pair.h"
2409efe848SGuillaume Chatelet 
2509efe848SGuillaume Chatelet #include <stddef.h> // For size_t
2609efe848SGuillaume Chatelet #include <stdint.h>
2709efe848SGuillaume Chatelet 
285ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
2909efe848SGuillaume Chatelet 
3009efe848SGuillaume Chatelet namespace multiword {
3109efe848SGuillaume Chatelet 
3209efe848SGuillaume Chatelet // A type trait mapping unsigned integers to their half-width unsigned
3309efe848SGuillaume Chatelet // counterparts.
3409efe848SGuillaume Chatelet template <typename T> struct half_width;
3509efe848SGuillaume Chatelet template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
3609efe848SGuillaume Chatelet template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
3709efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64
3809efe848SGuillaume Chatelet template <> struct half_width<uint64_t> : cpp::type_identity<uint32_t> {};
3909efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128
4009efe848SGuillaume Chatelet template <> struct half_width<__uint128_t> : cpp::type_identity<uint64_t> {};
4109efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT128
4209efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT64
4309efe848SGuillaume Chatelet template <typename T> using half_width_t = typename half_width<T>::type;
4409efe848SGuillaume Chatelet 
4509efe848SGuillaume Chatelet // An array of two elements that can be used in multiword operations.
4609efe848SGuillaume Chatelet template <typename T> struct DoubleWide final : cpp::array<T, 2> {
4709efe848SGuillaume Chatelet   using UP = cpp::array<T, 2>;
4809efe848SGuillaume Chatelet   using UP::UP;
4909efe848SGuillaume Chatelet   LIBC_INLINE constexpr DoubleWide(T lo, T hi) : UP({lo, hi}) {}
5009efe848SGuillaume Chatelet };
5109efe848SGuillaume Chatelet 
5209efe848SGuillaume Chatelet // Converts an unsigned value into a DoubleWide<half_width_t<T>>.
5309efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr auto split(T value) {
5409efe848SGuillaume Chatelet   static_assert(cpp::is_unsigned_v<T>);
5509efe848SGuillaume Chatelet   using half_type = half_width_t<T>;
5609efe848SGuillaume Chatelet   return DoubleWide<half_type>(
5709efe848SGuillaume Chatelet       half_type(value),
5809efe848SGuillaume Chatelet       half_type(value >> cpp::numeric_limits<half_type>::digits));
5909efe848SGuillaume Chatelet }
6009efe848SGuillaume Chatelet 
6109efe848SGuillaume Chatelet // The low part of a DoubleWide value.
6209efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr T lo(const DoubleWide<T> &value) {
6309efe848SGuillaume Chatelet   return value[0];
6409efe848SGuillaume Chatelet }
6509efe848SGuillaume Chatelet // The high part of a DoubleWide value.
6609efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr T hi(const DoubleWide<T> &value) {
6709efe848SGuillaume Chatelet   return value[1];
6809efe848SGuillaume Chatelet }
6909efe848SGuillaume Chatelet // The low part of an unsigned value.
7009efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr half_width_t<T> lo(T value) {
7109efe848SGuillaume Chatelet   return lo(split(value));
7209efe848SGuillaume Chatelet }
7309efe848SGuillaume Chatelet // The high part of an unsigned value.
7409efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr half_width_t<T> hi(T value) {
7509efe848SGuillaume Chatelet   return hi(split(value));
7609efe848SGuillaume Chatelet }
7709efe848SGuillaume Chatelet 
7809efe848SGuillaume Chatelet // Returns 'a' times 'b' in a DoubleWide<word>. Cannot overflow by construction.
7909efe848SGuillaume Chatelet template <typename word>
8009efe848SGuillaume Chatelet LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) {
8109efe848SGuillaume Chatelet   if constexpr (cpp::is_same_v<word, uint8_t>) {
8209efe848SGuillaume Chatelet     return split<uint16_t>(uint16_t(a) * uint16_t(b));
8309efe848SGuillaume Chatelet   } else if constexpr (cpp::is_same_v<word, uint16_t>) {
8409efe848SGuillaume Chatelet     return split<uint32_t>(uint32_t(a) * uint32_t(b));
8509efe848SGuillaume Chatelet   }
8609efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64
8709efe848SGuillaume Chatelet   else if constexpr (cpp::is_same_v<word, uint32_t>) {
8809efe848SGuillaume Chatelet     return split<uint64_t>(uint64_t(a) * uint64_t(b));
8909efe848SGuillaume Chatelet   }
9009efe848SGuillaume Chatelet #endif
9109efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128
9209efe848SGuillaume Chatelet   else if constexpr (cpp::is_same_v<word, uint64_t>) {
9309efe848SGuillaume Chatelet     return split<__uint128_t>(__uint128_t(a) * __uint128_t(b));
9409efe848SGuillaume Chatelet   }
9509efe848SGuillaume Chatelet #endif
9609efe848SGuillaume Chatelet   else {
9709efe848SGuillaume Chatelet     using half_word = half_width_t<word>;
9809efe848SGuillaume Chatelet     const auto shiftl = [](word value) -> word {
9909efe848SGuillaume Chatelet       return value << cpp::numeric_limits<half_word>::digits;
10009efe848SGuillaume Chatelet     };
10109efe848SGuillaume Chatelet     const auto shiftr = [](word value) -> word {
10209efe848SGuillaume Chatelet       return value >> cpp::numeric_limits<half_word>::digits;
10309efe848SGuillaume Chatelet     };
10409efe848SGuillaume Chatelet     // Here we do a one digit multiplication where 'a' and 'b' are of type
10509efe848SGuillaume Chatelet     // word. We split 'a' and 'b' into half words and perform the classic long
10609efe848SGuillaume Chatelet     // multiplication with 'a' and 'b' being two-digit numbers.
10709efe848SGuillaume Chatelet 
10809efe848SGuillaume Chatelet     //    a      a_hi a_lo
10909efe848SGuillaume Chatelet     //  x b => x b_hi b_lo
11009efe848SGuillaume Chatelet     // ----    -----------
11109efe848SGuillaume Chatelet     //    c         result
11209efe848SGuillaume Chatelet     // We convert 'lo' and 'hi' from 'half_word' to 'word' so multiplication
11309efe848SGuillaume Chatelet     // doesn't overflow.
11409efe848SGuillaume Chatelet     const word a_lo = lo(a);
11509efe848SGuillaume Chatelet     const word b_lo = lo(b);
11609efe848SGuillaume Chatelet     const word a_hi = hi(a);
11709efe848SGuillaume Chatelet     const word b_hi = hi(b);
11809efe848SGuillaume Chatelet     const word step1 = b_lo * a_lo; // no overflow;
11909efe848SGuillaume Chatelet     const word step2 = b_lo * a_hi; // no overflow;
12009efe848SGuillaume Chatelet     const word step3 = b_hi * a_lo; // no overflow;
12109efe848SGuillaume Chatelet     const word step4 = b_hi * a_hi; // no overflow;
12209efe848SGuillaume Chatelet     word lo_digit = step1;
12309efe848SGuillaume Chatelet     word hi_digit = step4;
12409efe848SGuillaume Chatelet     const word no_carry = 0;
12509efe848SGuillaume Chatelet     word carry;
12609efe848SGuillaume Chatelet     word _; // unused carry variable.
12709efe848SGuillaume Chatelet     lo_digit = add_with_carry<word>(lo_digit, shiftl(step2), no_carry, carry);
12809efe848SGuillaume Chatelet     hi_digit = add_with_carry<word>(hi_digit, shiftr(step2), carry, _);
12909efe848SGuillaume Chatelet     lo_digit = add_with_carry<word>(lo_digit, shiftl(step3), no_carry, carry);
13009efe848SGuillaume Chatelet     hi_digit = add_with_carry<word>(hi_digit, shiftr(step3), carry, _);
13109efe848SGuillaume Chatelet     return DoubleWide<word>(lo_digit, hi_digit);
13209efe848SGuillaume Chatelet   }
13309efe848SGuillaume Chatelet }
13409efe848SGuillaume Chatelet 
13509efe848SGuillaume Chatelet // In-place 'dst op= rhs' with operation with carry propagation. Returns carry.
13609efe848SGuillaume Chatelet template <typename Function, typename word, size_t N, size_t M>
13709efe848SGuillaume Chatelet LIBC_INLINE constexpr word inplace_binop(Function op_with_carry,
13809efe848SGuillaume Chatelet                                          cpp::array<word, N> &dst,
13909efe848SGuillaume Chatelet                                          const cpp::array<word, M> &rhs) {
14009efe848SGuillaume Chatelet   static_assert(N >= M);
14109efe848SGuillaume Chatelet   word carry_out = 0;
14209efe848SGuillaume Chatelet   for (size_t i = 0; i < N; ++i) {
14309efe848SGuillaume Chatelet     const bool has_rhs_value = i < M;
14409efe848SGuillaume Chatelet     const word rhs_value = has_rhs_value ? rhs[i] : 0;
14509efe848SGuillaume Chatelet     const word carry_in = carry_out;
14609efe848SGuillaume Chatelet     dst[i] = op_with_carry(dst[i], rhs_value, carry_in, carry_out);
14709efe848SGuillaume Chatelet     // stop early when rhs is over and no carry is to be propagated.
14809efe848SGuillaume Chatelet     if (!has_rhs_value && carry_out == 0)
14909efe848SGuillaume Chatelet       break;
15009efe848SGuillaume Chatelet   }
15109efe848SGuillaume Chatelet   return carry_out;
15209efe848SGuillaume Chatelet }
15309efe848SGuillaume Chatelet 
15409efe848SGuillaume Chatelet // In-place addition. Returns carry.
15509efe848SGuillaume Chatelet template <typename word, size_t N, size_t M>
15609efe848SGuillaume Chatelet LIBC_INLINE constexpr word add_with_carry(cpp::array<word, N> &dst,
15709efe848SGuillaume Chatelet                                           const cpp::array<word, M> &rhs) {
15809efe848SGuillaume Chatelet   return inplace_binop(LIBC_NAMESPACE::add_with_carry<word>, dst, rhs);
15909efe848SGuillaume Chatelet }
16009efe848SGuillaume Chatelet 
16109efe848SGuillaume Chatelet // In-place subtraction. Returns borrow.
16209efe848SGuillaume Chatelet template <typename word, size_t N, size_t M>
16309efe848SGuillaume Chatelet LIBC_INLINE constexpr word sub_with_borrow(cpp::array<word, N> &dst,
16409efe848SGuillaume Chatelet                                            const cpp::array<word, M> &rhs) {
16509efe848SGuillaume Chatelet   return inplace_binop(LIBC_NAMESPACE::sub_with_borrow<word>, dst, rhs);
16609efe848SGuillaume Chatelet }
16709efe848SGuillaume Chatelet 
16809efe848SGuillaume Chatelet // In-place multiply-add. Returns carry.
16909efe848SGuillaume Chatelet // i.e., 'dst += b * c'
17009efe848SGuillaume Chatelet template <typename word, size_t N>
17109efe848SGuillaume Chatelet LIBC_INLINE constexpr word mul_add_with_carry(cpp::array<word, N> &dst, word b,
17209efe848SGuillaume Chatelet                                               word c) {
17309efe848SGuillaume Chatelet   return add_with_carry(dst, mul2(b, c));
17409efe848SGuillaume Chatelet }
17509efe848SGuillaume Chatelet 
17609efe848SGuillaume Chatelet // An array of two elements serving as an accumulator during multiword
17709efe848SGuillaume Chatelet // computations.
17809efe848SGuillaume Chatelet template <typename T> struct Accumulator final : cpp::array<T, 2> {
17909efe848SGuillaume Chatelet   using UP = cpp::array<T, 2>;
18009efe848SGuillaume Chatelet   LIBC_INLINE constexpr Accumulator() : UP({0, 0}) {}
18109efe848SGuillaume Chatelet   LIBC_INLINE constexpr T advance(T carry_in) {
18209efe848SGuillaume Chatelet     auto result = UP::front();
18309efe848SGuillaume Chatelet     UP::front() = UP::back();
18409efe848SGuillaume Chatelet     UP::back() = carry_in;
18509efe848SGuillaume Chatelet     return result;
18609efe848SGuillaume Chatelet   }
18709efe848SGuillaume Chatelet   LIBC_INLINE constexpr T sum() const { return UP::front(); }
18809efe848SGuillaume Chatelet   LIBC_INLINE constexpr T carry() const { return UP::back(); }
18909efe848SGuillaume Chatelet };
19009efe848SGuillaume Chatelet 
19109efe848SGuillaume Chatelet // In-place multiplication by a single word. Returns carry.
19209efe848SGuillaume Chatelet template <typename word, size_t N>
19309efe848SGuillaume Chatelet LIBC_INLINE constexpr word scalar_multiply_with_carry(cpp::array<word, N> &dst,
19409efe848SGuillaume Chatelet                                                       word x) {
19509efe848SGuillaume Chatelet   Accumulator<word> acc;
19609efe848SGuillaume Chatelet   for (auto &val : dst) {
19709efe848SGuillaume Chatelet     const word carry = mul_add_with_carry(acc, val, x);
19809efe848SGuillaume Chatelet     val = acc.advance(carry);
19909efe848SGuillaume Chatelet   }
20009efe848SGuillaume Chatelet   return acc.carry();
20109efe848SGuillaume Chatelet }
20209efe848SGuillaume Chatelet 
20309efe848SGuillaume Chatelet // Multiplication of 'lhs' by 'rhs' into 'dst'. Returns carry.
20409efe848SGuillaume Chatelet // This function is safe to use for signed numbers.
20509efe848SGuillaume Chatelet // https://stackoverflow.com/a/20793834
20609efe848SGuillaume Chatelet // https://pages.cs.wisc.edu/%7Emarkhill/cs354/Fall2008/beyond354/int.mult.html
20709efe848SGuillaume Chatelet template <typename word, size_t O, size_t M, size_t N>
20809efe848SGuillaume Chatelet LIBC_INLINE constexpr word multiply_with_carry(cpp::array<word, O> &dst,
20909efe848SGuillaume Chatelet                                                const cpp::array<word, M> &lhs,
21009efe848SGuillaume Chatelet                                                const cpp::array<word, N> &rhs) {
21109efe848SGuillaume Chatelet   static_assert(O >= M + N);
21209efe848SGuillaume Chatelet   Accumulator<word> acc;
21309efe848SGuillaume Chatelet   for (size_t i = 0; i < O; ++i) {
21409efe848SGuillaume Chatelet     const size_t lower_idx = i < N ? 0 : i - N + 1;
21509efe848SGuillaume Chatelet     const size_t upper_idx = i < M ? i : M - 1;
21609efe848SGuillaume Chatelet     word carry = 0;
21709efe848SGuillaume Chatelet     for (size_t j = lower_idx; j <= upper_idx; ++j)
21809efe848SGuillaume Chatelet       carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]);
21909efe848SGuillaume Chatelet     dst[i] = acc.advance(carry);
22009efe848SGuillaume Chatelet   }
22109efe848SGuillaume Chatelet   return acc.carry();
22209efe848SGuillaume Chatelet }
22309efe848SGuillaume Chatelet 
22409efe848SGuillaume Chatelet template <typename word, size_t N>
22509efe848SGuillaume Chatelet LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst,
22609efe848SGuillaume Chatelet                                         const cpp::array<word, N> &lhs,
22709efe848SGuillaume Chatelet                                         const cpp::array<word, N> &rhs) {
22809efe848SGuillaume Chatelet   Accumulator<word> acc;
22909efe848SGuillaume Chatelet   word carry = 0;
23009efe848SGuillaume Chatelet   // First round of accumulation for those at N - 1 in the full product.
23109efe848SGuillaume Chatelet   for (size_t i = 0; i < N; ++i)
23209efe848SGuillaume Chatelet     carry += mul_add_with_carry(acc, lhs[i], rhs[N - 1 - i]);
23309efe848SGuillaume Chatelet   for (size_t i = N; i < 2 * N - 1; ++i) {
23409efe848SGuillaume Chatelet     acc.advance(carry);
23509efe848SGuillaume Chatelet     carry = 0;
23609efe848SGuillaume Chatelet     for (size_t j = i - N + 1; j < N; ++j)
23709efe848SGuillaume Chatelet       carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]);
23809efe848SGuillaume Chatelet     dst[i - N] = acc.sum();
23909efe848SGuillaume Chatelet   }
24009efe848SGuillaume Chatelet   dst.back() = acc.carry();
24109efe848SGuillaume Chatelet }
24209efe848SGuillaume Chatelet 
24309efe848SGuillaume Chatelet template <typename word, size_t N>
24409efe848SGuillaume Chatelet LIBC_INLINE constexpr bool is_negative(cpp::array<word, N> &array) {
24509efe848SGuillaume Chatelet   using signed_word = cpp::make_signed_t<word>;
24609efe848SGuillaume Chatelet   return cpp::bit_cast<signed_word>(array.back()) < 0;
24709efe848SGuillaume Chatelet }
24809efe848SGuillaume Chatelet 
24909efe848SGuillaume Chatelet // An enum for the shift function below.
25009efe848SGuillaume Chatelet enum Direction { LEFT, RIGHT };
25109efe848SGuillaume Chatelet 
25209efe848SGuillaume Chatelet // A bitwise shift on an array of elements.
253b88a1dd6SGuillaume Chatelet // 'offset' must be less than TOTAL_BITS (i.e., sizeof(word) * CHAR_BIT * N)
254b88a1dd6SGuillaume Chatelet // otherwise the behavior is undefined.
25509efe848SGuillaume Chatelet template <Direction direction, bool is_signed, typename word, size_t N>
25609efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
25709efe848SGuillaume Chatelet                                                 size_t offset) {
25809efe848SGuillaume Chatelet   static_assert(direction == LEFT || direction == RIGHT);
25909efe848SGuillaume Chatelet   constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
26009efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128
261bd589f5cSGuillaume Chatelet   constexpr size_t TOTAL_BITS = N * WORD_BITS;
26209efe848SGuillaume Chatelet   if constexpr (TOTAL_BITS == 128) {
26309efe848SGuillaume Chatelet     using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>;
26409efe848SGuillaume Chatelet     auto tmp = cpp::bit_cast<type>(array);
26509efe848SGuillaume Chatelet     if constexpr (direction == LEFT)
26609efe848SGuillaume Chatelet       tmp <<= offset;
26709efe848SGuillaume Chatelet     else
26809efe848SGuillaume Chatelet       tmp >>= offset;
26909efe848SGuillaume Chatelet     return cpp::bit_cast<cpp::array<word, N>>(tmp);
27009efe848SGuillaume Chatelet   }
27109efe848SGuillaume Chatelet #endif
272b88a1dd6SGuillaume Chatelet   if (LIBC_UNLIKELY(offset == 0))
273b88a1dd6SGuillaume Chatelet     return array;
27409efe848SGuillaume Chatelet   const bool is_neg = is_signed && is_negative(array);
27509efe848SGuillaume Chatelet   constexpr auto at = [](size_t index) -> int {
27609efe848SGuillaume Chatelet     // reverse iteration when direction == LEFT.
27709efe848SGuillaume Chatelet     if constexpr (direction == LEFT)
27809efe848SGuillaume Chatelet       return int(N) - int(index) - 1;
27909efe848SGuillaume Chatelet     return int(index);
28009efe848SGuillaume Chatelet   };
28109efe848SGuillaume Chatelet   const auto safe_get_at = [&](size_t index) -> word {
28209efe848SGuillaume Chatelet     // return appropriate value when accessing out of bound elements.
28309efe848SGuillaume Chatelet     const int i = at(index);
28409efe848SGuillaume Chatelet     if (i < 0)
28509efe848SGuillaume Chatelet       return 0;
28609efe848SGuillaume Chatelet     if (i >= int(N))
28709efe848SGuillaume Chatelet       return is_neg ? -1 : 0;
28809efe848SGuillaume Chatelet     return array[i];
28909efe848SGuillaume Chatelet   };
29009efe848SGuillaume Chatelet   const size_t index_offset = offset / WORD_BITS;
29109efe848SGuillaume Chatelet   const size_t bit_offset = offset % WORD_BITS;
29209efe848SGuillaume Chatelet #ifdef LIBC_COMPILER_IS_CLANG
29309efe848SGuillaume Chatelet   __builtin_assume(index_offset < N);
29409efe848SGuillaume Chatelet #endif
29509efe848SGuillaume Chatelet   cpp::array<word, N> out = {};
29609efe848SGuillaume Chatelet   for (size_t index = 0; index < N; ++index) {
29709efe848SGuillaume Chatelet     const word part1 = safe_get_at(index + index_offset);
29809efe848SGuillaume Chatelet     const word part2 = safe_get_at(index + index_offset + 1);
29909efe848SGuillaume Chatelet     word &dst = out[at(index)];
30009efe848SGuillaume Chatelet     if (bit_offset == 0)
30109efe848SGuillaume Chatelet       dst = part1; // no crosstalk between parts.
30209efe848SGuillaume Chatelet     else if constexpr (direction == LEFT)
3036b21e170SOverMighty       dst = static_cast<word>((part1 << bit_offset) |
3046b21e170SOverMighty                               (part2 >> (WORD_BITS - bit_offset)));
30509efe848SGuillaume Chatelet     else
306b5efd214SOverMighty       dst = static_cast<word>((part1 >> bit_offset) |
307b5efd214SOverMighty                               (part2 << (WORD_BITS - bit_offset)));
30809efe848SGuillaume Chatelet   }
30909efe848SGuillaume Chatelet   return out;
31009efe848SGuillaume Chatelet }
31109efe848SGuillaume Chatelet 
31209efe848SGuillaume Chatelet #define DECLARE_COUNTBIT(NAME, INDEX_EXPR)                                     \
31309efe848SGuillaume Chatelet   template <typename word, size_t N>                                           \
31409efe848SGuillaume Chatelet   LIBC_INLINE constexpr int NAME(const cpp::array<word, N> &val) {             \
31509efe848SGuillaume Chatelet     int bit_count = 0;                                                         \
31609efe848SGuillaume Chatelet     for (size_t i = 0; i < N; ++i) {                                           \
31709efe848SGuillaume Chatelet       const int word_count = cpp::NAME<word>(val[INDEX_EXPR]);                 \
31809efe848SGuillaume Chatelet       bit_count += word_count;                                                 \
31909efe848SGuillaume Chatelet       if (word_count != cpp::numeric_limits<word>::digits)                     \
32009efe848SGuillaume Chatelet         break;                                                                 \
32109efe848SGuillaume Chatelet     }                                                                          \
32209efe848SGuillaume Chatelet     return bit_count;                                                          \
32309efe848SGuillaume Chatelet   }
32409efe848SGuillaume Chatelet 
32509efe848SGuillaume Chatelet DECLARE_COUNTBIT(countr_zero, i)         // iterating forward
32609efe848SGuillaume Chatelet DECLARE_COUNTBIT(countr_one, i)          // iterating forward
32709efe848SGuillaume Chatelet DECLARE_COUNTBIT(countl_zero, N - i - 1) // iterating backward
32809efe848SGuillaume Chatelet DECLARE_COUNTBIT(countl_one, N - i - 1)  // iterating backward
32909efe848SGuillaume Chatelet 
33009efe848SGuillaume Chatelet } // namespace multiword
33109efe848SGuillaume Chatelet 
33209efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename WordType = uint64_t>
33309efe848SGuillaume Chatelet struct BigInt {
33409efe848SGuillaume Chatelet private:
33509efe848SGuillaume Chatelet   static_assert(cpp::is_integral_v<WordType> && cpp::is_unsigned_v<WordType>,
33609efe848SGuillaume Chatelet                 "WordType must be unsigned integer.");
33709efe848SGuillaume Chatelet 
33809efe848SGuillaume Chatelet   struct Division {
33909efe848SGuillaume Chatelet     BigInt quotient;
34009efe848SGuillaume Chatelet     BigInt remainder;
34109efe848SGuillaume Chatelet   };
34209efe848SGuillaume Chatelet 
34309efe848SGuillaume Chatelet public:
34409efe848SGuillaume Chatelet   using word_type = WordType;
34509efe848SGuillaume Chatelet   using unsigned_type = BigInt<Bits, false, word_type>;
34609efe848SGuillaume Chatelet   using signed_type = BigInt<Bits, true, word_type>;
34709efe848SGuillaume Chatelet 
34809efe848SGuillaume Chatelet   LIBC_INLINE_VAR static constexpr bool SIGNED = Signed;
34909efe848SGuillaume Chatelet   LIBC_INLINE_VAR static constexpr size_t BITS = Bits;
35009efe848SGuillaume Chatelet   LIBC_INLINE_VAR
35109efe848SGuillaume Chatelet   static constexpr size_t WORD_SIZE = sizeof(WordType) * CHAR_BIT;
35209efe848SGuillaume Chatelet 
35309efe848SGuillaume Chatelet   static_assert(Bits > 0 && Bits % WORD_SIZE == 0,
35409efe848SGuillaume Chatelet                 "Number of bits in BigInt should be a multiple of WORD_SIZE.");
35509efe848SGuillaume Chatelet 
35609efe848SGuillaume Chatelet   LIBC_INLINE_VAR static constexpr size_t WORD_COUNT = Bits / WORD_SIZE;
35709efe848SGuillaume Chatelet 
35809efe848SGuillaume Chatelet   cpp::array<WordType, WORD_COUNT> val{}; // zero initialized.
35909efe848SGuillaume Chatelet 
36009efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt() = default;
36109efe848SGuillaume Chatelet 
36209efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt(const BigInt &other) = default;
36309efe848SGuillaume Chatelet 
36487db0c06SMichael Jones   template <size_t OtherBits, bool OtherSigned, typename OtherWordType>
36509efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt(
36687db0c06SMichael Jones       const BigInt<OtherBits, OtherSigned, OtherWordType> &other) {
36787db0c06SMichael Jones     using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>;
36887db0c06SMichael Jones     const bool should_sign_extend = Signed && other.is_neg();
36987db0c06SMichael Jones 
37087db0c06SMichael Jones     static_assert(!(Bits == OtherBits && WORD_SIZE != BigIntOther::WORD_SIZE) &&
37187db0c06SMichael Jones                   "This is currently untested for casting between bigints with "
37287db0c06SMichael Jones                   "the same bit width but different word sizes.");
37387db0c06SMichael Jones 
37487db0c06SMichael Jones     if constexpr (BigIntOther::WORD_SIZE < WORD_SIZE) {
37587db0c06SMichael Jones       // OtherWordType is smaller
37687db0c06SMichael Jones       constexpr size_t WORD_SIZE_RATIO = WORD_SIZE / BigIntOther::WORD_SIZE;
37787db0c06SMichael Jones       static_assert(
37887db0c06SMichael Jones           (WORD_SIZE % BigIntOther::WORD_SIZE) == 0 &&
37987db0c06SMichael Jones           "Word types must be multiples of each other for correct conversion.");
38087db0c06SMichael Jones       if constexpr (OtherBits >= Bits) { // truncate
38187db0c06SMichael Jones         // for each big word
38287db0c06SMichael Jones         for (size_t i = 0; i < WORD_COUNT; ++i) {
38387db0c06SMichael Jones           WordType cur_word = 0;
38487db0c06SMichael Jones           // combine WORD_SIZE_RATIO small words into a big word
38587db0c06SMichael Jones           for (size_t j = 0; j < WORD_SIZE_RATIO; ++j)
38687db0c06SMichael Jones             cur_word |= static_cast<WordType>(other[(i * WORD_SIZE_RATIO) + j])
38787db0c06SMichael Jones                         << (BigIntOther::WORD_SIZE * j);
38887db0c06SMichael Jones 
38987db0c06SMichael Jones           val[i] = cur_word;
39087db0c06SMichael Jones         }
39187db0c06SMichael Jones       } else { // zero or sign extend
39287db0c06SMichael Jones         size_t i = 0;
39387db0c06SMichael Jones         WordType cur_word = 0;
39487db0c06SMichael Jones         // for each small word
39587db0c06SMichael Jones         for (; i < BigIntOther::WORD_COUNT; ++i) {
39687db0c06SMichael Jones           // combine WORD_SIZE_RATIO small words into a big word
39787db0c06SMichael Jones           cur_word |= static_cast<WordType>(other[i])
39887db0c06SMichael Jones                       << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO));
39987db0c06SMichael Jones           // if we've completed a big word, copy it into place and reset
40087db0c06SMichael Jones           if ((i % WORD_SIZE_RATIO) == WORD_SIZE_RATIO - 1) {
40187db0c06SMichael Jones             val[i / WORD_SIZE_RATIO] = cur_word;
40287db0c06SMichael Jones             cur_word = 0;
40387db0c06SMichael Jones           }
40487db0c06SMichael Jones         }
40587db0c06SMichael Jones         // Pretend there are extra words of the correct sign extension as needed
40687db0c06SMichael Jones 
40787db0c06SMichael Jones         const WordType extension_bits =
40887db0c06SMichael Jones             should_sign_extend ? cpp::numeric_limits<WordType>::max()
40987db0c06SMichael Jones                                : cpp::numeric_limits<WordType>::min();
41087db0c06SMichael Jones         if ((i % WORD_SIZE_RATIO) != 0) {
41187db0c06SMichael Jones           cur_word |= static_cast<WordType>(extension_bits)
41287db0c06SMichael Jones                       << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO));
41387db0c06SMichael Jones         }
41487db0c06SMichael Jones         // Copy the last word into place.
41587db0c06SMichael Jones         val[(i / WORD_SIZE_RATIO)] = cur_word;
41687db0c06SMichael Jones         extend((i / WORD_SIZE_RATIO) + 1, should_sign_extend);
41787db0c06SMichael Jones       }
41887db0c06SMichael Jones     } else if constexpr (BigIntOther::WORD_SIZE == WORD_SIZE) {
41987db0c06SMichael Jones       if constexpr (OtherBits >= Bits) { // truncate
42009efe848SGuillaume Chatelet         for (size_t i = 0; i < WORD_COUNT; ++i)
42109efe848SGuillaume Chatelet           val[i] = other[i];
42209efe848SGuillaume Chatelet       } else { // zero or sign extend
42309efe848SGuillaume Chatelet         size_t i = 0;
42487db0c06SMichael Jones         for (; i < BigIntOther::WORD_COUNT; ++i)
42509efe848SGuillaume Chatelet           val[i] = other[i];
42687db0c06SMichael Jones         extend(i, should_sign_extend);
42787db0c06SMichael Jones       }
42887db0c06SMichael Jones     } else {
42987db0c06SMichael Jones       // OtherWordType is bigger.
43087db0c06SMichael Jones       constexpr size_t WORD_SIZE_RATIO = BigIntOther::WORD_SIZE / WORD_SIZE;
43187db0c06SMichael Jones       static_assert(
43287db0c06SMichael Jones           (BigIntOther::WORD_SIZE % WORD_SIZE) == 0 &&
43387db0c06SMichael Jones           "Word types must be multiples of each other for correct conversion.");
43487db0c06SMichael Jones       if constexpr (OtherBits >= Bits) { // truncate
43587db0c06SMichael Jones         // for each small word
43687db0c06SMichael Jones         for (size_t i = 0; i < WORD_COUNT; ++i) {
43787db0c06SMichael Jones           // split each big word into WORD_SIZE_RATIO small words
43887db0c06SMichael Jones           val[i] = static_cast<WordType>(other[i / WORD_SIZE_RATIO] >>
43987db0c06SMichael Jones                                          ((i % WORD_SIZE_RATIO) * WORD_SIZE));
44087db0c06SMichael Jones         }
44187db0c06SMichael Jones       } else { // zero or sign extend
44287db0c06SMichael Jones         size_t i = 0;
44387db0c06SMichael Jones         // for each big word
44487db0c06SMichael Jones         for (; i < BigIntOther::WORD_COUNT; ++i) {
44587db0c06SMichael Jones           // split each big word into WORD_SIZE_RATIO small words
44687db0c06SMichael Jones           for (size_t j = 0; j < WORD_SIZE_RATIO; ++j)
44787db0c06SMichael Jones             val[(i * WORD_SIZE_RATIO) + j] =
44887db0c06SMichael Jones                 static_cast<WordType>(other[i] >> (j * WORD_SIZE));
44987db0c06SMichael Jones         }
45087db0c06SMichael Jones         extend(i * WORD_SIZE_RATIO, should_sign_extend);
45187db0c06SMichael Jones       }
45209efe848SGuillaume Chatelet     }
45309efe848SGuillaume Chatelet   }
45409efe848SGuillaume Chatelet 
45509efe848SGuillaume Chatelet   // Construct a BigInt from a C array.
45609efe848SGuillaume Chatelet   template <size_t N> LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) {
45709efe848SGuillaume Chatelet     static_assert(N == WORD_COUNT);
45809efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i)
45909efe848SGuillaume Chatelet       val[i] = nums[i];
46009efe848SGuillaume Chatelet   }
46109efe848SGuillaume Chatelet 
46209efe848SGuillaume Chatelet   LIBC_INLINE constexpr explicit BigInt(
46309efe848SGuillaume Chatelet       const cpp::array<WordType, WORD_COUNT> &words) {
46409efe848SGuillaume Chatelet     val = words;
46509efe848SGuillaume Chatelet   }
46609efe848SGuillaume Chatelet 
46709efe848SGuillaume Chatelet   // Initialize the first word to |v| and the rest to 0.
4687a036664SOverMighty   template <typename T, typename = cpp::enable_if_t<cpp::is_integral_v<T> &&
4697a036664SOverMighty                                                     !cpp::is_same_v<T, bool>>>
47009efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt(T v) {
47109efe848SGuillaume Chatelet     constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT;
472*7302c8dbSNick Desaulniers     const bool is_neg = v < 0;
47309efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i) {
47409efe848SGuillaume Chatelet       if (v == 0) {
47509efe848SGuillaume Chatelet         extend(i, is_neg);
47609efe848SGuillaume Chatelet         return;
47709efe848SGuillaume Chatelet       }
47809efe848SGuillaume Chatelet       val[i] = static_cast<WordType>(v);
47909efe848SGuillaume Chatelet       if constexpr (T_SIZE > WORD_SIZE)
48009efe848SGuillaume Chatelet         v >>= WORD_SIZE;
48109efe848SGuillaume Chatelet       else
48209efe848SGuillaume Chatelet         v = 0;
48309efe848SGuillaume Chatelet     }
48409efe848SGuillaume Chatelet   }
48509efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator=(const BigInt &other) = default;
48609efe848SGuillaume Chatelet 
48709efe848SGuillaume Chatelet   // constants
48809efe848SGuillaume Chatelet   LIBC_INLINE static constexpr BigInt zero() { return BigInt(); }
48909efe848SGuillaume Chatelet   LIBC_INLINE static constexpr BigInt one() { return BigInt(1); }
49009efe848SGuillaume Chatelet   LIBC_INLINE static constexpr BigInt all_ones() { return ~zero(); }
49109efe848SGuillaume Chatelet   LIBC_INLINE static constexpr BigInt min() {
49209efe848SGuillaume Chatelet     BigInt out;
49309efe848SGuillaume Chatelet     if constexpr (SIGNED)
49409efe848SGuillaume Chatelet       out.set_msb();
49509efe848SGuillaume Chatelet     return out;
49609efe848SGuillaume Chatelet   }
49709efe848SGuillaume Chatelet   LIBC_INLINE static constexpr BigInt max() {
49809efe848SGuillaume Chatelet     BigInt out = all_ones();
49909efe848SGuillaume Chatelet     if constexpr (SIGNED)
50009efe848SGuillaume Chatelet       out.clear_msb();
50109efe848SGuillaume Chatelet     return out;
50209efe848SGuillaume Chatelet   }
50309efe848SGuillaume Chatelet 
50409efe848SGuillaume Chatelet   // TODO: Reuse the Sign type.
50509efe848SGuillaume Chatelet   LIBC_INLINE constexpr bool is_neg() const { return SIGNED && get_msb(); }
50609efe848SGuillaume Chatelet 
507*7302c8dbSNick Desaulniers   template <size_t OtherBits, bool OtherSigned, typename OtherWordType>
508*7302c8dbSNick Desaulniers   LIBC_INLINE constexpr explicit
509*7302c8dbSNick Desaulniers   operator BigInt<OtherBits, OtherSigned, OtherWordType>() const {
510*7302c8dbSNick Desaulniers     return BigInt<OtherBits, OtherSigned, OtherWordType>(this);
511*7302c8dbSNick Desaulniers   }
512*7302c8dbSNick Desaulniers 
51309efe848SGuillaume Chatelet   template <typename T> LIBC_INLINE constexpr explicit operator T() const {
51409efe848SGuillaume Chatelet     return to<T>();
51509efe848SGuillaume Chatelet   }
51609efe848SGuillaume Chatelet 
51709efe848SGuillaume Chatelet   template <typename T>
51809efe848SGuillaume Chatelet   LIBC_INLINE constexpr cpp::enable_if_t<
51909efe848SGuillaume Chatelet       cpp::is_integral_v<T> && !cpp::is_same_v<T, bool>, T>
52009efe848SGuillaume Chatelet   to() const {
52109efe848SGuillaume Chatelet     constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT;
52209efe848SGuillaume Chatelet     T lo = static_cast<T>(val[0]);
52309efe848SGuillaume Chatelet     if constexpr (T_SIZE <= WORD_SIZE)
52409efe848SGuillaume Chatelet       return lo;
52509efe848SGuillaume Chatelet     constexpr size_t MAX_COUNT =
52609efe848SGuillaume Chatelet         T_SIZE > Bits ? WORD_COUNT : T_SIZE / WORD_SIZE;
52709efe848SGuillaume Chatelet     for (size_t i = 1; i < MAX_COUNT; ++i)
5287a036664SOverMighty       lo += static_cast<T>(static_cast<T>(val[i]) << (WORD_SIZE * i));
52909efe848SGuillaume Chatelet     if constexpr (Signed && (T_SIZE > Bits)) {
53009efe848SGuillaume Chatelet       // Extend sign for negative numbers.
53109efe848SGuillaume Chatelet       constexpr T MASK = (~T(0) << Bits);
53209efe848SGuillaume Chatelet       if (is_neg())
53309efe848SGuillaume Chatelet         lo |= MASK;
53409efe848SGuillaume Chatelet     }
53509efe848SGuillaume Chatelet     return lo;
53609efe848SGuillaume Chatelet   }
53709efe848SGuillaume Chatelet 
53809efe848SGuillaume Chatelet   LIBC_INLINE constexpr explicit operator bool() const { return !is_zero(); }
53909efe848SGuillaume Chatelet 
54009efe848SGuillaume Chatelet   LIBC_INLINE constexpr bool is_zero() const {
54109efe848SGuillaume Chatelet     for (auto part : val)
54209efe848SGuillaume Chatelet       if (part != 0)
54309efe848SGuillaume Chatelet         return false;
54409efe848SGuillaume Chatelet     return true;
54509efe848SGuillaume Chatelet   }
54609efe848SGuillaume Chatelet 
54709efe848SGuillaume Chatelet   // Add 'rhs' to this number and store the result in this number.
54809efe848SGuillaume Chatelet   // Returns the carry value produced by the addition operation.
54909efe848SGuillaume Chatelet   LIBC_INLINE constexpr WordType add_overflow(const BigInt &rhs) {
55009efe848SGuillaume Chatelet     return multiword::add_with_carry(val, rhs.val);
55109efe848SGuillaume Chatelet   }
55209efe848SGuillaume Chatelet 
55309efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator+(const BigInt &other) const {
55409efe848SGuillaume Chatelet     BigInt result = *this;
55509efe848SGuillaume Chatelet     result.add_overflow(other);
55609efe848SGuillaume Chatelet     return result;
55709efe848SGuillaume Chatelet   }
55809efe848SGuillaume Chatelet 
55909efe848SGuillaume Chatelet   // This will only apply when initializing a variable from constant values, so
56009efe848SGuillaume Chatelet   // it will always use the constexpr version of add_with_carry.
56109efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator+(BigInt &&other) const {
56209efe848SGuillaume Chatelet     // We use addition commutativity to reuse 'other' and prevent allocation.
56309efe848SGuillaume Chatelet     other.add_overflow(*this); // Returned carry value is ignored.
56409efe848SGuillaume Chatelet     return other;
56509efe848SGuillaume Chatelet   }
56609efe848SGuillaume Chatelet 
56709efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator+=(const BigInt &other) {
56809efe848SGuillaume Chatelet     add_overflow(other); // Returned carry value is ignored.
56909efe848SGuillaume Chatelet     return *this;
57009efe848SGuillaume Chatelet   }
57109efe848SGuillaume Chatelet 
57209efe848SGuillaume Chatelet   // Subtract 'rhs' to this number and store the result in this number.
57309efe848SGuillaume Chatelet   // Returns the carry value produced by the subtraction operation.
57409efe848SGuillaume Chatelet   LIBC_INLINE constexpr WordType sub_overflow(const BigInt &rhs) {
57509efe848SGuillaume Chatelet     return multiword::sub_with_borrow(val, rhs.val);
57609efe848SGuillaume Chatelet   }
57709efe848SGuillaume Chatelet 
57809efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator-(const BigInt &other) const {
57909efe848SGuillaume Chatelet     BigInt result = *this;
58009efe848SGuillaume Chatelet     result.sub_overflow(other); // Returned carry value is ignored.
58109efe848SGuillaume Chatelet     return result;
58209efe848SGuillaume Chatelet   }
58309efe848SGuillaume Chatelet 
58409efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator-(BigInt &&other) const {
58509efe848SGuillaume Chatelet     BigInt result = *this;
58609efe848SGuillaume Chatelet     result.sub_overflow(other); // Returned carry value is ignored.
58709efe848SGuillaume Chatelet     return result;
58809efe848SGuillaume Chatelet   }
58909efe848SGuillaume Chatelet 
59009efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator-=(const BigInt &other) {
59109efe848SGuillaume Chatelet     // TODO(lntue): Set overflow flag / errno when carry is true.
59209efe848SGuillaume Chatelet     sub_overflow(other); // Returned carry value is ignored.
59309efe848SGuillaume Chatelet     return *this;
59409efe848SGuillaume Chatelet   }
59509efe848SGuillaume Chatelet 
59609efe848SGuillaume Chatelet   // Multiply this number with x and store the result in this number.
59709efe848SGuillaume Chatelet   LIBC_INLINE constexpr WordType mul(WordType x) {
59809efe848SGuillaume Chatelet     return multiword::scalar_multiply_with_carry(val, x);
59909efe848SGuillaume Chatelet   }
60009efe848SGuillaume Chatelet 
60109efe848SGuillaume Chatelet   // Return the full product.
60209efe848SGuillaume Chatelet   template <size_t OtherBits>
60309efe848SGuillaume Chatelet   LIBC_INLINE constexpr auto
60409efe848SGuillaume Chatelet   ful_mul(const BigInt<OtherBits, Signed, WordType> &other) const {
60509efe848SGuillaume Chatelet     BigInt<Bits + OtherBits, Signed, WordType> result;
60609efe848SGuillaume Chatelet     multiword::multiply_with_carry(result.val, val, other.val);
60709efe848SGuillaume Chatelet     return result;
60809efe848SGuillaume Chatelet   }
60909efe848SGuillaume Chatelet 
61009efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator*(const BigInt &other) const {
61109efe848SGuillaume Chatelet     // Perform full mul and truncate.
61209efe848SGuillaume Chatelet     return BigInt(ful_mul(other));
61309efe848SGuillaume Chatelet   }
61409efe848SGuillaume Chatelet 
61509efe848SGuillaume Chatelet   // Fast hi part of the full product.  The normal product `operator*` returns
61609efe848SGuillaume Chatelet   // `Bits` least significant bits of the full product, while this function will
61709efe848SGuillaume Chatelet   // approximate `Bits` most significant bits of the full product with errors
61809efe848SGuillaume Chatelet   // bounded by:
61909efe848SGuillaume Chatelet   //   0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= WORD_COUNT - 1.
62009efe848SGuillaume Chatelet   //
62109efe848SGuillaume Chatelet   // An example usage of this is to quickly (but less accurately) compute the
62209efe848SGuillaume Chatelet   // product of (normalized) mantissas of floating point numbers:
62309efe848SGuillaume Chatelet   //   (mant_1, mant_2) -> quick_mul_hi -> normalize leading bit
62409efe848SGuillaume Chatelet   // is much more efficient than:
62509efe848SGuillaume Chatelet   //   (mant_1, mant_2) -> ful_mul -> normalize leading bit
62609efe848SGuillaume Chatelet   //                    -> convert back to same Bits width by shifting/rounding,
62709efe848SGuillaume Chatelet   // especially for higher precisions.
62809efe848SGuillaume Chatelet   //
62909efe848SGuillaume Chatelet   // Performance summary:
63009efe848SGuillaume Chatelet   //   Number of 64-bit x 64-bit -> 128-bit multiplications performed.
63109efe848SGuillaume Chatelet   //   Bits  WORD_COUNT  ful_mul  quick_mul_hi  Error bound
63209efe848SGuillaume Chatelet   //    128      2         4           3            1
63309efe848SGuillaume Chatelet   //    196      3         9           6            2
63409efe848SGuillaume Chatelet   //    256      4        16          10            3
63509efe848SGuillaume Chatelet   //    512      8        64          36            7
63609efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const {
63709efe848SGuillaume Chatelet     BigInt result;
63809efe848SGuillaume Chatelet     multiword::quick_mul_hi(result.val, val, other.val);
63909efe848SGuillaume Chatelet     return result;
64009efe848SGuillaume Chatelet   }
64109efe848SGuillaume Chatelet 
64209efe848SGuillaume Chatelet   // BigInt(x).pow_n(n) computes x ^ n.
64309efe848SGuillaume Chatelet   // Note 0 ^ 0 == 1.
64409efe848SGuillaume Chatelet   LIBC_INLINE constexpr void pow_n(uint64_t power) {
64509efe848SGuillaume Chatelet     static_assert(!Signed);
64609efe848SGuillaume Chatelet     BigInt result = one();
64709efe848SGuillaume Chatelet     BigInt cur_power = *this;
64809efe848SGuillaume Chatelet     while (power > 0) {
64909efe848SGuillaume Chatelet       if ((power % 2) > 0)
65009efe848SGuillaume Chatelet         result *= cur_power;
65109efe848SGuillaume Chatelet       power >>= 1;
65209efe848SGuillaume Chatelet       cur_power *= cur_power;
65309efe848SGuillaume Chatelet     }
65409efe848SGuillaume Chatelet     *this = result;
65509efe848SGuillaume Chatelet   }
65609efe848SGuillaume Chatelet 
65709efe848SGuillaume Chatelet   // Performs inplace signed / unsigned division. Returns remainder if not
65809efe848SGuillaume Chatelet   // dividing by zero.
65909efe848SGuillaume Chatelet   // For signed numbers it behaves like C++ signed integer division.
66009efe848SGuillaume Chatelet   // That is by truncating the fractionnal part
66109efe848SGuillaume Chatelet   // https://stackoverflow.com/a/3602857
66209efe848SGuillaume Chatelet   LIBC_INLINE constexpr cpp::optional<BigInt> div(const BigInt &divider) {
66309efe848SGuillaume Chatelet     if (LIBC_UNLIKELY(divider.is_zero()))
66409efe848SGuillaume Chatelet       return cpp::nullopt;
66509efe848SGuillaume Chatelet     if (LIBC_UNLIKELY(divider == BigInt::one()))
66609efe848SGuillaume Chatelet       return BigInt::zero();
66709efe848SGuillaume Chatelet     Division result;
66809efe848SGuillaume Chatelet     if constexpr (SIGNED)
66909efe848SGuillaume Chatelet       result = divide_signed(*this, divider);
67009efe848SGuillaume Chatelet     else
67109efe848SGuillaume Chatelet       result = divide_unsigned(*this, divider);
67209efe848SGuillaume Chatelet     *this = result.quotient;
67309efe848SGuillaume Chatelet     return result.remainder;
67409efe848SGuillaume Chatelet   }
67509efe848SGuillaume Chatelet 
67609efe848SGuillaume Chatelet   // Efficiently perform BigInt / (x * 2^e), where x is a half-word-size
67709efe848SGuillaume Chatelet   // unsigned integer, and return the remainder. The main idea is as follow:
67809efe848SGuillaume Chatelet   //   Let q = y / (x * 2^e) be the quotient, and
67909efe848SGuillaume Chatelet   //       r = y % (x * 2^e) be the remainder.
68009efe848SGuillaume Chatelet   //   First, notice that:
68109efe848SGuillaume Chatelet   //     r % (2^e) = y % (2^e),
68209efe848SGuillaume Chatelet   // so we just need to focus on all the bits of y that is >= 2^e.
68309efe848SGuillaume Chatelet   //   To speed up the shift-and-add steps, we only use x as the divisor, and
68409efe848SGuillaume Chatelet   // performing 32-bit shiftings instead of bit-by-bit shiftings.
68509efe848SGuillaume Chatelet   //   Since the remainder of each division step < x < 2^(WORD_SIZE / 2), the
68609efe848SGuillaume Chatelet   // computation of each step is now properly contained within WordType.
68709efe848SGuillaume Chatelet   //   And finally we perform some extra alignment steps for the remaining bits.
68809efe848SGuillaume Chatelet   LIBC_INLINE constexpr cpp::optional<BigInt>
68909efe848SGuillaume Chatelet   div_uint_half_times_pow_2(multiword::half_width_t<WordType> x, size_t e) {
69009efe848SGuillaume Chatelet     BigInt remainder;
69109efe848SGuillaume Chatelet     if (x == 0)
69209efe848SGuillaume Chatelet       return cpp::nullopt;
69309efe848SGuillaume Chatelet     if (e >= Bits) {
69409efe848SGuillaume Chatelet       remainder = *this;
69509efe848SGuillaume Chatelet       *this = BigInt<Bits, false, WordType>();
69609efe848SGuillaume Chatelet       return remainder;
69709efe848SGuillaume Chatelet     }
69809efe848SGuillaume Chatelet     BigInt quotient;
69909efe848SGuillaume Chatelet     WordType x_word = static_cast<WordType>(x);
70009efe848SGuillaume Chatelet     constexpr size_t LOG2_WORD_SIZE = cpp::bit_width(WORD_SIZE) - 1;
70109efe848SGuillaume Chatelet     constexpr size_t HALF_WORD_SIZE = WORD_SIZE >> 1;
70209efe848SGuillaume Chatelet     constexpr WordType HALF_MASK = ((WordType(1) << HALF_WORD_SIZE) - 1);
70309efe848SGuillaume Chatelet     // lower = smallest multiple of WORD_SIZE that is >= e.
70409efe848SGuillaume Chatelet     size_t lower = ((e >> LOG2_WORD_SIZE) + ((e & (WORD_SIZE - 1)) != 0))
70509efe848SGuillaume Chatelet                    << LOG2_WORD_SIZE;
70609efe848SGuillaume Chatelet     // lower_pos is the index of the closest WORD_SIZE-bit chunk >= 2^e.
70709efe848SGuillaume Chatelet     size_t lower_pos = lower / WORD_SIZE;
70809efe848SGuillaume Chatelet     // Keep track of current remainder mod x * 2^(32*i)
70909efe848SGuillaume Chatelet     WordType rem = 0;
71009efe848SGuillaume Chatelet     // pos is the index of the current 64-bit chunk that we are processing.
71109efe848SGuillaume Chatelet     size_t pos = WORD_COUNT;
71209efe848SGuillaume Chatelet 
71309efe848SGuillaume Chatelet     // TODO: look into if constexpr(Bits > 256) skip leading zeroes.
71409efe848SGuillaume Chatelet 
71509efe848SGuillaume Chatelet     for (size_t q_pos = WORD_COUNT - lower_pos; q_pos > 0; --q_pos) {
71609efe848SGuillaume Chatelet       // q_pos is 1 + the index of the current WORD_SIZE-bit chunk of the
71709efe848SGuillaume Chatelet       // quotient being processed. Performing the division / modulus with
71809efe848SGuillaume Chatelet       // divisor:
71909efe848SGuillaume Chatelet       //   x * 2^(WORD_SIZE*q_pos - WORD_SIZE/2),
72009efe848SGuillaume Chatelet       // i.e. using the upper (WORD_SIZE/2)-bit of the current WORD_SIZE-bit
72109efe848SGuillaume Chatelet       // chunk.
72209efe848SGuillaume Chatelet       rem <<= HALF_WORD_SIZE;
72309efe848SGuillaume Chatelet       rem += val[--pos] >> HALF_WORD_SIZE;
72409efe848SGuillaume Chatelet       WordType q_tmp = rem / x_word;
72509efe848SGuillaume Chatelet       rem %= x_word;
72609efe848SGuillaume Chatelet 
72709efe848SGuillaume Chatelet       // Performing the division / modulus with divisor:
72809efe848SGuillaume Chatelet       //   x * 2^(WORD_SIZE*(q_pos - 1)),
72909efe848SGuillaume Chatelet       // i.e. using the lower (WORD_SIZE/2)-bit of the current WORD_SIZE-bit
73009efe848SGuillaume Chatelet       // chunk.
73109efe848SGuillaume Chatelet       rem <<= HALF_WORD_SIZE;
73209efe848SGuillaume Chatelet       rem += val[pos] & HALF_MASK;
73309efe848SGuillaume Chatelet       quotient.val[q_pos - 1] = (q_tmp << HALF_WORD_SIZE) + rem / x_word;
73409efe848SGuillaume Chatelet       rem %= x_word;
73509efe848SGuillaume Chatelet     }
73609efe848SGuillaume Chatelet 
73709efe848SGuillaume Chatelet     // So far, what we have is:
73809efe848SGuillaume Chatelet     //   quotient = y / (x * 2^lower), and
73909efe848SGuillaume Chatelet     //        rem = (y % (x * 2^lower)) / 2^lower.
74009efe848SGuillaume Chatelet     // If (lower > e), we will need to perform an extra adjustment of the
74109efe848SGuillaume Chatelet     // quotient and remainder, namely:
74209efe848SGuillaume Chatelet     //   y / (x * 2^e) = [ y / (x * 2^lower) ] * 2^(lower - e) +
74309efe848SGuillaume Chatelet     //                   + (rem * 2^(lower - e)) / x
74409efe848SGuillaume Chatelet     //   (y % (x * 2^e)) / 2^e = (rem * 2^(lower - e)) % x
74509efe848SGuillaume Chatelet     size_t last_shift = lower - e;
74609efe848SGuillaume Chatelet 
74709efe848SGuillaume Chatelet     if (last_shift > 0) {
74809efe848SGuillaume Chatelet       // quotient * 2^(lower - e)
74909efe848SGuillaume Chatelet       quotient <<= last_shift;
75009efe848SGuillaume Chatelet       WordType q_tmp = 0;
75109efe848SGuillaume Chatelet       WordType d = val[--pos];
75209efe848SGuillaume Chatelet       if (last_shift >= HALF_WORD_SIZE) {
75309efe848SGuillaume Chatelet         // The shifting (rem * 2^(lower - e)) might overflow WordTyoe, so we
75409efe848SGuillaume Chatelet         // perform a HALF_WORD_SIZE-bit shift first.
75509efe848SGuillaume Chatelet         rem <<= HALF_WORD_SIZE;
75609efe848SGuillaume Chatelet         rem += d >> HALF_WORD_SIZE;
75709efe848SGuillaume Chatelet         d &= HALF_MASK;
75809efe848SGuillaume Chatelet         q_tmp = rem / x_word;
75909efe848SGuillaume Chatelet         rem %= x_word;
76009efe848SGuillaume Chatelet         last_shift -= HALF_WORD_SIZE;
76109efe848SGuillaume Chatelet       } else {
76209efe848SGuillaume Chatelet         // Only use the upper HALF_WORD_SIZE-bit of the current WORD_SIZE-bit
76309efe848SGuillaume Chatelet         // chunk.
76409efe848SGuillaume Chatelet         d >>= HALF_WORD_SIZE;
76509efe848SGuillaume Chatelet       }
76609efe848SGuillaume Chatelet 
76709efe848SGuillaume Chatelet       if (last_shift > 0) {
76809efe848SGuillaume Chatelet         rem <<= HALF_WORD_SIZE;
76909efe848SGuillaume Chatelet         rem += d;
77009efe848SGuillaume Chatelet         q_tmp <<= last_shift;
77109efe848SGuillaume Chatelet         x_word <<= HALF_WORD_SIZE - last_shift;
77209efe848SGuillaume Chatelet         q_tmp += rem / x_word;
77309efe848SGuillaume Chatelet         rem %= x_word;
77409efe848SGuillaume Chatelet       }
77509efe848SGuillaume Chatelet 
77609efe848SGuillaume Chatelet       quotient.val[0] += q_tmp;
77709efe848SGuillaume Chatelet 
77809efe848SGuillaume Chatelet       if (lower - e <= HALF_WORD_SIZE) {
77909efe848SGuillaume Chatelet         // The remainder rem * 2^(lower - e) might overflow to the higher
78009efe848SGuillaume Chatelet         // WORD_SIZE-bit chunk.
78109efe848SGuillaume Chatelet         if (pos < WORD_COUNT - 1) {
78209efe848SGuillaume Chatelet           remainder[pos + 1] = rem >> HALF_WORD_SIZE;
78309efe848SGuillaume Chatelet         }
78409efe848SGuillaume Chatelet         remainder[pos] = (rem << HALF_WORD_SIZE) + (val[pos] & HALF_MASK);
78509efe848SGuillaume Chatelet       } else {
78609efe848SGuillaume Chatelet         remainder[pos] = rem;
78709efe848SGuillaume Chatelet       }
78809efe848SGuillaume Chatelet 
78909efe848SGuillaume Chatelet     } else {
79009efe848SGuillaume Chatelet       remainder[pos] = rem;
79109efe848SGuillaume Chatelet     }
79209efe848SGuillaume Chatelet 
79309efe848SGuillaume Chatelet     // Set the remaining lower bits of the remainder.
79409efe848SGuillaume Chatelet     for (; pos > 0; --pos) {
79509efe848SGuillaume Chatelet       remainder[pos - 1] = val[pos - 1];
79609efe848SGuillaume Chatelet     }
79709efe848SGuillaume Chatelet 
79809efe848SGuillaume Chatelet     *this = quotient;
79909efe848SGuillaume Chatelet     return remainder;
80009efe848SGuillaume Chatelet   }
80109efe848SGuillaume Chatelet 
80209efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator/(const BigInt &other) const {
80309efe848SGuillaume Chatelet     BigInt result(*this);
80409efe848SGuillaume Chatelet     result.div(other);
80509efe848SGuillaume Chatelet     return result;
80609efe848SGuillaume Chatelet   }
80709efe848SGuillaume Chatelet 
80809efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator/=(const BigInt &other) {
80909efe848SGuillaume Chatelet     div(other);
81009efe848SGuillaume Chatelet     return *this;
81109efe848SGuillaume Chatelet   }
81209efe848SGuillaume Chatelet 
81309efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator%(const BigInt &other) const {
81409efe848SGuillaume Chatelet     BigInt result(*this);
81509efe848SGuillaume Chatelet     return *result.div(other);
81609efe848SGuillaume Chatelet   }
81709efe848SGuillaume Chatelet 
8180ccec541SMikhail R. Gadelha   LIBC_INLINE constexpr BigInt operator%=(const BigInt &other) {
819dffa28faSMikhail R. Gadelha     *this = *this % other;
820dffa28faSMikhail R. Gadelha     return *this;
8210ccec541SMikhail R. Gadelha   }
8220ccec541SMikhail R. Gadelha 
82309efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator*=(const BigInt &other) {
82409efe848SGuillaume Chatelet     *this = *this * other;
82509efe848SGuillaume Chatelet     return *this;
82609efe848SGuillaume Chatelet   }
82709efe848SGuillaume Chatelet 
82809efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator<<=(size_t s) {
82909efe848SGuillaume Chatelet     val = multiword::shift<multiword::LEFT, SIGNED>(val, s);
83009efe848SGuillaume Chatelet     return *this;
83109efe848SGuillaume Chatelet   }
83209efe848SGuillaume Chatelet 
83309efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator<<(size_t s) const {
83409efe848SGuillaume Chatelet     return BigInt(multiword::shift<multiword::LEFT, SIGNED>(val, s));
83509efe848SGuillaume Chatelet   }
83609efe848SGuillaume Chatelet 
83709efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator>>=(size_t s) {
83809efe848SGuillaume Chatelet     val = multiword::shift<multiword::RIGHT, SIGNED>(val, s);
83909efe848SGuillaume Chatelet     return *this;
84009efe848SGuillaume Chatelet   }
84109efe848SGuillaume Chatelet 
84209efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator>>(size_t s) const {
84309efe848SGuillaume Chatelet     return BigInt(multiword::shift<multiword::RIGHT, SIGNED>(val, s));
84409efe848SGuillaume Chatelet   }
84509efe848SGuillaume Chatelet 
84609efe848SGuillaume Chatelet #define DEFINE_BINOP(OP)                                                       \
84709efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs,           \
84809efe848SGuillaume Chatelet                                                   const BigInt &rhs) {         \
84909efe848SGuillaume Chatelet     BigInt result;                                                             \
85009efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i)                                    \
85109efe848SGuillaume Chatelet       result[i] = lhs[i] OP rhs[i];                                            \
85209efe848SGuillaume Chatelet     return result;                                                             \
85309efe848SGuillaume Chatelet   }                                                                            \
85409efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr BigInt operator OP##=(BigInt &lhs,              \
85509efe848SGuillaume Chatelet                                                      const BigInt &rhs) {      \
85609efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i)                                    \
85709efe848SGuillaume Chatelet       lhs[i] OP## = rhs[i];                                                    \
85809efe848SGuillaume Chatelet     return lhs;                                                                \
85909efe848SGuillaume Chatelet   }
86009efe848SGuillaume Chatelet 
86109efe848SGuillaume Chatelet   DEFINE_BINOP(&) // & and &=
86209efe848SGuillaume Chatelet   DEFINE_BINOP(|) // | and |=
86309efe848SGuillaume Chatelet   DEFINE_BINOP(^) // ^ and ^=
86409efe848SGuillaume Chatelet #undef DEFINE_BINOP
86509efe848SGuillaume Chatelet 
86609efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator~() const {
86709efe848SGuillaume Chatelet     BigInt result;
86809efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i)
86909efe848SGuillaume Chatelet       result[i] = ~val[i];
87009efe848SGuillaume Chatelet     return result;
87109efe848SGuillaume Chatelet   }
87209efe848SGuillaume Chatelet 
87309efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator-() const {
87409efe848SGuillaume Chatelet     BigInt result(*this);
87509efe848SGuillaume Chatelet     result.negate();
87609efe848SGuillaume Chatelet     return result;
87709efe848SGuillaume Chatelet   }
87809efe848SGuillaume Chatelet 
87909efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator==(const BigInt &lhs,
88009efe848SGuillaume Chatelet                                                const BigInt &rhs) {
88109efe848SGuillaume Chatelet     for (size_t i = 0; i < WORD_COUNT; ++i)
88209efe848SGuillaume Chatelet       if (lhs.val[i] != rhs.val[i])
88309efe848SGuillaume Chatelet         return false;
88409efe848SGuillaume Chatelet     return true;
88509efe848SGuillaume Chatelet   }
88609efe848SGuillaume Chatelet 
88709efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator!=(const BigInt &lhs,
88809efe848SGuillaume Chatelet                                                const BigInt &rhs) {
88909efe848SGuillaume Chatelet     return !(lhs == rhs);
89009efe848SGuillaume Chatelet   }
89109efe848SGuillaume Chatelet 
89209efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator>(const BigInt &lhs,
89309efe848SGuillaume Chatelet                                               const BigInt &rhs) {
89409efe848SGuillaume Chatelet     return cmp(lhs, rhs) > 0;
89509efe848SGuillaume Chatelet   }
89609efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator>=(const BigInt &lhs,
89709efe848SGuillaume Chatelet                                                const BigInt &rhs) {
89809efe848SGuillaume Chatelet     return cmp(lhs, rhs) >= 0;
89909efe848SGuillaume Chatelet   }
90009efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator<(const BigInt &lhs,
90109efe848SGuillaume Chatelet                                               const BigInt &rhs) {
90209efe848SGuillaume Chatelet     return cmp(lhs, rhs) < 0;
90309efe848SGuillaume Chatelet   }
90409efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr bool operator<=(const BigInt &lhs,
90509efe848SGuillaume Chatelet                                                const BigInt &rhs) {
90609efe848SGuillaume Chatelet     return cmp(lhs, rhs) <= 0;
90709efe848SGuillaume Chatelet   }
90809efe848SGuillaume Chatelet 
90909efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator++() {
91009efe848SGuillaume Chatelet     increment();
91109efe848SGuillaume Chatelet     return *this;
91209efe848SGuillaume Chatelet   }
91309efe848SGuillaume Chatelet 
91409efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator++(int) {
91509efe848SGuillaume Chatelet     BigInt oldval(*this);
91609efe848SGuillaume Chatelet     increment();
91709efe848SGuillaume Chatelet     return oldval;
91809efe848SGuillaume Chatelet   }
91909efe848SGuillaume Chatelet 
92009efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt &operator--() {
92109efe848SGuillaume Chatelet     decrement();
92209efe848SGuillaume Chatelet     return *this;
92309efe848SGuillaume Chatelet   }
92409efe848SGuillaume Chatelet 
92509efe848SGuillaume Chatelet   LIBC_INLINE constexpr BigInt operator--(int) {
92609efe848SGuillaume Chatelet     BigInt oldval(*this);
92709efe848SGuillaume Chatelet     decrement();
92809efe848SGuillaume Chatelet     return oldval;
92909efe848SGuillaume Chatelet   }
93009efe848SGuillaume Chatelet 
93109efe848SGuillaume Chatelet   // Return the i-th word of the number.
93209efe848SGuillaume Chatelet   LIBC_INLINE constexpr const WordType &operator[](size_t i) const {
93309efe848SGuillaume Chatelet     return val[i];
93409efe848SGuillaume Chatelet   }
93509efe848SGuillaume Chatelet 
93609efe848SGuillaume Chatelet   // Return the i-th word of the number.
93709efe848SGuillaume Chatelet   LIBC_INLINE constexpr WordType &operator[](size_t i) { return val[i]; }
93809efe848SGuillaume Chatelet 
93909efe848SGuillaume Chatelet private:
94009efe848SGuillaume Chatelet   LIBC_INLINE friend constexpr int cmp(const BigInt &lhs, const BigInt &rhs) {
94109efe848SGuillaume Chatelet     constexpr auto compare = [](WordType a, WordType b) {
94209efe848SGuillaume Chatelet       return a == b ? 0 : a > b ? 1 : -1;
94309efe848SGuillaume Chatelet     };
94409efe848SGuillaume Chatelet     if constexpr (Signed) {
94509efe848SGuillaume Chatelet       const bool lhs_is_neg = lhs.is_neg();
94609efe848SGuillaume Chatelet       const bool rhs_is_neg = rhs.is_neg();
94709efe848SGuillaume Chatelet       if (lhs_is_neg != rhs_is_neg)
94809efe848SGuillaume Chatelet         return rhs_is_neg ? 1 : -1;
94909efe848SGuillaume Chatelet     }
95009efe848SGuillaume Chatelet     for (size_t i = WORD_COUNT; i-- > 0;)
95109efe848SGuillaume Chatelet       if (auto cmp = compare(lhs[i], rhs[i]); cmp != 0)
95209efe848SGuillaume Chatelet         return cmp;
95309efe848SGuillaume Chatelet     return 0;
95409efe848SGuillaume Chatelet   }
95509efe848SGuillaume Chatelet 
95609efe848SGuillaume Chatelet   LIBC_INLINE constexpr void bitwise_not() {
95709efe848SGuillaume Chatelet     for (auto &part : val)
95809efe848SGuillaume Chatelet       part = ~part;
95909efe848SGuillaume Chatelet   }
96009efe848SGuillaume Chatelet 
96109efe848SGuillaume Chatelet   LIBC_INLINE constexpr void negate() {
96209efe848SGuillaume Chatelet     bitwise_not();
96309efe848SGuillaume Chatelet     increment();
96409efe848SGuillaume Chatelet   }
96509efe848SGuillaume Chatelet 
96609efe848SGuillaume Chatelet   LIBC_INLINE constexpr void increment() {
96709efe848SGuillaume Chatelet     multiword::add_with_carry(val, cpp::array<WordType, 1>{1});
96809efe848SGuillaume Chatelet   }
96909efe848SGuillaume Chatelet 
97009efe848SGuillaume Chatelet   LIBC_INLINE constexpr void decrement() {
97109efe848SGuillaume Chatelet     multiword::add_with_carry(val, cpp::array<WordType, 1>{1});
97209efe848SGuillaume Chatelet   }
97309efe848SGuillaume Chatelet 
97409efe848SGuillaume Chatelet   LIBC_INLINE constexpr void extend(size_t index, bool is_neg) {
97509efe848SGuillaume Chatelet     const WordType value = is_neg ? cpp::numeric_limits<WordType>::max()
97609efe848SGuillaume Chatelet                                   : cpp::numeric_limits<WordType>::min();
97709efe848SGuillaume Chatelet     for (size_t i = index; i < WORD_COUNT; ++i)
97809efe848SGuillaume Chatelet       val[i] = value;
97909efe848SGuillaume Chatelet   }
98009efe848SGuillaume Chatelet 
98109efe848SGuillaume Chatelet   LIBC_INLINE constexpr bool get_msb() const {
98209efe848SGuillaume Chatelet     return val.back() >> (WORD_SIZE - 1);
98309efe848SGuillaume Chatelet   }
98409efe848SGuillaume Chatelet 
98509efe848SGuillaume Chatelet   LIBC_INLINE constexpr void set_msb() {
98609efe848SGuillaume Chatelet     val.back() |= mask_leading_ones<WordType, 1>();
98709efe848SGuillaume Chatelet   }
98809efe848SGuillaume Chatelet 
98909efe848SGuillaume Chatelet   LIBC_INLINE constexpr void clear_msb() {
99009efe848SGuillaume Chatelet     val.back() &= mask_trailing_ones<WordType, WORD_SIZE - 1>();
99109efe848SGuillaume Chatelet   }
99209efe848SGuillaume Chatelet 
99309efe848SGuillaume Chatelet   LIBC_INLINE constexpr void set_bit(size_t i) {
99409efe848SGuillaume Chatelet     const size_t word_index = i / WORD_SIZE;
99509efe848SGuillaume Chatelet     val[word_index] |= WordType(1) << (i % WORD_SIZE);
99609efe848SGuillaume Chatelet   }
99709efe848SGuillaume Chatelet 
99809efe848SGuillaume Chatelet   LIBC_INLINE constexpr static Division divide_unsigned(const BigInt &dividend,
99909efe848SGuillaume Chatelet                                                         const BigInt &divider) {
100009efe848SGuillaume Chatelet     BigInt remainder = dividend;
100109efe848SGuillaume Chatelet     BigInt quotient;
100209efe848SGuillaume Chatelet     if (remainder >= divider) {
100309efe848SGuillaume Chatelet       BigInt subtractor = divider;
100409efe848SGuillaume Chatelet       int cur_bit = multiword::countl_zero(subtractor.val) -
100509efe848SGuillaume Chatelet                     multiword::countl_zero(remainder.val);
100609efe848SGuillaume Chatelet       subtractor <<= cur_bit;
100709efe848SGuillaume Chatelet       for (; cur_bit >= 0 && remainder > 0; --cur_bit, subtractor >>= 1) {
100809efe848SGuillaume Chatelet         if (remainder < subtractor)
100909efe848SGuillaume Chatelet           continue;
101009efe848SGuillaume Chatelet         remainder -= subtractor;
101109efe848SGuillaume Chatelet         quotient.set_bit(cur_bit);
101209efe848SGuillaume Chatelet       }
101309efe848SGuillaume Chatelet     }
101409efe848SGuillaume Chatelet     return Division{quotient, remainder};
101509efe848SGuillaume Chatelet   }
101609efe848SGuillaume Chatelet 
101709efe848SGuillaume Chatelet   LIBC_INLINE constexpr static Division divide_signed(const BigInt &dividend,
101809efe848SGuillaume Chatelet                                                       const BigInt &divider) {
101909efe848SGuillaume Chatelet     // Special case because it is not possible to negate the min value of a
102009efe848SGuillaume Chatelet     // signed integer.
102109efe848SGuillaume Chatelet     if (dividend == min() && divider == min())
102209efe848SGuillaume Chatelet       return Division{one(), zero()};
102309efe848SGuillaume Chatelet     // 1. Convert the dividend and divisor to unsigned representation.
102409efe848SGuillaume Chatelet     unsigned_type udividend(dividend);
102509efe848SGuillaume Chatelet     unsigned_type udivider(divider);
102609efe848SGuillaume Chatelet     // 2. Negate the dividend if it's negative, and similarly for the divisor.
102709efe848SGuillaume Chatelet     const bool dividend_is_neg = dividend.is_neg();
102809efe848SGuillaume Chatelet     const bool divider_is_neg = divider.is_neg();
102909efe848SGuillaume Chatelet     if (dividend_is_neg)
103009efe848SGuillaume Chatelet       udividend.negate();
103109efe848SGuillaume Chatelet     if (divider_is_neg)
103209efe848SGuillaume Chatelet       udivider.negate();
103309efe848SGuillaume Chatelet     // 3. Use unsigned multiword division algorithm.
103409efe848SGuillaume Chatelet     const auto unsigned_result = divide_unsigned(udividend, udivider);
103509efe848SGuillaume Chatelet     // 4. Convert the quotient and remainder to signed representation.
103609efe848SGuillaume Chatelet     Division result;
103709efe848SGuillaume Chatelet     result.quotient = signed_type(unsigned_result.quotient);
103809efe848SGuillaume Chatelet     result.remainder = signed_type(unsigned_result.remainder);
103909efe848SGuillaume Chatelet     // 5. Negate the quotient if the dividend and divisor had opposite signs.
104009efe848SGuillaume Chatelet     if (dividend_is_neg != divider_is_neg)
104109efe848SGuillaume Chatelet       result.quotient.negate();
104209efe848SGuillaume Chatelet     // 6. Negate the remainder if the dividend was negative.
104309efe848SGuillaume Chatelet     if (dividend_is_neg)
104409efe848SGuillaume Chatelet       result.remainder.negate();
104509efe848SGuillaume Chatelet     return result;
104609efe848SGuillaume Chatelet   }
104709efe848SGuillaume Chatelet 
104809efe848SGuillaume Chatelet   friend signed_type;
104909efe848SGuillaume Chatelet   friend unsigned_type;
105009efe848SGuillaume Chatelet };
105109efe848SGuillaume Chatelet 
105209efe848SGuillaume Chatelet namespace internal {
105309efe848SGuillaume Chatelet // We default BigInt's WordType to 'uint64_t' or 'uint32_t' depending on type
105409efe848SGuillaume Chatelet // availability.
105509efe848SGuillaume Chatelet template <size_t Bits>
105609efe848SGuillaume Chatelet struct WordTypeSelector : cpp::type_identity<
105709efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64
105809efe848SGuillaume Chatelet                               uint64_t
105909efe848SGuillaume Chatelet #else
106009efe848SGuillaume Chatelet                               uint32_t
106109efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT64
106209efe848SGuillaume Chatelet                               > {
106309efe848SGuillaume Chatelet };
10646b21e170SOverMighty // Except if we request 16 or 32 bits explicitly.
10656b21e170SOverMighty template <> struct WordTypeSelector<16> : cpp::type_identity<uint16_t> {};
106609efe848SGuillaume Chatelet template <> struct WordTypeSelector<32> : cpp::type_identity<uint32_t> {};
1067*7302c8dbSNick Desaulniers template <> struct WordTypeSelector<96> : cpp::type_identity<uint32_t> {};
1068*7302c8dbSNick Desaulniers 
106909efe848SGuillaume Chatelet template <size_t Bits>
107009efe848SGuillaume Chatelet using WordTypeSelectorT = typename WordTypeSelector<Bits>::type;
107109efe848SGuillaume Chatelet } // namespace internal
107209efe848SGuillaume Chatelet 
107309efe848SGuillaume Chatelet template <size_t Bits>
107409efe848SGuillaume Chatelet using UInt = BigInt<Bits, false, internal::WordTypeSelectorT<Bits>>;
107509efe848SGuillaume Chatelet 
107609efe848SGuillaume Chatelet template <size_t Bits>
107709efe848SGuillaume Chatelet using Int = BigInt<Bits, true, internal::WordTypeSelectorT<Bits>>;
107809efe848SGuillaume Chatelet 
1079f3aceeeeSOverMighty // Provides limits of BigInt.
1080f3aceeeeSOverMighty template <size_t Bits, bool Signed, typename T>
1081f3aceeeeSOverMighty struct cpp::numeric_limits<BigInt<Bits, Signed, T>> {
1082f3aceeeeSOverMighty   LIBC_INLINE static constexpr BigInt<Bits, Signed, T> max() {
1083f3aceeeeSOverMighty     return BigInt<Bits, Signed, T>::max();
1084f3aceeeeSOverMighty   }
1085f3aceeeeSOverMighty   LIBC_INLINE static constexpr BigInt<Bits, Signed, T> min() {
1086f3aceeeeSOverMighty     return BigInt<Bits, Signed, T>::min();
1087f3aceeeeSOverMighty   }
108809efe848SGuillaume Chatelet   // Meant to match std::numeric_limits interface.
108909efe848SGuillaume Chatelet   // NOLINTNEXTLINE(readability-identifier-naming)
1090f3aceeeeSOverMighty   LIBC_INLINE_VAR static constexpr int digits = Bits - Signed;
109109efe848SGuillaume Chatelet };
109209efe848SGuillaume Chatelet 
109309efe848SGuillaume Chatelet // type traits to determine whether a T is a BigInt.
109409efe848SGuillaume Chatelet template <typename T> struct is_big_int : cpp::false_type {};
109509efe848SGuillaume Chatelet 
109609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T>
109709efe848SGuillaume Chatelet struct is_big_int<BigInt<Bits, Signed, T>> : cpp::true_type {};
109809efe848SGuillaume Chatelet 
109909efe848SGuillaume Chatelet template <class T>
110009efe848SGuillaume Chatelet LIBC_INLINE_VAR constexpr bool is_big_int_v = is_big_int<T>::value;
110109efe848SGuillaume Chatelet 
110209efe848SGuillaume Chatelet // extensions of type traits to include BigInt
110309efe848SGuillaume Chatelet 
110409efe848SGuillaume Chatelet // is_integral_or_big_int
110509efe848SGuillaume Chatelet template <typename T>
110609efe848SGuillaume Chatelet struct is_integral_or_big_int
110709efe848SGuillaume Chatelet     : cpp::bool_constant<(cpp::is_integral_v<T> || is_big_int_v<T>)> {};
110809efe848SGuillaume Chatelet 
110909efe848SGuillaume Chatelet template <typename T>
111009efe848SGuillaume Chatelet LIBC_INLINE_VAR constexpr bool is_integral_or_big_int_v =
111109efe848SGuillaume Chatelet     is_integral_or_big_int<T>::value;
111209efe848SGuillaume Chatelet 
111309efe848SGuillaume Chatelet // make_big_int_unsigned
111409efe848SGuillaume Chatelet template <typename T> struct make_big_int_unsigned;
111509efe848SGuillaume Chatelet 
111609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T>
111709efe848SGuillaume Chatelet struct make_big_int_unsigned<BigInt<Bits, Signed, T>>
111809efe848SGuillaume Chatelet     : cpp::type_identity<BigInt<Bits, false, T>> {};
111909efe848SGuillaume Chatelet 
112009efe848SGuillaume Chatelet template <typename T>
112109efe848SGuillaume Chatelet using make_big_int_unsigned_t = typename make_big_int_unsigned<T>::type;
112209efe848SGuillaume Chatelet 
112309efe848SGuillaume Chatelet // make_big_int_signed
112409efe848SGuillaume Chatelet template <typename T> struct make_big_int_signed;
112509efe848SGuillaume Chatelet 
112609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T>
112709efe848SGuillaume Chatelet struct make_big_int_signed<BigInt<Bits, Signed, T>>
112809efe848SGuillaume Chatelet     : cpp::type_identity<BigInt<Bits, true, T>> {};
112909efe848SGuillaume Chatelet 
113009efe848SGuillaume Chatelet template <typename T>
113109efe848SGuillaume Chatelet using make_big_int_signed_t = typename make_big_int_signed<T>::type;
113209efe848SGuillaume Chatelet 
113309efe848SGuillaume Chatelet // make_integral_or_big_int_unsigned
113409efe848SGuillaume Chatelet template <typename T, class = void> struct make_integral_or_big_int_unsigned;
113509efe848SGuillaume Chatelet 
113609efe848SGuillaume Chatelet template <typename T>
113709efe848SGuillaume Chatelet struct make_integral_or_big_int_unsigned<
113809efe848SGuillaume Chatelet     T, cpp::enable_if_t<cpp::is_integral_v<T>>> : cpp::make_unsigned<T> {};
113909efe848SGuillaume Chatelet 
114009efe848SGuillaume Chatelet template <typename T>
114109efe848SGuillaume Chatelet struct make_integral_or_big_int_unsigned<T, cpp::enable_if_t<is_big_int_v<T>>>
114209efe848SGuillaume Chatelet     : make_big_int_unsigned<T> {};
114309efe848SGuillaume Chatelet 
114409efe848SGuillaume Chatelet template <typename T>
114509efe848SGuillaume Chatelet using make_integral_or_big_int_unsigned_t =
114609efe848SGuillaume Chatelet     typename make_integral_or_big_int_unsigned<T>::type;
114709efe848SGuillaume Chatelet 
114809efe848SGuillaume Chatelet // make_integral_or_big_int_signed
114909efe848SGuillaume Chatelet template <typename T, class = void> struct make_integral_or_big_int_signed;
115009efe848SGuillaume Chatelet 
115109efe848SGuillaume Chatelet template <typename T>
115209efe848SGuillaume Chatelet struct make_integral_or_big_int_signed<T,
115309efe848SGuillaume Chatelet                                        cpp::enable_if_t<cpp::is_integral_v<T>>>
115409efe848SGuillaume Chatelet     : cpp::make_signed<T> {};
115509efe848SGuillaume Chatelet 
115609efe848SGuillaume Chatelet template <typename T>
115709efe848SGuillaume Chatelet struct make_integral_or_big_int_signed<T, cpp::enable_if_t<is_big_int_v<T>>>
115809efe848SGuillaume Chatelet     : make_big_int_signed<T> {};
115909efe848SGuillaume Chatelet 
116009efe848SGuillaume Chatelet template <typename T>
116109efe848SGuillaume Chatelet using make_integral_or_big_int_signed_t =
116209efe848SGuillaume Chatelet     typename make_integral_or_big_int_signed<T>::type;
116309efe848SGuillaume Chatelet 
1164f3aceeeeSOverMighty // is_unsigned_integral_or_big_int
1165f3aceeeeSOverMighty template <typename T>
1166f3aceeeeSOverMighty struct is_unsigned_integral_or_big_int
1167f3aceeeeSOverMighty     : cpp::bool_constant<
1168f3aceeeeSOverMighty           cpp::is_same_v<T, make_integral_or_big_int_unsigned_t<T>>> {};
1169f3aceeeeSOverMighty 
1170f3aceeeeSOverMighty template <typename T>
1171f3aceeeeSOverMighty // Meant to look like <type_traits> helper variable templates.
1172f3aceeeeSOverMighty // NOLINTNEXTLINE(readability-identifier-naming)
1173f3aceeeeSOverMighty LIBC_INLINE_VAR constexpr bool is_unsigned_integral_or_big_int_v =
1174f3aceeeeSOverMighty     is_unsigned_integral_or_big_int<T>::value;
1175f3aceeeeSOverMighty 
117609efe848SGuillaume Chatelet namespace cpp {
117709efe848SGuillaume Chatelet 
117809efe848SGuillaume Chatelet // Specialization of cpp::bit_cast ('bit.h') from T to BigInt.
117909efe848SGuillaume Chatelet template <typename To, typename From>
118009efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<
118109efe848SGuillaume Chatelet     (sizeof(To) == sizeof(From)) && cpp::is_trivially_copyable<To>::value &&
118209efe848SGuillaume Chatelet         cpp::is_trivially_copyable<From>::value && is_big_int<To>::value,
118309efe848SGuillaume Chatelet     To>
118409efe848SGuillaume Chatelet bit_cast(const From &from) {
118509efe848SGuillaume Chatelet   To out;
118609efe848SGuillaume Chatelet   using Storage = decltype(out.val);
118709efe848SGuillaume Chatelet   out.val = cpp::bit_cast<Storage>(from);
118809efe848SGuillaume Chatelet   return out;
118909efe848SGuillaume Chatelet }
119009efe848SGuillaume Chatelet 
119109efe848SGuillaume Chatelet // Specialization of cpp::bit_cast ('bit.h') from BigInt to T.
119209efe848SGuillaume Chatelet template <typename To, size_t Bits>
119309efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<
119409efe848SGuillaume Chatelet     sizeof(To) == sizeof(UInt<Bits>) &&
119509efe848SGuillaume Chatelet         cpp::is_trivially_constructible<To>::value &&
119609efe848SGuillaume Chatelet         cpp::is_trivially_copyable<To>::value &&
119709efe848SGuillaume Chatelet         cpp::is_trivially_copyable<UInt<Bits>>::value,
119809efe848SGuillaume Chatelet     To>
119909efe848SGuillaume Chatelet bit_cast(const UInt<Bits> &from) {
120009efe848SGuillaume Chatelet   return cpp::bit_cast<To>(from.val);
120109efe848SGuillaume Chatelet }
120209efe848SGuillaume Chatelet 
120309efe848SGuillaume Chatelet // Specialization of cpp::popcount ('bit.h') for BigInt.
120409efe848SGuillaume Chatelet template <typename T>
120509efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
120609efe848SGuillaume Chatelet popcount(T value) {
120709efe848SGuillaume Chatelet   int bits = 0;
120809efe848SGuillaume Chatelet   for (auto word : value.val)
120909efe848SGuillaume Chatelet     if (word)
121009efe848SGuillaume Chatelet       bits += popcount(word);
121109efe848SGuillaume Chatelet   return bits;
121209efe848SGuillaume Chatelet }
121309efe848SGuillaume Chatelet 
121409efe848SGuillaume Chatelet // Specialization of cpp::has_single_bit ('bit.h') for BigInt.
121509efe848SGuillaume Chatelet template <typename T>
121609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, bool>
121709efe848SGuillaume Chatelet has_single_bit(T value) {
121809efe848SGuillaume Chatelet   int bits = 0;
121909efe848SGuillaume Chatelet   for (auto word : value.val) {
122009efe848SGuillaume Chatelet     if (word == 0)
122109efe848SGuillaume Chatelet       continue;
122209efe848SGuillaume Chatelet     bits += popcount(word);
122309efe848SGuillaume Chatelet     if (bits > 1)
122409efe848SGuillaume Chatelet       return false;
122509efe848SGuillaume Chatelet   }
122609efe848SGuillaume Chatelet   return bits == 1;
122709efe848SGuillaume Chatelet }
122809efe848SGuillaume Chatelet 
122909efe848SGuillaume Chatelet // Specialization of cpp::countr_zero ('bit.h') for BigInt.
123009efe848SGuillaume Chatelet template <typename T>
123109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
123209efe848SGuillaume Chatelet countr_zero(const T &value) {
123309efe848SGuillaume Chatelet   return multiword::countr_zero(value.val);
123409efe848SGuillaume Chatelet }
123509efe848SGuillaume Chatelet 
123609efe848SGuillaume Chatelet // Specialization of cpp::countl_zero ('bit.h') for BigInt.
123709efe848SGuillaume Chatelet template <typename T>
123809efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
123909efe848SGuillaume Chatelet countl_zero(const T &value) {
124009efe848SGuillaume Chatelet   return multiword::countl_zero(value.val);
124109efe848SGuillaume Chatelet }
124209efe848SGuillaume Chatelet 
124309efe848SGuillaume Chatelet // Specialization of cpp::countl_one ('bit.h') for BigInt.
124409efe848SGuillaume Chatelet template <typename T>
124509efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
124609efe848SGuillaume Chatelet countl_one(T value) {
124709efe848SGuillaume Chatelet   return multiword::countl_one(value.val);
124809efe848SGuillaume Chatelet }
124909efe848SGuillaume Chatelet 
125009efe848SGuillaume Chatelet // Specialization of cpp::countr_one ('bit.h') for BigInt.
125109efe848SGuillaume Chatelet template <typename T>
125209efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
125309efe848SGuillaume Chatelet countr_one(T value) {
125409efe848SGuillaume Chatelet   return multiword::countr_one(value.val);
125509efe848SGuillaume Chatelet }
125609efe848SGuillaume Chatelet 
125709efe848SGuillaume Chatelet // Specialization of cpp::bit_width ('bit.h') for BigInt.
125809efe848SGuillaume Chatelet template <typename T>
125909efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
126009efe848SGuillaume Chatelet bit_width(T value) {
126109efe848SGuillaume Chatelet   return cpp::numeric_limits<T>::digits - cpp::countl_zero(value);
126209efe848SGuillaume Chatelet }
126309efe848SGuillaume Chatelet 
126409efe848SGuillaume Chatelet // Forward-declare rotr so that rotl can use it.
126509efe848SGuillaume Chatelet template <typename T>
126609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
126709efe848SGuillaume Chatelet rotr(T value, int rotate);
126809efe848SGuillaume Chatelet 
126909efe848SGuillaume Chatelet // Specialization of cpp::rotl ('bit.h') for BigInt.
127009efe848SGuillaume Chatelet template <typename T>
127109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
127209efe848SGuillaume Chatelet rotl(T value, int rotate) {
127309efe848SGuillaume Chatelet   constexpr unsigned N = cpp::numeric_limits<T>::digits;
127409efe848SGuillaume Chatelet   rotate = rotate % N;
127509efe848SGuillaume Chatelet   if (!rotate)
127609efe848SGuillaume Chatelet     return value;
127709efe848SGuillaume Chatelet   if (rotate < 0)
127809efe848SGuillaume Chatelet     return cpp::rotr<T>(value, -rotate);
127909efe848SGuillaume Chatelet   return (value << rotate) | (value >> (N - rotate));
128009efe848SGuillaume Chatelet }
128109efe848SGuillaume Chatelet 
128209efe848SGuillaume Chatelet // Specialization of cpp::rotr ('bit.h') for BigInt.
128309efe848SGuillaume Chatelet template <typename T>
128409efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
128509efe848SGuillaume Chatelet rotr(T value, int rotate) {
128609efe848SGuillaume Chatelet   constexpr unsigned N = cpp::numeric_limits<T>::digits;
128709efe848SGuillaume Chatelet   rotate = rotate % N;
128809efe848SGuillaume Chatelet   if (!rotate)
128909efe848SGuillaume Chatelet     return value;
129009efe848SGuillaume Chatelet   if (rotate < 0)
129109efe848SGuillaume Chatelet     return cpp::rotl<T>(value, -rotate);
129209efe848SGuillaume Chatelet   return (value >> rotate) | (value << (N - rotate));
129309efe848SGuillaume Chatelet }
129409efe848SGuillaume Chatelet 
129509efe848SGuillaume Chatelet } // namespace cpp
129609efe848SGuillaume Chatelet 
129709efe848SGuillaume Chatelet // Specialization of mask_trailing_ones ('math_extras.h') for BigInt.
129809efe848SGuillaume Chatelet template <typename T, size_t count>
129909efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
130009efe848SGuillaume Chatelet mask_trailing_ones() {
130109efe848SGuillaume Chatelet   static_assert(!T::SIGNED && count <= T::BITS);
130209efe848SGuillaume Chatelet   if (count == T::BITS)
130309efe848SGuillaume Chatelet     return T::all_ones();
130409efe848SGuillaume Chatelet   constexpr size_t QUOTIENT = count / T::WORD_SIZE;
130509efe848SGuillaume Chatelet   constexpr size_t REMAINDER = count % T::WORD_SIZE;
130609efe848SGuillaume Chatelet   T out; // zero initialized
130709efe848SGuillaume Chatelet   for (size_t i = 0; i <= QUOTIENT; ++i)
130809efe848SGuillaume Chatelet     out[i] = i < QUOTIENT
130909efe848SGuillaume Chatelet                  ? -1
131009efe848SGuillaume Chatelet                  : mask_trailing_ones<typename T::word_type, REMAINDER>();
131109efe848SGuillaume Chatelet   return out;
131209efe848SGuillaume Chatelet }
131309efe848SGuillaume Chatelet 
131409efe848SGuillaume Chatelet // Specialization of mask_leading_ones ('math_extras.h') for BigInt.
131509efe848SGuillaume Chatelet template <typename T, size_t count>
131609efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> mask_leading_ones() {
131709efe848SGuillaume Chatelet   static_assert(!T::SIGNED && count <= T::BITS);
131809efe848SGuillaume Chatelet   if (count == T::BITS)
131909efe848SGuillaume Chatelet     return T::all_ones();
132009efe848SGuillaume Chatelet   constexpr size_t QUOTIENT = (T::BITS - count - 1U) / T::WORD_SIZE;
132109efe848SGuillaume Chatelet   constexpr size_t REMAINDER = count % T::WORD_SIZE;
132209efe848SGuillaume Chatelet   T out; // zero initialized
132309efe848SGuillaume Chatelet   for (size_t i = QUOTIENT; i < T::WORD_COUNT; ++i)
132409efe848SGuillaume Chatelet     out[i] = i > QUOTIENT
132509efe848SGuillaume Chatelet                  ? -1
132609efe848SGuillaume Chatelet                  : mask_leading_ones<typename T::word_type, REMAINDER>();
132709efe848SGuillaume Chatelet   return out;
132809efe848SGuillaume Chatelet }
132909efe848SGuillaume Chatelet 
133009efe848SGuillaume Chatelet // Specialization of mask_trailing_zeros ('math_extras.h') for BigInt.
133109efe848SGuillaume Chatelet template <typename T, size_t count>
133209efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
133309efe848SGuillaume Chatelet mask_trailing_zeros() {
133409efe848SGuillaume Chatelet   return mask_leading_ones<T, T::BITS - count>();
133509efe848SGuillaume Chatelet }
133609efe848SGuillaume Chatelet 
133709efe848SGuillaume Chatelet // Specialization of mask_leading_zeros ('math_extras.h') for BigInt.
133809efe848SGuillaume Chatelet template <typename T, size_t count>
133909efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T>
134009efe848SGuillaume Chatelet mask_leading_zeros() {
134109efe848SGuillaume Chatelet   return mask_trailing_ones<T, T::BITS - count>();
134209efe848SGuillaume Chatelet }
134309efe848SGuillaume Chatelet 
134409efe848SGuillaume Chatelet // Specialization of count_zeros ('math_extras.h') for BigInt.
134509efe848SGuillaume Chatelet template <typename T>
134609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
134709efe848SGuillaume Chatelet count_zeros(T value) {
134809efe848SGuillaume Chatelet   return cpp::popcount(~value);
134909efe848SGuillaume Chatelet }
135009efe848SGuillaume Chatelet 
135109efe848SGuillaume Chatelet // Specialization of first_leading_zero ('math_extras.h') for BigInt.
135209efe848SGuillaume Chatelet template <typename T>
135309efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
135409efe848SGuillaume Chatelet first_leading_zero(T value) {
135509efe848SGuillaume Chatelet   return value == cpp::numeric_limits<T>::max() ? 0
135609efe848SGuillaume Chatelet                                                 : cpp::countl_one(value) + 1;
135709efe848SGuillaume Chatelet }
135809efe848SGuillaume Chatelet 
135909efe848SGuillaume Chatelet // Specialization of first_leading_one ('math_extras.h') for BigInt.
136009efe848SGuillaume Chatelet template <typename T>
136109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
136209efe848SGuillaume Chatelet first_leading_one(T value) {
136309efe848SGuillaume Chatelet   return first_leading_zero(~value);
136409efe848SGuillaume Chatelet }
136509efe848SGuillaume Chatelet 
136609efe848SGuillaume Chatelet // Specialization of first_trailing_zero ('math_extras.h') for BigInt.
136709efe848SGuillaume Chatelet template <typename T>
136809efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
136909efe848SGuillaume Chatelet first_trailing_zero(T value) {
137009efe848SGuillaume Chatelet   return value == cpp::numeric_limits<T>::max() ? 0
137109efe848SGuillaume Chatelet                                                 : cpp::countr_zero(~value) + 1;
137209efe848SGuillaume Chatelet }
137309efe848SGuillaume Chatelet 
137409efe848SGuillaume Chatelet // Specialization of first_trailing_one ('math_extras.h') for BigInt.
137509efe848SGuillaume Chatelet template <typename T>
137609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
137709efe848SGuillaume Chatelet first_trailing_one(T value) {
137809efe848SGuillaume Chatelet   return value == cpp::numeric_limits<T>::max() ? 0
137909efe848SGuillaume Chatelet                                                 : cpp::countr_zero(value) + 1;
138009efe848SGuillaume Chatelet }
138109efe848SGuillaume Chatelet 
13825ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
138309efe848SGuillaume Chatelet 
138421895a84SOleksandr T. #endif // LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
1385