Another batch of added config.h
[alexxy/gromacs.git] / src / gromacs / mdlib / nbnxn_kernels / nbnxn_kernel_simd_utils_x86_128s.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,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 #ifndef _nbnxn_kernel_simd_utils_x86_128s_h_
36 #define _nbnxn_kernel_simd_utils_x86_128s_h_
37
38 #include "gromacs/legacyheaders/types/simple.h"
39
40 #include "config.h"
41
42 /* This files contains all functions/macros for the SIMD kernels
43  * which have explicit dependencies on the j-cluster size and/or SIMD-width.
44  * The functionality which depends on the j-cluster size is:
45  *   LJ-parameter lookup
46  *   force table lookup
47  *   energy group pair energy storage
48  */
49
50 typedef gmx_simd_int32_t gmx_exclfilter;
51 static const int filter_stride = GMX_SIMD_INT32_WIDTH/GMX_SIMD_REAL_WIDTH;
52
53 /* Collect element 0 and 1 of the 4 inputs to out0 and out1, respectively */
54 static gmx_inline void gmx_simdcall
55 gmx_shuffle_4_ps_fil01_to_2_ps(__m128 in0, __m128 in1, __m128 in2, __m128 in3,
56                                __m128 *out0, __m128 *out1)
57 {
58     __m128 _c01, _c23;
59
60     _c01  = _mm_movelh_ps(in0, in1);
61     _c23  = _mm_movelh_ps(in2, in3);
62     *out0 = _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(2, 0, 2, 0));
63     *out1 = _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(3, 1, 3, 1));
64 }
65
66 /* Collect element 2 of the 4 inputs to out */
67 static gmx_inline __m128 gmx_simdcall
68 gmx_shuffle_4_ps_fil2_to_1_ps(__m128 in0, __m128 in1, __m128 in2, __m128 in3)
69 {
70     __m128 _c01, _c23;
71
72     _c01 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 2, 3, 2));
73     _c23 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 2, 3, 2));
74
75     return _mm_shuffle_ps(_c01, _c23, _MM_SHUFFLE(2, 0, 2, 0));
76 }
77
78 /* Sum the elements within each input register and store the sums in out */
79 static gmx_inline __m128 gmx_simdcall
80 gmx_mm_transpose_sum4_pr(__m128 in0, __m128 in1,
81                          __m128 in2, __m128 in3)
82 {
83     _MM_TRANSPOSE4_PS(in0, in1, in2, in3);
84     in0  = _mm_add_ps(in0, in1);
85     in2  = _mm_add_ps(in2, in3);
86
87     return _mm_add_ps(in0, in2);
88 }
89
90 static gmx_inline void
91 load_lj_pair_params(const real *nbfp, const int *type, int aj,
92                     __m128 *c6_S, __m128 *c12_S)
93 {
94     __m128 clj_S[UNROLLJ];
95     int    p;
96
97     for (p = 0; p < UNROLLJ; p++)
98     {
99         /* Here we load 4 aligned floats, but we need just 2 */
100         clj_S[p] = gmx_simd_load_r(nbfp+type[aj+p]*nbfp_stride);
101     }
102     gmx_shuffle_4_ps_fil01_to_2_ps(clj_S[0], clj_S[1], clj_S[2], clj_S[3], c6_S, c12_S);
103 }
104
105 /* The load_table functions below are performance critical.
106  * The routines issue UNROLLI*UNROLLJ _mm_load_ps calls.
107  * As these all have latencies, scheduling is crucial.
108  * The Intel compilers and CPUs seem to do a good job at this.
109  * But AMD CPUs perform significantly worse with gcc than with icc.
110  * Performance is improved a bit by using the extract function UNROLLJ times,
111  * instead of doing an _mm_store_si128 for every i-particle.
112  * This is only faster when we use FDV0 formatted tables, where we also need
113  * to multiple the index by 4, which can be done by a SIMD bit shift.
114  * With single precision AVX, 8 extracts are much slower than 1 store.
115  * Because of this, the load_table_f function always takes the ti
116  * parameter, which should contain a buffer that is aligned with
117  * prepare_table_load_buffer(), but it is only used with full-width
118  * AVX_256. */
119
120 static gmx_inline void gmx_simdcall
121 load_table_f(const real *tab_coul_FDV0, gmx_simd_int32_t ti_S, int gmx_unused *ti,
122              __m128 *ctab0_S, __m128 *ctab1_S)
123 {
124     int    idx[4];
125     __m128 ctab_S[4];
126
127     /* Table has 4 entries, left-shift index by 2 */
128     ti_S = _mm_slli_epi32(ti_S, 2);
129     /* Without SSE4.1 the extract macro needs an immediate: unroll */
130     idx[0]    = gmx_simd_extract_i(ti_S, 0);
131     ctab_S[0] = _mm_load_ps(tab_coul_FDV0+idx[0]);
132     idx[1]    = gmx_simd_extract_i(ti_S, 1);
133     ctab_S[1] = _mm_load_ps(tab_coul_FDV0+idx[1]);
134     idx[2]    = gmx_simd_extract_i(ti_S, 2);
135     ctab_S[2] = _mm_load_ps(tab_coul_FDV0+idx[2]);
136     idx[3]    = gmx_simd_extract_i(ti_S, 3);
137     ctab_S[3] = _mm_load_ps(tab_coul_FDV0+idx[3]);
138
139     /* Shuffle the force table entries to a convenient order */
140     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[0], ctab_S[1], ctab_S[2], ctab_S[3], ctab0_S, ctab1_S);
141 }
142
143 static gmx_inline void gmx_simdcall
144 load_table_f_v(const real *tab_coul_FDV0, gmx_simd_int32_t ti_S, int gmx_unused *ti,
145                __m128 *ctab0_S, __m128 *ctab1_S, __m128 *ctabv_S)
146 {
147     int    idx[4];
148     __m128 ctab_S[4];
149
150     /* Table has 4 entries, left-shift index by 2 */
151     ti_S = _mm_slli_epi32(ti_S, 2);
152     /* Without SSE4.1 the extract macro needs an immediate: unroll */
153     idx[0]    = gmx_simd_extract_i(ti_S, 0);
154     ctab_S[0] = _mm_load_ps(tab_coul_FDV0+idx[0]);
155     idx[1]    = gmx_simd_extract_i(ti_S, 1);
156     ctab_S[1] = _mm_load_ps(tab_coul_FDV0+idx[1]);
157     idx[2]    = gmx_simd_extract_i(ti_S, 2);
158     ctab_S[2] = _mm_load_ps(tab_coul_FDV0+idx[2]);
159     idx[3]    = gmx_simd_extract_i(ti_S, 3);
160     ctab_S[3] = _mm_load_ps(tab_coul_FDV0+idx[3]);
161
162     /* Shuffle the force table entries to a convenient order */
163     gmx_shuffle_4_ps_fil01_to_2_ps(ctab_S[0], ctab_S[1], ctab_S[2], ctab_S[3], ctab0_S, ctab1_S);
164
165     *ctabv_S = gmx_shuffle_4_ps_fil2_to_1_ps(ctab_S[0], ctab_S[1], ctab_S[2], ctab_S[3]);
166 }
167
168 static gmx_inline gmx_exclfilter gmx_simdcall
169 gmx_load1_exclfilter(int e)
170 {
171     return _mm_set1_epi32(e);
172 }
173
174 static gmx_inline gmx_exclfilter gmx_simdcall
175 gmx_load_exclusion_filter(const unsigned *i)
176 {
177     return gmx_simd_load_i(i);
178 }
179
180 static gmx_inline gmx_simd_bool_t gmx_simdcall
181 gmx_checkbitmask_pb(gmx_exclfilter m0, gmx_exclfilter m1)
182 {
183     return _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_andnot_si128(m0, m1), _mm_setzero_si128()));
184 }
185
186 #endif /* _nbnxn_kernel_simd_utils_x86_s128s_h_ */