Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:37:13

0001 /***************************************************************************
0002  * Copyright (c) Andreas Krebbel                                            *
0003  * Based on xsimd_vsx.hpp                                                   *
0004  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0005  * Martin Renou                                                             *
0006  * Copyright (c) QuantStack                                                 *
0007  * Copyright (c) Serge Guelton                                              *
0008  *                                                                          *
0009  * Distributed under the terms of the BSD 3-Clause License.                 *
0010  *                                                                          *
0011  * The full license is in the file LICENSE, distributed with this software. *
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         // builtin_t<T> - the scalar type as it would be used for a vector intrinsic
0039         // VXE vector intrinsics do not support long, unsigned long, and char
0040         // The builtin<T> definition can be used to map the incoming
0041         // type to the right one to be used with the intrinsics.
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         // bitwise_cast
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         // batch_bool_cast
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         // load
0084 
0085         // load_unaligned
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         // load_aligned
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         // load_complex
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                 // Interleave real and imaginary parts
0106                 // hi = [r0, i0, r1, i1], lo = [r2, i2, r3, i3]
0107                 // We need: real = [r0, r1, r2, r3], imag = [i0, i1, i2, i3]
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                 // hi = [r0, i0], lo = [r1, i1]
0120                 // We need: real = [r0, r1], imag = [i0, i1]
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         // store
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         // set
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         // first
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         // insert
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             // vec_insert on float is broken with clang
0196             batch<T, A> out(self);
0197             out.data[I] = val;
0198             return out;
0199         }
0200 
0201         // eq
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         // neq
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         // sub
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         // broadcast
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         // abs
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         // bitwise_and
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         // bitwise_or
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         // bitwise_xor
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         // bitwise_not
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             // ~ operator does not work on floating point vectors
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         // bitwise_andnot
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         // div
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         // neg
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         // add
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         // all
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         // any
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         // avgr
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         // max
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         // min
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         // fma
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         // fms
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         // mul
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         // haddp
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); // { r[0][2], r[1][2], r[0][3], r[1][3] }
0396             hi01 = vec_mergeh(r[0].data, r[1].data); // { r[0][0], r[1][0], r[0][1], r[1][1] }
0397             lo23 = vec_mergel(r[2].data, r[3].data); // { r[2][2], r[2][2], r[3][3], r[3][3] }
0398             hi23 = vec_mergeh(r[2].data, r[3].data); // { r[2][0], r[2][0], r[3][1], r[3][1] }
0399             sum01 = lo01 + hi01; // { r[0][0] + r[0][2], r[1][0] + r[1][2], r[0][1] + r[0][3], r[1][1] + r[1][3] }
0400             sum23 = lo23 + hi23; // { r[2][0] + r[2][2], r[3][0] + r[3][2], r[2][1] + r[2][3], r[3][1] + r[3][3] }
0401             sumeven = (v4sf)vec_mergeh((v2di)sum01, (v2di)sum23); // { r[0][0] + r[0][2], r[1][0] + r[1][2], r[2][0] + r[2][2], r[3][0] + r[3][2] }
0402             sumodd = (v4sf)vec_mergel((v2di)sum01, (v2di)sum23); // { r[0][1] + r[0][3], r[1][1] + r[1][3], r[2][1] + r[2][3], r[3][1] + r[3][3] }
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         // reduce_add
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         // select
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         // slide_left
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         // slide_right
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         // sqrt
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         // rsqrt
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         // shuffle
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         // swizzle
0569         // 16 x 8bit
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         // 8 x 16 bit
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         // 4 x 32 bit
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         // 2 x 64 bit
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         // zip_hi
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         // zip_lo
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         // bitwise_rshift
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         // bitwise_lshift
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         // isnan
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         // ceil
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         // floor
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         // round
0771         // vec_round rounds ties to even instead of zero
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         // trunc
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