Re: [PATCH] libstdc++: arm: convert vpadd_* operands to intrinsic types [PR122981]

Torbjorn SVENSSON <[email protected]> Thu, 6 Aug 2026 17:55:25 +0200
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel
Message-ID <[email protected]>

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.cc b/libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.cc
>> new file mode 100644
>> index 00000000000..f7f79166ae6
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/experimental/simd/pr122981_find_last_set_neon.cc
>> @@ -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();
>> +}
>> -- 
>> 2.43.0
>>
>>
>