File indexing completed on 2026-11-07 10:37:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef XSIMD_VXE_HPP
0015 #define XSIMD_VXE_HPP
0016
0017 #include "../types/xsimd_vxe_register.hpp"
0018
0019 #include <type_traits>
0020
0021 namespace xsimd
0022 {
0023 namespace kernel
0024 {
0025 using namespace types;
0026 using v1ti = __int128 __attribute__((vector_size(16)));
0027 using v4sf = float __attribute__((vector_size(16)));
0028 using v2df = double __attribute__((vector_size(16)));
0029 using uv2di = unsigned long long int __attribute__((vector_size(16)));
0030 using v2di = long long int __attribute__((vector_size(16)));
0031 using uv4si = unsigned int __attribute__((vector_size(16)));
0032 using v4si = int __attribute__((vector_size(16)));
0033 using uv8hi = unsigned short int __attribute__((vector_size(16)));
0034 using v8hi = short int __attribute__((vector_size(16)));
0035 using uv16qi = unsigned char __attribute__((vector_size(16)));
0036 using v16qi = signed char __attribute__((vector_size(16)));
0037
0038
0039
0040
0041
0042 template <typename T>
0043 struct builtin_scalar
0044 {
0045 using type = T;
0046 };
0047
0048 template <>
0049 struct builtin_scalar<unsigned long>
0050 {
0051 using type = unsigned long long;
0052 };
0053
0054 template <>
0055 struct builtin_scalar<long>
0056 {
0057 using type = long long;
0058 };
0059
0060 template <>
0061 struct builtin_scalar<char>
0062 {
0063 using type = typename std::conditional<std::is_signed<char>::value, signed char, unsigned char>::type;
0064 };
0065
0066 template <typename T>
0067 using builtin_t = typename builtin_scalar<T>::type;
0068
0069
0070 template <class A, class T_in, class T_out>
0071 XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& self, batch<T_out, A> const&, requires_arch<vxe>) noexcept
0072 {
0073 return (typename batch<T_out, A>::register_type)(self.data);
0074 }
0075
0076
0077 template <class A, class T_out, class T_in>
0078 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<vxe>) noexcept
0079 {
0080 return (typename batch_bool<T_out, A>::register_type)self.data;
0081 }
0082
0083
0084
0085
0086 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0087 XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<vxe>) noexcept
0088 {
0089 return (typename batch<T, A>::register_type)vec_xl(0, (builtin_t<T>*)mem);
0090 }
0091
0092
0093 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0094 XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<vxe>) noexcept
0095 {
0096 return load_unaligned<A>(mem, kernel::convert<T> {}, vxe {});
0097 }
0098
0099
0100 namespace detail
0101 {
0102 template <class A>
0103 XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<vxe>) noexcept
0104 {
0105
0106
0107
0108 using v4sf = float __attribute__((vector_size(16)));
0109 uv16qi perm_real = (uv16qi) { 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 };
0110 uv16qi perm_imag = (uv16qi) { 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 };
0111 v4sf real = vec_perm((v4sf)hi.data, (v4sf)lo.data, perm_real);
0112 v4sf imag = vec_perm((v4sf)hi.data, (v4sf)lo.data, perm_imag);
0113 return { batch<float, A>(real), batch<float, A>(imag) };
0114 }
0115
0116 template <class A>
0117 XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<vxe>) noexcept
0118 {
0119
0120
0121 using v2df = double __attribute__((vector_size(16)));
0122 uv16qi perm_real = (uv16qi) { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 };
0123 uv16qi perm_imag = (uv16qi) { 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 };
0124 v2df real = vec_perm((v2df)hi.data, (v2df)lo.data, perm_real);
0125 v2df imag = vec_perm((v2df)hi.data, (v2df)lo.data, perm_imag);
0126 return { batch<double, A>(real), batch<double, A>(imag) };
0127 }
0128
0129 template <class A>
0130 XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<vxe>) noexcept
0131 {
0132 uv16qi perm = (uv16qi) { 0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23 };
0133 return batch<float, A>(vec_perm((v4sf)self.real().data, (v4sf)self.imag().data, perm));
0134 }
0135
0136 template <class A>
0137 XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<vxe>) noexcept
0138 {
0139 uv16qi perm = (uv16qi) { 8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31 };
0140 return batch<float, A>(vec_perm((v4sf)self.real().data, (v4sf)self.imag().data, perm));
0141 }
0142
0143 template <class A>
0144 XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<vxe>) noexcept
0145 {
0146 uv16qi perm = (uv16qi) { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 };
0147 return batch<double, A>(vec_perm((v2df)self.real().data, (v2df)self.imag().data, perm));
0148 }
0149
0150 template <class A>
0151 XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<vxe>) noexcept
0152 {
0153 uv16qi perm = (uv16qi) { 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 };
0154 return batch<double, A>(vec_perm((v2df)self.real().data, (v2df)self.imag().data, perm));
0155 }
0156 }
0157
0158
0159 template <class A, class T>
0160 XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<vxe>) noexcept
0161 {
0162 vec_xst(src.data, 0, (builtin_t<T>*)dst);
0163 }
0164
0165 template <class A, class T>
0166 XSIMD_INLINE void store_unaligned(T* dst, batch<T, A> const& src, requires_arch<vxe>) noexcept
0167 {
0168 store_aligned<A>(dst, src, vxe {});
0169 }
0170
0171
0172 template <class A, class T, class... Values>
0173 XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<vxe>, Values... values) noexcept
0174 {
0175 static_assert(sizeof...(Values) == batch<T, A>::size, "consistent init");
0176 return typename batch<T, A>::register_type { values... };
0177 }
0178
0179 template <class A, class T, class... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
0180 XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<vxe>, Values... values) noexcept
0181 {
0182 static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
0183 return typename batch_bool<T, A>::register_type { static_cast<decltype(std::declval<typename batch_bool<T, A>::register_type>()[0])>(values ? -1LL : 0LL)... };
0184 }
0185
0186 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0187 XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<vxe>) noexcept
0188 {
0189 return self.data[0];
0190 }
0191
0192 template <class A, class T, size_t I, class = std::enable_if_t<std::is_scalar<T>::value>>
0193 XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<vxe>) noexcept
0194 {
0195
0196 batch<T, A> out(self);
0197 out.data[I] = val;
0198 return out;
0199 }
0200
0201
0202 template <class A, class T>
0203 XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0204 {
0205 return self.data == other.data;
0206 }
0207 template <class A, class T>
0208 XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0209 {
0210 return self.data == other.data;
0211 }
0212
0213 template <class A, class T>
0214 XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0215 {
0216 return self.data < other.data;
0217 }
0218 template <class A, class T>
0219 XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0220 {
0221 return self.data <= other.data;
0222 }
0223
0224
0225 template <class A, class T>
0226 XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0227 {
0228 return ~(self.data == other.data);
0229 }
0230
0231 template <class A, class T>
0232 XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0233 {
0234 return bitwise_xor(self, other);
0235 }
0236
0237
0238 template <class A, class T>
0239 XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0240 {
0241 return self.data - other.data;
0242 }
0243
0244
0245 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0246 XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<vxe>) noexcept
0247 {
0248 return vec_splats(static_cast<builtin_t<T>>(val));
0249 }
0250
0251
0252 template <class A, class T, class = typename std::enable_if<std::is_signed<T>::value, void>::type>
0253 XSIMD_INLINE batch<T, A> abs(batch<T, A> const& self, requires_arch<vxe>) noexcept
0254 {
0255 return vec_abs(self.data);
0256 }
0257
0258 template <class A, class T>
0259 XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0260 {
0261 return (typename batch<T, A>::register_type)((v4si)self.data & (v4si)other.data);
0262 }
0263 template <class A, class T>
0264 XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0265 {
0266 return self.data & other.data;
0267 }
0268
0269
0270 template <class A, class T>
0271 XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0272 {
0273 return (typename batch<T, A>::register_type)((v4si)self.data | (v4si)other.data);
0274 }
0275 template <class A, class T>
0276 XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0277 {
0278 return self.data | other.data;
0279 }
0280
0281
0282 template <class A, class T>
0283 XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0284 {
0285 return (typename batch<T, A>::register_type)((v4si)self.data ^ (v4si)other.data);
0286 }
0287 template <class A, class T>
0288 XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0289 {
0290 return self.data ^ other.data;
0291 }
0292
0293
0294 template <class A, class T>
0295 XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<vxe>) noexcept
0296 {
0297
0298 return (typename batch<T, A>::register_type)(~(v4si)self.data);
0299 }
0300 template <class A, class T>
0301 XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<vxe>) noexcept
0302 {
0303 return ~self.data;
0304 }
0305
0306
0307 template <class A, class T>
0308 XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0309 {
0310 return (typename batch<T, A>::register_type)((v4si)self.data & ~(v4si)other.data);
0311 }
0312 template <class A, class T>
0313 XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vxe>) noexcept
0314 {
0315 return self.data & ~other.data;
0316 }
0317
0318
0319 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0320 XSIMD_INLINE batch<T, A> div(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0321 {
0322 return self.data / other.data;
0323 }
0324
0325
0326 template <class A, class T>
0327 XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<vxe>) noexcept
0328 {
0329 return (typename batch<T, A>::register_type) { 0 } - self.data;
0330 }
0331
0332
0333 template <class A, class T>
0334 XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0335 {
0336 return self.data + other.data;
0337 }
0338
0339
0340 template <class A, class T>
0341 XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<vxe>) noexcept
0342 {
0343 return ((v1ti)self.data)[0] == -1;
0344 }
0345
0346
0347 template <class A, class T>
0348 XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<vxe>) noexcept
0349 {
0350 return ((v1ti)self.data)[0] != 0;
0351 }
0352
0353 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0354 XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0355 {
0356 return vec_avg(self.data, other.data);
0357 }
0358
0359
0360 template <class A, class T>
0361 XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0362 {
0363 return vec_max(self.data, other.data);
0364 }
0365
0366 template <class A, class T>
0367 XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0368 {
0369 return vec_min(self.data, other.data);
0370 }
0371
0372 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0373 XSIMD_INLINE batch<T, A> fma(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<vxe>) noexcept
0374 {
0375 return vec_madd(x.data, y.data, z.data);
0376 }
0377
0378 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0379 XSIMD_INLINE batch<T, A> fms(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<vxe>) noexcept
0380 {
0381 return vec_msub(x.data, y.data, z.data);
0382 }
0383
0384
0385 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0386 XSIMD_INLINE batch<T, A> mul(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0387 {
0388 return self.data * other.data;
0389 }
0390
0391 template <class A>
0392 XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* r, requires_arch<vxe>) noexcept
0393 {
0394 v4sf lo01, hi01, lo23, hi23, sum01, sum23, sumeven, sumodd;
0395 lo01 = vec_mergel(r[0].data, r[1].data);
0396 hi01 = vec_mergeh(r[0].data, r[1].data);
0397 lo23 = vec_mergel(r[2].data, r[3].data);
0398 hi23 = vec_mergeh(r[2].data, r[3].data);
0399 sum01 = lo01 + hi01;
0400 sum23 = lo23 + hi23;
0401 sumeven = (v4sf)vec_mergeh((v2di)sum01, (v2di)sum23);
0402 sumodd = (v4sf)vec_mergel((v2di)sum01, (v2di)sum23);
0403 return sumeven + sumodd;
0404 }
0405 template <class A>
0406 XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<vxe>) noexcept
0407 {
0408 return vec_mergeh(row[0].data, row[1].data) + vec_mergel(row[0].data, row[1].data);
0409 }
0410
0411
0412 template <class A>
0413 XSIMD_INLINE float reduce_add(batch<float, A> const& self, requires_arch<vxe>) noexcept
0414 {
0415 v4sf shifted_64 = vec_sld(self.data, self.data, 8);
0416 v4sf added_1 = self.data + shifted_64;
0417 v4sf shifted_32 = vec_sld(added_1, added_1, 4);
0418 return (added_1 + shifted_32)[0];
0419 }
0420
0421 template <class A>
0422 XSIMD_INLINE double reduce_add(batch<double, A> const& self, requires_arch<vxe>) noexcept
0423 {
0424 return (self.data + vec_sld(self.data, self.data, 8))[0];
0425 }
0426
0427 template <class A>
0428 XSIMD_INLINE uint64_t reduce_add(batch<uint64_t, A> const& self, requires_arch<vxe>) noexcept
0429 {
0430 uv2di shifted = vec_sld((uv2di)self.data, (uv2di)self.data, 8);
0431 uv2di sum = (uv2di)self.data + shifted;
0432 return (uint64_t)sum[0];
0433 }
0434 template <class A>
0435 XSIMD_INLINE int64_t reduce_add(batch<int64_t, A> const& self, requires_arch<vxe>) noexcept
0436 {
0437 v2di shifted = vec_sld((v2di)self.data, (v2di)self.data, 8);
0438 v2di sum = (v2di)self.data + shifted;
0439 return (int64_t)sum[0];
0440 }
0441 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0442 XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<vxe>) noexcept
0443 {
0444 XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0445 {
0446 using t = typename batch<T, A>::register_type;
0447 t shifted_64 = vec_sld(self.data, self.data, 8);
0448 t added_1 = self.data + shifted_64;
0449 t shifted_32 = vec_sld(added_1, added_1, 4);
0450 return (added_1 + shifted_32)[0];
0451 }
0452 else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
0453 {
0454 using t = typename batch<T, A>::register_type;
0455 t shifted_64 = vec_sld(self.data, self.data, 8);
0456 t added_1 = self.data + shifted_64;
0457 t shifted_32 = vec_sld(added_1, added_1, 4);
0458 t added_2 = added_1 + shifted_32;
0459 t shifted_16 = vec_sld(added_2, added_2, 2);
0460 return (added_2 + shifted_16)[0];
0461 }
0462 else
0463 {
0464 using t = typename batch<T, A>::register_type;
0465 t shifted_64 = vec_sld(self.data, self.data, 8);
0466 t added_1 = self.data + shifted_64;
0467 t shifted_32 = vec_sld(added_1, added_1, 4);
0468 t added_2 = added_1 + shifted_32;
0469 t shifted_16 = vec_sld(added_2, added_2, 2);
0470 t added_3 = added_2 + shifted_16;
0471 t shifted_8 = vec_sld(added_3, added_3, 1);
0472 return (added_3 + shifted_8)[0];
0473 }
0474 }
0475
0476
0477 template <class A, class T>
0478 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<vxe>) noexcept
0479 {
0480 return vec_sel(false_br.data, true_br.data, cond.data);
0481 }
0482 template <class A, class T, bool... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
0483 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<vxe>) noexcept
0484 {
0485 return select(batch_bool<T, A> { Values... }, true_br, false_br, vxe {});
0486 }
0487
0488
0489 template <size_t N, class A, class T>
0490 XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<vxe>) noexcept
0491 {
0492 XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
0493 {
0494 return batch<T, A>(0);
0495 }
0496 else
0497 {
0498 auto shift_count = vec_splats((uint8_t)(8 * N));
0499 return vec_sll(x.data, shift_count);
0500 }
0501 }
0502
0503
0504 template <size_t N, class A, class T>
0505 XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<vxe>) noexcept
0506 {
0507 XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
0508 {
0509 return batch<T, A>(0);
0510 }
0511 else
0512 {
0513 auto shift_count = vec_splats((uint8_t)(8 * N));
0514 return vec_srl(x.data, shift_count);
0515 }
0516 }
0517
0518
0519 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0520 XSIMD_INLINE batch<T, A> sqrt(batch<T, A> const& val, requires_arch<vxe>) noexcept
0521 {
0522 return vec_sqrt(val.data);
0523 }
0524
0525
0526 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0527 XSIMD_INLINE batch<T, A> rsqrt(batch<T, A> const& val, requires_arch<vxe>) noexcept
0528 {
0529 return batch<T, A>(T(1)) / sqrt(val, vxe {});
0530 }
0531
0532
0533 template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3>
0534 XSIMD_INLINE batch<float, A> shuffle(batch<float, A> const& x, batch<float, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3>, requires_arch<vxe>) noexcept
0535 {
0536 return vec_perm(x.data, y.data,
0537 (__vector unsigned char) {
0538 4 * I0 + 0, 4 * I0 + 1, 4 * I0 + 2, 4 * I0 + 3,
0539 4 * I1 + 0, 4 * I1 + 1, 4 * I1 + 2, 4 * I1 + 3,
0540 4 * I2 + 0, 4 * I2 + 1, 4 * I2 + 2, 4 * I2 + 3,
0541 4 * I3 + 0, 4 * I3 + 1, 4 * I3 + 2, 4 * I3 + 3 });
0542 }
0543
0544 template <class A, class ITy, ITy I0, ITy I1>
0545 XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1>, requires_arch<vxe>) noexcept
0546 {
0547 return vec_perm(x.data, y.data,
0548 (__vector unsigned char) {
0549 8 * I0 + 0,
0550 8 * I0 + 1,
0551 8 * I0 + 2,
0552 8 * I0 + 3,
0553 8 * I0 + 4,
0554 8 * I0 + 5,
0555 8 * I0 + 6,
0556 8 * I0 + 7,
0557 8 * I1 + 0,
0558 8 * I1 + 1,
0559 8 * I1 + 2,
0560 8 * I1 + 3,
0561 8 * I1 + 4,
0562 8 * I1 + 5,
0563 8 * I1 + 6,
0564 8 * I1 + 7,
0565 });
0566 }
0567
0568
0569
0570 template <class A, uint8_t... Values>
0571 XSIMD_INLINE batch<uint8_t, A> swizzle(batch<uint8_t, A> const& self, batch_constant<uint8_t, A, Values...>, requires_arch<vxe>) noexcept
0572 {
0573 static_assert(sizeof...(Values) == batch<uint8_t, A>::size, "consistent init");
0574 uv16qi perm = (uv16qi) { Values... };
0575 return vec_perm(self.data, self.data, perm);
0576 }
0577 template <class A, uint8_t... Values>
0578 XSIMD_INLINE batch<int8_t, A> swizzle(batch<int8_t, A> const& self, batch_constant<uint8_t, A, Values...>, requires_arch<vxe>) noexcept
0579 {
0580 static_assert(sizeof...(Values) == batch<int8_t, A>::size, "consistent init");
0581 uv16qi perm = (uv16qi) { Values... };
0582 return vec_perm(self.data, self.data, perm);
0583 }
0584
0585
0586 template <class A, uint16_t V0, uint16_t V1, uint16_t V2, uint16_t V3, uint16_t V4, uint16_t V5, uint16_t V6, uint16_t V7>
0587 XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self, batch_constant<uint16_t, A, V0, V1, V2, V3, V4, V5, V6, V7>, requires_arch<vxe>) noexcept
0588 {
0589 uv16qi perm = (uv16qi) {
0590 2 * V0, 2 * V0 + 1,
0591 2 * V1, 2 * V1 + 1,
0592 2 * V2, 2 * V2 + 1,
0593 2 * V3, 2 * V3 + 1,
0594 2 * V4, 2 * V4 + 1,
0595 2 * V5, 2 * V5 + 1,
0596 2 * V6, 2 * V6 + 1,
0597 2 * V7, 2 * V7 + 1
0598 };
0599 return vec_perm(self.data, self.data, perm);
0600 }
0601 template <class A, uint16_t V0, uint16_t V1, uint16_t V2, uint16_t V3, uint16_t V4, uint16_t V5, uint16_t V6, uint16_t V7>
0602 XSIMD_INLINE batch<int16_t, A> swizzle(batch<int16_t, A> const& self, batch_constant<uint16_t, A, V0, V1, V2, V3, V4, V5, V6, V7>, requires_arch<vxe>) noexcept
0603 {
0604 uv16qi perm = (uv16qi) {
0605 2 * V0, 2 * V0 + 1,
0606 2 * V1, 2 * V1 + 1,
0607 2 * V2, 2 * V2 + 1,
0608 2 * V3, 2 * V3 + 1,
0609 2 * V4, 2 * V4 + 1,
0610 2 * V5, 2 * V5 + 1,
0611 2 * V6, 2 * V6 + 1,
0612 2 * V7, 2 * V7 + 1
0613 };
0614 return vec_perm(self.data, self.data, perm);
0615 }
0616
0617
0618 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0619 XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<vxe>) noexcept
0620 {
0621 uv16qi perm = (uv16qi) {
0622 4 * V0, 4 * V0 + 1, 4 * V0 + 2, 4 * V0 + 3,
0623 4 * V1, 4 * V1 + 1, 4 * V1 + 2, 4 * V1 + 3,
0624 4 * V2, 4 * V2 + 1, 4 * V2 + 2, 4 * V2 + 3,
0625 4 * V3, 4 * V3 + 1, 4 * V3 + 2, 4 * V3 + 3
0626 };
0627 return vec_perm(self.data, self.data, perm);
0628 }
0629 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0630 XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<vxe>) noexcept
0631 {
0632 uv16qi perm = (uv16qi) {
0633 4 * V0, 4 * V0 + 1, 4 * V0 + 2, 4 * V0 + 3,
0634 4 * V1, 4 * V1 + 1, 4 * V1 + 2, 4 * V1 + 3,
0635 4 * V2, 4 * V2 + 1, 4 * V2 + 2, 4 * V2 + 3,
0636 4 * V3, 4 * V3 + 1, 4 * V3 + 2, 4 * V3 + 3
0637 };
0638 return vec_perm(self.data, self.data, perm);
0639 }
0640 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0641 XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<vxe>) noexcept
0642 {
0643 uv16qi perm = (uv16qi) {
0644 4 * V0, 4 * V0 + 1, 4 * V0 + 2, 4 * V0 + 3,
0645 4 * V1, 4 * V1 + 1, 4 * V1 + 2, 4 * V1 + 3,
0646 4 * V2, 4 * V2 + 1, 4 * V2 + 2, 4 * V2 + 3,
0647 4 * V3, 4 * V3 + 1, 4 * V3 + 2, 4 * V3 + 3
0648 };
0649 return vec_perm(self.data, self.data, perm);
0650 }
0651
0652
0653 template <class A, uint64_t V0, uint64_t V1>
0654 XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<vxe>) noexcept
0655 {
0656 using out = typename batch<uint64_t, A>::register_type;
0657 uv16qi perm = (uv16qi) {
0658 8 * V0 + 0,
0659 8 * V0 + 1,
0660 8 * V0 + 2,
0661 8 * V0 + 3,
0662 8 * V0 + 4,
0663 8 * V0 + 5,
0664 8 * V0 + 6,
0665 8 * V0 + 7,
0666 8 * V1 + 0,
0667 8 * V1 + 1,
0668 8 * V1 + 2,
0669 8 * V1 + 3,
0670 8 * V1 + 4,
0671 8 * V1 + 5,
0672 8 * V1 + 6,
0673 8 * V1 + 7,
0674 };
0675 return (out)vec_perm((uv2di)self.data, (uv2di)self.data, perm);
0676 }
0677 template <class A, uint64_t V0, uint64_t V1>
0678 XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<vxe>) noexcept
0679 {
0680 using out = typename batch<int64_t, A>::register_type;
0681 uv16qi perm = (uv16qi) {
0682 8 * V0 + 0,
0683 8 * V0 + 1,
0684 8 * V0 + 2,
0685 8 * V0 + 3,
0686 8 * V0 + 4,
0687 8 * V0 + 5,
0688 8 * V0 + 6,
0689 8 * V0 + 7,
0690 8 * V1 + 0,
0691 8 * V1 + 1,
0692 8 * V1 + 2,
0693 8 * V1 + 3,
0694 8 * V1 + 4,
0695 8 * V1 + 5,
0696 8 * V1 + 6,
0697 8 * V1 + 7,
0698 };
0699 return (out)vec_perm((v2di)self.data, (v2di)self.data, perm);
0700 }
0701 template <class A, uint64_t V0, uint64_t V1>
0702 XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<vxe>) noexcept
0703 {
0704 uv16qi perm = (uv16qi) {
0705 8 * V0 + 0,
0706 8 * V0 + 1,
0707 8 * V0 + 2,
0708 8 * V0 + 3,
0709 8 * V0 + 4,
0710 8 * V0 + 5,
0711 8 * V0 + 6,
0712 8 * V0 + 7,
0713 8 * V1 + 0,
0714 8 * V1 + 1,
0715 8 * V1 + 2,
0716 8 * V1 + 3,
0717 8 * V1 + 4,
0718 8 * V1 + 5,
0719 8 * V1 + 6,
0720 8 * V1 + 7,
0721 };
0722 return vec_perm(self.data, self.data, perm);
0723 }
0724
0725 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0726 XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0727 {
0728 return vec_mergel(self.data, other.data);
0729 }
0730
0731
0732 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0733 XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vxe>) noexcept
0734 {
0735 return vec_mergeh(self.data, other.data);
0736 }
0737
0738 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0739 XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<vxe>) noexcept
0740 {
0741 return self.data >> other;
0742 }
0743
0744 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0745 XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<vxe>) noexcept
0746 {
0747 return self.data << other;
0748 }
0749
0750
0751 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0752 XSIMD_INLINE batch_bool<T, A> isnan(batch<T, A> const& self, requires_arch<vxe>) noexcept
0753 {
0754 return ~vec_cmpeq(self.data, self.data);
0755 }
0756
0757
0758 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0759 XSIMD_INLINE batch<T, A> ceil(batch<T, A> const& self, requires_arch<vxe>) noexcept
0760 {
0761 return vec_ceil(self.data);
0762 }
0763
0764
0765 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0766 XSIMD_INLINE batch<T, A> floor(batch<T, A> const& self, requires_arch<vxe>) noexcept
0767 {
0768 return vec_floor(self.data);
0769 }
0770
0771
0772 #if defined __has_builtin && __has_builtin(__builtin_s390_vfi)
0773 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0774 XSIMD_INLINE batch<T, A> round(batch<T, A> const& self, requires_arch<vxe>) noexcept
0775 {
0776 return __builtin_s390_vfi(self.data, 4, 1);
0777 }
0778 #endif
0779
0780 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0781 XSIMD_INLINE batch<T, A> trunc(batch<T, A> const& self, requires_arch<vxe>) noexcept
0782 {
0783 return vec_trunc(self.data);
0784 }
0785 }
0786 }
0787 #endif