// mul_hi template <class A>
XSIMD_INLINE batch<int32_t, A> mul_hi(batch<int32_t, A> const& self, batch<int32_t, A> const& other, requires_arch<sse4_1>) noexcept
{
__m128i even = _mm_mul_epi32(self, other); // 64-bit products in lanes 0,2
__m128i odd = _mm_mul_epi32(_mm_srli_epi64(self, 32), _mm_srli_epi64(other, 32)); // hi halves in the low 32 of each 64 lane of (even>>32), and in the high 32 of odd
__m128i even_hi = _mm_srli_epi64(even, 32); // blend: 32-bit lanes {even_hi[0], odd_hi[1], even_hi[2], odd_hi[3]} return _mm_blend_epi16(even_hi, odd, 0xCC);
} template <class A>
XSIMD_INLINE batch<uint32_t, A> mul_hi(batch<uint32_t, A> const& self, batch<uint32_t, A> const& other, requires_arch<sse4_1>) noexcept
{
__m128i even = _mm_mul_epu32(self, other);
__m128i odd = _mm_mul_epu32(_mm_srli_epi64(self, 32), _mm_srli_epi64(other, 32));
__m128i even_hi = _mm_srli_epi64(even, 32); return _mm_blend_epi16(even_hi, odd, 0xCC);
}
template <class A>
XSIMD_INLINE batch<uint64_t, A> mul_hi(batch<uint64_t, A> const& self, batch<uint64_t, A> const& other, requires_arch<sse4_1>) noexcept
{ return detail::mulhi_u64_core<A>(self, other,
[](batch<uint64_t, A> a, batch<uint64_t, A> b)
{ return batch<uint64_t, A>(_mm_mul_epu32(a, b)); });
} template <class A>
XSIMD_INLINE batch<int64_t, A> mul_hi(batch<int64_t, A> const& self, batch<int64_t, A> const& other, requires_arch<sse4_1>) noexcept
{ return detail::mulhi_i64_core<A>(self, other,
[](batch<uint64_t, A> a, batch<uint64_t, A> b)
{ return batch<uint64_t, A>(_mm_mul_epu32(a, b)); });
}
// nearbyint template <class A>
XSIMD_INLINE batch<float, A> nearbyint(batch<float, A> const& self, requires_arch<sse4_1>) noexcept
{ return _mm_round_ps(self, _MM_FROUND_TO_NEAREST_INT);
} template <class A>
XSIMD_INLINE batch<double, A> nearbyint(batch<double, A> const& self, requires_arch<sse4_1>) noexcept
{ return _mm_round_pd(self, _MM_FROUND_TO_NEAREST_INT);
}
template <class A, class T, class = std::enable_if_t<std::is_integral<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<sse4_1>) noexcept
{ return _mm_blendv_epi8(false_br, true_br, cond);
} template <class A>
XSIMD_INLINE batch<float, A> select(batch_bool<float, A> const& cond, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<sse4_1>) noexcept
{ return _mm_blendv_ps(false_br, true_br, cond);
} template <class A>
XSIMD_INLINE batch<double, A> select(batch_bool<double, A> const& cond, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<sse4_1>) noexcept
{ return _mm_blendv_pd(false_br, true_br, cond);
}
template <class A, class T, bool... Values, class = std::enable_if_t<std::is_integral<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<sse4_1>) noexcept
{
constexpr int mask = batch_bool_constant<T, A, Values...>::mask();
XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{ return _mm_blend_epi16(false_br, true_br, mask);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{
constexpr int imask = detail::interleave(mask); return _mm_blend_epi16(false_br, true_br, imask);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{
constexpr int imask = detail::interleave(mask);
constexpr int imask2 = detail::interleave(imask); return _mm_blend_epi16(false_br, true_br, imask2);
} else
{ return select(batch_bool_constant<T, A, Values...>(), true_br, false_br, ssse3 {});
}
} template <class A, bool... Values>
XSIMD_INLINE batch<float, A> select(batch_bool_constant<float, A, Values...> const&, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<sse4_1>) noexcept
{
constexpr int mask = batch_bool_constant<float, A, Values...>::mask(); return _mm_blend_ps(false_br, true_br, mask);
} template <class A, bool... Values>
XSIMD_INLINE batch<double, A> select(batch_bool_constant<double, A, Values...> const&, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<sse4_1>) noexcept
{
constexpr int mask = batch_bool_constant<double, A, Values...>::mask(); return _mm_blend_pd(false_br, true_br, mask);
}
// trunc template <class A>
XSIMD_INLINE batch<float, A> trunc(batch<float, A> const& self, requires_arch<sse4_1>) noexcept
{ return _mm_round_ps(self, _MM_FROUND_TO_ZERO);
} template <class A>
XSIMD_INLINE batch<double, A> trunc(batch<double, A> const& self, requires_arch<sse4_1>) noexcept
{ return _mm_round_pd(self, _MM_FROUND_TO_ZERO);
}
// widen template <class A, class T>
XSIMD_INLINE std::array<batch<widen_t<T>, A>, 2> widen(batch<T, A> const& x, requires_arch<sse4_1>) noexcept
{
__m128i x_lo = x;
__m128i x_hi = _mm_unpackhi_epi64(x, x);
__m128i lo, hi;
XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{
XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
{
lo = _mm_cvtepi32_epi64(x_lo);
hi = _mm_cvtepi32_epi64(x_hi);
} else
{
lo = _mm_cvtepu32_epi64(x_lo);
hi = _mm_cvtepu32_epi64(x_hi);
}
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{
XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
{
lo = _mm_cvtepi16_epi32(x_lo);
hi = _mm_cvtepi16_epi32(x_hi);
} else
{
lo = _mm_cvtepu16_epi32(x_lo);
hi = _mm_cvtepu16_epi32(x_hi);
}
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{
XSIMD_IF_CONSTEXPR(std::is_signed<T>::value)
{
lo = _mm_cvtepi8_epi16(x_lo);
hi = _mm_cvtepi8_epi16(x_hi);
} else
{
lo = _mm_cvtepu8_epi16(x_lo);
hi = _mm_cvtepu8_epi16(x_hi);
}
} return { lo, hi };
} template <class A>
XSIMD_INLINE std::array<batch<double, A>, 2> widen(batch<float, A> const& x, requires_arch<sse4_1>) noexcept
{
__m128 x_shuf = _mm_unpackhi_ps(x, x);
__m128d lo = _mm_cvtps_pd(x);
__m128d hi = _mm_cvtps_pd(x_shuf); return { lo, hi };
}
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.