/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * Copyright (c) QuantStack * * Copyright (c) Serge Guelton * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
template <class A, class... Args>
XSIMD_INLINE batch_bool<float, A> set(batch_bool<float, A> const&, requires_arch<neon>, Args... args) noexcept
{ using register_type = typename batch_bool<float, A>::register_type; using unsigned_type = as_unsigned_integer_t<float>; return register_type { static_cast<unsigned_type>(args ? -1LL : 0LL)... };
}
/************* * from_bool *
*************/
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_u8(arg, vdupq_n_u8(1));
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_s8(reinterpret_cast<int8x16_t>(arg.data), vdupq_n_s8(1));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_u16(arg, vdupq_n_u16(1));
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_s16(reinterpret_cast<int16x8_t>(arg.data), vdupq_n_s16(1));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_u32(arg, vdupq_n_u32(1));
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_s32(reinterpret_cast<int32x4_t>(arg.data), vdupq_n_s32(1));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_u64(arg, vdupq_n_u64(1));
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> from_bool(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return vandq_s64(reinterpret_cast<int64x2_t>(arg.data), vdupq_n_s64(1));
}
template <class A>
XSIMD_INLINE batch<float, A> from_bool(batch_bool<float, A> const& arg, requires_arch<neon>) noexcept
{ return vreinterpretq_f32_u32(vandq_u32(arg, vreinterpretq_u32_f32(vdupq_n_f32(1.f))));
}
/******** * load *
********/
// It is not possible to use a call to A::alignment() here, so use an // immediate instead. #ifdefined(__clang__) || defined(__GNUC__) #define xsimd_aligned_load(inst, type, expr) inst((type)__builtin_assume_aligned(expr, 16)) #elifdefined(_MSC_VER) #define xsimd_aligned_load(inst, type, expr) inst##_ex((type)expr, 128) #else #define xsimd_aligned_load(inst, type, expr) inst((type)expr) #endif
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_u8, uint8_t*, src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_s8, int8_t*, src);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_u16, uint16_t*, src);
} template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_s16, int16_t*, src);
} template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_u32, uint32_t*, src);
} template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_s32, int32_t*, src);
} template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_u64, uint64_t*, src);
} template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> load_aligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_s64, int64_t*, src);
}
template <class A>
XSIMD_INLINE batch<float, A> load_aligned(floatconst* src, convert<float>, requires_arch<neon>) noexcept
{ return xsimd_aligned_load(vld1q_f32, float*, src);
}
#undef xsimd_aligned_load
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_u8((uint8_t*)src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_s8((int8_t*)src);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_u16((uint16_t*)src);
} template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_s16((int16_t*)src);
} template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_u32((uint32_t*)src);
} template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_s32((int32_t*)src);
} template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_u64((uint64_t*)src);
} template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> load_unaligned(T const* src, convert<T>, requires_arch<neon>) noexcept
{ return vld1q_s64((int64_t*)src);
}
template <class A>
XSIMD_INLINE batch<float, A> load_unaligned(floatconst* src, convert<float>, requires_arch<neon>) noexcept
{ return vld1q_f32(src);
}
/********* * store *
*********/
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_u8((uint8_t*)dst, src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_s8((int8_t*)dst, src);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_u16((uint16_t*)dst, src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_s16((int16_t*)dst, src);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_u32((uint32_t*)dst, src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_s32((int32_t*)dst, src);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_u64((uint64_t*)dst, src);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE void store_aligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
vst1q_s64((int64_t*)dst, src);
}
template <class A>
XSIMD_INLINE void store_aligned(float* dst, batch<float, A> const& src, requires_arch<neon>) noexcept
{
vst1q_f32(dst, src);
}
template <class A, class T>
XSIMD_INLINE void store_unaligned(T* dst, batch<T, A> const& src, requires_arch<neon>) noexcept
{
store_aligned<A>(dst, src, A {});
}
template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
XSIMD_INLINE batch<T, A> mul(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ using register_type = typename batch<T, A>::register_type; const detail::excluding_int64_dispatcher::binary dispatcher = {
std::make_tuple(wrap::vmulq_u8, wrap::vmulq_s8, wrap::vmulq_u16, wrap::vmulq_s16,
wrap::vmulq_u32, wrap::vmulq_s32, wrap::vmulq_f32)
}; return dispatcher.apply(register_type(lhs), register_type(rhs));
}
/******* * div *
*******/
#ifdefined(XSIMD_FAST_INTEGER_DIVISION) template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vcvtq_s32_f32(vcvtq_f32_s32(lhs) / vcvtq_f32_s32(rhs));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> div(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vcvtq_u32_f32(vcvtq_f32_u32(lhs) / vcvtq_f32_u32(rhs));
} #endif
template <class A>
XSIMD_INLINE batch<float, A> div(batch<float, A> const& lhs, batch<float, A> const& rhs, requires_arch<neon>) noexcept
{ // from stackoverflow & https://projectne10.github.io/Ne10/doc/NE10__divc_8neon_8c_source.html // get an initial estimate of 1/b.
float32x4_t rcp = reciprocal(rhs);
// use a couple Newton-Raphson steps to refine the estimate. Depending on your // application's accuracy requirements, you may be able to get away with only // one refinement (instead of the two used here). Be sure to test!
rcp = vmulq_f32(vrecpsq_f32(rhs, rcp), rcp);
rcp = vmulq_f32(vrecpsq_f32(rhs, rcp), rcp);
// and finally, compute a / b = a * (1 / b) return vmulq_f32(lhs, rcp);
}
template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ using register_type = typename batch<T, A>::register_type; const detail::excluding_int64_comp_dispatcher::binary dispatcher = {
std::make_tuple(wrap::vceqq_u8, wrap::vceqq_s8, wrap::vceqq_u16, wrap::vceqq_s16,
wrap::vceqq_u32, wrap::vceqq_s32, wrap::vceqq_f32)
}; return dispatcher.apply(register_type(lhs), register_type(rhs));
}
template <class A, class T, detail::exclude_int64_neon_t<T> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
{ using register_type = typename batch_bool<T, A>::register_type; using dispatcher_type = detail::neon_comp_dispatcher_impl<uint8x16_t, uint16x8_t, uint32x4_t>::binary; const dispatcher_type dispatcher = {
std::make_tuple(wrap::vceqq_u8, wrap::vceqq_u16, wrap::vceqq_u32)
}; return dispatcher.apply(register_type(lhs), register_type(rhs));
}
template <class A, class T, detail::enable_sized_integral_t<T, 8> = 0>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return batch_bool<T, A>({ lhs.get(0) == rhs.get(0), lhs.get(1) == rhs.get(1) });
}
template <class A, class T, detail::enable_sized_integral_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<neon>) noexcept
{ return batch_bool<T, A>({ lhs.get(0) == rhs.get(0), lhs.get(1) == rhs.get(1) });
}
/************* * 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<neon>) noexcept
{ return vcvtq_f32_s32(self);
}
template <class A>
XSIMD_INLINE batch<float, A> fast_cast(batch<uint32_t, A> const& self, batch<float, A> const&, requires_arch<neon>) noexcept
{ return vcvtq_f32_u32(self);
}
template <class A>
XSIMD_INLINE batch<int32_t, A> fast_cast(batch<float, A> const& self, batch<int32_t, A> const&, requires_arch<neon>) noexcept
{ return vcvtq_s32_f32(self);
}
template <class A>
XSIMD_INLINE batch<uint32_t, A> fast_cast(batch<float, A> const& self, batch<uint32_t, A> const&, requires_arch<neon>) noexcept
{ return vcvtq_u32_f32(self);
}
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<neon>) noexcept
{ using register_type = typename batch_bool<T_out, A>::register_type; return register_type(self);
}
template <class A, class T, detail::enable_neon_type_t<T> = 0>
XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ using register_type = typename batch<T, A>::register_type; return detail::bitwise_xor_neon(register_type(lhs), register_type(rhs));
}
template <class A, class T, detail::enable_neon_type_t<T> = 0>
XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
{ using register_type = typename batch_bool<T, A>::register_type; return detail::bitwise_xor_neon(register_type(lhs), register_type(rhs));
}
/******* * neq *
*******/
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> neq(batch_bool<T, A> const& lhs, batch_bool<T, A> const& rhs, requires_arch<neon>) noexcept
{ return bitwise_xor(lhs, rhs, A {});
}
#ifdef __ARM_FEATURE_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<neon>) noexcept
{ return vfmaq_f32(z, x, y);
}
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<neon>) noexcept
{ return vfmaq_f32(-z, x, y);
} #endif
template <class A>
XSIMD_INLINE batch<float, A>
reciprocal(const batch<float, A>& x,
kernel::requires_arch<neon>) noexcept
{ return vrecpeq_f32(x);
}
/********** * insert *
**********/
template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_u8(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_s8(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_u16(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<int16_t, A> insert(batch<int16_t, A> const& self, int16_t val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_s16(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_u32(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_s32(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_u64(val, self, I);
}
template <class A, class T, size_t I, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_s64(val, self, I);
}
template <class A, size_t I>
XSIMD_INLINE batch<float, A> insert(batch<float, A> const& self, float val, index<I>, requires_arch<neon>) noexcept
{ return vsetq_lane_f32(val, self, I);
}
template <class A>
XSIMD_INLINE batch<int32_t, A> nearbyint_as_int(batch<float, A> const& self,
requires_arch<neon>) noexcept
{ /* origin: https://github.com/DLTcollab/sse2neon/blob/cad518a93b326f0f644b7972d488d04eaa2b0475/sse2neon.h#L4028-L4047 */ // Contributors to this work are: // John W. Ratcliff <jratcliffscarab@gmail.com> // Brandon Rowlett <browlett@nvidia.com> // Ken Fast <kfast@gdeb.com> // Eric van Beurden <evanbeurden@nvidia.com> // Alexander Potylitsin <apotylitsin@nvidia.com> // Hasindu Gamaarachchi <hasindu2008@gmail.com> // Jim Huang <jserv@biilabs.io> // Mark Cheng <marktwtn@biilabs.io> // Malcolm James MacLeod <malcolm@gulden.com> // Devin Hussey (easyaspi314) <husseydevin@gmail.com> // Sebastian Pop <spop@amazon.com> // Developer Ecosystem Engineering <DeveloperEcosystemEngineering@apple.com> // Danila Kutenin <danilak@google.com> // François Turban (JishinMaster) <francois.turban@gmail.com> // Pei-Hsuan Hung <afcidk@gmail.com> // Yang-Hao Yuan <yanghau@biilabs.io> // Syoyo Fujita <syoyo@lighttransport.com> // Brecht Van Lommel <brecht@blender.org>
/* * sse2neon is freely redistributable under the MIT License. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/
namespace detail
{ template <class T, class A, class V>
XSIMD_INLINE T sum_batch(V const& arg) noexcept
{
T res = T(0); for (std::size_t i = 0; i < batch<T, A>::size; ++i)
{
res += arg[i];
} return res;
}
}
template <class U>
U apply(comp_return_type<U> cond, U lhs, U rhs) const noexcept
{ using func_type = U (*)(comp_return_type<U>, U, U); auto func = xsimd::detail::get<func_type>(m_func); return func(cond, lhs, rhs);
}
};
namespace detail
{ template <class A, class T>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const&, batch<T, A> const& /*rhs*/, std::size_t, ::xsimd::detail::index_sequence<>) noexcept
{
assert(false && "extract_pair out of bounds"); return batch<T, A> {};
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_u8(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_s8(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_u16(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_s16(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_u32(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_s32(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_u64(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t I, size_t... Is, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_s64(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, size_t I, size_t... Is>
XSIMD_INLINE batch<float, A> extract_pair(batch<float, A> const& lhs, batch<float, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vextq_f32(rhs, lhs, I);
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
template <class A, class T, size_t... Is>
XSIMD_INLINE batch<T, A> extract_pair_impl(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, ::xsimd::detail::index_sequence<0, Is...>) noexcept
{ if (n == 0)
{ return rhs;
} else
{ return extract_pair(lhs, rhs, n, ::xsimd::detail::index_sequence<Is...>());
}
}
}
template <class A, class T>
XSIMD_INLINE batch<T, A> extract_pair(batch<T, A> const& lhs, batch<T, A> const& rhs, std::size_t n, requires_arch<neon>) noexcept
{
constexpr std::size_t size = batch<T, A>::size;
assert(n < size && "index in bounds"); return detail::extract_pair_impl(lhs, rhs, n, ::xsimd::detail::make_index_sequence<size>());
}
namespace detail
{ template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& /*lhs*/, int /*n*/, ::xsimd::detail::int_sequence<>) noexcept
{
assert(false && "bitwise_lshift out of bounds"); return batch<T, A> {};
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_u8(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_s8(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_u16(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_s16(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_u32(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_s32(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_u64(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshlq_n_s64(lhs, I);
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int... Is>
XSIMD_INLINE batch<T, A> bitwise_lshift_impl(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<0, Is...>) noexcept
{ if (n == 0)
{ return lhs;
} else
{ return bitwise_lshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
}
template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, int n, requires_arch<neon>) noexcept
{
constexpr int size = sizeof(typename batch<T, A>::value_type) * 8;
assert(0 <= n && n < size && "index in bounds"); return detail::bitwise_lshift_impl(lhs, n, ::xsimd::detail::make_int_sequence<size>());
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s8(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s16(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s32(lhs, rhs);
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u64(lhs, rhs);
}
template <class A, class T, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_lshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s64(lhs, rhs);
}
namespace detail
{ template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& /*lhs*/, int /*n*/, ::xsimd::detail::int_sequence<>) noexcept
{
assert(false && "bitwise_rshift out of bounds"); return batch<T, A> {};
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_u8(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_s8(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_u16(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_s16(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_u32(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_s32(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_unsigned_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_u64(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int I, int... Is, detail::enable_sized_signed_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<I, Is...>) noexcept
{ if (n == I)
{ return vshrq_n_s64(lhs, I);
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
template <class A, class T, int... Is>
XSIMD_INLINE batch<T, A> bitwise_rshift_impl(batch<T, A> const& lhs, int n, ::xsimd::detail::int_sequence<0, Is...>) noexcept
{ if (n == 0)
{ return lhs;
} else
{ return bitwise_rshift(lhs, n, ::xsimd::detail::int_sequence<Is...>());
}
}
}
template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, int n, requires_arch<neon>) noexcept
{
constexpr int size = sizeof(typename batch<T, A>::value_type) * 8;
assert(0 <= n && n < size && "index in bounds"); return detail::bitwise_rshift_impl(lhs, n, ::xsimd::detail::make_int_sequence<size>());
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u8(lhs, vnegq_s8(rhs));
}
template <class A, class T, detail::enable_sized_signed_t<T, 1> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s8(lhs, vnegq_s8(rhs));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u16(lhs, vnegq_s16(rhs));
}
template <class A, class T, detail::enable_sized_signed_t<T, 2> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s16(lhs, vnegq_s16(rhs));
}
template <class A, class T, detail::enable_sized_unsigned_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<as_signed_integer_t<T>, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_u32(lhs, vnegq_s32(rhs));
}
template <class A, class T, detail::enable_sized_signed_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> bitwise_rshift(batch<T, A> const& lhs, batch<T, A> const& rhs, requires_arch<neon>) noexcept
{ return vshlq_s32(lhs, vnegq_s32(rhs));
}
// Overloads of bitwise shifts accepting two batches of uint64/int64 are not available with ARMv7
/******* * all *
*******/
template <class A, class T, detail::enable_sized_t<T, 8> = 0>
XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{
uint64x1_t tmp = vand_u64(vget_low_u64(arg), vget_high_u64(arg)); return vget_lane_u64(tmp, 0) == ~0ULL;
}
template <class A, class T, detail::enable_sized_t<T, 1> = 0>
XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u8(arg)), neon {});
}
template <class A, class T, detail::enable_sized_t<T, 2> = 0>
XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u16(arg)), neon {});
}
template <class A, class T, detail::enable_sized_t<T, 4> = 0>
XSIMD_INLINE bool all(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return all(batch_bool<uint64_t, A>(vreinterpretq_u64_u32(arg)), neon {});
}
/******* * any *
*******/
template <class A, class T, detail::enable_sized_t<T, 8> = 0>
XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{
uint32x2_t tmp = vqmovn_u64(arg); return vget_lane_u64(vreinterpret_u64_u32(tmp), 0) != 0;
}
template <class A, class T, detail::enable_sized_t<T, 1> = 0>
XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u8(arg)), neon {});
}
template <class A, class T, detail::enable_sized_t<T, 2> = 0>
XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u16(arg)), neon {});
}
template <class A, class T, detail::enable_sized_t<T, 4> = 0>
XSIMD_INLINE bool any(batch_bool<T, A> const& arg, requires_arch<neon>) noexcept
{ return any(batch_bool<uint64_t, A>(vreinterpretq_u64_u32(arg)), neon {});
}
template <class A>
XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& arg, requires_arch<neon>) noexcept
{ return !(arg == arg);
}
// slide_left namespace detail
{ template <size_t N> struct slider_left
{ template <class A, class T>
XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
{ constauto left = vdupq_n_u8(0); constauto right = bitwise_cast<uint8_t>(x).data; const batch<uint8_t, A> res(vextq_u8(left, right, 16 - N)); return bitwise_cast<T>(res);
}
};
template <> struct slider_left<0>
{ template <class A, class T>
XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
{ return x;
}
};
} // namespace detail
template <size_t N, class A, class T>
XSIMD_INLINE batch<T, A> slide_left(batch<T, A> const& x, requires_arch<neon>) noexcept
{ return detail::slider_left<N> {}(x, A {});
}
// slide_right namespace detail
{ template <size_t N> struct slider_right
{ template <class A, class T>
XSIMD_INLINE batch<T, A> operator()(batch<T, A> const& x, requires_arch<neon>) noexcept
{ constauto left = bitwise_cast<uint8_t>(x).data; constauto right = vdupq_n_u8(0); const batch<uint8_t, A> res(vextq_u8(left, right, N)); return bitwise_cast<T>(res);
}
};
template <> struct slider_right<16>
{ template <class A, class T>
XSIMD_INLINE batch<T, A> operator()(batch<T, A> const&, requires_arch<neon>) noexcept
{ return batch<T, A> {};
}
};
} // namespace detail
template <size_t N, class A, class T>
XSIMD_INLINE batch<T, A> slide_right(batch<T, A> const& x, requires_arch<neon>) noexcept
{ return detail::slider_right<N> {}(x, A {});
}
/**************** * rotate_left *
****************/ namespace wrap
{ template <size_t N>
XSIMD_INLINE uint8x16_t rotate_left_u8(uint8x16_t a, uint8x16_t b) noexcept { return vextq_u8(a, b, N); } template <size_t N>
XSIMD_INLINE int8x16_t rotate_left_s8(int8x16_t a, int8x16_t b) noexcept { return vextq_s8(a, b, N); } template <size_t N>
XSIMD_INLINE uint16x8_t rotate_left_u16(uint16x8_t a, uint16x8_t b) noexcept { return vextq_u16(a, b, N); } template <size_t N>
XSIMD_INLINE int16x8_t rotate_left_s16(int16x8_t a, int16x8_t b) noexcept { return vextq_s16(a, b, N); } template <size_t N>
XSIMD_INLINE uint32x4_t rotate_left_u32(uint32x4_t a, uint32x4_t b) noexcept { return vextq_u32(a, b, N); } template <size_t N>
XSIMD_INLINE int32x4_t rotate_left_s32(int32x4_t a, int32x4_t b) noexcept { return vextq_s32(a, b, N); } template <size_t N>
XSIMD_INLINE uint64x2_t rotate_left_u64(uint64x2_t a, uint64x2_t b) noexcept { return vextq_u64(a, b, N); } template <size_t N>
XSIMD_INLINE int64x2_t rotate_left_s64(int64x2_t a, int64x2_t b) noexcept { return vextq_s64(a, b, N); } template <size_t N>
XSIMD_INLINE float32x4_t rotate_left_f32(float32x4_t a, float32x4_t b) noexcept { returnvextq_f32(a, b, N); }
}
template <size_t N, class A, class T, detail::enable_neon_type_t<T> = 0>
XSIMD_INLINE batch<T, A> rotate_left(batch<T, A> const& a, requires_arch<neon>) noexcept
{ using register_type = typename batch<T, A>::register_type; const detail::neon_dispatcher::binary dispatcher = {
std::make_tuple(wrap::rotate_left_u8<N>, wrap::rotate_left_s8<N>, wrap::rotate_left_u16<N>, wrap::rotate_left_s16<N>,
wrap::rotate_left_u32<N>, wrap::rotate_left_s32<N>, wrap::rotate_left_u64<N>, wrap::rotate_left_s64<N>,
wrap::rotate_left_f32<N>)
}; return dispatcher.apply(register_type(a), register_type(a));
}
}
template <typename T, class A, T... Values> struct batch_constant;
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.