Dune Core Modules (2.7.1)

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