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>
94 inline fixed_size_simd<T, N>
min(
const SimdArray<T, N, V, M> &x,
95 const SimdArray<T, N, V, M> &y);
96 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
97 inline fixed_size_simd<T, N>
max(
const SimdArray<T, N, V, M> &x,
98 const SimdArray<T, N, V, M> &y);
105 #define Vc_CURRENT_CLASS_NAME SimdArray
115 template <
typename T, std::
size_t N,
typename VectorType_>
116 class SimdArray<T, N, VectorType_, N>
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;
138 using value_type = T;
139 using mask_type = fixed_size_simd_mask<T, N>;
140 using index_type = fixed_size_simd<int, N>;
141 static constexpr std::size_t size() {
return N; }
142 using Mask = mask_type;
143 using MaskType = Mask;
144 using MaskArgument =
const MaskType &;
145 using VectorEntryType = vectorentry_type;
146 using EntryType = value_type;
147 using IndexType = index_type;
148 using AsArg =
const SimdArray &;
149 using reference = Detail::ElementReference<SimdArray>;
150 static constexpr std::size_t Size = size();
154 Vc_INTRINSIC SimdArray() =
default;
157 Vc_INTRINSIC SimdArray(
const SimdArray &) =
default;
158 Vc_INTRINSIC SimdArray(SimdArray &&) =
default;
159 Vc_INTRINSIC SimdArray &operator=(
const SimdArray &) =
default;
162 Vc_INTRINSIC SimdArray(
const value_type &a) : data(a) {}
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>>
175 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x)
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)>,
181 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x)
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>
188 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x)
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,
221 enable_if<std::is_convertible<T, U>::value && Vector<U, A>::Size == N &&
222 !std::is_same<A, simd_abi::fixed_size<N>>::value>>
223 Vc_INTRINSIC
operator Vector<U, A>()
const
225 return simd_cast<Vector<U, A>>(data);
227 operator fixed_size_simd<T, N> &()
229 return static_cast<fixed_size_simd<T, N> &
>(*this);
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>
245 explicit Vc_INTRINSIC SimdArray(
246 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
249 data += value_type(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)...);
275 static Vc_INTRINSIC fixed_size_simd<T, N>
Zero()
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 = {}) : 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 = {})
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 = {})
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 = {})
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) {
1275 r.data1.load(&tmp[(amount + data0.size()) % size()],
Vc::Unaligned);
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_