Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / gmxlib / nonbonded / nb_kernel_avx_256_double / kernelutil_x86_avx_256_double.h
1 /*
2  *                This source code is part of
3  *
4  *                 G   R   O   M   A   C   S
5  *
6  * Copyright (c) 2011-2012, The GROMACS Development Team
7  *
8  * Gromacs is a library for molecular simulation and trajectory analysis,
9  * written by Erik Lindahl, David van der Spoel, Berk Hess, and others - for
10  * a full list of developers and information, check out http://www.gromacs.org
11  *
12  * This program is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the Free
14  * Software Foundation; either version 2 of the License, or (at your option) any
15  * later version.
16  * As a special exception, you may use this file as part of a free software
17  * library without restriction.  Specifically, if other files instantiate
18  * templates or use macros or inline functions from this file, or you compile
19  * this file and link it with other files to produce an executable, this
20  * file does not by itself cause the resulting executable to be covered by
21  * the GNU Lesser General Public License.
22  *
23  * In plain-speak: do not worry about classes/macros/templates either - only
24  * changes to the library have to be LGPL, not an application linking with it.
25  *
26  * To help fund GROMACS development, we humbly ask that you cite
27  * the papers people have written on it - you can find them on the website!
28  */
29 #ifndef _kernelutil_x86_avx_256_double_h_
30 #define _kernelutil_x86_avx_256_double_h_
31
32
33 #include "gmx_x86_avx_256.h"
34
35
36 static int
37 gmx_mm256_any_lt(__m256d a, __m256d b)
38 {
39     return _mm256_movemask_pd(_mm256_cmp_pd(a, b, _CMP_LT_OQ));
40 }
41
42 static gmx_inline __m256d
43 gmx_mm256_calc_rsq_pd(__m256d dx, __m256d dy, __m256d dz)
44 {
45     return _mm256_add_pd( _mm256_add_pd( _mm256_mul_pd(dx, dx), _mm256_mul_pd(dy, dy) ), _mm256_mul_pd(dz, dz) );
46 }
47
48 /* Normal sum of four ymm registers */
49 #define gmx_mm256_sum4_pd(t0, t1, t2, t3)  _mm256_add_pd(_mm256_add_pd(t0, t1), _mm256_add_pd(t2, t3))
50
51
52 /* Load a single value from 1-4 places, merge into xmm register */
53 static __m256d
54 gmx_mm256_load_1real_pd(const double * gmx_restrict ptrA)
55 {
56     return _mm256_castpd128_pd256(_mm_load_sd(ptrA));
57 }
58
59 static __m256d
60 gmx_mm256_load_2real_swizzle_pd(const double * gmx_restrict ptrA,
61                                 const double * gmx_restrict ptrB)
62 {
63     __m128d tA, tB;
64
65     tA = _mm_load_sd(ptrA);
66     tB = _mm_load_sd(ptrB);
67
68     return _mm256_castpd128_pd256(_mm_unpacklo_pd(tA, tB));
69 }
70
71
72 static __m256d
73 gmx_mm256_load_4real_swizzle_pd(const double * gmx_restrict ptrA, const double * gmx_restrict ptrB,
74                                 const double * gmx_restrict ptrC, const double * gmx_restrict ptrD)
75 {
76     __m128d t1, t2;
77
78     t1 = _mm_unpacklo_pd(_mm_load_sd(ptrA), _mm_load_sd(ptrB));
79     t2 = _mm_unpacklo_pd(_mm_load_sd(ptrC), _mm_load_sd(ptrD));
80     return gmx_mm256_set_m128d(t2, t1);
81 }
82
83
84
85 static void
86 gmx_mm256_store_1real_pd(double * gmx_restrict ptrA, __m256d xmm1)
87 {
88     _mm_store_sd(ptrA, _mm256_castpd256_pd128(xmm1));
89 }
90
91
92 static void
93 gmx_mm256_store_2real_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB, __m256d xmm1)
94 {
95     __m256d t2;
96
97     t2       = _mm256_permute_pd(xmm1, _GMX_MM_PERMUTE256D(1, 1, 1, 1));
98     _mm_store_sd(ptrA, _mm256_castpd256_pd128(xmm1));
99     _mm_store_sd(ptrB, _mm256_castpd256_pd128(t2));
100 }
101
102
103
104
105 static void
106 gmx_mm256_store_4real_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB,
107                                  double * gmx_restrict ptrC, double * gmx_restrict ptrD, __m256d xmm1)
108 {
109     __m256d t2;
110     __m128d t3, t4;
111
112     t2       = _mm256_permute_pd(xmm1, _GMX_MM_PERMUTE256D(1, 1, 1, 1));
113     t3       = _mm256_extractf128_pd(xmm1, 0x1);
114     t4       = _mm_permute_pd(t3, _GMX_MM_PERMUTE128D(1, 1));
115     _mm_store_sd(ptrA, _mm256_castpd256_pd128(xmm1));
116     _mm_store_sd(ptrB, _mm256_castpd256_pd128(t2));
117     _mm_store_sd(ptrC, t3);
118     _mm_store_sd(ptrD, t4);
119 }
120
121
122
123
124 static void
125 gmx_mm256_increment_1real_pd(double * gmx_restrict ptrA, __m256d xmm1)
126 {
127     __m128d t1;
128
129     t1   = _mm256_castpd256_pd128(xmm1);
130     t1   = _mm_add_sd(t1, _mm_load_sd(ptrA));
131
132     _mm_store_sd(ptrA, t1);
133 }
134
135
136 static void
137 gmx_mm256_increment_2real_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB, __m256d xmm1)
138 {
139     __m128d t1, t2;
140
141     t1   = _mm256_castpd256_pd128(xmm1);
142     t2   = _mm_permute_pd(t1, _GMX_MM_PERMUTE128D(1, 1));
143
144     t1   = _mm_add_sd(t1, _mm_load_sd(ptrA));
145     t2   = _mm_add_sd(t2, _mm_load_sd(ptrB));
146
147     _mm_store_sd(ptrA, t1);
148     _mm_store_sd(ptrB, t2);
149 }
150
151
152 static void
153 gmx_mm256_increment_4real_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB,
154                                      double * gmx_restrict ptrC, double * gmx_restrict ptrD, __m256d xmm1)
155 {
156     __m128d t1, t2, t3, t4;
157
158     t1   = _mm256_castpd256_pd128(xmm1);
159     t2   = _mm_permute_pd(t1, _GMX_MM_PERMUTE128D(1, 1));
160     t3   = _mm256_extractf128_pd(xmm1, 0x1);
161     t4   = _mm_permute_pd(t3, _GMX_MM_PERMUTE128D(1, 1));
162
163     t1   = _mm_add_sd(t1, _mm_load_sd(ptrA));
164     t2   = _mm_add_sd(t2, _mm_load_sd(ptrB));
165     t3   = _mm_add_sd(t3, _mm_load_sd(ptrC));
166     t4   = _mm_add_sd(t4, _mm_load_sd(ptrD));
167
168     _mm_store_sd(ptrA, t1);
169     _mm_store_sd(ptrB, t2);
170     _mm_store_sd(ptrC, t3);
171     _mm_store_sd(ptrD, t4);
172 }
173
174
175
176 static void
177 gmx_mm256_load_1pair_swizzle_pd(const double * gmx_restrict p1, __m256d *c6, __m256d *c12)
178 {
179     *c6     = _mm256_castpd128_pd256(_mm_load_sd(p1));
180     *c12    = _mm256_castpd128_pd256(_mm_load_sd(p1+1));
181 }
182
183
184 static void
185 gmx_mm256_load_2pair_swizzle_pd(const double * gmx_restrict p1, const double * gmx_restrict p2, __m256d *c6, __m256d *c12)
186 {
187     __m128d t1, t2, t3;
188
189     t1   = _mm_loadu_pd(p1);
190     t2   = _mm_loadu_pd(p2);
191     *c6  = _mm256_castpd128_pd256(_mm_unpacklo_pd(t1, t2));
192     *c12 = _mm256_castpd128_pd256(_mm_unpackhi_pd(t1, t2));
193 }
194
195
196
197 static void
198 gmx_mm256_load_4pair_swizzle_pd(const double * gmx_restrict p1, const double * gmx_restrict p2,
199                                 const double * gmx_restrict p3, const double * gmx_restrict p4,
200                                 __m256d * gmx_restrict c6, __m256d * gmx_restrict c12)
201 {
202     __m256d t1, t2;
203
204     t1   = gmx_mm256_set_m128d(_mm_loadu_pd(p3), _mm_loadu_pd(p1)); /* c12c  c6c | c12a  c6a */
205     t2   = gmx_mm256_set_m128d(_mm_loadu_pd(p4), _mm_loadu_pd(p2)); /* c12d  c6d | c12b  c6b */
206
207     *c6  = _mm256_unpacklo_pd(t1, t2);                              /* c6d c6c | c6b c6a */
208     *c12 = _mm256_unpackhi_pd(t1, t2);                              /* c12d c12c | c12b c12a */
209 }
210
211
212 static gmx_inline void
213 gmx_mm256_load_shift_and_1rvec_broadcast_pd(const double * gmx_restrict xyz_shift,
214                                             const double * gmx_restrict xyz,
215                                             __m256d * gmx_restrict      x1,
216                                             __m256d * gmx_restrict      y1,
217                                             __m256d * gmx_restrict      z1)
218 {
219     __m128d mem_xy, mem_z, mem_sxy, mem_sz, tx, ty, tz;
220
221     mem_xy  = _mm_loadu_pd(xyz);
222     mem_z   = _mm_load_sd(xyz+2);
223     mem_sxy = _mm_loadu_pd(xyz_shift);
224     mem_sz  = _mm_load_sd(xyz_shift+2);
225
226     mem_xy  = _mm_add_pd(mem_xy, mem_sxy);
227     mem_z   = _mm_add_pd(mem_z, mem_sz);
228
229     tx  = _mm_shuffle_pd(mem_xy, mem_xy, _MM_SHUFFLE2(0, 0));
230     ty  = _mm_shuffle_pd(mem_xy, mem_xy, _MM_SHUFFLE2(1, 1));
231     tz  = _mm_shuffle_pd(mem_z, mem_z, _MM_SHUFFLE2(0, 0));
232
233     *x1 = gmx_mm256_set_m128d(tx, tx);
234     *y1 = gmx_mm256_set_m128d(ty, ty);
235     *z1 = gmx_mm256_set_m128d(tz, tz);
236 }
237
238
239 static gmx_inline void
240 gmx_mm256_load_shift_and_3rvec_broadcast_pd(const double * gmx_restrict xyz_shift,
241                                             const double * gmx_restrict xyz,
242                                             __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
243                                             __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
244                                             __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3)
245 {
246     __m128d t1, t2, t3, t4, t5, sxy, sz, szx, syz, tx, ty, tz;
247
248     t1  = _mm_loadu_pd(xyz);
249     t2  = _mm_loadu_pd(xyz+2);
250     t3  = _mm_loadu_pd(xyz+4);
251     t4  = _mm_loadu_pd(xyz+6);
252     t5  = _mm_load_sd(xyz+8);
253
254     sxy = _mm_loadu_pd(xyz_shift);
255     sz  = _mm_load_sd(xyz_shift+2);
256     szx = _mm_shuffle_pd(sz, sxy, _MM_SHUFFLE2(0, 0));
257     syz = _mm_shuffle_pd(sxy, sz, _MM_SHUFFLE2(0, 1));
258
259     t1  = _mm_add_pd(t1, sxy);
260     t2  = _mm_add_pd(t2, szx);
261     t3  = _mm_add_pd(t3, syz);
262     t4  = _mm_add_pd(t4, sxy);
263     t5  = _mm_add_sd(t5, sz);
264
265     tx   = _mm_shuffle_pd(t1, t1, _MM_SHUFFLE2(0, 0));
266     ty   = _mm_shuffle_pd(t1, t1, _MM_SHUFFLE2(1, 1));
267     tz   = _mm_shuffle_pd(t2, t2, _MM_SHUFFLE2(0, 0));
268     *x1  = gmx_mm256_set_m128d(tx, tx);
269     *y1  = gmx_mm256_set_m128d(ty, ty);
270     *z1  = gmx_mm256_set_m128d(tz, tz);
271     tx   = _mm_shuffle_pd(t2, t2, _MM_SHUFFLE2(1, 1));
272     ty   = _mm_shuffle_pd(t3, t3, _MM_SHUFFLE2(0, 0));
273     tz   = _mm_shuffle_pd(t3, t3, _MM_SHUFFLE2(1, 1));
274     *x2  = gmx_mm256_set_m128d(tx, tx);
275     *y2  = gmx_mm256_set_m128d(ty, ty);
276     *z2  = gmx_mm256_set_m128d(tz, tz);
277     tx   = _mm_shuffle_pd(t4, t4, _MM_SHUFFLE2(0, 0));
278     ty   = _mm_shuffle_pd(t4, t4, _MM_SHUFFLE2(1, 1));
279     tz   = _mm_shuffle_pd(t5, t5, _MM_SHUFFLE2(0, 0));
280     *x3  = gmx_mm256_set_m128d(tx, tx);
281     *y3  = gmx_mm256_set_m128d(ty, ty);
282     *z3  = gmx_mm256_set_m128d(tz, tz);
283 }
284
285
286 static gmx_inline void
287 gmx_mm256_load_shift_and_4rvec_broadcast_pd(const double * gmx_restrict xyz_shift,
288                                             const double * gmx_restrict xyz,
289                                             __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
290                                             __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
291                                             __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3,
292                                             __m256d * gmx_restrict x4, __m256d * gmx_restrict y4, __m256d * gmx_restrict z4)
293 {
294     __m128d t1, t2, t3, t4, t5, t6, sxy, sz, szx, syz, tx, ty, tz;
295
296     t1  = _mm_loadu_pd(xyz);
297     t2  = _mm_loadu_pd(xyz+2);
298     t3  = _mm_loadu_pd(xyz+4);
299     t4  = _mm_loadu_pd(xyz+6);
300     t5  = _mm_loadu_pd(xyz+8);
301     t6  = _mm_loadu_pd(xyz+10);
302
303     sxy = _mm_loadu_pd(xyz_shift);
304     sz  = _mm_load_sd(xyz_shift+2);
305     szx = _mm_shuffle_pd(sz, sxy, _MM_SHUFFLE2(0, 0));
306     syz = _mm_shuffle_pd(sxy, sz, _MM_SHUFFLE2(0, 1));
307
308     t1  = _mm_add_pd(t1, sxy);
309     t2  = _mm_add_pd(t2, szx);
310     t3  = _mm_add_pd(t3, syz);
311     t4  = _mm_add_pd(t4, sxy);
312     t5  = _mm_add_pd(t5, szx);
313     t6  = _mm_add_pd(t6, syz);
314
315     tx   = _mm_shuffle_pd(t1, t1, _MM_SHUFFLE2(0, 0));
316     ty   = _mm_shuffle_pd(t1, t1, _MM_SHUFFLE2(1, 1));
317     tz   = _mm_shuffle_pd(t2, t2, _MM_SHUFFLE2(0, 0));
318     *x1  = gmx_mm256_set_m128d(tx, tx);
319     *y1  = gmx_mm256_set_m128d(ty, ty);
320     *z1  = gmx_mm256_set_m128d(tz, tz);
321     tx   = _mm_shuffle_pd(t2, t2, _MM_SHUFFLE2(1, 1));
322     ty   = _mm_shuffle_pd(t3, t3, _MM_SHUFFLE2(0, 0));
323     tz   = _mm_shuffle_pd(t3, t3, _MM_SHUFFLE2(1, 1));
324     *x2  = gmx_mm256_set_m128d(tx, tx);
325     *y2  = gmx_mm256_set_m128d(ty, ty);
326     *z2  = gmx_mm256_set_m128d(tz, tz);
327     tx   = _mm_shuffle_pd(t4, t4, _MM_SHUFFLE2(0, 0));
328     ty   = _mm_shuffle_pd(t4, t4, _MM_SHUFFLE2(1, 1));
329     tz   = _mm_shuffle_pd(t5, t5, _MM_SHUFFLE2(0, 0));
330     *x3  = gmx_mm256_set_m128d(tx, tx);
331     *y3  = gmx_mm256_set_m128d(ty, ty);
332     *z3  = gmx_mm256_set_m128d(tz, tz);
333     tx   = _mm_shuffle_pd(t5, t5, _MM_SHUFFLE2(1, 1));
334     ty   = _mm_shuffle_pd(t6, t6, _MM_SHUFFLE2(0, 0));
335     tz   = _mm_shuffle_pd(t6, t6, _MM_SHUFFLE2(1, 1));
336     *x4  = gmx_mm256_set_m128d(tx, tx);
337     *y4  = gmx_mm256_set_m128d(ty, ty);
338     *z4  = gmx_mm256_set_m128d(tz, tz);
339 }
340
341
342 static void
343 gmx_mm256_load_1rvec_1ptr_swizzle_pd(const double * gmx_restrict p1,
344                                      __m256d * gmx_restrict x, __m256d * gmx_restrict y, __m256d * gmx_restrict z)
345 {
346     __m256d t1;
347
348     t1            = _mm256_loadu_pd(p1);
349     *x            = t1;
350     *y            = _mm256_permute_pd(t1, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
351     *z            = _mm256_castpd128_pd256(_mm256_extractf128_pd(t1, 0x1));
352 }
353
354
355 static void
356 gmx_mm256_load_3rvec_1ptr_swizzle_pd(const double * gmx_restrict p1,
357                                      __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
358                                      __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
359                                      __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3)
360 {
361     __m256d t1, t2, t3, t4;
362
363     t1            = _mm256_loadu_pd(p1);
364     t3            = _mm256_loadu_pd(p1+4);
365     *x1           = t1;
366     *y2           = t3;
367     t2            = gmx_mm256_unpack128hi_pd(t1, t1);
368     t4            = gmx_mm256_unpack128hi_pd(t3, t3);
369     *z1           = t2;
370     *x3           = t4;
371     *y1           = _mm256_permute_pd(t1, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
372     *z2           = _mm256_permute_pd(t3, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
373     *x2           = _mm256_permute_pd(t2, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
374     *y3           = _mm256_permute_pd(t4, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
375     *z3           = _mm256_castpd128_pd256(_mm_load_sd(p1+8));
376 }
377
378 static void
379 gmx_mm256_load_4rvec_1ptr_swizzle_pd(const double * gmx_restrict p1,
380                                      __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
381                                      __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
382                                      __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3,
383                                      __m256d * gmx_restrict x4, __m256d * gmx_restrict y4, __m256d * gmx_restrict z4)
384 {
385     __m256d t1, t2, t3, t4, t5, t6;
386
387     t1            = _mm256_loadu_pd(p1);
388     t2            = _mm256_loadu_pd(p1+4);
389     t3            = _mm256_loadu_pd(p1+8);
390
391     t4            = _mm256_castpd128_pd256(_mm256_extractf128_pd(t1, 0x1));
392     t5            = _mm256_castpd128_pd256(_mm256_extractf128_pd(t2, 0x1));
393     t6            = _mm256_castpd128_pd256(_mm256_extractf128_pd(t3, 0x1));
394
395     *x1           = t1;
396     *y2           = t2;
397     *z3           = t3;
398     *z1           = t4;
399     *x3           = t5;
400     *y4           = t6;
401
402     *y1           = _mm256_permute_pd(t1, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
403     *z2           = _mm256_permute_pd(t2, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
404     *x4           = _mm256_permute_pd(t3, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
405     *x2           = _mm256_permute_pd(t4, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
406     *y3           = _mm256_permute_pd(t5, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
407     *z4           = _mm256_permute_pd(t6, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
408 }
409
410
411 static void
412 gmx_mm256_load_1rvec_4ptr_swizzle_pd(const double * gmx_restrict ptrA, const double * gmx_restrict ptrB,
413                                      const double * gmx_restrict ptrC, const double * gmx_restrict ptrD,
414                                      __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1)
415 {
416     __m256d t1, t2, t3, t4, t5, t6;
417
418     t1           = _mm256_loadu_pd(ptrA);        /*   -  z1a | y1a x1a */
419     t2           = _mm256_loadu_pd(ptrB);        /*   -  z1b | y1b x1b */
420     t3           = _mm256_loadu_pd(ptrC);        /*   -  z1c | y1c x1c */
421     t4           = _mm256_loadu_pd(ptrD);        /*   -  z1d | y1d x1d */
422
423     t5           = _mm256_unpacklo_pd(t1, t2);   /*  z1b z1a | x1b x1a */
424     t6           = _mm256_unpackhi_pd(t1, t2);   /*   -   -  | y1b y1a */
425     t1           = _mm256_unpacklo_pd(t3, t4);   /*  z1c z1c | x1d x1c */
426     t2           = _mm256_unpackhi_pd(t3, t4);   /*   -   -  | y1d y1c */
427
428     *x1          = gmx_mm256_unpack128lo_pd(t5, t1);
429     *y1          = gmx_mm256_unpack128lo_pd(t6, t2);
430     *z1          = gmx_mm256_unpack128hi_pd(t5, t1);
431 }
432
433
434
435 static void
436 gmx_mm256_load_3rvec_4ptr_swizzle_pd(const double * gmx_restrict ptrA, const double * gmx_restrict ptrB,
437                                      const double * gmx_restrict ptrC, const double * gmx_restrict ptrD,
438                                      __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
439                                      __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
440                                      __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3)
441 {
442     __m256d t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14;
443
444     t1           = _mm256_loadu_pd(ptrA);                       /*  x2a z1a | y1a x1a */
445     t2           = _mm256_loadu_pd(ptrB);                       /*  x2b z1b | y1b x1b */
446     t3           = _mm256_loadu_pd(ptrC);                       /*  x2c z1c | y1c x1c */
447     t4           = _mm256_loadu_pd(ptrD);                       /*  x2d z1d | y1d x1d */
448     t5           = _mm256_loadu_pd(ptrA+4);                     /*  y3a x3a | z2a y2a */
449     t6           = _mm256_loadu_pd(ptrB+4);                     /*  y3b x3b | z2b y2b */
450     t7           = _mm256_loadu_pd(ptrC+4);                     /*  y3c x3c | z2c y2c */
451     t8           = _mm256_loadu_pd(ptrD+4);                     /*  y3d x3d | z2d y2d */
452     t9           = _mm256_castpd128_pd256(_mm_load_sd(ptrA+8)); /*   -   -  |  -  z3a */
453     t10          = _mm256_castpd128_pd256(_mm_load_sd(ptrB+8)); /*   -   -  |  -  z3b */
454     t11          = _mm256_castpd128_pd256(_mm_load_sd(ptrC+8)); /*   -   -  |  -  z3c */
455     t12          = _mm256_castpd128_pd256(_mm_load_sd(ptrD+8)); /*   -   -  |  -  z3d */
456
457     t13          = _mm256_unpacklo_pd(t1, t2);                  /*  z1b z1a | x1b x1a */
458     t14          = _mm256_unpackhi_pd(t1, t2);                  /*  x2b x2a | y1b y1a */
459     t1           = _mm256_unpacklo_pd(t3, t4);                  /*  z1d z1c | x1d x1c */
460     t2           = _mm256_unpackhi_pd(t3, t4);                  /*  x2d x2c | y1d y1c */
461
462     t3           = _mm256_unpacklo_pd(t5, t6);                  /*  x3b x3a | y2b y2a */
463     t4           = _mm256_unpackhi_pd(t5, t6);                  /*  y3b y3a | z2b z2a */
464     t5           = _mm256_unpacklo_pd(t7, t8);                  /*  x3d x3c | y2d y2c */
465     t6           = _mm256_unpackhi_pd(t7, t8);                  /*  y3d y3c | z2d z2c */
466
467     t9           = _mm256_unpacklo_pd(t9, t10);                 /*   -   -  | z3b z3a */
468     t11          = _mm256_unpacklo_pd(t11, t12);                /*   -   -  | z3d z3c */
469
470     *x1          = gmx_mm256_unpack128lo_pd(t13, t1);
471     *y1          = gmx_mm256_unpack128lo_pd(t14, t2);
472     *z1          = gmx_mm256_unpack128hi_pd(t13, t1);
473     *x2          = gmx_mm256_unpack128hi_pd(t14, t2);
474     *y2          = gmx_mm256_unpack128lo_pd(t3, t5);
475     *z2          = gmx_mm256_unpack128lo_pd(t4, t6);
476     *x3          = gmx_mm256_unpack128hi_pd(t3, t5);
477     *y3          = gmx_mm256_unpack128hi_pd(t4, t6);
478     *z3          = gmx_mm256_unpack128lo_pd(t9, t11);
479 }
480
481
482
483 static void
484 gmx_mm256_load_4rvec_4ptr_swizzle_pd(const double * gmx_restrict ptrA, const double * gmx_restrict ptrB,
485                                      const double * gmx_restrict ptrC, const double * gmx_restrict ptrD,
486                                      __m256d * gmx_restrict x1, __m256d * gmx_restrict y1, __m256d * gmx_restrict z1,
487                                      __m256d * gmx_restrict x2, __m256d * gmx_restrict y2, __m256d * gmx_restrict z2,
488                                      __m256d * gmx_restrict x3, __m256d * gmx_restrict y3, __m256d * gmx_restrict z3,
489                                      __m256d * gmx_restrict x4, __m256d * gmx_restrict y4, __m256d * gmx_restrict z4)
490 {
491     __m256d t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14;
492
493     t1           = _mm256_loadu_pd(ptrA);        /*  x2a z1a | y1a x1a */
494     t2           = _mm256_loadu_pd(ptrB);        /*  x2b z1b | y1b x1b */
495     t3           = _mm256_loadu_pd(ptrC);        /*  x2c z1c | y1c x1c */
496     t4           = _mm256_loadu_pd(ptrD);        /*  x2d z1d | y1d x1d */
497     t5           = _mm256_loadu_pd(ptrA+4);      /*  y3a x3a | z2a y2a */
498     t6           = _mm256_loadu_pd(ptrB+4);      /*  y3b x3b | z2b y2b */
499     t7           = _mm256_loadu_pd(ptrC+4);      /*  y3c x3c | z2c y2c */
500     t8           = _mm256_loadu_pd(ptrD+4);      /*  y3d x3d | z2d y2d */
501     t9           = _mm256_loadu_pd(ptrA+8);      /*  z4a y4a | x4a z3a */
502     t10          = _mm256_loadu_pd(ptrB+8);      /*  z4b y4b | x4b z3b */
503     t11          = _mm256_loadu_pd(ptrC+8);      /*  z4c y4c | x4c z3c */
504     t12          = _mm256_loadu_pd(ptrD+8);      /*  z4d y4d | x4d z3d */
505
506     t13          = _mm256_unpacklo_pd(t1, t2);   /*  z1b z1a | x1b x1a */
507     t14          = _mm256_unpackhi_pd(t1, t2);   /*  x2b x2a | y1b y1a */
508     t1           = _mm256_unpacklo_pd(t3, t4);   /*  z1d z1c | x1d x1c */
509     t2           = _mm256_unpackhi_pd(t3, t4);   /*  x2d x2c | y1d y1c */
510
511     t3           = _mm256_unpacklo_pd(t5, t6);   /*  x3b x3a | y2b y2a */
512     t4           = _mm256_unpackhi_pd(t5, t6);   /*  y3b y3a | z2b z2a */
513     t5           = _mm256_unpacklo_pd(t7, t8);   /*  x3d x3c | y2d y2c */
514     t6           = _mm256_unpackhi_pd(t7, t8);   /*  y3d y3c | z2d z2c */
515
516     t7           = _mm256_unpacklo_pd(t9, t10);  /*  y4b y4a | z3b z3a */
517     t8           = _mm256_unpackhi_pd(t9, t10);  /*  z4b z4a | x4b x4a */
518     t9           = _mm256_unpacklo_pd(t11, t12); /*  y4d y4c | z3d z3c */
519     t10          = _mm256_unpackhi_pd(t11, t12); /*  z4d z4c | x4d x4c */
520
521     *x1          = gmx_mm256_unpack128lo_pd(t13, t1);
522     *y1          = gmx_mm256_unpack128lo_pd(t14, t2);
523     *z1          = gmx_mm256_unpack128hi_pd(t13, t1);
524     *x2          = gmx_mm256_unpack128hi_pd(t14, t2);
525     *y2          = gmx_mm256_unpack128lo_pd(t3, t5);
526     *z2          = gmx_mm256_unpack128lo_pd(t4, t6);
527     *x3          = gmx_mm256_unpack128hi_pd(t3, t5);
528     *y3          = gmx_mm256_unpack128hi_pd(t4, t6);
529     *z3          = gmx_mm256_unpack128lo_pd(t7, t9);
530     *x4          = gmx_mm256_unpack128lo_pd(t8, t10);
531     *y4          = gmx_mm256_unpack128hi_pd(t7, t9);
532     *z4          = gmx_mm256_unpack128hi_pd(t8, t10);
533 }
534
535
536
537 static void
538 gmx_mm256_decrement_1rvec_4ptr_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB,
539                                           double * gmx_restrict ptrC, double * gmx_restrict ptrD,
540                                           __m256d x1, __m256d y1, __m256d z1)
541 {
542     __m256d t1, t2, tA, tB, tC, tD;
543     __m256i mask;
544
545     t1          = _mm256_unpacklo_pd(x1, y1);       /*  y1c x1c | y1a x1a */
546     t2          = _mm256_unpackhi_pd(x1, y1);       /*  y1d x1d | y1b x1b */
547     x1          = gmx_mm256_unpack128lo_pd(t1, z1); /*  -  z1a | y1a x1a */
548     y1          = gmx_mm256_unpack128hi_pd(t1, z1); /*  -  z1c | y1c x1c */
549     z1          = _mm256_permute_pd(z1, _GMX_MM_PERMUTE256D(0, 1, 0, 1));
550     t1          = gmx_mm256_unpack128lo_pd(t2, z1); /*  -  z1b | y1b x1b */
551     z1          = gmx_mm256_unpack128hi_pd(t2, z1); /*  -  z1d | y1d x1d */
552
553     /* Construct a mask without executing any data loads */
554     mask        = _mm256_castpd_si256(_mm256_blend_pd(_mm256_setzero_pd(),
555                                                       _mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_OQ), 0x7));
556
557     tA          = _mm256_loadu_pd(ptrA);
558     tB          = _mm256_loadu_pd(ptrB);
559     tC          = _mm256_loadu_pd(ptrC);
560     tD          = _mm256_loadu_pd(ptrD);
561
562     tA          = _mm256_sub_pd(tA, x1);
563     tB          = _mm256_sub_pd(tB, t1);
564     tC          = _mm256_sub_pd(tC, y1);
565     tD          = _mm256_sub_pd(tD, z1);
566
567     _mm256_maskstore_pd(ptrA, mask, tA);
568     _mm256_maskstore_pd(ptrB, mask, tB);
569     _mm256_maskstore_pd(ptrC, mask, tC);
570     _mm256_maskstore_pd(ptrD, mask, tD);
571 }
572
573
574
575 #if defined (_MSC_VER) && defined(_M_IX86)
576 /* Macro work-around since 32-bit MSVC cannot handle >3 xmm/ymm parameters */
577 #define gmx_mm256_decrement_3rvec_4ptr_swizzle_pd(ptrA, ptrB, ptrC, ptrD, \
578                                                   _x1, _y1, _z1, _x2, _y2, _z2, _x3, _y3, _z3) \
579     { \
580         __m256d _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9, _t10; \
581         __m128d _tA, _tB, _tC, _tD, _tE; \
582         _t1          = _mm256_loadu_pd(ptrA); \
583         _t2          = _mm256_loadu_pd(ptrB); \
584         _t3          = _mm256_loadu_pd(ptrC); \
585         _t4          = _mm256_loadu_pd(ptrD); \
586         _t5          = _mm256_loadu_pd(ptrA+4); \
587         _t6          = _mm256_loadu_pd(ptrB+4); \
588         _t7          = _mm256_loadu_pd(ptrC+4); \
589         _t8          = _mm256_loadu_pd(ptrD+4); \
590         _tA          = _mm_load_sd(ptrA+8); \
591         _tB          = _mm_load_sd(ptrB+8); \
592         _tC          = _mm_load_sd(ptrC+8); \
593         _tD          = _mm_load_sd(ptrD+8); \
594         _t9          = _mm256_unpacklo_pd(_x1, _y1); \
595         _x1          = _mm256_unpackhi_pd(_x1, _y1); \
596         _y1          = _mm256_unpacklo_pd(_z1, _x2); \
597         _z1          = _mm256_unpackhi_pd(_z1, _x2); \
598         _x2          = _mm256_unpacklo_pd(_y2, _z2); \
599         _y2          = _mm256_unpackhi_pd(_y2, _z2); \
600         _z2          = _mm256_unpacklo_pd(_x3, _y3); \
601         _x3          = _mm256_unpackhi_pd(_x3, _y3); \
602         _t10         = gmx_mm256_unpack128lo_pd(_t9, _y1); \
603         _y3          = gmx_mm256_unpack128hi_pd(_t9, _y1); \
604         _t9          = gmx_mm256_unpack128lo_pd(_x1, _z1); \
605         _y1          = gmx_mm256_unpack128hi_pd(_x1, _z1); \
606         _x1          = gmx_mm256_unpack128lo_pd(_x2, _z2); \
607         _z1          = gmx_mm256_unpack128hi_pd(_x2, _z2); \
608         _x2          = gmx_mm256_unpack128lo_pd(_y2, _x3); \
609         _z2          = gmx_mm256_unpack128hi_pd(_y2, _x3); \
610         _t1          = _mm256_sub_pd(_t1, _t10); \
611         _t2          = _mm256_sub_pd(_t2, _t9); \
612         _t3          = _mm256_sub_pd(_t3, _y3); \
613         _t4          = _mm256_sub_pd(_t4, _y1); \
614         _t5          = _mm256_sub_pd(_t5, _x1); \
615         _t6          = _mm256_sub_pd(_t6, _x2); \
616         _t7          = _mm256_sub_pd(_t7, _z1); \
617         _t8          = _mm256_sub_pd(_t8, _z2); \
618         _tA          = _mm_sub_sd(_tA, _mm256_castpd256_pd128(_z3)); \
619         _tB          = _mm_sub_sd(_tB, _mm_permute_pd(_mm256_castpd256_pd128(_z3), _GMX_MM_PERMUTE128D(1, 1))); \
620         _tE          = _mm256_extractf128_pd(_z3, 0x1); \
621         _tC          = _mm_sub_sd(_tC, _tE); \
622         _tD          = _mm_sub_sd(_tD, _mm_permute_pd(_tE, _GMX_MM_PERMUTE128D(1, 1))); \
623         _mm256_storeu_pd(ptrA, _t1); \
624         _mm256_storeu_pd(ptrB, _t2); \
625         _mm256_storeu_pd(ptrC, _t3); \
626         _mm256_storeu_pd(ptrD, _t4); \
627         _mm256_storeu_pd(ptrA+4, _t5); \
628         _mm256_storeu_pd(ptrB+4, _t6); \
629         _mm256_storeu_pd(ptrC+4, _t7); \
630         _mm256_storeu_pd(ptrD+4, _t8); \
631         _mm_store_sd(ptrA+8, _tA); \
632         _mm_store_sd(ptrB+8, _tB); \
633         _mm_store_sd(ptrC+8, _tC); \
634         _mm_store_sd(ptrD+8, _tD); \
635     }
636 #else
637 /* Real function for sane compilers */
638 static void
639 gmx_mm256_decrement_3rvec_4ptr_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB,
640                                           double * gmx_restrict ptrC, double * gmx_restrict ptrD,
641                                           __m256d x1, __m256d y1, __m256d z1,
642                                           __m256d x2, __m256d y2, __m256d z2,
643                                           __m256d x3, __m256d y3, __m256d z3)
644 {
645     __m256d t1, t2, t3, t4, t5, t6, t7, t8, t9, t10;
646     __m128d tA, tB, tC, tD, tE;
647
648     t1          = _mm256_loadu_pd(ptrA);
649     t2          = _mm256_loadu_pd(ptrB);
650     t3          = _mm256_loadu_pd(ptrC);
651     t4          = _mm256_loadu_pd(ptrD);
652     t5          = _mm256_loadu_pd(ptrA+4);
653     t6          = _mm256_loadu_pd(ptrB+4);
654     t7          = _mm256_loadu_pd(ptrC+4);
655     t8          = _mm256_loadu_pd(ptrD+4);
656     tA          = _mm_load_sd(ptrA+8);
657     tB          = _mm_load_sd(ptrB+8);
658     tC          = _mm_load_sd(ptrC+8);
659     tD          = _mm_load_sd(ptrD+8);
660
661     t9          = _mm256_unpacklo_pd(x1, y1);       /* y1c x1c | y1a x1a */
662     x1          = _mm256_unpackhi_pd(x1, y1);       /* y1d x1d | y1b x1b */
663
664     y1          = _mm256_unpacklo_pd(z1, x2);       /* x2c z1c | x2a z1a */
665     z1          = _mm256_unpackhi_pd(z1, x2);       /* x2d z1d | x2b z1b */
666
667     x2          = _mm256_unpacklo_pd(y2, z2);       /* z2c y2c | z2a y2a */
668     y2          = _mm256_unpackhi_pd(y2, z2);       /* z2d y2d | z2b y2b */
669
670     z2          = _mm256_unpacklo_pd(x3, y3);       /* y3c x3c | y3a x3a */
671     x3          = _mm256_unpackhi_pd(x3, y3);       /* y3d x3d | y3b x3b */
672
673     t10         = gmx_mm256_unpack128lo_pd(t9, y1); /* x2a z1a | y1a x1a */
674     y3          = gmx_mm256_unpack128hi_pd(t9, y1); /* x2c z1c | y1c x1c */
675
676     t9          = gmx_mm256_unpack128lo_pd(x1, z1); /* x2b z1b | y1b x1b */
677     y1          = gmx_mm256_unpack128hi_pd(x1, z1); /* x2d z1d | y1d x1d */
678
679     x1          = gmx_mm256_unpack128lo_pd(x2, z2); /* y3a x3a | z2a y2a */
680     z1          = gmx_mm256_unpack128hi_pd(x2, z2); /* y3c x3c | z2c y2c */
681
682     x2          = gmx_mm256_unpack128lo_pd(y2, x3); /* y3b x3b | z2b y2b */
683     z2          = gmx_mm256_unpack128hi_pd(y2, x3); /* y3d x3d | z2d y2d */
684
685     t1          = _mm256_sub_pd(t1, t10);
686     t2          = _mm256_sub_pd(t2, t9);
687     t3          = _mm256_sub_pd(t3, y3);
688     t4          = _mm256_sub_pd(t4, y1);
689     t5          = _mm256_sub_pd(t5, x1);
690     t6          = _mm256_sub_pd(t6, x2);
691     t7          = _mm256_sub_pd(t7, z1);
692     t8          = _mm256_sub_pd(t8, z2);
693
694     tA          = _mm_sub_sd(tA, _mm256_castpd256_pd128(z3));
695     tB          = _mm_sub_sd(tB, _mm_permute_pd(_mm256_castpd256_pd128(z3), _GMX_MM_PERMUTE128D(1, 1)));
696     tE          = _mm256_extractf128_pd(z3, 0x1);
697     tC          = _mm_sub_sd(tC, tE);
698     tD          = _mm_sub_sd(tD, _mm_permute_pd(tE, _GMX_MM_PERMUTE128D(1, 1)));
699
700     /* Here we store a full 256-bit value and a separate 64-bit one; no overlap can happen */
701     _mm256_storeu_pd(ptrA, t1);
702     _mm256_storeu_pd(ptrB, t2);
703     _mm256_storeu_pd(ptrC, t3);
704     _mm256_storeu_pd(ptrD, t4);
705     _mm256_storeu_pd(ptrA+4, t5);
706     _mm256_storeu_pd(ptrB+4, t6);
707     _mm256_storeu_pd(ptrC+4, t7);
708     _mm256_storeu_pd(ptrD+4, t8);
709     _mm_store_sd(ptrA+8, tA);
710     _mm_store_sd(ptrB+8, tB);
711     _mm_store_sd(ptrC+8, tC);
712     _mm_store_sd(ptrD+8, tD);
713 }
714 #endif
715
716 #if defined (_MSC_VER) && defined(_M_IX86)
717 /* Macro work-around since 32-bit MSVC cannot handle >3 xmm/ymm parameters */
718 #define gmx_mm256_decrement_4rvec_4ptr_swizzle_pd(ptrA, ptrB, ptrC, ptrD, \
719                                                   _x1, _y1, _z1, _x2, _y2, _z2, _x3, _y3, _z3, _x4, _y4, _z4) \
720     { \
721         __m256d _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9, _t10, _t11, _t12, _t13, _t14; \
722         __m128d _tA, _tB, _tC, _tD, _tE; \
723         _t1          = _mm256_loadu_pd(ptrA); \
724         _t2          = _mm256_loadu_pd(ptrB); \
725         _t3          = _mm256_loadu_pd(ptrC); \
726         _t4          = _mm256_loadu_pd(ptrD); \
727         _t5          = _mm256_loadu_pd(ptrA+4); \
728         _t6          = _mm256_loadu_pd(ptrB+4); \
729         _t7          = _mm256_loadu_pd(ptrC+4); \
730         _t8          = _mm256_loadu_pd(ptrD+4); \
731         _t9          = _mm256_loadu_pd(ptrA+8); \
732         _t10         = _mm256_loadu_pd(ptrB+8); \
733         _t11         = _mm256_loadu_pd(ptrC+8); \
734         _t12         = _mm256_loadu_pd(ptrD+8); \
735         _t13         = _mm256_unpacklo_pd(_x1, _y1); \
736         _x1          = _mm256_unpackhi_pd(_x1, _y1); \
737         _y1          = _mm256_unpacklo_pd(_z1, _x2); \
738         _z1          = _mm256_unpackhi_pd(_z1, _x2); \
739         _x2          = _mm256_unpacklo_pd(_y2, _z2); \
740         _y2          = _mm256_unpackhi_pd(_y2, _z2); \
741         _z2          = _mm256_unpacklo_pd(_x3, _y3); \
742         _x3          = _mm256_unpackhi_pd(_x3, _y3); \
743         _y3          = _mm256_unpacklo_pd(_z3, _x4); \
744         _z3          = _mm256_unpackhi_pd(_z3, _x4); \
745         _x4          = _mm256_unpacklo_pd(_y4, _z4); \
746         _y4          = _mm256_unpackhi_pd(_y4, _z4); \
747         _z4          = gmx_mm256_unpack128lo_pd(_t13, _y1); \
748         _t13         = gmx_mm256_unpack128hi_pd(_t13, _y1); \
749         _y1          = gmx_mm256_unpack128lo_pd(_x1, _z1); \
750         _x1          = gmx_mm256_unpack128hi_pd(_x1, _z1); \
751         _z1          = gmx_mm256_unpack128lo_pd(_x2, _z2); \
752         _x2          = gmx_mm256_unpack128hi_pd(_x2, _z2); \
753         _z2          = gmx_mm256_unpack128lo_pd(_y2, _x3); \
754         _y2          = gmx_mm256_unpack128hi_pd(_y2, _x3); \
755         _x3          = gmx_mm256_unpack128lo_pd(_y3, _x4); \
756         _y3          = gmx_mm256_unpack128hi_pd(_y3, _x4); \
757         _x4          = gmx_mm256_unpack128lo_pd(_z3, _y4); \
758         _z3          = gmx_mm256_unpack128hi_pd(_z3, _y4); \
759         _t1          = _mm256_sub_pd(_t1, _z4); \
760         _t2          = _mm256_sub_pd(_t2, _y1); \
761         _t3          = _mm256_sub_pd(_t3, _t13); \
762         _t4          = _mm256_sub_pd(_t4, _x1); \
763         _t5          = _mm256_sub_pd(_t5, _z1); \
764         _t6          = _mm256_sub_pd(_t6, _z2); \
765         _t7          = _mm256_sub_pd(_t7, _x2); \
766         _t8          = _mm256_sub_pd(_t8, _y2); \
767         _t9          = _mm256_sub_pd(_t9, _x3); \
768         _t10         = _mm256_sub_pd(_t10, _x4); \
769         _t11         = _mm256_sub_pd(_t11, _y3); \
770         _t12         = _mm256_sub_pd(_t12, _z3); \
771         _mm256_storeu_pd(ptrA, _t1); \
772         _mm256_storeu_pd(ptrB, _t2); \
773         _mm256_storeu_pd(ptrC, _t3); \
774         _mm256_storeu_pd(ptrD, _t4); \
775         _mm256_storeu_pd(ptrA+4, _t5); \
776         _mm256_storeu_pd(ptrB+4, _t6); \
777         _mm256_storeu_pd(ptrC+4, _t7); \
778         _mm256_storeu_pd(ptrD+4, _t8); \
779         _mm256_storeu_pd(ptrA+8, _t9); \
780         _mm256_storeu_pd(ptrB+8, _t10); \
781         _mm256_storeu_pd(ptrC+8, _t11); \
782         _mm256_storeu_pd(ptrD+8, _t12); \
783     }
784 #else
785 /* Real function for sane compilers */
786 static void
787 gmx_mm256_decrement_4rvec_4ptr_swizzle_pd(double * gmx_restrict ptrA, double * gmx_restrict ptrB,
788                                           double * gmx_restrict ptrC, double * gmx_restrict ptrD,
789                                           __m256d x1, __m256d y1, __m256d z1,
790                                           __m256d x2, __m256d y2, __m256d z2,
791                                           __m256d x3, __m256d y3, __m256d z3,
792                                           __m256d x4, __m256d y4, __m256d z4)
793 {
794     __m256d t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14;
795     __m128d tA, tB, tC, tD, tE;
796
797     t1          = _mm256_loadu_pd(ptrA);
798     t2          = _mm256_loadu_pd(ptrB);
799     t3          = _mm256_loadu_pd(ptrC);
800     t4          = _mm256_loadu_pd(ptrD);
801     t5          = _mm256_loadu_pd(ptrA+4);
802     t6          = _mm256_loadu_pd(ptrB+4);
803     t7          = _mm256_loadu_pd(ptrC+4);
804     t8          = _mm256_loadu_pd(ptrD+4);
805     t9          = _mm256_loadu_pd(ptrA+8);
806     t10         = _mm256_loadu_pd(ptrB+8);
807     t11         = _mm256_loadu_pd(ptrC+8);
808     t12         = _mm256_loadu_pd(ptrD+8);
809
810     t13         = _mm256_unpacklo_pd(x1, y1);        /* y1c x1c | y1a x1a */
811     x1          = _mm256_unpackhi_pd(x1, y1);        /* y1d x1d | y1b x1b */
812     y1          = _mm256_unpacklo_pd(z1, x2);        /* x2c z1c | x2a z1a */
813     z1          = _mm256_unpackhi_pd(z1, x2);        /* x2d z1d | x2b z1b */
814     x2          = _mm256_unpacklo_pd(y2, z2);        /* z2c y2c | z2a y2a */
815     y2          = _mm256_unpackhi_pd(y2, z2);        /* z2d y2d | z2b y2b */
816     z2          = _mm256_unpacklo_pd(x3, y3);        /* y3c x3c | y3a x3a */
817     x3          = _mm256_unpackhi_pd(x3, y3);        /* y3d x3d | y3b x3b */
818     y3          = _mm256_unpacklo_pd(z3, x4);        /* x4c z3c | x4a z3a */
819     z3          = _mm256_unpackhi_pd(z3, x4);        /* x4d z3d | x4b z3b */
820     x4          = _mm256_unpacklo_pd(y4, z4);        /* z4c y4c | z4a y4a */
821     y4          = _mm256_unpackhi_pd(y4, z4);        /* z4d y4d | z4b y4b */
822
823     z4          = gmx_mm256_unpack128lo_pd(t13, y1); /* x2a z1a | y1a x1a */
824     t13         = gmx_mm256_unpack128hi_pd(t13, y1); /* x2c z1c | y1c x1c */
825     y1          = gmx_mm256_unpack128lo_pd(x1, z1);  /* x2b z1b | y1b x1b */
826     x1          = gmx_mm256_unpack128hi_pd(x1, z1);  /* x2d z1d | y1d x1d */
827     z1          = gmx_mm256_unpack128lo_pd(x2, z2);  /* y3a x3a | z2a y2a */
828     x2          = gmx_mm256_unpack128hi_pd(x2, z2);  /* y3c x3c | z2c y2c */
829     z2          = gmx_mm256_unpack128lo_pd(y2, x3);  /* y3b x3b | z2b y2b */
830     y2          = gmx_mm256_unpack128hi_pd(y2, x3);  /* y3d x3d | z2d y2d */
831     x3          = gmx_mm256_unpack128lo_pd(y3, x4);  /* z4a y4a | x4a z3a */
832     y3          = gmx_mm256_unpack128hi_pd(y3, x4);  /* z4c y4c | x4c z3c */
833     x4          = gmx_mm256_unpack128lo_pd(z3, y4);  /* z4b y4b | x4b z3b */
834     z3          = gmx_mm256_unpack128hi_pd(z3, y4);  /* z4d y4d | x4d z3d */
835
836     t1          = _mm256_sub_pd(t1, z4);
837     t2          = _mm256_sub_pd(t2, y1);
838     t3          = _mm256_sub_pd(t3, t13);
839     t4          = _mm256_sub_pd(t4, x1);
840     t5          = _mm256_sub_pd(t5, z1);
841     t6          = _mm256_sub_pd(t6, z2);
842     t7          = _mm256_sub_pd(t7, x2);
843     t8          = _mm256_sub_pd(t8, y2);
844     t9          = _mm256_sub_pd(t9, x3);
845     t10         = _mm256_sub_pd(t10, x4);
846     t11         = _mm256_sub_pd(t11, y3);
847     t12         = _mm256_sub_pd(t12, z3);
848
849     /* Here we store a full 256-bit value and a separate 128-bit one; no overlap can happen */
850     _mm256_storeu_pd(ptrA, t1);
851     _mm256_storeu_pd(ptrB, t2);
852     _mm256_storeu_pd(ptrC, t3);
853     _mm256_storeu_pd(ptrD, t4);
854     _mm256_storeu_pd(ptrA+4, t5);
855     _mm256_storeu_pd(ptrB+4, t6);
856     _mm256_storeu_pd(ptrC+4, t7);
857     _mm256_storeu_pd(ptrD+4, t8);
858     _mm256_storeu_pd(ptrA+8, t9);
859     _mm256_storeu_pd(ptrB+8, t10);
860     _mm256_storeu_pd(ptrC+8, t11);
861     _mm256_storeu_pd(ptrD+8, t12);
862 }
863 #endif
864
865
866
867
868
869 static gmx_inline void
870 gmx_mm256_update_iforce_1atom_swizzle_pd(__m256d fix1, __m256d fiy1, __m256d fiz1,
871                                          double * gmx_restrict fptr,
872                                          double * gmx_restrict fshiftptr)
873 {
874     __m256d t1, t2;
875     __m128d tA, tB;
876     fix1 = _mm256_hadd_pd(fix1, fiy1);
877     fiz1 = _mm256_hadd_pd(fiz1, _mm256_setzero_pd());
878
879     /* Add across the two lanes */
880     tA   = _mm_add_pd(_mm256_castpd256_pd128(fix1), _mm256_extractf128_pd(fix1, 0x1));
881     tB   = _mm_add_pd(_mm256_castpd256_pd128(fiz1), _mm256_extractf128_pd(fiz1, 0x1));
882
883     fix1 = gmx_mm256_set_m128d(tB, tA); /* 0 fiz fiy fix */
884
885     t1   = _mm256_loadu_pd(fptr);
886     t2   = _mm256_loadu_pd(fshiftptr);
887
888     t1   = _mm256_add_pd(t1, fix1);
889     t2   = _mm256_add_pd(t2, fix1);
890
891     _mm256_storeu_pd(fptr, t1);
892     _mm256_storeu_pd(fshiftptr, t2);
893 }
894
895
896
897 #if defined (_MSC_VER) && defined(_M_IX86)
898 /* Macro work-around since 32-bit MSVC cannot handle >3 xmm/ymm parameters */
899 #define gmx_mm256_update_iforce_3atom_swizzle_pd(fix1, fiy1, fiz1, fix2, fiy2, fiz2, fix3, fiy3, fiz3, \
900                                                  fptr, fshiftptr) \
901     { \
902         __m256d _t1, _t2, _t3, _t4; \
903         __m128d _tz3, _tA, _tB, _tC, _tD; \
904         fix1  = _mm256_hadd_pd(fix1, fiy1); \
905         fiz1  = _mm256_hadd_pd(fiz1, fix2); \
906         fiy2  = _mm256_hadd_pd(fiy2, fiz2); \
907         fix3  = _mm256_hadd_pd(fix3, fiy3); \
908         fiz3  = _mm256_hadd_pd(fiz3, _mm256_setzero_pd()); \
909         _t1   = gmx_mm256_unpack128lo_pd(fix1, fiz1); \
910         _t2   = gmx_mm256_unpack128hi_pd(fix1, fiz1); \
911         _t1   = _mm256_add_pd(_t1, _t2); \
912         _t3   = gmx_mm256_unpack128lo_pd(fiy2, fix3); \
913         _t4   = gmx_mm256_unpack128hi_pd(fiy2, fix3); \
914         _t3   = _mm256_add_pd(_t3, _t4); \
915         _tz3  = _mm_add_pd(_mm256_castpd256_pd128(fiz3), _mm256_extractf128_pd(fiz3, 0x1)); \
916         _t2   = _mm256_loadu_pd(fptr); \
917         _t4   = _mm256_loadu_pd(fptr+4); \
918         _tA   = _mm_load_sd(fptr+8); \
919         _t2   = _mm256_add_pd(_t2, _t1); \
920         _t4   = _mm256_add_pd(_t4, _t3); \
921         _tA   = _mm_add_sd(_tA, _tz3); \
922         _mm256_storeu_pd(fptr, _t2); \
923         _mm256_storeu_pd(fptr+4, _t4); \
924         _mm_store_sd(fptr+8, _tA); \
925         _tB   = _mm256_extractf128_pd(_t1, 0x1); \
926         _tC   = _mm256_extractf128_pd(_t3, 0x1); \
927         _tz3  = _mm_add_sd(_tz3, _tB); \
928         _tD   = _mm_permute_pd(_mm256_castpd256_pd128(_t3), _GMX_MM_PERMUTE128D(1, 1)); \
929         _tz3  = _mm_add_sd(_tz3, _tD); \
930         _tC   = _mm_add_pd(_tC, _mm256_castpd256_pd128(_t1)); \
931         _tD   = _mm_shuffle_pd(_tB, _mm256_castpd256_pd128(_t3), _MM_SHUFFLE2(0, 1)); \
932         _tC   = _mm_add_pd(_tC, _tD); \
933         _tA   = _mm_loadu_pd(fshiftptr); \
934         _tB   = _mm_load_sd(fshiftptr+2); \
935         _tA   = _mm_add_pd(_tA, _tC); \
936         _tB   = _mm_add_sd(_tB, _tz3); \
937         _mm_storeu_pd(fshiftptr, _tA); \
938         _mm_store_sd(fshiftptr+2, _tB); \
939     }
940 #else
941 /* Real function for sane compilers */
942 static gmx_inline void
943 gmx_mm256_update_iforce_3atom_swizzle_pd(__m256d fix1, __m256d fiy1, __m256d fiz1,
944                                          __m256d fix2, __m256d fiy2, __m256d fiz2,
945                                          __m256d fix3, __m256d fiy3, __m256d fiz3,
946                                          double * gmx_restrict fptr,
947                                          double * gmx_restrict fshiftptr)
948 {
949     __m256d t1, t2, t3, t4;
950     __m128d tz3, tA, tB, tC, tD;
951
952     fix1 = _mm256_hadd_pd(fix1, fiy1);                /*  Y1c-d X1c-d | Y1a-b X1a-b */
953     fiz1 = _mm256_hadd_pd(fiz1, fix2);                /*  X2c-d Z1c-d | X2a-b Z1a-b */
954     fiy2 = _mm256_hadd_pd(fiy2, fiz2);                /*  Z2c-d Y2c-d | Z2a-b Y2a-b */
955     fix3 = _mm256_hadd_pd(fix3, fiy3);                /*  Y3c-d X3c-d | Y3a-b X3a-b */
956     fiz3 = _mm256_hadd_pd(fiz3, _mm256_setzero_pd()); /*  0     Z3c-d | 0     Z3a-b */
957
958     /* Add across the two lanes by swapping and adding back */
959     t1   = gmx_mm256_unpack128lo_pd(fix1, fiz1);                                       /* X2a-b Z1a-b | Y1a-b X1a-b */
960     t2   = gmx_mm256_unpack128hi_pd(fix1, fiz1);                                       /* X2c-d Z1c-d | Y1c-d X1c-d */
961     t1   = _mm256_add_pd(t1, t2);                                                      /* x2 z1 | y1 x1 */
962
963     t3   = gmx_mm256_unpack128lo_pd(fiy2, fix3);                                       /* Y3a-b X3a-b | Z2a-b Y2a-b */
964     t4   = gmx_mm256_unpack128hi_pd(fiy2, fix3);                                       /* Y3c-d X3c-d | Z2c-d Y2c-d */
965     t3   = _mm256_add_pd(t3, t4);                                                      /* y3 x3 | z2 y2 */
966
967     tz3  = _mm_add_pd(_mm256_castpd256_pd128(fiz3), _mm256_extractf128_pd(fiz3, 0x1)); /* 0 z3 */
968
969     t2   = _mm256_loadu_pd(fptr);
970     t4   = _mm256_loadu_pd(fptr+4);
971     tA   = _mm_load_sd(fptr+8);
972
973     t2   = _mm256_add_pd(t2, t1);
974     t4   = _mm256_add_pd(t4, t3);
975     tA   = _mm_add_sd(tA, tz3);
976
977     _mm256_storeu_pd(fptr, t2);
978     _mm256_storeu_pd(fptr+4, t4);
979     _mm_store_sd(fptr+8, tA);
980
981     /* Add up shift force */
982     /* t1:   x2 z1 | y1 x1 */
983     /* t3:   y3 x3 | z2 y2 */
984     /* tz3:           0 z3 */
985
986     /* z component */
987     tB   = _mm256_extractf128_pd(t1, 0x1);                                     /* x2 z1 */
988     tC   = _mm256_extractf128_pd(t3, 0x1);                                     /* y3 x3 */
989     tz3  = _mm_add_sd(tz3, tB);                                                /* 0  z1+z3 */
990     tD   = _mm_permute_pd(_mm256_castpd256_pd128(t3), _GMX_MM_PERMUTE128D(1, 1));
991     tz3  = _mm_add_sd(tz3, tD);                                                /* - z */
992
993     tC   = _mm_add_pd(tC, _mm256_castpd256_pd128(t1));                         /* y1+y3 x1+x3 */
994
995     tD   = _mm_shuffle_pd(tB, _mm256_castpd256_pd128(t3), _MM_SHUFFLE2(0, 1)); /* y2 x2 */
996     tC   = _mm_add_pd(tC, tD);                                                 /* y x */
997
998     tA   = _mm_loadu_pd(fshiftptr);
999     tB   = _mm_load_sd(fshiftptr+2);
1000     tA   = _mm_add_pd(tA, tC);
1001     tB   = _mm_add_sd(tB, tz3);
1002     _mm_storeu_pd(fshiftptr, tA);
1003     _mm_store_sd(fshiftptr+2, tB);
1004 }
1005 #endif
1006
1007
1008 #if defined (_MSC_VER) && defined(_M_IX86)
1009 /* Macro work-around since 32-bit MSVC cannot handle >3 xmm/ymm parameters */
1010 #define gmx_mm256_update_iforce_4atom_swizzle_pd(fix1, fiy1, fiz1, fix2, fiy2, fiz2, fix3, fiy3, fiz3, fix4, fiy4, fiz4, \
1011                                                  fptr, fshiftptr) \
1012     { \
1013         __m256d _t1, _t2, _t3, _t4, _t5, _t6; \
1014         __m128d _tA, _tB, _tC, _tD; \
1015         fix1  = _mm256_hadd_pd(fix1, fiy1); \
1016         fiz1  = _mm256_hadd_pd(fiz1, fix2); \
1017         fiy2  = _mm256_hadd_pd(fiy2, fiz2); \
1018         fix3  = _mm256_hadd_pd(fix3, fiy3); \
1019         fiz3  = _mm256_hadd_pd(fiz3, fix4); \
1020         fiy4  = _mm256_hadd_pd(fiy4, fiz4); \
1021         _t1   = gmx_mm256_unpack128lo_pd(fix1, fiz1); \
1022         _t2   = gmx_mm256_unpack128hi_pd(fix1, fiz1); \
1023         _t1   = _mm256_add_pd(_t1, _t2); \
1024         _t3   = gmx_mm256_unpack128lo_pd(fiy2, fix3); \
1025         _t4   = gmx_mm256_unpack128hi_pd(fiy2, fix3); \
1026         _t3   = _mm256_add_pd(_t3, _t4); \
1027         _t5   = gmx_mm256_unpack128lo_pd(fiz3, fiy4); \
1028         _t6   = gmx_mm256_unpack128hi_pd(fiz3, fiy4); \
1029         _t5   = _mm256_add_pd(_t5, _t6); \
1030         _t2   = _mm256_loadu_pd(fptr); \
1031         _t4   = _mm256_loadu_pd(fptr+4); \
1032         _t6   = _mm256_loadu_pd(fptr+8); \
1033         _t2   = _mm256_add_pd(_t2, _t1); \
1034         _t4   = _mm256_add_pd(_t4, _t3); \
1035         _t6   = _mm256_add_pd(_t6, _t5); \
1036         _mm256_storeu_pd(fptr, _t2); \
1037         _mm256_storeu_pd(fptr+4, _t4); \
1038         _mm256_storeu_pd(fptr+8, _t6); \
1039         _tA   = _mm256_extractf128_pd(_t1, 0x1); \
1040         _tB   = _mm256_extractf128_pd(_t3, 0x1); \
1041         _tC   = _mm256_extractf128_pd(_t5, 0x1); \
1042         _tB   = _mm_add_pd(_tB, _mm256_castpd256_pd128(_t1)); \
1043         _tA   = _mm_add_pd(_tA, _mm256_castpd256_pd128(_t5)); \
1044         _tC   = _mm_add_pd(_tC, _mm256_castpd256_pd128(_t3)); \
1045         _tD   = _mm_shuffle_pd(_tA, _tC, _MM_SHUFFLE2(0, 1)); \
1046         _tB   = _mm_add_pd(_tB, _tD); \
1047         _tC   = _mm_permute_pd(_tC, _GMX_MM_PERMUTE128D(1, 1)); \
1048         _tC   = _mm_add_sd(_tC, _tA); \
1049         _tA   = _mm_loadu_pd(fshiftptr); \
1050         _tD   = _mm_load_sd(fshiftptr+2); \
1051         _tA   = _mm_add_pd(_tA, _tB); \
1052         _tD   = _mm_add_sd(_tD, _tC); \
1053         _mm_storeu_pd(fshiftptr, _tA); \
1054         _mm_store_sd(fshiftptr+2, _tD); \
1055     }
1056 #else
1057 /* Real function for sane compilers */
1058 static gmx_inline void
1059 gmx_mm256_update_iforce_4atom_swizzle_pd(__m256d fix1, __m256d fiy1, __m256d fiz1,
1060                                          __m256d fix2, __m256d fiy2, __m256d fiz2,
1061                                          __m256d fix3, __m256d fiy3, __m256d fiz3,
1062                                          __m256d fix4, __m256d fiy4, __m256d fiz4,
1063                                          double * gmx_restrict fptr,
1064                                          double * gmx_restrict fshiftptr)
1065 {
1066     __m256d t1, t2, t3, t4, t5, t6;
1067     __m128d tA, tB, tC, tD;
1068
1069     fix1 = _mm256_hadd_pd(fix1, fiy1);                /*  Y1c-d X1c-d | Y1a-b X1a-b */
1070     fiz1 = _mm256_hadd_pd(fiz1, fix2);                /*  X2c-d Z1c-d | X2a-b Z1a-b */
1071     fiy2 = _mm256_hadd_pd(fiy2, fiz2);                /*  Z2c-d Y2c-d | Z2a-b Y2a-b */
1072     fix3 = _mm256_hadd_pd(fix3, fiy3);                /*  Y3c-d X3c-d | Y3a-b X3a-b */
1073     fiz3 = _mm256_hadd_pd(fiz3, fix4);                /*  X4c-d Z3c-d | X4a-b Z3a-b */
1074     fiy4 = _mm256_hadd_pd(fiy4, fiz4);                /*  Z4c-d Y4c-d | Z4a-b Y4a-b */
1075
1076     /* Add across the two lanes by swapping and adding back */
1077     t1   = gmx_mm256_unpack128lo_pd(fix1, fiz1); /* X2a-b Z1a-b | Y1a-b X1a-b */
1078     t2   = gmx_mm256_unpack128hi_pd(fix1, fiz1); /* X2c-d Z1c-d | Y1c-d X1c-d */
1079     t1   = _mm256_add_pd(t1, t2);                /* x2 z1 | y1 x1 */
1080
1081     t3   = gmx_mm256_unpack128lo_pd(fiy2, fix3); /* Y3a-b X3a-b | Z2a-b Y2a-b */
1082     t4   = gmx_mm256_unpack128hi_pd(fiy2, fix3); /* Y3c-d X3c-d | Z2c-d Y2c-d */
1083     t3   = _mm256_add_pd(t3, t4);                /* y3 x3 | z2 y2 */
1084
1085     t5   = gmx_mm256_unpack128lo_pd(fiz3, fiy4); /* Z4a-b Y4a-b | X4a-b Z3a-b */
1086     t6   = gmx_mm256_unpack128hi_pd(fiz3, fiy4); /* Z4c-d Y4c-d | X4c-d Z3c-d */
1087     t5   = _mm256_add_pd(t5, t6);                /* z4 y4 | x4 z3 */
1088
1089     t2   = _mm256_loadu_pd(fptr);
1090     t4   = _mm256_loadu_pd(fptr+4);
1091     t6   = _mm256_loadu_pd(fptr+8);
1092
1093     t2   = _mm256_add_pd(t2, t1);
1094     t4   = _mm256_add_pd(t4, t3);
1095     t6   = _mm256_add_pd(t6, t5);
1096
1097     _mm256_storeu_pd(fptr, t2);
1098     _mm256_storeu_pd(fptr+4, t4);
1099     _mm256_storeu_pd(fptr+8, t6);
1100
1101     /* Add up shift force  */
1102     /* t1:   x2. z1. | y1. x1. */
1103     /* t3:   y3. x3. | z2 y2 */
1104     /* t5:   z4 y4 | x4. z3. */
1105
1106     /* z component */
1107     tA   = _mm256_extractf128_pd(t1, 0x1);                /* x2 z1 */
1108     tB   = _mm256_extractf128_pd(t3, 0x1);                /* y3 x3 */
1109     tC   = _mm256_extractf128_pd(t5, 0x1);                /* z4 y4 */
1110
1111     tB   = _mm_add_pd(tB, _mm256_castpd256_pd128(t1));    /*  y1+y3  x1+x3 */
1112     tA   = _mm_add_pd(tA, _mm256_castpd256_pd128(t5));    /*  x2+x4  z1+z3 */
1113     tC   = _mm_add_pd(tC, _mm256_castpd256_pd128(t3));    /*  z4+z2  y4+y2 */
1114
1115     tD   = _mm_shuffle_pd(tA, tC, _MM_SHUFFLE2(0, 1));    /* y4+y2 x2+x4 */
1116     tB   = _mm_add_pd(tB, tD);                            /* y x */
1117     tC   = _mm_permute_pd(tC, _GMX_MM_PERMUTE128D(1, 1)); /*    - z4+z2 */
1118     tC   = _mm_add_sd(tC, tA);                            /* - z */
1119
1120     tA   = _mm_loadu_pd(fshiftptr);
1121     tD   = _mm_load_sd(fshiftptr+2);
1122     tA   = _mm_add_pd(tA, tB);
1123     tD   = _mm_add_sd(tD, tC);
1124     _mm_storeu_pd(fshiftptr, tA);
1125     _mm_store_sd(fshiftptr+2, tD);
1126 }
1127 #endif
1128
1129
1130
1131 static void
1132 gmx_mm256_update_1pot_pd(__m256d pot1, double * gmx_restrict ptrA)
1133 {
1134     __m128d t1;
1135
1136     pot1 = _mm256_hadd_pd(pot1, pot1);
1137
1138     t1   = _mm_add_pd(_mm256_castpd256_pd128(pot1), _mm256_extractf128_pd(pot1, 0x1));
1139
1140     _mm_store_sd(ptrA, _mm_add_sd(_mm_load_sd(ptrA), t1));
1141 }
1142
1143 static void
1144 gmx_mm256_update_2pot_pd(__m256d pot1, double * gmx_restrict ptrA,
1145                          __m256d pot2, double * gmx_restrict ptrB)
1146 {
1147     __m128d t1, t2;
1148
1149     pot1 = _mm256_hadd_pd(pot1, pot2);
1150
1151     t1   = _mm_add_pd(_mm256_castpd256_pd128(pot1), _mm256_extractf128_pd(pot1, 0x1));
1152
1153     t2   = _mm_permute_pd(t1, _GMX_MM_PERMUTE128D(1, 1));
1154     _mm_store_sd(ptrA, _mm_add_sd(_mm_load_sd(ptrA), t1));
1155     _mm_store_sd(ptrB, _mm_add_sd(_mm_load_sd(ptrB), t2));
1156 }
1157
1158
1159 #endif /* _kernelutil_x86_avx_256_double_h_ */