libstdc++: Fix mask reduction of simd_mask<double> on POWER7
authorMatthias Kretz <kretz@kde.org>
Wed, 3 Feb 2021 15:49:30 +0000 (15:49 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 3 Feb 2021 15:49:30 +0000 (15:49 +0000)
POWER7 does not support __vector long long reductions, making the
generic _S_popcount implementation ill-formed. Specializing _S_popcount
for PPC allows optimization and avoids the issue.

libstdc++-v3/ChangeLog:

* include/experimental/bits/simd.h: Add __have_power10vec
conditional on _ARCH_PWR10.
* include/experimental/bits/simd_builtin.h: Forward declare
_MaskImplPpc and use it as _MaskImpl when __ALTIVEC__ is
defined.
(_MaskImplBuiltin::_S_some_of): Call _S_popcount from the
_SuperImpl for optimizations and correctness.
* include/experimental/bits/simd_ppc.h: Add _MaskImplPpc.
(_MaskImplPpc::_S_popcount): Implement via vec_cntm for POWER10.
Otherwise, for >=int use -vec_sums divided by a sizeof factor.
For <int use -vec_sums(vec_sum4s(...)) to sum all mask entries.

libstdc++-v3/include/experimental/bits/simd.h
libstdc++-v3/include/experimental/bits/simd_builtin.h
libstdc++-v3/include/experimental/bits/simd_ppc.h

index 149396d6f82a9e32c46091494f60a39f7e1845e9..becd1d6a4bb7104938d62f3274c29ea9e768a154 100644 (file)
@@ -477,6 +477,11 @@ constexpr inline bool __support_neon_float =
   false;
 #endif
 
+#ifdef _ARCH_PWR10
+constexpr inline bool __have_power10vec = true;
+#else
+constexpr inline bool __have_power10vec = false;
+#endif
 #ifdef __POWER9_VECTOR__
 constexpr inline bool __have_power9vec = true;
 #else
index efca65fa6e3856e69d4e51981b90df66af99fd4c..7f728a10488b75280eb15a1f71dafaaf7b115d20 100644 (file)
@@ -920,6 +920,7 @@ template <typename _Abi> struct _MaskImplX86;
 template <typename _Abi> struct _SimdImplNeon;
 template <typename _Abi> struct _MaskImplNeon;
 template <typename _Abi> struct _SimdImplPpc;
+template <typename _Abi> struct _MaskImplPpc;
 
 // simd_abi::_VecBuiltin {{{
 template <int _UsedBytes>
@@ -959,10 +960,11 @@ template <int _UsedBytes>
     using _CommonImpl = _CommonImplBuiltin;
 #ifdef __ALTIVEC__
     using _SimdImpl = _SimdImplPpc<_VecBuiltin<_UsedBytes>>;
+    using _MaskImpl = _MaskImplPpc<_VecBuiltin<_UsedBytes>>;
 #else
     using _SimdImpl = _SimdImplBuiltin<_VecBuiltin<_UsedBytes>>;
-#endif
     using _MaskImpl = _MaskImplBuiltin<_VecBuiltin<_UsedBytes>>;
+#endif
 #endif
 
     // }}}
@@ -2899,7 +2901,7 @@ template <typename _Abi>
       _GLIBCXX_SIMD_INTRINSIC static bool
       _S_some_of(simd_mask<_Tp, _Abi> __k)
       {
-       const int __n_true = _S_popcount(__k);
+       const int __n_true = _SuperImpl::_S_popcount(__k);
        return __n_true > 0 && __n_true < int(_S_size<_Tp>);
       }
 
index b92fc19ccb85406b9baa83051a926c6c56890f2b..ef52d129a85327799db54f770018d8bcebc2526d 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef __ALTIVEC__
 #error "simd_ppc.h may only be included when AltiVec/VMX is available"
 #endif
+#include <altivec.h>
 
 _GLIBCXX_SIMD_BEGIN_NAMESPACE
 
@@ -114,10 +115,42 @@ template <typename _Abi>
     // }}}
   };
 
+// }}}
+// _MaskImplPpc {{{
+template <typename _Abi>
+  struct _MaskImplPpc : _MaskImplBuiltin<_Abi>
+  {
+    using _Base = _MaskImplBuiltin<_Abi>;
+
+    // _S_popcount {{{
+    template <typename _Tp>
+      _GLIBCXX_SIMD_INTRINSIC static int _S_popcount(simd_mask<_Tp, _Abi> __k)
+      {
+       const auto __kv = __as_vector(__k);
+       if constexpr (__have_power10vec)
+         {
+           return vec_cntm(__to_intrin(__kv), 1);
+         }
+       else if constexpr (sizeof(_Tp) >= sizeof(int))
+         {
+           using _Intrin = __intrinsic_type16_t<int>;
+           const int __sum = -vec_sums(__intrin_bitcast<_Intrin>(__kv), _Intrin())[3];
+           return __sum / (sizeof(_Tp) / sizeof(int));
+         }
+       else
+         {
+           const auto __summed_to_int = vec_sum4s(__to_intrin(__kv), __intrinsic_type16_t<int>());
+           return -vec_sums(__summed_to_int, __intrinsic_type16_t<int>())[3];
+         }
+      }
+
+    // }}}
+  };
+
 // }}}
 
 _GLIBCXX_SIMD_END_NAMESPACE
 #endif // __cplusplus >= 201703L
 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_PPC_H_
 
-// vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80
+// vim: foldmethod=marker foldmarker={{{,}}} sw=2 noet ts=8 sts=2 tw=100