TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Simd_template.h
1/****************************************************************************
2* Copyright (c) 2024, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#ifndef Simd_template_included
17#define Simd_template_included
18
19#include <assert.h>
20#include <stdint.h>
21#include <cstdlib>
22#include <cmath>
23
24#include <kokkos++.h>
25#ifdef _KOKKOS_AVX
26#include <Kokkos_SIMD.hpp>
27#endif
28
29/*! @brief This class provides a generic access to simd operations on x86, x86 AMD and ARM architectures.
30 *
31 * Functionalities provided by the class are :
32 * - load vector size aligned data from memory (SimdGet)
33 * - getting x[i-1] and x[i+1] for finite difference algorithms
34 * (SimdGetAtLeft, SimdGetAtRight, etc)
35 * - arithmetic operations (+ - * /)
36 * - conditional affectation (SimdSelect)
37 *
38 */
39template<typename _TYPE_>
41{
42public:
43 using value_type = _TYPE_;
44#ifdef _KOKKOS_AVX
45 using simd_type = Kokkos::Experimental::native_simd<_TYPE_>;
46#endif
47 Simd_template() { data_ = 0.; };
48 // Commodity default constructor (provides implicit conversion)
49 Simd_template(_TYPE_ x) : data_(x) {};
50#ifdef _KOKKOS_AVX
51 Simd_template(simd_type x) : data_(x) {};
52#endif
53 // Size of the vector
54 static int size()
55 {
56#ifdef _KOKKOS_AVX
57 return int(simd_type::size());
58#else
59 return 1;
60#endif
61 }
65
66 _TYPE_& operator[](int idx)
67 {
68 assert(idx>=0 && idx<size());
69#ifdef _KOKKOS_AVX
70 return data_[idx];
71#else
72 return data_;
73#endif
74 }
75
76 _TYPE_ operator[](int idx) const
77 {
78 assert(idx>=0 && idx<size());
79#ifdef _KOKKOS_AVX
80 return data_[idx];
81#else
82 return data_;
83#endif
84 }
85
86 _TYPE_ sumReduction()
87 {
88#ifdef _KOKKOS_AVX
89 _TYPE_ res(0.);
90 for(int ivec = 0; ivec < size(); ivec++)
91 res += data_[ivec];
92 return res;
93#else
94 return data_;
95#endif
96 }
97
98#ifdef _KOKKOS_AVX
99 simd_type data_;
100#else
101 _TYPE_ data_;
102#endif
103};
104
105using Simd_float = Simd_template<float>;
106using Simd_double = Simd_template<double>;
107using Simd_int = Simd_template<int>;
108using RightSimdArrayView = Kokkos::View<Simd_double*,Kokkos::LayoutRight>;
109using RightSimdTabView = Kokkos::View<Simd_double**,Kokkos::LayoutRight>;
110
111#ifdef _KOKKOS_AVX
112using tag_type = Kokkos::Experimental::element_aligned_tag;
113#endif
114
115/*! @brief returns 1 if pointer is aligned on size bytes, 0 otherwise
116 *
117 * Warn: size must be a power of 2.
118 *
119 */
120inline int aligned(const void *ptr, int size)
121{
122 // uintptr_t is the result of pointer operations like ptr1-ptr2
123 return ((uintptr_t)ptr & (uintptr_t)(size-1)) == 0;
124}
125
126/*! @brief Returns the vector found at address data.
127 *
128 * data must be aligned for the architecture
129 *
130 */
131template<typename _TYPE_>
132inline Simd_template<_TYPE_> SimdGet(const _TYPE_ *data)
133{
134#ifdef _KOKKOS_AVX
136 v.data_.copy_from(data,tag_type());
137 return v;
138#else
139 return *data;
140#endif
141}
142
143/*! @brief Stores vector x at address data.
144 *
145 * data must be aligned for the architecture
146 *
147 */
148template<typename _TYPE_>
149inline void SimdPut(_TYPE_ *data, Simd_template<_TYPE_> x)
150{
151#ifdef _KOKKOS_AVX
152 x.data_.copy_to(data, tag_type());
153#else
154 *data = x.data_;
155#endif
156}
157
158/*! @brief Returns the vector x starting at adress data+1, data must be aligned for the architecture
159 *
160 */
161template<typename _TYPE_>
162inline Simd_template<_TYPE_> SimdGetAtRight(const _TYPE_ *data)
163{
164#ifdef _KOKKOS_AVX
166 v.data_.copy_from(data+1,tag_type());
167 return v;
168#else
169 return data[1];
170#endif
171}
172
173/*! @brief Returns the vector x starting at adress data-1 data must be aligned for the architecture
174 *
175 */
176template<typename _TYPE_>
177inline Simd_template<_TYPE_> SimdGetAtLeft(const _TYPE_ *data)
178{
179#ifdef _KOKKOS_AVX
181 v.data_.copy_from(data-1,tag_type());
182 return v;
183#else
184 return data[-1];
185#endif
186}
187
188/*! @brief Returns the vector left and center starting at adress data-1 and data data must be aligned for the architecture
189 *
190 */
191template<typename _TYPE_>
192inline void SimdGetLeftCenter(const _TYPE_ *data, Simd_template<_TYPE_>& left, Simd_template<_TYPE_>& center)
193{
194#ifdef _KOKKOS_AVX
195 left.data_.copy_from(data-1, tag_type());
196 center.data_.copy_from(data, tag_type());
197#else
198 left = data[-1];
199 center = data[0];
200#endif
201}
202
203/*! @brief Returns the vector center and right starting at adress data and data+1 data must be aligned for the architecture
204 *
205 */
206template<typename _TYPE_>
207inline void SimdGetCenterRight(const _TYPE_ *data,
208 Simd_template<_TYPE_>& center,
210{
211#ifdef _KOKKOS_AVX
212 center.data_.copy_from(data, tag_type());
213 right.data_.copy_from(data+1, tag_type());
214#else
215 center = data[0];
216 right = data[1];
217#endif
218}
219
220/*! @brief Returns the vectors left, center and right starting at adress data-1, data and data+1 data must be aligned for the architecture
221 *
222 */
223template<typename _TYPE_>
224inline void SimdGetLeftCenterRight(const _TYPE_ *data,
226 Simd_template<_TYPE_>& center,
228{
229#ifdef _KOKKOS_AVX
230 left.data_.copy_from(data-1, tag_type());
231 center.data_.copy_from(data, tag_type());
232 right.data_.copy_from(data+1, tag_type());
233#else
234 left = data[-1];
235 center = data[0];
236 right = data[1];
237#endif
238}
239
240/*! @brief Returns the vectors leftleft, left, center and right starting at adress data-2, data-1, data and data+1 data must be aligned for the architecture
241 *
242 */
243template<typename _TYPE_>
244inline void SimdGetLeftleftLeftCenterRight(const _TYPE_ *data,
245 Simd_template<_TYPE_>& leftleft,
247 Simd_template<_TYPE_>& center,
249{
250#ifdef _KOKKOS_AVX
251 leftleft.data_.copy_from(data-2, tag_type());
252 left.data_.copy_from(data-1, tag_type());
253 center.data_.copy_from(data, tag_type());
254 right.data_.copy_from(data+1, tag_type());
255#else
256 leftleft = data[-2];
257 left = data[-1];
258 center = data[0];
259 right = data[1];
260#endif
261}
262
263/*! @brief returns a+b
264 *
265 */
266template<typename _TYPE_>
267inline Simd_template<_TYPE_> operator+(Simd_template<_TYPE_> a, Simd_template<_TYPE_> b) { return a.data_ + b.data_; }
268template<typename _TYPE_>
269inline Simd_template<_TYPE_> operator+(Simd_template<_TYPE_> a, double b) { return a.data_ + b; }
270template<typename _TYPE_>
271inline Simd_template<_TYPE_> operator+(double a, Simd_template<_TYPE_> b) { return a + b.data_; }
272/*! @brief returns a-b
273 *
274 */
275template<typename _TYPE_>
276inline Simd_template<_TYPE_> operator-(Simd_template<_TYPE_> a, Simd_template<_TYPE_> b) { return a.data_ - b.data_; }
277template<typename _TYPE_>
278inline Simd_template<_TYPE_> operator-(Simd_template<_TYPE_> a, double b) { return a.data_ - b; }
279template<typename _TYPE_>
280inline Simd_template<_TYPE_> operator-(double a, Simd_template<_TYPE_> b) { return a - b.data_; }
281
282
283/*! @brief returns a*b
284 *
285 */
286template<typename _TYPE_>
287inline Simd_template<_TYPE_> operator*(Simd_template<_TYPE_> a, Simd_template<_TYPE_> b) { return a.data_ * b.data_; }
288template<typename _TYPE_>
289inline Simd_template<_TYPE_> operator*(Simd_template<_TYPE_> a, double b) { return a.data_ * b; }
290template<typename _TYPE_>
291inline Simd_template<_TYPE_> operator*(double a, Simd_template<_TYPE_> b) { return a * b.data_; }
292
293template<typename _TYPE_>
294inline Simd_template<_TYPE_> operator/(Simd_template<_TYPE_> a, Simd_template<_TYPE_> b) { return a.data_ / b.data_; }
295template<typename _TYPE_>
296inline Simd_template<_TYPE_> operator/(Simd_template<_TYPE_> a, double b) { return a.data_ / b; }
297template<typename _TYPE_>
298inline Simd_template<_TYPE_> operator/(double a, Simd_template<_TYPE_> b) { return a / b.data_; }
299
300template<typename _TYPE_>
301inline Simd_template<_TYPE_> Simd_absolute_value(Simd_template<_TYPE_> a)
302{
303#ifdef _KOKKOS_AVX
304 return Kokkos::abs(a.data_);
305#else
306 return std::abs(a.data_);
307#endif
308}
309
310template<typename _TYPE_>
312{
313#ifdef _KOKKOS_AVX
314 return Kokkos::exp(a.data_);
315#else
316 return std::exp(a.data_);
317#endif
318}
319
320template<typename _TYPE_>
322{
323#ifdef _KOKKOS_AVX
324 return Kokkos::sqrt(a.data_);
325#else
326 return std::sqrt(a.data_);
327#endif
328}
329
330// Returns a vector built with min(a[i],b[i]) (element wise)
331template<typename _TYPE_>
333{
334#ifdef _KOKKOS_AVX
335 return Kokkos::min(a.data_, b.data_);
336#else
337 return (a.data_ < b.data_) ? a : b;
338#endif
339}
340
341// Returns a vector built with max(a[i],b[i]) (element wise)
342template<typename _TYPE_>
344{
345#ifdef _KOKKOS_AVX
346 return Kokkos::max(a.data_, b.data_);
347#else
348 return (a.data_ > b.data_) ? a : b;
349#endif
350}
351
352// Approximation of a/b not available with Kokkos... classic division
353template<typename _TYPE_>
354inline Simd_template<_TYPE_> SimdDivideMed(const Simd_template<_TYPE_>& a, const Simd_template<_TYPE_>& b)
355{
356 return a.data_ / b.data_;
357}
358
359// // Approximation of 1/b not available with Kokkos... classic reciprocal
360template<typename _TYPE_>
361inline Simd_template<_TYPE_> SimdReciprocalMed(const Simd_template<_TYPE_>& b)
362{
363 return 1. / b.data_;
364}
365
366
367/*! @brief This function performs the following operation on the vectors for (i=0; i<size())
368 *
369 * if (x1[i] < x2[i])
370 * result[i] = value_if_x1_lower_than_x2[i]
371 * else
372 * result[i] = value_otherwise[i]
373 *
374 */
375template<typename _TYPE_>
378 Simd_template<_TYPE_> value_if_x1_lower_than_x2,
379 Simd_template<_TYPE_> value_otherwise)
380{
381#ifdef _KOKKOS_AVX
382 Simd_template<_TYPE_> res(value_otherwise.data_);
383 where(x1.data_ < x2.data_, res.data_) = value_if_x1_lower_than_x2.data_;
384 return res;
385#else
386 return (x1.data_ < x2.data_) ? value_if_x1_lower_than_x2.data_ : value_otherwise.data_;
387#endif
388}
389
390#endif
391
392
This class provides a generic access to simd operations on x86, x86 AMD and ARM architectures.
Simd_template(_TYPE_ x)
void operator+=(Simd_template a)
_TYPE_ sumReduction()
void operator-=(Simd_template a)
_TYPE_ & operator[](int idx)
static int size()
void operator*=(Simd_template a)
_TYPE_ operator[](int idx) const