Dune Core Modules (unstable)

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