HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
int_carry.hpp
1// Copyright Take Vos 2019-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "required.hpp"
8#include "cast.hpp"
9#include <complex>
10#include <cmath>
11#include <limits>
12#include <span>
13#include <tuple>
14#include <concepts>
15
16#if TT_COMPILER == TT_CC_MSVC
17#include <intrin.h>
18#endif
19#if TT_PROCESSOR == TT_CPU_X64
20#include <immintrin.h>
21#endif
22
23namespace tt {
24
31template<std::unsigned_integral T>
32constexpr std::pair<T, T> shift_left_carry(T lhs, unsigned int rhs, T carry = 0) noexcept
33{
34 constexpr unsigned int nr_bits = sizeof(T) * 8;
35 unsigned int reverse_count = nr_bits - rhs;
36
37 return {(lhs << rhs) | carry, lhs >> reverse_count};
38}
39
46template<std::unsigned_integral T>
47constexpr std::pair<T, T> shift_right_carry(T lhs, unsigned int rhs, T carry = 0) noexcept
48{
49 constexpr unsigned int nr_bits = sizeof(T) * 8;
50 unsigned int reverse_count = nr_bits - rhs;
51
52 return {(lhs >> rhs) | carry, lhs << reverse_count};
53}
54
61template<std::unsigned_integral T>
62constexpr std::pair<T, T> add_carry(T lhs, T rhs, T carry = 0) noexcept
63{
64 tt_axiom(carry == 0 || carry == 1);
65
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)};
69
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)};
73
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)};
77
78 } else if constexpr (sizeof(T) == 8) {
79#if TT_COMPILER == TT_MSVC
80 uint64_t r;
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)};
86#else
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;
91 return {r2, c};
92#endif
93 }
94}
95
106template<std::unsigned_integral T>
107constexpr std::pair<T, T> mul_carry(T lhs, T rhs, T carry = 0, T accumulator = 0) noexcept
108{
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)};
112
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)};
116
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)};
120
121 } else if constexpr (sizeof(T) == 8) {
122#if TT_COMPILER == TT_CC_MSVC
123 uint64_t hi = 0;
124 uint64_t lo = _umul128(lhs, rhs, &hi);
125 uint64_t c = 0;
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);
130 return {lo, hi};
131
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)};
135#else
136#error "Not implemented"
137#endif
138 }
139}
140
148template<std::unsigned_integral T>
149constexpr std::pair<T, T> wide_mul(T lhs, T rhs) noexcept
150{
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)};
154
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)};
158
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)};
162
163 } else if constexpr (sizeof(T) == 8) {
164#if TT_COMPILER == TT_CC_MSVC
165 uint64_t hi = 0;
166 uint64_t lo = _umul128(lhs, rhs, &hi);
167 return {lo, hi};
168
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)};
172#else
173#error "Not implemented"
174#endif
175 }
176}
177
187template<std::unsigned_integral T>
188constexpr T wide_div(T lhs_lo, T lhs_hi, T rhs) noexcept
189{
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);
193
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);
197
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);
201
202 } else if constexpr (sizeof(T) == 8) {
203#if TT_COMPILER == TT_CC_MSVC
204 uint64_t remainder;
205 return _udiv128(lhs_hi, lhs_lo, rhs, &remainder);
206
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);
210#else
211#error "Not implemented"
212#endif
213 }
214}
215
216} // namespace tt
T remainder(T... args)
T tie(T... args)