Dune Core Modules (2.6.0)

simd.hh
1 #ifndef DUNE_COMMON_SIMD_HH
2 #define DUNE_COMMON_SIMD_HH
3 
20 #include <cassert>
21 #include <cstddef>
22 #include <type_traits>
23 #include <utility>
24 
25 #include <dune/common/conditional.hh>
27 #include <dune/common/vc.hh>
28 
29 namespace Dune
30 {
31 
32 #if HAVE_VC
33  namespace VcImpl {
35 
44  template<class V>
45  class Proxy
46  {
47  static_assert(std::is_same<V, std::decay_t<V> >::value, "Class Proxy "
48  "may only be instantiated with unqualified types");
49  public:
50  using value_type = typename V::value_type;
51 
52  private:
53  static_assert(std::is_arithmetic<value_type>::value,
54  "Only artihmetic types are supported");
55  V &vec_;
56  std::size_t idx_;
57 
58  public:
59  Proxy(std::size_t idx, V &vec)
60  : vec_(vec), idx_(idx)
61  { }
62 
63  operator value_type() const { return vec_[idx_]; }
64 
65  // postfix operators
66 
67  template<class T = value_type,
68  class = std::enable_if_t<!std::is_same<T, bool>::value> >
69  value_type operator++(int) { return vec_[idx_]++; }
70  template<class T = value_type,
71  class = std::enable_if_t<!std::is_same<T, bool>::value> >
72  value_type operator--(int) { return vec_[idx_]--; }
73 
74  // unary (prefix) operators
75  template<class T = value_type,
76  class = std::enable_if_t<!std::is_same<T, bool>::value> >
77  Proxy &operator++() { ++(vec_[idx_]); return *this; }
78  template<class T = value_type,
79  class = std::enable_if_t<!std::is_same<T, bool>::value> >
80  Proxy &operator--() { --(vec_[idx_]); return *this; }
81  decltype(auto) operator!() const { return !(vec_[idx_]); }
82  decltype(auto) operator+() const { return +(vec_[idx_]); }
83  decltype(auto) operator-() const { return -(vec_[idx_]); }
84  template<class T = value_type,
85  class = std::enable_if_t<std::is_integral<T>::value> >
86  decltype(auto) operator~() const { return ~(vec_[idx_]); }
87 
88  // binary operators
89 #define DUNE_SIMD_VC_BINARY_OP(OP) \
90  template<class T> \
91  auto operator OP(T &&o) const \
92  -> decltype(vec_[idx_] OP valueCast(std::forward<T>(o))) \
93  { \
94  return vec_[idx_] OP valueCast(std::forward<T>(o)); \
95  }
96 
97  DUNE_SIMD_VC_BINARY_OP(*);
98  DUNE_SIMD_VC_BINARY_OP(/);
99  DUNE_SIMD_VC_BINARY_OP(%);
100 
101  DUNE_SIMD_VC_BINARY_OP(+);
102  DUNE_SIMD_VC_BINARY_OP(-);
103 
104  DUNE_SIMD_VC_BINARY_OP(<<);
105  DUNE_SIMD_VC_BINARY_OP(>>);
106 
107  DUNE_SIMD_VC_BINARY_OP(<);
108  DUNE_SIMD_VC_BINARY_OP(>);
109  DUNE_SIMD_VC_BINARY_OP(<=);
110  DUNE_SIMD_VC_BINARY_OP(>=);
111 
112  DUNE_SIMD_VC_BINARY_OP(==);
113  DUNE_SIMD_VC_BINARY_OP(!=);
114 
115  DUNE_SIMD_VC_BINARY_OP(&);
116  DUNE_SIMD_VC_BINARY_OP(^);
117  DUNE_SIMD_VC_BINARY_OP(|);
118 
119  DUNE_SIMD_VC_BINARY_OP(&&);
120  DUNE_SIMD_VC_BINARY_OP(||);
121 #undef DUNE_SIMD_VC_BINARY_OP
122 
123 #define DUNE_SIMD_VC_ASSIGNMENT(OP) \
124  template<class T> \
125  auto operator OP(T &&o) \
126  -> std::enable_if_t<AlwaysTrue<decltype( \
127  vec_[idx_] OP valueCast(std::forward<T>(o)) \
128  )>::value, Proxy&> \
129  { \
130  vec_[idx_] OP valueCast(std::forward<T>(o)); \
131  return *this; \
132  }
133 
134  DUNE_SIMD_VC_ASSIGNMENT(=);
135  DUNE_SIMD_VC_ASSIGNMENT(*=);
136  DUNE_SIMD_VC_ASSIGNMENT(/=);
137  DUNE_SIMD_VC_ASSIGNMENT(%=);
138  DUNE_SIMD_VC_ASSIGNMENT(+=);
139  DUNE_SIMD_VC_ASSIGNMENT(-=);
140  DUNE_SIMD_VC_ASSIGNMENT(<<=);
141  DUNE_SIMD_VC_ASSIGNMENT(>>=);
142  DUNE_SIMD_VC_ASSIGNMENT(&=);
143  DUNE_SIMD_VC_ASSIGNMENT(^=);
144  DUNE_SIMD_VC_ASSIGNMENT(|=);
145 #undef DUNE_SIMD_VC_ASSIGNMENT
146 
147  // swap on proxies swaps the proxied vector entries. As such, it
148  // applies to rvalues of proxies too, not just lvalues
149  template<class V1, class V2>
150  friend void swap(Proxy<V1>, Proxy<V2>);
151 
152  template<class T>
153  friend void swap(Proxy p1, T& s2)
154  {
155  // don't use swap() ourselves -- not supported by Vc 1.3.0 (but is
156  // supported by Vc 1.3.2)
157  T tmp = p1.vec_[p1.idx_];
158  p1.vec_[p1.idx_] = s2;
159  s2 = tmp;
160  }
161 
162  template<class T>
163  friend void swap(T& s1, Proxy p2)
164  {
165  T tmp = s1;
166  s1 = p2.vec_[p2.idx_];
167  p2.vec_[p2.idx_] = tmp;
168  }
169  };
170 
171  template<class V1, class V2>
172  void swap(Proxy<V1> p1, Proxy<V2> p2)
173  {
174  typename V1::value_type tmp = p1.vec_[p1.idx_];
175  p1.vec_[p1.idx_] = p2.vec_[p2.idx_];
176  p2.vec_[p2.idx_] = tmp;
177  }
178  } // namespace VcImpl
179 #endif // HAVE_VC
180 
181  template<typename T>
182  struct SimdScalarTypeTraits
183  {
184  using type = T;
185  };
186 
187  template<typename T>
188  using SimdScalar = typename SimdScalarTypeTraits<T>::type;
189 
190 #if HAVE_VC
191  /*
192  Add Vc specializations for the SimdScalarTypeTraits trais class
193  */
194  template<typename T, typename A>
195  struct SimdScalarTypeTraits< Vc::Vector<T,A> >
196  {
197  using type = T;
198  };
199 
200  template<typename T, std::size_t N, typename V, std::size_t M>
201  struct SimdScalarTypeTraits< Vc::SimdArray<T,N,V,M> >
202  {
203  using type = T;
204  };
205 #endif // HAVE_VC
206 
207  template<typename V, typename = void>
208  struct SimdIndexTypeTraits {
209  using type = std::size_t;
210  };
211 
213 
219  template<typename V>
220  using SimdIndex = typename SimdIndexTypeTraits<V>::type;
221 
222 #if HAVE_VC
223  template<typename T, typename A>
224  struct SimdIndexTypeTraits<Vc::Vector<T, A> > {
225  using type = typename Vc::Vector<T, A>::index_type;
226  };
227 
228  template<typename T, std::size_t n, typename V>
229  struct SimdIndexTypeTraits<Vc::SimdArray<T, n, V> > {
230  using type = typename Vc::SimdArray<T, n, V>::index_type;
231  };
232 #endif // HAVE_VC
233 
234  template<typename V, typename = void>
235  struct SimdMaskTypeTraits {
236  using type = bool;
237  };
238 
240 
243  template<typename V>
244  using SimdMask = typename SimdMaskTypeTraits<V>::type;
245 
246 #if HAVE_VC
247  template<typename T, typename A>
248  struct SimdMaskTypeTraits<Vc::Vector<T, A> > {
249  using type = typename Vc::Vector<T, A>::mask_type;
250  };
251 
252  template<typename T, std::size_t n, typename V>
253  struct SimdMaskTypeTraits<Vc::SimdArray<T, n, V> > {
254  using type = typename Vc::SimdArray<T, n, V>::mask_type;
255  };
256 #endif // HAVE_VC
257 
258 #if HAVE_VC
259  /*
260  Add Vc specializations for cond(), see conditional.hh
261  */
262  template<typename T, typename A>
263  Vc::Vector<T,A> cond(const Vc::Mask<T,A> & b,
264  const Vc::Vector<T,A> & v1,
265  const Vc::Vector<T,A> & v2)
266  {
267  return std::move(Vc::iif(b, v1, v2));
268  }
269 
270  template<typename T, std::size_t N, typename V, std::size_t M>
271  Vc::SimdArray<T,N,V,M> cond(const typename Vc::SimdArray<T,N,V,M>::mask_type & b,
272  const Vc::SimdArray<T,N,V,M> & v1,
273  const Vc::SimdArray<T,N,V,M> & v2)
274  {
275  return std::move(Vc::iif(b, v1, v2));
276  }
277 #endif // HAVE_VC
278 
279 #if HAVE_VC
280  /*
281  Add Vc specializations for several boolean operations, see rangeutitlities.hh:
282 
283  max_value, min_value, any_true, all_true
284  */
285  template<typename T, typename A>
286  T max_value(const Vc::Vector<T,A> & v)
287  {
288  return v.max();
289  }
290 
291  template<typename T, std::size_t N, typename V, std::size_t M>
292  double max_value(const Vc::SimdArray<T,N,V,M> & v)
293  {
294  return v.max();
295  }
296 
297  template<typename T, typename A>
298  T min_value(const Vc::Vector<T,A> & v)
299  {
300  return v.min();
301  }
302 
303  template<typename T, std::size_t N, typename V, std::size_t M>
304  double min_value(const Vc::SimdArray<T,N,V,M> & v)
305  {
306  return v.min();
307  }
308 
309  template<typename T, typename A>
310  bool any_true(const Vc::Mask<T,A> & v)
311  {
312  return Vc::any_of(v);
313  }
314 
315  template<typename T, std::size_t N, typename V, std::size_t M>
316  bool any_true(const Vc::SimdMaskArray<T,N,V,M> & v)
317  {
318  return Vc::any_of(v);
319  }
320 
321  template<typename T, typename A>
322  bool all_true(const Vc::Mask<T,A> & v)
323  {
324  return Vc::all_of(v);
325  }
326 
327  template<typename T, std::size_t N, typename V, std::size_t M>
328  bool all_true(const Vc::SimdMaskArray<T,N,V,M> & v)
329  {
330  return Vc::all_of(v);
331  }
332 #endif // HAVE_VC
333 
335  template<class T>
336  std::size_t lanes(const T &) { return 1; }
337 
339  template<class T>
340  T lane(std::size_t l, const T &v)
341  {
342  assert(l == 0);
343  return v;
344  }
345 
347  template<class T>
348  T &lane(std::size_t l, T &v)
349  {
350  assert(l == 0);
351  return v;
352  }
353 
354 #if HAVE_VC
355  template<class T, class A>
356  std::size_t lanes(const Vc::Vector<T, A> &)
357  {
358  return Vc::Vector<T, A>::size();
359  }
360 
361  template<class T, class A>
362  T lane(std::size_t l, const Vc::Vector<T, A> &v)
363  {
364  assert(l < lanes(v));
365  return v[l];
366  }
367 
368  template<class T, class A>
369  auto lane(std::size_t l, Vc::Vector<T, A> &v)
370  {
371  assert(l < lanes(v));
372  return VcImpl::Proxy<Vc::Vector<T, A> >{l, v};
373  }
374 
375  template<class T, std::size_t n, class V>
376  std::size_t lanes(const Vc::SimdArray<T, n, V> &)
377  {
378  return n;
379  }
380 
381  template<class T, std::size_t n, class V>
382  T lane(std::size_t l, const Vc::SimdArray<T, n, V> &v)
383  {
384  assert(l < n);
385  return v[l];
386  }
387 
388  template<class T, std::size_t n, class V>
389  auto lane(std::size_t l, Vc::SimdArray<T, n, V> &v)
390  {
391  assert(l < n);
392  return VcImpl::Proxy<Vc::SimdArray<T, n, V> >{l, v};
393  }
394 
395  template<class T, std::size_t n, class V>
396  std::size_t lanes(const Vc::SimdMaskArray<T, n, V> &)
397  {
398  return n;
399  }
400 
401  template<class T, std::size_t n, class V>
402  const bool lane(std::size_t l, const Vc::SimdMaskArray<T, n, V> &v)
403  {
404  assert(l < n);
405  return v[l];
406  }
407 
408  template<class T, std::size_t n, class V>
409  auto lane(std::size_t l, Vc::SimdMaskArray<T, n, V> &v)
410  {
411  assert(l < n);
412  return VcImpl::Proxy<Vc::SimdMaskArray<T, n, V> >{l, v};
413  }
414 #endif // HAVE_VC
415 
417 
420  template<class T>
421  void assign(T &dst, const T &src, bool mask)
422  {
423  if(mask) dst = src;
424  }
425 
426 #if HAVE_VC
427  /*
428  Add Vc specializations for masked assignment
429  */
430  template<class T, class A>
431  void assign(Vc::Vector<T, A> &dst, const Vc::Vector<T, A> &src,
432  typename Vc::Vector<T, A>::mask_type mask)
433  {
434  dst(mask) = src;
435  }
436 
437  template<class T, std::size_t n, class V>
438  void assign(Vc::SimdArray<T, n, V> &dst, const Vc::SimdArray<T, n, V> &src,
439  typename Vc::SimdArray<T, n, V>::mask_type mask)
440  {
441  dst(mask) = src;
442  }
443 #endif // HAVE_VC
444 
445  template<class T>
446  void swap(T &v1, T &v2, bool mask)
447  {
448  using std::swap;
449  if(mask) swap(v1, v2);
450  }
451 
452 #if HAVE_VC
453  /*
454  Add Vc specializations for masked swap
455  */
456  template<class T, class A>
457  void swap(Vc::Vector<T, A> &v1, Vc::Vector<T, A> &v2,
458  typename Vc::Vector<T, A>::mask_type mask)
459  {
460  auto tmp = v1;
461  v1(mask) = v2;
462  v2(mask) = tmp;
463  }
464 
465  template<class T, std::size_t n, class V>
466  void swap(Vc::SimdArray<T, n, V> &v1, Vc::SimdArray<T, n, V> &v2,
467  typename Vc::SimdArray<T, n, V>::mask_type mask)
468  {
469  auto tmp = v1;
470  v1(mask) = v2;
471  v2(mask) = tmp;
472  }
473 #endif // HAVE_VC
474 
475 } // end namespace Dune
476 
477 #endif // DUNE_COMMON_SIMD_HH
Dune namespace.
Definition: alignedallocator.hh:10
typename SimdIndexTypeTraits< V >::type SimdIndex
An simd vector of indices corresponding to a simd vector V.
Definition: simd.hh:220
typename SimdMaskTypeTraits< V >::type SimdMask
A simd vector of truth values corresponding to a simd vector V.
Definition: simd.hh:244
T lane(std::size_t l, const T &v)
access a lane of a simd vector (scalar version)
Definition: simd.hh:340
void assign(T &dst, const T &src, bool mask)
masked Simd assignment (scalar version)
Definition: simd.hh:421
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition: conditional.hh:26
std::size_t lanes(const T &)
get the number of lanes of a simd vector (scalar version)
Definition: simd.hh:336
Utilities for reduction like operations on ranges.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (Mar 28, 23:30, 2024)