1#ifndef DUNE_COMMON_SIMD_LOOP_HH
2#define DUNE_COMMON_SIMD_LOOP_HH
21# pragma GCC diagnostic push
22# pragma GCC diagnostic ignored "-Wbool-operation"
23# pragma GCC diagnostic ignored "-Wint-in-bool-context"
37 template<
class T, std::
size_t S, std::
size_t A = 0>
38 class alignas(A==0?alignof(T):A)
LoopSIMD :
public std::array<T,S> {
52 template<std::
size_t OA>
54 : std::array<T,S>(other)
64#define DUNE_SIMD_LOOP_PREFIX_OP(SYMBOL) \
65 auto operator SYMBOL() { \
66 for(std::size_t i=0; i<S; i++){ \
71 static_assert(true, "expecting ;")
73 DUNE_SIMD_LOOP_PREFIX_OP(++);
74 DUNE_SIMD_LOOP_PREFIX_OP(--);
75#undef DUNE_SIMD_LOOP_PREFIX_OP
78#define DUNE_SIMD_LOOP_UNARY_OP(SYMBOL) \
79 auto operator SYMBOL() const { \
80 LoopSIMD<T,S,A> out; \
81 for(std::size_t i=0; i<S; i++){ \
82 out[i] = SYMBOL((*this)[i]); \
86 static_assert(true, "expecting ;")
88 DUNE_SIMD_LOOP_UNARY_OP(+);
89 DUNE_SIMD_LOOP_UNARY_OP(-);
90 DUNE_SIMD_LOOP_UNARY_OP(~);
92 auto operator!()
const {
94 for(std::size_t i=0; i<S; i++){
95 out[i] = !((*this)[i]);
99#undef DUNE_SIMD_LOOP_UNARY_OP
102#define DUNE_SIMD_LOOP_POSTFIX_OP(SYMBOL) \
103 auto operator SYMBOL(int){ \
104 LoopSIMD<T,S,A> out = *this; \
108 static_assert(true, "expecting ;")
110 DUNE_SIMD_LOOP_POSTFIX_OP(++);
111 DUNE_SIMD_LOOP_POSTFIX_OP(--);
112#undef DUNE_SIMD_LOOP_POSTFIX_OP
115#define DUNE_SIMD_LOOP_ASSIGNMENT_OP(SYMBOL) \
116 auto operator SYMBOL(const Simd::Scalar<T> s) { \
117 for(std::size_t i=0; i<S; i++){ \
118 (*this)[i] SYMBOL s; \
123 auto operator SYMBOL(const LoopSIMD<T,S,A> &v) { \
124 for(std::size_t i=0; i<S; i++){ \
125 (*this)[i] SYMBOL v[i]; \
129 static_assert(true, "expecting ;")
131 DUNE_SIMD_LOOP_ASSIGNMENT_OP(+=);
132 DUNE_SIMD_LOOP_ASSIGNMENT_OP(-=);
133 DUNE_SIMD_LOOP_ASSIGNMENT_OP(*=);
134 DUNE_SIMD_LOOP_ASSIGNMENT_OP(/=);
135 DUNE_SIMD_LOOP_ASSIGNMENT_OP(%=);
136 DUNE_SIMD_LOOP_ASSIGNMENT_OP(<<=);
137 DUNE_SIMD_LOOP_ASSIGNMENT_OP(>>=);
138 DUNE_SIMD_LOOP_ASSIGNMENT_OP(&=);
139 DUNE_SIMD_LOOP_ASSIGNMENT_OP(|=);
140 DUNE_SIMD_LOOP_ASSIGNMENT_OP(^=);
141#undef DUNE_SIMD_LOOP_ASSIGNMENT_OP
145#define DUNE_SIMD_LOOP_BINARY_OP(SYMBOL) \
146 template<class T, std::size_t S, std::size_t A> \
147 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
148 LoopSIMD<T,S,A> out; \
149 for(std::size_t i=0; i<S; i++){ \
150 out[i] = v[i] SYMBOL s; \
154 template<class T, std::size_t S, std::size_t A> \
155 auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
156 LoopSIMD<T,S,A> out; \
157 for(std::size_t i=0; i<S; i++){ \
158 out[i] = s SYMBOL v[i]; \
162 template<class T, std::size_t S, std::size_t A> \
163 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
164 const LoopSIMD<T,S,A> &w) { \
165 LoopSIMD<T,S,A> out; \
166 for(std::size_t i=0; i<S; i++){ \
167 out[i] = v[i] SYMBOL w[i]; \
171 static_assert(true, "expecting ;")
173 DUNE_SIMD_LOOP_BINARY_OP(+);
174 DUNE_SIMD_LOOP_BINARY_OP(-);
175 DUNE_SIMD_LOOP_BINARY_OP(*);
176 DUNE_SIMD_LOOP_BINARY_OP(/);
177 DUNE_SIMD_LOOP_BINARY_OP(%);
179 DUNE_SIMD_LOOP_BINARY_OP(&);
180 DUNE_SIMD_LOOP_BINARY_OP(|);
181 DUNE_SIMD_LOOP_BINARY_OP(^);
183#undef DUNE_SIMD_LOOP_BINARY_OP
186#define DUNE_SIMD_LOOP_BITSHIFT_OP(SYMBOL) \
187 template<class T, std::size_t S, std::size_t A, class U> \
188 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
189 LoopSIMD<T,S,A> out; \
190 for(std::size_t i=0; i<S; i++){ \
191 out[i] = v[i] SYMBOL s; \
195 template<class T, std::size_t S, std::size_t A, class U, std::size_t AU> \
196 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
197 const LoopSIMD<U,S,AU> &w) { \
198 LoopSIMD<T,S,A> out; \
199 for(std::size_t i=0; i<S; i++){ \
200 out[i] = v[i] SYMBOL w[i]; \
204 static_assert(true, "expecting ;")
206 DUNE_SIMD_LOOP_BITSHIFT_OP(<<);
207 DUNE_SIMD_LOOP_BITSHIFT_OP(>>);
209#undef DUNE_SIMD_LOOP_BITSHIFT_OP
212#define DUNE_SIMD_LOOP_COMPARISON_OP(SYMBOL) \
213 template<class T, std::size_t S, std::size_t A, class U> \
214 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const U s) { \
215 Simd::Mask<LoopSIMD<T,S,A>> out; \
216 for(std::size_t i=0; i<S; i++){ \
217 out[i] = v[i] SYMBOL s; \
221 template<class T, std::size_t S, std::size_t A> \
222 auto operator SYMBOL(const Simd::Scalar<T> s, const LoopSIMD<T,S,A> &v) { \
223 Simd::Mask<LoopSIMD<T,S,A>> out; \
224 for(std::size_t i=0; i<S; i++){ \
225 out[i] = s SYMBOL v[i]; \
229 template<class T, std::size_t S, std::size_t A> \
230 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
231 const LoopSIMD<T,S,A> &w) { \
232 Simd::Mask<LoopSIMD<T,S,A>> out; \
233 for(std::size_t i=0; i<S; i++){ \
234 out[i] = v[i] SYMBOL w[i]; \
238 static_assert(true, "expecting ;")
240 DUNE_SIMD_LOOP_COMPARISON_OP(<);
241 DUNE_SIMD_LOOP_COMPARISON_OP(>);
242 DUNE_SIMD_LOOP_COMPARISON_OP(<=);
243 DUNE_SIMD_LOOP_COMPARISON_OP(>=);
244 DUNE_SIMD_LOOP_COMPARISON_OP(==);
245 DUNE_SIMD_LOOP_COMPARISON_OP(!=);
246#undef DUNE_SIMD_LOOP_COMPARISON_OP
249#define DUNE_SIMD_LOOP_BOOLEAN_OP(SYMBOL) \
250 template<class T, std::size_t S, std::size_t A> \
251 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, const Simd::Scalar<T> s) { \
252 Simd::Mask<LoopSIMD<T,S,A>> out; \
253 for(std::size_t i=0; i<S; i++){ \
254 out[i] = v[i] SYMBOL s; \
258 template<class T, std::size_t S, std::size_t A> \
259 auto operator SYMBOL(const Simd::Mask<T> s, const LoopSIMD<T,S,A> &v) { \
260 Simd::Mask<LoopSIMD<T,S,A>> out; \
261 for(std::size_t i=0; i<S; i++){ \
262 out[i] = s SYMBOL v[i]; \
266 template<class T, std::size_t S, std::size_t A> \
267 auto operator SYMBOL(const LoopSIMD<T,S,A> &v, \
268 const LoopSIMD<T,S,A> &w) { \
269 Simd::Mask<LoopSIMD<T,S,A>> out; \
270 for(std::size_t i=0; i<S; i++){ \
271 out[i] = v[i] SYMBOL w[i]; \
275 static_assert(true, "expecting ;")
277 DUNE_SIMD_LOOP_BOOLEAN_OP(&&);
278 DUNE_SIMD_LOOP_BOOLEAN_OP(||);
279#undef DUNE_SIMD_LOOP_BOOLEAN_OP
282 template<
class T, std::
size_t S, std::
size_t A>
283 std::ostream& operator<< (std::ostream &os,
const LoopSIMD<T,S,A> &v) {
285 for(std::size_t i=0; i<S-1; i++) {
293 namespace Overloads {
300 template<
class T, std::
size_t S, std::
size_t A>
301 struct ScalarType<LoopSIMD<T,S,A>> {
302 using type = Simd::Scalar<T>;
305 template<
class U,
class T, std::
size_t S, std::
size_t A>
306 struct RebindType<U, LoopSIMD<T,S,A>> {
307 using type = LoopSIMD<Simd::Rebind<U, T>,S,A>;
311 template<
class T, std::
size_t S, std::
size_t A>
312 struct LaneCount<LoopSIMD<T,S,A>> :
index_constant<S*lanes<T>()> {};
314 template<
class T, std::
size_t S, std::
size_t A>
315 auto lane(ADLTag<5>, std::size_t l, LoopSIMD<T,S,A> &&v)
316 ->
decltype(std::move(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()])))
318 return std::move(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]));
321 template<
class T, std::
size_t S, std::
size_t A>
322 auto lane(ADLTag<5>, std::size_t l,
const LoopSIMD<T,S,A> &v)
323 ->
decltype(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
325 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
328 template<
class T, std::
size_t S, std::
size_t A>
329 auto lane(ADLTag<5>, std::size_t l, LoopSIMD<T,S,A> &v)
330 ->
decltype(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
332 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
335 template<
class T, std::
size_t S, std::
size_t AM, std::
size_t AD>
337 LoopSIMD<T,S,AD> ifTrue, LoopSIMD<T,S,AD> ifFalse) {
338 LoopSIMD<T,S,AD> out;
339 for(std::size_t i=0; i<S; i++) {
345 template<
class M,
class T, std::
size_t S, std::
size_t A>
346 auto cond(ADLTag<5, std::is_same<
bool, Simd::Scalar<M> >::value
347 && Simd::lanes<M>() ==
Simd::lanes<LoopSIMD<T,S,A> >()>,
348 M
mask, LoopSIMD<T,S,A> ifTrue, LoopSIMD<T,S,A> ifFalse)
356 template<
class M, std::
size_t S, std::
size_t A>
357 bool anyTrue(ADLTag<5>, LoopSIMD<M,S,A>
mask) {
359 for(std::size_t i=0; i<S; i++) {
365 template<
class M, std::
size_t S, std::
size_t A>
368 for(std::size_t i=0; i<S; i++) {
374 template<
class M, std::
size_t S, std::
size_t A>
377 for(std::size_t i=0; i<S; i++) {
383 template<
class M, std::
size_t S, std::
size_t A>
386 for(std::size_t i=0; i<S; i++) {
403#define DUNE_SIMD_LOOP_CMATH_UNARY_OP(expr) \
404 template<class T, std::size_t S, std::size_t A, typename Sfinae = \
405 typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
406 auto expr(const LoopSIMD<T,S,A> &v) { \
408 LoopSIMD<T,S,A> out; \
409 for(std::size_t i=0; i<S; i++) { \
410 out[i] = expr(v[i]); \
414 static_assert(true, "expecting ;")
416#define DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(expr, returnType) \
417 template<class T, std::size_t S, std::size_t A, typename Sfinae = \
418 typename std::enable_if_t<!std::is_integral<Simd::Scalar<T>>::value> > \
419 auto expr(const LoopSIMD<T,S,A> &v) { \
421 LoopSIMD<returnType,S> out; \
422 for(std::size_t i=0; i<S; i++) { \
423 out[i] = expr(v[i]); \
427 static_assert(true, "expecting ;")
429 DUNE_SIMD_LOOP_CMATH_UNARY_OP(cos);
430 DUNE_SIMD_LOOP_CMATH_UNARY_OP(sin);
431 DUNE_SIMD_LOOP_CMATH_UNARY_OP(tan);
432 DUNE_SIMD_LOOP_CMATH_UNARY_OP(acos);
433 DUNE_SIMD_LOOP_CMATH_UNARY_OP(asin);
434 DUNE_SIMD_LOOP_CMATH_UNARY_OP(atan);
435 DUNE_SIMD_LOOP_CMATH_UNARY_OP(cosh);
436 DUNE_SIMD_LOOP_CMATH_UNARY_OP(sinh);
437 DUNE_SIMD_LOOP_CMATH_UNARY_OP(tanh);
438 DUNE_SIMD_LOOP_CMATH_UNARY_OP(acosh);
439 DUNE_SIMD_LOOP_CMATH_UNARY_OP(asinh);
440 DUNE_SIMD_LOOP_CMATH_UNARY_OP(atanh);
442 DUNE_SIMD_LOOP_CMATH_UNARY_OP(exp);
443 DUNE_SIMD_LOOP_CMATH_UNARY_OP(log);
444 DUNE_SIMD_LOOP_CMATH_UNARY_OP(log10);
445 DUNE_SIMD_LOOP_CMATH_UNARY_OP(exp2);
446 DUNE_SIMD_LOOP_CMATH_UNARY_OP(expm1);
447 DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(ilogb,
int);
448 DUNE_SIMD_LOOP_CMATH_UNARY_OP(log1p);
449 DUNE_SIMD_LOOP_CMATH_UNARY_OP(log2);
450 DUNE_SIMD_LOOP_CMATH_UNARY_OP(logb);
452 DUNE_SIMD_LOOP_CMATH_UNARY_OP(sqrt);
453 DUNE_SIMD_LOOP_CMATH_UNARY_OP(cbrt);
455 DUNE_SIMD_LOOP_CMATH_UNARY_OP(erf);
456 DUNE_SIMD_LOOP_CMATH_UNARY_OP(erfc);
457 DUNE_SIMD_LOOP_CMATH_UNARY_OP(tgamma);
458 DUNE_SIMD_LOOP_CMATH_UNARY_OP(lgamma);
460 DUNE_SIMD_LOOP_CMATH_UNARY_OP(ceil);
461 DUNE_SIMD_LOOP_CMATH_UNARY_OP(floor);
462 DUNE_SIMD_LOOP_CMATH_UNARY_OP(
trunc);
463 DUNE_SIMD_LOOP_CMATH_UNARY_OP(
round);
464 DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(lround,
long);
465 DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(llround,
long long);
466 DUNE_SIMD_LOOP_CMATH_UNARY_OP(rint);
467 DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(lrint,
long);
468 DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(llrint,
long long);
469 DUNE_SIMD_LOOP_CMATH_UNARY_OP(nearbyint);
471 DUNE_SIMD_LOOP_CMATH_UNARY_OP(fabs);
472 DUNE_SIMD_LOOP_CMATH_UNARY_OP(abs);
474#undef DUNE_SIMD_LOOP_CMATH_UNARY_OP
475#undef DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN
497#define DUNE_SIMD_LOOP_STD_UNARY_OP(expr) \
498 template<class T, std::size_t S, std::size_t A> \
499 auto expr(const LoopSIMD<T,S,A> &v) { \
501 LoopSIMD<T,S,A> out; \
502 for(std::size_t i=0; i<S; i++) { \
503 out[i] = expr(v[i]); \
508 template<class T, std::size_t S, std::size_t A> \
509 auto expr(const LoopSIMD<std::complex<T>,S,A> &v) { \
511 LoopSIMD<T,S,A> out; \
512 for(std::size_t i=0; i<S; i++) { \
513 out[i] = expr(v[i]); \
517 static_assert(true, "expecting ;")
519 DUNE_SIMD_LOOP_STD_UNARY_OP(real);
520 DUNE_SIMD_LOOP_STD_UNARY_OP(imag);
522#undef DUNE_SIMD_LOOP_STD_UNARY_OP
524#define DUNE_SIMD_LOOP_STD_BINARY_OP(expr) \
525 template<class T, std::size_t S, std::size_t A> \
526 auto expr(const LoopSIMD<T,S,A> &v, const LoopSIMD<T,S,A> &w) { \
528 LoopSIMD<T,S,A> out; \
529 for(std::size_t i=0; i<S; i++) { \
530 out[i] = expr(v[i],w[i]); \
534 static_assert(true, "expecting ;")
536 DUNE_SIMD_LOOP_STD_BINARY_OP(
max);
537 DUNE_SIMD_LOOP_STD_BINARY_OP(
min);
539#undef DUNE_SIMD_LOOP_STD_BINARY_OP
541 namespace MathOverloads {
542 template<
class T, std::
size_t S, std::
size_t A>
543 auto isNaN(
const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
544 Simd::Mask<LoopSIMD<T,S,A>> out;
545 for(
auto l : range(S))
546 out[l] = Dune::isNaN(v[l]);
550 template<
class T, std::
size_t S, std::
size_t A>
551 auto isInf(
const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
552 Simd::Mask<LoopSIMD<T,S,A>> out;
553 for(
auto l : range(S))
554 out[l] = Dune::isInf(v[l]);
558 template<
class T, std::
size_t S, std::
size_t A>
559 auto isFinite(
const LoopSIMD<T,S,A> &v, PriorityTag<3>, ADLTag) {
560 Simd::Mask<LoopSIMD<T,S,A>> out;
561 for(
auto l : range(S))
562 out[l] = Dune::isFinite(v[l]);
567 template<
class T, std::
size_t S, std::
size_t A>
568 struct IsNumber<LoopSIMD<T,S,A>> :
569 public std::integral_constant<bool, IsNumber<T>::value>{
573# pragma GCC diagnostic pop
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: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
bool anyTrue(const Mask &mask)
Whether any entry is true
Definition: interface.hh:427
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: interface.hh:384
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: interface.hh:437
bool anyFalse(const Mask &mask)
Whether any entry is false
Definition: interface.hh:447
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
Rebind< bool, V > Mask
Mask type type of some SIMD type.
Definition: interface.hh:287
bool allFalse(const Mask &mask)
Whether all entries are false
Definition: interface.hh:457
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:233
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:11
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.