28 #ifndef VC_COMMON_SIMDARRAYHELPER_H_
29 #define VC_COMMON_SIMDARRAYHELPER_H_
33 namespace Vc_VERSIONED_NAMESPACE
38 static constexpr
struct private_init_t {} private_init = {};
51 #define Vc_DEFINE_OPERATION(name_) \
52 struct name_ : public tag { \
53 template <typename V, typename... Args> \
54 Vc_INTRINSIC void operator()(V &v, Args &&... args) \
56 v.name_(std::forward<Args>(args)...); \
59 Vc_DEFINE_OPERATION(gather);
60 Vc_DEFINE_OPERATION(scatter);
61 Vc_DEFINE_OPERATION(load);
62 Vc_DEFINE_OPERATION(store);
63 Vc_DEFINE_OPERATION(setZero);
64 Vc_DEFINE_OPERATION(setZeroInverted);
65 Vc_DEFINE_OPERATION(assign);
66 #undef Vc_DEFINE_OPERATION
67 #define Vc_DEFINE_OPERATION(name_, code_) \
68 struct name_ : public tag { \
69 template <typename V> Vc_INTRINSIC void operator()(V &v) { code_; } \
71 Vc_DEFINE_OPERATION(increment, ++(v));
72 Vc_DEFINE_OPERATION(decrement, --(v));
73 Vc_DEFINE_OPERATION(random, v = V::Random());
74 #undef Vc_DEFINE_OPERATION
75 #define Vc_DEFINE_OPERATION_FORWARD(name_) \
76 struct Forward_##name_ : public tag \
78 template <typename... Args, typename = decltype(name_(std::declval<Args>()...))> \
79 Vc_INTRINSIC void operator()(decltype(name_(std::declval<Args>()...)) &v, \
82 v = name_(std::forward<Args>(args)...); \
84 template <typename... Args, typename = decltype(name_(std::declval<Args>()...))> \
85 Vc_INTRINSIC void operator()(std::nullptr_t, Args && ... args) \
87 name_(std::forward<Args>(args)...); \
90 Vc_DEFINE_OPERATION_FORWARD(
abs);
91 Vc_DEFINE_OPERATION_FORWARD(
asin);
92 Vc_DEFINE_OPERATION_FORWARD(
atan);
93 Vc_DEFINE_OPERATION_FORWARD(
atan2);
94 Vc_DEFINE_OPERATION_FORWARD(
cos);
95 Vc_DEFINE_OPERATION_FORWARD(
ceil);
96 Vc_DEFINE_OPERATION_FORWARD(
copysign);
97 Vc_DEFINE_OPERATION_FORWARD(
exp);
98 Vc_DEFINE_OPERATION_FORWARD(
exponent);
99 Vc_DEFINE_OPERATION_FORWARD(
fma);
100 Vc_DEFINE_OPERATION_FORWARD(
floor);
101 Vc_DEFINE_OPERATION_FORWARD(
frexp);
102 Vc_DEFINE_OPERATION_FORWARD(
isfinite);
103 Vc_DEFINE_OPERATION_FORWARD(
isinf);
104 Vc_DEFINE_OPERATION_FORWARD(
isnan);
106 Vc_DEFINE_OPERATION_FORWARD(
ldexp);
107 Vc_DEFINE_OPERATION_FORWARD(
log);
108 Vc_DEFINE_OPERATION_FORWARD(
log10);
109 Vc_DEFINE_OPERATION_FORWARD(
log2);
111 Vc_DEFINE_OPERATION_FORWARD(
round);
112 Vc_DEFINE_OPERATION_FORWARD(
rsqrt);
113 Vc_DEFINE_OPERATION_FORWARD(
sin);
114 Vc_DEFINE_OPERATION_FORWARD(
sincos);
115 Vc_DEFINE_OPERATION_FORWARD(
sqrt);
116 Vc_DEFINE_OPERATION_FORWARD(
trunc);
117 Vc_DEFINE_OPERATION_FORWARD(
min);
118 Vc_DEFINE_OPERATION_FORWARD(
max);
119 #undef Vc_DEFINE_OPERATION_FORWARD
120 template<
typename T>
using is_operation = std::is_base_of<tag, T>;
130 template <
typename T_, std::
size_t Pieces_, std::
size_t Index_>
struct Segment
132 static_assert(Index_ < Pieces_,
"You found a bug in Vc. Please report.");
135 using type_decayed =
typename std::decay<type>::type;
136 static constexpr std::size_t Pieces = Pieces_;
137 static constexpr std::size_t Index = Index_;
138 using fixed_size_type =
139 fixed_size_simd<conditional_t<Traits::is_simd_vector<type_decayed>::value,
140 typename type_decayed::EntryType,
float>,
141 type_decayed::Size / Pieces>;
145 static constexpr std::size_t EntryOffset = Index * type_decayed::Size / Pieces;
148 decltype(std::declval<const type &>()[0]) operator[](
size_t i)
const {
return data[i + EntryOffset]; }
150 fixed_size_type to_fixed_size()
const
152 return simd_cast<fixed_size_type, Index>(data);
157 template <
typename T_, std::
size_t Pieces_, std::
size_t Index_>
158 struct Segment<T_ *, Pieces_, Index_> {
159 static_assert(Index_ < Pieces_,
"You found a bug in Vc. Please report.");
162 using type_decayed =
typename std::decay<T_>::type;
163 static constexpr
size_t Pieces = Pieces_;
164 static constexpr
size_t Index = Index_;
165 using fixed_size_type = fixed_size_simd<
166 typename std::conditional<Traits::is_simd_vector<type_decayed>::value,
167 typename type_decayed::VectorEntryType,
float>::type,
168 type_decayed::Size / Pieces> *;
172 static constexpr std::size_t EntryOffset = Index * type_decayed::size() / Pieces;
174 fixed_size_type to_fixed_size()
const
176 return reinterpret_cast<
180 typename std::remove_pointer<fixed_size_type>::type
182 MayAlias<typename std::remove_pointer<fixed_size_type>::type
>
201 template <
typename T, std::
size_t Offset>
struct AddOffset
203 constexpr AddOffset() =
default;
215 template <std::
size_t secondOffset>
class Split
218 template <
typename U, std::size_t N,
typename V, std::size_t M,
219 typename = enable_if<N != M>>
220 static Vc_INTRINSIC
auto loImpl(
const SimdArray<U, N, V, M> &x)
221 -> decltype(internal_data0(x))
223 return internal_data0(x);
225 template <
typename U, std::size_t N,
typename V, std::size_t M,
226 typename = enable_if<N != M>>
227 static Vc_INTRINSIC
auto hiImpl(
const SimdArray<U, N, V, M> &x)
228 -> decltype(internal_data1(x))
230 return internal_data1(x);
232 template <
typename U, std::size_t N,
typename V, std::size_t M,
233 typename = enable_if<N != M>>
234 static Vc_INTRINSIC
auto loImpl(SimdArray<U, N, V, M> *x)
235 -> decltype(&internal_data0(*x))
237 return &internal_data0(*x);
239 template <
typename U, std::size_t N,
typename V, std::size_t M,
240 typename = enable_if<N != M>>
241 static Vc_INTRINSIC
auto hiImpl(SimdArray<U, N, V, M> *x)
242 -> decltype(&internal_data1(*x))
244 return &internal_data1(*x);
248 template <
typename U, std::
size_t N,
typename V>
249 static Vc_INTRINSIC Segment<V, 2, 0> loImpl(
const SimdArray<U, N, V, N> &x)
251 return {internal_data(x)};
253 template <
typename U, std::
size_t N,
typename V>
254 static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(
const SimdArray<U, N, V, N> &x)
256 return {internal_data(x)};
258 template <
typename U, std::
size_t N,
typename V>
259 static Vc_INTRINSIC Segment<V *, 2, 0> loImpl(SimdArray<U, N, V, N> *x)
261 return {&internal_data(*x)};
263 template <
typename U, std::
size_t N,
typename V>
264 static Vc_INTRINSIC Segment<V *, 2, 1> hiImpl(SimdArray<U, N, V, N> *x)
266 return {&internal_data(*x)};
270 template <
typename U, std::
size_t N,
typename V, std::
size_t M>
271 static Vc_INTRINSIC
auto loImpl(
const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data0(x))
273 return internal_data0(x);
275 template <
typename U, std::
size_t N,
typename V, std::
size_t M>
276 static Vc_INTRINSIC
auto hiImpl(
const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data1(x))
278 return internal_data1(x);
281 template <
typename U, std::
size_t N,
typename V>
282 static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 0> loImpl(
283 const SimdMaskArray<U, N, V, N> &x)
285 return {internal_data(x)};
287 template <
typename U, std::
size_t N,
typename V>
288 static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 1> hiImpl(
289 const SimdMaskArray<U, N, V, N> &x)
291 return {internal_data(x)};
297 static Vc_INTRINSIC SSE::Vector<T> loImpl(Vector<T, VectorAbi::Avx> &&x)
299 return simd_cast<SSE::Vector<T>, 0>(x);
302 static Vc_INTRINSIC SSE::Vector<T> hiImpl(Vector<T, VectorAbi::Avx> &&x)
304 return simd_cast<SSE::Vector<T>, 1>(x);
307 static Vc_INTRINSIC SSE::Mask<T> loImpl(Mask<T, VectorAbi::Avx> &&x)
309 return simd_cast<SSE::Mask<T>, 0>(x);
312 static Vc_INTRINSIC SSE::Mask<T> hiImpl(Mask<T, VectorAbi::Avx> &&x)
314 return simd_cast<SSE::Mask<T>, 1>(x);
316 #endif // Vc_IMPL_AVX
317 template <
typename T>
318 static constexpr
bool is_vector_or_mask(){
319 return (Traits::is_simd_vector<T>::value && !Traits::isSimdArray<T>::value) ||
320 (Traits::is_simd_mask<T>::value && !Traits::isSimdMaskArray<T>::value);
322 template <
typename V>
323 static Vc_INTRINSIC Segment<V, 2, 0> loImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
325 return {std::forward<V>(x)};
327 template <
typename V>
328 static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
330 return {std::forward<V>(x)};
334 template <
class T,
class A>
335 static Vc_INTRINSIC
const T *loImpl(
const std::vector<T, A> &x)
339 template <
class T,
class A>
340 static Vc_INTRINSIC
const T *hiImpl(
const std::vector<T, A> &x)
342 return x.data() + secondOffset;
346 template <
typename V, std::
size_t Pieces, std::
size_t Index>
347 static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index> loImpl(
348 const Segment<V, Pieces, Index> &x)
352 template <
typename V, std::
size_t Pieces, std::
size_t Index>
353 static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index + 1> hiImpl(
354 const Segment<V, Pieces, Index> &x)
363 template <typename T, typename = decltype(loImpl(std::declval<T>()))>
364 static std::true_type have_lo_impl(
int);
365 template <
typename T>
static std::false_type have_lo_impl(
float);
366 template <
typename T>
static constexpr
bool have_lo_impl()
368 return decltype(have_lo_impl<T>(1))::value;
371 template <typename T, typename = decltype(hiImpl(std::declval<T>()))>
372 static std::true_type have_hi_impl(
int);
373 template <
typename T>
static std::false_type have_hi_impl(
float);
374 template <
typename T>
static constexpr
bool have_hi_impl()
376 return decltype(have_hi_impl<T>(1))::value;
388 template <
typename U>
389 static Vc_INTRINSIC
const U *lo(Operations::gather,
const U *ptr)
393 template <
typename U>
394 static Vc_INTRINSIC
const U *hi(Operations::gather,
const U *ptr)
396 return ptr + secondOffset;
398 template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
399 static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>()))
400 lo(Operations::gather, U &&x)
402 return loImpl(std::forward<U>(x));
404 template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
405 static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>()))
406 hi(Operations::gather, U &&x)
408 return hiImpl(std::forward<U>(x));
410 template <
typename U>
411 static Vc_INTRINSIC
const U *lo(Operations::scatter,
const U *ptr)
415 template <
typename U>
416 static Vc_INTRINSIC
const U *hi(Operations::scatter,
const U *ptr)
418 return ptr + secondOffset;
433 template <
typename U>
434 static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>())) lo(U &&x)
436 return loImpl(std::forward<U>(x));
438 template <
typename U>
439 static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>())) hi(U &&x)
441 return hiImpl(std::forward<U>(x));
444 template <
typename U>
445 static Vc_ALWAYS_INLINE enable_if<!have_lo_impl<U>(), U> lo(U &&x)
447 return std::forward<U>(x);
449 template <
typename U>
450 static Vc_ALWAYS_INLINE enable_if<!have_hi_impl<U>(), U> hi(U &&x)
452 return std::forward<U>(x);
458 template <
typename Op,
typename U, std::
size_t M,
typename V>
459 static Vc_INTRINSIC
const V &actual_value(Op,
const SimdArray<U, M, V, M> &x)
461 return internal_data(x);
463 template <
typename Op,
typename U, std::
size_t M,
typename V>
464 static Vc_INTRINSIC V *actual_value(Op, SimdArray<U, M, V, M> *x)
466 return &internal_data(*x);
468 template <
typename Op,
typename T,
size_t Pieces,
size_t Index>
469 static Vc_INTRINSIC
typename Segment<T, Pieces, Index>::fixed_size_type actual_value(
470 Op, Segment<T, Pieces, Index> &&seg)
472 return seg.to_fixed_size();
475 template <
typename Op,
typename U, std::
size_t M,
typename V>
476 static Vc_INTRINSIC
const typename V::Mask &actual_value(Op,
const SimdMaskArray<U, M, V, M> &x)
478 return internal_data(x);
480 template <
typename Op,
typename U, std::
size_t M,
typename V>
481 static Vc_INTRINSIC
typename V::Mask *actual_value(Op, SimdMaskArray<U, M, V, M> *x)
483 return &internal_data(*x);
505 template <
typename Op,
typename Arg>
506 Vc_INTRINSIC decltype(actual_value(std::declval<Op &>(), std::declval<Arg>()))
507 conditionalUnpack(std::true_type, Op op, Arg &&arg)
509 return actual_value(op, std::forward<Arg>(arg));
512 template <
typename Op,
typename Arg>
513 Vc_INTRINSIC Arg conditionalUnpack(std::false_type, Op, Arg &&arg)
515 return std::forward<Arg>(arg);
519 template <
size_t A,
size_t B>
520 struct selectorType :
public std::integral_constant<bool, !((A & (size_t(1) << B)) != 0)> {
524 template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
525 Vc_INTRINSIC decltype(std::declval<Op &>()(std::declval<R &>(),
526 conditionalUnpack(selectorType<I, Indexes>(),
527 std::declval<Op &>(),
528 std::declval<Args>())...))
529 unpackArgumentsAutoImpl(int, index_sequence<Indexes...>, Op op, R &&r, Args &&... args)
531 op(std::forward<R>(r),
532 conditionalUnpack(selectorType<I, Indexes>(), op, std::forward<Args>(args))...);
536 template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
537 Vc_INTRINSIC enable_if<(I <= (size_t(1) << sizeof...(Args))), void> unpackArgumentsAutoImpl(
538 float, index_sequence<Indexes...> is, Op op, R &&r, Args &&... args)
545 I < (1 << sizeof...(Args)) - (std::is_same<R, std::nullptr_t>::value ? 1 : 0),
546 "Vc or compiler bug. Please report. Failed to find a combination of "
547 "actual_value(arg) transformations that allows calling Op.");
548 unpackArgumentsAutoImpl<I + 1, Op, R, Args...>(int(), is, op, std::forward<R>(r),
549 std::forward<Args>(args)...);
553 template <size_t, typename... Ts> struct IccWorkaround {
556 template <typename... Ts> struct IccWorkaround<2, Ts...> {
557 using type = typename std::remove_pointer<typename std::decay<
558 typename std::tuple_element<1, std::tuple<Ts...>>::type>::type>::type;
563 template <typename Op, typename R, typename... Args>
564 Vc_INTRINSIC void unpackArgumentsAuto(Op op, R &&r, Args &&... args)
570 const int recursionStart =
572 typename IccWorkaround<sizeof...(Args), Args...>::type>::value &&
573 (std::is_same<Op, Common::Operations::Forward_frexp>::value ||
574 std::is_same<Op, Common::Operations::Forward_ldexp>::value)
578 const int recursionStart = 0;
580 unpackArgumentsAutoImpl<recursionStart>(
581 int(), make_index_sequence<sizeof...(Args)>(), op, std::forward<R>(r),
582 std::forward<Args>(args)...);