mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 23:25:24 +02:00
libstdc++: Fix find_last_set(simd_mask) to ignore padding bits
With the change to the AVX512 find_last_set implementation, the change to AVX512 operator!= is unnecessary. However, the latter was not producing optimal code and unnecessarily set the padding bits. In theory, the compiler could determine that with the new != implementation, the bit operation for clearing the padding bits is a no-op and can be elided. Signed-off-by: Matthias Kretz <m.kretz@gsi.de> libstdc++-v3/ChangeLog: PR libstdc++/115454 * include/experimental/bits/simd_x86.h (_S_not_equal_to): Use neq comparison instead of bitwise negation after eq. (_S_find_last_set): Clear unused high bits before computing bit_width. * testsuite/experimental/simd/pr115454_find_last_set.cc: New test.
This commit is contained in:
@@ -2339,29 +2339,29 @@ template <typename _Abi, typename>
|
||||
__assert_unreachable<_Tp>();
|
||||
}
|
||||
else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
|
||||
return ~_mm512_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
|
||||
return _mm512_mask_cmpneq_epi64_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
|
||||
return ~_mm512_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
|
||||
return _mm512_mask_cmpneq_epi32_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 2)
|
||||
return ~_mm512_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
|
||||
return _mm512_mask_cmpneq_epi16_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 1)
|
||||
return ~_mm512_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
|
||||
return _mm512_mask_cmpneq_epi8_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
|
||||
return ~_mm256_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
|
||||
return _mm256_mask_cmpneq_epi64_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
|
||||
return ~_mm256_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
|
||||
return _mm256_mask_cmpneq_epi32_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 2)
|
||||
return ~_mm256_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
|
||||
return _mm256_mask_cmpneq_epi16_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 1)
|
||||
return ~_mm256_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
|
||||
return _mm256_mask_cmpneq_epi8_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
|
||||
return ~_mm_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
|
||||
return _mm_mask_cmpneq_epi64_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
|
||||
return ~_mm_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
|
||||
return _mm_mask_cmpneq_epi32_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 2)
|
||||
return ~_mm_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
|
||||
return _mm_mask_cmpneq_epi16_mask(__k1, __xi, __yi);
|
||||
else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 1)
|
||||
return ~_mm_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
|
||||
return _mm_mask_cmpneq_epi8_mask(__k1, __xi, __yi);
|
||||
else
|
||||
__assert_unreachable<_Tp>();
|
||||
} // }}}
|
||||
@@ -5292,7 +5292,7 @@ template <typename _Abi, typename>
|
||||
_S_find_last_set(simd_mask<_Tp, _Abi> __k)
|
||||
{
|
||||
if constexpr (__is_avx512_abi<_Abi>())
|
||||
return std::__bit_width(__k._M_data._M_data) - 1;
|
||||
return std::__bit_width(_Abi::_S_masked(__k._M_data)._M_data) - 1;
|
||||
else
|
||||
return _Base::_S_find_last_set(__k);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target *-*-* } }
|
||||
// { dg-require-effective-target c++17 }
|
||||
// { dg-additional-options "-march=x86-64-v4" { target avx512f } }
|
||||
// { dg-require-cmath "" }
|
||||
|
||||
#include <experimental/simd>
|
||||
|
||||
namespace stdx = std::experimental;
|
||||
|
||||
using T = std::uint64_t;
|
||||
|
||||
template <typename U, int N>
|
||||
using V = stdx::simd<U, stdx::simd_abi::deduce_t<U, N>>;
|
||||
|
||||
[[gnu::noinline, gnu::noipa]]
|
||||
int reduce(V<T, 4> x)
|
||||
{
|
||||
static_assert(stdx::find_last_set(V<T, 4>([](unsigned i) { return i; }) != V<T, 4>(0)) == 3);
|
||||
return stdx::find_last_set(x != -1);
|
||||
}
|
||||
|
||||
[[gnu::noinline, gnu::noipa]]
|
||||
int reduce2()
|
||||
{
|
||||
using M8 = typename V<short, 8>::mask_type;
|
||||
using M4 = typename V<int, 4>::mask_type;
|
||||
if constexpr (sizeof(M8) == sizeof(M4))
|
||||
{
|
||||
M4 k;
|
||||
__builtin_memcpy(&__data(k), &__data(M8(true)), sizeof(M4));
|
||||
return stdx::find_last_set(k);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
const V<T, 4> x {};
|
||||
|
||||
const int r = reduce(x);
|
||||
if (r != 3)
|
||||
__builtin_abort();
|
||||
|
||||
const int r2 = reduce2();
|
||||
if (r2 != 3)
|
||||
__builtin_abort();
|
||||
}
|
||||
Reference in New Issue
Block a user