Vc  1.0.0-dev
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 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the names of contributing organizations nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 }}}*/
28 
29 #ifndef VC_COMMON_SIMDARRAYHELPER_H_
30 #define VC_COMMON_SIMDARRAYHELPER_H_
31 
32 #include "macros.h"
33 
34 namespace Vc_VERSIONED_NAMESPACE
35 {
36 namespace Common
37 {
38 
41 
42 namespace Operations/*{{{*/
43 {
44 struct tag {};
45 #define Vc_DEFINE_OPERATION(name__) \
46  struct name__ : public tag \
47  { \
48  template <typename V, typename... Args> \
49  Vc_INTRINSIC void operator()(V &v, Args &&... args) \
50  { \
51  v.name__(std::forward<Args>(args)...); \
52  } \
53  }
54 Vc_DEFINE_OPERATION(gather);
55 Vc_DEFINE_OPERATION(scatter);
56 Vc_DEFINE_OPERATION(load);
57 Vc_DEFINE_OPERATION(store);
58 Vc_DEFINE_OPERATION(setZero);
59 Vc_DEFINE_OPERATION(setZeroInverted);
60 Vc_DEFINE_OPERATION(assign);
61 #undef Vc_DEFINE_OPERATION
62 #define Vc_DEFINE_OPERATION(name__, code__) \
63  struct name__ : public tag \
64  { \
65  template <typename V> Vc_INTRINSIC void operator()(V & v) { code__; } \
66  }
67 Vc_DEFINE_OPERATION(increment, ++v);
68 Vc_DEFINE_OPERATION(decrement, --v);
69 Vc_DEFINE_OPERATION(random, v = V::Random());
70 #undef Vc_DEFINE_OPERATION
71 #define Vc_DEFINE_OPERATION(name__, code__) \
72  struct name__ : public tag \
73  { \
74  template <typename V, typename... Args> \
75  Vc_INTRINSIC void operator()(V &v, Args &&... args) \
76  { \
77  code__; \
78  } \
79  }
80 Vc_DEFINE_OPERATION(Abs, v = abs(std::forward<Args>(args)...));
81 Vc_DEFINE_OPERATION(Isnan, v = isnan(std::forward<Args>(args)...));
82 Vc_DEFINE_OPERATION(Frexp, v = frexp(std::forward<Args>(args)...));
83 Vc_DEFINE_OPERATION(Ldexp, v = ldexp(std::forward<Args>(args)...));
84 #undef Vc_DEFINE_OPERATION
85 template<typename T> using is_operation = std::is_base_of<tag, T>;
86 } // namespace Operations }}}
87 
93 template <typename T_, std::size_t Pieces_, std::size_t Index_> struct Segment/*{{{*/
94 {
95  static_assert(Index_ < Pieces_, "You found a bug in Vc. Please report.");
96 
97  using type = T_;
98  using type_decayed = typename std::decay<type>::type;
99  static constexpr std::size_t Pieces = Pieces_;
100  static constexpr std::size_t Index = Index_;
101 
102  type data;
103 
104  static constexpr std::size_t EntryOffset = Index * type_decayed::Size / Pieces;
105 
106  decltype(std::declval<type>()[0]) operator[](size_t i) { return data[i + EntryOffset]; }
107  decltype(std::declval<type>()[0]) operator[](size_t i) const { return data[i + EntryOffset]; }
108 };/*}}}*/
109 
119 template <typename T, std::size_t Offset> struct AddOffset
120 {
121  constexpr AddOffset() = default;
122 };
123 
132 template <std::size_t secondOffset> class Split/*{{{*/
133 {
134  static Vc_INTRINSIC AddOffset<VectorSpecialInitializerIndexesFromZero, secondOffset>
135  hiImpl(VectorSpecialInitializerIndexesFromZero)
136  {
137  return {};
138  }
139  template <std::size_t Offset>
140  static Vc_INTRINSIC
141  AddOffset<VectorSpecialInitializerIndexesFromZero, Offset + secondOffset>
142  hiImpl(AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
143  {
144  return {};
145  }
146 
147  // split composite SimdArray
148  template <typename U, std::size_t N, typename V, std::size_t M>
149  static Vc_INTRINSIC auto loImpl(const SimdArray<U, N, V, M> &x) -> decltype(internal_data0(x))
150  {
151  return internal_data0(x);
152  }
153  template <typename U, std::size_t N, typename V, std::size_t M>
154  static Vc_INTRINSIC auto hiImpl(const SimdArray<U, N, V, M> &x) -> decltype(internal_data1(x))
155  {
156  return internal_data1(x);
157  }
158  template <typename U, std::size_t N, typename V, std::size_t M>
159  static Vc_INTRINSIC auto loImpl(SimdArray<U, N, V, M> *x) -> decltype(&internal_data0(*x))
160  {
161  return &internal_data0(*x);
162  }
163  template <typename U, std::size_t N, typename V, std::size_t M>
164  static Vc_INTRINSIC auto hiImpl(SimdArray<U, N, V, M> *x) -> decltype(&internal_data1(*x))
165  {
166  return &internal_data1(*x);
167  }
168 
169  template <typename U, std::size_t N, typename V>
170  static Vc_INTRINSIC Segment<V, 2, 0> loImpl(const SimdArray<U, N, V, N> &x)
171  {
172  return {internal_data(x)};
173  }
174  template <typename U, std::size_t N, typename V>
175  static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(const SimdArray<U, N, V, N> &x)
176  {
177  return {internal_data(x)};
178  }
179  template <typename U, std::size_t N, typename V>
180  static Vc_INTRINSIC Segment<V *, 2, 0> loImpl(const SimdArray<U, N, V, N> *x)
181  {
182  return {&internal_data(*x)};
183  }
184  template <typename U, std::size_t N, typename V>
185  static Vc_INTRINSIC Segment<V *, 2, 1> hiImpl(const SimdArray<U, N, V, N> *x)
186  {
187  return {&internal_data(*x)};
188  }
189 
190  // split composite SimdMaskArray
191  template <typename U, std::size_t N, typename V, std::size_t M>
192  static Vc_INTRINSIC auto loImpl(const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data0(x))
193  {
194  return internal_data0(x);
195  }
196  template <typename U, std::size_t N, typename V, std::size_t M>
197  static Vc_INTRINSIC auto hiImpl(const SimdMaskArray<U, N, V, M> &x) -> decltype(internal_data1(x))
198  {
199  return internal_data1(x);
200  }
201 
202  template <typename U, std::size_t N, typename V>
203  static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 0> loImpl(
204  const SimdMaskArray<U, N, V, N> &x)
205  {
206  return {internal_data(x)};
207  }
208  template <typename U, std::size_t N, typename V>
209  static Vc_INTRINSIC Segment<typename SimdMaskArray<U, N, V, N>::mask_type, 2, 1> hiImpl(
210  const SimdMaskArray<U, N, V, N> &x)
211  {
212  return {internal_data(x)};
213  }
214 
215  // split Vector<T> and Mask<T>
216  template <typename T>
217  static constexpr bool is_vector_or_mask(){
218  return (Traits::is_simd_vector<T>::value && !Traits::isSimdArray<T>::value) ||
219  (Traits::is_simd_mask<T>::value && !Traits::isSimdMaskArray<T>::value);
220  }
221  template <typename V>
222  static Vc_INTRINSIC Segment<V, 2, 0> loImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
223  {
224  return {std::forward<V>(x)};
225  }
226  template <typename V>
227  static Vc_INTRINSIC Segment<V, 2, 1> hiImpl(V &&x, enable_if<is_vector_or_mask<V>()> = nullarg)
228  {
229  return {std::forward<V>(x)};
230  }
231 
232  // generically split Segments
233  template <typename V, std::size_t Pieces, std::size_t Index>
234  static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index> loImpl(
235  const Segment<V, Pieces, Index> &x)
236  {
237  return {x.data};
238  }
239  template <typename V, std::size_t Pieces, std::size_t Index>
240  static Vc_INTRINSIC Segment<V, 2 * Pieces, 2 * Index + 1> hiImpl(
241  const Segment<V, Pieces, Index> &x)
242  {
243  return {x.data};
244  }
245 
250  template <typename T, typename = decltype(loImpl(std::declval<T>()))>
251  static std::true_type have_lo_impl(int);
252  template <typename T> static std::false_type have_lo_impl(float);
253  template <typename T> static constexpr bool have_lo_impl()
254  {
255  return decltype(have_lo_impl<T>(1))::value;
256  }
257 
258  template <typename T, typename = decltype(hiImpl(std::declval<T>()))>
259  static std::true_type have_hi_impl(int);
260  template <typename T> static std::false_type have_hi_impl(float);
261  template <typename T> static constexpr bool have_hi_impl()
262  {
263  return decltype(have_hi_impl<T>(1))::value;
264  }
266 
267 public:
275  template <typename U>
276  static Vc_INTRINSIC const U *lo(Operations::gather, const U *ptr)
277  {
278  return ptr;
279  }
280  template <typename U>
281  static Vc_INTRINSIC const U *hi(Operations::gather, const U *ptr)
282  {
283  return ptr + secondOffset;
284  }
285  template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
286  static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>()))
287  lo(Operations::gather, U &&x)
288  {
289  return loImpl(std::forward<U>(x));
290  }
291  template <typename U, typename = enable_if<!std::is_pointer<U>::value>>
292  static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>()))
293  hi(Operations::gather, U &&x)
294  {
295  return hiImpl(std::forward<U>(x));
296  }
297  template <typename U>
298  static Vc_INTRINSIC const U *lo(Operations::scatter, const U *ptr)
299  {
300  return ptr;
301  }
302  template <typename U>
303  static Vc_INTRINSIC const U *hi(Operations::scatter, const U *ptr)
304  {
305  return ptr + secondOffset;
306  }
308 
320  template <typename U>
321  static Vc_ALWAYS_INLINE decltype(loImpl(std::declval<U>())) lo(U &&x)
322  {
323  return loImpl(std::forward<U>(x));
324  }
325  template <typename U>
326  static Vc_ALWAYS_INLINE decltype(hiImpl(std::declval<U>())) hi(U &&x)
327  {
328  return hiImpl(std::forward<U>(x));
329  }
330 
331  template <typename U>
332  static Vc_ALWAYS_INLINE enable_if<!have_lo_impl<U>(), U> lo(U &&x)
333  {
334  return std::forward<U>(x);
335  }
336  template <typename U>
337  static Vc_ALWAYS_INLINE enable_if<!have_hi_impl<U>(), U> hi(U &&x)
338  {
339  return std::forward<U>(x);
340  }
342 };/*}}}*/
343 
344 template <typename Op, typename U> static Vc_INTRINSIC U actual_value(Op, U &&x)
345 {
346  return std::forward<U>(x);
347 }
348 template <typename Op, typename U, std::size_t M, typename V>
349 static Vc_INTRINSIC const V &actual_value(Op, const SimdArray<U, M, V, M> &x)
350 {
351  return internal_data(x);
352 }
353 template <typename Op, typename U, std::size_t M, typename V>
354 static Vc_INTRINSIC const V &actual_value(Op, SimdArray<U, M, V, M> &&x)
355 {
356  return internal_data(x);
357 }
358 template <typename Op, typename U, std::size_t M, typename V>
359 static Vc_INTRINSIC V *actual_value(Op, SimdArray<U, M, V, M> *x)
360 {
361  return &internal_data(*x);
362 }
363 template <typename Op, typename U, std::size_t M, typename V>
364 static Vc_INTRINSIC const typename V::Mask &actual_value(Op, const SimdMaskArray<U, M, V, M> &x)
365 {
366  return internal_data(x);
367 }
368 template <typename Op, typename U, std::size_t M, typename V>
369 static Vc_INTRINSIC const typename V::Mask &actual_value(Op, SimdMaskArray<U, M, V, M> &&x)
370 {
371  return internal_data(x);
372 }
373 template <typename Op, typename U, std::size_t M, typename V>
374 static Vc_INTRINSIC typename V::Mask *actual_value(Op, SimdMaskArray<U, M, V, M> *x)
375 {
376  return &internal_data(*x);
377 }
378 
380 
381 } // namespace Common
382 } // namespace Vc
383 
384 #endif // VC_COMMON_SIMDARRAYHELPER_H_
385 
386 // 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 > 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.
void assign(Adapter< S, T, N > &a, size_t i, const S &x)
Assigns one scalar object x to a SIMD slot at offset i in the simdized object a.
Definition: simdize.h:941
Vc::Mask< T > isnan(const Vc::Vector< T > &x)