[PATCH] libstdc++: arm: convert vpadd_* operands to intrinsic types [PR122981]
Torbjorn SVENSSON
torbjorn.svensson@foss.st.com
Fri Aug 14 10:19:11 GMT 2026
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 <torbjorn.svensson@foss.st.com>
>>>> ---
>>>> .../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();
>>>> +}
>
>
More information about the Libstdc++
mailing list