eb962590e17e9b165d9e54124c3a6a41a22765d0
[alexxy/gromacs.git] / src / mdlib / nbnxn_search_x86_simd.h
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  *          GROningen MAchine for Chemical Simulations
9  *
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2012, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
34  */
35
36 /* GMX_MM128_HERE or GMX_MM256_HERE should be set before including this file.
37  * gmx_sse_or_avh.h should be included before including this file.
38  */
39
40 /* Copies PBC shifted i-cell packed atom coordinates to working array */
41 #ifdef GMX_MM128_HERE
42 static void icell_set_x_x86_simd128
43 #else
44 #ifdef GMX_MM256_HERE
45 static void icell_set_x_x86_simd256
46 #else
47 "error: GMX_MM128_HERE or GMX_MM256_HERE not defined"
48 #endif
49 #endif
50                                    (int ci,
51                                     real shx,real shy,real shz,
52                                     int na_c,
53                                     int stride,const real *x,
54                                     nbnxn_list_work_t *work)
55 {
56     int  ia;
57 #ifdef GMX_MM128_HERE
58     nbnxn_x_ci_x86_simd128_t *x_ci;
59
60     x_ci = work->x_ci_x86_simd128;
61
62     ia = X_IND_CI_S128(ci);
63 #else
64     nbnxn_x_ci_x86_simd256_t *x_ci;
65
66     x_ci = work->x_ci_x86_simd256;
67
68     ia = X_IND_CI_S256(ci);
69 #endif
70
71     x_ci->ix_SSE0 = gmx_set1_pr(x[ia + 0*STRIDE_S    ] + shx);
72     x_ci->iy_SSE0 = gmx_set1_pr(x[ia + 1*STRIDE_S    ] + shy);
73     x_ci->iz_SSE0 = gmx_set1_pr(x[ia + 2*STRIDE_S    ] + shz);
74     x_ci->ix_SSE1 = gmx_set1_pr(x[ia + 0*STRIDE_S + 1] + shx);
75     x_ci->iy_SSE1 = gmx_set1_pr(x[ia + 1*STRIDE_S + 1] + shy);
76     x_ci->iz_SSE1 = gmx_set1_pr(x[ia + 2*STRIDE_S + 1] + shz);
77     x_ci->ix_SSE2 = gmx_set1_pr(x[ia + 0*STRIDE_S + 2] + shx);
78     x_ci->iy_SSE2 = gmx_set1_pr(x[ia + 1*STRIDE_S + 2] + shy);
79     x_ci->iz_SSE2 = gmx_set1_pr(x[ia + 2*STRIDE_S + 2] + shz);
80     x_ci->ix_SSE3 = gmx_set1_pr(x[ia + 0*STRIDE_S + 3] + shx);
81     x_ci->iy_SSE3 = gmx_set1_pr(x[ia + 1*STRIDE_S + 3] + shy);
82     x_ci->iz_SSE3 = gmx_set1_pr(x[ia + 2*STRIDE_S + 3] + shz);
83 }
84
85 /* SSE or AVX code for making a pair list of cell ci vs cell cjf-cjl
86  * for coordinates in packed format.
87  * Checks bouding box distances and possibly atom pair distances.
88  * This is an accelerated version of make_cluster_list_simple.
89  */
90 #ifdef GMX_MM128_HERE
91 static void make_cluster_list_x86_simd128
92 #else
93 #ifdef GMX_MM256_HERE
94 static void make_cluster_list_x86_simd256
95 #else
96 "error: GMX_MM128_HERE or GMX_MM256_HERE not defined"
97 #endif
98 #endif
99                                          (const nbnxn_grid_t *gridj,
100                                           nbnxn_pairlist_t *nbl,
101                                           int ci,int cjf,int cjl,
102                                           gmx_bool remove_sub_diag,
103                                           const real *x_j,
104                                           real rl2,float rbb2,
105                                           int *ndistc)
106 {
107 #ifdef GMX_MM128_HERE
108     const nbnxn_x_ci_x86_simd128_t *work;
109 #else
110     const nbnxn_x_ci_x86_simd256_t *work;
111 #endif
112
113     const float *bb_ci;
114
115     gmx_mm_pr  jx_SSE,jy_SSE,jz_SSE;
116
117     gmx_mm_pr  dx_SSE0,dy_SSE0,dz_SSE0;
118     gmx_mm_pr  dx_SSE1,dy_SSE1,dz_SSE1;
119     gmx_mm_pr  dx_SSE2,dy_SSE2,dz_SSE2;
120     gmx_mm_pr  dx_SSE3,dy_SSE3,dz_SSE3;
121
122     gmx_mm_pr  rsq_SSE0;
123     gmx_mm_pr  rsq_SSE1;
124     gmx_mm_pr  rsq_SSE2;
125     gmx_mm_pr  rsq_SSE3;
126
127     gmx_mm_pr  wco_SSE0;
128     gmx_mm_pr  wco_SSE1;
129     gmx_mm_pr  wco_SSE2;
130     gmx_mm_pr  wco_SSE3;
131     gmx_mm_pr  wco_any_SSE01,wco_any_SSE23,wco_any_SSE;
132     
133     gmx_mm_pr  rc2_SSE;
134
135     gmx_bool   InRange;
136     float      d2;
137     int        xind_f,xind_l,cj;
138
139 #ifdef GMX_MM128_HERE
140     cjf = CI_TO_CJ_S128(cjf);
141     cjl = CI_TO_CJ_S128(cjl+1) - 1;
142
143     work = nbl->work->x_ci_x86_simd128;
144 #else
145     cjf = CI_TO_CJ_S256(cjf);
146     cjl = CI_TO_CJ_S256(cjl+1) - 1;
147
148     work = nbl->work->x_ci_x86_simd256;
149 #endif
150
151     bb_ci = nbl->work->bb_ci;
152
153     rc2_SSE   = gmx_set1_pr(rl2);
154
155     InRange = FALSE;
156     while (!InRange && cjf <= cjl)
157     {
158         d2 = subc_bb_dist2_sse(4,0,bb_ci,cjf,gridj->bbj);
159         *ndistc += 2;
160         
161         /* Check if the distance is within the distance where
162          * we use only the bounding box distance rbb,
163          * or within the cut-off and there is at least one atom pair
164          * within the cut-off.
165          */
166         if (d2 < rbb2)
167         {
168             InRange = TRUE;
169         }
170         else if (d2 < rl2)
171         {
172 #ifdef GMX_MM128_HERE
173             xind_f  = X_IND_CJ_S128(CI_TO_CJ_S128(gridj->cell0) + cjf);
174 #else
175             xind_f  = X_IND_CJ_S256(CI_TO_CJ_S256(gridj->cell0) + cjf);
176 #endif
177             jx_SSE  = gmx_load_pr(x_j+xind_f+0*STRIDE_S);
178             jy_SSE  = gmx_load_pr(x_j+xind_f+1*STRIDE_S);
179             jz_SSE  = gmx_load_pr(x_j+xind_f+2*STRIDE_S);
180
181             
182             /* Calculate distance */
183             dx_SSE0            = gmx_sub_pr(work->ix_SSE0,jx_SSE);
184             dy_SSE0            = gmx_sub_pr(work->iy_SSE0,jy_SSE);
185             dz_SSE0            = gmx_sub_pr(work->iz_SSE0,jz_SSE);
186             dx_SSE1            = gmx_sub_pr(work->ix_SSE1,jx_SSE);
187             dy_SSE1            = gmx_sub_pr(work->iy_SSE1,jy_SSE);
188             dz_SSE1            = gmx_sub_pr(work->iz_SSE1,jz_SSE);
189             dx_SSE2            = gmx_sub_pr(work->ix_SSE2,jx_SSE);
190             dy_SSE2            = gmx_sub_pr(work->iy_SSE2,jy_SSE);
191             dz_SSE2            = gmx_sub_pr(work->iz_SSE2,jz_SSE);
192             dx_SSE3            = gmx_sub_pr(work->ix_SSE3,jx_SSE);
193             dy_SSE3            = gmx_sub_pr(work->iy_SSE3,jy_SSE);
194             dz_SSE3            = gmx_sub_pr(work->iz_SSE3,jz_SSE);
195             
196             /* rsq = dx*dx+dy*dy+dz*dz */
197             rsq_SSE0           = gmx_calc_rsq_pr(dx_SSE0,dy_SSE0,dz_SSE0);
198             rsq_SSE1           = gmx_calc_rsq_pr(dx_SSE1,dy_SSE1,dz_SSE1);
199             rsq_SSE2           = gmx_calc_rsq_pr(dx_SSE2,dy_SSE2,dz_SSE2);
200             rsq_SSE3           = gmx_calc_rsq_pr(dx_SSE3,dy_SSE3,dz_SSE3);
201             
202             wco_SSE0           = gmx_cmplt_pr(rsq_SSE0,rc2_SSE);
203             wco_SSE1           = gmx_cmplt_pr(rsq_SSE1,rc2_SSE);
204             wco_SSE2           = gmx_cmplt_pr(rsq_SSE2,rc2_SSE);
205             wco_SSE3           = gmx_cmplt_pr(rsq_SSE3,rc2_SSE);
206             
207             wco_any_SSE01      = gmx_or_pr(wco_SSE0,wco_SSE1);
208             wco_any_SSE23      = gmx_or_pr(wco_SSE2,wco_SSE3);
209             wco_any_SSE        = gmx_or_pr(wco_any_SSE01,wco_any_SSE23);
210             
211             InRange            = gmx_movemask_pr(wco_any_SSE);
212
213             *ndistc += 4*GMX_X86_SIMD_WIDTH_HERE;
214         }
215         if (!InRange)
216         {
217             cjf++;
218         }
219     }
220     if (!InRange)
221     {
222         return;
223     }
224
225     InRange = FALSE;
226     while (!InRange && cjl > cjf)
227     {
228         d2 = subc_bb_dist2_sse(4,0,bb_ci,cjl,gridj->bbj);
229         *ndistc += 2;
230         
231         /* Check if the distance is within the distance where
232          * we use only the bounding box distance rbb,
233          * or within the cut-off and there is at least one atom pair
234          * within the cut-off.
235          */
236         if (d2 < rbb2)
237         {
238             InRange = TRUE;
239         }
240         else if (d2 < rl2)
241         {
242 #ifdef GMX_MM128_HERE
243             xind_l  = X_IND_CJ_S128(CI_TO_CJ_S128(gridj->cell0) + cjl);
244 #else
245             xind_l  = X_IND_CJ_S256(CI_TO_CJ_S256(gridj->cell0) + cjl);
246 #endif
247             jx_SSE  = gmx_load_pr(x_j+xind_l+0*STRIDE_S);
248             jy_SSE  = gmx_load_pr(x_j+xind_l+1*STRIDE_S);
249             jz_SSE  = gmx_load_pr(x_j+xind_l+2*STRIDE_S);
250             
251             /* Calculate distance */
252             dx_SSE0            = gmx_sub_pr(work->ix_SSE0,jx_SSE);
253             dy_SSE0            = gmx_sub_pr(work->iy_SSE0,jy_SSE);
254             dz_SSE0            = gmx_sub_pr(work->iz_SSE0,jz_SSE);
255             dx_SSE1            = gmx_sub_pr(work->ix_SSE1,jx_SSE);
256             dy_SSE1            = gmx_sub_pr(work->iy_SSE1,jy_SSE);
257             dz_SSE1            = gmx_sub_pr(work->iz_SSE1,jz_SSE);
258             dx_SSE2            = gmx_sub_pr(work->ix_SSE2,jx_SSE);
259             dy_SSE2            = gmx_sub_pr(work->iy_SSE2,jy_SSE);
260             dz_SSE2            = gmx_sub_pr(work->iz_SSE2,jz_SSE);
261             dx_SSE3            = gmx_sub_pr(work->ix_SSE3,jx_SSE);
262             dy_SSE3            = gmx_sub_pr(work->iy_SSE3,jy_SSE);
263             dz_SSE3            = gmx_sub_pr(work->iz_SSE3,jz_SSE);
264             
265             /* rsq = dx*dx+dy*dy+dz*dz */
266             rsq_SSE0           = gmx_calc_rsq_pr(dx_SSE0,dy_SSE0,dz_SSE0);
267             rsq_SSE1           = gmx_calc_rsq_pr(dx_SSE1,dy_SSE1,dz_SSE1);
268             rsq_SSE2           = gmx_calc_rsq_pr(dx_SSE2,dy_SSE2,dz_SSE2);
269             rsq_SSE3           = gmx_calc_rsq_pr(dx_SSE3,dy_SSE3,dz_SSE3);
270             
271             wco_SSE0           = gmx_cmplt_pr(rsq_SSE0,rc2_SSE);
272             wco_SSE1           = gmx_cmplt_pr(rsq_SSE1,rc2_SSE);
273             wco_SSE2           = gmx_cmplt_pr(rsq_SSE2,rc2_SSE);
274             wco_SSE3           = gmx_cmplt_pr(rsq_SSE3,rc2_SSE);
275             
276             wco_any_SSE01      = gmx_or_pr(wco_SSE0,wco_SSE1);
277             wco_any_SSE23      = gmx_or_pr(wco_SSE2,wco_SSE3);
278             wco_any_SSE        = gmx_or_pr(wco_any_SSE01,wco_any_SSE23);
279             
280             InRange            = gmx_movemask_pr(wco_any_SSE);
281
282             *ndistc += 4*GMX_X86_SIMD_WIDTH_HERE;
283         }
284         if (!InRange)
285         {
286             cjl--;
287         }
288     }
289
290     if (cjf <= cjl)
291     {
292         for(cj=cjf; cj<=cjl; cj++)
293         {
294             /* Store cj and the interaction mask */
295 #ifdef GMX_MM128_HERE
296             nbl->cj[nbl->ncj].cj   = CI_TO_CJ_S128(gridj->cell0) + cj;
297             nbl->cj[nbl->ncj].excl = get_imask_x86_simd128(remove_sub_diag,ci,cj);
298 #else
299             nbl->cj[nbl->ncj].cj   = CI_TO_CJ_S256(gridj->cell0) + cj;
300             nbl->cj[nbl->ncj].excl = get_imask_x86_simd256(remove_sub_diag,ci,cj);
301 #endif
302             nbl->ncj++;
303         }
304         /* Increase the closing index in i super-cell list */
305         nbl->ci[nbl->nci].cj_ind_end = nbl->ncj;
306     }
307 }