File indexing completed on 2026-11-07 10:36:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef XSIMD_COMMON_DETAILS_HPP
0013 #define XSIMD_COMMON_DETAILS_HPP
0014
0015 #include "../../math/xsimd_rem_pio2.hpp"
0016 #include "../../types/xsimd_common_arch.hpp"
0017 #include "../../types/xsimd_utils.hpp"
0018 #include "../xsimd_constants.hpp"
0019
0020 #include <complex>
0021
0022 namespace xsimd
0023 {
0024
0025 template <class T, class A>
0026 XSIMD_INLINE batch<T, A> abs(batch<T, A> const& self) noexcept;
0027 template <class T, class A>
0028 XSIMD_INLINE batch<T, A> abs(batch<std::complex<T>, A> const& self) noexcept;
0029 template <class T, class A>
0030 XSIMD_INLINE bool any(batch_bool<T, A> const& self) noexcept;
0031 template <class T, class A>
0032 XSIMD_INLINE batch<T, A> atan2(batch<T, A> const& self, batch<T, A> const& other) noexcept;
0033 template <class A, class T_out, class T_in>
0034 XSIMD_INLINE batch<T_out, A> batch_cast(batch<T_in, A> const&, batch<T_out, A> const& out) noexcept;
0035 template <class T, class A>
0036 XSIMD_INLINE batch<T, A> bitofsign(batch<T, A> const& self) noexcept;
0037 template <class T_out, class T_in, class A>
0038 XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& self) noexcept;
0039 template <class T, class A>
0040 XSIMD_INLINE batch<T, A> cos(batch<T, A> const& self) noexcept;
0041 template <class T, class A>
0042 XSIMD_INLINE batch<T, A> cosh(batch<T, A> const& self) noexcept;
0043 template <class T, class A>
0044 XSIMD_INLINE batch<T, A> exp(batch<T, A> const& self) noexcept;
0045 template <class T, class A>
0046 XSIMD_INLINE batch<T, A> fma(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z) noexcept;
0047 template <class T, class A>
0048 XSIMD_INLINE batch<T, A> fms(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z) noexcept;
0049 template <class T, class A>
0050 XSIMD_INLINE batch<T, A> fmas(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z) noexcept;
0051 template <class T, class A>
0052 XSIMD_INLINE batch<T, A> frexp(const batch<T, A>& x, const batch<as_integer_t<T>, A>& e) noexcept;
0053 template <class T, class A, uint64_t... Coefs>
0054 XSIMD_INLINE batch<T, A> horner(const batch<T, A>& self) noexcept;
0055 template <class T, class A>
0056 XSIMD_INLINE batch<T, A> hypot(const batch<T, A>& self) noexcept;
0057 template <class T, class A>
0058 XSIMD_INLINE batch_bool<T, A> is_even(batch<T, A> const& self) noexcept;
0059 template <class T, class A>
0060 XSIMD_INLINE batch_bool<T, A> is_flint(batch<T, A> const& self) noexcept;
0061 template <class T, class A>
0062 XSIMD_INLINE batch_bool<T, A> is_odd(batch<T, A> const& self) noexcept;
0063 template <class T, class A>
0064 XSIMD_INLINE typename batch<T, A>::batch_bool_type isinf(batch<T, A> const& self) noexcept;
0065 template <class T, class A>
0066 XSIMD_INLINE typename batch<T, A>::batch_bool_type isfinite(batch<T, A> const& self) noexcept;
0067 template <class T, class A>
0068 XSIMD_INLINE typename batch<T, A>::batch_bool_type isnan(batch<T, A> const& self) noexcept;
0069 template <class T, class A>
0070 XSIMD_INLINE batch<T, A> ldexp(const batch<T, A>& x, const batch<as_integer_t<T>, A>& e) noexcept;
0071 template <class T, class A>
0072 XSIMD_INLINE batch<T, A> log(batch<T, A> const& self) noexcept;
0073 template <class T, class A>
0074 XSIMD_INLINE batch<T, A> nearbyint(batch<T, A> const& self) noexcept;
0075 template <class T, class A>
0076 XSIMD_INLINE batch<as_integer_t<T>, A> nearbyint_as_int(const batch<T, A>& x) noexcept;
0077 template <class T, class A>
0078 XSIMD_INLINE T reduce_add(batch<T, A> const&) noexcept;
0079 template <class T, class A>
0080 XSIMD_INLINE T reduce_mul(batch<T, A> const&) noexcept;
0081 template <class T, class A>
0082 XSIMD_INLINE batch<T, A> select(batch_bool<T, A> const&, batch<T, A> const&, batch<T, A> const&) noexcept;
0083 template <class T, class A>
0084 XSIMD_INLINE batch<std::complex<T>, A> select(batch_bool<T, A> const&, batch<std::complex<T>, A> const&, batch<std::complex<T>, A> const&) noexcept;
0085 template <class T, class A>
0086 XSIMD_INLINE batch<T, A> sign(batch<T, A> const& self) noexcept;
0087 template <class T, class A>
0088 XSIMD_INLINE batch<T, A> signnz(batch<T, A> const& self) noexcept;
0089 template <class T, class A>
0090 XSIMD_INLINE batch<T, A> sin(batch<T, A> const& self) noexcept;
0091 template <class T, class A>
0092 XSIMD_INLINE batch<T, A> sinh(batch<T, A> const& self) noexcept;
0093 template <class T, class A>
0094 XSIMD_INLINE std::pair<batch<T, A>, batch<T, A>> sincos(batch<T, A> const& self) noexcept;
0095 template <class T, class A>
0096 XSIMD_INLINE batch<T, A> sqrt(batch<T, A> const& self) noexcept;
0097 template <class T, class A, class Vt, Vt... Values>
0098 XSIMD_INLINE std::enable_if_t<std::is_arithmetic<T>::value, batch<T, A>>
0099 swizzle(batch<T, A> const& x, batch_constant<Vt, A, Values...> mask) noexcept;
0100 template <class T, class A>
0101 XSIMD_INLINE batch<T, A> tan(batch<T, A> const& self) noexcept;
0102 template <class T, class A>
0103 XSIMD_INLINE batch<as_float_t<T>, A> to_float(batch<T, A> const& self) noexcept;
0104 template <class T, class A>
0105 XSIMD_INLINE batch<as_integer_t<T>, A> to_int(batch<T, A> const& self) noexcept;
0106 template <class T, class A>
0107 XSIMD_INLINE batch<T, A> trunc(batch<T, A> const& self) noexcept;
0108
0109 namespace kernel
0110 {
0111
0112 namespace detail
0113 {
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 template <class T>
0128 XSIMD_INLINE void reassociation_barrier(T& x, const char*) noexcept
0129 {
0130 #if XSIMD_REASSOCIATIVE_MATH && XSIMD_WITH_INLINE_ASM && !defined(__EMSCRIPTEN__)
0131 #if XSIMD_WITH_SSE2
0132 __asm__ volatile("" : "+x"(x));
0133 #elif XSIMD_WITH_NEON || XSIMD_WITH_SVE
0134 __asm__ volatile("" : "+w"(x));
0135 #elif XSIMD_WITH_VSX
0136 __asm__ volatile("" : "+wa"(x));
0137 #else
0138 __asm__ volatile("" : "+m"(x));
0139 #endif
0140 #else
0141 (void)x;
0142 #endif
0143 }
0144
0145
0146
0147
0148 #if XSIMD_REASSOCIATIVE_MATH && XSIMD_WITH_INLINE_ASM && defined(__riscv)
0149 XSIMD_INLINE void reassociation_barrier(float& x, const char*) noexcept
0150 {
0151 __asm__ volatile("" : "+f"(x));
0152 }
0153 XSIMD_INLINE void reassociation_barrier(double& x, const char*) noexcept
0154 {
0155 __asm__ volatile("" : "+f"(x));
0156 }
0157 #endif
0158
0159 template <class T, size_t N>
0160 XSIMD_INLINE void reassociation_barrier(std::array<T, N>& arr, const char* reason) noexcept
0161 {
0162 for (auto& v : arr)
0163 reassociation_barrier(v, reason);
0164 }
0165
0166 template <class T, class A>
0167 XSIMD_INLINE void reassociation_barrier(batch<T, A>& b, const char* reason) noexcept
0168 {
0169 #if XSIMD_REASSOCIATIVE_MATH && XSIMD_WITH_RVV && XSIMD_WITH_INLINE_ASM && ((__GNUC__ >= 15) || (__clang_major__ >= 20))
0170 __asm__ volatile("" : "+vr"(b.data.value.value));
0171 (void)reason;
0172 #else
0173 reassociation_barrier(b.data, reason);
0174 #endif
0175 }
0176
0177 template <class F, class A, class T, class... Batches>
0178 XSIMD_INLINE batch<T, A> apply(F&& func, batch<T, A> const& self, batch<T, A> const& other) noexcept
0179 {
0180 constexpr std::size_t size = batch<T, A>::size;
0181 alignas(A::alignment()) T self_buffer[size];
0182 alignas(A::alignment()) T other_buffer[size];
0183 self.store_aligned(&self_buffer[0]);
0184 other.store_aligned(&other_buffer[0]);
0185 for (std::size_t i = 0; i < size; ++i)
0186 {
0187 self_buffer[i] = func(self_buffer[i], other_buffer[i]);
0188 }
0189 return batch<T, A>::load_aligned(self_buffer);
0190 }
0191
0192 template <class U, class F, class A, class T>
0193 XSIMD_INLINE batch<U, A> apply_transform(F&& func, batch<T, A> const& self) noexcept
0194 {
0195 static_assert(batch<T, A>::size == batch<U, A>::size,
0196 "Source and destination sizes must match");
0197 constexpr std::size_t src_size = batch<T, A>::size;
0198 constexpr std::size_t dest_size = batch<U, A>::size;
0199 alignas(A::alignment()) T self_buffer[src_size];
0200 alignas(A::alignment()) U other_buffer[dest_size];
0201 self.store_aligned(&self_buffer[0]);
0202 for (std::size_t i = 0; i < src_size; ++i)
0203 {
0204 other_buffer[i] = func(self_buffer[i]);
0205 }
0206 return batch<U, A>::load_aligned(other_buffer);
0207 }
0208 }
0209
0210
0211 namespace detail
0212 {
0213 template <class A>
0214 XSIMD_INLINE batch<uint8_t, A> fast_cast(batch<int8_t, A> const& self, batch<uint8_t, A> const&, requires_arch<common>) noexcept
0215 {
0216 return bitwise_cast<uint8_t>(self);
0217 }
0218 template <class A>
0219 XSIMD_INLINE batch<uint16_t, A> fast_cast(batch<int16_t, A> const& self, batch<uint16_t, A> const&, requires_arch<common>) noexcept
0220 {
0221 return bitwise_cast<uint16_t>(self);
0222 }
0223 template <class A>
0224 XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<int32_t, A> const& self, batch<uint32_t, A> const&, requires_arch<common>) noexcept
0225 {
0226 return bitwise_cast<uint32_t>(self);
0227 }
0228 template <class A>
0229 XSIMD_INLINE batch<uint64_t, A> fast_cast(batch<int64_t, A> const& self, batch<uint64_t, A> const&, requires_arch<common>) noexcept
0230 {
0231 return bitwise_cast<uint64_t>(self);
0232 }
0233 template <class A>
0234 XSIMD_INLINE batch<int8_t, A> fast_cast(batch<uint8_t, A> const& self, batch<int8_t, A> const&, requires_arch<common>) noexcept
0235 {
0236 return bitwise_cast<int8_t>(self);
0237 }
0238 template <class A>
0239 XSIMD_INLINE batch<int16_t, A> fast_cast(batch<uint16_t, A> const& self, batch<int16_t, A> const&, requires_arch<common>) noexcept
0240 {
0241 return bitwise_cast<int16_t>(self);
0242 }
0243 template <class A>
0244 XSIMD_INLINE batch<int32_t, A> fast_cast(batch<uint32_t, A> const& self, batch<int32_t, A> const&, requires_arch<common>) noexcept
0245 {
0246 return bitwise_cast<int32_t>(self);
0247 }
0248 template <class A>
0249 XSIMD_INLINE batch<int64_t, A> fast_cast(batch<uint64_t, A> const& self, batch<int64_t, A> const&, requires_arch<common>) noexcept
0250 {
0251 return bitwise_cast<int64_t>(self);
0252 }
0253
0254
0255
0256 template <class A, class = decltype(fast_cast(std::declval<batch<int32_t, A> const&>(), std::declval<batch<float, A> const&>(), A {}))>
0257 XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& v, batch<float, A> const&, requires_arch<common>) noexcept
0258 {
0259
0260 batch<uint32_t, A> msk_lo(0xFFFF);
0261 batch<float, A> cnst65536f(65536.0f);
0262
0263 auto v_lo = batch_cast<int32_t>(v & msk_lo);
0264 auto v_hi = batch_cast<int32_t>(v >> 16);
0265 auto v_lo_flt = batch_cast<float>(v_lo);
0266 auto v_hi_flt = batch_cast<float>(v_hi);
0267 v_hi_flt = cnst65536f * v_hi_flt;
0268 return v_hi_flt + v_lo_flt;
0269 }
0270
0271
0272
0273 template <class A, class = decltype(fast_cast(std::declval<batch<float, A> const&>(), std::declval<batch<int32_t, A> const&>(), A {}))>
0274 XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<float, A> const& v, batch<uint32_t, A> const&, requires_arch<common>) noexcept
0275 {
0276 auto is_large = v >= batch<float, A>(1u << 31);
0277 auto small_v = bitwise_cast<float>(batch_cast<int32_t>(v));
0278 auto large_v = bitwise_cast<float>(
0279 batch_cast<int32_t>(v - batch<float, A>(1u << 31))
0280 ^ batch<int32_t, A>(1u << 31));
0281 return bitwise_cast<uint32_t>(select(is_large, large_v, small_v));
0282 }
0283 }
0284
0285 namespace detail
0286 {
0287
0288
0289
0290
0291 struct with_fast_conversion
0292 {
0293 };
0294 struct with_slow_conversion
0295 {
0296 };
0297
0298 template <class A, class From, class To, class = void>
0299 struct conversion_type_impl
0300 {
0301 using type = with_slow_conversion;
0302 };
0303
0304 using xsimd::detail::void_t;
0305
0306 template <class A, class From, class To>
0307 struct conversion_type_impl<A, From, To,
0308 void_t<decltype(fast_cast(std::declval<const batch<From, A>&>(),
0309 std::declval<const batch<To, A>&>(),
0310 std::declval<const A&>()))>>
0311 {
0312 using type = with_fast_conversion;
0313 };
0314
0315 template <class A, class From, class To>
0316 using conversion_type = typename conversion_type_impl<A, From, To>::type;
0317 }
0318
0319 namespace detail
0320 {
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330 template <class B, uint64_t c>
0331 XSIMD_INLINE B coef() noexcept
0332 {
0333 using value_type = typename B::value_type;
0334 return B(bit_cast<value_type>(as_unsigned_integer_t<value_type>(c)));
0335 }
0336 template <class B>
0337 XSIMD_INLINE B horner(const B&) noexcept
0338 {
0339 return B(typename B::value_type(0.));
0340 }
0341
0342 template <class B, uint64_t c0>
0343 XSIMD_INLINE B horner(const B&) noexcept
0344 {
0345 return coef<B, c0>();
0346 }
0347
0348 template <class B, uint64_t c0, uint64_t c1, uint64_t... args>
0349 XSIMD_INLINE B horner(const B& self) noexcept
0350 {
0351 return fma(self, horner<B, c1, args...>(self), coef<B, c0>());
0352 }
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363 template <class B>
0364 XSIMD_INLINE B horner1(const B&) noexcept
0365 {
0366 return B(1.);
0367 }
0368
0369 template <class B, uint64_t c0>
0370 XSIMD_INLINE B horner1(const B& x) noexcept
0371 {
0372 return x + detail::coef<B, c0>();
0373 }
0374
0375 template <class B, uint64_t c0, uint64_t c1, uint64_t... args>
0376 XSIMD_INLINE B horner1(const B& x) noexcept
0377 {
0378 return fma(x, horner1<B, c1, args...>(x), detail::coef<B, c0>());
0379 }
0380 }
0381
0382 }
0383
0384 }
0385
0386 #endif