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 }");
125 std::is_same<VectorType_,
126 typename Common::select_best_vector_type<T, N>::type>::value &&
127 VectorType_::size() == N,
128 "ERROR: leave the third and fourth template parameters with their defaults. They " 129 "are implementation details.");
132 static constexpr
bool is_atomic =
true;
133 using VectorType = VectorType_;
134 using vector_type = VectorType;
135 using storage_type = vector_type;
136 using vectorentry_type =
typename vector_type::VectorEntryType;
140 static constexpr std::size_t size() {
return N; }
144 using VectorEntryType = vectorentry_type;
148 using reference = Detail::ElementReference<SimdArray>;
149 static constexpr std::size_t Size = size();
166 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
173 template <
class U,
class V,
class = enable_if<N == V::Size>>
175 : data(simd_cast<vector_type>(internal_data(x)))
178 template <
class U,
class V,
class = enable_if<(N > V::Size && N <= 2 * V::Size)>,
181 : data(simd_cast<vector_type>(internal_data(internal_data0(x)),
182 internal_data(internal_data1(x))))
185 template <
class U,
class V,
class = enable_if<(N > 2 * V::Size && N <= 4 * V::Size)>,
186 class = U,
class = U>
188 : data(simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
189 internal_data(internal_data1(internal_data0(x))),
190 internal_data(internal_data0(internal_data1(x))),
191 internal_data(internal_data1(internal_data1(x)))))
195 template <
typename V, std::
size_t Pieces, std::
size_t Index>
196 Vc_INTRINSIC SimdArray(Common::Segment<V, Pieces, Index> &&x)
197 : data(simd_cast<vector_type, Index>(x.data))
201 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
204 Vc_ASSERT(init.size() == size());
211 Vc_INTRINSIC SimdArray(
const V &x)
212 : data(simd_cast<vector_type>(x))
218 template <
typename U,
typename A,
221 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
235 #include "gatherinterface.h" 236 #include "scatterinterface.h" 239 template <
typename... Args,
240 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
241 !Traits::is_gather_signature<Args...>::value &&
242 !Traits::is_initializer_list<Args...>::value>>
243 explicit Vc_INTRINSIC SimdArray(Args &&... args)
244 : data(std::forward<Args>(args)...)
248 template <std::
size_t Offset>
249 explicit Vc_INTRINSIC SimdArray(
250 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
256 Vc_INTRINSIC
void setZero() { data.setZero(); }
257 Vc_INTRINSIC
void setZero(
mask_type k) { data.setZero(internal_data(k)); }
258 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
259 Vc_INTRINSIC
void setZeroInverted(
mask_type k) { data.setZeroInverted(internal_data(k)); }
261 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
262 Vc_INTRINSIC
void setQnan(
mask_type m) { data.setQnan(internal_data(m)); }
265 template <
typename Op,
typename... Args>
269 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
273 template <
typename Op,
typename... Args>
274 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
276 Common::unpackArgumentsAuto(op,
nullptr, std::forward<Args>(args)...);
293 return fromOperation(Common::Operations::random());
296 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
298 data.load(std::forward<Args>(args)...);
301 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const 303 data.store(std::forward<Args>(args)...);
308 return {private_init, !data};
313 return {private_init, -data};
321 return {private_init, ~data};
324 template <
typename U,
325 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
328 return {private_init, data << x};
330 template <
typename U,
331 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
337 template <
typename U,
338 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
341 return {private_init, data >> x};
343 template <
typename U,
344 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
351 #define Vc_BINARY_OPERATOR_(op) \ 352 Vc_INTRINSIC fixed_size_simd<T, N> &operator op##=(const SimdArray &rhs) \ 354 data op## = rhs.data; \ 357 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
358 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
359 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
360 #undef Vc_BINARY_OPERATOR_ 363 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 370 Vc_INTRINSIC
static value_type get(
const SimdArray &o,
int i) noexcept
374 template <
typename U>
375 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
376 noexcept(std::declval<value_type &>() = v))
388 Vc_INTRINSIC reference operator[](
size_t i) noexcept
390 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
391 return {*
this, int(i)};
393 Vc_INTRINSIC
value_type operator[](
size_t i)
const noexcept
395 return get(*
this, int(i));
398 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
405 data.assign(v.data, internal_data(k));
409 #define Vc_REDUCTION_FUNCTION_(name_) \ 410 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \ 411 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \ 413 return data.name_(internal_data(mask)); \ 415 Vc_NOTHING_EXPECTING_SEMICOLON 416 Vc_REDUCTION_FUNCTION_(
min);
417 Vc_REDUCTION_FUNCTION_(
max);
418 Vc_REDUCTION_FUNCTION_(product);
419 Vc_REDUCTION_FUNCTION_(sum);
420 #undef Vc_REDUCTION_FUNCTION_ 428 return {private_init, data.
apply(std::forward<F>(f))};
432 return {private_init, data.
apply(std::forward<F>(f), k)};
437 return {private_init, data.shifted(amount)};
440 template <std::
size_t NN>
444 return {private_init, data.shifted(amount, simd_cast<VectorType>(shiftIn))};
449 return {private_init, data.
rotated(amount)};
455 return {private_init,
exponent(data)};
460 return {private_init, data.interleaveLow(x.data)};
464 return {private_init, data.interleaveHigh(x.data)};
469 return {private_init, data.
reversed()};
474 return {private_init, data.
sorted()};
479 return {private_init, VectorType::generate(gen)};
482 Vc_DEPRECATED(
"use copysign(x, y) instead")
488 friend VectorType &internal_data<>(SimdArray &x);
489 friend const VectorType &internal_data<>(
const SimdArray &x);
492 Vc_INTRINSIC SimdArray(private_init_t, VectorType &&x) : data(std::move(x)) {}
494 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type));
500 alignas(
static_cast<std::size_t
>(
501 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
502 VectorType_::size()>::value)) storage_type data;
505 template <
typename T, std::
size_t N,
typename VectorType>
507 template <
typename T, std::
size_t N,
typename VectorType>
515 template <
typename T, std::
size_t N,
typename VectorType>
525 template <
typename T> T unpackIfSegment(T &&x) {
return std::forward<T>(x); }
526 template <
typename T,
size_t Pieces,
size_t Index>
527 auto unpackIfSegment(Common::Segment<T, Pieces, Index> &&x) -> decltype(x.asSimdArray())
529 return x.asSimdArray();
533 template <
typename T, std::
size_t N,
typename VectorType>
534 template <
typename MT,
typename IT>
538 data.
gather(mem, unpackIfSegment(indexes));
540 template <
typename T, std::
size_t N,
typename VectorType>
541 template <
typename MT,
typename IT>
546 data.
gather(mem, unpackIfSegment(indexes), mask);
550 template <
typename T, std::
size_t N,
typename VectorType>
551 template <
typename MT,
typename IT>
555 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)));
557 template <
typename T, std::
size_t N,
typename VectorType>
558 template <
typename MT,
typename IT>
563 data.
scatter(mem, unpackIfSegment(std::forward<IT>(indexes)), mask);
599 template <
typename T,
size_t N,
typename V,
size_t Wt>
class SimdArray
601 static_assert(std::is_same<T, double>::value ||
602 std::is_same<T, float>::value ||
603 std::is_same<T, int32_t>::value ||
604 std::is_same<T, uint32_t>::value ||
605 std::is_same<T, int16_t>::value ||
606 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 }");
608 std::is_same<V,
typename Common::select_best_vector_type<T, N>::type>::value &&
610 "ERROR: leave the third and fourth template parameters with their defaults. They " 611 "are implementation details.");
614 std::is_same<typename V::EntryType, typename V::VectorEntryType>::value ||
616 (N % V::size() == 0),
617 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * " 618 "MIC::(u)short_v::size(), i.e. k * 16.");
620 using my_traits = SimdArrayTraits<T, N>;
621 static constexpr std::size_t N0 = my_traits::N0;
622 static constexpr std::size_t N1 = my_traits::N1;
623 using Split = Common::Split<N0>;
624 template <
typename U, std::
size_t K>
using CArray = U[K];
627 static constexpr
bool is_atomic =
false;
630 static_assert(storage_type0::size() == N0,
"");
635 using vector_type = V;
636 using vectorentry_type =
typename storage_type0::vectorentry_type;
637 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
658 static constexpr std::size_t
size() {
return N; }
665 using VectorEntryType = vectorentry_type;
670 using AsArg =
const SimdArray &;
672 using reference = Detail::ElementReference<SimdArray>;
675 static constexpr std::size_t MemoryAlignment =
704 return fromOperation(Common::Operations::random());
710 auto tmp = storage_type0::generate(gen);
715 return {std::move(tmp),
716 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
724 SimdArray() =
default;
734 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
736 : SimdArray(static_cast<value_type>(a))
742 SimdArray(
const SimdArray &) =
default;
743 SimdArray(SimdArray &&) =
default;
744 SimdArray &operator=(
const SimdArray &) =
default;
748 typename = enable_if<std::is_arithmetic<U>::value &&
749 Traits::is_load_store_flag<Flags>::value>>
750 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
751 : data0(mem, f), data1(mem + storage_type0::size(), f)
763 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
764 typename = enable_if<std::is_arithmetic<U>::value &&
765 Traits::is_load_store_flag<Flags>::value>>
766 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
767 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
773 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
774 typename = enable_if<std::is_arithmetic<U>::value &&
775 Traits::is_load_store_flag<Flags>::value>>
776 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
777 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
783 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
787 Vc_ASSERT(init.size() == size());
790 #include "gatherinterface.h" 791 #include "scatterinterface.h" 794 template <
typename... Args,
795 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
796 !Traits::is_initializer_list<Args...>::value &&
797 !Traits::is_gather_signature<Args...>::value &&
798 !Traits::is_load_arguments<Args...>::value>>
799 explicit Vc_INTRINSIC SimdArray(Args &&... args)
800 : data0(Split::lo(args)...)
802 , data1(Split::hi(std::forward<Args>(args))...)
807 template <
class W,
class = enable_if<
810 !(std::is_convertible<Traits::entry_type_of<W>, T>::value &&
812 Vc_INTRINSIC
explicit SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
817 template <
class W,
class = enable_if<
819 Traits::simd_vector_size<W>::value == N &&
820 std::is_convertible<Traits::entry_type_of<W>, T>::value)>,
822 Vc_INTRINSIC SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
828 template <
typename U,
typename A,
830 enable_if<std::is_convertible<T, U>::value && Vector<U, A>::Size == N &&
831 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
848 Vc_INTRINSIC
void setZero()
853 Vc_INTRINSIC
void setZero(
const mask_type &k)
855 data0.setZero(Split::lo(k));
856 data1.setZero(Split::hi(k));
858 Vc_INTRINSIC
void setZeroInverted()
860 data0.setZeroInverted();
861 data1.setZeroInverted();
863 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
865 data0.setZeroInverted(Split::lo(k));
866 data1.setZeroInverted(Split::hi(k));
870 Vc_INTRINSIC
void setQnan() {
874 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
875 data0.setQnan(Split::lo(m));
876 data1.setQnan(Split::hi(m));
880 template <
typename Op,
typename... Args>
884 storage_type0::fromOperation(op, Split::lo(args)...),
887 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
892 template <
typename Op,
typename... Args>
893 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
895 storage_type0::callOperation(op, Split::lo(args)...);
896 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
900 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
902 data0.load(mem, Split::lo(args)...);
904 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
907 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const 909 data0.store(mem, Split::lo(args)...);
911 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
916 return {!data0, !data1};
921 return {-data0, -data1};
929 return {~data0, ~data1};
933 template <
typename U,
934 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
937 return {data0 << x, data1 << x};
939 template <
typename U,
940 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
947 template <
typename U,
948 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
951 return {data0 >> x, data1 >> x};
953 template <
typename U,
954 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
963 #define Vc_BINARY_OPERATOR_(op) \ 964 Vc_INTRINSIC fixed_size_simd<T, N> &operator op##=(const SimdArray &rhs) \ 966 data0 op## = rhs.data0; \ 967 data1 op## = rhs.data1; \ 970 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
971 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
972 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
973 #undef Vc_BINARY_OPERATOR_ 981 Vc_INTRINSIC
static value_type get(
const SimdArray &o,
int i) noexcept
983 return reinterpret_cast<const alias_type *
>(&o)[i];
985 template <
typename U>
986 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
987 noexcept(std::declval<value_type &>() = v))
989 reinterpret_cast<alias_type *
>(&o)[i] = v;
1002 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
1003 return {*
this, int(i)};
1009 return get(*
this, int(index));
1015 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type>
operator()(
1018 return {*
this, mask};
1024 data0.assign(v.data0, internal_data0(k));
1025 data1.assign(v.data1, internal_data1(k));
1029 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \ 1031 template <typename ForSfinae = void> \ 1032 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1033 storage_type0::Size == storage_type1::Size, \ 1034 value_type> name_##_impl() const \ 1036 return binary_fun_(data0, data1).name_(); \ 1039 template <typename ForSfinae = void> \ 1040 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1041 storage_type0::Size != storage_type1::Size, \ 1042 value_type> name_##_impl() const \ 1044 return scalar_fun_(data0.name_(), data1.name_()); \ 1049 Vc_INTRINSIC value_type name_() const { return name_##_impl(); } \ 1051 Vc_INTRINSIC value_type name_(const mask_type &mask) const \ 1053 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \ 1054 return data1.name_(Split::hi(mask)); \ 1055 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \ 1056 return data0.name_(Split::lo(mask)); \ 1058 return scalar_fun_(data0.name_(Split::lo(mask)), \ 1059 data1.name_(Split::hi(mask))); \ 1062 Vc_NOTHING_EXPECTING_SEMICOLON 1065 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_);
1066 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_);
1067 #undef Vc_REDUCTION_FUNCTION_ 1073 tmp[0] += ps0[data0.size() - 1];
1081 return {data0.apply(f), data1.apply(f)};
1084 template <
typename F>
1087 return {data0.apply(f, Split::lo(k)), data1.apply(f, Split::hi(k))};
1094 constexpr
int SSize = Size;
1095 constexpr
int SSize0 = storage_type0::Size;
1096 constexpr
int SSize1 = storage_type1::Size;
1101 if (amount > -SSize0) {
1102 return {data0.shifted(amount), data1.shifted(amount, data0)};
1104 if (amount == -SSize0) {
1105 return {storage_type0(0), simd_cast<storage_type1>(data0)};
1107 if (amount < -SSize0) {
1108 return {storage_type0(0), simd_cast<storage_type1>(data0.shifted(
1113 if (amount >= SSize) {
1115 }
else if (amount >= SSize0) {
1117 simd_cast<storage_type0>(data1).
shifted(amount - SSize0),
1119 }
else if (amount >= SSize1) {
1120 return {data0.shifted(amount, data1), storage_type1(0)};
1122 return {data0.shifted(amount, data1), data1.shifted(amount)};
1127 template <std::
size_t NN>
1129 !(std::is_same<storage_type0, storage_type1>::value &&
1134 constexpr
int SSize = Size;
1139 return operator[](i);
1140 }
else if (i >= -SSize) {
1141 return shiftIn[i + SSize];
1149 return operator[](i);
1150 }
else if (i < 2 * SSize) {
1151 return shiftIn[i - SSize];
1160 template <std::
size_t NN>
struct bisectable_shift
1161 :
public std::integral_constant<bool,
1162 std::is_same<storage_type0, storage_type1>::value &&
1168 template <std::
size_t NN>
1170 enable_if<bisectable_shift<NN>::value,
int> amount,
1173 constexpr
int SSize = Size;
1175 if (amount > -static_cast<int>(storage_type0::Size)) {
1176 return {data0.shifted(amount, internal_data1(shiftIn)),
1177 data1.shifted(amount, data0)};
1179 if (amount == -static_cast<int>(storage_type0::Size)) {
1180 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
1182 if (amount > -SSize) {
1184 internal_data1(shiftIn)
1185 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1186 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1188 if (amount == -SSize) {
1191 if (amount > -2 * SSize) {
1192 return shiftIn.
shifted(amount + SSize);
1198 if (amount < static_cast<int>(storage_type0::Size)) {
1199 return {data0.shifted(amount, data1),
1200 data1.shifted(amount, internal_data0(shiftIn))};
1202 if (amount == static_cast<int>(storage_type0::Size)) {
1203 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1205 if (amount < SSize) {
1206 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1207 internal_data0(shiftIn)
1208 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1210 if (amount == SSize) {
1213 if (amount < 2 * SSize) {
1214 return shiftIn.
shifted(amount - SSize);
1223 amount %= int(size());
1226 }
else if (amount < 0) {
1243 auto &&d0cvtd = simd_cast<storage_type1>(data0);
1244 auto &&d1cvtd = simd_cast<storage_type0>(data1);
1245 constexpr
int size0 = storage_type0::size();
1246 constexpr
int size1 = storage_type1::size();
1248 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1249 return {std::move(d1cvtd), std::move(d0cvtd)};
1250 }
else if (amount < size1) {
1251 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1252 }
else if (amount == size1) {
1253 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1254 }
else if (
int(size()) - amount < size1) {
1255 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1256 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1257 }
else if (
int(size()) - amount == size1) {
1258 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1259 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1260 }
else if (amount <= size0) {
1261 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1262 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1264 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1265 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1276 return {data0.interleaveLow(x.data0),
1277 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1282 return interleaveHighImpl(
1284 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1291 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1296 return {data0.interleaveHigh(x.data0)
1298 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1299 data1.interleaveHigh(x.data1)};
1306 if (std::is_same<storage_type0, storage_type1>::value) {
1307 return {simd_cast<storage_type0>(data1).reversed(),
1308 simd_cast<storage_type1>(data0).reversed()};
1319 return {data0.shifted(storage_type1::Size, data1).reversed(),
1320 simd_cast<storage_type1>(data0.reversed().shifted(
1321 storage_type0::Size - storage_type1::Size))};
1329 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1335 #ifdef Vc_DEBUG_SORTED 1336 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1338 const auto a = data0.
sorted();
1340 const auto lo =
Vc::min(a, b);
1341 const auto hi =
Vc::max(a, b);
1342 return {lo.sorted(), hi.sorted()};
1348 using SortableArray =
1350 auto sortable = simd_cast<SortableArray>(*this);
1351 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1352 using limits = std::numeric_limits<value_type>;
1353 if (limits::has_infinity) {
1354 sortable[i] = limits::infinity();
1393 static constexpr std::size_t Size = size();
1396 Vc_DEPRECATED(
"use exponent(x) instead")
1399 return {exponent(data0), exponent(data1)};
1403 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 1409 Vc_DEPRECATED(
"use copysign(x, y) instead")
1418 friend storage_type0 &internal_data0<>(SimdArray &x);
1419 friend storage_type1 &internal_data1<>(SimdArray &x);
1420 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1421 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1424 Vc_INTRINSIC SimdArray(storage_type0 &&x, storage_type1 &&y)
1425 : data0(std::move(x)), data1(std::move(y))
1429 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type0));
1435 alignas(
static_cast<std::size_t
>(
1436 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
1437 V::size()>::value)) storage_type0 data0;
1438 storage_type1 data1;
1440 #undef Vc_CURRENT_CLASS_NAME 1441 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1443 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1447 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1448 template <
typename MT,
typename IT>
1452 data0.
gather(mem, Split::lo(Common::Operations::gather(), indexes));
1453 data1.gather(mem, Split::hi(Common::Operations::gather(), indexes));
1455 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1456 template <
typename MT,
typename IT>
1461 data0.
gather(mem, Split::lo(Common::Operations::gather(), indexes), Split::lo(mask));
1462 data1.gather(mem, Split::hi(Common::Operations::gather(), indexes), Split::hi(mask));
1466 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1467 template <
typename MT,
typename IT>
1471 data0.
scatter(mem, Split::lo(Common::Operations::gather(),
1474 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1476 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1477 template <
typename MT,
typename IT>
1481 data0.
scatter(mem, Split::lo(Common::Operations::gather(), indexes),
1484 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1490 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1500 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1510 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1520 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1533 #if defined Vc_MSVC && defined Vc_IMPL_SSE && !defined Vc_IMPL_AVX 1537 : data0(x), data1(0)
1546 #define Vc_FIXED_OP(op) \ 1547 template <class T, int N, \ 1548 class = typename std::enable_if<fixed_size_simd<T, N>::is_atomic>::type> \ 1549 fixed_size_simd<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1550 const fixed_size_simd<T, N> &b) \ 1552 return {private_init, internal_data(a) op internal_data(b)}; \ 1554 template <class T, int N, \ 1555 class = typename std::enable_if<!fixed_size_simd<T, N>::is_atomic>::type, \ 1557 fixed_size_simd<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1558 const fixed_size_simd<T, N> &b) \ 1560 return {internal_data0(a) op internal_data0(b), \ 1561 internal_data1(a) op internal_data1(b)}; \ 1563 Vc_ALL_ARITHMETICS(Vc_FIXED_OP);
1564 Vc_ALL_BINARY(Vc_FIXED_OP);
1565 Vc_ALL_SHIFTS(Vc_FIXED_OP);
1567 #define Vc_FIXED_OP(op) \ 1568 template <class T, int N, \ 1569 class = typename std::enable_if<fixed_size_simd<T, N>::is_atomic>::type> \ 1570 fixed_size_simd_mask<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1571 const fixed_size_simd<T, N> &b) \ 1573 return {private_init, internal_data(a) op internal_data(b)}; \ 1575 template <class T, int N, \ 1576 class = typename std::enable_if<!fixed_size_simd<T, N>::is_atomic>::type, \ 1578 fixed_size_simd_mask<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1579 const fixed_size_simd<T, N> &b) \ 1581 return {internal_data0(a) op internal_data0(b), \ 1582 internal_data1(a) op internal_data1(b)}; \ 1584 Vc_ALL_COMPARES(Vc_FIXED_OP);
1590 namespace result_vector_type_internal
1592 template <
typename T>
1593 using remove_cvref =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1595 template <
typename T>
1596 using is_integer_larger_than_int = std::integral_constant<
1597 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1598 std::is_same<T, long>::value ||
1599 std::is_same<T, unsigned long>::value)>;
1602 typename L,
typename R,
1607 !(Traits::is_fixed_size_simd<L>::value &&
1608 Traits::is_fixed_size_simd<R>::value) &&
1609 ((std::is_arithmetic<remove_cvref<L>>::value &&
1610 !is_integer_larger_than_int<remove_cvref<L>>::value) ||
1611 (std::is_arithmetic<remove_cvref<R>>::value &&
1612 !is_integer_larger_than_int<remove_cvref<R>>::value) ||
1618 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1621 using LScalar = Traits::entry_type_of<L>;
1622 using RScalar = Traits::entry_type_of<R>;
1624 template <
bool B,
typename T,
typename F>
1625 using conditional =
typename std::conditional<B, T, F>::type;
1639 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1640 sizeof(LScalar) <
sizeof(
int) &&
1641 sizeof(RScalar) <
sizeof(
int)),
1642 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1643 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1644 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1645 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1651 template <
typename L,
typename R>
1652 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1654 #define Vc_BINARY_OPERATORS_(op_) \ 1656 template <typename L, typename R> \ 1657 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \ 1659 using Return = result_vector_type<L, R>; \ 1660 return Vc::Detail::operator op_( \ 1661 static_cast<const Return &>(std::forward<L>(lhs)), \ 1662 static_cast<const Return &>(std::forward<R>(rhs))); \ 1681 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_);
1683 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_);
1685 #undef Vc_BINARY_OPERATORS_ 1686 #define Vc_BINARY_OPERATORS_(op_) \ 1688 template <typename L, typename R> \ 1689 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \ 1692 using Promote = result_vector_type<L, R>; \ 1693 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \ 1712 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_);
1715 #undef Vc_BINARY_OPERATORS_ 1718 #define Vc_FORWARD_UNARY_OPERATOR(name_) \ 1720 template <typename T, std::size_t N, typename V, std::size_t M> \ 1721 inline fixed_size_simd<T, N> name_(const SimdArray<T, N, V, M> &x) \ 1723 return fixed_size_simd<T, N>::fromOperation( \ 1724 Common::Operations::Forward_##name_(), x); \ 1726 template <class T, int N> \ 1727 fixed_size_simd<T, N> name_(const fixed_size_simd<T, N> &x) \ 1729 return fixed_size_simd<T, N>::fromOperation( \ 1730 Common::Operations::Forward_##name_(), x); \ 1732 Vc_NOTHING_EXPECTING_SEMICOLON 1734 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \ 1736 template <typename T, std::size_t N, typename V, std::size_t M> \ 1737 inline fixed_size_simd_mask<T, N> name_(const SimdArray<T, N, V, M> &x) \ 1739 return fixed_size_simd_mask<T, N>::fromOperation( \ 1740 Common::Operations::Forward_##name_(), x); \ 1742 template <class T, int N> \ 1743 fixed_size_simd_mask<T, N> name_(const fixed_size_simd<T, N> &x) \ 1745 return fixed_size_simd_mask<T, N>::fromOperation( \ 1746 Common::Operations::Forward_##name_(), x); \ 1748 Vc_NOTHING_EXPECTING_SEMICOLON 1750 #define Vc_FORWARD_BINARY_OPERATOR(name_) \ 1752 template <typename T, std::size_t N, typename V, std::size_t M> \ 1753 inline fixed_size_simd<T, N> name_(const SimdArray<T, N, V, M> &x, \ 1754 const SimdArray<T, N, V, M> &y) \ 1756 return fixed_size_simd<T, N>::fromOperation( \ 1757 Common::Operations::Forward_##name_(), x, y); \ 1759 Vc_NOTHING_EXPECTING_SEMICOLON 1765 Vc_FORWARD_UNARY_OPERATOR(abs);
1767 Vc_FORWARD_UNARY_OPERATOR(asin);
1768 Vc_FORWARD_UNARY_OPERATOR(atan);
1770 Vc_FORWARD_UNARY_OPERATOR(ceil);
1772 Vc_FORWARD_UNARY_OPERATOR(cos);
1773 Vc_FORWARD_UNARY_OPERATOR(exp);
1774 Vc_FORWARD_UNARY_OPERATOR(exponent);
1775 Vc_FORWARD_UNARY_OPERATOR(floor);
1777 template <
typename T, std::
size_t N>
1783 Vc_FORWARD_UNARY_BOOL_OPERATOR(isfinite);
1784 Vc_FORWARD_UNARY_BOOL_OPERATOR(isinf);
1785 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnan);
1786 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnegative);
1788 template <
typename T, std::
size_t N>
1794 template <
typename T, std::
size_t N>
1799 Vc_FORWARD_UNARY_OPERATOR(log);
1800 Vc_FORWARD_UNARY_OPERATOR(log10);
1801 Vc_FORWARD_UNARY_OPERATOR(log2);
1802 Vc_FORWARD_UNARY_OPERATOR(reciprocal);
1803 Vc_FORWARD_UNARY_OPERATOR(round);
1804 Vc_FORWARD_UNARY_OPERATOR(rsqrt);
1805 Vc_FORWARD_UNARY_OPERATOR(sin);
1807 template <
typename T, std::
size_t N>
1812 Vc_FORWARD_UNARY_OPERATOR(sqrt);
1813 Vc_FORWARD_UNARY_OPERATOR(trunc);
1814 Vc_FORWARD_BINARY_OPERATOR(
min);
1815 Vc_FORWARD_BINARY_OPERATOR(
max);
1817 #undef Vc_FORWARD_UNARY_OPERATOR 1818 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR 1819 #undef Vc_FORWARD_BINARY_OPERATOR 1823 #define Vc_DUMMY_ARG0 , int = 0 1824 #define Vc_DUMMY_ARG1 , long = 0 1825 #define Vc_DUMMY_ARG2 , short = 0 1826 #define Vc_DUMMY_ARG3 , char = '0' 1827 #define Vc_DUMMY_ARG4 , unsigned = 0u 1828 #define Vc_DUMMY_ARG5 , unsigned short = 0u 1830 #define Vc_DUMMY_ARG0 1831 #define Vc_DUMMY_ARG1 1832 #define Vc_DUMMY_ARG2 1833 #define Vc_DUMMY_ARG3 1834 #define Vc_DUMMY_ARG4 1835 #define Vc_DUMMY_ARG5 1842 template <
typename Return, std::size_t N,
typename T,
typename... From>
1843 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1844 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1846 Return r = simd_cast<Return>(xs...);
1847 for (
size_t i = 0; i < N; ++i) {
1848 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1852 template <
typename Return, std::
size_t N,
typename T>
1853 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1855 Return r = Return();
1856 for (
size_t i = 0; i < N; ++i) {
1857 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1861 template <
typename Return, std::size_t N,
typename T,
typename... From>
1862 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1863 const From &... xs,
const T &last)
1865 Return r = simd_cast<Return>(xs...);
1866 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1867 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1871 template <
typename Return, std::
size_t N,
typename T>
1872 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1874 Return r = Return();
1875 for (
size_t i = 0; i < Return::size(); ++i) {
1876 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1882 template <
typename Return,
typename T,
typename... From>
1883 Vc_INTRINSIC_L Vc_CONST_L Return
1884 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1887 template <
typename... Ts>
struct are_all_types_equal;
1888 template <
typename T>
1889 struct are_all_types_equal<T> :
public std::integral_constant<bool, true>
1892 template <
typename T0,
typename T1,
typename... Ts>
1893 struct are_all_types_equal<T0, T1, Ts...>
1894 :
public std::integral_constant<
1895 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1919 template <
typename Return,
typename... Ts>
1920 Vc_INTRINSIC Vc_CONST Return
1921 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1925 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1926 Vc_INTRINSIC Vc_CONST
1927 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1928 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1930 template <
typename Return, std::
size_t offset,
typename From>
1931 Vc_INTRINSIC Vc_CONST
1932 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1933 simd_cast_with_offset(
const From &x);
1935 template <
typename Return, std::
size_t offset,
typename From>
1936 Vc_INTRINSIC Vc_CONST
1937 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1939 !Traits::isAtomicSimdArray<Return>::value) ||
1941 !Traits::isAtomicSimdMaskArray<Return>::value))),
1943 simd_cast_with_offset(
const From &x);
1945 template <
typename Return, std::
size_t offset,
typename From>
1946 Vc_INTRINSIC Vc_CONST
1947 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1949 Traits::isAtomicSimdArray<Return>::value) ||
1951 Traits::isAtomicSimdMaskArray<Return>::value))),
1953 simd_cast_with_offset(
const From &x);
1955 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1956 Vc_INTRINSIC Vc_CONST enable_if<
1957 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1958 simd_cast_with_offset(
const From &,
const Froms &... xs)
1960 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
1964 template <
typename Return, std::
size_t offset,
typename From>
1965 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
1972 template <
typename T,
typename... Ts>
struct first_type_of_impl
1976 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
1979 template <
typename Return,
typename From>
1980 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
1981 template <
typename Return,
typename... Froms>
1982 Vc_INTRINSIC Vc_CONST
1983 enable_if<(are_all_types_equal<Froms...>::value &&
1984 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1986 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
1990 template <
typename Return,
typename From,
typename... Froms>
1991 Vc_INTRINSIC Vc_CONST enable_if<
1992 (are_all_types_equal<From, Froms...>::value &&
1993 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1995 simd_cast_drop_arguments(Froms... xs, From x, From);
1996 template <
typename Return,
typename From>
1997 Vc_INTRINSIC Vc_CONST
1998 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1999 simd_cast_drop_arguments(From x, From);
2003 #ifdef Vc_DEBUG_SIMD_CAST 2004 void debugDoNothing(
const std::initializer_list<void *> &) {}
2005 template <
typename T0,
typename... Ts>
2006 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
2009 std::cerr << prefix << arg0;
2010 debugDoNothing({&(std::cerr <<
", " << args)...});
2011 std::cerr << suffix;
2014 template <
typename T0,
typename... Ts>
2015 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
2022 template <
size_t A,
size_t B>
2023 struct is_less :
public std::integral_constant<bool, (A < B)> {
2028 struct is_power_of_2 : public std::integral_constant<bool, ((N - 1) & N) == 0> {
2032 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2033 template <typename Return, typename T, typename A, typename... Froms> \
2034 Vc_INTRINSIC Vc_CONST enable_if< \
2035 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2036 is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2037 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2038 !detail::is_fixed_size_abi<A>::value), \
2040 simd_cast(NativeType_<T, A> x, Froms... xs) \
2042 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
2043 return {private_init, simd_cast<typename Return::storage_type>(x, xs...)}; \
2045 template <typename Return, typename T, typename A, typename... Froms> \
2046 Vc_INTRINSIC Vc_CONST enable_if< \
2047 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2048 !is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2049 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2050 !detail::is_fixed_size_abi<A>::value), \
2052 simd_cast(NativeType_<T, A> x, Froms... xs) \
2054 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
2055 return {simd_cast_without_last<Return, NativeType_<T, A>, Froms...>(x, xs...)}; \
2057 template <typename Return, typename T, typename A, typename... Froms> \
2058 Vc_INTRINSIC Vc_CONST \
2059 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2060 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2061 is_less<Common::left_size<Return::Size>(), \
2062 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2063 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2064 !detail::is_fixed_size_abi<A>::value), \
2066 simd_cast(NativeType_<T, A> x, Froms... xs) \
2068 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
2069 using R0 = typename Return::storage_type0; \
2070 using R1 = typename Return::storage_type1; \
2071 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
2072 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
2074 template <typename Return, typename T, typename A, typename... Froms> \
2075 Vc_INTRINSIC Vc_CONST \
2076 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2077 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2078 !is_less<Common::left_size<Return::Size>(), \
2079 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2080 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2081 !detail::is_fixed_size_abi<A>::value), \
2083 simd_cast(NativeType_<T, A> x, Froms... xs) \
2085 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
2086 using R0 = typename Return::storage_type0; \
2087 using R1 = typename Return::storage_type1; \
2088 return {simd_cast<R0>(x, xs...), R1(0)}; \
2090 Vc_NOTHING_EXPECTING_SEMICOLON
2092 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2093 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2094 #undef Vc_SIMDARRAY_CASTS
2097 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2099 template <typename Return, int offset, typename T, typename A> \
2100 Vc_INTRINSIC Vc_CONST \
2101 enable_if<Traits::isAtomic##SimdArrayType_<Return>::value, Return> \
2102 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG0) \
2104 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
2105 return {private_init, simd_cast<typename Return::storage_type, offset>(x)}; \
2108 template <typename Return, int offset, typename T, typename A> \
2109 Vc_INTRINSIC Vc_CONST \
2110 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2111 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2112 Return::Size * offset + Common::left_size<Return::Size>() < \
2113 NativeType_<T, A>::Size), \
2115 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG1) \
2117 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
2118 using R0 = typename Return::storage_type0; \
2119 constexpr int entries_offset = offset * Return::Size; \
2120 constexpr int entries_offset_right = entries_offset + R0::Size; \
2122 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
2123 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
2128 template <typename Return, int offset, typename T, typename A> \
2129 Vc_INTRINSIC Vc_CONST \
2130 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2131 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2132 Return::Size * offset + Common::left_size<Return::Size>() >= \
2133 NativeType_<T, A>::Size), \
2135 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG2) \
2137 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
2138 using R0 = typename Return::storage_type0; \
2139 using R1 = typename Return::storage_type1; \
2140 constexpr int entries_offset = offset * Return::Size; \
2141 return {simd_cast_with_offset<R0, entries_offset>(x), R1(0)}; \
2143 Vc_NOTHING_EXPECTING_SEMICOLON
2145 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2146 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2147 #undef Vc_SIMDARRAY_CASTS
2150 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
2152 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2153 Vc_INTRINSIC Vc_CONST \
2154 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2155 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
2156 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2158 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2160 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
2161 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
2164 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2165 Vc_INTRINSIC Vc_CONST \
2166 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2167 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
2168 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2170 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2172 vc_debug_(
"simd_cast{indivisible2}(",
")\n", x0, xs...); \
2173 return simd_cast_without_last<Return, \
2174 typename SimdArrayType_<T, N, V, N>::storage_type, \
2175 typename From::storage_type...>( \
2176 internal_data(x0), internal_data(xs)...); \
2179 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2181 Vc_INTRINSIC Vc_CONST enable_if< \
2182 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2183 !std::is_same<Return, SimdArrayType_<T, N, V, M>>::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{bisectable}(",
")\n", x0, xs...); \
2189 return simd_cast_interleaved_argument_order< \
2190 Return,
typename SimdArrayType_<T, N, V, M>::storage_type0, \
2191 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
2192 internal_data1(x0), internal_data1(xs)...); \
2196 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2198 Vc_INTRINSIC Vc_CONST enable_if< \
2199 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2200 !is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2202 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2204 vc_debug_(
"simd_cast{bisectable2}(",
")\n", x0, xs...); \
2205 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
2209 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2211 Vc_INTRINSIC Vc_CONST enable_if< \
2212 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2213 N * (1 +
sizeof...(From)) <= Return::Size && !is_power_of_2<N>::value), \
2215 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2217 vc_debug_(
"simd_cast{remaining}(",
")\n", x0, xs...); \
2218 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
2219 From...>(x0, xs...); \
2222 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2224 Vc_INTRINSIC Vc_CONST enable_if< \
2225 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2226 N * (1 +
sizeof...(From)) > Return::Size && !is_power_of_2<N>::value), \
2228 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2230 vc_debug_(
"simd_cast{remaining2}(",
")\n", x0, xs...); \
2231 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
2232 From...>(x0, xs...); \
2235 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2236 Vc_INTRINSIC Vc_CONST \
2237 enable_if<(N != M && N >= 2 * Return::Size && is_power_of_2<N>::value), Return> \
2238 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2240 vc_debug_(
"simd_cast{single bisectable}(",
")\n", x); \
2241 return simd_cast<Return>(internal_data0(x)); \
2243 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2244 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
2245 N < 2 * Return::Size && is_power_of_2<N>::value), \
2247 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2249 vc_debug_(
"simd_cast{single bisectable2}(",
")\n", x); \
2250 return simd_cast<Return>(internal_data0(x), internal_data1(x)); \
2252 Vc_NOTHING_EXPECTING_SEMICOLON
2254 Vc_SIMDARRAY_CASTS(SimdArray);
2256 #undef Vc_SIMDARRAY_CASTS 2257 template <
class Return,
class T,
int N,
class... Ts,
2258 class = enable_if<!std::is_same<Return, fixed_size_simd<T, N>>::value>>
2264 template <
class Return,
class T,
int N,
class... Ts,
2265 class = enable_if<!std::is_same<Return, fixed_size_simd_mask<T, N>>::value>>
2273 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \ 2275 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2277 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \ 2278 const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG0) \ 2280 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \ 2281 return simd_cast<Return>(x); \ 2284 template <typename Return, int offset, typename T, std::size_t N, typename V> \ 2285 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \ 2286 const SimdArrayType_<T, N, V, N> &x Vc_DUMMY_ARG1) \ 2288 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \ 2289 return simd_cast<Return, offset>(internal_data(x)); \ 2292 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2294 Vc_INTRINSIC Vc_CONST \ 2295 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2296 offset != 0 && Common::left_size<N>() % Return::Size == 0), \ 2298 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG2) \ 2300 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \ 2301 return simd_cast<Return, offset - Common::left_size<N>() / Return::Size>( \ 2302 internal_data1(x)); \ 2306 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2308 Vc_INTRINSIC Vc_CONST \ 2309 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2310 offset != 0 && Common::left_size<N>() % Return::Size != 0), \ 2312 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG3) \ 2314 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \ 2315 return simd_cast_with_offset<Return, \ 2316 offset * Return::Size - Common::left_size<N>()>( \ 2317 internal_data1(x)); \ 2320 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2322 Vc_INTRINSIC Vc_CONST enable_if< \ 2324 offset != 0 && (offset + 1) * Return::Size <= Common::left_size<N>()), \ 2326 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG4) \ 2328 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \ 2329 return simd_cast<Return, offset>(internal_data0(x)); \ 2332 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2334 Vc_INTRINSIC Vc_CONST \ 2335 enable_if<(N != M && (offset * Return::Size < Common::left_size<N>()) && \ 2336 offset != 0 && (offset + 1) * Return::Size > Common::left_size<N>()), \ 2338 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG5) \ 2340 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \ 2341 using R = typename Return::EntryType; \ 2342 Return r = Return(0); \ 2343 for (std::size_t i = offset * Return::Size; \ 2344 i < std::min(N, (offset + 1) * Return::Size); ++i) { \ 2345 r[i - offset * Return::Size] = static_cast<R>(x[i]); \ 2349 Vc_NOTHING_EXPECTING_SEMICOLON 2350 Vc_SIMDARRAY_CASTS(SimdArray);
2352 #undef Vc_SIMDARRAY_CASTS 2354 template <
typename Return,
typename From>
2355 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
2357 return simd_cast<Return>(x);
2359 template <
typename Return,
typename... Froms>
2360 Vc_INTRINSIC Vc_CONST
2361 enable_if<(are_all_types_equal<Froms...>::value &&
2362 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2364 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
2366 return simd_cast<Return>(xs..., x);
2371 template <
typename Return,
typename From,
typename... Froms>
2372 Vc_INTRINSIC Vc_CONST enable_if<
2373 (are_all_types_equal<From, Froms...>::value &&
2374 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2376 simd_cast_drop_arguments(Froms... xs, From x, From)
2378 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
2380 template <
typename Return,
typename From>
2381 Vc_INTRINSIC Vc_CONST
2382 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2383 simd_cast_drop_arguments(From x, From)
2385 return simd_cast_drop_arguments<Return>(x);
2389 template <
typename Return, std::
size_t offset,
typename From>
2390 Vc_INTRINSIC Vc_CONST
2391 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
2392 Return> simd_cast_with_offset(
const From &x)
2394 return simd_cast<Return, offset / Return::Size>(x);
2396 template <
typename Return, std::
size_t offset,
typename From>
2397 Vc_INTRINSIC Vc_CONST
2398 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2400 !Traits::isAtomicSimdArray<Return>::value) ||
2402 !Traits::isAtomicSimdMaskArray<Return>::value))),
2404 simd_cast_with_offset(
const From &x)
2406 using R0 =
typename Return::storage_type0;
2407 using R1 =
typename Return::storage_type1;
2408 return {simd_cast_with_offset<R0, offset>(x),
2409 simd_cast_with_offset<R1, offset + R0::Size>(x)};
2411 template <
typename Return, std::
size_t offset,
typename From>
2412 Vc_INTRINSIC Vc_CONST
2413 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2415 Traits::isAtomicSimdArray<Return>::value) ||
2417 Traits::isAtomicSimdMaskArray<Return>::value))),
2419 simd_cast_with_offset(
const From &x)
2421 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
2423 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
2424 Vc_INTRINSIC Vc_CONST
2425 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
2426 simd_cast_with_offset(
const From &x,
const Froms &... xs)
2428 return simd_cast<Return>(x, xs...);
2432 template <
typename Return,
typename T,
typename... From>
2433 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
2435 return simd_cast<Return>(xs...);
2444 template <std::
size_t I,
typename T0>
2445 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
const T0 &)
2449 template <std::
size_t I,
typename T0>
2450 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
const T0 &b0)
2457 template <std::size_t I,
typename T0,
typename... Ts>
2458 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2466 template <std::size_t I,
typename T0,
typename... Ts>
2467 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2475 template <std::size_t I,
typename T0,
typename... Ts>
2476 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2481 return extract_interleaved<I - 2, Ts...>(a..., b...);
2484 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2485 Vc_INTRINSIC Vc_CONST Return
2486 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2489 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2493 template <
typename Return,
typename... Ts>
2494 Vc_INTRINSIC Vc_CONST Return
2495 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2497 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2498 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2502 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \ 2503 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \ 2505 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \ 2506 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \ 2508 lhs(mask) op_ rhs; \ 2510 Vc_NOTHING_EXPECTING_SEMICOLON 2511 Vc_CONDITIONAL_ASSIGN( Assign, =);
2512 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
2513 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
2514 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
2515 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
2516 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
2517 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
2518 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
2519 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
2520 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
2521 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
2522 #undef Vc_CONDITIONAL_ASSIGN 2524 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \ 2525 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \ 2526 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \ 2527 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \ 2531 Vc_NOTHING_EXPECTING_SEMICOLON 2532 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
2533 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
2534 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
2535 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
2536 #undef Vc_CONDITIONAL_ASSIGN 2540 template <
typename T,
size_t N,
typename V>
2541 inline void transpose_impl(
2546 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2547 &internal_data(*r[2]), &internal_data(*r[3])};
2548 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2549 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2550 internal_data(std::get<1>(proxy.in)),
2551 internal_data(std::get<2>(proxy.in)),
2552 internal_data(std::get<3>(proxy.in))});
2555 template <
typename T,
typename V>
2556 inline void transpose_impl(
2563 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2564 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2565 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2566 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2567 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2568 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2569 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2570 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2573 template <
typename T,
typename V>
2574 inline void transpose_impl(
2579 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2580 &internal_data(*r[2]), &internal_data(*r[3])};
2581 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2582 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2583 internal_data(std::get<1>(proxy.in)),
2584 internal_data(std::get<2>(proxy.in)),
2585 internal_data(std::get<3>(proxy.in))});
2588 template <
typename T,
size_t N,
typename V>
2589 inline void transpose_impl(
2597 transpose_impl(TransposeTag<2, 4>(), &r0[0],
2598 TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2599 internal_data0(std::get<1>(proxy.in)),
2600 internal_data0(std::get<2>(proxy.in)),
2601 internal_data0(std::get<3>(proxy.in))});
2602 transpose_impl(TransposeTag<2, 4>(), &r1[0],
2603 TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2604 internal_data1(std::get<1>(proxy.in)),
2605 internal_data1(std::get<2>(proxy.in)),
2606 internal_data1(std::get<3>(proxy.in))});
2647 template <
class T,
size_t N,
class V,
size_t VSizeof>
2648 struct InterleaveImpl<SimdArray<T, N, V, N>, N, VSizeof> {
2649 template <
class I,
class... VV>
2650 static Vc_INTRINSIC
void interleave(T *
const data,
const I &i,
const VV &... vv)
2654 template <
class I,
class... VV>
2655 static Vc_INTRINSIC
void deinterleave(T
const *
const data,
const I &i, VV &... vv)
2696 template <
typename T,
size_t N,
typename V,
size_t VN>
2697 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2704 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2706 return numeric_limits<T>::lowest();
2708 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2710 return numeric_limits<T>::epsilon();
2712 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2714 return numeric_limits<T>::round_error();
2716 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2718 return numeric_limits<T>::infinity();
2720 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2722 return numeric_limits<T>::quiet_NaN();
2724 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2726 return numeric_limits<T>::signaling_NaN();
2728 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2730 return numeric_limits<T>::denorm_min();
2736 #endif // VC_COMMON_SIMDARRAY_H_ value_type operator[](size_t index) const noexcept
This operator can be used to read scalar entries of the vector.
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 ...
fixed_size_simd< T, N > max(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: max function component-wise and concurrently.
Vc::Vector< T > min(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
Vector apply(F &&f) const
Call f on every entry of the vector and return the results as a new vector.
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.
static fixed_size_simd< T, N > Zero()
Returns a vector with the entries initialized to zero.
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
fixed_size_simd< T, N > copysign(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: copysign function component-wise and concurrently.
Vc::Vector< T > max(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
static fixed_size_simd< T, N > IndexesFromZero()
Returns a vector with the entries initialized to 0, 1, 2, 3, 4, 5, ...
Identifies any possible SimdArray<T, N> type (independent of const/volatile or reference) ...
fixed_size_simd< T, N > atan2(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: atan2 function component-wise and concurrently.
fixed_size_simd< T, N > min(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: min function component-wise and concurrently.
Identifies any possible SimdMaskArray<T, N> type (independent of const/volatile or reference) ...
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...
fixed_size_simd< T, N > rotated(int amount) const
Rotate vector entries to the left by amount.
Vector reversed() const
Returns a vector with all components reversed.
fixed_size_simd< T, N > reversed() const
Returns a vector with all components reversed.
Data-parallel mask type with user-defined number of boolean elements.
Vector sorted() const
Return a sorted copy of the vector.
Vector rotated(int amount) const
Rotate vector entries to the left by amount.
Vector shifted(int amount) const
Shift vector entries to the left by amount; shifting in zeros.
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.
fixed_size_simd< T, N > sorted() const
Return a sorted copy of the vector.
fixed_size_simd_mask< T, N > isnegative(const SimdArray< T, N, V, M > &x)
Applies the std:: isnegative function component-wise and concurrently.
Identifies any SIMD vector type (independent of implementation or whether it's SimdArray<T, N>).
Common::WriteMaskedVector< SimdArray, mask_type > operator()(const mask_type &mask)
Writemask the vector before an assignment.
static fixed_size_simd< T, N > Random()
Returns a vector with pseudo-random entries.
Vector partialSum() const
Returns a vector containing the sum of all entries with smaller index.
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
static fixed_size_simd< T, N > One()
Returns a vector with the entries initialized to one.
fixed_size_simd< T, N > apply(F &&f) const
Call f on every entry of the vector and return the results as a new vector.
fixed_size_simd< T, N > apply(F &&f, const mask_type &k) const
As above, but skip the entries where mask is not set.
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)
constexpr AlignedTag Aligned
Use this object for a flags parameter to request aligned loads and stores.
void gather(const MT *mem, const IT &indexes)
Gather function.
SimdArray(value_type a)
Broadcast Constructor.
The main SIMD mask class.
void load(const EntryType *mem)
Load the vector entries from mem, overwriting the previous values.
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.
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.
Vector Classes Namespace.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true...
void scatter(MT *mem, IT &&indexes) const
Scatter function.
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.
fixed_size_simd< T, N > shifted(int amount) const
Shift vector entries to the left by amount; shifting in zeros.
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< T, N > ldexp(const SimdArray< T, N > &x, const SimdArray< int, N > &e)
Applies the std::ldexp function component-wise and concurrently.
fixed_size_simd< T, N > exponent(const SimdArray< T, N, V, M > &x)
Applies the std:: exponent function component-wise and concurrently.
static fixed_size_simd< T, N > generate(const G &gen)
Generate a vector object from return values of gen (static variant of fill).
fixed_size_simd< T, N > operator+() const
Returns a copy of itself.
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.