Vc  1.4.0
SIMD Vector Classes for C++
simdarrayhelper.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2013-2015 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef VC_COMMON_SIMDARRAYHELPER_H_
29 #define VC_COMMON_SIMDARRAYHELPER_H_
30 
31 #include "macros.h"
32 
33 namespace Vc_VERSIONED_NAMESPACE
34 {
35 // private_init {{{
36 namespace
37 {
38 static constexpr struct private_init_t {} private_init = {};
39 } // unnamed namespace
40 // }}}
41 
42 namespace Common
43 {
44 
47 
48 namespace Operations/*{{{*/
49 {
50 struct tag {};
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) \
55  { \
56  v.name_(std::forward<Args>(args)...); \
57  } \
58  }
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_; } \
70  }
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 \
77  { \
78  template <typename... Args, typename = decltype(name_(std::declval<Args>()...))> \
79  Vc_INTRINSIC void operator()(decltype(name_(std::declval<Args>()...)) &v, \
80  Args &&... args) \
81  { \
82  v = name_(std::forward<Args>(args)...); \
83  } \
84  template <typename... Args, typename = decltype(name_(std::declval<Args>()...))> \
85  Vc_INTRINSIC void operator()(std::nullptr_t, Args && ... args) \
86  { \
87  name_(std::forward<Args>(args)...); \
88  } \
89  }
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);
105 Vc_DEFINE_OPERATION_FORWARD(isnegative);
106 Vc_DEFINE_OPERATION_FORWARD(ldexp);
107 Vc_DEFINE_OPERATION_FORWARD(log);
108 Vc_DEFINE_OPERATION_FORWARD(log10);
109 Vc_DEFINE_OPERATION_FORWARD(log2);
110 Vc_DEFINE_OPERATION_FORWARD(reciprocal);
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>;
121 } // namespace Operations }}}
122 
130 template <typename T_, std::size_t Pieces_, std::size_t Index_> struct Segment/*{{{*/
131 {
132  static_assert(Index_ < Pieces_, "You found a bug in Vc. Please report.");
133 
134  using type = T_;
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 simd_array_type = SimdArray<
139  typename std::conditional<Traits::is_simd_vector<type_decayed>::value,
140  typename type_decayed::EntryType, float>::type,
141  type_decayed::Size / Pieces>;
142 
143  type data;
144 
145  static constexpr std::size_t EntryOffset = Index * type_decayed::Size / Pieces;
146 
147  // no non-const operator[] needed
148  decltype(std::declval<const type &>()[0]) operator[](size_t i) const { return data[i + EntryOffset]; }
149 
150  simd_array_type asSimdArray() const
151  {
152  return simd_cast<simd_array_type, Index>(data);
153  }
154 };/*}}}*/
155 
156 //Segment<T *, ...> specialization {{{
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.");
160 
161  using type = T_ *;
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 simd_array_type = SimdArray<
166  typename std::conditional<Traits::is_simd_vector<type_decayed>::value,
167  typename type_decayed::VectorEntryType, float>::type,
168  type_decayed::Size / Pieces> *;
169 
170  type data;
171 
172  static constexpr std::size_t EntryOffset = Index * type_decayed::size() / Pieces;
173 
174  simd_array_type asSimdArray() const
175  {
176  return reinterpret_cast<
177 #ifdef Vc_GCC
178  // GCC might ICE if this type is declared with may_alias. If it doesn't
179  // ICE it warns about ignoring the attribute.
180  typename std::remove_pointer<simd_array_type>::type
181 #else
182  MayAlias<typename std::remove_pointer<simd_array_type>::type>
183 #endif
184  *>(data) +
185  Index;
186  }
187 
188  //decltype(std::declval<type>()[0]) operator[](size_t i) { return data[i + EntryOffset]; }
189  //decltype(std::declval<type>()[0]) operator[](size_t i) const { return data[i + EntryOffset]; }
190 };/*}}}*/
191 
201 template <typename T, std::size_t Offset> struct AddOffset
202 {
203  constexpr AddOffset() = default;
204 };
205 
206 // class Split {{{1
215 template <std::size_t secondOffset> class Split
216 {
217  // split (only for high part) generator functions
218  template <class G>
219  struct GeneratorOffset {
220  G gen;
221  Vc_INTRINSIC decltype(gen(std::size_t())) operator()(std::size_t i)
222  {
223  return gen(i + secondOffset);
224  }
225  };
226  template <class G, class = decltype(std::declval<G>()(std::size_t())),
227  class = typename std::enable_if<!Traits::is_simd_vector<G>::value>::type>
228  static Vc_INTRINSIC GeneratorOffset<G> hiImpl(G &&gen)
229  {
230  return {std::forward<G>(gen)};
231  }
232 
233  // split (only for high part) IndexesFromZero
234  static Vc_INTRINSIC AddOffset<VectorSpecialInitializerIndexesFromZero, secondOffset>
235  hiImpl(VectorSpecialInitializerIndexesFromZero)
236  {
237  return {};
238  }
239  template <std::size_t Offset>
240  static Vc_INTRINSIC
241  AddOffset<VectorSpecialInitializerIndexesFromZero, Offset + secondOffset>
242  hiImpl(AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
243  {
244  return {};
245  }
246 
247  // split composite SimdArray
248  template <typename U, std::size_t N, typename V, std::size_t M,
249  typename = enable_if<N != M>>
250  static Vc_INTRINSIC auto loImpl(const SimdArray<U, N, V, M> &x)
251  -> decltype(internal_data0(x))
252  {
253  return internal_data0(x);
254  }
255  template <typename U, std::size_t N, typename V, std::size_t M,
256  typename = enable_if<N != M>>
257  static Vc_INTRINSIC auto hiImpl(const SimdArray<U, N, V, M> &x)
258  -> decltype(internal_data1(x))
259  {
260  return internal_data1(x);
261  }
262  template <typename U, std::size_t N, typename V, std::size_t M,
263  typename = enable_if<N != M>>
264  static Vc_INTRINSIC auto loImpl(SimdArray<U, N, V, M> *x)
265  -> decltype(&internal_data0(*x))
266  {
267  return &internal_data0(*x);
268  }
269  template <typename U, std::size_t N, typename V, std::size_t M,
270  typename = enable_if<N != M>>
271  static Vc_INTRINSIC auto hiImpl(SimdArray<U, N, V, M> *x)
272  -> decltype(&internal_data1(*x))
273  {
274  return &internal_data1(*x);
275  }
276 
277  // split atomic SimdArray
278  template <typename U, std::size_t N, typename V>
279  static Vc_INTRINSIC Segment<V, 2, 0> loImpl(const SimdArray<U, N, V, N> &x)
280  {
281  return {internal_data(x)};
282  }
283  template <typename U, std::size_t N, typename V>
284  static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(const SimdArray<U, N, V, N> &x)
285  {
286  return {internal_data(x)};
287  }
288  template <typename U, std::size_t N, typename V>
289  static Vc_INTRINSIC Segment<V *, 2, 0> loImpl(SimdArray<U, N, V, N> *x)
290  {
291  return {&internal_data(*x)};
292  }
293  template <typename U, std::size_t N, typename V>
294  static Vc_INTRINSIC Segment<V *, 2, 1> hiImpl(SimdArray<U, N, V, N> *x)
295  {
296  return {&internal_data(*x)};
297  }
298 
299  // split composite SimdMaskArray
300  template <typename U, std::size_t N, typename V, std::size_t M>
301  static Vc_INTRINSIC auto loImpl(const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data0(x))
302  {
303  return internal_data0(x);
304  }
305  template <typename U, std::size_t N, typename V, std::size_t M>
306  static Vc_INTRINSIC auto hiImpl(const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data1(x))
307  {
308  return internal_data1(x);
309  }
310 
311  template <typename U, std::size_t N, typename V>
312  static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 0> loImpl(
313  const SimdMaskArray<U, N, V, N> &x)
314  {
315  return {internal_data(x)};
316  }
317  template <typename U, std::size_t N, typename V>
318  static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 1> hiImpl(
319  const SimdMaskArray<U, N, V, N> &x)
320  {
321  return {internal_data(x)};
322  }
323 
324  // split Vector<T> and Mask<T>
325  template <typename T>
326  static constexpr bool is_vector_or_mask(){
327  return (Traits::is_simd_vector<T>::value && !Traits::isSimdArray<T>::value) ||
328  (Traits::is_simd_mask<T>::value && !Traits::isSimdMaskArray<T>::value);
329  }
330  template <typename V>
331  static Vc_INTRINSIC Segment<V, 2, 0> loImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
332  {
333  return {std::forward<V>(x)};
334  }
335  template <typename V>
336  static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
337  {
338  return {std::forward<V>(x)};
339  }
340 
341  // generically split Segments
342  template <typename V, std::size_t Pieces, std::size_t Index>
343  static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index> loImpl(
344  const Segment<V, Pieces, Index> &x)
345  {
346  return {x.data};
347  }
348  template <typename V, std::size_t Pieces, std::size_t Index>
349  static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index + 1> hiImpl(
350  const Segment<V, Pieces, Index> &x)
351  {
352  return {x.data};
353  }
354 
359  template <typename T, typename = decltype(loImpl(std::declval<T>()))>
360  static std::true_type have_lo_impl(int);
361  template <typename T> static std::false_type have_lo_impl(float);
362  template <typename T> static constexpr bool have_lo_impl()
363  {
364  return decltype(have_lo_impl<T>(1))::value;
365  }
366 
367  template <typename T, typename = decltype(hiImpl(std::declval<T>()))>
368  static std::true_type have_hi_impl(int);
369  template <typename T> static std::false_type have_hi_impl(float);
370  template <typename T> static constexpr bool have_hi_impl()
371  {
372  return decltype(have_hi_impl<T>(1))::value;
373  }
375 
376 public:
384  template <typename U>
385  static Vc_INTRINSIC const U *lo(Operations::gather, const U *ptr)
386  {
387  return ptr;
388  }
389  template <typename U>
390  static Vc_INTRINSIC const U *hi(Operations::gather, const U *ptr)
391  {
392  return ptr + secondOffset;
393  }
394  template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
395  static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>()))
396  lo(Operations::gather, U &&x)
397  {
398  return loImpl(std::forward<U>(x));
399  }
400  template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
401  static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>()))
402  hi(Operations::gather, U &&x)
403  {
404  return hiImpl(std::forward<U>(x));
405  }
406  template <typename U>
407  static Vc_INTRINSIC const U *lo(Operations::scatter, const U *ptr)
408  {
409  return ptr;
410  }
411  template <typename U>
412  static Vc_INTRINSIC const U *hi(Operations::scatter, const U *ptr)
413  {
414  return ptr + secondOffset;
415  }
417 
429  template <typename U>
430  static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>())) lo(U &&x)
431  {
432  return loImpl(std::forward<U>(x));
433  }
434  template <typename U>
435  static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>())) hi(U &&x)
436  {
437  return hiImpl(std::forward<U>(x));
438  }
439 
440  template <typename U>
441  static Vc_ALWAYS_INLINE enable_if<!have_lo_impl<U>(), U> lo(U &&x)
442  {
443  return std::forward<U>(x);
444  }
445  template <typename U>
446  static Vc_ALWAYS_INLINE enable_if<!have_hi_impl<U>(), U> hi(U &&x)
447  {
448  return std::forward<U>(x);
449  }
451 };
452 
453 // actual_value {{{1
454 template <typename Op, typename U, std::size_t M, typename V>
455 static Vc_INTRINSIC const V &actual_value(Op, const SimdArray<U, M, V, M> &x)
456 {
457  return internal_data(x);
458 }
459 template <typename Op, typename U, std::size_t M, typename V>
460 static Vc_INTRINSIC V *actual_value(Op, SimdArray<U, M, V, M> *x)
461 {
462  return &internal_data(*x);
463 }
464 template <typename Op, typename T, size_t Pieces, size_t Index>
465 static Vc_INTRINSIC typename Segment<T, Pieces, Index>::simd_array_type actual_value(
466  Op, Segment<T, Pieces, Index> &&seg)
467 {
468  return seg.asSimdArray();
469 }
470 
471 template <typename Op, typename U, std::size_t M, typename V>
472 static Vc_INTRINSIC const typename V::Mask &actual_value(Op, const SimdMaskArray<U, M, V, M> &x)
473 {
474  return internal_data(x);
475 }
476 template <typename Op, typename U, std::size_t M, typename V>
477 static Vc_INTRINSIC typename V::Mask *actual_value(Op, SimdMaskArray<U, M, V, M> *x)
478 {
479  return &internal_data(*x);
480 }
481 
482 // unpackArgumentsAuto {{{1
498 
501 template <typename Op, typename Arg>
502 Vc_INTRINSIC decltype(actual_value(std::declval<Op &>(), std::declval<Arg>()))
503 conditionalUnpack(std::true_type, Op op, Arg &&arg)
504 {
505  return actual_value(op, std::forward<Arg>(arg));
506 }
508 template <typename Op, typename Arg>
509 Vc_INTRINSIC Arg conditionalUnpack(std::false_type, Op, Arg &&arg)
510 {
511  return std::forward<Arg>(arg);
512 }
513 
515 template <size_t A, size_t B>
516 struct selectorType : public std::integral_constant<bool, !((A & (size_t(1) << B)) != 0)> {
517 };
518 
520 template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
521 Vc_INTRINSIC decltype(std::declval<Op &>()(std::declval<R &>(),
522  conditionalUnpack(selectorType<I, Indexes>(),
523  std::declval<Op &>(),
524  std::declval<Args>())...))
525 unpackArgumentsAutoImpl(int, index_sequence<Indexes...>, Op op, R &&r, Args &&... args)
526 {
527  op(std::forward<R>(r),
528  conditionalUnpack(selectorType<I, Indexes>(), op, std::forward<Args>(args))...);
529 }
530 
532 template <size_t I, typename Op, typename R, typename... Args, size_t... Indexes>
533 Vc_INTRINSIC enable_if<(I <= (size_t(1) << sizeof...(Args))), void> unpackArgumentsAutoImpl(
534  float, index_sequence<Indexes...> is, Op op, R &&r, Args &&... args)
535 {
536  // if R is nullptr_t then the return type cannot enforce that actually any unwrapping
537  // of the SimdArray types happens. Thus, you could get an endless loop of the
538  // SimdArray function overload calling itself, if the index goes up to (1 <<
539  // sizeof...(Args)) - 1 (which means no argument transformations via actual_value).
540  static_assert(
541  I < (1 << sizeof...(Args)) - (std::is_same<R, std::nullptr_t>::value ? 1 : 0),
542  "Vc or compiler bug. Please report. Failed to find a combination of "
543  "actual_value(arg) transformations that allows calling Op.");
544  unpackArgumentsAutoImpl<I + 1, Op, R, Args...>(int(), is, op, std::forward<R>(r),
545  std::forward<Args>(args)...);
546 }
547 
548 #ifdef Vc_ICC
549 template <size_t, typename... Ts> struct IccWorkaround {
550  using type = void;
551 };
552 template <typename... Ts> struct IccWorkaround<2, Ts...> {
553  using type = typename std::remove_pointer<typename std::decay<
554  typename std::tuple_element<1, std::tuple<Ts...>>::type>::type>::type;
555 };
556 #endif
557 
559 template <typename Op, typename R, typename... Args>
560 Vc_INTRINSIC void unpackArgumentsAuto(Op op, R &&r, Args &&... args)
561 {
562 #ifdef Vc_ICC
563  // ugly hacky workaround for ICC:
564  // The compiler fails to do SFINAE right on recursion. We have to hit the right
565  // recursionStart number from the start.
566  const int recursionStart =
567  Traits::isSimdArray<
568  typename IccWorkaround<sizeof...(Args), Args...>::type>::value &&
569  (std::is_same<Op, Common::Operations::Forward_frexp>::value ||
570  std::is_same<Op, Common::Operations::Forward_ldexp>::value)
571  ? 2
572  : 0;
573 #else
574  const int recursionStart = 0;
575 #endif
576  unpackArgumentsAutoImpl<recursionStart>(
577  int(), make_index_sequence<sizeof...(Args)>(), op, std::forward<R>(r),
578  std::forward<Args>(args)...);
579 }
581 
582 //}}}1
584 } // namespace Common
585 } // namespace Vc
586 
587 #endif // VC_COMMON_SIMDARRAYHELPER_H_
588 
589 // vim: foldmethod=marker
Vc::Vector< T > frexp(const Vc::Vector< T > &x, Vc::SimdArray< int, size()> *e)
Convert floating-point number to fractional and integral components.
Vc::Vector< T > log2(const Vc::Vector< T > &v)
Vc::Vector< T > exp(const Vc::Vector< T > &v)
Vc::Vector< T > min(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
Vc::Vector< T > reciprocal(const Vc::Vector< T > &v)
Returns the reciprocal of v.
fixed_size_simd< T, N > floor(const SimdArray< T, N, V, M > &x)
Applies the std:: floor function component-wise and concurrently.
Definition: simdarray.h:1775
Vc::Vector< T > ldexp(Vc::Vector< T > x, Vc::SimdArray< int, size()> e)
Multiply floating-point number by integral power of 2.
Vc::Vector< T > abs(const Vc::Vector< T > &v)
Returns the absolute value of v.
fixed_size_simd< T, N > atan(const SimdArray< T, N, V, M > &x)
Applies the std:: atan function component-wise and concurrently.
Definition: simdarray.h:1768
fixed_size_simd< T, N > copysign(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: copysign function component-wise and concurrently.
Definition: simdarray.h:1771
Vc::Vector< T > max(const Vc::Vector< T > &x, const Vc::Vector< T > &y)
Definition: vector.h:249
fixed_size_simd< T, N > atan2(const SimdArray< T, N, V, M > &x, const SimdArray< T, N, V, M > &y)
Applies the std:: atan2 function component-wise and concurrently.
Definition: simdarray.h:1769
fixed_size_simd< T, N > asin(const SimdArray< T, N, V, M > &x)
Applies the std:: asin function component-wise and concurrently.
Definition: simdarray.h:1767
Vc::Vector< T > log(const Vc::Vector< T > &v)
Vc::Vector< T > fma(Vc::Vector< T > a, Vc::Vector< T > b, Vc::Vector< T > c)
Multiplies a with b and then adds c, without rounding between the multiplication and the addition...
Vc::Vector< T > round(const Vc::Vector< T > &v)
Returns the closest integer to v; 0.5 is rounded to even.
Vc::Vector< T > rsqrt(const Vc::Vector< T > &v)
Returns the reciprocal square root of v.
fixed_size_simd_mask< T, N > isnegative(const SimdArray< T, N, V, M > &x)
Applies the std:: isnegative function component-wise and concurrently.
Definition: simdarray.h:1786
Vc::Vector< T > log10(const Vc::Vector< T > &v)
Vc::Mask< T > isfinite(const Vc::Vector< T > &x)
Vc::Mask< T > isnan(const Vc::Vector< T > &x)
#define Vc_GCC
This macro is defined to a number identifying the GCC version if the current translation unit is comp...
Definition: global.h:75
fixed_size_simd< T, N > cos(const SimdArray< T, N, V, M > &x)
Applies the std:: cos function component-wise and concurrently.
Definition: simdarray.h:1772
fixed_size_simd< T, N > sin(const SimdArray< T, N, V, M > &x)
Applies the std:: sin function component-wise and concurrently.
Definition: simdarray.h:1805
void sincos(const SimdArray< T, N > &x, SimdArray< T, N > *sin, SimdArray< T, N > *cos)
Determines sine and cosine concurrently and component-wise on x.
Definition: simdarray.h:1808
fixed_size_simd< T, N > trunc(const SimdArray< T, N, V, M > &x)
Applies the std:: trunc function component-wise and concurrently.
Definition: simdarray.h:1813
fixed_size_simd_mask< T, N > isinf(const SimdArray< T, N, V, M > &x)
Applies the std:: isinf function component-wise and concurrently.
Definition: simdarray.h:1784
fixed_size_simd< T, N > exponent(const SimdArray< T, N, V, M > &x)
Applies the std:: exponent function component-wise and concurrently.
Definition: simdarray.h:1774
Vc::Vector< T > sqrt(const Vc::Vector< T > &v)
Returns the square root of v.
fixed_size_simd< T, N > ceil(const SimdArray< T, N, V, M > &x)
Applies the std:: ceil function component-wise and concurrently.
Definition: simdarray.h:1770