Dune Core Modules (2.7.1)

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