template <class A>
XSIMD_INLINE void store_complex_unaligned(std::complex<double>* dst, batch<std::complex<double>, A> const& src, requires_arch<neon64>) noexcept
{
store_complex_aligned(dst, src, A {});
}
/******* *set*
*******/
template <class A>
XSIMD_INLINE batch<double, A> set(batch<double, A> const&, requires_arch<neon64> req, double d0, double d1) noexcept
{
alignas(A::alignment()) double data[] = { d0, d1 }; return load_aligned<A>(data, {}, req);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> set(batch_bool<double, A> const&, requires_arch<neon64>, bool b0, bool b1) noexcept
{ using unsigned_type = as_unsigned_integer_t<double>; autoconst out = batch<unsigned_type, A> { static_cast<unsigned_type>(b0 ? -1LL : 0LL), static_cast<unsigned_type>(b1 ? -1LL : 0LL)
}; return { out.data };
}
/******* *neg*
*******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_u64_s64(vnegq_s64(vreinterpretq_s64_u64(rhs)));
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> neg(batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vnegq_s64(rhs);
}
template <class A>
XSIMD_INLINE batch<double, A> neg(batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vnegq_f64(rhs);
}
/******* *add*
*******/
template <class A>
XSIMD_INLINE batch<double, A> add(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vaddq_f64(lhs, rhs);
}
/******** *sadd*
********/
template <class A>
XSIMD_INLINE batch<double, A> sadd(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return add(lhs, rhs, neon64 {});
}
/******* *sub*
*******/
template <class A>
XSIMD_INLINE batch<double, A> sub(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vsubq_f64(lhs, rhs);
}
/******** *ssub*
********/
template <class A>
XSIMD_INLINE batch<double, A> ssub(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return sub(lhs, rhs, neon64 {});
}
/******* *mul*
*******/
template <class A>
XSIMD_INLINE batch<double, A> mul(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vmulq_f64(lhs, rhs);
}
/******* *div*
*******/
#ifdefined(XSIMD_FAST_INTEGER_DIVISION) template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcvtq_u64_f64(vcvtq_f64_u64(lhs) / vcvtq_f64_u64(rhs));
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcvtq_s64_f64(vcvtq_f64_s64(lhs) / vcvtq_f64_s64(rhs));
} #endif template <class A>
XSIMD_INLINE batch<double, A> div(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vdivq_f64(lhs, rhs);
}
/****** *eq*
******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_f64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_u64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> eq(batch_bool<double, A> const& lhs, batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vceqq_u64(lhs, rhs);
}
/************* *fast_cast*
*************/
namespace detail
{ template <class A>
XSIMD_INLINE batch<double, A> fast_cast(batch<int64_t, A> const& x, batch<double, A> const&, requires_arch<neon64>) noexcept
{ return vcvtq_f64_s64(x);
}
template <class A>
XSIMD_INLINE batch<double, A> fast_cast(batch<uint64_t, A> const& x, batch<double, A> const&, requires_arch<neon64>) noexcept
{ return vcvtq_f64_u64(x);
}
template <class A>
XSIMD_INLINE batch<int64_t, A> fast_cast(batch<double, A> const& x, batch<int64_t, A> const&, requires_arch<neon64>) noexcept
{ return vcvtq_s64_f64(x);
}
template <class A>
XSIMD_INLINE batch<uint64_t, A> fast_cast(batch<double, A> const& x, batch<uint64_t, A> const&, requires_arch<neon64>) noexcept
{ return vcvtq_u64_f64(x);
}
}
/****** *lt*
******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcltq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> lt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcltq_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcltq_f64(lhs, rhs);
}
/****** *le*
******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcleq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcleq_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcleq_f64(lhs, rhs);
}
/****** *gt*
******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgtq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgtq_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> gt(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgtq_f64(lhs, rhs);
}
/****** *ge*
******/
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgeq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgeq_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> ge(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vcgeq_f64(lhs, rhs);
}
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<neon64>) noexcept
{ using register_type = typename batch_bool<T_out, A>::register_type; return register_type(self);
}
/*************** *bitwise_and*
***************/
template <class A>
XSIMD_INLINE batch<double, A> bitwise_and(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(lhs),
vreinterpretq_u64_f64(rhs)));
}
template <class A>
XSIMD_INLINE batch_bool<double, A> bitwise_and(batch_bool<double, A> const& lhs, batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vandq_u64(lhs, rhs);
}
/************** *bitwise_or*
**************/
template <class A>
XSIMD_INLINE batch<double, A> bitwise_or(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(lhs),
vreinterpretq_u64_f64(rhs)));
}
template <class A>
XSIMD_INLINE batch_bool<double, A> bitwise_or(batch_bool<double, A> const& lhs, batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vorrq_u64(lhs, rhs);
}
/*************** *bitwise_xor*
***************/
template <class A>
XSIMD_INLINE batch<double, A> bitwise_xor(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(lhs),
vreinterpretq_u64_f64(rhs)));
}
template <class A>
XSIMD_INLINE batch_bool<double, A> bitwise_xor(batch_bool<double, A> const& lhs, batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return veorq_u64(lhs, rhs);
}
/******* *neq*
*******/
template <class A>
XSIMD_INLINE batch_bool<double, A> neq(batch_bool<double, A> const& lhs, batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return bitwise_xor(lhs, rhs, A {});
}
/*************** *bitwise_not*
***************/
template <class A>
XSIMD_INLINE batch<double, A> bitwise_not(batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_f64_u32(vmvnq_u32(vreinterpretq_u32_f64(rhs)));
}
template <class A>
XSIMD_INLINE batch_bool<double, A> bitwise_not(batch_bool<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vreinterpretq_u64_u32(vmvnq_u32(vreinterpretq_u32_u64(rhs)));
}
#ifdef __ARM_FEATURE_FMA 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<neon64>) noexcept
{ return vfmaq_f64(z, x, y);
}
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<neon64>) noexcept
{ return vfmaq_f64(-z, x, y);
} #endif
/********* *haddp*
*********/
template <class A>
XSIMD_INLINE batch<double, A> haddp(const batch<double, A>* row, requires_arch<neon64>) noexcept
{ return vpaddq_f64(row[0], row[1]);
}
/********** *insert*
**********/
template <class A, size_t I>
XSIMD_INLINE batch<double, A> insert(batch<double, A> const& self, double val, index<I>, requires_arch<neon64>) noexcept
{ return vsetq_lane_f64(val, self, I);
}
/************** *reduce_add*
**************/
namespace wrap
{ // TODO(c++17): Make a single function with if constexpr switch // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC) // the vector types are all aliases of the same type. template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
XSIMD_INLINE uint8_t x_vaddvq(uint8x16_t a) noexcept { return vaddvq_u8(a); } template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
XSIMD_INLINE int8_t x_vaddvq(int8x16_t a) noexcept { return vaddvq_s8(a); } template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
XSIMD_INLINE uint16_t x_vaddvq(uint16x8_t a) noexcept { return vaddvq_u16(a); } template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
XSIMD_INLINE int16_t x_vaddvq(int16x8_t a) noexcept { return vaddvq_s16(a); } template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
XSIMD_INLINE uint32_t x_vaddvq(uint32x4_t a) noexcept { return vaddvq_u32(a); } template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
XSIMD_INLINE int32_t x_vaddvq(int32x4_t a) noexcept { return vaddvq_s32(a); } template <class T, std::enable_if_t<std::is_same<T, uint64_t>::value, int> = 0>
XSIMD_INLINE uint64_t x_vaddvq(uint64x2_t a) noexcept { return vaddvq_u64(a); } template <class T, std::enable_if_t<std::is_same<T, int64_t>::value, int> = 0>
XSIMD_INLINE int64_t x_vaddvq(int64x2_t a) noexcept { return vaddvq_s64(a); } template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
XSIMD_INLINE float x_vaddvq(float32x4_t a) noexcept { return vaddvq_f32(a); } template <class T, std::enable_if_t<std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE double x_vaddvq(float64x2_t a) noexcept { return vaddvq_f64(a); }
}
template <class A, class T, detail::enable_neon64_type_t<T> = 0>
XSIMD_INLINE typename batch<T, A>::value_type reduce_add(batch<T, A> const& arg, requires_arch<neon64>) noexcept
{ using register_type = typename batch<T, A>::register_type; return wrap::x_vaddvq<T>(register_type(arg));
}
/************** *reduce_max*
**************/
namespace wrap
{ // TODO(c++17): Make a single function with if constexpr switch // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC) // the vector types are all aliases of the same type. template <class T, std::enable_if_t<std::is_same<T, uint8_t>::value, int> = 0>
XSIMD_INLINE uint8_t x_vmaxvq(uint8x16_t a) noexcept { return vmaxvq_u8(a); } template <class T, std::enable_if_t<std::is_same<T, int8_t>::value, int> = 0>
XSIMD_INLINE int8_t x_vmaxvq(int8x16_t a) noexcept { return vmaxvq_s8(a); } template <class T, std::enable_if_t<std::is_same<T, uint16_t>::value, int> = 0>
XSIMD_INLINE uint16_t x_vmaxvq(uint16x8_t a) noexcept { return vmaxvq_u16(a); } template <class T, std::enable_if_t<std::is_same<T, int16_t>::value, int> = 0>
XSIMD_INLINE int16_t x_vmaxvq(int16x8_t a) noexcept { return vmaxvq_s16(a); } template <class T, std::enable_if_t<std::is_same<T, uint32_t>::value, int> = 0>
XSIMD_INLINE uint32_t x_vmaxvq(uint32x4_t a) noexcept { return vmaxvq_u32(a); } template <class T, std::enable_if_t<std::is_same<T, int32_t>::value, int> = 0>
XSIMD_INLINE int32_t x_vmaxvq(int32x4_t a) noexcept { return vmaxvq_s32(a); } template <class T, std::enable_if_t<std::is_same<T, float>::value, int> = 0>
XSIMD_INLINE float x_vmaxvq(float32x4_t a) noexcept { return vmaxvq_f32(a); } template <class T, std::enable_if_t<std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE double x_vmaxvq(float64x2_t a) noexcept { return vmaxvq_f64(a); }
template <class A, class T, detail::enable_neon64_type_t<T> = 0>
XSIMD_INLINE typename batch<T, A>::value_type reduce_min(batch<T, A> const& arg, requires_arch<neon64>) noexcept
{ using register_type = typename batch<T, A>::register_type; return wrap::x_vminvq<T>(register_type(arg));
}
/********** *select*
**********/
template <class A>
XSIMD_INLINE batch<double, A> select(batch_bool<double, A> const& cond, batch<double, A> const& a, batch<double, A> const& b, requires_arch<neon64>) noexcept
{ return vbslq_f64(cond, a, b);
}
template <class A, bool... b>
XSIMD_INLINE batch<double, A> select(batch_bool_constant<double, A, b...> const&,
batch<double, A> const& true_br,
batch<double, A> const& false_br,
requires_arch<neon64>) noexcept
{ return select(batch_bool<double, A> { b... }, true_br, false_br, neon64 {});
}
/********** *zip_lo*
**********/ template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_u8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_s8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_u16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_s16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_u32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_s32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> zip_lo(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch<float, A> zip_lo(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_f32(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch<double, A> zip_lo(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip1q_f64(lhs, rhs);
}
/********** *zip_hi*
**********/
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_u8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_s8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_u16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_s16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_u32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_s32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> zip_hi(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_s64(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch<float, A> zip_hi(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_f32(lhs, rhs);
}
template <class A>
XSIMD_INLINE batch<double, A> zip_hi(batch<double, A> const& lhs, batch<double, A> const& rhs, requires_arch<neon64>) noexcept
{ return vzip2q_f64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, requires_arch<neon64>) noexcept
{ return bitwise_rshift<A>(lhs, n, neon {});
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ // Blindly converting to signed since out of bounds shifts are UB anyways
assert(detail::shifts_all_positive(rhs)); return vshlq_u64(lhs, vnegq_s64(vreinterpretq_s64_u64(rhs)));
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, requires_arch<neon64>) noexcept
{ return bitwise_rshift<A>(lhs, n, neon {});
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon64>) noexcept
{ return vshlq_s64(lhs, vnegq_s64(rhs));
}
namespace wrap
{ // TODO(c++17): Make a single function with if constexpr switch // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC) // the vector types are all aliases of the same type. template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, uint8_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(uint8x16_t a) noexcept { return vreinterpretq_f64_u8(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, int8_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(int8x16_t a) noexcept { return vreinterpretq_f64_s8(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, uint16_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(uint16x8_t a) noexcept { return vreinterpretq_f64_u16(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, int16_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(int16x8_t a) noexcept { return vreinterpretq_f64_s16(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, uint32_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(uint32x4_t a) noexcept { return vreinterpretq_f64_u32(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, int32_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(int32x4_t a) noexcept { return vreinterpretq_f64_s32(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, uint64_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(uint64x2_t a) noexcept { return vreinterpretq_f64_u64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, int64_t>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(int64x2_t a) noexcept { return vreinterpretq_f64_s64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, float>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(float32x4_t a) noexcept { return vreinterpretq_f64_f32(a); } template <class R, class T, std::enable_if_t<std::is_same<R, double>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE float64x2_t x_vreinterpretq(float64x2_t a) noexcept { return a; }
// TODO(c++17): Make a single function with if constexpr switch // Templating on the scalar type `T` is required because in some compilers (e.g. MSVC) // the vector types are all aliases of the same type. template <class R, class T, std::enable_if_t<std::is_same<R, uint8_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE uint8x16_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_u8_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, int8_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE int8x16_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_s8_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, uint16_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE uint16x8_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_u16_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, int16_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE int16x8_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_s16_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, uint32_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE uint32x4_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_u32_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, int32_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE int32x4_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_s32_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, uint64_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE uint64x2_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_u64_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, int64_t>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE int64x2_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_s64_f64(a); } template <class R, class T, std::enable_if_t<std::is_same<R, float>::value && std::is_same<T, double>::value, int> = 0>
XSIMD_INLINE float32x4_t x_vreinterpretq(float64x2_t a) noexcept { return vreinterpretq_f32_f64(a); }
}
template <class A, class T>
XSIMD_INLINE batch<double, A> bitwise_cast(batch<T, A> const& arg, batch<double, A> const&, requires_arch<neon64>) noexcept
{ using register_type = typename batch<T, A>::register_type; return wrap::x_vreinterpretq<double, map_to_sized_type_t<T>>(register_type(arg));
}
template <class A, class R>
XSIMD_INLINE batch<R, A> bitwise_cast(batch<double, A> const& arg, batch<R, A> const&, requires_arch<neon64>) noexcept
{ using src_register_type = typename batch<double, A>::register_type; return wrap::x_vreinterpretq<map_to_sized_type_t<R>, double>(src_register_type(arg));
}
template <class A>
XSIMD_INLINE batch<double, A> bitwise_cast(batch<double, A> const& arg, batch<double, A> const&, requires_arch<neon64>) noexcept
{ return arg;
}
/********* *isnan*
*********/
template <class A>
XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& arg, requires_arch<neon64>) noexcept
{ return !(arg == arg);
}
/**************** *rotate_left*
****************/ template <size_t N, class A>
XSIMD_INLINE batch<double, A> rotate_left(batch<double, A> const& a, requires_arch<neon64>) noexcept
{ return vextq_f64(a, a, N);
}
}
template <typename T, class A, T... Values> struct batch_constant;
namespace kernel
{ /********************* *swizzle(dynamic)*
*********************/ template <class A>
XSIMD_INLINE batch<uint8_t, A> swizzle(batch<uint8_t, A> const& self, batch<uint8_t, A> idx,
requires_arch<neon64>) noexcept
{ return vqtbl1q_u8(self, idx);
}
template <class A>
XSIMD_INLINE batch<int8_t, A> swizzle(batch<int8_t, A> const& self, batch<uint8_t, A> idx,
requires_arch<neon64>) noexcept
{ return vqtbl1q_s8(self, idx);
}
template <class A>
XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self,
batch<uint16_t, A> idx,
requires_arch<neon64>) noexcept
{ using batch_type = batch<uint8_t, A>; using index_type = batch<uint8_t, A>; return vreinterpretq_u16_u8(swizzle(batch_type(vreinterpretq_u8_u16(self)),
index_type(vreinterpretq_u8_u16(idx * 0x0202 + 0x0100)),
neon64 {}));
}
template <class A>
XSIMD_INLINE batch<int16_t, A> swizzle(batch<int16_t, A> const& self,
batch<uint16_t, A> idx,
requires_arch<neon64>) noexcept
{ return bitwise_cast<int16_t>(swizzle(bitwise_cast<uint16_t>(self), idx, neon64 {}));
}
template <class A>
XSIMD_INLINE batch<uint32_t, A> swizzle(batch<uint32_t, A> const& self,
batch<uint32_t, A> idx,
requires_arch<neon64>) noexcept
{ using batch_type = batch<uint8_t, A>; using index_type = batch<uint8_t, A>; return vreinterpretq_u32_u8(swizzle(batch_type(vreinterpretq_u8_u32(self)),
index_type(vreinterpretq_u8_u32(idx * 0x04040404 + 0x03020100)),
neon64 {}));
}
template <class A>
XSIMD_INLINE batch<int32_t, A> swizzle(batch<int32_t, A> const& self,
batch<uint32_t, A> idx,
requires_arch<neon64>) noexcept
{ return bitwise_cast<int32_t>(swizzle(bitwise_cast<uint32_t>(self), idx, neon64 {}));
}
template <class A>
XSIMD_INLINE batch<uint64_t, A> swizzle(batch<uint64_t, A> const& self,
batch<uint64_t, A> idx,
requires_arch<neon64>) noexcept
{ using batch_type = batch<uint8_t, A>; using index_type = batch<uint8_t, A>; return vreinterpretq_u64_u8(swizzle(batch_type(vreinterpretq_u8_u64(self)),
index_type(vreinterpretq_u8_u64(idx * 0x0808080808080808ull + 0x0706050403020100ull)),
neon64 {}));
}
template <class A>
XSIMD_INLINE batch<int64_t, A> swizzle(batch<int64_t, A> const& self,
batch<uint64_t, A> idx,
requires_arch<neon64>) noexcept
{ return bitwise_cast<int64_t>(swizzle(bitwise_cast<uint64_t>(self), idx, neon64 {}));
}
template <class A>
XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self,
batch<uint32_t, A> idx,
requires_arch<neon64>) noexcept
{ return bitwise_cast<float>(swizzle(bitwise_cast<uint32_t>(self), idx, neon64 {}));
}
template <class A>
XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self,
batch<uint64_t, A> idx,
requires_arch<neon64>) noexcept
{ return bitwise_cast<double>(swizzle(bitwise_cast<uint64_t>(self), idx, neon64 {}));
}
template <class CB1, class CB2, class IS> struct index_burst_impl;
template <typename T1, class A, typename T2, T2... V,
T2... incr> struct index_burst_impl<batch_constant<T1, A>, batch_constant<T2, A, V...>,
std::integer_sequence<T2, incr...>>
{ using type = batch_constant<T2, A, V...>;
};
template <typename T1, class A, T1 V0, T1... V1, typename T2, T2... V2, T2... incr> struct index_burst_impl<batch_constant<T1, A, V0, V1...>, batch_constant<T2, A, V2...>,
std::integer_sequence<T2, incr...>>
{ using next_input = batch_constant<T1, A, V1...>; using next_output = batch_constant<T2, A, V2..., (V0 + incr)...>; using type = typename index_burst_impl<next_input, next_output, std::integer_sequence<T2, incr...>>::type;
};
template <class B, class T> struct index_burst;
template <typename Tp, class A, Tp... V, typename T> struct index_burst<batch_constant<Tp, A, V...>, T>
{ static constexpr size_t mul = sizeof(Tp) / sizeof(T); using input = batch_constant<Tp, A, (mul * V)...>; using output = batch_constant<T, A>; using type = typename index_burst_impl<input, output, std::make_integer_sequence<T, mul>>::type;
};
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.