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