Made reference SIMD work again
[alexxy/gromacs.git] / src / gromacs / simd / macros.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /* The macros in this file are intended to be used for writing
37  * architecture-independent SIMD intrinsics code.
38  * To support a new architecture, adding macros here should be (nearly)
39  * all that is needed.
40  */
41
42 #ifdef GMX_SIMD_MACROS_H
43 #error "gromacs/simd/macros.h included twice"
44 #else
45 #define GMX_SIMD_MACROS_H
46
47 /* NOTE: SSE2 acceleration does not include floor or blendv */
48
49
50 /* Uncomment the next line, without other SIMD active, for testing plain-C */
51 /* #define GMX_SIMD_REFERENCE_PLAIN_C */
52 #ifdef GMX_SIMD_REFERENCE_PLAIN_C
53 /* Plain C SIMD reference implementation, also serves as documentation */
54 #define GMX_HAVE_SIMD_MACROS
55
56 /* In general the reference SIMD supports any SIMD width, including 1.
57  * But the nbnxn SIMD 4xN kernels only support 2, 4, 8 and 2xNN only 8, 16,
58  * see types/nb_verlet.h for details
59  */
60 #define GMX_SIMD_REF_WIDTH  4
61
62 /* Include plain-C reference implementation, also serves as documentation */
63 #include "gromacs/simd/macros_ref.h"
64
65 #define GMX_SIMD_WIDTH_HERE  GMX_SIMD_REF_WIDTH
66
67 /* float/double SIMD register type */
68 #define gmx_mm_pr  gmx_simd_ref_pr
69
70 /* boolean SIMD register type */
71 #define gmx_mm_pb  gmx_simd_ref_pb
72
73 /* integer SIMD register type, only for table indexing and exclusion masks */
74 #define gmx_epi32  gmx_simd_ref_epi32
75 #define GMX_SIMD_EPI32_WIDTH  GMX_SIMD_REF_EPI32_WIDTH
76
77 /* Load GMX_SIMD_WIDTH_HERE reals for memory starting at r */
78 #define gmx_load_pr       gmx_simd_ref_load_pr
79 /* Set all SIMD register elements to *r */
80 #define gmx_load1_pr      gmx_simd_ref_load1_pr
81 #define gmx_set1_pr       gmx_simd_ref_set1_pr
82 #define gmx_setzero_pr    gmx_simd_ref_setzero_pr
83 #define gmx_store_pr      gmx_simd_ref_store_pr
84
85 #define gmx_add_pr        gmx_simd_ref_add_pr
86 #define gmx_sub_pr        gmx_simd_ref_sub_pr
87 #define gmx_mul_pr        gmx_simd_ref_mul_pr
88 /* For the FMA macros below, aim for c=d in code, so FMA3 uses 1 instruction */
89 #define gmx_madd_pr       gmx_simd_ref_madd_pr
90 #define gmx_nmsub_pr      gmx_simd_ref_nmsub_pr
91
92 #define gmx_max_pr        gmx_simd_ref_max_pr
93 #define gmx_blendzero_pr  gmx_simd_ref_blendzero_pr
94
95 #define gmx_round_pr      gmx_simd_ref_round_pr
96
97 /* Not required, only used to speed up the nbnxn tabulated PME kernels */
98 #define GMX_SIMD_HAVE_FLOOR
99 #ifdef GMX_SIMD_HAVE_FLOOR
100 #define gmx_floor_pr      gmx_simd_ref_floor_pr
101 #endif
102
103 /* Not required, only used when blendv is faster than comparison */
104 #define GMX_SIMD_HAVE_BLENDV
105 #ifdef GMX_SIMD_HAVE_BLENDV
106 #define gmx_blendv_pr     gmx_simd_ref_blendv_pr
107 #endif
108
109 /* Copy the sign of a to b, assumes b >= 0 for efficiency */
110 #define gmx_cpsgn_nonneg_pr  gmx_simd_ref_cpsgn_nonneg_pr
111
112 /* Very specific operation required in the non-bonded kernels */
113 #define gmx_masknot_add_pr   gmx_simd_ref_masknot_add_pr
114
115 /* Comparison */
116 #define gmx_cmplt_pr      gmx_simd_ref_cmplt_pr
117
118 /* Logical operations on SIMD booleans */
119 #define gmx_and_pb        gmx_simd_ref_and_pb
120 #define gmx_or_pb         gmx_simd_ref_or_pb
121
122 /* Returns a single int (0/1) which tells if any of the 4 booleans is True */
123 #define gmx_anytrue_pb    gmx_simd_ref_anytrue_pb
124
125 /* Conversions only used for PME table lookup */
126 #define gmx_cvttpr_epi32  gmx_simd_ref_cvttpr_epi32
127 #define gmx_cvtepi32_pr   gmx_simd_ref_cvtepi32_pr
128
129 /* These two function only need to be approximate, Newton-Raphson iteration
130  * is used for full accuracy in gmx_invsqrt_pr and gmx_inv_pr.
131  */
132 #define gmx_rsqrt_pr      gmx_simd_ref_rsqrt_pr
133 #define gmx_rcp_pr        gmx_simd_ref_rcp_pr
134
135 /* sqrt+inv+sin+cos+acos+atan2 are used for bonded potentials, exp for PME */
136 #define GMX_SIMD_HAVE_EXP
137 #ifdef GMX_SIMD_HAVE_EXP
138 #define gmx_exp_pr        gmx_simd_ref_exp_pr
139 #endif
140 #define GMX_SIMD_HAVE_TRIGONOMETRIC
141 #ifdef GMX_SIMD_HAVE_TRIGONOMETRIC
142 #define gmx_sqrt_pr       gmx_simd_ref_sqrt_pr
143 #define gmx_sincos_pr     gmx_simd_ref_sincos_pr
144 #define gmx_acos_pr       gmx_simd_ref_acos_pr
145 #define gmx_atan2_pr      gmx_simd_ref_atan2_pr
146 #endif
147
148 #endif /* GMX_SIMD_REFERENCE_PLAIN_C */
149
150
151 /* The same SIMD macros can be translated to SIMD intrinsics (and compiled
152  * to instructions for) different SIMD width and float precision.
153  *
154  * On x86: The gmx_ prefix is replaced by _mm_ or _mm256_ (SSE or AVX).
155  * The _pr suffix is replaced by _ps or _pd (for single or double precision).
156  * Compiler settings will decide if 128-bit intrinsics will
157  * be translated into SSE or AVX instructions.
158  */
159
160
161 #ifdef GMX_USE_HALF_WIDTH_SIMD_HERE
162 #if defined GMX_X86_AVX_256 || defined __MIC__
163 /* We have half SIMD width support, continue */
164 #else
165 #error "half SIMD width intrinsics are not supported"
166 #endif
167 #endif
168
169 #if defined GMX_TARGET_X86 && !defined __MIC__
170
171 #ifdef GMX_X86_SSE2
172 /* This is for general x86 SIMD instruction sets that also support SSE2 */
173 #define GMX_HAVE_SIMD_MACROS
174
175 /* Include the highest supported x86 SIMD intrisics + math functions */
176 #ifdef GMX_X86_AVX_256
177 #include "general_x86_avx_256.h"
178 #ifdef GMX_DOUBLE
179 #include "math_x86_avx_256_double.h"
180 #else  /* GMX_DOUBLE */
181 #include "math_x86_avx_256_single.h"
182 #endif /* GMX_DOUBLE */
183 #else  /* GMX_X86_AVX_256 */
184 #ifdef GMX_X86_AVX_128_FMA
185 #include "general_x86_avx_128_fma.h"
186 #ifdef GMX_DOUBLE
187 #include "math_x86_avx_128_fma_double.h"
188 #else  /* GMX_DOUBLE */
189 #include "math_x86_avx_128_fma_single.h"
190 #endif /* GMX_DOUBLE */
191 #else  /* GMX_X86_AVX_128_FMA */
192 #ifdef GMX_X86_SSE4_1
193 #include "general_x86_sse4_1.h"
194 #ifdef GMX_DOUBLE
195 #include "math_x86_sse4_1_double.h"
196 #else  /* GMX_DOUBLE */
197 #include "math_x86_sse4_1_single.h"
198 #endif /* GMX_DOUBLE */
199 #else  /* GMX_X86_SSE4_1 */
200 #ifdef GMX_X86_SSE2
201 #include "general_x86_sse2.h"
202 #ifdef GMX_DOUBLE
203 #include "math_x86_sse2_double.h"
204 #else  /* GMX_DOUBLE */
205 #include "math_x86_sse2_single.h"
206 #endif /* GMX_DOUBLE */
207 #else  /* GMX_X86_SSE2 */
208 #error No x86 acceleration defined
209 #endif /* GMX_X86_SSE2 */
210 #endif /* GMX_X86_SSE4_1 */
211 #endif /* GMX_X86_AVX_128_FMA */
212 #endif /* GMX_X86_AVX_256 */
213
214 /* exp and trigonometric functions are included above */
215 #define GMX_SIMD_HAVE_EXP
216 #define GMX_SIMD_HAVE_ERFC
217 #define GMX_SIMD_HAVE_TRIGONOMETRIC
218
219 #if !defined GMX_X86_AVX_256 || defined GMX_USE_HALF_WIDTH_SIMD_HERE
220
221 #ifndef GMX_DOUBLE
222
223 #define GMX_SIMD_WIDTH_HERE  4
224
225 #define gmx_mm_pr  __m128
226
227 #define gmx_mm_pb  __m128
228
229 #define gmx_epi32  __m128i
230 #define GMX_SIMD_EPI32_WIDTH  4
231
232 #define gmx_load_pr       _mm_load_ps
233 #define gmx_load1_pr      _mm_load1_ps
234 #define gmx_set1_pr       _mm_set1_ps
235 #define gmx_setzero_pr    _mm_setzero_ps
236 #define gmx_store_pr      _mm_store_ps
237
238 #define gmx_add_pr        _mm_add_ps
239 #define gmx_sub_pr        _mm_sub_ps
240 #define gmx_mul_pr        _mm_mul_ps
241 #ifdef GMX_X86_AVX_128_FMA
242 #define GMX_SIMD_HAVE_FMA
243 #define gmx_madd_pr(a, b, c)   _mm_macc_ps(a, b, c)
244 #define gmx_nmsub_pr(a, b, c)  _mm_nmacc_ps(a, b, c)
245 #else
246 #define gmx_madd_pr(a, b, c)   _mm_add_ps(c, _mm_mul_ps(a, b))
247 #define gmx_nmsub_pr(a, b, c)  _mm_sub_ps(c, _mm_mul_ps(a, b))
248 #endif
249 #define gmx_max_pr        _mm_max_ps
250 #define gmx_blendzero_pr  _mm_and_ps
251
252 #define gmx_cmplt_pr      _mm_cmplt_ps
253 #define gmx_and_pb        _mm_and_ps
254 #define gmx_or_pb         _mm_or_ps
255
256 #ifdef GMX_X86_SSE4_1
257 #define gmx_round_pr(x)   _mm_round_ps(x, 0x0)
258 #define GMX_SIMD_HAVE_FLOOR
259 #define gmx_floor_pr      _mm_floor_ps
260 #else
261 #define gmx_round_pr(x)   _mm_cvtepi32_ps(_mm_cvtps_epi32(x))
262 #endif
263
264 #ifdef GMX_X86_SSE4_1
265 #define GMX_SIMD_HAVE_BLENDV
266 #define gmx_blendv_pr     _mm_blendv_ps
267 #endif
268
269 static gmx_inline gmx_mm_pr gmx_cpsgn_nonneg_pr(gmx_mm_pr a, gmx_mm_pr b)
270 {
271     /* The value -0.0 has only the sign-bit set */
272     gmx_mm_pr sign_mask = _mm_set1_ps(-0.0);
273     return _mm_or_ps(_mm_and_ps(a, sign_mask), b);
274 };
275
276 static gmx_inline gmx_mm_pr gmx_masknot_add_pr(gmx_mm_pb a, gmx_mm_pr b, gmx_mm_pr c)
277 {
278     return _mm_add_ps(b, _mm_andnot_ps(a, c));
279 };
280
281 #define gmx_anytrue_pb    _mm_movemask_ps
282
283 #define gmx_cvttpr_epi32  _mm_cvttps_epi32
284 #define gmx_cvtepi32_pr   _mm_cvtepi32_ps
285
286 #define gmx_rsqrt_pr      _mm_rsqrt_ps
287 #define gmx_rcp_pr        _mm_rcp_ps
288
289 #define gmx_exp_pr        gmx_mm_exp_ps
290 #define gmx_sqrt_pr       gmx_mm_sqrt_ps
291 #define gmx_sincos_pr     gmx_mm_sincos_ps
292 #define gmx_acos_pr       gmx_mm_acos_ps
293 #define gmx_atan2_pr      gmx_mm_atan2_ps
294 #define gmx_erfc_pr       gmx_mm_erfc_ps
295
296 #else /* ifndef GMX_DOUBLE */
297
298 #define GMX_SIMD_WIDTH_HERE  2
299
300 #define gmx_mm_pr  __m128d
301
302 #define gmx_mm_pb  __m128d
303
304 #define gmx_epi32  __m128i
305 #define GMX_SIMD_EPI32_WIDTH  4
306
307 #define gmx_load_pr       _mm_load_pd
308 #define gmx_load1_pr      _mm_load1_pd
309 #define gmx_set1_pr       _mm_set1_pd
310 #define gmx_setzero_pr    _mm_setzero_pd
311 #define gmx_store_pr      _mm_store_pd
312
313 #define gmx_add_pr        _mm_add_pd
314 #define gmx_sub_pr        _mm_sub_pd
315 #define gmx_mul_pr        _mm_mul_pd
316 #ifdef GMX_X86_AVX_128_FMA
317 #define GMX_SIMD_HAVE_FMA
318 #define gmx_madd_pr(a, b, c)   _mm_macc_pd(a, b, c)
319 #define gmx_nmsub_pr(a, b, c)  _mm_nmacc_pd(a, b, c)
320 #else
321 #define gmx_madd_pr(a, b, c)   _mm_add_pd(c, _mm_mul_pd(a, b))
322 #define gmx_nmsub_pr(a, b, c)  _mm_sub_pd(c, _mm_mul_pd(a, b))
323 #endif
324 #define gmx_max_pr        _mm_max_pd
325 #define gmx_blendzero_pr  _mm_and_pd
326
327 #ifdef GMX_X86_SSE4_1
328 #define gmx_round_pr(x)   _mm_round_pd(x, 0x0)
329 #define GMX_SIMD_HAVE_FLOOR
330 #define gmx_floor_pr      _mm_floor_pd
331 #else
332 #define gmx_round_pr(x)   _mm_cvtepi32_pd(_mm_cvtpd_epi32(x))
333 /* gmx_floor_pr is not used in code for pre-SSE4_1 hardware */
334 #endif
335
336 #ifdef GMX_X86_SSE4_1
337 #define GMX_SIMD_HAVE_BLENDV
338 #define gmx_blendv_pr     _mm_blendv_pd
339 #endif
340
341 static gmx_inline gmx_mm_pr gmx_cpsgn_nonneg_pr(gmx_mm_pr a, gmx_mm_pr b)
342 {
343     gmx_mm_pr sign_mask = _mm_set1_pd(-0.0);
344     return _mm_or_pd(_mm_and_pd(a, sign_mask), b);
345 };
346
347 static gmx_inline gmx_mm_pr gmx_masknot_add_pr(gmx_mm_pb a, gmx_mm_pr b, gmx_mm_pr c)
348 {
349     return _mm_add_pd(b, _mm_andnot_pd(a, c));
350 };
351
352 #define gmx_cmplt_pr      _mm_cmplt_pd
353
354 #define gmx_and_pb        _mm_and_pd
355 #define gmx_or_pb         _mm_or_pd
356
357 #define gmx_anytrue_pb    _mm_movemask_pd
358
359 #define gmx_cvttpr_epi32  _mm_cvttpd_epi32
360 #define gmx_cvtepi32_pr   _mm_cvtepi32_pd
361
362 #define gmx_rsqrt_pr(r)   _mm_cvtps_pd(_mm_rsqrt_ps(_mm_cvtpd_ps(r)))
363 #define gmx_rcp_pr(r)     _mm_cvtps_pd(_mm_rcp_ps(_mm_cvtpd_ps(r)))
364
365 #define gmx_exp_pr        gmx_mm_exp_pd
366 #define gmx_sqrt_pr       gmx_mm_sqrt_pd
367 #define gmx_sincos_pr     gmx_mm_sincos_pd
368 #define gmx_acos_pr       gmx_mm_acos_pd
369 #define gmx_atan2_pr      gmx_mm_atan2_pd
370 #define gmx_erfc_pr       gmx_mm_erfc_pd
371
372 #endif /* ifndef GMX_DOUBLE */
373
374 #else
375 /* We have GMX_X86_AVX_256 and not GMX_USE_HALF_WIDTH_SIMD_HERE,
376  * so we use 256-bit SIMD.
377  */
378
379 #ifndef GMX_DOUBLE
380
381 #define GMX_SIMD_WIDTH_HERE  8
382
383 #define gmx_mm_pr  __m256
384
385 #define gmx_mm_pb  __m256
386
387 #define gmx_epi32  __m256i
388 #define GMX_SIMD_EPI32_WIDTH  8
389
390 #define gmx_load_pr       _mm256_load_ps
391 #define gmx_load1_pr(x)   _mm256_set1_ps((x)[0])
392 #define gmx_set1_pr       _mm256_set1_ps
393 #define gmx_setzero_pr    _mm256_setzero_ps
394 #define gmx_store_pr      _mm256_store_ps
395
396 #define gmx_add_pr        _mm256_add_ps
397 #define gmx_sub_pr        _mm256_sub_ps
398 #define gmx_mul_pr        _mm256_mul_ps
399 #define gmx_madd_pr(a, b, c)   _mm256_add_ps(c, _mm256_mul_ps(a, b))
400 #define gmx_nmsub_pr(a, b, c)  _mm256_sub_ps(c, _mm256_mul_ps(a, b))
401 #define gmx_max_pr        _mm256_max_ps
402 #define gmx_blendzero_pr  _mm256_and_ps
403
404 #define gmx_round_pr(x)   _mm256_round_ps(x, 0x0)
405 #define GMX_SIMD_HAVE_FLOOR
406 #define gmx_floor_pr      _mm256_floor_ps
407
408 #define GMX_SIMD_HAVE_BLENDV
409 #define gmx_blendv_pr     _mm256_blendv_ps
410
411 static gmx_inline gmx_mm_pr gmx_cpsgn_nonneg_pr(gmx_mm_pr a, gmx_mm_pr b)
412 {
413     gmx_mm_pr sign_mask = _mm256_set1_ps(-0.0);
414     return _mm256_or_ps(_mm256_and_ps(a, sign_mask), b);
415 };
416
417 static gmx_inline gmx_mm_pr gmx_masknot_add_pr(gmx_mm_pb a, gmx_mm_pr b, gmx_mm_pr c)
418 {
419     return _mm256_add_ps(b, _mm256_andnot_ps(a, c));
420 };
421
422 /* Less-than (we use ordered, non-signaling, but that's not required) */
423 #define gmx_cmplt_pr(x, y) _mm256_cmp_ps(x, y, 0x11)
424 #define gmx_and_pb        _mm256_and_ps
425 #define gmx_or_pb         _mm256_or_ps
426
427 #define gmx_anytrue_pb    _mm256_movemask_ps
428
429 #define gmx_cvttpr_epi32  _mm256_cvttps_epi32
430
431 #define gmx_rsqrt_pr      _mm256_rsqrt_ps
432 #define gmx_rcp_pr        _mm256_rcp_ps
433
434 #define gmx_exp_pr        gmx_mm256_exp_ps
435 #define gmx_sqrt_pr       gmx_mm256_sqrt_ps
436 #define gmx_sincos_pr     gmx_mm256_sincos_ps
437 #define gmx_acos_pr       gmx_mm256_acos_ps
438 #define gmx_atan2_pr      gmx_mm256_atan2_ps
439 #define gmx_erfc_pr       gmx_mm256_erfc_ps
440
441 #else /* ifndef GMX_DOUBLE */
442
443 #define GMX_SIMD_WIDTH_HERE  4
444
445 #define gmx_mm_pr  __m256d
446
447 #define gmx_mm_pb  __m256d
448
449 /* We use 128-bit integer registers because of missing 256-bit operations */
450 #define gmx_epi32  __m128i
451 #define GMX_SIMD_EPI32_WIDTH  4
452
453 #define gmx_load_pr       _mm256_load_pd
454 #define gmx_load1_pr(x)   _mm256_set1_pd((x)[0])
455 #define gmx_set1_pr       _mm256_set1_pd
456 #define gmx_setzero_pr    _mm256_setzero_pd
457 #define gmx_store_pr      _mm256_store_pd
458
459 #define gmx_add_pr        _mm256_add_pd
460 #define gmx_sub_pr        _mm256_sub_pd
461 #define gmx_mul_pr        _mm256_mul_pd
462 #define gmx_madd_pr(a, b, c)   _mm256_add_pd(c, _mm256_mul_pd(a, b))
463 #define gmx_nmsub_pr(a, b, c)  _mm256_sub_pd(c, _mm256_mul_pd(a, b))
464 #define gmx_max_pr        _mm256_max_pd
465 #define gmx_blendzero_pr  _mm256_and_pd
466
467 #define gmx_round_pr(x)   _mm256_round_pd(x, 0x0)
468 #define GMX_SIMD_HAVE_FLOOR
469 #define gmx_floor_pr      _mm256_floor_pd
470
471 #define GMX_SIMD_HAVE_BLENDV
472 #define gmx_blendv_pr     _mm256_blendv_pd
473
474 static gmx_inline gmx_mm_pr gmx_cpsgn_nonneg_pr(gmx_mm_pr a, gmx_mm_pr b)
475 {
476     gmx_mm_pr sign_mask = _mm256_set1_pd(-0.0);
477     return _mm256_or_pd(_mm256_and_pd(a, sign_mask), b);
478 };
479
480 static gmx_inline gmx_mm_pr gmx_masknot_add_pr(gmx_mm_pb a, gmx_mm_pr b, gmx_mm_pr c)
481 {
482     return _mm256_add_pd(b, _mm256_andnot_pd(a, c));
483 };
484
485 /* Less-than (we use ordered, non-signaling, but that's not required) */
486 #define gmx_cmplt_pr(x, y) _mm256_cmp_pd(x, y, 0x11)
487
488 #define gmx_and_pb        _mm256_and_pd
489 #define gmx_or_pb         _mm256_or_pd
490
491 #define gmx_anytrue_pb    _mm256_movemask_pd
492
493 #define gmx_cvttpr_epi32  _mm256_cvttpd_epi32
494
495 #define gmx_rsqrt_pr(r)   _mm256_cvtps_pd(_mm_rsqrt_ps(_mm256_cvtpd_ps(r)))
496 #define gmx_rcp_pr(r)     _mm256_cvtps_pd(_mm_rcp_ps(_mm256_cvtpd_ps(r)))
497
498 #define gmx_exp_pr        gmx_mm256_exp_pd
499 #define gmx_sqrt_pr       gmx_mm256_sqrt_pd
500 #define gmx_sincos_pr     gmx_mm256_sincos_pd
501 #define gmx_acos_pr       gmx_mm256_acos_pd
502 #define gmx_atan2_pr      gmx_mm256_atan2_pd
503 #define gmx_erfc_pr       gmx_mm256_erfc_pd
504
505 #endif /* ifndef GMX_DOUBLE */
506
507 #endif /* 128- or 256-bit x86 SIMD */
508
509 #endif /* GMX_X86_SSE2 */
510
511 #endif /* GMX_TARGET_X86 */
512
513 #ifdef GMX_CPU_ACCELERATION_IBM_QPX
514
515 /* This hack works on the compilers that can reach this code. A real
516    solution with broader scope will be proposed in master branch. */
517 #define gmx_always_inline __attribute__((always_inline))
518
519 /* This is for the A2 core on BlueGene/Q that supports IBM's QPX
520    vector built-in functions */
521 #include <mass_simd.h>
522 #define GMX_HAVE_SIMD_MACROS
523 #ifdef __clang__
524 #include <qpxmath.h>
525 #endif
526
527 /* No need to version the code by the precision, because the QPX AXU
528    extends to and truncates from double precision for free. */
529
530 #define GMX_SIMD_WIDTH_HERE  4
531 typedef vector4double gmx_mm_pr;
532 typedef vector4double gmx_mm_pb;
533 typedef vector4double gmx_epi32;
534 #define GMX_SIMD_EPI32_WIDTH  4
535
536 static gmx_inline gmx_mm_pr gmx_always_inline gmx_load_pr(const real *a)
537 {
538 #ifdef NDEBUG
539     return vec_ld(0, (real *) a);
540 #else
541     return vec_lda(0, (real *) a);
542 #endif
543 }
544
545 static gmx_inline gmx_mm_pr gmx_always_inline gmx_load1_pr(const real *a)
546 {
547     return vec_splats(*a);
548 }
549
550 static gmx_inline gmx_mm_pr gmx_always_inline gmx_set1_pr(real a)
551 {
552     return vec_splats(a);
553 }
554
555 static gmx_inline gmx_mm_pr gmx_always_inline gmx_setzero_pr()
556 {
557     return vec_splats(0.0);
558 }
559
560 static gmx_inline void gmx_always_inline gmx_store_pr(real *a, gmx_mm_pr b)
561 {
562 #ifdef NDEBUG
563     vec_st(b, 0, a);
564 #else
565     vec_sta(b, 0, a);
566 #endif
567 }
568
569 static gmx_inline gmx_mm_pr gmx_always_inline gmx_add_pr(gmx_mm_pr a, gmx_mm_pr b)
570 {
571     return vec_add(a, b);
572 }
573
574 static gmx_inline gmx_mm_pr gmx_always_inline gmx_sub_pr(gmx_mm_pr a, gmx_mm_pr b)
575 {
576     return vec_sub(a, b);
577 }
578
579 static gmx_inline gmx_mm_pr gmx_always_inline gmx_mul_pr(gmx_mm_pr a, gmx_mm_pr b)
580 {
581     return vec_mul(a, b);
582 }
583
584 static gmx_inline gmx_mm_pr gmx_always_inline gmx_madd_pr(gmx_mm_pr a, gmx_mm_pr b, gmx_mm_pr c)
585 {
586     return vec_madd(a, b, c);
587 }
588
589 static gmx_inline gmx_mm_pr gmx_always_inline gmx_nmsub_pr(gmx_mm_pr a, gmx_mm_pr b, gmx_mm_pr c)
590 {
591     return vec_nmsub(a, b, c);
592 }
593
594 static gmx_inline gmx_mm_pr gmx_always_inline gmx_max_pr(gmx_mm_pr a, gmx_mm_pr b)
595 {
596     return vec_sel(b, a, vec_sub(a, b));
597 }
598
599 static gmx_inline gmx_mm_pr gmx_always_inline gmx_blendzero_pr(gmx_mm_pr a, gmx_mm_pr b)
600 {
601     return vec_sel(gmx_setzero_pr(), a, b);
602 }
603
604 static gmx_inline gmx_mm_pb gmx_always_inline gmx_cmplt_pr(gmx_mm_pr a, gmx_mm_pr b)
605 {
606     return vec_cmplt(a, b);
607 }
608
609 static gmx_inline gmx_mm_pb gmx_always_inline gmx_and_pb(gmx_mm_pb a, gmx_mm_pb b)
610 {
611     return vec_and(a, b);
612 }
613
614 static gmx_inline gmx_mm_pb gmx_always_inline gmx_or_pb(gmx_mm_pb a, gmx_mm_pb b)
615 {
616     return vec_or(a, b);
617 }
618
619 static gmx_inline gmx_mm_pr gmx_always_inline gmx_round_pr(gmx_mm_pr a)
620 {
621     return vec_round(a);
622 }
623
624 #define GMX_SIMD_HAVE_FLOOR
625 static gmx_inline gmx_mm_pr gmx_always_inline gmx_floor_pr(gmx_mm_pr a)
626 {
627     return vec_floor(a);
628 }
629
630 #define GMX_SIMD_HAVE_BLENDV
631 static gmx_inline gmx_mm_pr gmx_always_inline gmx_blendv_pr(gmx_mm_pr a, gmx_mm_pr b, gmx_mm_pr c)
632 {
633     return vec_sel(b, a, gmx_cmplt_pr(gmx_setzero_pr(), c));
634 }
635
636 static gmx_inline gmx_mm_pr gmx_always_inline gmx_cpsgn_nonneg_pr(gmx_mm_pr a, gmx_mm_pr b)
637 {
638     return vec_cpsgn(a, b);
639 };
640
641 static gmx_inline gmx_mm_pr gmx_always_inline gmx_masknot_add_pr(gmx_mm_pb a, gmx_mm_pr b, gmx_mm_pr c)
642 {
643     return vec_add(b, vec_sel(c, gmx_setzero_pr(), a));
644 };
645
646 static gmx_inline gmx_bool gmx_always_inline
647 GMX_SIMD_IS_TRUE(real x)
648 {
649     return x >= 0.0;
650 }
651
652 static gmx_inline gmx_epi32 gmx_always_inline gmx_cvttpr_epi32(gmx_mm_pr a)
653 {
654     return vec_ctiwuz(a);
655 }
656 /* Don't want this, we have floor */
657 /* #define gmx_cvtepi32_pr   vec_cvtepi32 */
658
659 /* A2 core on BG/Q delivers relative error of 2^-14, whereas Power ISA
660    Architecture only promises 2^-8. So probably no need for
661    Newton-Raphson iterates at single or double. */
662 static gmx_inline gmx_mm_pr gmx_always_inline gmx_rsqrt_pr(gmx_mm_pr a)
663 {
664     return vec_rsqrte(a);
665 }
666
667 /* A2 core on BG/Q delivers relative error of 2^-14, whereas Power ISA
668    Architecture only promises 2^-5. So probably no need for
669    Newton-Raphson iterates at single or double. */
670 static gmx_inline gmx_mm_pr gmx_always_inline gmx_rcp_pr(gmx_mm_pr a)
671 {
672     return vec_re(a);
673 }
674
675 /* Note that here, and below, we use the built-in SLEEF port when
676    compiling on BlueGene/Q with clang */
677
678 #define GMX_SIMD_HAVE_EXP
679 static gmx_inline gmx_mm_pr gmx_always_inline gmx_exp_pr(gmx_mm_pr a)
680 {
681 #ifdef __clang__
682 #ifndef GMX_DOUBLE
683     return xexpf(a);
684 #else
685     return xexp(a);
686 #endif
687 #else
688 #ifndef GMX_DOUBLE
689     return expf4(a);
690 #else
691     return expd4(a);
692 #endif
693 #endif
694 }
695
696 static gmx_inline gmx_mm_pr gmx_always_inline gmx_sqrt_pr(gmx_mm_pr a)
697 {
698 #ifdef NDEBUG
699     return vec_swsqrt_nochk(a);
700 #else
701     return vec_swsqrt(a);
702 #endif
703 }
704
705 #define GMX_SIMD_HAVE_TRIGONOMETRIC
706 static gmx_inline int gmx_always_inline gmx_sincos_pr(gmx_mm_pr a, gmx_mm_pr *b, gmx_mm_pr *c)
707 {
708 #ifdef __clang__
709 #ifndef GMX_DOUBLE
710     xsincosf(a, b, c);
711 #else
712     xsincos(a, b, c);
713 #endif
714 #else
715 #ifndef GMX_DOUBLE
716     sincosf4(a, b, c);
717 #else
718     sincosd4(a, b, c);
719 #endif
720 #endif
721     return 1;
722 }
723
724 static gmx_inline gmx_mm_pr gmx_always_inline gmx_acos_pr(gmx_mm_pr a)
725 {
726 #ifdef __clang__
727 #ifndef GMX_DOUBLE
728     return xacosf(a);
729 #else
730     return xacos(a);
731 #endif
732 #else
733 #ifndef GMX_DOUBLE
734     return acosf4(a);
735 #else
736     return acosd4(a);
737 #endif
738 #endif
739 }
740
741 /* NB The order of parameters here is correct; the
742    documentation of atan2[df]4 in SIMD MASS is wrong. */
743 static gmx_inline gmx_mm_pr gmx_always_inline gmx_atan2_pr(gmx_mm_pr a, gmx_mm_pr b)
744 {
745 #ifdef __clang__
746 #ifndef GMX_DOUBLE
747     return xatan2f(a, b);
748 #else
749     return xatan2(a, b);
750 #endif
751 #else
752 #ifndef GMX_DOUBLE
753     return atan2f4(a, b);
754 #else
755     return atan2d4(a, b);
756 #endif
757 #endif
758 }
759
760 #define GMX_SIMD_HAVE_ERFC
761 static gmx_inline gmx_mm_pr gmx_always_inline gmx_erfc_pr(gmx_mm_pr a)
762 {
763     /* The BG/Q qpxmath.h vector math library intended for use with
764        bgclang does not have erfc, so we need to use a function from
765        mass_simd.h. If this changes, then the #include <mass_simd.h> can
766        become conditional. */
767 #ifndef GMX_DOUBLE
768     return erfcf4(a);
769 #else
770     return erfcd4(a);
771 #endif
772 }
773
774 /* TODO: gmx_mm_erfc_p[sd] should be generalized using gmx_*_pr, so that it just works on BlueGene */
775
776 static gmx_inline int gmx_always_inline
777 gmx_anytrue_pb(gmx_mm_pb a)
778 {
779     /* The "anytrue" is done solely on the QPX AXU (which is the only
780        available FPU). This is awkward, because pretty much no
781        "horizontal" SIMD-vector operations exist, unlike x86 where
782        SSE4.1 added various kinds of horizontal operations. So we have
783        to make do with shifting vector elements and operating on the
784        results. This makes for lots of data dependency, but the main
785        alternative of storing to memory and reloading is not going to
786        help, either. OpenMP over 2 or 4 hardware threads per core will
787        hide much of the latency from the data dependency. The
788        vec_extract() lets the compiler correctly use a floating-point
789        comparison on the zeroth vector element, which avoids needing
790        memory at all.
791      */
792     gmx_mm_pb vec_shifted_left_0 = a;
793     gmx_mm_pb vec_shifted_left_1 = vec_sldw(a, a, 1);
794     gmx_mm_pb vec_shifted_left_2 = vec_sldw(a, a, 2);
795     gmx_mm_pb vec_shifted_left_3 = vec_sldw(a, a, 3);
796
797     gmx_mm_pb vec_return = vec_or(vec_or(vec_shifted_left_2, vec_shifted_left_3),
798                                   vec_or(vec_shifted_left_0, vec_shifted_left_1));
799     return (0.0 < vec_extract(vec_return, 0));
800 };
801
802 #undef gmx_always_inline
803
804 #endif /* GMX_CPU_ACCELERATION_IBM_QPX */
805
806 #ifdef __MIC__
807 #include "general_x86_mic.h"
808 #endif
809
810 #ifdef GMX_HAVE_SIMD_MACROS
811 /* Generic functions to extract a SIMD aligned pointer from a pointer x.
812  * x should have at least GMX_SIMD_WIDTH_HERE elements extra compared
813  * to how many you want to use, to avoid indexing outside the aligned region.
814  */
815
816 static gmx_inline real *
817 gmx_simd_align_real(const real *x)
818 {
819     return (real *)(((size_t)((x)+GMX_SIMD_WIDTH_HERE)) & (~((size_t)(GMX_SIMD_WIDTH_HERE*sizeof(real)-1))));
820 }
821
822 static gmx_inline int *
823 gmx_simd_align_int(const int *x)
824 {
825     return (int  *)(((size_t)((x)+GMX_SIMD_WIDTH_HERE)) & (~((size_t)(GMX_SIMD_WIDTH_HERE*sizeof(int )-1))));
826 }
827
828
829 /* Include the math functions which only need the above macros,
830  * generally these are the ones that don't need masking operations.
831  */
832 #ifdef GMX_DOUBLE
833 #include "math_double.h"
834 #else
835 #include "math_single.h"
836 #endif
837
838
839 #endif /* GMX_HAVE_SIMD_MACROS */
840
841 #endif