Dune Core Modules (2.7.0)

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>
13
14namespace 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 {
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
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:151
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
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.111.3 (Jul 15, 22:36, 2024)