[PATCH] libstdc++: fix _MaskImplNeon::_S_popcount NEON temporaries on 32-bit Arm [PR122981]
Jonathan Wakely
jwakely@redhat.com
Fri Jul 24 16:37:54 GMT 2026
On Mon, 13 Jul 2026 at 17:10 +0200, Torbjorn SVENSSON wrote:
>Hi Dominic,
>
>When you send patches for libstdc++, please don't forget to CC that mailing list (I've added it).
>Also, you might want to CC one (or more) of the libstdc++ maintainers and probably also some Arm folks to get a review of your patch.
Just CC libstdc++@gcc not individual maintainers.
>I'm in no position to say if your patch is acceptable or not.
>
>One note though, the commit message feels very AI-like.
>I'm not saying that it's wrong, but it could give a potential reviewer a bad after taste...
>
>Kind regards,
>Torbjörn
>
>On 2026-07-13 07:30, Dominic P wrote:
>>_MaskImplNeon::_S_popcount initialises NEON intrinsic-typed
>>temporaries (int8x8_t, int16x4_t, int32x2_t) directly from generic
>>__vector values. On 32-bit Arm the intrinsic vector types are
>>distinct from the generic __vector(N) T types, so the C++ front end
>>rejects the conversion and the popcount path fails to compile, e.g.:
>>
>> simd_neon.h:483: error: cannot convert '__vector(8) signed char'
>> to 'int8x8_t'
>>
>>This is the same class of error fixed for _S_to_bits by wrapping the
>>vpadd_* operands in __to_intrin, and complements that fix: __to_intrin
>>is a same-size reinterpret, so this is a pure type correction with no
>>change to the computed result. AArch64 is unaffected because there
>>the two vector type families coincide.
>>
>>libstdc++-v3/ChangeLog:
>>
>> PR libstdc++/122981
>> * include/experimental/bits/simd_neon.h (_MaskImplNeon::
>> _S_popcount): Convert the pairwise-add temporaries with
>> __to_intrin.
>> * testsuite/experimental/simd/pr122981_popcount_neon.cc:
>> New test.
>>
>>Signed-off-by: Dominic P <gcc@gcc.dp11.uk>
OK for trunk.
N.B. <experimental/simd> has been superseded by <simd> and it would be
better to spend time adding arm support to <simd> instead of polishing
the old code.
>>---
>>Hi Torbjörn,
>>
>>We hit the same failures independently on arm-none-eabi and had an
>>equivalent fix queued, so: your patch matches what we tested for the
>>_S_to_bits paths, and with it applied pr115454_find_last_set.cc
>>compiles and passes here too.
>>
>>There is one more instance of the same class of error that it does not
>>cover: _MaskImplNeon::_S_popcount (around line 481) initialises NEON
>>intrinsic-typed temporaries directly from generic __vector values,
>>
>> int8x8_t __tmp = __lo64(__s8) + __hi64z(__s8);
>>
>>which the front end rejects on 32-bit Arm for the same reason, so the
>>popcount path still fails to compile after your patch. Below is a
>>complementary patch (it applies independently of yours - the hunks are
>>disjoint) wrapping those three temporaries in __to_intrin, plus a
>>popcount test in the style of your find_last_set one.
>>
>>Tested on arm-none-eabi (armv7-a+neon): the new popcount test fails to
>>compile without the patch and compiles with it. AArch64 is unaffected
>>by construction - there the intrinsic and generic vector types
>>coincide, so __to_intrin is the identity there, as with your patch.
>>
>>Dominic
>>
>> .../include/experimental/bits/simd_neon.h | 6 ++--
>> .../simd/pr122981_popcount_neon.cc | 31 +++++++++++++++++++
>> 2 files changed, 34 insertions(+), 3 deletions(-)
>> create mode 100644 libstdc++-v3/testsuite/experimental/simd/pr122981_popcount_neon.cc
>>
>>diff --git a/libstdc++-v3/include/experimental/bits/simd_neon.h b/libstdc++-v3/include/experimental/bits/simd_neon.h
>>index 8fabee7f3..f8cb1a66a 100644
>>--- a/libstdc++-v3/include/experimental/bits/simd_neon.h
>>+++ b/libstdc++-v3/include/experimental/bits/simd_neon.h
>>@@ -481,20 +481,20 @@ template <typename _Abi, typename>
>> if constexpr (sizeof(_Tp) == 1)
>> {
>> const auto __s8 = __vector_bitcast<_SChar>(__k._M_data);
>>- int8x8_t __tmp = __lo64(__s8) + __hi64z(__s8);
>>+ int8x8_t __tmp = __to_intrin(__lo64(__s8) + __hi64z(__s8));
>> return -vpadd_s8(vpadd_s8(vpadd_s8(__tmp, int8x8_t()), int8x8_t()),
>> int8x8_t())[0];
>> }
>> else if constexpr (sizeof(_Tp) == 2)
>> {
>> const auto __s16 = __vector_bitcast<short>(__k._M_data);
>>- int16x4_t __tmp = __lo64(__s16) + __hi64z(__s16);
>>+ int16x4_t __tmp = __to_intrin(__lo64(__s16) + __hi64z(__s16));
>> return -vpadd_s16(vpadd_s16(__tmp, int16x4_t()), int16x4_t())[0];
>> }
>> else if constexpr (sizeof(_Tp) == 4)
>> {
>> const auto __s32 = __vector_bitcast<int>(__k._M_data);
>>- int32x2_t __tmp = __lo64(__s32) + __hi64z(__s32);
>>+ int32x2_t __tmp = __to_intrin(__lo64(__s32) + __hi64z(__s32));
>> return -vpadd_s32(__tmp, int32x2_t())[0];
>> }
>> else if constexpr (sizeof(_Tp) == 8)
>>diff --git a/libstdc++-v3/testsuite/experimental/simd/pr122981_popcount_neon.cc b/libstdc++-v3/testsuite/experimental/simd/pr122981_popcount_neon.cc
>>new file mode 100644
>>index 000000000..05884e27e
>>--- /dev/null
>>+++ b/libstdc++-v3/testsuite/experimental/simd/pr122981_popcount_neon.cc
>>@@ -0,0 +1,31 @@
>>+// { dg-options "-std=gnu++17" }
>>+// { dg-do compile { target { arm*-*-* } } }
>>+// { dg-require-effective-target arm_neon_ok }
>>+// { dg-add-options arm_neon }
>>+// PR libstdc++/122981: _MaskImplNeon::_S_popcount initialised NEON
>>+// intrinsic-typed temporaries (int8x8_t etc.) from generic __vector
>>+// values, which the C++ front end rejects on 32-bit Arm where the
>>+// intrinsic and generic vector types are distinct.
>>+
>>+#include <experimental/simd>
>>+
>>+namespace stdx = std::experimental;
>>+
>>+template <typename T>
>>+ int
>>+ test_popcount ()
>>+ {
>>+ using M = typename stdx::native_simd<T>::mask_type;
>>+ M k(true);
>>+ return stdx::popcount (k);
>>+ }
>>+
>>+int
>>+main ()
>>+{
>>+ int n = 0;
>>+ n += test_popcount<signed char> ();
>>+ n += test_popcount<short> ();
>>+ n += test_popcount<int> ();
>>+ return n == 0;
>>+}
>
>
More information about the Libstdc++
mailing list