namespace xsimd
{ template <typename T, class A, bool... Values> struct batch_bool_constant;
template <class T_out, class T_in, class A>
XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& x) noexcept;
template <typename T, class A, T... Values> struct batch_constant;
namespace kernel
{ // builtin_t<T> - the scalar type as it would be used for a vector intrinsic // VSX vector intrinsics do not support long, unsigned long, and char // The builtin<T> definition can be used to map the incoming // type to the right one to be used with the intrinsics. template <typename T> struct builtin_scalar
{ using type = T;
};
template <> struct builtin_scalar<unsignedlong>
{ using type = unsignedlonglong;
};
template <> struct builtin_scalar<long>
{ using type = longlong;
};
template <> struct builtin_scalar<char>
{ using type = typename std::conditional<std::is_signed<char>::value, signedchar, unsignedchar>::type;
};
template <typename T> using builtin_t = typename builtin_scalar<T>::type;
template <class A, class T>
XSIMD_INLINE batch<T, A> avg(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept; template <class A, class T>
XSIMD_INLINE batch<T, A> avgr(batch<T, A> const&, batch<T, A> const&, requires_arch<common>) noexcept;
// abs template <class A>
XSIMD_INLINE batch<float, A> abs(batch<float, A> const& self, requires_arch<vsx>) noexcept
{ return vec_abs(self.data);
}
template <class A>
XSIMD_INLINE batch<double, A> abs(batch<double, A> const& self, requires_arch<vsx>) noexcept
{ return vec_abs(self.data);
}
// add template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> add(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_add(self.data, other.data);
}
// all template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_all_ne(self.data, vec_xor(self.data, self.data));
}
// any template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_any_ne(self.data, vec_xor(self.data, self.data));
}
// avgr template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value && sizeof(T) < 8>>
XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_avg(self.data, other.data);
} template <class A>
XSIMD_INLINE batch<float, A> avgr(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
{ return avgr(self, other, common {});
} template <class A>
XSIMD_INLINE batch<double, A> avgr(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
{ return avgr(self, other, common {});
}
// avg template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
XSIMD_INLINE batch<T, A> avg(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) < 8)
{
constexpr auto nbit = 8 * sizeof(T) - 1; auto adj = bitwise_cast<T>(bitwise_cast<as_unsigned_integer_t<T>>((self ^ other) << nbit) >> nbit); return avgr(self, other, A {}) - adj;
} else
{ return avg(self, other, common {});
}
} template <class A>
XSIMD_INLINE batch<float, A> avg(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
{ return avg(self, other, common {});
} template <class A>
XSIMD_INLINE batch<double, A> avg(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
{ return avg(self, other, common {});
}
// batch_bool_cast template <class A, class T_out, class T_in>
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
{ return (typename batch_bool<T_out, A>::register_type)self.data;
}
// bitwise_and template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_and(self.data, other.data);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_and(self.data, other.data);
}
// bitwise_andnot template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_and(self.data, vec_nor(other.data, other.data));
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ return self.data & ~other.data;
}
// bitwise_lshift template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& self, int32_t other, requires_arch<vsx>) noexcept
{ using shift_type = as_unsigned_integer_t<T>;
batch<shift_type, A> shift(static_cast<shift_type>(other)); return vec_sl(self.data, shift.data);
}
// bitwise_not template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_nor(self.data, self.data);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_nor(self.data, self.data);
}
// bitwise_or template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_or(self.data, other.data);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_or(self.data, other.data);
}
// bitwise_rshift template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& self, int32_t other, requires_arch<vsx>) noexcept
{ using shift_type = as_unsigned_integer_t<T>;
batch<shift_type, A> shift(static_cast<shift_type>(other));
XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
{ return vec_sra(self.data, shift.data);
} else
{ return vec_sr(self.data, shift.data);
}
}
// bitwise_xor template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_xor(self.data, other.data);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_xor(self.data, other.data);
}
// bitwise_cast template <class A, class T_in, class T_out>
XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& self, batch<T_out, A> const&, requires_arch<vsx>) noexcept
{ return (typename batch<T_out, A>::register_type)(self.data);
}
// broadcast template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> broadcast(T val, requires_arch<vsx>) noexcept
{ return vec_splats(static_cast<builtin_t<T>>(val));
}
// ceil template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
XSIMD_INLINE batch<T, A> ceil(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_ceil(self.data);
}
// store_complex namespace detail
{ // complex_low template <class A>
XSIMD_INLINE batch<float, A> complex_low(batch<std::complex<float>, A> const& self, requires_arch<vsx>) noexcept
{ return vec_mergeh(self.real().data, self.imag().data);
} template <class A>
XSIMD_INLINE batch<double, A> complex_low(batch<std::complex<double>, A> const& self, requires_arch<vsx>) noexcept
{ return vec_mergeh(self.real().data, self.imag().data);
} // complex_high template <class A>
XSIMD_INLINE batch<float, A> complex_high(batch<std::complex<float>, A> const& self, requires_arch<vsx>) noexcept
{ return vec_mergel(self.real().data, self.imag().data);
} template <class A>
XSIMD_INLINE batch<double, A> complex_high(batch<std::complex<double>, A> const& self, requires_arch<vsx>) noexcept
{ return vec_mergel(self.real().data, self.imag().data);
}
}
// decr_if template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
XSIMD_INLINE batch<T, A> decr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<vsx>) noexcept
{ return self + batch<T, A>((typename batch<T, A>::register_type)mask.data);
}
// div template <class A>
XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<vsx>) noexcept
{ return vec_div(self.data, other.data);
} template <class A>
XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<vsx>) noexcept
{ return vec_div(self.data, other.data);
}
// fast_cast namespace detail
{ template <class A>
XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<vsx>) noexcept
{ return vec_ctf(self.data, 0);
} template <class A>
XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& self, batch<float, A> const&, requires_arch<vsx>) noexcept
{ return vec_ctf(self.data, 0);
}
template <class A>
XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<vsx>) noexcept
{ return vec_cts(self.data, 0);
}
template <class A>
XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<float, A> const& self, batch<uint32_t, A> const&, requires_arch<vsx>) noexcept
{ return vec_ctu(self.data, 0);
}
}
// fma template <class A>
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
{ return vec_madd(x.data, y.data, z.data);
}
template <class A>
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
{ return vec_madd(x.data, y.data, z.data);
}
// fms template <class A>
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
{ return vec_msub(x.data, y.data, z.data);
}
template <class A>
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
{ return vec_msub(x.data, y.data, z.data);
}
// eq template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ auto res = vec_cmpeq(self.data, other.data); return *reinterpret_cast<typename batch_bool<T, A>::register_type*>(&res);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ auto res = vec_cmpeq(self.data, other.data); return *reinterpret_cast<typename batch_bool<T, A>::register_type*>(&res);
}
// first template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE T first(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_extract(self.data, 0);
}
// floor template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
XSIMD_INLINE batch<T, A> floor(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_floor(self.data);
}
// ge template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_cmpge(self.data, other.data);
}
// gt template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_cmpgt(self.data, other.data);
}
// haddp template <class A>
XSIMD_INLINE batch<float, A> haddp(batch<float, A> const* row, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_mergee(row[0].data, row[1].data); // v00 v10 v02 v12 auto tmp1 = vec_mergeo(row[0].data, row[1].data); // v01 v11 v03 v13 auto tmp4 = vec_add(tmp0, tmp1); // (v00 + v01, v10 + v11, v02 + v03, v12 + v13)
template <class A>
XSIMD_INLINE batch<double, A> haddp(batch<double, A> const* row, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_mergee(row[0].data, row[1].data); // v00 v10 v02 v12 auto tmp1 = vec_mergeo(row[0].data, row[1].data); // v01 v11 v03 v13 return vec_add(tmp0, tmp1);
}
// incr_if template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
XSIMD_INLINE batch<T, A> incr_if(batch<T, A> const& self, batch_bool<T, A> const& mask, requires_arch<vsx>) noexcept
{ return self - batch<T, A>((typename batch<T, A>::register_type)mask.data);
}
// insert template <class A, class T, size_t I, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<vsx>) noexcept
{ return vec_insert(val, self.data, I);
}
// isnan template <class A>
XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<vsx>) noexcept
{ return ~vec_cmpeq(self.data, self.data);
} template <class A>
XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<vsx>) noexcept
{ return ~vec_cmpeq(self.data, self.data);
}
// load_unaligned template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<vsx>) noexcept
{ return (typename batch<T, A>::register_type)vec_xl(0, (builtin_t<T>*)mem);
}
// load_aligned template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<vsx>) noexcept
{ return load_unaligned<A>(mem, kernel::convert<T> {}, vsx {});
}
// le template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_cmple(self.data, other.data);
}
// lt template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_cmplt(self.data, other.data);
}
// max template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_max(self.data, other.data);
}
// min template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_min(self.data, other.data);
}
// mul template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> mul(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return self.data * other.data;
}
// neg template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> neg(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return -(self.data);
}
// neq template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return ~vec_cmpeq(self.data, other.data);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<vsx>) noexcept
{ return ~vec_cmpeq(self.data, other.data);
}
// reciprocal template <class A>
XSIMD_INLINE batch<float, A> reciprocal(batch<float, A> const& self,
kernel::requires_arch<vsx>)
{ return vec_re(self.data);
} template <class A>
XSIMD_INLINE batch<double, A> reciprocal(batch<double, A> const& self,
kernel::requires_arch<vsx>)
{ return vec_re(self.data);
}
// reduce_add template <class A>
XSIMD_INLINE signed reduce_add(batch<signed, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_add(self.data, tmp0); // v0 + v3, v1 + v2, v2 + v1, v3 + v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 + v1, v2 + v1, v3 + v0, v3 + v0 auto tmp3 = vec_add(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE unsigned reduce_add(batch<unsigned, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_add(self.data, tmp0); // v0 + v3, v1 + v2, v2 + v1, v3 + v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 + v1, v2 + v1, v3 + v0, v3 + v0 auto tmp3 = vec_add(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE float reduce_add(batch<float, A> const& self, requires_arch<vsx>) noexcept
{ // FIXME: find an in-order approach auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_add(self.data, tmp0); // v0 + v3, v1 + v2, v2 + v1, v3 + v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 + v1, v2 + v1, v3 + v0, v3 + v0 auto tmp3 = vec_add(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE double reduce_add(batch<double, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v1, v0 auto tmp1 = vec_add(self.data, tmp0); // v0 + v1, v1 + v0 return vec_extract(tmp1, 0);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE T reduce_add(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return reduce_add(self, common {});
}
// reduce_mul template <class A>
XSIMD_INLINE signed reduce_mul(batch<signed, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_mul(self.data, tmp0); // v0 * v3, v1 * v2, v2 * v1, v3 * v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 * v1, v2 * v1, v3 * v0, v3 * v0 auto tmp3 = vec_mul(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE unsigned reduce_mul(batch<unsigned, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_mul(self.data, tmp0); // v0 * v3, v1 * v2, v2 * v1, v3 * v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 * v1, v2 * v1, v3 * v0, v3 * v0 auto tmp3 = vec_mul(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE float reduce_mul(batch<float, A> const& self, requires_arch<vsx>) noexcept
{ // FIXME: find an in-order approach auto tmp0 = vec_reve(self.data); // v3, v2, v1, v0 auto tmp1 = vec_mul(self.data, tmp0); // v0 * v3, v1 * v2, v2 * v1, v3 * v0 auto tmp2 = vec_mergel(tmp1, tmp1); // v2 * v1, v2 * v1, v3 * v0, v3 * v0 auto tmp3 = vec_mul(tmp1, tmp2); return vec_extract(tmp3, 0);
} template <class A>
XSIMD_INLINE double reduce_mul(batch<double, A> const& self, requires_arch<vsx>) noexcept
{ auto tmp0 = vec_reve(self.data); // v1, v0 auto tmp1 = vec_mul(self.data, tmp0); // v0 * v1, v1 * v0 return vec_extract(tmp1, 0);
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE T reduce_mul(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return reduce_mul(self, common {});
}
// round
// vec_round exists also for float vectors but is mapped to vrfin instruction which uses the wrong rounding mode #ifdefined __has_builtin && __has_builtin(__builtin_vsx_xvrspi) template <class A>
XSIMD_INLINE batch<float, A> round(batch<float, A> const& self, requires_arch<vsx>) noexcept
{ return __builtin_vsx_xvrspi(self.data);
} #endif // For double vectors vec_round uses xvrdpi which does the right thing template <class A>
XSIMD_INLINE batch<double, A> round(batch<double, A> const& self, requires_arch<vsx>) noexcept
{ return vec_round(self.data);
}
// rsqrt template <class A>
XSIMD_INLINE batch<float, A> rsqrt(batch<float, A> const& val, requires_arch<vsx>) noexcept
{ return vec_rsqrt(val.data);
} template <class A>
XSIMD_INLINE batch<double, A> rsqrt(batch<double, A> const& val, requires_arch<vsx>) noexcept
{ return vec_rsqrt(val.data);
}
// select template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
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
{ return vec_sel(false_br.data, true_br.data, cond.data);
} template <class A, class T, bool... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
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
{ return select(batch_bool<T, A> { Values... }, true_br, false_br, vsx {});
}
// sqrt template <class A>
XSIMD_INLINE batch<float, A> sqrt(batch<float, A> const& val, requires_arch<vsx>) noexcept
{ return vec_sqrt(val.data);
}
template <class A>
XSIMD_INLINE batch<double, A> sqrt(batch<double, A> const& val, requires_arch<vsx>) noexcept
{ return vec_sqrt(val.data);
}
// slide_left template <size_t N, class A, class T>
XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<vsx>) noexcept
{
XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
{ return batch<T, A>(0);
} else
{ auto slider = vec_splats((uint8_t)(8 * N)); return (typename batch<T, A>::register_type)vec_slo(x.data, slider);
}
}
// slide_right template <size_t N, class A, class T>
XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<vsx>) noexcept
{
XSIMD_IF_CONSTEXPR(N == batch<T, A>::size * sizeof(T))
{ return batch<T, A>(0);
} else
{ auto slider = vec_splats((uint8_t)(8 * N)); return (typename batch<T, A>::register_type)vec_sro((__vector unsignedchar)x.data, slider);
}
}
// sadd template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value && sizeof(T) != 8>>
XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_adds(self.data, other.data);
}
// set template <class A, class T, class... Values>
XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<vsx>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch<T, A>::size, "consistent init"); returntypename batch<T, A>::register_type { values... };
}
template <class A, class T, class... Values, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<vsx>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init"); returntypename batch_bool<T, A>::register_type { static_cast<decltype(std::declval<typename batch_bool<T, A>::register_type>()[0])>(values ? -1LL : 0LL)... };
}
// ssub
template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value && sizeof(T) == 1>>
XSIMD_INLINE batch<T, A> ssub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_subs(self.data, other.data);
}
// store_aligned template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE void store_aligned(T* mem, batch<T, A> const& self, requires_arch<vsx>) noexcept
{
vec_xst((typename batch<T, A>::register_type)self.data, 0, (builtin_t<T>*)mem);
}
// store_unaligned template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE void store_unaligned(T* mem, batch<T, A> const& self, requires_arch<vsx>) noexcept
{
store_aligned<A>(mem, self, vsx {});
}
// sub template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> sub(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_sub(self.data, other.data);
}
// trunc template <class A, class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
XSIMD_INLINE batch<T, A> trunc(batch<T, A> const& self, requires_arch<vsx>) noexcept
{ return vec_trunc(self.data);
}
// widen template <class A>
XSIMD_INLINE std::array<batch<double, A>, 2> widen(batch<float, A> const& x, requires_arch<vsx>) noexcept
{ return { batch<double, A>(vec_doublel(x.data)), batch<double, A>(vec_doubleh(x.data)) };
} template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<vsx>) noexcept
{ auto even = vec_mule(x.data, vec_splats(T(1))); // x0, x2, x4, x6 auto odd = vec_mulo(x.data, vec_splats(T(1))); // x1, x3, x5, x7 return { batch<widen_t<T>, A>(vec_mergel(even, odd)), batch<widen_t<T>, A>(vec_mergeh(even, odd)) };
}
// zip_hi template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_mergel(self.data, other.data);
}
// zip_lo template <class A, class T, class = std::enable_if_t<std::is_scalar<T>::value>>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<vsx>) noexcept
{ return vec_mergeh(self.data, other.data);
}
}
}
#endif
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.