Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
SimdAVX.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SimdAVX.h (C) 2000-2016 */
9/* */
10/* Vectorisation pour AVX et AVX2. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_SIMDAVX_H
13#define ARCANE_UTILS_SIMDAVX_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * Ce fichier ne doit pas être inclus directement.
18 * Utiliser 'Simd.h' à la place.
19 */
20
21/*---------------------------------------------------------------------------*/
22/*---------------------------------------------------------------------------*/
23
24//! A définir si on souhaite utiliser le gather de l'AVX2.
25// #define ARCANE_USE_AVX2_GATHER
26
27// Le gather n'est disponible que avec l'AVX2
28#ifndef __AVX2__
29#undef ARCANE_USE_AVX2_GATHER
30#endif
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35ARCANE_BEGIN_NAMESPACE
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39/*!
40 * \ingroup ArcaneSimd
41 * \brief Vectorisation des entiers Int32 en utilisant AVX.
42 */
44{
45 public:
46 static const int BLOCK_SIZE = 8;
47 enum
48 {
49 Length = 8,
50 Alignment = 32
51 };
52 public:
53 __m256i v0;
55 AVXSimdX8Int32(__m256i _v0) : v0(_v0) {}
56 explicit AVXSimdX8Int32(Int32 a) : v0(_mm256_set1_epi32(a)){}
57 private:
58 AVXSimdX8Int32(Int32 a7,Int32 a6,Int32 a5,Int32 a4,Int32 a3,Int32 a2,Int32 a1,Int32 a0)
59 : v0(_mm256_set_epi32(a7,a6,a5,a4,a3,a2,a1,a0)){}
60 public:
61 AVXSimdX8Int32(const Int32* base,const Int32* idx)
62 : v0(_mm256_set_epi32(base[idx[7]],base[idx[6]],base[idx[5]],base[idx[4]],
63 base[idx[3]],base[idx[2]],base[idx[1]],base[idx[0]])) {}
64 explicit AVXSimdX8Int32(const Int32* base)
65 : v0(_mm256_load_si256((const __m256i*)base)){}
66
67 Int32 operator[](Integer i) const { return ((const Int32*)&v0)[i]; }
68 Int32& operator[](Integer i) { return ((Int32*)&v0)[i]; }
69
70 void set(ARCANE_RESTRICT Int32* base,const ARCANE_RESTRICT Int32* idx) const
71 {
72 const Int32* x = (const Int32*)(this);
73 base[idx[0]] = x[0];
74 base[idx[1]] = x[1];
75 base[idx[2]] = x[2];
76 base[idx[3]] = x[3];
77 base[idx[4]] = x[4];
78 base[idx[5]] = x[5];
79 base[idx[6]] = x[6];
80 base[idx[7]] = x[7];
81 }
82
83 void set(ARCANE_RESTRICT Int32* base) const
84 {
85 _mm256_store_si256((__m256i*)base,v0);
86 }
87
88 void load(const AVXSimdX8Int32* base)
89 {
90 v0 = _mm256_load_si256((const __m256i*)base);
91 }
92
93 static AVXSimdX8Int32 fromScalar(Int32 a0,Int32 a1,Int32 a2,Int32 a3,
94 Int32 a4,Int32 a5,Int32 a6,Int32 a7)
95 {
96 return AVXSimdX8Int32(a7,a6,a5,a4,a3,a2,a1,a0);
97 }
98
99 private:
100 void operator=(Int32 _v);
101};
102
103/*---------------------------------------------------------------------------*/
104/*---------------------------------------------------------------------------*/
105/*!
106 * \ingroup ArcaneSimd
107 * \brief Vectorisation des réels en utilisant AVX.
108 * \note Cette classe doit être alignée sur 32 octets.
109 */
111{
112 public:
113 static const int BLOCK_SIZE = 4;
114 enum
115 {
116 Length = 4
117 };
119 public:
120 __m256d v0;
121 AVXSimdX4Real(){}
122 AVXSimdX4Real(__m256d _v0)
123 : v0(_v0) {}
124 explicit AVXSimdX4Real(Real r)
125 : v0(_mm256_set1_pd(r)) { }
126 private:
127 AVXSimdX4Real(Real a3,Real a2,Real a1,Real a0)
128 : v0(_mm256_set_pd(a3,a2,a1,a0)) { }
129 public:
130 AVXSimdX4Real(const Real* base,const Int32* idx)
131 : v0(_mm256_set_pd(base[idx[3]],base[idx[2]],base[idx[1]],base[idx[0]])) {}
132
133 AVXSimdX4Real(const Real* base,const Int32IndexType& simd_idx)
134#ifdef ARCANE_USE_AVX2_GATHER
135 : v0(_mm256_i32gather_pd(base,simd_idx.v0,8)){}
136#else
137 : AVXSimdX4Real(base,(const Int32*)&simd_idx){}
138#endif
139
140 AVXSimdX4Real(const Real* base,const Int32IndexType* simd_idx)
141#ifdef ARCANE_USE_AVX2_GATHER
142 : v0(_mm256_i32gather_pd((Real*)base,simd_idx->v0,8)){}
143#else
144 : AVXSimdX4Real(base,(const Int32*)simd_idx){}
145#endif
146
147 //! Charge les valeurs continues situées à l'adresse \a base qui doit être alignée.
148 explicit AVXSimdX4Real(const Real* base)
149 : v0(_mm256_load_pd(base)) { }
150
151 Real operator[](Integer i) const { return ((const Real*)&v0)[i]; }
152 Real& operator[](Integer i) { return ((Real*)&v0)[i]; }
153
154 void set(ARCANE_RESTRICT Real* base,const Int32* idx) const
155 {
156#if 1
157 const Real* x = (const Real*)(this);
158 base[idx[0]] = x[0];
159 base[idx[1]] = x[1];
160 base[idx[2]] = x[2];
161 base[idx[3]] = x[3];
162#else
163 // Ces méthodes de scatter ne sont disponibles que
164 // pour l'AVX512VL
165 __m128i idx0 = _mm_load_si128((__m128i*)idx);
166 _mm256_i32scatter_pd(base,idx0,v0, 8);
167#endif
168 }
169
170 void set(ARCANE_RESTRICT Real* base,const Int32IndexType& simd_idx) const
171 {
172 this->set(base,&simd_idx);
173 }
174
175 void set(ARCANE_RESTRICT Real* base,const Int32IndexType* simd_idx) const
176 {
177 this->set(base,(const Int32*)simd_idx);
178 }
179 //! Stocke les valeurs de l'instance à l'adresse \a base qui doit être alignée.
180 void set(ARCANE_RESTRICT Real* base) const
181 {
182 _mm256_store_pd(base,v0);
183 }
184
185 static AVXSimdX4Real fromScalar(Real a0,Real a1,Real a2,Real a3)
186 {
187 return AVXSimdX4Real(a3,a2,a1,a0);
188 }
189
190 // Unary operation operator-
191 inline AVXSimdX4Real operator- () const
192 {
193 return AVXSimdX4Real(_mm256_sub_pd(_mm256_setzero_pd(),v0));
194 }
195
196 private:
197 void operator=(Real _v);
198};
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202/*!
203 * \ingroup ArcaneSimd
204 * \brief Vectorisation des réels en utilisant AVX avec des blocs de 8 reels.
205 * \note Cette classe doit être alignée sur 32 octets.
206 */
208{
209 public:
210 static const int BLOCK_SIZE = 8;
211 enum
212 {
213 Length = 8
214 };
215 public:
216 __m256d v0;
217 __m256d v1;
218 AVXSimdX8Real(){}
219 AVXSimdX8Real(__m256d _v0,__m256d _v1)
220 : v0(_v0), v1(_v1){}
221 explicit AVXSimdX8Real(Real r)
222 {
223 v0 = _mm256_set1_pd(r);
224 v1 = _mm256_set1_pd(r);
225 }
226 private:
227 AVXSimdX8Real(Real a7,Real a6,Real a5,Real a4,Real a3,Real a2,Real a1,Real a0)
228 {
229 v0 = _mm256_set_pd(a3,a2,a1,a0);
230 v1 = _mm256_set_pd(a7,a6,a5,a4);
231 }
232 public:
233 AVXSimdX8Real(const Real* base,const Int32* idx)
234 {
235 //TODO Avec AVX2, utiliser vgather mais pour l'instant on ne le détecte pas
236 // et les tests montrent que ce n'est pas toujours le plus
237 // performant (peut-être avec des indices alignés).
238#if 1
239 v0 = _mm256_set_pd(base[idx[3]],base[idx[2]],base[idx[1]],base[idx[0]]);
240 v1 = _mm256_set_pd(base[idx[7]],base[idx[6]],base[idx[5]],base[idx[4]]);
241#else
242 __m128i idx0 = _mm_loadu_si128((__m128i*)idx);
243 __m128i idx1 = _mm_loadu_si128((__m128i*)(idx+4));
244 v0 = _mm256_i32gather_pd((Real*)base,idx0,8);
245 v1 = _mm256_i32gather_pd((Real*)base,idx1,8);
246#endif
247 }
248
249 //! Charge les valeurs continues situées à l'adresse \a base qui doit être alignée.
250 explicit AVXSimdX8Real(const Real* base)
251 {
252 v0 = _mm256_load_pd(base);
253 v1 = _mm256_load_pd(base+4);
254 }
255
256 Real operator[](Integer i) const { return ((const Real*)&v0)[i]; }
257 Real& operator[](Integer i) { return ((Real*)&v0)[i]; }
258
259 void set(ARCANE_RESTRICT Real* base,const ARCANE_RESTRICT Int32* idx) const
260 {
261#if 1
262 const Real* x = (const Real*)(this);
263 base[idx[0]] = x[0];
264 base[idx[1]] = x[1];
265 base[idx[2]] = x[2];
266 base[idx[3]] = x[3];
267 base[idx[4]] = x[4];
268 base[idx[5]] = x[5];
269 base[idx[6]] = x[6];
270 base[idx[7]] = x[7];
271#else
272 // Ces méthodes de scatter ne sont disponibles que
273 // pour l'AVX512VL
274 __m128i idx0 = _mm_loadu_si128((__m128i*)idx);
275 __m128i idx1 = _mm_loadu_si128((__m128i*)(idx+4));
276 _mm256_i32scatter_pd(base,idx0,v0, 8);
277 _mm256_i32scatter_pd(base,idx1,v1, 8);
278#endif
279 }
280
281 //! Stocke les valeurs de l'instance à l'adresse \a base qui doit être alignée.
282 void set(ARCANE_RESTRICT Real* base) const
283 {
284 _mm256_store_pd(base,v0);
285 _mm256_store_pd(base+4,v1);
286 }
287
288 static AVXSimdX8Real fromScalar(Real a0,Real a1,Real a2,Real a3,
289 Real a4,Real a5,Real a6,Real a7)
290 {
291 return AVXSimdX8Real(a7,a6,a5,a4,a3,a2,a1,a0);
292 }
293
294 // Unary operation operator-
295 inline AVXSimdX8Real operator- () const
296 {
297 return AVXSimdX8Real(_mm256_sub_pd(_mm256_setzero_pd(),v0),
298 _mm256_sub_pd(_mm256_setzero_pd(),v1));
299 }
300
301 private:
302 void operator=(Real _v);
303};
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307/*!
308 * \brief Vecteur de 'double' en implémentation par SSE.
309 *
310 * Utilise le vecteur de 4 éléments comme vecteur par défaut en SSE.
311 * Les différents tests montrent que c'est la meilleur taille. Avec une
312 * taille de deux les boucles sont trop petites et avec une taille de 8
313 * le compilateur a souvent trop de temporaires à gérer ce qui limite
314 * l'optimisation.
315 */
317
318/*---------------------------------------------------------------------------*/
319/*---------------------------------------------------------------------------*/
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
325{
326 public:
327 static const char* name() { return "AVX"; }
328 enum
329 {
330 Int32IndexSize = AVXSimdReal::Length
331 };
332 typedef AVXSimdReal SimdReal;
334};
335
336/*---------------------------------------------------------------------------*/
337/*---------------------------------------------------------------------------*/
338
339ARCANE_UTILS_EXPORT std::ostream& operator<<(std::ostream& o,const AVXSimdReal& s);
340
341/*---------------------------------------------------------------------------*/
342/*---------------------------------------------------------------------------*/
343
344ARCANE_END_NAMESPACE
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
349#endif
#define ARCANE_ALIGNAS_PACKED(value)
Macro pour garantir le compactage et l'alignement d'une classe sur value octets.
Vectorisation des réels en utilisant AVX.
Definition SimdAVX.h:111
AVXSimdX4Real(const Real *base)
Charge les valeurs continues situées à l'adresse base qui doit être alignée.
Definition SimdAVX.h:148
void set(ARCANE_RESTRICT Real *base) const
Stocke les valeurs de l'instance à l'adresse base qui doit être alignée.
Definition SimdAVX.h:180
Vectorisation des entiers Int32 en utilisant AVX.
Definition SimdAVX.h:44
Vectorisation des réels en utilisant AVX avec des blocs de 8 reels.
Definition SimdAVX.h:208
void set(ARCANE_RESTRICT Real *base) const
Stocke les valeurs de l'instance à l'adresse base qui doit être alignée.
Definition SimdAVX.h:282
AVXSimdX8Real(const Real *base)
Charge les valeurs continues situées à l'adresse base qui doit être alignée.
Definition SimdAVX.h:250
Vectorisation des entiers en utilisant SSE.
Definition SimdSSE.h:35
std::ostream & operator<<(std::ostream &ostr, eItemKind item_kind)
Opérateur de sortie sur un flot.
double Real
Type représentant un réel.