29 #ifndef VC_COMMON_SIMDARRAY_H_
30 #define VC_COMMON_SIMDARRAY_H_
34 #if defined Vc_DEBUG_SIMD_CAST || defined Vc_DEBUG_SORTED
40 #include "writemaskedvector.h"
41 #include "simdarrayhelper.h"
42 #include "simdmaskarray.h"
44 #include "interleave.h"
45 #include "indexsequence.h"
46 #include "transpose.h"
49 namespace Vc_VERSIONED_NAMESPACE
54 template <
typename T> T Vc_INTRINSIC Vc_PURE product_helper_(
const T &l,
const T &r) {
return l * r; }
55 template <
typename T> T Vc_INTRINSIC Vc_PURE sum_helper_(
const T &l,
const T &r) {
return l + r; }
59 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
60 inline SimdArray<T, N, V, M>
min(
const SimdArray<T, N, V, M> &x,
61 const SimdArray<T, N, V, M> &y);
62 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
63 inline SimdArray<T, N, V, M>
max(
const SimdArray<T, N, V, M> &x,
64 const SimdArray<T, N, V, M> &y);
71 #define Vc_CURRENT_CLASS_NAME SimdArray
81 template <
typename T, std::
size_t N,
typename VectorType_>
84 ((Common::nextPowerOfTwo(N) * (sizeof(VectorType_) / VectorType_::size()) - 1) & 127) +
86 1) SimdArray<T, N, VectorType_, N>
88 static_assert(std::is_same<T, double>::value || std::is_same<T, float>::value ||
89 std::is_same<T, int32_t>::value ||
90 std::is_same<T, uint32_t>::value ||
91 std::is_same<T, int16_t>::value ||
92 std::is_same<T, uint16_t>::value,
93 "SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, "
94 "int16_t, uint16_t }");
97 using VectorType = VectorType_;
98 using vector_type = VectorType;
99 using storage_type = vector_type;
100 using vectorentry_type =
typename vector_type::VectorEntryType;
101 using value_type = T;
102 using mask_type = SimdMaskArray<T, N, vector_type>;
103 using index_type = SimdArray<int, N>;
104 static constexpr std::size_t size() {
return N; }
105 using Mask = mask_type;
106 using MaskType = Mask;
107 using MaskArgument =
const MaskType &;
108 using VectorEntryType = vectorentry_type;
109 using EntryType = value_type;
110 using IndexType = index_type;
111 using AsArg =
const SimdArray &;
112 static constexpr std::size_t Size = size();
116 Vc_INTRINSIC SimdArray() =
default;
119 Vc_INTRINSIC SimdArray(
const SimdArray &) =
default;
120 Vc_INTRINSIC SimdArray(SimdArray &&) =
default;
121 Vc_INTRINSIC SimdArray &operator=(
const SimdArray &) =
default;
124 Vc_INTRINSIC SimdArray(
const value_type &a) : data(a) {}
125 Vc_INTRINSIC SimdArray(value_type &a) : data(a) {}
126 Vc_INTRINSIC SimdArray(value_type &&a) : data(a) {}
129 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
130 Vc_INTRINSIC SimdArray(U a)
131 : SimdArray(static_cast<value_type>(a))
136 template <
typename U,
typename V>
137 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x, enable_if<N == V::size()> = nullarg)
138 : data(
simd_cast<vector_type>(internal_data(x)))
141 template <
typename U,
typename V>
142 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x,
143 enable_if<(N > V::size() && N <= 2 * V::size())> = nullarg)
144 : data(
simd_cast<vector_type>(internal_data(internal_data0(x)), internal_data(internal_data1(x))))
147 template <
typename U,
typename V>
148 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x,
149 enable_if<(N > 2 * V::size() && N <= 4 * V::size())> = nullarg)
150 : data(
simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
151 internal_data(internal_data1(internal_data0(x))),
152 internal_data(internal_data0(internal_data1(x))),
153 internal_data(internal_data1(internal_data1(x)))))
157 template <
typename V, std::
size_t Pieces, std::
size_t Index>
158 Vc_INTRINSIC SimdArray(Common::Segment<V, Pieces, Index> &&x)
159 : data(
simd_cast<vector_type, Index>(x.data))
163 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
166 #if defined Vc_CXX14 && 0 // doesn't compile yet
167 static_assert(init.size() == size(),
"The initializer_list argument to "
168 "SimdArray<T, N> must contain exactly N "
171 Vc_ASSERT(init.size() == size());
178 typename = enable_if<Traits::is_simd_vector<V>::value && !Traits::isSimdArray<V>::value>>
179 explicit Vc_INTRINSIC SimdArray(
const V &x)
186 template <
typename V,
187 typename = enable_if<
189 std::is_convertible<T, typename V::EntryType>::value && V::size() == N>>
190 Vc_INTRINSIC
operator V()
const
195 #include "gatherinterface.h"
198 template <
typename... Args,
199 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
200 !Traits::is_gather_signature<Args...>::value &&
201 !Traits::is_initializer_list<Args...>::value>>
202 explicit Vc_INTRINSIC SimdArray(Args &&... args)
203 : data(
std::forward<Args>(args)...)
207 template <std::
size_t Offset>
208 explicit Vc_INTRINSIC SimdArray(
209 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
212 data += value_type(Offset);
215 Vc_INTRINSIC
void setZero() { data.setZero(); }
216 Vc_INTRINSIC
void setZero(mask_type k) { data.setZero(internal_data(k)); }
217 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
218 Vc_INTRINSIC
void setZeroInverted(mask_type k) { data.setZeroInverted(internal_data(k)); }
220 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
221 Vc_INTRINSIC
void setQnan(mask_type m) { data.setQnan(internal_data(m)); }
224 template <
typename Op,
typename... Args>
225 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
232 template <
typename Op,
typename... Args>
233 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
238 static Vc_INTRINSIC SimdArray
Zero()
242 static Vc_INTRINSIC SimdArray
One()
250 static Vc_INTRINSIC SimdArray Random()
252 return fromOperation(Common::Operations::random());
255 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
257 data.load(std::forward<Args>(args)...);
260 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const
262 data.store(std::forward<Args>(args)...);
265 Vc_INTRINSIC mask_type operator!()
const
270 Vc_INTRINSIC SimdArray operator-()
const
276 Vc_INTRINSIC SimdArray operator+()
const {
return *
this; }
278 Vc_INTRINSIC SimdArray operator~()
const
283 template <
typename U,
284 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
285 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const
289 template <
typename U,
290 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
291 Vc_INTRINSIC SimdArray &operator<<=(U x)
296 template <
typename U,
297 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
298 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const
302 template <
typename U,
303 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
304 Vc_INTRINSIC SimdArray &operator>>=(U x)
310 #define Vc_BINARY_OPERATOR_(op) \
311 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \
313 return {data op rhs.data}; \
315 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \
317 data op## = rhs.data; \
320 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_)
321 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_)
322 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_)
323 #undef Vc_BINARY_OPERATOR_
325 #define Vc_COMPARES(op) \
326 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \
328 return {data op rhs.data}; \
330 Vc_ALL_COMPARES(Vc_COMPARES)
334 Vc_INTRINSIC Vc_DEPRECATED(
"use isnegative(x) instead") MaskType isNegative()
const
336 return {isnegative(data)};
339 Vc_INTRINSIC decltype(std::declval<vector_type &>()[0]) operator[](
std::
size_t i)
343 Vc_INTRINSIC value_type operator[](std::size_t i)
const {
return data[i]; }
345 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
350 Vc_INTRINSIC
void assign(
const SimdArray &v,
const mask_type &k)
352 data.assign(v.data, internal_data(k));
356 #define Vc_REDUCTION_FUNCTION_(name_) \
357 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \
358 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \
360 return data.name_(internal_data(mask)); \
362 Vc_REDUCTION_FUNCTION_(min)
363 Vc_REDUCTION_FUNCTION_(max)
364 Vc_REDUCTION_FUNCTION_(product)
365 Vc_REDUCTION_FUNCTION_(sum)
366 #undef Vc_REDUCTION_FUNCTION_
367 Vc_INTRINSIC Vc_PURE SimdArray partialSum()
const {
return data.partialSum(); }
369 Vc_INTRINSIC
void fusedMultiplyAdd(
const SimdArray &factor,
const SimdArray &summand)
371 data.fusedMultiplyAdd(internal_data(factor), internal_data(summand));
374 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f)
const
376 return {data.apply(std::forward<F>(f))};
378 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f,
const mask_type &k)
const
380 return {data.apply(std::forward<F>(f), k)};
383 Vc_INTRINSIC SimdArray
shifted(
int amount)
const
385 return {data.shifted(amount)};
388 template <std::
size_t NN>
389 Vc_INTRINSIC SimdArray
shifted(
int amount,
const SimdArray<value_type, NN> &shiftIn)
392 return {data.shifted(amount, simd_cast<VectorType>(shiftIn))};
395 Vc_INTRINSIC SimdArray rotated(
int amount)
const
397 return {data.rotated(amount)};
401 Vc_INTRINSIC Vc_DEPRECATED(
"use exponent(x) instead") SimdArray exponent()
const
403 return {exponent(data)};
406 Vc_INTRINSIC SimdArray interleaveLow(SimdArray x)
const
408 return {data.interleaveLow(x.data)};
410 Vc_INTRINSIC SimdArray interleaveHigh(SimdArray x)
const
412 return {data.interleaveHigh(x.data)};
415 Vc_INTRINSIC SimdArray reversed()
const
417 return {data.reversed()};
420 Vc_INTRINSIC SimdArray sorted()
const
422 return {data.sorted()};
425 template <
typename G>
static Vc_INTRINSIC SimdArray generate(
const G &gen)
427 return {VectorType::generate(gen)};
430 Vc_INTRINSIC Vc_DEPRECATED(
"use copysign(x, y) instead") SimdArray
431 copySign(const SimdArray &reference)
const
436 friend VectorType &internal_data<>(SimdArray &x);
437 friend const VectorType &internal_data<>(
const SimdArray &x);
440 Vc_INTRINSIC SimdArray(VectorType &&x) : data(
std::move(x)) {}
444 template <
typename T, std::
size_t N,
typename VectorType> constexpr std::size_t SimdArray<T, N, VectorType, N>::Size;
445 template <
typename T, std::
size_t N,
typename VectorType>
447 template <
typename T, std::
size_t N,
typename VectorType>
448 Vc_INTRINSIC VectorType &internal_data(SimdArray<T, N, VectorType, N> &x)
452 template <
typename T, std::
size_t N,
typename VectorType>
453 Vc_INTRINSIC
const VectorType &internal_data(
const SimdArray<T, N, VectorType, N> &x)
459 template <
typename T, std::
size_t N,
typename VectorType>
460 template <
typename MT,
typename IT>
461 inline void SimdArray<T, N, VectorType, N>::gatherImplementation(
const MT *mem,
464 data.gather(mem, std::forward<IT>(indexes));
466 template <
typename T, std::
size_t N,
typename VectorType>
467 template <
typename MT,
typename IT>
468 inline void SimdArray<T, N, VectorType, N>::gatherImplementation(
const MT *mem,
472 data.gather(mem, std::forward<IT>(indexes), mask);
480 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t>
483 ((Common::nextPowerOfTwo(N) * (sizeof(VectorType) / VectorType::size()) - 1) & 127) +
487 static_assert(std::is_same<T, double>::value ||
488 std::is_same<T, float>::value ||
489 std::is_same<T, int32_t>::value ||
490 std::is_same<T, uint32_t>::value ||
491 std::is_same<T, int16_t>::value ||
492 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 }");
495 std::is_same<
typename VectorType::EntryType,
496 typename VectorType::VectorEntryType>::value ||
498 (N % VectorType::size() == 0),
499 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * "
500 "MIC::(u)short_v::size(), i.e. k * 16.");
502 using my_traits = SimdArrayTraits<T, N>;
503 static constexpr std::size_t N0 = my_traits::N0;
504 static constexpr std::size_t N1 = my_traits::N1;
505 using Split = Common::Split<N0>;
506 template <
typename U, std::
size_t K>
using CArray = U[K];
511 static_assert(storage_type0::size() == N0,
"");
513 using vector_type = VectorType;
514 using vectorentry_type =
typename storage_type0::vectorentry_type;
515 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
516 using value_type = T;
517 using mask_type = SimdMaskArray<T, N, vector_type>;
519 static constexpr std::size_t size() {
return N; }
520 using Mask = mask_type;
521 using MaskType = Mask;
522 using MaskArgument =
const MaskType &;
523 using VectorEntryType = vectorentry_type;
524 using EntryType = value_type;
526 using AsArg =
const SimdArray &;
527 static constexpr std::size_t Size = size();
528 static constexpr std::size_t MemoryAlignment =
536 SimdArray() =
default;
539 SimdArray(
const SimdArray &) =
default;
540 SimdArray(SimdArray &&) =
default;
541 SimdArray &operator=(
const SimdArray &) =
default;
544 Vc_INTRINSIC SimdArray(value_type a) : data0(a), data1(a) {}
547 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
549 : SimdArray(static_cast<value_type>(a))
554 template <
typename U,
556 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
557 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
558 : data0(mem, f), data1(mem + storage_type0::size(), f)
567 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
568 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
569 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
570 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
576 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
577 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
578 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
579 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
584 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
588 #if defined Vc_CXX14 && 0 // doesn't compile yet
589 static_assert(init.size() == size(),
"The initializer_list argument to "
590 "SimdArray<T, N> must contain exactly N "
593 Vc_ASSERT(init.size() == size());
597 #include "gatherinterface.h"
600 template <
typename... Args,
601 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
602 !Traits::is_initializer_list<Args...>::value &&
603 !Traits::is_gather_signature<Args...>::value &&
604 !Traits::is_load_arguments<Args...>::value>>
605 explicit Vc_INTRINSIC SimdArray(Args &&... args)
606 : data0(Split::lo(args)...)
608 , data1(Split::hi(std::forward<Args>(args))...)
613 template <
typename V>
614 Vc_INTRINSIC
explicit SimdArray(
617 !(std::is_convertible<Traits::entry_type_of<V>, T>::value &&
619 : data0(Split::lo(x)), data1(Split::hi(x))
624 template <
typename V>
625 Vc_INTRINSIC SimdArray(
628 std::is_convertible<Traits::entry_type_of<V>, T>::value)> = nullarg)
629 : data0(Split::lo(x)), data1(Split::hi(x))
635 template <
typename V,
636 typename = enable_if<
638 std::is_convertible<T, typename V::EntryType>::value && V::size() == N>>
646 Vc_INTRINSIC
void setZero()
651 Vc_INTRINSIC
void setZero(
const mask_type &k)
653 data0.setZero(Split::lo(k));
654 data1.setZero(Split::hi(k));
656 Vc_INTRINSIC
void setZeroInverted()
658 data0.setZeroInverted();
659 data1.setZeroInverted();
661 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
663 data0.setZeroInverted(Split::lo(k));
664 data1.setZeroInverted(Split::hi(k));
668 Vc_INTRINSIC
void setQnan() {
672 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
673 data0.setQnan(Split::lo(m));
674 data1.setQnan(Split::hi(m));
678 template <
typename Op,
typename... Args>
679 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
682 storage_type0::fromOperation(op, Split::lo(args)...),
685 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
690 template <
typename Op,
typename... Args>
691 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
693 storage_type0::callOperation(op, Split::lo(args)...);
694 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
698 static Vc_INTRINSIC SimdArray
Zero()
704 static Vc_INTRINSIC SimdArray
One()
716 static Vc_INTRINSIC SimdArray Random()
718 return fromOperation(Common::Operations::random());
721 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
723 data0.load(mem, Split::lo(args)...);
725 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
728 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const
730 data0.store(mem, Split::lo(args)...);
732 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
735 Vc_INTRINSIC mask_type operator!()
const
737 return {!data0, !data1};
740 Vc_INTRINSIC SimdArray operator-()
const
742 return {-data0, -data1};
746 Vc_INTRINSIC SimdArray operator+()
const {
return *
this; }
748 Vc_INTRINSIC SimdArray operator~()
const
750 return {~data0, ~data1};
754 template <
typename U,
755 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
756 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const
758 return {data0 << x, data1 << x};
760 template <
typename U,
761 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
762 Vc_INTRINSIC SimdArray &operator<<=(U x)
768 template <
typename U,
769 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
770 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const
772 return {data0 >> x, data1 >> x};
774 template <
typename U,
775 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
776 Vc_INTRINSIC SimdArray &operator>>=(U x)
784 #define Vc_BINARY_OPERATOR_(op) \
785 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \
787 return {data0 op rhs.data0, data1 op rhs.data1}; \
789 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \
791 data0 op## = rhs.data0; \
792 data1 op## = rhs.data1; \
795 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_)
796 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_)
797 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_)
798 #undef Vc_BINARY_OPERATOR_
800 #define Vc_COMPARES(op) \
801 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \
803 return {data0 op rhs.data0, data1 op rhs.data1}; \
805 Vc_ALL_COMPARES(Vc_COMPARES)
809 Vc_INTRINSIC MaskType isNegative()
const
811 return {isnegative(data0), isnegative(data1)};
815 Vc_INTRINSIC value_type operator[](std::size_t i)
const
817 const auto tmp =
reinterpret_cast<const alias_type *
>(
this);
821 Vc_INTRINSIC alias_type &operator[](std::size_t i)
823 auto tmp =
reinterpret_cast<alias_type *
>(
this);
827 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
832 Vc_INTRINSIC
void assign(
const SimdArray &v,
const mask_type &k)
834 data0.assign(v.data0, internal_data0(k));
835 data1.assign(v.data1, internal_data1(k));
839 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \
840 template <typename ForSfinae = void> \
841 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \
842 storage_type0::size() == storage_type1::size(), \
846 return binary_fun_(data0, data1).name_(); \
849 template <typename ForSfinae = void> \
850 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \
851 storage_type0::size() != storage_type1::size(), \
855 return scalar_fun_(data0.name_(), data1.name_()); \
858 Vc_INTRINSIC value_type name_(const mask_type &mask) const \
860 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \
861 return data1.name_(Split::hi(mask)); \
862 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \
863 return data0.name_(Split::lo(mask)); \
865 return scalar_fun_(data0.name_(Split::lo(mask)), \
866 data1.name_(Split::hi(mask))); \
869 Vc_REDUCTION_FUNCTION_(min,
Vc::min, std::min)
870 Vc_REDUCTION_FUNCTION_(max,
Vc::max,
std::max)
871 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_)
872 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_)
873 #undef Vc_REDUCTION_FUNCTION_
874 Vc_INTRINSIC Vc_PURE SimdArray partialSum() const
876 auto ps0 = data0.partialSum();
878 tmp[0] += ps0[data0.size() - 1];
879 return {std::move(ps0), tmp.partialSum()};
882 void fusedMultiplyAdd(
const SimdArray &factor,
const SimdArray &summand)
884 data0.fusedMultiplyAdd(Split::lo(factor), Split::lo(summand));
885 data1.fusedMultiplyAdd(Split::hi(factor), Split::hi(summand));
889 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f)
const
891 return {data0.apply(f), data1.apply(f)};
893 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f,
const mask_type &k)
const
895 return {data0.apply(f, Split::lo(k)), data1.apply(f, Split::hi(k))};
899 inline SimdArray
shifted(
int amount)
const
901 constexpr
int SSize = Size;
902 constexpr
int SSize0 = storage_type0::Size;
903 constexpr
int SSize1 = storage_type1::Size;
908 if (amount > -SSize0) {
909 return {data0.shifted(amount), data1.shifted(amount, data0)};
911 if (amount == -SSize0) {
914 if (amount < -SSize0) {
920 if (amount >= SSize) {
922 }
else if (amount >= SSize0) {
926 }
else if (amount >= SSize1) {
929 return {data0.shifted(amount, data1), data1.shifted(amount)};
934 template <std::
size_t NN>
936 !(std::is_same<storage_type0, storage_type1>::value &&
939 shifted(
int amount,
const SimdArray<value_type, NN> &shiftIn)
const
941 constexpr
int SSize = Size;
943 return SimdArray::generate([&](
int i) -> value_type {
946 return operator[](i);
947 }
else if (i >= -SSize) {
948 return shiftIn[i + SSize];
953 return SimdArray::generate([&](
int i) -> value_type {
956 return operator[](i);
957 }
else if (i < 2 * SSize) {
958 return shiftIn[i - SSize];
964 template <std::
size_t NN>
966 enable_if<(std::is_same<storage_type0, storage_type1>::value &&
969 shifted(
int amount,
const SimdArray<value_type, NN> &shiftIn)
const
971 constexpr
int SSize = Size;
973 if (amount > -static_cast<int>(storage_type0::Size)) {
974 return {data0.shifted(amount, internal_data1(shiftIn)),
975 data1.shifted(amount, data0)};
977 if (amount == -static_cast<int>(storage_type0::Size)) {
978 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
980 if (amount > -SSize) {
982 internal_data1(shiftIn)
983 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
984 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
986 if (amount == -SSize) {
989 if (amount > -2 * SSize) {
990 return shiftIn.shifted(amount + SSize);
996 if (amount < static_cast<int>(storage_type0::Size)) {
997 return {data0.shifted(amount, data1),
998 data1.shifted(amount, internal_data0(shiftIn))};
1000 if (amount == static_cast<int>(storage_type0::Size)) {
1001 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1003 if (amount < SSize) {
1004 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1005 internal_data0(shiftIn)
1006 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1008 if (amount == SSize) {
1011 if (amount < 2 * SSize) {
1012 return shiftIn.shifted(amount - SSize);
1018 Vc_INTRINSIC SimdArray rotated(
int amount)
const
1020 amount %= int(size());
1023 }
else if (amount < 0) {
1027 auto &&d0cvtd =
simd_cast<storage_type1>(data0);
1028 auto &&d1cvtd =
simd_cast<storage_type0>(data1);
1029 constexpr
int size0 = storage_type0::size();
1030 constexpr
int size1 = storage_type1::size();
1032 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1033 return {std::move(d1cvtd), std::move(d0cvtd)};
1034 }
else if (amount < size1) {
1035 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1036 }
else if (amount == size1) {
1037 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1038 }
else if (
int(size()) - amount < size1) {
1039 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1040 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1041 }
else if (
int(size()) - amount == size1) {
1042 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1043 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1044 }
else if (amount <= size0) {
1045 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1046 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1048 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1049 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1055 Vc_INTRINSIC Vc_DEPRECATED(
"use exponent(x) instead") SimdArray exponent()
const
1057 return {exponent(data0), exponent(data1)};
1061 Vc_INTRINSIC SimdArray interleaveLow(
const SimdArray &x)
const
1064 return {data0.interleaveLow(x.data0),
1065 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1067 Vc_INTRINSIC SimdArray interleaveHigh(
const SimdArray &x)
const
1069 return interleaveHighImpl(
1071 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1075 Vc_INTRINSIC SimdArray interleaveHighImpl(
const SimdArray &x, std::true_type)
const
1077 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1079 inline SimdArray interleaveHighImpl(
const SimdArray &x, std::false_type)
const
1081 return {data0.interleaveHigh(x.data0)
1082 .shifted(storage_type1::Size,
1083 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1084 data1.interleaveHigh(x.data1)};
1088 inline SimdArray reversed() const
1090 if (std::is_same<storage_type0, storage_type1>::value) {
1091 return {
simd_cast<storage_type0>(data1).reversed(),
1092 simd_cast<storage_type1>(data0).reversed()};
1094 return {data0.shifted(storage_type1::Size, data1).reversed(),
1095 simd_cast<storage_type1>(data0.reversed().shifted(
1096 storage_type0::Size - storage_type1::Size))};
1099 inline SimdArray sorted() const
1102 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1105 Vc_INTRINSIC SimdArray sortedImpl(std::true_type)
const
1107 #ifdef Vc_DEBUG_SORTED
1108 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1110 const auto a = data0.sorted();
1111 const auto b = data1.sorted().reversed();
1112 const auto lo =
Vc::min(a, b);
1113 const auto hi =
Vc::max(a, b);
1114 return {lo.sorted(), hi.sorted()};
1117 Vc_INTRINSIC SimdArray sortedImpl(std::false_type)
const
1119 using SortableArray = SimdArray<value_type, Common::nextPowerOfTwo(size())>;
1120 auto sortable =
simd_cast<SortableArray>(*this);
1121 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1122 using limits = std::numeric_limits<value_type>;
1123 if (limits::has_infinity) {
1124 sortable[i] = limits::infinity();
1126 sortable[i] = std::numeric_limits<value_type>::max();
1129 return simd_cast<SimdArray>(sortable.sorted());
1158 template <
typename G>
static Vc_INTRINSIC SimdArray generate(
const G &gen)
1160 auto tmp = storage_type0::generate(gen);
1165 return {std::move(tmp),
1166 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
1169 Vc_INTRINSIC Vc_DEPRECATED(
"use copysign(x, y) instead") SimdArray
1170 copySign(const SimdArray &reference)
const
1177 friend storage_type0 &internal_data0<>(SimdArray &x);
1178 friend storage_type1 &internal_data1<>(SimdArray &x);
1179 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1180 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1183 Vc_INTRINSIC SimdArray(storage_type0 &&x, storage_type1 &&y)
1184 : data0(
std::move(x)), data1(
std::move(y))
1188 storage_type0 data0;
1189 storage_type1 data1;
1191 #undef Vc_CURRENT_CLASS_NAME
1192 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M> constexpr std::size_t SimdArray<T, N, VectorType, M>::Size;
1193 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1197 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1198 template <
typename MT,
typename IT>
1199 inline void SimdArray<T, N, VectorType, M>::gatherImplementation(
const MT *mem,
1202 data0.gather(mem, Split::lo(Common::Operations::gather(),
1205 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1207 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1208 template <
typename MT,
typename IT>
1209 inline void SimdArray<T, N, VectorType, M>::gatherImplementation(
const MT *mem,
1210 IT &&indexes, MaskArgument mask)
1212 data0.gather(mem, Split::lo(Common::Operations::gather(), indexes),
1215 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1220 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1221 Vc_INTRINSIC
typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1222 SimdArray<T, N, V, M> &x)
1226 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1227 Vc_INTRINSIC
typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1228 SimdArray<T, N, V, M> &x)
1232 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1233 Vc_INTRINSIC
const typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1234 const SimdArray<T, N, V, M> &x)
1238 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1239 Vc_INTRINSIC
const typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1240 const SimdArray<T, N, V, M> &x)
1246 namespace result_vector_type_internal
1248 template <
typename T>
1249 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1251 template <
typename T>
1252 using is_integer_larger_than_int = std::integral_constant<
1253 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1254 std::is_same<T, long>::value ||
1255 std::is_same<T, unsigned long>::value)>;
1258 typename L,
typename R, std::size_t N = Traits::isSimdArray<L>::value
1259 ? Traits::simd_vector_size<L>::value
1260 : Traits::simd_vector_size<R>::value,
1261 bool = (Traits::isSimdArray<L>::value ||
1262 Traits::isSimdArray<R>::value)
1264 !std::is_same<type<L>, type<R>>::value
1267 ((std::is_arithmetic<type<L>>::value &&
1268 !is_integer_larger_than_int<type<L>>::value) ||
1269 (std::is_arithmetic<type<R>>::value &&
1270 !is_integer_larger_than_int<
1273 (Traits::is_simd_vector<L>::value && !Traits::isSimdArray<L>::value) ||
1274 (Traits::is_simd_vector<R>::value &&
1275 !Traits::isSimdArray<R>::value)
1276 ) >
struct evaluate;
1278 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1281 using LScalar = Traits::entry_type_of<L>;
1282 using RScalar = Traits::entry_type_of<R>;
1284 template <
bool B,
typename True,
typename False>
1285 using conditional =
typename std::conditional<B, True, False>::type;
1298 using type = SimdArray<
1299 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1300 sizeof(LScalar) <
sizeof(
int) &&
1301 sizeof(RScalar) <
sizeof(
int)),
1302 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1303 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1304 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1305 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1311 template <
typename L,
typename R>
1312 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1317 "result_vector_type does not work");
1319 #define Vc_BINARY_OPERATORS_(op_) \
1320 template <typename L, typename R> \
1321 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \
1323 using Return = result_vector_type<L, R>; \
1324 return Return(std::forward<L>(lhs)) op_ Return(std::forward<R>(rhs)); \
1326 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_)
1327 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_)
1328 #undef Vc_BINARY_OPERATORS_
1329 #define Vc_BINARY_OPERATORS_(op_) \
1330 template <typename L, typename R> \
1331 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \
1334 using Promote = result_vector_type<L, R>; \
1335 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \
1337 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_)
1338 #undef Vc_BINARY_OPERATORS_
1341 #define Vc_FORWARD_UNARY_OPERATOR(name_) \
1342 template <typename T, std::size_t N, typename V, std::size_t M> \
1343 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \
1345 return SimdArray<T, N, V, M>::fromOperation( \
1346 Common::Operations::Forward_##name_(), x); \
1349 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \
1350 template <typename T, std::size_t N, typename V, std::size_t M> \
1351 inline SimdMaskArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \
1353 return SimdMaskArray<T, N, V, M>::fromOperation( \
1354 Common::Operations::Forward_##name_(), x); \
1357 #define Vc_FORWARD_BINARY_OPERATOR(name_) \
1358 template <typename T, std::size_t N, typename V, std::size_t M> \
1359 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x, \
1360 const SimdArray<T, N, V, M> &y) \
1362 return SimdArray<T, N, V, M>::fromOperation( \
1363 Common::Operations::Forward_##name_(), x, y); \
1366 Vc_FORWARD_UNARY_OPERATOR(abs)
1367 Vc_FORWARD_UNARY_OPERATOR(asin)
1368 Vc_FORWARD_UNARY_OPERATOR(atan)
1369 Vc_FORWARD_BINARY_OPERATOR(atan2)
1370 Vc_FORWARD_UNARY_OPERATOR(ceil)
1371 Vc_FORWARD_BINARY_OPERATOR(copysign)
1372 Vc_FORWARD_UNARY_OPERATOR(cos)
1373 Vc_FORWARD_UNARY_OPERATOR(exp)
1374 Vc_FORWARD_UNARY_OPERATOR(exponent)
1375 Vc_FORWARD_UNARY_OPERATOR(floor)
1376 template <typename T,
std::
size_t N>
1377 SimdArray<T, N> fma(const SimdArray<T, N> &a, const SimdArray<T, N> &b, const SimdArray<T, N> &c)
1379 return SimdArray<T, N>::fromOperation(Common::Operations::Forward_fma(), a, b, c);
1381 Vc_FORWARD_UNARY_BOOL_OPERATOR(isfinite)
1382 Vc_FORWARD_UNARY_BOOL_OPERATOR(isinf)
1383 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnan)
1384 Vc_FORWARD_UNARY_BOOL_OPERATOR(isnegative)
1385 template <typename T,
std::
size_t N>
1386 SimdArray<T, N> frexp(const SimdArray<T, N> &x, SimdArray<
int, N> *e)
1388 return SimdArray<T, N>::fromOperation(Common::Operations::Forward_frexp(), x, e);
1390 template <
typename T, std::
size_t N>
1391 SimdArray<T, N>
ldexp(
const SimdArray<T, N> &x,
const SimdArray<int, N> &e)
1393 return SimdArray<T, N>::fromOperation(Common::Operations::Forward_ldexp(), x, e);
1395 Vc_FORWARD_UNARY_OPERATOR(log)
1396 Vc_FORWARD_UNARY_OPERATOR(log10)
1397 Vc_FORWARD_UNARY_OPERATOR(log2)
1398 Vc_FORWARD_UNARY_OPERATOR(reciprocal)
1399 Vc_FORWARD_UNARY_OPERATOR(round)
1400 Vc_FORWARD_UNARY_OPERATOR(rsqrt)
1401 Vc_FORWARD_UNARY_OPERATOR(sin)
1402 template <typename T,
std::
size_t N>
1403 void sincos(const SimdArray<T, N> &x, SimdArray<T, N> *sin, SimdArray<T, N> *cos)
1405 SimdArray<T, N>::callOperation(Common::Operations::Forward_sincos(), x, sin, cos);
1407 Vc_FORWARD_UNARY_OPERATOR(sqrt)
1408 Vc_FORWARD_UNARY_OPERATOR(trunc)
1409 Vc_FORWARD_BINARY_OPERATOR(min)
1410 Vc_FORWARD_BINARY_OPERATOR(max)
1411 #undef Vc_FORWARD_UNARY_OPERATOR
1412 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR
1413 #undef Vc_FORWARD_BINARY_OPERATOR
1420 template <
typename Return, std::size_t N,
typename T,
typename... From>
1421 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1422 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1425 for (
size_t i = 0; i < N; ++i) {
1426 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1430 template <
typename Return, std::
size_t N,
typename T>
1431 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1433 Return r = Return();
1434 for (
size_t i = 0; i < N; ++i) {
1435 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1439 template <
typename Return, std::size_t N,
typename T,
typename... From>
1440 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1441 const From &... xs,
const T &last)
1444 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1445 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1449 template <
typename Return, std::
size_t N,
typename T>
1450 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1452 Return r = Return();
1453 for (
size_t i = 0; i < Return::size(); ++i) {
1454 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1460 template <
typename Return,
typename T,
typename... From>
1461 Vc_INTRINSIC_L Vc_CONST_L Return
1462 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1465 template <typename... Ts> struct are_all_types_equal;
1466 template <typename T>
1467 struct are_all_types_equal<T> : public
std::integral_constant<
bool, true>
1470 template <
typename T0,
typename T1,
typename... Ts>
1471 struct are_all_types_equal<T0, T1, Ts...>
1472 :
public std::integral_constant<
1473 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1497 template <
typename Return,
typename... Ts>
1498 Vc_INTRINSIC Vc_CONST Return
1499 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1503 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1504 Vc_INTRINSIC Vc_CONST
1505 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1506 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1508 template <
typename Return, std::
size_t offset,
typename From>
1509 Vc_INTRINSIC Vc_CONST
1510 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1511 simd_cast_with_offset(
const From &x);
1513 template <
typename Return, std::
size_t offset,
typename From>
1514 Vc_INTRINSIC Vc_CONST
1515 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1516 ((Traits::isSimdArray<Return>::value &&
1517 !Traits::isAtomicSimdArray<Return>::value) ||
1518 (Traits::isSimdMaskArray<Return>::value &&
1519 !Traits::isAtomicSimdMaskArray<Return>::value))),
1521 simd_cast_with_offset(
const From &x);
1523 template <
typename Return, std::
size_t offset,
typename From>
1524 Vc_INTRINSIC Vc_CONST
1525 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1526 ((Traits::isSimdArray<Return>::value &&
1527 Traits::isAtomicSimdArray<Return>::value) ||
1528 (Traits::isSimdMaskArray<Return>::value &&
1529 Traits::isAtomicSimdMaskArray<Return>::value))),
1531 simd_cast_with_offset(
const From &x);
1533 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1534 Vc_INTRINSIC Vc_CONST enable_if<
1535 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1536 simd_cast_with_offset(
const From &,
const Froms &... xs)
1538 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
1542 template <
typename Return, std::
size_t offset,
typename From>
1543 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
1550 template <
typename T,
typename... Ts>
struct first_type_of_impl
1554 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
1557 template <
typename Return,
typename From>
1558 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
1559 template <
typename Return,
typename... Froms>
1560 Vc_INTRINSIC Vc_CONST
1561 enable_if<(are_all_types_equal<Froms...>::value &&
1562 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1564 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
1568 template <
typename Return,
typename From,
typename... Froms>
1569 Vc_INTRINSIC Vc_CONST enable_if<
1570 (are_all_types_equal<From, Froms...>::value &&
1571 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1573 simd_cast_drop_arguments(Froms... xs, From x, From);
1574 template <
typename Return,
typename From>
1575 Vc_INTRINSIC Vc_CONST
1576 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1577 simd_cast_drop_arguments(From x, From);
1581 #ifdef Vc_DEBUG_SIMD_CAST
1582 void debugDoNothing(
const std::initializer_list<void *> &) {}
1583 template <
typename T0,
typename... Ts>
1584 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
1587 std::cerr << prefix << arg0;
1588 debugDoNothing({&(std::cerr <<
", " << args)...});
1589 std::cerr << suffix;
1592 template <
typename T0,
typename... Ts>
1593 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
1600 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, trait_name_) \
1601 template <typename Return, typename From, typename... Froms> \
1602 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1603 !Traits::is##SimdArrayType_<From>::value && \
1604 Traits::is_simd_##trait_name_<From>::value && \
1605 From::Size * sizeof...(Froms) < Return::Size && \
1606 are_all_types_equal<From, Froms...>::value), \
1608 simd_cast(From x, Froms... xs) \
1610 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
1611 return {simd_cast<typename Return::storage_type>(x, xs...)}; \
1613 template <typename Return, typename From, typename... Froms> \
1614 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1615 !Traits::is##SimdArrayType_<From>::value && \
1616 Traits::is_simd_##trait_name_<From>::value && \
1617 From::Size * sizeof...(Froms) >= Return::Size && \
1618 are_all_types_equal<From, Froms...>::value), \
1620 simd_cast(From x, Froms... xs) \
1622 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
1623 return {simd_cast_without_last<Return, From, Froms...>(x, xs...)}; \
1625 template <typename Return, typename From, typename... Froms> \
1626 Vc_INTRINSIC Vc_CONST enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1627 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1628 !Traits::is##SimdArrayType_<From>::value && \
1629 Traits::is_simd_##trait_name_<From>::value && \
1630 Common::left_size(Return::Size) < \
1631 From::Size * (1 + sizeof...(Froms)) && \
1632 are_all_types_equal<From, Froms...>::value), \
1634 simd_cast(From x, Froms... xs) \
1636 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
1637 using R0 = typename Return::storage_type0; \
1638 using R1 = typename Return::storage_type1; \
1639 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
1640 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
1642 template <typename Return, typename From, typename... Froms> \
1643 Vc_INTRINSIC Vc_CONST enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1644 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1645 !Traits::is##SimdArrayType_<From>::value && \
1646 Traits::is_simd_##trait_name_<From>::value && \
1647 Common::left_size(Return::Size) >= \
1648 From::Size * (1 + sizeof...(Froms)) && \
1649 are_all_types_equal<From, Froms...>::value), \
1651 simd_cast(From x, Froms... xs) \
1653 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
1654 using R0 = typename Return::storage_type0; \
1655 using R1 = typename Return::storage_type1; \
1656 return {simd_cast<R0>(x, xs...), R1::Zero()}; \
1658 Vc_SIMDARRAY_CASTS(SimdArray,
vector)
1659 Vc_SIMDARRAY_CASTS(SimdMaskArray, mask)
1660 #undef Vc_SIMDARRAY_CASTS
1663 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, trait_name_) \
1665 template <typename Return, int offset, typename From> \
1666 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1667 !Traits::is##SimdArrayType_<From>::value && \
1668 Traits::is_simd_##trait_name_<From>::value), \
1672 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
1673 return {simd_cast<typename Return::storage_type, offset>(x)}; \
1676 template <typename Return, int offset, typename From> \
1677 Vc_INTRINSIC Vc_CONST enable_if< \
1678 (Traits::is##SimdArrayType_<Return>::value && \
1679 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1680 !Traits::is##SimdArrayType_<From>::value && \
1681 Traits::is_simd_##trait_name_<From>::value && \
1682 Return::Size * offset + Common::left_size(Return::Size) < From::Size), \
1686 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
1687 using R0 = typename Return::storage_type0; \
1688 constexpr int entries_offset = offset * Return::Size; \
1689 constexpr int entries_offset_right = entries_offset + R0::Size; \
1691 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
1692 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
1697 template <typename Return, int offset, typename From> \
1698 Vc_INTRINSIC Vc_CONST enable_if< \
1699 (Traits::is##SimdArrayType_<Return>::value && \
1700 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1701 !Traits::is##SimdArrayType_<From>::value && \
1702 Traits::is_simd_##trait_name_<From>::value && \
1703 Return::Size * offset + Common::left_size(Return::Size) >= From::Size), \
1707 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
1708 using R0 = typename Return::storage_type0; \
1709 using R1 = typename Return::storage_type1; \
1710 constexpr int entries_offset = offset * Return::Size; \
1711 return {simd_cast_with_offset<R0, entries_offset>(x), R1::Zero()}; \
1713 Vc_SIMDARRAY_CASTS(SimdArray,
vector)
1714 Vc_SIMDARRAY_CASTS(SimdMaskArray, mask)
1715 #undef Vc_SIMDARRAY_CASTS
1718 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
1720 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
1721 Vc_INTRINSIC Vc_CONST \
1722 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
1723 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
1724 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
1726 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
1728 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
1729 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
1732 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
1733 Vc_INTRINSIC Vc_CONST \
1734 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
1735 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
1736 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
1738 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
1740 vc_debug_("simd_cast{indivisible2}(", ")\n", x0, xs...); \
1741 return simd_cast_without_last<Return, \
1742 typename SimdArrayType_<T, N, V, N>::storage_type, \
1743 typename From::storage_type...>( \
1744 internal_data(x0), internal_data(xs)...); \
1747 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1749 Vc_INTRINSIC Vc_CONST enable_if< \
1750 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1751 N * sizeof...(From) < Return::Size && ((N - 1) & N) == 0), \
1753 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1755 vc_debug_("simd_cast{bisectable}(", ")\n", x0, xs...); \
1756 return simd_cast_interleaved_argument_order< \
1757 Return, typename SimdArrayType_<T, N, V, M>::storage_type0, \
1758 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
1759 internal_data1(x0), internal_data1(xs)...); \
1763 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1765 Vc_INTRINSIC Vc_CONST enable_if< \
1766 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1767 N * sizeof...(From) >= Return::Size && ((N - 1) & N) == 0), \
1769 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1771 vc_debug_("simd_cast{bisectable2}(", ")\n", x0, xs...); \
1772 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
1776 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1778 Vc_INTRINSIC Vc_CONST enable_if< \
1779 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1780 N * (1 + sizeof...(From)) <= Return::Size && ((N - 1) & N) != 0), \
1782 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1784 vc_debug_("simd_cast{remaining}(", ")\n", x0, xs...); \
1785 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
1786 From...>(x0, xs...); \
1789 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1791 Vc_INTRINSIC Vc_CONST enable_if< \
1792 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1793 N * (1 + sizeof...(From)) > Return::Size && ((N - 1) & N) != 0), \
1795 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1797 vc_debug_("simd_cast{remaining2}(", ")\n", x0, xs...); \
1798 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
1799 From...>(x0, xs...); \
1802 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
1803 Vc_INTRINSIC Vc_CONST \
1804 enable_if<(N != M && N >= 2 * Return::Size && ((N - 1) & N) == 0), Return> \
1805 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1807 vc_debug_("simd_cast{single bisectable}(", ")\n", x); \
1808 return simd_cast<Return>(internal_data0(x)); \
1810 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
1811 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
1812 N < 2 * Return::Size && ((N - 1) & N) == 0), \
1814 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1816 vc_debug_("simd_cast{single bisectable2}(", ")\n", x); \
1817 return simd_cast<Return>(internal_data0(x), internal_data1(x)); \
1819 Vc_SIMDARRAY_CASTS(SimdArray)
1820 Vc_SIMDARRAY_CASTS(SimdMaskArray)
1821 #undef Vc_SIMDARRAY_CASTS
1824 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
1826 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1828 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \
1829 const SimdArrayType_<T, N, V, M> &x) \
1831 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \
1832 return simd_cast<Return>(x); \
1835 template <typename Return, int offset, typename T, std::size_t N, typename V> \
1836 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \
1837 const SimdArrayType_<T, N, V, N> &x) \
1839 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \
1840 return simd_cast<Return, offset>(internal_data(x)); \
1843 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1845 Vc_INTRINSIC Vc_CONST \
1846 enable_if<(N != M && offset * Return::Size >= Common::left_size(N) && \
1847 offset != 0 && Common::left_size(N) % Return::Size == 0), \
1849 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1851 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \
1852 return simd_cast<Return, offset - Common::left_size(N) / Return::Size>( \
1853 internal_data1(x)); \
1857 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1859 Vc_INTRINSIC Vc_CONST \
1860 enable_if<(N != M && offset * Return::Size >= Common::left_size(N) && \
1861 offset != 0 && Common::left_size(N) % Return::Size != 0), \
1863 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1865 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \
1866 return simd_cast_with_offset<Return, \
1867 offset * Return::Size - Common::left_size(N)>( \
1868 internal_data1(x)); \
1871 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1873 Vc_INTRINSIC Vc_CONST \
1874 enable_if<(N != M && \
1875 offset != 0 && (offset + 1) * Return::Size <= Common::left_size(N)), \
1877 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1879 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \
1880 return simd_cast<Return, offset>(internal_data0(x)); \
1883 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1885 Vc_INTRINSIC Vc_CONST \
1886 enable_if<(N != M && (offset * Return::Size < Common::left_size(N)) && \
1887 offset != 0 && (offset + 1) * Return::Size > Common::left_size(N)), \
1889 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1891 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \
1892 using R = typename Return::EntryType; \
1893 Return r = Return::Zero(); \
1894 for (std::size_t i = offset * Return::Size; \
1895 i < std::min(N, (offset + 1) * Return::Size); ++i) { \
1896 r[i - offset * Return::Size] = static_cast<R>(x[i]); \
1900 Vc_SIMDARRAY_CASTS(SimdArray)
1901 Vc_SIMDARRAY_CASTS(SimdMaskArray)
1902 #undef Vc_SIMDARRAY_CASTS
1904 template <
typename Return,
typename From>
1905 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
1909 template <
typename Return,
typename... Froms>
1910 Vc_INTRINSIC Vc_CONST
1911 enable_if<(are_all_types_equal<Froms...>::value &&
1912 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1914 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
1921 template <
typename Return,
typename From,
typename... Froms>
1922 Vc_INTRINSIC Vc_CONST enable_if<
1923 (are_all_types_equal<From, Froms...>::value &&
1924 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1926 simd_cast_drop_arguments(Froms... xs, From x, From)
1928 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
1930 template <
typename Return,
typename From>
1931 Vc_INTRINSIC Vc_CONST
1932 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1933 simd_cast_drop_arguments(From x, From)
1935 return simd_cast_drop_arguments<Return>(x);
1939 template <
typename Return, std::
size_t offset,
typename From>
1940 Vc_INTRINSIC Vc_CONST
1941 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
1942 Return> simd_cast_with_offset(
const From &x)
1944 return simd_cast<Return, offset / Return::Size>(x);
1946 template <
typename Return, std::
size_t offset,
typename From>
1947 Vc_INTRINSIC Vc_CONST
1948 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1949 ((Traits::isSimdArray<Return>::value &&
1950 !Traits::isAtomicSimdArray<Return>::value) ||
1951 (Traits::isSimdMaskArray<Return>::value &&
1952 !Traits::isAtomicSimdMaskArray<Return>::value))),
1954 simd_cast_with_offset(
const From &x)
1956 using R0 =
typename Return::storage_type0;
1957 using R1 =
typename Return::storage_type1;
1958 return {simd_cast_with_offset<R0, offset>(x),
1959 simd_cast_with_offset<R1, offset + R0::Size>(x)};
1961 template <
typename Return, std::
size_t offset,
typename From>
1962 Vc_INTRINSIC Vc_CONST
1963 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1964 ((Traits::isSimdArray<Return>::value &&
1965 Traits::isAtomicSimdArray<Return>::value) ||
1966 (Traits::isSimdMaskArray<Return>::value &&
1967 Traits::isAtomicSimdMaskArray<Return>::value))),
1969 simd_cast_with_offset(
const From &x)
1971 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
1973 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1974 Vc_INTRINSIC Vc_CONST
1975 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1976 simd_cast_with_offset(
const From &x,
const Froms &... xs)
1982 template <
typename Return,
typename T,
typename... From>
1983 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
1991 template <std::size_t I,
typename T0,
typename... Ts>
1992 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2000 template <std::size_t I,
typename T0,
typename... Ts>
2001 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2009 template <std::size_t I,
typename T0,
typename... Ts>
2010 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2015 return extract_interleaved<I - 2, Ts...>(a..., b...);
2019 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2020 Vc_INTRINSIC Vc_CONST Return
2021 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2024 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2028 template <
typename Return,
typename... Ts>
2029 Vc_INTRINSIC Vc_CONST Return
2030 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2032 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2033 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2037 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \
2038 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \
2040 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \
2041 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \
2043 lhs(mask) op_ rhs; \
2045 Vc_CONDITIONAL_ASSIGN( Assign, =)
2046 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=)
2047 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=)
2048 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=)
2049 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=)
2050 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=)
2051 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=)
2052 Vc_CONDITIONAL_ASSIGN( AndAssign, &=)
2053 Vc_CONDITIONAL_ASSIGN( OrAssign, |=)
2054 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=)
2055 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=)
2056 #undef Vc_CONDITIONAL_ASSIGN
2058 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \
2059 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \
2060 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \
2061 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \
2065 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++)
2066 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask))
2067 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--)
2068 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask))
2069 #undef Vc_CONDITIONAL_ASSIGN
2073 template <
int L,
typename T, std::
size_t N,
typename V>
2074 inline enable_if<L == 4, void> transpose_impl(
2075 SimdArray<T, N, V, N> * Vc_RESTRICT r[],
2076 const TransposeProxy<SimdArray<T, N, V, N>, SimdArray<T, N, V, N>,
2077 SimdArray<T, N, V, N>, SimdArray<T, N, V, N>> &proxy)
2079 V *Vc_RESTRICT r2[L] = {&internal_data(*r[0]), &internal_data(*r[1]),
2080 &internal_data(*r[2]), &internal_data(*r[3])};
2082 &r2[0], TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2083 internal_data(std::get<1>(proxy.in)),
2084 internal_data(std::get<2>(proxy.in)),
2085 internal_data(std::get<3>(proxy.in))});
2087 template <
int L,
typename T,
typename V>
2088 inline enable_if<(L == 2), void> transpose_impl(
2089 SimdArray<T, 4, V, 1> *Vc_RESTRICT r[],
2090 const TransposeProxy<SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>,
2091 SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>> &proxy)
2095 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2096 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2097 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2098 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2099 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2100 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2101 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2102 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2104 template <
int L,
typename T, std::
size_t N,
typename V>
2105 inline enable_if<(L == 4 && N > 1),
void> transpose_impl(
2106 SimdArray<T, N, V, 1> *Vc_RESTRICT r[],
2107 const TransposeProxy<SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>,
2108 SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>> &proxy)
2110 SimdArray<T, N, V, 1> *Vc_RESTRICT r0[L / 2] = {r[0], r[1]};
2111 SimdArray<T, N, V, 1> *Vc_RESTRICT r1[L / 2] = {r[2], r[3]};
2112 using H = SimdArray<T, 2>;
2114 &r0[0], TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2115 internal_data0(std::get<1>(proxy.in)),
2116 internal_data0(std::get<2>(proxy.in)),
2117 internal_data0(std::get<3>(proxy.in))});
2119 &r1[0], TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2120 internal_data1(std::get<1>(proxy.in)),
2121 internal_data1(std::get<2>(proxy.in)),
2122 internal_data1(std::get<3>(proxy.in))});
2174 template <
typename T,
size_t N,
typename V,
size_t VN>
2175 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2180 static Vc_ALWAYS_INLINE Vc_CONST R max() noexcept {
return numeric_limits<T>::max(); }
2181 static Vc_ALWAYS_INLINE Vc_CONST R
min() noexcept {
return numeric_limits<T>::min(); }
2182 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2184 return numeric_limits<T>::lowest();
2186 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2188 return numeric_limits<T>::epsilon();
2190 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2192 return numeric_limits<T>::round_error();
2194 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2196 return numeric_limits<T>::infinity();
2198 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2200 return numeric_limits<T>::quiet_NaN();
2202 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2204 return numeric_limits<T>::signaling_NaN();
2206 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2208 return numeric_limits<T>::denorm_min();