28 #ifndef VC_COMMON_SIMDARRAY_H_ 29 #define VC_COMMON_SIMDARRAY_H_ 37 #include "writemaskedvector.h" 38 #include "simdarrayhelper.h" 39 #include "simdmaskarray.h" 41 #include "interleave.h" 42 #include "indexsequence.h" 43 #include "transpose.h" 46 namespace Vc_VERSIONED_NAMESPACE
57 template <std::size_t N,
class... Candidates>
struct select_best_vector_type_impl;
59 template <std::
size_t N,
class T>
struct select_best_vector_type_impl<N, T> {
63 template <std::size_t N,
class T,
class... Candidates>
64 struct select_best_vector_type_impl<N, T, Candidates...> {
65 using type =
typename std::conditional<
66 (N < T::Size),
typename select_best_vector_type_impl<N, Candidates...>::type,
69 template <
class T, std::
size_t N>
70 struct select_best_vector_type : select_best_vector_type_impl<N,
73 #elif defined Vc_IMPL_AVX
79 Vc::Scalar::Vector<T>> {
87 template <
typename T> T Vc_INTRINSIC Vc_PURE product_helper_(
const T &l,
const T &r) {
return l * r; }
88 template <
typename T> T Vc_INTRINSIC Vc_PURE sum_helper_(
const T &l,
const T &r) {
return l + r; }
92 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
95 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
104 #define Vc_CURRENT_CLASS_NAME SimdArray 114 template <
typename T, std::
size_t N,
typename VectorType_>
117 static_assert(std::is_same<T, double>::value || std::is_same<T, float>::value ||
118 std::is_same<T, int32_t>::value ||
119 std::is_same<T, uint32_t>::value ||
120 std::is_same<T, int16_t>::value ||
121 std::is_same<T, uint16_t>::value,
122 "SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, " 123 "int16_t, uint16_t }");
126 using VectorType = VectorType_;
127 using vector_type = VectorType;
128 using storage_type = vector_type;
129 using vectorentry_type =
typename vector_type::VectorEntryType;
133 static constexpr std::size_t size() {
return N; }
137 using VectorEntryType = vectorentry_type;
141 using reference = Detail::ElementReference<SimdArray>;
142 static constexpr std::size_t Size = size();
146 #ifndef Vc_MSVC // bogus error C2580 158 Vc_INTRINSIC SimdArray(
value_type &&a) : data(a) {}
161 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
162 Vc_INTRINSIC SimdArray(U a)
163 : SimdArray(static_cast<value_type>(a))
168 template <
class U,
class V,
class...,
class = enable_if<N == V::Size>>
170 : data(simd_cast<vector_type>(internal_data(x)))
173 template <
class U,
class V,
class...,
class...,
174 class = enable_if<(N > V::Size && N <= 2 * V::Size)>>
176 : data(simd_cast<vector_type>(internal_data(internal_data0(x)),
177 internal_data(internal_data1(x))))
180 template <
class U,
class V,
class...,
class...,
class...,
181 class = enable_if<(N > 2 * V::Size && N <= 4 * V::Size)>>
183 : data(simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
184 internal_data(internal_data1(internal_data0(x))),
185 internal_data(internal_data0(internal_data1(x))),
186 internal_data(internal_data1(internal_data1(x)))))
190 template <
typename V, std::
size_t Pieces, std::
size_t Index>
191 Vc_INTRINSIC
SimdArray(Common::Segment<V, Pieces, Index> &&x)
192 : data(simd_cast<vector_type, Index>(x.data))
196 Vc_INTRINSIC
SimdArray(
const std::initializer_list<value_type> &init)
199 #if defined Vc_CXX14 && 0 // doesn't compile yet 200 static_assert(init.size() == size(),
"The initializer_list argument to " 201 "SimdArray<T, N> must contain exactly N " 204 Vc_ASSERT(init.size() == size());
212 Vc_INTRINSIC SimdArray(
const V &x)
213 : data(simd_cast<vector_type>(x))
219 template <
typename U,
typename A,
222 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
232 #include "gatherinterface.h" 233 #include "scatterinterface.h" 236 template <
typename... Args,
237 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
238 !Traits::is_gather_signature<Args...>::value &&
239 !Traits::is_initializer_list<Args...>::value>>
240 explicit Vc_INTRINSIC SimdArray(Args &&... args)
241 : data(std::forward<Args>(args)...)
245 template <std::
size_t Offset>
246 explicit Vc_INTRINSIC SimdArray(
247 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
253 Vc_INTRINSIC
void setZero() { data.setZero(); }
254 Vc_INTRINSIC
void setZero(
mask_type k) { data.setZero(internal_data(k)); }
255 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
256 Vc_INTRINSIC
void setZeroInverted(
mask_type k) { data.setZeroInverted(internal_data(k)); }
258 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
259 Vc_INTRINSIC
void setQnan(
mask_type m) { data.setQnan(internal_data(m)); }
262 template <
typename Op,
typename... Args>
263 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
266 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
270 template <
typename Op,
typename... Args>
271 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
273 Common::unpackArgumentsAuto(op,
nullptr, std::forward<Args>(args)...);
276 static Vc_INTRINSIC SimdArray
Zero()
280 static Vc_INTRINSIC SimdArray
One()
288 static Vc_INTRINSIC SimdArray Random()
290 return fromOperation(Common::Operations::random());
293 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
295 data.load(std::forward<Args>(args)...);
298 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const 300 data.store(std::forward<Args>(args)...);
305 return {private_init, !data};
310 return {private_init, -data};
314 Vc_INTRINSIC SimdArray
operator+()
const {
return *
this; }
316 Vc_INTRINSIC SimdArray operator~()
const 318 return {private_init, ~data};
321 template <
typename U,
322 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
323 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const 325 return {private_init, data << x};
327 template <
typename U,
328 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
329 Vc_INTRINSIC SimdArray &operator<<=(U x)
334 template <
typename U,
335 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
336 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const 338 return {private_init, data >> x};
340 template <
typename U,
341 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
342 Vc_INTRINSIC SimdArray &operator>>=(U x)
348 #define Vc_BINARY_OPERATOR_(op) \ 349 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \ 351 return {private_init, data op rhs.data}; \ 353 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \ 355 data op## = rhs.data; \ 358 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
359 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
360 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
361 #undef Vc_BINARY_OPERATOR_ 363 #define Vc_COMPARES(op) \ 364 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \ 366 return {private_init, data op rhs.data}; \ 368 Vc_ALL_COMPARES(Vc_COMPARES);
372 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 379 Vc_INTRINSIC
static value_type get(
const SimdArray &o,
int i) noexcept
383 template <
typename U>
384 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
385 noexcept(std::declval<value_type &>() = v))
397 Vc_INTRINSIC reference operator[](
size_t i) noexcept
399 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
400 return {*
this, int(i)};
402 Vc_INTRINSIC
value_type operator[](
size_t i)
const noexcept
404 return get(*
this, int(i));
407 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
414 data.assign(v.data, internal_data(k));
418 #define Vc_REDUCTION_FUNCTION_(name_) \ 419 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \ 420 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \ 422 return data.name_(internal_data(mask)); \ 424 Vc_NOTHING_EXPECTING_SEMICOLON 425 Vc_REDUCTION_FUNCTION_(
min);
426 Vc_REDUCTION_FUNCTION_(
max);
427 Vc_REDUCTION_FUNCTION_(product);
428 Vc_REDUCTION_FUNCTION_(sum);
429 #undef Vc_REDUCTION_FUNCTION_ 430 Vc_INTRINSIC Vc_PURE SimdArray partialSum()
const 432 return {private_init, data.partialSum()};
435 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f)
const 437 return {private_init, data.apply(std::forward<F>(f))};
439 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f,
const mask_type &k)
const 441 return {private_init, data.apply(std::forward<F>(f), k)};
444 Vc_INTRINSIC SimdArray
shifted(
int amount)
const 446 return {private_init, data.shifted(amount)};
449 template <std::
size_t NN>
453 return {private_init, data.shifted(amount, simd_cast<VectorType>(shiftIn))};
456 Vc_INTRINSIC SimdArray rotated(
int amount)
const 458 return {private_init, data.rotated(amount)};
462 Vc_DEPRECATED(
"use exponent(x) instead") Vc_INTRINSIC SimdArray
exponent()
const 464 return {private_init,
exponent(data)};
467 Vc_INTRINSIC SimdArray interleaveLow(SimdArray x)
const 469 return {private_init, data.interleaveLow(x.data)};
471 Vc_INTRINSIC SimdArray interleaveHigh(SimdArray x)
const 473 return {private_init, data.interleaveHigh(x.data)};
476 Vc_INTRINSIC SimdArray reversed()
const 478 return {private_init, data.reversed()};
481 Vc_INTRINSIC SimdArray sorted()
const 483 return {private_init, data.sorted()};
486 template <
typename G>
static Vc_INTRINSIC SimdArray generate(
const G &gen)
488 return {private_init, VectorType::generate(gen)};
491 Vc_DEPRECATED(
"use copysign(x, y) instead") Vc_INTRINSIC SimdArray
492 copySign(
const SimdArray &x)
const 497 friend VectorType &internal_data<>(SimdArray &x);
498 friend const VectorType &internal_data<>(
const SimdArray &x);
501 Vc_INTRINSIC SimdArray(private_init_t, VectorType &&x) : data(std::move(x)) {}
503 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type));
509 alignas(
static_cast<std::size_t
>(
510 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
511 VectorType_::size()>::value)) storage_type data;
514 template <
typename T, std::
size_t N,
typename VectorType>
516 template <
typename T, std::
size_t N,
typename VectorType>
524 template <
typename T, std::
size_t N,
typename VectorType>
534 template <
typename T> T unpackIfSegment(T &&x) {
return std::forward<T>(x); }
535 template <
typename T,
size_t Pieces,
size_t Index>
536 auto unpackIfSegment(Common::Segment<T, Pieces, Index> &&x) -> decltype(x.asSimdArray())
538 return x.asSimdArray();
542 template <
typename T, std::
size_t N,
typename VectorType>
543 template <
typename MT,
typename IT>
547 data.
gather(mem, unpackIfSegment(indexes));
549 template <
typename T, std::
size_t N,
typename VectorType>
550 template <
typename MT,
typename IT>
555 data.
gather(mem, unpackIfSegment(indexes), mask);
559 template <
typename T, std::
size_t N,
typename VectorType>
560 template <
typename MT,
typename IT>
564 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)));
566 template <
typename T, std::
size_t N,
typename VectorType>
567 template <
typename MT,
typename IT>
572 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)), mask);
608 template <
typename T,
size_t N,
typename V,
size_t Wt>
class SimdArray 610 static_assert(std::is_same<T, double>::value ||
611 std::is_same<T, float>::value ||
612 std::is_same<T, int32_t>::value ||
613 std::is_same<T, uint32_t>::value ||
614 std::is_same<T, int16_t>::value ||
615 std::is_same<T, uint16_t>::value,
"SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, int16_t, uint16_t }");
618 std::is_same<typename V::EntryType, typename V::VectorEntryType>::value ||
620 (N % V::size() == 0),
621 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * " 622 "MIC::(u)short_v::size(), i.e. k * 16.");
624 using my_traits = SimdArrayTraits<T, N>;
625 static constexpr std::size_t N0 = my_traits::N0;
626 static constexpr std::size_t N1 = my_traits::N1;
627 using Split = Common::Split<N0>;
628 template <
typename U, std::
size_t K>
using CArray = U[K];
633 static_assert(storage_type0::size() == N0,
"");
638 using vector_type = V;
639 using vectorentry_type =
typename storage_type0::vectorentry_type;
640 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
661 static constexpr std::size_t
size() {
return N; }
668 using VectorEntryType = vectorentry_type;
675 using reference = Detail::ElementReference<SimdArray>;
707 return fromOperation(Common::Operations::random());
713 auto tmp = storage_type0::generate(gen);
718 return {std::move(tmp),
719 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
727 #ifndef Vc_MSVC // bogus error C2580 739 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
741 : SimdArray(static_cast<value_type>(a))
747 SimdArray(
const SimdArray &) =
default;
748 SimdArray(SimdArray &&) =
default;
749 SimdArray &operator=(
const SimdArray &) =
default;
753 typename = enable_if<std::is_arithmetic<U>::value &&
754 Traits::is_load_store_flag<Flags>::value>>
755 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
756 : data0(mem, f), data1(mem + storage_type0::size(), f)
768 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
769 typename = enable_if<std::is_arithmetic<U>::value &&
770 Traits::is_load_store_flag<Flags>::value>>
771 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
772 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
778 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
779 typename = enable_if<std::is_arithmetic<U>::value &&
780 Traits::is_load_store_flag<Flags>::value>>
781 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
782 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
788 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
792 #if defined Vc_CXX14 && 0 // doesn't compile yet 793 static_assert(init.size() == size(),
"The initializer_list argument to " 794 "SimdArray<T, N> must contain exactly N " 797 Vc_ASSERT(init.size() == size());
801 #include "gatherinterface.h" 802 #include "scatterinterface.h" 805 template <
typename... Args,
806 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
807 !Traits::is_initializer_list<Args...>::value &&
808 !Traits::is_gather_signature<Args...>::value &&
809 !Traits::is_load_arguments<Args...>::value>>
810 explicit Vc_INTRINSIC SimdArray(Args &&... args)
811 : data0(Split::lo(args)...)
813 , data1(Split::hi(std::forward<Args>(args))...)
820 class = enable_if<(Traits::is_simd_vector<W>::value &&
822 !(std::is_convertible<Traits::entry_type_of<W>, T>::value &&
824 Vc_INTRINSIC
explicit SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
830 class W,
class...,
class...,
831 class = enable_if<(Traits::isSimdArray<W>::value &&
832 Traits::simd_vector_size<W>::value == N &&
833 std::is_convertible<Traits::entry_type_of<W>, T>::value)>>
834 Vc_INTRINSIC SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
840 template <
typename U,
typename A,
843 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
856 Vc_INTRINSIC
void setZero()
861 Vc_INTRINSIC
void setZero(
const mask_type &k)
863 data0.setZero(Split::lo(k));
864 data1.setZero(Split::hi(k));
866 Vc_INTRINSIC
void setZeroInverted()
868 data0.setZeroInverted();
869 data1.setZeroInverted();
871 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
873 data0.setZeroInverted(Split::lo(k));
874 data1.setZeroInverted(Split::hi(k));
878 Vc_INTRINSIC
void setQnan() {
882 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
883 data0.setQnan(Split::lo(m));
884 data1.setQnan(Split::hi(m));
888 template <
typename Op,
typename... Args>
889 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
892 storage_type0::fromOperation(op, Split::lo(args)...),
895 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
900 template <
typename Op,
typename... Args>
901 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
903 storage_type0::callOperation(op, Split::lo(args)...);
904 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
908 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
910 data0.load(mem, Split::lo(args)...);
912 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
915 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const 917 data0.store(mem, Split::lo(args)...);
919 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
924 return {!data0, !data1};
929 return {-data0, -data1};
933 Vc_INTRINSIC SimdArray
operator+()
const {
return *
this; }
935 Vc_INTRINSIC SimdArray operator~()
const 937 return {~data0, ~data1};
941 template <
typename U,
942 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
943 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const 945 return {data0 << x, data1 << x};
947 template <
typename U,
948 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
949 Vc_INTRINSIC SimdArray &operator<<=(U x)
955 template <
typename U,
956 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
957 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const 959 return {data0 >> x, data1 >> x};
961 template <
typename U,
962 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
963 Vc_INTRINSIC SimdArray &operator>>=(U x)
971 #define Vc_BINARY_OPERATOR_(op) \ 972 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \ 974 return {data0 op rhs.data0, data1 op rhs.data1}; \ 976 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \ 978 data0 op## = rhs.data0; \ 979 data1 op## = rhs.data1; \ 982 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
983 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
984 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
985 #undef Vc_BINARY_OPERATOR_ 987 #define Vc_COMPARES(op) \ 988 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \ 990 return {data0 op rhs.data0, data1 op rhs.data1}; \ 992 Vc_ALL_COMPARES(Vc_COMPARES);
1001 Vc_INTRINSIC
static value_type get(
const SimdArray &o,
int i) noexcept
1003 return reinterpret_cast<const alias_type *
>(&o)[i];
1005 template <
typename U>
1006 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
1007 noexcept(std::declval<value_type &>() = v))
1009 reinterpret_cast<alias_type *
>(&o)[i] = v;
1022 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
1023 return {*
this, int(i)};
1029 return get(*
this, int(index));
1035 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type>
operator()(
1038 return {*
this, mask};
1044 data0.assign(v.data0, internal_data0(k));
1045 data1.assign(v.data1, internal_data1(k));
1049 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \ 1051 template <typename ForSfinae = void> \ 1052 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1053 storage_type0::Size == storage_type1::Size, \ 1054 value_type> name_##_impl() const \ 1056 return binary_fun_(data0, data1).name_(); \ 1059 template <typename ForSfinae = void> \ 1060 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1061 storage_type0::Size != storage_type1::Size, \ 1062 value_type> name_##_impl() const \ 1064 return scalar_fun_(data0.name_(), data1.name_()); \ 1069 Vc_INTRINSIC value_type name_() const { return name_##_impl(); } \ 1071 Vc_INTRINSIC value_type name_(const mask_type &mask) const \ 1073 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \ 1074 return data1.name_(Split::hi(mask)); \ 1075 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \ 1076 return data0.name_(Split::lo(mask)); \ 1078 return scalar_fun_(data0.name_(Split::lo(mask)), \ 1079 data1.name_(Split::hi(mask))); \ 1082 Vc_NOTHING_EXPECTING_SEMICOLON 1085 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_);
1086 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_);
1087 #undef Vc_REDUCTION_FUNCTION_ 1088 Vc_INTRINSIC Vc_PURE SimdArray partialSum() const
1091 auto ps0 = data0.partialSum();
1093 tmp[0] += ps0[data0.size() - 1];
1094 return {std::move(ps0), tmp.partialSum()};
1099 template <
typename F>
inline SimdArray
apply(F &&f)
const 1106 return {data0.
apply(f, Split::lo(k)), data1.
apply(f, Split::hi(k))};
1113 constexpr
int SSize = Size;
1114 constexpr
int SSize0 = storage_type0::Size;
1115 constexpr
int SSize1 = storage_type1::Size;
1120 if (amount > -SSize0) {
1123 if (amount == -SSize0) {
1126 if (amount < -SSize0) {
1132 if (amount >= SSize) {
1134 }
else if (amount >= SSize0) {
1136 simd_cast<storage_type0>(data1).
shifted(amount - SSize0),
1138 }
else if (amount >= SSize1) {
1141 return {data0.shifted(amount, data1), data1.shifted(amount)};
1146 template <std::
size_t NN>
1148 !(std::is_same<storage_type0, storage_type1>::value &&
1153 constexpr
int SSize = Size;
1155 return SimdArray::generate([&](
int i) ->
value_type {
1158 return operator[](i);
1159 }
else if (i >= -SSize) {
1160 return shiftIn[i + SSize];
1165 return SimdArray::generate([&](
int i) ->
value_type {
1168 return operator[](i);
1169 }
else if (i < 2 * SSize) {
1170 return shiftIn[i - SSize];
1179 template <std::
size_t NN>
struct bisectable_shift
1180 :
public std::integral_constant<bool,
1181 std::is_same<storage_type0, storage_type1>::value &&
1187 template <std::
size_t NN>
1188 inline SimdArray
shifted(enable_if<bisectable_shift<NN>::value,
int> amount,
1191 constexpr
int SSize = Size;
1193 if (amount > -static_cast<int>(storage_type0::Size)) {
1194 return {data0.shifted(amount, internal_data1(shiftIn)),
1195 data1.shifted(amount, data0)};
1197 if (amount == -static_cast<int>(storage_type0::Size)) {
1198 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
1200 if (amount > -SSize) {
1202 internal_data1(shiftIn)
1203 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1204 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1206 if (amount == -SSize) {
1209 if (amount > -2 * SSize) {
1210 return shiftIn.
shifted(amount + SSize);
1216 if (amount < static_cast<int>(storage_type0::Size)) {
1217 return {data0.shifted(amount, data1),
1218 data1.shifted(amount, internal_data0(shiftIn))};
1220 if (amount == static_cast<int>(storage_type0::Size)) {
1221 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1223 if (amount < SSize) {
1224 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1225 internal_data0(shiftIn)
1226 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1228 if (amount == SSize) {
1231 if (amount < 2 * SSize) {
1232 return shiftIn.
shifted(amount - SSize);
1241 amount %= int(size());
1244 }
else if (amount < 0) {
1258 r.data1.load(&tmp[(amount + data0.size()) % size()],
Vc::Unaligned);
1261 auto &&d0cvtd = simd_cast<storage_type1>(data0);
1262 auto &&d1cvtd = simd_cast<storage_type0>(data1);
1263 constexpr
int size0 = storage_type0::size();
1264 constexpr
int size1 = storage_type1::size();
1266 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1267 return {std::move(d1cvtd), std::move(d0cvtd)};
1268 }
else if (amount < size1) {
1269 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1270 }
else if (amount == size1) {
1271 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1272 }
else if (
int(size()) - amount < size1) {
1273 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1274 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1275 }
else if (
int(size()) - amount == size1) {
1276 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1277 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1278 }
else if (amount <= size0) {
1279 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1280 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1282 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1283 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1291 Vc_INTRINSIC SimdArray interleaveLow(
const SimdArray &x)
const 1294 return {data0.interleaveLow(x.data0),
1295 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1298 Vc_INTRINSIC SimdArray interleaveHigh(
const SimdArray &x)
const 1300 return interleaveHighImpl(
1302 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1307 Vc_INTRINSIC SimdArray interleaveHighImpl(
const SimdArray &x, std::true_type)
const 1309 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1312 inline SimdArray interleaveHighImpl(
const SimdArray &x, std::false_type)
const 1314 return {data0.interleaveHigh(x.data0)
1315 .shifted(storage_type1::Size,
1316 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1317 data1.interleaveHigh(x.data1)};
1324 if (std::is_same<storage_type0, storage_type1>::value) {
1325 return {simd_cast<storage_type0>(data1).reversed(),
1326 simd_cast<storage_type1>(data0).reversed()};
1337 return {data0.shifted(storage_type1::Size, data1).reversed(),
1338 simd_cast<storage_type1>(data0.reversed().shifted(
1339 storage_type0::Size - storage_type1::Size))};
1347 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1351 Vc_INTRINSIC SimdArray sortedImpl(std::true_type)
const 1353 #ifdef Vc_DEBUG_SORTED 1354 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1356 const auto a = data0.sorted();
1357 const auto b = data1.sorted().reversed();
1358 const auto lo =
Vc::min(a, b);
1359 const auto hi =
Vc::max(a, b);
1360 return {lo.sorted(), hi.sorted()};
1364 Vc_INTRINSIC SimdArray sortedImpl(std::false_type)
const 1366 using SortableArray =
1368 auto sortable = simd_cast<SortableArray>(*this);
1369 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1370 using limits = std::numeric_limits<value_type>;
1371 if (limits::has_infinity) {
1372 sortable[i] = limits::infinity();
1377 return simd_cast<SimdArray>(sortable.sorted());
1411 static constexpr std::size_t Size = size();
1414 Vc_DEPRECATED(
"use exponent(x) instead") Vc_INTRINSIC SimdArray
exponent()
const 1420 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 1426 Vc_DEPRECATED(
"use copysign(x, y) instead") Vc_INTRINSIC SimdArray
1435 friend storage_type0 &internal_data0<>(SimdArray &x);
1436 friend storage_type1 &internal_data1<>(SimdArray &x);
1437 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1438 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1441 Vc_INTRINSIC SimdArray(storage_type0 &&x, storage_type1 &&y)
1442 : data0(std::move(x)), data1(std::move(y))
1446 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type0));
1452 alignas(
static_cast<std::size_t
>(
1453 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
1454 V::size()>::value)) storage_type0 data0;
1455 storage_type1 data1;
1457 #undef Vc_CURRENT_CLASS_NAME 1458 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1460 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1464 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1465 template <
typename MT,
typename IT>
1469 data0.
gather(mem, Split::lo(Common::Operations::gather(), indexes));
1470 data1.gather(mem, Split::hi(Common::Operations::gather(), indexes));
1472 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1473 template <
typename MT,
typename IT>
1478 data0.
gather(mem, Split::lo(Common::Operations::gather(), indexes), Split::lo(mask));
1479 data1.gather(mem, Split::hi(Common::Operations::gather(), indexes), Split::hi(mask));
1483 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1484 template <
typename MT,
typename IT>
1488 data0.
scatter(mem, Split::lo(Common::Operations::gather(),
1491 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1493 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1494 template <
typename MT,
typename IT>
1498 data0.
scatter(mem, Split::lo(Common::Operations::gather(), indexes),
1501 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1507 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1517 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1527 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1537 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1550 #if defined Vc_MSVC && defined Vc_IMPL_SSE 1554 : data0(x), data1(0)
1561 namespace result_vector_type_internal
1563 template <
typename T>
1564 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1566 template <
typename T>
1567 using is_integer_larger_than_int = std::integral_constant<
1568 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1569 std::is_same<T, long>::value ||
1570 std::is_same<T, unsigned long>::value)>;
1573 typename L,
typename R,
1579 && !std::is_same<type<L>, type<R>>::value
1582 ((std::is_arithmetic<type<L>>::value &&
1583 !is_integer_larger_than_int<type<L>>::value) ||
1584 (std::is_arithmetic<type<R>>::value &&
1585 !is_integer_larger_than_int<type<R>>::value)
1595 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1598 using LScalar = Traits::entry_type_of<L>;
1599 using RScalar = Traits::entry_type_of<R>;
1601 template <
bool B,
typename T,
typename F>
1602 using conditional =
typename std::conditional<B, T, F>::type;
1615 using type = SimdArray<
1616 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1617 sizeof(LScalar) <
sizeof(
int) &&
1618 sizeof(RScalar) <
sizeof(
int)),
1619 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1620 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1621 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1622 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1628 template <
typename L,
typename R>
1629 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1634 "result_vector_type does not work");
1636 #define Vc_BINARY_OPERATORS_(op_) \ 1638 template <typename L, typename R> \ 1639 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \ 1641 using Return = result_vector_type<L, R>; \ 1642 return Return(std::forward<L>(lhs)).operator op_(std::forward<R>(rhs)); \ 1661 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_);
1663 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_);
1665 #undef Vc_BINARY_OPERATORS_ 1666 #define Vc_BINARY_OPERATORS_(op_) \ 1668 template <typename L, typename R> \ 1669 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \ 1672 using Promote = result_vector_type<L, R>; \ 1673 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \ 1692 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_);
1695 #undef Vc_BINARY_OPERATORS_ 1698 #define Vc_FORWARD_UNARY_OPERATOR(name_) \ 1700 template <typename T, std::size_t N, typename V, std::size_t M> \ 1701 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \ 1703 return SimdArray<T, N, V, M>::fromOperation( \ 1704 Common::Operations::Forward_##name_(), x); \ 1706 Vc_NOTHING_EXPECTING_SEMICOLON 1708 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \ 1710 template <typename T, std::size_t N, typename V, std::size_t M> \ 1711 inline SimdMaskArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \ 1713 return SimdMaskArray<T, N, V, M>::fromOperation( \ 1714 Common::Operations::Forward_##name_(), x); \ 1716 Vc_NOTHING_EXPECTING_SEMICOLON 1718 #define Vc_FORWARD_BINARY_OPERATOR(name_) \ 1720 template <typename T, std::size_t N, typename V, std::size_t M> \ 1721 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x, \ 1722 const SimdArray<T, N, V, M> &y) \ 1724 return SimdArray<T, N, V, M>::fromOperation( \ 1725 Common::Operations::Forward_##name_(), x, y); \ 1727 Vc_NOTHING_EXPECTING_SEMICOLON 1733 Vc_FORWARD_UNARY_OPERATOR(
abs);
1740 Vc_FORWARD_UNARY_OPERATOR(
cos);
1741 Vc_FORWARD_UNARY_OPERATOR(
exp);
1745 template <
typename T, std::
size_t N>
1754 #if defined Vc_MSVC && defined Vc_IMPL_SSE 1756 const SimdArray<
double, 8, SSE::Vector<double>, 2> &x)
1758 using V = SSE::Vector<double>;
1763 internal_data(internal_data0(r0)) =
isnan(internal_data(internal_data0(x0)));
1764 internal_data(internal_data1(r0)) =
isnan(internal_data(internal_data1(x0)));
1765 internal_data(internal_data0(r1)) =
isnan(internal_data(internal_data0(x1)));
1766 internal_data(internal_data1(r1)) =
isnan(internal_data(internal_data1(x1)));
1767 return {std::move(r0), std::move(r1)};
1772 template <
typename T, std::
size_t N>
1778 template <
typename T, std::
size_t N>
1783 Vc_FORWARD_UNARY_OPERATOR(
log);
1789 Vc_FORWARD_UNARY_OPERATOR(
sin);
1791 template <
typename T, std::
size_t N>
1798 Vc_FORWARD_BINARY_OPERATOR(
min);
1799 Vc_FORWARD_BINARY_OPERATOR(
max);
1801 #undef Vc_FORWARD_UNARY_OPERATOR 1802 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR 1803 #undef Vc_FORWARD_BINARY_OPERATOR 1807 #define Vc_DUMMY_ARG0 , int = 0 1808 #define Vc_DUMMY_ARG1 , long = 0 1809 #define Vc_DUMMY_ARG2 , short = 0 1810 #define Vc_DUMMY_ARG3 , char = '0' 1811 #define Vc_DUMMY_ARG4 , unsigned = 0u 1812 #define Vc_DUMMY_ARG5 , unsigned short = 0u 1814 #define Vc_DUMMY_ARG0 1815 #define Vc_DUMMY_ARG1 1816 #define Vc_DUMMY_ARG2 1817 #define Vc_DUMMY_ARG3 1818 #define Vc_DUMMY_ARG4 1819 #define Vc_DUMMY_ARG5 1826 template <
typename Return, std::size_t N,
typename T,
typename... From>
1827 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1828 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1830 Return r = simd_cast<Return>(xs...);
1831 for (
size_t i = 0; i < N; ++i) {
1832 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1836 template <
typename Return, std::
size_t N,
typename T>
1837 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1839 Return r = Return();
1840 for (
size_t i = 0; i < N; ++i) {
1841 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1845 template <
typename Return, std::size_t N,
typename T,
typename... From>
1846 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1847 const From &... xs,
const T &last)
1849 Return r = simd_cast<Return>(xs...);
1850 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1851 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1855 template <
typename Return, std::
size_t N,
typename T>
1856 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1858 Return r = Return();
1859 for (
size_t i = 0; i < Return::size(); ++i) {
1860 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1866 template <
typename Return,
typename T,
typename... From>
1867 Vc_INTRINSIC_L Vc_CONST_L Return
1868 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1871 template <typename... Ts> struct are_all_types_equal;
1872 template <typename T>
1873 struct are_all_types_equal<T> : public
std::integral_constant<
bool, true>
1876 template <
typename T0,
typename T1,
typename... Ts>
1877 struct are_all_types_equal<T0, T1, Ts...>
1878 :
public std::integral_constant<
1879 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1903 template <
typename Return,
typename... Ts>
1904 Vc_INTRINSIC Vc_CONST Return
1905 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1909 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1910 Vc_INTRINSIC Vc_CONST
1911 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1912 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1914 template <
typename Return, std::
size_t offset,
typename From>
1915 Vc_INTRINSIC Vc_CONST
1916 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1917 simd_cast_with_offset(
const From &x);
1919 template <
typename Return, std::
size_t offset,
typename From>
1920 Vc_INTRINSIC Vc_CONST
1921 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1923 !Traits::isAtomicSimdArray<Return>::value) ||
1925 !Traits::isAtomicSimdMaskArray<Return>::value))),
1927 simd_cast_with_offset(
const From &x);
1929 template <
typename Return, std::
size_t offset,
typename From>
1930 Vc_INTRINSIC Vc_CONST
1931 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1933 Traits::isAtomicSimdArray<Return>::value) ||
1935 Traits::isAtomicSimdMaskArray<Return>::value))),
1937 simd_cast_with_offset(
const From &x);
1939 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1940 Vc_INTRINSIC Vc_CONST enable_if<
1941 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1942 simd_cast_with_offset(
const From &,
const Froms &... xs)
1944 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
1948 template <
typename Return, std::
size_t offset,
typename From>
1949 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
1956 template <
typename T,
typename... Ts>
struct first_type_of_impl
1960 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
1963 template <
typename Return,
typename From>
1964 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
1965 template <
typename Return,
typename... Froms>
1966 Vc_INTRINSIC Vc_CONST
1967 enable_if<(are_all_types_equal<Froms...>::value &&
1968 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1970 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
1974 template <
typename Return,
typename From,
typename... Froms>
1975 Vc_INTRINSIC Vc_CONST enable_if<
1976 (are_all_types_equal<From, Froms...>::value &&
1977 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1979 simd_cast_drop_arguments(Froms... xs, From x, From);
1980 template <
typename Return,
typename From>
1981 Vc_INTRINSIC Vc_CONST
1982 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1983 simd_cast_drop_arguments(From x, From);
1987 #ifdef Vc_DEBUG_SIMD_CAST 1988 void debugDoNothing(
const std::initializer_list<void *> &) {}
1989 template <
typename T0,
typename... Ts>
1990 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
1993 std::cerr << prefix << arg0;
1994 debugDoNothing({&(std::cerr <<
", " << args)...});
1995 std::cerr << suffix;
1998 template <
typename T0,
typename... Ts>
1999 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
2006 template <
size_t A,
size_t B>
2007 struct is_less :
public std::integral_constant<bool, (A < B)> {
2012 struct is_power_of_2 : public std::integral_constant<bool, ((N - 1) & N) == 0> {
2016 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2017 template <typename Return, typename T, typename A, typename... Froms> \
2018 Vc_INTRINSIC Vc_CONST enable_if< \
2019 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2020 is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2021 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2022 !detail::is_fixed_size_abi<A>::value), \
2024 simd_cast(NativeType_<T, A> x, Froms... xs) \
2026 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
2027 return {private_init, simd_cast<typename Return::storage_type>(x, xs...)}; \
2029 template <typename Return, typename T, typename A, typename... Froms> \
2030 Vc_INTRINSIC Vc_CONST enable_if< \
2031 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2032 !is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2033 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2034 !detail::is_fixed_size_abi<A>::value), \
2036 simd_cast(NativeType_<T, A> x, Froms... xs) \
2038 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
2039 return {simd_cast_without_last<Return, NativeType_<T, A>, Froms...>(x, xs...)}; \
2041 template <typename Return, typename T, typename A, typename... Froms> \
2042 Vc_INTRINSIC Vc_CONST \
2043 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2044 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2045 is_less<Common::left_size<Return::Size>(), \
2046 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2047 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2048 !detail::is_fixed_size_abi<A>::value), \
2050 simd_cast(NativeType_<T, A> x, Froms... xs) \
2052 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
2053 using R0 = typename Return::storage_type0; \
2054 using R1 = typename Return::storage_type1; \
2055 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
2056 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
2058 template <typename Return, typename T, typename A, typename... Froms> \
2059 Vc_INTRINSIC Vc_CONST \
2060 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2061 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2062 !is_less<Common::left_size<Return::Size>(), \
2063 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2064 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2065 !detail::is_fixed_size_abi<A>::value), \
2067 simd_cast(NativeType_<T, A> x, Froms... xs) \
2069 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
2070 using R0 = typename Return::storage_type0; \
2071 using R1 = typename Return::storage_type1; \
2072 return {simd_cast<R0>(x, xs...), R1::Zero()}; \
2074 Vc_NOTHING_EXPECTING_SEMICOLON
2076 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2077 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2078 #undef Vc_SIMDARRAY_CASTS
2081 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2083 template <typename Return, int offset, typename T, typename A> \
2084 Vc_INTRINSIC Vc_CONST \
2085 enable_if<Traits::isAtomic##SimdArrayType_<Return>::value, Return> \
2086 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG0) \
2088 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
2089 return {private_init, simd_cast<typename Return::storage_type, offset>(x)}; \
2092 template <typename Return, int offset, typename T, typename A> \
2093 Vc_INTRINSIC Vc_CONST \
2094 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2095 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2096 Return::Size * offset + Common::left_size<Return::Size>() < \
2097 NativeType_<T, A>::Size), \
2099 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG1) \
2101 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
2102 using R0 = typename Return::storage_type0; \
2103 constexpr int entries_offset = offset * Return::Size; \
2104 constexpr int entries_offset_right = entries_offset + R0::Size; \
2106 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
2107 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
2112 template <typename Return, int offset, typename T, typename A> \
2113 Vc_INTRINSIC Vc_CONST \
2114 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2115 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2116 Return::Size * offset + Common::left_size<Return::Size>() >= \
2117 NativeType_<T, A>::Size), \
2119 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG2) \
2121 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
2122 using R0 = typename Return::storage_type0; \
2123 using R1 = typename Return::storage_type1; \
2124 constexpr int entries_offset = offset * Return::Size; \
2125 return {simd_cast_with_offset<R0, entries_offset>(x), R1::Zero()}; \
2127 Vc_NOTHING_EXPECTING_SEMICOLON
2129 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2130 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2131 #undef Vc_SIMDARRAY_CASTS
2134 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
2136 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2137 Vc_INTRINSIC Vc_CONST \
2138 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2139 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
2140 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2142 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2144 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
2145 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
2148 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2149 Vc_INTRINSIC Vc_CONST \
2150 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2151 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
2152 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2154 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2156 vc_debug_(
"simd_cast{indivisible2}(",
")\n", x0, xs...); \
2157 return simd_cast_without_last<Return, \
2158 typename SimdArrayType_<T, N, V, N>::storage_type, \
2159 typename From::storage_type...>( \
2160 internal_data(x0), internal_data(xs)...); \
2163 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2165 Vc_INTRINSIC Vc_CONST enable_if< \
2166 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2167 !std::is_same<Return, SimdArrayType_<T, N, V, M>>::value && \
2168 is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2170 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2172 vc_debug_(
"simd_cast{bisectable}(",
")\n", x0, xs...); \
2173 return simd_cast_interleaved_argument_order< \
2174 Return,
typename SimdArrayType_<T, N, V, M>::storage_type0, \
2175 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
2176 internal_data1(x0), internal_data1(xs)...); \
2180 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2182 Vc_INTRINSIC Vc_CONST enable_if< \
2183 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2184 !is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2186 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2188 vc_debug_(
"simd_cast{bisectable2}(",
")\n", x0, xs...); \
2189 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
2193 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2195 Vc_INTRINSIC Vc_CONST enable_if< \
2196 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2197 N * (1 +
sizeof...(From)) <= Return::Size && !is_power_of_2<N>::value), \
2199 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2201 vc_debug_(
"simd_cast{remaining}(",
")\n", x0, xs...); \
2202 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
2203 From...>(x0, xs...); \
2206 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2208 Vc_INTRINSIC Vc_CONST enable_if< \
2209 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2210 N * (1 +
sizeof...(From)) > Return::Size && !is_power_of_2<N>::value), \
2212 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2214 vc_debug_(
"simd_cast{remaining2}(",
")\n", x0, xs...); \
2215 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
2216 From...>(x0, xs...); \
2219 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2220 Vc_INTRINSIC Vc_CONST \
2221 enable_if<(N != M && N >= 2 * Return::Size && is_power_of_2<N>::value), Return> \
2222 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2224 vc_debug_(
"simd_cast{single bisectable}(",
")\n", x); \
2225 return simd_cast<Return>(internal_data0(x)); \
2227 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2228 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
2229 N < 2 * Return::Size && is_power_of_2<N>::value), \
2231 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2233 vc_debug_(
"simd_cast{single bisectable2}(",
")\n", x); \
2234 return simd_cast<Return>(internal_data0(x), internal_data1(x)); \
2236 Vc_NOTHING_EXPECTING_SEMICOLON
2238 Vc_SIMDARRAY_CASTS(SimdArray);
2240 #undef Vc_SIMDARRAY_CASTS 2243 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \ 2245 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2247 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \ 2248 const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG0) \ 2250 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \ 2251 return simd_cast<Return>(x); \ 2254 template <typename Return, int offset, typename T, std::size_t N, typename V> \ 2255 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \ 2256 const SimdArrayType_<T, N, V, N> &x Vc_DUMMY_ARG1) \ 2258 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \ 2259 return simd_cast<Return, offset>(internal_data(x)); \ 2262 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2264 Vc_INTRINSIC Vc_CONST \ 2265 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2266 offset != 0 && Common::left_size<N>() % Return::Size == 0), \ 2268 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG2) \ 2270 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \ 2271 return simd_cast<Return, offset - Common::left_size<N>() / Return::Size>( \ 2272 internal_data1(x)); \ 2276 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2278 Vc_INTRINSIC Vc_CONST \ 2279 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2280 offset != 0 && Common::left_size<N>() % Return::Size != 0), \ 2282 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG3) \ 2284 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \ 2285 return simd_cast_with_offset<Return, \ 2286 offset * Return::Size - Common::left_size<N>()>( \ 2287 internal_data1(x)); \ 2290 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2292 Vc_INTRINSIC Vc_CONST enable_if< \ 2294 offset != 0 && (offset + 1) * Return::Size <= Common::left_size<N>()), \ 2296 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG4) \ 2298 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \ 2299 return simd_cast<Return, offset>(internal_data0(x)); \ 2302 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2304 Vc_INTRINSIC Vc_CONST \ 2305 enable_if<(N != M && (offset * Return::Size < Common::left_size<N>()) && \ 2306 offset != 0 && (offset + 1) * Return::Size > Common::left_size<N>()), \ 2308 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG5) \ 2310 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \ 2311 using R = typename Return::EntryType; \ 2312 Return r = Return::Zero(); \ 2313 for (std::size_t i = offset * Return::Size; \ 2314 i < std::min(N, (offset + 1) * Return::Size); ++i) { \ 2315 r[i - offset * Return::Size] = static_cast<R>(x[i]); \ 2319 Vc_NOTHING_EXPECTING_SEMICOLON 2320 Vc_SIMDARRAY_CASTS(SimdArray);
2322 #undef Vc_SIMDARRAY_CASTS 2324 template <
typename Return,
typename From>
2325 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
2327 return simd_cast<Return>(x);
2329 template <
typename Return,
typename... Froms>
2330 Vc_INTRINSIC Vc_CONST
2331 enable_if<(are_all_types_equal<Froms...>::value &&
2332 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2334 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
2336 return simd_cast<Return>(xs..., x);
2341 template <
typename Return,
typename From,
typename... Froms>
2342 Vc_INTRINSIC Vc_CONST enable_if<
2343 (are_all_types_equal<From, Froms...>::value &&
2344 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2346 simd_cast_drop_arguments(Froms... xs, From x, From)
2348 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
2350 template <
typename Return,
typename From>
2351 Vc_INTRINSIC Vc_CONST
2352 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2353 simd_cast_drop_arguments(From x, From)
2355 return simd_cast_drop_arguments<Return>(x);
2359 template <
typename Return, std::
size_t offset,
typename From>
2360 Vc_INTRINSIC Vc_CONST
2361 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
2362 Return> simd_cast_with_offset(
const From &x)
2364 return simd_cast<Return, offset / Return::Size>(x);
2366 template <
typename Return, std::
size_t offset,
typename From>
2367 Vc_INTRINSIC Vc_CONST
2368 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2370 !Traits::isAtomicSimdArray<Return>::value) ||
2372 !Traits::isAtomicSimdMaskArray<Return>::value))),
2374 simd_cast_with_offset(
const From &x)
2376 using R0 =
typename Return::storage_type0;
2377 using R1 =
typename Return::storage_type1;
2378 return {simd_cast_with_offset<R0, offset>(x),
2379 simd_cast_with_offset<R1, offset + R0::Size>(x)};
2381 template <
typename Return, std::
size_t offset,
typename From>
2382 Vc_INTRINSIC Vc_CONST
2383 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2385 Traits::isAtomicSimdArray<Return>::value) ||
2387 Traits::isAtomicSimdMaskArray<Return>::value))),
2389 simd_cast_with_offset(
const From &x)
2391 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
2393 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
2394 Vc_INTRINSIC Vc_CONST
2395 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
2396 simd_cast_with_offset(
const From &x,
const Froms &... xs)
2398 return simd_cast<Return>(x, xs...);
2402 template <
typename Return,
typename T,
typename... From>
2403 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
2405 return simd_cast<Return>(xs...);
2414 template <std::
size_t I,
typename T0>
2415 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
const T0 &)
2419 template <std::
size_t I,
typename T0>
2420 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
const T0 &b0)
2427 template <std::size_t I,
typename T0,
typename... Ts>
2428 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2436 template <std::size_t I,
typename T0,
typename... Ts>
2437 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2445 template <std::size_t I,
typename T0,
typename... Ts>
2446 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2451 return extract_interleaved<I - 2, Ts...>(a..., b...);
2454 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2455 Vc_INTRINSIC Vc_CONST Return
2456 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2459 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2463 template <
typename Return,
typename... Ts>
2464 Vc_INTRINSIC Vc_CONST Return
2465 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2467 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2468 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2472 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \ 2473 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \ 2475 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \ 2476 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \ 2478 lhs(mask) op_ rhs; \ 2480 Vc_NOTHING_EXPECTING_SEMICOLON 2481 Vc_CONDITIONAL_ASSIGN( Assign, =);
2482 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
2483 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
2484 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
2485 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
2486 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
2487 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
2488 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
2489 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
2490 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
2491 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
2492 #undef Vc_CONDITIONAL_ASSIGN 2494 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \ 2495 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \ 2496 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \ 2497 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \ 2501 Vc_NOTHING_EXPECTING_SEMICOLON 2502 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
2503 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
2504 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
2505 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
2506 #undef Vc_CONDITIONAL_ASSIGN 2510 template <
typename T,
size_t N,
typename V>
2511 inline void transpose_impl(
2516 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2517 &internal_data(*r[2]), &internal_data(*r[3])};
2518 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2519 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2520 internal_data(std::get<1>(proxy.in)),
2521 internal_data(std::get<2>(proxy.in)),
2522 internal_data(std::get<3>(proxy.in))});
2525 template <
typename T,
typename V>
2526 inline void transpose_impl(
2533 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2534 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2535 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2536 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2537 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2538 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2539 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2540 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2543 template <
typename T,
typename V>
2544 inline void transpose_impl(
2549 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2550 &internal_data(*r[2]), &internal_data(*r[3])};
2551 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2552 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2553 internal_data(std::get<1>(proxy.in)),
2554 internal_data(std::get<2>(proxy.in)),
2555 internal_data(std::get<3>(proxy.in))});
2558 template <
typename T,
size_t N,
typename V>
2559 inline void transpose_impl(
2567 transpose_impl(TransposeTag<2, 4>(), &r0[0],
2568 TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2569 internal_data0(std::get<1>(proxy.in)),
2570 internal_data0(std::get<2>(proxy.in)),
2571 internal_data0(std::get<3>(proxy.in))});
2572 transpose_impl(TransposeTag<2, 4>(), &r1[0],
2573 TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2574 internal_data1(std::get<1>(proxy.in)),
2575 internal_data1(std::get<2>(proxy.in)),
2576 internal_data1(std::get<3>(proxy.in))});
2626 template <
class T,
size_t N,
class V,
size_t VSizeof>
2627 struct InterleaveImpl<SimdArray<T, N, V, N>, N, VSizeof> {
2628 template <
class I,
class... VV>
2629 static Vc_INTRINSIC
void interleave(T *
const data,
const I &i,
const VV &... vv)
2633 template <
class I,
class... VV>
2634 static Vc_INTRINSIC
void deinterleave(T
const *
const data,
const I &i, VV &... vv)
2675 template <
typename T,
size_t N,
typename V,
size_t VN>
2676 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2683 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2685 return numeric_limits<T>::lowest();
2687 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2689 return numeric_limits<T>::epsilon();
2691 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2693 return numeric_limits<T>::round_error();
2695 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2697 return numeric_limits<T>::infinity();
2699 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2701 return numeric_limits<T>::quiet_NaN();
2703 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2705 return numeric_limits<T>::signaling_NaN();
2707 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2709 return numeric_limits<T>::denorm_min();
2715 #endif // VC_COMMON_SIMDARRAY_H_ SimdArray< T, N, V, M > ceil(const SimdArray< T, N, V, M > &x)
Applies the std:: ceil function component-wise and concurrently.
static SimdArray generate(const G &gen)
Generate a vector object from return values of gen (static variant of fill).
value_type operator[](size_t index) const noexcept
This operator can be used to read scalar entries of the vector.
SimdArray< T, N, V, M > floor(const SimdArray< T, N, V, M > &x)
Applies the std:: floor function component-wise and concurrently.
The main vector class for expressing data parallelism.
constexpr VectorSpecialInitializerIndexesFromZero IndexesFromZero
The special object Vc::IndexesFromZero can be used to construct Vector objects initialized to values ...
Vc::Vector< T > min(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
SimdArray rotated(int amount) const
Rotate vector entries to the left by amount.
std::ostream & operator<<(std::ostream &out, const Vc::Vector< T, Abi > &v)
Prints the contents of a vector into a stream object.
SimdArray< T, N, V, M > asin(const SimdArray< T, N, V, M > &x)
Applies the std:: asin function component-wise and concurrently.
UnalignedTag DefaultLoadTag
The default load tag type uses unaligned (non-streaming) loads.
SimdArray< T, N, V, M > rsqrt(const SimdArray< T, N, V, M > &x)
Applies the std:: rsqrt function component-wise and concurrently.
SimdArray apply(F &&f, const mask_type &k) const
As above, but skip the entries where mask is not set.
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Vc::Vector< T > max(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
Identifies any possible SimdArray<T, N> type (independent of const/volatile or reference) ...
SimdArray< T, N, V, M > log10(const SimdArray< T, N, V, M > &x)
Applies the std:: log10 function component-wise and concurrently.
SimdArray< T, N, V, M > min(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: min function component-wise and concurrently.
static SimdArray IndexesFromZero()
Returns a vector with the entries initialized to 0, 1, 2, 3, 4, 5, ...
SimdArray< T, N, V, M > max(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: max function component-wise and concurrently.
Identifies any possible SimdMaskArray<T, N> type (independent of const/volatile or reference) ...
SimdArray shifted(int amount) const
Shift vector entries to the left by amount; shifting in zeros.
Data-parallel arithmetic type with user-defined number of elements.
The value member will either be the number of SIMD vector entries or 0 if T is not a SIMD type...
SimdArray< T, N, V, M > sin(const SimdArray< T, N, V, M > &x)
Applies the std:: sin function component-wise and concurrently.
Data-parallel mask type with user-defined number of boolean elements.
SimdArray< T, N, V, M > exp(const SimdArray< T, N, V, M > &x)
Applies the std:: exp function component-wise and concurrently.
SimdArray< T, N, V, M > sqrt(const SimdArray< T, N, V, M > &x)
Applies the std:: sqrt function component-wise and concurrently.
SimdArray apply(F &&f) const
Call f on every entry of the vector and return the results as a new vector.
SimdArray< T, N, V, M > reciprocal(const SimdArray< T, N, V, M > &x)
Applies the std:: reciprocal function component-wise and concurrently.
void assign(SimdizeDetail::Adapter< S, T, N > &a, size_t i, const S &x)
Assigns one scalar object x to a SIMD slot at offset i in the simdized object a.
static SimdArray Zero()
Returns a vector with the entries initialized to zero.
Identifies any SIMD vector type (independent of implementation or whether it's SimdArray<T, N>).
SimdMaskArray< T, N, V, M > isnegative(const SimdArray< T, N, V, M > &x)
Applies the std:: isnegative function component-wise and concurrently.
Common::WriteMaskedVector< SimdArray, mask_type > operator()(const mask_type &mask)
Writemask the vector before an assignment.
SimdArray< T, N, V, M > abs(const SimdArray< T, N, V, M > &x)
Applies the std:: abs function component-wise and concurrently.
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
SimdArray< T, N, V, M > trunc(const SimdArray< T, N, V, M > &x)
Applies the std:: trunc function component-wise and concurrently.
Type trait that tells whether a container stores its data inside the object or inside allocated memor...
SimdArray< T, N, V, M > exponent(const SimdArray< T, N, V, M > &x)
Applies the std:: exponent function component-wise and concurrently.
static constexpr std::size_t size()
Returns N, the number of scalar components in an object of this type.
value_type EntryType
The type of the elements (i.e. T)
void deinterleave(V *a, V *b, const M *memory, A align)
SimdArray< T, N, V, M > copysign(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: copysign function component-wise and concurrently.
constexpr AlignedTag Aligned
Use this object for a flags parameter to request aligned loads and stores.
SimdArray operator+() const
Returns a copy of itself.
SimdArray< T, N, V, M > atan(const SimdArray< T, N, V, M > &x)
Applies the std:: atan function component-wise and concurrently.
void gather(const MT *mem, const IT &indexes)
Gather function.
SimdArray(value_type a)
Broadcast Constructor.
SimdArray< T, N, V, M > log2(const SimdArray< T, N, V, M > &x)
Applies the std:: log2 function component-wise and concurrently.
SimdMaskArray< T, N, V, M > isfinite(const SimdArray< T, N, V, M > &x)
Applies the std:: isfinite function component-wise and concurrently.
static SimdArray Random()
Returns a vector with pseudo-random entries.
SimdMaskArray< T, N, V, M > isnan(const SimdArray< T, N, V, M > &x)
Applies the std:: isnan function component-wise and concurrently.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
void scatter(MT *mem, IT &&indexes) const
Scatter function.
SimdArray< T, N, V, M > cos(const SimdArray< T, N, V, M > &x)
Applies the std:: cos function component-wise and concurrently.
T value_type
The type of the elements (i.e. T)
SimdArray< T, N > frexp(const SimdArray< T, N > &x, SimdArray< int, N > *e)
Applies the std::frexp function component-wise and concurrently.
SimdArray< T, N, V, M > log(const SimdArray< T, N, V, M > &x)
Applies the std:: log function component-wise and concurrently.
Vector Classes Namespace.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true...
std::pair< V, V > interleave(const V &a, const V &b)
Interleaves the entries from a and b into two vectors of the same type.
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
reference operator[](size_t i) noexcept
This operator can be used to modify scalar entries of the vector.
SimdArray< T, N, V, M > round(const SimdArray< T, N, V, M > &x)
Applies the std:: round function component-wise and concurrently.
void sincos(const SimdArray< T, N > &x, SimdArray< T, N > *sin, SimdArray< T, N > *cos)
Determines sine and cosine concurrently and component-wise on x.
SimdArray< T, N > fma(const SimdArray< T, N > &a, const SimdArray< T, N > &b, const SimdArray< T, N > &c)
Applies the std::fma function component-wise and concurrently.
SimdArray reversed() const
Returns a vector with all components reversed.
SimdArray< T, N > ldexp(const SimdArray< T, N > &x, const SimdArray< int, N > &e)
Applies the std::ldexp function component-wise and concurrently.
SimdArray copySign(const SimdArray &x) const
Copies the signs of the components of reference to the components of the current vector, returning the result.
static SimdArray One()
Returns a vector with the entries initialized to one.
SimdArray sorted() const
Return a sorted copy of the vector.
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
SimdArray< T, N, V, M > atan2(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: atan2 function component-wise and concurrently.
SimdMaskArray< T, N, V, M > isinf(const SimdArray< T, N, V, M > &x)
Applies the std:: isinf function component-wise and concurrently.