16#if TT_COMPILER == TT_CC_MSVC
19#if TT_PROCESSOR == TT_CPU_X64
31template<std::
unsigned_
integral T>
32constexpr std::pair<T, T> shift_left_carry(T lhs,
unsigned int rhs, T carry = 0) noexcept
34 constexpr unsigned int nr_bits =
sizeof(T) * 8;
35 unsigned int reverse_count = nr_bits - rhs;
37 return {(lhs << rhs) | carry, lhs >> reverse_count};
46template<std::
unsigned_
integral T>
47constexpr std::pair<T, T> shift_right_carry(T lhs,
unsigned int rhs, T carry = 0) noexcept
49 constexpr unsigned int nr_bits =
sizeof(T) * 8;
50 unsigned int reverse_count = nr_bits - rhs;
52 return {(lhs >> rhs) | carry, lhs << reverse_count};
61template<std::
unsigned_
integral T>
64 tt_axiom(carry == 0 || carry == 1);
66 if constexpr (
sizeof(T) == 1) {
67 uint16_t r =
static_cast<uint16_t
>(lhs) +
static_cast<uint16_t
>(rhs) + carry;
68 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8)};
70 }
else if constexpr (
sizeof(T) == 2) {
71 uint32_t r =
static_cast<uint32_t
>(lhs) +
static_cast<uint32_t
>(rhs) + carry;
72 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16)};
74 }
else if constexpr (
sizeof(T) == 4) {
75 uint64_t r =
static_cast<uint64_t
>(lhs) +
static_cast<uint64_t
>(rhs) + carry;
76 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32)};
78 }
else if constexpr (
sizeof(T) == 8) {
79#if TT_COMPILER == TT_MSVC
81 auto carry_out = _addcarry_u64(
static_cast<unsigned char>(carry), lhs, rhs, &r);
82 return {r,
static_cast<uint64_t
>(carry_out)};
83#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
84 auto r =
static_cast<__uint128_t
>(lhs) +
static_cast<__uint128_t
>(rhs) + carry;
85 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64)};
87 uint64_t r1 = lhs + rhs;
88 uint64_t c = (r1 < lhs) ? 1 : 0;
89 uint64_t r2 = r1 + carry;
90 c += (r2 < r1) ? 1 : 0;
106template<std::
unsigned_
integral T>
107constexpr std::pair<T, T> mul_carry(T lhs, T rhs, T carry = 0, T accumulator = 0) noexcept
109 if constexpr (
sizeof(T) == 1) {
110 uint16_t r =
static_cast<uint16_t
>(lhs) *
static_cast<uint16_t
>(rhs) + carry + accumulator;
111 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8)};
113 }
else if constexpr (
sizeof(T) == 2) {
114 uint32_t r =
static_cast<uint32_t
>(lhs) *
static_cast<uint32_t
>(rhs) + carry + accumulator;
115 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16)};
117 }
else if constexpr (
sizeof(T) == 4) {
118 uint64_t r =
static_cast<uint64_t
>(lhs) *
static_cast<uint64_t
>(rhs) + carry + accumulator;
119 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32)};
121 }
else if constexpr (
sizeof(T) == 8) {
122#if TT_COMPILER == TT_CC_MSVC
124 uint64_t lo = _umul128(lhs, rhs, &hi);
126 std::tie(lo, c) = add_carry(lo, carry, uint64_t{0});
127 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
128 std::tie(lo, c) = add_carry(lo, accumulator, uint64_t{0});
129 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
132#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
133 auto r =
static_cast<__uint128_t
>(lhs) *
static_cast<__uint128_t
>(rhs) + carry + accumulator;
134 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64)};
136#error "Not implemented"
148template<std::
unsigned_
integral T>
151 if constexpr (
sizeof(T) == 1) {
152 uint16_t r =
static_cast<uint16_t
>(lhs) *
static_cast<uint16_t
>(rhs);
153 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8)};
155 }
else if constexpr (
sizeof(T) == 2) {
156 uint32_t r =
static_cast<uint32_t
>(lhs) *
static_cast<uint32_t
>(rhs);
157 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16)};
159 }
else if constexpr (
sizeof(T) == 4) {
160 uint64_t r =
static_cast<uint64_t
>(lhs) *
static_cast<uint64_t
>(rhs);
161 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32)};
163 }
else if constexpr (
sizeof(T) == 8) {
164#if TT_COMPILER == TT_CC_MSVC
166 uint64_t lo = _umul128(lhs, rhs, &hi);
169#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
170 auto r =
static_cast<__uint128_t
>(lhs) *
static_cast<__uint128_t
>(rhs);
171 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64)};
173#error "Not implemented"
187template<std::
unsigned_
integral T>
188constexpr T wide_div(T lhs_lo, T lhs_hi, T rhs)
noexcept
190 if constexpr (
sizeof(T) == 1) {
191 ttlet lhs =
static_cast<uint16_t
>(lhs_hi) << 8 |
static_cast<uint16_t
>(lhs_lo);
192 return narrow_cast<uint8_t>(lhs / rhs);
194 }
else if constexpr (
sizeof(T) == 2) {
195 ttlet lhs =
static_cast<uint32_t
>(lhs_hi) << 16 |
static_cast<uint32_t
>(lhs_lo);
196 return narrow_cast<uint16_t>(lhs / rhs);
198 }
else if constexpr (
sizeof(T) == 4) {
199 ttlet lhs =
static_cast<uint64_t
>(lhs_hi) << 32 |
static_cast<uint64_t
>(lhs_lo);
200 return narrow_cast<uint32_t>(lhs / rhs);
202 }
else if constexpr (
sizeof(T) == 8) {
203#if TT_COMPILER == TT_CC_MSVC
205 return _udiv128(lhs_hi, lhs_lo, rhs, &remainder);
207#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
208 ttlet lhs =
static_cast<__uint128_t
>(lhs_hi) << 64 |
static_cast<__uint128_t
>(lhs_lo);
209 return narrow_cast<uint64_t>(lhs / rhs);
211#error "Not implemented"