Thanks Torbjorn,

and sorry for not looking earlier (yes, vacation and the madness that comes 
after).

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?

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.

- 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();
> >> +}


-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Center for Heavy Ion Research               https://gsi.de
 std::simd
──────────────────────────────────────────────────────────────────────────



Reply via email to