2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
36 #ifndef GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
37 #define GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
40 /* Fujitsu header borrows the name from SSE2, since some instructions have aliases */
41 #include <emmintrin.h>
44 /* Sparc64 HPC-ACE SIMD instruction wrappers
46 * Please see documentation in gromacs/simd/simd.h for defines.
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.
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
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
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.
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 */
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)
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)
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)
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.
247 const _fjsp_v2r4 *p = (const _fjsp_v2r4 *)m;
251 return _fjsp_stod_v2r8(simd);
254 static gmx_inline void
255 gmx_simd_store_f_sparc64_hpc_ace(float *m, gmx_simd_float_t x)
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.
260 _fjsp_v2r4 *p = (_fjsp_v2r4 *)m;
261 *p = _fjsp_dtos_v2r4(x);
264 static gmx_inline gmx_simd_dint32_t
265 gmx_simd_load_di_sparc64_hpc_ace(const int *m)
277 return _fjsp_load_v2r8( (double *) &(conv.simd) );
280 static gmx_inline void
281 gmx_simd_store_di_sparc64_hpc_ace(int *m, gmx_simd_dint32_t x)
290 _fjsp_store_v2r8( (double *) &(conv.simd), x );
296 static gmx_inline gmx_simd_dint32_t
297 gmx_simd_set1_di_sparc64_hpc_ace(int i)
309 return _fjsp_load_v2r8( (double *) &(conv.simd) );
312 static gmx_inline int
313 gmx_simd_extract_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
316 /* This conditional should be optimized away at compile time */
319 _fjsp_storel_v2r8((double *)&res, x);
323 _fjsp_storeh_v2r8((double *)&res, x);
328 static gmx_inline gmx_simd_dint32_t
329 gmx_simd_slli_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
331 _fjsp_v2i8 ix = *((_fjsp_v2i8 *)&x);
332 ix = _fjsp_slli_v2i8(ix, i);
333 x = *((_fjsp_v2r8 *)&ix);
337 static gmx_inline gmx_simd_dint32_t
338 gmx_simd_srli_di_sparc64_hpc_ace(gmx_simd_dint32_t x, int i)
340 _fjsp_v2i8 ix = *((_fjsp_v2i8 *)&x);
341 ix = _fjsp_srli_v2i8(ix, i);
342 x = *((_fjsp_v2r8 *)&ix);
346 static gmx_inline gmx_simd_dint32_t
347 gmx_simd_cvt_d2i_sparc64_hpc_ace(gmx_simd_double_t x)
349 _fjsp_v2r8 signbit = _fjsp_set_v2r8(-0.0, -0.0);
350 _fjsp_v2r8 half = _fjsp_set_v2r8(0.5, 0.5);
352 x = _fjsp_add_v2r8(x, _fjsp_or_v2r8(_fjsp_and_v2r8(signbit, x), half));
353 return _fjsp_dtox_v2r8(x);
356 static gmx_inline int
357 gmx_simd_anytrue_d_sparc64_hpc_ace(gmx_simd_dbool_t x)
360 x = _fjsp_or_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
361 _fjsp_storel_v2r8((double *)&i, x);
365 static gmx_inline double
366 gmx_simd_reduce_d_sparc64_hpc_ace(gmx_simd_double_t x)
369 x = _fjsp_add_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
370 _fjsp_storel_v2r8(&d, x);
375 static gmx_inline gmx_simd_double_t
376 gmx_simd_get_exponent_d_sparc64_hpc_ace(gmx_simd_double_t x)
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
383 const gmx_int64_t expmask = 0x7ff0000000000000LL;
384 const gmx_int64_t expbias = 1023LL;
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);
400 static gmx_inline gmx_simd_double_t
401 gmx_simd_get_mantissa_d_sparc64_hpc_ace(gmx_simd_double_t x)
403 gmx_int64_t mantmask[2] = {0x000fffffffffffffLL, 0x000fffffffffffffLL};
404 gmx_simd_double_t one = _fjsp_set_v2r8(1.0, 1.0);
406 x = _fjsp_and_v2r8(x, _fjsp_load_v2r8((double *)mantmask));
407 return _fjsp_or_v2r8(x, one);
410 static gmx_inline gmx_simd_double_t
411 gmx_simd_set_exponent_d_sparc64_hpc_ace(gmx_simd_double_t x)
413 const gmx_int64_t expbias = 1023;
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;
426 return _fjsp_load_v2r8( (double *) &conv.simd);
430 /* No SIMD4 support, since both single & double are only 2-wide */
432 #endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_H */