3#ifndef DUNE_COMMON_SIMD_TEST_HH
4#define DUNE_COMMON_SIMD_TEST_HH
20#include <unordered_set>
24#include <dune/common/hybridutilities.hh>
27#include <dune/common/simd/loop.hh>
29#include <dune/common/std/type_traits.hh>
30#include <dune/common/typelist.hh>
38 template<
class T,
class SFINAE =
void>
39 struct LessThenComparable : std::false_type {};
41 struct LessThenComparable<T,
std::
void_t<decltype(std::declval<T>()
42 < std::declval<T>())> > :
46 template<
class Dst,
class Src>
47 struct CopyConstHelper
51 template<
class Dst,
class Src>
52 struct CopyConstHelper<Dst, const Src>
54 using type = std::add_const_t<Dst>;
57 template<
class Dst,
class Src>
58 struct CopyVolatileHelper
62 template<
class Dst,
class Src>
63 struct CopyVolatileHelper<Dst, volatile Src>
65 using type = std::add_volatile_t<Dst>;
68 template<
class Dst,
class Src>
69 struct CopyReferenceHelper
73 template<
class Dst,
class Src>
74 struct CopyReferenceHelper<Dst, Src&>
76 using type = std::add_lvalue_reference_t<Dst>;
79 template<
class Dst,
class Src>
80 struct CopyReferenceHelper<Dst, Src&&>
82 using type = std::add_rvalue_reference_t<Dst>;
85 template<
class Dst,
class Src>
86 using CopyRefQual =
typename CopyReferenceHelper<
87 typename CopyVolatileHelper<
88 typename CopyConstHelper<
90 std::remove_reference_t<Src>
92 std::remove_reference_t<Src>
97 template<
class Mark,
class Types,
99 std::make_index_sequence<TypeListSize<Types>::value - 1> >
101 template<
class Mark,
class Types, std::size_t... I>
102 struct RemoveEnd<Mark, Types,
std::index_sequence<I...>>
104 using Back = TypeListEntry_t<TypeListSize<Types>::value - 1, Types>;
105 static_assert(std::is_same<Mark, Back>::value,
106 "TypeList not terminated by proper EndMark");
107 using type = TypeList<TypeListEntry_t<I, Types>...>;
110 template<
class T,
class List,
class =
void>
114 struct TypeInList<T,
TypeList<> > : std::false_type {};
116 template<
class T,
class... Rest>
117 struct TypeInList<T,
TypeList<T, Rest...> > : std::true_type {};
119 template<
class T,
class Head,
class... Rest>
120 struct TypeInList<T,
TypeList<Head, Rest...>,
121 std::enable_if_t<!std::is_same<T, Head>::value> > :
122 TypeInList<T, TypeList<Rest...> >::type
126 struct IsLoop : std::false_type {};
127 template<
class T, std::
size_t S>
128 struct IsLoop<LoopSIMD<T, S> > : std::true_type {};
137 constexpr bool debugTypes(std::true_type) {
return true; }
138 template<
class... Types>
140 constexpr bool debugTypes(std::false_type) {
return false; }
156 template<
class... Types>
162 using IsLoop =
typename Impl::IsLoop<T>::type;
166 std::ostream &log_ = std::cerr;
169 std::unordered_set<std::type_index> seen_;
176 void complain(
const char *file,
int line,
const char *func,
179 void complain(
const char *file,
int line,
const char *func,
180 const std::string &opname,
const char *expr);
186#define DUNE_SIMD_CHECK(expr) \
187 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, #expr))
191#define DUNE_SIMD_CHECK_OP(expr) \
192 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, \
193 DUNE_SIMD_OPNAME, #expr))
197 static std::decay_t<T> prvalue(T &&t)
199 return std::forward<T>(t);
204 static bool is42(
const V &v)
208 for(std::size_t l = 0; l <
lanes(v); ++l)
224 for(std::size_t l = 0; l <
lanes(vec); ++l)
225 lane(l, vec) = l + 1;
231 static bool is123(
const V &v)
235 for(std::size_t l = 0; l <
lanes(v); ++l)
243 static V leftVector()
248 for(std::size_t l = 0; l <
lanes(res); ++l)
254 static V rightVector()
259 for(std::size_t l = 0; l <
lanes(res); ++l)
267 static T leftScalar()
273 static T rightScalar()
280 template<
class Dst,
class Src>
281 using CopyRefQual = Impl::CopyRefQual<Dst, Src>;
288 template<
class Op,
class... Vectors>
290 decltype(std::declval<Op>().
305 static_assert(std::is_same<T, std::decay_t<T> >::value,
"Scalar types "
306 "must not be references, and must not include "
308 [[maybe_unused]] T a{};
312 [[deprecated(
"Warning: please include bool in the Rebinds for "
313 "simd type V, as Masks are not checked otherwise.")]]
314 void warnMissingMaskRebind(std::true_type) {}
316 void warnMissingMaskRebind(std::false_type) {}
318 template<
class V,
class Rebinds,
template<
class>
class RebindPrune,
319 template<
class>
class RebindAccept,
class Recurse>
320 void checkRebindOf(Recurse recurse)
323 using T =
typename decltype(target)::type;
327 log_ <<
"Type " << className<V>() <<
" rebound to "
328 << className<T>() <<
" is " << className<W>() << std::endl;
330 static_assert(std::is_same<W, std::decay_t<W> >::value,
"Rebound "
331 "types must not be references, and must not include "
333 static_assert(lanes<V>() == lanes<W>(),
"Rebound types must have "
334 "the same number of lanes as the original vector "
336 static_assert(std::is_same<T, Scalar<W> >::value,
"Rebound types "
337 "must have the bound-to scalar type");
339 if constexpr (RebindPrune<W>{}) {
340 log_ <<
"Pruning check of Simd type " << className<W>()
344 using Impl::debugTypes;
345 static_assert(debugTypes<T, V, W>(RebindAccept<W>{}),
346 "Rebind<T, V> is W, but that is not accepted "
352 static_assert(std::is_same<Rebind<Scalar<V>, V>, V>::value,
"A type "
353 "rebound to its own scalar type must be the same type "
354 "as the original type");
355 static_assert(std::is_same<Rebind<bool, V>,
Mask<V> >::value,
"A type "
356 "rebound to bool must be the mask type for that type");
358 constexpr bool hasBool = Impl::TypeInList<bool, Rebinds>::value;
359 warnMissingMaskRebind<V>(Std::bool_constant<!hasBool>{});
371 static_assert(std::is_same<std::size_t, decltype(lanes<V>())>::value,
372 "return type of lanes<V>() should be std::size_t");
373 static_assert(std::is_same<std::size_t,
decltype(
lanes(V{}))>::value,
374 "return type of lanes(V{}) should be std::size_t");
377 [[maybe_unused]]
constexpr auto size = lanes<V>();
379 DUNE_SIMD_CHECK(lanes<V>() ==
lanes(V{}));
383 void checkDefaultConstruct()
385 { [[maybe_unused]] V vec; }
386 { [[maybe_unused]] V vec{}; }
387 { [[maybe_unused]] V vec = {}; }
397 for(std::size_t l = 0; l <
lanes(vec); ++l)
398 lane(l, vec) = l + 1;
399 for(std::size_t l = 0; l <
lanes(vec); ++l)
401 using MLRes =
decltype(
lane(0, vec));
402 static_assert(std::is_same<MLRes, Scalar<V>&>::value ||
403 std::is_same<MLRes, std::decay_t<MLRes> >::value,
404 "Result of lane() on a mutable lvalue vector must "
405 "either be a mutable reference to a scalar of that "
406 "vector or a proxy object (which itself may not be a "
407 "reference nor const).");
411 for(std::size_t l = 0; l <
lanes(vec); ++l)
413 using CLRes =
decltype(
lane(0, vec2));
414 static_assert(std::is_same<CLRes, const Scalar<V>&>::value ||
415 std::is_same<CLRes, std::decay_t<CLRes> >::value,
416 "Result of lane() on a const lvalue vector must "
417 "either be a const lvalue reference to a scalar of that "
418 "vector or a proxy object (which itself may not be a "
419 "reference nor const).");
420 static_assert(!std::is_assignable<CLRes, Scalar<V> >::value,
421 "Result of lane() on a const lvalue vector must not be "
422 "assignable from a scalar.");
425 for(std::size_t l = 0; l <
lanes(vec); ++l)
427 using RRes =
decltype(
lane(0, prvalue(vec)));
436 static_assert(std::is_same<RRes, Scalar<V> >::value ||
437 std::is_same<RRes, Scalar<V>&&>::value,
438 "Result of lane() on a rvalue vector V must be "
439 "Scalar<V> or Scalar<V>&&.");
450 void checkCopyMoveConstruct()
453 { V vec (make123<V>()); DUNE_SIMD_CHECK(is123(vec)); }
454 { V vec = make123<V>() ; DUNE_SIMD_CHECK(is123(vec)); }
455 { V vec {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
456 { V vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
459 { V ref(make123<V>()); V vec (ref);
460 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
461 { V ref(make123<V>()); V vec = ref ;
462 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
463 { V ref(make123<V>()); V vec {ref};
464 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
465 { V ref(make123<V>()); V vec = {ref};
466 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
467 {
const V ref(make123<V>()); V vec (ref);
468 DUNE_SIMD_CHECK(is123(vec)); }
469 {
const V ref(make123<V>()); V vec = ref ;
470 DUNE_SIMD_CHECK(is123(vec)); }
471 {
const V ref(make123<V>()); V vec {ref};
472 DUNE_SIMD_CHECK(is123(vec)); }
473 {
const V ref(make123<V>()); V vec = {ref};
474 DUNE_SIMD_CHECK(is123(vec)); }
477 { V ref(make123<V>()); V vec (std::move(ref));
478 DUNE_SIMD_CHECK(is123(vec)); }
479 { V ref(make123<V>()); V vec = std::move(ref) ;
480 DUNE_SIMD_CHECK(is123(vec)); }
481 { V ref(make123<V>()); V vec {std::move(ref)};
482 DUNE_SIMD_CHECK(is123(vec)); }
483 { V ref(make123<V>()); V vec = {std::move(ref)};
484 DUNE_SIMD_CHECK(is123(vec)); }
488 void checkBroadcastVectorConstruct()
492 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
494 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
500 DUNE_SIMD_CHECK(is42(vec)); }
501 {
const Scalar<V> ref = 42; V vec = ref ;
502 DUNE_SIMD_CHECK(is42(vec)); }
509 {
Scalar<V> ref = 42; V vec (std::move(ref));
510 DUNE_SIMD_CHECK(is42(vec)); }
511 {
Scalar<V> ref = 42; V vec = std::move(ref) ;
512 DUNE_SIMD_CHECK(is42(vec)); }
520 void checkBroadcastMaskConstruct()
524 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
528 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
532 DUNE_SIMD_CHECK(is42(vec)); }
536 DUNE_SIMD_CHECK(is42(vec)); }
541 {
Scalar<V> ref = 42; V vec (std::move(ref));
542 DUNE_SIMD_CHECK(is42(vec)); }
545 {
Scalar<V> ref = 42; V vec {std::move(ref)};
546 DUNE_SIMD_CHECK(is42(vec)); }
552 template<
class FromV,
class ToV>
556 FromV fromVec = make123<FromV>();
557 auto toVec = implCast<ToV>(fromVec);
558 static_assert(std::is_same<
decltype(toVec), ToV>::value,
559 "Unexpected result type for implCast<ToV>(FromV&)");
560 DUNE_SIMD_CHECK(is123(fromVec));
561 DUNE_SIMD_CHECK(is123(toVec));
565 const FromV fromVec = make123<FromV>();
566 auto toVec = implCast<ToV>(fromVec);
567 static_assert(std::is_same<
decltype(toVec), ToV>::value,
568 "Unexpected result type for implCast<ToV>(const "
570 DUNE_SIMD_CHECK(is123(toVec));
574 auto toVec = implCast<ToV>(make123<FromV>());
575 static_assert(std::is_same<
decltype(toVec), ToV>::value,
576 "Unexpected result type for implCast<ToV>(FromV&&)");
577 DUNE_SIMD_CHECK(is123(toVec));
588 checkImplCast<V, V>();
589 checkImplCast<V, LoopV>();
590 checkImplCast<LoopV, V>();
595 void checkBroadcast()
600 auto vec = broadcast<V>(ref);
601 static_assert(std::is_same<
decltype(vec), V>::value,
602 "Unexpected result type for broadcast<V>()");
603 DUNE_SIMD_CHECK(is42(vec));
609 auto vec = broadcast<V>(ref);
610 static_assert(std::is_same<
decltype(vec), V>::value,
611 "Unexpected result type for broadcast<V>()");
612 DUNE_SIMD_CHECK(is42(vec));
617 static_assert(std::is_same<
decltype(vec), V>::value,
618 "Unexpected result type for broadcast<V>()");
619 DUNE_SIMD_CHECK(is42(vec));
623 auto vec = broadcast<V>(42);
624 static_assert(std::is_same<
decltype(vec), V>::value,
625 "Unexpected result type for broadcast<V>()");
626 DUNE_SIMD_CHECK(is42(vec));
630 auto vec = broadcast<V>(42.0);
631 static_assert(std::is_same<
decltype(vec), V>::value,
632 "Unexpected result type for broadcast<V>()");
633 DUNE_SIMD_CHECK(is42(vec));
638 void checkBracedAssign()
641 { V ref = make123<V>(); V vec; vec = {ref};
642 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
643 {
const V ref = make123<V>(); V vec; vec = {ref};
644 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
647 { V vec; vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
651 void checkBracedBroadcastAssign()
670#define DUNE_SIMD_POSTFIX_OP(NAME, SYMBOL) \
671 struct OpPostfix##NAME \
674 auto operator()(V&& v) const \
675 -> decltype(std::forward<V>(v) SYMBOL) \
677 return std::forward<V>(v) SYMBOL; \
681#define DUNE_SIMD_PREFIX_OP(NAME, SYMBOL) \
682 struct OpPrefix##NAME \
685 auto operator()(V&& v) const \
686 -> decltype(SYMBOL std::forward<V>(v)) \
688 return SYMBOL std::forward<V>(v); \
692 DUNE_SIMD_POSTFIX_OP(Decrement, -- );
693 DUNE_SIMD_POSTFIX_OP(Increment, ++ );
695 DUNE_SIMD_PREFIX_OP (Decrement, -- );
696 DUNE_SIMD_PREFIX_OP (Increment, ++ );
698 DUNE_SIMD_PREFIX_OP (Plus, + );
699 DUNE_SIMD_PREFIX_OP (Minus, - );
700 DUNE_SIMD_PREFIX_OP (LogicNot, ! );
706#pragma GCC diagnostic push
707#pragma GCC diagnostic ignored "-Wpragmas"
708#pragma GCC diagnostic ignored "-Wunknown-warning-option"
709#pragma GCC diagnostic ignored "-Wbool-operation"
710 DUNE_SIMD_PREFIX_OP (BitNot, ~ );
711#pragma GCC diagnostic pop
713#undef DUNE_SIMD_POSTFIX_OP
714#undef DUNE_SIMD_PREFIX_OP
716 template<
class V,
class Op>
721#define DUNE_SIMD_OPNAME (className<Op(V)>())
723 auto val = leftVector<std::decay_t<V>>();
727 auto &&result = op(
static_cast<V
>(arg));
728 using T =
Scalar<std::decay_t<
decltype(result)> >;
729 for(std::size_t l = 0; l <
lanes(val); ++l)
746 ==
static_cast<T
>(op(
lane(l,
static_cast<V
>(val)))));
750 for(std::size_t l = 0; l < lanes<std::decay_t<V> >(); ++l)
751 DUNE_SIMD_CHECK_OP(
lane(l, val) ==
lane(l, arg));
752#undef DUNE_SIMD_OPNAME
755 template<
class V,
class Op>
765 template<
class V,
class Op>
766 void checkUnaryOpsV(Op op)
768 checkUnaryOpV<V&>(op);
769 checkUnaryOpV<const V&>(op);
770 checkUnaryOpV<V&&>(op);
784#define DUNE_SIMD_INFIX_OP(NAME, SYMBOL) \
785 struct OpInfix##NAME \
787 template<class V1, class V2> \
788 decltype(auto) operator()(V1&& v1, V2&& v2) const \
790 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
792 template<class S1, class S2> \
793 auto scalar(S1&& s1, S2&& s2) const \
794 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
805#define DUNE_SIMD_ASSIGN_OP(NAME, SYMBOL) \
806 struct OpInfix##NAME \
808 template<class V1, class V2> \
809 decltype(auto) operator()(V1&& v1, V2&& v2) const \
811 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
813 template<class S1, class S2> \
814 auto scalar(S1& s1, S2&& s2) const \
815 -> decltype(s1 SYMBOL std::forward<S2>(s2)); \
818#define DUNE_SIMD_REPL_OP(NAME, REPLFN, SYMBOL) \
819 struct OpInfix##NAME \
821 template<class V1, class V2> \
822 decltype(auto) operator()(V1&& v1, V2&& v2) const \
824 return Simd::REPLFN(std::forward<V1>(v1), std::forward<V2>(v2)); \
826 template<class S1, class S2> \
827 auto scalar(S1&& s1, S2&& s2) const \
828 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
831 DUNE_SIMD_INFIX_OP(Mul, * );
832 DUNE_SIMD_INFIX_OP(Div, / );
833 DUNE_SIMD_INFIX_OP(Remainder, % );
835 DUNE_SIMD_INFIX_OP(Plus, + );
836 DUNE_SIMD_INFIX_OP(Minus, - );
838 DUNE_SIMD_INFIX_OP(LeftShift, << );
839 DUNE_SIMD_INFIX_OP(RightShift, >> );
841 DUNE_SIMD_INFIX_OP(Less, < );
842 DUNE_SIMD_INFIX_OP(Greater, > );
843 DUNE_SIMD_INFIX_OP(LessEqual, <= );
844 DUNE_SIMD_INFIX_OP(GreaterEqual, >= );
846 DUNE_SIMD_INFIX_OP(Equal, == );
847 DUNE_SIMD_INFIX_OP(NotEqual, != );
849 DUNE_SIMD_INFIX_OP(BitAnd, & );
850 DUNE_SIMD_INFIX_OP(BitXor, ^ );
851 DUNE_SIMD_INFIX_OP(BitOr, | );
855 DUNE_SIMD_REPL_OP(LogicAnd,
maskAnd, && );
856 DUNE_SIMD_REPL_OP(LogicOr,
maskOr, || );
858 DUNE_SIMD_ASSIGN_OP(Assign, = );
859 DUNE_SIMD_ASSIGN_OP(AssignMul, *= );
860 DUNE_SIMD_ASSIGN_OP(AssignDiv, /= );
861 DUNE_SIMD_ASSIGN_OP(AssignRemainder, %= );
862 DUNE_SIMD_ASSIGN_OP(AssignPlus, += );
863 DUNE_SIMD_ASSIGN_OP(AssignMinus, -= );
864 DUNE_SIMD_ASSIGN_OP(AssignLeftShift, <<=);
865 DUNE_SIMD_ASSIGN_OP(AssignRightShift, >>=);
866 DUNE_SIMD_ASSIGN_OP(AssignAnd, &= );
867 DUNE_SIMD_ASSIGN_OP(AssignXor, ^= );
868 DUNE_SIMD_ASSIGN_OP(AssignOr, |= );
870#undef DUNE_SIMD_INFIX_OP
871#undef DUNE_SIMD_REPL_OP
872#undef DUNE_SIMD_ASSIGN_OP
875 struct OpInfixComma {};
877 template<
class T1,
class T2>
878 void checkCommaOp(
const std::decay_t<T1> &val1,
879 const std::decay_t<T2> &val2)
881#define DUNE_SIMD_OPNAME (className<OpInfixComma(T1, T2)>())
882 static_assert(std::is_same<decltype((std::declval<T1>(),
883 std::declval<T2>())), T2>::value,
884 "Type and value category of the comma operator must "
885 "match that of the second operand");
894#pragma GCC diagnostic push
895#pragma GCC diagnostic ignored "-Wunused-value"
896 auto &&result = (
static_cast<T1
>(arg1),
897 static_cast<T2
>(arg2));
898#pragma GCC diagnostic pop
899 if(std::is_reference<T2>::value)
903 DUNE_SIMD_CHECK_OP(&result == &arg2);
905 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
906 DUNE_SIMD_CHECK_OP(
allTrue(val2 == arg2));
912 DUNE_SIMD_CHECK_OP(
allTrue(result == arg2));
914 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
918#undef DUNE_SIMD_OPNAME
943 template<
class V1,
class V2,
class Op>
944 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
947#define DUNE_SIMD_OPNAME (className<Op(V1, V2)>())
948 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
949 "Internal testsystem error: called with two types that "
950 "don't decay to the same thing");
953 auto vref1 = leftVector<std::decay_t<V1>>();
954 auto vref2 = rightVector<std::decay_t<V2>>();
961 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
962 using VR =
decltype(vopres);
965 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
966 "The result must have the same number of lanes as the "
972 for(
auto l : range(
lanes(vopres)))
978 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
979 lane(l,
static_cast<V2
>(vref2)))));
983 for(
auto l : range(
lanes(vop1)))
984 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
987 for(
auto l : range(
lanes(vop2)))
988 DUNE_SIMD_CHECK_OP(
lane(l, vop2) ==
lane(l, vref2));
990#undef DUNE_SIMD_OPNAME
993 template<
class V1,
class V2,
class Op>
994 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1003 template<
class V1,
class V2>
1006 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
1007 "Internal testsystem error: called with two types that "
1008 "don't decay to the same thing");
1010 checkCommaOp<V1, V2>(leftVector<std::decay_t<V1>>(),
1011 rightVector<std::decay_t<V2>>());
1047 template<
class V1,
class T2,
class Op>
1048 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1051#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1052 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1053 std::decay_t<T2> >::value,
1054 "Internal testsystem error: called with a scalar that "
1055 "does not match the vector type.");
1058 auto sinit2 = rightScalar<std::decay_t<T2>>();
1061 auto vref1 = leftVector<std::decay_t<V1>>();
1062 auto sref2 = sinit2;
1069 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<T2
>(sop2));
1070 using VR =
decltype(vopres);
1073 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1074 "The result must have the same number of lanes as the "
1078 DUNE_SIMD_CHECK_OP(sop2 == sinit2);
1081 using T =
Scalar<std::decay_t<
decltype(vopres)> >;
1082 for(
auto l : range(
lanes(vopres)))
1089 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1090 static_cast<T2
>(sref2) )));
1092 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1096 for(
auto l : range(
lanes(vop1)))
1097 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1099#undef DUNE_SIMD_OPNAME
1102 template<
class V1,
class T2,
class Op>
1103 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1112 template<
class V1,
class T2>
1115 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1116 std::decay_t<T2> >::value,
1117 "Internal testsystem error: called with a scalar that "
1118 "does not match the vector type.");
1120 checkCommaOp<V1, T2>(leftVector<std::decay_t<V1>>(),
1121 rightScalar<std::decay_t<T2>>());
1150 template<
class V1,
class T2,
class Op>
1151 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1154#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1155 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1156 std::decay_t<T2> >::value,
1157 "Internal testsystem error: called with a scalar that "
1158 "does not match the vector type.");
1161 auto sinit2 = rightScalar<std::decay_t<T2>>();
1164 auto vop1 = leftVector<std::decay_t<V1>>();
1165 using V2 = CopyRefQual<V1, T2>;
1166 std::decay_t<V2> vop2(sinit2);
1169 op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
1172 for(
auto l : range(
lanes(vop2)))
1173 DUNE_SIMD_CHECK_OP(
lane(l, vop2) == sinit2);
1175#undef DUNE_SIMD_OPNAME
1178 template<
class V1,
class T2,
class Op>
1179 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1188 template<
class V1,
class T2>
1226 template<
class V1,
class V2,
class Op>
1227 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
1230 using P2 =
decltype(
lane(0, std::declval<V2>()));
1231 using T2 = CopyRefQual<Scalar<V2>, V2>;
1232#define DUNE_SIMD_OPNAME (className<Op(V1, P2)>())
1233 static_assert(std::is_same<Scalar<V1>,
Scalar<V2> >::value,
1234 "Internal testsystem error: called with two vector "
1235 "types whose scalar types don't match.");
1238 auto sinit2 = rightScalar<Scalar<V2>>();
1241 auto vref1 = leftVector<std::decay_t<V1>>();
1242 auto sref2 = sinit2;
1247 lane(0, vop2) = sref2;
1251 op(
static_cast<V1
>(vop1),
lane(0,
static_cast<V2
>(vop2)));
1252 using VR =
decltype(vopres);
1255 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1256 "The result must have the same number of lanes as the "
1260 DUNE_SIMD_CHECK_OP(
lane(0, vop2) == sinit2);
1263 using T =
Scalar<
decltype(vopres)>;
1264 for(
auto l : range(
lanes(vopres)))
1271 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1272 static_cast<T2
>(sref2) )));
1274 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1278 for(
auto l : range(
lanes(vop1)))
1279 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1281#undef DUNE_SIMD_OPNAME
1284 template<
class V1,
class V2,
class Op>
1285 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1294 template<
class V1,
class V2>
1306 struct OpInfixSwappedArgs
1310 template<
class V1,
class V2>
1311 decltype(
auto)
operator()(V1&& v1, V2&& v2)
const
1313 return orig(std::forward<V2>(v2), std::forward<V1>(v1));
1315 template<
class S1,
class S2>
1316 auto scalar(S1&& s1, S2&& s2)
const
1317 ->
decltype(orig.scalar(std::forward<S2>(s2), std::forward<S1>(s1)));
1320 template<
class T1,
class V2,
class Op>
1323 checkBinaryOpVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1326 template<
class T1,
class V2>
1329 static_assert(std::is_same<std::decay_t<T1>,
1331 "Internal testsystem error: called with a scalar that "
1332 "does not match the vector type.");
1334 checkCommaOp<T1, V2>(leftScalar<std::decay_t<T1>>(),
1335 rightVector<std::decay_t<V2>>());
1338 template<
class V1,
class V2,
class Op>
1341 checkBinaryOpVP(v2, v1, OpInfixSwappedArgs<Op>{op});
1344 template<
class V1,
class V2>
1376 template<
class T1,
class V2,
class Op>
1379 checkBinaryOpVVAgainstVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1382 template<
class V1,
class T2>
1391 template<
class T1,
class T2,
bool condition,
class Checker>
1392 void checkBinaryRefQual(Checker checker)
1394 if constexpr (condition) {
1403 template<
class V,
class Checker>
1404 void checkBinaryOps(Checker checker)
1406 using Std::bool_constant;
1408 constexpr bool isMask = std::is_same<Scalar<V>,
bool>::value;
1410 constexpr bool do_ =
false;
1411 constexpr bool do_SV =
true;
1412 constexpr bool do_VV =
true;
1413 constexpr bool do_VS =
true;
1415#define DUNE_SIMD_DO(M1, M2, M3, V1, V2, V3, NAME) \
1416 checker(bool_constant<isMask ? do_##M1 : do_##V1>{}, \
1417 bool_constant<isMask ? do_##M2 : do_##V2>{}, \
1418 bool_constant<isMask ? do_##M3 : do_##V3>{}, \
1423 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMul );
1424 DUNE_SIMD_DO( , , , SV, VV, VS, InfixDiv );
1425 DUNE_SIMD_DO( , , , SV, VV, VS, InfixRemainder );
1427 DUNE_SIMD_DO( , , , SV, VV, VS, InfixPlus );
1428 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMinus );
1430 DUNE_SIMD_DO( , , , , VV, VS, InfixLeftShift );
1431 DUNE_SIMD_DO( , , , , VV, VS, InfixRightShift );
1433 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLess );
1434 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreater );
1435 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLessEqual );
1436 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreaterEqual );
1438 DUNE_SIMD_DO( , , , SV, VV, VS, InfixEqual );
1439 DUNE_SIMD_DO( , , , SV, VV, VS, InfixNotEqual );
1441 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitAnd );
1442 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitXor );
1443 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitOr );
1445 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicAnd );
1446 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicOr );
1448 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssign );
1449 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMul );
1450 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignDiv );
1451 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRemainder );
1452 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignPlus );
1453 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMinus );
1454 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignLeftShift );
1455 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRightShift);
1456 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignAnd );
1457 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignXor );
1458 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignOr );
1460 DUNE_SIMD_DO(SV, VV, VS, SV, , VS, InfixComma );
1471 void checkAutoCopy()
1473 using RValueResult =
decltype(autoCopy(
lane(0, std::declval<V>())));
1474 static_assert(std::is_same<RValueResult, Scalar<V> >::value,
1475 "Result of autoCopy() must always be Scalar<V>");
1477 using MutableLValueResult =
1478 decltype(autoCopy(
lane(0, std::declval<V&>())));
1479 static_assert(std::is_same<MutableLValueResult, Scalar<V> >::value,
1480 "Result of autoCopy() must always be Scalar<V>");
1482 using ConstLValueResult =
1483 decltype(autoCopy(
lane(0, std::declval<const V&>())));
1484 static_assert(std::is_same<ConstLValueResult, Scalar<V> >::value,
1485 "Result of autoCopy() must always be Scalar<V>");
1487 V vec = make123<V>();
1488 for(std::size_t l = 0; l <
lanes(vec); ++l)
1494 void checkBoolReductions()
1499 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(trueVec)) ==
true);
1500 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(trueVec)) ==
true);
1501 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(trueVec)) ==
false);
1502 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(trueVec)) ==
false);
1505 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(trueVec)) ==
true);
1506 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(trueVec)) ==
true);
1507 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(trueVec)) ==
false);
1508 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(trueVec)) ==
false);
1511 DUNE_SIMD_CHECK(
allTrue (M(
true)) ==
true);
1512 DUNE_SIMD_CHECK(
anyTrue (M(
true)) ==
true);
1513 DUNE_SIMD_CHECK(
allFalse(M(
true)) ==
false);
1514 DUNE_SIMD_CHECK(
anyFalse(M(
true)) ==
false);
1519 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(falseVec)) ==
false);
1520 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(falseVec)) ==
false);
1521 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(falseVec)) ==
true);
1522 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(falseVec)) ==
true);
1525 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(falseVec)) ==
false);
1526 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(falseVec)) ==
false);
1527 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(falseVec)) ==
true);
1528 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(falseVec)) ==
true);
1531 DUNE_SIMD_CHECK(
allTrue (M(
false)) ==
false);
1532 DUNE_SIMD_CHECK(
anyTrue (M(
false)) ==
false);
1533 DUNE_SIMD_CHECK(
allFalse(M(
false)) ==
true);
1534 DUNE_SIMD_CHECK(
anyFalse(M(
false)) ==
true);
1536 auto mixedVec = broadcast<M>(0);
1537 for(std::size_t l = 0; l <
lanes(mixedVec); ++l)
1538 lane(l, mixedVec) = (l % 2);
1542 (
allTrue (
static_cast<M&
>(mixedVec)) ==
false);
1544 (
anyTrue (
static_cast<M&
>(mixedVec)) == (lanes<M>() > 1));
1546 (
allFalse(
static_cast<M&
>(mixedVec)) == (lanes<M>() == 1));
1548 (
anyFalse(
static_cast<M&
>(mixedVec)) ==
true);
1552 (
allTrue (
static_cast<const M&
>(mixedVec)) ==
false);
1554 (
anyTrue (
static_cast<const M&
>(mixedVec)) == (lanes<M>() > 1));
1556 (
allFalse(
static_cast<const M&
>(mixedVec)) == (lanes<M>() == 1));
1558 (
anyFalse(
static_cast<const M&
>(mixedVec)) ==
true);
1561 DUNE_SIMD_CHECK(
allTrue (M(mixedVec)) ==
false);
1562 DUNE_SIMD_CHECK(
anyTrue (M(mixedVec)) == (lanes<M>() > 1));
1563 DUNE_SIMD_CHECK(
allFalse(M(mixedVec)) == (lanes<M>() == 1));
1564 DUNE_SIMD_CHECK(
anyFalse(M(mixedVec)) ==
true);
1573 (std::is_same<decltype(cond(std::declval<M>(), std::declval<V>(),
1574 std::declval<V>())), V>::value,
1575 "The result of cond(M, V, V) should have exactly the type V");
1578 (std::is_same<decltype(cond(std::declval<const M&>(),
1579 std::declval<const V&>(),
1580 std::declval<const V&>())), V>::value,
1581 "The result of cond(const M&, const V&, const V&) should have "
1582 "exactly the type V");
1585 (std::is_same<decltype(cond(std::declval<M&>(), std::declval<V&>(),
1586 std::declval<V&>())), V>::value,
1587 "The result of cond(M&, V&, V&) should have exactly the type V");
1589 V vec1 = leftVector<V>();
1590 V vec2 = rightVector<V>();
1592 DUNE_SIMD_CHECK(
allTrue(
cond(M(
true), vec1, vec2) == vec1));
1593 DUNE_SIMD_CHECK(
allTrue(
cond(M(
false), vec1, vec2) == vec2));
1595 auto mixedResult = broadcast<V>(0);
1596 auto mixedMask = broadcast<M>(
false);
1597 for(std::size_t l = 0; l <
lanes(mixedMask); ++l)
1599 lane(l, mixedMask ) = (l % 2);
1600 lane(l, mixedResult) =
lane(l, (l % 2) ? vec1 : vec2);
1603 DUNE_SIMD_CHECK(
allTrue(
cond(mixedMask, vec1, vec2) == mixedResult));
1607 void checkBoolCond()
1610 (std::is_same<decltype(cond(std::declval<bool>(), std::declval<V>(),
1611 std::declval<V>())), V>::value,
1612 "The result of cond(bool, V, V) should have exactly the type V");
1615 (std::is_same<decltype(cond(std::declval<const bool&>(),
1616 std::declval<const V&>(),
1617 std::declval<const V&>())), V>::value,
1618 "The result of cond(const bool&, const V&, const V&) should have "
1619 "exactly the type V");
1622 (std::is_same<decltype(cond(std::declval<bool&>(),
1624 std::declval<V&>())), V>::value,
1625 "The result of cond(bool&, V&, V&) should have exactly the type V");
1627 V vec1 = leftVector<V>();
1628 V vec2 = rightVector<V>();
1630 DUNE_SIMD_CHECK(
allTrue(
cond(
true, vec1, vec2) == vec1));
1631 DUNE_SIMD_CHECK(
allTrue(
cond(
false, vec1, vec2) == vec2));
1635 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1636 checkHorizontalMinMax() {}
1639 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1640 checkHorizontalMinMax()
1643 (std::is_same<decltype(max(std::declval<V>())),
Scalar<V> >::value,
1644 "The result of max(V) should be exactly Scalar<V>");
1647 (std::is_same<decltype(min(std::declval<V>())),
Scalar<V> >::value,
1648 "The result of min(V) should be exactly Scalar<V>");
1651 (std::is_same<decltype(max(std::declval<V&>())),
Scalar<V> >::value,
1652 "The result of max(V) should be exactly Scalar<V>");
1655 (std::is_same<decltype(min(std::declval<V&>())),
Scalar<V> >::value,
1656 "The result of min(V) should be exactly Scalar<V>");
1658 const V vec1 = leftVector<V>();
1665 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1666 checkBinaryMinMax() {}
1669 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1676 (std::is_same<decltype(Simd::max(std::declval<V>(),
1677 std::declval<V>())), V>::value,
1678 "The result of Simd::max(V, V) should be exactly V");
1680 (std::is_same<decltype(Simd::min(std::declval<V>(),
1681 std::declval<V>())), V>::value,
1682 "The result of Simd::min(V, V) should be exactly V");
1685 (std::is_same<decltype(Simd::max(std::declval<V&>(),
1686 std::declval<V&>())), V>::value,
1687 "The result of Simd::max(V&, V&) should be exactly V");
1689 (std::is_same<decltype(Simd::min(std::declval<V&>(),
1690 std::declval<V&>())), V>::value,
1691 "The result of Simd::min(V&, V&) should be exactly V");
1693 const V arg1 = leftVector<V>();
1694 const V arg2 = rightVector<V>();
1697 for(
auto l : range(lanes<V>()))
1710 const V vec1 = leftVector<V>();
1712 std::string reference;
1714 const char *sep =
"";
1715 for(
auto l : range(
lanes(vec1)))
1717 std::ostringstream stream;
1718 stream <<
lane(l, vec1);
1721 reference += stream.str();
1727 std::ostringstream stream;
1729 if(
lanes(vec1) == 1)
1730 DUNE_SIMD_CHECK(stream.str() == reference);
1732 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1736 std::ostringstream stream;
1737 stream <<
vio(vec1);
1738 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1742#undef DUNE_SIMD_CHECK
1807 template<
class V>
void checkType();
1808 template<
class V>
void checkNonOps();
1809 template<
class V>
void checkUnaryOps();
1810 template<
class V>
void checkBinaryOps();
1811 template<
class V>
void checkBinaryOpsVectorVector();
1812 template<
class V>
void checkBinaryOpsScalarVector();
1813 template<
class V>
void checkBinaryOpsVectorScalar();
1814 template<
class V>
void checkBinaryOpsProxyVector();
1815 template<
class V>
void checkBinaryOpsVectorProxy();
1836 template<
class V,
class Rebinds,
1837 template<
class>
class RebindPrune =
IsLoop,
1841 if(seen_.emplace(typeid (V)).second ==
false)
1849 auto recurse = [
this](
auto w) {
1850 using W =
typename decltype(w)::type;
1851 this->
template check<W, Rebinds, RebindPrune, RebindAccept>();
1853 checkRebindOf<V, Rebinds, RebindPrune, RebindAccept>(recurse);
1866 template<
class V>
void UnitTest::checkType()
1868 static_assert(std::is_same<V, std::decay_t<V> >::value,
"Simd types "
1869 "must not be references, and must not include "
1872 log_ <<
"Checking SIMD type " << className<V>() << std::endl;
1876 checkBinaryOps<V>();
1878 template<
class V>
void UnitTest::checkNonOps()
1880 constexpr auto isMask =
typename std::is_same<Scalar<V>,
bool>::type{};
1885 checkDefaultConstruct<V>();
1887 checkCopyMoveConstruct<V>();
1889 checkBroadcast<V>();
1890 if constexpr (isMask)
1891 this->
template checkBroadcastMaskConstruct<V>();
1893 this->
template checkBroadcastVectorConstruct<V>();
1894 checkBracedAssign<V>();
1895 checkBracedBroadcastAssign<V>();
1901 if constexpr (isMask)
1902 this->
template checkBoolReductions<V>();
1905 checkHorizontalMinMax<V>();
1906 checkBinaryMinMax<V>();
1909 template<
class V>
void UnitTest::checkUnaryOps()
1911 if constexpr (std::is_same_v<Scalar<V>,
bool>) {
1913 auto check = [
this](
auto op) {
1914 this->
template checkUnaryOpsV<V>(op);
1929 check(OpPrefixLogicNot{});
1934 auto check = [
this](
auto op) {
1935 this->
template checkUnaryOpsV<V>(op);
1947 check(OpPrefixMinus{});
1948 check(OpPrefixLogicNot{});
1949 check(OpPrefixBitNot{});
1952 template<
class V>
void UnitTest::checkBinaryOps()
1954 checkBinaryOpsVectorVector<V>();
1955 checkBinaryOpsScalarVector<V>();
1956 checkBinaryOpsVectorScalar<V>();
1957 checkBinaryOpsProxyVector<V>();
1958 checkBinaryOpsVectorProxy<V>();
1960 template<
class V>
void UnitTest::checkBinaryOpsVectorVector()
1962 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1963 auto check = [
this,op](
auto t1,
auto t2) {
1964 this->checkBinaryOpVV(t1, t2, op);
1966 this->checkBinaryRefQual<V, V, doVV>(check);
1968 checkBinaryOps<V>(checker);
1970 template<
class V>
void UnitTest::checkBinaryOpsScalarVector()
1972 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1973 auto check = [
this,op](
auto t1,
auto t2) {
1974 this->checkBinaryOpSV(t1, t2, op);
1976 this->checkBinaryRefQual<Scalar<V>, V, doSV>(check);
1978 auto crossCheck = [
this,op](
auto t1,
auto t2) {
1979 this->checkBinaryOpVVAgainstSV(t1, t2, op);
1981 this->checkBinaryRefQual<Scalar<V>, V, doSV && doVV>(crossCheck);
1983 checkBinaryOps<V>(checker);
1985 template<
class V>
void UnitTest::checkBinaryOpsVectorScalar()
1987 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1988 auto check = [
this,op](
auto t1,
auto t2) {
1989 this->checkBinaryOpVS(t1, t2, op);
1991 this->checkBinaryRefQual<V, Scalar<V>, doVS>(check);
1993 auto crossCheck = [
this,op](
auto t1,
auto t2) {
1994 this->checkBinaryOpVVAgainstVS(t1, t2, op);
1996 this->checkBinaryRefQual<V, Scalar<V>, doVV && doVS>(crossCheck);
1998 checkBinaryOps<V>(checker);
2000 template<
class V>
void UnitTest::checkBinaryOpsProxyVector()
2002 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2003 auto check = [
this,op](
auto t1,
auto t2) {
2004 this->checkBinaryOpPV(t1, t2, op);
2006 this->checkBinaryRefQual<V, V, doSV>(check);
2008 checkBinaryOps<V>(checker);
2010 template<
class V>
void UnitTest::checkBinaryOpsVectorProxy()
2012 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2013 auto check = [
this,op](
auto t1,
auto t2) {
2014 this->checkBinaryOpVP(t1, t2, op);
2016 this->checkBinaryRefQual<V, V, doVS>(check);
2018 checkBinaryOps<V>(checker);
A free function to provide the demangled class name of a given object or type as a string.
IO interface of the SIMD abstraction.
typename Impl::voider< Types... >::type void_t
Is void for all valid input types. The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:40
constexpr GeometryType line
GeometryType representing a line.
Definition: type.hh:498
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:256
bool anyTrue(const Mask &mask)
Whether any entry is true
Definition: interface.hh:429
auto maskOr(const V1 &v1, const V2 &v2)
Logic or of masks.
Definition: interface.hh:499
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: interface.hh:386
auto io(const V &v)
construct a stream inserter
Definition: io.hh:106
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: interface.hh:439
auto vio(const V &v)
construct a stream inserter
Definition: io.hh:90
typename Overloads::RebindType< std::decay_t< S >, std::decay_t< V > >::type Rebind
Construct SIMD type with different scalar type.
Definition: interface.hh:253
auto max(const V &v1, const V &v2)
The binary maximum value over two simd objects.
Definition: interface.hh:409
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
auto maskAnd(const V1 &v1, const V2 &v2)
Logic and of masks.
Definition: interface.hh:509
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:235
auto min(const V &v1, const V &v2)
The binary minimum value over two simd objects.
Definition: interface.hh:419
std::tuple< MetaType< T >... > TypeList
A simple type list.
Definition: typelist.hh:87
typename Impl::RemoveEnd< EndMark, TypeList< Types... > >::type RebindList
A list of types with the final element removed.
Definition: test.hh:158
typename Impl::IsLoop< T >::type IsLoop
check whether a type is an instance of LoopSIMD
Definition: test.hh:162
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
Utilities for reduction like operations on ranges.
Include file for users of the SIMD abstraction layer.
template which always yields a true value
Definition: typetraits.hh:134
Check if a type is callable with ()-operator and given arguments.
Definition: typetraits.hh:162
final element marker for RebindList
Definition: test.hh:145
Traits for type conversions and type information.