Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_TinyVec.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef STOKHOS_TINY_VEC_HPP
11 #define STOKHOS_TINY_VEC_HPP
12 
13 #include "Stokhos_ConfigDefs.h"
14 #if defined(HAVE_STOKHOS_INTRINSICS) && !defined( __CUDACC__ )
15 
16 extern "C" {
17 #include <immintrin.h>
18 }
19 
20 #endif
21 
22 #include "Kokkos_Macros.hpp"
23 
24 namespace Stokhos {
25 
26 #if defined(__INTEL_COMPILER) && ! defined( __CUDA_ARCH__)
27 
28 template <typename ValueType, int N, bool UseIntrinsics, bool Mask = false >
29 class TinyVec {
30 public:
31 
32  static const int Num = N;
33 
34  KOKKOS_INLINE_FUNCTION
35  TinyVec() {}
36 
37  KOKKOS_INLINE_FUNCTION
38  TinyVec(const ValueType a[]) {
39  load(a);
40  }
41 
42  template <typename OrdinalType>
43  KOKKOS_INLINE_FUNCTION
44  TinyVec(const ValueType a[], const OrdinalType idx[]) {
45  gather(a,idx);
46  }
47 
48  KOKKOS_INLINE_FUNCTION
49  TinyVec(const ValueType a) {
50  load(a);
51  }
52 
53  KOKKOS_INLINE_FUNCTION
54  TinyVec(const TinyVec& tv) {
55 #pragma ivdep
56 #pragma vector aligned
57  for (int i=0; i<Num; ++i)
58  v[i] = tv.v[i];
59  }
60 
61  KOKKOS_INLINE_FUNCTION
62  TinyVec& operator=(const TinyVec& tv) {
63 #pragma ivdep
64 #pragma vector aligned
65  for (int i=0; i<Num; ++i)
66  v[i] = tv.v[i];
67  return *this;
68  }
69 
70  KOKKOS_INLINE_FUNCTION
71  void load(const ValueType a[]) {
72 #pragma ivdep
73 #pragma vector aligned
74  for (int i=0; i<Num; ++i)
75  v[i] = a[i];
76  }
77 
78  KOKKOS_INLINE_FUNCTION
79  void load(const ValueType a) {
80 #pragma ivdep
81 #pragma vector aligned
82  for (int i=0; i<Num; ++i)
83  v[i] = a;
84  }
85 
86  KOKKOS_INLINE_FUNCTION
87  void aligned_load(const ValueType a[]) {
88 #pragma ivdep
89 #pragma vector aligned
90  for (int i=0; i<Num; ++i)
91  v[i] = a[i];
92  }
93 
94  template <typename OrdinalType>
95  KOKKOS_INLINE_FUNCTION
96  void gather(const ValueType a[], const OrdinalType idx[]) {
97 #pragma ivdep
98 #pragma vector aligned
99  for (int i=0; i<Num; ++i)
100  v[i] = a[idx[i]];
101  }
102 
103  KOKKOS_INLINE_FUNCTION
104  void scatter(ValueType a[]) const {
105 #pragma ivdep
106 #pragma vector aligned
107  for (int i=0; i<Num; ++i)
108  a[i] = v[i];
109  }
110 
111  KOKKOS_INLINE_FUNCTION
112  void aligned_scatter(ValueType a[]) const {
113 #pragma ivdep
114 #pragma vector aligned
115  for (int i=0; i<Num; ++i)
116  a[i] = v[i];
117  }
118 
119  KOKKOS_INLINE_FUNCTION
120  void zero() {
121 #pragma ivdep
122 #pragma vector aligned
123  for (int i=0; i<Num; ++i)
124  v[i] = ValueType(0.0);
125  }
126 
127  KOKKOS_INLINE_FUNCTION
128  void plus_equal(const TinyVec& t) {
129 #pragma ivdep
130 #pragma vector aligned
131  for (int i=0; i<Num; ++i)
132  v[i] += t.v[i];
133  }
134 
135  KOKKOS_INLINE_FUNCTION
136  void times_equal(const TinyVec& t) {
137 #pragma ivdep
138 #pragma vector aligned
139  for (int i=0; i<Num; ++i)
140  v[i] *= t.v[i];
141  }
142 
143  // *this = *this + t1 * t2
144  KOKKOS_INLINE_FUNCTION
145  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
146 #pragma ivdep
147 #pragma vector aligned
148  for (int i=0; i<Num; ++i)
149  v[i] += t1.v[i]*t2.v[i];
150  }
151 
152  KOKKOS_INLINE_FUNCTION
153  ValueType sum() const {
154  ValueType s(0.0);
155 #pragma ivdep
156 #pragma vector aligned
157  for (int i=0; i<Num; ++i)
158  s += v[i];
159  return s;
160  }
161 
162 private:
163  ValueType v[Num] __attribute__((aligned(64)));
164 };
165 
166 template <typename ValueType, int N, bool UseIntrinsics >
167 class TinyVec<ValueType,N,UseIntrinsics,true> {
168 public:
169 
170  static const int Num = N;
171 
172  KOKKOS_INLINE_FUNCTION
173  TinyVec(int size) { sz = size; }
174 
175  KOKKOS_INLINE_FUNCTION
176  TinyVec(const ValueType a[], int size) {
177  sz = size;
178  load(a);
179  }
180 
181  template <typename OrdinalType>
182  KOKKOS_INLINE_FUNCTION
183  TinyVec(const ValueType a[], const OrdinalType idx[], int size) {
184  sz = size;
185  gather(a,idx);
186  }
187 
188  KOKKOS_INLINE_FUNCTION
189  TinyVec(const ValueType a, int size) {
190  sz = size;
191  load(a);
192  }
193 
194  KOKKOS_INLINE_FUNCTION
195  TinyVec(const TinyVec& tv) {
196  sz = tv.sz;
197 #pragma ivdep
198 #pragma vector aligned
199  for (int i=0; i<sz; ++i)
200  v[i] = tv.v[i];
201  }
202 
203  KOKKOS_INLINE_FUNCTION
204  TinyVec& operator=(const TinyVec& tv) {
205  sz = tv.sz;
206 #pragma ivdep
207 #pragma vector aligned
208  for (int i=0; i<sz; ++i)
209  v[i] = tv.v[i];
210  return *this;
211  }
212 
213  KOKKOS_INLINE_FUNCTION
214  void load(const ValueType a[]) {
215 #pragma ivdep
216 #pragma vector aligned
217  for (int i=0; i<sz; ++i)
218  v[i] = a[i];
219  }
220 
221  KOKKOS_INLINE_FUNCTION
222  void load(const ValueType a) {
223 #pragma ivdep
224 #pragma vector aligned
225  for (int i=0; i<sz; ++i)
226  v[i] = a;
227  }
228 
229  KOKKOS_INLINE_FUNCTION
230  void aligned_load(const ValueType a[]) {
231 #pragma ivdep
232 #pragma vector aligned
233  for (int i=0; i<sz; ++i)
234  v[i] = a[i];
235  }
236 
237  template <typename OrdinalType>
238  KOKKOS_INLINE_FUNCTION
239  void gather(const ValueType a[], const OrdinalType idx[]) {
240 #pragma ivdep
241 #pragma vector aligned
242  for (int i=0; i<sz; ++i)
243  v[i] = a[idx[i]];
244  }
245 
246  KOKKOS_INLINE_FUNCTION
247  void scatter(ValueType a[]) const {
248 #pragma ivdep
249 #pragma vector aligned
250  for (int i=0; i<sz; ++i)
251  a[i] = v[i];
252  }
253 
254  KOKKOS_INLINE_FUNCTION
255  void aligned_scatter(ValueType a[]) const {
256 #pragma ivdep
257 #pragma vector aligned
258  for (int i=0; i<sz; ++i)
259  a[i] = v[i];
260  }
261 
262  KOKKOS_INLINE_FUNCTION
263  void zero() {
264 #pragma ivdep
265 #pragma vector aligned
266  for (int i=0; i<sz; ++i)
267  v[i] = ValueType(0.0);
268  }
269 
270  KOKKOS_INLINE_FUNCTION
271  void plus_equal(const TinyVec& t) {
272 #pragma ivdep
273 #pragma vector aligned
274  for (int i=0; i<sz; ++i)
275  v[i] += t.v[i];
276  }
277 
278  KOKKOS_INLINE_FUNCTION
279  void times_equal(const TinyVec& t) {
280 #pragma ivdep
281 #pragma vector aligned
282  for (int i=0; i<sz; ++i)
283  v[i] *= t.v[i];
284  }
285 
286  // *this = *this + t1 * t2
287  KOKKOS_INLINE_FUNCTION
288  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
289 #pragma ivdep
290 #pragma vector aligned
291  for (int i=0; i<sz; ++i)
292  v[i] += t1.v[i]*t2.v[i];
293  }
294 
295  KOKKOS_INLINE_FUNCTION
296  ValueType sum() const {
297  ValueType s(0.0);
298 #pragma ivdep
299 #pragma vector aligned
300  for (int i=0; i<sz; ++i)
301  s += v[i];
302  return s;
303  }
304 
305 private:
306  ValueType v[Num] __attribute__((aligned(64)));
307  int sz;
308 };
309 
310 #else
311 
312 template <typename ValueType, int N, bool UseIntrinsics, bool Mask = false >
313 class TinyVec {
314 public:
315 
316  static const int Num = N;
317 
318  KOKKOS_INLINE_FUNCTION
319  TinyVec() {}
320 
321  KOKKOS_INLINE_FUNCTION
322  TinyVec(const ValueType a[]) {
323  load(a);
324  }
325 
326  template <typename OrdinalType>
327  KOKKOS_INLINE_FUNCTION
328  TinyVec(const ValueType a[], const OrdinalType idx[]) {
329  gather(a,idx);
330  }
331 
332  KOKKOS_INLINE_FUNCTION
333  TinyVec(const ValueType a) {
334  load(a);
335  }
336 
337  KOKKOS_INLINE_FUNCTION
338  TinyVec(const TinyVec& tv) {
339  for (int i=0; i<Num; ++i)
340  v[i] = tv.v[i];
341  }
342 
343  KOKKOS_INLINE_FUNCTION
344  TinyVec& operator=(const TinyVec& tv) {
345  for (int i=0; i<Num; ++i)
346  v[i] = tv.v[i];
347  return *this;
348  }
349 
350  KOKKOS_INLINE_FUNCTION
351  void load(const ValueType a[]) {
352  for (int i=0; i<Num; ++i)
353  v[i] = a[i];
354  }
355 
356  KOKKOS_INLINE_FUNCTION
357  void load(const ValueType a) {
358  for (int i=0; i<Num; ++i)
359  v[i] = a;
360  }
361 
362  KOKKOS_INLINE_FUNCTION
363  void aligned_load(const ValueType a[]) {
364  for (int i=0; i<Num; ++i)
365  v[i] = a[i];
366  }
367 
368  template <typename OrdinalType>
369  KOKKOS_INLINE_FUNCTION
370  void gather(const ValueType a[], const OrdinalType idx[]) {
371  for (int i=0; i<Num; ++i)
372  v[i] = a[idx[i]];
373  }
374 
375  KOKKOS_INLINE_FUNCTION
376  void scatter(ValueType a[]) const {
377  for (int i=0; i<Num; ++i)
378  a[i] = v[i];
379  }
380 
381  KOKKOS_INLINE_FUNCTION
382  void aligned_scatter(ValueType a[]) const {
383  for (int i=0; i<Num; ++i)
384  a[i] = v[i];
385  }
386 
387  KOKKOS_INLINE_FUNCTION
388  void zero() {
389  for (int i=0; i<Num; ++i)
390  v[i] = ValueType(0.0);
391  }
392 
393  KOKKOS_INLINE_FUNCTION
394  void plus_equal(const TinyVec& t) {
395  for (int i=0; i<Num; ++i)
396  v[i] += t.v[i];
397  }
398 
399  KOKKOS_INLINE_FUNCTION
400  void times_equal(const TinyVec& t) {
401  for (int i=0; i<Num; ++i)
402  v[i] *= t.v[i];
403  }
404 
405  // *this = *this + t1 * t2
406  KOKKOS_INLINE_FUNCTION
407  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
408  for (int i=0; i<Num; ++i)
409  v[i] += t1.v[i]*t2.v[i];
410  }
411 
412  KOKKOS_INLINE_FUNCTION
413  ValueType sum() const {
414  ValueType s(0.0);
415  for (int i=0; i<Num; ++i)
416  s += v[i];
417  return s;
418  }
419 
420 private:
421  ValueType v[Num];
422 };
423 
424 template <typename ValueType, int N, bool UseIntrinsics >
425 class TinyVec<ValueType,N,UseIntrinsics,true> {
426 public:
427 
428  static const int Num = N;
429 
430  KOKKOS_INLINE_FUNCTION
431  TinyVec(int size) { sz = size; }
432 
433  KOKKOS_INLINE_FUNCTION
434  TinyVec(const ValueType a[], int size) {
435  sz = size;
436  load(a);
437  }
438 
439  template <typename OrdinalType>
440  KOKKOS_INLINE_FUNCTION
441  TinyVec(const ValueType a[], const OrdinalType idx[], int size) {
442  sz = size;
443  gather(a,idx);
444  }
445 
446  KOKKOS_INLINE_FUNCTION
447  TinyVec(const ValueType a, int size) {
448  sz = size;
449  load(a);
450  }
451 
452  KOKKOS_INLINE_FUNCTION
453  TinyVec(const TinyVec& tv) {
454  sz = tv.sz;
455  for (int i=0; i<sz; ++i)
456  v[i] = tv.v[i];
457  }
458 
459  KOKKOS_INLINE_FUNCTION
460  TinyVec& operator=(const TinyVec& tv) {
461  sz = tv.sz;
462  for (int i=0; i<sz; ++i)
463  v[i] = tv.v[i];
464  return *this;
465  }
466 
467  KOKKOS_INLINE_FUNCTION
468  void load(const ValueType a[]) {
469  for (int i=0; i<sz; ++i)
470  v[i] = a[i];
471  }
472 
473  KOKKOS_INLINE_FUNCTION
474  void load(const ValueType a) {
475  for (int i=0; i<sz; ++i)
476  v[i] = a;
477  }
478 
479  KOKKOS_INLINE_FUNCTION
480  void aligned_load(const ValueType a[]) {
481  for (int i=0; i<sz; ++i)
482  v[i] = a[i];
483  }
484 
485  template <typename OrdinalType>
486  KOKKOS_INLINE_FUNCTION
487  void gather(const ValueType a[], const OrdinalType idx[]) {
488  for (int i=0; i<sz; ++i)
489  v[i] = a[idx[i]];
490  }
491 
492  KOKKOS_INLINE_FUNCTION
493  void scatter(ValueType a[]) const {
494  for (int i=0; i<sz; ++i)
495  a[i] = v[i];
496  }
497 
498  KOKKOS_INLINE_FUNCTION
499  void aligned_scatter(ValueType a[]) const {
500  for (int i=0; i<sz; ++i)
501  a[i] = v[i];
502  }
503 
504  KOKKOS_INLINE_FUNCTION
505  void zero() {
506  for (int i=0; i<sz; ++i)
507  v[i] = ValueType(0.0);
508  }
509 
510  KOKKOS_INLINE_FUNCTION
511  void plus_equal(const TinyVec& t) {
512  for (int i=0; i<sz; ++i)
513  v[i] += t.v[i];
514  }
515 
516  KOKKOS_INLINE_FUNCTION
517  void times_equal(const TinyVec& t) {
518  for (int i=0; i<sz; ++i)
519  v[i] *= t.v[i];
520  }
521 
522  // *this = *this + t1 * t2
523  KOKKOS_INLINE_FUNCTION
524  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
525  for (int i=0; i<sz; ++i)
526  v[i] += t1.v[i]*t2.v[i];
527  }
528 
529  KOKKOS_INLINE_FUNCTION
530  ValueType sum() const {
531  ValueType s(0.0);
532  for (int i=0; i<sz; ++i)
533  s += v[i];
534  return s;
535  }
536 
537 private:
538  ValueType v[Num];
539  int sz;
540 };
541 
542 #endif
543 
544 #if defined(HAVE_STOKHOS_INTRINSICS) && !defined( __CUDACC__ )
545 
546 #ifdef __SSE2__
547 template <>
548 class TinyVec<double,2,true,false> {
549 public:
550 
551  typedef double ValueType;
552  static const int Num = 2;
553 
554  TinyVec() {}
555 
556  TinyVec(const ValueType a[]) {
557  load(a);
558  }
559 
560  template <typename OrdinalType>
561  TinyVec(const ValueType a[], const OrdinalType idx[]) {
562  gather(a,idx);
563  }
564 
565  TinyVec(const ValueType a) {
566  load(a);
567  }
568 
569  TinyVec(const TinyVec& tv) {
570  v = tv.v;
571  }
572 
573  TinyVec& operator=(const TinyVec& tv) {
574  v = tv.v;
575  return *this;
576  }
577 
578  void load(const ValueType a[]) {
579  v = _mm_set_pd(a[1], a[0]);
580  }
581 
582  void load(const ValueType a) {
583  v = _mm_set1_pd(a);
584  }
585 
586  void aligned_load(const ValueType a[]) {
587  v = _mm_load_pd(a);
588  }
589 
590  template <typename OrdinalType>
591  void gather(const ValueType a[], const OrdinalType idx[]) {
592  v = _mm_set_pd(a[idx[1]], a[idx[0]]);
593  }
594 
595  void scatter(ValueType a[]) const {
596  _mm_storel_pd(&a[0], v);
597  _mm_storeh_pd(&a[1], v);
598  }
599 
600  void aligned_scatter(ValueType a[]) const {
601  _mm_store_pd(a, v);
602  }
603 
604  void zero() {
605  v = _mm_setzero_pd();
606  }
607 
608  void plus_equal(const TinyVec& t) {
609  v = _mm_add_pd(v, t.v);
610  }
611 
612  void times_equal(const TinyVec& t) {
613  v = _mm_mul_pd(v, t.v);
614  }
615 
616  // *this = *this + t1 * t2
617  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
618  __m128d t = _mm_mul_pd(t1.v, t2.v);
619  v = _mm_add_pd(v, t);
620  }
621 
622  ValueType sum() const {
623  ValueType a[Num];
624  scatter(a);
625  return a[0]+a[1];
626  }
627 
628 private:
629  __m128d v;
630 };
631 #endif
632 
633 #ifdef __AVX__
634 template <>
635 class TinyVec<float,8,true,false> {
636 public:
637 
638  typedef float ValueType;
639  static const int Num = 8;
640 
641  TinyVec() {}
642 
643  TinyVec(const ValueType a[]) {
644  aligned_load(a);
645  }
646 
647  template <typename OrdinalType>
648  TinyVec(const ValueType a[], const OrdinalType idx[]) {
649  gather(a,idx);
650  }
651 
652  TinyVec(const ValueType a) {
653  load(a);
654  }
655 
656  TinyVec(const TinyVec& tv) {
657  v = tv.v;
658  }
659 
660  TinyVec& operator=(const TinyVec& tv) {
661  v = tv.v;
662  return *this;
663  }
664 
665  void load(const ValueType a[]) {
666  v = _mm256_loadu_ps(a);
667  }
668 
669  void load(const ValueType a) {
670  v = _mm256_set1_ps(a);
671  }
672 
673  void aligned_load(const ValueType a[]) {
674  v = _mm256_load_ps(a);
675  }
676 
677  template <typename OrdinalType>
678  void gather(const ValueType a[], const OrdinalType idx[]) {
679  __m128 v1 = _mm_set_ps(a[idx[3]], a[idx[2]], a[idx[1]], a[idx[0]]);
680  __m128 v2 = _mm_set_ps(a[idx[7]], a[idx[6]], a[idx[5]], a[idx[4]]);
681  v = _mm256_insertf128_ps(v, v1, 0);
682  v = _mm256_insertf128_ps(v, v2, 1);
683  }
684 
685  void scatter(ValueType a[]) const {
686  _mm256_storeu_ps(a, v);
687  }
688 
689  void aligned_scatter(ValueType a[]) const {
690  _mm256_store_ps(a, v);
691  }
692 
693  void zero() {
694  v = _mm256_setzero_ps();
695  }
696 
697  void plus_equal(const TinyVec& t) {
698  v = _mm256_add_ps(v, t.v);
699  }
700 
701  void times_equal(const TinyVec& t) {
702  v = _mm256_mul_ps(v, t.v);
703  }
704 
705  // *this = *this + t1 * t2
706  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
707  __m256 t = _mm256_mul_ps(t1.v, t2.v);
708  v = _mm256_add_ps(v, t);
709  }
710 
711  ValueType sum() {
712  __m256 s = _mm256_hadd_ps(v,v);
713  __m128 sl = _mm256_extractf128_ps(s, 0);
714  __m128 sh = _mm256_extractf128_ps(s, 1);
715  sl = _mm_add_ps(sl,sh);
716  sl = _mm_hadd_ps(sl,sl);
717  ValueType res;
718  _MM_EXTRACT_FLOAT(res, sl, 0);
719 
720  return res;
721  }
722 
723 private:
724  __m256 v;
725 };
726 
727 template <>
728 class TinyVec<double,4,true,false> {
729 public:
730 
731  typedef double ValueType;
732  static const int Num = 4;
733 
734  TinyVec() {}
735 
736  TinyVec(const ValueType a[]) {
737  aligned_load(a);
738  }
739 
740  template <typename OrdinalType>
741  TinyVec(const ValueType a[], const OrdinalType idx[]) {
742  gather(a,idx);
743  }
744 
745  TinyVec(const ValueType a) {
746  load(a);
747  }
748 
749  TinyVec(const TinyVec& tv) {
750  v = tv.v;
751  }
752 
753  TinyVec& operator=(const TinyVec& tv) {
754  v = tv.v;
755  return *this;
756  }
757 
758  void load(const ValueType a[]) {
759  v = _mm256_loadu_pd(a);
760  }
761 
762  void load(const ValueType a) {
763  v = _mm256_set1_pd(a);
764  }
765 
766  void aligned_load(const ValueType a[]) {
767  v = _mm256_load_pd(a);
768  }
769 
770  template <typename OrdinalType>
771  void gather(const ValueType a[], const OrdinalType idx[]) {
772  __m128d v1 = _mm_set_pd(a[idx[1]], a[idx[0]]);
773  __m128d v2 = _mm_set_pd(a[idx[3]], a[idx[2]]);
774  v = _mm256_insertf128_pd(v, v1, 0);
775  v = _mm256_insertf128_pd(v, v2, 1);
776  }
777 
778  void scatter(ValueType a[]) const {
779  _mm256_storeu_pd(a, v);
780  }
781 
782  void aligned_scatter(ValueType a[]) const {
783  _mm256_store_pd(a, v);
784  }
785 
786  void zero() {
787  v = _mm256_setzero_pd();
788  }
789 
790  void plus_equal(const TinyVec& t) {
791  v = _mm256_add_pd(v, t.v);
792  }
793 
794  void times_equal(const TinyVec& t) {
795  v = _mm256_mul_pd(v, t.v);
796  }
797 
798  // *this = *this + t1 * t2
799  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
800  __m256d t = _mm256_mul_pd(t1.v, t2.v);
801  v = _mm256_add_pd(v, t);
802  }
803 
804  ValueType sum() {
805  // ValueType a[Num];
806  // scatter(a);
807  // return a[0]+a[1]+a[2]+a[3];
808 
809  // __m128d vl = _mm256_extractf128_pd(v, 0); // v[0], v[1]
810  // __m128d vh = _mm256_extractf128_pd(v, 1); // v[2], v[3]
811  // vh = _mm_hadd_pd(vl, vh); // v[0]+v[1], v[2]+v[3]
812  // vh = _mm_hadd_pd(vh, vh); // v[0]+v[1]+v[2]+v[3], v[0]+v[1]+v[2]+v[3]
813  // ValueType res;
814  // _mm_storel_pd(&res, vh);
815  // return res;
816 
817  __m256d s = _mm256_hadd_pd(v,v); //v[0]+v[1] v[0]+v[1] v[2]+v[3] v[2]+v[3]
818  __m128d sl = _mm256_extractf128_pd(s, 0); //v[0]+v[1] v[0]+v[1]
819  __m128d sh = _mm256_extractf128_pd(s, 1); //v[2]+v[3] v[2]+v[3]
820  sl = _mm_add_pd(sl,sh); // v[0]+v[1]+v[2]+v[3] v[0]+v[1]+v[2]+v[3]
821  ValueType res;
822  _mm_storel_pd(&res, sl);
823  return res;
824  }
825 
826 private:
827  __m256d v;
828 };
829 
830 template <>
831 class TinyVec<double,8,true,false> {
832 public:
833 
834  typedef double ValueType;
835  static const int Num = 8;
836 
837  TinyVec() {}
838 
839  TinyVec(const ValueType a[]) {
840  load(a);
841  }
842 
843  template <typename OrdinalType>
844  TinyVec(const ValueType a[], const OrdinalType idx[]) {
845  gather(a,idx);
846  }
847 
848  TinyVec(const ValueType a) {
849  load(a);
850  }
851 
852  TinyVec(const TinyVec& tv) {
853  v1 = tv.v1; v2 = tv.v2;
854  }
855 
856  TinyVec& operator=(const TinyVec& tv) {
857  v1 = tv.v1; v2 = tv.v2;
858  return *this;
859  }
860 
861  void load(const ValueType a[]) {
862  v1 = _mm256_loadu_pd(a);
863  v2 = _mm256_loadu_pd(a+4);
864  }
865 
866  void load(const ValueType a) {
867  v1 = _mm256_set1_pd(a);
868  v2 = _mm256_set1_pd(a);
869  }
870 
871  void aligned_load(const ValueType a[]) {
872  v1 = _mm256_load_pd(a);
873  v2 = _mm256_load_pd(a+4);
874  }
875 
876  template <typename OrdinalType>
877  void gather(const ValueType a[], const OrdinalType idx[]) {
878  __m128d t1 = _mm_set_pd(a[idx[1]], a[idx[0]]);
879  __m128d t2 = _mm_set_pd(a[idx[3]], a[idx[2]]);
880  __m128d t3 = _mm_set_pd(a[idx[5]], a[idx[4]]);
881  __m128d t4 = _mm_set_pd(a[idx[7]], a[idx[6]]);
882  v1 = _mm256_insertf128_pd(v1, t1, 0);
883  v1 = _mm256_insertf128_pd(v1, t2, 1);
884  v2 = _mm256_insertf128_pd(v2, t3, 0);
885  v2 = _mm256_insertf128_pd(v2, t4, 1);
886  }
887 
888  void scatter(ValueType a[]) const {
889  _mm256_storeu_pd(a, v1);
890  _mm256_storeu_pd(a+4, v2);
891  }
892 
893  void aligned_scatter(ValueType a[]) const {
894  _mm256_store_pd(a, v1);
895  _mm256_store_pd(a+4, v2);
896  }
897 
898  void zero() {
899  v1 = _mm256_setzero_pd();
900  v2 = _mm256_setzero_pd();
901  }
902 
903  void plus_equal(const TinyVec& t) {
904  v1 = _mm256_add_pd(v1, t.v1);
905  v2 = _mm256_add_pd(v2, t.v2);
906  }
907 
908  void times_equal(const TinyVec& t) {
909  v1 = _mm256_mul_pd(v1, t.v1);
910  v2 = _mm256_mul_pd(v2, t.v2);
911  }
912 
913  // *this = *this + t1 * t2
914  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
915  __m256d t = _mm256_mul_pd(t1.v1, t2.v1);
916  __m256d s = _mm256_mul_pd(t1.v2, t2.v2);
917  v1 = _mm256_add_pd(v1, t);
918  v2 = _mm256_add_pd(v2, s);
919  }
920 
921  ValueType sum() {
922  __m256d s1 = _mm256_hadd_pd(v1,v1);//v[0]+v[1] v[0]+v[1] v[2]+v[3] v[2]+v[3]
923  __m128d s1l = _mm256_extractf128_pd(s1, 0); //v[0]+v[1] v[0]+v[1]
924  __m128d s1h = _mm256_extractf128_pd(s1, 1); //v[2]+v[3] v[2]+v[3]
925  s1l = _mm_add_pd(s1l,s1h); // v[0]+v[1]+v[2]+v[3] v[0]+v[1]+v[2]+v[3]
926  ValueType res1;
927  _mm_storel_pd(&res1, s1l);
928 
929  __m256d s2 = _mm256_hadd_pd(v2,v2);//v[0]+v[1] v[0]+v[1] v[2]+v[3] v[2]+v[3]
930  __m128d s2l = _mm256_extractf128_pd(s2, 0); //v[0]+v[1] v[0]+v[1]
931  __m128d s2h = _mm256_extractf128_pd(s2, 1); //v[2]+v[3] v[2]+v[3]
932  s2l = _mm_add_pd(s2l,s2h); // v[0]+v[1]+v[2]+v[3] v[0]+v[1]+v[2]+v[3]
933  ValueType res2;
934  _mm_storel_pd(&res2, s2l);
935 
936  return res1 + res2;
937  }
938 
939 private:
940  __m256d v1, v2;
941 };
942 #endif
943 
944 #if defined( __MIC__ )
945 template <>
946 class TinyVec<double,8,true,false> {
947 public:
948 
949  typedef double ValueType;
950  static const int Num = 8;
951 
952  TinyVec() {}
953 
954  TinyVec(const ValueType a[]) {
955  load(a);
956  }
957 
958  template <typename OrdinalType>
959  TinyVec(const ValueType a[], const OrdinalType idx[]) {
960  gather(a,idx);
961  }
962 
963  TinyVec(const ValueType a) {
964  load(a);
965  }
966 
967  TinyVec(const TinyVec& tv) {
968  v = tv.v;
969  }
970 
971  TinyVec& operator=(const TinyVec& tv) {
972  v = tv.v;
973  return *this;
974  }
975 
976  void load(const ValueType a[]) {
977  v = _mm512_load_pd(a);
978  }
979 
980  void load(const ValueType a) {
981  v = _mm512_set1_pd(a);
982  }
983 
984  void aligned_load(const ValueType a[]) {
985  v = _mm512_load_pd(a);
986  }
987 
988  template <typename OrdinalType>
989  void gather(const ValueType a[], const OrdinalType idx[]) {
990  __mmask16 mask = _mm512_int2mask(255);
991  __m512i vidx = _mm512_setzero_epi32();
992  vidx = _mm512_mask_load_epi32(vidx, mask, idx);
993  v = _mm512_i32logather_pd(vidx, a, 8);
994  }
995 
996  void scatter(ValueType a[]) const {
997  _mm512_store_pd(a, v);
998  }
999 
1000  void aligned_scatter(ValueType a[]) const {
1001  _mm512_store_pd(a, v);
1002  }
1003 
1004  void zero() {
1005  v = _mm512_setzero_pd();
1006  }
1007 
1008  void plus_equal(const TinyVec& t) {
1009  v = _mm512_add_pd(v, t.v);
1010  }
1011 
1012  void times_equal(const TinyVec& t) {
1013  v = _mm512_mul_pd(v, t.v);
1014  }
1015 
1016  // *this = *this + t1 * t2
1017  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
1018  v = _mm512_fmadd_pd(t1.v, t2.v, v);
1019  }
1020 
1021  ValueType sum() {
1022  return _mm512_reduce_add_pd(v);
1023  }
1024 
1025 private:
1026  __m512d v;
1027 };
1028 
1029 template <>
1030 class TinyVec<double,8,true,true> {
1031 public:
1032 
1033  typedef double ValueType;
1034  static const int Num = 8;
1035 
1036  TinyVec(const int sz) {
1037  mask = _mm512_int2mask((1 << (sz+1))-1);
1038  }
1039 
1040  TinyVec(const ValueType a[], const int sz) {
1041  mask = _mm512_int2mask((1 << (sz+1))-1);
1042  load(a);
1043  }
1044 
1045  template <typename OrdinalType>
1046  TinyVec(const ValueType a[], const OrdinalType idx[], const int sz) {
1047  mask = _mm512_int2mask((1 << (sz+1))-1);
1048  gather(a,idx);
1049  }
1050 
1051  TinyVec(const ValueType a, int sz) {
1052  mask = _mm512_int2mask((1 << (sz+1))-1);
1053  load(a);
1054  }
1055 
1056  TinyVec(const TinyVec& tv) {
1057  mask = tv.mask;
1058  v = tv.v;
1059  }
1060 
1061  TinyVec& operator=(const TinyVec& tv) {
1062  mask = tv.mask;
1063  v = tv.v;
1064  return *this;
1065  }
1066 
1067  void load(const ValueType a[]) {
1068  v = _mm512_setzero_pd();
1069  v = _mm512_mask_load_pd(v, mask, a);
1070  }
1071 
1072  void load(const ValueType a) {
1073  v = _mm512_set1_pd(a);
1074  }
1075 
1076  void aligned_load(const ValueType a[]) {
1077  v = _mm512_setzero_pd();
1078  v = _mm512_mask_load_pd(v, mask, a);
1079  }
1080 
1081  template <typename OrdinalType>
1082  void gather(const ValueType a[], const OrdinalType idx[]) {
1083  // We're assuming idx is an array of 32-bit integers
1084  // Load 16 integers into v1idx, then permute the high 256 bits
1085  // to the low 256 bits (DCBA -> BADC where 128 bit lanes are read right to
1086  // left). Then load the vectors into v1 and v2.
1087  // logather_pd only uses the low 256 bits in the index vector.
1088  __m512i vidx = _mm512_load_epi32(idx);
1089  v = _mm512_setzero_pd();
1090  v = _mm512_mask_i32logather_pd(v, mask, vidx, a, 8);
1091  }
1092 
1093  void scatter(ValueType a[]) const {
1094  _mm512_mask_store_pd(a, mask, v);
1095  }
1096 
1097  void aligned_scatter(ValueType a[]) const {
1098  _mm512_mask_store_pd(a, mask, v);
1099  }
1100 
1101  void zero() {
1102  v = _mm512_setzero_pd();
1103  }
1104 
1105  void plus_equal(const TinyVec& t) {
1106  v = _mm512_mask_add_pd(v, mask, v, t.v);
1107  }
1108 
1109  void times_equal(const TinyVec& t) {
1110  v = _mm512_mask_mul_pd(v, mask, v, t.v);
1111  }
1112 
1113  // *this = *this + t1 * t2
1114  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
1115  v = _mm512_mask3_fmadd_pd(t1.v, t2.v, v, mask);
1116  }
1117 
1118  ValueType sum() {
1119  return _mm512_mask_reduce_add_pd(mask, v);
1120  }
1121 
1122 private:
1123  __mmask8 mask;
1124  __m512d v;
1125 };
1126 
1127 template <>
1128 class TinyVec<double,16,true,false> {
1129 public:
1130 
1131  typedef double ValueType;
1132  static const int Num = 16;
1133 
1134  TinyVec() {}
1135 
1136  TinyVec(const ValueType a[]) {
1137  load(a);
1138  }
1139 
1140  template <typename OrdinalType>
1141  TinyVec(const ValueType a[], const OrdinalType idx[]) {
1142  gather(a,idx);
1143  }
1144 
1145  TinyVec(const ValueType a) {
1146  load(a);
1147  }
1148 
1149  TinyVec(const TinyVec& tv) {
1150  v1 = tv.v1; v2 = tv.v2;
1151  }
1152 
1153  TinyVec& operator=(const TinyVec& tv) {
1154  v1 = tv.v1; v2 = tv.v2;
1155  return *this;
1156  }
1157 
1158  void load(const ValueType a[]) {
1159  v1 = _mm512_load_pd(a);
1160  v2 = _mm512_load_pd(a+8);
1161  }
1162 
1163  void load(const ValueType a) {
1164  v1 = _mm512_set1_pd(a);
1165  v2 = _mm512_set1_pd(a);
1166  }
1167 
1168  void aligned_load(const ValueType a[]) {
1169  v1 = _mm512_load_pd(a);
1170  v2 = _mm512_load_pd(a+8);
1171  }
1172 
1173  template <typename OrdinalType>
1174  void gather(const ValueType a[], const OrdinalType idx[]) {
1175  // We're assuming idx is an array of 32-bit integers
1176  // Load 16 integers into v1idx, then permute the high 256 bits
1177  // to the low 256 bits (DCBA -> BADC where 128 bit lanes are read right to
1178  // left). Then load the vectors into v1 and v2.
1179  // logather_pd only uses the low 256 bits in the index vector.
1180  __m512i v1idx = _mm512_load_epi32(idx);
1181  __m512i v2idx = _mm512_permute4f128_epi32(v1idx, _MM_PERM_BADC);
1182  v1 = _mm512_i32logather_pd(v1idx, a, 8);
1183  v2 = _mm512_i32logather_pd(v2idx, a, 8);
1184  }
1185 
1186  void scatter(ValueType a[]) const {
1187  _mm512_store_pd(a, v1);
1188  _mm512_store_pd(a+8, v2);
1189  }
1190 
1191  void aligned_scatter(ValueType a[]) const {
1192  _mm512_store_pd(a, v1);
1193  _mm512_store_pd(a+8, v2);
1194  }
1195 
1196  void zero() {
1197  v1 = _mm512_setzero_pd();
1198  v2 = _mm512_setzero_pd();
1199  }
1200 
1201  void plus_equal(const TinyVec& t) {
1202  v1 = _mm512_add_pd(v1, t.v1);
1203  v2 = _mm512_add_pd(v2, t.v2);
1204  }
1205 
1206  void times_equal(const TinyVec& t) {
1207  v1 = _mm512_mul_pd(v1, t.v1);
1208  v2 = _mm512_mul_pd(v2, t.v2);
1209  }
1210 
1211  // *this = *this + t1 * t2
1212  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
1213  v1 = _mm512_fmadd_pd(t1.v1, t2.v1, v1);
1214  v2 = _mm512_fmadd_pd(t1.v2, t2.v2, v2);
1215  }
1216 
1217  ValueType sum() {
1218  return _mm512_reduce_add_pd(v1) + _mm512_reduce_add_pd(v2);
1219  }
1220 
1221 private:
1222  __m512d v1, v2;
1223 };
1224 
1225 template <>
1226 class TinyVec<double,16,true,true> {
1227 public:
1228 
1229  typedef double ValueType;
1230  static const int Num = 16;
1231 
1232  TinyVec(const int sz) {
1233  mask = _mm512_int2mask((1 << (sz-7))-1);
1234  }
1235 
1236  TinyVec(const ValueType a[], int sz) {
1237  mask = _mm512_int2mask((1 << (sz-7))-1);
1238  load(a);
1239  }
1240 
1241  template <typename OrdinalType>
1242  TinyVec(const ValueType a[], const OrdinalType idx[], int sz) {
1243  mask = _mm512_int2mask((1 << (sz-7))-1);
1244  gather(a,idx);
1245  }
1246 
1247  TinyVec(const ValueType a, int sz) {
1248  mask = _mm512_int2mask((1 << (sz-7))-1);
1249  load(a);
1250  }
1251 
1252  TinyVec(const TinyVec& tv) {
1253  mask = tv.mask;
1254  v1 = tv.v1; v2 = tv.v2;
1255  }
1256 
1257  TinyVec& operator=(const TinyVec& tv) {
1258  mask = tv.mask;
1259  v1 = tv.v1; v2 = tv.v2;
1260  return *this;
1261  }
1262 
1263  void load(const ValueType a[]) {
1264  v1 = _mm512_load_pd(a);
1265  v2 = _mm512_setzero_pd();
1266  v2 = _mm512_mask_load_pd(v2, mask, a+8);
1267  }
1268 
1269  void load(const ValueType a) {
1270  v1 = _mm512_set1_pd(a);
1271  v2 = _mm512_set1_pd(a);
1272  }
1273 
1274  void aligned_load(const ValueType a[]) {
1275  v1 = _mm512_load_pd(a);
1276  v2 = _mm512_setzero_pd();
1277  v2 = _mm512_mask_load_pd(v2, mask, a+8);
1278  }
1279 
1280  template <typename OrdinalType>
1281  void gather(const ValueType a[], const OrdinalType idx[]) {
1282  // We're assuming idx is an array of 32-bit integers
1283  // Load 16 integers into v1idx, then permute the high 256 bits
1284  // to the low 256 bits (DCBA -> BADC where 128 bit lanes are read right to
1285  // left). Then load the vectors into v1 and v2.
1286  // logather_pd only uses the low 256 bits in the index vector.
1287  // Note: permute4f128 overwrites its argument, so we need to load v1 first
1288  __m512i v1idx = _mm512_load_epi32(idx);
1289  v1 = _mm512_i32logather_pd(v1idx, a, 8);
1290 
1291  v1idx = _mm512_permute4f128_epi32(v1idx, _MM_PERM_BADC);
1292  v2 = _mm512_setzero_pd();
1293  v2 = _mm512_mask_i32logather_pd(v2, mask, v1idx, a, 8);
1294  }
1295 
1296  void scatter(ValueType a[]) const {
1297  _mm512_store_pd(a, v1);
1298  _mm512_mask_store_pd(a+8, mask, v2);
1299  }
1300 
1301  void aligned_scatter(ValueType a[]) const {
1302  _mm512_store_pd(a, v1);
1303  _mm512_mask_store_pd(a+8, mask, v2);
1304  }
1305 
1306  void zero() {
1307  v1 = _mm512_setzero_pd();
1308  v2 = _mm512_setzero_pd();
1309  }
1310 
1311  void plus_equal(const TinyVec& t) {
1312  v1 = _mm512_add_pd(v1, t.v1);
1313  v2 = _mm512_mask_add_pd(v2, mask, v2, t.v2);
1314  }
1315 
1316  void times_equal(const TinyVec& t) {
1317  v1 = _mm512_mul_pd(v1, t.v1);
1318  v2 = _mm512_mask_mul_pd(v2, mask, v2, t.v2);
1319  }
1320 
1321  // *this = *this + t1 * t2
1322  void multiply_add(const TinyVec& t1, const TinyVec& t2) {
1323  v1 = _mm512_fmadd_pd(t1.v1, t2.v1, v1);
1324  v2 = _mm512_mask3_fmadd_pd(t1.v2, t2.v2, v2, mask);
1325  }
1326 
1327  ValueType sum() {
1328  return _mm512_reduce_add_pd(v1) + _mm512_mask_reduce_add_pd(mask, v2);
1329  }
1330 
1331 private:
1332  __mmask8 mask;
1333  __m512d v1, v2;
1334 };
1335 #endif
1336 
1337 #endif // #if defined(HAVE_STOKHOS_INTRINSICS) && !defined( __CUDACC__ )
1338 
1339 } // namespace Stokhos
1340 
1341 #endif /* #ifndef STOKHOS_TINY_VEC_HPP */
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a[])
KOKKOS_INLINE_FUNCTION void gather(const ValueType a[], const OrdinalType idx[])
KOKKOS_INLINE_FUNCTION TinyVec & operator=(const TinyVec &tv)
KOKKOS_INLINE_FUNCTION void load(const ValueType a[])
static const int Num
KOKKOS_INLINE_FUNCTION void scatter(ValueType a[]) const
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a[], int size)
KOKKOS_INLINE_FUNCTION void aligned_load(const ValueType a[])
KOKKOS_INLINE_FUNCTION TinyVec & operator=(const TinyVec &tv)
KOKKOS_INLINE_FUNCTION void multiply_add(const TinyVec &t1, const TinyVec &t2)
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a[], const OrdinalType idx[], int size)
ValueType v[Num]
KOKKOS_INLINE_FUNCTION void times_equal(const TinyVec &t)
KOKKOS_INLINE_FUNCTION TinyVec()
KOKKOS_INLINE_FUNCTION void multiply_add(const TinyVec &t1, const TinyVec &t2)
KOKKOS_INLINE_FUNCTION TinyVec(const TinyVec &tv)
KOKKOS_INLINE_FUNCTION void aligned_scatter(ValueType a[]) const
KOKKOS_INLINE_FUNCTION ValueType sum() const
KOKKOS_INLINE_FUNCTION void load(const ValueType a)
KOKKOS_INLINE_FUNCTION ValueType sum() const
KOKKOS_INLINE_FUNCTION void load(const ValueType a[])
KOKKOS_INLINE_FUNCTION void times_equal(const TinyVec &t)
KOKKOS_INLINE_FUNCTION void scatter(ValueType a[]) const
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a, int size)
KOKKOS_INLINE_FUNCTION void plus_equal(const TinyVec &t)
KOKKOS_INLINE_FUNCTION void gather(const ValueType a[], const OrdinalType idx[])
KOKKOS_INLINE_FUNCTION void plus_equal(const TinyVec &t)
KOKKOS_INLINE_FUNCTION void aligned_scatter(ValueType a[]) const
KOKKOS_INLINE_FUNCTION void load(const ValueType a)
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a[], const OrdinalType idx[])
KOKKOS_INLINE_FUNCTION TinyVec(const TinyVec &tv)
KOKKOS_INLINE_FUNCTION void zero()
KOKKOS_INLINE_FUNCTION TinyVec(const ValueType a)
KOKKOS_INLINE_FUNCTION void aligned_load(const ValueType a[])