Dune Core Modules (2.8.0)

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.
40#endif
42#include <dune/common/vc.hh>
43
44namespace 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
Traits for type conversions and type information.
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:11
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.
Compatibility header for including <Vc/Vc>
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)