Used IWYU to partially clean up some includes
[alexxy/gromacs.git] / src / gromacs / simd / impl_x86_avx_256 / impl_x86_avx_256.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_X86_AVX_256_H
37 #define GMX_SIMD_IMPL_X86_AVX_256_H
38
39 #include "config.h"
40
41 #include <immintrin.h>
42
43 /* It is cleaner to start the AVX implementation from scratch rather than
44  * first inheriting from SSE4.1, which in turn inherits from SSE2. However,
45  * the capabilities still form a superset.
46  */
47 #define GMX_SIMD_X86_SSE2_OR_HIGHER
48 #define GMX_SIMD_X86_SSE4_1_OR_HIGHER
49 #define GMX_SIMD_X86_AVX_256_OR_HIGHER
50
51
52 /* x86 256-bit AVX SIMD instruction wrappers
53  *
54  * Please see documentation in gromacs/simd/simd.h for defines.
55  */
56
57 /* Capability definitions for 256-bit AVX - no inheritance from SSE */
58 #define GMX_SIMD_HAVE_FLOAT
59 #define GMX_SIMD_HAVE_DOUBLE
60 #define GMX_SIMD_HAVE_SIMD_HARDWARE
61 #define GMX_SIMD_HAVE_LOADU
62 #define GMX_SIMD_HAVE_STOREU
63 #define GMX_SIMD_HAVE_LOGICAL
64 #undef  GMX_SIMD_HAVE_FMA
65 #undef  GMX_SIMD_HAVE_FRACTION
66 #define GMX_SIMD_HAVE_FINT32
67 #define GMX_SIMD_HAVE_FINT32_EXTRACT     /* Emulated */
68 #undef  GMX_SIMD_HAVE_FINT32_LOGICAL     /* AVX1 cannot do 256-bit int shifts */
69 #undef  GMX_SIMD_HAVE_FINT32_ARITHMETICS /* AVX1 cannot do 256-bit int +,-,*  */
70 #define GMX_SIMD_HAVE_DINT32
71 #define GMX_SIMD_HAVE_DINT32_EXTRACT     /* Native, dint uses 128-bit SIMD    */
72 #define GMX_SIMD_HAVE_DINT32_LOGICAL
73 #define GMX_SIMD_HAVE_DINT32_ARITHMETICS
74 #define GMX_SIMD4_HAVE_FLOAT
75 #define GMX_SIMD4_HAVE_DOUBLE
76
77 /* Implementation details */
78 #define GMX_SIMD_FLOAT_WIDTH         8
79 #define GMX_SIMD_DOUBLE_WIDTH        4
80 #define GMX_SIMD_FINT32_WIDTH        8
81 #define GMX_SIMD_DINT32_WIDTH        4
82 #define GMX_SIMD_RSQRT_BITS         11
83 #define GMX_SIMD_RCP_BITS           11
84
85 /****************************************************
86  *      SINGLE PRECISION SIMD IMPLEMENTATION        *
87  ****************************************************/
88 #define gmx_simd_float_t           __m256
89 #define gmx_simd_load_f            _mm256_load_ps
90 #define gmx_simd_load1_f           _mm256_broadcast_ss
91 #define gmx_simd_set1_f            _mm256_set1_ps
92 #define gmx_simd_store_f           _mm256_store_ps
93 #define gmx_simd_loadu_f           _mm256_loadu_ps
94 #define gmx_simd_storeu_f          _mm256_storeu_ps
95 #define gmx_simd_setzero_f         _mm256_setzero_ps
96 #define gmx_simd_add_f             _mm256_add_ps
97 #define gmx_simd_sub_f             _mm256_sub_ps
98 #define gmx_simd_mul_f             _mm256_mul_ps
99 #define gmx_simd_fmadd_f(a, b, c)    _mm256_add_ps(_mm256_mul_ps(a, b), c)
100 #define gmx_simd_fmsub_f(a, b, c)    _mm256_sub_ps(_mm256_mul_ps(a, b), c)
101 #define gmx_simd_fnmadd_f(a, b, c)   _mm256_sub_ps(c, _mm256_mul_ps(a, b))
102 #define gmx_simd_fnmsub_f(a, b, c)   _mm256_sub_ps(_mm256_setzero_ps(), gmx_simd_fmadd_f(a, b, c))
103 #define gmx_simd_and_f             _mm256_and_ps
104 #define gmx_simd_andnot_f          _mm256_andnot_ps
105 #define gmx_simd_or_f              _mm256_or_ps
106 #define gmx_simd_xor_f             _mm256_xor_ps
107 #define gmx_simd_rsqrt_f           _mm256_rsqrt_ps
108 #define gmx_simd_rcp_f             _mm256_rcp_ps
109 #define gmx_simd_fabs_f(x)         _mm256_andnot_ps(_mm256_set1_ps(GMX_FLOAT_NEGZERO), x)
110 #define gmx_simd_fneg_f(x)         _mm256_xor_ps(x, _mm256_set1_ps(GMX_FLOAT_NEGZERO))
111 #define gmx_simd_max_f             _mm256_max_ps
112 #define gmx_simd_min_f             _mm256_min_ps
113 #define gmx_simd_round_f(x)        _mm256_round_ps(x, _MM_FROUND_NINT)
114 #define gmx_simd_trunc_f(x)        _mm256_round_ps(x, _MM_FROUND_TRUNC)
115 #define gmx_simd_fraction_f(x)     _mm256_sub_ps(x, gmx_simd_trunc_f(x))
116 #define gmx_simd_get_exponent_f    gmx_simd_get_exponent_f_avx_256
117 #define gmx_simd_get_mantissa_f    gmx_simd_get_mantissa_f_avx_256
118 #define gmx_simd_set_exponent_f    gmx_simd_set_exponent_f_avx_256
119 /* integer datatype corresponding to float: gmx_simd_fint32_t */
120 #define gmx_simd_fint32_t          __m256i
121 #define gmx_simd_load_fi(m)        _mm256_load_si256((__m256i const*)m)
122 #define gmx_simd_set1_fi           _mm256_set1_epi32
123 #define gmx_simd_store_fi(m, x)    _mm256_store_si256((__m256i *)m, x)
124 #define gmx_simd_loadu_fi(m)       _mm256_loadu_si256((__m256i const*)m)
125 #define gmx_simd_storeu_fi(m, x)   _mm256_storeu_si256((__m256i *)m, x)
126 #define gmx_simd_setzero_fi        _mm256_setzero_si256
127 #define gmx_simd_cvt_f2i           _mm256_cvtps_epi32
128 #define gmx_simd_cvtt_f2i          _mm256_cvttps_epi32
129 #define gmx_simd_cvt_i2f           _mm256_cvtepi32_ps
130 #define gmx_simd_extract_fi(x, i)   _mm_extract_epi32(_mm256_extractf128_si256(x, (i)>>2), (i)&0x3)
131 /* Integer logical ops on gmx_simd_fint32_t */
132 /* gmx_simd_add_fi not supported     */
133 /* gmx_simd_sub_fi not supported     */
134 /* gmx_simd_mul_fi not supported     */
135 /* gmx_simd_slli_fi not supported    */
136 /* gmx_simd_srli_fi not supported    */
137 /* gmx_simd_and_fi not supported     */
138 /* gmx_simd_andnot_fi not supported  */
139 /* gmx_simd_or_fi not supported      */
140 /* gmx_simd_xor_fi not supported     */
141 /* Integer arithmetic ops on gmx_simd_fint32_t */
142 /* gmx_simd_add_fi not supported     */
143 /* gmx_simd_sub_fi not supported     */
144 /* gmx_simd_mul_fi not supported     */
145 /* Boolean & comparison operations on gmx_simd_float_t */
146 #define gmx_simd_fbool_t           __m256
147 #define gmx_simd_cmpeq_f(a, b)      _mm256_cmp_ps(a, b, _CMP_EQ_OQ)
148 #define gmx_simd_cmplt_f(a, b)      _mm256_cmp_ps(a, b, _CMP_LT_OQ)
149 #define gmx_simd_cmple_f(a, b)      _mm256_cmp_ps(a, b, _CMP_LE_OQ)
150 #define gmx_simd_and_fb            _mm256_and_ps
151 #define gmx_simd_or_fb             _mm256_or_ps
152 #define gmx_simd_anytrue_fb        _mm256_movemask_ps
153 #define gmx_simd_blendzero_f       _mm256_and_ps
154 #define gmx_simd_blendnotzero_f(a, sel)  _mm256_andnot_ps(sel, a)
155 #define gmx_simd_blendv_f          _mm256_blendv_ps
156 #define gmx_simd_reduce_f          gmx_simd_reduce_f_avx_256
157 /* Boolean & comparison operations on gmx_simd_fint32_t */
158 #define gmx_simd_fibool_t          __m256i
159 /* gmx_simd_cmpeq_fi not supported        */
160 /* gmx_simd_cmplt_fi not supported        */
161 /* gmx_simd_and_fib not supported         */
162 /* gmx_simd_or_fib not supported          */
163 /* gmx_simd_anytrue_fib not supported     */
164 /* gmx_simd_blendzero_fi not supported    */
165 /* gmx_simd_blendnotzero_fi not supported    */
166 /* gmx_simd_blendv_fi not supported       */
167 /* Conversions between different booleans */
168 #define gmx_simd_cvt_fb2fib        _mm256_castps_si256
169 #define gmx_simd_cvt_fib2fb        _mm256_castsi256_ps
170
171 /****************************************************
172  *      DOUBLE PRECISION SIMD IMPLEMENTATION        *
173  ****************************************************/
174 #define gmx_simd_double_t          __m256d
175 #define gmx_simd_load_d            _mm256_load_pd
176 #define gmx_simd_load1_d           _mm256_broadcast_sd
177 #define gmx_simd_set1_d            _mm256_set1_pd
178 #define gmx_simd_store_d           _mm256_store_pd
179 #define gmx_simd_loadu_d           _mm256_loadu_pd
180 #define gmx_simd_storeu_d          _mm256_storeu_pd
181 #define gmx_simd_setzero_d         _mm256_setzero_pd
182 #define gmx_simd_add_d             _mm256_add_pd
183 #define gmx_simd_sub_d             _mm256_sub_pd
184 #define gmx_simd_mul_d             _mm256_mul_pd
185 #define gmx_simd_fmadd_d(a, b, c)    _mm256_add_pd(_mm256_mul_pd(a, b), c)
186 #define gmx_simd_fmsub_d(a, b, c)    _mm256_sub_pd(_mm256_mul_pd(a, b), c)
187 #define gmx_simd_fnmadd_d(a, b, c)   _mm256_sub_pd(c, _mm256_mul_pd(a, b))
188 #define gmx_simd_fnmsub_d(a, b, c)   _mm256_sub_pd(_mm256_setzero_pd(), gmx_simd_fmadd_d(a, b, c))
189 #define gmx_simd_and_d             _mm256_and_pd
190 #define gmx_simd_andnot_d          _mm256_andnot_pd
191 #define gmx_simd_or_d              _mm256_or_pd
192 #define gmx_simd_xor_d             _mm256_xor_pd
193 #define gmx_simd_rsqrt_d(x)        _mm256_cvtps_pd(_mm_rsqrt_ps(_mm256_cvtpd_ps(x)))
194 #define gmx_simd_rcp_d(x)          _mm256_cvtps_pd(_mm_rcp_ps(_mm256_cvtpd_ps(x)))
195 #define gmx_simd_fabs_d(x)         _mm256_andnot_pd(_mm256_set1_pd(-0.0), x)
196 #define gmx_simd_fneg_d(x)         _mm256_xor_pd(x, _mm256_set1_pd(-0.0))
197 #define gmx_simd_max_d             _mm256_max_pd
198 #define gmx_simd_min_d             _mm256_min_pd
199 #define gmx_simd_round_d(x)        _mm256_round_pd(x, _MM_FROUND_NINT)
200 #define gmx_simd_trunc_d(x)        _mm256_round_pd(x, _MM_FROUND_TRUNC)
201 #define gmx_simd_fraction_d(x)     _mm256_sub_pd(x, gmx_simd_trunc_d(x))
202 #define gmx_simd_get_exponent_d    gmx_simd_get_exponent_d_avx_256
203 #define gmx_simd_get_mantissa_d    gmx_simd_get_mantissa_d_avx_256
204 #define gmx_simd_set_exponent_d    gmx_simd_set_exponent_d_avx_256
205 /* integer datatype corresponding to double: gmx_simd_dint32_t */
206 #define gmx_simd_dint32_t          __m128i
207 #define gmx_simd_load_di(m)        _mm_load_si128((const __m128i *)m)
208 #define gmx_simd_set1_di           _mm_set1_epi32
209 #define gmx_simd_store_di(m, x)     _mm_store_si128((__m128i *)m, x)
210 #define gmx_simd_loadu_di(m)       _mm_loadu_si128((const __m128i *)m)
211 #define gmx_simd_storeu_di(m, x)    _mm_storeu_si128((__m128i *)m, x)
212 #define gmx_simd_setzero_di        _mm_setzero_si128
213 #define gmx_simd_cvt_d2i           _mm256_cvtpd_epi32
214 #define gmx_simd_cvtt_d2i          _mm256_cvttpd_epi32
215 #define gmx_simd_cvt_i2d           _mm256_cvtepi32_pd
216 #define gmx_simd_extract_di        _mm_extract_epi32
217 /* Integer logical ops on gmx_simd_dint32_t */
218 #define gmx_simd_slli_di           _mm_slli_epi32
219 #define gmx_simd_srli_di           _mm_srli_epi32
220 #define gmx_simd_and_di            _mm_and_si128
221 #define gmx_simd_andnot_di         _mm_andnot_si128
222 #define gmx_simd_or_di             _mm_or_si128
223 #define gmx_simd_xor_di            _mm_xor_si128
224 /* Integer arithmetic ops on integer datatype corresponding to double */
225 #define gmx_simd_add_di            _mm_add_epi32
226 #define gmx_simd_sub_di            _mm_sub_epi32
227 #define gmx_simd_mul_di            _mm_mullo_epi32
228 /* Boolean & comparison operations on gmx_simd_double_t */
229 #define gmx_simd_dbool_t           __m256d
230 #define gmx_simd_cmpeq_d(a, b)      _mm256_cmp_pd(a, b, _CMP_EQ_OQ)
231 #define gmx_simd_cmplt_d(a, b)      _mm256_cmp_pd(a, b, _CMP_LT_OQ)
232 #define gmx_simd_cmple_d(a, b)      _mm256_cmp_pd(a, b, _CMP_LE_OQ)
233 #define gmx_simd_and_db            _mm256_and_pd
234 #define gmx_simd_or_db             _mm256_or_pd
235 #define gmx_simd_anytrue_db        _mm256_movemask_pd
236 #define gmx_simd_blendzero_d       _mm256_and_pd
237 #define gmx_simd_blendnotzero_d(a, sel)  _mm256_andnot_pd(sel, a)
238 #define gmx_simd_blendv_d          _mm256_blendv_pd
239 #define gmx_simd_reduce_d          gmx_simd_reduce_d_avx_256
240 /* Boolean & comparison operations on gmx_simd_dint32_t */
241 #define gmx_simd_dibool_t          __m128i
242 #define gmx_simd_cmpeq_di          _mm_cmpeq_epi32
243 #define gmx_simd_cmplt_di          _mm_cmplt_epi32
244 #define gmx_simd_and_dib           _mm_and_si128
245 #define gmx_simd_or_dib            _mm_or_si128
246 #define gmx_simd_anytrue_dib       _mm_movemask_epi8
247 #define gmx_simd_blendzero_di      _mm_and_si128
248 #define gmx_simd_blendnotzero_di(a, sel)  _mm_andnot_si128(sel, a)
249 #define gmx_simd_blendv_di         _mm_blendv_epi8
250 /* Conversions between different booleans */
251 #define gmx_simd_cvt_db2dib        gmx_simd_cvt_db2dib_avx_256
252 #define gmx_simd_cvt_dib2db        gmx_simd_cvt_dib2db_avx_256
253 /* Float/double conversion */
254 #define gmx_simd_cvt_f2dd          gmx_simd_cvt_f2dd_avx_256
255 #define gmx_simd_cvt_dd2f          gmx_simd_cvt_dd2f_avx_256
256
257 /****************************************************
258  *      SINGLE PRECISION SIMD4 IMPLEMENTATION       *
259  ****************************************************/
260 #define gmx_simd4_float_t          __m128
261 #define gmx_simd4_load_f           _mm_load_ps
262 #define gmx_simd4_load1_f          _mm_broadcast_ss
263 #define gmx_simd4_set1_f           _mm_set1_ps
264 #define gmx_simd4_store_f          _mm_store_ps
265 #define gmx_simd4_loadu_f          _mm_loadu_ps
266 #define gmx_simd4_storeu_f         _mm_storeu_ps
267 #define gmx_simd4_setzero_f        _mm_setzero_ps
268 #define gmx_simd4_add_f            _mm_add_ps
269 #define gmx_simd4_sub_f            _mm_sub_ps
270 #define gmx_simd4_mul_f            _mm_mul_ps
271 #define gmx_simd4_fmadd_f(a, b, c)   _mm_add_ps(_mm_mul_ps(a, b), c)
272 #define gmx_simd4_fmsub_f(a, b, c)   _mm_sub_ps(_mm_mul_ps(a, b), c)
273 #define gmx_simd4_fnmadd_f(a, b, c)  _mm_sub_ps(c, _mm_mul_ps(a, b))
274 #define gmx_simd4_fnmsub_f(a, b, c)  _mm_sub_ps(_mm_setzero_ps(), gmx_simd4_fmadd_f(a, b, c))
275 #define gmx_simd4_and_f            _mm_and_ps
276 #define gmx_simd4_andnot_f         _mm_andnot_ps
277 #define gmx_simd4_or_f             _mm_or_ps
278 #define gmx_simd4_xor_f            _mm_xor_ps
279 #define gmx_simd4_rsqrt_f          _mm_rsqrt_ps
280 #define gmx_simd4_fabs_f(x)        _mm_andnot_ps(_mm_set1_ps(-0.0), x)
281 #define gmx_simd4_fneg_f(x)        _mm_xor_ps(x, _mm_set1_ps(-0.0))
282 #define gmx_simd4_max_f            _mm_max_ps
283 #define gmx_simd4_min_f            _mm_min_ps
284 #define gmx_simd4_round_f(x)       _mm_round_ps(x, _MM_FROUND_NINT)
285 #define gmx_simd4_trunc_f(x)       _mm_round_ps(x, _MM_FROUND_TRUNC)
286 #define gmx_simd4_dotproduct3_f    gmx_simd4_dotproduct3_f_avx_256
287 #define gmx_simd4_fbool_t          __m128
288 #define gmx_simd4_cmpeq_f          _mm_cmpeq_ps
289 #define gmx_simd4_cmplt_f          _mm_cmplt_ps
290 #define gmx_simd4_cmple_f          _mm_cmple_ps
291 #define gmx_simd4_and_fb           _mm_and_ps
292 #define gmx_simd4_or_fb            _mm_or_ps
293 #define gmx_simd4_anytrue_fb       _mm_movemask_ps
294 #define gmx_simd4_blendzero_f      _mm_and_ps
295 #define gmx_simd4_blendnotzero_f(a, sel)  _mm_andnot_ps(sel, a)
296 #define gmx_simd4_blendv_f         _mm_blendv_ps
297 #define gmx_simd4_reduce_f         gmx_simd4_reduce_f_avx_256
298
299 /****************************************************
300  *      DOUBLE PRECISION SIMD4 IMPLEMENTATION       *
301  ****************************************************/
302 #define gmx_simd4_double_t          gmx_simd_double_t
303 #define gmx_simd4_load_d            gmx_simd_load_d
304 #define gmx_simd4_load1_d           gmx_simd_load1_d
305 #define gmx_simd4_set1_d            gmx_simd_set1_d
306 #define gmx_simd4_store_d           gmx_simd_store_d
307 #define gmx_simd4_loadu_d           gmx_simd_loadu_d
308 #define gmx_simd4_storeu_d          gmx_simd_storeu_d
309 #define gmx_simd4_setzero_d         gmx_simd_setzero_d
310 #define gmx_simd4_add_d             gmx_simd_add_d
311 #define gmx_simd4_sub_d             gmx_simd_sub_d
312 #define gmx_simd4_mul_d             gmx_simd_mul_d
313 #define gmx_simd4_fmadd_d           gmx_simd_fmadd_d
314 #define gmx_simd4_fmsub_d           gmx_simd_fmsub_d
315 #define gmx_simd4_fnmadd_d          gmx_simd_fnmadd_d
316 #define gmx_simd4_fnmsub_d          gmx_simd_fnmsub_d
317 #define gmx_simd4_and_d             gmx_simd_and_d
318 #define gmx_simd4_andnot_d          gmx_simd_andnot_d
319 #define gmx_simd4_or_d              gmx_simd_or_d
320 #define gmx_simd4_xor_d             gmx_simd_xor_d
321 #define gmx_simd4_rsqrt_d           gmx_simd_rsqrt_d
322 #define gmx_simd4_fabs_d            gmx_simd_fabs_d
323 #define gmx_simd4_fneg_d            gmx_simd_fneg_d
324 #define gmx_simd4_max_d             gmx_simd_max_d
325 #define gmx_simd4_min_d             gmx_simd_min_d
326 #define gmx_simd4_round_d           gmx_simd_round_d
327 #define gmx_simd4_trunc_d           gmx_simd_trunc_d
328 #define gmx_simd4_dotproduct3_d     gmx_simd4_dotproduct3_d_avx_256
329 #define gmx_simd4_dbool_t           gmx_simd_dbool_t
330 #define gmx_simd4_cmpeq_d           gmx_simd_cmpeq_d
331 #define gmx_simd4_cmplt_d           gmx_simd_cmplt_d
332 #define gmx_simd4_cmple_d           gmx_simd_cmple_d
333 #define gmx_simd4_and_db            gmx_simd_and_db
334 #define gmx_simd4_or_db             gmx_simd_or_db
335 #define gmx_simd4_anytrue_db        gmx_simd_anytrue_db
336 #define gmx_simd4_blendzero_d       gmx_simd_blendzero_d
337 #define gmx_simd4_blendnotzero_d    gmx_simd_blendnotzero_d
338 #define gmx_simd4_blendv_d          gmx_simd_blendv_d
339 #define gmx_simd4_reduce_d          gmx_simd_reduce_d
340 /* SIMD4 float/double conversion */
341 #define gmx_simd4_cvt_f2d           _mm256_cvtps_pd
342 #define gmx_simd4_cvt_d2f           _mm256_cvtpd_ps
343
344 /*********************************************************
345  * SIMD SINGLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
346  *********************************************************/
347 static gmx_inline __m256 gmx_simdcall
348 gmx_simd_get_exponent_f_avx_256(__m256 x)
349 {
350     const __m256  expmask      = _mm256_castsi256_ps(_mm256_set1_epi32(0x7F800000));
351     const __m128i expbias      = _mm_set1_epi32(127);
352     __m256i       iexp256;
353     __m128i       iexp128a, iexp128b;
354
355     iexp256   = _mm256_castps_si256(_mm256_and_ps(x, expmask));
356     iexp128b  = _mm256_extractf128_si256(iexp256, 0x1);
357     iexp128a  = _mm256_castsi256_si128(iexp256);
358     iexp128a  = _mm_srli_epi32(iexp128a, 23);
359     iexp128b  = _mm_srli_epi32(iexp128b, 23);
360     iexp128a  = _mm_sub_epi32(iexp128a, expbias);
361     iexp128b  = _mm_sub_epi32(iexp128b, expbias);
362     iexp256   = _mm256_castsi128_si256(iexp128a);
363     iexp256   = _mm256_insertf128_si256(iexp256, iexp128b, 0x1);
364     return _mm256_cvtepi32_ps(iexp256);
365 }
366
367 static gmx_inline __m256 gmx_simdcall
368 gmx_simd_get_mantissa_f_avx_256(__m256 x)
369 {
370     const __m256 mantmask   = _mm256_castsi256_ps(_mm256_set1_epi32(0x007FFFFF));
371     const __m256 one        = _mm256_set1_ps(1.0);
372
373     x = _mm256_and_ps(x, mantmask);
374     return _mm256_or_ps(x, one);
375 }
376
377 static gmx_inline __m256 gmx_simdcall
378 gmx_simd_set_exponent_f_avx_256(__m256 x)
379 {
380     const __m128i expbias      = _mm_set1_epi32(127);
381     __m256i       iexp256;
382     __m128i       iexp128a, iexp128b;
383
384     iexp256   = _mm256_cvtps_epi32(x);
385     iexp128b  = _mm256_extractf128_si256(iexp256, 0x1);
386     iexp128a  = _mm256_castsi256_si128(iexp256);
387     iexp128a  = _mm_slli_epi32(_mm_add_epi32(iexp128a, expbias), 23);
388     iexp128b  = _mm_slli_epi32(_mm_add_epi32(iexp128b, expbias), 23);
389     iexp256   = _mm256_castsi128_si256(iexp128a);
390     iexp256   = _mm256_insertf128_si256(iexp256, iexp128b, 0x1);
391     return _mm256_castsi256_ps(iexp256);
392 }
393
394 static gmx_inline float gmx_simdcall
395 gmx_simd_reduce_f_avx_256(__m256 a)
396 {
397     float  f;
398
399     __m128 a0, a1;
400     a  = _mm256_hadd_ps(a, a);
401     a  = _mm256_hadd_ps(a, a);
402     a0 = _mm256_castps256_ps128(a);
403     a1 = _mm256_extractf128_ps(a, 0x1);
404     a0 = _mm_add_ss(a0, a1);
405     _mm_store_ss(&f, a0);
406     return f;
407 }
408
409 /*********************************************************
410  * SIMD DOUBLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
411  *********************************************************/
412 static gmx_inline __m256d gmx_simdcall
413 gmx_simd_get_exponent_d_avx_256(__m256d x)
414 {
415     const __m256d expmask      = _mm256_castsi256_pd( _mm256_set1_epi64x(0x7FF0000000000000LL));
416     const __m128i expbias      = _mm_set1_epi32(1023);
417     __m256i       iexp256;
418     __m128i       iexp128a, iexp128b;
419
420     iexp256   = _mm256_castpd_si256(_mm256_and_pd(x, expmask));
421     iexp128b  = _mm256_extractf128_si256(iexp256, 0x1);
422     iexp128a  = _mm256_castsi256_si128(iexp256);
423     iexp128a  = _mm_srli_epi64(iexp128a, 52);
424     iexp128b  = _mm_srli_epi64(iexp128b, 52);
425     iexp128a  = _mm_shuffle_epi32(iexp128a, _MM_SHUFFLE(1, 1, 2, 0));
426     iexp128b  = _mm_shuffle_epi32(iexp128b, _MM_SHUFFLE(2, 0, 1, 1));
427     iexp128a  = _mm_or_si128(iexp128a, iexp128b);
428     iexp128a  = _mm_sub_epi32(iexp128a, expbias);
429     return _mm256_cvtepi32_pd(iexp128a);
430 }
431
432 static gmx_inline __m256d gmx_simdcall
433 gmx_simd_get_mantissa_d_avx_256(__m256d x)
434 {
435     const __m256d mantmask   = _mm256_castsi256_pd(_mm256_set1_epi64x(0x000FFFFFFFFFFFFFLL));
436     const __m256d one        = _mm256_set1_pd(1.0);
437
438     x = _mm256_and_pd(x, mantmask);
439     return _mm256_or_pd(x, one);
440 }
441
442 static gmx_inline __m256d gmx_simdcall
443 gmx_simd_set_exponent_d_avx_256(__m256d x)
444 {
445     const __m128i expbias      = _mm_set1_epi32(1023);
446     __m128i       iexp128a, iexp128b;
447
448     iexp128a = _mm256_cvtpd_epi32(x);
449     iexp128a = _mm_add_epi32(iexp128a, expbias);
450     iexp128b = _mm_shuffle_epi32(iexp128a, _MM_SHUFFLE(3, 3, 2, 2));
451     iexp128a = _mm_shuffle_epi32(iexp128a, _MM_SHUFFLE(1, 1, 0, 0));
452     iexp128b = _mm_slli_epi64(iexp128b, 52);
453     iexp128a = _mm_slli_epi64(iexp128a, 52);
454     return _mm256_castsi256_pd(_mm256_insertf128_si256(_mm256_castsi128_si256(iexp128a), iexp128b, 0x1));
455 }
456
457 static gmx_inline double gmx_simdcall
458 gmx_simd_reduce_d_avx_256(__m256d a)
459 {
460     double  f;
461     __m128d a0, a1;
462     a  = _mm256_hadd_pd(a, a);
463     a0 = _mm256_castpd256_pd128(a);
464     a1 = _mm256_extractf128_pd(a, 0x1);
465     a0 = _mm_add_sd(a0, a1);
466     _mm_store_sd(&f, a0);
467     return f;
468 }
469
470 static gmx_inline gmx_simd_dibool_t gmx_simdcall
471 gmx_simd_cvt_db2dib_avx_256(gmx_simd_dbool_t a)
472 {
473     __m128i a1 = _mm256_extractf128_si256(_mm256_castpd_si256(a), 0x1);
474     __m128i a0 = _mm256_castsi256_si128(_mm256_castpd_si256(a));
475     a0 = _mm_shuffle_epi32(a0, _MM_SHUFFLE(2, 0, 2, 0));
476     a1 = _mm_shuffle_epi32(a1, _MM_SHUFFLE(2, 0, 2, 0));
477     return _mm_blend_epi16(a0, a1, 0xF0);
478 }
479
480 static gmx_inline gmx_simd_dbool_t gmx_simdcall
481 gmx_simd_cvt_dib2db_avx_256(gmx_simd_dibool_t a)
482 {
483     __m128i a1 = _mm_shuffle_epi32(a, _MM_SHUFFLE(3, 3, 2, 2));
484     __m128i a0 = _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 1, 0, 0));
485     return _mm256_castsi256_pd(_mm256_insertf128_si256(_mm256_castsi128_si256(a0), a1, 0x1));
486 }
487
488 static gmx_inline void gmx_simdcall
489 gmx_simd_cvt_f2dd_avx_256(__m256 f, __m256d *d0, __m256d *d1)
490 {
491     *d0 = _mm256_cvtps_pd(_mm256_castps256_ps128(f));
492     *d1 = _mm256_cvtps_pd(_mm256_extractf128_ps(f, 0x1));
493 }
494
495 static gmx_inline __m256 gmx_simdcall
496 gmx_simd_cvt_dd2f_avx_256(__m256d d0, __m256d d1)
497 {
498     __m128 f0 = _mm256_cvtpd_ps(d0);
499     __m128 f1 = _mm256_cvtpd_ps(d1);
500     return _mm256_insertf128_ps(_mm256_castps128_ps256(f0), f1, 0x1);
501 }
502
503 /* SIMD4 reduce helper */
504 static gmx_inline float gmx_simdcall
505 gmx_simd4_reduce_f_avx_256(__m128 a)
506 {
507     float f;
508     a = _mm_hadd_ps(a, a);
509     a = _mm_hadd_ps(a, a);
510     _mm_store_ss(&f, a);
511     return f;
512 }
513
514 /* SIMD4 Dotproduct helper function */
515 static gmx_inline float gmx_simdcall
516 gmx_simd4_dotproduct3_f_avx_256(__m128 a, __m128 b)
517 {
518     float  f;
519     __m128 c;
520     a = _mm_mul_ps(a, b);
521     c = _mm_add_ps(a, _mm_permute_ps(a, _MM_SHUFFLE(0, 3, 2, 1)));
522     c = _mm_add_ps(c, _mm_permute_ps(a, _MM_SHUFFLE(1, 0, 3, 2)));
523     _mm_store_ss(&f, c);
524     return f;
525 }
526
527 static gmx_inline double gmx_simdcall
528 gmx_simd4_dotproduct3_d_avx_256(__m256d a, __m256d b)
529 {
530     double  d;
531     __m128d tmp1, tmp2;
532     a    = _mm256_mul_pd(a, b);
533     tmp1 = _mm256_castpd256_pd128(a);
534     tmp2 = _mm256_extractf128_pd(a, 0x1);
535
536     tmp1 = _mm_add_pd(tmp1, _mm_permute_pd(tmp1, _MM_SHUFFLE2(0, 1)));
537     tmp1 = _mm_add_pd(tmp1, tmp2);
538     _mm_store_sd(&d, tmp1);
539     return d;
540 }
541
542 /* Function to check whether SIMD operations have resulted in overflow */
543 static int
544 gmx_simd_check_and_reset_overflow(void)
545 {
546     int MXCSR;
547     int sse_overflow;
548
549     MXCSR = _mm_getcsr();
550     /* The overflow flag is bit 3 in the register */
551     if (MXCSR & 0x0008)
552     {
553         sse_overflow = 1;
554         /* Set the overflow flag to zero */
555         MXCSR = MXCSR & 0xFFF7;
556         _mm_setcsr(MXCSR);
557     }
558     else
559     {
560         sse_overflow = 0;
561     }
562     return sse_overflow;
563 }
564
565
566 #endif /* GMX_SIMD_IMPL_X86_AVX_256_H */