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
29namespace 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.111.3 (Dec 26, 23:30, 2024)