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_X86_SSE2_H
37 #define GMX_SIMD_IMPL_X86_SSE2_H
40 #include <emmintrin.h>
42 /* Set capabilities that can be inherited */
43 #define GMX_SIMD_X86_SSE2_OR_HIGHER
45 /* x86 SSE2 SIMD instruction wrappers
47 * Please see documentation in gromacs/simd/simd.h for defines.
50 /* Capability definitions for SSE2 */
51 #define GMX_SIMD_HAVE_FLOAT
52 #define GMX_SIMD_HAVE_DOUBLE
53 #define GMX_SIMD_HAVE_HARDWARE
54 #define GMX_SIMD_HAVE_LOADU
55 #define GMX_SIMD_HAVE_STOREU
56 #define GMX_SIMD_HAVE_LOGICAL
57 #undef GMX_SIMD_HAVE_FMA
58 #undef GMX_SIMD_HAVE_FRACTION
59 #define GMX_SIMD_HAVE_FINT32
60 #define GMX_SIMD_HAVE_FINT32_EXTRACT /* No SSE2 instruction, but use shifts */
61 #define GMX_SIMD_HAVE_FINT32_LOGICAL
62 #define GMX_SIMD_HAVE_FINT32_ARITHMETICS
63 #define GMX_SIMD_HAVE_DINT32
64 #define GMX_SIMD_HAVE_DINT32_EXTRACT /* No SSE2 instruction, but use shifts */
65 #define GMX_SIMD_HAVE_DINT32_LOGICAL
66 #define GMX_SIMD_HAVE_DINT32_ARITHMETICS
67 #define GMX_SIMD4_HAVE_FLOAT
68 #undef GMX_SIMD4_HAVE_DOUBLE
70 /* Implementation details */
71 #define GMX_SIMD_FLOAT_WIDTH 4
72 #define GMX_SIMD_DOUBLE_WIDTH 2
73 #define GMX_SIMD_FINT32_WIDTH 4
74 #define GMX_SIMD_DINT32_WIDTH 2
75 #define GMX_SIMD_RSQRT_BITS 11
76 #define GMX_SIMD_RCP_BITS 11
78 /****************************************************
79 * SINGLE PRECISION SIMD IMPLEMENTATION *
80 ****************************************************/
81 #define gmx_simd_float_t __m128
82 #define gmx_simd_load_f _mm_load_ps
83 #define gmx_simd_load1_f _mm_load1_ps
84 #define gmx_simd_set1_f _mm_set1_ps
85 #define gmx_simd_store_f _mm_store_ps
86 #define gmx_simd_loadu_f _mm_loadu_ps
87 #define gmx_simd_storeu_f _mm_storeu_ps
88 #define gmx_simd_setzero_f _mm_setzero_ps
89 #define gmx_simd_add_f _mm_add_ps
90 #define gmx_simd_sub_f _mm_sub_ps
91 #define gmx_simd_mul_f _mm_mul_ps
92 #define gmx_simd_fmadd_f(a, b, c) _mm_add_ps(_mm_mul_ps(a, b), c)
93 #define gmx_simd_fmsub_f(a, b, c) _mm_sub_ps(_mm_mul_ps(a, b), c)
94 #define gmx_simd_fnmadd_f(a, b, c) _mm_sub_ps(c, _mm_mul_ps(a, b))
95 #define gmx_simd_fnmsub_f(a, b, c) _mm_sub_ps(_mm_setzero_ps(), gmx_simd_fmadd_f(a, b, c))
96 #define gmx_simd_and_f _mm_and_ps
97 #define gmx_simd_andnot_f _mm_andnot_ps
98 #define gmx_simd_or_f _mm_or_ps
99 #define gmx_simd_xor_f _mm_xor_ps
100 #define gmx_simd_rsqrt_f _mm_rsqrt_ps
101 #define gmx_simd_rcp_f _mm_rcp_ps
102 #define gmx_simd_fabs_f(x) _mm_andnot_ps(_mm_set1_ps(GMX_FLOAT_NEGZERO), x)
103 #define gmx_simd_fneg_f(x) _mm_xor_ps(x, _mm_set1_ps(GMX_FLOAT_NEGZERO))
104 #define gmx_simd_max_f _mm_max_ps
105 #define gmx_simd_min_f _mm_min_ps
106 #define gmx_simd_round_f(x) _mm_cvtepi32_ps(_mm_cvtps_epi32(x))
107 #define gmx_simd_trunc_f(x) _mm_cvtepi32_ps(_mm_cvttps_epi32(x))
108 #define gmx_simd_fraction_f(x) _mm_sub_ps(x, gmx_simd_trunc_f(x))
109 #define gmx_simd_get_exponent_f gmx_simd_get_exponent_f_sse2
110 #define gmx_simd_get_mantissa_f gmx_simd_get_mantissa_f_sse2
111 #define gmx_simd_set_exponent_f gmx_simd_set_exponent_f_sse2
112 /* integer datatype corresponding to float: gmx_simd_fint32_t */
113 #define gmx_simd_fint32_t __m128i
114 #define gmx_simd_load_fi(m) _mm_load_si128((const __m128i *)m)
115 #define gmx_simd_set1_fi _mm_set1_epi32
116 #define gmx_simd_store_fi(m, x) _mm_store_si128((__m128i *)m, x)
117 #define gmx_simd_loadu_fi(m) _mm_loadu_si128((const __m128i *)m)
118 #define gmx_simd_storeu_fi(m, x) _mm_storeu_si128((__m128i *)m, x)
119 #define gmx_simd_setzero_fi _mm_setzero_si128
120 #define gmx_simd_cvt_f2i _mm_cvtps_epi32
121 #define gmx_simd_cvtt_f2i _mm_cvttps_epi32
122 #define gmx_simd_cvt_i2f _mm_cvtepi32_ps
123 #define gmx_simd_extract_fi(x, i) _mm_cvtsi128_si32(_mm_srli_si128((x), 4 * (i)))
124 /* Integer logical ops on gmx_simd_fint32_t */
125 #define gmx_simd_slli_fi _mm_slli_epi32
126 #define gmx_simd_srli_fi _mm_srli_epi32
127 #define gmx_simd_and_fi _mm_and_si128
128 #define gmx_simd_andnot_fi _mm_andnot_si128
129 #define gmx_simd_or_fi _mm_or_si128
130 #define gmx_simd_xor_fi _mm_xor_si128
131 /* Integer arithmetic ops on gmx_simd_fint32_t */
132 #define gmx_simd_add_fi _mm_add_epi32
133 #define gmx_simd_sub_fi _mm_sub_epi32
134 #define gmx_simd_mul_fi gmx_simd_mul_fi_sse2
135 /* Boolean & comparison operations on gmx_simd_float_t */
136 #define gmx_simd_fbool_t __m128
137 #define gmx_simd_cmpeq_f _mm_cmpeq_ps
138 #define gmx_simd_cmplt_f _mm_cmplt_ps
139 #define gmx_simd_cmple_f _mm_cmple_ps
140 #define gmx_simd_and_fb _mm_and_ps
141 #define gmx_simd_or_fb _mm_or_ps
142 #define gmx_simd_anytrue_fb _mm_movemask_ps
143 #define gmx_simd_blendzero_f _mm_and_ps
144 #define gmx_simd_blendnotzero_f(a, sel) _mm_andnot_ps(sel, a)
145 #define gmx_simd_blendv_f(a, b, s) _mm_or_ps(_mm_andnot_ps(s, a), _mm_and_ps(s, b))
146 #define gmx_simd_reduce_f(a) gmx_simd_reduce_f_sse2(a)
147 /* Boolean & comparison operations on gmx_simd_fint32_t */
148 #define gmx_simd_fibool_t __m128i
149 #define gmx_simd_cmpeq_fi _mm_cmpeq_epi32
150 #define gmx_simd_cmplt_fi _mm_cmplt_epi32
151 #define gmx_simd_and_fib _mm_and_si128
152 #define gmx_simd_or_fib _mm_or_si128
153 #define gmx_simd_anytrue_fib _mm_movemask_epi8
154 #define gmx_simd_blendzero_fi _mm_and_si128
155 #define gmx_simd_blendnotzero_fi(a, sel) _mm_andnot_si128(sel, a)
156 #define gmx_simd_blendv_fi(a, b, s) _mm_or_si128(_mm_andnot_si128(s, a), _mm_and_si128(s, b))
157 /* Conversions between different booleans */
158 #define gmx_simd_cvt_fb2fib _mm_castps_si128
159 #define gmx_simd_cvt_fib2fb _mm_castsi128_ps
161 /****************************************************
162 * DOUBLE PRECISION SIMD IMPLEMENTATION *
163 ****************************************************/
164 #define gmx_simd_double_t __m128d
165 #define gmx_simd_load_d _mm_load_pd
166 #define gmx_simd_load1_d _mm_load1_pd
167 #define gmx_simd_set1_d _mm_set1_pd
168 #define gmx_simd_store_d _mm_store_pd
169 #define gmx_simd_loadu_d _mm_loadu_pd
170 #define gmx_simd_storeu_d _mm_storeu_pd
171 #define gmx_simd_setzero_d _mm_setzero_pd
172 #define gmx_simd_add_d _mm_add_pd
173 #define gmx_simd_sub_d _mm_sub_pd
174 #define gmx_simd_mul_d _mm_mul_pd
175 #define gmx_simd_fmadd_d(a, b, c) _mm_add_pd(_mm_mul_pd(a, b), c)
176 #define gmx_simd_fmsub_d(a, b, c) _mm_sub_pd(_mm_mul_pd(a, b), c)
177 #define gmx_simd_fnmadd_d(a, b, c) _mm_sub_pd(c, _mm_mul_pd(a, b))
178 #define gmx_simd_fnmsub_d(a, b, c) _mm_sub_pd(_mm_setzero_pd(), gmx_simd_fmadd_d(a, b, c))
179 #define gmx_simd_and_d _mm_and_pd
180 #define gmx_simd_andnot_d _mm_andnot_pd
181 #define gmx_simd_or_d _mm_or_pd
182 #define gmx_simd_xor_d _mm_xor_pd
183 #define gmx_simd_rsqrt_d(x) _mm_cvtps_pd(_mm_rsqrt_ps(_mm_cvtpd_ps(x)))
184 /* Don't use FMA for sqrt N-R iterations - this saves 1 instruction without FMA hardware */
185 #define gmx_simd_rcp_d(x) _mm_cvtps_pd(_mm_rcp_ps(_mm_cvtpd_ps(x)))
186 #define gmx_simd_fabs_d(x) _mm_andnot_pd(_mm_set1_pd(GMX_DOUBLE_NEGZERO), x)
187 #define gmx_simd_fneg_d(x) _mm_xor_pd(x, _mm_set1_pd(GMX_DOUBLE_NEGZERO))
188 #define gmx_simd_max_d _mm_max_pd
189 #define gmx_simd_min_d _mm_min_pd
190 #define gmx_simd_round_d(x) _mm_cvtepi32_pd(_mm_cvtpd_epi32(x))
191 #define gmx_simd_trunc_d(x) _mm_cvtepi32_pd(_mm_cvttpd_epi32(x))
192 #define gmx_simd_fraction_d(x) _mm_sub_pd(x, gmx_simd_trunc_d(x))
193 #define gmx_simd_get_exponent_d gmx_simd_get_exponent_d_sse2
194 #define gmx_simd_get_mantissa_d gmx_simd_get_mantissa_d_sse2
195 #define gmx_simd_set_exponent_d gmx_simd_set_exponent_d_sse2
196 /* integer datatype corresponding to double: gmx_simd_dint32_t */
197 #define gmx_simd_dint32_t __m128i
198 #define gmx_simd_load_di(m) _mm_loadl_epi64((const __m128i *)m)
199 #define gmx_simd_set1_di _mm_set1_epi32
200 #define gmx_simd_store_di(m, x) _mm_storel_epi64((__m128i *)m, x)
201 #define gmx_simd_loadu_di(m) _mm_loadl_epi64((const __m128i *)m)
202 #define gmx_simd_storeu_di(m, x) _mm_storel_epi64((__m128i *)m, x)
203 #define gmx_simd_setzero_di _mm_setzero_si128
204 #define gmx_simd_cvt_d2i _mm_cvtpd_epi32
205 #define gmx_simd_cvtt_d2i _mm_cvttpd_epi32
206 #define gmx_simd_cvt_i2d _mm_cvtepi32_pd
207 #define gmx_simd_extract_di(x, i) _mm_cvtsi128_si32(_mm_srli_si128((x), 4 * (i)))
208 /* Integer logical ops on gmx_simd_dint32_t */
209 #define gmx_simd_slli_di _mm_slli_epi32
210 #define gmx_simd_srli_di _mm_srli_epi32
211 #define gmx_simd_and_di _mm_and_si128
212 #define gmx_simd_andnot_di _mm_andnot_si128
213 #define gmx_simd_or_di _mm_or_si128
214 #define gmx_simd_xor_di _mm_xor_si128
215 /* Integer arithmetic ops on integer datatype corresponding to double */
216 #define gmx_simd_add_di _mm_add_epi32
217 #define gmx_simd_sub_di _mm_sub_epi32
218 #define gmx_simd_mul_di gmx_simd_mul_di_sse2
219 /* Boolean & comparison operations on gmx_simd_double_t */
220 #define gmx_simd_dbool_t __m128d
221 #define gmx_simd_cmpeq_d _mm_cmpeq_pd
222 #define gmx_simd_cmplt_d _mm_cmplt_pd
223 #define gmx_simd_cmple_d _mm_cmple_pd
224 #define gmx_simd_and_db _mm_and_pd
225 #define gmx_simd_or_db _mm_or_pd
226 #define gmx_simd_anytrue_db _mm_movemask_pd
227 #define gmx_simd_blendzero_d _mm_and_pd
228 #define gmx_simd_blendnotzero_d(a, sel) _mm_andnot_pd(sel, a)
229 #define gmx_simd_blendv_d(a, b, sel) _mm_or_pd(_mm_andnot_pd(sel, a), _mm_and_pd(sel, b))
230 #define gmx_simd_reduce_d(a) gmx_simd_reduce_d_sse2(a)
232 /* Boolean & comparison operations on gmx_simd_dint32_t */
233 #define gmx_simd_dibool_t __m128i
234 #define gmx_simd_cmpeq_di _mm_cmpeq_epi32
235 #define gmx_simd_cmplt_di _mm_cmplt_epi32
236 #define gmx_simd_and_dib _mm_and_si128
237 #define gmx_simd_or_dib _mm_or_si128
238 #define gmx_simd_anytrue_dib(x) _mm_movemask_epi8(_mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 1, 0)))
239 #define gmx_simd_blendzero_di _mm_and_si128
240 #define gmx_simd_blendnotzero_di(a, sel) _mm_andnot_si128(sel, a)
241 #define gmx_simd_blendv_di(a, b, sel) _mm_or_si128(_mm_andnot_si128(sel, a), _mm_and_si128(sel, b))
242 #define gmx_simd_cvt_db2dib(x) _mm_shuffle_epi32(_mm_castpd_si128(x), _MM_SHUFFLE(2, 0, 2, 0))
243 #define gmx_simd_cvt_dib2db(x) _mm_castsi128_pd(_mm_shuffle_epi32(x, _MM_SHUFFLE(1, 1, 0, 0)))
244 /* Float/double conversion */
245 #define gmx_simd_cvt_f2dd(f, d0, d1) { *d0 = _mm_cvtps_pd(f); *d1 = _mm_cvtps_pd(_mm_movehl_ps(f, f)); }
246 #define gmx_simd_cvt_dd2f(d0, d1) _mm_movelh_ps(_mm_cvtpd_ps(d0), _mm_cvtpd_ps(d1))
249 /****************************************************
250 * SINGLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
251 ****************************************************/
252 static gmx_inline __m128 gmx_simdcall
253 gmx_simd_get_exponent_f_sse2(__m128 x)
255 const __m128 expmask = _mm_castsi128_ps(_mm_set1_epi32(0x7F800000));
256 const __m128i expbias = _mm_set1_epi32(127);
259 iexp = _mm_castps_si128(_mm_and_ps(x, expmask));
260 iexp = _mm_sub_epi32(_mm_srli_epi32(iexp, 23), expbias);
261 return _mm_cvtepi32_ps(iexp);
264 static gmx_inline __m128 gmx_simdcall
265 gmx_simd_get_mantissa_f_sse2(__m128 x)
267 const __m128 mantmask = _mm_castsi128_ps(_mm_set1_epi32(0x007FFFFF));
268 const __m128 one = _mm_set1_ps(1.0f);
270 x = _mm_and_ps(x, mantmask);
271 return _mm_or_ps(x, one);
274 static gmx_inline __m128 gmx_simdcall
275 gmx_simd_set_exponent_f_sse2(__m128 x)
277 const __m128i expbias = _mm_set1_epi32(127);
278 __m128i iexp = _mm_cvtps_epi32(x);
280 iexp = _mm_slli_epi32(_mm_add_epi32(iexp, expbias), 23);
281 return _mm_castsi128_ps(iexp);
284 static gmx_inline __m128i gmx_simdcall
285 gmx_simd_mul_fi_sse2(__m128i a, __m128i b)
287 __m128i a1 = _mm_srli_si128(a, 4); /* - a[3] a[2] a[1] */
288 __m128i b1 = _mm_srli_si128(b, 4); /* - b[3] b[2] b[1] */
289 __m128i c = _mm_mul_epu32(a, b);
290 __m128i c1 = _mm_mul_epu32(a1, b1);
292 c = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 1, 2, 0)); /* - - a[2]*b[2] a[0]*b[0] */
293 c1 = _mm_shuffle_epi32(c1, _MM_SHUFFLE(3, 1, 2, 0)); /* - - a[3]*b[3] a[1]*b[1] */
295 return _mm_unpacklo_epi32(c, c1);
298 static gmx_inline float gmx_simdcall
299 gmx_simd_reduce_f_sse2(__m128 a)
303 b = _mm_add_ps(a, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2)));
304 b = _mm_add_ss(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 3, 2, 1)));
309 /****************************************************
310 * DOUBLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
311 ****************************************************/
312 static gmx_inline __m128d gmx_simdcall
313 gmx_simd_get_exponent_d_sse2(__m128d x)
315 /* Don't use _mm_set1_epi64x() - on MSVC it is only supported for 64-bit builds */
316 const __m128d expmask = _mm_castsi128_pd( _mm_set_epi32(0x7FF00000, 0x00000000, 0x7FF00000, 0x00000000) );
317 const __m128i expbias = _mm_set1_epi32(1023);
320 iexp = _mm_castpd_si128(_mm_and_pd(x, expmask));
321 iexp = _mm_sub_epi32(_mm_srli_epi64(iexp, 52), expbias);
322 iexp = _mm_shuffle_epi32(iexp, _MM_SHUFFLE(3, 1, 2, 0) );
323 return _mm_cvtepi32_pd(iexp);
326 static gmx_inline __m128d gmx_simdcall
327 gmx_simd_get_mantissa_d_sse2(__m128d x)
329 /* Don't use _mm_set1_epi64x() - on MSVC it is only supported for 64-bit builds */
330 const __m128d mantmask = _mm_castsi128_pd( _mm_set_epi32(0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF) );
331 const __m128d one = _mm_set1_pd(1.0);
333 x = _mm_and_pd(x, mantmask);
334 return _mm_or_pd(x, one);
337 static gmx_inline __m128d gmx_simdcall
338 gmx_simd_set_exponent_d_sse2(__m128d x)
340 const __m128i expbias = _mm_set1_epi32(1023);
341 __m128i iexp = _mm_cvtpd_epi32(x);
343 /* After conversion integers will be in slot 0,1. Move them to 0,2 so
344 * we can do a 64-bit shift and get them to the dp exponents. */
345 iexp = _mm_shuffle_epi32(iexp, _MM_SHUFFLE(3, 1, 2, 0));
346 iexp = _mm_slli_epi64(_mm_add_epi32(iexp, expbias), 52);
347 return _mm_castsi128_pd(iexp);
350 static gmx_inline __m128i gmx_simdcall
351 gmx_simd_mul_di_sse2(__m128i a, __m128i b)
355 a = _mm_unpacklo_epi32(a, _mm_setzero_si128()); /* 0 a[1] 0 a[0] */
356 b = _mm_unpacklo_epi32(b, _mm_setzero_si128()); /* 0 b[1] 0 b[0] */
358 c = _mm_mul_epu32(a, b); /* 0 a[1]*b[1] 0 a[0]*b[0] */
359 return _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 1, 2, 0)); /* 0 0 a[1]*b[1] a[0]*b[0] */
362 static gmx_inline double gmx_simdcall
363 gmx_simd_reduce_d_sse2(__m128d a)
368 b = _mm_add_sd(a, _mm_shuffle_pd(a, a, _MM_SHUFFLE2(1, 1)));
373 /* Function to check whether SIMD operations have resulted in overflow */
375 gmx_simd_check_and_reset_overflow(void)
380 MXCSR = _mm_getcsr();
381 /* The overflow flag is bit 3 in the register */
385 /* Set the overflow flag to zero */
386 MXCSR = MXCSR & 0xFFF7;
396 /* SSE2 is already 4-wide in single, so we just reuse float datatype for SIMD4.
397 * SSE2 cannot do double-precision SIMD4.
399 #define gmx_simd4_float_t gmx_simd_float_t
400 #define gmx_simd4_load_f gmx_simd_load_f
401 #define gmx_simd4_load1_f gmx_simd_load1_f
402 #define gmx_simd4_set1_f gmx_simd_set1_f
403 #define gmx_simd4_store_f gmx_simd_store_f
404 #define gmx_simd4_loadu_f gmx_simd_loadu_f
405 #define gmx_simd4_storeu_f gmx_simd_storeu_f
406 #define gmx_simd4_setzero_f gmx_simd_setzero_f
407 #define gmx_simd4_add_f gmx_simd_add_f
408 #define gmx_simd4_sub_f gmx_simd_sub_f
409 #define gmx_simd4_mul_f gmx_simd_mul_f
410 #define gmx_simd4_fmadd_f gmx_simd_fmadd_f
411 #define gmx_simd4_fmsub_f gmx_simd_fmsub_f
412 #define gmx_simd4_fnmadd_f gmx_simd_fnmadd_f
413 #define gmx_simd4_fnmsub_f gmx_simd_fnmsub_f
414 #define gmx_simd4_and_f gmx_simd_and_f
415 #define gmx_simd4_andnot_f gmx_simd_andnot_f
416 #define gmx_simd4_or_f gmx_simd_or_f
417 #define gmx_simd4_xor_f gmx_simd_xor_f
418 #define gmx_simd4_rsqrt_f gmx_simd_rsqrt_f
419 #define gmx_simd4_fabs_f gmx_simd_fabs_f
420 #define gmx_simd4_fneg_f gmx_simd_fneg_f
421 #define gmx_simd4_max_f gmx_simd_max_f
422 #define gmx_simd4_min_f gmx_simd_min_f
423 #define gmx_simd4_round_f gmx_simd_round_f
424 #define gmx_simd4_trunc_f gmx_simd_trunc_f
425 #define gmx_simd4_dotproduct3_f gmx_simd4_dotproduct3_f_sse2
426 #define gmx_simd4_fbool_t gmx_simd_fbool_t
427 #define gmx_simd4_cmpeq_f gmx_simd_cmpeq_f
428 #define gmx_simd4_cmplt_f gmx_simd_cmplt_f
429 #define gmx_simd4_cmple_f gmx_simd_cmple_f
430 #define gmx_simd4_and_fb gmx_simd_and_fb
431 #define gmx_simd4_or_fb gmx_simd_or_fb
432 #define gmx_simd4_anytrue_fb gmx_simd_anytrue_fb
433 #define gmx_simd4_blendzero_f gmx_simd_blendzero_f
434 #define gmx_simd4_blendnotzero_f gmx_simd_blendnotzero_f
435 #define gmx_simd4_blendv_f gmx_simd_blendv_f
436 #define gmx_simd4_reduce_f gmx_simd_reduce_f
438 /* SIMD4 Dotproduct helper function */
439 static gmx_inline float gmx_simdcall
440 gmx_simd4_dotproduct3_f_sse2(__m128 a, __m128 b)
444 a = _mm_mul_ps(a, b);
445 c = _mm_add_ps(a, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 2, 1)));
446 c = _mm_add_ps(c, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 3, 2)));
451 #endif /* GMX_SIMD_IMPL_X86_SSE2_H */