File indexing completed on 2026-11-07 10:37:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef XSIMD_AVX512VL_256_HPP
0014 #define XSIMD_AVX512VL_256_HPP
0015
0016 #include "../types/xsimd_avx512vl_register.hpp"
0017 #include "../types/xsimd_batch_constant.hpp"
0018
0019 #include <type_traits>
0020
0021 namespace xsimd
0022 {
0023 namespace kernel
0024 {
0025 using namespace types;
0026
0027 namespace detail
0028 {
0029
0030
0031
0032
0033 XSIMD_INLINE uint32_t morton(uint16_t x, uint16_t y) noexcept;
0034 template <size_t N>
0035 XSIMD_INLINE unsigned char tobitset(unsigned char unpacked[N]);
0036
0037 template <class A, class T, int Cmp>
0038 XSIMD_INLINE batch_bool<T, A> compare_int_avx512vl_256(batch<T, A> const& self, batch<T, A> const& other) noexcept
0039 {
0040 using register_type = typename batch_bool<T, A>::register_type;
0041 if (std::is_signed<T>::value)
0042 {
0043 XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
0044 {
0045
0046 uint64_t mask_low0 = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x000000FF)) << 24,
0047 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x000000FF)) << 24,
0048 Cmp);
0049 uint64_t mask_low1 = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x0000FF00)) << 16,
0050 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x0000FF00)) << 16,
0051 Cmp);
0052 uint64_t mask_high0 = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x00FF0000)) << 8,
0053 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x00FF0000)) << 8,
0054 Cmp);
0055 uint64_t mask_high1 = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0xFF000000)),
0056 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0xFF000000)),
0057 Cmp);
0058 uint64_t mask = 0;
0059 for (unsigned i = 0; i < 8; ++i)
0060 {
0061 mask |= (mask_low0 & (uint64_t(1) << i)) << (3 * i + 0);
0062 mask |= (mask_low1 & (uint64_t(1) << i)) << (3 * i + 1);
0063 mask |= (mask_high0 & (uint64_t(1) << i)) << (3 * i + 2);
0064 mask |= (mask_high1 & (uint64_t(1) << i)) << (3 * i + 3);
0065 }
0066 return (register_type)mask;
0067 }
0068 else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
0069 {
0070
0071 uint16_t mask_low = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0x0000FFFF)) << 16,
0072 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0x0000FFFF)) << 16,
0073 Cmp);
0074 uint16_t mask_high = _mm256_cmp_epi32_mask((batch<int32_t, A>(self.data) & batch<int32_t, A>(0xFFFF0000)),
0075 (batch<int32_t, A>(other.data) & batch<int32_t, A>(0xFFFF0000)),
0076 Cmp);
0077 return static_cast<register_type>(morton(mask_low, mask_high));
0078 }
0079 else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0080 {
0081 return (register_type)_mm256_cmp_epi32_mask(self, other, Cmp);
0082 }
0083 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0084 {
0085 return (register_type)_mm256_cmp_epi64_mask(self, other, Cmp);
0086 }
0087 }
0088 else
0089 {
0090 XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
0091 {
0092 uint64_t mask_low0 = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x000000FF)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x000000FF)), Cmp);
0093 uint64_t mask_low1 = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x0000FF00)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x0000FF00)), Cmp);
0094 uint64_t mask_high0 = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x00FF0000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x00FF0000)), Cmp);
0095 uint64_t mask_high1 = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0xFF000000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0xFF000000)), Cmp);
0096 uint64_t mask = 0;
0097 for (unsigned i = 0; i < 8; ++i)
0098 {
0099 mask |= (mask_low0 & (uint64_t(1) << i)) << (3 * i + 0);
0100 mask |= (mask_low1 & (uint64_t(1) << i)) << (3 * i + 1);
0101 mask |= (mask_high0 & (uint64_t(1) << i)) << (3 * i + 2);
0102 mask |= (mask_high1 & (uint64_t(1) << i)) << (3 * i + 3);
0103 }
0104 return (register_type)mask;
0105 }
0106 else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
0107 {
0108 uint16_t mask_low = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0x0000FFFF)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0x0000FFFF)), Cmp);
0109 uint16_t mask_high = _mm256_cmp_epu32_mask((batch<uint32_t, A>(self.data) & batch<uint32_t, A>(0xFFFF0000)), (batch<uint32_t, A>(other.data) & batch<uint32_t, A>(0xFFFF0000)), Cmp);
0110 return static_cast<register_type>(morton(mask_low, mask_high));
0111 }
0112 else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0113 {
0114 return (register_type)_mm256_cmp_epu32_mask(self, other, Cmp);
0115 }
0116 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0117 {
0118 return (register_type)_mm256_cmp_epu64_mask(self, other, Cmp);
0119 }
0120 }
0121 }
0122 }
0123
0124
0125 template <class A, class T>
0126 XSIMD_INLINE batch_bool<T, A> load_unaligned(bool const* mem, batch_bool<T, A>, requires_arch<avx512vl_256>) noexcept
0127 {
0128 using register_type = typename batch_bool<T, A>::register_type;
0129 constexpr auto size = batch_bool<T, A>::size;
0130 constexpr auto chunk_size = size >= 8 ? 8 : 4;
0131 constexpr auto iter = size / chunk_size;
0132 static_assert((size % chunk_size) == 0, "incorrect size of bool batch");
0133 register_type mask = 0;
0134 for (std::size_t i = 0; i < iter; ++i)
0135 {
0136 unsigned char block = detail::tobitset<chunk_size>((unsigned char*)mem + i * chunk_size);
0137 mask |= (register_type(block) << (i * chunk_size));
0138 }
0139 return mask;
0140 }
0141
0142
0143 template <class A, class T>
0144 XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0145 {
0146 return select(self, batch<T, A>(1), batch<T, A>(0));
0147 }
0148
0149
0150 template <class T, class A>
0151 XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<avx512vl_256>) noexcept
0152 {
0153 assert(mask == (mask & ((uint64_t(1) << batch_bool<T, A>::size) - 1)) && "inbound mask");
0154 return static_cast<typename batch_bool<T, A>::register_type>(mask & ((uint64_t(1) << batch_bool<T, A>::size) - 1));
0155 }
0156
0157
0158 template <class A, class T>
0159 XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0160 {
0161 return self.data & ((uint64_t(1) << batch_bool<T, A>::size) - 1);
0162 }
0163
0164
0165 template <class A, class T_out, class T_in>
0166 XSIMD_INLINE batch_bool<T_out, A> batch_bool_cast(batch_bool<T_in, A> const& self, batch_bool<T_out, A> const&, requires_arch<avx512vl_256>) noexcept
0167 {
0168 return self.data;
0169 }
0170
0171
0172 template <class A, class T, class... Values>
0173 XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx512vl_256>, Values... values) noexcept
0174 {
0175 static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
0176 using register_type = typename batch_bool<T, A>::register_type;
0177 register_type r = 0;
0178 unsigned shift = 0;
0179 (void)std::initializer_list<register_type> { (r |= register_type(values ? 1 : 0) << (shift++))... };
0180 return r;
0181 }
0182
0183
0184 template <class T, class A>
0185 XSIMD_INLINE void store(batch_bool<T, A> const& self, bool* mem, requires_arch<avx512vl_256>) noexcept
0186 {
0187 constexpr auto size = batch_bool<T, A>::size;
0188 for (std::size_t i = 0; i < size; ++i)
0189 mem[i] = (self.data >> i) & 0x1;
0190 }
0191
0192
0193 template <class A>
0194 XSIMD_INLINE batch<int64_t, A> abs(batch<int64_t, A> const& self, requires_arch<avx512vl_256>) noexcept
0195 {
0196 return _mm256_abs_epi64(self);
0197 }
0198
0199
0200
0201
0202
0203
0204
0205 namespace detail
0206 {
0207
0208
0209
0210 template <class T, class Mode, enable_sized_integral_t<T, 4> = 0>
0211 XSIMD_INLINE __m256i maskload256(T const* mem, uint64_t m, Mode) noexcept
0212 {
0213 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0214 {
0215 return _mm256_maskz_load_epi32((__mmask8)m, mem);
0216 }
0217 else
0218 {
0219 return _mm256_maskz_loadu_epi32((__mmask8)m, mem);
0220 }
0221 }
0222 template <class T, class Mode, enable_sized_integral_t<T, 8> = 0>
0223 XSIMD_INLINE __m256i maskload256(T const* mem, uint64_t m, Mode) noexcept
0224 {
0225 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0226 {
0227 return _mm256_maskz_load_epi64((__mmask8)m, mem);
0228 }
0229 else
0230 {
0231 return _mm256_maskz_loadu_epi64((__mmask8)m, mem);
0232 }
0233 }
0234 template <class Mode>
0235 XSIMD_INLINE __m256 maskload256(float const* mem, uint64_t m, Mode) noexcept
0236 {
0237 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0238 {
0239 return _mm256_maskz_load_ps((__mmask8)m, mem);
0240 }
0241 else
0242 {
0243 return _mm256_maskz_loadu_ps((__mmask8)m, mem);
0244 }
0245 }
0246 template <class Mode>
0247 XSIMD_INLINE __m256d maskload256(double const* mem, uint64_t m, Mode) noexcept
0248 {
0249 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0250 {
0251 return _mm256_maskz_load_pd((__mmask8)m, mem);
0252 }
0253 else
0254 {
0255 return _mm256_maskz_loadu_pd((__mmask8)m, mem);
0256 }
0257 }
0258
0259 template <class T, class Mode, enable_sized_integral_t<T, 4> = 0>
0260 XSIMD_INLINE void maskstore256(T* mem, __m256i src, uint64_t m, Mode) noexcept
0261 {
0262 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0263 {
0264 _mm256_mask_store_epi32(mem, (__mmask8)m, src);
0265 }
0266 else
0267 {
0268 _mm256_mask_storeu_epi32(mem, (__mmask8)m, src);
0269 }
0270 }
0271 template <class T, class Mode, enable_sized_integral_t<T, 8> = 0>
0272 XSIMD_INLINE void maskstore256(T* mem, __m256i src, uint64_t m, Mode) noexcept
0273 {
0274 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0275 {
0276 _mm256_mask_store_epi64(mem, (__mmask8)m, src);
0277 }
0278 else
0279 {
0280 _mm256_mask_storeu_epi64(mem, (__mmask8)m, src);
0281 }
0282 }
0283 template <class Mode>
0284 XSIMD_INLINE void maskstore256(float* mem, __m256 src, uint64_t m, Mode) noexcept
0285 {
0286 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0287 {
0288 _mm256_mask_store_ps(mem, (__mmask8)m, src);
0289 }
0290 else
0291 {
0292 _mm256_mask_storeu_ps(mem, (__mmask8)m, src);
0293 }
0294 }
0295 template <class Mode>
0296 XSIMD_INLINE void maskstore256(double* mem, __m256d src, uint64_t m, Mode) noexcept
0297 {
0298 XSIMD_IF_CONSTEXPR(std::is_same<Mode, aligned_mode>::value)
0299 {
0300 _mm256_mask_store_pd(mem, (__mmask8)m, src);
0301 }
0302 else
0303 {
0304 _mm256_mask_storeu_pd(mem, (__mmask8)m, src);
0305 }
0306 }
0307 }
0308
0309
0310
0311 template <class A, class T, bool... V, class Mode,
0312 typename = std::enable_if_t<std::is_arithmetic<T>::value && (sizeof(T) == 4 || sizeof(T) == 8)>>
0313 XSIMD_INLINE batch<T, A> load_masked(T const* mem, batch_bool_constant<T, A, V...> mask, convert<T>, Mode, requires_arch<avx512vl_256>) noexcept
0314 {
0315
0316 XSIMD_IF_CONSTEXPR(mask.all())
0317 {
0318 return batch<T, A>::load(mem, Mode {});
0319 }
0320 else XSIMD_IF_CONSTEXPR(detail::lowers_to_plain_moves(mask))
0321 {
0322 return detail::plain_move_load<avx>(mem, mask, convert<T> {}, Mode {});
0323 }
0324 else
0325 {
0326 return detail::maskload256(mem, mask.mask(), Mode {});
0327 }
0328 }
0329
0330 template <class A, class T, class Mode,
0331 typename = std::enable_if_t<std::is_arithmetic<T>::value && (sizeof(T) == 4 || sizeof(T) == 8)>>
0332 XSIMD_INLINE batch<T, A> load_masked(T const* mem, batch_bool<T, A> mask, convert<T>, Mode, requires_arch<avx512vl_256>) noexcept
0333 {
0334 return detail::maskload256(mem, mask.mask(), Mode {});
0335 }
0336
0337 template <class A, class T, bool... V, class Mode,
0338 typename = std::enable_if_t<std::is_arithmetic<T>::value && (sizeof(T) == 4 || sizeof(T) == 8)>>
0339 XSIMD_INLINE void store_masked(T* mem, batch<T, A> const& src, batch_bool_constant<T, A, V...> mask, Mode, requires_arch<avx512vl_256>) noexcept
0340 {
0341 XSIMD_IF_CONSTEXPR(mask.all())
0342 {
0343 src.store(mem, Mode {});
0344 }
0345 else XSIMD_IF_CONSTEXPR(detail::lowers_to_plain_moves(mask))
0346 {
0347 detail::plain_move_store<avx2>(mem, src, mask, Mode {});
0348 }
0349 else
0350 {
0351 detail::maskstore256(mem, src, mask.mask(), Mode {});
0352 }
0353 }
0354
0355 template <class A, class T, class Mode,
0356 typename = std::enable_if_t<std::is_arithmetic<T>::value && (sizeof(T) == 4 || sizeof(T) == 8)>>
0357 XSIMD_INLINE void store_masked(T* mem, batch<T, A> const& src, batch_bool<T, A> mask, Mode, requires_arch<avx512vl_256>) noexcept
0358 {
0359 detail::maskstore256(mem, src, mask.mask(), Mode {});
0360 }
0361
0362
0363 template <class T, class A, class U, detail::enable_sized_integral_t<T, 4> = 0, detail::enable_sized_integral_t<U, 4> = 0>
0364 XSIMD_INLINE batch<T, A> gather(batch<T, A> const&, T const* src, batch<U, A> const& index,
0365 kernel::requires_arch<avx512vl_256>) noexcept
0366 {
0367 return _mm256_mmask_i32gather_epi32(_mm256_setzero_si256(), (__mmask8)0xFF, index, static_cast<const void*>(src), sizeof(T));
0368 }
0369
0370 template <class T, class A, class U, detail::enable_sized_integral_t<T, 8> = 0, detail::enable_sized_integral_t<U, 8> = 0>
0371 XSIMD_INLINE batch<T, A> gather(batch<T, A> const&, T const* src, batch<U, A> const& index,
0372 kernel::requires_arch<avx512vl_256>) noexcept
0373 {
0374 return _mm256_mmask_i64gather_epi64(_mm256_setzero_si256(), (__mmask8)0xF, index, static_cast<const void*>(src), sizeof(T));
0375 }
0376
0377 template <class A, class U, detail::enable_sized_integral_t<U, 4> = 0>
0378 XSIMD_INLINE batch<float, A> gather(batch<float, A> const&, float const* src,
0379 batch<U, A> const& index,
0380 kernel::requires_arch<avx512vl_256>) noexcept
0381 {
0382 return _mm256_mmask_i32gather_ps(_mm256_setzero_ps(), (__mmask8)0xFF, index, src, sizeof(float));
0383 }
0384
0385 template <class A, class U, detail::enable_sized_integral_t<U, 8> = 0>
0386 XSIMD_INLINE batch<double, A> gather(batch<double, A> const&, double const* src,
0387 batch<U, A> const& index,
0388 requires_arch<avx512vl_256>) noexcept
0389 {
0390 return _mm256_mmask_i64gather_pd(_mm256_setzero_pd(), (__mmask8)0xF, index, src, sizeof(double));
0391 }
0392
0393
0394 template <class A, class T,
0395 class = std::enable_if_t<std::is_same<uint32_t, T>::value || std::is_same<int32_t, T>::value>>
0396 XSIMD_INLINE void scatter(batch<T, A> const& src, T* dst,
0397 batch<int32_t, A> const& index,
0398 kernel::requires_arch<avx512vl_256>) noexcept
0399 {
0400 _mm256_i32scatter_epi32(dst, index, src, sizeof(T));
0401 }
0402
0403 template <class A, class T,
0404 class = std::enable_if_t<std::is_same<uint64_t, T>::value || std::is_same<int64_t, T>::value>>
0405 XSIMD_INLINE void scatter(batch<T, A> const& src, T* dst,
0406 batch<int64_t, A> const& index,
0407 kernel::requires_arch<avx512vl_256>) noexcept
0408 {
0409 _mm256_i64scatter_epi64(dst, index, src, sizeof(T));
0410 }
0411
0412 template <class A>
0413 XSIMD_INLINE void scatter(batch<float, A> const& src, float* dst,
0414 batch<int32_t, A> const& index,
0415 kernel::requires_arch<avx512vl_256>) noexcept
0416 {
0417 _mm256_i32scatter_ps(dst, index, src, sizeof(float));
0418 }
0419
0420 template <class A>
0421 XSIMD_INLINE void scatter(batch<double, A> const& src, double* dst,
0422 batch<int64_t, A> const& index,
0423 kernel::requires_arch<avx512vl_256>) noexcept
0424 {
0425 _mm256_i64scatter_pd(dst, index, src, sizeof(double));
0426 }
0427
0428
0429 template <class A>
0430 XSIMD_INLINE batch<int64_t, A> max(batch<int64_t, A> const& self, batch<int64_t, A> const& other, requires_arch<avx512vl_256>) noexcept
0431 {
0432 return _mm256_max_epi64(self, other);
0433 }
0434 template <class A>
0435 XSIMD_INLINE batch<uint64_t, A> max(batch<uint64_t, A> const& self, batch<uint64_t, A> const& other, requires_arch<avx512vl_256>) noexcept
0436 {
0437 return _mm256_max_epu64(self, other);
0438 }
0439
0440
0441 template <class A>
0442 XSIMD_INLINE batch<int64_t, A> min(batch<int64_t, A> const& self, batch<int64_t, A> const& other, requires_arch<avx512vl_256>) noexcept
0443 {
0444 return _mm256_min_epi64(self, other);
0445 }
0446 template <class A>
0447 XSIMD_INLINE batch<uint64_t, A> min(batch<uint64_t, A> const& self, batch<uint64_t, A> const& other, requires_arch<avx512vl_256>) noexcept
0448 {
0449 return _mm256_min_epu64(self, other);
0450 }
0451
0452
0453 template <class A>
0454 XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512vl_256>) noexcept
0455 {
0456 return _mm256_permutexvar_ps(mask, self);
0457 }
0458
0459 template <class A>
0460 XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512vl_256>) noexcept
0461 {
0462 return _mm256_permutexvar_pd(mask, self);
0463 }
0464
0465 template <class A>
0466 XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512vl_256>) noexcept
0467 {
0468 return _mm256_permutexvar_epi64(mask, self);
0469 }
0470
0471 template <class A>
0472 XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch<uint64_t, A> mask, requires_arch<avx512vl_256>) noexcept
0473 {
0474 return bitwise_cast<int64_t>(swizzle(bitwise_cast<uint64_t>(self), mask, avx512vl_256 {}));
0475 }
0476
0477 template <class A>
0478 XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512vl_256>) noexcept
0479 {
0480 return _mm256_permutexvar_epi32(mask, self);
0481 }
0482
0483 template <class A>
0484 XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch<uint32_t, A> mask, requires_arch<avx512vl_256>) noexcept
0485 {
0486 return bitwise_cast<int32_t>(swizzle(bitwise_cast<uint32_t>(self), mask, avx512vl_256 {}));
0487 }
0488 template <class A>
0489 XSIMD_INLINE batch<uint8_t, A> swizzle(batch<uint8_t, A> const& self, batch<uint8_t, A> mask, requires_arch<avx512vl_256>) noexcept
0490 {
0491 return swizzle(batch<uint8_t, avx2> { self.data }, batch<uint8_t, avx2> { mask.data }, avx2 {}).data;
0492 }
0493
0494
0495
0496
0497 template <class A>
0498 XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self, batch<uint16_t, A> mask, requires_arch<avx512vl_256>) noexcept
0499 {
0500 return swizzle(batch<uint16_t, avx2> { self.data }, batch<uint16_t, avx2> { mask.data }, avx2 {}).data;
0501 }
0502 template <class A, typename T, detail::enable_sized_t<T, 1> = 0>
0503 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch<uint8_t, A> const& mask, requires_arch<avx512vl_256> req) noexcept
0504 {
0505 return bitwise_cast<T>(swizzle(bitwise_cast<uint8_t>(self), mask, req));
0506 }
0507 template <class A, typename T, detail::enable_sized_t<T, 2> = 0>
0508 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch<uint16_t, A> const& mask, requires_arch<avx512vl_256> req) noexcept
0509 {
0510 return bitwise_cast<T>(swizzle(bitwise_cast<uint16_t>(self), mask, req));
0511 }
0512
0513
0514 template <class A, uint8_t... Vals, typename T, detail::enable_sized_t<T, 1> = 0>
0515 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<uint8_t, A, Vals...> const& mask, requires_arch<avx512vl_256>) noexcept
0516 {
0517 return swizzle(self, mask, fma3<avx2> {});
0518 }
0519 template <class A, uint16_t... Vals, typename T, detail::enable_sized_t<T, 2> = 0>
0520 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<uint16_t, A, Vals...> const& mask, requires_arch<avx512vl_256>) noexcept
0521 {
0522 return swizzle(self, mask, fma3<avx2> {});
0523 }
0524 template <class A, uint32_t... Vals, typename T, detail::enable_sized_t<T, 4> = 0>
0525 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<uint32_t, A, Vals...> const& mask, requires_arch<avx512vl_256>) noexcept
0526 {
0527 return swizzle(self, mask, fma3<avx2> {});
0528 }
0529
0530 template <class A, uint64_t V0, uint64_t V1, uint64_t V2, uint64_t V3>
0531 XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch_constant<uint64_t, A, V0, V1, V2, V3>, requires_arch<avx512vl_256>) noexcept
0532 {
0533 constexpr auto mask = detail::mod_shuffle(V0, V1, V2, V3);
0534 return _mm256_permutex_pd(self, mask);
0535 }
0536 template <class A, typename T, uint64_t V0, uint64_t V1, uint64_t V2, uint64_t V3, detail::enable_sized_t<T, 8> = 0>
0537 XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch_constant<uint64_t, A, V0, V1, V2, V3>, requires_arch<avx512vl_256>) noexcept
0538 {
0539 constexpr auto mask = detail::mod_shuffle(V0, V1, V2, V3);
0540 return _mm256_permutex_epi64(self, mask);
0541 }
0542
0543
0544 template <class A, size_t I>
0545 XSIMD_INLINE batch<float, A> insert(batch<float, A> const& self, float val, index<I>, requires_arch<avx512vl_256>) noexcept
0546 {
0547
0548 int32_t tmp = bit_cast<int32_t>(val);
0549 return _mm256_castsi256_ps(_mm256_mask_set1_epi32(_mm256_castps_si256(self), __mmask8(1 << (I & 7)), tmp));
0550 }
0551
0552 template <class A, size_t I>
0553 XSIMD_INLINE batch<double, A> insert(batch<double, A> const& self, double val, index<I>, requires_arch<avx512vl_256>) noexcept
0554 {
0555 int64_t tmp = bit_cast<int64_t>(val);
0556 return _mm256_castsi256_pd(_mm256_mask_set1_epi64(_mm256_castpd_si256(self), __mmask8(1 << (I & 3)), tmp));
0557 }
0558
0559 template <class A, class T, size_t I, class = std::enable_if_t<std::is_integral<T>::value>>
0560 XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I> pos, requires_arch<avx512vl_256>) noexcept
0561 {
0562 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0563 {
0564 return _mm256_mask_set1_epi32(self, __mmask8(1 << (I & 7)), val);
0565 }
0566 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0567 {
0568 return _mm256_mask_set1_epi64(self, __mmask8(1 << (I & 3)), val);
0569 }
0570 else
0571 {
0572 return insert(self, val, pos, common {});
0573 }
0574 }
0575
0576
0577 template <class A>
0578 XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<avx512vl_256>) noexcept
0579 {
0580 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, self, _CMP_UNORD_Q);
0581 }
0582 template <class A>
0583 XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<avx512vl_256>) noexcept
0584 {
0585 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, self, _CMP_UNORD_Q);
0586 }
0587
0588
0589
0590
0591 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0592 XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<avx512vl_256>) noexcept
0593 {
0594 XSIMD_IF_CONSTEXPR(std::is_signed<T>::value && sizeof(T) == 8)
0595 {
0596 return _mm256_srai_epi64(self, other);
0597 }
0598 else
0599 {
0600 return bitwise_rshift(self, other, avx2 {});
0601 }
0602 }
0603 template <size_t shift, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0604 XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0605 {
0606 constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
0607 static_assert(shift < bits, "Shift amount must be less than the number of bits in T");
0608 XSIMD_IF_CONSTEXPR(std::is_signed<T>::value && sizeof(T) == 8)
0609 {
0610 return _mm256_srai_epi64(self, shift);
0611 }
0612 else
0613 {
0614 return bitwise_rshift<shift>(self, avx2 {});
0615 }
0616 }
0617 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0618 XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0619 {
0620 XSIMD_IF_CONSTEXPR(std::is_signed<T>::value && sizeof(T) == 8)
0621 {
0622 return _mm256_srav_epi64(self, other);
0623 }
0624 else
0625 {
0626 return bitwise_rshift(self, other, avx2 {});
0627 }
0628 }
0629
0630
0631 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0632 XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0633 {
0634 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0635 {
0636 return _mm256_rolv_epi32(self, other);
0637 }
0638 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0639 {
0640 return _mm256_rolv_epi64(self, other);
0641 }
0642 else
0643 {
0644 return rotl(self, other, avx2 {});
0645 }
0646 }
0647 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0648 XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, int32_t other, requires_arch<avx512vl_256>) noexcept
0649 {
0650 return rotl(self, batch<T, A>(other), A {});
0651 }
0652 template <size_t count, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0653 XSIMD_INLINE batch<T, A> rotl(batch<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0654 {
0655 constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
0656 static_assert(count < bits, "Count must be less than the number of bits in T");
0657 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0658 {
0659 return _mm256_rol_epi32(self, count);
0660 }
0661 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0662 {
0663 return _mm256_rol_epi64(self, count);
0664 }
0665 else
0666 {
0667 return rotl<count>(self, avx2 {});
0668 }
0669 }
0670
0671
0672 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0673 XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0674 {
0675 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0676 {
0677 return _mm256_rorv_epi32(self, other);
0678 }
0679 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0680 {
0681 return _mm256_rorv_epi64(self, other);
0682 }
0683 else
0684 {
0685 return rotr(self, other, avx2 {});
0686 }
0687 }
0688 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0689 XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, int32_t other, requires_arch<avx512vl_256>) noexcept
0690 {
0691 return rotr(self, batch<T, A>(other), A {});
0692 }
0693
0694 template <size_t count, class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0695 XSIMD_INLINE batch<T, A> rotr(batch<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0696 {
0697 constexpr auto bits = std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed;
0698 static_assert(count < bits, "Count must be less than the number of bits in T");
0699 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0700 {
0701 return _mm256_ror_epi32(self, count);
0702 }
0703 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0704 {
0705 return _mm256_ror_epi64(self, count);
0706 }
0707 else
0708 {
0709 return rotr<count>(self, avx2 {});
0710 }
0711 }
0712
0713
0714
0715 template <class A>
0716 XSIMD_INLINE batch<float, A> compress(batch<float, A> const& self, batch_bool<float, A> const& mask, requires_arch<avx512vl_256>) noexcept
0717 {
0718 return _mm256_maskz_compress_ps(mask.mask(), self);
0719 }
0720 template <class A>
0721 XSIMD_INLINE batch<double, A> compress(batch<double, A> const& self, batch_bool<double, A> const& mask, requires_arch<avx512vl_256>) noexcept
0722 {
0723 return _mm256_maskz_compress_pd(mask.mask(), self);
0724 }
0725 template <class A>
0726 XSIMD_INLINE batch<int32_t, A> compress(batch<int32_t, A> const& self, batch_bool<int32_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0727 {
0728 return _mm256_maskz_compress_epi32(mask.mask(), self);
0729 }
0730 template <class A>
0731 XSIMD_INLINE batch<uint32_t, A> compress(batch<uint32_t, A> const& self, batch_bool<uint32_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0732 {
0733 return _mm256_maskz_compress_epi32(mask.mask(), self);
0734 }
0735 template <class A>
0736 XSIMD_INLINE batch<int64_t, A> compress(batch<int64_t, A> const& self, batch_bool<int64_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0737 {
0738 return _mm256_maskz_compress_epi64(mask.mask(), self);
0739 }
0740 template <class A>
0741 XSIMD_INLINE batch<uint64_t, A> compress(batch<uint64_t, A> const& self, batch_bool<uint64_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0742 {
0743 return _mm256_maskz_compress_epi64(mask.mask(), self);
0744 }
0745
0746
0747 template <class A>
0748 XSIMD_INLINE batch<float, A> expand(batch<float, A> const& self, batch_bool<float, A> const& mask, requires_arch<avx512vl_256>) noexcept
0749 {
0750 return _mm256_maskz_expand_ps(mask.mask(), self);
0751 }
0752 template <class A>
0753 XSIMD_INLINE batch<double, A> expand(batch<double, A> const& self, batch_bool<double, A> const& mask, requires_arch<avx512vl_256>) noexcept
0754 {
0755 return _mm256_maskz_expand_pd(mask.mask(), self);
0756 }
0757 template <class A>
0758 XSIMD_INLINE batch<int32_t, A> expand(batch<int32_t, A> const& self, batch_bool<int32_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0759 {
0760 return _mm256_maskz_expand_epi32(mask.mask(), self);
0761 }
0762 template <class A>
0763 XSIMD_INLINE batch<uint32_t, A> expand(batch<uint32_t, A> const& self, batch_bool<uint32_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0764 {
0765 return _mm256_maskz_expand_epi32(mask.mask(), self);
0766 }
0767 template <class A>
0768 XSIMD_INLINE batch<int64_t, A> expand(batch<int64_t, A> const& self, batch_bool<int64_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0769 {
0770 return _mm256_maskz_expand_epi64(mask.mask(), self);
0771 }
0772 template <class A>
0773 XSIMD_INLINE batch<uint64_t, A> expand(batch<uint64_t, A> const& self, batch_bool<uint64_t, A> const& mask, requires_arch<avx512vl_256>) noexcept
0774 {
0775 return _mm256_maskz_expand_epi64(mask.mask(), self);
0776 }
0777
0778
0779 template <class A, class T>
0780 XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0781 {
0782 using register_type = typename batch_bool<T, A>::register_type;
0783 constexpr register_type bitmask = (register_type(1) << batch_bool<T, A>::size) - 1;
0784 return (self.data & bitmask) == bitmask;
0785 }
0786
0787
0788 template <class A, class T>
0789 XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<avx512vl_256>) noexcept
0790 {
0791 using register_type = typename batch_bool<T, A>::register_type;
0792 constexpr register_type bitmask = (register_type(1) << batch_bool<T, A>::size) - 1;
0793 return (self.data & bitmask) != 0;
0794 }
0795
0796
0797 template <class A>
0798 XSIMD_INLINE batch_bool<float, A> eq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0799 {
0800 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_EQ_OQ);
0801 }
0802 template <class A>
0803 XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0804 {
0805 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_EQ_OQ);
0806 }
0807
0808 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0809 XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0810 {
0811 return detail::compare_int_avx512vl_256<A, T, _MM_CMPINT_EQ>(self, other);
0812 }
0813 template <class A, class T>
0814 XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0815 {
0816 using register_type = typename batch_bool<T, A>::register_type;
0817 return register_type(~self.data ^ other.data);
0818 }
0819
0820
0821 template <class A>
0822 XSIMD_INLINE batch_bool<float, A> neq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0823 {
0824 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_NEQ_UQ);
0825 }
0826 template <class A>
0827 XSIMD_INLINE batch_bool<double, A> neq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0828 {
0829 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_NEQ_UQ);
0830 }
0831
0832 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0833 XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0834 {
0835 return (~(self == other));
0836 }
0837 template <class A, class T>
0838 XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0839 {
0840 using register_type = typename batch_bool<T, A>::register_type;
0841 return register_type(self.data ^ other.data);
0842 }
0843
0844
0845 template <class A>
0846 XSIMD_INLINE batch_bool<float, A> gt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0847 {
0848 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_GT_OQ);
0849 }
0850 template <class A>
0851 XSIMD_INLINE batch_bool<double, A> gt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0852 {
0853 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_GT_OQ);
0854 }
0855 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0856 XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0857 {
0858 return detail::compare_int_avx512vl_256<A, T, _MM_CMPINT_GT>(self, other);
0859 }
0860
0861
0862 template <class A>
0863 XSIMD_INLINE batch_bool<float, A> ge(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0864 {
0865 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_GE_OQ);
0866 }
0867 template <class A>
0868 XSIMD_INLINE batch_bool<double, A> ge(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0869 {
0870 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_GE_OQ);
0871 }
0872
0873 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0874 XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0875 {
0876 return detail::compare_int_avx512vl_256<A, T, _MM_CMPINT_GE>(self, other);
0877 }
0878
0879
0880 template <class A>
0881 XSIMD_INLINE batch_bool<float, A> lt(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0882 {
0883 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_LT_OQ);
0884 }
0885 template <class A>
0886 XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0887 {
0888 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_LT_OQ);
0889 }
0890
0891 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0892 XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0893 {
0894 return detail::compare_int_avx512vl_256<A, T, _MM_CMPINT_LT>(self, other);
0895 }
0896
0897
0898 template <class A>
0899 XSIMD_INLINE batch_bool<float, A> le(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512vl_256>) noexcept
0900 {
0901 return (typename batch_bool<float, A>::register_type)_mm256_cmp_ps_mask(self, other, _CMP_LE_OQ);
0902 }
0903 template <class A>
0904 XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512vl_256>) noexcept
0905 {
0906 return (typename batch_bool<double, A>::register_type)_mm256_cmp_pd_mask(self, other, _CMP_LE_OQ);
0907 }
0908
0909 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0910 XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0911 {
0912 return detail::compare_int_avx512vl_256<A, T, _MM_CMPINT_LE>(self, other);
0913 }
0914
0915
0916 template <class A>
0917 XSIMD_INLINE batch<float, A> select(batch_bool<float, A> const& cond, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<avx512vl_256>) noexcept
0918 {
0919 return _mm256_mask_blend_ps(cond, false_br, true_br);
0920 }
0921 template <class A>
0922 XSIMD_INLINE batch<double, A> select(batch_bool<double, A> const& cond, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<avx512vl_256>) noexcept
0923 {
0924 return _mm256_mask_blend_pd(cond, false_br, true_br);
0925 }
0926 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0927 XSIMD_INLINE batch<T, A> select(batch_bool<T, A> const& cond, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<avx512vl_256>) noexcept
0928 {
0929 XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
0930 {
0931 batch_bool<T, avx2> batch_cond = batch_bool<T, avx2>::from_mask(cond.mask());
0932 return _mm256_blendv_epi8(false_br, true_br, batch_cond);
0933 }
0934 else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
0935 {
0936 batch_bool<T, avx2> batch_cond = batch_bool<T, avx2>::from_mask(cond.mask());
0937 return _mm256_blendv_epi8(false_br, true_br, batch_cond);
0938 }
0939 else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0940 {
0941 return _mm256_mask_blend_epi32(cond, false_br, true_br);
0942 }
0943 else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
0944 {
0945 return _mm256_mask_blend_epi64(cond, false_br, true_br);
0946 }
0947 }
0948 template <class A, class T, bool... Values>
0949 XSIMD_INLINE batch<T, A> select(batch_bool_constant<T, A, Values...> const&, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<avx512vl_256>) noexcept
0950 {
0951 return select(batch_bool<T, A> { Values... }, true_br, false_br, avx512vl_256 {});
0952 }
0953
0954
0955
0956
0957
0958
0959 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0960 XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx512vl_256>) noexcept
0961 {
0962 return decr_if(self, mask, common {});
0963 }
0964 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0965 XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<avx512vl_256>) noexcept
0966 {
0967 return incr_if(self, mask, common {});
0968 }
0969
0970
0971 template <class A>
0972 XSIMD_INLINE batch<float, A>
0973 reciprocal(batch<float, A> const& self,
0974 kernel::requires_arch<avx512vl_256>) noexcept
0975 {
0976 return _mm256_rcp14_ps(self);
0977 }
0978
0979 template <class A>
0980 XSIMD_INLINE batch<double, A>
0981 reciprocal(batch<double, A> const& self,
0982 kernel::requires_arch<avx512vl_256>) noexcept
0983 {
0984 return _mm256_rcp14_pd(self);
0985 }
0986
0987
0988 template <class A, class T>
0989 XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0990 {
0991 using register_type = typename batch_bool<T, A>::register_type;
0992 return register_type(self.data & other.data);
0993 }
0994
0995
0996 template <class A, class T>
0997 XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
0998 {
0999 using register_type = typename batch_bool<T, A>::register_type;
1000 return register_type(self.data & ~other.data);
1001 }
1002
1003
1004 template <class A, class T>
1005 XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<avx512vl_256>) noexcept
1006 {
1007 using register_type = typename batch_bool<T, A>::register_type;
1008 return register_type(~self.data);
1009 }
1010
1011
1012 template <class A, class T>
1013 XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
1014 {
1015 using register_type = typename batch_bool<T, A>::register_type;
1016 return register_type(self.data | other.data);
1017 }
1018
1019
1020 template <class A, class T>
1021 XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<avx512vl_256>) noexcept
1022 {
1023 using register_type = typename batch_bool<T, A>::register_type;
1024 return register_type(self.data ^ other.data);
1025 }
1026
1027
1028 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
1029 XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512vl_256>) noexcept
1030 {
1031 if (std::is_signed<T>::value)
1032 {
1033 auto mask = other < 0;
1034 auto self_pos_branch = min(std::numeric_limits<T>::max() - other, self);
1035 auto self_neg_branch = max(std::numeric_limits<T>::min() - other, self);
1036 return other + select(mask, self_neg_branch, self_pos_branch);
1037 }
1038 else
1039 {
1040 const auto diffmax = std::numeric_limits<T>::max() - self;
1041 const auto mindiff = min(diffmax, other);
1042 return self + mindiff;
1043 }
1044 }
1045
1046 }
1047 }
1048
1049 #endif