SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / gromacs / simd / simd.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
5  * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36
37 /*! \libinternal
38  * \defgroup module_simd SIMD intrinsics interface (simd)
39  * \ingroup group_utilitymodules
40  *
41  * \brief Provides an architecture-independent way of doing SIMD coding.
42  *
43  * Overview of the SIMD implementation is provided in \ref page_simd.
44  * The details are documented in gromacs/simd/simd.h and the reference
45  * implementation impl_reference.h.
46  *
47  * \author Erik Lindahl <erik.lindahl@scilifelab.se>
48  */
49
50 #ifndef GMX_SIMD_SIMD_H
51 #define GMX_SIMD_SIMD_H
52
53 /*! \libinternal \file
54  *
55  * \brief Definitions, capabilities, and wrappers for SIMD module.
56  *
57  * The macros in this file are intended to be used for writing
58  * architecture-independent SIMD intrinsics code.
59  * To support a new architecture, adding a new sub-include with macros here
60  * should be (nearly) all that is needed.
61  *
62  * The defines in this top-level file will set default Gromacs real precision
63  * operations to either single or double precision based on whether
64  * GMX_DOUBLE is 1. The actual implementation - including e.g.
65  * conversion operations specifically between single and double - is documented
66  * in impl_reference.h.
67  *
68  * \author Erik Lindahl <erik.lindahl@scilifelab.se>
69  *
70  * \inlibraryapi
71  * \ingroup module_simd
72  */
73
74 #include "config.h"
75
76 #include <cstddef>
77 #include <cstdint>
78
79 #include <array>
80 #include <memory>
81 #include <type_traits>
82
83 #include "gromacs/utility/basedefinitions.h"
84 #include "gromacs/utility/real.h"
85
86 //! \cond libapi
87
88
89 /*! \addtogroup module_simd
90  * \{
91  */
92
93 namespace gmx
94 {
95 /*! \libinternal \brief Tag type to select to load SimdFloat with simdLoad(U) */
96 struct SimdFloatTag
97 {
98 };
99 /*! \libinternal \brief Tag type to select to load SimdDouble with simdLoad(U) */
100 struct SimdDoubleTag
101 {
102 };
103 /*! \libinternal \brief Tag type to select to load SimdFInt32 with simdLoad(U) */
104 struct SimdFInt32Tag
105 {
106 };
107 /*! \libinternal \brief Tag type to select to load SimdDInt32 with simdLoad(U) */
108 struct SimdDInt32Tag
109 {
110 };
111 } // namespace gmx
112
113 /*! \name SIMD predefined macros to describe high-level capabilities
114  *
115  *  These macros are used to describe the features available in default
116  *  Gromacs real precision. They are set from the lower-level implementation
117  *  files that have macros describing single and double precision individually,
118  *  as well as the implementation details.
119  *  \{
120  */
121
122 #ifdef __clang__
123 #    pragma clang diagnostic push
124 /* reinterpret_cast is used for SIMD->scalar conversion
125  *
126  * In general using reinterpret_cast for bit_cast is UB but
127  * for intrinsics types it works for all known compilers
128  * and not all compilers produce as good code for memcpy.
129  */
130 #    pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
131 #endif
132
133 #if GMX_SIMD_X86_SSE2
134 #    include "impl_x86_sse2/impl_x86_sse2.h"
135 #elif GMX_SIMD_X86_SSE4_1
136 #    include "impl_x86_sse4_1/impl_x86_sse4_1.h"
137 #elif GMX_SIMD_X86_AVX_128_FMA
138 #    include "impl_x86_avx_128_fma/impl_x86_avx_128_fma.h"
139 #elif GMX_SIMD_X86_AVX_256
140 #    include "impl_x86_avx_256/impl_x86_avx_256.h"
141 #elif GMX_SIMD_X86_AVX2_256
142 #    include "impl_x86_avx2_256/impl_x86_avx2_256.h"
143 #elif GMX_SIMD_X86_AVX2_128
144 #    include "impl_x86_avx2_128/impl_x86_avx2_128.h"
145 #elif GMX_SIMD_X86_AVX_512
146 #    include "impl_x86_avx_512/impl_x86_avx_512.h"
147 #elif GMX_SIMD_X86_AVX_512_KNL
148 #    include "impl_x86_avx_512_knl/impl_x86_avx_512_knl.h"
149 #elif GMX_SIMD_ARM_NEON_ASIMD
150 #    include "impl_arm_neon_asimd/impl_arm_neon_asimd.h"
151 #elif GMX_SIMD_ARM_SVE
152 #    include "impl_arm_sve/impl_arm_sve.h"
153 #elif GMX_SIMD_IBM_VSX
154 #    include "impl_ibm_vsx/impl_ibm_vsx.h"
155 #elif (GMX_SIMD_REFERENCE || defined DOXYGEN)
156 #    include "impl_reference/impl_reference.h" // Includes doxygen documentation
157 #else
158 #    include "impl_none/impl_none.h"
159 #endif
160
161 #ifdef __clang__
162 #    pragma clang diagnostic pop
163 #endif
164
165 // The scalar SIMD-mimicking functions are always included so we can use
166 // templated functions even without SIMD support.
167 #include "gromacs/simd/scalar/scalar.h"
168 #include "gromacs/simd/scalar/scalar_math.h"
169 #include "gromacs/simd/scalar/scalar_util.h"
170
171
172 #if GMX_DOUBLE
173 #    define GMX_SIMD_HAVE_REAL GMX_SIMD_HAVE_DOUBLE
174 #    define GMX_SIMD_REAL_WIDTH GMX_SIMD_DOUBLE_WIDTH
175 #    define GMX_SIMD_HAVE_INT32_EXTRACT GMX_SIMD_HAVE_DINT32_EXTRACT
176 #    define GMX_SIMD_HAVE_INT32_LOGICAL GMX_SIMD_HAVE_DINT32_LOGICAL
177 #    define GMX_SIMD_HAVE_INT32_ARITHMETICS GMX_SIMD_HAVE_DINT32_ARITHMETICS
178 #    define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_REAL \
179         GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE
180 #    define GMX_SIMD_HAVE_HSIMD_UTIL_REAL GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE
181 #    define GMX_SIMD4_HAVE_REAL GMX_SIMD4_HAVE_DOUBLE
182 #else // GMX_DOUBLE
183
184 /*! \brief 1 if SimdReal is available, otherwise 0.
185  *
186  *  \ref GMX_SIMD_HAVE_DOUBLE if GMX_DOUBLE is 1, otherwise \ref GMX_SIMD_HAVE_FLOAT.
187  */
188 #    define GMX_SIMD_HAVE_REAL GMX_SIMD_HAVE_FLOAT
189
190 /*! \brief Width of SimdReal.
191  *
192  *  \ref GMX_SIMD_DOUBLE_WIDTH if GMX_DOUBLE is 1, otherwise \ref GMX_SIMD_FLOAT_WIDTH.
193  */
194 #    define GMX_SIMD_REAL_WIDTH GMX_SIMD_FLOAT_WIDTH
195
196 /*! \brief 1 if support is available for extracting elements from SimdInt32, otherwise 0
197  *
198  *  \ref GMX_SIMD_HAVE_DINT32_EXTRACT if GMX_DOUBLE is 1, otherwise
199  *  \ref GMX_SIMD_HAVE_FINT32_EXTRACT.
200  */
201 #    define GMX_SIMD_HAVE_INT32_EXTRACT GMX_SIMD_HAVE_FINT32_EXTRACT
202
203 /*! \brief 1 if logical ops are supported on SimdInt32, otherwise 0.
204  *
205  *  \ref GMX_SIMD_HAVE_DINT32_LOGICAL if GMX_DOUBLE is 1, otherwise
206  *  \ref GMX_SIMD_HAVE_FINT32_LOGICAL.
207  */
208 #    define GMX_SIMD_HAVE_INT32_LOGICAL GMX_SIMD_HAVE_FINT32_LOGICAL
209
210 /*! \brief 1 if arithmetic ops are supported on SimdInt32, otherwise 0.
211  *
212  *  \ref GMX_SIMD_HAVE_DINT32_ARITHMETICS if GMX_DOUBLE is 1, otherwise
213  *  \ref GMX_SIMD_HAVE_FINT32_ARITHMETICS.
214  */
215 #    define GMX_SIMD_HAVE_INT32_ARITHMETICS GMX_SIMD_HAVE_FINT32_ARITHMETICS
216
217 /*! \brief 1 if gmx::simdGatherLoadUBySimdIntTranspose is present, otherwise 0
218  *
219  *  \ref GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE if GMX_DOUBLE is 1, otherwise
220  *  \ref GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT.
221  */
222 #    define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_REAL \
223         GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT
224
225 /*! \brief 1 if real half-register load/store/reduce utils present, otherwise 0
226  *
227  *  \ref GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE if GMX_DOUBLE is 1, otherwise
228  *  \ref GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT.
229  */
230 #    define GMX_SIMD_HAVE_HSIMD_UTIL_REAL GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT
231
232 /*! \brief 1 if Simd4Real is available, otherwise 0.
233  *
234  *  \ref GMX_SIMD4_HAVE_DOUBLE if GMX_DOUBLE is 1, otherwise \ref GMX_SIMD4_HAVE_FLOAT.
235  */
236 #    define GMX_SIMD4_HAVE_REAL GMX_SIMD4_HAVE_FLOAT
237
238 #endif // GMX_DOUBLE
239
240 //! \}  end of name-group describing high-level capabilities
241
242 namespace gmx
243 {
244
245 template<class T, size_t N>
246 struct AlignedArray;
247
248 #if GMX_SIMD_HAVE_FLOAT
249 /*! \libinternal \brief Identical to std::array with GMX_SIMD_FLOAT_WIDTH alignment.
250  *  Should not be deleted through base pointer (destructor is non-virtual).
251  */
252 template<size_t N>
253 struct alignas(GMX_SIMD_FLOAT_WIDTH * sizeof(float)) AlignedArray<float, N> :
254     public std::array<float, N>
255 {
256 };
257 #endif
258
259 #if GMX_SIMD_HAVE_DOUBLE
260 /*! \libinternal \brief  Identical to std::array with GMX_SIMD_DOUBLE_WIDTH alignment.
261  *  Should not be deleted through base pointer (destructor is non-virtual).
262  */
263 template<size_t N>
264 struct alignas(GMX_SIMD_DOUBLE_WIDTH * sizeof(double)) AlignedArray<double, N> :
265     public std::array<double, N>
266 {
267 };
268 #endif
269
270 #if GMX_SIMD_HAVE_REAL
271
272 /*! \name SIMD data types
273  *
274  *  The actual storage of these types is implementation dependent. The
275  *  documentation is generated from the reference implementation, but for
276  *  normal usage this will likely not be what you are using.
277  * \{
278  */
279
280 /*! \brief Real precision floating-point SIMD datatype.
281  *
282  * This type is only available if \ref GMX_SIMD_HAVE_REAL is 1.
283  *
284  * \ref SimdDouble if GMX_DOUBLE is 1, otherwise \ref SimdFloat.
285  *
286  * \note This variable cannot be placed inside other structures or classes, since
287  *       some compilers (including at least clang-3.7) appear to lose the
288  *       alignment. This is likely particularly severe when allocating such
289  *       memory on the heap, but it occurs for stack structures too.
290  */
291 #    if GMX_DOUBLE
292 typedef SimdDouble SimdReal;
293 #    else
294 typedef SimdFloat  SimdReal;
295 #    endif
296
297
298 /*! \brief Boolean SIMD type for usage with \ref SimdReal.
299  *
300  * This type is only available if \ref GMX_SIMD_HAVE_REAL is 1.
301  *
302  * If GMX_DOUBLE is 1, this will be set to \ref SimdDBool
303  * internally, otherwise \ref SimdFBool. This is necessary since some
304  * SIMD implementations use bitpatterns for marking truth, so single-
305  * vs. double precision booleans are not necessarily exchangable.
306  * As long as you just use this type you will not have to worry about precision.
307  *
308  * See \ref SimdIBool for an explanation of real vs. integer booleans.
309  *
310  * \note This variable cannot be placed inside other structures or classes, since
311  *       some compilers (including at least clang-3.7) appear to lose the
312  *       alignment. This is likely particularly severe when allocating such
313  *       memory on the heap, but it occurs for stack structures too.
314  */
315 #    if GMX_DOUBLE
316 typedef SimdDBool SimdBool;
317 #    else
318 typedef SimdFBool  SimdBool;
319 #    endif
320
321
322 /*! \brief 32-bit integer SIMD type.
323  *
324  * If GMX_DOUBLE is 1, this will be set to \ref SimdDInt32
325  * internally, otherwise \ref SimdFInt32. This might seem a strange
326  * implementation detail, but it is because some SIMD implementations use
327  * different types/widths of integers registers when converting from
328  * double vs. single precision floating point. As long as you just use
329  * this type you will not have to worry about precision.
330  *
331  * \note This variable cannot be placed inside other structures or classes, since
332  *       some compilers (including at least clang-3.7) appear to lose the
333  *       alignment. This is likely particularly severe when allocating such
334  *       memory on the heap, but it occurs for stack structures too.
335  */
336 #    if GMX_DOUBLE
337 typedef SimdDInt32 SimdInt32;
338 #    else
339 typedef SimdFInt32 SimdInt32;
340 #    endif
341
342 #    if GMX_SIMD_HAVE_INT32_ARITHMETICS
343 /*! \brief Boolean SIMD type for usage with \ref SimdInt32.
344  *
345  * This type is only available if \ref GMX_SIMD_HAVE_INT32_ARITHMETICS is 1.
346  *
347  * If GMX_DOUBLE is 1, this will be set to \ref SimdDIBool
348  * internally, otherwise \ref SimdFIBool. This is necessary since some
349  * SIMD implementations use bitpatterns for marking truth, so single-
350  * vs. double precision booleans are not necessarily exchangable, and while
351  * a double-precision boolean might be represented with a 64-bit mask, the
352  * corresponding integer might only use a 32-bit mask.
353  *
354  * We provide conversion routines for these cases, so the only thing you need to
355  * keep in mind is to use \ref SimdBool when working with
356  * \ref SimdReal while you pick \ref SimdIBool when working with
357  * \ref SimdInt32 .
358  *
359  * To convert between them, use \ref cvtB2IB and \ref cvtIB2B.
360  *
361  * \note This variable cannot be placed inside other structures or classes, since
362  *       some compilers (including at least clang-3.7) appear to lose the
363  *       alignment. This is likely particularly severe when allocating such
364  *       memory on the heap, but it occurs for stack structures too.
365  */
366 #        if GMX_DOUBLE
367 typedef SimdDIBool SimdIBool;
368 #        else
369 typedef SimdFIBool SimdIBool;
370 #        endif
371 #    endif // GMX_SIMD_HAVE_INT32_ARITHMETICS
372
373
374 #    if GMX_DOUBLE
375 const int c_simdBestPairAlignment = c_simdBestPairAlignmentDouble;
376 #    else
377 const int          c_simdBestPairAlignment = c_simdBestPairAlignmentFloat;
378 #    endif
379
380 #endif // GMX_SIMD_HAVE_REAL
381
382 #if GMX_SIMD4_HAVE_REAL
383 /*! \brief Real precision floating-point SIMD4 datatype.
384  *
385  * This type is only available if \ref GMX_SIMD4_HAVE_REAL is 1.
386  *
387  * \ref Simd4Double if GMX_DOUBLE is 1, otherwise \ref Simd4Float.
388  *
389  * \note This variable cannot be placed inside other structures or classes, since
390  *       some compilers (including at least clang-3.7) appear to lose the
391  *       alignment. This is likely particularly severe when allocating such
392  *       memory on the heap, but it occurs for stack structures too.
393  */
394 #    if GMX_DOUBLE
395 typedef Simd4Double Simd4Real;
396 #    else
397 typedef Simd4Float Simd4Real;
398 #    endif
399
400
401 /*! \brief Boolean SIMD4 type for usage with \ref SimdReal.
402  *
403  * This type is only available if \ref GMX_SIMD4_HAVE_REAL is 1.
404  *
405  * If GMX_DOUBLE is 1, this will be set to \ref Simd4DBool
406  * internally, otherwise \ref Simd4FBool. This is necessary since some
407  * SIMD implementations use bitpatterns for marking truth, so single-
408  * vs. double precision booleans are not necessarily exchangable.
409  * As long as you just use this type you will not have to worry about precision.
410  *
411  * \note This variable cannot be placed inside other structures or classes, since
412  *       some compilers (including at least clang-3.7) appear to lose the
413  *       alignment. This is likely particularly severe when allocating such
414  *       memory on the heap, but it occurs for stack structures too.
415  */
416 #    if GMX_DOUBLE
417 typedef Simd4DBool Simd4Bool;
418 #    else
419 typedef Simd4FBool Simd4Bool;
420 #    endif
421 #endif // GMX_SIMD4_HAVE_REAL
422
423 //! \}  end of name-group describing SIMD data types
424
425 /*! \name High-level SIMD proxy objects to disambiguate load/set operations
426  * \{
427  */
428
429 namespace internal
430 {
431 /*! \libinternal \brief Simd traits
432  *
433  * These traits are used to query data about SIMD types. Currently provided
434  * data is useful for SIMD loads (load function and helper classes for
435  * ArrayRef<> in simd_memory.h). Provided data:
436  *  - type: scalar type corresponding to the SIMD type
437  *  - width: SIMD width
438  *  - tag: tag used for type dispatch of load function
439  */
440 template<typename T>
441 struct SimdTraits
442 {
443 };
444
445 #if GMX_SIMD_HAVE_FLOAT
446 template<>
447 struct SimdTraits<SimdFloat>
448 {
449     using type                 = float;
450     static constexpr int width = GMX_SIMD_FLOAT_WIDTH;
451     using tag                  = SimdFloatTag;
452 };
453 #endif
454 #if GMX_SIMD_HAVE_DOUBLE
455 template<>
456 struct SimdTraits<SimdDouble>
457 {
458     using type                 = double;
459     static constexpr int width = GMX_SIMD_DOUBLE_WIDTH;
460     using tag                  = SimdDoubleTag;
461 };
462 #endif
463 #if GMX_SIMD_HAVE_FLOAT
464 template<>
465 struct SimdTraits<SimdFInt32>
466 {
467     using type                 = int;
468     static constexpr int width = GMX_SIMD_FINT32_WIDTH;
469     using tag                  = SimdFInt32Tag;
470 };
471 #endif
472 #if GMX_SIMD_HAVE_DOUBLE
473 template<>
474 struct SimdTraits<SimdDInt32>
475 {
476     using type                 = int;
477     static constexpr int width = GMX_SIMD_DINT32_WIDTH;
478     using tag                  = SimdDInt32Tag;
479 };
480 #endif
481 template<typename T>
482 using SimdTraitsT = typename SimdTraits<T>::type;
483 template<typename T>
484 struct SimdTraits<const T>
485 {
486     using type                 = const SimdTraitsT<T>;
487     static constexpr int width = SimdTraits<T>::width;
488     using tag                  = typename SimdTraits<T>::tag;
489 };
490 } // namespace internal
491
492 /*! \brief Load function that returns SIMD or scalar
493  *
494  * Note that a load of T* where T is const returns a value, which is a
495  * copy, and the caller cannot be constrained to not change it, so the
496  * return type uses std::remove_const_t.
497  *
498  * \tparam T Type to load (type is always mandatory)
499  * \param  m Pointer to aligned memory
500  * \return   Loaded value
501  */
502 template<typename T>
503 static inline std::remove_const_t<T> load(const internal::SimdTraitsT<T>* m) // disabled by SFINAE for non-SIMD types
504 {
505     return simdLoad(m, typename internal::SimdTraits<T>::tag());
506 }
507
508 template<typename T>
509 static inline T
510 /* the enable_if serves to prevent two different type of misuse:
511  * 1) load<SimdReal>(SimdReal*); should only be called on real* or int*
512  * 2) load(real*); template parameter is mandatory because otherwise ambiguity is
513  *    created. The dependent type disables type deduction.
514  */
515 load(const std::enable_if_t<std::is_arithmetic_v<T>, T> *m)
516 {
517     return *m;
518 }
519
520 template<typename T, size_t N>
521 static inline T gmx_simdcall load(const AlignedArray<internal::SimdTraitsT<T>, N>& m)
522 {
523     return simdLoad(m.data(), typename internal::SimdTraits<T>::tag());
524 }
525
526 /*! \brief Load function that returns SIMD or scalar based on template argument
527  *
528  * \tparam T Type to load (type is always mandatory)
529  * \param m Pointer to unaligned memory
530  * \return Loaded SimdFloat/Double/Int or basic scalar type
531  */
532 template<typename T>
533 static inline T loadU(const internal::SimdTraitsT<T>* m)
534 {
535     return simdLoadU(m, typename internal::SimdTraits<T>::tag());
536 }
537
538 template<typename T>
539 static inline T loadU(const std::enable_if_t<std::is_arithmetic_v<T>, T>* m)
540 {
541     return *m;
542 }
543
544 template<typename T, size_t N>
545 static inline T gmx_simdcall loadU(const AlignedArray<internal::SimdTraitsT<T>, N>& m)
546 {
547     return simdLoadU(m.data(), typename internal::SimdTraits<T>::tag());
548 }
549
550 /*! \libinternal \brief Proxy object to enable setZero() for SIMD and real types.
551  *
552  * This object is returned by setZero(), and depending on what type you assign
553  * the result to the conversion method will call the right low-level function.
554  */
555 class SimdSetZeroProxy
556 {
557 public:
558     //!\brief Conversion method that returns 0.0 as float
559     operator float() const { return 0.0F; }
560     //!\brief Conversion method that returns 0.0 as double
561     operator double() const { return 0.0; }
562     //!\brief Conversion method that returns 0.0 as int32
563     operator std::int32_t() const { return 0; }
564 #if GMX_SIMD_HAVE_FLOAT
565     //!\brief Conversion method that will execute setZero() for SimdFloat
566     operator SimdFloat() const { return setZeroF(); }
567     //!\brief Conversion method that will execute setZero() for SimdFInt32
568     operator SimdFInt32() const { return setZeroFI(); }
569 #endif
570 #if GMX_SIMD4_HAVE_FLOAT
571     //!\brief Conversion method that will execute setZero() for Simd4Float
572     operator Simd4Float() const { return simd4SetZeroF(); }
573 #endif
574 #if GMX_SIMD_HAVE_DOUBLE
575     //!\brief Conversion method that will execute setZero() for SimdDouble
576     operator SimdDouble() const { return setZeroD(); }
577     //!\brief Conversion method that will execute setZero() for SimdDInt32
578     operator SimdDInt32() const { return setZeroDI(); }
579 #endif
580 #if GMX_SIMD4_HAVE_DOUBLE
581     //!\brief Conversion method that will execute setZero() for Simd4Double
582     operator Simd4Double() const { return simd4SetZeroD(); }
583 #endif
584 };
585
586 /*! \brief Helper function to set any SIMD or scalar variable to zero
587  *
588  * \return Proxy object that will call the actual function to set a SIMD/scalar
589  *         variable to zero based on the conversion function called when you
590  *         assign the result.
591  */
592 static inline SimdSetZeroProxy gmx_simdcall setZero()
593 {
594     return {};
595 }
596
597 namespace internal
598 {
599 // TODO: Don't forward function but properly rename them and use proper traits
600 template<typename T>
601 struct Simd4Traits
602 {
603 };
604
605 #if GMX_SIMD4_HAVE_FLOAT
606 template<>
607 struct Simd4Traits<Simd4Float>
608 {
609     using type = float;
610 };
611 #endif
612
613 #if GMX_SIMD4_HAVE_DOUBLE
614 template<>
615 struct Simd4Traits<Simd4Double>
616 {
617     using type = double;
618 };
619 #endif
620 template<typename T>
621 using Simd4TraitsT = typename Simd4Traits<T>::type;
622 } // namespace internal
623
624 #if GMX_SIMD4_HAVE_REAL
625 template<typename T>
626 T load(const internal::Simd4TraitsT<T>* m)
627 {
628     return load4(m);
629 }
630 template<typename T>
631 T loadU(const internal::Simd4TraitsT<T>* m)
632 {
633     return load4U(m);
634 }
635 #endif
636
637 /* Implement most of 4xn functions by forwarding them to other functions when possible.
638  * The functions forwarded here don't need to be implemented by each implementation.
639  * For width=4 all functions are forwarded and for width=8 all but loadU4NOffset are forwarded.
640  */
641 #if GMX_SIMD_HAVE_FLOAT
642 #    if GMX_SIMD_FLOAT_WIDTH < 4
643 #        define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT (GMX_SIMD_HAVE_LOADU && GMX_SIMD4_HAVE_FLOAT)
644 #    elif GMX_SIMD_FLOAT_WIDTH == 4
645 #        define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT GMX_SIMD_HAVE_LOADU
646 // For GMX_SIMD_FLOAT_WIDTH>4 it is the reponsibility of the implementation to set
647 // GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT
648 #    endif
649
650 #    if GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT
651 #        if GMX_SIMD_FLOAT_WIDTH < 4
652 using Simd4NFloat = Simd4Float;
653 #            define GMX_SIMD4N_FLOAT_WIDTH 4
654 #        else
655 using Simd4NFloat = SimdFloat;
656 #            define GMX_SIMD4N_FLOAT_WIDTH GMX_SIMD_FLOAT_WIDTH
657 #        endif
658
659 #        if GMX_SIMD_FLOAT_WIDTH <= 4
660 static inline Simd4NFloat gmx_simdcall loadUNDuplicate4(const float* f)
661 {
662     return Simd4NFloat(*f);
663 }
664 static inline Simd4NFloat gmx_simdcall load4DuplicateN(const float* f)
665 {
666     return load<Simd4NFloat>(f);
667 }
668 static inline Simd4NFloat gmx_simdcall loadU4NOffset(const float* f, int)
669 {
670     return loadU<Simd4NFloat>(f);
671 }
672 #        elif GMX_SIMD_FLOAT_WIDTH == 8
673 static inline Simd4NFloat gmx_simdcall loadUNDuplicate4(const float* f)
674 {
675     return loadU1DualHsimd(f);
676 }
677 static inline Simd4NFloat gmx_simdcall load4DuplicateN(const float* f)
678 {
679     return loadDuplicateHsimd(f);
680 }
681 #        endif
682 #    endif // GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT
683 #else      // GMX_SIMD_HAVE_FLOAT
684 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT 0
685 #endif
686
687 #if GMX_SIMD_HAVE_DOUBLE
688 #    if GMX_SIMD_DOUBLE_WIDTH < 4
689 #        define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE (GMX_SIMD_HAVE_LOADU && GMX_SIMD4_HAVE_DOUBLE)
690 #    elif GMX_SIMD_DOUBLE_WIDTH == 4
691 #        define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE GMX_SIMD_HAVE_LOADU
692 // For GMX_SIMD_DOUBLE_WIDTH>4 it is the reponsibility of the implementation to set
693 // GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE
694 #    endif
695
696 #    if GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE
697 #        if GMX_SIMD_DOUBLE_WIDTH < 4
698 using Simd4NDouble = Simd4Double;
699 #            define GMX_SIMD4N_DOUBLE_WIDTH 4
700 #        else
701 using Simd4NDouble = SimdDouble;
702 #            define GMX_SIMD4N_DOUBLE_WIDTH GMX_SIMD_DOUBLE_WIDTH
703 #        endif
704
705 #        if GMX_SIMD_DOUBLE_WIDTH <= 4
706 static inline Simd4NDouble gmx_simdcall loadUNDuplicate4(const double* f)
707 {
708     return Simd4NDouble(*f);
709 }
710 static inline Simd4NDouble gmx_simdcall load4DuplicateN(const double* f)
711 {
712     return load<Simd4NDouble>(f);
713 }
714 static inline Simd4NDouble gmx_simdcall loadU4NOffset(const double* f, int /*unused*/)
715 {
716     return loadU<Simd4NDouble>(f);
717 }
718 #        elif GMX_SIMD_DOUBLE_WIDTH == 8
719 static inline Simd4NDouble gmx_simdcall loadUNDuplicate4(const double* f)
720 {
721     return loadU1DualHsimd(f);
722 }
723 static inline Simd4NDouble gmx_simdcall load4DuplicateN(const double* f)
724 {
725     return loadDuplicateHsimd(f);
726 }
727 #        endif
728 #    endif // GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE
729 #else      // GMX_SIMD_HAVE_DOUBLE
730 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE 0
731 #endif
732
733 #if GMX_DOUBLE
734 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_REAL GMX_SIMD_HAVE_4NSIMD_UTIL_DOUBLE
735 #else
736 #    define GMX_SIMD_HAVE_4NSIMD_UTIL_REAL GMX_SIMD_HAVE_4NSIMD_UTIL_FLOAT
737 #endif
738
739 #if GMX_SIMD_HAVE_4NSIMD_UTIL_REAL
740 #    if GMX_DOUBLE
741 using Simd4NReal = Simd4NDouble;
742 #        define GMX_SIMD4N_REAL_WIDTH GMX_SIMD4N_DOUBLE_WIDTH
743 #    else
744 using Simd4NReal = Simd4NFloat;
745 #        define GMX_SIMD4N_REAL_WIDTH GMX_SIMD4N_FLOAT_WIDTH
746 #    endif
747 #endif
748
749 //! \}  end of name-group proxy objects
750
751 } // namespace gmx
752
753 //! \}          end of module_simd
754
755 //! \endcond   end of condition libapi
756
757
758 #if GMX_SIMD_HAVE_FLOAT
759
760 /*! \brief Returns whether a pointer to float is aligned to a SIMD boundary
761  *
762  * \param[in] ptr  A pointer to a float
763  */
764 static inline bool isSimdAligned(const float* ptr)
765 {
766     return reinterpret_cast<std::size_t>(ptr) % (GMX_SIMD_FLOAT_WIDTH * sizeof(float)) == 0;
767 }
768
769 #endif // GMX_SIMD_HAVE_FLOAT
770
771 #if GMX_SIMD_HAVE_DOUBLE
772
773 /*! \brief Returns whether a pointer to double is aligned to a SIMD boundary
774  *
775  * \param[in] ptr  A pointer to a double
776  */
777 static inline bool isSimdAligned(const double* ptr)
778 {
779     return reinterpret_cast<std::size_t>(ptr) % (GMX_SIMD_DOUBLE_WIDTH * sizeof(double)) == 0;
780 }
781
782 #endif // GMX_SIMD_HAVE_DOUBLE
783
784
785 #if GMX_SIMD_HAVE_REAL
786 #    if GMX_SIMD_REAL_WIDTH > GMX_REAL_MAX_SIMD_WIDTH
787 #        error "GMX_SIMD_REAL_WIDTH > GMX_REAL_MAX_SIMD_WIDTH: increase GMX_REAL_MAX_SIMD_WIDTH in real.h"
788 #    endif
789 #endif
790
791
792 #if 0
793 /* This is a hack to cover the corner case of using an
794    explicit GMX_SIMD_HAVE_FLOAT or GMX_SIMD_HAVE_DOUBLE, rather than
795    GMX_SIMD_HAVE_REAL.
796
797    Such code is expected to include simd.h to get those symbols
798    defined, but the actual definitions are in the implemention headers
799    included by simd.h. check-source.py is not a full preprocessor, so
800    it does not see the definitions in the implementation headers as
801    belonging to simd.h, thus it cannot check that simd.h is being used
802    correctly in the above hypothetical corner case. However, the
803    checker also does not parse #if 0, so we can fool the checker into
804    thinking that definition occurs here, and that will work well
805    enough.
806
807    If there's ever other kinds of SIMD code that might have the same
808    problem, we might want to add other variables here.
809  */
810 #    define GMX_SIMD_HAVE_FLOAT 1
811 #    define GMX_SIMD_HAVE_DOUBLE 1
812
813 #endif // end of hack
814
815 // The ArrayRef<SimdReal> specialization is always included, because compiler
816 // errors are confusing when template specialization aren't available.
817 #include "gromacs/simd/simd_memory.h"
818
819 #endif // GMX_SIMD_SIMD_H