1#ifndef DUNE_COMMON_SIMD_TEST_HH
2#define DUNE_COMMON_SIMD_TEST_HH
18#include <unordered_set>
22#include <dune/common/hybridutilities.hh>
25#include <dune/common/simd/loop.hh>
27#include <dune/common/std/type_traits.hh>
28#include <dune/common/typelist.hh>
36 template<
class Expr,
class SFINAE =
void>
38 template<
class Op,
class... Args,
class SFINAE>
39 struct CanCall<Op(Args...), SFINAE> : std::false_type {};
40 template<
class Op,
class... Args>
41 struct CanCall<Op(Args...),
std::
void_t<std::result_of_t<Op(Args...)> > >
45 template<
class T,
class SFINAE =
void>
46 struct LessThenComparable : std::false_type {};
48 struct LessThenComparable<T,
std::
void_t<decltype(std::declval<T>()
49 < std::declval<T>())> > :
53 template<
class Dst,
class Src>
54 struct CopyConstHelper
58 template<
class Dst,
class Src>
59 struct CopyConstHelper<Dst, const Src>
61 using type = std::add_const_t<Dst>;
64 template<
class Dst,
class Src>
65 struct CopyVolatileHelper
69 template<
class Dst,
class Src>
70 struct CopyVolatileHelper<Dst, volatile Src>
72 using type = std::add_volatile_t<Dst>;
75 template<
class Dst,
class Src>
76 struct CopyReferenceHelper
80 template<
class Dst,
class Src>
81 struct CopyReferenceHelper<Dst, Src&>
83 using type = std::add_lvalue_reference_t<Dst>;
86 template<
class Dst,
class Src>
87 struct CopyReferenceHelper<Dst, Src&&>
89 using type = std::add_rvalue_reference_t<Dst>;
92 template<
class Dst,
class Src>
93 using CopyRefQual =
typename CopyReferenceHelper<
94 typename CopyVolatileHelper<
95 typename CopyConstHelper<
97 std::remove_reference_t<Src>
99 std::remove_reference_t<Src>
104 template<
class Mark,
class Types,
106 std::make_index_sequence<TypeListSize<Types>::value - 1> >
108 template<
class Mark,
class Types, std::size_t... I>
109 struct RemoveEnd<Mark, Types,
std::index_sequence<I...>>
111 using Back = TypeListEntry_t<TypeListSize<Types>::value - 1, Types>;
112 static_assert(std::is_same<Mark, Back>::value,
113 "TypeList not terminated by proper EndMark");
114 using type = TypeList<TypeListEntry_t<I, Types>...>;
117 template<
class T,
class List,
class =
void>
121 struct TypeInList<T,
TypeList<> > : std::false_type {};
123 template<
class T,
class... Rest>
124 struct TypeInList<T,
TypeList<T, Rest...> > : std::true_type {};
126 template<
class T,
class Head,
class... Rest>
127 struct TypeInList<T,
TypeList<Head, Rest...>,
128 std::enable_if_t<!std::is_same<T, Head>::value> > :
129 TypeInList<T, TypeList<Rest...> >::type
133 struct IsLoop : std::false_type {};
134 template<
class T, std::
size_t S>
135 struct IsLoop<LoopSIMD<T, S> > : std::true_type {};
144 constexpr bool debugTypes(std::true_type) {
return true; }
145 template<
class... Types>
147 constexpr bool debugTypes(std::false_type) {
return false; }
163 template<
class... Types>
169 using IsLoop =
typename Impl::IsLoop<T>::type;
173 std::ostream &log_ = std::cerr;
176 std::unordered_set<std::type_index> seen_;
183 void complain(
const char *file,
int line,
const char *func,
186 void complain(
const char *file,
int line,
const char *func,
187 const std::string &opname,
const char *expr);
193#define DUNE_SIMD_CHECK(expr) \
194 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, #expr))
198#define DUNE_SIMD_CHECK_OP(expr) \
199 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, \
200 DUNE_SIMD_OPNAME, #expr))
204 static std::decay_t<T> prvalue(T &&t)
206 return std::forward<T>(t);
211 static bool is42(
const V &v)
215 for(std::size_t l = 0; l <
lanes(v); ++l)
231 for(std::size_t l = 0; l <
lanes(vec); ++l)
232 lane(l, vec) = l + 1;
238 static bool is123(
const V &v)
242 for(std::size_t l = 0; l <
lanes(v); ++l)
250 static V leftVector()
255 for(std::size_t l = 0; l <
lanes(res); ++l)
261 static V rightVector()
266 for(std::size_t l = 0; l <
lanes(res); ++l)
274 static T leftScalar()
280 static T rightScalar()
288 using CanCall = Impl::CanCall<Call>;
290 template<
class Dst,
class Src>
291 using CopyRefQual = Impl::CopyRefQual<Dst, Src>;
298 template<
class Op,
class... Vectors>
300 decltype(std::declval<Op>().
315 static_assert(std::is_same<T, std::decay_t<T> >::value,
"Scalar types "
316 "must not be references, and must not include "
318 [[maybe_unused]] T a{};
322 [[deprecated(
"Warning: please include bool in the Rebinds for "
323 "simd type V, as Masks are not checked otherwise.")]]
324 void warnMissingMaskRebind(std::true_type) {}
326 void warnMissingMaskRebind(std::false_type) {}
328 template<
class V,
class Rebinds,
template<
class>
class RebindPrune,
329 template<
class>
class RebindAccept,
class Recurse>
330 void checkRebindOf(Recurse recurse)
333 using T =
typename decltype(target)::type;
337 log_ <<
"Type " << className<V>() <<
" rebound to "
338 << className<T>() <<
" is " << className<W>() << std::endl;
340 static_assert(std::is_same<W, std::decay_t<W> >::value,
"Rebound "
341 "types must not be references, and must not include "
343 static_assert(lanes<V>() == lanes<W>(),
"Rebound types must have "
344 "the same number of lanes as the original vector "
346 static_assert(std::is_same<T, Scalar<W> >::value,
"Rebound types "
347 "must have the bound-to scalar type");
349 if constexpr (RebindPrune<W>{}) {
350 log_ <<
"Pruning check of Simd type " << className<W>()
354 using Impl::debugTypes;
355 static_assert(debugTypes<T, V, W>(RebindAccept<W>{}),
356 "Rebind<T, V> is W, but that is not accepted "
362 static_assert(std::is_same<Rebind<Scalar<V>, V>, V>::value,
"A type "
363 "rebound to its own scalar type must be the same type "
364 "as the original type");
365 static_assert(std::is_same<Rebind<bool, V>,
Mask<V> >::value,
"A type "
366 "rebound to bool must be the mask type for that type");
368 constexpr bool hasBool = Impl::TypeInList<bool, Rebinds>::value;
369 warnMissingMaskRebind<V>(Std::bool_constant<!hasBool>{});
381 static_assert(std::is_same<std::size_t, decltype(lanes<V>())>::value,
382 "return type of lanes<V>() should be std::size_t");
383 static_assert(std::is_same<std::size_t,
decltype(
lanes(V{}))>::value,
384 "return type of lanes(V{}) should be std::size_t");
387 [[maybe_unused]]
constexpr auto size = lanes<V>();
389 DUNE_SIMD_CHECK(lanes<V>() ==
lanes(V{}));
393 void checkDefaultConstruct()
395 { [[maybe_unused]] V vec; }
396 { [[maybe_unused]] V vec{}; }
397 { [[maybe_unused]] V vec = {}; }
407 for(std::size_t l = 0; l <
lanes(vec); ++l)
408 lane(l, vec) = l + 1;
409 for(std::size_t l = 0; l <
lanes(vec); ++l)
411 using MLRes =
decltype(
lane(0, vec));
412 static_assert(std::is_same<MLRes, Scalar<V>&>::value ||
413 std::is_same<MLRes, std::decay_t<MLRes> >::value,
414 "Result of lane() on a mutable lvalue vector must "
415 "either be a mutable reference to a scalar of that "
416 "vector or a proxy object (which itself may not be a "
417 "reference nor const).");
421 for(std::size_t l = 0; l <
lanes(vec); ++l)
423 using CLRes =
decltype(
lane(0, vec2));
424 static_assert(std::is_same<CLRes, const Scalar<V>&>::value ||
425 std::is_same<CLRes, std::decay_t<CLRes> >::value,
426 "Result of lane() on a const lvalue vector must "
427 "either be a const lvalue reference to a scalar of that "
428 "vector or a proxy object (which itself may not be a "
429 "reference nor const).");
430 static_assert(!std::is_assignable<CLRes, Scalar<V> >::value,
431 "Result of lane() on a const lvalue vector must not be "
432 "assignable from a scalar.");
435 for(std::size_t l = 0; l <
lanes(vec); ++l)
437 using RRes =
decltype(
lane(0, prvalue(vec)));
446 static_assert(std::is_same<RRes, Scalar<V> >::value ||
447 std::is_same<RRes, Scalar<V>&&>::value,
448 "Result of lane() on a rvalue vector V must be "
449 "Scalar<V> or Scalar<V>&&.");
460 void checkCopyMoveConstruct()
463 { V vec (make123<V>()); DUNE_SIMD_CHECK(is123(vec)); }
464 { V vec = make123<V>() ; DUNE_SIMD_CHECK(is123(vec)); }
465 { V vec {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
466 { V vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
469 { V ref(make123<V>()); V vec (ref);
470 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
471 { V ref(make123<V>()); V vec = ref ;
472 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
473 { V ref(make123<V>()); V vec {ref};
474 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
475 { V ref(make123<V>()); V vec = {ref};
476 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
477 {
const V ref(make123<V>()); V vec (ref);
478 DUNE_SIMD_CHECK(is123(vec)); }
479 {
const V ref(make123<V>()); V vec = ref ;
480 DUNE_SIMD_CHECK(is123(vec)); }
481 {
const V ref(make123<V>()); V vec {ref};
482 DUNE_SIMD_CHECK(is123(vec)); }
483 {
const V ref(make123<V>()); V vec = {ref};
484 DUNE_SIMD_CHECK(is123(vec)); }
487 { V ref(make123<V>()); V vec (std::move(ref));
488 DUNE_SIMD_CHECK(is123(vec)); }
489 { V ref(make123<V>()); V vec = std::move(ref) ;
490 DUNE_SIMD_CHECK(is123(vec)); }
491 { V ref(make123<V>()); V vec {std::move(ref)};
492 DUNE_SIMD_CHECK(is123(vec)); }
493 { V ref(make123<V>()); V vec = {std::move(ref)};
494 DUNE_SIMD_CHECK(is123(vec)); }
498 void checkBroadcastVectorConstruct()
502 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
504 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
510 DUNE_SIMD_CHECK(is42(vec)); }
511 {
const Scalar<V> ref = 42; V vec = ref ;
512 DUNE_SIMD_CHECK(is42(vec)); }
519 {
Scalar<V> ref = 42; V vec (std::move(ref));
520 DUNE_SIMD_CHECK(is42(vec)); }
521 {
Scalar<V> ref = 42; V vec = std::move(ref) ;
522 DUNE_SIMD_CHECK(is42(vec)); }
530 void checkBroadcastMaskConstruct()
534 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
538 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
542 DUNE_SIMD_CHECK(is42(vec)); }
546 DUNE_SIMD_CHECK(is42(vec)); }
551 {
Scalar<V> ref = 42; V vec (std::move(ref));
552 DUNE_SIMD_CHECK(is42(vec)); }
555 {
Scalar<V> ref = 42; V vec {std::move(ref)};
556 DUNE_SIMD_CHECK(is42(vec)); }
562 template<
class FromV,
class ToV>
566 FromV fromVec = make123<FromV>();
567 auto toVec = implCast<ToV>(fromVec);
568 static_assert(std::is_same<
decltype(toVec), ToV>::value,
569 "Unexpected result type for implCast<ToV>(FromV&)");
570 DUNE_SIMD_CHECK(is123(fromVec));
571 DUNE_SIMD_CHECK(is123(toVec));
575 const FromV fromVec = make123<FromV>();
576 auto toVec = implCast<ToV>(fromVec);
577 static_assert(std::is_same<
decltype(toVec), ToV>::value,
578 "Unexpected result type for implCast<ToV>(const "
580 DUNE_SIMD_CHECK(is123(toVec));
584 auto toVec = implCast<ToV>(make123<FromV>());
585 static_assert(std::is_same<
decltype(toVec), ToV>::value,
586 "Unexpected result type for implCast<ToV>(FromV&&)");
587 DUNE_SIMD_CHECK(is123(toVec));
598 checkImplCast<V, V>();
599 checkImplCast<V, LoopV>();
600 checkImplCast<LoopV, V>();
605 void checkBroadcast()
610 auto vec = broadcast<V>(ref);
611 static_assert(std::is_same<
decltype(vec), V>::value,
612 "Unexpected result type for broadcast<V>()");
613 DUNE_SIMD_CHECK(is42(vec));
619 auto vec = broadcast<V>(ref);
620 static_assert(std::is_same<
decltype(vec), V>::value,
621 "Unexpected result type for broadcast<V>()");
622 DUNE_SIMD_CHECK(is42(vec));
627 static_assert(std::is_same<
decltype(vec), V>::value,
628 "Unexpected result type for broadcast<V>()");
629 DUNE_SIMD_CHECK(is42(vec));
633 auto vec = broadcast<V>(42);
634 static_assert(std::is_same<
decltype(vec), V>::value,
635 "Unexpected result type for broadcast<V>()");
636 DUNE_SIMD_CHECK(is42(vec));
640 auto vec = broadcast<V>(42.0);
641 static_assert(std::is_same<
decltype(vec), V>::value,
642 "Unexpected result type for broadcast<V>()");
643 DUNE_SIMD_CHECK(is42(vec));
648 void checkBracedAssign()
651 { V ref = make123<V>(); V vec; vec = {ref};
652 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
653 {
const V ref = make123<V>(); V vec; vec = {ref};
654 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
657 { V vec; vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
661 void checkBracedBroadcastAssign()
680#define DUNE_SIMD_POSTFIX_OP(NAME, SYMBOL) \
681 struct OpPostfix##NAME \
684 auto operator()(V&& v) const \
685 -> decltype(std::forward<V>(v) SYMBOL) \
687 return std::forward<V>(v) SYMBOL; \
691#define DUNE_SIMD_PREFIX_OP(NAME, SYMBOL) \
692 struct OpPrefix##NAME \
695 auto operator()(V&& v) const \
696 -> decltype(SYMBOL std::forward<V>(v)) \
698 return SYMBOL std::forward<V>(v); \
702 DUNE_SIMD_POSTFIX_OP(Decrement, -- );
703 DUNE_SIMD_POSTFIX_OP(Increment, ++ );
705 DUNE_SIMD_PREFIX_OP (Decrement, -- );
706 DUNE_SIMD_PREFIX_OP (Increment, ++ );
708 DUNE_SIMD_PREFIX_OP (Plus, + );
709 DUNE_SIMD_PREFIX_OP (Minus, - );
710 DUNE_SIMD_PREFIX_OP (LogicNot, ! );
716#pragma GCC diagnostic push
717#pragma GCC diagnostic ignored "-Wpragmas"
718#pragma GCC diagnostic ignored "-Wunknown-warning-option"
719#pragma GCC diagnostic ignored "-Wbool-operation"
720 DUNE_SIMD_PREFIX_OP (BitNot, ~ );
721#pragma GCC diagnostic pop
723#undef DUNE_SIMD_POSTFIX_OP
724#undef DUNE_SIMD_PREFIX_OP
726 template<
class V,
class Op>
728 CanCall<Op(decltype(lane(0, std::declval<V>())))>::value>
731#define DUNE_SIMD_OPNAME (className<Op(V)>())
733 auto val = leftVector<std::decay_t<V>>();
737 auto &&result = op(
static_cast<V
>(arg));
738 using T =
Scalar<std::decay_t<
decltype(result)> >;
739 for(std::size_t l = 0; l <
lanes(val); ++l)
756 ==
static_cast<T
>(op(
lane(l,
static_cast<V
>(val)))));
760 for(std::size_t l = 0; l < lanes<std::decay_t<V> >(); ++l)
761 DUNE_SIMD_CHECK_OP(
lane(l, val) ==
lane(l, arg));
762#undef DUNE_SIMD_OPNAME
765 template<
class V,
class Op>
767 !CanCall<Op(decltype(lane(0, std::declval<V>())))>::value>
775 template<
class V,
class Op>
776 void checkUnaryOpsV(Op op)
778 checkUnaryOpV<V&>(op);
779 checkUnaryOpV<const V&>(op);
780 checkUnaryOpV<V&&>(op);
794#define DUNE_SIMD_INFIX_OP(NAME, SYMBOL) \
795 struct OpInfix##NAME \
797 template<class V1, class V2> \
798 decltype(auto) operator()(V1&& v1, V2&& v2) const \
800 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
802 template<class S1, class S2> \
803 auto scalar(S1&& s1, S2&& s2) const \
804 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
815#define DUNE_SIMD_ASSIGN_OP(NAME, SYMBOL) \
816 struct OpInfix##NAME \
818 template<class V1, class V2> \
819 decltype(auto) operator()(V1&& v1, V2&& v2) const \
821 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
823 template<class S1, class S2> \
824 auto scalar(S1& s1, S2&& s2) const \
825 -> decltype(s1 SYMBOL std::forward<S2>(s2)); \
828#define DUNE_SIMD_REPL_OP(NAME, REPLFN, SYMBOL) \
829 struct OpInfix##NAME \
831 template<class V1, class V2> \
832 decltype(auto) operator()(V1&& v1, V2&& v2) const \
834 return Simd::REPLFN(std::forward<V1>(v1), std::forward<V2>(v2)); \
836 template<class S1, class S2> \
837 auto scalar(S1&& s1, S2&& s2) const \
838 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
841 DUNE_SIMD_INFIX_OP(Mul, * );
842 DUNE_SIMD_INFIX_OP(Div, / );
843 DUNE_SIMD_INFIX_OP(Remainder, % );
845 DUNE_SIMD_INFIX_OP(Plus, + );
846 DUNE_SIMD_INFIX_OP(Minus, - );
848 DUNE_SIMD_INFIX_OP(LeftShift, << );
849 DUNE_SIMD_INFIX_OP(RightShift, >> );
851 DUNE_SIMD_INFIX_OP(Less, < );
852 DUNE_SIMD_INFIX_OP(Greater, > );
853 DUNE_SIMD_INFIX_OP(LessEqual, <= );
854 DUNE_SIMD_INFIX_OP(GreaterEqual, >= );
856 DUNE_SIMD_INFIX_OP(Equal, == );
857 DUNE_SIMD_INFIX_OP(NotEqual, != );
859 DUNE_SIMD_INFIX_OP(BitAnd, & );
860 DUNE_SIMD_INFIX_OP(BitXor, ^ );
861 DUNE_SIMD_INFIX_OP(BitOr, | );
865 DUNE_SIMD_REPL_OP(LogicAnd,
maskAnd, && );
866 DUNE_SIMD_REPL_OP(LogicOr,
maskOr, || );
868 DUNE_SIMD_ASSIGN_OP(Assign, = );
869 DUNE_SIMD_ASSIGN_OP(AssignMul, *= );
870 DUNE_SIMD_ASSIGN_OP(AssignDiv, /= );
871 DUNE_SIMD_ASSIGN_OP(AssignRemainder, %= );
872 DUNE_SIMD_ASSIGN_OP(AssignPlus, += );
873 DUNE_SIMD_ASSIGN_OP(AssignMinus, -= );
874 DUNE_SIMD_ASSIGN_OP(AssignLeftShift, <<=);
875 DUNE_SIMD_ASSIGN_OP(AssignRightShift, >>=);
876 DUNE_SIMD_ASSIGN_OP(AssignAnd, &= );
877 DUNE_SIMD_ASSIGN_OP(AssignXor, ^= );
878 DUNE_SIMD_ASSIGN_OP(AssignOr, |= );
880#undef DUNE_SIMD_INFIX_OP
881#undef DUNE_SIMD_REPL_OP
882#undef DUNE_SIMD_ASSIGN_OP
885 struct OpInfixComma {};
887 template<
class T1,
class T2>
888 void checkCommaOp(
const std::decay_t<T1> &val1,
889 const std::decay_t<T2> &val2)
891#define DUNE_SIMD_OPNAME (className<OpInfixComma(T1, T2)>())
892 static_assert(std::is_same<decltype((std::declval<T1>(),
893 std::declval<T2>())), T2>::value,
894 "Type and value category of the comma operator must "
895 "match that of the second operand");
904#pragma GCC diagnostic push
905#pragma GCC diagnostic ignored "-Wunused-value"
906 auto &&result = (
static_cast<T1
>(arg1),
907 static_cast<T2
>(arg2));
908#pragma GCC diagnostic pop
909 if(std::is_reference<T2>::value)
913 DUNE_SIMD_CHECK_OP(&result == &arg2);
915 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
916 DUNE_SIMD_CHECK_OP(
allTrue(val2 == arg2));
922 DUNE_SIMD_CHECK_OP(
allTrue(result == arg2));
924 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
928#undef DUNE_SIMD_OPNAME
953 template<
class V1,
class V2,
class Op>
954 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
957#define DUNE_SIMD_OPNAME (className<Op(V1, V2)>())
958 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
959 "Internal testsystem error: called with two types that "
960 "don't decay to the same thing");
963 auto vref1 = leftVector<std::decay_t<V1>>();
964 auto vref2 = rightVector<std::decay_t<V2>>();
971 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
972 using VR =
decltype(vopres);
975 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
976 "The result must have the same number of lanes as the "
982 for(
auto l : range(
lanes(vopres)))
988 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
989 lane(l,
static_cast<V2
>(vref2)))));
993 for(
auto l : range(
lanes(vop1)))
994 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
997 for(
auto l : range(
lanes(vop2)))
998 DUNE_SIMD_CHECK_OP(
lane(l, vop2) ==
lane(l, vref2));
1000#undef DUNE_SIMD_OPNAME
1003 template<
class V1,
class V2,
class Op>
1004 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1013 template<
class V1,
class V2>
1016 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
1017 "Internal testsystem error: called with two types that "
1018 "don't decay to the same thing");
1020 checkCommaOp<V1, V2>(leftVector<std::decay_t<V1>>(),
1021 rightVector<std::decay_t<V2>>());
1057 template<
class V1,
class T2,
class Op>
1058 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1061#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1062 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1063 std::decay_t<T2> >::value,
1064 "Internal testsystem error: called with a scalar that "
1065 "does not match the vector type.");
1068 auto sinit2 = rightScalar<std::decay_t<T2>>();
1071 auto vref1 = leftVector<std::decay_t<V1>>();
1072 auto sref2 = sinit2;
1079 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<T2
>(sop2));
1080 using VR =
decltype(vopres);
1083 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1084 "The result must have the same number of lanes as the "
1088 DUNE_SIMD_CHECK_OP(sop2 == sinit2);
1091 using T =
Scalar<std::decay_t<
decltype(vopres)> >;
1092 for(
auto l : range(
lanes(vopres)))
1099 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1100 static_cast<T2
>(sref2) )));
1102 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1106 for(
auto l : range(
lanes(vop1)))
1107 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1109#undef DUNE_SIMD_OPNAME
1112 template<
class V1,
class T2,
class Op>
1113 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1122 template<
class V1,
class T2>
1125 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1126 std::decay_t<T2> >::value,
1127 "Internal testsystem error: called with a scalar that "
1128 "does not match the vector type.");
1130 checkCommaOp<V1, T2>(leftVector<std::decay_t<V1>>(),
1131 rightScalar<std::decay_t<T2>>());
1160 template<
class V1,
class T2,
class Op>
1161 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1164#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1165 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1166 std::decay_t<T2> >::value,
1167 "Internal testsystem error: called with a scalar that "
1168 "does not match the vector type.");
1171 auto sinit2 = rightScalar<std::decay_t<T2>>();
1174 auto vop1 = leftVector<std::decay_t<V1>>();
1175 using V2 = CopyRefQual<V1, T2>;
1176 std::decay_t<V2> vop2(sinit2);
1179 op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
1182 for(
auto l : range(
lanes(vop2)))
1183 DUNE_SIMD_CHECK_OP(
lane(l, vop2) == sinit2);
1185#undef DUNE_SIMD_OPNAME
1188 template<
class V1,
class T2,
class Op>
1189 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1198 template<
class V1,
class T2>
1236 template<
class V1,
class V2,
class Op>
1237 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
1240 using P2 =
decltype(
lane(0, std::declval<V2>()));
1241 using T2 = CopyRefQual<Scalar<V2>, V2>;
1242#define DUNE_SIMD_OPNAME (className<Op(V1, P2)>())
1243 static_assert(std::is_same<Scalar<V1>,
Scalar<V2> >::value,
1244 "Internal testsystem error: called with two vector "
1245 "types whose scalar types don't match.");
1248 auto sinit2 = rightScalar<Scalar<V2>>();
1251 auto vref1 = leftVector<std::decay_t<V1>>();
1252 auto sref2 = sinit2;
1257 lane(0, vop2) = sref2;
1261 op(
static_cast<V1
>(vop1),
lane(0,
static_cast<V2
>(vop2)));
1262 using VR =
decltype(vopres);
1265 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1266 "The result must have the same number of lanes as the "
1270 DUNE_SIMD_CHECK_OP(
lane(0, vop2) == sinit2);
1273 using T =
Scalar<
decltype(vopres)>;
1274 for(
auto l : range(
lanes(vopres)))
1281 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1282 static_cast<T2
>(sref2) )));
1284 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1288 for(
auto l : range(
lanes(vop1)))
1289 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1291#undef DUNE_SIMD_OPNAME
1294 template<
class V1,
class V2,
class Op>
1295 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1304 template<
class V1,
class V2>
1316 struct OpInfixSwappedArgs
1320 template<
class V1,
class V2>
1321 decltype(
auto)
operator()(V1&& v1, V2&& v2)
const
1323 return orig(std::forward<V2>(v2), std::forward<V1>(v1));
1325 template<
class S1,
class S2>
1326 auto scalar(S1&& s1, S2&& s2)
const
1327 ->
decltype(orig.scalar(std::forward<S2>(s2), std::forward<S1>(s1)));
1330 template<
class T1,
class V2,
class Op>
1333 checkBinaryOpVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1336 template<
class T1,
class V2>
1339 static_assert(std::is_same<std::decay_t<T1>,
1341 "Internal testsystem error: called with a scalar that "
1342 "does not match the vector type.");
1344 checkCommaOp<T1, V2>(leftScalar<std::decay_t<T1>>(),
1345 rightVector<std::decay_t<V2>>());
1348 template<
class V1,
class V2,
class Op>
1351 checkBinaryOpVP(v2, v1, OpInfixSwappedArgs<Op>{op});
1354 template<
class V1,
class V2>
1386 template<
class T1,
class V2,
class Op>
1389 checkBinaryOpVVAgainstVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1392 template<
class V1,
class T2>
1401 template<
class T1,
class T2,
bool condition,
class Checker>
1402 void checkBinaryRefQual(Checker checker)
1404 if constexpr (condition) {
1413 template<
class V,
class Checker>
1414 void checkBinaryOps(Checker checker)
1416 using Std::bool_constant;
1418 constexpr bool isMask = std::is_same<Scalar<V>,
bool>::value;
1420 constexpr bool do_ =
false;
1421 constexpr bool do_SV =
true;
1422 constexpr bool do_VV =
true;
1423 constexpr bool do_VS =
true;
1425#define DUNE_SIMD_DO(M1, M2, M3, V1, V2, V3, NAME) \
1426 checker(bool_constant<isMask ? do_##M1 : do_##V1>{}, \
1427 bool_constant<isMask ? do_##M2 : do_##V2>{}, \
1428 bool_constant<isMask ? do_##M3 : do_##V3>{}, \
1433 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMul );
1434 DUNE_SIMD_DO( , , , SV, VV, VS, InfixDiv );
1435 DUNE_SIMD_DO( , , , SV, VV, VS, InfixRemainder );
1437 DUNE_SIMD_DO( , , , SV, VV, VS, InfixPlus );
1438 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMinus );
1440 DUNE_SIMD_DO( , , , , VV, VS, InfixLeftShift );
1441 DUNE_SIMD_DO( , , , , VV, VS, InfixRightShift );
1443 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLess );
1444 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreater );
1445 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLessEqual );
1446 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreaterEqual );
1448 DUNE_SIMD_DO( , , , SV, VV, VS, InfixEqual );
1449 DUNE_SIMD_DO( , , , SV, VV, VS, InfixNotEqual );
1451 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitAnd );
1452 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitXor );
1453 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitOr );
1455 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicAnd );
1456 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicOr );
1458 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssign );
1459 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMul );
1460 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignDiv );
1461 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRemainder );
1462 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignPlus );
1463 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMinus );
1464 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignLeftShift );
1465 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRightShift);
1466 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignAnd );
1467 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignXor );
1468 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignOr );
1470 DUNE_SIMD_DO(SV, VV, VS, SV, , VS, InfixComma );
1481 void checkAutoCopy()
1483 using RValueResult =
decltype(
autoCopy(
lane(0, std::declval<V>())));
1484 static_assert(std::is_same<RValueResult, Scalar<V> >::value,
1485 "Result of autoCopy() must always be Scalar<V>");
1487 using MutableLValueResult =
1489 static_assert(std::is_same<MutableLValueResult, Scalar<V> >::value,
1490 "Result of autoCopy() must always be Scalar<V>");
1492 using ConstLValueResult =
1494 static_assert(std::is_same<ConstLValueResult, Scalar<V> >::value,
1495 "Result of autoCopy() must always be Scalar<V>");
1497 V vec = make123<V>();
1498 for(std::size_t l = 0; l <
lanes(vec); ++l)
1504 void checkBoolReductions()
1509 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(trueVec)) ==
true);
1510 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(trueVec)) ==
true);
1511 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(trueVec)) ==
false);
1512 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(trueVec)) ==
false);
1515 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(trueVec)) ==
true);
1516 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(trueVec)) ==
true);
1517 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(trueVec)) ==
false);
1518 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(trueVec)) ==
false);
1521 DUNE_SIMD_CHECK(
allTrue (M(
true)) ==
true);
1522 DUNE_SIMD_CHECK(
anyTrue (M(
true)) ==
true);
1523 DUNE_SIMD_CHECK(
allFalse(M(
true)) ==
false);
1524 DUNE_SIMD_CHECK(
anyFalse(M(
true)) ==
false);
1529 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(falseVec)) ==
false);
1530 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(falseVec)) ==
false);
1531 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(falseVec)) ==
true);
1532 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(falseVec)) ==
true);
1535 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(falseVec)) ==
false);
1536 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(falseVec)) ==
false);
1537 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(falseVec)) ==
true);
1538 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(falseVec)) ==
true);
1541 DUNE_SIMD_CHECK(
allTrue (M(
false)) ==
false);
1542 DUNE_SIMD_CHECK(
anyTrue (M(
false)) ==
false);
1543 DUNE_SIMD_CHECK(
allFalse(M(
false)) ==
true);
1544 DUNE_SIMD_CHECK(
anyFalse(M(
false)) ==
true);
1546 auto mixedVec = broadcast<M>(0);
1547 for(std::size_t l = 0; l <
lanes(mixedVec); ++l)
1548 lane(l, mixedVec) = (l % 2);
1552 (
allTrue (
static_cast<M&
>(mixedVec)) ==
false);
1554 (
anyTrue (
static_cast<M&
>(mixedVec)) == (lanes<M>() > 1));
1556 (
allFalse(
static_cast<M&
>(mixedVec)) == (lanes<M>() == 1));
1558 (
anyFalse(
static_cast<M&
>(mixedVec)) ==
true);
1562 (
allTrue (
static_cast<const M&
>(mixedVec)) ==
false);
1564 (
anyTrue (
static_cast<const M&
>(mixedVec)) == (lanes<M>() > 1));
1566 (
allFalse(
static_cast<const M&
>(mixedVec)) == (lanes<M>() == 1));
1568 (
anyFalse(
static_cast<const M&
>(mixedVec)) ==
true);
1571 DUNE_SIMD_CHECK(
allTrue (M(mixedVec)) ==
false);
1572 DUNE_SIMD_CHECK(
anyTrue (M(mixedVec)) == (lanes<M>() > 1));
1573 DUNE_SIMD_CHECK(
allFalse(M(mixedVec)) == (lanes<M>() == 1));
1574 DUNE_SIMD_CHECK(
anyFalse(M(mixedVec)) ==
true);
1583 (std::is_same<decltype(cond(std::declval<M>(), std::declval<V>(),
1584 std::declval<V>())), V>::value,
1585 "The result of cond(M, V, V) should have exactly the type V");
1588 (std::is_same<decltype(cond(std::declval<const M&>(),
1589 std::declval<const V&>(),
1590 std::declval<const V&>())), V>::value,
1591 "The result of cond(const M&, const V&, const V&) should have "
1592 "exactly the type V");
1595 (std::is_same<decltype(cond(std::declval<M&>(), std::declval<V&>(),
1596 std::declval<V&>())), V>::value,
1597 "The result of cond(M&, V&, V&) should have exactly the type V");
1599 V vec1 = leftVector<V>();
1600 V vec2 = rightVector<V>();
1602 DUNE_SIMD_CHECK(
allTrue(
cond(M(
true), vec1, vec2) == vec1));
1603 DUNE_SIMD_CHECK(
allTrue(
cond(M(
false), vec1, vec2) == vec2));
1605 auto mixedResult = broadcast<V>(0);
1606 auto mixedMask = broadcast<M>(
false);
1607 for(std::size_t l = 0; l <
lanes(mixedMask); ++l)
1609 lane(l, mixedMask ) = (l % 2);
1610 lane(l, mixedResult) =
lane(l, (l % 2) ? vec1 : vec2);
1613 DUNE_SIMD_CHECK(
allTrue(
cond(mixedMask, vec1, vec2) == mixedResult));
1617 void checkBoolCond()
1620 (std::is_same<decltype(cond(std::declval<bool>(), std::declval<V>(),
1621 std::declval<V>())), V>::value,
1622 "The result of cond(bool, V, V) should have exactly the type V");
1625 (std::is_same<decltype(cond(std::declval<const bool&>(),
1626 std::declval<const V&>(),
1627 std::declval<const V&>())), V>::value,
1628 "The result of cond(const bool&, const V&, const V&) should have "
1629 "exactly the type V");
1632 (std::is_same<decltype(cond(std::declval<bool&>(),
1634 std::declval<V&>())), V>::value,
1635 "The result of cond(bool&, V&, V&) should have exactly the type V");
1637 V vec1 = leftVector<V>();
1638 V vec2 = rightVector<V>();
1640 DUNE_SIMD_CHECK(
allTrue(
cond(
true, vec1, vec2) == vec1));
1641 DUNE_SIMD_CHECK(
allTrue(
cond(
false, vec1, vec2) == vec2));
1645 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1646 checkHorizontalMinMax() {}
1649 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1650 checkHorizontalMinMax()
1653 (std::is_same<decltype(max(std::declval<V>())),
Scalar<V> >::value,
1654 "The result of max(V) should be exactly Scalar<V>");
1657 (std::is_same<decltype(min(std::declval<V>())),
Scalar<V> >::value,
1658 "The result of min(V) should be exactly Scalar<V>");
1661 (std::is_same<decltype(max(std::declval<V&>())),
Scalar<V> >::value,
1662 "The result of max(V) should be exactly Scalar<V>");
1665 (std::is_same<decltype(min(std::declval<V&>())),
Scalar<V> >::value,
1666 "The result of min(V) should be exactly Scalar<V>");
1668 const V vec1 = leftVector<V>();
1675 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1676 checkBinaryMinMax() {}
1679 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1686 (std::is_same<decltype(Simd::max(std::declval<V>(),
1687 std::declval<V>())), V>::value,
1688 "The result of Simd::max(V, V) should be exactly V");
1690 (std::is_same<decltype(Simd::min(std::declval<V>(),
1691 std::declval<V>())), V>::value,
1692 "The result of Simd::min(V, V) should be exactly V");
1695 (std::is_same<decltype(Simd::max(std::declval<V&>(),
1696 std::declval<V&>())), V>::value,
1697 "The result of Simd::max(V&, V&) should be exactly V");
1699 (std::is_same<decltype(Simd::min(std::declval<V&>(),
1700 std::declval<V&>())), V>::value,
1701 "The result of Simd::min(V&, V&) should be exactly V");
1703 const V arg1 = leftVector<V>();
1704 const V arg2 = rightVector<V>();
1707 for(
auto l : range(lanes<V>()))
1720 const V vec1 = leftVector<V>();
1722 std::string reference;
1724 const char *sep =
"";
1725 for(
auto l : range(
lanes(vec1)))
1727 std::ostringstream stream;
1728 stream <<
lane(l, vec1);
1731 reference += stream.str();
1737 std::ostringstream stream;
1739 if(
lanes(vec1) == 1)
1740 DUNE_SIMD_CHECK(stream.str() == reference);
1742 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1746 std::ostringstream stream;
1747 stream <<
vio(vec1);
1748 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1752#undef DUNE_SIMD_CHECK
1817 template<
class V>
void checkType();
1818 template<
class V>
void checkNonOps();
1819 template<
class V>
void checkUnaryOps();
1820 template<
class V>
void checkBinaryOps();
1821 template<
class V>
void checkBinaryOpsVectorVector();
1822 template<
class V>
void checkBinaryOpsScalarVector();
1823 template<
class V>
void checkBinaryOpsVectorScalar();
1824 template<
class V>
void checkBinaryOpsProxyVector();
1825 template<
class V>
void checkBinaryOpsVectorProxy();
1846 template<
class V,
class Rebinds,
1847 template<
class>
class RebindPrune =
IsLoop,
1851 if(seen_.emplace(typeid (V)).second ==
false)
1859 auto recurse = [
this](
auto w) {
1860 using W =
typename decltype(w)::type;
1861 this->
template check<W, Rebinds, RebindPrune, RebindAccept>();
1863 checkRebindOf<V, Rebinds, RebindPrune, RebindAccept>(recurse);
1876 template<
class V>
void UnitTest::checkType()
1878 static_assert(std::is_same<V, std::decay_t<V> >::value,
"Simd types "
1879 "must not be references, and must not include "
1882 log_ <<
"Checking SIMD type " << className<V>() << std::endl;
1886 checkBinaryOps<V>();
1888 template<
class V>
void UnitTest::checkNonOps()
1890 constexpr auto isMask =
typename std::is_same<Scalar<V>,
bool>::type{};
1895 checkDefaultConstruct<V>();
1897 checkCopyMoveConstruct<V>();
1899 checkBroadcast<V>();
1900 if constexpr (isMask)
1901 this->
template checkBroadcastMaskConstruct<V>();
1903 this->
template checkBroadcastVectorConstruct<V>();
1904 checkBracedAssign<V>();
1905 checkBracedBroadcastAssign<V>();
1911 if constexpr (isMask)
1912 this->
template checkBoolReductions<V>();
1915 checkHorizontalMinMax<V>();
1916 checkBinaryMinMax<V>();
1919 template<
class V>
void UnitTest::checkUnaryOps()
1921 if constexpr (std::is_same_v<Scalar<V>,
bool>) {
1923 auto check = [
this](
auto op) {
1924 this->
template checkUnaryOpsV<V>(op);
1939 check(OpPrefixLogicNot{});
1944 auto check = [
this](
auto op) {
1945 this->
template checkUnaryOpsV<V>(op);
1957 check(OpPrefixMinus{});
1958 check(OpPrefixLogicNot{});
1959 check(OpPrefixBitNot{});
1962 template<
class V>
void UnitTest::checkBinaryOps()
1964 checkBinaryOpsVectorVector<V>();
1965 checkBinaryOpsScalarVector<V>();
1966 checkBinaryOpsVectorScalar<V>();
1967 checkBinaryOpsProxyVector<V>();
1968 checkBinaryOpsVectorProxy<V>();
1970 template<
class V>
void UnitTest::checkBinaryOpsVectorVector()
1972 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1973 auto check = [
this,op](
auto t1,
auto t2) {
1974 this->checkBinaryOpVV(t1, t2, op);
1976 this->checkBinaryRefQual<V, V, doVV>(check);
1978 checkBinaryOps<V>(checker);
1980 template<
class V>
void UnitTest::checkBinaryOpsScalarVector()
1982 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1983 auto check = [
this,op](
auto t1,
auto t2) {
1984 this->checkBinaryOpSV(t1, t2, op);
1986 this->checkBinaryRefQual<Scalar<V>, V, doSV>(check);
1988 auto crossCheck = [
this,op](
auto t1,
auto t2) {
1989 this->checkBinaryOpVVAgainstSV(t1, t2, op);
1991 this->checkBinaryRefQual<Scalar<V>, V, doSV && doVV>(crossCheck);
1993 checkBinaryOps<V>(checker);
1995 template<
class V>
void UnitTest::checkBinaryOpsVectorScalar()
1997 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1998 auto check = [
this,op](
auto t1,
auto t2) {
1999 this->checkBinaryOpVS(t1, t2, op);
2001 this->checkBinaryRefQual<V, Scalar<V>, doVS>(check);
2003 auto crossCheck = [
this,op](
auto t1,
auto t2) {
2004 this->checkBinaryOpVVAgainstVS(t1, t2, op);
2006 this->checkBinaryRefQual<V, Scalar<V>, doVV && doVS>(crossCheck);
2008 checkBinaryOps<V>(checker);
2010 template<
class V>
void UnitTest::checkBinaryOpsProxyVector()
2012 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2013 auto check = [
this,op](
auto t1,
auto t2) {
2014 this->checkBinaryOpPV(t1, t2, op);
2016 this->checkBinaryRefQual<V, V, doSV>(check);
2018 checkBinaryOps<V>(checker);
2020 template<
class V>
void UnitTest::checkBinaryOpsVectorProxy()
2022 auto checker = [
this](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2023 auto check = [
this,op](
auto t1,
auto t2) {
2024 this->checkBinaryOpVP(t1, t2, op);
2026 this->checkBinaryRefQual<V, V, doVS>(check);
2028 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.
Traits for type conversions and type information.
constexpr AutonomousValue< T > autoCopy(T &&v)
Autonomous copy of an expression's value for use in auto type deduction.
Definition: typetraits.hh:642
typename Impl::voider< Types... >::type void_t
Is void for all valid input types. The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:38
constexpr GeometryType line
GeometryType representing a line.
Definition: type.hh:510
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:266
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
auto maskOr(const V1 &v1, const V2 &v2)
Logic or of masks.
Definition: interface.hh:497
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: interface.hh:384
auto io(const V &v)
construct a stream inserter
Definition: io.hh:104
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: interface.hh:437
auto vio(const V &v)
construct a stream inserter
Definition: io.hh:88
typename Overloads::RebindType< std::decay_t< S >, std::decay_t< V > >::type Rebind
Construct SIMD type with different scalar type.
Definition: interface.hh:251
auto max(const V &v1, const V &v2)
The binary maximum value over two simd objects.
Definition: interface.hh:407
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
auto maskAnd(const V1 &v1, const V2 &v2)
Logic and of masks.
Definition: interface.hh:507
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:233
auto min(const V &v1, const V &v2)
The binary minimum value over two simd objects.
Definition: interface.hh:417
std::tuple< MetaType< T >... > TypeList
A simple type list.
Definition: typelist.hh:85
Namespace with predefined compile time indices for the range [0,19].
Definition: indices.hh:49
typename Impl::RemoveEnd< EndMark, TypeList< Types... > >::type RebindList
A list of types with the final element removed.
Definition: test.hh:165
typename Impl::IsLoop< T >::type IsLoop
check whether a type is an instance of LoopSIMD
Definition: test.hh:169
Dune namespace.
Definition: alignedallocator.hh:11
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
final element marker for RebindList
Definition: test.hh:152