3 #ifndef DUNE_COMMON_SIMD_LOOP_HH 4 #define DUNE_COMMON_SIMD_LOOP_HH 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 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 47 #define DUNE_PRAGMA_OMP_SIMD _Pragma("omp simd") 49 #define DUNE_PRAGMA_OMP_SIMD 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> {
79 template<std::
size_t OA>
81 :
std::array<T,S>(other)
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++){ \ 99 static_assert(true, "expecting ;") 103 #undef DUNE_SIMD_LOOP_PREFIX_OP 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]); \ 115 static_assert(true, "expecting ;") 124 for(std::size_t
i=0;
i<S;
i++){
125 out[
i] = !((*this)[
i]);
129 #undef DUNE_SIMD_LOOP_UNARY_OP 132 #define DUNE_SIMD_LOOP_POSTFIX_OP(SYMBOL) \ 133 auto operator SYMBOL(int){ \ 134 LoopSIMD<T,S,A> out = *this; \ 138 static_assert(true, "expecting ;") 142 #undef DUNE_SIMD_LOOP_POSTFIX_OP 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; \ 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]; \ 161 static_assert(true, "expecting ;") 173 #undef DUNE_SIMD_LOOP_ASSIGNMENT_OP 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; \ 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]; \ 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]; \ 206 static_assert(true, "expecting ;") 218 #undef DUNE_SIMD_LOOP_BINARY_OP 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; \ 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]; \ 241 static_assert(true, "expecting ;") 246 #undef DUNE_SIMD_LOOP_BITSHIFT_OP 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; \ 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]; \ 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]; \ 278 static_assert(true, "expecting ;") 286 #undef DUNE_SIMD_LOOP_COMPARISON_OP 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; \ 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]; \ 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]; \ 318 static_assert(true, "expecting ;") 322 #undef DUNE_SIMD_LOOP_BOOLEAN_OP 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) {
328 for(std::size_t
i=0;
i<S-1;
i++) {
336 namespace Overloads {
343 template<
class T, std::
size_t S, std::
size_t A>
348 template<
class U,
class T, std::
size_t S, std::
size_t A>
354 template<
class T, std::
size_t S, std::
size_t A>
357 template<
class T, std::
size_t S, std::
size_t A>
359 -> decltype(std::move(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()])))
361 return std::move(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]));
364 template<
class T, std::
size_t S, std::
size_t A>
366 -> decltype(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
368 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
371 template<
class T, std::
size_t S, std::
size_t A>
373 -> decltype(
Simd::lane(l%lanes<T>(), v[l/lanes<T>()]))
375 return Simd::lane(l%lanes<T>(), v[l/lanes<T>()]);
378 template<
class T, std::
size_t S, std::
size_t AM, std::
size_t AD>
382 for(std::size_t
i=0;
i<S;
i++) {
388 template<
class M,
class T, std::
size_t S, std::
size_t A>
399 template<
class M, std::
size_t S, std::
size_t A>
402 for(std::size_t
i=0;
i<S;
i++) {
408 template<
class M, std::
size_t S, std::
size_t A>
411 for(std::size_t
i=0;
i<S;
i++) {
417 template<
class M, std::
size_t S, std::
size_t A>
420 for(std::size_t
i=0;
i<S;
i++) {
426 template<
class M, std::
size_t S, std::
size_t A>
429 for(std::size_t
i=0;
i<S;
i++) {
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) { \ 451 LoopSIMD<T,S,A> out; \ 452 for(std::size_t i=0; i<S; i++) { \ 453 out[i] = expr(v[i]); \ 457 static_assert(true, "expecting ;") 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) { \ 464 LoopSIMD<returnType,S> out; \ 465 for(std::size_t i=0; i<S; i++) { \ 466 out[i] = expr(v[i]); \ 470 static_assert(true, "expecting ;") 517 #undef DUNE_SIMD_LOOP_CMATH_UNARY_OP 518 #undef DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN 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) { \ 544 LoopSIMD<T,S,A> out; \ 545 for(std::size_t i=0; i<S; i++) { \ 546 out[i] = expr(v[i]); \ 551 template<class T, std::size_t S, std::size_t A> \ 552 auto expr(const LoopSIMD<std::complex<T>,S,A> &v) { \ 554 LoopSIMD<T,S,A> out; \ 555 for(std::size_t i=0; i<S; i++) { \ 556 out[i] = expr(v[i]); \ 560 static_assert(true, "expecting ;") 565 #undef DUNE_SIMD_LOOP_STD_UNARY_OP 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) { \ 571 LoopSIMD<T,S,A> out; \ 572 for(std::size_t i=0; i<S; i++) { \ 573 out[i] = expr(v[i],w[i]); \ 577 static_assert(true, "expecting ;") 582 #undef DUNE_SIMD_LOOP_STD_BINARY_OP 584 namespace MathOverloads {
585 template<
class T, std::
size_t S, std::
size_t A>
588 for(
auto l :
range(S))
593 template<
class T, std::
size_t S, std::
size_t A>
596 for(
auto l :
range(S))
601 template<
class T, std::
size_t S, std::
size_t A>
604 for(
auto l :
range(S))
610 template<
class T, std::
size_t S, std::
size_t A>
612 public std::integral_constant<bool, IsNumber<T>::value>{
615 #ifdef CLANG_WARNING_DISABLED 616 # pragma clang diagnostic pop 617 # undef CLANG_WARNING_DISABLED 620 #ifdef GCC_WARNING_DISABLED 621 # pragma GCC diagnostic pop 622 # undef GCC_WARNING_DISABLED constexpr std::size_t lanes()
Number of lanes in a SIMD type.
Definition: simd/interface.hh:305
Simd::Scalar< T > type
Definition: loop.hh:345
DUNE_SIMD_LOOP_BITSHIFT_OP(<<)
DUNE_SIMD_LOOP_POSTFIX_OP(++)
auto isFinite(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether all entries are finite.
Definition: fvector.hh:435
auto isNaN(const LoopSIMD< T, S, A > &v, PriorityTag< 3 >, ADLTag)
Definition: loop.hh:586
LoopSIMD()
Definition: loop.hh:70
bool isNaN(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is NaN.
Definition: fvector.hh:458
LoopSIMD(Simd::Scalar< T > i)
Definition: loop.hh:75
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: bigunsignedint.hh:628
Some useful basic math stuff.
decltype(auto) lane(std::size_t l, V &&v)
Extract an element of a SIMD type.
Definition: simd/interface.hh:324
DUNE_SIMD_LOOP_BINARY_OP(+)
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
DUNE_SIMD_LOOP_STD_BINARY_OP(max)
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:407
bool anyFalse(const Mask &mask)
Whether any entry is false
Definition: simd/interface.hh:449
bool anyFalse(ADLTag< 0 >, const Mask &mask)
implements Simd::anyFalse()
Definition: defaults.hh:114
bool allFalse(ADLTag< 0 >, const Mask &mask)
implements Simd::allFalse()
Definition: defaults.hh:124
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
DUNE_SIMD_LOOP_BOOLEAN_OP && DUNE_SIMD_LOOP_BOOLEAN_OP(||);template< class T, std::size_t S, std::size_t A > std::ostream &operator<<(std::ostream &os, const LoopSIMD< T, S, A > &v
Definition: loop.hh:321
DUNE_SIMD_LOOP_UNARY_OP(+)
T & lane(ADLTag< 5 >, std::size_t l, AlignedNumber< T, align > &v)
Definition: debugalign.hh:533
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
I i
Definition: hybridmultiindex.hh:328
Tag to make sure the functions in this namespace can be found by ADL.
Definition: math.hh:212
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: simd/interface.hh:235
should have a member type type
Definition: base.hh:196
Dune namespace
Definition: alignedallocator.hh:12
LoopSIMD(const LoopSIMD< T, S, OA > &other)
Definition: loop.hh:80
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:288
bool allTrue(ADLTag< 0 >, const Mask &mask)
implements Simd::allTrue()
Definition: defaults.hh:104
auto isFinite(const LoopSIMD< T, S, A > &v, PriorityTag< 3 >, ADLTag)
Definition: loop.hh:602
DUNE_SIMD_LOOP_STD_UNARY_OP(real)
DUNE_SIMD_LOOP_CMATH_UNARY_OP(cos)
DUNE_SIMD_LOOP_CMATH_UNARY_OP_WITH_RETURN(ilogb, int)
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:511
#define DUNE_PRAGMA_OMP_SIMD
Definition: loop.hh:49
DUNE_SIMD_LOOP_ASSIGNMENT_OP(+=)
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition: base.hh:182
DUNE_SIMD_LOOP_COMPARISON_OP(<)
auto isInf(const LoopSIMD< T, S, A > &v, PriorityTag< 3 >, ADLTag)
Definition: loop.hh:594
bool isInf(const FieldVector< K, SIZE > &b, PriorityTag< 2 >, ADLTag)
Returns whether any entry is infinite.
Definition: fvector.hh:446
constexpr auto sqrt(T t) requires(std
Definition: cmath.hh:39
Helper class for tagging priorities.
Definition: typeutilities.hh:72
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:311
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: simd/interface.hh:439
bool allFalse(const Mask &mask)
Whether all entries are false
Definition: simd/interface.hh:459
should be derived from a Dune::index_constant
Definition: base.hh:212
bool anyTrue(const Mask &mask)
Whether any entry is true
Definition: simd/interface.hh:429
Rebind< bool, V > Mask
Mask type type of some SIMD type.
Definition: simd/interface.hh:289
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition: debugalign.hh:556
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
auto operator!() const
Definition: loop.hh:121
Traits for type conversions and type information.
constexpr T abs(T t)
Definition: cmath.hh:27
should have a member type type
Definition: base.hh:204
Include file for users of the SIMD abstraction layer.
DUNE_SIMD_LOOP_PREFIX_OP(++)
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: simd/interface.hh:386