Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
Simd.h
Aller à la documentation de ce fichier.
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/* Simd.h (C) 2000-2017 */
9/* */
10/* Types pour la vectorisation. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_SIMD_H
13#define ARCANE_UTILS_SIMD_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/SimdCommon.h"
18#include "arcane/utils/Real3.h"
19#include "arcane/utils/Real2.h"
20#include "arcane/utils/Real3x3.h"
21#include "arcane/utils/Real2x2.h"
22#include "arcane/utils/ArrayView.h"
23
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26/*!
27 * \file Simd.h
28 *
29 * Ce fichier contient les déclarations des types utilisés pour gérer
30 * la vectorisation. Comme il existe plusieurs mécanismes possibles, il
31 * faut faire un choix en fonction de l'architecture machine et des
32 * options de compilation. Chaque mécanisme utilise des vecteurs
33 * de taille différente. Dans notre cas comme la vectorisation est
34 * utilisée principalement pour les calculs sur des doubles, la
35 * taille d'un vecteur sera égale au nombre de double qu'on peut mettre
36 * dans un vecteur.
37 *
38 * Actuellement, on supporte les modes suivants par ordre de priorité. Si
39 * un mode est supporté, les autres ne sont pas utilisés.
40 * - AVX512 pour les architectures de type Intel Knight Landing (KNL) ou
41 * Xeon Skylake. La taille des vecteurs est de 8 dans ce mode.
42 * - AVX. Pour ce mode, il faut compiler Arcane avec l'option '--with-avx'. Il
43 * existe deux modes, l'AVX classique et l'AVX2. Pour l'instant, seul le
44 * premier est utilisé, faute de machines pour tester le second. La taille
45 * des vecteurs est de 4 dans ce mode.
46 * - SSE. Ce mode est disponible par défaut car il existe sur toutes les
47 * plateformes x64. La aussi il existe plusieurs versions et on se limite
48 * à la version 2. La taille des vecteurs est de 2 dans ce mode
49 * - aucun mode. Dans ce cas il n'y a pas de vectorisation spécifique.
50 * Néanmoins pour tester le code, on permet une émulation avec
51 * des vecteurs de taille de 2.
52 */
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56/*
57 * Les compilateurs (gcc et icc) définissent les macros suivantes
58 * sur x64 suivant le support de la vectorisation
59 * : avx: __AVX__
60 * : avx2: __AVX2__
61 * : avx512f: __AVX512F__
62 * : sse2: __SSE2__
63 *
64 * A noter que pour l'avx2 avec gcc, il n'y a pas par défaut le FMA.
65 * Par exemple:
66 * - gcc -mavx2 : pas de fma
67 * - gcc -mavx2 -mfma : fma actif
68 * - gcc -march=haswell : fma actif
69 */
70
71// Simd via émulation.
72#include "arcane/utils/SimdEMUL.h"
73
74// Ajoute support de SSE s'il existe
75#if (defined(_M_X64) || defined(__x86_64__)) && !defined(ARCANE_NO_SSE)
76// SSE2 est disponible sur tous les CPU x64
77// La macro __x64_64__ est définie pour les machines linux
78// La macro _M_X64 est définie pour les machines Windows
79#define ARCANE_HAS_SSE
80#include <emmintrin.h>
81#include "arcane/utils/SimdSSE.h"
82#endif
83
84// Ajoute support de AVX si dispo
85#if defined(ARCANE_HAS_AVX) || defined(ARCANE_HAS_AVX512)
86#include <immintrin.h>
87#include "arcane/utils/SimdAVX.h"
88#endif
89
90// Ajoute support de l'AVX512 si dispo
91#if defined(ARCANE_HAS_AVX512)
92#include <immintrin.h>
93#include "arcane/utils/SimdAVX512.h"
94#endif
95
96/*---------------------------------------------------------------------------*/
97/*---------------------------------------------------------------------------*/
98/*!
99 * \ingroup ArcaneSimd
100 * \brief Macro pour itérer sur les index d'un vecteur
101 * Simd de réel ou dérivé (Real2, Real3, ...).
102 */
103#define ENUMERATE_SIMD_REAL(_iter) \
104 for( ::Arcane::Integer _iter(0); _iter < SimdReal ::BLOCK_SIZE; ++ _iter )
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
109ARCANE_BEGIN_NAMESPACE
110
111/*---------------------------------------------------------------------------*/
112/*---------------------------------------------------------------------------*/
113/*
114 * Définit le type SimdInfo en fonction de la vectorisation disponible.
115 * On prend le type qui permet le plus de vectorisation.
116 */
117#if defined(ARCANE_HAS_AVX512)
118typedef AVX512SimdInfo SimdInfo;
119#elif defined(ARCANE_HAS_AVX)
120typedef AVXSimdInfo SimdInfo;
121#elif defined(ARCANE_HAS_SSE)
122typedef SSESimdInfo SimdInfo;
123#else
124typedef EMULSimdInfo SimdInfo;
125#endif
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
129
130/*!
131 * \ingroup ArcaneSimd
132 * \brief Vecteur SIMD de réel.
133 */
135const int SimdSize = SimdReal::Length;
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140/*---------------------------------------------------------------------------*/
141/*---------------------------------------------------------------------------*/
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
145/*!
146 * \ingroup ArcaneSimd
147 * \brief Représente un Real3 vectoriel.
148 */
149class ARCANE_UTILS_EXPORT SimdReal3
150{
151 public:
153 public:
154 SimdReal x;
155 SimdReal y;
156 SimdReal z;
157 SimdReal3() {}
158 SimdReal3(SimdReal _x,SimdReal _y,SimdReal _z) : x(_x), y(_y), z(_z){}
159 SimdReal3(const Real3* base,const Int32IndexType& idx)
160 {
161 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
162 Real3 v = base[idx[i]];
163 this->set(i,v);
164 }
165 }
166 const Real3 operator[](Integer i) const { return Real3(x[i],y[i],z[i]); }
167
168 void set(Real3* base,const Int32IndexType& idx) const
169 {
170 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
171 base[idx[i]] = this->get(i);
172 }
173 }
174
175 // TODO: renommer cette méthode
176 void set(Integer i,Real3 r)
177 {
178 x[i] = r.x;
179 y[i] = r.y;
180 z[i] = r.z;
181 }
182 Real3 get(Integer i) const
183 {
184 return Real3(x[i],y[i],z[i]);
185 }
186};
187
188/*---------------------------------------------------------------------------*/
189/*---------------------------------------------------------------------------*/
190/*!
191 * \ingroup ArcaneSimd
192 * \brief Représente un Real2 vectoriel.
193 */
194class ARCANE_UTILS_EXPORT SimdReal2
195{
196 public:
198 public:
199 SimdReal x;
200 SimdReal y;
201 SimdReal2() {}
202 SimdReal2(SimdReal _x,SimdReal _y) : x(_x), y(_y){}
203 SimdReal2(const Real2* base,const Int32IndexType& idx)
204 {
205 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
206 Real2 v = base[idx[i]];
207 this->set(i,v);
208 }
209 }
210 const Real2 operator[](Integer i) const { return Real2(x[i],y[i]); }
211
212 void set(Real2* base,const Int32IndexType& idx) const
213 {
214 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
215 base[idx[i]] = this->get(i);
216 }
217 }
218
219 void set(Integer i,Real2 r)
220 {
221 x[i] = r.x;
222 y[i] = r.y;
223 }
224 Real2 get(Integer i) const
225 {
226 return Real2(x[i],y[i]);
227 }
228};
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232/*!
233 * \ingroup ArcaneSimd
234 * \brief Représente un Real3x3 vectoriel.
235 */
236class ARCANE_UTILS_EXPORT SimdReal3x3
237{
238 public:
240 public:
241 SimdReal3 x;
242 SimdReal3 y;
243 SimdReal3 z;
244 SimdReal3x3() {}
245 SimdReal3x3(SimdReal3 _x,SimdReal3 _y,SimdReal3 _z) : x(_x), y(_y), z(_z){}
246 SimdReal3x3(const Real3x3* base,const Int32IndexType& idx)
247 {
248 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
249 Real3x3 v = base[idx[i]];
250 this->set(i,v);
251 }
252 }
253 const Real3x3 operator[](Integer i) const { return Real3x3(x[i],y[i],z[i]); }
254
255 void set(Real3x3* base,const Int32IndexType& idx) const
256 {
257 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
258 base[idx[i]] = this->get(i);
259 }
260 }
261
262 // TODO: renommer cette méthode
263 void set(Integer i,Real3x3 r)
264 {
265 x.set(i,r.x);
266 y.set(i,r.y);
267 z.set(i,r.z);
268 }
269 Real3x3 get(Integer i) const
270 {
271 return Real3x3(x[i],y[i],z[i]);
272 }
273};
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277/*!
278 * \ingroup ArcaneSimd
279 * \brief Représente un Real2x2 vectoriel.
280 */
281class ARCANE_UTILS_EXPORT SimdReal2x2
282{
283 public:
285 public:
286 SimdReal2 x;
287 SimdReal2 y;
288 SimdReal2x2() {}
289 SimdReal2x2(SimdReal2 _x,SimdReal2 _y) : x(_x), y(_y){}
290 SimdReal2x2(const Real2x2* base,const Int32IndexType& idx)
291 {
292 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
293 Real2x2 v = base[idx[i]];
294 this->set(i,v);
295 }
296 }
297 const Real2x2 operator[](Integer i) const { return Real2x2(x[i],y[i]); }
298
299 void set(Real2x2* base,const Int32IndexType& idx) const
300 {
301 for( Integer i=0, n=SimdReal::BLOCK_SIZE; i<n; ++i ){
302 base[idx[i]] = this->get(i);
303 }
304 }
305
306 // TODO: renommer cette méthode
307 void set(Integer i,Real2x2 r)
308 {
309 x.set(i,r.x);
310 y.set(i,r.y);
311 }
312 Real2x2 get(Integer i) const
313 {
314 return Real2x2(x[i],y[i]);
315 }
316};
317
318/*---------------------------------------------------------------------------*/
319/*---------------------------------------------------------------------------*/
320/*!
321 * \ingroup ArcaneSimd
322 * \brief Charactéristiques des types vectoriels.
323 *
324 * Instantiation par défaut pour les types n'ayant pas de type vectoriel
325 * correspondant. Actuellement, seuls les types 'Real', 'Real2' et 'Real3'
326 * en ont un.
327 */
328template<typename DataType>
330{
331 public:
332 typedef void SimdType;
333};
334
335template<>
336class SimdTypeTraits<Real>
337{
338 public:
339 typedef SimdReal SimdType;
340};
341
342template<>
344{
345 public:
346 typedef SimdReal2 SimdType;
347};
348
349template<>
351{
352 public:
353 typedef SimdReal2x2 SimdType;
354};
355
356template<>
358{
359 public:
360 typedef SimdReal3 SimdType;
361};
362
363template<>
365{
366 public:
367 typedef SimdReal3x3 SimdType;
368};
369
370/*---------------------------------------------------------------------------*/
371/*---------------------------------------------------------------------------*/
372/*!
373 * \ingroup ArcaneSimd
374 * \brief Classe de base des énumérateurs vectoriels avec indirection.
375 *
376 * \warning Les tableaux des indices locaux (\a local_ids) passés aux
377 * constructeurs doivent être alignés.
378 */
379class ARCANE_UTILS_EXPORT SimdEnumeratorBase
380{
381 public:
382
384
385 public:
386
388 : m_local_ids(nullptr), m_index(0), m_count(0) { }
389 SimdEnumeratorBase(const Int32* local_ids,Integer n)
390 : m_local_ids(local_ids), m_index(0), m_count(n)
391 { _checkValid(); }
392 explicit SimdEnumeratorBase(Int32ConstArrayView local_ids)
393 : m_local_ids(local_ids.data()), m_index(0), m_count(local_ids.size())
394 { _checkValid(); }
395
396 public:
397
398 bool hasNext() { return m_index<m_count; }
399
400 //! Indices locaux
401 const Int32* unguardedLocalIds() const { return m_local_ids; }
402
403 void operator++() { m_index += SimdSize; }
404
405 /*!
406 * \brief Nombre de valeurs valides pour l'itérateur courant.
407 * \pre hasNext()==true
408 */
409 inline Integer nbValid() const
410 {
411 Integer nb_valid = (m_count-m_index);
412 if (nb_valid>SimdSize)
413 nb_valid = SimdSize;
414 return nb_valid;
415 }
416
417 Integer count() const { return m_count; }
418
419 protected:
420
421 const Int32* ARCANE_RESTRICT m_local_ids;
422 Integer m_index;
423 Integer m_count;
424
425 const SimdIndexType* ARCANE_RESTRICT
426 _currentSimdIndex() const
427 {
428 return (const SimdIndexType*)(m_local_ids+m_index);
429 }
430
431 private:
432
433 // Vérifie que m_local_ids est correctement aligné.
434 void _checkValid()
435 {
436#ifdef ARCANE_SIMD_BENCH
437 Int64 modulo = (Int64)(m_local_ids) % SimdIndexType::Alignment;
438 if (modulo!=0){
439 throw BadAlignmentException();
440 }
441#else
442 _checkValidHelper();
443#endif
444 }
445 void _checkValidHelper();
446};
447
448/*---------------------------------------------------------------------------*/
449/*---------------------------------------------------------------------------*/
450
451ARCANE_END_NAMESPACE
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456#endif
Vectorisation des réels par émulation.
Definition SimdEMUL.h:155
Vectorisation des entiers en utilisant une émulation.
Definition SimdEMUL.h:35
Classe gérant un vecteur de réel de dimension 2.
Definition Real2.h:121
Classe gérant une matrice de réel de dimension 2x2.
Definition Real2x2.h:53
Real2 x
Première composante.
Definition Real2x2.h:98
Real2 y
Deuxième composante.
Definition Real2x2.h:99
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Classe gérant une matrice de réel de dimension 3x3.
Definition Real3x3.h:66
Real3 z
premier élément du triplet
Definition Real3x3.h:119
Real3 y
premier élément du triplet
Definition Real3x3.h:118
Real3 x
premier élément du triplet
Definition Real3x3.h:117
Classe de base des énumérateurs vectoriels avec indirection.
Definition Simd.h:380
const Int32 * unguardedLocalIds() const
Indices locaux.
Definition Simd.h:401
Integer nbValid() const
Nombre de valeurs valides pour l'itérateur courant.
Definition Simd.h:409
Représente un Real2 vectoriel.
Definition Simd.h:195
Représente un Real2x2 vectoriel.
Definition Simd.h:282
Représente un Real3 vectoriel.
Definition Simd.h:150
Représente un Real3x3 vectoriel.
Definition Simd.h:237
Charactéristiques des types vectoriels.
Definition Simd.h:330
Vue constante d'un tableau de type T.
Real y
deuxième composante du couple
Definition Real2.h:35
Real x
première composante du couple
Definition Real2.h:34
Real y
deuxième composante du triplet
Definition Real3.h:36
Real z
troisième composante du triplet
Definition Real3.h:37
Real x
première composante du triplet
Definition Real3.h:35