HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
int_carry.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/required.hpp"
7#include "TTauri/Foundation/numeric_cast.hpp"
8#include <complex>
9#include <cmath>
10#include <limits>
11#include <nonstd/span>
12#include <tuple>
13
14#if TT_COMPILER == TT_CC_MSVC
15#include <intrin.h>
16#endif
17#if TT_PROCESSOR == TT_CPU_X64
18#include <immintrin.h>
19#endif
20
21namespace tt {
22
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
30{
31 constexpr unsigned int nr_bits = sizeof(T) * 8;
32 unsigned int reverse_count = nr_bits - count;
33
34 return {
35 (a << count) | carry,
36 a >> reverse_count
37 };
38}
39
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
47{
48 constexpr unsigned int nr_bits = sizeof(T) * 8;
49 unsigned int reverse_count = nr_bits - count;
50
51 return {
52 (a >> count) | carry,
53 a << reverse_count
54 };
55}
56
57
62template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>,int> = 0>
63constexpr std::pair<T, T> add_carry(T a, T b, T carry = 0) noexcept
64{
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) };
68
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) };
72
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) };
76
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) };
81#else
82 uint64_t r1 = a + b;
83 uint64_t c = (r1 < a) ? 1 : 0;
84 uint64_t r2 = r1 + carry;
85 c += (r2 < r1) ? 1 : 0;
86 return { r2, c };
87#endif
88 }
89}
90
91template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>,int> = 0>
92constexpr std::pair<T, T> wide_multiply(T a, T b) noexcept
93{
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) };
97
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) };
101
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) };
105
106 } else if constexpr (sizeof(T) == 8) {
107#if TT_COMPILER == TT_CC_MSVC
108 uint64_t hi = 0;
109 uint64_t lo = _umul128(a, b, &hi);
110 return { lo, hi };
111
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) };
115#else
116#error "Not implemented"
117#endif
118 }
119}
120
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
123{
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) };
127
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) };
131
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) };
135
136 } else if constexpr (sizeof(T) == 8) {
137#if TT_COMPILER == TT_CC_MSVC
138 uint64_t hi = 0;
139 uint64_t lo = _umul128(a, b, &hi);
140 uint64_t c = 0;
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);
145 return { lo, hi };
146
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) };
150#else
151#error "Not implemented"
152#endif
153 }
154}
155
156}
T count(T... args)
T tie(T... args)