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.
42#endif
44#include <dune/common/vc.hh>
45
46namespace 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:128
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.111.3 (Dec 21, 23:30, 2024)