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>
16
17namespace 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>, const Simd::Mask<LoopSIMD<T,S,AM>>& mask,
380 const LoopSIMD<T,S,AD>& ifTrue, const 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 const M& mask, const LoopSIMD<T,S,A>& ifTrue, const 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>, const 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>, const 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>, const 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>, const 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
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
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
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.
bool isNaN(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is NaN.
Definition: fvector.hh:627
bool isInf(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is infinite.
Definition: fvector.hh:615
auto isFinite(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether all entries are finite.
Definition: fvector.hh:604
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.111.3 (Dec 21, 23:30, 2024)