Dune Core Modules (2.9.0)

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