Re: [PATCH] libstdc++: arm: convert vpadd_* operands to intrinsic types [PR122981]
Torbjorn SVENSSON <[email protected]>
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Matthias, Thanks for the reply. On 2026-08-13 16:22, Matthias Kretz wrote: > Thanks Torbjorn, > > and sorry for not looking earlier (yes, vacation and the madness that comes > after). No worries! :) > I'm fairly certain that the code worked at some point. Actually, a quick test > on Compiler Explorer and I can't reproduce the issue. But I must admit that > I'm lost to all the variants of ARM, and I'm probably not testing the one that > fails for you. > > Can you show me how to compile https://compiler-explorer.com/z/jWPEPTo8a so > that it requires the cast to intrinsic type? First of all, the toolchain that you select is a linux based and it has different rules than arm-none-eabi. Regardless, the problem happens when the GNU vector has different size than what NEON can work with. In your example at https://compiler-explorer.com/z/jWPEPTo8a, simply change to using V [[gnu::vector_size(4)]] = signed char; and you will see the problem, regardless if you are using linux ABI or none ABI. Calling the std::experimental::parallelism_v2::__to_intrin() before would ensure that the input value matches the expected vector size. Here is an updated example that has both a working variant and a failing one: https://compiler-explorer.com/z/aWz1P4Kdj > Also, if you know of a better way to turn a vector-mask into a bit-mask, I'd > be happy to replace that code altogether. Sorry, don't think I'm the right person for this task. :| Kind regards, Torbjörn > > - Matthias > > Torbjorn SVENSSON [Thursday, 6 August 2026, 17:55:25 CEST]: >> On 2026-07-24 18:34, Jonathan Wakely wrote: >>> On Sun, 12 Jul 2026 at 19:42 +0200, Torbjörn SVENSSON wrote: >>>> I hope this is the right fix for the issue. >>>> I've regtested for arm-none-eabi on top of r15-11320-g7909a9f85f30b6 and >>>> it applies cleanly on trunk. The new test is derived from >>>> libstdc++-v3/testsuite/experimental/simd/pr115454_find_last_set.cc. >>>> >>>> Ok for trunk, releases/gcc-16 and releases/gcc-15? >>> >>> OK for trunk but for the backports I'd prefer to wait for Matthias to >>> confirm this is the correct fix. >> >> I've been holding of to push this since I do not want to push something that >> might not be correct. Do you have any idea when Matthias is back (assuming >> vacation period right now)? >> >> Kind regards, >> Torbjörn >> >>>> When testing r15-10798-gae573c9d0e7f1c, I noticed that the >>>> experimental/simd/pr115454_find_last_set.cc was failing due to that the >>>> GNU vector type was used instead of the NEON intrinsic type. >>>> >>>> PR libstdc++/122981 >>>> >>>> libstdc++-v3/ChangeLog: >>>> >>>> * include/experimental/bits/simd_neon.h: Convert AArch32 NEON >>>> vpadd_* operands to intrinsic types. >>>> * testsuite/experimental/simd/pr122981_find_last_set_neon.cc: New >>>> test. >>>> >>>> Signed-off-by: Torbjörn SVENSSON <[email protected]> >>>> --- >>>> .../include/experimental/bits/simd_neon.h | 31 +++++++----- >>>> .../simd/pr122981_find_last_set_neon.cc | 50 +++++++++++++++++++ >>>> 2 files changed, 69 insertions(+), 12 deletions(-) >>>> create mode 100644 >>>> libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.cc >>>> >>>> diff --git a/libstdc++-v3/include/experimental/bits/simd_neon.h >>>> b/libstdc++-v3/include/experimental/bits/simd_neon.h index >>>> d3785db2bfd..23c205f3dc9 100644 >>>> --- a/libstdc++-v3/include/experimental/bits/simd_neon.h >>>> +++ b/libstdc++-v3/include/experimental/bits/simd_neon.h >>>> @@ -297,9 +297,10 @@ struct _MaskImplNeonMixin >>>> __zero))[0]; >>>> #else >>>> return __vector_bitcast<_UShort>( >>>> - vpadd_s8(vpadd_s8(vpadd_s8(__lo64(__asint), __hi64(__asint)), >>>> - __zero), >>>> - __zero))[0]; >>>> + vpadd_s8(vpadd_s8(vpadd_s8(__to_intrin(__lo64(__asint)), >>>> + __to_intrin(__hi64(__asint))), >>>> + __to_intrin(__zero)), >>>> + __to_intrin(__zero)))[0]; >>>> #endif >>>> } >>>> else if constexpr (sizeof(_Tp) == 2) >>>> @@ -313,9 +314,10 @@ struct _MaskImplNeonMixin >>>> #ifdef __aarch64__ >>>> return vaddvq_s16(__asint); >>>> #else >>>> - return vpadd_s16( >>>> - vpadd_s16(vpadd_s16(__lo64(__asint), __hi64(__asint)), __zero), >>>> - __zero)[0]; >>>> + return >>>> vpadd_s16(vpadd_s16(vpadd_s16(__to_intrin(__lo64(__asint)), >>>> + __to_intrin(__hi64(__asint))), >>>> + __to_intrin(__zero)), >>>> + __to_intrin(__zero))[0]; >>>> #endif >>>> } >>>> else if constexpr (sizeof(_Tp) == 4) >>>> @@ -329,8 +331,9 @@ struct _MaskImplNeonMixin >>>> #ifdef __aarch64__ >>>> return vaddvq_s32(__asint); >>>> #else >>>> - return vpadd_s32(vpadd_s32(__lo64(__asint), __hi64(__asint)), >>>> - __zero)[0]; >>>> + return vpadd_s32(vpadd_s32(__to_intrin(__lo64(__asint)), >>>> + __to_intrin(__hi64(__asint))), >>>> + __to_intrin(__zero))[0]; >>>> #endif >>>> } >>>> else if constexpr (sizeof(_Tp) == 8) >>>> @@ -353,8 +356,10 @@ struct _MaskImplNeonMixin >>>> #ifdef __aarch64__ >>>> return vaddv_s8(__asint); >>>> #else >>>> - return vpadd_s8(vpadd_s8(vpadd_s8(__asint, __zero), __zero), >>>> - __zero)[0]; >>>> + return vpadd_s8(vpadd_s8(vpadd_s8(__to_intrin(__asint), >>>> + __to_intrin(__zero)), >>>> + __to_intrin(__zero)), >>>> + __to_intrin(__zero))[0]; >>>> #endif >>>> } >>>> else if constexpr (sizeof(_Tp) == 2) >>>> @@ -368,7 +373,9 @@ struct _MaskImplNeonMixin >>>> #ifdef __aarch64__ >>>> return vaddv_s16(__asint); >>>> #else >>>> - return vpadd_s16(vpadd_s16(__asint, __zero), __zero)[0]; >>>> + return vpadd_s16(vpadd_s16(__to_intrin(__asint), >>>> + __to_intrin(__zero)), >>>> + __to_intrin(__zero))[0]; >>>> #endif >>>> } >>>> else if constexpr (sizeof(_Tp) == 4) >>>> @@ -377,7 +384,7 @@ struct _MaskImplNeonMixin >>>> #ifdef __aarch64__ >>>> return vaddv_s32(__asint); >>>> #else >>>> - return vpadd_s32(__asint, __zero)[0]; >>>> + return vpadd_s32(__to_intrin(__asint), >>>> __to_intrin(__zero))[0]; >>>> #endif >>>> } >>>> else >>>> diff --git >>>> a/libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.c >>>> c >>>> b/libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.c >>>> c new file mode 100644 >>>> index 00000000000..f7f79166ae6 >>>> --- /dev/null >>>> +++ >>>> b/libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.c >>>> c @@ -0,0 +1,50 @@ >>>> +// { dg-options "-std=gnu++17" } >>>> +// { dg-do compile { target c++17 } } >>>> +// { dg-require-effective-target arm_neon_ok } >>>> +// { dg-add-options arm_neon } >>>> +// { dg-require-cmath "" } >>>> + >>>> +#include <experimental/simd> >>>> + >>>> +namespace stdx = std::experimental; >>>> + >>>> +template <typename U, int N> >>>> +using V = stdx::simd<U, stdx::simd_abi::deduce_t<U, N>>; >>>> + >>>> +template <typename U, int N> >>>> +[[gnu::noinline, gnu::noipa]] >>>> +int reduce(typename V<U, N>::mask_type x) >>>> +{ >>>> + using M = typename V<U, N>::mask_type; >>>> + static_assert(stdx::find_last_set(M(true)) == N - 1); >>>> + return stdx::find_last_set(x); >>>> +} >>>> + >>>> +int main() >>>> +{ >>>> + // 16 bytes: 16 int8_t lanes, 8 int16_t lanes, 4 int32_t lanes. >>>> + const int r_int8_16 = reduce<std::int8_t, 16>(typename V<std::int8_t, >>>> 16>::mask_type(true)); + if (r_int8_16 != 15) >>>> + __builtin_abort(); >>>> + >>>> + const int r_int16_8 = reduce<std::int16_t, 8>(typename V<std::int16_t, >>>> 8>::mask_type(true)); + if (r_int16_8 != 7) >>>> + __builtin_abort(); >>>> + >>>> + const int r_int32_4 = reduce<std::int32_t, 4>(typename V<std::int32_t, >>>> 4>::mask_type(true)); + if (r_int32_4 != 3) >>>> + __builtin_abort(); >>>> + >>>> + // 8 bytes: 8 int8_t lanes, 4 int16_t lanes, 2 int32_t lanes. >>>> + const int r_int8_8 = reduce<std::int8_t, 8>(typename V<std::int8_t, >>>> 8>::mask_type(true)); + if (r_int8_8 != 7) >>>> + __builtin_abort(); >>>> + >>>> + const int r_int16_4 = reduce<std::int16_t, 4>(typename V<std::int16_t, >>>> 4>::mask_type(true)); + if (r_int16_4 != 3) >>>> + __builtin_abort(); >>>> + >>>> + const int r_int32_2 = reduce<std::int32_t, 2>(typename V<std::int32_t, >>>> 2>::mask_type(true)); + if (r_int32_2 != 1) >>>> + __builtin_abort(); >>>> +} > >