Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / mdlib / nbnxn_kernels / nbnxn_kernel_simd_utils_x86_256s.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2012, The GROMACS Development Team
6  * Copyright (c) 2012,2013, by the GROMACS development team, led by
7  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
8  * others, as listed in the AUTHORS file in the top-level source
9  * directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #ifndef _nbnxn_kernel_simd_utils_x86_256s_h_
38 #define _nbnxn_kernel_simd_utils_x86_256s_h_
39
40 /* This files contains all functions/macros for the SIMD kernels
41  * which have explicit dependencies on the j-cluster size and/or SIMD-width.
42  * The functionality which depends on the j-cluster size is:
43  *   LJ-parameter lookup
44  *   force table lookup
45  *   energy group pair energy storage
46  */
47
48 #define gmx_exclfilter gmx_mm_pr
49 static const int filter_stride = 1;
50
51 /* The 4xn kernel operates on 4-wide i-force registers */
52 #define gmx_mm_pr4     __m128
53 #define gmx_load_pr4   _mm_load_ps
54 #define gmx_store_pr4  _mm_store_ps
55 #define gmx_add_pr4    _mm_add_ps
56
57
58 #ifdef GMX_NBNXN_SIMD_2XNN
59 /* Half-width operations are required for the 2xnn kernels */
60
61 /* Half-width SIMD real type */
62 #define gmx_mm_hpr  __m128
63
64 /* Half-width SIMD operations */
65 /* Load reals at half-width aligned pointer b into half-width SIMD register a */
66 #define gmx_load_hpr(a, b)    *(a) = _mm_load_ps(b)
67 /* Set all entries in half-width SIMD register *a to b */
68 #define gmx_set1_hpr(a, b)   *(a) = _mm_set1_ps(b)
69 /* Load one real at b and one real at b+1 into halves of a, respectively */
70 #define gmx_load1p1_pr(a, b)  *(a) = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load1_ps(b)), _mm_load1_ps(b+1), 0x1)
71 /* Load reals at half-width aligned pointer b into two halves of a */
72 #define gmx_loaddh_pr(a, b)   *(a) = gmx_mm256_load4_ps(b)
73 /* To half-width SIMD register b into half width aligned memory a */
74 #define gmx_store_hpr(a, b)          _mm_store_ps(a, b)
75 #define gmx_add_hpr                  _mm_add_ps
76 #define gmx_sub_hpr                  _mm_sub_ps
77 /* Sum over 4 half SIMD registers */
78 #define gmx_sum4_hpr                 gmx_mm256_sum4h_m128
79
80 static gmx_inline void
81 gmx_pr_to_2hpr(gmx_mm_pr a, gmx_mm_hpr *b, gmx_mm_hpr *c)
82 {
83     *b = _mm256_extractf128_ps(a, 0);
84     *c = _mm256_extractf128_ps(a, 1);
85 }
86
87 /* Store half width SIMD registers a and b in full width register *c */
88 static gmx_inline void
89 gmx_2hpr_to_pr(gmx_mm_hpr a, gmx_mm_hpr b, gmx_mm_pr *c)
90 {
91     *c = _mm256_insertf128_ps(_mm256_castps128_ps256(a), b, 0x1);
92 }
93
94 #endif /* GMX_NBNXN_SIMD_2XNN */
95
96 /* Collect element 0 and 1 of the 4 inputs to out0 and out1, respectively */
97 static gmx_inline void
98 gmx_shuffle_4_ps_fil01_to_2_ps(__m128 in0, __m128 in1, __m128 in2, __m128 in3,
99                                __m128 *out0, __m128 *out1)
100 {
101     __m128 _c01, _c23;
102
103     _c01  = _mm_movelh_ps(in0, in1);
104     _c23  = _mm_movelh_ps(in2, in3);
105     *out0 = _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(2, 0, 2, 0));
106     *out1 = _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(3, 1, 3, 1));
107 }
108
109 /* Collect element 2 of the 4 inputs to out */
110 static gmx_inline __m128
111 gmx_shuffle_4_ps_fil2_to_1_ps(__m128 in0, __m128 in1, __m128 in2, __m128 in3)
112 {
113     __m128 _c01, _c23;
114
115     _c01 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 2, 3, 2));
116     _c23 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 2, 3, 2));
117
118     return _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(2, 0, 2, 0));
119 }
120
121 /* Sum the elements within each input register and return the sums */
122 static gmx_inline __m128
123 gmx_mm_transpose_sum4_pr(__m256 in0, __m256 in1,
124                          __m256 in2, __m256 in3)
125 {
126     in0 = _mm256_hadd_ps(in0, in1);
127     in2 = _mm256_hadd_ps(in2, in3);
128     in1 = _mm256_hadd_ps(in0, in2);
129
130     return _mm_add_ps(_mm256_castps256_ps128(in1),
131                       _mm256_extractf128_ps(in1, 1));
132 }
133
134 /* Sum the elements of halfs of each input register and return the sums */
135 static gmx_inline __m128
136 gmx_mm_transpose_sum4h_pr(__m256 in0, __m256 in2)
137 {
138     in0 = _mm256_hadd_ps(in0, _mm256_setzero_ps());
139     in2 = _mm256_hadd_ps(in2, _mm256_setzero_ps());
140     in0 = _mm256_hadd_ps(in0, in2);
141     in2 = _mm256_permute_ps(in0, _MM_SHUFFLE(2, 3, 0, 1));
142
143     return _mm_add_ps(_mm256_castps256_ps128(in0), _mm256_extractf128_ps(in2, 1));
144 }
145
146 /* Put two 128-bit 4-float registers into one 256-bit 8-float register */
147 static gmx_inline __m256
148 gmx_2_mm_to_m256(__m128 in0, __m128 in1)
149 {
150     return _mm256_insertf128_ps(_mm256_castps128_ps256(in0), in1, 1);
151 }
152
153 #if UNROLLJ == 8
154 static gmx_inline void
155 load_lj_pair_params(const real *nbfp, const int *type, int aj,
156                     __m256 *c6_S, __m256 *c12_S)
157 {
158     __m128 clj_S[UNROLLJ], c6t_S[2], c12t_S[2];
159     int    p;
160
161     for (p = 0; p < UNROLLJ; p++)
162     {
163         /* Here we load 4 aligned floats, but we need just 2 */
164         clj_S[p] = _mm_load_ps(nbfp+type[aj+p]*nbfp_stride);
165     }
166     gmx_shuffle_4_ps_fil01_to_2_ps(clj_S[0], clj_S[1], clj_S[2], clj_S[3],
167                                    &c6t_S[0], &c12t_S[0]);
168     gmx_shuffle_4_ps_fil01_to_2_ps(clj_S[4], clj_S[5], clj_S[6], clj_S[7],
169                                    &c6t_S[1], &c12t_S[1]);
170
171     *c6_S  = gmx_2_mm_to_m256(c6t_S[0], c6t_S[1]);
172     *c12_S = gmx_2_mm_to_m256(c12t_S[0], c12t_S[1]);
173 }
174 #endif
175
176 #if UNROLLJ == 4
177 static gmx_inline void
178 load_lj_pair_params2(const real *nbfp0, const real *nbfp1,
179                      const int *type, int aj,
180                      __m256 *c6_S, __m256 *c12_S)
181 {
182     __m128 clj_S0[UNROLLJ], clj_S1[UNROLLJ], c6t_S[2], c12t_S[2];
183     int    p;
184
185     for (p = 0; p < UNROLLJ; p++)
186     {
187         /* Here we load 4 aligned floats, but we need just 2 */
188         clj_S0[p] = _mm_load_ps(nbfp0+type[aj+p]*nbfp_stride);
189     }
190     for (p = 0; p < UNROLLJ; p++)
191     {
192         /* Here we load 4 aligned floats, but we need just 2 */
193         clj_S1[p] = _mm_load_ps(nbfp1+type[aj+p]*nbfp_stride);
194     }
195     gmx_shuffle_4_ps_fil01_to_2_ps(clj_S0[0], clj_S0[1], clj_S0[2], clj_S0[3],
196                                    &c6t_S[0], &c12t_S[0]);
197     gmx_shuffle_4_ps_fil01_to_2_ps(clj_S1[0], clj_S1[1], clj_S1[2], clj_S1[3],
198                                    &c6t_S[1], &c12t_S[1]);
199
200     *c6_S  = gmx_2_mm_to_m256(c6t_S[0], c6t_S[1]);
201     *c12_S = gmx_2_mm_to_m256(c12t_S[0], c12t_S[1]);
202 }
203 #endif
204
205
206 /* The load_table functions below are performance critical.
207  * The routines issue UNROLLI*UNROLLJ _mm_load_ps calls.
208  * As these all have latencies, scheduling is crucial.
209  * The Intel compilers and CPUs seem to do a good job at this.
210  * But AMD CPUs perform significantly worse with gcc than with icc.
211  * Performance is improved a bit by using the extract function UNROLLJ times,
212  * instead of doing an _mm_store_si128 for every i-particle.
213  * This is only faster when we use FDV0 formatted tables, where we also need
214  * to multiple the index by 4, which can be done by a SIMD bit shift.
215  * With single precision AVX, 8 extracts are much slower than 1 store.
216  * Because of this, the load_table_f function always takes the ti
217  * parameter, which should contain a buffer that is aligned with
218  * prepare_table_load_buffer(), but it is only used with full-width
219  * AVX_256. */
220
221 static gmx_inline void
222 load_table_f(const real *tab_coul_FDV0, gmx_epi32 ti_S, int *ti,
223              __m256 *ctab0_S, __m256 *ctab1_S)
224 {
225     __m128 ctab_S[8], ctabt_S[4];
226     int    j;
227
228     /* Bit shifting would be faster, but AVX doesn't support that */
229     _mm256_store_si256((__m256i *)ti, ti_S);
230     for (j = 0; j < 8; j++)
231     {
232         ctab_S[j] = _mm_load_ps(tab_coul_FDV0+ti[j]*4);
233     }
234     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[0], ctab_S[1], ctab_S[2], ctab_S[3],
235                                    &ctabt_S[0], &ctabt_S[2]);
236     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[4], ctab_S[5], ctab_S[6], ctab_S[7],
237                                    &ctabt_S[1], &ctabt_S[3]);
238
239     *ctab0_S = gmx_2_mm_to_m256(ctabt_S[0], ctabt_S[1]);
240     *ctab1_S = gmx_2_mm_to_m256(ctabt_S[2], ctabt_S[3]);
241 }
242
243 static gmx_inline void
244 load_table_f_v(const real *tab_coul_FDV0, gmx_epi32 ti_S, int *ti,
245                __m256 *ctab0_S, __m256 *ctab1_S, __m256 *ctabv_S)
246 {
247     __m128 ctab_S[8], ctabt_S[4], ctabvt_S[2];
248     int    j;
249
250     /* Bit shifting would be faster, but AVX doesn't support that */
251     _mm256_store_si256((__m256i *)ti, ti_S);
252     for (j = 0; j < 8; j++)
253     {
254         ctab_S[j] = _mm_load_ps(tab_coul_FDV0+ti[j]*4);
255     }
256     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[0], ctab_S[1], ctab_S[2], ctab_S[3],
257                                    &ctabt_S[0], &ctabt_S[2]);
258     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[4], ctab_S[5], ctab_S[6], ctab_S[7],
259                                    &ctabt_S[1], &ctabt_S[3]);
260
261     *ctab0_S = gmx_2_mm_to_m256(ctabt_S[0], ctabt_S[1]);
262     *ctab1_S = gmx_2_mm_to_m256(ctabt_S[2], ctabt_S[3]);
263
264     ctabvt_S[0] = gmx_shuffle_4_ps_fil2_to_1_ps(ctab_S[0], ctab_S[1],
265                                                 ctab_S[2], ctab_S[3]);
266     ctabvt_S[1] = gmx_shuffle_4_ps_fil2_to_1_ps(ctab_S[4], ctab_S[5],
267                                                 ctab_S[6], ctab_S[7]);
268
269     *ctabv_S = gmx_2_mm_to_m256(ctabvt_S[0], ctabvt_S[1]);
270 }
271
272 static gmx_inline gmx_exclfilter
273 gmx_load1_exclfilter(int e)
274 {
275     return _mm256_castsi256_ps(_mm256_set1_epi32(e));
276 }
277
278 static gmx_inline gmx_exclfilter
279 gmx_load_exclusion_filter(const unsigned *i)
280 {
281     return gmx_load_pr((real *) (i));
282 }
283
284 static gmx_inline gmx_mm_pb
285 gmx_checkbitmask_pb(gmx_exclfilter m0, gmx_exclfilter m1)
286 {
287     return _mm256_cmp_ps(_mm256_cvtepi32_ps(_mm256_castps_si256(_mm256_and_ps(m0, m1))), _mm256_setzero_ps(), 0x0c);
288 }
289
290 #endif /* _nbnxn_kernel_simd_utils_x86_s256s_h_ */