Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / simd / tests / simd.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 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 GMX_SIMD_TESTS_SIMD_H
36 #define GMX_SIMD_TESTS_SIMD_H
37
38 /*! \internal \file
39  * \brief
40  * Declares fixture for testing of normal SIMD (not SIMD4) functionality.
41  *
42  * The SIMD tests are both simple and complicated. The actual testing logic
43  * is \a very straightforward since we just need to test single values against
44  * the math library, and for some math functions we need to do it in a loop.
45  * This could have been achieved in minutes with the default Google Test tools,
46  * if it wasn't for the problem that we cannot access or compare SIMD contents
47  * directly without using lots of other SIMD functionality. For this reason
48  * we have separate the basic testing of load/store operations into a separate
49  * bootstrapping test. Once this works, we use a set of utility routines to
50  * convert SIMD contents to/from std:vector<> and perform the rest of the tests,
51  * which then can farmed out to the base class SimdBaseTest that is common
52  * to SIMD and SIMD4.
53  *
54  * Another complication is that the width of the SIMD implementation will
55  * depend on the hardware and precision. For some simple operations it is
56  * sufficient to set all SIMD elements to the same value, and check that the
57  * result is present in all elements. However, for a few more complex
58  * instructions that might rely on shuffling under-the-hood it is important
59  * that we can test operations with different elements. We achieve this by
60  * having test code that can initialize a SIMD variable from an std::vector
61  * of arbitrary length; the vector is simply repeated to fill all elements in
62  * the SIMD variable. We also have similar routines to compare a SIMD result
63  * with values in a vector, which returns true iff all elements match.
64  *
65  * This way we can write simple tests that use different values for all SIMD
66  * elements. Personally I like using vectors of length 3, since this means
67  * there are no simple repeated patterns in low/high halves of SIMD variables
68  * that are 2,4,8,or 16 elements wide, and we still don't have to care about
69  * the exact SIMD width of the underlying implementation.
70  *
71  * Note that this utility uses a few SIMD load/store instructions internally -
72  * those have been tested separately in the bootstrap_loadstore.cpp file.
73  *
74  * \author Erik Lindahl <erik.lindahl@scilifelab.se>
75  * \ingroup module_simd
76  */
77 #include <vector>
78
79 #include <gtest/gtest.h>
80
81 #include "gromacs/simd/simd.h"
82
83 #include "base.h"
84
85 namespace gmx
86 {
87 namespace test
88 {
89
90 /*! \cond internal */
91 /*! \addtogroup module_simd */
92 /*! \{ */
93
94 /* Unfortunately we cannot keep static SIMD constants in the test fixture class.
95  * The problem is that SIMD memory need to be aligned, and in particular
96  * this applies to automatic storage of variables in classes. For SSE registers
97  * this means 16-byte alignment (which seems to work), but AVX requires 32-bit
98  * alignment. At least both gcc-4.7.3 and Apple clang-5.0 (OS X 10.9) fail to
99  * align these variables when they are stored as data in a class.
100  *
101  * In theory we could set some of these on-the-fly e.g. with setSimdFrom3R()
102  * instead (although that would mean repeating code between tests), but many of
103  * the constants depend on the current precision not to mention they
104  * occasionally have many digits that need to be exactly right, and keeping
105  * them in a single place makes sure they are consistent.
106  */
107 #ifdef GMX_SIMD_HAVE_REAL
108 extern const gmx_simd_real_t rSimd_1_2_3;     //!< Generic (different) fp values.
109 extern const gmx_simd_real_t rSimd_4_5_6;     //!< Generic (different) fp values.
110 extern const gmx_simd_real_t rSimd_7_8_9;     //!< Generic (different) fp values.
111 extern const gmx_simd_real_t rSimd_5_7_9;     //!< rSimd_1_2_3 + rSimd_4_5_6.
112 extern const gmx_simd_real_t rSimd_m1_m2_m3;  //!< Generic negative floating-point values.
113 extern const gmx_simd_real_t rSimd_3_1_4;     //!< Used to test min/max.
114 extern const gmx_simd_real_t rSimd_m3_m1_m4;  //!< negative rSimd_3_1_4.
115 extern const gmx_simd_real_t rSimd_2p25;      //!< Value that rounds down.
116 extern const gmx_simd_real_t rSimd_3p75;      //!< Value that rounds up.
117 extern const gmx_simd_real_t rSimd_m2p25;     //!< Negative value that rounds up.
118 extern const gmx_simd_real_t rSimd_m3p75;     //!< Negative value that rounds down.
119 //! Three large floating-point values whose exponents are >32.
120 extern const gmx_simd_real_t rSimd_Exp;
121 #    if (defined GMX_SIMD_HAVE_DOUBLE) && (defined GMX_DOUBLE)
122 // Make sure we also test exponents outside single precision when we use double
123 extern const gmx_simd_real_t rSimd_ExpDouble;
124 #    endif
125 // Magic FP numbers corresponding to specific bit patterns
126 extern const gmx_simd_real_t rSimd_Bits1;       //!< Pattern F0 repeated to fill single/double.
127 extern const gmx_simd_real_t rSimd_Bits2;       //!< Pattern CC repeated to fill single/double.
128 extern const gmx_simd_real_t rSimd_Bits3;       //!< Pattern C0 repeated to fill single/double.
129 extern const gmx_simd_real_t rSimd_Bits4;       //!< Pattern 0C repeated to fill single/double.
130 extern const gmx_simd_real_t rSimd_Bits5;       //!< Pattern FC repeated to fill single/double.
131 extern const gmx_simd_real_t rSimd_Bits6;       //!< Pattern 3C repeated to fill single/double.
132 #endif                                          // GMX_SIMD_HAVE_REAL
133 #ifdef GMX_SIMD_HAVE_INT32
134 extern const gmx_simd_int32_t iSimd_1_2_3;      //!< Three generic ints.
135 extern const gmx_simd_int32_t iSimd_4_5_6;      //!< Three generic ints.
136 extern const gmx_simd_int32_t iSimd_7_8_9;      //!< Three generic ints.
137 extern const gmx_simd_int32_t iSimd_5_7_9;      //!< iSimd_1_2_3 + iSimd_4_5_6.
138 extern const gmx_simd_int32_t iSimd_1M_2M_3M;   //!< Term1 for 32bit add/sub.
139 extern const gmx_simd_int32_t iSimd_4M_5M_6M;   //!< Term2 for 32bit add/sub.
140 extern const gmx_simd_int32_t iSimd_5M_7M_9M;   //!< iSimd_1M_2M_3M + iSimd_4M_5M_6M.
141 extern const gmx_simd_int32_t iSimd_0xF0F0F0F0; //!< Bitpattern to test integer logical operations.
142 extern const gmx_simd_int32_t iSimd_0xCCCCCCCC; //!< Bitpattern to test integer logical operations.
143 #endif                                          // GMX_SIMD_HAVE_INT32
144
145
146 /*! \internal
147  * \brief
148  * Test fixture for SIMD tests.
149  *
150  * This is a very simple test fixture that basically just takes the common
151  * SIMD/SIMD4 functionality from SimdBaseTest and creates wrapper routines
152  * specific for normal SIMD functionality.
153  */
154 class SimdTest : public SimdBaseTest
155 {
156     public:
157 #ifdef GMX_SIMD_HAVE_REAL
158         /*! \brief Compare two real SIMD variables for approximate equality.
159          *
160          * This is an internal implementation routine. YOu should always use
161          * GMX_EXPECT_SIMD_REAL_NEAR() instead.
162          *
163          * This routine is designed according to the Google test specs, so the char
164          * strings will describe the arguments to the macro.
165          *
166          * The comparison is applied to each element, and it returns true if each element
167          * in the SIMD test variable is within the class tolerances of the corresponding
168          * reference element.
169          */
170             ::testing::AssertionResult
171         compareSimdRealUlp(const char * refExpr, const char * tstExpr,
172                            const gmx_simd_real_t ref, const gmx_simd_real_t tst);
173
174         /*! \brief Compare two real SIMD variables for exact equality.
175          *
176          * This is an internal implementation routine. YOu should always use
177          * GMX_EXPECT_SIMD_REAL_NEAR() instead.
178          *
179          * This routine is designed according to the Google test specs, so the char
180          * strings will describe the arguments to the macro.
181          *
182          * The comparison is applied to each element, and it returns true if each element
183          * in the SIMD test variable is within the class tolerances of the corresponding
184          * reference element.
185          */
186         ::testing::AssertionResult
187         compareSimdRealEq(const char * refExpr, const char * tstExpr,
188                           const gmx_simd_real_t ref, const gmx_simd_real_t tst);
189
190 #endif
191
192 #ifdef GMX_SIMD_HAVE_INT32
193         /*! \brief Compare two 32-bit integer SIMD variables.
194          *
195          * This is an internal implementation routine. YOu should always use
196          * GMX_EXPECT_SIMD_INT_EQ() instead.
197          *
198          * This routine is designed according to the Google test specs, so the char
199          * strings will describe the arguments to the macro, while the SIMD and
200          * tolerance arguments are used to decide if the values are approximately equal.
201          *
202          * The comparison is applied to each element, and it returns true if each element
203          * in the SIMD variable tst is identical to the corresponding reference element.
204          */
205             ::testing::AssertionResult
206         compareSimdInt32(const char * refExpr, const char *  tstExpr,
207                          const gmx_simd_int32_t ref, const gmx_simd_int32_t tst);
208 #endif
209 };
210
211 #ifdef GMX_SIMD_HAVE_REAL
212 /*! \brief Convert SIMD real to std::vector<real>.
213  *
214  * The returned vector will have the same length as the SIMD width.
215  */
216 std::vector<real> simdReal2Vector(const gmx_simd_real_t simd);
217
218 /*! \brief Return floating-point SIMD value from std::vector<real>.
219  *
220  * If the vector is longer than SIMD width, only the first elements will be used.
221  * If it is shorter, the contents will be repeated to fill the SIMD register.
222  */
223 gmx_simd_real_t   vector2SimdReal(const std::vector<real> &v);
224
225 /*! \brief Set SIMD register contents from three real values.
226  *
227  * Our reason for using three values is that 3 is not a factor in any known
228  * SIMD width, so this way there will not be any simple repeated patterns e.g.
229  * between the low/high 64/128/256 bits in the SIMD register, which could hide bugs.
230  */
231 gmx_simd_real_t   setSimdRealFrom3R(real r0, real r1, real r2);
232
233 /*! \brief Set SIMD register contents from single real value.
234  *
235  * All elements is set from the given value. This is effectively the same
236  * operation as gmx_simd_set1_r(), but is implemented using only load/store
237  * operations that have been tested separately in the bootstrapping tests.
238  */
239 gmx_simd_real_t   setSimdRealFrom1R(real value);
240
241 /*! \brief Test if a SIMD real is bitwise identical to reference SIMD value. */
242 #define GMX_EXPECT_SIMD_REAL_EQ(ref, tst)   EXPECT_PRED_FORMAT2(compareSimdRealEq, ref, tst)
243
244 /*! \brief Test if a SIMD real is within tolerance of reference SIMD value. */
245 #define GMX_EXPECT_SIMD_REAL_NEAR(ref, tst) EXPECT_PRED_FORMAT2(compareSimdRealUlp, ref, tst)
246
247 #endif  // GMX_SIMD_HAVE_REAL
248
249 #ifdef GMX_SIMD_HAVE_INT32
250 /*! \brief Convert SIMD integer to std::vector<int>.
251  *
252  * The returned vector will have the same length as the SIMD width.
253  */
254 std::vector<int>   simdInt2Vector(const gmx_simd_int32_t simd);
255
256 /*! \brief Return 32-bit integer SIMD value from std::vector<int>.
257  *
258  * If the vector is longer than SIMD width, only the first elements will be used.
259  * If it is shorter, the contents will be repeated to fill the SIMD register.
260  */
261 gmx_simd_int32_t   vector2SimdInt(const std::vector<int> &v);
262
263 /*! \brief Set SIMD register contents from three int values.
264  *
265  * Our reason for using three values is that 3 is not a factor in any known
266  * SIMD width, so this way there will not be any simple repeated patterns e.g.
267  * between the low/high 64/128/256 bits in the SIMD register, which could hide bugs.
268  */
269 gmx_simd_int32_t   setSimdIntFrom3I(int i0, int i1, int i2);
270
271 /*! \brief Set SIMD register contents from single integer value.
272  *
273  * All elements is set from the given value. This is effectively the same
274  * operation as gmx_simd_set1_i(), but is implemented using only load/store
275  * operations that have been tested separately in the bootstrapping tests.
276  */
277 gmx_simd_int32_t   setSimdIntFrom1I(int value);
278
279 /*! \brief Macro that checks SIMD integer expression against SIMD or reference int.
280  *
281  * If the reference argument is a scalar integer it will be expanded into
282  * the width of the SIMD register and tested against all elements.
283  */
284 #define GMX_EXPECT_SIMD_INT_EQ(ref, tst)    EXPECT_PRED_FORMAT2(compareSimdInt32, ref, tst)
285
286 #endif  // GMX_SIMD_HAVE_INT32
287
288 /*! \} */
289 /*! \endcond */
290
291 }      // namespace
292 }      // namespace
293
294 #endif // GMX_SIMD_TESTS_SIMD_H