1 // ==========================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2018, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 // its contributors may be used to endorse or promote products derived
17 // from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32 // Author: David Weese <david.weese@fu-berlin.de>
33 // Marcel Ehrhardt <marcel.ehrhardt@fu-berlin.de>
34 // ==========================================================================
35 // Tests for SIMD vectors.
36 // ==========================================================================
37
38 #ifndef SEQAN_CORE_TESTS_SIMD_TEST_SIMD_VECTOR_H_
39 #define SEQAN_CORE_TESTS_SIMD_TEST_SIMD_VECTOR_H_
40
41 #include <seqan/simd.h>
42 #include <random>
43 #include <seqan/sequence.h>
44 #include <seqan/misc/bit_twiddling.h>
45
46 #if defined(SEQAN_SIMD_ENABLED)
47 namespace seqan {
48
49 template <int ROWS, typename TVector>
test_matrix_transpose()50 inline void test_matrix_transpose()
51 {
52 typedef typename Value<TVector>::Type TValue;
53 typedef TVector TMatrix[LENGTH<TVector>::VALUE];
54 const int COLS = LENGTH<TVector>::VALUE;
55
56 String<TValue> random;
57 resize(random, ROWS * COLS);
58
59 std::mt19937 rng;
60 // http://stackoverflow.com/questions/31460733/why-arent-stduniform-int-distributionuint8-t-and-stduniform-int-distri
61 std::uniform_int_distribution<uint64_t> pdf(0, MaxValue<TValue>::VALUE);
62 for (unsigned i = 0; i < length(random); ++i)
63 random[i] = static_cast<TValue>(pdf(rng));
64
65 TMatrix tmp;
66 for (int i = 0; i < ROWS; ++i)
67 for (int j = 0; j < COLS; ++j)
68 tmp[i][j] = random[i * COLS + j];
69
70 // for(int i=0;i<ROWS;++i)
71 // print(std::cout, tmp[i]) << std::endl;
72
73 transpose<ROWS>(tmp);
74
75 // std::cout << std::endl;
76 // std::cout << std::endl;
77 // for(int i=0;i<DIM;++i)
78 // print(std::cout, tmp[i]) << std::endl;
79 #if defined(__x86_64__) || defined(__amd64__)
80 _mm_empty(); // Fixes icpc warning #13203: No EMMS instruction before call to function
81 #endif // defined(__x86_64__) || defined(__amd64__)
82 for (int i = 0; i < ROWS; ++i)
83 for (int j = 0; j < COLS; ++j)
84 SEQAN_ASSERT_EQ(tmp[i][j], random[j * ROWS + i]);
85 }
86
87 template <typename TSimdVector>
fillVectors(TSimdVector & a,TSimdVector & b)88 void fillVectors(TSimdVector & a, TSimdVector & b)
89 {
90 using namespace seqan;
91 constexpr auto length = LENGTH<TSimdVector>::VALUE;
92
93 for (auto i = 0; i < length; ++i)
94 {
95 a[i] = (i - 1) * 3;
96 b[i] = length - i;
97 }
98 }
99
100 template <typename TSimdVector, typename TSize>
reverseIndexSequence(TSimdVector & idx,TSize length)101 void reverseIndexSequence(TSimdVector & idx, TSize length)
102 {
103 for (auto i = 0; i < length; ++i)
104 {
105 // note: umesimd swizzle interface has no a[i] = i; support.
106 assignValue(idx, i, length - i - 1);
107 }
108 }
109
110 template <typename TSimdVector>
trueValue()111 constexpr auto trueValue()
112 {
113 using TSimdMaskVector = typename SimdMaskVector<TSimdVector>::Type;
114 using TValue = typename Value<TSimdMaskVector>::Type;
115 return static_cast<TValue>(-1);
116 }
117
118 } // namespace seqan
119
120 // ----------------------------------------------------------------------------
121 // Configuration of typed tests for simd vectors.
122 // ----------------------------------------------------------------------------
123
124 template <typename TSimdVector_>
125 class SimdVectorTestCommon : public seqan::Test
126 {
127 public:
128 using TValue = typename seqan::Value<TSimdVector_>::Type;
129 constexpr static auto const LENGTH = seqan::LENGTH<TSimdVector_>::VALUE;
130 using TSimdVector = TSimdVector_;
131 };
132
133 template <typename TSimdVector_>
134 class SimdVectorTestGather : public seqan::Test
135 {
136 public:
137 using TValue = typename seqan::Value<TSimdVector_>::Type;
138 constexpr static auto const LENGTH = seqan::LENGTH<TSimdVector_>::VALUE;
139 using TSimdVector = TSimdVector_;
140 };
141
142 typedef
143 seqan::TagList<seqan::SimdVector<int8_t, 16>::Type,
144 seqan::TagList<seqan::SimdVector<int16_t, 8>::Type,
145 seqan::TagList<seqan::SimdVector<int32_t, 4>::Type,
146 seqan::TagList<seqan::SimdVector<int64_t, 2>::Type,
147 seqan::TagList<seqan::SimdVector<uint8_t, 16>::Type,
148 seqan::TagList<seqan::SimdVector<uint16_t, 8>::Type,
149 seqan::TagList<seqan::SimdVector<uint32_t, 4>::Type,
150 seqan::TagList<seqan::SimdVector<uint64_t, 2>::Type
151 #if SEQAN_SIZEOF_MAX_VECTOR >= 32
152 , // Extension of the list above
153 seqan::TagList<seqan::SimdVector<int8_t, 32>::Type,
154 seqan::TagList<seqan::SimdVector<int16_t, 16>::Type,
155 seqan::TagList<seqan::SimdVector<int32_t, 8>::Type,
156 seqan::TagList<seqan::SimdVector<int64_t, 4>::Type,
157 seqan::TagList<seqan::SimdVector<uint8_t, 32>::Type,
158 seqan::TagList<seqan::SimdVector<uint16_t, 16>::Type,
159 seqan::TagList<seqan::SimdVector<uint32_t, 8>::Type,
160 seqan::TagList<seqan::SimdVector<uint64_t, 4>::Type
161 #if SEQAN_SIZEOF_MAX_VECTOR >= 64
162 , // Extension of the list above
163 seqan::TagList<seqan::SimdVector<int8_t, 64>::Type,
164 seqan::TagList<seqan::SimdVector<int16_t, 32>::Type,
165 seqan::TagList<seqan::SimdVector<int32_t, 16>::Type,
166 seqan::TagList<seqan::SimdVector<int64_t, 8>::Type,
167 seqan::TagList<seqan::SimdVector<uint8_t, 64>::Type,
168 seqan::TagList<seqan::SimdVector<uint16_t, 32>::Type,
169 seqan::TagList<seqan::SimdVector<uint32_t, 16>::Type,
170 seqan::TagList<seqan::SimdVector<uint64_t, 8>::Type
171 > > > > > > > >
172 #endif
173 > > > > > > > >
174 #endif
175 > > > > > > > >
176 SimdVectorCommonCommonTypes;
177
178 SEQAN_TYPED_TEST_CASE(SimdVectorTestCommon, SimdVectorCommonCommonTypes);
179 SEQAN_TYPED_TEST_CASE(SimdVectorTestGather, SimdVectorCommonCommonTypes);
180
SEQAN_DEFINE_TEST(test_simd_types)181 SEQAN_DEFINE_TEST(test_simd_types)
182 {
183 using namespace seqan;
184
185 // SimdVector16Char
186 static_assert(std::is_same<SimdVector<int8_t, 16>::Type, SimdVector16SChar>::value, "should be the same type");
187 static_assert(std::is_same<SimdVector<int16_t, 8>::Type, SimdVector8Short>::value, "should be the same type");
188 static_assert(std::is_same<SimdVector<int32_t, 4>::Type, SimdVector4Int>::value, "should be the same type");
189 static_assert(std::is_same<SimdVector<int64_t, 2>::Type, SimdVector2Int64>::value, "should be the same type");
190 static_assert(std::is_same<SimdVector<uint8_t, 16>::Type, SimdVector16UChar>::value, "should be the same type");
191 static_assert(std::is_same<SimdVector<uint16_t, 8>::Type, SimdVector8UShort>::value, "should be the same type");
192 static_assert(std::is_same<SimdVector<uint32_t, 4>::Type, SimdVector4UInt>::value, "should be the same type");
193 static_assert(std::is_same<SimdVector<uint64_t, 2>::Type, SimdVector2UInt64>::value, "should be the same type");
194
195 static_assert(LENGTH<SimdVector4UInt>::VALUE == 4, "128bit register fits 4 int's");
196 static_assert(LENGTH<SimdVector<uint32_t, 4>::Type>::VALUE == 4, "128bit register fits 4 int's");
197 SimdVector<uint32_t, 4>::Type a128 = {0, 1, 2, 3};
198 for (uint32_t i = 0; i < 4; ++i) {
199 // std::cout << "DEBUG: " << i << ": " << a128[i] << " = " << i << std::endl;
200 SEQAN_ASSERT_EQ(a128[i], i);
201 }
202
203 // SimdVector32Char
204 #if SEQAN_SIZEOF_MAX_VECTOR >= 32
205 static_assert(std::is_same<SimdVector<int8_t, 32>::Type, SimdVector32SChar>::value, "should be the same type");
206 static_assert(std::is_same<SimdVector<int16_t, 16>::Type, SimdVector16Short>::value, "should be the same type");
207 static_assert(std::is_same<SimdVector<int32_t, 8>::Type, SimdVector8Int>::value, "should be the same type");
208 static_assert(std::is_same<SimdVector<int64_t, 4>::Type, SimdVector4Int64>::value, "should be the same type");
209 static_assert(std::is_same<SimdVector<uint8_t, 32>::Type, SimdVector32UChar>::value, "should be the same type");
210 static_assert(std::is_same<SimdVector<uint16_t, 16>::Type, SimdVector16UShort>::value, "should be the same type");
211 static_assert(std::is_same<SimdVector<uint32_t, 8>::Type, SimdVector8UInt>::value, "should be the same type");
212 static_assert(std::is_same<SimdVector<uint64_t, 4>::Type, SimdVector4UInt64>::value, "should be the same type");
213
214 static_assert(LENGTH<SimdVector8UInt>::VALUE == 8, "256bit register fits 8 int's");
215 static_assert(LENGTH<SimdVector<uint32_t, 8>::Type>::VALUE == 8, "256bit register fits 8 int's");
216 SimdVector<uint32_t, 8>::Type a256 = {0, 1, 2, 3, 4, 5, 6, 7};
217 for (uint32_t i = 0; i < 8; ++i) {
218 // std::cout << "DEBUG: " << i << ": " << a256[i] << " = " << i << std::endl;
219 SEQAN_ASSERT_EQ(a256[i], i);
220 }
221 #endif
222
223 #if SEQAN_SIZEOF_MAX_VECTOR >= 64
224 static_assert(std::is_same<SimdVector<int8_t, 64>::Type, SimdVector64SChar>::value, "should be the same type");
225 static_assert(std::is_same<SimdVector<int16_t, 32>::Type, SimdVector32Short>::value, "should be the same type");
226 static_assert(std::is_same<SimdVector<int32_t, 16>::Type, SimdVector16Int>::value, "should be the same type");
227 static_assert(std::is_same<SimdVector<int64_t, 8>::Type, SimdVector8Int64>::value, "should be the same type");
228 static_assert(std::is_same<SimdVector<uint8_t, 64>::Type, SimdVector64UChar>::value, "should be the same type");
229 static_assert(std::is_same<SimdVector<uint16_t, 32>::Type, SimdVector32UShort>::value, "should be the same type");
230 static_assert(std::is_same<SimdVector<uint32_t, 16>::Type, SimdVector16UInt>::value, "should be the same type");
231 static_assert(std::is_same<SimdVector<uint64_t, 8>::Type, SimdVector8UInt64>::value, "should be the same type");
232
233 static_assert(LENGTH<SimdVector16UInt>::VALUE == 16, "512bit register fits 16 int's");
234 static_assert(LENGTH<SimdVector<uint32_t, 16>::Type>::VALUE == 16, "512bit register fits 16 int's");
235 SimdVector<uint32_t, 16>::Type a512 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
236 for (uint32_t i = 0; i < 16; ++i) {
237 // std::cout << "DEBUG: " << i << ": " << a512[i] << " = " << i << std::endl;
238 SEQAN_ASSERT_EQ(a512[i], i);
239 }
240 #endif
241 }
242
SEQAN_TYPED_TEST(SimdVectorTestCommon,MetaFunctions)243 SEQAN_TYPED_TEST(SimdVectorTestCommon, MetaFunctions)
244 {
245 using namespace seqan;
246 using TSimdVector = typename TestFixture::TSimdVector;
247
248 // NOTE(marehr): explicit namespace is necessary for msvc 2015:
249 // error C2039: 'VALUE': is not a member of '`global namespace''
250 constexpr auto length = seqan::LENGTH<TSimdVector>::VALUE;
251 using TValue = typename Value<TSimdVector>::Type;
252 typedef typename SimdVector<TValue, length>::Type TSimdVectorNew;
253
254 bool sameType = IsSameType<TSimdVector, TSimdVectorNew>::VALUE;
255 SEQAN_ASSERT(sameType);
256 }
257
SEQAN_TYPED_TEST(SimdVectorTestCommon,SizeOf)258 SEQAN_TYPED_TEST(SimdVectorTestCommon, SizeOf)
259 {
260 using namespace seqan;
261 using TSimdVector = typename TestFixture::TSimdVector;
262 using TValue = typename TestFixture::TValue;
263 constexpr auto length = TestFixture::LENGTH;
264
265 TSimdVector a{0u};
266
267 // only on windows are the values unequal
268 SEQAN_ASSERT_GEQ(sizeof(a), sizeof(TValue) * length);
269
270 // on linux we assume that the sizes are equal
271 #ifndef STDLIB_VS
272 SEQAN_ASSERT_EQ(sizeof(a), sizeof(TValue) * length);
273 #endif
274 }
275
SEQAN_TYPED_TEST(SimdVectorTestCommon,SubscriptType)276 SEQAN_TYPED_TEST(SimdVectorTestCommon, SubscriptType)
277 {
278 using namespace seqan;
279 using TSimdVector = typename TestFixture::TSimdVector;
280 using TValue = typename TestFixture::TValue;
281
282 TSimdVector a{0u}, b{0u};
283 fillVectors(a, b);
284 TValue c = a[0];
285
286 bool sameType = IsSameType<TValue, decltype(c)>::VALUE;
287 SEQAN_ASSERT(sameType);
288 }
289
SEQAN_TYPED_TEST(SimdVectorTestCommon,ClearVector)290 SEQAN_TYPED_TEST(SimdVectorTestCommon, ClearVector)
291 {
292 using namespace seqan;
293 using TSimdVector = typename TestFixture::TSimdVector;
294 using TValue = typename TestFixture::TValue;
295 constexpr auto length = TestFixture::LENGTH;
296
297 auto zero = static_cast<TValue>(0);
298 TSimdVector a{0u}, b{0u};
299 fillVectors(a, b);
300
301 clearVector(a);
302
303 for (auto i = 0; i < length; ++i)
304 {
305 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)a[i] << " = " << 0 << std::endl;
306 SEQAN_ASSERT_EQ(a[i], zero);
307 }
308 }
309
SEQAN_TYPED_TEST(SimdVectorTestCommon,CreateVector)310 SEQAN_TYPED_TEST(SimdVectorTestCommon, CreateVector)
311 {
312 using namespace seqan;
313 using TSimdVector = typename TestFixture::TSimdVector;
314 using TValue = typename TestFixture::TValue;
315 constexpr auto length = TestFixture::LENGTH;
316
317 auto scalar = static_cast<TValue>(23);
318 auto a = createVector<TSimdVector>(scalar);
319
320 for (auto i = 0; i < length; ++i)
321 {
322 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)a[i] << " = " << 23 << std::endl;
323 SEQAN_ASSERT_EQ(a[i], scalar);
324 }
325 }
326
SEQAN_TYPED_TEST(SimdVectorTestCommon,FillVectorConstant)327 SEQAN_TYPED_TEST(SimdVectorTestCommon, FillVectorConstant)
328 {
329 using namespace seqan;
330 using TSimdVector = typename TestFixture::TSimdVector;
331 using TValue = typename TestFixture::TValue;
332 constexpr auto length = TestFixture::LENGTH;
333
334 TSimdVector a{0u};
335
336 fillVector(a, 5);
337
338 for (auto i = 0; i < length; ++i)
339 {
340 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)a[i] << " = " << i << std::endl;
341 SEQAN_ASSERT_EQ(a[i], static_cast<TValue>(5));
342 }
343 }
344
345 template <typename TSimdVector, std::size_t... index >
346 inline void
call_fill_vector(TSimdVector & a,std::index_sequence<index...>)347 call_fill_vector(TSimdVector & a, std::index_sequence<index...>)
348 {
349 seqan::fillVector(a, index...);
350 }
351
SEQAN_TYPED_TEST(SimdVectorTestCommon,FillVector)352 SEQAN_TYPED_TEST(SimdVectorTestCommon, FillVector)
353 {
354 using namespace seqan;
355 using TSimdVector = typename TestFixture::TSimdVector;
356 using TValue = typename TestFixture::TValue;
357 constexpr auto length = TestFixture::LENGTH;
358
359 TSimdVector a{0u};
360
361 // calls seqan::fillVector(a, 0, 1, 2, 3, ..., length-1);
362 call_fill_vector(a, std::make_index_sequence<length>{});
363
364 for (auto i = 0; i < length; ++i)
365 {
366 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)a[i] << " = " << i << std::endl;
367 SEQAN_ASSERT_EQ(a[i], static_cast<TValue>(i));
368 }
369 }
370
SEQAN_TYPED_TEST(SimdVectorTestCommon,CmpEqual)371 SEQAN_TYPED_TEST(SimdVectorTestCommon, CmpEqual)
372 {
373 using namespace seqan;
374 using TSimdVector = typename TestFixture::TSimdVector;
375 using TSimdMaskVector = typename SimdMaskVector<TSimdVector>::Type;
376 using TValue = typename TestFixture::TValue;
377 using TBoolValue = decltype(trueValue<TSimdVector>());
378 constexpr auto length = TestFixture::LENGTH;
379
380 TBoolValue false_ = 0,
381 true_ = trueValue<TSimdVector>();
382
383 TSimdVector a{0u}, b{0u};
384 fillVectors(a, b);
385
386 // There is never a match for the most instantiations of this test.
387 a[1] = 23;
388 b[1] = 23;
389
390 TSimdMaskVector c = cmpEq(a, b);
391
392 for (auto i = 0; i < length; ++i)
393 {
394 TValue a_i = (i == 1) ? 23 : (-3 + i * 3);
395 TValue b_i = (i == 1) ? 23 : (length - i);
396 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " == " << (int)b[i] << std::endl;
397 SEQAN_ASSERT_EQ(c[i], a[i] == b[i] ? true_ : false_);
398 SEQAN_ASSERT_EQ(c[i], a_i == b_i ? true_ : false_);
399 }
400 }
401
SEQAN_TYPED_TEST(SimdVectorTestCommon,CmpGt)402 SEQAN_TYPED_TEST(SimdVectorTestCommon, CmpGt)
403 {
404 using namespace seqan;
405 using TSimdVector = typename TestFixture::TSimdVector;
406 using TSimdMaskVector = typename SimdMaskVector<TSimdVector>::Type;
407 using TValue = typename TestFixture::TValue;
408 using TBoolValue = decltype(trueValue<TSimdVector>());
409 constexpr auto length = TestFixture::LENGTH;
410
411 TBoolValue false_ = 0,
412 true_ = trueValue<TSimdVector>();
413
414 TSimdVector a{0u}, b{0u};
415 fillVectors(a, b);
416
417 TSimdMaskVector c = cmpGt(a, b);
418
419 for (auto i = 0; i < length; ++i)
420 {
421 TValue a_i = -3 + i * 3, b_i = length - i;
422 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " > " << (int)b[i] << std::endl;
423 SEQAN_ASSERT_EQ(c[i], a[i] > b[i] ? true_ : false_);
424 SEQAN_ASSERT_EQ(c[i], a_i > b_i ? true_ : false_);
425 }
426 }
427
SEQAN_TYPED_TEST(SimdVectorTestCommon,Max)428 SEQAN_TYPED_TEST(SimdVectorTestCommon, Max)
429 {
430 using namespace seqan;
431 using TSimdVector = typename TestFixture::TSimdVector;
432 using TValue = typename TestFixture::TValue;
433 constexpr auto length = TestFixture::LENGTH;
434
435 TSimdVector a{0u}, b{0u};
436 fillVectors(a, b);
437
438 auto c = max(a, b);
439
440 for (auto i = 0; i < length; ++i)
441 {
442 TValue a_i = -3 + i * 3, b_i = length - i;
443 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = max (" << (int)a[i] << ", " << (int)b[i] << ")" << std::endl;
444 SEQAN_ASSERT_EQ(c[i], std::max(a[i], b[i]));
445 SEQAN_ASSERT_EQ(c[i], std::max(a_i, b_i));
446 }
447 }
448
SEQAN_TYPED_TEST(SimdVectorTestCommon,Min)449 SEQAN_TYPED_TEST(SimdVectorTestCommon, Min)
450 {
451 using namespace seqan;
452 using TSimdVector = typename TestFixture::TSimdVector;
453 using TValue = typename TestFixture::TValue;
454 constexpr auto length = TestFixture::LENGTH;
455
456 TSimdVector a{0u}, b{0u};
457 fillVectors(a, b);
458
459 auto c = min(a, b);
460
461 for (auto i = 0; i < length; ++i)
462 {
463 TValue a_i = -3 + i * 3, b_i = length - i;
464 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = min (" << (int)a[i] << ", " << (int)b[i] << ")" << std::endl;
465 SEQAN_ASSERT_EQ(c[i], std::min(a[i], b[i]));
466 SEQAN_ASSERT_EQ(c[i], std::min(a_i, b_i));
467 }
468 }
469
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseOr)470 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseOr)
471 {
472 using namespace seqan;
473 using TSimdVector = typename TestFixture::TSimdVector;
474 using TValue = typename TestFixture::TValue;
475 constexpr auto length = TestFixture::LENGTH;
476
477 TSimdVector a{0u}, b{0u};
478 fillVectors(a, b);
479
480 auto c = a | b;
481
482 for (auto i = 0; i < length; ++i)
483 {
484 TValue a_i = -3 + i * 3, b_i = length - i;
485 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " | " << (int)b[i] << std::endl;
486 SEQAN_ASSERT_EQ(c[i], a[i] | b[i]);
487 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i | b_i));
488 }
489 }
490
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseOrAssign)491 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseOrAssign)
492 {
493 using namespace seqan;
494 using TSimdVector = typename TestFixture::TSimdVector;
495 using TValue = typename TestFixture::TValue;
496 constexpr auto length = TestFixture::LENGTH;
497
498 TSimdVector a{0u}, b{0u}, c{0u};
499 fillVectors(a, b);
500
501 c = a;
502 c |= b;
503
504 for (auto i = 0; i < length; ++i)
505 {
506 TValue a_i = -3 + i * 3, b_i = length - i;
507 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " | " << (int)b[i] << std::endl;
508 SEQAN_ASSERT_EQ(c[i], a[i] | b[i]);
509 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i | b_i));
510 }
511 }
512
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseAnd)513 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseAnd)
514 {
515 using namespace seqan;
516 using TSimdVector = typename TestFixture::TSimdVector;
517 using TValue = typename TestFixture::TValue;
518 constexpr auto length = TestFixture::LENGTH;
519
520 TSimdVector a{0u}, b{0u};
521 fillVectors(a, b);
522
523 auto c = a & b;
524
525 for (auto i = 0; i < length; ++i)
526 {
527 TValue a_i = -3 + i * 3, b_i = length - i;
528 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " & " << (int)b[i] << std::endl;
529 SEQAN_ASSERT_EQ(c[i], a[i] & b[i]);
530 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i & b_i));
531 }
532 }
533
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseAndAssign)534 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseAndAssign)
535 {
536 using namespace seqan;
537 using TSimdVector = typename TestFixture::TSimdVector;
538 using TValue = typename TestFixture::TValue;
539 constexpr auto length = TestFixture::LENGTH;
540
541 TSimdVector a{0u}, b{0u}, c{0u};
542 fillVectors(a, b);
543
544 c = a;
545 c &= b;
546
547 for (auto i = 0; i < length; ++i)
548 {
549 TValue a_i = -3 + i * 3, b_i = length - i;
550 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " & " << (int)b[i] << std::endl;
551 SEQAN_ASSERT_EQ(c[i], a[i] & b[i]);
552 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i & b_i));
553 }
554 }
555
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseNot)556 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseNot)
557 {
558 using namespace seqan;
559 using TSimdVector = typename TestFixture::TSimdVector;
560 using TValue = typename TestFixture::TValue;
561 constexpr auto length = TestFixture::LENGTH;
562
563 TSimdVector a{0u}, b{0u};
564 fillVectors(a, b);
565
566 auto c = ~a;
567
568 for (auto i = 0; i < length; ++i)
569 {
570 TValue a_i = -3 + i * 3;
571 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = ~" << (int)a[i] << std::endl;
572 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(~a[i]));
573 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(~a_i));
574 }
575 }
576
SEQAN_TYPED_TEST(SimdVectorTestCommon,Addition)577 SEQAN_TYPED_TEST(SimdVectorTestCommon, Addition)
578 {
579 using namespace seqan;
580 using TSimdVector = typename TestFixture::TSimdVector;
581 using TValue = typename TestFixture::TValue;
582 constexpr auto length = TestFixture::LENGTH;
583
584 TSimdVector a{0u}, b{0u};
585 fillVectors(a, b);
586
587 auto c = a + b;
588
589 for (auto i = 0; i < length; ++i)
590 {
591 TValue a_i = -3 + i * 3, b_i = length - i;
592 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " + " << (int)b[i] << std::endl;
593 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a[i] + b[i]));
594 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i + b_i));
595 }
596 }
597
SEQAN_TYPED_TEST(SimdVectorTestCommon,Subtraction)598 SEQAN_TYPED_TEST(SimdVectorTestCommon, Subtraction)
599 {
600 using namespace seqan;
601 using TSimdVector = typename TestFixture::TSimdVector;
602 using TValue = typename TestFixture::TValue;
603 constexpr auto length = TestFixture::LENGTH;
604
605 TSimdVector a{0u}, b{0u};
606 fillVectors(a, b);
607
608 auto c = a - b;
609
610 for (auto i = 0; i < length; ++i)
611 {
612 TValue a_i = -3 + i * 3, b_i = length - i;
613 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " - " << (int)b[i] << std::endl;
614 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a[i] - b[i]));
615 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i - b_i));
616 }
617 }
618
SEQAN_TYPED_TEST(SimdVectorTestCommon,Multiplication)619 SEQAN_TYPED_TEST(SimdVectorTestCommon, Multiplication)
620 {
621 using namespace seqan;
622 using TSimdVector = typename TestFixture::TSimdVector;
623 using TValue = typename TestFixture::TValue;
624 constexpr auto length = TestFixture::LENGTH;
625
626 TSimdVector a{0u}, b{0u};
627 fillVectors(a, b);
628
629 auto c = a * b;
630
631 for (size_t i = 0; i < length; ++i)
632 {
633 TValue a_i = -3 + i * 3, b_i = length - i;
634 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " * " << (int)b[i] << std::endl;
635 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a[i] * b[i]));
636 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i * b_i));
637 }
638 }
639
SEQAN_TYPED_TEST(SimdVectorTestCommon,Division)640 SEQAN_TYPED_TEST(SimdVectorTestCommon, Division)
641 {
642 using namespace seqan;
643 using TSimdVector = typename TestFixture::TSimdVector;
644 using TValue = typename TestFixture::TValue;
645 constexpr auto length = TestFixture::LENGTH;
646
647 TSimdVector a{0u}, b{0u};
648 fillVectors(a, b);
649
650 auto c = a / b;
651
652 for (auto i = 0; i < length; ++i)
653 {
654 TValue a_i = -3 + i * 3, b_i = length - i;
655 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " / " << (int)b[i] << std::endl;
656 SEQAN_ASSERT_EQ(c[i], a[i] / b[i]);
657 SEQAN_ASSERT_EQ(c[i], a_i / b_i);
658 }
659 }
660
SEQAN_TYPED_TEST(SimdVectorTestCommon,BitwiseAndNot)661 SEQAN_TYPED_TEST(SimdVectorTestCommon, BitwiseAndNot)
662 {
663 using namespace seqan;
664 using TSimdVector = typename TestFixture::TSimdVector;
665 using TValue = typename TestFixture::TValue;
666 constexpr auto length = TestFixture::LENGTH;
667
668 TSimdVector a{0u}, b{0u};
669 fillVectors(a, b);
670
671 auto c = andNot(a, b);
672
673 for (auto i = 0; i < length; ++i)
674 {
675 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = (~" << (int)a[i] << ") & " << (int)b[i] << std::endl;
676 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(~a[i] & b[i]));
677 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(~(-3 + i * 3) & (length - i)));
678 }
679 }
680
SEQAN_TYPED_TEST(SimdVectorTestCommon,ShiftRightLogical)681 SEQAN_TYPED_TEST(SimdVectorTestCommon, ShiftRightLogical)
682 {
683 using namespace seqan;
684 using TSimdVector = typename TestFixture::TSimdVector;
685 using TValue = typename TestFixture::TValue;
686 constexpr auto length = TestFixture::LENGTH;
687
688 TSimdVector a{0u}, b{0u};
689 fillVectors(a, b);
690
691 // ensure that a >= 0, because (-3) >> 2 has undefined behavior according to
692 // C++ 11 standard.
693 a = a + createVector<TSimdVector>(3);
694
695 auto c = shiftRightLogical(a, 2);
696
697 for (auto i = 0; i < length; ++i)
698 {
699 TValue a_i = i * 3;
700 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " >> " << (int)2 << std::endl;
701 SEQAN_ASSERT_EQ(c[i], a[i] >> 2);
702 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a_i >> 2));
703 }
704 }
705
SEQAN_TYPED_TEST(SimdVectorTestCommon,Blend)706 SEQAN_TYPED_TEST(SimdVectorTestCommon, Blend)
707 {
708 using namespace seqan;
709 using TSimdVector = typename TestFixture::TSimdVector;
710 using TValue = typename TestFixture::TValue;
711 constexpr auto length = TestFixture::LENGTH;
712
713 TSimdVector a{0u}, b{0u};
714 fillVectors(a, b);
715
716 auto c = blend(b, a, cmpGt(a, b));
717
718 for (auto i = 0; i < length; ++i)
719 {
720 TValue a_i = -3 + i * 3, b_i = length - i;
721 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << " > " << (int)b[i] << " ? " << (int)a[i] << " : " << (int)b[i] << std::endl;
722 SEQAN_ASSERT_EQ(c[i], a[i] > b[i] ? (TValue)a[i] : (TValue)b[i]);
723 SEQAN_ASSERT_EQ(c[i], a_i > b_i ? a_i : b_i);
724 }
725 }
726
SEQAN_TYPED_TEST(SimdVectorTestCommon,Storeu)727 SEQAN_TYPED_TEST(SimdVectorTestCommon, Storeu)
728 {
729 using namespace seqan;
730 using TSimdVector = typename TestFixture::TSimdVector;
731 using TValue = typename TestFixture::TValue;
732 constexpr auto length = TestFixture::LENGTH;
733
734 TSimdVector a{0u}, b{0u};
735 fillVectors(a, b);
736
737 TValue c[length];
738 storeu(c, a);
739
740 for (auto i = 0; i < length; ++i)
741 {
742 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << std::endl;
743 SEQAN_ASSERT_EQ(c[i], a[i]);
744 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(-3 + i * 3));
745 }
746 }
747
SEQAN_TYPED_TEST(SimdVectorTestCommon,Load)748 SEQAN_TYPED_TEST(SimdVectorTestCommon, Load)
749 {
750 using namespace seqan;
751 using TSimdVector = typename TestFixture::TSimdVector;
752 using TValue = typename TestFixture::TValue;
753 constexpr auto length = TestFixture::LENGTH;
754
755 TSimdVector a{0u}, c{0u};
756 fillVectors(a, c);
757
758 alignas(TSimdVector) TValue b[length];
759 storeu(b, a);
760 c = load<TSimdVector>(b);
761
762 for (auto i = 0; i < length; ++i)
763 {
764 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[i] << std::endl;
765 SEQAN_ASSERT_EQ(c[i], a[i]);
766 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(-3 + i * 3));
767 }
768 }
769
SEQAN_TYPED_TEST(SimdVectorTestCommon,Gather)770 SEQAN_TYPED_TEST(SimdVectorTestCommon, Gather)
771 {
772 using namespace seqan;
773 using TSimdVector = typename TestFixture::TSimdVector;
774 using TValue = typename TestFixture::TValue;
775 constexpr auto length = TestFixture::LENGTH;
776
777 TSimdVector a{0u}, idx{0u};
778 fillVectors(a, idx);
779 reverseIndexSequence(idx, length);
780
781 TValue b[length];
782 storeu(b, a);
783 auto c = gather(b, idx);
784
785 for (auto i = 0; i < length; ++i)
786 {
787 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[idx[i]] << std::endl;
788 SEQAN_ASSERT_EQ(c[i], a[idx[i]]);
789 SEQAN_ASSERT_EQ(c[i], a[length - i - 1]);
790 }
791 }
792
SEQAN_TYPED_TEST(SimdVectorTestCommon,ShuffleConstant1)793 SEQAN_TYPED_TEST(SimdVectorTestCommon, ShuffleConstant1)
794 {
795 using namespace seqan;
796 using TSimdVector = typename TestFixture::TSimdVector;
797 constexpr auto length = TestFixture::LENGTH;
798 typedef typename SimdSwizzleVector<TSimdVector>::Type TSimdSwizzleVector;
799
800 TSimdVector a{0u}, b{0u};
801 auto idx = createVector<TSimdSwizzleVector>(1);
802 fillVectors(a, b);
803
804 auto c = shuffleVector(a, idx);
805
806 for (auto i = 0; i < length; ++i)
807 {
808 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[idx[i]] << ", idx: " << (int)idx[i] << std::endl;
809 SEQAN_ASSERT_EQ(c[i], a[idx[i]]);
810 SEQAN_ASSERT_EQ(c[i], a[1]);
811 }
812 }
813
SEQAN_TYPED_TEST(SimdVectorTestCommon,ShuffleConstant2)814 SEQAN_TYPED_TEST(SimdVectorTestCommon, ShuffleConstant2)
815 {
816 using namespace seqan;
817 using TSimdVector = typename TestFixture::TSimdVector;
818 constexpr auto length = TestFixture::LENGTH;
819 typedef typename SimdSwizzleVector<TSimdVector>::Type TSimdSwizzleVector;
820
821 TSimdVector a{0u}, b{0u};
822 auto idx = createVector<TSimdSwizzleVector>(length - 2);
823 fillVectors(a, b);
824
825 auto c = shuffleVector(a, idx);
826
827 for (auto i = 0; i < length; ++i)
828 {
829 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[idx[i]] << ", idx: " << (int)idx[i] << std::endl;
830 SEQAN_ASSERT_EQ(c[i], a[idx[i]]);
831 SEQAN_ASSERT_EQ(c[i], a[length-2]);
832 }
833 }
834
SEQAN_TYPED_TEST(SimdVectorTestCommon,Shuffle)835 SEQAN_TYPED_TEST(SimdVectorTestCommon, Shuffle)
836 {
837 using namespace seqan;
838 using TSimdVector = typename TestFixture::TSimdVector;
839 constexpr auto length = TestFixture::LENGTH;
840 typedef typename SimdSwizzleVector<TSimdVector>::Type TSimdSwizzleVector;
841
842 TSimdVector a{0u}, b{0u};
843 TSimdSwizzleVector idx{0u};
844 fillVectors(a, b);
845 reverseIndexSequence(idx, length);
846
847 auto c = shuffleVector(a, idx);
848
849 for (auto i = 0; i < length; ++i)
850 {
851 // std::cout << "DEBUG: " << i << " / " << length << ": " << (int)c[i] << " = " << (int)a[idx[i]] << ", idx: " << (int)idx[i] << std::endl;
852 SEQAN_ASSERT_EQ(c[i], a[idx[i]]);
853 SEQAN_ASSERT_EQ(c[i], a[length - i - 1]);
854 }
855 }
856
857 template <typename TSimdVector, typename TValue, typename TArrayValue>
test_gather_array()858 inline void test_gather_array()
859 {
860 using namespace seqan;
861 constexpr auto length = LENGTH<TSimdVector>::VALUE;
862
863 TSimdVector idx{0u};
864 reverseIndexSequence(idx, length);
865
866 TArrayValue a[2*length];
867
868 // fill gather array
869 for (auto i = 0; i < 2*length; ++i)
870 {
871 a[i] = (i-1)*3;
872 }
873
874 auto c = gather(a, idx);
875
876 for (auto i = 0; i < length; ++i)
877 {
878 // std::cout << "DEBUG: " << i << " / " << length << ": " << (TValue)c[i] << " = " << (TValue)a[idx[i]] << std::endl;
879 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a[idx[i]]));
880 SEQAN_ASSERT_EQ(c[i], static_cast<TValue>(a[length - i - 1]));
881 }
882 }
883
SEQAN_TYPED_TEST(SimdVectorTestGather,CharArray)884 SEQAN_TYPED_TEST(SimdVectorTestGather, CharArray)
885 {
886 test_gather_array<
887 typename TestFixture::TSimdVector,
888 typename TestFixture::TValue,
889 int8_t
890 >();
891 }
892
SEQAN_TYPED_TEST(SimdVectorTestGather,ShortArray)893 SEQAN_TYPED_TEST(SimdVectorTestGather, ShortArray)
894 {
895 test_gather_array<
896 typename TestFixture::TSimdVector,
897 typename TestFixture::TValue,
898 int16_t
899 >();
900 }
901
SEQAN_TYPED_TEST(SimdVectorTestGather,IntArray)902 SEQAN_TYPED_TEST(SimdVectorTestGather, IntArray)
903 {
904 test_gather_array<
905 typename TestFixture::TSimdVector,
906 typename TestFixture::TValue,
907 int32_t
908 >();
909 }
910
SEQAN_TYPED_TEST(SimdVectorTestGather,LongArray)911 SEQAN_TYPED_TEST(SimdVectorTestGather, LongArray)
912 {
913 test_gather_array<
914 typename TestFixture::TSimdVector,
915 typename TestFixture::TValue,
916 int64_t
917 >();
918 }
919
SEQAN_TYPED_TEST(SimdVectorTestGather,UCharArray)920 SEQAN_TYPED_TEST(SimdVectorTestGather, UCharArray)
921 {
922 test_gather_array<
923 typename TestFixture::TSimdVector,
924 typename TestFixture::TValue,
925 uint8_t
926 >();
927 }
928
SEQAN_TYPED_TEST(SimdVectorTestGather,UShortArray)929 SEQAN_TYPED_TEST(SimdVectorTestGather, UShortArray)
930 {
931 test_gather_array<
932 typename TestFixture::TSimdVector,
933 typename TestFixture::TValue,
934 uint16_t
935 >();
936 }
937
SEQAN_TYPED_TEST(SimdVectorTestGather,UIntArray)938 SEQAN_TYPED_TEST(SimdVectorTestGather, UIntArray)
939 {
940 test_gather_array<
941 typename TestFixture::TSimdVector,
942 typename TestFixture::TValue,
943 uint32_t
944 >();
945 }
946
SEQAN_TYPED_TEST(SimdVectorTestGather,ULongArray)947 SEQAN_TYPED_TEST(SimdVectorTestGather, ULongArray)
948 {
949 test_gather_array<
950 typename TestFixture::TSimdVector,
951 typename TestFixture::TValue,
952 uint64_t
953 >();
954 }
955
956 #ifdef __SSE4_1__
957
SEQAN_DEFINE_TEST(test_simd_transpose_8x8)958 SEQAN_DEFINE_TEST(test_simd_transpose_8x8)
959 {
960 seqan::test_matrix_transpose<8, seqan::SimdVector<unsigned char, 8>::Type>();
961 }
962
SEQAN_DEFINE_TEST(test_simd_transpose_16x16)963 SEQAN_DEFINE_TEST(test_simd_transpose_16x16)
964 {
965 seqan::test_matrix_transpose<16, seqan::SimdVector<unsigned char, 16>::Type>();
966 }
967
968 #endif // #ifdef __SSE4_1__
969 #ifdef __AVX2__
970
SEQAN_DEFINE_TEST(test_simd_transpose_32x32)971 SEQAN_DEFINE_TEST(test_simd_transpose_32x32)
972 {
973 seqan::test_matrix_transpose<32, seqan::SimdVector<unsigned char, 32>::Type >();
974 }
975
976 #endif // #ifdef __AVX2__
977 #endif // SEQAN_SIMD_ENABLED
978
979 #endif // #ifndef SEQAN_CORE_TESTS_SIMD_TEST_SIMD_VECTOR_H_
980