Message ID | 2402789.jZfb76A358@centauriprime |
---|---|
State | New |
Headers | show |
Series | libstdc++: Fix find_last_set(simd_mask) to ignore padding bits | expand |
Ping. I fear that time to make GCC 11.5 is running out. -Matthias On Tuesday, 18 June 2024 08:22:13 GMT+2 Matthias Kretz wrote: > Tested on x86_64-linux-gnu (also -m32 and -mx32), aarch64-linux-gnu, and > arm- linux-gnueabi(hf). > > OK for trunk and backports? OK, to go for GCC 11.5 as early as possible? > > ----------------------- 8< ----------------------- > > 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. > --- > .../include/experimental/bits/simd_x86.h | 26 +++++----- > .../simd/pr115454_find_last_set.cc | 49 +++++++++++++++++++ > 2 files changed, 62 insertions(+), 13 deletions(-) > create mode 100644 libstdc++-v3/testsuite/experimental/simd/ > pr115454_find_last_set.cc > > > -- > ────────────────────────────────────────────────────────────────────────── > Dr. Matthias Kretz https://mattkretz.github.io > GSI Helmholtz Centre for Heavy Ion Research https://gsi.de > stdₓ::simd > ──────────────────────────────────────────────────────────────────────────
On Tue, 18 Jun 2024 at 07:22, Matthias Kretz <m.kretz@gsi.de> wrote: > > Tested on x86_64-linux-gnu (also -m32 and -mx32), aarch64-linux-gnu, and arm- > linux-gnueabi(hf). > > OK for trunk and backports? OK, to go for GCC 11.5 as early as possible? OK for all branches, thanks. > > ----------------------- 8< ----------------------- > > 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. > --- > .../include/experimental/bits/simd_x86.h | 26 +++++----- > .../simd/pr115454_find_last_set.cc | 49 +++++++++++++++++++ > 2 files changed, 62 insertions(+), 13 deletions(-) > create mode 100644 libstdc++-v3/testsuite/experimental/simd/ > pr115454_find_last_set.cc > > > -- > ────────────────────────────────────────────────────────────────────────── > Dr. Matthias Kretz https://mattkretz.github.io > GSI Helmholtz Centre for Heavy Ion Research https://gsi.de > stdₓ::simd > ──────────────────────────────────────────────────────────────────────────
diff --git a/libstdc++-v3/include/experimental/bits/simd_x86.h b/libstdc++-v3/include/experimental/bits/simd_x86.h index 517c4b4a5be..8a23aa2082b 100644 --- a/libstdc++-v3/include/experimental/bits/simd_x86.h +++ b/libstdc++-v3/include/experimental/bits/simd_x86.h @@ -2339,29 +2339,29 @@ _S_not_equal_to(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y) __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 @@ _S_find_first_set(simd_mask<_Tp, _Abi> __k) _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); } diff --git a/libstdc++-v3/testsuite/experimental/simd/pr115454_find_last_set.cc b/libstdc++-v3/testsuite/experimental/simd/pr115454_find_last_set.cc new file mode 100644 index 00000000000..b47f19d3067 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/simd/pr115454_find_last_set.cc @@ -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(); +}
Tested on x86_64-linux-gnu (also -m32 and -mx32), aarch64-linux-gnu, and arm- linux-gnueabi(hf). OK for trunk and backports? OK, to go for GCC 11.5 as early as possible? ----------------------- 8< ----------------------- 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. --- .../include/experimental/bits/simd_x86.h | 26 +++++----- .../simd/pr115454_find_last_set.cc | 49 +++++++++++++++++++ 2 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/simd/ pr115454_find_last_set.cc -- ────────────────────────────────────────────────────────────────────────── Dr. Matthias Kretz https://mattkretz.github.io GSI Helmholtz Centre for Heavy Ion Research https://gsi.de stdₓ::simd ──────────────────────────────────────────────────────────────────────────