K-computer specific modifications
[alexxy/gromacs.git] / src / gromacs / simd / impl_sparc64_hpc_ace / impl_sparc64_hpc_ace.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 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 #ifndef GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
37 #define GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
38
39 #include <math.h>
40 /* Fujitsu header borrows the name from SSE2, since some instructions have aliases */
41 #include <emmintrin.h>
42
43
44 /* Sparc64 HPC-ACE SIMD instruction wrappers
45  *
46  * Please see documentation in gromacs/simd/simd.h for defines.
47  */
48
49 /* Capability definitions for Sparc64 HPC-ACE */
50 /* HPC-ACE is actually double-only on the register level, but we also implement
51  * a single-precision interface where we only offer single-precision accuracy
52  * in math functions - this can save quite a few cycles.
53  */
54 #define GMX_SIMD_HAVE_FLOAT
55 #define GMX_SIMD_HAVE_DOUBLE
56 #define GMX_SIMD_HAVE_HARDWARE
57 #undef  GMX_SIMD_HAVE_LOADU
58 #undef  GMX_SIMD_HAVE_STOREU
59 #define GMX_SIMD_HAVE_LOGICAL
60 #define GMX_SIMD_HAVE_FMA
61 #undef  GMX_SIMD_HAVE_FRACTION
62 #define GMX_SIMD_HAVE_FINT32
63 #define GMX_SIMD_HAVE_FINT32_EXTRACT
64 #define GMX_SIMD_HAVE_FINT32_LOGICAL
65 #undef  GMX_SIMD_HAVE_FINT32_ARITHMETICS
66 #define GMX_SIMD_HAVE_DINT32
67 #define GMX_SIMD_HAVE_DINT32_EXTRACT
68 #define GMX_SIMD_HAVE_DINT32_LOGICAL
69 #undef  GMX_SIMD_HAVE_DINT32_ARITHMETICS
70 #undef  GMX_SIMD4_HAVE_FLOAT
71 #undef  GMX_SIMD4_HAVE_DOUBLE
72
73 /* Implementation details */
74 #define GMX_SIMD_FLOAT_WIDTH         2
75 #define GMX_SIMD_DOUBLE_WIDTH        2
76 #define GMX_SIMD_FINT32_WIDTH        2
77 #define GMX_SIMD_DINT32_WIDTH        2
78 #define GMX_SIMD_RSQRT_BITS         10
79 #define GMX_SIMD_RCP_BITS            9
80
81 /* HPC-ACE is a bit strange; some instructions like
82  * shifts only work on _integer_ versions of SIMD
83  * registers, but there are no intrinsics to load
84  * or convert, or even to cast. The only way to use
85  * them is to declare unions with the SIMD integer
86  * type. However, this will lead to extra load ops,
87  * and the normal real-to-int and int-to-real
88  * conversions work purely on the v2r8 fp regs.
89  * Since our most common usage is to convert and
90  * then extract the result for table lookups, we
91  * define the gmx_simd_fint32_t datatype to use
92  * the v2r8 rather than v2i8 SIMD type.
93  */
94
95 /****************************************************
96  *      SINGLE PRECISION SIMD IMPLEMENTATION        *
97  ****************************************************/
98 #define gmx_simd_float_t          _fjsp_v2r8
99 #define gmx_simd_load_f           gmx_simd_load_f_sparc64_hpc_ace
100 #define gmx_simd_load1_f(m)       _fjsp_set_v2r8((*m), (*m))
101 #define gmx_simd_set1_f(a)        _fjsp_set_v2r8(a, a)
102 #define gmx_simd_store_f          gmx_simd_store_f_sparc64_hpc_ace
103 #define gmx_simd_loadu_f          gmx_simd_load_f
104 /* No unaligned store of gmx_simd_float_t */
105 #define gmx_simd_setzero_f        _fjsp_setzero_v2r8
106 #define gmx_simd_add_f            _fjsp_add_v2r8
107 #define gmx_simd_sub_f            _fjsp_sub_v2r8
108 #define gmx_simd_mul_f            _fjsp_mul_v2r8
109 #define gmx_simd_fmadd_f(a, b, c)   _fjsp_madd_v2r8(a, b, c)
110 #define gmx_simd_fmsub_f(a, b, c)   _fjsp_msub_v2r8(a, b, c)
111 #define gmx_simd_fnmadd_f(a, b, c)  _fjsp_nmsub_v2r8(a, b, c)
112 #define gmx_simd_fnmsub_f(a, b, c)  _fjsp_nmadd_v2r8(a, b, c)
113 #define gmx_simd_and_f            _fjsp_and_v2r8
114 #define gmx_simd_andnot_f         _fjsp_andnot1_v2r8
115 #define gmx_simd_or_f             _fjsp_or_v2r8
116 #define gmx_simd_xor_f            _fjsp_xor_v2r8
117 #define gmx_simd_rsqrt_f          _fjsp_rsqrta_v2r8
118 #define gmx_simd_rcp_f            _fjsp_rcpa_v2r8
119 #define gmx_simd_fabs_f(x)        _fjsp_abs_v2r8(x)
120 #define gmx_simd_fneg_f(x)        _fjsp_neg_v2r8(x)
121 #define gmx_simd_max_f            _fjsp_max_v2r8
122 #define gmx_simd_min_f            _fjsp_min_v2r8
123 #define gmx_simd_round_f(x)       gmx_simd_round_d(x)
124 #define gmx_simd_trunc_f(x)       gmx_simd_trunc_d(x)
125 #define gmx_simd_fraction_f(x)    gmx_simd_sub_f(x, gmx_simd_trunc_f(x))
126 #define gmx_simd_get_exponent_f   gmx_simd_get_exponent_d_sparc64_hpc_ace
127 #define gmx_simd_get_mantissa_f   gmx_simd_get_mantissa_d_sparc64_hpc_ace
128 #define gmx_simd_set_exponent_f   gmx_simd_set_exponent_d_sparc64_hpc_ace
129 /* integer datatype corresponding to float: gmx_simd_fint32_t */
130 #define gmx_simd_fint32_t         _fjsp_v2r8
131 #define gmx_simd_load_fi(m)       gmx_simd_load_di_sparc64_hpc_ace(m)
132 #define gmx_simd_set1_fi(i)       gmx_simd_set1_di_sparc64_hpc_ace(i)
133 #define gmx_simd_store_fi(m, x)   gmx_simd_store_di_sparc64_hpc_ace(m, x)
134 #define gmx_simd_loadu_fi         gmx_simd_load_fi
135 /* No unaligned store of gmx_simd_fint32_t */
136 #define gmx_simd_setzero_fi       _fjsp_setzero_v2r8
137 #define gmx_simd_cvt_f2i          gmx_simd_cvt_d2i
138 #define gmx_simd_cvtt_f2i         _fjsp_dtox_v2r8
139 #define gmx_simd_cvt_i2f          _fjsp_xtod_v2r8
140 #define gmx_simd_extract_fi      gmx_simd_extract_di_sparc64_hpc_ace
141 /* Integer logical ops on gmx_simd_fint32_t */
142 /* Shifts are horrible since they require memory re-loads. */
143 #define gmx_simd_slli_fi          gmx_simd_slli_di_sparc64_hpc_ace
144 #define gmx_simd_srli_fi          gmx_simd_srli_di_sparc64_hpc_ace
145 #define gmx_simd_and_fi           _fjsp_and_v2r8
146 #define gmx_simd_andnot_fi(a, b)   _fjsp_andnot1_v2r8(a, b)
147 #define gmx_simd_or_fi            _fjsp_or_v2r8
148 #define gmx_simd_xor_fi           _fjsp_xor_v2r8
149 /* No integer arithmetic ops on gmx_simd_fint32_t */
150 /* Boolean & comparison operations on gmx_simd_float_t */
151 #define gmx_simd_fbool_t          _fjsp_v2r8
152 #define gmx_simd_cmpeq_f          _fjsp_cmpeq_v2r8
153 #define gmx_simd_cmplt_f          _fjsp_cmplt_v2r8
154 #define gmx_simd_cmple_f          _fjsp_cmple_v2r8
155 #define gmx_simd_and_fb           _fjsp_and_v2r8
156 #define gmx_simd_or_fb            _fjsp_or_v2r8
157 #define gmx_simd_anytrue_fb       gmx_simd_anytrue_d_sparc64_hpc_ace
158 #define gmx_simd_blendzero_f      _fjsp_and_v2r8
159 #define gmx_simd_blendnotzero_f(a, sel) _fjsp_andnot1_v2r8(sel, a)
160 #define gmx_simd_blendv_f(a, b, s) _fjsp_selmov_v2r8(b, a, s)
161 #define gmx_simd_reduce_f(a)       gmx_simd_reduce_d_sparc64_hpc_ace(a)
162 /* No boolean & comparison operations on gmx_simd_fint32_t */
163 /* No conversions between different booleans */
164
165 /****************************************************
166  *      DOUBLE PRECISION SIMD IMPLEMENTATION        *
167  ****************************************************/
168 #define gmx_simd_double_t          _fjsp_v2r8
169 #define gmx_simd_load_d            _fjsp_load_v2r8
170 #define gmx_simd_load1_d(m)        _fjsp_set_v2r8((*m), (*m))
171 #define gmx_simd_set1_d(a)         _fjsp_set_v2r8(a, a)
172 #define gmx_simd_store_d           _fjsp_store_v2r8
173 #define gmx_simd_loadu_d           gmx_simd_load_d
174 /* No unaligned store of gmx_simd_double_t */
175 #define gmx_simd_setzero_d         _fjsp_setzero_v2r8
176 #define gmx_simd_add_d             _fjsp_add_v2r8
177 #define gmx_simd_sub_d             _fjsp_sub_v2r8
178 #define gmx_simd_mul_d             _fjsp_mul_v2r8
179 #define gmx_simd_fmadd_d(a, b, c)   _fjsp_madd_v2r8(a, b, c)
180 #define gmx_simd_fmsub_d(a, b, c)   _fjsp_msub_v2r8(a, b, c)
181 #define gmx_simd_fnmadd_d(a, b, c)  _fjsp_nmsub_v2r8(a, b, c)
182 #define gmx_simd_fnmsub_d(a, b, c)  _fjsp_nmadd_v2r8(a, b, c)
183 #define gmx_simd_and_d             _fjsp_and_v2r8
184 #define gmx_simd_andnot_d          _fjsp_andnot1_v2r8
185 #define gmx_simd_or_d              _fjsp_or_v2r8
186 #define gmx_simd_xor_d             _fjsp_xor_v2r8
187 #define gmx_simd_rsqrt_d(x)        _fjsp_rsqrta_v2r8(x)
188 #define gmx_simd_rcp_d(x)          _fjsp_rcpa_v2r8(x)
189 #define gmx_simd_fabs_d(x)         _fjsp_abs_v2r8(x)
190 #define gmx_simd_fneg_d(x)         _fjsp_neg_v2r8(x)
191 #define gmx_simd_max_d             _fjsp_max_v2r8
192 #define gmx_simd_min_d             _fjsp_min_v2r8
193 #define gmx_simd_round_d(x)        gmx_simd_cvt_i2d(gmx_simd_cvt_d2i(x))
194 #define gmx_simd_trunc_d(x)        gmx_simd_cvt_i2d(gmx_simd_cvtt_d2i(x))
195 #define gmx_simd_fraction_d(x)     gmx_simd_sub_d(x, gmx_simd_trunc_d(x))
196 #define gmx_simd_get_exponent_d    gmx_simd_get_exponent_d_sparc64_hpc_ace
197 #define gmx_simd_get_mantissa_d    gmx_simd_get_mantissa_d_sparc64_hpc_ace
198 #define gmx_simd_set_exponent_d    gmx_simd_set_exponent_d_sparc64_hpc_ace
199 /* integer datatype corresponding to double: gmx_simd_dint32_t */
200 #define gmx_simd_dint32_t          _fjsp_v2r8
201 #define gmx_simd_load_di(m)        gmx_simd_load_di_sparc64_hpc_ace(m)
202 #define gmx_simd_set1_di(i)        gmx_simd_set1_di_sparc64_hpc_ace(i)
203 #define gmx_simd_store_di(m, x)    gmx_simd_store_di_sparc64_hpc_ace(m, x)
204 #define gmx_simd_loadu_di          gmx_simd_load_di
205 /* No unaligned store of gmx_simd_dint32_t */
206 #define gmx_simd_setzero_di        _fjsp_setzero_v2r8
207 #define gmx_simd_cvt_d2i           gmx_simd_cvt_d2i_sparc64_hpc_ace
208 #define gmx_simd_cvtt_d2i          _fjsp_dtox_v2r8
209 #define gmx_simd_cvt_i2d           _fjsp_xtod_v2r8
210 #define gmx_simd_extract_di        gmx_simd_extract_di_sparc64_hpc_ace
211 /* Integer logical ops on gmx_simd_dint32_t */
212 #define gmx_simd_slli_di           gmx_simd_slli_di_sparc64_hpc_ace
213 #define gmx_simd_srli_di           gmx_simd_srli_di_sparc64_hpc_ace
214 #define gmx_simd_and_di            _fjsp_and_v2r8
215 #define gmx_simd_andnot_di         _fjsp_andnot1_v2r8
216 #define gmx_simd_or_di             _fjsp_or_v2r8
217 #define gmx_simd_xor_di            _fjsp_xor_v2r8
218 /* Integer arithmetic ops on integer datatype corresponding to double */
219 /* Boolean & comparison operations on gmx_simd_double_t */
220 #define gmx_simd_dbool_t           _fjsp_v2r8
221 #define gmx_simd_cmpeq_d           _fjsp_cmpeq_v2r8
222 #define gmx_simd_cmplt_d           _fjsp_cmplt_v2r8
223 #define gmx_simd_cmple_d           _fjsp_cmple_v2r8
224 #define gmx_simd_and_db            _fjsp_and_v2r8
225 #define gmx_simd_or_db             _fjsp_or_v2r8
226 #define gmx_simd_anytrue_db         gmx_simd_anytrue_d_sparc64_hpc_ace
227 #define gmx_simd_blendzero_d        _fjsp_and_v2r8
228 #define gmx_simd_blendnotzero_d(a, sel)  _fjsp_andnot1_v2r8(sel, a)
229 #define gmx_simd_blendv_d(a, b, sel) _fjsp_selmov_v2r8(b, a, sel)
230 #define gmx_simd_reduce_d(a)        gmx_simd_reduce_d_sparc64_hpc_ace(a)
231
232 /* No boolean & comparison operations on gmx_simd_dint32_t */
233 /* Float/double conversion */
234 #define gmx_simd_cvt_f2d(f)         (f)
235 #define gmx_simd_cvt_d2f(d)         (d)
236
237
238 /****************************************************
239  * SINGLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
240  ****************************************************/
241 static gmx_inline gmx_simd_float_t
242 gmx_simd_load_f_sparc64_hpc_ace(const float *m)
243 {
244     /* We are not allowed to cast single-to-double registers, but we can
245      * masquerade the memory location as a variable of type _fjsp_v2r4.
246      */
247     const _fjsp_v2r4 *p = (const _fjsp_v2r4 *)m;
248     _fjsp_v2r4        simd;
249
250     simd = *p;
251     return _fjsp_stod_v2r8(simd);
252 }
253
254 static gmx_inline void
255 gmx_simd_store_f_sparc64_hpc_ace(float *m, gmx_simd_float_t x)
256 {
257     /* We are not allowed to cast single-to-double registers, but we can
258      * masquerade the memory location as a variable of type _fjsp_v2r4.
259      */
260     _fjsp_v2r4 *p = (_fjsp_v2r4 *)m;
261     *p = _fjsp_dtos_v2r4(x);
262 }
263
264 static gmx_inline gmx_simd_dint32_t
265 gmx_simd_load_di_sparc64_hpc_ace(const int *m)
266 {
267     union
268     {
269         _fjsp_v2r8       simd;
270         long long int    i[2];
271     }
272     conv;
273
274     conv.i[0] = m[0];
275     conv.i[1] = m[1];
276
277     return _fjsp_load_v2r8( (double *) &(conv.simd) );
278 }
279
280 static gmx_inline void
281 gmx_simd_store_di_sparc64_hpc_ace(int *m, gmx_simd_dint32_t x)
282 {
283     union
284     {
285         _fjsp_v2r8       simd;
286         long long int    i[2];
287     }
288     conv;
289
290     _fjsp_store_v2r8( (double *) &(conv.simd), x );
291
292     m[0] = conv.i[0];
293     m[1] = conv.i[1];
294 }
295
296 static gmx_inline gmx_simd_dint32_t
297 gmx_simd_set1_di_sparc64_hpc_ace(int i)
298 {
299     union
300     {
301         _fjsp_v2r8       simd;
302         long long int    i[2];
303     }
304     conv;
305
306     conv.i[0] = i;
307     conv.i[1] = i;
308
309     return _fjsp_load_v2r8( (double *) &(conv.simd) );
310 }
311
312 static gmx_inline int
313 gmx_simd_extract_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
314 {
315     long long int res;
316     /* This conditional should be optimized away at compile time */
317     if (i == 0)
318     {
319         _fjsp_storel_v2r8((double *)&res, x);
320     }
321     else
322     {
323         _fjsp_storeh_v2r8((double *)&res, x);
324     }
325     return (int)res;
326 }
327
328 static gmx_inline gmx_simd_dint32_t
329 gmx_simd_slli_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
330 {
331     _fjsp_v2i8 ix = *((_fjsp_v2i8 *)&x);
332     ix = _fjsp_slli_v2i8(ix, i);
333     x  = *((_fjsp_v2r8 *)&ix);
334     return x;
335 }
336
337 static gmx_inline gmx_simd_dint32_t
338 gmx_simd_srli_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
339 {
340     _fjsp_v2i8 ix = *((_fjsp_v2i8 *)&x);
341     ix = _fjsp_srli_v2i8(ix, i);
342     x  = *((_fjsp_v2r8 *)&ix);
343     return x;
344 }
345
346 static gmx_inline gmx_simd_dint32_t
347 gmx_simd_cvt_d2i_sparc64_hpc_ace(gmx_simd_double_t x)
348 {
349     _fjsp_v2r8 signbit = _fjsp_set_v2r8(-0.0, -0.0);
350     _fjsp_v2r8 half    = _fjsp_set_v2r8(0.5, 0.5);
351
352     x = _fjsp_add_v2r8(x, _fjsp_or_v2r8(_fjsp_and_v2r8(signbit, x), half));
353     return _fjsp_dtox_v2r8(x);
354 }
355
356 static gmx_inline int
357 gmx_simd_anytrue_d_sparc64_hpc_ace(gmx_simd_dbool_t x)
358 {
359     long long int i;
360     x = _fjsp_or_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
361     _fjsp_storel_v2r8((double *)&i, x);
362     return (i != 0LL);
363 }
364
365 static gmx_inline double
366 gmx_simd_reduce_d_sparc64_hpc_ace(gmx_simd_double_t x)
367 {
368     double d;
369     x = _fjsp_add_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
370     _fjsp_storel_v2r8(&d, x);
371     return d;
372 }
373
374
375 static gmx_inline gmx_simd_double_t
376 gmx_simd_get_exponent_d_sparc64_hpc_ace(gmx_simd_double_t x)
377 {
378     /* HPC-ACE cannot cast _fjsp_v2r8 to _fjsp_v4i4, so to perform shifts we
379      * would need to store and reload. Since we are only operating on two
380      * numbers it is likely more efficient to do the operations directly on
381      * normal registers.
382      */
383     const gmx_int64_t    expmask   = 0x7ff0000000000000LL;
384     const gmx_int64_t    expbias   = 1023LL;
385
386     union
387     {
388         _fjsp_v2r8       simd;
389         long long int    i[2];
390     }
391     conv;
392
393     _fjsp_store_v2r8( (double *) &conv.simd, x);
394     conv.i[0] = ((conv.i[0] & expmask) >> 52) - expbias;
395     conv.i[1] = ((conv.i[1] & expmask) >> 52) - expbias;
396     x         = _fjsp_load_v2r8( (double *) &conv.simd);
397     return _fjsp_xtod_v2r8(x);
398 }
399
400 static gmx_inline gmx_simd_double_t
401 gmx_simd_get_mantissa_d_sparc64_hpc_ace(gmx_simd_double_t x)
402 {
403     gmx_int64_t       mantmask[2] = {0x000fffffffffffffLL, 0x000fffffffffffffLL};
404     gmx_simd_double_t one         = _fjsp_set_v2r8(1.0, 1.0);
405
406     x = _fjsp_and_v2r8(x, _fjsp_load_v2r8((double *)mantmask));
407     return _fjsp_or_v2r8(x, one);
408 }
409
410 static gmx_inline gmx_simd_double_t
411 gmx_simd_set_exponent_d_sparc64_hpc_ace(gmx_simd_double_t x)
412 {
413     const gmx_int64_t    expbias   = 1023;
414     union
415     {
416         _fjsp_v2r8       simd;
417         long long int    i[2];
418     }
419     conv;
420
421
422     _fjsp_store_v2r8( (double *) &conv.simd, gmx_simd_cvt_d2i_sparc64_hpc_ace(x));
423     conv.i[0] = (conv.i[0] + expbias) << 52;
424     conv.i[1] = (conv.i[1] + expbias) << 52;
425
426     return _fjsp_load_v2r8( (double *) &conv.simd);
427 }
428
429
430 /* No SIMD4 support, since both single & double are only 2-wide */
431
432 #endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_H */