1#ifndef DUNE_COMMON_SIMD_TEST_HH
2#define DUNE_COMMON_SIMD_TEST_HH
18#include <unordered_set>
23#include <dune/common/hybridutilities.hh>
26#include <dune/common/simd/loop.hh>
28#include <dune/common/std/type_traits.hh>
29#include <dune/common/typelist.hh>
38 template<
class Expr,
class SFINAE =
void>
40 template<
class Op,
class... Args,
class SFINAE>
41 struct CanCall<Op(Args...), SFINAE> : std::false_type {};
42 template<
class Op,
class... Args>
43 struct CanCall<Op(Args...),
void_t<
std::result_of_t<Op(Args...)> > >
47 template<
class T,
class SFINAE =
void>
48 struct LessThenComparable : std::false_type {};
50 struct LessThenComparable<T,
void_t<decltype(
std::declval<T>()
51 < std::declval<T>())> > :
55 template<
class Dst,
class Src>
56 struct CopyConstHelper
60 template<
class Dst,
class Src>
61 struct CopyConstHelper<Dst, const Src>
63 using type = std::add_const_t<Dst>;
66 template<
class Dst,
class Src>
67 struct CopyVolatileHelper
71 template<
class Dst,
class Src>
72 struct CopyVolatileHelper<Dst, volatile Src>
74 using type = std::add_volatile_t<Dst>;
77 template<
class Dst,
class Src>
78 struct CopyReferenceHelper
82 template<
class Dst,
class Src>
83 struct CopyReferenceHelper<Dst, Src&>
85 using type = std::add_lvalue_reference_t<Dst>;
88 template<
class Dst,
class Src>
89 struct CopyReferenceHelper<Dst, Src&&>
91 using type = std::add_rvalue_reference_t<Dst>;
94 template<
class Dst,
class Src>
95 using CopyRefQual =
typename CopyReferenceHelper<
96 typename CopyVolatileHelper<
97 typename CopyConstHelper<
99 std::remove_reference_t<Src>
101 std::remove_reference_t<Src>
106 template<
class Mark,
class Types,
108 std::make_index_sequence<TypeListSize<Types>::value - 1> >
110 template<
class Mark,
class Types, std::size_t... I>
111 struct RemoveEnd<Mark, Types,
std::index_sequence<I...>>
113 using Back = TypeListEntry_t<TypeListSize<Types>::value - 1, Types>;
114 static_assert(std::is_same<Mark, Back>::value,
115 "TypeList not terminated by proper EndMark");
116 using type = TypeList<TypeListEntry_t<I, Types>...>;
119 template<
class T,
class List,
class =
void>
123 struct TypeInList<T,
TypeList<> > : std::false_type {};
125 template<
class T,
class... Rest>
126 struct TypeInList<T,
TypeList<T, Rest...> > : std::true_type {};
128 template<
class T,
class Head,
class... Rest>
129 struct TypeInList<T,
TypeList<Head, Rest...>,
130 std::enable_if_t<!std::is_same<T, Head>::value> > :
131 TypeInList<T, TypeList<Rest...> >::type
135 struct IsLoop : std::false_type {};
136 template<
class T, std::
size_t S>
137 struct IsLoop<LoopSIMD<T, S> > : std::true_type {};
146 constexpr bool debugTypes(std::true_type) {
return true; }
147 template<
class... Types>
149 constexpr bool debugTypes(std::false_type) {
return false; }
165 template<
class... Types>
171 using IsLoop =
typename Impl::IsLoop<T>::type;
175 std::ostream &log_ = std::cerr;
178 std::unordered_set<std::type_index> seen_;
185 void complain(
const char *file,
int line,
const char *func,
188 void complain(
const char *file,
int line,
const char *func,
189 const std::string &opname,
const char *expr);
195#define DUNE_SIMD_CHECK(expr) \
196 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, #expr))
200#define DUNE_SIMD_CHECK_OP(expr) \
201 ((expr) ? void() : complain(__FILE__, __LINE__, __func__, \
202 DUNE_SIMD_OPNAME, #expr))
206 static std::decay_t<T> prvalue(T &&t)
208 return std::forward<T>(t);
213 static bool is42(
const V &v)
217 for(std::size_t l = 0; l <
lanes(v); ++l)
233 for(std::size_t l = 0; l <
lanes(vec); ++l)
234 lane(l, vec) = l + 1;
240 static bool is123(
const V &v)
244 for(std::size_t l = 0; l <
lanes(v); ++l)
252 static V leftVector()
257 for(std::size_t l = 0; l <
lanes(res); ++l)
263 static V rightVector()
268 for(std::size_t l = 0; l <
lanes(res); ++l)
276 static T leftScalar()
282 static T rightScalar()
290 using CanCall = Impl::CanCall<Call>;
292 template<
class Dst,
class Src>
293 using CopyRefQual = Impl::CopyRefQual<Dst, Src>;
300 template<
class Op,
class... Vectors>
302 decltype(std::declval<Op>().
317 static_assert(std::is_same<T, std::decay_t<T> >::value,
"Scalar types "
318 "must not be references, and must not include "
325 "simd type V, as Masks are not checked otherwise.")
326 void warnMissingMaskRebind(std::true_type) {}
328 void warnMissingMaskRebind(std::false_type) {}
330 template<
class V,
class Rebinds,
template<
class>
class RebindPrune,
331 template<
class>
class RebindAccept,
class Recurse>
332 void checkRebindOf(Recurse recurse)
335 using T =
typename decltype(target)::type;
339 log_ <<
"Type " << className<V>() <<
" rebound to "
340 << className<T>() <<
" is " << className<W>() << std::endl;
342 static_assert(std::is_same<W, std::decay_t<W> >::value,
"Rebound "
343 "types must not be references, and must not include "
345 static_assert(lanes<V>() == lanes<W>(),
"Rebound types must have "
346 "the same number of lanes as the original vector "
348 static_assert(std::is_same<T, Scalar<W> >::value,
"Rebound types "
349 "must have the bound-to scalar type");
353 log_ <<
"Pruning check of Simd type " << className<W>()
357 using Impl::debugTypes;
358 static_assert(debugTypes<T, V, W>(
id(RebindAccept<W>{})),
359 "Rebind<T, V> is W, but that is not accepted "
365 static_assert(std::is_same<Rebind<Scalar<V>, V>, V>::value,
"A type "
366 "rebound to its own scalar type must be the same type "
367 "as the original type");
368 static_assert(std::is_same<Rebind<bool, V>,
Mask<V> >::value,
"A type "
369 "rebound to bool must be the mask type for that type");
371 constexpr bool hasBool = Impl::TypeInList<bool, Rebinds>::value;
384 static_assert(std::is_same<std::size_t, decltype(lanes<V>())>::value,
385 "return type of lanes<V>() should be std::size_t");
386 static_assert(std::is_same<std::size_t,
decltype(
lanes(V{}))>::value,
387 "return type of lanes(V{}) should be std::size_t");
392 DUNE_SIMD_CHECK(lanes<V>() ==
lanes(V{}));
396 void checkDefaultConstruct()
410 for(std::size_t l = 0; l <
lanes(vec); ++l)
411 lane(l, vec) = l + 1;
412 for(std::size_t l = 0; l <
lanes(vec); ++l)
414 using MLRes =
decltype(
lane(0, vec));
415 static_assert(std::is_same<MLRes, Scalar<V>&>::value ||
416 std::is_same<MLRes, std::decay_t<MLRes> >::value,
417 "Result of lane() on a mutable lvalue vector must "
418 "either be a mutable reference to a scalar of that "
419 "vector or a proxy object (which itself may not be a "
420 "reference nor const).");
424 for(std::size_t l = 0; l <
lanes(vec); ++l)
426 using CLRes =
decltype(
lane(0, vec2));
427 static_assert(std::is_same<CLRes, const Scalar<V>&>::value ||
428 std::is_same<CLRes, std::decay_t<CLRes> >::value,
429 "Result of lane() on a const lvalue vector must "
430 "either be a const lvalue reference to a scalar of that "
431 "vector or a proxy object (which itself may not be a "
432 "reference nor const).");
433 static_assert(!std::is_assignable<CLRes, Scalar<V> >::value,
434 "Result of lane() on a const lvalue vector must not be "
435 "assignable from a scalar.");
438 for(std::size_t l = 0; l <
lanes(vec); ++l)
440 using RRes =
decltype(
lane(0, prvalue(vec)));
449 static_assert(std::is_same<RRes, Scalar<V> >::value ||
450 std::is_same<RRes, Scalar<V>&&>::value,
451 "Result of lane() on a rvalue vector V must be "
452 "Scalar<V> or Scalar<V>&&.");
463 void checkCopyMoveConstruct()
466 { V vec (make123<V>()); DUNE_SIMD_CHECK(is123(vec)); }
467 { V vec = make123<V>() ; DUNE_SIMD_CHECK(is123(vec)); }
468 { V vec {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
469 { V vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
472 { V ref(make123<V>()); V vec (ref);
473 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
474 { V ref(make123<V>()); V vec = ref ;
475 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
476 { V ref(make123<V>()); V vec {ref};
477 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
478 { V ref(make123<V>()); V vec = {ref};
479 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
480 {
const V ref(make123<V>()); V vec (ref);
481 DUNE_SIMD_CHECK(is123(vec)); }
482 {
const V ref(make123<V>()); V vec = ref ;
483 DUNE_SIMD_CHECK(is123(vec)); }
484 {
const V ref(make123<V>()); V vec {ref};
485 DUNE_SIMD_CHECK(is123(vec)); }
486 {
const V ref(make123<V>()); V vec = {ref};
487 DUNE_SIMD_CHECK(is123(vec)); }
490 { V ref(make123<V>()); V vec (std::move(ref));
491 DUNE_SIMD_CHECK(is123(vec)); }
492 { V ref(make123<V>()); V vec = std::move(ref) ;
493 DUNE_SIMD_CHECK(is123(vec)); }
494 { V ref(make123<V>()); V vec {std::move(ref)};
495 DUNE_SIMD_CHECK(is123(vec)); }
496 { V ref(make123<V>()); V vec = {std::move(ref)};
497 DUNE_SIMD_CHECK(is123(vec)); }
501 void checkBroadcastVectorConstruct()
505 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
507 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
513 DUNE_SIMD_CHECK(is42(vec)); }
514 {
const Scalar<V> ref = 42; V vec = ref ;
515 DUNE_SIMD_CHECK(is42(vec)); }
522 {
Scalar<V> ref = 42; V vec (std::move(ref));
523 DUNE_SIMD_CHECK(is42(vec)); }
524 {
Scalar<V> ref = 42; V vec = std::move(ref) ;
525 DUNE_SIMD_CHECK(is42(vec)); }
533 void checkBroadcastMaskConstruct()
537 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
541 DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref ==
Scalar<V>(42)); }
545 DUNE_SIMD_CHECK(is42(vec)); }
549 DUNE_SIMD_CHECK(is42(vec)); }
554 {
Scalar<V> ref = 42; V vec (std::move(ref));
555 DUNE_SIMD_CHECK(is42(vec)); }
558 {
Scalar<V> ref = 42; V vec {std::move(ref)};
559 DUNE_SIMD_CHECK(is42(vec)); }
565 template<
class FromV,
class ToV>
569 FromV fromVec = make123<FromV>();
570 auto toVec = implCast<ToV>(fromVec);
571 static_assert(std::is_same<
decltype(toVec), ToV>::value,
572 "Unexpected result type for implCast<ToV>(FromV&)");
573 DUNE_SIMD_CHECK(is123(fromVec));
574 DUNE_SIMD_CHECK(is123(toVec));
578 const FromV fromVec = make123<FromV>();
579 auto toVec = implCast<ToV>(fromVec);
580 static_assert(std::is_same<
decltype(toVec), ToV>::value,
581 "Unexpected result type for implCast<ToV>(const "
583 DUNE_SIMD_CHECK(is123(toVec));
587 auto toVec = implCast<ToV>(make123<FromV>());
588 static_assert(std::is_same<
decltype(toVec), ToV>::value,
589 "Unexpected result type for implCast<ToV>(FromV&&)");
590 DUNE_SIMD_CHECK(is123(toVec));
601 checkImplCast<V, V>();
602 checkImplCast<V, LoopV>();
603 checkImplCast<LoopV, V>();
608 void checkBroadcast()
613 auto vec = broadcast<V>(ref);
614 static_assert(std::is_same<
decltype(vec), V>::value,
615 "Unexpected result type for broadcast<V>()");
616 DUNE_SIMD_CHECK(is42(vec));
622 auto vec = broadcast<V>(ref);
623 static_assert(std::is_same<
decltype(vec), V>::value,
624 "Unexpected result type for broadcast<V>()");
625 DUNE_SIMD_CHECK(is42(vec));
630 static_assert(std::is_same<
decltype(vec), V>::value,
631 "Unexpected result type for broadcast<V>()");
632 DUNE_SIMD_CHECK(is42(vec));
636 auto vec = broadcast<V>(42);
637 static_assert(std::is_same<
decltype(vec), V>::value,
638 "Unexpected result type for broadcast<V>()");
639 DUNE_SIMD_CHECK(is42(vec));
643 auto vec = broadcast<V>(42.0);
644 static_assert(std::is_same<
decltype(vec), V>::value,
645 "Unexpected result type for broadcast<V>()");
646 DUNE_SIMD_CHECK(is42(vec));
651 void checkBracedAssign()
654 { V ref = make123<V>(); V vec; vec = {ref};
655 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
656 {
const V ref = make123<V>(); V vec; vec = {ref};
657 DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); }
660 { V vec; vec = {make123<V>()}; DUNE_SIMD_CHECK(is123(vec)); }
664 void checkBracedBroadcastAssign()
683#define DUNE_SIMD_POSTFIX_OP(NAME, SYMBOL) \
684 struct OpPostfix##NAME \
687 auto operator()(V&& v) const \
688 -> decltype(std::forward<V>(v) SYMBOL) \
690 return std::forward<V>(v) SYMBOL; \
694#define DUNE_SIMD_PREFIX_OP(NAME, SYMBOL) \
695 struct OpPrefix##NAME \
698 auto operator()(V&& v) const \
699 -> decltype(SYMBOL std::forward<V>(v)) \
701 return SYMBOL std::forward<V>(v); \
705 DUNE_SIMD_POSTFIX_OP(Decrement, -- );
706 DUNE_SIMD_POSTFIX_OP(Increment, ++ );
708 DUNE_SIMD_PREFIX_OP (Decrement, -- );
709 DUNE_SIMD_PREFIX_OP (Increment, ++ );
711 DUNE_SIMD_PREFIX_OP (Plus, + );
712 DUNE_SIMD_PREFIX_OP (Minus, - );
713 DUNE_SIMD_PREFIX_OP (LogicNot, ! );
719#pragma GCC diagnostic push
720#pragma GCC diagnostic ignored "-Wpragmas"
721#pragma GCC diagnostic ignored "-Wunknown-warning-option"
722#pragma GCC diagnostic ignored "-Wbool-operation"
723 DUNE_SIMD_PREFIX_OP (BitNot, ~ );
724#pragma GCC diagnostic pop
726#undef DUNE_SIMD_POSTFIX_OP
727#undef DUNE_SIMD_PREFIX_OP
729 template<
class V,
class Op>
731 CanCall<Op(decltype(lane(0, std::declval<V>())))>::value>
734#define DUNE_SIMD_OPNAME (className<Op(V)>())
736 auto val = leftVector<std::decay_t<V>>();
740 auto &&result = op(
static_cast<V
>(arg));
741 using T =
Scalar<std::decay_t<
decltype(result)> >;
742 for(std::size_t l = 0; l <
lanes(val); ++l)
759 ==
static_cast<T
>(op(
lane(l,
static_cast<V
>(val)))));
763 for(std::size_t l = 0; l < lanes<std::decay_t<V> >(); ++l)
764 DUNE_SIMD_CHECK_OP(
lane(l, val) ==
lane(l, arg));
765#undef DUNE_SIMD_OPNAME
768 template<
class V,
class Op>
770 !CanCall<Op(decltype(lane(0, std::declval<V>())))>::value>
778 template<
class V,
class Op>
779 void checkUnaryOpsV(Op op)
781 checkUnaryOpV<V&>(op);
782 checkUnaryOpV<const V&>(op);
783 checkUnaryOpV<V&&>(op);
797#define DUNE_SIMD_INFIX_OP(NAME, SYMBOL) \
798 struct OpInfix##NAME \
800 template<class V1, class V2> \
801 decltype(auto) operator()(V1&& v1, V2&& v2) const \
803 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
805 template<class S1, class S2> \
806 auto scalar(S1&& s1, S2&& s2) const \
807 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
818#define DUNE_SIMD_ASSIGN_OP(NAME, SYMBOL) \
819 struct OpInfix##NAME \
821 template<class V1, class V2> \
822 decltype(auto) operator()(V1&& v1, V2&& v2) const \
824 return std::forward<V1>(v1) SYMBOL std::forward<V2>(v2); \
826 template<class S1, class S2> \
827 auto scalar(S1& s1, S2&& s2) const \
828 -> decltype(s1 SYMBOL std::forward<S2>(s2)); \
831#define DUNE_SIMD_REPL_OP(NAME, REPLFN, SYMBOL) \
832 struct OpInfix##NAME \
834 template<class V1, class V2> \
835 decltype(auto) operator()(V1&& v1, V2&& v2) const \
837 return Simd::REPLFN(std::forward<V1>(v1), std::forward<V2>(v2)); \
839 template<class S1, class S2> \
840 auto scalar(S1&& s1, S2&& s2) const \
841 -> decltype(std::forward<S1>(s1) SYMBOL std::forward<S2>(s2)); \
844 DUNE_SIMD_INFIX_OP(Mul, * );
845 DUNE_SIMD_INFIX_OP(Div, / );
846 DUNE_SIMD_INFIX_OP(Remainder, % );
848 DUNE_SIMD_INFIX_OP(Plus, + );
849 DUNE_SIMD_INFIX_OP(Minus, - );
851 DUNE_SIMD_INFIX_OP(LeftShift, << );
852 DUNE_SIMD_INFIX_OP(RightShift, >> );
854 DUNE_SIMD_INFIX_OP(Less, < );
855 DUNE_SIMD_INFIX_OP(Greater, > );
856 DUNE_SIMD_INFIX_OP(LessEqual, <= );
857 DUNE_SIMD_INFIX_OP(GreaterEqual, >= );
859 DUNE_SIMD_INFIX_OP(Equal, == );
860 DUNE_SIMD_INFIX_OP(NotEqual, != );
862 DUNE_SIMD_INFIX_OP(BitAnd, & );
863 DUNE_SIMD_INFIX_OP(BitXor, ^ );
864 DUNE_SIMD_INFIX_OP(BitOr, | );
868 DUNE_SIMD_REPL_OP(LogicAnd,
maskAnd, && );
869 DUNE_SIMD_REPL_OP(LogicOr,
maskOr, || );
871 DUNE_SIMD_ASSIGN_OP(Assign, = );
872 DUNE_SIMD_ASSIGN_OP(AssignMul, *= );
873 DUNE_SIMD_ASSIGN_OP(AssignDiv, /= );
874 DUNE_SIMD_ASSIGN_OP(AssignRemainder, %= );
875 DUNE_SIMD_ASSIGN_OP(AssignPlus, += );
876 DUNE_SIMD_ASSIGN_OP(AssignMinus, -= );
877 DUNE_SIMD_ASSIGN_OP(AssignLeftShift, <<=);
878 DUNE_SIMD_ASSIGN_OP(AssignRightShift, >>=);
879 DUNE_SIMD_ASSIGN_OP(AssignAnd, &= );
880 DUNE_SIMD_ASSIGN_OP(AssignXor, ^= );
881 DUNE_SIMD_ASSIGN_OP(AssignOr, |= );
883#undef DUNE_SIMD_INFIX_OP
884#undef DUNE_SIMD_REPL_OP
885#undef DUNE_SIMD_ASSIGN_OP
888 struct OpInfixComma {};
890 template<
class T1,
class T2>
891 void checkCommaOp(
const std::decay_t<T1> &val1,
892 const std::decay_t<T2> &val2)
894#define DUNE_SIMD_OPNAME (className<OpInfixComma(T1, T2)>())
895 static_assert(std::is_same<decltype((std::declval<T1>(),
896 std::declval<T2>())), T2>::value,
897 "Type and value category of the comma operator must "
898 "match that of the second operand");
907#pragma GCC diagnostic push
908#pragma GCC diagnostic ignored "-Wunused-value"
909 auto &&result = (
static_cast<T1
>(arg1),
910 static_cast<T2
>(arg2));
911#pragma GCC diagnostic pop
912 if(std::is_reference<T2>::value)
916 DUNE_SIMD_CHECK_OP(&result == &arg2);
918 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
919 DUNE_SIMD_CHECK_OP(
allTrue(val2 == arg2));
925 DUNE_SIMD_CHECK_OP(
allTrue(result == arg2));
927 DUNE_SIMD_CHECK_OP(
allTrue(val1 == arg1));
931#undef DUNE_SIMD_OPNAME
956 template<
class V1,
class V2,
class Op>
957 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
960#define DUNE_SIMD_OPNAME (className<Op(V1, V2)>())
961 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
962 "Internal testsystem error: called with two types that "
963 "don't decay to the same thing");
966 auto vref1 = leftVector<std::decay_t<V1>>();
967 auto vref2 = rightVector<std::decay_t<V2>>();
974 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
975 using VR =
decltype(vopres);
978 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
979 "The result must have the same number of lanes as the "
985 for(
auto l : range(
lanes(vopres)))
991 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
992 lane(l,
static_cast<V2
>(vref2)))));
996 for(
auto l : range(
lanes(vop1)))
997 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1000 for(
auto l : range(
lanes(vop2)))
1001 DUNE_SIMD_CHECK_OP(
lane(l, vop2) ==
lane(l, vref2));
1003#undef DUNE_SIMD_OPNAME
1006 template<
class V1,
class V2,
class Op>
1007 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1016 template<
class V1,
class V2>
1019 static_assert(std::is_same<std::decay_t<V1>, std::decay_t<V2> >::value,
1020 "Internal testsystem error: called with two types that "
1021 "don't decay to the same thing");
1023 checkCommaOp<V1, V2>(leftVector<std::decay_t<V1>>(),
1024 rightVector<std::decay_t<V2>>());
1060 template<
class V1,
class T2,
class Op>
1061 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1064#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1065 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1066 std::decay_t<T2> >::value,
1067 "Internal testsystem error: called with a scalar that "
1068 "does not match the vector type.");
1071 auto sinit2 = rightScalar<std::decay_t<T2>>();
1074 auto vref1 = leftVector<std::decay_t<V1>>();
1075 auto sref2 = sinit2;
1082 auto &&vopres = op(
static_cast<V1
>(vop1),
static_cast<T2
>(sop2));
1083 using VR =
decltype(vopres);
1086 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1087 "The result must have the same number of lanes as the "
1091 DUNE_SIMD_CHECK_OP(sop2 == sinit2);
1094 using T =
Scalar<std::decay_t<
decltype(vopres)> >;
1095 for(
auto l : range(
lanes(vopres)))
1102 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1103 static_cast<T2
>(sref2) )));
1105 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1109 for(
auto l : range(
lanes(vop1)))
1110 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1112#undef DUNE_SIMD_OPNAME
1115 template<
class V1,
class T2,
class Op>
1116 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1125 template<
class V1,
class T2>
1128 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1129 std::decay_t<T2> >::value,
1130 "Internal testsystem error: called with a scalar that "
1131 "does not match the vector type.");
1133 checkCommaOp<V1, T2>(leftVector<std::decay_t<V1>>(),
1134 rightScalar<std::decay_t<T2>>());
1163 template<
class V1,
class T2,
class Op>
1164 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, T2> >
1167#define DUNE_SIMD_OPNAME (className<Op(V1, T2)>())
1168 static_assert(std::is_same<Scalar<std::decay_t<V1> >,
1169 std::decay_t<T2> >::value,
1170 "Internal testsystem error: called with a scalar that "
1171 "does not match the vector type.");
1174 auto sinit2 = rightScalar<std::decay_t<T2>>();
1177 auto vop1 = leftVector<std::decay_t<V1>>();
1178 using V2 = CopyRefQual<V1, T2>;
1179 std::decay_t<V2> vop2(sinit2);
1182 op(
static_cast<V1
>(vop1),
static_cast<V2
>(vop2));
1185 for(
auto l : range(
lanes(vop2)))
1186 DUNE_SIMD_CHECK_OP(
lane(l, vop2) == sinit2);
1188#undef DUNE_SIMD_OPNAME
1191 template<
class V1,
class T2,
class Op>
1192 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, T2> >
1201 template<
class V1,
class T2>
1239 template<
class V1,
class V2,
class Op>
1240 std::enable_if_t<Std::is_detected_v<ScalarResult, Op, V1, V2> >
1243 using P2 =
decltype(
lane(0, std::declval<V2>()));
1244 using T2 = CopyRefQual<Scalar<V2>, V2>;
1245#define DUNE_SIMD_OPNAME (className<Op(V1, P2)>())
1246 static_assert(std::is_same<Scalar<V1>,
Scalar<V2> >::value,
1247 "Internal testsystem error: called with two vector "
1248 "types whose scalar types don't match.");
1251 auto sinit2 = rightScalar<Scalar<V2>>();
1254 auto vref1 = leftVector<std::decay_t<V1>>();
1255 auto sref2 = sinit2;
1260 lane(0, vop2) = sref2;
1264 op(
static_cast<V1
>(vop1),
lane(0,
static_cast<V2
>(vop2)));
1265 using VR =
decltype(vopres);
1268 static_assert(lanes<std::decay_t<VR> >() ==
lanes<std::decay_t<V1> >(),
1269 "The result must have the same number of lanes as the "
1273 DUNE_SIMD_CHECK_OP(
lane(0, vop2) == sinit2);
1276 using T =
Scalar<
decltype(vopres)>;
1277 for(
auto l : range(
lanes(vopres)))
1284 ==
static_cast<T
>(op(
lane(l,
static_cast<V1
>(vref1)),
1285 static_cast<T2
>(sref2) )));
1287 DUNE_SIMD_CHECK_OP(sref2 == sinit2);
1291 for(
auto l : range(
lanes(vop1)))
1292 DUNE_SIMD_CHECK_OP(
lane(l, vop1) ==
lane(l, vref1));
1294#undef DUNE_SIMD_OPNAME
1297 template<
class V1,
class V2,
class Op>
1298 std::enable_if_t<!Std::is_detected_v<ScalarResult, Op, V1, V2> >
1307 template<
class V1,
class V2>
1319 struct OpInfixSwappedArgs
1323 template<
class V1,
class V2>
1324 decltype(
auto)
operator()(V1&& v1, V2&& v2)
const
1326 return orig(std::forward<V2>(v2), std::forward<V1>(v1));
1328 template<
class S1,
class S2>
1329 auto scalar(S1&& s1, S2&& s2)
const
1330 ->
decltype(orig.scalar(std::forward<S2>(s2), std::forward<S1>(s1)));
1333 template<
class T1,
class V2,
class Op>
1336 checkBinaryOpVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1339 template<
class T1,
class V2>
1342 static_assert(std::is_same<std::decay_t<T1>,
1344 "Internal testsystem error: called with a scalar that "
1345 "does not match the vector type.");
1347 checkCommaOp<T1, V2>(leftScalar<std::decay_t<T1>>(),
1348 rightVector<std::decay_t<V2>>());
1351 template<
class V1,
class V2,
class Op>
1354 checkBinaryOpVP(v2, v1, OpInfixSwappedArgs<Op>{op});
1357 template<
class V1,
class V2>
1389 template<
class T1,
class V2,
class Op>
1392 checkBinaryOpVVAgainstVS(v2, t1, OpInfixSwappedArgs<Op>{op});
1395 template<
class V1,
class T2>
1404 template<
class T1,
class T2,
bool condition,
class Checker>
1405 void checkBinaryRefQual(Checker checker)
1412 [=] (
auto t2) { id(checker)(t1, t2); });
1417 template<
class V,
class Checker>
1418 void checkBinaryOps(Checker checker)
1422 constexpr bool isMask = std::is_same<Scalar<V>,
bool>::value;
1424 constexpr bool do_ =
false;
1425 constexpr bool do_SV =
true;
1426 constexpr bool do_VV =
true;
1427 constexpr bool do_VS =
true;
1429#define DUNE_SIMD_DO(M1, M2, M3, V1, V2, V3, NAME) \
1430 checker(bool_constant<isMask ? do_##M1 : do_##V1>{}, \
1431 bool_constant<isMask ? do_##M2 : do_##V2>{}, \
1432 bool_constant<isMask ? do_##M3 : do_##V3>{}, \
1437 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMul );
1438 DUNE_SIMD_DO( , , , SV, VV, VS, InfixDiv );
1439 DUNE_SIMD_DO( , , , SV, VV, VS, InfixRemainder );
1441 DUNE_SIMD_DO( , , , SV, VV, VS, InfixPlus );
1442 DUNE_SIMD_DO( , , , SV, VV, VS, InfixMinus );
1444 DUNE_SIMD_DO( , , , , VV, VS, InfixLeftShift );
1445 DUNE_SIMD_DO( , , , , VV, VS, InfixRightShift );
1447 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLess );
1448 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreater );
1449 DUNE_SIMD_DO( , , , SV, VV, VS, InfixLessEqual );
1450 DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreaterEqual );
1452 DUNE_SIMD_DO( , , , SV, VV, VS, InfixEqual );
1453 DUNE_SIMD_DO( , , , SV, VV, VS, InfixNotEqual );
1455 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitAnd );
1456 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitXor );
1457 DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitOr );
1459 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicAnd );
1460 DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicOr );
1462 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssign );
1463 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMul );
1464 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignDiv );
1465 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRemainder );
1466 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignPlus );
1467 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMinus );
1468 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignLeftShift );
1469 DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRightShift);
1470 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignAnd );
1471 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignXor );
1472 DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignOr );
1474 DUNE_SIMD_DO(SV, VV, VS, SV, , VS, InfixComma );
1485 void checkAutoCopy()
1487 using RValueResult =
decltype(
autoCopy(
lane(0, std::declval<V>())));
1488 static_assert(std::is_same<RValueResult, Scalar<V> >::value,
1489 "Result of autoCopy() must always be Scalar<V>");
1491 using MutableLValueResult =
1493 static_assert(std::is_same<MutableLValueResult, Scalar<V> >::value,
1494 "Result of autoCopy() must always be Scalar<V>");
1496 using ConstLValueResult =
1498 static_assert(std::is_same<ConstLValueResult, Scalar<V> >::value,
1499 "Result of autoCopy() must always be Scalar<V>");
1501 V vec = make123<V>();
1502 for(std::size_t l = 0; l <
lanes(vec); ++l)
1508 void checkBoolReductions()
1513 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(trueVec)) ==
true);
1514 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(trueVec)) ==
true);
1515 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(trueVec)) ==
false);
1516 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(trueVec)) ==
false);
1519 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(trueVec)) ==
true);
1520 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(trueVec)) ==
true);
1521 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(trueVec)) ==
false);
1522 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(trueVec)) ==
false);
1525 DUNE_SIMD_CHECK(
allTrue (M(
true)) ==
true);
1526 DUNE_SIMD_CHECK(
anyTrue (M(
true)) ==
true);
1527 DUNE_SIMD_CHECK(
allFalse(M(
true)) ==
false);
1528 DUNE_SIMD_CHECK(
anyFalse(M(
true)) ==
false);
1533 DUNE_SIMD_CHECK(
allTrue (
static_cast<M&
>(falseVec)) ==
false);
1534 DUNE_SIMD_CHECK(
anyTrue (
static_cast<M&
>(falseVec)) ==
false);
1535 DUNE_SIMD_CHECK(
allFalse(
static_cast<M&
>(falseVec)) ==
true);
1536 DUNE_SIMD_CHECK(
anyFalse(
static_cast<M&
>(falseVec)) ==
true);
1539 DUNE_SIMD_CHECK(
allTrue (
static_cast<const M&
>(falseVec)) ==
false);
1540 DUNE_SIMD_CHECK(
anyTrue (
static_cast<const M&
>(falseVec)) ==
false);
1541 DUNE_SIMD_CHECK(
allFalse(
static_cast<const M&
>(falseVec)) ==
true);
1542 DUNE_SIMD_CHECK(
anyFalse(
static_cast<const M&
>(falseVec)) ==
true);
1545 DUNE_SIMD_CHECK(
allTrue (M(
false)) ==
false);
1546 DUNE_SIMD_CHECK(
anyTrue (M(
false)) ==
false);
1547 DUNE_SIMD_CHECK(
allFalse(M(
false)) ==
true);
1548 DUNE_SIMD_CHECK(
anyFalse(M(
false)) ==
true);
1550 auto mixedVec = broadcast<M>(0);
1551 for(std::size_t l = 0; l <
lanes(mixedVec); ++l)
1552 lane(l, mixedVec) = (l % 2);
1556 (
allTrue (
static_cast<M&
>(mixedVec)) ==
false);
1558 (
anyTrue (
static_cast<M&
>(mixedVec)) == (lanes<M>() > 1));
1560 (
allFalse(
static_cast<M&
>(mixedVec)) == (lanes<M>() == 1));
1562 (
anyFalse(
static_cast<M&
>(mixedVec)) ==
true);
1566 (
allTrue (
static_cast<const M&
>(mixedVec)) ==
false);
1568 (
anyTrue (
static_cast<const M&
>(mixedVec)) == (lanes<M>() > 1));
1570 (
allFalse(
static_cast<const M&
>(mixedVec)) == (lanes<M>() == 1));
1572 (
anyFalse(
static_cast<const M&
>(mixedVec)) ==
true);
1575 DUNE_SIMD_CHECK(
allTrue (M(mixedVec)) ==
false);
1576 DUNE_SIMD_CHECK(
anyTrue (M(mixedVec)) == (lanes<M>() > 1));
1577 DUNE_SIMD_CHECK(
allFalse(M(mixedVec)) == (lanes<M>() == 1));
1578 DUNE_SIMD_CHECK(
anyFalse(M(mixedVec)) ==
true);
1587 (std::is_same<decltype(cond(std::declval<M>(), std::declval<V>(),
1588 std::declval<V>())), V>::value,
1589 "The result of cond(M, V, V) should have exactly the type V");
1592 (std::is_same<decltype(cond(std::declval<const M&>(),
1593 std::declval<const V&>(),
1594 std::declval<const V&>())), V>::value,
1595 "The result of cond(const M&, const V&, const V&) should have "
1596 "exactly the type V");
1599 (std::is_same<decltype(cond(std::declval<M&>(), std::declval<V&>(),
1600 std::declval<V&>())), V>::value,
1601 "The result of cond(M&, V&, V&) should have exactly the type V");
1603 V vec1 = leftVector<V>();
1604 V vec2 = rightVector<V>();
1606 DUNE_SIMD_CHECK(
allTrue(
cond(M(
true), vec1, vec2) == vec1));
1607 DUNE_SIMD_CHECK(
allTrue(
cond(M(
false), vec1, vec2) == vec2));
1609 auto mixedResult = broadcast<V>(0);
1610 auto mixedMask = broadcast<M>(
false);
1611 for(std::size_t l = 0; l <
lanes(mixedMask); ++l)
1613 lane(l, mixedMask ) = (l % 2);
1614 lane(l, mixedResult) =
lane(l, (l % 2) ? vec1 : vec2);
1617 DUNE_SIMD_CHECK(
allTrue(
cond(mixedMask, vec1, vec2) == mixedResult));
1621 void checkBoolCond()
1624 (std::is_same<decltype(cond(std::declval<bool>(), std::declval<V>(),
1625 std::declval<V>())), V>::value,
1626 "The result of cond(bool, V, V) should have exactly the type V");
1629 (std::is_same<decltype(cond(std::declval<const bool&>(),
1630 std::declval<const V&>(),
1631 std::declval<const V&>())), V>::value,
1632 "The result of cond(const bool&, const V&, const V&) should have "
1633 "exactly the type V");
1636 (std::is_same<decltype(cond(std::declval<bool&>(),
1638 std::declval<V&>())), V>::value,
1639 "The result of cond(bool&, V&, V&) should have exactly the type V");
1641 V vec1 = leftVector<V>();
1642 V vec2 = rightVector<V>();
1644 DUNE_SIMD_CHECK(
allTrue(
cond(
true, vec1, vec2) == vec1));
1645 DUNE_SIMD_CHECK(
allTrue(
cond(
false, vec1, vec2) == vec2));
1649 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1650 checkHorizontalMinMax() {}
1653 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1654 checkHorizontalMinMax()
1657 (std::is_same<decltype(max(std::declval<V>())),
Scalar<V> >::value,
1658 "The result of max(V) should be exactly Scalar<V>");
1661 (std::is_same<decltype(min(std::declval<V>())),
Scalar<V> >::value,
1662 "The result of min(V) should be exactly Scalar<V>");
1665 (std::is_same<decltype(max(std::declval<V&>())),
Scalar<V> >::value,
1666 "The result of max(V) should be exactly Scalar<V>");
1669 (std::is_same<decltype(min(std::declval<V&>())),
Scalar<V> >::value,
1670 "The result of min(V) should be exactly Scalar<V>");
1672 const V vec1 = leftVector<V>();
1679 std::enable_if_t<!Impl::LessThenComparable<Scalar<V> >::value>
1680 checkBinaryMinMax() {}
1683 std::enable_if_t<Impl::LessThenComparable<Scalar<V> >::value>
1690 (std::is_same<decltype(Simd::max(std::declval<V>(),
1691 std::declval<V>())), V>::value,
1692 "The result of Simd::max(V, V) should be exactly V");
1694 (std::is_same<decltype(Simd::min(std::declval<V>(),
1695 std::declval<V>())), V>::value,
1696 "The result of Simd::min(V, V) should be exactly V");
1699 (std::is_same<decltype(Simd::max(std::declval<V&>(),
1700 std::declval<V&>())), V>::value,
1701 "The result of Simd::max(V&, V&) should be exactly V");
1703 (std::is_same<decltype(Simd::min(std::declval<V&>(),
1704 std::declval<V&>())), V>::value,
1705 "The result of Simd::min(V&, V&) should be exactly V");
1707 const V arg1 = leftVector<V>();
1708 const V arg2 = rightVector<V>();
1711 for(
auto l : range(lanes<V>()))
1724 const V vec1 = leftVector<V>();
1726 std::string reference;
1728 const char *sep =
"";
1729 for(
auto l : range(
lanes(vec1)))
1731 std::ostringstream stream;
1732 stream <<
lane(l, vec1);
1735 reference += stream.str();
1741 std::ostringstream stream;
1743 if(
lanes(vec1) == 1)
1744 DUNE_SIMD_CHECK(stream.str() == reference);
1746 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1750 std::ostringstream stream;
1751 stream <<
vio(vec1);
1752 DUNE_SIMD_CHECK(stream.str() ==
"<" + reference +
">");
1756#undef DUNE_SIMD_CHECK
1796 template<
class V>
void checkType();
1797 template<
class V>
void checkNonOps();
1798 template<
class V>
void checkUnaryOps();
1799 template<
class V>
void checkBinaryOps();
1800 template<
class V>
void checkBinaryOpsVectorVector();
1801 template<
class V>
void checkBinaryOpsScalarVector();
1802 template<
class V>
void checkBinaryOpsVectorScalar();
1803 template<
class V>
void checkBinaryOpsProxyVector();
1804 template<
class V>
void checkBinaryOpsVectorProxy();
1825 template<
class V,
class Rebinds,
1826 template<
class>
class RebindPrune =
IsLoop,
1830 if(seen_.emplace(typeid (V)).second ==
false)
1838 auto recurse = [
this](
auto w) {
1839 using W =
typename decltype(w)::type;
1840 this->
template check<W, Rebinds, RebindPrune, RebindAccept>();
1842 checkRebindOf<V, Rebinds, RebindPrune, RebindAccept>(recurse);
1888 template<
class V,
class Rebinds,
template<
class>
class Prune =
IsLoop>
1890 "checkType() and friends instead")
1901 template<
class V>
void UnitTest::checkType()
1903 static_assert(std::is_same<V, std::decay_t<V> >::value,
"Simd types "
1904 "must not be references, and must not include "
1907 log_ <<
"Checking SIMD type " << className<V>() << std::endl;
1911 checkBinaryOps<V>();
1913 template<
class V>
void UnitTest::checkNonOps()
1915 constexpr auto isMask =
typename std::is_same<Scalar<V>,
bool>::type{};
1920 checkDefaultConstruct<V>();
1922 checkCopyMoveConstruct<V>();
1924 checkBroadcast<V>();
1926 [
this](
auto id) { id(
this)->template checkBroadcastMaskConstruct<V>(); },
1927 [
this](
auto id) { id(
this)->template checkBroadcastVectorConstruct<V>(); });
1928 checkBracedAssign<V>();
1929 checkBracedBroadcastAssign<V>();
1936 [
this](
auto id) { id(
this)->template checkBoolReductions<V>(); });
1939 checkHorizontalMinMax<V>();
1940 checkBinaryMinMax<V>();
1943 template<
class V>
void UnitTest::checkUnaryOps()
1945 auto checkMask = [=](
auto id) {
1946 auto check = [=](
auto op) {
1947 id(
this)->template checkUnaryOpsV<V>(op);
1962 check(OpPrefixLogicNot{});
1966 auto checkVector = [=](
auto id) {
1967 auto check = [=](
auto op) {
1968 id(
this)->template checkUnaryOpsV<V>(op);
1980 check(OpPrefixMinus{});
1981 check(OpPrefixLogicNot{});
1982 check(OpPrefixBitNot{});
1985 Hybrid::ifElse(std::is_same<Scalar<V>,
bool>{}, checkMask, checkVector);
1987 template<
class V>
void UnitTest::checkBinaryOps()
1989 checkBinaryOpsVectorVector<V>();
1990 checkBinaryOpsScalarVector<V>();
1991 checkBinaryOpsVectorScalar<V>();
1992 checkBinaryOpsProxyVector<V>();
1993 checkBinaryOpsVectorProxy<V>();
1995 template<
class V>
void UnitTest::checkBinaryOpsVectorVector()
1997 auto checker = [=](
auto doSV,
auto doVV,
auto doVS,
auto op) {
1998 auto check = [=](
auto t1,
auto t2) {
1999 this->checkBinaryOpVV(t1, t2, op);
2001 this->checkBinaryRefQual<V, V, doVV>(check);
2003 checkBinaryOps<V>(checker);
2005 template<
class V>
void UnitTest::checkBinaryOpsScalarVector()
2007 auto checker = [=](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2008 auto check = [=](
auto t1,
auto t2) {
2009 this->checkBinaryOpSV(t1, t2, op);
2011 this->checkBinaryRefQual<Scalar<V>, V, doSV>(check);
2013 auto crossCheck = [=](
auto t1,
auto t2) {
2014 this->checkBinaryOpVVAgainstSV(t1, t2, op);
2016 this->checkBinaryRefQual<Scalar<V>, V, doSV && doVV>(crossCheck);
2018 checkBinaryOps<V>(checker);
2020 template<
class V>
void UnitTest::checkBinaryOpsVectorScalar()
2022 auto checker = [=](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2023 auto check = [=](
auto t1,
auto t2) {
2024 this->checkBinaryOpVS(t1, t2, op);
2026 this->checkBinaryRefQual<V, Scalar<V>, doVS>(check);
2028 auto crossCheck = [=](
auto t1,
auto t2) {
2029 this->checkBinaryOpVVAgainstVS(t1, t2, op);
2031 this->checkBinaryRefQual<V, Scalar<V>, doVV && doVS>(crossCheck);
2033 checkBinaryOps<V>(checker);
2035 template<
class V>
void UnitTest::checkBinaryOpsProxyVector()
2037 auto checker = [=](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2038 auto check = [=](
auto t1,
auto t2) {
2039 this->checkBinaryOpPV(t1, t2, op);
2041 this->checkBinaryRefQual<V, V, doSV>(check);
2043 checkBinaryOps<V>(checker);
2045 template<
class V>
void UnitTest::checkBinaryOpsVectorProxy()
2047 auto checker = [=](
auto doSV,
auto doVV,
auto doVS,
auto op) {
2048 auto check = [=](
auto t1,
auto t2) {
2049 this->checkBinaryOpVP(t1, t2, op);
2051 this->checkBinaryRefQual<V, V, doVS>(check);
2053 checkBinaryOps<V>(checker);
2058 template<
class V,
class Rebinds,
template<
class>
class Prune>
2059 void UnitTest::checkVector()
2062 if(seen_.emplace(typeid (V)).second ==
false)
2070 auto recurse = [
this](
auto w) {
2071 using W =
typename decltype(w)::type;
2072 this->
template checkVector<W, Rebinds, Prune>();
2074 checkRebindOf<V, Rebinds, Prune, Std::to_true_type>(recurse);
A free function to provide the demangled class name of a given object or type as a string.
Definition of the DUNE_DEPRECATED macro for the case that config.h is not available.
IO interface of the SIMD abstraction.
std::integral_constant< bool, value > bool_constant
A template alias for std::integral_constant<bool, value>
Definition: type_traits.hh:118
#define DUNE_UNUSED
A macro for marking variables that the compiler mistakenly flags as unused, which sometimes happens d...
Definition: unused.hh:16
constexpr AutonomousValue< T > autoCopy(T &&v)
Autonomous copy of an expression's value for use in auto type deduction.
Definition: typetraits.hh:723
typename Impl::voider< Types... >::type void_t
Is void for all valid input types (see N3911). The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:40
#define DUNE_DEPRECATED_MSG(text)
Mark some entity as deprecated.
Definition: deprecated.hh:169
#define DUNE_DEPRECATED
Mark some entity as deprecated.
Definition: deprecated.hh:84
constexpr GeometryType line
GeometryType representing a line.
Definition: type.hh:803
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:267
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition: hybridutilities.hh:355
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:87
typename Impl::RemoveEnd< EndMark, TypeList< Types... > >::type RebindList
A list of types with the final element removed.
Definition: test.hh:167
typename Impl::IsLoop< T >::type IsLoop
check whether a type is an instance of LoopSIMD
Definition: test.hh:171
Dune namespace.
Definition: alignedallocator.hh:14
Utilities for reduction like operations on ranges.
Include file for users of the SIMD abstraction layer.
final element marker for RebindList
Definition: test.hh:154
template mapping a type to std::true_type
Definition: type_traits.hh:97
Traits for type conversions and type information.
Definition of the DUNE_UNUSED macro for the case that config.h is not available.