Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / simd / impl_x86_avx_128_fma / impl_x86_avx_128_fma_simd4_double.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2017,2019, 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_128_FMA_SIMD4_DOUBLE_H
37 #define GMX_SIMD_IMPL_X86_AVX_128_FMA_SIMD4_DOUBLE_H
38
39 #include "config.h"
40
41 #include <cassert>
42 #include <cstddef>
43
44 #include <immintrin.h>
45 #include <x86intrin.h>
46
47 namespace gmx
48 {
49
50 class Simd4Double
51 {
52 public:
53     Simd4Double() {}
54
55     Simd4Double(double d) : simdInternal_(_mm256_set1_pd(d)) {}
56
57     // Internal utility constructor to simplify return statements
58     Simd4Double(__m256d simd) : simdInternal_(simd) {}
59
60     __m256d simdInternal_;
61 };
62
63 class Simd4DBool
64 {
65 public:
66     Simd4DBool() {}
67
68     //! \brief Construct from scalar bool
69     Simd4DBool(bool b) : simdInternal_(_mm256_castsi256_pd(_mm256_set1_epi32(b ? 0xFFFFFFFF : 0)))
70     {
71     }
72
73     // Internal utility constructor to simplify return statements
74     Simd4DBool(__m256d simd) : simdInternal_(simd) {}
75
76     __m256d simdInternal_;
77 };
78
79 static inline Simd4Double gmx_simdcall load4(const double* m)
80 {
81     assert(size_t(m) % 32 == 0);
82     return { _mm256_load_pd(m) };
83 }
84
85 static inline void gmx_simdcall store4(double* m, Simd4Double a)
86 {
87     assert(size_t(m) % 32 == 0);
88     _mm256_store_pd(m, a.simdInternal_);
89 }
90
91 static inline Simd4Double gmx_simdcall load4U(const double* m)
92 {
93     return { _mm256_loadu_pd(m) };
94 }
95
96 static inline void gmx_simdcall store4U(double* m, Simd4Double a)
97 {
98     _mm256_storeu_pd(m, a.simdInternal_);
99 }
100
101 static inline Simd4Double gmx_simdcall simd4SetZeroD()
102 {
103     return { _mm256_setzero_pd() };
104 }
105
106 static inline Simd4Double gmx_simdcall operator&(Simd4Double a, Simd4Double b)
107 {
108     return { _mm256_and_pd(a.simdInternal_, b.simdInternal_) };
109 }
110
111 static inline Simd4Double gmx_simdcall andNot(Simd4Double a, Simd4Double b)
112 {
113     return { _mm256_andnot_pd(a.simdInternal_, b.simdInternal_) };
114 }
115
116 static inline Simd4Double gmx_simdcall operator|(Simd4Double a, Simd4Double b)
117 {
118     return { _mm256_or_pd(a.simdInternal_, b.simdInternal_) };
119 }
120
121 static inline Simd4Double gmx_simdcall operator^(Simd4Double a, Simd4Double b)
122 {
123     return { _mm256_xor_pd(a.simdInternal_, b.simdInternal_) };
124 }
125
126 static inline Simd4Double gmx_simdcall operator+(Simd4Double a, Simd4Double b)
127 {
128     return { _mm256_add_pd(a.simdInternal_, b.simdInternal_) };
129 }
130
131 static inline Simd4Double gmx_simdcall operator-(Simd4Double a, Simd4Double b)
132 {
133     return { _mm256_sub_pd(a.simdInternal_, b.simdInternal_) };
134 }
135
136 static inline Simd4Double gmx_simdcall operator-(Simd4Double x)
137 {
138     return { _mm256_xor_pd(x.simdInternal_, _mm256_set1_pd(GMX_DOUBLE_NEGZERO)) };
139 }
140
141 static inline Simd4Double gmx_simdcall operator*(Simd4Double a, Simd4Double b)
142 {
143     return { _mm256_mul_pd(a.simdInternal_, b.simdInternal_) };
144 }
145
146 static inline Simd4Double gmx_simdcall fma(Simd4Double a, Simd4Double b, Simd4Double c)
147 {
148     return { _mm256_macc_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
149 }
150
151 static inline Simd4Double gmx_simdcall fms(Simd4Double a, Simd4Double b, Simd4Double c)
152 {
153     return { _mm256_msub_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
154 }
155
156 static inline Simd4Double gmx_simdcall fnma(Simd4Double a, Simd4Double b, Simd4Double c)
157 {
158     return { _mm256_nmacc_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
159 }
160
161 static inline Simd4Double gmx_simdcall fnms(Simd4Double a, Simd4Double b, Simd4Double c)
162 {
163     return { _mm256_nmsub_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
164 }
165
166 static inline Simd4Double gmx_simdcall rsqrt(Simd4Double x)
167 {
168     return { _mm256_cvtps_pd(_mm_rsqrt_ps(_mm256_cvtpd_ps(x.simdInternal_))) };
169 }
170
171 static inline Simd4Double gmx_simdcall abs(Simd4Double x)
172 {
173     return { _mm256_andnot_pd(_mm256_set1_pd(GMX_DOUBLE_NEGZERO), x.simdInternal_) };
174 }
175
176 static inline Simd4Double gmx_simdcall max(Simd4Double a, Simd4Double b)
177 {
178     return { _mm256_max_pd(a.simdInternal_, b.simdInternal_) };
179 }
180
181 static inline Simd4Double gmx_simdcall min(Simd4Double a, Simd4Double b)
182 {
183     return { _mm256_min_pd(a.simdInternal_, b.simdInternal_) };
184 }
185
186 static inline Simd4Double gmx_simdcall round(Simd4Double x)
187 {
188     return { _mm256_round_pd(x.simdInternal_, _MM_FROUND_NINT) };
189 }
190
191 static inline Simd4Double gmx_simdcall trunc(Simd4Double x)
192 {
193     return { _mm256_round_pd(x.simdInternal_, _MM_FROUND_TRUNC) };
194 }
195
196 static inline double gmx_simdcall dotProduct(Simd4Double a, Simd4Double b)
197 {
198     __m128d tmp1, tmp2;
199     a.simdInternal_ = _mm256_mul_pd(a.simdInternal_, b.simdInternal_);
200     tmp1            = _mm256_castpd256_pd128(a.simdInternal_);
201     tmp2            = _mm256_extractf128_pd(a.simdInternal_, 0x1);
202
203     tmp1 = _mm_add_pd(tmp1, _mm_permute_pd(tmp1, _MM_SHUFFLE2(0, 1)));
204     tmp1 = _mm_add_pd(tmp1, tmp2);
205     return *reinterpret_cast<double*>(&tmp1);
206 }
207
208 static inline void gmx_simdcall transpose(Simd4Double* v0, Simd4Double* v1, Simd4Double* v2, Simd4Double* v3)
209 {
210     __m256d t1, t2, t3, t4;
211     t1                = _mm256_unpacklo_pd(v0->simdInternal_, v1->simdInternal_);
212     t2                = _mm256_unpackhi_pd(v0->simdInternal_, v1->simdInternal_);
213     t3                = _mm256_unpacklo_pd(v2->simdInternal_, v3->simdInternal_);
214     t4                = _mm256_unpackhi_pd(v2->simdInternal_, v3->simdInternal_);
215     v0->simdInternal_ = _mm256_permute2f128_pd(t1, t3, 0x20);
216     v1->simdInternal_ = _mm256_permute2f128_pd(t2, t4, 0x20);
217     v2->simdInternal_ = _mm256_permute2f128_pd(t1, t3, 0x31);
218     v3->simdInternal_ = _mm256_permute2f128_pd(t2, t4, 0x31);
219 }
220
221 static inline Simd4DBool gmx_simdcall operator==(Simd4Double a, Simd4Double b)
222 {
223     return { _mm256_cmp_pd(a.simdInternal_, b.simdInternal_, _CMP_EQ_OQ) };
224 }
225
226 static inline Simd4DBool gmx_simdcall operator!=(Simd4Double a, Simd4Double b)
227 {
228     return { _mm256_cmp_pd(a.simdInternal_, b.simdInternal_, _CMP_NEQ_OQ) };
229 }
230
231 static inline Simd4DBool gmx_simdcall operator<(Simd4Double a, Simd4Double b)
232 {
233     return { _mm256_cmp_pd(a.simdInternal_, b.simdInternal_, _CMP_LT_OQ) };
234 }
235
236 static inline Simd4DBool gmx_simdcall operator<=(Simd4Double a, Simd4Double b)
237 {
238     return { _mm256_cmp_pd(a.simdInternal_, b.simdInternal_, _CMP_LE_OQ) };
239 }
240
241 static inline Simd4DBool gmx_simdcall operator&&(Simd4DBool a, Simd4DBool b)
242 {
243     return { _mm256_and_pd(a.simdInternal_, b.simdInternal_) };
244 }
245
246 static inline Simd4DBool gmx_simdcall operator||(Simd4DBool a, Simd4DBool b)
247 {
248     return { _mm256_or_pd(a.simdInternal_, b.simdInternal_) };
249 }
250
251 static inline bool gmx_simdcall anyTrue(Simd4DBool a)
252 {
253     return _mm256_movemask_pd(a.simdInternal_) != 0;
254 }
255
256 static inline Simd4Double gmx_simdcall selectByMask(Simd4Double a, Simd4DBool mask)
257 {
258     return { _mm256_and_pd(a.simdInternal_, mask.simdInternal_) };
259 }
260
261 static inline Simd4Double gmx_simdcall selectByNotMask(Simd4Double a, Simd4DBool mask)
262 {
263     return { _mm256_andnot_pd(mask.simdInternal_, a.simdInternal_) };
264 }
265
266 static inline Simd4Double gmx_simdcall blend(Simd4Double a, Simd4Double b, Simd4DBool sel)
267 {
268     return { _mm256_blendv_pd(a.simdInternal_, b.simdInternal_, sel.simdInternal_) };
269 }
270
271 static inline double gmx_simdcall reduce(Simd4Double a)
272 {
273     __m128d a0, a1;
274     /* test with shuffle & add as an alternative to hadd later */
275     a.simdInternal_ = _mm256_hadd_pd(a.simdInternal_, a.simdInternal_);
276     a0              = _mm256_castpd256_pd128(a.simdInternal_);
277     a1              = _mm256_extractf128_pd(a.simdInternal_, 0x1);
278     a0              = _mm_add_sd(a0, a1);
279     return *reinterpret_cast<double*>(&a0);
280 }
281
282 } // namespace gmx
283
284 #endif // GMX_SIMD_IMPL_X86_AVX_128_FMA_SIMD4_DOUBLE_H