30template <
class T,
int N>
34 std::enable_if_t<(N > kSimdDefaultSize<T> && Simd<T>::kIsSupported),
SimdConcept>> {
53 "Some functions may need to be updated to support other SIMD sizes");
56 "Inconsistent SIMD emulation flags");
68 template <
class Half, MOCHI_CONCEPT(Half::kIsComposite && (Half::kSize * 2 == kSize))>
70 static_assert(std::is_same_v<Scalar, typename Half::Scalar>,
"Type mismatch");
71 static_assert(
kSizeFirst == 2 && Half::kSize == 4 &&
kSize == 8,
"Unsupported size");
74 second.second.first = b.first;
75 second.second.second = b.second;
79 template <
class U, MOCHI_REQUIRES_NON_BOOL_SCALAR(U, Scalar)>
127 template <
typename... MoreScalars>
137 MoreScalars... args) {
146 static constexpr auto kNumArgs =
sizeof...(args);
147 if constexpr (kNumArgs == 0) {
149 }
else if constexpr (kNumArgs == 1) {
164 return First::template
Get<i>(a.first);
172 return First::Get(a.first, i);
181 static_assert(Half::kIsSupported);
183 if constexpr (i == 0) {
190 Half::kIsComposite &&
kSize == 8 &&
kSizeFirst == 2,
"Not yet supported for other sizes");
191 if constexpr (i == 0) {
192 return Half{a.first, a.second.first};
194 return Half{a.second.second.first, a.second.second.second};
201 return {First::Set(a.first, i, value), a.second};
203 return {a.first, Second::Set(a.second, i -
kSizeFirst, value)};
210 return {First::template
Set<i>(a.first, value), a.second};
212 return {a.first, Second::template
Set<i -
kSizeFirst>(a.second, value)};
218 static_assert(
kSize == 4,
"Unsupported size");
224 Scalar constexpr kSequence[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
227 "Vector size is too large. Size of kSequence must be increased.");
228 auto first = First::Load(kSequence);
230 if constexpr (std::is_same_v<First, Second>) {
233 second = Second::Sequence();
237 "Vector size is too large. Size of kSequence must be increased.");
238 second = Second::Load(kSequence);
243 template <
int x = 0,
int y = 1,
int z = 2,
int w = 3>
245 static_assert(
kSize == 4,
"Unsupported size");
249 template <
int x = 0,
int y = 1,
int z = 2,
int w = 3>
251 static_assert(
kSize == 4,
"Unsupported size");
255 template <
int SZ = kSize>
257 static_assert(SZ <=
kSize);
266 template <
int SZ = kSize>
277 static_assert(
kSize == 4,
"Unsupported size");
278 return {a.first, Second::template
Set<1>(a.second,
Scalar(0))};
282 static_assert(
kSize == 4,
"Unsupported size");
283 return {a.first, Second::template
Set<1>(a.second,
Scalar(1))};
286 template <
int x,
int y,
int z,
int w>
288 static_assert(
kSize == 4,
"Unsupported size");
295 return {First::Broadcast(p), Second::Broadcast(p)};
318 template <
int SZ = kSize>
332 return {First::Load(ptr, n),
Second{}};
338 template <
typename IntT, MOCHI_CONCEPT(std::is_
integral_v<IntT>)>
341 using IMatch = std::conditional_t<
sizeof(
Scalar) == 4,
int, int64_t>;
343 static_assert(IVec::kIsComposite &&
sizeof(IVec) ==
sizeof(
Simd));
346 First::LoadIndexed(ptr, matchingIndices.first),
347 Second::LoadIndexed(ptr, matchingIndices.second)};
350 template <
int kTupleCount =
kSize,
class... OutputVectors>
353 OutputVectors&... out) {
354 static_assert(kTupleCount >= 1 && kTupleCount <=
kSize,
"Invalid kTupleCount");
357 ((out.second = {}), ...);
361 ptr +
sizeof...(OutputVectors) *
kSizeFirst, out.second...);
367 First::Select(mask.first, a.first, b.first),
368 Second::Select(mask.second, a.second, b.second)};
371 template <
int kShift>
373 static_assert(kShift >= 0 && kShift < (8 *
sizeof(T)),
"Shift amount out-of-range");
374 if constexpr (kShift == 0) {
383 template <
int SZ = kSize>
396 memcpy(ptr, &v,
sizeof(
Scalar) * n);
400 int count = First::StoreSelected(ptr, condition.first, values.first);
401 count += Second::StoreSelected(ptr + count, condition.second, values.second);
405 template <
int kTupleCount =
kSize,
class... InputVectors>
410 ptr +
sizeof...(InputVectors) *
kSizeFirst, v.second...);
415 return {First::SignBitMask(), Second::SignBitMask()};
418 template <
int SZ = kSize>
421 return First::template
HMin<SZ>(a.first);
432 First::Min(a.first, First::Min(a.second.first, a.second.second)));
437 First::Min(a.second.first, First::Min(a.second.second.first, a.second.second.second))));
446 template <
int SZ = kSize>
449 return First::template
HMax<SZ>(a.first);
460 First::Max(a.first, First::Max(a.second.first, a.second.second)));
465 First::Max(a.second.first, First::Max(a.second.second.first, a.second.second.second))));
474 template <
int SZ = kSize>
477 return First::template
HSum<SZ>(a.first);
486 return First::template
HSum<kSizeFirst>(a.first + a.second.first + a.second.second);
490 a.first + a.second.first + a.second.second.first + a.second.second.second);
498 template <
int SZ = kSize>
501 return First::template
HProd<SZ>(a.first);
514 template <
int SZ = kSize>
520 return {First::Zero(), Second::Zero()};
525 template <
class U, MOCHI_REQUIRES_NON_BOOL_SCALAR(U, Scalar)>
536 First::Equal(this->first, rhs.first) & Second::Equal(this->second, rhs.second));
538 return (this->first == rhs.first) && (this->second == rhs.second);
543 return !(*
this == rhs);
547 return Get(*
this, i);
551 return {this->first << i, this->second << i};
561 return {this->first >> i, this->second >> i};
570#define MOCHI_SIMD_COMPOSITE_FN_1(FnName) \
571 [[nodiscard]] static MOCHI_ANY MOCHI_FORCE_INLINE Simd FnName(Simd a) { \
572 return {First::FnName(a.first), Second::FnName(a.second)}; \
575#define MOCHI_SIMD_COMPOSITE_FN_2(FnName) \
576 [[nodiscard]] static MOCHI_ANY MOCHI_FORCE_INLINE Simd FnName(Simd a, Simd b) { \
577 return {First::FnName(a.first, b.first), Second::FnName(a.second, b.second)}; \
580#define MOCHI_SIMD_COMPOSITE_FN_3(FnName) \
581 [[nodiscard]] static MOCHI_ANY MOCHI_FORCE_INLINE Simd FnName(Simd a, Simd b, Simd c) { \
583 First::FnName(a.first, b.first, c.first), Second::FnName(a.second, b.second, c.second)}; \
586#define MOCHI_SIMD_COMPOSITE_OP_1(OP) \
587 [[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd operator OP() const { \
588 return {OP this->first, OP this->second}; \
591#define MOCHI_SIMD_COMPOSITE_OP_2(OP) \
592 [[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd operator OP(Simd rhs) const { \
593 return {this->first OP rhs.first, this->second OP rhs.second}; \
596#define MOCHI_SIMD_COMPOSITE_OP_EQ(OP_EQ, OP) \
597 MOCHI_ANY MOCHI_FORCE_INLINE Simd& operator OP_EQ(Simd a) { \
598 this->first = this->first OP a.first; \
599 this->second = this->second OP a.second; \
603#define MOCHI_SIMD_COMPOSITE_OP_EQ_WITH_SCALAR(OP_EQ, OP) \
604 MOCHI_SIMD_COMPOSITE_OP_EQ(OP_EQ, OP); \
605 MOCHI_ANY MOCHI_FORCE_INLINE Simd& operator OP_EQ(Scalar a) { \
606 this->first = this->first OP First{a}; \
607 this->second = this->second OP Second{a}; \
673#undef MOCHI_SIMD_COMPOSITE_FN_1
674#undef MOCHI_SIMD_COMPOSITE_FN_2
675#undef MOCHI_SIMD_COMPOSITE_FN_3
676#undef MOCHI_SIMD_COMPOSITE_OP_1
677#undef MOCHI_SIMD_COMPOSITE_OP_2
678#undef MOCHI_SIMD_COMPOSITE_OP_EQ
679#undef MOCHI_SIMD_COMPOSITE_OP_EQ_WITH_SCALAR
690 ReinterpretCast<typename To::First>(a.first), ReinterpretCast<typename To::Second>(a.second)};
695[[nodiscard]]
constexpr bool IsCompositeWithEqualHalves() {
696 if constexpr (T::kIsComposite) {
697 return T::kSizeFirst == T::kSizeSecond;
703template <
class To,
class From, std::size_t... Is>
705StaticCastElementwise(From
const& a, std::index_sequence<Is...>) {
706 return To{
static_cast<typename To::Scalar
>(a[Is])...};
712template <
class To,
class From, MOCHI_CONCEPT_DEF(IsSimd<To>&& IsSimd<From>)>
714 static_assert(To::kSize == From::kSize,
"Size mismatch");
715 static_assert(To::kIsSupported,
"Unsupported type");
716 using ToHalf =
Simd<
typename To::Scalar, To::kSize / 2>;
717 using FromHalf =
Simd<
typename From::Scalar, From::kSize / 2>;
718 if constexpr (std::is_same_v<typename To::Scalar, typename From::Scalar>) {
720 }
else if constexpr (
721 To::kIsComposite && From::kIsComposite &&
722 (
sizeof(
typename To::Scalar) ==
sizeof(
typename From::Scalar))) {
726 }
else if constexpr (
727 From::kIsComposite && !To::kIsComposite && ToHalf::kIsSupported &&
728 (
sizeof(
typename To::Scalar) * 2 ==
sizeof(
typename From::Scalar))) {
732 }
else if constexpr (
733 To::kIsComposite && !From::kIsComposite && FromHalf::kIsSupported &&
734 (
sizeof(
typename To::Scalar) == 2 *
sizeof(
typename From::Scalar))) {
740 }
else if constexpr (
741 ::superdex::details::IsCompositeWithEqualHalves<From>() &&
742 ::superdex::details::IsCompositeWithEqualHalves<To>() &&
743 sizeof(
typename To::Scalar) !=
sizeof(
typename From::Scalar)) {
751 return superdex::details::StaticCastElementwise<To>(a, std::make_index_sequence<From::kSize>{});
Simd(Scalar a, Scalar b, Scalar c, Scalar d, Scalar e, Scalar f=Scalar(0))
static Simd NotEqual(Simd a, Simd b)
static Simd RcpSqrtApprox(Simd a)
static void StoreTransposed(Scalar *ptr, InputVectors... v)
static Simd FastRound(Simd a)
static constexpr int kSizeFirst
static Simd NegMulAdd(Simd a, Simd b, Simd c)
static Simd ShiftRight(Simd a)
static Simd SignBitMask()
static Simd Dot(Simd a, Simd b)
Simd< T, N - First::kSize > Second
static constexpr bool kIsComposite
Simd(Half const &a, Half const &b)
bool operator==(Simd rhs) const
Simd & operator>>=(int i)
static bool AnyTrue(Simd a)
static auto GetHalf(Simd a)
static Simd MulAdd(Simd a, Simd b, Simd c)
static Simd Set(Simd a, int i, Scalar value)
static constexpr size_t size()
static void Store(Scalar *ptr, Simd a)
static Simd AsPoint(Simd a)
Simd(Scalar a, Scalar b, Scalar c, Scalar d, Scalar e, Scalar f, Scalar g, Scalar h, MoreScalars... args)
static Simd Min(Simd a, Simd b)
static Simd RcpApprox(Simd a)
Simd(Scalar a, Scalar b, Scalar c, Scalar d=Scalar(0))
Simd(First const &p0, Second const &p1)
static Simd Shuffle(Simd a)
static Simd Shuffle(Simd a, Simd b)
Scalar operator[](int i) const
static Simd NegMulSub(Simd a, Simd b, Simd c)
static Scalar HMin(Simd a)
static Scalar HProd(Simd a)
static Simd MulSub(Simd a, Simd b, Simd c)
Simd & operator<<=(int i)
static Simd Broadcast(Scalar const *p)
static Scalar HMax(Simd a)
static Simd Blend(Simd a, Simd b)
static constexpr int kSize
Simd operator<<(int i) const
static Simd Equal(Simd a, Simd b)
Simd & operator=(Simd const &rhs)=default
static constexpr int kSizeSecond
static Simd Max(Simd a, Simd b)
static Simd Broadcast(Simd a)
static constexpr bool kIsEmulated
bool operator!=(Simd rhs) const
static Scalar Get(Simd a, int i)
static Simd LoadIndexed(Scalar const *ptr, Simd< IntT, kSize > const &indices)
static Scalar Get(Simd a)
static void LoadTransposed(Scalar const *ptr, OutputVectors &... out)
static Simd Set(Simd a, Scalar value)
Simd operator>>(int i) const
static Simd Broadcast(Scalar a)
static Simd Select(Simd mask, Simd a, Simd b)
static bool AllTrue(Simd a)
static constexpr bool kIsSupported
static Simd Load(T const *ptr)
static void Store(Scalar *ptr, Simd v, int n)
static int StoreSelected(Scalar *ptr, Simd condition, Simd values)
static Simd Load(Scalar const *ptr, int n)
Simd(Simd const &a)=default
static Simd Floor(Simd a)
static Simd SetBasisVector()
static Scalar HSum(Simd a)
Simd< T, kSimdDefaultSize< T > > NativeType
static Simd AsDirection(Simd a)
Simd(Scalar a, Scalar b, Scalar c, Scalar d, Scalar e, Scalar f, Scalar g)
static constexpr bool kIsComposite
static constexpr bool kIsEmulated
static constexpr int kSize
static constexpr bool kIsSupported
#define MOCHI_ASSERT_VERBOSE(condition_without_side_effects,...)
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
constexpr T const & Min(T const &a, T const &b)
constexpr To StaticCast(From const &a)
Simd< T, N > Set(Simd< T, N > a, T value)
V Broadcast(typename V::Scalar a)
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
Simd< T, N/2 > GetHalf(Simd< T, N > a)
constexpr T const & Max(T const &a, T const &b)
void LoadTransposed(T const *ptr, Simd< T, N > &out0, Simd< T, N > &out1, Simd< T, N > &out2)
void StoreTransposed(T *ptr, Simd< T, N > a, Simd< T, N > b, Simd< T, N > c)
void Store(T *ptr, Simd< T, N > a)
V Load(typename V::Scalar const *ptr)
Simd< T, N > ShiftRight(Simd< T, N > a)
#define MOCHI_SIMD_COMPOSITE_FN_3(FnName)
#define MOCHI_SIMD_COMPOSITE_OP_1(OP)
#define MOCHI_SIMD_COMPOSITE_OP_EQ(OP_EQ, OP)
#define MOCHI_SIMD_COMPOSITE_FN_2(FnName)
#define MOCHI_SIMD_COMPOSITE_OP_2(OP)
#define MOCHI_SIMD_COMPOSITE_OP_EQ_WITH_SCALAR(OP_EQ, OP)
#define MOCHI_SIMD_COMPOSITE_FN_1(FnName)