10#include "constexpr_wrapper.h"
12#if __has_include (<bit>) && __cplusplus >= 202002L
14#define VIR_HAVE_STD_BIT_CAST 1
16#define VIR_HAVE_STD_BIT_CAST 0
19#if defined _GLIBCXX_EXPERIMENTAL_SIMD_H && defined __cpp_lib_experimental_parallel_simd
20#define VIR_GLIBCXX_STDX_SIMD 1
22#define VIR_GLIBCXX_STDX_SIMD 0
27#if VIR_GLIBCXX_STDX_SIMD && (defined __STRICT_ANSI__ || defined __clang__)
28#define VIR_SIMD_CONSTEXPR_SIMD const
29#define VIR_SIMD_HAVE_CONSTEXPR_API 0
31#define VIR_SIMD_CONSTEXPR_SIMD constexpr
32#define VIR_SIMD_HAVE_CONSTEXPR_API 1
35#if defined __GNUC__ and not defined __clang__
36#define VIR_LAMBDA_ALWAYS_INLINE __attribute__((__always_inline__))
38#define VIR_LAMBDA_ALWAYS_INLINE
45#if __has_builtin(__builtin_shufflevector) and __clang_major__ != 17
46#define VIR_HAVE_WORKING_SHUFFLEVECTOR 1
48#if __has_builtin(__builtin_bit_cast)
49#define VIR_HAVE_BUILTIN_BIT_CAST 1
52#ifndef VIR_HAVE_WORKING_SHUFFLEVECTOR
53#define VIR_HAVE_WORKING_SHUFFLEVECTOR 0
55#ifndef VIR_HAVE_BUILTIN_BIT_CAST
56#define VIR_HAVE_BUILTIN_BIT_CAST 0
65 using is_simd_or_mask = std::disjunction<stdx::is_simd<T>, stdx::is_simd_mask<T>>;
68 inline constexpr bool is_simd_or_mask_v = std::disjunction_v<stdx::is_simd<T>,
69 stdx::is_simd_mask<T>>;
76 using type_identity_t =
typename type_identity<T>::type;
78 template <
typename T,
typename U =
long long,
bool = (sizeof(T) == sizeof(U))>
81 template <
typename T,
typename U>
82 struct as_int<T, U, true>
86 struct as_int<T, long long, false>
90 struct as_int<T, long, false>
94 struct as_int<T, int, false>
95 : as_int<T, short> {};
98 struct as_int<T, short, false>
99 : as_int<T, signed char> {};
102#pragma GCC diagnostic push
103#pragma GCC diagnostic ignored "-Wpedantic"
105 template <
typename T>
106 struct as_int<T, signed char, false>
107 #ifdef __SIZEOF_INT128__
108 : as_int<T, __int128> {};
110 template <
typename T>
111 struct as_int<T, __int128, false>
115#pragma GCC diagnostic pop
118 template <
typename T>
119 using as_int_t =
typename as_int<T>::type;
121 template <
typename T,
typename U =
unsigned long long,
bool = (sizeof(T) == sizeof(U))>
124 template <
typename T,
typename U>
125 struct as_unsigned<T, U, true>
128 template <
typename T>
129 struct as_unsigned<T, unsigned long long, false>
130 : as_unsigned<T, unsigned long> {};
132 template <
typename T>
133 struct as_unsigned<T, unsigned long, false>
134 : as_unsigned<T, unsigned int> {};
136 template <
typename T>
137 struct as_unsigned<T, unsigned int, false>
138 : as_unsigned<T, unsigned short> {};
140 template <
typename T>
141 struct as_unsigned<T, unsigned short, false>
142 : as_unsigned<T, unsigned char> {};
145#pragma GCC diagnostic push
146#pragma GCC diagnostic ignored "-Wpedantic"
148 template <
typename T>
149 struct as_unsigned<T, unsigned char, false>
150 #ifdef __SIZEOF_INT128__
151 : as_unsigned<T, unsigned __int128> {};
153 template <
typename T>
154 struct as_unsigned<T, unsigned __int128, false>
158#pragma GCC diagnostic pop
161 template <
typename T>
162 using as_unsigned_t =
typename as_unsigned<T>::type;
169 template <
typename T,
typename = std::enable_if_t<std::is_
floating_po
int_v<T>>>
170 using FloatingPoint = T;
172 using namespace vir::stdx;
178 template <
typename T,
int N>
179 using deduced_simd = stdx::simd<T, stdx::simd_abi::deduce_t<T, N>>;
181 template <
typename T,
int N>
182 using deduced_simd_mask = stdx::simd_mask<T, stdx::simd_abi::deduce_t<T, N>>;
184 template <
typename T>
187 {
return (x & (x - 1)) == 0 ? x : bit_ceil((x | (x >> 1)) + 1); }
190 template <
typename T,
int N,
unsigned Bytes = sizeof(T) * bit_ceil(
unsigned(N))>
191 using gnu_vector [[gnu::vector_size(Bytes)]] = T;
193 template <
typename T>
195 is_vec_builtin_impl(gnu_vector<std::remove_cv_t<std::remove_reference_t<
decltype(T()[0])>>,
199 template <
typename T>
201 is_vec_builtin_impl(...);
203 template <
typename T>
204 struct is_vec_builtin
205 : decltype(is_vec_builtin_impl<T>(std::declval<T>()))
208 template <
typename T>
209 constexpr bool is_vec_builtin_v = is_vec_builtin<T>::value;
213 static_assert(not is_vec_builtin_v<int>);
215 static_assert(is_vec_builtin_v<gnu_vector<int, 4>>);
219 template <
typename T>
221 internal_data_hack(T&& x,
float)
224 template <
typename T>
226 internal_data_hack(T&& x,
int) -> std::enable_if_t<
sizeof(T) ==
sizeof(
decltype(__data(x))),
228 {
return __data(x); }
230 template <
typename T>
232 internal_data_hack(T&& x,
int) -> std::enable_if_t<
sizeof(T) ==
sizeof(
decltype(_data_(x))),
234 {
return _data_(x); }
236 template <
typename To,
typename From>
238 bit_cast(
const From& x)
240 static_assert(
sizeof(To) ==
sizeof(From));
241#if VIR_HAVE_STD_BIT_CAST
242 return std::bit_cast<To>(x);
243#elif VIR_HAVE_BUILTIN_BIT_CAST
244 return __builtin_bit_cast(To, x);
246 if constexpr (is_vec_builtin_v<To>)
247 return reinterpret_cast<To
>(x);
251 std::memcpy(&internal_data_hack(r, 0), &internal_data_hack(x, 0),
sizeof(x));
257#if VIR_HAVE_CONSTEXPR_WRAPPER
258 template <
int Iterations, auto I = 0,
typename F>
259 [[gnu::always_inline, gnu::flatten]]
263 if constexpr (Iterations != 0)
266 unroll<Iterations - 1, I + 1>(
static_cast<F&&
>(fun));
270 template <
int Iterations>
271 [[gnu::always_inline, gnu::flatten]]
273 unroll2(
auto&& fun0,
auto&& fun1)
275 [&]<
int... Is>(std::integer_sequence<int, Is...>) VIR_LAMBDA_ALWAYS_INLINE {
276 [&](
auto&&... r0s) VIR_LAMBDA_ALWAYS_INLINE {
277 (fun1(vir::cw<Is>,
static_cast<decltype(r0s)
>(r0s)), ...);
278 }(fun0(vir::cw<Is>)...);
279 }(std::make_integer_sequence<int, Iterations>());