Partager via


Extension SIMD

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 -openmpde 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);
    }

Voir aussi

/openmp (Activer la prise en charge OpenMP 2.0)