Implement changes for CMake policy 0068
[alexxy/gromacs.git] / src / gromacs / simd / tests / simd_integer.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2016,2017, 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 #include "gmxpre.h"
36
37 #include "gromacs/simd/simd.h"
38 #include "gromacs/utility/basedefinitions.h"
39
40 #include "simd.h"
41
42 /* Some notes on the setup of these tests:
43  *
44  * It might seem strange to mix different instructions for "setting" SIMD
45  * registers, but the difference is that the routines like setSimdIntFrom1I()
46  * only use the load/store operations that we already test separately in
47  * bootstrap_loadstore.cpp. Since these are "known good" if the bootstrap
48  * tests pass, we use them to test the normal SIMD implementation instructions.
49  */
50
51 #if GMX_SIMD
52
53 namespace gmx
54 {
55 namespace test
56 {
57 namespace
58 {
59
60 /*! \cond internal */
61 /*! \addtogroup module_simd */
62 /*! \{ */
63
64 /*! \brief Test fixture for integer tests (identical to the generic \ref SimdTest) */
65 typedef SimdTest SimdIntegerTest;
66
67 /* Yes, Virginia. We test for real even for integers. This is because we use
68  * the floating-point type when no real integer SIMD type exists (which in turn
69  * is because the results of real-to-integer conversions end up there). This
70  * means the basic integer SIMD type is available whenever the real one is,
71  * but depending on the precision selected that might not be the case.
72  *
73  * The second we have default-precision floating-point SIMD, we also have
74  * the integer SIMD dataype and the most fundamental load/store ops.
75  */
76 #if GMX_SIMD_HAVE_REAL
77
78 TEST_F(SimdIntegerTest, setZero)
79 {
80     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(0), setZero());
81 }
82 TEST_F(SimdIntegerTest, set)
83 {
84     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(1), SimdInt32(1));
85 }
86 #endif      // GMX_SIMD_HAVE_REAL
87
88 #if GMX_SIMD_HAVE_INT32_ARITHMETICS
89 TEST_F(SimdIntegerTest, add)
90 {
91     GMX_EXPECT_SIMD_INT_EQ(iSimd_5_7_9, iSimd_1_2_3 + iSimd_4_5_6 );         // short add
92     GMX_EXPECT_SIMD_INT_EQ(iSimd_5M_7M_9M, iSimd_1M_2M_3M + iSimd_4M_5M_6M); // 32 bit add
93 }
94
95 TEST_F(SimdIntegerTest, sub)
96 {
97     GMX_EXPECT_SIMD_INT_EQ(iSimd_1_2_3, iSimd_5_7_9 - iSimd_4_5_6 );          // short sub
98     GMX_EXPECT_SIMD_INT_EQ(iSimd_1M_2M_3M, iSimd_5M_7M_9M - iSimd_4M_5M_6M ); // 32 bit sub
99 }
100
101 TEST_F(SimdIntegerTest, mul)
102 {
103     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(4, 10, 18), iSimd_1_2_3 * iSimd_4_5_6);            // 2*3=6 (short mul)
104     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(268435456), SimdInt32(16384) * SimdInt32(16384) ); // 16384*16384 = 268435456 (long mul)
105 }
106
107 #endif                                                                     // GMX_SIMD_HAVE_INT32_ARITHMETICS
108
109 #if GMX_SIMD_HAVE_INT32_LOGICAL
110 TEST_F(SimdIntegerTest, and)
111 {
112     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(0xC0C0C0C0), iSimd_0xF0F0F0F0 & iSimd_0xCCCCCCCC);
113 }
114
115 TEST_F(SimdIntegerTest, andNot)
116 {
117     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(0x0C0C0C0C), andNot(iSimd_0xF0F0F0F0, iSimd_0xCCCCCCCC));
118 }
119
120 TEST_F(SimdIntegerTest, or)
121 {
122     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(0xFCFCFCFC), iSimd_0xF0F0F0F0 | iSimd_0xCCCCCCCC);
123 }
124
125 TEST_F(SimdIntegerTest, xor)
126 {
127     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(0x3C3C3C3C), iSimd_0xF0F0F0F0 ^iSimd_0xCCCCCCCC);
128 }
129 #endif      // GMX_SIMD_HAVE_INT32_LOGICAL
130
131 #if GMX_SIMD_HAVE_INT32_EXTRACT
132 TEST_F(SimdIntegerTest, extract)
133 {
134     alignas(GMX_SIMD_ALIGNMENT) std::int32_t  idata[GMX_SIMD_REAL_WIDTH];
135     SimdInt32 simd;
136
137     for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
138     {
139         idata[i] = i+1;
140     }
141     simd = load<SimdInt32>(idata);
142
143     /* We cannot do a loop here, since
144      * - C++ gets confused about signed/unsigned if SSE macros are used in EXPECT_EQ()
145      * - Extract macros can only take immediates (not variables) on some archs,
146      *   and some compilers are not smart enough to expand the for loop.
147      *
148      * To solve this we use a few values manually instead of a for-loop.
149      */
150     int extracted_int;
151     extracted_int = extract<0>(simd);
152     EXPECT_EQ(1, extracted_int);
153 #if GMX_SIMD_REAL_WIDTH >= 2
154     extracted_int = extract<1>(simd);
155     EXPECT_EQ(2, extracted_int);
156 #endif
157 #if GMX_SIMD_REAL_WIDTH >= 4
158     extracted_int = extract<3>(simd);
159     EXPECT_EQ(4, extracted_int);
160 #endif
161 #if GMX_SIMD_REAL_WIDTH >= 6
162     extracted_int = extract<5>(simd);
163     EXPECT_EQ(6, extracted_int);
164 #endif
165 #if GMX_SIMD_REAL_WIDTH >= 8
166     extracted_int = extract<7>(simd);
167     EXPECT_EQ(8, extracted_int);
168 #endif
169 }
170 #endif      // GMX_SIMD_HAVE_INT32_EXTRACT
171
172 #if GMX_SIMD_HAVE_REAL
173 TEST_F(SimdIntegerTest, cvtR2I)
174 {
175     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(2), cvtR2I(rSimd_2p25));
176     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-2), cvtR2I(rSimd_m2p25));
177     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(4), cvtR2I(rSimd_3p75));
178     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-4), cvtR2I(rSimd_m3p75));
179     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(3), cvtR2I(rSimd_3p25));
180     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-3), cvtR2I(rSimd_m3p25));
181
182     // Test multi-byte numbers
183     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(123457), cvtR2I(setSimdRealFrom1R(123456.7)));
184     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-123457), cvtR2I(setSimdRealFrom1R(-123456.7)));
185     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(123456), cvtR2I(setSimdRealFrom1R(123456.3)));
186     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-123456), cvtR2I(setSimdRealFrom1R(-123456.3)));
187
188 #if GMX_DOUBLE
189     // Test number with more digits than we can represent in single.
190     // Note that our SIMD integers are only 32 bits, so we cannot go beyond that.
191     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(12345679), cvtR2I(setSimdRealFrom1R(12345678.6)));
192     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-12345679), cvtR2I(setSimdRealFrom1R(-12345678.6)));
193     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(12345678), cvtR2I(setSimdRealFrom1R(12345678.3)));
194     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-12345678), cvtR2I(setSimdRealFrom1R(-12345678.3)));
195 #endif
196 }
197
198 TEST_F(SimdIntegerTest, cvttR2I)
199 {
200     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(2), cvttR2I(rSimd_2p25));
201     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-2), cvttR2I(rSimd_m2p25));
202     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(3), cvttR2I(rSimd_3p75));
203     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-3), cvttR2I(rSimd_m3p75));
204     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(3), cvttR2I(rSimd_3p25));
205     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-3), cvttR2I(rSimd_m3p25));
206
207     // Test multi-byte numbers
208     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(123456), cvttR2I(setSimdRealFrom1R(123456.7)));
209     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-123456), cvttR2I(setSimdRealFrom1R(-123456.7)));
210     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(123456), cvttR2I(setSimdRealFrom1R(123456.3)));
211     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-123456), cvttR2I(setSimdRealFrom1R(-123456.3)));
212
213 #if GMX_DOUBLE
214     // Test number with more digits than we can represent in single.
215     // Note that our SIMD integers are only 32 bits, so we cannot go beyond that.
216     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(12345678), cvttR2I(setSimdRealFrom1R(12345678.6)));
217     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-12345678), cvttR2I(setSimdRealFrom1R(-12345678.6)));
218     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(12345678), cvttR2I(setSimdRealFrom1R(12345678.3)));
219     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom1I(-12345678), cvttR2I(setSimdRealFrom1R(-12345678.3)));
220 #endif
221 }
222
223 TEST_F(SimdIntegerTest, cvtI2R)
224 {
225     GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom1R(2.0), cvtI2R(SimdInt32(2)));
226     GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom1R(-2.0), cvtI2R(SimdInt32(-2)));
227     GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom1R(102448689), cvtI2R(SimdInt32(102448689)));
228     GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom1R(-102448689), cvtI2R(SimdInt32(-102448689)));
229 }
230 #endif      // GMX_SIMD_HAVE_REAL
231
232 #if GMX_SIMD_HAVE_INT32_ARITHMETICS
233 TEST_F(SimdIntegerTest, cmpEqAndSelectMask)
234 {
235     SimdIBool eq   = (iSimd_5_7_9 == iSimd_7_8_9);
236     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(0, 0, 3), selectByMask(iSimd_1_2_3, eq));
237 }
238
239 TEST_F(SimdIntegerTest, cmpEqAndSelectNotMask)
240 {
241     SimdIBool eq   = (iSimd_5_7_9 == iSimd_7_8_9);
242     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(1, 2, 0), selectByNotMask(iSimd_1_2_3, eq));
243 }
244
245 TEST_F(SimdIntegerTest, cmpLt)
246 {
247     SimdIBool lt   = (iSimd_5_7_9 < iSimd_7_8_9);
248     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(1, 2, 0), selectByMask(iSimd_1_2_3, lt));
249 }
250
251 TEST_F(SimdIntegerTest, testBits)
252 {
253     SimdIBool eq   = testBits(setSimdIntFrom3I(1, 0, 2));
254     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(1, 0, 3), selectByMask(iSimd_1_2_3, eq));
255
256     // Test if we detect only the sign bit being set
257     eq            = testBits(setSimdIntFrom1I(0x80000000));
258     GMX_EXPECT_SIMD_INT_EQ(iSimd_1_2_3, selectByMask(iSimd_1_2_3, eq));
259 }
260
261 TEST_F(SimdIntegerTest, andB)
262 {
263     SimdIBool eq1  = (iSimd_5_7_9 == iSimd_7_8_9);
264     SimdIBool eq2  = (iSimd_5_7_9 == iSimd_5_7_9);
265     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(0, 0, 3), selectByMask(iSimd_1_2_3, eq1 && eq2));
266 }
267
268 TEST_F(SimdIntegerTest, orB)
269 {
270     SimdIBool eq1  = (iSimd_5_7_9 == iSimd_7_8_9);
271     SimdIBool eq2  = (iSimd_5_7_9 == setSimdIntFrom3I(5, 0, 0));
272     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(1, 0, 3), selectByMask(iSimd_1_2_3, eq1 || eq2));
273 }
274
275 TEST_F(SimdIntegerTest, anyTrue)
276 {
277     SimdIBool eq;
278
279     /* See comment in floatingpoint.cpp. We should only check the first element here,
280      * since the SIMD width could be 1 as a special case.
281      */
282     eq = (iSimd_5_7_9 == setSimdIntFrom3I(5, 0, 0));
283     EXPECT_TRUE(anyTrue(eq));
284
285     eq = (iSimd_1_2_3 == iSimd_4_5_6);
286     EXPECT_FALSE(anyTrue(eq));
287 }
288
289 TEST_F(SimdIntegerTest, blend)
290 {
291     SimdIBool lt   = (iSimd_5_7_9 < iSimd_7_8_9);
292     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(4, 5, 3), blend(iSimd_1_2_3, iSimd_4_5_6, lt));
293 }
294 #endif      // GMX_SIMD_HAVE_INT32_ARITHMETICS
295
296 #if GMX_SIMD_HAVE_REAL && GMX_SIMD_HAVE_INT32_ARITHMETICS
297 TEST_F(SimdIntegerTest, cvtB2IB)
298 {
299     SimdBool  eq   = (rSimd_c3c4c5 == rSimd_c3c0c4);  // eq should be T,F,F
300     SimdIBool eqi  = cvtB2IB(eq);
301     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(1, 0, 0), selectByMask(iSimd_1_2_3, eqi));
302
303 }
304
305 TEST_F(SimdIntegerTest, cvtIB2B)
306 {
307     SimdIBool eqi  = (iSimd_5_7_9 == setSimdIntFrom3I(5, 0, 0));  // eq should be T,F,F
308     SimdBool  eq   = cvtIB2B(eqi);
309     GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom3R(c0, 0, 0), selectByMask(rSimd_c0c1c2, eq));
310 }
311 #endif      // GMX_SIMD_HAVE_REAL && GMX_SIMD_HAVE_INT32_ARITHMETICS
312
313 /*! \} */
314 /*! \endcond */
315
316 }      // namespace
317 }      // namespace
318 }      // namespace
319
320 #endif // GMX_SIMD