28 #ifndef VC_COMMON_SIMDARRAY_H_ 29 #define VC_COMMON_SIMDARRAY_H_ 38 #include "writemaskedvector.h" 39 #include "simdarrayhelper.h" 40 #include "simdmaskarray.h" 42 #include "interleave.h" 43 #include "indexsequence.h" 44 #include "transpose.h" 47 namespace Vc_VERSIONED_NAMESPACE
58 template <std::size_t N,
class... Candidates>
struct select_best_vector_type_impl;
60 template <std::
size_t N,
class T>
struct select_best_vector_type_impl<N, T> {
64 template <std::size_t N,
class T,
class... Candidates>
65 struct select_best_vector_type_impl<N, T, Candidates...> {
66 using type =
typename std::conditional<
67 (N < T::Size),
typename select_best_vector_type_impl<N, Candidates...>::type,
70 template <
class T, std::
size_t N>
71 struct select_best_vector_type : select_best_vector_type_impl<N,
74 #elif defined Vc_IMPL_AVX
80 Vc::Scalar::Vector<T>> {
88 template <
typename T> T Vc_INTRINSIC Vc_PURE product_helper_(
const T &l,
const T &r) {
return l * r; }
89 template <
typename T> T Vc_INTRINSIC Vc_PURE sum_helper_(
const T &l,
const T &r) {
return l + r; }
93 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
96 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
105 #define Vc_CURRENT_CLASS_NAME SimdArray 115 template <
typename T, std::
size_t N,
typename VectorType_>
118 static_assert(std::is_same<T, double>::value || std::is_same<T, float>::value ||
119 std::is_same<T, int32_t>::value ||
120 std::is_same<T, uint32_t>::value ||
121 std::is_same<T, int16_t>::value ||
122 std::is_same<T, uint16_t>::value,
123 "SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, " 124 "int16_t, uint16_t }");
126 std::is_same<VectorType_,
127 typename Common::select_best_vector_type<T, N>::type>::value &&
128 VectorType_::size() == N,
129 "ERROR: leave the third and fourth template parameters with their defaults. They " 130 "are implementation details.");
133 static constexpr
bool is_atomic =
true;
134 using VectorType = VectorType_;
135 using vector_type = VectorType;
136 using storage_type = vector_type;
137 using vectorentry_type =
typename vector_type::VectorEntryType;
141 static constexpr std::size_t size() {
return N; }
142 using Mask = mask_type;
145 using VectorEntryType = vectorentry_type;
149 using reference = Detail::ElementReference<SimdArray>;
150 static constexpr std::size_t Size = size();
163 Vc_INTRINSIC
SimdArray(value_type &a) : data(a) {}
164 Vc_INTRINSIC SimdArray(value_type &&a) : data(a) {}
167 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
168 Vc_INTRINSIC SimdArray(U a)
169 : SimdArray(static_cast<value_type>(a))
174 template <
class U,
class V,
class = enable_if<N == V::Size>>
176 : data(simd_cast<vector_type>(internal_data(x)))
179 template <
class U,
class V,
class = enable_if<(N > V::Size && N <= 2 * V::Size)>,
182 : data(simd_cast<vector_type>(internal_data(internal_data0(x)),
183 internal_data(internal_data1(x))))
186 template <
class U,
class V,
class = enable_if<(N > 2 * V::Size && N <= 4 * V::Size)>,
187 class = U,
class = U>
189 : data(simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
190 internal_data(internal_data1(internal_data0(x))),
191 internal_data(internal_data0(internal_data1(x))),
192 internal_data(internal_data1(internal_data1(x)))))
196 template <
typename V, std::
size_t Pieces, std::
size_t Index>
197 Vc_INTRINSIC
SimdArray(Common::Segment<V, Pieces, Index> &&x)
198 : data(simd_cast<vector_type, Index>(x.data))
202 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
205 Vc_ASSERT(init.size() == size());
211 typename = enable_if<Traits::is_simd_vector<V>::value && !Traits::isSimdArray<V>::value>>
212 Vc_INTRINSIC SimdArray(
const V &x)
213 : data(simd_cast<vector_type>(x))
219 template <
typename U,
typename A,
222 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
231 operator const fixed_size_simd<T, N> &()
const 233 return static_cast<const fixed_size_simd<T, N> &
>(*this);
236 #include "gatherinterface.h" 237 #include "scatterinterface.h" 239 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerZero) : data() {}
240 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerOne o) : data(o) {}
241 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerIndexesFromZero i) : data(i)
244 template <std::
size_t Offset>
246 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
252 Vc_INTRINSIC
void setZero() { data.setZero(); }
253 Vc_INTRINSIC
void setZero(mask_type k) { data.setZero(internal_data(k)); }
254 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
255 Vc_INTRINSIC
void setZeroInverted(mask_type k) { data.setZeroInverted(internal_data(k)); }
257 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
258 Vc_INTRINSIC
void setQnan(mask_type m) { data.setQnan(internal_data(m)); }
261 template <
typename Op,
typename... Args>
262 static Vc_INTRINSIC fixed_size_simd<T, N> fromOperation(Op op, Args &&... args)
264 fixed_size_simd<T, N> r;
265 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
269 template <
typename Op,
typename... Args>
270 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
272 Common::unpackArgumentsAuto(op,
nullptr, std::forward<Args>(args)...);
279 static Vc_INTRINSIC fixed_size_simd<T, N>
One()
287 static Vc_INTRINSIC fixed_size_simd<T, N> Random()
289 return fromOperation(Common::Operations::random());
294 class = enable_if<std::is_arithmetic<U>::value &&
295 Traits::is_load_store_flag<Flags>::value>>
296 explicit Vc_INTRINSIC
SimdArray(
const U *mem, Flags f = Flags()) : data(mem, f)
300 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
302 data.load(std::forward<Args>(args)...);
305 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const 307 data.store(std::forward<Args>(args)...);
310 Vc_INTRINSIC mask_type operator!()
const 312 return {private_init, !data};
315 Vc_INTRINSIC fixed_size_simd<T, N>
operator-()
const 317 return {private_init, -data};
321 Vc_INTRINSIC fixed_size_simd<T, N>
operator+()
const {
return *
this; }
323 Vc_INTRINSIC fixed_size_simd<T, N> operator~()
const 325 return {private_init, ~data};
328 template <
typename U,
329 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
330 Vc_INTRINSIC Vc_CONST fixed_size_simd<T, N>
operator<<(U x)
const 332 return {private_init, data << x};
334 template <
typename U,
335 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
336 Vc_INTRINSIC fixed_size_simd<T, N> &operator<<=(U x)
341 template <
typename U,
342 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
343 Vc_INTRINSIC Vc_CONST fixed_size_simd<T, N> operator>>(U x)
const 345 return {private_init, data >> x};
347 template <
typename U,
348 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
349 Vc_INTRINSIC fixed_size_simd<T, N> &operator>>=(U x)
355 #define Vc_BINARY_OPERATOR_(op) \ 356 Vc_INTRINSIC fixed_size_simd<T, N> &operator op##=(const SimdArray &rhs) \ 358 data op## = rhs.data; \ 361 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
362 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
363 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
364 #undef Vc_BINARY_OPERATOR_ 367 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC MaskType isNegative()
const 374 Vc_INTRINSIC
static value_type
get(
const SimdArray &o,
int i) noexcept
378 template <
typename U>
379 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
380 noexcept(std::declval<value_type &>() = v))
392 Vc_INTRINSIC reference operator[](
size_t i) noexcept
394 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
395 return {*
this, int(i)};
397 Vc_INTRINSIC value_type operator[](
size_t i)
const noexcept
399 return get(*
this, int(i));
402 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
407 Vc_INTRINSIC
void assign(
const SimdArray &v,
const mask_type &k)
409 data.assign(v.data, internal_data(k));
413 #define Vc_REDUCTION_FUNCTION_(name_) \ 414 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \ 415 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \ 417 return data.name_(internal_data(mask)); \ 419 Vc_NOTHING_EXPECTING_SEMICOLON 420 Vc_REDUCTION_FUNCTION_(
min);
421 Vc_REDUCTION_FUNCTION_(
max);
422 Vc_REDUCTION_FUNCTION_(product);
423 Vc_REDUCTION_FUNCTION_(sum);
424 #undef Vc_REDUCTION_FUNCTION_ 425 Vc_INTRINSIC Vc_PURE fixed_size_simd<T, N> partialSum()
const 427 return {private_init, data.partialSum()};
430 template <
typename F> Vc_INTRINSIC fixed_size_simd<T, N> apply(F &&f)
const 432 return {private_init, data.apply(std::forward<F>(f))};
434 template <
typename F> Vc_INTRINSIC fixed_size_simd<T, N> apply(F &&f,
const mask_type &k)
const 436 return {private_init, data.apply(std::forward<F>(f), k)};
439 Vc_INTRINSIC fixed_size_simd<T, N>
shifted(
int amount)
const 441 return {private_init, data.shifted(amount)};
444 template <std::
size_t NN>
445 Vc_INTRINSIC fixed_size_simd<T, N>
shifted(
int amount,
const SimdArray<value_type, NN> &shiftIn)
448 return {private_init, data.shifted(amount, simd_cast<VectorType>(shiftIn))};
451 Vc_INTRINSIC fixed_size_simd<T, N> rotated(
int amount)
const 453 return {private_init, data.rotated(amount)};
457 Vc_DEPRECATED(
"use exponent(x) instead") Vc_INTRINSIC fixed_size_simd<T, N> exponent()
const 459 return {private_init,
exponent(data)};
462 Vc_INTRINSIC fixed_size_simd<T, N> interleaveLow(SimdArray x)
const 464 return {private_init, data.interleaveLow(x.data)};
466 Vc_INTRINSIC fixed_size_simd<T, N> interleaveHigh(SimdArray x)
const 468 return {private_init, data.interleaveHigh(x.data)};
471 Vc_INTRINSIC fixed_size_simd<T, N> reversed()
const 473 return {private_init, data.reversed()};
476 Vc_INTRINSIC fixed_size_simd<T, N> sorted()
const 478 return {private_init, data.sorted()};
481 template <
class G,
class = decltype(std::declval<G>()(std::
size_t())),
482 class = enable_if<!Traits::is_simd_vector<G>::value>>
483 Vc_INTRINSIC SimdArray(
const G &gen) : data(gen)
486 template <
typename G>
static Vc_INTRINSIC fixed_size_simd<T, N> generate(
const G &gen)
488 return {private_init, VectorType::generate(gen)};
491 Vc_DEPRECATED(
"use copysign(x, y) instead")
492 Vc_INTRINSIC fixed_size_simd<T, N> copySign(const SimdArray &x)
const 497 friend VectorType &internal_data<>(SimdArray &x);
498 friend const VectorType &internal_data<>(
const SimdArray &x);
501 Vc_INTRINSIC SimdArray(private_init_t, VectorType &&x) : data(
std::move(x)) {}
503 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type));
509 alignas(
static_cast<std::size_t
>(
510 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
511 VectorType_::size()>::value)) storage_type data;
513 template <
typename T, std::
size_t N,
typename VectorType> constexpr std::size_t SimdArray<T, N, VectorType, N>::Size;
514 template <
typename T, std::
size_t N,
typename VectorType>
516 template <
typename T, std::
size_t N,
typename VectorType>
520 VectorType &internal_data(SimdArray<T, N, VectorType, N> &x)
524 template <
typename T, std::
size_t N,
typename VectorType>
528 const VectorType &internal_data(
const SimdArray<T, N, VectorType, N> &x)
534 template <
class T> Vc_INTRINSIC T unwrap(
const T &x) {
return x; }
536 template <
class T,
size_t N,
class V>
537 Vc_INTRINSIC V unwrap(
const SimdArray<T, N, V, N> &x)
539 return internal_data(x);
542 template <
class T,
size_t Pieces,
size_t Index>
543 Vc_INTRINSIC
auto unwrap(
const Common::Segment<T, Pieces, Index> &x)
544 -> decltype(x.to_fixed_size())
546 return unwrap(x.to_fixed_size());
550 template <
typename T, std::
size_t N,
typename VectorType>
551 template <
class MT,
class IT,
int Scale>
552 Vc_INTRINSIC
void SimdArray<T, N, VectorType, N>::gatherImplementation(
553 const Common::GatherArguments<MT, IT, Scale> &args)
555 data.gather(Common::make_gather<Scale>(args.address, unwrap(args.indexes)));
557 template <
typename T, std::
size_t N,
typename VectorType>
558 template <
class MT,
class IT,
int Scale>
559 Vc_INTRINSIC
void SimdArray<T, N, VectorType, N>::gatherImplementation(
560 const Common::GatherArguments<MT, IT, Scale> &args, MaskArgument mask)
562 data.gather(Common::make_gather<Scale>(args.address, unwrap(args.indexes)),
567 template <
typename T, std::
size_t N,
typename VectorType>
568 template <
typename MT,
typename IT>
569 inline void SimdArray<T, N, VectorType, N>::scatterImplementation(MT *mem,
572 data.scatter(mem, unwrap(std::forward<IT>(indexes)));
574 template <
typename T, std::
size_t N,
typename VectorType>
575 template <
typename MT,
typename IT>
576 inline void SimdArray<T, N, VectorType, N>::scatterImplementation(MT *mem,
578 MaskArgument mask)
const 580 data.scatter(mem, unwrap(std::forward<IT>(indexes)), mask);
616 template <
typename T,
size_t N,
typename V,
size_t Wt>
class SimdArray
618 static_assert(std::is_same<T, double>::value ||
619 std::is_same<T, float>::value ||
620 std::is_same<T, int32_t>::value ||
621 std::is_same<T, uint32_t>::value ||
622 std::is_same<T, int16_t>::value ||
623 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 }");
625 std::is_same<V,
typename Common::select_best_vector_type<T, N>::type>::value &&
627 "ERROR: leave the third and fourth template parameters with their defaults. They " 628 "are implementation details.");
631 std::is_same<typename V::EntryType, typename V::VectorEntryType>::value ||
633 (N % V::size() == 0),
634 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * " 635 "MIC::(u)short_v::size(), i.e. k * 16.");
637 using my_traits = SimdArrayTraits<T, N>;
638 static constexpr std::size_t N0 = my_traits::N0;
639 static constexpr std::size_t N1 = my_traits::N1;
640 using Split = Common::Split<N0>;
641 template <
typename U, std::
size_t K>
using CArray = U[K];
644 static constexpr
bool is_atomic =
false;
645 using storage_type0 =
typename my_traits::storage_type0;
646 using storage_type1 =
typename my_traits::storage_type1;
647 static_assert(storage_type0::size() == N0,
"");
652 using vector_type = V;
653 using vectorentry_type =
typename storage_type0::vectorentry_type;
654 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
675 static constexpr std::size_t
size() {
return N; }
682 using VectorEntryType = vectorentry_type;
689 using reference = Detail::ElementReference<SimdArray>;
721 return fromOperation(Common::Operations::random());
724 template <
class G,
class = decltype(std::declval<G>()(std::
size_t())),
725 class = enable_if<!Traits::is_simd_vector<G>::value>>
727 : data0(gen), data1([&](
std::size_t i) {
return gen(i + storage_type0::size()); })
734 auto tmp = storage_type0::generate(gen);
739 return {std::move(tmp),
740 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
758 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
766 SimdArray(
const SimdArray &) =
default;
767 SimdArray(SimdArray &&) =
default;
768 SimdArray &operator=(
const SimdArray &) =
default;
771 template <
typename U,
typename Flags = DefaultLoadTag,
772 typename = enable_if<std::is_arithmetic<U>::value &&
773 Traits::is_load_store_flag<Flags>::value>>
774 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
775 : data0(mem, f), data1(mem + storage_type0::size(), f)
787 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
788 typename = enable_if<std::is_arithmetic<U>::value &&
789 Traits::is_load_store_flag<Flags>::value>>
790 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
791 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
797 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
798 typename = enable_if<std::is_arithmetic<U>::value &&
799 Traits::is_load_store_flag<Flags>::value>>
800 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
801 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
807 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
809 , data1(init.begin() + storage_type0::size(),
Vc::
Unaligned)
811 Vc_ASSERT(init.size() == size());
814 #include "gatherinterface.h" 815 #include "scatterinterface.h" 817 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerZero) : data0(), data1() {}
818 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerOne o) : data0(o), data1(o) {}
819 explicit Vc_INTRINSIC SimdArray(VectorSpecialInitializerIndexesFromZero i)
821 , data1(Common::AddOffset<VectorSpecialInitializerIndexesFromZero,
822 storage_type0::size()>())
825 template <
size_t Offset>
826 explicit Vc_INTRINSIC SimdArray(
827 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset> i)
829 , data1(Common::AddOffset<VectorSpecialInitializerIndexesFromZero,
830 storage_type0::size() + Offset>())
835 template <
class W,
class = enable_if<
836 (Traits::is_simd_vector<W>::value &&
837 Traits::simd_vector_size<W>::value == N &&
838 !(std::is_convertible<Traits::entry_type_of<W>, T>::value &&
839 Traits::isSimdArray<W>::value))>>
840 Vc_INTRINSIC
explicit SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
845 template <
class W,
class = enable_if<
846 (Traits::isSimdArray<W>::value &&
847 Traits::simd_vector_size<W>::value == N &&
848 std::is_convertible<Traits::entry_type_of<W>, T>::value)>,
850 Vc_INTRINSIC SimdArray(W &&x) : data0(Split::lo(x)), data1(Split::hi(x))
854 template <
class W, std::
size_t Pieces, std::
size_t Index>
855 Vc_INTRINSIC SimdArray(Common::Segment<W, Pieces, Index> &&x)
856 : data0(Common::Segment<W, 2 * Pieces, 2 * Index>{x.data})
857 , data1(Common::Segment<W, 2 * Pieces, 2 * Index + 1>{x.data})
863 template <
typename U,
typename A,
865 enable_if<std::is_convertible<T, U>::value && Vector<U, A>::Size == N &&
866 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
867 operator Vector<U, A>()
const 869 auto r = simd_cast<Vector<U, A>>(data0, data1);
872 Vc_INTRINSIC
operator fixed_size_simd<T, N> &()
874 return static_cast<fixed_size_simd<T, N> &
>(*this);
876 Vc_INTRINSIC
operator const fixed_size_simd<T, N> &()
const 878 return static_cast<const fixed_size_simd<T, N> &
>(*this);
883 Vc_INTRINSIC
void setZero()
888 Vc_INTRINSIC
void setZero(
const mask_type &k)
890 data0.setZero(Split::lo(k));
891 data1.setZero(Split::hi(k));
893 Vc_INTRINSIC
void setZeroInverted()
895 data0.setZeroInverted();
896 data1.setZeroInverted();
898 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
900 data0.setZeroInverted(Split::lo(k));
901 data1.setZeroInverted(Split::hi(k));
905 Vc_INTRINSIC
void setQnan() {
909 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
910 data0.setQnan(Split::lo(m));
911 data1.setQnan(Split::hi(m));
915 template <
typename Op,
typename... Args>
916 static Vc_INTRINSIC fixed_size_simd<T, N> fromOperation(Op op, Args &&... args)
918 fixed_size_simd<T, N> r = {
919 storage_type0::fromOperation(op, Split::lo(args)...),
922 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
927 template <
typename Op,
typename... Args>
928 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
930 storage_type0::callOperation(op, Split::lo(args)...);
931 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
935 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
937 data0.load(mem, Split::lo(args)...);
939 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
942 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const 944 data0.store(mem, Split::lo(args)...);
946 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
949 Vc_INTRINSIC mask_type operator!()
const 951 return {!data0, !data1};
954 Vc_INTRINSIC fixed_size_simd<T, N>
operator-()
const 956 return {-data0, -data1};
964 return {~data0, ~data1};
968 template <
typename U,
969 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
970 Vc_INTRINSIC Vc_CONST fixed_size_simd<T, N>
operator<<(U x)
const 972 return {data0 << x, data1 << x};
974 template <
typename U,
975 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
976 Vc_INTRINSIC fixed_size_simd<T, N> &operator<<=(U x)
982 template <
typename U,
983 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
984 Vc_INTRINSIC Vc_CONST fixed_size_simd<T, N> operator>>(U x)
const 986 return {data0 >> x, data1 >> x};
988 template <
typename U,
989 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
990 Vc_INTRINSIC fixed_size_simd<T, N> &operator>>=(U x)
998 #define Vc_BINARY_OPERATOR_(op) \ 999 Vc_INTRINSIC fixed_size_simd<T, N> &operator op##=(const SimdArray &rhs) \ 1001 data0 op## = rhs.data0; \ 1002 data1 op## = rhs.data1; \ 1005 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
1006 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
1007 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
1008 #undef Vc_BINARY_OPERATOR_ 1016 Vc_INTRINSIC
static value_type
get(
const SimdArray &o,
int i) noexcept
1018 return reinterpret_cast<const alias_type *
>(&o)[i];
1020 template <
typename U>
1021 Vc_INTRINSIC
static void set(SimdArray &o,
int i, U &&v) noexcept(
1022 noexcept(std::declval<value_type &>() = v))
1024 reinterpret_cast<alias_type *
>(&o)[i] = v;
1037 static_assert(noexcept(reference{std::declval<SimdArray &>(),
int()}),
"");
1038 return {*
this, int(i)};
1044 return get(*
this, int(index));
1050 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type>
operator()(
1053 return {*
this, mask};
1059 data0.assign(v.data0, internal_data0(k));
1060 data1.assign(v.data1, internal_data1(k));
1064 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \ 1066 template <typename ForSfinae = void> \ 1067 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1068 storage_type0::Size == storage_type1::Size, \ 1069 value_type> name_##_impl() const \ 1071 return binary_fun_(data0, data1).name_(); \ 1074 template <typename ForSfinae = void> \ 1075 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \ 1076 storage_type0::Size != storage_type1::Size, \ 1077 value_type> name_##_impl() const \ 1079 return scalar_fun_(data0.name_(), data1.name_()); \ 1084 Vc_INTRINSIC value_type name_() const { return name_##_impl(); } \ 1086 Vc_INTRINSIC value_type name_(const mask_type &mask) const \ 1088 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \ 1089 return data1.name_(Split::hi(mask)); \ 1090 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \ 1091 return data0.name_(Split::lo(mask)); \ 1093 return scalar_fun_(data0.name_(Split::lo(mask)), \ 1094 data1.name_(Split::hi(mask))); \ 1097 Vc_NOTHING_EXPECTING_SEMICOLON 1100 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_);
1101 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_);
1102 #undef Vc_REDUCTION_FUNCTION_ 1108 tmp[0] += ps0[data0.size() - 1];
1116 return {data0.apply(f), data1.apply(f)};
1119 template <
typename F>
1122 return {data0.apply(f, Split::lo(k)), data1.apply(f, Split::hi(k))};
1129 constexpr
int SSize = Size;
1130 constexpr
int SSize0 = storage_type0::Size;
1131 constexpr
int SSize1 = storage_type1::Size;
1136 if (amount > -SSize0) {
1137 return {data0.shifted(amount), data1.shifted(amount, data0)};
1139 if (amount == -SSize0) {
1140 return {storage_type0(0), simd_cast<storage_type1>(data0)};
1142 if (amount < -SSize0) {
1143 return {storage_type0(0), simd_cast<storage_type1>(data0.shifted(
1148 if (amount >= SSize) {
1150 }
else if (amount >= SSize0) {
1152 simd_cast<storage_type0>(data1).
shifted(amount - SSize0),
1154 }
else if (amount >= SSize1) {
1155 return {data0.shifted(amount, data1), storage_type1(0)};
1157 return {data0.shifted(amount, data1), data1.shifted(amount)};
1162 template <std::
size_t NN>
1164 !(std::is_same<storage_type0, storage_type1>::value &&
1169 constexpr
int SSize = Size;
1174 return operator[](i);
1175 }
else if (i >= -SSize) {
1176 return shiftIn[i + SSize];
1181 return fixed_size_simd<T, N>([&](
int i) -> value_type {
1184 return operator[](i);
1185 }
else if (i < 2 * SSize) {
1186 return shiftIn[i - SSize];
1195 template <std::
size_t NN>
struct bisectable_shift
1196 :
public std::integral_constant<bool,
1197 std::is_same<storage_type0, storage_type1>::value &&
1203 template <std::
size_t NN>
1204 inline fixed_size_simd<T, N>
shifted(
1205 enable_if<bisectable_shift<NN>::value,
int> amount,
1206 const SimdArray<value_type, NN> &shiftIn)
const 1208 constexpr
int SSize = Size;
1210 if (amount > -static_cast<int>(storage_type0::Size)) {
1211 return {data0.shifted(amount, internal_data1(shiftIn)),
1212 data1.shifted(amount, data0)};
1214 if (amount == -static_cast<int>(storage_type0::Size)) {
1215 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
1217 if (amount > -SSize) {
1219 internal_data1(shiftIn)
1220 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1221 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1223 if (amount == -SSize) {
1226 if (amount > -2 * SSize) {
1227 return shiftIn.shifted(amount + SSize);
1233 if (amount < static_cast<int>(storage_type0::Size)) {
1234 return {data0.shifted(amount, data1),
1235 data1.shifted(amount, internal_data0(shiftIn))};
1237 if (amount == static_cast<int>(storage_type0::Size)) {
1238 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1240 if (amount < SSize) {
1241 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1242 internal_data0(shiftIn)
1243 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1245 if (amount == SSize) {
1248 if (amount < 2 * SSize) {
1249 return shiftIn.shifted(amount - SSize);
1258 amount %= int(size());
1261 }
else if (amount < 0) {
1278 auto &&d0cvtd = simd_cast<storage_type1>(data0);
1279 auto &&d1cvtd = simd_cast<storage_type0>(data1);
1280 constexpr
int size0 = storage_type0::size();
1281 constexpr
int size1 = storage_type1::size();
1283 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1284 return {std::move(d1cvtd), std::move(d0cvtd)};
1285 }
else if (amount < size1) {
1286 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1287 }
else if (amount == size1) {
1288 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1289 }
else if (
int(size()) - amount < size1) {
1290 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1291 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1292 }
else if (
int(size()) - amount == size1) {
1293 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1294 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1295 }
else if (amount <= size0) {
1296 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1297 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1299 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1300 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1311 return {data0.interleaveLow(x.data0),
1312 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1315 Vc_INTRINSIC fixed_size_simd<T, N> interleaveHigh(
const SimdArray &x)
const 1317 return interleaveHighImpl(
1319 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1324 Vc_INTRINSIC fixed_size_simd<T, N> interleaveHighImpl(
const SimdArray &x, std::true_type)
const 1326 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1329 inline fixed_size_simd<T, N> interleaveHighImpl(
const SimdArray &x, std::false_type)
const 1331 return {data0.interleaveHigh(x.data0)
1332 .shifted(storage_type1::Size,
1333 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1334 data1.interleaveHigh(x.data1)};
1341 if (std::is_same<storage_type0, storage_type1>::value) {
1342 return {simd_cast<storage_type0>(data1).reversed(),
1343 simd_cast<storage_type1>(data0).reversed()};
1354 return {data0.shifted(storage_type1::Size, data1).reversed(),
1355 simd_cast<storage_type1>(data0.reversed().shifted(
1356 storage_type0::Size - storage_type1::Size))};
1364 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1370 #ifdef Vc_DEBUG_SORTED 1371 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1373 const auto a = data0.
sorted();
1375 const auto lo =
Vc::min(a, b);
1376 const auto hi =
Vc::max(a, b);
1377 return {lo.sorted(), hi.sorted()};
1381 Vc_INTRINSIC fixed_size_simd<T, N> sortedImpl(std::false_type)
const 1383 using SortableArray =
1384 fixed_size_simd<value_type, Common::NextPowerOfTwo<size()>::value>;
1385 auto sortable = simd_cast<SortableArray>(*this);
1386 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1387 using limits = std::numeric_limits<value_type>;
1388 if (limits::has_infinity) {
1389 sortable[i] = limits::infinity();
1394 return simd_cast<fixed_size_simd<T, N>>(sortable.sorted());
1428 static constexpr std::size_t Size = size();
1431 Vc_DEPRECATED(
"use exponent(x) instead")
1438 Vc_DEPRECATED(
"use isnegative(x) instead") Vc_INTRINSIC
MaskType isNegative()
const 1444 Vc_DEPRECATED(
"use copysign(x, y) instead")
1453 friend storage_type0 &internal_data0<>(
SimdArray &x);
1454 friend storage_type1 &internal_data1<>(
SimdArray &x);
1455 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1456 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1459 Vc_INTRINSIC
SimdArray(storage_type0 &&x, storage_type1 &&y)
1460 : data0(
std::move(x)), data1(
std::move(y))
1464 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type0));
1470 alignas(
static_cast<std::size_t
>(
1471 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
1472 V::size()>::value)) storage_type0 data0;
1473 storage_type1 data1;
1475 #undef Vc_CURRENT_CLASS_NAME 1476 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>
1482 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1483 template <
class MT,
class IT,
int Scale>
1485 const Common::GatherArguments<MT, IT, Scale> &args)
1487 data0.
gather(Common::make_gather<Scale>(
1488 args.address, Split::lo(Common::Operations::gather(), args.indexes)));
1489 data1.gather(Common::make_gather<Scale>(
1490 args.address, Split::hi(Common::Operations::gather(), args.indexes)));
1492 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1493 template <
class MT,
class IT,
int Scale>
1494 inline void SimdArray<T, N, VectorType, M>::gatherImplementation(
1495 const Common::GatherArguments<MT, IT, Scale> &args, MaskArgument mask)
1497 data0.gather(Common::make_gather<Scale>(
1498 args.address, Split::lo(Common::Operations::gather(), args.indexes)),
1500 data1.gather(Common::make_gather<Scale>(
1501 args.address, Split::hi(Common::Operations::gather(), args.indexes)),
1506 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1507 template <
typename MT,
typename IT>
1508 inline void SimdArray<T, N, VectorType, M>::scatterImplementation(MT *mem,
1511 data0.scatter(mem, Split::lo(Common::Operations::gather(),
1514 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1516 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1517 template <
typename MT,
typename IT>
1518 inline void SimdArray<T, N, VectorType, M>::scatterImplementation(MT *mem,
1519 IT &&indexes, MaskArgument mask)
const 1521 data0.scatter(mem, Split::lo(Common::Operations::gather(), indexes),
1524 data1.scatter(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1530 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1534 typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1535 SimdArray<T, N, V, M> &x)
1540 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1544 typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1545 SimdArray<T, N, V, M> &x)
1550 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1554 const typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1555 const SimdArray<T, N, V, M> &x)
1560 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1564 const typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1565 const SimdArray<T, N, V, M> &x)
1573 #if defined Vc_MSVC && defined Vc_IMPL_SSE && !defined Vc_IMPL_AVX 1575 Vc_INTRINSIC SimdArray<double, 8>::SimdArray(fixed_size_simd<double, 4> &&x,
1576 fixed_size_simd<double, 4> &&y)
1577 : data0(x), data1(0)
1586 #define Vc_FIXED_OP(op) \ 1587 template <class T, int N, \ 1588 class = typename std::enable_if<fixed_size_simd<T, N>::is_atomic>::type> \ 1589 fixed_size_simd<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1590 const fixed_size_simd<T, N> &b) \ 1592 return {private_init, internal_data(a) op internal_data(b)}; \ 1594 template <class T, int N, \ 1595 class = typename std::enable_if<!fixed_size_simd<T, N>::is_atomic>::type, \ 1597 fixed_size_simd<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1598 const fixed_size_simd<T, N> &b) \ 1600 return {internal_data0(a) op internal_data0(b), \ 1601 internal_data1(a) op internal_data1(b)}; \ 1603 Vc_ALL_ARITHMETICS(Vc_FIXED_OP);
1604 Vc_ALL_BINARY(Vc_FIXED_OP);
1605 Vc_ALL_SHIFTS(Vc_FIXED_OP);
1607 #define Vc_FIXED_OP(op) \ 1608 template <class T, int N, \ 1609 class = typename std::enable_if<fixed_size_simd<T, N>::is_atomic>::type> \ 1610 fixed_size_simd_mask<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1611 const fixed_size_simd<T, N> &b) \ 1613 return {private_init, internal_data(a) op internal_data(b)}; \ 1615 template <class T, int N, \ 1616 class = typename std::enable_if<!fixed_size_simd<T, N>::is_atomic>::type, \ 1618 fixed_size_simd_mask<T, N> operator op(const fixed_size_simd<T, N> &a, \ 1619 const fixed_size_simd<T, N> &b) \ 1621 return {internal_data0(a) op internal_data0(b), \ 1622 internal_data1(a) op internal_data1(b)}; \ 1624 Vc_ALL_COMPARES(Vc_FIXED_OP);
1630 namespace result_vector_type_internal
1632 template <
typename T>
1633 using remove_cvref =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1635 template <
typename T>
1636 using is_integer_larger_than_int = std::integral_constant<
1637 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1638 std::is_same<T, long>::value ||
1639 std::is_same<T, unsigned long>::value)>;
1642 typename L,
typename R,
1643 std::size_t N = Traits::isSimdArray<L>::value ? Traits::simd_vector_size<L>::value
1644 : Traits::simd_vector_size<R>::value,
1645 bool = (Traits::isSimdArray<L>::value ||
1646 Traits::isSimdArray<R>::value) &&
1647 !(Traits::is_fixed_size_simd<L>::value &&
1648 Traits::is_fixed_size_simd<R>::value) &&
1649 ((std::is_arithmetic<remove_cvref<L>>::value &&
1650 !is_integer_larger_than_int<remove_cvref<L>>::value) ||
1651 (std::is_arithmetic<remove_cvref<R>>::value &&
1652 !is_integer_larger_than_int<remove_cvref<R>>::value) ||
1655 Traits::simd_vector_size<L>::value == Traits::simd_vector_size<R>::value)>
1658 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1661 using LScalar = Traits::entry_type_of<L>;
1662 using RScalar = Traits::entry_type_of<R>;
1664 template <
bool B,
typename T,
typename F>
1665 using conditional =
typename std::conditional<B, T, F>::type;
1678 using type = fixed_size_simd<
1679 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1680 sizeof(LScalar) <
sizeof(
int) &&
1681 sizeof(RScalar) <
sizeof(
int)),
1682 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1683 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1684 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1685 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1691 template <
typename L,
typename R>
1692 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1694 #define Vc_BINARY_OPERATORS_(op_) \ 1696 template <typename L, typename R> \ 1697 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \ 1699 using Return = result_vector_type<L, R>; \ 1700 return Vc::Detail::operator op_( \ 1701 static_cast<const Return &>(std::forward<L>(lhs)), \ 1702 static_cast<const Return &>(std::forward<R>(rhs))); \ 1721 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_);
1723 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_);
1725 #undef Vc_BINARY_OPERATORS_ 1726 #define Vc_BINARY_OPERATORS_(op_) \ 1728 template <typename L, typename R> \ 1729 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \ 1732 using Promote = result_vector_type<L, R>; \ 1733 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \ 1752 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_);
1755 #undef Vc_BINARY_OPERATORS_ 1758 #define Vc_FORWARD_UNARY_OPERATOR(name_) \ 1760 template <typename T, std::size_t N, typename V, std::size_t M> \ 1761 inline fixed_size_simd<T, N> name_(const SimdArray<T, N, V, M> &x) \ 1763 return fixed_size_simd<T, N>::fromOperation( \ 1764 Common::Operations::Forward_##name_(), x); \ 1766 template <class T, int N> \ 1767 fixed_size_simd<T, N> name_(const fixed_size_simd<T, N> &x) \ 1769 return fixed_size_simd<T, N>::fromOperation( \ 1770 Common::Operations::Forward_##name_(), x); \ 1772 Vc_NOTHING_EXPECTING_SEMICOLON 1774 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \ 1776 template <typename T, std::size_t N, typename V, std::size_t M> \ 1777 inline fixed_size_simd_mask<T, N> name_(const SimdArray<T, N, V, M> &x) \ 1779 return fixed_size_simd_mask<T, N>::fromOperation( \ 1780 Common::Operations::Forward_##name_(), x); \ 1782 template <class T, int N> \ 1783 fixed_size_simd_mask<T, N> name_(const fixed_size_simd<T, N> &x) \ 1785 return fixed_size_simd_mask<T, N>::fromOperation( \ 1786 Common::Operations::Forward_##name_(), x); \ 1788 Vc_NOTHING_EXPECTING_SEMICOLON 1790 #define Vc_FORWARD_BINARY_OPERATOR(name_) \ 1792 template <typename T, std::size_t N, typename V, std::size_t M> \ 1793 inline fixed_size_simd<T, N> name_(const SimdArray<T, N, V, M> &x, \ 1794 const SimdArray<T, N, V, M> &y) \ 1796 return fixed_size_simd<T, N>::fromOperation( \ 1797 Common::Operations::Forward_##name_(), x, y); \ 1799 Vc_NOTHING_EXPECTING_SEMICOLON 1805 Vc_FORWARD_UNARY_OPERATOR(abs);
1807 Vc_FORWARD_UNARY_OPERATOR(asin);
1808 Vc_FORWARD_UNARY_OPERATOR(atan);
1810 Vc_FORWARD_UNARY_OPERATOR(ceil);
1812 Vc_FORWARD_UNARY_OPERATOR(cos);
1813 Vc_FORWARD_UNARY_OPERATOR(exp);
1814 Vc_FORWARD_UNARY_OPERATOR(exponent);
1815 Vc_FORWARD_UNARY_OPERATOR(floor);
1817 template <
typename T, std::
size_t N>
1823 Vc_FORWARD_UNARY_BOOL_OPERATOR(isfinite);
1824 Vc_FORWARD_UNARY_BOOL_OPERATOR(isinf);
1825 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnan);
1826 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnegative);
1828 template <
typename T, std::
size_t N>
1834 template <
typename T, std::
size_t N>
1839 Vc_FORWARD_UNARY_OPERATOR(log);
1840 Vc_FORWARD_UNARY_OPERATOR(log10);
1841 Vc_FORWARD_UNARY_OPERATOR(log2);
1842 Vc_FORWARD_UNARY_OPERATOR(reciprocal);
1843 Vc_FORWARD_UNARY_OPERATOR(round);
1844 Vc_FORWARD_UNARY_OPERATOR(rsqrt);
1845 Vc_FORWARD_UNARY_OPERATOR(sin);
1847 template <
typename T, std::
size_t N>
1852 Vc_FORWARD_UNARY_OPERATOR(sqrt);
1853 Vc_FORWARD_UNARY_OPERATOR(trunc);
1854 Vc_FORWARD_BINARY_OPERATOR(
min);
1855 Vc_FORWARD_BINARY_OPERATOR(
max);
1857 #undef Vc_FORWARD_UNARY_OPERATOR 1858 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR 1859 #undef Vc_FORWARD_BINARY_OPERATOR 1863 #define Vc_DUMMY_ARG0 , int = 0 1864 #define Vc_DUMMY_ARG1 , long = 0 1865 #define Vc_DUMMY_ARG2 , short = 0 1866 #define Vc_DUMMY_ARG3 , char = '0' 1867 #define Vc_DUMMY_ARG4 , unsigned = 0u 1868 #define Vc_DUMMY_ARG5 , unsigned short = 0u 1870 #define Vc_DUMMY_ARG0 1871 #define Vc_DUMMY_ARG1 1872 #define Vc_DUMMY_ARG2 1873 #define Vc_DUMMY_ARG3 1874 #define Vc_DUMMY_ARG4 1875 #define Vc_DUMMY_ARG5 1882 template <
typename Return, std::size_t N,
typename T,
typename... From>
1883 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1884 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1886 Return r = simd_cast<Return>(xs...);
1887 for (
size_t i = 0; i < N; ++i) {
1888 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1892 template <
typename Return, std::
size_t N,
typename T>
1893 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1895 Return r = Return();
1896 for (
size_t i = 0; i < N; ++i) {
1897 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1901 template <
typename Return, std::size_t N,
typename T,
typename... From>
1902 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1903 const From &... xs,
const T &last)
1905 Return r = simd_cast<Return>(xs...);
1906 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1907 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1911 template <
typename Return, std::
size_t N,
typename T>
1912 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1914 Return r = Return();
1915 for (
size_t i = 0; i < Return::size(); ++i) {
1916 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1922 template <
typename Return,
typename T,
typename... From>
1923 Vc_INTRINSIC_L Vc_CONST_L Return
1924 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1927 template <
typename... Ts>
struct are_all_types_equal;
1928 template <
typename T>
1929 struct are_all_types_equal<T> :
public std::integral_constant<bool, true>
1932 template <
typename T0,
typename T1,
typename... Ts>
1933 struct are_all_types_equal<T0, T1, Ts...>
1934 :
public std::integral_constant<
1935 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1959 template <
typename Return,
typename... Ts>
1960 Vc_INTRINSIC Vc_CONST Return
1961 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1965 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1966 Vc_INTRINSIC Vc_CONST
1967 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1968 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1970 template <
typename Return, std::
size_t offset,
typename From>
1971 Vc_INTRINSIC Vc_CONST
1972 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1973 simd_cast_with_offset(
const From &x);
1975 template <
typename Return, std::
size_t offset,
typename From>
1976 Vc_INTRINSIC Vc_CONST
1977 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1978 ((Traits::isSimdArray<Return>::value &&
1979 !Traits::isAtomicSimdArray<Return>::value) ||
1980 (Traits::isSimdMaskArray<Return>::value &&
1981 !Traits::isAtomicSimdMaskArray<Return>::value))),
1983 simd_cast_with_offset(
const From &x);
1985 template <
typename Return, std::
size_t offset,
typename From>
1986 Vc_INTRINSIC Vc_CONST
1987 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1988 ((Traits::isSimdArray<Return>::value &&
1989 Traits::isAtomicSimdArray<Return>::value) ||
1990 (Traits::isSimdMaskArray<Return>::value &&
1991 Traits::isAtomicSimdMaskArray<Return>::value))),
1993 simd_cast_with_offset(
const From &x);
1995 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1996 Vc_INTRINSIC Vc_CONST enable_if<
1997 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1998 simd_cast_with_offset(
const From &,
const Froms &... xs)
2000 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
2004 template <
typename Return, std::
size_t offset,
typename From>
2005 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
2012 template <
typename T,
typename... Ts>
struct first_type_of_impl
2016 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
2019 template <
typename Return,
typename From>
2020 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
2021 template <
typename Return,
typename... Froms>
2022 Vc_INTRINSIC Vc_CONST
2023 enable_if<(are_all_types_equal<Froms...>::value &&
2024 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2026 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
2030 template <
typename Return,
typename From,
typename... Froms>
2031 Vc_INTRINSIC Vc_CONST enable_if<
2032 (are_all_types_equal<From, Froms...>::value &&
2033 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2035 simd_cast_drop_arguments(Froms... xs, From x, From);
2036 template <
typename Return,
typename From>
2037 Vc_INTRINSIC Vc_CONST
2038 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2039 simd_cast_drop_arguments(From x, From);
2043 #ifdef Vc_DEBUG_SIMD_CAST 2044 void debugDoNothing(
const std::initializer_list<void *> &) {}
2045 template <
typename T0,
typename... Ts>
2046 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
2049 std::cerr << prefix << arg0;
2050 debugDoNothing({&(std::cerr <<
", " << args)...});
2051 std::cerr << suffix;
2054 template <
typename T0,
typename... Ts>
2055 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
2062 template <
size_t A,
size_t B>
2063 struct is_less :
public std::integral_constant<bool, (A < B)> {
2068 struct is_power_of_2 : public std::integral_constant<bool, ((N - 1) & N) == 0> {
2072 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2073 template <typename Return, typename T, typename A, typename... Froms> \
2074 Vc_INTRINSIC Vc_CONST enable_if< \
2075 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2076 is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2077 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2078 !detail::is_fixed_size_abi<A>::value), \
2080 simd_cast(NativeType_<T, A> x, Froms... xs) \
2082 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
2083 return {private_init, simd_cast<typename Return::storage_type>(x, xs...)}; \
2085 template <typename Return, typename T, typename A, typename... Froms> \
2086 Vc_INTRINSIC Vc_CONST enable_if< \
2087 (Traits::isAtomic##SimdArrayType_<Return>::value && \
2088 !is_less<NativeType_<T, A>::Size * sizeof...(Froms), Return::Size>::value && \
2089 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2090 !detail::is_fixed_size_abi<A>::value), \
2092 simd_cast(NativeType_<T, A> x, Froms... xs) \
2094 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
2095 return {simd_cast_without_last<Return, NativeType_<T, A>, Froms...>(x, xs...)}; \
2097 template <typename Return, typename T, typename A, typename... Froms> \
2098 Vc_INTRINSIC Vc_CONST \
2099 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2100 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2101 is_less<Common::left_size<Return::Size>(), \
2102 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2103 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2104 !detail::is_fixed_size_abi<A>::value), \
2106 simd_cast(NativeType_<T, A> x, Froms... xs) \
2108 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
2109 using R0 = typename Return::storage_type0; \
2110 using R1 = typename Return::storage_type1; \
2111 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
2112 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
2114 template <typename Return, typename T, typename A, typename... Froms> \
2115 Vc_INTRINSIC Vc_CONST \
2116 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2117 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2118 !is_less<Common::left_size<Return::Size>(), \
2119 NativeType_<T, A>::Size *(1 + sizeof...(Froms))>::value && \
2120 are_all_types_equal<NativeType_<T, A>, Froms...>::value && \
2121 !detail::is_fixed_size_abi<A>::value), \
2123 simd_cast(NativeType_<T, A> x, Froms... xs) \
2125 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
2126 using R0 = typename Return::storage_type0; \
2127 using R1 = typename Return::storage_type1; \
2128 return {simd_cast<R0>(x, xs...), R1(0)}; \
2130 Vc_NOTHING_EXPECTING_SEMICOLON
2132 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2133 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2134 #undef Vc_SIMDARRAY_CASTS
2137 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, NativeType_) \
2139 template <typename Return, int offset, typename T, typename A> \
2140 Vc_INTRINSIC Vc_CONST \
2141 enable_if<Traits::isAtomic##SimdArrayType_<Return>::value, Return> \
2142 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG0) \
2144 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
2145 return {private_init, simd_cast<typename Return::storage_type, offset>(x)}; \
2148 template <typename Return, int offset, typename T, typename A> \
2149 Vc_INTRINSIC Vc_CONST \
2150 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2151 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2152 Return::Size * offset + Common::left_size<Return::Size>() < \
2153 NativeType_<T, A>::Size), \
2155 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG1) \
2157 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
2158 using R0 = typename Return::storage_type0; \
2159 constexpr int entries_offset = offset * Return::Size; \
2160 constexpr int entries_offset_right = entries_offset + R0::Size; \
2162 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
2163 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
2168 template <typename Return, int offset, typename T, typename A> \
2169 Vc_INTRINSIC Vc_CONST \
2170 enable_if<(Traits::is##SimdArrayType_<Return>::value && \
2171 !Traits::isAtomic##SimdArrayType_<Return>::value && \
2172 Return::Size * offset + Common::left_size<Return::Size>() >= \
2173 NativeType_<T, A>::Size), \
2175 simd_cast(NativeType_<T, A> x Vc_DUMMY_ARG2) \
2177 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
2178 using R0 = typename Return::storage_type0; \
2179 using R1 = typename Return::storage_type1; \
2180 constexpr int entries_offset = offset * Return::Size; \
2181 return {simd_cast_with_offset<R0, entries_offset>(x), R1(0)}; \
2183 Vc_NOTHING_EXPECTING_SEMICOLON
2185 Vc_SIMDARRAY_CASTS(SimdArray, Vc::Vector);
2186 Vc_SIMDARRAY_CASTS(SimdMaskArray, Vc::Mask);
2187 #undef Vc_SIMDARRAY_CASTS
2190 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
2192 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2193 Vc_INTRINSIC Vc_CONST \
2194 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2195 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
2196 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2198 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2200 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
2201 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
2204 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
2205 Vc_INTRINSIC Vc_CONST \
2206 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
2207 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
2208 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
2210 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
2212 vc_debug_(
"simd_cast{indivisible2}(",
")\n", x0, xs...); \
2213 return simd_cast_without_last<Return, \
2214 typename SimdArrayType_<T, N, V, N>::storage_type, \
2215 typename From::storage_type...>( \
2216 internal_data(x0), internal_data(xs)...); \
2219 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2221 Vc_INTRINSIC Vc_CONST enable_if< \
2222 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2223 !std::is_same<Return, SimdArrayType_<T, N, V, M>>::value && \
2224 is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2226 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2228 vc_debug_(
"simd_cast{bisectable}(",
")\n", x0, xs...); \
2229 return simd_cast_interleaved_argument_order< \
2230 Return,
typename SimdArrayType_<T, N, V, M>::storage_type0, \
2231 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
2232 internal_data1(x0), internal_data1(xs)...); \
2236 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2238 Vc_INTRINSIC Vc_CONST enable_if< \
2239 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2240 !is_less<N *
sizeof...(From), Return::Size>::value && is_power_of_2<N>::value), \
2242 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2244 vc_debug_(
"simd_cast{bisectable2}(",
")\n", x0, xs...); \
2245 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
2249 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2251 Vc_INTRINSIC Vc_CONST enable_if< \
2252 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2253 N * (1 +
sizeof...(From)) <= Return::Size && !is_power_of_2<N>::value), \
2255 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2257 vc_debug_(
"simd_cast{remaining}(",
")\n", x0, xs...); \
2258 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
2259 From...>(x0, xs...); \
2262 template <
typename Return,
typename T, std::size_t N,
typename V, std::size_t M, \
2264 Vc_INTRINSIC Vc_CONST enable_if< \
2265 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
2266 N * (1 +
sizeof...(From)) > Return::Size && !is_power_of_2<N>::value), \
2268 simd_cast(
const SimdArrayType_<T, N, V, M> &x0,
const From &... xs) \
2270 vc_debug_(
"simd_cast{remaining2}(",
")\n", x0, xs...); \
2271 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
2272 From...>(x0, xs...); \
2275 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2276 Vc_INTRINSIC Vc_CONST \
2277 enable_if<(N != M && N >= 2 * Return::Size && is_power_of_2<N>::value), Return> \
2278 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2280 vc_debug_(
"simd_cast{single bisectable}(",
")\n", x); \
2281 return simd_cast<Return>(internal_data0(x)); \
2283 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
2284 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
2285 N < 2 * Return::Size && is_power_of_2<N>::value), \
2287 simd_cast(
const SimdArrayType_<T, N, V, M> &x) \
2289 vc_debug_(
"simd_cast{single bisectable2}(",
")\n", x); \
2290 return simd_cast<Return>(internal_data0(x), internal_data1(x)); \
2292 Vc_NOTHING_EXPECTING_SEMICOLON
2294 Vc_SIMDARRAY_CASTS(SimdArray);
2295 Vc_SIMDARRAY_CASTS(SimdMaskArray);
2296 #undef Vc_SIMDARRAY_CASTS 2297 template <
class Return,
class T,
int N,
class... Ts,
2298 class = enable_if<!std::is_same<Return, fixed_size_simd<T, N>>::value>>
2299 Vc_INTRINSIC Return simd_cast(
const fixed_size_simd<T, N> &x,
const Ts &... xs)
2301 return simd_cast<Return>(
static_cast<const SimdArray<T, N> &
>(x),
2302 static_cast<const SimdArray<T, N> &
>(xs)...);
2304 template <
class Return,
class T,
int N,
class... Ts,
2305 class = enable_if<!std::is_same<Return, fixed_size_simd_mask<T, N>>::value>>
2306 Vc_INTRINSIC Return simd_cast(
const fixed_size_simd_mask<T, N> &x,
const Ts &... xs)
2308 return simd_cast<Return>(
static_cast<const SimdMaskArray<T, N> &
>(x),
2309 static_cast<const SimdMaskArray<T, N> &
>(xs)...);
2313 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \ 2315 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2317 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \ 2318 const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG0) \ 2320 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \ 2321 return simd_cast<Return>(x); \ 2324 template <typename Return, int offset, typename T, std::size_t N, typename V> \ 2325 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \ 2326 const SimdArrayType_<T, N, V, N> &x Vc_DUMMY_ARG1) \ 2328 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \ 2329 return simd_cast<Return, offset>(internal_data(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 && Common::left_size<N>() % Return::Size == 0), \ 2338 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG2) \ 2340 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \ 2341 return simd_cast<Return, offset - Common::left_size<N>() / Return::Size>( \ 2342 internal_data1(x)); \ 2346 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2348 Vc_INTRINSIC Vc_CONST \ 2349 enable_if<(N != M && offset * Return::Size >= Common::left_size<N>() && \ 2350 offset != 0 && Common::left_size<N>() % Return::Size != 0), \ 2352 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG3) \ 2354 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \ 2355 return simd_cast_with_offset<Return, \ 2356 offset * Return::Size - Common::left_size<N>()>( \ 2357 internal_data1(x)); \ 2360 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2362 Vc_INTRINSIC Vc_CONST enable_if< \ 2364 offset != 0 && (offset + 1) * Return::Size <= Common::left_size<N>()), \ 2366 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG4) \ 2368 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \ 2369 return simd_cast<Return, offset>(internal_data0(x)); \ 2372 template <typename Return, int offset, typename T, std::size_t N, typename V, \ 2374 Vc_INTRINSIC Vc_CONST \ 2375 enable_if<(N != M && (offset * Return::Size < Common::left_size<N>()) && \ 2376 offset != 0 && (offset + 1) * Return::Size > Common::left_size<N>()), \ 2378 simd_cast(const SimdArrayType_<T, N, V, M> &x Vc_DUMMY_ARG5) \ 2380 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \ 2381 using R = typename Return::EntryType; \ 2382 Return r = Return(0); \ 2383 for (std::size_t i = offset * Return::Size; \ 2384 i < std::min(N, (offset + 1) * Return::Size); ++i) { \ 2385 r[i - offset * Return::Size] = static_cast<R>(x[i]); \ 2389 Vc_NOTHING_EXPECTING_SEMICOLON 2390 Vc_SIMDARRAY_CASTS(SimdArray);
2391 Vc_SIMDARRAY_CASTS(SimdMaskArray);
2392 #undef Vc_SIMDARRAY_CASTS 2394 template <
typename Return,
typename From>
2395 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
2397 return simd_cast<Return>(x);
2399 template <
typename Return,
typename... Froms>
2400 Vc_INTRINSIC Vc_CONST
2401 enable_if<(are_all_types_equal<Froms...>::value &&
2402 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2404 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
2406 return simd_cast<Return>(xs..., x);
2411 template <
typename Return,
typename From,
typename... Froms>
2412 Vc_INTRINSIC Vc_CONST enable_if<
2413 (are_all_types_equal<From, Froms...>::value &&
2414 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2416 simd_cast_drop_arguments(Froms... xs, From x, From)
2418 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
2420 template <
typename Return,
typename From>
2421 Vc_INTRINSIC Vc_CONST
2422 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2423 simd_cast_drop_arguments(From x, From)
2425 return simd_cast_drop_arguments<Return>(x);
2429 template <
typename Return, std::
size_t offset,
typename From>
2430 Vc_INTRINSIC Vc_CONST
2431 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
2432 Return> simd_cast_with_offset(
const From &x)
2434 return simd_cast<Return, offset / Return::Size>(x);
2436 template <
typename Return, std::
size_t offset,
typename From>
2437 Vc_INTRINSIC Vc_CONST
2438 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2439 ((Traits::isSimdArray<Return>::value &&
2440 !Traits::isAtomicSimdArray<Return>::value) ||
2441 (Traits::isSimdMaskArray<Return>::value &&
2442 !Traits::isAtomicSimdMaskArray<Return>::value))),
2444 simd_cast_with_offset(
const From &x)
2446 using R0 =
typename Return::storage_type0;
2447 using R1 =
typename Return::storage_type1;
2448 return {simd_cast_with_offset<R0, offset>(x),
2449 simd_cast_with_offset<R1, offset + R0::Size>(x)};
2451 template <
typename Return, std::
size_t offset,
typename From>
2452 Vc_INTRINSIC Vc_CONST
2453 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2454 ((Traits::isSimdArray<Return>::value &&
2455 Traits::isAtomicSimdArray<Return>::value) ||
2456 (Traits::isSimdMaskArray<Return>::value &&
2457 Traits::isAtomicSimdMaskArray<Return>::value))),
2459 simd_cast_with_offset(
const From &x)
2461 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
2463 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
2464 Vc_INTRINSIC Vc_CONST
2465 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
2466 simd_cast_with_offset(
const From &x,
const Froms &... xs)
2468 return simd_cast<Return>(x, xs...);
2472 template <
typename Return,
typename T,
typename... From>
2473 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
2475 return simd_cast<Return>(xs...);
2484 template <std::
size_t I,
typename T0>
2485 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
const T0 &)
2489 template <std::
size_t I,
typename T0>
2490 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
const T0 &b0)
2497 template <std::size_t I,
typename T0,
typename... Ts>
2498 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2506 template <std::size_t I,
typename T0,
typename... Ts>
2507 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2515 template <std::size_t I,
typename T0,
typename... Ts>
2516 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2521 return extract_interleaved<I - 2, Ts...>(a..., b...);
2524 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2525 Vc_INTRINSIC Vc_CONST Return
2526 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2529 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2533 template <
typename Return,
typename... Ts>
2534 Vc_INTRINSIC Vc_CONST Return
2535 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2537 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2538 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2542 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \ 2543 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \ 2545 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \ 2546 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \ 2548 lhs(mask) op_ rhs; \ 2550 Vc_NOTHING_EXPECTING_SEMICOLON 2551 Vc_CONDITIONAL_ASSIGN( Assign, =);
2552 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
2553 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
2554 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
2555 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
2556 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
2557 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
2558 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
2559 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
2560 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
2561 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
2562 #undef Vc_CONDITIONAL_ASSIGN 2564 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \ 2565 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \ 2566 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \ 2567 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \ 2571 Vc_NOTHING_EXPECTING_SEMICOLON 2572 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
2573 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
2574 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
2575 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
2576 #undef Vc_CONDITIONAL_ASSIGN 2580 template <
typename T,
size_t N,
typename V>
2581 inline void transpose_impl(
2582 TransposeTag<4, 4>, SimdArray<T, N, V, N> *Vc_RESTRICT r[],
2583 const TransposeProxy<SimdArray<T, N, V, N>, SimdArray<T, N, V, N>,
2584 SimdArray<T, N, V, N>, SimdArray<T, N, V, N>> &proxy)
2586 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2587 &internal_data(*r[2]), &internal_data(*r[3])};
2588 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2589 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2590 internal_data(std::get<1>(proxy.in)),
2591 internal_data(std::get<2>(proxy.in)),
2592 internal_data(std::get<3>(proxy.in))});
2595 template <
typename T,
typename V>
2596 inline void transpose_impl(
2597 TransposeTag<2, 4>, SimdArray<T, 4, V, 1> *Vc_RESTRICT r[],
2598 const TransposeProxy<SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>,
2599 SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>> &proxy)
2603 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2604 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2605 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2606 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2607 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2608 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2609 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2610 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2613 template <
typename T,
typename V>
2614 inline void transpose_impl(
2615 TransposeTag<4, 4>, SimdArray<T, 1, V, 1> *Vc_RESTRICT r[],
2616 const TransposeProxy<SimdArray<T, 1, V, 1>, SimdArray<T, 1, V, 1>,
2617 SimdArray<T, 1, V, 1>, SimdArray<T, 1, V, 1>> &proxy)
2619 V *Vc_RESTRICT r2[4] = {&internal_data(*r[0]), &internal_data(*r[1]),
2620 &internal_data(*r[2]), &internal_data(*r[3])};
2621 transpose_impl(TransposeTag<4, 4>(), &r2[0],
2622 TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2623 internal_data(std::get<1>(proxy.in)),
2624 internal_data(std::get<2>(proxy.in)),
2625 internal_data(std::get<3>(proxy.in))});
2628 template <
typename T,
size_t N,
typename V>
2629 inline void transpose_impl(
2630 TransposeTag<4, 4>, SimdArray<T, N, V, 1> *Vc_RESTRICT r[],
2631 const TransposeProxy<SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>,
2632 SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>> &proxy)
2634 SimdArray<T, N, V, 1> *Vc_RESTRICT r0[4 / 2] = {r[0], r[1]};
2635 SimdArray<T, N, V, 1> *Vc_RESTRICT r1[4 / 2] = {r[2], r[3]};
2636 using H = SimdArray<T, 2>;
2637 transpose_impl(TransposeTag<2, 4>(), &r0[0],
2638 TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2639 internal_data0(std::get<1>(proxy.in)),
2640 internal_data0(std::get<2>(proxy.in)),
2641 internal_data0(std::get<3>(proxy.in))});
2642 transpose_impl(TransposeTag<2, 4>(), &r1[0],
2643 TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2644 internal_data1(std::get<1>(proxy.in)),
2645 internal_data1(std::get<2>(proxy.in)),
2646 internal_data1(std::get<3>(proxy.in))});
2687 template <
class T,
size_t N,
class V,
size_t VSizeof>
2688 struct InterleaveImpl<SimdArray<T, N, V, N>, N, VSizeof> {
2689 template <
class I,
class... VV>
2690 static Vc_INTRINSIC
void interleave(T *
const data,
const I &i,
const VV &... vv)
2694 template <
class I,
class... VV>
2695 static Vc_INTRINSIC
void deinterleave(T
const *
const data,
const I &i, VV &... vv)
2736 template <
typename T,
size_t N,
typename V,
size_t VN>
2737 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2744 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2746 return numeric_limits<T>::lowest();
2748 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2750 return numeric_limits<T>::epsilon();
2752 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2754 return numeric_limits<T>::round_error();
2756 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2758 return numeric_limits<T>::infinity();
2760 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2762 return numeric_limits<T>::quiet_NaN();
2764 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2766 return numeric_limits<T>::signaling_NaN();
2768 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2770 return numeric_limits<T>::denorm_min();
2776 #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)
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, ...
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.
Data-parallel arithmetic type with user-defined number of elements.
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.
Vector sorted() const
Return a sorted copy of the vector.
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.
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...
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...
fixed_size_simd< T, N > cos(const SimdArray< T, N, V, M > &x)
Applies the std:: cos function component-wise and concurrently.
fixed_size_simd< T, N > sin(const SimdArray< T, N, V, M > &x)
Applies the std:: sin function component-wise and concurrently.
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.