Dune Core Modules (unstable)

loop.hh
1 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3 #ifndef DUNE_COMMON_SIMD_LOOP_HH
4 #define DUNE_COMMON_SIMD_LOOP_HH
5 
6 #include <array>
7 #include <cmath>
8 #include <cstddef>
9 #include <cstdlib>
10 #include <cstdint>
11 #include <ostream>
12 
13 #include <dune/common/math.hh>
14 #include <dune/common/simd/simd.hh>
16 
17 namespace Dune {
18 
19 
20 /*
21  * silence warnings from GCC about using integer operands on a bool
22  * (when instantiated for T=bool)
23  */
24 #if __GNUC__ >= 7
25 # pragma GCC diagnostic push
26 # pragma GCC diagnostic ignored "-Wbool-operation"
27 # pragma GCC diagnostic ignored "-Wint-in-bool-context"
28 # define GCC_WARNING_DISABLED
29 #endif
30 
31 /*
32  * silence warnings from Clang about using bitwise operands on
33  * a bool (when instantiated for T=bool)
34  */
35 #ifdef __clang__
36 #if __has_warning("-Wbitwise-instead-of-logical")
37 # pragma clang diagnostic push
38 # pragma clang diagnostic ignored "-Wbitwise-instead-of-logical"
39 # define CLANG_WARNING_DISABLED
40 #endif
41 #endif
42 
43 /*
44  * Introduce a simd pragma if OpenMP is available in standard version >= 4
45  */
46 #if _OPENMP >= 201307
47  #define DUNE_PRAGMA_OMP_SIMD _Pragma("omp simd")
48 #else
49  #define DUNE_PRAGMA_OMP_SIMD
50 #endif
51 
52 
64  template<class T, std::size_t S, std::size_t A = 0>
65  class alignas(A==0?alignof(T):A) LoopSIMD : public std::array<T,S> {
66 
67  public:
68 
69  //default constructor
70  LoopSIMD() {
71  assert(reinterpret_cast<uintptr_t>(this) % std::min(alignof(LoopSIMD<T,S,A>),alignof(std::max_align_t)) == 0);
72  }
73 
74  // broadcast constructor initializing the content with a given value
76  this->fill(i);
77  }
78 
79  template<std::size_t OA>
80  explicit LoopSIMD(const LoopSIMD<T,S,OA>& other)
81  : std::array<T,S>(other)
82  {
83  assert(reinterpret_cast<uintptr_t>(this) % std::min(alignof(LoopSIMD<T,S,A>),alignof(std::max_align_t)) == 0);
84  }
85 
86  /*
87  * Definition of basic operators
88  */
89 
90  //Prefix operators
91 #define DUNE_SIMD_LOOP_PREFIX_OP(SYMBOL) \
92  auto operator SYMBOL() { \
93  DUNE_PRAGMA_OMP_SIMD \
94  for(std::size_t i=0; i<S; i++){ \
95  SYMBOL(*this)[i]; \
96  } \
97  return *this; \
98  } \
99  static_assert(true, "expecting ;")
100 
101  DUNE_SIMD_LOOP_PREFIX_OP(++);
102  DUNE_SIMD_LOOP_PREFIX_OP(--);
103 #undef DUNE_SIMD_LOOP_PREFIX_OP
104 
105  //Unary operators
106 #define DUNE_SIMD_LOOP_UNARY_OP(SYMBOL) \
107  auto operator SYMBOL() const { \
108  LoopSIMD<T,S,A> out; \
109  DUNE_PRAGMA_OMP_SIMD \
110  for(std::size_t i=0; i<S; i++){ \
111  out[i] = SYMBOL((*this)[i]); \
112  } \
113  return out; \
114  } \
115  static_assert(true, "expecting ;")
116 
117  DUNE_SIMD_LOOP_UNARY_OP(+);
118  DUNE_SIMD_LOOP_UNARY_OP(-);
119  DUNE_SIMD_LOOP_UNARY_OP(~);
120 
121  auto operator!() const {
123  DUNE_PRAGMA_OMP_SIMD
124  for(std::size_t i=0; i<S; i++){
125  out[i] = !((*this)[i]);
126  }
127  return out;
128  }
129 #undef DUNE_SIMD_LOOP_UNARY_OP
130 
131  //Postfix operators
132 #define DUNE_SIMD_LOOP_POSTFIX_OP(SYMBOL) \
133  auto operator SYMBOL(int){ \
134  LoopSIMD<T,S,A> out = *this; \
135  SYMBOL(*this); \
136  return out; \
137  } \
138  static_assert(true, "expecting ;")
139 
140  DUNE_SIMD_LOOP_POSTFIX_OP(++);
141  DUNE_SIMD_LOOP_POSTFIX_OP(--);
142 #undef DUNE_SIMD_LOOP_POSTFIX_OP
143 
144  //Assignment operators
145 #define DUNE_SIMD_LOOP_ASSIGNMENT_OP(SYMBOL) \
146  auto operator SYMBOL(const Simd::Scalar<T> s) { \
147  DUNE_PRAGMA_OMP_SIMD \
148  for(std::size_t i=0; i<S; i++){ \
149  (*this)[i] SYMBOL s; \
150  } \
151  return *this; \
152  } \
153  \
154  auto operator SYMBOL(const LoopSIMD<T,S,A> &v) { \
155  DUNE_PRAGMA_OMP_SIMD \
156  for(std::size_t i=0; i<S; i++){ \
157  (*this)[i] SYMBOL v[i]; \
158  } \
159  return *this; \
160  } \
161  static_assert(true, "expecting ;")
162 
163  DUNE_SIMD_LOOP_ASSIGNMENT_OP(+=);
164  DUNE_SIMD_LOOP_ASSIGNMENT_OP(-=);
165  DUNE_SIMD_LOOP_ASSIGNMENT_OP(*=);
166  DUNE_SIMD_LOOP_ASSIGNMENT_OP(/=);
167  DUNE_SIMD_LOOP_ASSIGNMENT_OP(%=);
168  DUNE_SIMD_LOOP_ASSIGNMENT_OP(<<=);
169  DUNE_SIMD_LOOP_ASSIGNMENT_OP(>>=);
170  DUNE_SIMD_LOOP_ASSIGNMENT_OP(&=);
171  DUNE_SIMD_LOOP_ASSIGNMENT_OP(|=);
172  DUNE_SIMD_LOOP_ASSIGNMENT_OP(^=);
173 #undef DUNE_SIMD_LOOP_ASSIGNMENT_OP
174  };
175 
176  //Arithmetic operators
177 #define DUNE_SIMD_LOOP_BINARY_OP(SYMBOL) \
178  template<class T, std::size_t S, std::size_t A> \
179  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
180  LoopSIMD<T,S,A> out; \
181  DUNE_PRAGMA_OMP_SIMD \
182  for(std::size_t i=0; i<S; i++){ \
183  out[i] = v[i] SYMBOL s; \
184  } \
185  return out; \
186  } \
187  template<class T, std::size_t S, std::size_t A> \
188  auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
189  LoopSIMD<T,S,A> out; \
190  DUNE_PRAGMA_OMP_SIMD \
191  for(std::size_t i=0; i<S; i++){ \
192  out[i] = s SYMBOL v[i]; \
193  } \
194  return out; \
195  } \
196  template<class T, std::size_t S, std::size_t A> \
197  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
198  const LoopSIMD<T,S,A> &w) { \
199  LoopSIMD<T,S,A> out; \
200  DUNE_PRAGMA_OMP_SIMD \
201  for(std::size_t i=0; i<S; i++){ \
202  out[i] = v[i] SYMBOL w[i]; \
203  } \
204  return out; \
205  } \
206  static_assert(true, "expecting ;")
207 
208  DUNE_SIMD_LOOP_BINARY_OP(+);
209  DUNE_SIMD_LOOP_BINARY_OP(-);
210  DUNE_SIMD_LOOP_BINARY_OP(*);
211  DUNE_SIMD_LOOP_BINARY_OP(/);
212  DUNE_SIMD_LOOP_BINARY_OP(%);
213 
214  DUNE_SIMD_LOOP_BINARY_OP(&);
215  DUNE_SIMD_LOOP_BINARY_OP(|);
216  DUNE_SIMD_LOOP_BINARY_OP(^);
217 
218 #undef DUNE_SIMD_LOOP_BINARY_OP
219 
220  //Bitshift operators
221 #define DUNE_SIMD_LOOP_BITSHIFT_OP(SYMBOL) \
222  template<class T, std::size_t S, std::size_t A, class U> \
223  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
224  LoopSIMD<T,S,A> out; \
225  DUNE_PRAGMA_OMP_SIMD \
226  for(std::size_t i=0; i<S; i++){ \
227  out[i] = v[i] SYMBOL s; \
228  } \
229  return out; \
230  } \
231  template<class T, std::size_t S, std::size_t A, class U, std::size_t AU> \
232  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
233  const LoopSIMD<U,S,AU> &w) { \
234  LoopSIMD<T,S,A> out; \
235  DUNE_PRAGMA_OMP_SIMD \
236  for(std::size_t i=0; i<S; i++){ \
237  out[i] = v[i] SYMBOL w[i]; \
238  } \
239  return out; \
240  } \
241  static_assert(true, "expecting ;")
242 
243  DUNE_SIMD_LOOP_BITSHIFT_OP(<<);
244  DUNE_SIMD_LOOP_BITSHIFT_OP(>>);
245 
246 #undef DUNE_SIMD_LOOP_BITSHIFT_OP
247 
248  //Comparison operators
249 #define DUNE_SIMD_LOOP_COMPARISON_OP(SYMBOL) \
250  template<class T, std::size_t S, std::size_t A, class U> \
251  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
252  Simd::Mask<LoopSIMD<T,S,A>> out; \
253  DUNE_PRAGMA_OMP_SIMD \
254  for(std::size_t i=0; i<S; i++){ \
255  out[i] = v[i] SYMBOL s; \
256  } \
257  return out; \
258  } \
259  template<class T, std::size_t S, std::size_t A> \
260  auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
261  Simd::Mask<LoopSIMD<T,S,A>> out; \
262  DUNE_PRAGMA_OMP_SIMD \
263  for(std::size_t i=0; i<S; i++){ \
264  out[i] = s SYMBOL v[i]; \
265  } \
266  return out; \
267  } \
268  template<class T, std::size_t S, std::size_t A> \
269  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
270  const LoopSIMD<T,S,A> &w) { \
271  Simd::Mask<LoopSIMD<T,S,A>> out; \
272  DUNE_PRAGMA_OMP_SIMD \
273  for(std::size_t i=0; i<S; i++){ \
274  out[i] = v[i] SYMBOL w[i]; \
275  } \
276  return out; \
277  } \
278  static_assert(true, "expecting ;")
279 
280  DUNE_SIMD_LOOP_COMPARISON_OP(<);
281  DUNE_SIMD_LOOP_COMPARISON_OP(>);
282  DUNE_SIMD_LOOP_COMPARISON_OP(<=);
283  DUNE_SIMD_LOOP_COMPARISON_OP(>=);
284  DUNE_SIMD_LOOP_COMPARISON_OP(==);
285  DUNE_SIMD_LOOP_COMPARISON_OP(!=);
286 #undef DUNE_SIMD_LOOP_COMPARISON_OP
287 
288  //Boolean operators
289 #define DUNE_SIMD_LOOP_BOOLEAN_OP(SYMBOL) \
290  template<class T, std::size_t S, std::size_t A> \
291  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
292  Simd::Mask<LoopSIMD<T,S,A>> out; \
293  DUNE_PRAGMA_OMP_SIMD \
294  for(std::size_t i=0; i<S; i++){ \
295  out[i] = v[i] SYMBOL s; \
296  } \
297  return out; \
298  } \
299  template<class T, std::size_t S, std::size_t A> \
300  auto operator SYMBOL(const Simd::Mask<T> s, const LoopSIMD<T,S,A> &v) { \
301  Simd::Mask<LoopSIMD<T,S,A>> out; \
302  DUNE_PRAGMA_OMP_SIMD \
303  for(std::size_t i=0; i<S; i++){ \
304  out[i] = s SYMBOL v[i]; \
305  } \
306  return out; \
307  } \
308  template<class T, std::size_t S, std::size_t A> \
309  auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
310  const LoopSIMD<T,S,A> &w) { \
311  Simd::Mask<LoopSIMD<T,S,A>> out; \
312  DUNE_PRAGMA_OMP_SIMD \
313  for(std::size_t i=0; i<S; i++){ \
314  out[i] = v[i] SYMBOL w[i]; \
315  } \
316  return out; \
317  } \
318  static_assert(true, "expecting ;")
319 
320  DUNE_SIMD_LOOP_BOOLEAN_OP(&&);
321  DUNE_SIMD_LOOP_BOOLEAN_OP(||);
322 #undef DUNE_SIMD_LOOP_BOOLEAN_OP
323 
324  //prints a given LoopSIMD
325  template<class T, std::size_t S, std::size_t A>
326  std::ostream& operator<< (std::ostream &os, const LoopSIMD<T,S,A> &v) {
327  os << "[";
328  for(std::size_t i=0; i<S-1; i++) {
329  os << v[i] << ", ";
330  }
331  os << v[S-1] << "]";
332  return os;
333  }
334 
335  namespace Simd {
336  namespace Overloads {
337  /*
338  * Implementation/Overloads of the functions needed for
339  * SIMD-interface-compatibility
340  */
341 
342  //Implementation of SIMD-interface-types
343  template<class T, std::size_t S, std::size_t A>
344  struct ScalarType<LoopSIMD<T,S,A>> {
345  using type = Simd::Scalar<T>;
346  };
347 
348  template<class U, class T, std::size_t S, std::size_t A>
349  struct RebindType<U, LoopSIMD<T,S,A>> {
350  using type = LoopSIMD<Simd::Rebind<U, T>,S,A>;
351  };
352 
353  //Implementation of SIMD-interface-functionality
354  template<class T, std::size_t S, std::size_t A>
355  struct LaneCount<LoopSIMD<T,S,A>> : index_constant<S*lanes<T>()> {};
356 
357  template<class T, std::size_t S, std::size_t A>
358  auto lane(ADLTag<5>, std::size_t l, LoopSIMD<T,S,A> &&v)
359  -> decltype(std::move(Simd::lane(l%lanes<T>(), v[l/lanes<T>()])))
360  {
361  return std::move(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]));
362  }
363 
364  template<class T, std::size_t S, std::size_t A>
365  auto lane(ADLTag<5>, std::size_t l, const LoopSIMD<T,S,A> &v)
366  -> decltype(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
367  {
368  return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
369  }
370 
371  template<class T, std::size_t S, std::size_t A>
372  auto lane(ADLTag<5>, std::size_t l, LoopSIMD<T,S,A> &v)
373  -> decltype(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
374  {
375  return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
376  }
377 
378  template<class T, std::size_t S, std::size_t AM, std::size_t AD>
379  auto cond(ADLTag<5>, Simd::Mask<LoopSIMD<T,S,AM>> mask,
380  LoopSIMD<T,S,AD> ifTrue, LoopSIMD<T,S,AD> ifFalse) {
381  LoopSIMD<T,S,AD> out;
382  for(std::size_t i=0; i<S; i++) {
383  out[i] = Simd::cond(mask[i], ifTrue[i], ifFalse[i]);
384  }
385  return out;
386  }
387 
388  template<class M, class T, std::size_t S, std::size_t A>
389  auto cond(ADLTag<5, std::is_same<bool, Simd::Scalar<M> >::value
390  && Simd::lanes<M>() == Simd::lanes<LoopSIMD<T,S,A> >()>,
391  M mask, LoopSIMD<T,S,A> ifTrue, LoopSIMD<T,S,A> ifFalse)
392  {
393  LoopSIMD<T,S,A> out;
394  for(auto l : range(Simd::lanes(mask)))
395  Simd::lane(l, out) = Simd::lane(l, mask) ? Simd::lane(l, ifTrue) : Simd::lane(l, ifFalse);
396  return out;
397  }
398 
399  template<class M, std::size_t S, std::size_t A>
400  bool anyTrue(ADLTag<5>, LoopSIMD<M,S,A> mask) {
401  bool out = false;
402  for(std::size_t i=0; i<S; i++) {
403  out |= Simd::anyTrue(mask[i]);
404  }
405  return out;
406  }
407 
408  template<class M, std::size_t S, std::size_t A>
409  bool allTrue(ADLTag<5>, LoopSIMD<M,S,A> mask) {
410  bool out = true;
411  for(std::size_t i=0; i<S; i++) {
412  out &= Simd::allTrue(mask[i]);
413  }
414  return out;
415  }
416 
417  template<class M, std::size_t S, std::size_t A>
418  bool anyFalse(ADLTag<5>, LoopSIMD<M,S,A> mask) {
419  bool out = false;
420  for(std::size_t i=0; i<S; i++) {
421  out |= Simd::anyFalse(mask[i]);
422  }
423  return out;
424  }
425 
426  template<class M, std::size_t S, std::size_t A>
427  bool allFalse(ADLTag<5>, LoopSIMD<M,S,A> mask) {
428  bool out = true;
429  for(std::size_t i=0; i<S; i++) {
430  out &= Simd::allFalse(mask[i]);
431  }
432  return out;
433  }
434  } //namespace Overloads
435 
436  } //namespace Simd
437 
438 
439  /*
440  * Overloads the unary cmath-operations. Operations requiring
441  * or returning more than one argument are not supported.
442  * Due to inconsistency with the return values, cmath-operations
443  * on integral types are also not supported-
444  */
445 
446 #define DUNE_SIMD_LOOP_CMATH_UNARY_OP(expr) \
447  template<class T, std::size_t S, std::size_t A, typename Sfinae = \
448  typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
449  auto expr(const LoopSIMD<T,S,A> &v) { \
450  using std::expr; \
451  LoopSIMD<T,S,A> out; \
452  for(std::size_t i=0; i<S; i++) { \
453  out[i] = expr(v[i]); \
454  } \
455  return out; \
456  } \
457  static_assert(true, "expecting ;")
458 
459 #define DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(expr, returnType) \
460  template<class T, std::size_t S, std::size_t A, typename Sfinae = \
461  typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
462  auto expr(const LoopSIMD<T,S,A> &v) { \
463  using std::expr; \
464  LoopSIMD<returnType,S> out; \
465  for(std::size_t i=0; i<S; i++) { \
466  out[i] = expr(v[i]); \
467  } \
468  return out; \
469  } \
470  static_assert(true, "expecting ;")
471 
472  DUNE_SIMD_LOOP_CMATH_UNARY_OP(cos);
473  DUNE_SIMD_LOOP_CMATH_UNARY_OP(sin);
474  DUNE_SIMD_LOOP_CMATH_UNARY_OP(tan);
475  DUNE_SIMD_LOOP_CMATH_UNARY_OP(acos);
476  DUNE_SIMD_LOOP_CMATH_UNARY_OP(asin);
477  DUNE_SIMD_LOOP_CMATH_UNARY_OP(atan);
478  DUNE_SIMD_LOOP_CMATH_UNARY_OP(cosh);
479  DUNE_SIMD_LOOP_CMATH_UNARY_OP(sinh);
480  DUNE_SIMD_LOOP_CMATH_UNARY_OP(tanh);
481  DUNE_SIMD_LOOP_CMATH_UNARY_OP(acosh);
482  DUNE_SIMD_LOOP_CMATH_UNARY_OP(asinh);
483  DUNE_SIMD_LOOP_CMATH_UNARY_OP(atanh);
484 
485  DUNE_SIMD_LOOP_CMATH_UNARY_OP(exp);
486  DUNE_SIMD_LOOP_CMATH_UNARY_OP(log);
487  DUNE_SIMD_LOOP_CMATH_UNARY_OP(log10);
488  DUNE_SIMD_LOOP_CMATH_UNARY_OP(exp2);
489  DUNE_SIMD_LOOP_CMATH_UNARY_OP(expm1);
490  DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(ilogb, int);
491  DUNE_SIMD_LOOP_CMATH_UNARY_OP(log1p);
492  DUNE_SIMD_LOOP_CMATH_UNARY_OP(log2);
493  DUNE_SIMD_LOOP_CMATH_UNARY_OP(logb);
494 
495  DUNE_SIMD_LOOP_CMATH_UNARY_OP(sqrt);
496  DUNE_SIMD_LOOP_CMATH_UNARY_OP(cbrt);
497 
498  DUNE_SIMD_LOOP_CMATH_UNARY_OP(erf);
499  DUNE_SIMD_LOOP_CMATH_UNARY_OP(erfc);
500  DUNE_SIMD_LOOP_CMATH_UNARY_OP(tgamma);
501  DUNE_SIMD_LOOP_CMATH_UNARY_OP(lgamma);
502 
503  DUNE_SIMD_LOOP_CMATH_UNARY_OP(ceil);
504  DUNE_SIMD_LOOP_CMATH_UNARY_OP(floor);
505  DUNE_SIMD_LOOP_CMATH_UNARY_OP(trunc);
506  DUNE_SIMD_LOOP_CMATH_UNARY_OP(round);
507  DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(lround, long);
508  DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(llround, long long);
509  DUNE_SIMD_LOOP_CMATH_UNARY_OP(rint);
510  DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(lrint, long);
511  DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(llrint, long long);
512  DUNE_SIMD_LOOP_CMATH_UNARY_OP(nearbyint);
513 
514  DUNE_SIMD_LOOP_CMATH_UNARY_OP(fabs);
515  DUNE_SIMD_LOOP_CMATH_UNARY_OP(abs);
516 
517 #undef DUNE_SIMD_LOOP_CMATH_UNARY_OP
518 #undef DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN
519 
520 
521  /* not implemented cmath-functions:
522  * atan2
523  * frexp, idexp
524  * modf
525  * scalbn, scalbln
526  * pow
527  * hypot
528  * remainder, remquo
529  * copysign
530  * nan
531  * nextafter, nexttoward
532  * fdim, fmax, fmin
533  */
534 
535  /*
536  * Overloads specific functions usually provided by the std library
537  * More overloads will be provided should the need arise.
538  */
539 
540 #define DUNE_SIMD_LOOP_STD_UNARY_OP(expr) \
541  template<class T, std::size_t S, std::size_t A> \
542  auto expr(const LoopSIMD<T,S,A> &v) { \
543  using std::expr; \
544  LoopSIMD<T,S,A> out; \
545  for(std::size_t i=0; i<S; i++) { \
546  out[i] = expr(v[i]); \
547  } \
548  return out; \
549  } \
550  \
551  template<class T, std::size_t S, std::size_t A> \
552  auto expr(const LoopSIMD<std::complex<T>,S,A> &v) { \
553  using std::expr; \
554  LoopSIMD<T,S,A> out; \
555  for(std::size_t i=0; i<S; i++) { \
556  out[i] = expr(v[i]); \
557  } \
558  return out; \
559  } \
560  static_assert(true, "expecting ;")
561 
562  DUNE_SIMD_LOOP_STD_UNARY_OP(real);
563  DUNE_SIMD_LOOP_STD_UNARY_OP(imag);
564 
565 #undef DUNE_SIMD_LOOP_STD_UNARY_OP
566 
567 #define DUNE_SIMD_LOOP_STD_BINARY_OP(expr) \
568  template<class T, std::size_t S, std::size_t A> \
569  auto expr(const LoopSIMD<T,S,A> &v, const LoopSIMD<T,S,A> &w) { \
570  using std::expr; \
571  LoopSIMD<T,S,A> out; \
572  for(std::size_t i=0; i<S; i++) { \
573  out[i] = expr(v[i],w[i]); \
574  } \
575  return out; \
576  } \
577  static_assert(true, "expecting ;")
578 
579  DUNE_SIMD_LOOP_STD_BINARY_OP(max);
580  DUNE_SIMD_LOOP_STD_BINARY_OP(min);
581 
582 #undef DUNE_SIMD_LOOP_STD_BINARY_OP
583 
584  namespace MathOverloads {
585  template<class T, std::size_t S, std::size_t A>
586  auto isNaN(const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
587  Simd::Mask<LoopSIMD<T,S,A>> out;
588  for(auto l : range(S))
589  out[l] = Dune::isNaN(v[l]);
590  return out;
591  }
592 
593  template<class T, std::size_t S, std::size_t A>
594  auto isInf(const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
595  Simd::Mask<LoopSIMD<T,S,A>> out;
596  for(auto l : range(S))
597  out[l] = Dune::isInf(v[l]);
598  return out;
599  }
600 
601  template<class T, std::size_t S, std::size_t A>
602  auto isFinite(const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
603  Simd::Mask<LoopSIMD<T,S,A>> out;
604  for(auto l : range(S))
605  out[l] = Dune::isFinite(v[l]);
606  return out;
607  }
608  } //namespace MathOverloads
609 
610  template<class T, std::size_t S, std::size_t A>
611  struct IsNumber<LoopSIMD<T,S,A>> :
612  public std::integral_constant<bool, IsNumber<T>::value>{
613  };
614 
615 #ifdef CLANG_WARNING_DISABLED
616 # pragma clang diagnostic pop
617 # undef CLANG_WARNING_DISABLED
618 #endif
619 
620 #ifdef GCC_WARNING_DISABLED
621 # pragma GCC diagnostic pop
622 # undef GCC_WARNING_DISABLED
623 #endif
624 
625 } //namespace Dune
626 
627 #endif
Definition: loop.hh:65
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:311
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:407
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:506
bool allFalse(ADLTag< 0 >, const Mask &mask)
implements Simd::allFalse()
Definition: defaults.hh:124
bool allTrue(ADLTag< 0 >, const Mask &mask)
implements Simd::allTrue()
Definition: defaults.hh:104
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
bool anyFalse(ADLTag< 0 >, const Mask &mask)
implements Simd::anyFalse()
Definition: defaults.hh:114
bool anyTrue(const Mask &mask)
Whether any entry is true
Definition: interface.hh:429
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: interface.hh:386
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: interface.hh:439
bool anyFalse(const Mask &mask)
Whether any entry is false
Definition: interface.hh:449
constexpr std::size_t lanes()
Number of lanes in a SIMD type.
Definition: interface.hh:305
decltype(auto) lane(std::size_t l, V &&v)
Extract an element of a SIMD type.
Definition: interface.hh:324
Rebind< bool, V > Mask
Mask type type of some SIMD type.
Definition: interface.hh:289
bool allFalse(const Mask &mask)
Whether all entries are false
Definition: interface.hh:459
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:235
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:13
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition: conditional.hh:28
Include file for users of the SIMD abstraction layer.
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (Apr 27, 22:29, 2024)