28#ifndef VC_COMMON_SIMDARRAYHELPER_H_
29#define VC_COMMON_SIMDARRAYHELPER_H_
33namespace Vc_VERSIONED_NAMESPACE
38static 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)...); \
59Vc_DEFINE_OPERATION(gather);
60Vc_DEFINE_OPERATION(scatter);
61Vc_DEFINE_OPERATION(load);
62Vc_DEFINE_OPERATION(store);
63Vc_DEFINE_OPERATION(setZero);
64Vc_DEFINE_OPERATION(setZeroInverted);
65Vc_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_; } \
71Vc_DEFINE_OPERATION(increment, ++(v));
72Vc_DEFINE_OPERATION(decrement, --(v));
73Vc_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)...); \
90Vc_DEFINE_OPERATION_FORWARD(abs);
91Vc_DEFINE_OPERATION_FORWARD(asin);
92Vc_DEFINE_OPERATION_FORWARD(atan);
93Vc_DEFINE_OPERATION_FORWARD(atan2);
94Vc_DEFINE_OPERATION_FORWARD(cos);
95Vc_DEFINE_OPERATION_FORWARD(ceil);
96Vc_DEFINE_OPERATION_FORWARD(copysign);
97Vc_DEFINE_OPERATION_FORWARD(exp);
98Vc_DEFINE_OPERATION_FORWARD(exponent);
99Vc_DEFINE_OPERATION_FORWARD(fma);
100Vc_DEFINE_OPERATION_FORWARD(floor);
101Vc_DEFINE_OPERATION_FORWARD(frexp);
102Vc_DEFINE_OPERATION_FORWARD(isfinite);
103Vc_DEFINE_OPERATION_FORWARD(isinf);
104Vc_DEFINE_OPERATION_FORWARD(isnan);
105Vc_DEFINE_OPERATION_FORWARD(isnegative);
106Vc_DEFINE_OPERATION_FORWARD(ldexp);
107Vc_DEFINE_OPERATION_FORWARD(log);
108Vc_DEFINE_OPERATION_FORWARD(log10);
109Vc_DEFINE_OPERATION_FORWARD(log2);
110Vc_DEFINE_OPERATION_FORWARD(reciprocal);
111Vc_DEFINE_OPERATION_FORWARD(round);
112Vc_DEFINE_OPERATION_FORWARD(rsqrt);
113Vc_DEFINE_OPERATION_FORWARD(sin);
114Vc_DEFINE_OPERATION_FORWARD(sincos);
115Vc_DEFINE_OPERATION_FORWARD(sqrt);
116Vc_DEFINE_OPERATION_FORWARD(trunc);
117Vc_DEFINE_OPERATION_FORWARD(min);
118Vc_DEFINE_OPERATION_FORWARD(max);
119#undef Vc_DEFINE_OPERATION_FORWARD
120template<
typename T>
using is_operation = std::is_base_of<tag, T>;
130template <
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);
157template <
typename T_, std::
size_t Pieces_, std::
size_t Index_>
158struct 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
>
201template <
typename T, std::
size_t Offset>
struct AddOffset
203 constexpr AddOffset() =
default;
215template <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);
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);
458template <
typename Op,
typename U, std::
size_t M,
typename V>
459static Vc_INTRINSIC
const V &actual_value(Op,
const SimdArray<U, M, V, M> &x)
461 return internal_data(x);
463template <
typename Op,
typename U, std::
size_t M,
typename V>
464static Vc_INTRINSIC V *actual_value(Op, SimdArray<U, M, V, M> *x)
466 return &internal_data(*x);
468template <
typename Op,
typename T,
size_t Pieces,
size_t Index>
469static 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();
475template <
typename Op,
typename U, std::
size_t M,
typename V>
476static Vc_INTRINSIC
const typename V::Mask &actual_value(Op,
const SimdMaskArray<U, M, V, M> &x)
478 return internal_data(x);
480template <
typename Op,
typename U, std::
size_t M,
typename V>
481static Vc_INTRINSIC
typename V::Mask *actual_value(Op, SimdMaskArray<U, M, V, M> *x)
483 return &internal_data(*x);
505template <
typename Op,
typename Arg>
506Vc_INTRINSIC
decltype(actual_value(std::declval<Op &>(), std::declval<Arg>()))
507conditionalUnpack(std::true_type, Op op, Arg &&arg)
509 return actual_value(op, std::forward<Arg>(arg));
512template <
typename Op,
typename Arg>
513Vc_INTRINSIC Arg conditionalUnpack(std::false_type, Op, Arg &&arg)
515 return std::forward<Arg>(arg);
519template <
size_t A,
size_t B>
520struct selectorType :
public std::integral_constant<bool, !((A & (size_t(1) << B)) != 0)> {
524template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
525Vc_INTRINSIC decltype(std::declval<Op &>()(std::declval<R &>(),
526 conditionalUnpack(selectorType<I, Indexes>(),
527 std::declval<Op &>(),
528 std::declval<Args>())...))
529unpackArgumentsAutoImpl(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))...);
536template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
537Vc_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)...);
553template <size_t, typename... Ts> struct IccWorkaround {
556template <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;
563template <typename Op, typename R, typename... Args>
564Vc_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)...);
#define Vc_GCC
This macro is defined to a number identifying the GCC version if the current translation unit is comp...