dune-common 2.12-git
Loading...
Searching...
No Matches
loop.hh
Go to the documentation of this file.
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
71 : std::array<T,S>{}
72 {
73 assert(reinterpret_cast<uintptr_t>(this) % std::min(alignof(LoopSIMD<T,S,A>),alignof(std::max_align_t)) == 0);
74 }
75
76 // broadcast constructor initializing the content with a given value
78 this->fill(i);
79 }
80
81 template<std::size_t OA>
82 explicit LoopSIMD(const LoopSIMD<T,S,OA>& other)
83 : std::array<T,S>(other)
84 {
85 assert(reinterpret_cast<uintptr_t>(this) % std::min(alignof(LoopSIMD<T,S,A>),alignof(std::max_align_t)) == 0);
86 }
87
88 /*
89 * Definition of basic operators
90 */
91
92 //Prefix operators
93#define DUNE_SIMD_LOOP_PREFIX_OP(SYMBOL) \
94 auto operator SYMBOL() { \
95 DUNE_PRAGMA_OMP_SIMD \
96 for(std::size_t i=0; i<S; i++){ \
97 SYMBOL(*this)[i]; \
98 } \
99 return *this; \
100 } \
101 static_assert(true, "expecting ;")
102
105#undef DUNE_SIMD_LOOP_PREFIX_OP
106
107 //Unary operators
108#define DUNE_SIMD_LOOP_UNARY_OP(SYMBOL) \
109 auto operator SYMBOL() const { \
110 LoopSIMD<T,S,A> out; \
111 DUNE_PRAGMA_OMP_SIMD \
112 for(std::size_t i=0; i<S; i++){ \
113 out[i] = SYMBOL((*this)[i]); \
114 } \
115 return out; \
116 } \
117 static_assert(true, "expecting ;")
118
122
123 auto operator!() const {
126 for(std::size_t i=0; i<S; i++){
127 out[i] = !((*this)[i]);
128 }
129 return out;
130 }
131#undef DUNE_SIMD_LOOP_UNARY_OP
132
133 //Postfix operators
134#define DUNE_SIMD_LOOP_POSTFIX_OP(SYMBOL) \
135 auto operator SYMBOL(int){ \
136 LoopSIMD<T,S,A> out = *this; \
137 SYMBOL(*this); \
138 return out; \
139 } \
140 static_assert(true, "expecting ;")
141
144#undef DUNE_SIMD_LOOP_POSTFIX_OP
145
146 //Assignment operators
147#define DUNE_SIMD_LOOP_ASSIGNMENT_OP(SYMBOL) \
148 auto operator SYMBOL(const Simd::Scalar<T> s) { \
149 DUNE_PRAGMA_OMP_SIMD \
150 for(std::size_t i=0; i<S; i++){ \
151 (*this)[i] SYMBOL s; \
152 } \
153 return *this; \
154 } \
155 \
156 auto operator SYMBOL(const LoopSIMD<T,S,A> &v) { \
157 DUNE_PRAGMA_OMP_SIMD \
158 for(std::size_t i=0; i<S; i++){ \
159 (*this)[i] SYMBOL v[i]; \
160 } \
161 return *this; \
162 } \
163 static_assert(true, "expecting ;")
164
175#undef DUNE_SIMD_LOOP_ASSIGNMENT_OP
176 };
177
178 //Arithmetic operators
179#define DUNE_SIMD_LOOP_BINARY_OP(SYMBOL) \
180 template<class T, std::size_t S, std::size_t A> \
181 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
182 LoopSIMD<T,S,A> out; \
183 DUNE_PRAGMA_OMP_SIMD \
184 for(std::size_t i=0; i<S; i++){ \
185 out[i] = v[i] SYMBOL s; \
186 } \
187 return out; \
188 } \
189 template<class T, std::size_t S, std::size_t A> \
190 auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
191 LoopSIMD<T,S,A> out; \
192 DUNE_PRAGMA_OMP_SIMD \
193 for(std::size_t i=0; i<S; i++){ \
194 out[i] = s SYMBOL v[i]; \
195 } \
196 return out; \
197 } \
198 template<class T, std::size_t S, std::size_t A> \
199 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
200 const LoopSIMD<T,S,A> &w) { \
201 LoopSIMD<T,S,A> out; \
202 DUNE_PRAGMA_OMP_SIMD \
203 for(std::size_t i=0; i<S; i++){ \
204 out[i] = v[i] SYMBOL w[i]; \
205 } \
206 return out; \
207 } \
208 static_assert(true, "expecting ;")
209
215
219
220#undef DUNE_SIMD_LOOP_BINARY_OP
221
222 //Bitshift operators
223#define DUNE_SIMD_LOOP_BITSHIFT_OP(SYMBOL) \
224 template<class T, std::size_t S, std::size_t A, class U> \
225 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
226 LoopSIMD<T,S,A> out; \
227 DUNE_PRAGMA_OMP_SIMD \
228 for(std::size_t i=0; i<S; i++){ \
229 out[i] = v[i] SYMBOL s; \
230 } \
231 return out; \
232 } \
233 template<class T, std::size_t S, std::size_t A, class U, std::size_t AU> \
234 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
235 const LoopSIMD<U,S,AU> &w) { \
236 LoopSIMD<T,S,A> out; \
237 DUNE_PRAGMA_OMP_SIMD \
238 for(std::size_t i=0; i<S; i++){ \
239 out[i] = v[i] SYMBOL w[i]; \
240 } \
241 return out; \
242 } \
243 static_assert(true, "expecting ;")
244
247
248#undef DUNE_SIMD_LOOP_BITSHIFT_OP
249
250 //Comparison operators
251#define DUNE_SIMD_LOOP_COMPARISON_OP(SYMBOL) \
252 template<class T, std::size_t S, std::size_t A, class U> \
253 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
254 Simd::Mask<LoopSIMD<T,S,A>> out; \
255 DUNE_PRAGMA_OMP_SIMD \
256 for(std::size_t i=0; i<S; i++){ \
257 out[i] = v[i] SYMBOL s; \
258 } \
259 return out; \
260 } \
261 template<class T, std::size_t S, std::size_t A> \
262 auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
263 Simd::Mask<LoopSIMD<T,S,A>> out; \
264 DUNE_PRAGMA_OMP_SIMD \
265 for(std::size_t i=0; i<S; i++){ \
266 out[i] = s SYMBOL v[i]; \
267 } \
268 return out; \
269 } \
270 template<class T, std::size_t S, std::size_t A> \
271 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
272 const LoopSIMD<T,S,A> &w) { \
273 Simd::Mask<LoopSIMD<T,S,A>> out; \
274 DUNE_PRAGMA_OMP_SIMD \
275 for(std::size_t i=0; i<S; i++){ \
276 out[i] = v[i] SYMBOL w[i]; \
277 } \
278 return out; \
279 } \
280 static_assert(true, "expecting ;")
281
288#undef DUNE_SIMD_LOOP_COMPARISON_OP
289
290 //Boolean operators
291#define DUNE_SIMD_LOOP_BOOLEAN_OP(SYMBOL) \
292 template<class T, std::size_t S, std::size_t A> \
293 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
294 Simd::Mask<LoopSIMD<T,S,A>> out; \
295 DUNE_PRAGMA_OMP_SIMD \
296 for(std::size_t i=0; i<S; i++){ \
297 out[i] = v[i] SYMBOL s; \
298 } \
299 return out; \
300 } \
301 template<class T, std::size_t S, std::size_t A> \
302 auto operator SYMBOL(const Simd::Mask<T>& s, const LoopSIMD<T,S,A> &v) { \
303 Simd::Mask<LoopSIMD<T,S,A>> out; \
304 DUNE_PRAGMA_OMP_SIMD \
305 for(std::size_t i=0; i<S; i++){ \
306 out[i] = s SYMBOL v[i]; \
307 } \
308 return out; \
309 } \
310 template<class T, std::size_t S, std::size_t A> \
311 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
312 const LoopSIMD<T,S,A> &w) { \
313 Simd::Mask<LoopSIMD<T,S,A>> out; \
314 DUNE_PRAGMA_OMP_SIMD \
315 for(std::size_t i=0; i<S; i++){ \
316 out[i] = v[i] SYMBOL w[i]; \
317 } \
318 return out; \
319 } \
320 static_assert(true, "expecting ;")
321
324#undef DUNE_SIMD_LOOP_BOOLEAN_OP
325
326 //prints a given LoopSIMD
327 template<class T, std::size_t S, std::size_t A>
329 os << "[";
330 for(std::size_t i=0; i<S-1; i++) {
331 os << v[i] << ", ";
332 }
333 os << v[S-1] << "]";
334 return os;
335 }
336
337 namespace Simd {
338 namespace Overloads {
339 /*
340 * Implementation/Overloads of the functions needed for
341 * SIMD-interface-compatibility
342 */
343
344 //Implementation of SIMD-interface-types
345 template<class T, std::size_t S, std::size_t A>
346 struct ScalarType<LoopSIMD<T,S,A>> {
348 };
349
350 template<class U, class T, std::size_t S, std::size_t A>
351 struct RebindType<U, LoopSIMD<T,S,A>> {
353 };
354
355 //Implementation of SIMD-interface-functionality
356 template<class T, std::size_t S, std::size_t A>
357 struct LaneCount<LoopSIMD<T,S,A>> : index_constant<S*lanes<T>()> {};
358
359 template<class T, std::size_t S, std::size_t A>
361 -> decltype(std::move(Simd::lane(l%lanes<T>(), v[l/lanes<T>()])))
362 {
363 return std::move(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]));
364 }
365
366 template<class T, std::size_t S, std::size_t A>
368 -> decltype(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
369 {
370 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
371 }
372
373 template<class T, std::size_t S, std::size_t A>
375 -> decltype(Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
376 {
377 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
378 }
379
380 template<class T, std::size_t S, std::size_t AM, std::size_t AD>
382 const LoopSIMD<T,S,AD>& ifTrue, const LoopSIMD<T,S,AD>& ifFalse) {
384 for(std::size_t i=0; i<S; i++) {
385 out[i] = Simd::cond(mask[i], ifTrue[i], ifFalse[i]);
386 }
387 return out;
388 }
389
390 template<class M, class T, std::size_t S, std::size_t A>
392 && Simd::lanes<M>() == Simd::lanes<LoopSIMD<T,S,A> >()>,
393 const M& mask, const LoopSIMD<T,S,A>& ifTrue, const LoopSIMD<T,S,A>& ifFalse)
394 {
395 LoopSIMD<T,S,A> out;
396 for(auto l : range(Simd::lanes(mask)))
397 Simd::lane(l, out) = Simd::lane(l, mask) ? Simd::lane(l, ifTrue) : Simd::lane(l, ifFalse);
398 return out;
399 }
400
401 template<class M, std::size_t S, std::size_t A>
403 bool out = false;
404 for(std::size_t i=0; i<S; i++) {
405 out |= Simd::anyTrue(mask[i]);
406 }
407 return out;
408 }
409
410 template<class M, std::size_t S, std::size_t A>
412 bool out = true;
413 for(std::size_t i=0; i<S; i++) {
414 out &= Simd::allTrue(mask[i]);
415 }
416 return out;
417 }
418
419 template<class M, std::size_t S, std::size_t A>
421 bool out = false;
422 for(std::size_t i=0; i<S; i++) {
423 out |= Simd::anyFalse(mask[i]);
424 }
425 return out;
426 }
427
428 template<class M, std::size_t S, std::size_t A>
430 bool out = true;
431 for(std::size_t i=0; i<S; i++) {
432 out &= Simd::allFalse(mask[i]);
433 }
434 return out;
435 }
436 } //namespace Overloads
437
438 } //namespace Simd
439
440
441 /*
442 * Overloads the unary cmath-operations. Operations requiring
443 * or returning more than one argument are not supported.
444 * Due to inconsistency with the return values, cmath-operations
445 * on integral types are also not supported-
446 */
447
448#define DUNE_SIMD_LOOP_CMATH_UNARY_OP(expr) \
449 template<class T, std::size_t S, std::size_t A, typename Sfinae = \
450 typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
451 auto expr(const LoopSIMD<T,S,A> &v) { \
452 using std::expr; \
453 LoopSIMD<T,S,A> out; \
454 for(std::size_t i=0; i<S; i++) { \
455 out[i] = expr(v[i]); \
456 } \
457 return out; \
458 } \
459 static_assert(true, "expecting ;")
460
461#define DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(expr, returnType) \
462 template<class T, std::size_t S, std::size_t A, typename Sfinae = \
463 typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
464 auto expr(const LoopSIMD<T,S,A> &v) { \
465 using std::expr; \
466 LoopSIMD<returnType,S> out; \
467 for(std::size_t i=0; i<S; i++) { \
468 out[i] = expr(v[i]); \
469 } \
470 return out; \
471 } \
472 static_assert(true, "expecting ;")
473
486
496
499
504
515
518
519#undef DUNE_SIMD_LOOP_CMATH_UNARY_OP
520#undef DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN
521
522
523 /* not implemented cmath-functions:
524 * atan2
525 * frexp, idexp
526 * modf
527 * scalbn, scalbln
528 * pow
529 * hypot
530 * remainder, remquo
531 * copysign
532 * nan
533 * nextafter, nexttoward
534 * fdim, fmax, fmin
535 */
536
537 /*
538 * Overloads specific functions usually provided by the std library
539 * More overloads will be provided should the need arise.
540 */
541
542#define DUNE_SIMD_LOOP_STD_UNARY_OP(expr) \
543 template<class T, std::size_t S, std::size_t A> \
544 auto expr(const LoopSIMD<T,S,A> &v) { \
545 using std::expr; \
546 LoopSIMD<T,S,A> out; \
547 for(std::size_t i=0; i<S; i++) { \
548 out[i] = expr(v[i]); \
549 } \
550 return out; \
551 } \
552 \
553 template<class T, std::size_t S, std::size_t A> \
554 auto expr(const LoopSIMD<std::complex<T>,S,A> &v) { \
555 using std::expr; \
556 LoopSIMD<T,S,A> out; \
557 for(std::size_t i=0; i<S; i++) { \
558 out[i] = expr(v[i]); \
559 } \
560 return out; \
561 } \
562 static_assert(true, "expecting ;")
563
566
567#undef DUNE_SIMD_LOOP_STD_UNARY_OP
568
569#define DUNE_SIMD_LOOP_STD_BINARY_OP(expr) \
570 template<class T, std::size_t S, std::size_t A> \
571 auto expr(const LoopSIMD<T,S,A> &v, const LoopSIMD<T,S,A> &w) { \
572 using std::expr; \
573 LoopSIMD<T,S,A> out; \
574 for(std::size_t i=0; i<S; i++) { \
575 out[i] = expr(v[i],w[i]); \
576 } \
577 return out; \
578 } \
579 static_assert(true, "expecting ;")
580
583
584#undef DUNE_SIMD_LOOP_STD_BINARY_OP
585
586 namespace MathOverloads {
587 template<class T, std::size_t S, std::size_t A>
590 for(auto l : range(S))
591 out[l] = Dune::isNaN(v[l]);
592 return out;
593 }
594
595 template<class T, std::size_t S, std::size_t A>
598 for(auto l : range(S))
599 out[l] = Dune::isInf(v[l]);
600 return out;
601 }
602
603 template<class T, std::size_t S, std::size_t A>
606 for(auto l : range(S))
607 out[l] = Dune::isFinite(v[l]);
608 return out;
609 }
610 } //namespace MathOverloads
611
612 template<class T, std::size_t S, std::size_t A>
613 struct IsNumber<LoopSIMD<T,S,A>> :
614 public std::integral_constant<bool, IsNumber<T>::value>{
615 };
616
617#ifdef CLANG_WARNING_DISABLED
618# pragma clang diagnostic pop
619# undef CLANG_WARNING_DISABLED
620#endif
621
622#ifdef GCC_WARNING_DISABLED
623# pragma GCC diagnostic pop
624# undef GCC_WARNING_DISABLED
625#endif
626
627} //namespace Dune
628
629#endif
#define DUNE_SIMD_LOOP_BINARY_OP(SYMBOL)
Definition loop.hh:179
#define DUNE_SIMD_LOOP_BOOLEAN_OP(SYMBOL)
Definition loop.hh:291
#define DUNE_SIMD_LOOP_STD_BINARY_OP(expr)
Definition loop.hh:569
#define DUNE_SIMD_LOOP_STD_UNARY_OP(expr)
Definition loop.hh:542
#define DUNE_SIMD_LOOP_BITSHIFT_OP(SYMBOL)
Definition loop.hh:223
#define DUNE_SIMD_LOOP_CMATH_UNARY_OP(expr)
Definition loop.hh:448
#define DUNE_PRAGMA_OMP_SIMD
Definition loop.hh:49
#define DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(expr, returnType)
Definition loop.hh:461
#define DUNE_SIMD_LOOP_ASSIGNMENT_OP(SYMBOL)
Definition loop.hh:147
Traits for type conversions and type information.
Some useful basic math stuff.
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition rangeutilities.hh:293
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition bigunsignedint.hh:301
bool anyTrue(const Mask &mask)
Whether any entry is true
Definition simd/interface.hh:429
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition simd/interface.hh:386
bool allTrue(const Mask &mask)
Whether all entries are true
Definition simd/interface.hh:439
bool anyFalse(const Mask &mask)
Whether any entry is false
Definition simd/interface.hh:449
constexpr std::size_t lanes()
Number of lanes in a SIMD type.
Definition simd/interface.hh:305
decltype(auto) lane(std::size_t l, V &&v)
Extract an element of a SIMD type.
Definition simd/interface.hh:324
Rebind< bool, V > Mask
Mask type type of some SIMD type.
Definition simd/interface.hh:289
bool allFalse(const Mask &mask)
Whether all entries are false
Definition simd/interface.hh:459
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition simd/interface.hh:235
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
STL namespace.
Dune namespace
Definition alignedallocator.hh:13
DUNE_SIMD_LOOP_COMPARISON_OP(<)
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition debugalign.hh:556
const AlignedNumber< T, align > & cond(ADLTag< 5 >, AlignedNumber< bool, align > mask, const AlignedNumber< T, align > &ifTrue, const AlignedNumber< T, align > &ifFalse)
Definition debugalign.hh:548
T & lane(ADLTag< 5 >, std::size_t l, AlignedNumber< T, align > &v)
Definition debugalign.hh:533
bool isNaN(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is NaN.
Definition fvector.hh:458
bool isInf(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is infinite.
Definition fvector.hh:446
auto isFinite(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether all entries are finite.
Definition fvector.hh:435
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition typetraits.hh:194
Tag to make sure the functions in this namespace can be found by ADL.
Definition math.hh:212
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition base.hh:182
should have a member type type
Definition standard.hh:60
should have a member type type
Definition standard.hh:67
should be derived from a Dune::index_constant
Definition standard.hh:74
Definition loop.hh:65
LoopSIMD(Simd::Scalar< T > i)
Definition loop.hh:77
DUNE_SIMD_LOOP_PREFIX_OP(++)
auto operator!() const
Definition loop.hh:123
DUNE_SIMD_LOOP_POSTFIX_OP(--)
DUNE_SIMD_LOOP_ASSIGNMENT_OP * DUNE_SIMD_LOOP_ASSIGNMENT_OP(/=);DUNE_SIMD_LOOP_ASSIGNMENT_OP(%=
DUNE_SIMD_LOOP_ASSIGNMENT_OP & DUNE_SIMD_LOOP_ASSIGNMENT_OP(|=);DUNE_SIMD_LOOP_ASSIGNMENT_OP(^=
DUNE_SIMD_LOOP_UNARY_OP(-)
DUNE_SIMD_LOOP_PREFIX_OP(--)
DUNE_SIMD_LOOP_POSTFIX_OP(++)
DUNE_SIMD_LOOP_ASSIGNMENT_OP(-=)
LoopSIMD(const LoopSIMD< T, S, OA > &other)
Definition loop.hh:82
LoopSIMD()
Definition loop.hh:70
DUNE_SIMD_LOOP_UNARY_OP(~)
DUNE_SIMD_LOOP_ASSIGNMENT_OP(+=)
DUNE_SIMD_LOOP_UNARY_OP(+)
DUNE_SIMD_LOOP_ASSIGNMENT_OP(<<=)
DUNE_SIMD_LOOP_ASSIGNMENT_OP(> >=)
Simd::Scalar< T > type
Definition loop.hh:347
Helper class for tagging priorities.
Definition typeutilities.hh:73
Include file for users of the SIMD abstraction layer.
T fill(T... args)
T min(T... args)