Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Visual C++ prend actuellement en charge la norme OpenMP 2.0, mais Visual Studio 2019 offre désormais également des fonctionnalités SIMD.
Remarque
Pour utiliser SIMD, compilez avec le -openmp:experimental
commutateur qui active des fonctionnalités OpenMP supplémentaires non disponibles lors de l’utilisation du -openmp
commutateur.
Les -openmp:experimental
sous-ensembles -openmp
de commutateurs, ce qui signifie que toutes les fonctionnalités OpenMP 2.0 sont incluses dans son utilisation.
Pour plus d’informations, consultez l’extension SIMD vers C++ OpenMP dans Visual Studio.
OpenMP SIMD dans Visual C++
OpenMP SIMD, introduit dans la norme OpenMP 4.0, cible la création de boucles vectorielles. En utilisant la simd
directive avant une boucle, le compilateur peut ignorer les dépendances vectorielles, rendre la boucle aussi conviviale que possible et respecter l’intention des utilisateurs d’avoir plusieurs itérations de boucle exécutées simultanément.
#pragma omp simd
for (i = 0; i < count; i++)
{
a[i] = a[i-1] + 1;
b[i] = *c + 1;
bar(i);
}
Visual C++ fournit des pragmas de boucle non OpenMP similaires comme #pragma vector
et #pragma ivdep
, toutefois, avec OpenMP SIMD, le compilateur peut faire plus, comme :
- Toujours autorisé à ignorer les dépendances vectorielles actuelles.
-
/fp:fast
est activé dans la boucle. - Les boucles externes et les boucles avec des appels de fonction sont compatibles avec les vecteurs.
- Les boucles imbriquées peuvent être fusionnées en une seule boucle et rendues vectorielles.
- Accélération hybride avec
#pragma omp for simd
pour permettre des vecteurs à plusieurs threads grossiers et affinés.
Pour les boucles vectorielles, le compilateur reste silencieux, sauf si vous utilisez un commutateur de journal de prise en charge vectorielle :
cl -O2 -openmp:experimental -Qvec-report:2 mycode.cpp
mycode.cpp(84) : info C5002: Omp simd loop not vectorized due to reason '1200'
mycode.cpp(90) : info C5002: Omp simd loop not vectorized due to reason '1200'
mycode.cpp(96) : info C5001: Omp simd loop vectorized
Pour les boucles non vectorielles, le compilateur émet chacun un message :
cl -O2 -openmp:experimental mycode.cpp
mycode.cpp(84) : info C5002: Omp simd loop not vectorized due to reason '1200'
mycode.cpp(90) : info C5002: Omp simd loop not vectorized due to reason '1200'
Clauses
La directive SIMD OpenMP peut également prendre les clauses suivantes pour améliorer la prise en charge vectorielle :
Instructions | Descriptif |
---|---|
simdlen(length) |
Spécifiez le nombre de voies vectorielles. |
safelen(length) |
Spécifiez la distance de dépendance vectorielle. |
linear(list[ : linear-step] ) |
Mappage linéaire d’une variable d’induction de boucle à un abonnement de tableau. |
aligned(list[ : alignment]) |
Alignement des données. |
private(list) |
Spécifiez la privatisation des données. |
lastprivate(list) |
Spécifiez la privatisation des données avec la valeur finale de la dernière itération. |
reduction(reduction-identifier:list) |
Spécifiez les opérations de réduction personnalisées. |
collapse(n) |
Imbrication de boucle de fusion. |
Remarque
Les clauses SIMD non effectives sont analysées et ignorées par le compilateur avec un avertissement.
Par exemple, l’utilisation du code suivant émet un avertissement :
#pragma omp simd simdlen(8)
for (i = 0; i < count; i++)
{
a[i] = a[i-1] + 1;
b[i] = *c + 1;
bar(i);
}
warning C4849: OpenMP 'simdlen' clause ignored in 'simd' directive
Exemple
La directive SIMD OpenMP permet aux utilisateurs de dicter le compilateur de rendre les boucles compatibles avec les vecteurs. En annoteant une boucle avec la directive SIMD OpenMP, les utilisateurs ont l’intention d’exécuter simultanément plusieurs itérations de boucle.
Par exemple, la boucle suivante est annotée avec la directive SIMD OpenMP. Il n’y a pas de parallélisme parfait entre les itérations de boucles, car il existe une dépendance descendante d’a[i] à a[i-1], mais en raison de la directive SIMD, le compilateur est toujours autorisé à empaquetér des itérations consécutives de la première instruction dans une instruction vectorielle et à les exécuter en parallèle.
#pragma omp simd
for (i = 0; i < count; i++)
{
a[i] = a[i-1] + 1;
b[i] = *c + 1;
bar(i);
}
Par conséquent, la forme de vecteur transformée suivante de la boucle est légale , car le compilateur conserve le comportement séquentiel de chaque itération de boucle d’origine. En d’autres termes, a[i]
est exécuté après a[-1]
, b[i]
est après a[i]
et l’appel à bar
se produire en dernier.
for (i = 0; i < count; i+=4)
{
a[i:i+3] = a[i-1:i+2] + 1;
b[i:i+3] = *c + 1;
bar(i);
bar(i+1);
bar(i+2);
bar(i+3);
}
Il n’est pas légal de déplacer la référence *c
mémoire hors de la boucle si elle peut alias avec a[i]
ou b[i]
. Il n’est pas non plus légal de réorganiser les instructions à l’intérieur d’une itération d’origine si elle interrompt la dépendance séquentielle. Par exemple, la boucle transformée suivante n’est pas légale :
c = b;
t = *c;
for (i = 0; i < count; i+=4)
{
a[i:i+3] = a[i-1:i+2] + 1;
bar(i); // illegal to reorder if bar[i] depends on b[i]
b[i:i+3] = t + 1; // illegal to move *c out of the loop
bar(i+1);
bar(i+2);
bar(i+3);
}