28 #ifndef VC_COMMON_SIMDARRAY_H_ 29 #define VC_COMMON_SIMDARRAY_H_ 33 #if defined Vc_DEBUG_SIMD_CAST || defined Vc_DEBUG_SORTED 39 #include "writemaskedvector.h" 40 #include "simdarrayhelper.h" 41 #include "simdmaskarray.h" 43 #include "interleave.h" 44 #include "indexsequence.h" 45 #include "transpose.h" 48 namespace Vc_VERSIONED_NAMESPACE
53 template <
typename T> T Vc_INTRINSIC Vc_PURE product_helper_(
const T &l,
const T &r) {
return l * r; }
54 template <
typename T> T Vc_INTRINSIC Vc_PURE sum_helper_(
const T &l,
const T &r) {
return l + r; }
58 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
59 inline SimdArray<T, N, V, M>
min(
const SimdArray<T, N, V, M> &x,
60 const SimdArray<T, N, V, M> &y);
61 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
62 inline SimdArray<T, N, V, M>
max(
const SimdArray<T, N, V, M> &x,
63 const SimdArray<T, N, V, M> &y);
70 #define Vc_CURRENT_CLASS_NAME SimdArray 80 template <
typename T, std::
size_t N,
typename VectorType_>
81 class SimdArray<T, N, VectorType_, N>
83 static_assert(std::is_same<T, double>::value || std::is_same<T, float>::value ||
84 std::is_same<T, int32_t>::value ||
85 std::is_same<T, uint32_t>::value ||
86 std::is_same<T, int16_t>::value ||
87 std::is_same<T, uint16_t>::value,
88 "SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, " 89 "int16_t, uint16_t }");
92 using VectorType = VectorType_;
93 using vector_type = VectorType;
94 using storage_type = vector_type;
95 using vectorentry_type =
typename vector_type::VectorEntryType;
97 using mask_type = SimdMaskArray<T, N, vector_type>;
98 using index_type = SimdArray<int, N>;
99 static constexpr std::size_t size() {
return N; }
103 using VectorEntryType = vectorentry_type;
107 using reference = Detail::ElementReference<SimdArray>;
108 static constexpr std::size_t Size = size();
112 #ifndef Vc_MSVC // bogus error C2580 124 Vc_INTRINSIC SimdArray(
value_type &&a) : data(a) {}
127 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
128 Vc_INTRINSIC SimdArray(U a)
129 : SimdArray(static_cast<value_type>(a))
134 template <
typename U,
typename V>
135 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x, enable_if<N == V::Size> = nullarg)
136 : data(simd_cast<vector_type>(internal_data(x)))
139 template <
typename U,
typename V>
141 enable_if<(N > V::Size && N <= 2 * V::Size)> = nullarg)
142 : data(simd_cast<vector_type>(internal_data(internal_data0(x)), internal_data(internal_data1(x))))
145 template <
typename U,
typename V>
147 enable_if<(N > 2 * V::Size && N <= 4 * V::Size)> = nullarg)
148 : data(simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
149 internal_data(internal_data1(internal_data0(x))),
150 internal_data(internal_data0(internal_data1(x))),
151 internal_data(internal_data1(internal_data1(x)))))
155 template <
typename V, std::
size_t Pieces, std::
size_t Index>
156 Vc_INTRINSIC SimdArray(Common::Segment<V, Pieces, Index> &&x)
157 : data(simd_cast<vector_type, Index>(x.data))
161 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
164 #if defined Vc_CXX14 && 0 // doesn't compile yet 165 static_assert(init.size() == size(),
"The initializer_list argument to " 166 "SimdArray<T, N> must contain exactly N " 169 Vc_ASSERT(init.size() == size());
177 explicit Vc_INTRINSIC SimdArray(
const V &x)
178 : data(simd_cast<vector_type>(x))
185 typename U,
typename A,
192 #include "gatherinterface.h" 193 #include "scatterinterface.h" 196 template <
typename... Args,
197 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
198 !Traits::is_gather_signature<Args...>::value &&
199 !Traits::is_initializer_list<Args...>::value>>
200 explicit Vc_INTRINSIC SimdArray(Args &&... args)
201 : data(
std::forward<Args>(args)...)
205 template <std::
size_t Offset>
206 explicit Vc_INTRINSIC SimdArray(
207 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
213 Vc_INTRINSIC
void setZero() { data.setZero(); }
214 Vc_INTRINSIC
void setZero(
mask_type k) { data.setZero(internal_data(k)); }
215 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
216 Vc_INTRINSIC
void setZeroInverted(
mask_type k) { data.setZeroInverted(internal_data(k)); }
218 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
219 Vc_INTRINSIC
void setQnan(
mask_type m) { data.setQnan(internal_data(m)); }
222 template <
typename Op,
typename... Args>
223 static Vc_INTRINSIC
SimdArray fromOperation(Op op, Args &&... args)
226 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
230 template <
typename Op,
typename... Args>
231 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
233 Common::unpackArgumentsAuto(op,
nullptr, std::forward<Args>(args)...);
250 return fromOperation(Common::Operations::random());
253 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
255 data.load(std::forward<Args>(args)...);
258 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const 260 data.store(std::forward<Args>(args)...);
281 template <
typename U,
282 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
287 template <
typename U,
288 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
294 template <
typename U,
295 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
296 Vc_INTRINSIC Vc_CONST
SimdArray operator>>(U x)
const 300 template <
typename U,
301 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
308 #define Vc_BINARY_OPERATOR_(op) \ 309 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \ 311 return {data op rhs.data}; \ 313 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \ 315 data op## = rhs.data; \ 318 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
319 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
320 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
321 #undef Vc_BINARY_OPERATOR_ 323 #define Vc_COMPARES(op) \ 324 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \ 326 return {data op rhs.data}; \ 328 Vc_ALL_COMPARES(Vc_COMPARES);
332 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 343 template <
typename U>
344 Vc_INTRINSIC
static void set(
SimdArray &o,
int i, U &&v) noexcept(
345 noexcept(std::declval<value_type &>() = v))
351 Vc_INTRINSIC reference operator[](
size_t i) noexcept
353 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
354 return {*
this, int(i)};
356 Vc_INTRINSIC
value_type operator[](
size_t i)
const noexcept
358 return get(*
this, int(i));
361 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
368 data.assign(v.data, internal_data(k));
372 #define Vc_REDUCTION_FUNCTION_(name_) \ 373 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \ 374 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \ 376 return data.name_(internal_data(mask)); \ 378 Vc_NOTHING_EXPECTING_SEMICOLON 379 Vc_REDUCTION_FUNCTION_(
min);
380 Vc_REDUCTION_FUNCTION_(
max);
381 Vc_REDUCTION_FUNCTION_(product);
382 Vc_REDUCTION_FUNCTION_(sum);
383 #undef Vc_REDUCTION_FUNCTION_ 386 template <
typename F> Vc_INTRINSIC
SimdArray apply(F &&f)
const 388 return {data.
apply(std::forward<F>(f))};
392 return {data.
apply(std::forward<F>(f), k)};
397 return {data.shifted(amount)};
400 template <std::
size_t NN>
404 return {data.shifted(amount, simd_cast<VectorType>(shiftIn))};
407 Vc_INTRINSIC
SimdArray rotated(
int amount)
const 420 return {data.interleaveLow(x.data)};
424 return {data.interleaveHigh(x.data)};
437 template <
typename G>
static Vc_INTRINSIC
SimdArray generate(
const G &gen)
439 return {VectorType::generate(gen)};
442 Vc_DEPRECATED(
"use copysign(x, y) instead") Vc_INTRINSIC
SimdArray 443 copySign(
const SimdArray &reference)
const 448 friend VectorType &internal_data<>(
SimdArray &x);
449 friend const VectorType &internal_data<>(
const SimdArray &x);
452 Vc_INTRINSIC
SimdArray(VectorType &&x) : data(std::move(x)) {}
454 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type));
460 alignas(
static_cast<std::size_t
>(
461 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
462 VectorType_::size()>::value)) storage_type data;
465 template <
typename T, std::
size_t N,
typename VectorType>
467 template <
typename T, std::
size_t N,
typename VectorType>
475 template <
typename T, std::
size_t N,
typename VectorType>
485 template <
typename T> T unpackIfSegment(T &&x) {
return std::forward<T>(x); }
486 template <
typename T,
size_t Pieces,
size_t Index>
487 auto unpackIfSegment(Common::Segment<T, Pieces, Index> &&x) -> decltype(x.asSimdArray())
489 return x.asSimdArray();
493 template <
typename T, std::
size_t N,
typename VectorType>
494 template <
typename MT,
typename IT>
498 data.
gather(mem, unpackIfSegment(std::forward<IT>(indexes)));
500 template <
typename T, std::
size_t N,
typename VectorType>
501 template <
typename MT,
typename IT>
506 data.
gather(mem, unpackIfSegment(std::forward<IT>(indexes)), mask);
510 template <
typename T, std::
size_t N,
typename VectorType>
511 template <
typename MT,
typename IT>
515 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)));
517 template <
typename T, std::
size_t N,
typename VectorType>
518 template <
typename MT,
typename IT>
523 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)), mask);
559 template <
typename T,
size_t N,
typename V,
size_t Wt>
class SimdArray
561 static_assert(std::is_same<T, double>::value ||
562 std::is_same<T, float>::value ||
563 std::is_same<T, int32_t>::value ||
564 std::is_same<T, uint32_t>::value ||
565 std::is_same<T, int16_t>::value ||
566 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 }");
569 std::is_same<typename V::EntryType, typename V::VectorEntryType>::value ||
571 (N % V::size() == 0),
572 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * " 573 "MIC::(u)short_v::size(), i.e. k * 16.");
575 using my_traits = SimdArrayTraits<T, N>;
576 static constexpr std::size_t N0 = my_traits::N0;
577 static constexpr std::size_t N1 = my_traits::N1;
578 using Split = Common::Split<N0>;
579 template <
typename U, std::
size_t K>
using CArray = U[K];
584 static_assert(storage_type0::size() == N0,
"");
589 using vector_type = V;
590 using vectorentry_type =
typename storage_type0::vectorentry_type;
591 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
612 static constexpr std::size_t
size() {
return N; }
619 using VectorEntryType = vectorentry_type;
624 using AsArg =
const SimdArray &;
626 using reference = Detail::ElementReference<SimdArray>;
638 static Vc_INTRINSIC SimdArray
Zero()
644 static Vc_INTRINSIC SimdArray
One()
658 return fromOperation(Common::Operations::random());
662 template <
typename G>
static Vc_INTRINSIC SimdArray
generate(
const G &gen)
664 auto tmp = storage_type0::generate(gen);
669 return {std::move(tmp),
670 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
678 #ifndef Vc_MSVC // bogus error C2580 679 SimdArray() =
default;
690 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
692 : SimdArray(static_cast<value_type>(a))
698 SimdArray(
const SimdArray &) =
default;
699 SimdArray(SimdArray &&) =
default;
700 SimdArray &operator=(
const SimdArray &) =
default;
703 template <
typename U,
705 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
706 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
707 : data0(mem, f), data1(mem + storage_type0::size(), f)
719 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
720 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
721 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
722 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
728 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
729 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
730 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
731 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
737 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
741 #if defined Vc_CXX14 && 0 // doesn't compile yet 742 static_assert(init.size() == size(),
"The initializer_list argument to " 743 "SimdArray<T, N> must contain exactly N " 746 Vc_ASSERT(init.size() == size());
750 #include "gatherinterface.h" 751 #include "scatterinterface.h" 754 template <
typename... Args,
755 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
756 !Traits::is_initializer_list<Args...>::value &&
757 !Traits::is_gather_signature<Args...>::value &&
758 !Traits::is_load_arguments<Args...>::value>>
759 explicit Vc_INTRINSIC SimdArray(Args &&... args)
760 : data0(Split::lo(args)...)
762 , data1(Split::hi(std::forward<Args>(args))...)
767 template <
typename W>
768 Vc_INTRINSIC
explicit SimdArray(
771 !(std::is_convertible<Traits::entry_type_of<W>, T>::value &&
773 : data0(Split::lo(x)), data1(Split::hi(x))
778 template <
typename W>
779 Vc_INTRINSIC SimdArray(
782 std::is_convertible<Traits::entry_type_of<W>, T>::value)> = nullarg)
783 : data0(Split::lo(x)), data1(Split::hi(x))
790 typename U,
typename A,
799 Vc_INTRINSIC
void setZero()
804 Vc_INTRINSIC
void setZero(
const mask_type &k)
806 data0.setZero(Split::lo(k));
807 data1.setZero(Split::hi(k));
809 Vc_INTRINSIC
void setZeroInverted()
811 data0.setZeroInverted();
812 data1.setZeroInverted();
814 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
816 data0.setZeroInverted(Split::lo(k));
817 data1.setZeroInverted(Split::hi(k));
821 Vc_INTRINSIC
void setQnan() {
825 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
826 data0.setQnan(Split::lo(m));
827 data1.setQnan(Split::hi(m));
831 template <
typename Op,
typename... Args>
832 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
835 storage_type0::fromOperation(op, Split::lo(args)...),
838 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
843 template <
typename Op,
typename... Args>
844 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
846 storage_type0::callOperation(op, Split::lo(args)...);
847 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
851 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
853 data0.load(mem, Split::lo(args)...);
855 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
858 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const 860 data0.store(mem, Split::lo(args)...);
862 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
867 return {!data0, !data1};
872 return {-data0, -data1};
876 Vc_INTRINSIC SimdArray
operator+()
const {
return *
this; }
878 Vc_INTRINSIC SimdArray operator~()
const 880 return {~data0, ~data1};
884 template <
typename U,
885 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
886 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const 888 return {data0 << x, data1 << x};
890 template <
typename U,
891 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
892 Vc_INTRINSIC SimdArray &operator<<=(U x)
898 template <
typename U,
899 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
900 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const 902 return {data0 >> x, data1 >> x};
904 template <
typename U,
905 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
906 Vc_INTRINSIC SimdArray &operator>>=(U x)
914 #define Vc_BINARY_OPERATOR_(op) \ 915 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \ 917 return {data0 op rhs.data0, data1 op rhs.data1}; \ 919 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \ 921 data0 op## = rhs.data0; \ 922 data1 op## = rhs.data1; \ 925 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
926 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
927 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
928 #undef Vc_BINARY_OPERATOR_ 930 #define Vc_COMPARES(op) \ 931 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \ 933 return {data0 op rhs.data0, data1 op rhs.data1}; \ 935 Vc_ALL_COMPARES(Vc_COMPARES);
944 Vc_INTRINSIC
static value_type get(
const SimdArray &o,
int i) noexcept
946 return reinterpret_cast<const alias_type *
>(&o)[i];
948 template <
typename U>
949 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
950 noexcept(std::declval<value_type &>() = v))
952 reinterpret_cast<alias_type *
>(&o)[i] = v;
959 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
960 return {*
this, int(i)};
966 return get(*
this, int(index));
972 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type>
operator()(
975 return {*
this, mask};
981 data0.assign(v.data0, internal_data0(k));
982 data1.assign(v.data1, internal_data1(k));
986 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \ 988 template <typename ForSfinae = void> \ 989 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 990 storage_type0::Size == storage_type1::Size, \ 991 value_type> name_##_impl() const \ 993 return binary_fun_(data0, data1).name_(); \ 996 template <typename ForSfinae = void> \ 997 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 998 storage_type0::Size != storage_type1::Size, \ 999 value_type> name_##_impl() const \ 1001 return scalar_fun_(data0.name_(), data1.name_()); \ 1006 Vc_INTRINSIC value_type name_() const { return name_##_impl(); } \ 1008 Vc_INTRINSIC value_type name_(const mask_type &mask) const \ 1010 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \ 1011 return data1.name_(Split::hi(mask)); \ 1012 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \ 1013 return data0.name_(Split::lo(mask)); \ 1015 return scalar_fun_(data0.name_(Split::lo(mask)), \ 1016 data1.name_(Split::hi(mask))); \ 1019 Vc_NOTHING_EXPECTING_SEMICOLON 1022 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_);
1023 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_);
1024 #undef Vc_REDUCTION_FUNCTION_ 1025 Vc_INTRINSIC Vc_PURE SimdArray partialSum() const
1028 auto ps0 = data0.partialSum();
1030 tmp[0] += ps0[data0.size() - 1];
1031 return {std::move(ps0), tmp.partialSum()};
1036 template <
typename F>
inline SimdArray
apply(F &&f)
const 1043 return {data0.
apply(f, Split::lo(k)), data1.
apply(f, Split::hi(k))};
1050 constexpr
int SSize = Size;
1051 constexpr
int SSize0 = storage_type0::Size;
1052 constexpr
int SSize1 = storage_type1::Size;
1057 if (amount > -SSize0) {
1060 if (amount == -SSize0) {
1063 if (amount < -SSize0) {
1069 if (amount >= SSize) {
1071 }
else if (amount >= SSize0) {
1073 simd_cast<storage_type0>(data1).
shifted(amount - SSize0),
1075 }
else if (amount >= SSize1) {
1078 return {data0.shifted(amount, data1), data1.shifted(amount)};
1083 template <std::
size_t NN>
1085 !(std::is_same<storage_type0, storage_type1>::value &&
1090 constexpr
int SSize = Size;
1092 return SimdArray::generate([&](
int i) ->
value_type {
1095 return operator[](i);
1096 }
else if (i >= -SSize) {
1097 return shiftIn[i + SSize];
1102 return SimdArray::generate([&](
int i) ->
value_type {
1105 return operator[](i);
1106 }
else if (i < 2 * SSize) {
1107 return shiftIn[i - SSize];
1116 template <std::
size_t NN>
struct bisectable_shift
1117 :
public std::integral_constant<bool,
1118 std::is_same<storage_type0, storage_type1>::value &&
1124 template <std::
size_t NN>
1125 inline SimdArray
shifted(enable_if<bisectable_shift<NN>::value,
int> amount,
1128 constexpr
int SSize = Size;
1130 if (amount > -static_cast<int>(storage_type0::Size)) {
1131 return {data0.shifted(amount, internal_data1(shiftIn)),
1132 data1.shifted(amount, data0)};
1134 if (amount == -static_cast<int>(storage_type0::Size)) {
1135 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
1137 if (amount > -SSize) {
1139 internal_data1(shiftIn)
1140 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1141 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1143 if (amount == -SSize) {
1146 if (amount > -2 * SSize) {
1147 return shiftIn.shifted(amount + SSize);
1153 if (amount < static_cast<int>(storage_type0::Size)) {
1154 return {data0.shifted(amount, data1),
1155 data1.shifted(amount, internal_data0(shiftIn))};
1157 if (amount == static_cast<int>(storage_type0::Size)) {
1158 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1160 if (amount < SSize) {
1161 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1162 internal_data0(shiftIn)
1163 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1165 if (amount == SSize) {
1168 if (amount < 2 * SSize) {
1169 return shiftIn.shifted(amount - SSize);
1178 amount %= int(size());
1181 }
else if (amount < 0) {
1195 r.data1.load(&tmp[(amount + data0.size()) % size()],
Vc::Unaligned);
1198 auto &&d0cvtd = simd_cast<storage_type1>(data0);
1199 auto &&d1cvtd = simd_cast<storage_type0>(data1);
1200 constexpr
int size0 = storage_type0::size();
1201 constexpr
int size1 = storage_type1::size();
1203 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1204 return {std::move(d1cvtd), std::move(d0cvtd)};
1205 }
else if (amount < size1) {
1206 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1207 }
else if (amount == size1) {
1208 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1209 }
else if (
int(size()) - amount < size1) {
1210 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1211 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1212 }
else if (
int(size()) - amount == size1) {
1213 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1214 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1215 }
else if (amount <= size0) {
1216 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1217 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1219 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1220 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1228 Vc_INTRINSIC SimdArray interleaveLow(
const SimdArray &x)
const 1231 return {data0.interleaveLow(x.data0),
1232 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1235 Vc_INTRINSIC SimdArray interleaveHigh(
const SimdArray &x)
const 1237 return interleaveHighImpl(
1239 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1244 Vc_INTRINSIC SimdArray interleaveHighImpl(
const SimdArray &x, std::true_type)
const 1246 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1249 inline SimdArray interleaveHighImpl(
const SimdArray &x, std::false_type)
const 1251 return {data0.interleaveHigh(x.data0)
1252 .shifted(storage_type1::Size,
1253 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1254 data1.interleaveHigh(x.data1)};
1261 if (std::is_same<storage_type0, storage_type1>::value) {
1262 return {simd_cast<storage_type0>(data1).reversed(),
1263 simd_cast<storage_type1>(data0).reversed()};
1274 return {data0.shifted(storage_type1::Size, data1).reversed(),
1275 simd_cast<storage_type1>(data0.reversed().shifted(
1276 storage_type0::Size - storage_type1::Size))};
1284 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1288 Vc_INTRINSIC SimdArray sortedImpl(std::true_type)
const 1290 #ifdef Vc_DEBUG_SORTED 1291 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1293 const auto a = data0.sorted();
1294 const auto b = data1.sorted().reversed();
1295 const auto lo =
Vc::min(a, b);
1296 const auto hi =
Vc::max(a, b);
1297 return {lo.sorted(), hi.sorted()};
1301 Vc_INTRINSIC SimdArray sortedImpl(std::false_type)
const 1303 using SortableArray =
1305 auto sortable = simd_cast<SortableArray>(*this);
1306 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1307 using limits = std::numeric_limits<value_type>;
1308 if (limits::has_infinity) {
1309 sortable[i] = limits::infinity();
1314 return simd_cast<SimdArray>(sortable.sorted());
1348 static constexpr std::size_t Size = size();
1351 Vc_DEPRECATED(
"use exponent(x) instead") Vc_INTRINSIC SimdArray
exponent()
const 1357 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 1363 Vc_DEPRECATED(
"use copysign(x, y) instead") Vc_INTRINSIC SimdArray
1372 friend storage_type0 &internal_data0<>(SimdArray &x);
1373 friend storage_type1 &internal_data1<>(SimdArray &x);
1374 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1375 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1378 Vc_INTRINSIC SimdArray(storage_type0 &&x, storage_type1 &&y)
1379 : data0(std::move(x)), data1(std::move(y))
1383 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type0));
1389 alignas(
static_cast<std::size_t
>(
1390 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
1391 V::size()>::value)) storage_type0 data0;
1392 storage_type1 data1;
1394 #undef Vc_CURRENT_CLASS_NAME 1395 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1397 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1401 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1402 template <
typename MT,
typename IT>
1406 data0.
gather(mem, Split::lo(Common::Operations::gather(),
1409 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1411 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1412 template <
typename MT,
typename IT>
1416 data0.
gather(mem, Split::lo(Common::Operations::gather(), indexes),
1419 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1424 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1425 template <
typename MT,
typename IT>
1429 data0.
scatter(mem, Split::lo(Common::Operations::gather(),
1432 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1434 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1435 template <
typename MT,
typename IT>
1439 data0.
scatter(mem, Split::lo(Common::Operations::gather(), indexes),
1442 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1448 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1458 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1468 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1478 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1491 #if defined Vc_MSVC && defined Vc_IMPL_SSE 1495 : data0(x), data1(0)
1502 namespace result_vector_type_internal
1504 template <
typename T>
1505 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1507 template <
typename T>
1508 using is_integer_larger_than_int = std::integral_constant<
1509 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1510 std::is_same<T, long>::value ||
1511 std::is_same<T, unsigned long>::value)>;
1514 typename L,
typename R,
1520 && !std::is_same<type<L>, type<R>>::value
1523 ((std::is_arithmetic<type<L>>::value &&
1524 !is_integer_larger_than_int<type<L>>::value) ||
1525 (std::is_arithmetic<type<R>>::value &&
1526 !is_integer_larger_than_int<type<R>>::value)
1536 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1539 using LScalar = Traits::entry_type_of<L>;
1540 using RScalar = Traits::entry_type_of<R>;
1542 template <
bool B,
typename True,
typename False>
1543 using conditional =
typename std::conditional<B, True, False>::type;
1556 using type = SimdArray<
1557 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1558 sizeof(LScalar) <
sizeof(
int) &&
1559 sizeof(RScalar) <
sizeof(
int)),
1560 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1561 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1562 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1563 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1569 template <
typename L,
typename R>
1570 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1575 "result_vector_type does not work");
1577 #define Vc_BINARY_OPERATORS_(op_) \ 1579 template <typename L, typename R> \ 1580 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \ 1582 using Return = result_vector_type<L, R>; \ 1583 return Return(std::forward<L>(lhs)) op_ Return(std::forward<R>(rhs)); \ 1602 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_);
1604 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_);
1606 #undef Vc_BINARY_OPERATORS_ 1607 #define Vc_BINARY_OPERATORS_(op_) \ 1609 template <typename L, typename R> \ 1610 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \ 1613 using Promote = result_vector_type<L, R>; \ 1614 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \ 1633 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_);
1636 #undef Vc_BINARY_OPERATORS_ 1639 #define Vc_FORWARD_UNARY_OPERATOR(name_) \ 1641 template <typename T, std::size_t N, typename V, std::size_t M> \ 1642 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \ 1644 return SimdArray<T, N, V, M>::fromOperation( \ 1645 Common::Operations::Forward_##name_(), x); \ 1647 Vc_NOTHING_EXPECTING_SEMICOLON 1649 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \ 1651 template <typename T, std::size_t N, typename V, std::size_t M> \ 1652 inline SimdMaskArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \ 1654 return SimdMaskArray<T, N, V, M>::fromOperation( \ 1655 Common::Operations::Forward_##name_(), x); \ 1657 Vc_NOTHING_EXPECTING_SEMICOLON 1659 #define Vc_FORWARD_BINARY_OPERATOR(name_) \ 1661 template <typename T, std::size_t N, typename V, std::size_t M> \ 1662 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x, \ 1663 const SimdArray<T, N, V, M> &y) \ 1665 return SimdArray<T, N, V, M>::fromOperation( \ 1666 Common::Operations::Forward_##name_(), x, y); \ 1668 Vc_NOTHING_EXPECTING_SEMICOLON 1674 Vc_FORWARD_UNARY_OPERATOR(
abs);
1681 Vc_FORWARD_UNARY_OPERATOR(
cos);
1682 Vc_FORWARD_UNARY_OPERATOR(
exp);
1686 template <
typename T, std::
size_t N>
1695 #if defined Vc_MSVC && defined Vc_IMPL_SSE 1697 const SimdArray<
double, 8, SSE::Vector<double>, 2> &x)
1699 using V = SSE::Vector<double>;
1704 internal_data(internal_data0(r0)) =
isnan(internal_data(internal_data0(x0)));
1705 internal_data(internal_data1(r0)) =
isnan(internal_data(internal_data1(x0)));
1706 internal_data(internal_data0(r1)) =
isnan(internal_data(internal_data0(x1)));
1707 internal_data(internal_data1(r1)) =
isnan(internal_data(internal_data1(x1)));
1708 return {std::move(r0), std::move(r1)};
1713 template <
typename T, std::
size_t N>
1719 template <
typename T, std::
size_t N>
1724 Vc_FORWARD_UNARY_OPERATOR(
log);
1730 Vc_FORWARD_UNARY_OPERATOR(
sin);
1732 template <
typename T, std::
size_t N>
1739 Vc_FORWARD_BINARY_OPERATOR(
min);
1740 Vc_FORWARD_BINARY_OPERATOR(
max);
1742 #undef Vc_FORWARD_UNARY_OPERATOR 1743 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR 1744 #undef Vc_FORWARD_BINARY_OPERATOR 1748 #define Vc_DUMMY_ARG0 , int = 0 1749 #define Vc_DUMMY_ARG1 , long = 0 1750 #define Vc_DUMMY_ARG2 , short = 0 1751 #define Vc_DUMMY_ARG3 , char = '0' 1752 #define Vc_DUMMY_ARG4 , unsigned = 0u 1753 #define Vc_DUMMY_ARG5 , unsigned short = 0u 1755 #define Vc_DUMMY_ARG0 1756 #define Vc_DUMMY_ARG1 1757 #define Vc_DUMMY_ARG2 1758 #define Vc_DUMMY_ARG3 1759 #define Vc_DUMMY_ARG4 1760 #define Vc_DUMMY_ARG5 1767 template <
typename Return, std::size_t N,
typename T,
typename... From>
1768 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1769 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1772 for (
size_t i = 0; i < N; ++i) {
1773 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1777 template <
typename Return, std::
size_t N,
typename T>
1778 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1780 Return r = Return();
1781 for (
size_t i = 0; i < N; ++i) {
1782 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1786 template <
typename Return, std::size_t N,
typename T,
typename... From>
1787 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1788 const From &... xs,
const T &last)
1791 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1792 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1796 template <
typename Return, std::
size_t N,
typename T>
1797 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1799 Return r = Return();
1800 for (
size_t i = 0; i < Return::size(); ++i) {
1801 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1807 template <
typename Return,
typename T,
typename... From>
1808 Vc_INTRINSIC_L Vc_CONST_L Return
1809 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1812 template <typename... Ts> struct are_all_types_equal;
1813 template <typename T>
1814 struct are_all_types_equal<T> : public
std::integral_constant<
bool, true>
1817 template <
typename T0,
typename T1,
typename... Ts>
1818 struct are_all_types_equal<T0, T1, Ts...>
1819 :
public std::integral_constant<
1820 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1844 template <
typename Return,
typename... Ts>
1845 Vc_INTRINSIC Vc_CONST Return
1846 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1850 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1851 Vc_INTRINSIC Vc_CONST
1852 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1853 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1855 template <
typename Return, std::
size_t offset,
typename From>
1856 Vc_INTRINSIC Vc_CONST
1857 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1858 simd_cast_with_offset(
const From &x);
1860 template <
typename Return, std::
size_t offset,
typename From>
1861 Vc_INTRINSIC Vc_CONST
1862 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1864 !Traits::isAtomicSimdArray<Return>::value) ||
1866 !Traits::isAtomicSimdMaskArray<Return>::value))),
1868 simd_cast_with_offset(
const From &x);
1870 template <
typename Return, std::
size_t offset,
typename From>
1871 Vc_INTRINSIC Vc_CONST
1872 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1874 Traits::isAtomicSimdArray<Return>::value) ||
1876 Traits::isAtomicSimdMaskArray<Return>::value))),
1878 simd_cast_with_offset(
const From &x);
1880 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1881 Vc_INTRINSIC Vc_CONST enable_if<
1882 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1883 simd_cast_with_offset(
const From &,
const Froms &... xs)
1885 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
1889 template <
typename Return, std::
size_t offset,
typename From>
1890 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
1897 template <
typename T,
typename... Ts>
struct first_type_of_impl
1901 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
1904 template <
typename Return,
typename From>
1905 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
1906 template <
typename Return,
typename... Froms>
1907 Vc_INTRINSIC Vc_CONST
1908 enable_if<(are_all_types_equal<Froms...>::value &&
1909 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1911 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
1915 template <
typename Return,
typename From,
typename... Froms>
1916 Vc_INTRINSIC Vc_CONST enable_if<
1917 (are_all_types_equal<From, Froms...>::value &&
1918 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1920 simd_cast_drop_arguments(Froms... xs, From x, From);
1921 template <
typename Return,
typename From>
1922 Vc_INTRINSIC Vc_CONST
1923 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1924 simd_cast_drop_arguments(From x, From);
1928 #ifdef Vc_DEBUG_SIMD_CAST 1929 void debugDoNothing(
const std::initializer_list<void *> &) {}
1930 template <
typename T0,
typename... Ts>
1931 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
1934 std::cerr << prefix << arg0;
1935 debugDoNothing({&(std::cerr <<
", " << args)...});
1936 std::cerr << suffix;
1939 template <
typename T0,
typename... Ts>
1940 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
1947 template <
size_t A,
size_t B>
1948 struct is_less :
public std::integral_constant<bool, (A < B)> {
1953 struct is_power_of_2 : public std::integral_constant<bool, ((N - 1) & N) == 0> {
1957 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
1958 template <typename Return, typename T, typename A, typename... Froms> \
1959 Vc_INTRINSIC Vc_CONST enable_if< \
1960 (Traits::isAtomic##SimdArrayType_<Return>::value && \
1961 is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
1962 are_all_types_equal<NativeType_<T, A>, Froms...>::value), \
1964 simd_cast(NativeType_<T, A> x, Froms... xs) \
1966 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
1967 return {simd_cast<typename Return::storage_type>(x, xs...)}; \
1969 template <typename Return, typename T, typename A, typename... Froms> \
1970 Vc_INTRINSIC Vc_CONST enable_if< \
1971 (Traits::isAtomic##SimdArrayType_<Return>::value && \
1972 !is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
1973 are_all_types_equal<NativeType_<T, A>, Froms...>::value), \
1975 simd_cast(NativeType_<T, A> x, Froms... xs) \
1977 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
1978 return {simd_cast_without_last<Return, NativeType_<T, A>, Froms...>(x, xs...)}; \
1980 template <typename Return, typename T, typename A, typename... Froms> \
1981 Vc_INTRINSIC Vc_CONST \
1982 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1983 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1984 is_less<Common::left_size<Return::Size>(), \
1985 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
1986 are_all_types_equal<NativeType_<T, A>, Froms...>::value), \
1988 simd_cast(NativeType_<T, A> x, Froms... xs) \
1990 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
1991 using R0 = typename Return::storage_type0; \
1992 using R1 = typename Return::storage_type1; \
1993 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
1994 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
1996 template <typename Return, typename T, typename A, typename... Froms> \
1997 Vc_INTRINSIC Vc_CONST \
1998 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1999 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2000 !is_less<Common::left_size<Return::Size>(), \
2001 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2002 are_all_types_equal<NativeType_<T, A>, Froms...>::value), \
2004 simd_cast(NativeType_<T, A> x, Froms... xs) \
2006 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
2007 using R0 = typename Return::storage_type0; \
2008 using R1 = typename Return::storage_type1; \
2009 return {simd_cast<R0>(x, xs...), R1::Zero()}; \
2011 Vc_NOTHING_EXPECTING_SEMICOLON
2013 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2014 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2015 #undef Vc_SIMDARRAY_CASTS
2018 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2020 template <typename Return, int offset, typename T, typename A> \
2021 Vc_INTRINSIC Vc_CONST \
2022 enable_if<Traits::isAtomic##SimdArrayType_<Return>::value, Return> \
2023 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG0) \
2025 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
2026 return {simd_cast<typename Return::storage_type, offset>(x)}; \
2029 template <typename Return, int offset, typename T, typename A> \
2030 Vc_INTRINSIC Vc_CONST \
2031 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2032 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2033 Return::Size * offset + Common::left_size<Return::Size>() < \
2034 NativeType_<T, A>::Size), \
2036 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG1) \
2038 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
2039 using R0 = typename Return::storage_type0; \
2040 constexpr int entries_offset = offset * Return::Size; \
2041 constexpr int entries_offset_right = entries_offset + R0::Size; \
2043 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
2044 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
2049 template <typename Return, int offset, typename T, typename A> \
2050 Vc_INTRINSIC Vc_CONST \
2051 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2052 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2053 Return::Size * offset + Common::left_size<Return::Size>() >= \
2054 NativeType_<T, A>::Size), \
2056 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG2) \
2058 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
2059 using R0 = typename Return::storage_type0; \
2060 using R1 = typename Return::storage_type1; \
2061 constexpr int entries_offset = offset * Return::Size; \
2062 return {simd_cast_with_offset<R0, entries_offset>(x), R1::Zero()}; \
2064 Vc_NOTHING_EXPECTING_SEMICOLON
2066 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2067 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2068 #undef Vc_SIMDARRAY_CASTS
2071 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
2073 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2074 Vc_INTRINSIC Vc_CONST \
2075 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2076 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
2077 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2079 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2081 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
2082 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
2085 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2086 Vc_INTRINSIC Vc_CONST \
2087 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2088 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
2089 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2091 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2093 vc_debug_(
"simd_cast{indivisible2}(",
")\n", x0, xs...); \
2094 return simd_cast_without_last<Return, \
2095 typename SimdArrayType_<T, N, V, N>::storage_type, \
2096 typename From::storage_type...>( \
2097 internal_data(x0), internal_data(xs)...); \
2100 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2102 Vc_INTRINSIC Vc_CONST enable_if< \
2103 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2104 !std::is_same<Return, SimdArrayType_<T, N, V, M>>::value && \
2105 is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2107 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2109 vc_debug_(
"simd_cast{bisectable}(",
")\n", x0, xs...); \
2110 return simd_cast_interleaved_argument_order< \
2111 Return,
typename SimdArrayType_<T, N, V, M>::storage_type0, \
2112 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
2113 internal_data1(x0), internal_data1(xs)...); \
2117 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2119 Vc_INTRINSIC Vc_CONST enable_if< \
2120 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2121 !is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2123 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2125 vc_debug_(
"simd_cast{bisectable2}(",
")\n", x0, xs...); \
2126 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
2130 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2132 Vc_INTRINSIC Vc_CONST enable_if< \
2133 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2134 N * (1 +
sizeof...(From)) <= Return::Size && !is_power_of_2<N>::value), \
2136 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2138 vc_debug_(
"simd_cast{remaining}(",
")\n", x0, xs...); \
2139 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
2140 From...>(x0, xs...); \
2143 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2145 Vc_INTRINSIC Vc_CONST enable_if< \
2146 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2147 N * (1 +
sizeof...(From)) > Return::Size && !is_power_of_2<N>::value), \
2149 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2151 vc_debug_(
"simd_cast{remaining2}(",
")\n", x0, xs...); \
2152 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
2153 From...>(x0, xs...); \
2156 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2157 Vc_INTRINSIC Vc_CONST \
2158 enable_if<(N != M && N >= 2 * Return::Size && is_power_of_2<N>::value), Return> \
2159 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2161 vc_debug_(
"simd_cast{single bisectable}(",
")\n", x); \
2162 return
simd_cast<Return>(internal_data0(x)); \
2164 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2165 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
2166 N < 2 * Return::Size && is_power_of_2<N>::value), \
2168 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2170 vc_debug_(
"simd_cast{single bisectable2}(",
")\n", x); \
2171 return
simd_cast<Return>(internal_data0(x), internal_data1(x)); \
2173 Vc_NOTHING_EXPECTING_SEMICOLON
2175 Vc_SIMDARRAY_CASTS(SimdArray);
2177 #undef Vc_SIMDARRAY_CASTS 2180 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \ 2182 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2184 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \ 2185 const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG0) \ 2187 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \ 2188 return simd_cast<Return>(x); \ 2191 template <typename Return, int offset, typename T, std::size_t N, typename V> \ 2192 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \ 2193 const SimdArrayType_<T, N, V, N> &x Vc_DUMMY_ARG1) \ 2195 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \ 2196 return simd_cast<Return, offset>(internal_data(x)); \ 2199 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2201 Vc_INTRINSIC Vc_CONST \ 2202 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2203 offset != 0 && Common::left_size<N>() % Return::Size == 0), \ 2205 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG2) \ 2207 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \ 2208 return simd_cast<Return, offset - Common::left_size<N>() / Return::Size>( \ 2209 internal_data1(x)); \ 2213 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2215 Vc_INTRINSIC Vc_CONST \ 2216 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2217 offset != 0 && Common::left_size<N>() % Return::Size != 0), \ 2219 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG3) \ 2221 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \ 2222 return simd_cast_with_offset<Return, \ 2223 offset * Return::Size - Common::left_size<N>()>( \ 2224 internal_data1(x)); \ 2227 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2229 Vc_INTRINSIC Vc_CONST enable_if< \ 2231 offset != 0 && (offset + 1) * Return::Size <= Common::left_size<N>()), \ 2233 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG4) \ 2235 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \ 2236 return simd_cast<Return, offset>(internal_data0(x)); \ 2239 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2241 Vc_INTRINSIC Vc_CONST \ 2242 enable_if<(N != M && (offset * Return::Size < Common::left_size<N>()) && \ 2243 offset != 0 && (offset + 1) * Return::Size > Common::left_size<N>()), \ 2245 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG5) \ 2247 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \ 2248 using R = typename Return::EntryType; \ 2249 Return r = Return::Zero(); \ 2250 for (std::size_t i = offset * Return::Size; \ 2251 i < std::min(N, (offset + 1) * Return::Size); ++i) { \ 2252 r[i - offset * Return::Size] = static_cast<R>(x[i]); \ 2256 Vc_NOTHING_EXPECTING_SEMICOLON 2257 Vc_SIMDARRAY_CASTS(SimdArray);
2259 #undef Vc_SIMDARRAY_CASTS 2261 template <
typename Return,
typename From>
2262 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
2266 template <
typename Return,
typename... Froms>
2267 Vc_INTRINSIC Vc_CONST
2268 enable_if<(are_all_types_equal<Froms...>::value &&
2269 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2271 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
2278 template <
typename Return,
typename From,
typename... Froms>
2279 Vc_INTRINSIC Vc_CONST enable_if<
2280 (are_all_types_equal<From, Froms...>::value &&
2281 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2283 simd_cast_drop_arguments(Froms... xs, From x, From)
2285 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
2287 template <
typename Return,
typename From>
2288 Vc_INTRINSIC Vc_CONST
2289 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2290 simd_cast_drop_arguments(From x, From)
2292 return simd_cast_drop_arguments<Return>(x);
2296 template <
typename Return, std::
size_t offset,
typename From>
2297 Vc_INTRINSIC Vc_CONST
2298 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
2299 Return> simd_cast_with_offset(
const From &x)
2301 return simd_cast<Return, offset / Return::Size>(x);
2303 template <
typename Return, std::
size_t offset,
typename From>
2304 Vc_INTRINSIC Vc_CONST
2305 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2307 !Traits::isAtomicSimdArray<Return>::value) ||
2309 !Traits::isAtomicSimdMaskArray<Return>::value))),
2311 simd_cast_with_offset(
const From &x)
2313 using R0 =
typename Return::storage_type0;
2314 using R1 =
typename Return::storage_type1;
2315 return {simd_cast_with_offset<R0, offset>(x),
2316 simd_cast_with_offset<R1, offset + R0::Size>(x)};
2318 template <
typename Return, std::
size_t offset,
typename From>
2319 Vc_INTRINSIC Vc_CONST
2320 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2322 Traits::isAtomicSimdArray<Return>::value) ||
2324 Traits::isAtomicSimdMaskArray<Return>::value))),
2326 simd_cast_with_offset(
const From &x)
2328 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
2330 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
2331 Vc_INTRINSIC Vc_CONST
2332 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
2333 simd_cast_with_offset(
const From &x,
const Froms &... xs)
2339 template <
typename Return,
typename T,
typename... From>
2340 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
2351 template <std::
size_t I,
typename T0>
2352 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
const T0 &)
2356 template <std::
size_t I,
typename T0>
2357 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
const T0 &b0)
2364 template <std::size_t I,
typename T0,
typename... Ts>
2365 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2373 template <std::size_t I,
typename T0,
typename... Ts>
2374 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2382 template <std::size_t I,
typename T0,
typename... Ts>
2383 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2388 return extract_interleaved<I - 2, Ts...>(a..., b...);
2391 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2392 Vc_INTRINSIC Vc_CONST Return
2393 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2396 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2400 template <
typename Return,
typename... Ts>
2401 Vc_INTRINSIC Vc_CONST Return
2402 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2404 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2405 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2409 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \ 2410 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \ 2412 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \ 2413 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \ 2415 lhs(mask) op_ rhs; \ 2417 Vc_NOTHING_EXPECTING_SEMICOLON 2418 Vc_CONDITIONAL_ASSIGN( Assign, =);
2419 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
2420 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
2421 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
2422 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
2423 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
2424 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
2425 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
2426 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
2427 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
2428 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
2429 #undef Vc_CONDITIONAL_ASSIGN 2431 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \ 2432 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \ 2433 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \ 2434 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \ 2438 Vc_NOTHING_EXPECTING_SEMICOLON 2439 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
2440 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
2441 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
2442 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
2443 #undef Vc_CONDITIONAL_ASSIGN 2447 template <
typename T,
size_t N,
typename V>
2448 inline void transpose_impl(
2453 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2454 &internal_data(*r[2]), &internal_data(*r[3])};
2455 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2456 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2457 internal_data(std::get<1>(proxy.in)),
2458 internal_data(std::get<2>(proxy.in)),
2459 internal_data(std::get<3>(proxy.in))});
2462 template <
typename T,
typename V>
2463 inline void transpose_impl(
2470 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2471 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2472 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2473 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2474 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2475 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2476 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2477 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2480 template <
typename T,
typename V>
2481 inline void transpose_impl(
2486 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2487 &internal_data(*r[2]), &internal_data(*r[3])};
2488 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2489 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2490 internal_data(std::get<1>(proxy.in)),
2491 internal_data(std::get<2>(proxy.in)),
2492 internal_data(std::get<3>(proxy.in))});
2495 template <
typename T,
size_t N,
typename V>
2496 inline void transpose_impl(
2504 transpose_impl(TransposeTag<2, 4>(), &r0[0],
2505 TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2506 internal_data0(std::get<1>(proxy.in)),
2507 internal_data0(std::get<2>(proxy.in)),
2508 internal_data0(std::get<3>(proxy.in))});
2509 transpose_impl(TransposeTag<2, 4>(), &r1[0],
2510 TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2511 internal_data1(std::get<1>(proxy.in)),
2512 internal_data1(std::get<2>(proxy.in)),
2513 internal_data1(std::get<3>(proxy.in))});
2566 template <
typename T,
size_t N,
typename V,
size_t VN>
2567 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2574 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2576 return numeric_limits<T>::lowest();
2578 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2580 return numeric_limits<T>::epsilon();
2582 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2584 return numeric_limits<T>::round_error();
2586 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2588 return numeric_limits<T>::infinity();
2590 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2592 return numeric_limits<T>::quiet_NaN();
2594 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2596 return numeric_limits<T>::signaling_NaN();
2598 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2600 return numeric_limits<T>::denorm_min();
2606 #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.
value_type max() const
Returns the largest entry in the vector.
Vc::Vector< T > frexp(const Vc::Vector< T > &x, Vc::SimdArray< int, size()> *e)
Convert floating-point number to fractional and integral components.
Vc::Vector< T > log2(const Vc::Vector< T > &v)
Vc::Vector< T > exp(const Vc::Vector< T > &v)
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 > sin(const Vc::Vector< T > &v)
Vc::Vector< T > cos(const Vc::Vector< T > &v)
Vc::Vector< T > min(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
Vc::Vector< T > reciprocal(const Vc::Vector< T > &v)
Returns the reciprocal of v.
SimdArray rotated(int amount) const
Rotate vector entries to the left by amount.
Vc::Vector< T > ldexp(Vc::Vector< T > x, Vc::SimdArray< int, size()> e)
Multiply floating-point number by integral power of 2.
std::ostream & operator<<(std::ostream &out, const Vc::Vector< T, Abi > &v)
Prints the contents of a vector into a stream object.
UnalignedTag DefaultLoadTag
The default load tag type uses unaligned (non-streaming) loads.
Vc::Vector< T > abs(const Vc::Vector< T > &v)
Returns the absolute value of v.
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)
SimdArray partialSum() const
Returns a vector containing the sum of all entries with smaller index.
Identifies any possible SimdArray<T, N> type (independent of const/volatile or reference) ...
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) ...
Vc::Vector< T > log(const Vc::Vector< T > &v)
SimdArray shifted(int amount) const
Shift vector entries to the left by amount; shifting in zeros.
Vc::Vector< T > fma(Vc::Vector< T > a, Vc::Vector< T > b, Vc::Vector< T > c)
Multiplies a with b and then adds c, without rounding between the multiplication and the addition...
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...
Data-parallel mask type with user-defined number of boolean elements.
Vc::Vector< T > round(const Vc::Vector< T > &v)
Returns the closest integer to v; 0.5 is rounded to even.
SimdArray apply(F &&f) const
Call f on every entry of the vector and return the results as a new vector.
static SimdArray Zero()
Returns a vector with the entries initialized to zero.
Vc::Vector< T > rsqrt(const Vc::Vector< T > &v)
Returns the reciprocal square root of v.
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.
Vc::Vector< T > log10(const Vc::Vector< T > &v)
Common::WriteMaskedVector< SimdArray, mask_type > operator()(const mask_type &mask)
Writemask the vector before an assignment.
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.
SimdArray exponent() const
Returns the exponents of the floating-point values in the vector.
Vc::Vector< T > atan2(const Vc::Vector< T > &y, const Vc::Vector< T > &x)
Calculates the angle given the lengths of the opposite and adjacent legs in a right triangle...
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)
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.
Vc::Vector< T > atan(const Vc::Vector< T > &v)
Vc::Vector< T > asin(const Vc::Vector< T > &v)
value_type min() const
Returns the smallest entry in the vector.
SimdArray operator+() const
Returns a copy of itself.
void assign(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.
Vc::Mask< T > isfinite(const Vc::Vector< T > &x)
SimdArray(value_type a)
Broadcast Constructor.
Vc::Mask< T > isnan(const Vc::Vector< T > &x)
static SimdArray Random()
Returns a vector with pseudo-random entries.
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.
T value_type
The type of the elements (i.e. T)
Vector Classes Namespace.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true...
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
void gather(const MT *mem, IT &&indexes)
Gather function.
To simd_cast(From &&x, enable_if< std::is_same< To, Traits::decay< From >>::value >=nullarg)
Casts the argument x from type From to type To.
reference operator[](size_t i) noexcept
This operator can be used to modify scalar entries of the vector.
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 reversed() const
Returns a vector with all components reversed.
SimdArray copySign(const SimdArray &reference) 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.
Vc::Vector< T > sqrt(const Vc::Vector< T > &v)
Returns the square root of v.
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
SimdMaskArray< T, N, V, M > isinf(const SimdArray< T, N, V, M > &x)
Applies the std:: isinf function component-wise and concurrently.