SIMD-Erweiterung

Visual C++ unterstützt derzeit den OpenMP 2.0-Standard, aber Visual Studio 2019 bietet jetzt auch SIMD-Funktionen.

Hinweis

Um SIMD zu verwenden, kompilieren Sie mit dem Switch, der -openmp:experimental zusätzliche OpenMP-Features aktiviert, die bei Verwendung des Schalters -openmp nicht verfügbar sind.

Der -openmp:experimental Switch zählt -openmpauf, was bedeutet, dass alle OpenMP 2.0-Features in seiner Verwendung enthalten sind.

Weitere Informationen finden Sie unter SIMD-Erweiterung für C++ OpenMP in Visual Studio.

OpenMP SIMD in Visual C++

OpenMP SIMD, eingeführt im OpenMP 4.0-Standard, zielt darauf ab, vektorfreundliche Schleifen zu erstellen. Mithilfe der simd -Direktive vor einer Schleife kann der Compiler Vektorabhängigkeiten ignorieren, die Schleife so vektorfreundlicher wie möglich gestalten und die Absicht der Benutzer berücksichtigen, mehrere Schleifeniterationen gleichzeitig auszuführen.

    #pragma omp simd
    for (i = 0; i < count; i++)
    {
        a[i] = a[i-1] + 1;
        b[i] = *c + 1;
        bar(i);
    }

Visual C++ stellt ähnliche Nicht-OpenMP-Schleifen-Pragmas wie #pragma vector und #pragma ivdepbereit. Mit OpenMP SIMD kann der Compiler jedoch mehr erreichen, z. B.:

  • Es ist immer zulässig, aktuelle Vektorabhängigkeiten zu ignorieren.
  • /fp:fast ist innerhalb der Schleife aktiviert.
  • Äußere Schleifen und Schleifen mit Funktionsaufrufen sind vektorfreundlicher.
  • Geschachtelte Schleifen können in einer Schleife zusammengeknüpft und vektorfreundlicher gestaltet werden.
  • Hybridbeschleunigung mit #pragma omp for simd , um ein differenziertes Multithreading und differenzierte Vektoren zu ermöglichen.

Bei vektorfreundlichen Schleifen bleibt der Compiler im Hintergrund, es sei denn, Sie verwenden einen Vektorunterstützungsprotokollschalter:

    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

Für nicht vektorfreundliche Schleifen gibt der Compiler jede Nachricht aus:

    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'

Klauseln

Die OpenMP SIMD-Direktive kann auch die folgenden Klauseln verwenden, um die Vektorunterstützung zu verbessern:

Anweisung Beschreibung
simdlen(length) Geben Sie die Anzahl der Vektorspuren an.
safelen(length) Geben Sie den Vektorabhängigkeitsabstand an.
linear(list[ : linear-step]) Die lineare Zuordnung von der Schleifeninproduktionsvariable zum Arrayabonnement.
aligned(list[ : alignment]) Die Ausrichtung der Daten.
private(list) Geben Sie die Datenprinalisierung an.
lastprivate(list) Geben Sie die Datenprinalisierung mit dem endgültigen Wert aus der letzten Iteration an.
reduction(reduction-identifier:list) Geben Sie benutzerdefinierte Reduzierungsvorgänge an.
collapse(n) Schachtelung der Zusammenfühschleife.

Hinweis

Nicht effektive SIMD-Klauseln werden vom Compiler mit einer Warnung analysiert und ignoriert.

Die Verwendung des folgenden Codes gibt beispielsweise eine Warnung aus:

   #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

Beispiel

Die OpenMP SIMD-Direktive bietet Benutzern eine Möglichkeit, den Compiler zu diktieren, um Schleifen vektorfreundlicher zu gestalten. Durch das Kommentieren einer Schleife mit der OpenMP SIMD-Direktive möchten Benutzer mehrere Schleifeniterationen gleichzeitig ausführen lassen.

Beispielsweise wird die folgende Schleife mit der OpenMP SIMD-Direktive kommentiert. Es gibt keine perfekte Parallelität zwischen Schleifeniterationen, da es eine Abwärtsabhängigkeit von a[i] zu a[i-1] gibt. Aufgrund der SIMD-Direktive kann der Compiler jedoch weiterhin aufeinander folgende Iterationen der ersten Anweisung in eine Vektoranweisung packen und parallel ausführen.

    #pragma omp simd
    for (i = 0; i < count; i++)
    {
        a[i] = a[i-1] + 1;
        b[i] = *c + 1;
        bar(i);
    }

Daher ist die folgende transformierte Vektorform der Schleife zulässig , da der Compiler das sequenzielle Verhalten jeder ursprünglichen Schleifeniteration beihält. Das heißt, wird nach ausgeführt, a[i] ist nach a[i] , b[i] und der Aufruf von bar erfolgt a[-1]zuletzt.

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

Es ist nicht zulässig , den Speicherverweis *c aus der Schleife zu verschieben, wenn er mit a[i] oder b[i]alias verwendet werden kann. Es ist auch nicht zulässig, die Anweisungen innerhalb einer ursprünglichen Iteration neu anzuordnen, wenn sie die sequenzielle Abhängigkeit unterbricht. Die folgende transformierte Schleife ist beispielsweise nicht zulässig:

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

Siehe auch

/openmp (OpenMP 2.0-Unterstützung aktivieren)