_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 <[email protected]>
---
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;
+}
-- 
2.55.0

Reply via email to