6#include "TTauri/Foundation/required.hpp"
7#include "TTauri/Foundation/numeric_cast.hpp"
14#if TT_COMPILER == TT_CC_MSVC
17#if TT_PROCESSOR == TT_CPU_X64
28template<
typename T, std::enable_if_t<std::is_
integral_v<T> && std::is_
unsigned_v<T>,
int> = 0>
29constexpr std::pair<T, T> shift_left_carry(T a,
unsigned int count, T carry = 0) noexcept
31 constexpr unsigned int nr_bits =
sizeof(T) * 8;
32 unsigned int reverse_count = nr_bits -
count;
45template<
typename T, std::enable_if_t<std::is_
integral_v<T> && std::is_
unsigned_v<T>,
int> = 0>
46constexpr std::pair<T, T> shift_right_carry(T a,
unsigned int count, T carry = 0) noexcept
48 constexpr unsigned int nr_bits =
sizeof(T) * 8;
49 unsigned int reverse_count = nr_bits -
count;
62template<
typename T, std::enable_if_t<std::is_
integral_v<T> && std::is_
unsigned_v<T>,
int> = 0>
65 if constexpr (
sizeof(T) == 1) {
66 uint16_t r =
static_cast<uint16_t
>(a) +
static_cast<uint16_t
>(b) + carry;
67 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8) };
69 }
else if constexpr (
sizeof(T) == 2) {
70 uint32_t r =
static_cast<uint32_t
>(a) +
static_cast<uint32_t
>(b) + carry;
71 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16) };
73 }
else if constexpr (
sizeof(T) == 4) {
74 uint64_t r =
static_cast<uint64_t
>(a) +
static_cast<uint64_t
>(b) + carry;
75 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32) };
77 }
else if constexpr (
sizeof(T) == 8) {
78#if TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
79 auto r =
static_cast<__uint128_t
>(a) +
static_cast<__uint128_t
>(b) + carry;
80 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64) };
83 uint64_t c = (r1 < a) ? 1 : 0;
84 uint64_t r2 = r1 + carry;
85 c += (r2 < r1) ? 1 : 0;
91template<
typename T, std::enable_if_t<std::is_
integral_v<T> && std::is_
unsigned_v<T>,
int> = 0>
94 if constexpr (
sizeof(T) == 1) {
95 uint16_t r =
static_cast<uint16_t
>(a) *
static_cast<uint16_t
>(b);
96 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8) };
98 }
else if constexpr (
sizeof(T) == 2) {
99 uint32_t r =
static_cast<uint32_t
>(a) *
static_cast<uint32_t
>(b);
100 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16) };
102 }
else if constexpr (
sizeof(T) == 4) {
103 uint64_t r =
static_cast<uint64_t
>(a) *
static_cast<uint64_t
>(b);
104 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32) };
106 }
else if constexpr (
sizeof(T) == 8) {
107#if TT_COMPILER == TT_CC_MSVC
109 uint64_t lo = _umul128(a, b, &hi);
112#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
113 auto r =
static_cast<__uint128_t
>(a) *
static_cast<__uint128_t
>(b);
114 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64) };
116#error "Not implemented"
121template<
typename T, std::enable_if_t<std::is_
integral_v<T> && std::is_
unsigned_v<T>,
int> = 0>
122constexpr std::pair<T, T> multiply_carry(T a, T b, T carry = 0, T accumulator = 0) noexcept
124 if constexpr (
sizeof(T) == 1) {
125 uint16_t r =
static_cast<uint16_t
>(a) *
static_cast<uint16_t
>(b) + carry + accumulator;
126 return {
static_cast<uint8_t
>(r),
static_cast<uint8_t
>(r >> 8) };
128 }
else if constexpr (
sizeof(T) == 2) {
129 uint32_t r =
static_cast<uint32_t
>(a) *
static_cast<uint32_t
>(b) + carry + accumulator;
130 return {
static_cast<uint16_t
>(r),
static_cast<uint16_t
>(r >> 16) };
132 }
else if constexpr (
sizeof(T) == 4) {
133 uint64_t r =
static_cast<uint64_t
>(a) *
static_cast<uint64_t
>(b) + carry + accumulator;
134 return {
static_cast<uint32_t
>(r),
static_cast<uint32_t
>(r >> 32) };
136 }
else if constexpr (
sizeof(T) == 8) {
137#if TT_COMPILER == TT_CC_MSVC
139 uint64_t lo = _umul128(a, b, &hi);
141 std::tie(lo, c) = add_carry(lo, carry, uint64_t{0});
142 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
143 std::tie(lo, c) = add_carry(lo, accumulator, uint64_t{0});
144 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
147#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
148 auto r =
static_cast<__uint128_t
>(a) *
static_cast<__uint128_t
>(b) + carry + accumulator;
149 return {
static_cast<uint64_t
>(r),
static_cast<uint64_t
>(r >> 64) };
151#error "Not implemented"