simd: revamp the (templated) decr3Hsimd() subroutine
authorGilles Gouaillardet <gilles@rist.or.jp>
Thu, 1 Oct 2020 21:11:39 +0000 (21:11 +0000)
committerArtem Zhmurov <zhmurov@gmail.com>
Thu, 1 Oct 2020 21:11:39 +0000 (21:11 +0000)
decr3Hsimd<stride>(m, a0, a1, a2) replaces three decrHsimd():

- decrHsimd(m, a0);
- decrHsimd(m + stride, a1);
- decrHsimd(m + 2*stride, a2);

providing a given architecture the opportunity to perform additional optimizations.

A simple wrapper is added to each architecture where
GMX_SIMD_HAVE_HSIMD_UTIL_{FLOAT,DOUBLE} is 1.

Refs !567

24 files changed:
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_inner.h
src/gromacs/simd/impl_arm_neon/impl_arm_neon_definitions.h
src/gromacs/simd/impl_arm_neon_asimd/impl_arm_neon_asimd_definitions.h
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_definitions.h
src/gromacs/simd/impl_ibm_vsx/impl_ibm_vsx_definitions.h
src/gromacs/simd/impl_reference/impl_reference_definitions.h
src/gromacs/simd/impl_reference/impl_reference_util_double.h
src/gromacs/simd/impl_reference/impl_reference_util_float.h
src/gromacs/simd/impl_x86_avx2_128/impl_x86_avx2_128_definitions.h
src/gromacs/simd/impl_x86_avx2_256/impl_x86_avx2_256_definitions.h
src/gromacs/simd/impl_x86_avx_128_fma/impl_x86_avx_128_fma_definitions.h
src/gromacs/simd/impl_x86_avx_256/impl_x86_avx_256_definitions.h
src/gromacs/simd/impl_x86_avx_256/impl_x86_avx_256_util_float.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_definitions.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_util_double.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_util_float.h
src/gromacs/simd/impl_x86_avx_512_knl/impl_x86_avx_512_knl_definitions.h
src/gromacs/simd/impl_x86_mic/impl_x86_mic_definitions.h
src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_double.h
src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_float.h
src/gromacs/simd/impl_x86_sse2/impl_x86_sse2_definitions.h
src/gromacs/simd/impl_x86_sse4_1/impl_x86_sse4_1_definitions.h
src/gromacs/simd/simd.h
src/gromacs/simd/tests/simd_floatingpoint_util.cpp

index 63f64e96c25122ed110dc24b910f4ca63108420f..458c23b1b8fa2fe9caf8008fe23f1e141cc5d447 100644 (file)
     fiz_S2 = fiz_S2 + tz_S2;
 
     /* Decrement j atom force */
-    decr3Hsimd<STRIDE>(f + aj * DIM, tx_S0 + tx_S2, ty_S0 + ty_S2, tz_S0 + tz_S2);
+    decr3Hsimd(f + aj * DIM, tx_S0 + tx_S2, ty_S0 + ty_S2, tz_S0 + tz_S2);
 }
 
 #undef rinv_ex_S0
index 8c722198e1ff93c43e91fe1f6c4dc6a94b190d8e..5aa27d56dd2455a387e6753750ec29ba6dc4da6d 100644 (file)
@@ -65,9 +65,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
index ed2ade80ddbd3e7a8cc437cd1e5465cfc92f32e9..f40c43b1b13a167357a77b03196848afdd1b7f38 100644 (file)
@@ -66,9 +66,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
index fcfce5b7c21de13c665a7b0a12fd272ddd278e5b..ece4a52b9f2f367fcd3e7153abe498364e5b00cf 100644 (file)
@@ -78,9 +78,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 0
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
index 05748637c1351aaa0e89ad64ff5cfa53400dc8d5..fe67d4b4f28ac84add54ee10973454d14c2d459a 100644 (file)
 #define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 // GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE is conditionally defined further down
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
+#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0  // No need for half-simd, width is 4
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // No need for half-simd, width is 2
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
 
index 6410a39c585facfa30b0447dc81039a59fbd23d6..29dd4ae697fee7e30c826e6e58b68bc8a2af95bf 100644 (file)
@@ -190,21 +190,9 @@ namespace gmx
 //! \brief 1 if float half-register load/store/reduce utils present, otherwise 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
 
-/*! \brief 1 if implementation provides single decr3Hsimd()
- *
- *  Only used in simd.h to selectively override the generic implementation.
- */
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
-
 //! \brief 1 if double half-register load/store/reduce utils present, otherwise 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 1
 
-/*! \brief 1 if implementation provides double decr3Hsimd()
- *
- *  Only used in simd.h to selectively override the generic implementation.
- */
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
-
 #ifdef GMX_SIMD_REF_FLOAT_WIDTH
 #    define GMX_SIMD_FLOAT_WIDTH GMX_SIMD_REF_FLOAT_WIDTH
 #else
index ab0a2f0938139112d37899987cfb78c01bbc9a9a..4c2df75fc8c189d701162a242801d4448defdf39 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -736,27 +736,40 @@ static inline void gmx_simdcall incrDualHsimd(double* m0, double* m1, SimdDouble
     }
 }
 
-/*! \brief Add the two halves of a SIMD double, subtract the sum from
- *         half-SIMD-width consecutive doubles in memory.
+/*! \brief Add the two halves of three SIMD doubles, subtract the sum from
+ *         three half-SIMD-width consecutive doubles in memory.
  *
  * \param m  half-width aligned memory, from which sum of the halves will be subtracted.
- * \param a  SIMD variable. Upper & lower halves will first be added.
+ * \param a0 SIMD variable. Upper & lower halves will first be added.
+ * \param a1 SIMD variable. Upper & lower halves will second be added.
+ * \param a2 SIMD variable. Upper & lower halves will third be added.
  *
- * If the SIMD width is 8 and contains [a b c d e f g h], the
- * memory will be modified to [m[0]-(a+e) m[1]-(b+f) m[2]-(c+g) m[3]-(d+h)].
+ * If the SIMD width is 8 and the vectors contain [a0 b0 c0 d0 e0 f0 g0 h0],
+ * [a1 b1 c1 d1 e1 f1 g1 g1] and [a2 b2 c2 d2 e2 f2 g2 h2], the
+ * memory will be modified to [m[0]-(a0+e0) m[1]-(b0+f0) m[2]-(c0+g0) m[3]-(d0+h0)
+ *                             m[4]-(a1+e1) m[5]-(b1+f1) m[6]-(c1+g1) m[7]-(d1+h1)
+ *                             m[8]-(a2+e2) m[9]-(b2+f2) m[10]-(c2+g2) m[11]-(d2+h2)].
  *
  * The memory must be aligned to half SIMD width.
  *
  * Available if \ref GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE is 1.
  */
-static inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
+static inline void gmx_simdcall decr3Hsimd(double* m, SimdDouble a0, SimdDouble a1, SimdDouble a2)
 {
-    // Make sure the memory pointer is aligned to half double SIMD width
     assert(std::size_t(m) % (GMX_SIMD_DOUBLE_WIDTH / 2 * sizeof(double)) == 0);
-
-    for (std::size_t i = 0; i < a.simdInternal_.size() / 2; i++)
+    for (std::size_t i = 0; i < a0.simdInternal_.size() / 2; i++)
+    {
+        m[i] -= a0.simdInternal_[i] + a0.simdInternal_[a0.simdInternal_.size() / 2 + i];
+    }
+    for (std::size_t i = 0; i < a1.simdInternal_.size() / 2; i++)
+    {
+        m[a1.simdInternal_.size() / 2 + i] -=
+                a1.simdInternal_[i] + a1.simdInternal_[a1.simdInternal_.size() / 2 + i];
+    }
+    for (std::size_t i = 0; i < a2.simdInternal_.size() / 2; i++)
     {
-        m[i] -= a.simdInternal_[i] + a.simdInternal_[a.simdInternal_.size() / 2 + i];
+        m[a2.simdInternal_.size() + i] -=
+                a2.simdInternal_[i] + a2.simdInternal_[a2.simdInternal_.size() / 2 + i];
     }
 }
 
index 54f66b2af0c7c8d551f8c5fe1508c50dec80de8a..99919f322301e6023988b4f9b8d214a935c5d202 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -781,27 +781,40 @@ static inline void gmx_simdcall incrDualHsimd(float* m0, float* m1, SimdFloat a)
     }
 }
 
-/*! \brief Add the two halves of a SIMD float, subtract the sum from
- *         half-SIMD-width consecutive floats in memory.
+/*! \brief Add the two halves of three SIMD floats, subtract the sum from
+ *         three half-SIMD-width consecutive floats in memory.
  *
  * \param m  half-width aligned memory, from which sum of the halves will be subtracted.
- * \param a  SIMD variable. Upper & lower halves will first be added.
+ * \param a0 SIMD variable. Upper & lower halves will first be added.
+ * \param a1 SIMD variable. Upper & lower halves will second be added.
+ * \param a2 SIMD variable. Upper & lower halves will third be added.
  *
- * If the SIMD width is 8 and contains [a b c d e f g h], the
- * memory will be modified to [m[0]-(a+e) m[1]-(b+f) m[2]-(c+g) m[3]-(d+h)].
+ * If the SIMD width is 8 and the vectors contain [a0 b0 c0 d0 e0 f0 g0 h0],
+ * [a1 b1 c1 d1 e1 f1 g1 g1] and [a2 b2 c2 d2 e2 f2 g2 h2], the
+ * memory will be modified to [m[0]-(a0+e0) m[1]-(b0+f0) m[2]-(c0+g0) m[3]-(d0+h0)
+ *                             m[4]-(a1+e1) m[5]-(b1+f1) m[6]-(c1+g1) m[7]-(d1+h1)
+ *                             m[8]-(a2+e2) m[9]-(b2+f2) m[10]-(c2+g2) m[11]-(d2+h2)].
  *
  * The memory must be aligned to half SIMD width.
  *
  * Available if \ref GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT is 1.
  */
-static inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+static inline void gmx_simdcall decr3Hsimd(float* m, SimdFloat a0, SimdFloat a1, SimdFloat a2)
 {
-    // Make sure the memory pointer is aligned to half float SIMD width
     assert(std::size_t(m) % (GMX_SIMD_FLOAT_WIDTH / 2 * sizeof(float)) == 0);
-
-    for (std::size_t i = 0; i < a.simdInternal_.size() / 2; i++)
+    for (std::size_t i = 0; i < a0.simdInternal_.size() / 2; i++)
+    {
+        m[i] -= a0.simdInternal_[i] + a0.simdInternal_[a0.simdInternal_.size() / 2 + i];
+    }
+    for (std::size_t i = 0; i < a1.simdInternal_.size() / 2; i++)
+    {
+        m[a1.simdInternal_.size() / 2 + i] -=
+                a1.simdInternal_[i] + a1.simdInternal_[a1.simdInternal_.size() / 2 + i];
+    }
+    for (std::size_t i = 0; i < a2.simdInternal_.size() / 2; i++)
     {
-        m[i] -= a.simdInternal_[i] + a.simdInternal_[a.simdInternal_.size() / 2 + i];
+        m[a2.simdInternal_.size() + i] -=
+                a2.simdInternal_[i] + a2.simdInternal_[a2.simdInternal_.size() / 2 + i];
     }
 }
 
index 13c064150fd12390ee4ac7b07fe3b59b0ec7688d..cffb4c6ba1314721ef1fc9485d67b16de4a7d255 100644 (file)
 #define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
+#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0  // No need for half-simd, width is 4
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // No need for half-simd, width is 2
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 1
index 85246a4d81f33410ec12c3c3287a28566f1a586a..7c2a6b198d8767319789a65497d7e335b4bd631b 100644 (file)
@@ -65,9 +65,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // Not needed for width 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT 1
 
 #define GMX_SIMD4_HAVE_FLOAT 1
index 6eb6d277b832c13ad975b13375d9ca0bc4ec71fd..9b65882f7cc66805fca4f0f51eda59e00a343d54 100644 (file)
 
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
+#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0  // No need for half-simd, width is 4
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // No need for half-simd, width is 2
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 1 // Uses 256-bit avx for SIMD4-double
index de56ecb2a10796326451fb8b3563eaa2c1f1b9bb..aa633c24edf6086d4c919543018675b4dd3b465a 100644 (file)
@@ -65,9 +65,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // Not needed for width 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT 1
 
 #define GMX_SIMD4_HAVE_FLOAT 1
index f6aadba6b8695e4ee4b5c26e6159ce9840b69500..8b4bd4fcea5a521728be03dd055f7a70a73d971f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 namespace gmx
 {
 
+namespace
+{
+/* This is an internal helper function used by decr3Hsimd(...).
+ */
+inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+{
+    assert(std::size_t(m) % 16 == 0);
+    __m128 asum = _mm_add_ps(_mm256_castps256_ps128(a.simdInternal_),
+                             _mm256_extractf128_ps(a.simdInternal_, 0x1));
+    _mm_store_ps(m, _mm_sub_ps(_mm_load_ps(m), asum));
+}
+} // namespace
+
 /* This is an internal helper function used by the three functions storing,
  * incrementing, or decrementing data. Do NOT use it outside this file.
  *
@@ -605,12 +618,12 @@ static inline void gmx_simdcall incrDualHsimd(float* m0, float* m1, SimdFloat a)
     _mm_store_ps(m1, _mm_add_ps(_mm256_extractf128_ps(a.simdInternal_, 0x1), _mm_load_ps(m1)));
 }
 
-static inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+static inline void gmx_simdcall decr3Hsimd(float* m, SimdFloat a0, SimdFloat a1, SimdFloat a2)
 {
     assert(std::size_t(m) % 16 == 0);
-    __m128 asum = _mm_add_ps(_mm256_castps256_ps128(a.simdInternal_),
-                             _mm256_extractf128_ps(a.simdInternal_, 0x1));
-    _mm_store_ps(m, _mm_sub_ps(_mm_load_ps(m), asum));
+    decrHsimd(m, a0);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH / 2, a1);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH, a2);
 }
 
 
index 613c76e9f1bd1c947271d2a0c35964641298ae71..75e4a97fe8c99de74ec64515892848feb3ef210a 100644 (file)
@@ -81,9 +81,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT 1
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE 1
 
index e722b77846fb8570f366c73a373eb262fddd7167..15b05d7848d469188e70492a1546bbb9c605f90f 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -85,6 +85,21 @@ static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const double*, Simd
 {
     // Nothing to do. Termination of recursion.
 }
+
+/* This is an internal helper function used by decr3Hsimd(...).
+ */
+inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
+{
+    __m256d t;
+
+    assert(std::size_t(m) % 32 == 0);
+
+    a.simdInternal_ = _mm512_add_pd(a.simdInternal_,
+                                    _mm512_shuffle_f64x2(a.simdInternal_, a.simdInternal_, 0xEE));
+    t               = _mm256_load_pd(m);
+    t               = _mm256_sub_pd(t, _mm512_castpd512_pd256(a.simdInternal_));
+    _mm256_store_pd(m, t);
+}
 } // namespace
 
 
@@ -348,20 +363,13 @@ static inline void gmx_simdcall incrDualHsimd(double* m0, double* m1, SimdDouble
     _mm256_store_pd(m1, x);
 }
 
-static inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
+static inline void gmx_simdcall decr3Hsimd(double* m, SimdDouble a0, SimdDouble a1, SimdDouble a2)
 {
-    __m256d t;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    a.simdInternal_ = _mm512_add_pd(a.simdInternal_,
-                                    _mm512_shuffle_f64x2(a.simdInternal_, a.simdInternal_, 0xEE));
-    t               = _mm256_load_pd(m);
-    t               = _mm256_sub_pd(t, _mm512_castpd512_pd256(a.simdInternal_));
-    _mm256_store_pd(m, t);
+    decrHsimd(m, a0);
+    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH / 2, a1);
+    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH, a2);
 }
 
-
 template<int align>
 static inline void gmx_simdcall gatherLoadTransposeHsimd(const double*      base0,
                                                          const double*      base1,
index b4072eb4957b1d4ed3a1f6dd413e2c753f18d29a..99daabee6fcc265daebe4d2c7fa4b3a7850b1695 100644 (file)
@@ -85,6 +85,21 @@ static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const float*, SimdF
 {
     // Nothing to do. Termination of recursion.
 }
+
+/* This is an internal helper function used by decr3Hsimd(...).
+ */
+inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+{
+    __m256 t;
+
+    assert(std::size_t(m) % 32 == 0);
+
+    a.simdInternal_ = _mm512_add_ps(a.simdInternal_,
+                                    _mm512_shuffle_f32x4(a.simdInternal_, a.simdInternal_, 0xEE));
+    t               = _mm256_load_ps(m);
+    t               = _mm256_sub_ps(t, _mm512_castps512_ps256(a.simdInternal_));
+    _mm256_store_ps(m, t);
+}
 } // namespace
 
 template<int align, typename... Targs>
@@ -384,17 +399,11 @@ static inline void gmx_simdcall incrDualHsimd(float* m0, float* m1, SimdFloat a)
     _mm256_store_ps(m1, x);
 }
 
-static inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+static inline void gmx_simdcall decr3Hsimd(float* m, SimdFloat a0, SimdFloat a1, SimdFloat a2)
 {
-    __m256 t;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    a.simdInternal_ = _mm512_add_ps(a.simdInternal_,
-                                    _mm512_shuffle_f32x4(a.simdInternal_, a.simdInternal_, 0xEE));
-    t               = _mm256_load_ps(m);
-    t               = _mm256_sub_ps(t, _mm512_castps512_ps256(a.simdInternal_));
-    _mm256_store_ps(m, t);
+    decrHsimd(m, a0);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH / 2, a1);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH, a2);
 }
 
 
index 91a07eb5fde74cf3acf158f26261d0eb1f24e3a2..13e924da8aa76805da9e6bd186dcdda52115d120 100644 (file)
@@ -70,9 +70,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT 1
 #define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE 1
 
index 05f04842643c3a4d6d43128c0da780093d4cf8e0..2f85b0cbc159172972218e8528a04c4171350a50 100644 (file)
@@ -64,9 +64,7 @@
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
 #define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 1
index dbf4665d587bfc3ac10bcf31098631a33923fbae..18769d61e43990578788d41fc031582b76f3684c 100644 (file)
 namespace gmx
 {
 
+namespace
+{
+/* This is an internal helper function used by decr3Hsimd(...).
+ */
+inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
+{
+    __m512d t;
+
+    assert(std::size_t(m) % 32 == 0);
+
+    t               = _mm512_extload_pd(m, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
+    a.simdInternal_ = _mm512_add_pd(
+            a.simdInternal_,
+            _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(a.simdInternal_), _MM_PERM_BADC)));
+    t = _mm512_sub_pd(t, a.simdInternal_);
+    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0x0F), t);
+}
+} // namespace
+
 // On MIC it is better to use scatter operations, so we define the load routines
 // that use a SIMD offset variable first.
 
@@ -361,18 +380,12 @@ static inline void gmx_simdcall incrDualHsimd(double* m0, double* m1, SimdDouble
     _mm512_mask_packstorelo_pd(m1, _mm512_int2mask(0xF0), x);
 }
 
-static inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
+static inline void gmx_simdcall decr3Hsimd(double* m, SimdDouble a0, SimdDouble a1, SimdDouble a2)
 {
-    __m512d t;
-
     assert(std::size_t(m) % 32 == 0);
-
-    t               = _mm512_extload_pd(m, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    a.simdInternal_ = _mm512_add_pd(
-            a.simdInternal_,
-            _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(a.simdInternal_), _MM_PERM_BADC)));
-    t = _mm512_sub_pd(t, a.simdInternal_);
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0x0F), t);
+    decrHsimd(m, a0);
+    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH / 2, a1);
+    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH, a2);
 }
 
 
index cd8ad93de797908d0dfd0912493e5652eca9b11c..13a6147f877cd7d3d2441a0ba76142a081d5a30a 100644 (file)
 namespace gmx
 {
 
+namespace
+{
+/* This is an internal helper function used by decr3Hsimd(...).
+ */
+inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+{
+    __m512 t;
+
+    assert(std::size_t(m) % 32 == 0);
+
+    t = _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m), _MM_UPCONV_PD_NONE,
+                                           _MM_BROADCAST_4X8, _MM_HINT_NONE));
+    a = _mm512_add_ps(a.simdInternal_, _mm512_permute4f128_ps(a.simdInternal_, _MM_PERM_BADC));
+    t = _mm512_sub_ps(t, a.simdInternal_);
+    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0x00FF), t);
+}
+} // namespace
+
 // On MIC it is better to use scatter operations, so we define the load routines
 // that use a SIMD offset variable first.
 
@@ -364,17 +382,12 @@ static inline void gmx_simdcall incrDualHsimd(float* m0, float* m1, SimdFloat a)
     _mm512_mask_packstorelo_ps(m1, _mm512_int2mask(0xFF00), x);
 }
 
-static inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
+static inline void gmx_simdcall decr3Hsimd(float* m, SimdFloat a0, SimdFloat a1, SimdFloat a2)
 {
-    __m512 t;
-
     assert(std::size_t(m) % 32 == 0);
-
-    t = _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m), _MM_UPCONV_PD_NONE,
-                                           _MM_BROADCAST_4X8, _MM_HINT_NONE));
-    a = _mm512_add_ps(a.simdInternal_, _mm512_permute4f128_ps(a.simdInternal_, _MM_PERM_BADC));
-    t = _mm512_sub_ps(t, a.simdInternal_);
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0x00FF), t);
+    decrHsimd(m, a0);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH / 2, a1);
+    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH, a2);
 }
 
 
index 21749416f88d974b5a9ca2f11bdbb83e2840bf46..f47f56b5b8ef6000faee4712a79ff36101b09f4b 100644 (file)
 #define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
+#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0  // No need for half-simd, width is 4
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // No need for half-simd, width is 2
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
index 6d12dea7ac4f157a8a7a0172d8999167cd05edc9..0e50fb0aec0e47e98e64867e588de9f0ff328397 100644 (file)
 #define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
 #define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT 0
+#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0  // No need for half-simd, width is 4
 #define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0 // No need for half-simd, width is 2
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE 0
 
 #define GMX_SIMD4_HAVE_FLOAT 1
 #define GMX_SIMD4_HAVE_DOUBLE 0
index 02bfba000357e4b604c924a0d590d87b93bdb34c..d67ce0bbab84b48090b0cae179ce69e54d5aa51c 100644 (file)
@@ -182,7 +182,6 @@ struct SimdDInt32Tag
 #    define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_REAL \
         GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE
 #    define GMX_SIMD_HAVE_HSIMD_UTIL_REAL GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE
-#    define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_REAL GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE
 #    define GMX_SIMD4_HAVE_REAL GMX_SIMD4_HAVE_DOUBLE
 #else // GMX_DOUBLE
 
@@ -234,13 +233,6 @@ struct SimdDInt32Tag
  */
 #    define GMX_SIMD_HAVE_HSIMD_UTIL_REAL GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT
 
-/*! \brief 1 if a native decr3Hsimd() implementation is available, otherwise 0
- *
- *  \ref GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_DOUBLE if GMX_DOUBLE is 1, otherwise
- *  \ref GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT.
- */
-#    define GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_REAL GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_FLOAT
-
 /*! \brief 1 if Simd4Real is available, otherwise 0.
  *
  *  \ref GMX_SIMD4_HAVE_DOUBLE if GMX_DOUBLE is 1, otherwise \ref GMX_SIMD4_HAVE_FLOAT.
@@ -742,16 +734,6 @@ static inline Simd4NDouble gmx_simdcall load4DuplicateN(const double* f)
 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE 0
 #endif
 
-#if GMX_SIMD_HAVE_HSIMD_UTIL_REAL && !GMX_SIMD_HAVE_HSIMD_UTIL_DECR3_REAL
-template<int stride>
-static inline void gmx_simdcall decr3Hsimd(real* m, SimdReal r0, SimdReal r1, SimdReal r2)
-{
-    decrHsimd(m, r0);
-    decrHsimd(m + stride, r1);
-    decrHsimd(m + 2 * stride, r2);
-}
-#endif
-
 #if GMX_DOUBLE
 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_REAL GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE
 #else
index 89cb01018e5b06eb3e3c376714f55014ef617f04..ee43c3cada45242f2fe5c960048e3b7ae7c7dac1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -810,11 +810,11 @@ TEST_F(SimdFloatingpointUtilTest, incrDualHsimdOverlapping)
     }
 }
 
-TEST_F(SimdFloatingpointUtilTest, decrHsimd)
+TEST_F(SimdFloatingpointUtilTest, decr3Hsimd)
 {
-    SimdReal               v0;
-    real                   ref[GMX_SIMD_REAL_WIDTH / 2];
-    int                    i;
+    SimdReal               v0, v1, v2;
+    real                   ref[3 * GMX_SIMD_REAL_WIDTH / 2];
+    int                    i, j;
     FloatingPointTolerance tolerance(defaultRealTolerance());
 
     // Point p to the upper half of val1_
@@ -823,11 +823,23 @@ TEST_F(SimdFloatingpointUtilTest, decrHsimd)
     {
         ref[i] = val0_[i] - (val1_[i] + p[i]);
     }
+    p = val2_ + GMX_SIMD_REAL_WIDTH / 2;
+    for (j = 0; j < GMX_SIMD_REAL_WIDTH / 2; i++, j++)
+    {
+        ref[i] = val0_[i] - (val2_[j] + p[j]);
+    }
+    p = val3_ + GMX_SIMD_REAL_WIDTH / 2;
+    for (j = 0; j < GMX_SIMD_REAL_WIDTH / 2; i++, j++)
+    {
+        ref[i] = val0_[i] - (val3_[j] + p[j]);
+    }
 
     v0 = load<SimdReal>(val1_);
-    decrHsimd(val0_, v0);
+    v1 = load<SimdReal>(val2_);
+    v2 = load<SimdReal>(val3_);
+    decr3Hsimd(val0_, v0, v1, v2);
 
-    for (i = 0; i < GMX_SIMD_REAL_WIDTH / 2; i++)
+    for (i = 0; i < 3 * GMX_SIMD_REAL_WIDTH / 2; i++)
     {
         EXPECT_REAL_EQ_TOL(ref[i], val0_[i], tolerance);
     }