File indexing completed on 2026-11-07 10:37:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef XSIMD_VSX_HPP
0013 #define XSIMD_VSX_HPP
0014
0015 #include "../types/xsimd_batch_fwd.hpp"
0016 #include "../types/xsimd_vsx_register.hpp"
0017 #include "./common/xsimd_common_cast.hpp"
0018
0019 #include <endian.h>
0020
0021 #include <complex>
0022 #include <type_traits>
0023
0024 namespace xsimd
0025 {
0026 template <typename T, class A, bool... Values>
0027 struct batch_bool_constant;
0028
0029 template <class T_out, class T_in, class A>
0030 XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& x) noexcept;
0031
0032 template <typename T, class A, T... Values>
0033 struct batch_constant;
0034
0035 namespace kernel
0036 {
0037
0038
0039
0040
0041 template <typename T>
0042 struct builtin_scalar
0043 {
0044 using type = T;
0045 };
0046
0047 template <>
0048 struct builtin_scalar<unsigned long>
0049 {
0050 using type = unsigned long long;
0051 };
0052
0053 template <>
0054 struct builtin_scalar<long>
0055 {
0056 using type = long long;
0057 };
0058
0059 template <>
0060 struct builtin_scalar<char>
0061 {
0062 using type = typename std::conditional<std::is_signed<char>::value, signed char, unsigned char>::type;
0063 };
0064
0065 template <typename T>
0066 using builtin_t = typename builtin_scalar<T>::type;
0067
0068 template <class A, class T>
0069 XSIMD_INLINE batch<T, A> avg(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept;
0070 template <class A, class T>
0071 XSIMD_INLINE batch<T, A> avgr(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept;
0072
0073
0074 template <class A>
0075 XSIMD_INLINE batch<float, A> abs(batch<float, A> const& self, requires_arch<vsx>) noexcept
0076 {
0077 return vec_abs(self.data);
0078 }
0079
0080 template <class A>
0081 XSIMD_INLINE batch<double, A> abs(batch<double, A> const& self, requires_arch<vsx>) noexcept
0082 {
0083 return vec_abs(self.data);
0084 }
0085
0086
0087 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0088 XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0089 {
0090 return vec_add(self.data, other.data);
0091 }
0092
0093
0094 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0095 XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
0096 {
0097 return vec_all_ne(self.data, vec_xor(self.data, self.data));
0098 }
0099
0100
0101 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0102 XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
0103 {
0104 return vec_any_ne(self.data, vec_xor(self.data, self.data));
0105 }
0106
0107
0108 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value && sizeof(T) < 8>>
0109 XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0110 {
0111 return vec_avg(self.data, other.data);
0112 }
0113 template <class A>
0114 XSIMD_INLINE batch<float, A> avgr(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
0115 {
0116 return avgr(self, other, common {});
0117 }
0118 template <class A>
0119 XSIMD_INLINE batch<double, A> avgr(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
0120 {
0121 return avgr(self, other, common {});
0122 }
0123
0124
0125 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0126 XSIMD_INLINE batch<T, A> avg(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0127 {
0128 XSIMD_IF_CONSTEXPR(sizeof(T) < 8)
0129 {
0130 constexpr auto nbit = 8 * sizeof(T) - 1;
0131 auto adj = bitwise_cast<T>(bitwise_cast<as_unsigned_integer_t<T>>((self ^ other) << nbit) >> nbit);
0132 return avgr(self, other, A {}) - adj;
0133 }
0134 else
0135 {
0136 return avg(self, other, common {});
0137 }
0138 }
0139 template <class A>
0140 XSIMD_INLINE batch<float, A> avg(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
0141 {
0142 return avg(self, other, common {});
0143 }
0144 template <class A>
0145 XSIMD_INLINE batch<double, A> avg(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
0146 {
0147 return avg(self, other, common {});
0148 }
0149
0150
0151 template <class A, class T_out, class T_in>
0152 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<vsx>) noexcept
0153 {
0154 return (typename batch_bool<T_out, A>::register_type)self.data;
0155 }
0156
0157
0158 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0159 XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0160 {
0161 return vec_and(self.data, other.data);
0162 }
0163 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0164 XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0165 {
0166 return vec_and(self.data, other.data);
0167 }
0168
0169
0170 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0171 XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0172 {
0173 return vec_and(self.data, vec_nor(other.data, other.data));
0174 }
0175 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0176 XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0177 {
0178 return self.data & ~other.data;
0179 }
0180
0181
0182 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0183 XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<vsx>) noexcept
0184 {
0185 using shift_type = as_unsigned_integer_t<T>;
0186 batch<shift_type, A> shift(static_cast<shift_type>(other));
0187 return vec_sl(self.data, shift.data);
0188 }
0189
0190
0191 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0192 XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<vsx>) noexcept
0193 {
0194 return vec_nor(self.data, self.data);
0195 }
0196 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0197 XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
0198 {
0199 return vec_nor(self.data, self.data);
0200 }
0201
0202
0203 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0204 XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0205 {
0206 return vec_or(self.data, other.data);
0207 }
0208 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0209 XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0210 {
0211 return vec_or(self.data, other.data);
0212 }
0213
0214
0215 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0216 XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<vsx>) noexcept
0217 {
0218 using shift_type = as_unsigned_integer_t<T>;
0219 batch<shift_type, A> shift(static_cast<shift_type>(other));
0220 XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
0221 {
0222 return vec_sra(self.data, shift.data);
0223 }
0224 else
0225 {
0226 return vec_sr(self.data, shift.data);
0227 }
0228 }
0229
0230
0231 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0232 XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0233 {
0234 return vec_xor(self.data, other.data);
0235 }
0236 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0237 XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0238 {
0239 return vec_xor(self.data, other.data);
0240 }
0241
0242
0243 template <class A, class T_in, class T_out>
0244 XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& self, batch<T_out, A> const&, requires_arch<vsx>) noexcept
0245 {
0246 return (typename batch<T_out, A>::register_type)(self.data);
0247 }
0248
0249
0250 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0251 XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<vsx>) noexcept
0252 {
0253 return vec_splats(static_cast<builtin_t<T>>(val));
0254 }
0255
0256
0257 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0258 XSIMD_INLINE batch<T, A> ceil(batch<T, A> const& self, requires_arch<vsx>) noexcept
0259 {
0260 return vec_ceil(self.data);
0261 }
0262
0263
0264 namespace detail
0265 {
0266
0267 template <class A>
0268 XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<vsx>) noexcept
0269 {
0270 return vec_mergeh(self.real().data, self.imag().data);
0271 }
0272 template <class A>
0273 XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<vsx>) noexcept
0274 {
0275 return vec_mergeh(self.real().data, self.imag().data);
0276 }
0277
0278 template <class A>
0279 XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<vsx>) noexcept
0280 {
0281 return vec_mergel(self.real().data, self.imag().data);
0282 }
0283 template <class A>
0284 XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<vsx>) noexcept
0285 {
0286 return vec_mergel(self.real().data, self.imag().data);
0287 }
0288 }
0289
0290
0291 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0292 XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<vsx>) noexcept
0293 {
0294 return self + batch<T, A>((typename batch<T, A>::register_type)mask.data);
0295 }
0296
0297
0298 template <class A>
0299 XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
0300 {
0301 return vec_div(self.data, other.data);
0302 }
0303 template <class A>
0304 XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
0305 {
0306 return vec_div(self.data, other.data);
0307 }
0308
0309
0310 namespace detail
0311 {
0312 template <class A>
0313 XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<vsx>) noexcept
0314 {
0315 return vec_ctf(self.data, 0);
0316 }
0317 template <class A>
0318 XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& self, batch<float, A> const&, requires_arch<vsx>) noexcept
0319 {
0320 return vec_ctf(self.data, 0);
0321 }
0322
0323 template <class A>
0324 XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<vsx>) noexcept
0325 {
0326 return vec_cts(self.data, 0);
0327 }
0328
0329 template <class A>
0330 XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<float, A> const& self, batch<uint32_t, A> const&, requires_arch<vsx>) noexcept
0331 {
0332 return vec_ctu(self.data, 0);
0333 }
0334 }
0335
0336
0337 template <class A>
0338 XSIMD_INLINE batch<float, A> fma(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<vsx>) noexcept
0339 {
0340 return vec_madd(x.data, y.data, z.data);
0341 }
0342
0343 template <class A>
0344 XSIMD_INLINE batch<double, A> fma(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<vsx>) noexcept
0345 {
0346 return vec_madd(x.data, y.data, z.data);
0347 }
0348
0349
0350 template <class A>
0351 XSIMD_INLINE batch<float, A> fms(batch<float, A> const& x, batch<float, A> const& y, batch<float, A> const& z, requires_arch<vsx>) noexcept
0352 {
0353 return vec_msub(x.data, y.data, z.data);
0354 }
0355
0356 template <class A>
0357 XSIMD_INLINE batch<double, A> fms(batch<double, A> const& x, batch<double, A> const& y, batch<double, A> const& z, requires_arch<vsx>) noexcept
0358 {
0359 return vec_msub(x.data, y.data, z.data);
0360 }
0361
0362
0363 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0364 XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0365 {
0366 auto res = vec_cmpeq(self.data, other.data);
0367 return *reinterpret_cast<typename batch_bool<T, A>::register_type*>(&res);
0368 }
0369 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0370 XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0371 {
0372 auto res = vec_cmpeq(self.data, other.data);
0373 return *reinterpret_cast<typename batch_bool<T, A>::register_type*>(&res);
0374 }
0375
0376
0377 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0378 XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<vsx>) noexcept
0379 {
0380 return vec_extract(self.data, 0);
0381 }
0382
0383
0384 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0385 XSIMD_INLINE batch<T, A> floor(batch<T, A> const& self, requires_arch<vsx>) noexcept
0386 {
0387 return vec_floor(self.data);
0388 }
0389
0390
0391 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0392 XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0393 {
0394 return vec_cmpge(self.data, other.data);
0395 }
0396
0397
0398 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0399 XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0400 {
0401 return vec_cmpgt(self.data, other.data);
0402 }
0403
0404
0405 template <class A>
0406 XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* row, requires_arch<vsx>) noexcept
0407 {
0408 auto tmp0 = vec_mergee(row[0].data, row[1].data);
0409 auto tmp1 = vec_mergeo(row[0].data, row[1].data);
0410 auto tmp4 = vec_add(tmp0, tmp1);
0411
0412 auto tmp2 = vec_mergee(row[2].data, row[3].data);
0413 auto tmp3 = vec_mergeo(row[2].data, row[3].data);
0414 auto tmp5 = vec_add(tmp0, tmp1);
0415
0416 auto tmp6 = vec_perm(tmp4, tmp5, (__vector unsigned char) { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 });
0417 auto tmp7 = vec_perm(tmp4, tmp5, (__vector unsigned char) { 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 });
0418
0419 return vec_add(tmp6, tmp7);
0420 }
0421
0422 template <class A>
0423 XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<vsx>) noexcept
0424 {
0425 auto tmp0 = vec_mergee(row[0].data, row[1].data);
0426 auto tmp1 = vec_mergeo(row[0].data, row[1].data);
0427 return vec_add(tmp0, tmp1);
0428 }
0429
0430
0431 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0432 XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<vsx>) noexcept
0433 {
0434 return self - batch<T, A>((typename batch<T, A>::register_type)mask.data);
0435 }
0436
0437
0438 template <class A, class T, size_t I, class = std::enable_if_t<std::is_scalar<T>::value>>
0439 XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<vsx>) noexcept
0440 {
0441 return vec_insert(val, self.data, I);
0442 }
0443
0444
0445 template <class A>
0446 XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<vsx>) noexcept
0447 {
0448 return ~vec_cmpeq(self.data, self.data);
0449 }
0450 template <class A>
0451 XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<vsx>) noexcept
0452 {
0453 return ~vec_cmpeq(self.data, self.data);
0454 }
0455
0456
0457 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0458 XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<vsx>) noexcept
0459 {
0460 return (typename batch<T, A>::register_type)vec_xl(0, (builtin_t<T>*)mem);
0461 }
0462
0463
0464 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0465 XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<vsx>) noexcept
0466 {
0467 return load_unaligned<A>(mem, kernel::convert<T> {}, vsx {});
0468 }
0469
0470
0471 namespace detail
0472 {
0473 template <class A>
0474 XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<vsx>) noexcept
0475 {
0476 __vector unsigned char perme = { 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 };
0477 __vector unsigned char permo = { 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 };
0478 return { vec_perm(hi.data, lo.data, perme), vec_perm(hi.data, lo.data, permo) };
0479 }
0480 template <class A>
0481 XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<vsx>) noexcept
0482 {
0483 return { vec_mergee(hi.data, lo.data), vec_mergeo(hi.data, lo.data) };
0484 }
0485 }
0486
0487
0488 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0489 XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0490 {
0491 return vec_cmple(self.data, other.data);
0492 }
0493
0494
0495 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0496 XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0497 {
0498 return vec_cmplt(self.data, other.data);
0499 }
0500
0501
0502 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0503 XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0504 {
0505 return vec_max(self.data, other.data);
0506 }
0507
0508
0509 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0510 XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0511 {
0512 return vec_min(self.data, other.data);
0513 }
0514
0515
0516 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0517 XSIMD_INLINE batch<T, A> mul(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0518 {
0519 return self.data * other.data;
0520 }
0521
0522
0523 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0524 XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<vsx>) noexcept
0525 {
0526 return -(self.data);
0527 }
0528
0529
0530 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0531 XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0532 {
0533 return ~vec_cmpeq(self.data, other.data);
0534 }
0535 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0536 XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
0537 {
0538 return ~vec_cmpeq(self.data, other.data);
0539 }
0540
0541
0542 template <class A>
0543 XSIMD_INLINE batch<float, A> reciprocal(batch<float, A> const& self,
0544 kernel::requires_arch<vsx>)
0545 {
0546 return vec_re(self.data);
0547 }
0548 template <class A>
0549 XSIMD_INLINE batch<double, A> reciprocal(batch<double, A> const& self,
0550 kernel::requires_arch<vsx>)
0551 {
0552 return vec_re(self.data);
0553 }
0554
0555
0556 template <class A>
0557 XSIMD_INLINE signed reduce_add(batch<signed, A> const& self, requires_arch<vsx>) noexcept
0558 {
0559 auto tmp0 = vec_reve(self.data);
0560 auto tmp1 = vec_add(self.data, tmp0);
0561 auto tmp2 = vec_mergel(tmp1, tmp1);
0562 auto tmp3 = vec_add(tmp1, tmp2);
0563 return vec_extract(tmp3, 0);
0564 }
0565 template <class A>
0566 XSIMD_INLINE unsigned reduce_add(batch<unsigned, A> const& self, requires_arch<vsx>) noexcept
0567 {
0568 auto tmp0 = vec_reve(self.data);
0569 auto tmp1 = vec_add(self.data, tmp0);
0570 auto tmp2 = vec_mergel(tmp1, tmp1);
0571 auto tmp3 = vec_add(tmp1, tmp2);
0572 return vec_extract(tmp3, 0);
0573 }
0574 template <class A>
0575 XSIMD_INLINE float reduce_add(batch<float, A> const& self, requires_arch<vsx>) noexcept
0576 {
0577
0578 auto tmp0 = vec_reve(self.data);
0579 auto tmp1 = vec_add(self.data, tmp0);
0580 auto tmp2 = vec_mergel(tmp1, tmp1);
0581 auto tmp3 = vec_add(tmp1, tmp2);
0582 return vec_extract(tmp3, 0);
0583 }
0584 template <class A>
0585 XSIMD_INLINE double reduce_add(batch<double, A> const& self, requires_arch<vsx>) noexcept
0586 {
0587 auto tmp0 = vec_reve(self.data);
0588 auto tmp1 = vec_add(self.data, tmp0);
0589 return vec_extract(tmp1, 0);
0590 }
0591 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0592 XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<vsx>) noexcept
0593 {
0594 return reduce_add(self, common {});
0595 }
0596
0597
0598 template <class A>
0599 XSIMD_INLINE signed reduce_mul(batch<signed, A> const& self, requires_arch<vsx>) noexcept
0600 {
0601 auto tmp0 = vec_reve(self.data);
0602 auto tmp1 = vec_mul(self.data, tmp0);
0603 auto tmp2 = vec_mergel(tmp1, tmp1);
0604 auto tmp3 = vec_mul(tmp1, tmp2);
0605 return vec_extract(tmp3, 0);
0606 }
0607 template <class A>
0608 XSIMD_INLINE unsigned reduce_mul(batch<unsigned, A> const& self, requires_arch<vsx>) noexcept
0609 {
0610 auto tmp0 = vec_reve(self.data);
0611 auto tmp1 = vec_mul(self.data, tmp0);
0612 auto tmp2 = vec_mergel(tmp1, tmp1);
0613 auto tmp3 = vec_mul(tmp1, tmp2);
0614 return vec_extract(tmp3, 0);
0615 }
0616 template <class A>
0617 XSIMD_INLINE float reduce_mul(batch<float, A> const& self, requires_arch<vsx>) noexcept
0618 {
0619
0620 auto tmp0 = vec_reve(self.data);
0621 auto tmp1 = vec_mul(self.data, tmp0);
0622 auto tmp2 = vec_mergel(tmp1, tmp1);
0623 auto tmp3 = vec_mul(tmp1, tmp2);
0624 return vec_extract(tmp3, 0);
0625 }
0626 template <class A>
0627 XSIMD_INLINE double reduce_mul(batch<double, A> const& self, requires_arch<vsx>) noexcept
0628 {
0629 auto tmp0 = vec_reve(self.data);
0630 auto tmp1 = vec_mul(self.data, tmp0);
0631 return vec_extract(tmp1, 0);
0632 }
0633 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0634 XSIMD_INLINE T reduce_mul(batch<T, A> const& self, requires_arch<vsx>) noexcept
0635 {
0636 return reduce_mul(self, common {});
0637 }
0638
0639
0640
0641
0642 #if defined __has_builtin && __has_builtin(__builtin_vsx_xvrspi)
0643 template <class A>
0644 XSIMD_INLINE batch<float, A> round(batch<float, A> const& self, requires_arch<vsx>) noexcept
0645 {
0646 return __builtin_vsx_xvrspi(self.data);
0647 }
0648 #endif
0649
0650 template <class A>
0651 XSIMD_INLINE batch<double, A> round(batch<double, A> const& self, requires_arch<vsx>) noexcept
0652 {
0653 return vec_round(self.data);
0654 }
0655
0656
0657 template <class A>
0658 XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& val, requires_arch<vsx>) noexcept
0659 {
0660 return vec_rsqrt(val.data);
0661 }
0662 template <class A>
0663 XSIMD_INLINE batch<double, A> rsqrt(batch<double, A> const& val, requires_arch<vsx>) noexcept
0664 {
0665 return vec_rsqrt(val.data);
0666 }
0667
0668
0669 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0670 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<vsx>) noexcept
0671 {
0672 return vec_sel(false_br.data, true_br.data, cond.data);
0673 }
0674 template <class A, class T, bool... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
0675 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<vsx>) noexcept
0676 {
0677 return select(batch_bool<T, A> { Values... }, true_br, false_br, vsx {});
0678 }
0679
0680
0681 template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3>
0682 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<vsx>) noexcept
0683 {
0684 return vec_perm(x.data, y.data,
0685 (__vector unsigned char) {
0686 4 * I0 + 0, 4 * I0 + 1, 4 * I0 + 2, 4 * I0 + 3,
0687 4 * I1 + 0, 4 * I1 + 1, 4 * I1 + 2, 4 * I1 + 3,
0688 4 * I2 + 0, 4 * I2 + 1, 4 * I2 + 2, 4 * I2 + 3,
0689 4 * I3 + 0, 4 * I3 + 1, 4 * I3 + 2, 4 * I3 + 3 });
0690 }
0691
0692 template <class A, class ITy, ITy I0, ITy I1>
0693 XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1>, requires_arch<vsx>) noexcept
0694 {
0695 return vec_perm(x.data, y.data,
0696 (__vector unsigned char) {
0697 8 * I0 + 0,
0698 8 * I0 + 1,
0699 8 * I0 + 2,
0700 8 * I0 + 3,
0701 8 * I0 + 4,
0702 8 * I0 + 5,
0703 8 * I0 + 6,
0704 8 * I0 + 7,
0705 8 * I1 + 0,
0706 8 * I1 + 1,
0707 8 * I1 + 2,
0708 8 * I1 + 3,
0709 8 * I1 + 4,
0710 8 * I1 + 5,
0711 8 * I1 + 6,
0712 8 * I1 + 7,
0713 });
0714 }
0715
0716
0717 template <class A>
0718 XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& val, requires_arch<vsx>) noexcept
0719 {
0720 return vec_sqrt(val.data);
0721 }
0722
0723 template <class A>
0724 XSIMD_INLINE batch<double, A> sqrt(batch<double, A> const& val, requires_arch<vsx>) noexcept
0725 {
0726 return vec_sqrt(val.data);
0727 }
0728
0729
0730 template <size_t N, class A, class T>
0731 XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<vsx>) noexcept
0732 {
0733 XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
0734 {
0735 return batch<T, A>(0);
0736 }
0737 else
0738 {
0739 auto slider = vec_splats((uint8_t)(8 * N));
0740 return (typename batch<T, A>::register_type)vec_slo(x.data, slider);
0741 }
0742 }
0743
0744
0745 template <size_t N, class A, class T>
0746 XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<vsx>) noexcept
0747 {
0748 XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
0749 {
0750 return batch<T, A>(0);
0751 }
0752 else
0753 {
0754 auto slider = vec_splats((uint8_t)(8 * N));
0755 return (typename batch<T, A>::register_type)vec_sro((__vector unsigned char)x.data, slider);
0756 }
0757 }
0758
0759
0760 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value && sizeof(T) != 8>>
0761 XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0762 {
0763 return vec_adds(self.data, other.data);
0764 }
0765
0766
0767 template <class A, class T, class... Values>
0768 XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<vsx>, Values... values) noexcept
0769 {
0770 static_assert(sizeof...(Values) == batch<T, A>::size, "consistent init");
0771 return typename batch<T, A>::register_type { values... };
0772 }
0773
0774 template <class A, class T, class... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
0775 XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<vsx>, Values... values) noexcept
0776 {
0777 static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
0778 return typename batch_bool<T, A>::register_type { static_cast<decltype(std::declval<typename batch_bool<T, A>::register_type>()[0])>(values ? -1LL : 0LL)... };
0779 }
0780
0781
0782
0783 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value && sizeof(T) == 1>>
0784 XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0785 {
0786 return vec_subs(self.data, other.data);
0787 }
0788
0789
0790 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0791 XSIMD_INLINE void store_aligned(T* mem, batch<T, A> const& self, requires_arch<vsx>) noexcept
0792 {
0793 vec_xst((typename batch<T, A>::register_type)self.data, 0, (builtin_t<T>*)mem);
0794 }
0795
0796
0797 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0798 XSIMD_INLINE void store_unaligned(T* mem, batch<T, A> const& self, requires_arch<vsx>) noexcept
0799 {
0800 store_aligned<A>(mem, self, vsx {});
0801 }
0802
0803
0804 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0805 XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0806 {
0807 return vec_sub(self.data, other.data);
0808 }
0809
0810
0811
0812 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0813 XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<vsx>) noexcept
0814 {
0815 return vec_perm(self.data, self.data,
0816 (__vector unsigned char) {
0817 4 * V0 + 0, 4 * V0 + 1, 4 * V0 + 2, 4 * V0 + 3,
0818 4 * V1 + 0, 4 * V1 + 1, 4 * V1 + 2, 4 * V1 + 3,
0819 4 * V2 + 0, 4 * V2 + 1, 4 * V2 + 2, 4 * V2 + 3,
0820 4 * V3 + 0, 4 * V3 + 1, 4 * V3 + 2, 4 * V3 + 3 });
0821 }
0822
0823 template <class A, uint64_t V0, uint64_t V1>
0824 XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<vsx>) noexcept
0825 {
0826 return vec_perm(self.data, self.data,
0827 (__vector unsigned char) {
0828 8 * V0 + 0,
0829 8 * V0 + 1,
0830 8 * V0 + 2,
0831 8 * V0 + 3,
0832 8 * V0 + 4,
0833 8 * V0 + 5,
0834 8 * V0 + 6,
0835 8 * V0 + 7,
0836 8 * V1 + 0,
0837 8 * V1 + 1,
0838 8 * V1 + 2,
0839 8 * V1 + 3,
0840 8 * V1 + 4,
0841 8 * V1 + 5,
0842 8 * V1 + 6,
0843 8 * V1 + 7,
0844 });
0845 }
0846
0847 template <class A, uint64_t V0, uint64_t V1>
0848 XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self, batch_constant<uint64_t, A, V0, V1>, requires_arch<vsx>) noexcept
0849 {
0850 return vec_perm(self.data, self.data,
0851 (__vector unsigned char) {
0852 8 * V0 + 0,
0853 8 * V0 + 1,
0854 8 * V0 + 2,
0855 8 * V0 + 3,
0856 8 * V0 + 4,
0857 8 * V0 + 5,
0858 8 * V0 + 6,
0859 8 * V0 + 7,
0860 8 * V1 + 0,
0861 8 * V1 + 1,
0862 8 * V1 + 2,
0863 8 * V1 + 3,
0864 8 * V1 + 4,
0865 8 * V1 + 5,
0866 8 * V1 + 6,
0867 8 * V1 + 7,
0868 });
0869 }
0870
0871 template <class A, uint64_t V0, uint64_t V1>
0872 XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self, batch_constant<uint64_t, A, V0, V1> mask, requires_arch<vsx>) noexcept
0873 {
0874 return bitwise_cast<int64_t>(swizzle(bitwise_cast<uint64_t>(self), mask, vsx {}));
0875 }
0876
0877 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0878 XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3>, requires_arch<vsx>) noexcept
0879 {
0880 return vec_perm(self.data, self.data,
0881 (__vector unsigned char) {
0882 4 * V0 + 0, 4 * V0 + 1, 4 * V0 + 2, 4 * V0 + 3,
0883 4 * V1 + 0, 4 * V1 + 1, 4 * V1 + 2, 4 * V1 + 3,
0884 4 * V2 + 0, 4 * V2 + 1, 4 * V2 + 2, 4 * V2 + 3,
0885 4 * V3 + 0, 4 * V3 + 1, 4 * V3 + 2, 4 * V3 + 3 });
0886 }
0887
0888 template <class A, uint32_t V0, uint32_t V1, uint32_t V2, uint32_t V3>
0889 XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self, batch_constant<uint32_t, A, V0, V1, V2, V3> mask, requires_arch<vsx>) noexcept
0890 {
0891 return bitwise_cast<int32_t>(swizzle(bitwise_cast<uint32_t>(self), mask, vsx {}));
0892 }
0893
0894 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>
0895 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<vsx>) noexcept
0896 {
0897 return vec_perm(self.data, self.data,
0898 (__vector unsigned char) {
0899 2 * V0 + 0, 2 * V0 + 1, 2 * V1 + 0, 2 * V1 + 1,
0900 2 * V2 + 0, 2 * V2 + 1, 2 * V3 + 0, 2 * V3 + 1,
0901 2 * V4 + 0, 2 * V4 + 1, 2 * V5 + 0, 2 * V5 + 1,
0902 2 * V6 + 0, 2 * V6 + 1, 2 * V7 + 0, 2 * V7 + 1 });
0903 }
0904
0905 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>
0906 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> mask, requires_arch<vsx>) noexcept
0907 {
0908 return bitwise_cast<int16_t>(swizzle(bitwise_cast<uint16_t>(self), mask, vsx {}));
0909 }
0910
0911
0912 template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
0913 XSIMD_INLINE batch<T, A> trunc(batch<T, A> const& self, requires_arch<vsx>) noexcept
0914 {
0915 return vec_trunc(self.data);
0916 }
0917
0918
0919 template <class A>
0920 XSIMD_INLINE std::array<batch<double, A>, 2> widen(batch<float, A> const& x, requires_arch<vsx>) noexcept
0921 {
0922 return { batch<double, A>(vec_doublel(x.data)), batch<double, A>(vec_doubleh(x.data)) };
0923 }
0924 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0925 XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<vsx>) noexcept
0926 {
0927 auto even = vec_mule(x.data, vec_splats(T(1)));
0928 auto odd = vec_mulo(x.data, vec_splats(T(1)));
0929 return { batch<widen_t<T>, A>(vec_mergel(even, odd)), batch<widen_t<T>, A>(vec_mergeh(even, odd)) };
0930 }
0931
0932
0933 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0934 XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0935 {
0936 return vec_mergel(self.data, other.data);
0937 }
0938
0939
0940 template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
0941 XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
0942 {
0943 return vec_mergeh(self.data, other.data);
0944 }
0945 }
0946 }
0947
0948 #endif