Rozszerzenie SIMD

Program Visual C++ obecnie obsługuje standard OpenMP 2.0, jednak program Visual Studio 2019 oferuje teraz również funkcje SIMD.

Uwaga

Aby użyć SIMD, skompiluj z użyciem przełącznika -openmp:experimental, który umożliwia dodatkowe funkcje OpenMP niedostępne podczas korzystania z przełącznika -openmp.

Przełącznik -openmp:experimental obejmuje -openmp, co oznacza, że wszystkie funkcje standardu OpenMP 2.0 są uwzględniane w jego użyciu.

Aby uzyskać więcej informacji, zobacz Rozszerzenie SIMD do C++ OpenMP w programie Visual Studio.

OpenMP SIMD w Visual C++

OpenMP SIMD, wprowadzony w standardzie OpenMP 4.0, ma na celu uczynienie pętli wektorowo przyjaznymi. Korzystając z simd dyrektywy przed pętlą, kompilator może ignorować zależności wektorowe, uczynić pętlę tak przyjazną dla wektorów, jak to możliwe i przestrzegać intencji użytkowników, aby wykonać jednocześnie wiele iteracji pętli.

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

Język Visual C++ udostępnia podobne pragmay pętli inne niż OpenMP, takie jak #pragma vector i #pragma ivdep, jednak w przypadku protokołu OPENMP SIMD kompilator może wykonywać więcej czynności, takich jak:

  • Zawsze zezwalaj na ignorowanie obecnych zależności wektorów.
  • /fp:fast jest aktywowane w ramach pętli.
  • Pętle zewnętrzne i pętle z wywołaniami funkcji są przyjazne dla wektorów.
  • Zagnieżdżone pętle można połączyć w jedną pętlę i dostosować do przetwarzania wektorowego.
  • Przyspieszanie hybrydowe z #pragma omp for simd w celu umożliwienia gruboziarnistego wielowątkowości i drobnoziarnistych wektorów.

W przypadku pętli przyjaznych dla wektorów kompilator pozostaje cichy, chyba że używasz przełącznika dziennika obsługującego wektory:

    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

W przypadku pętli nieprzyjaznych dla wektorów, kompilator wydaje komunikat:

    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'

Klauzule

Dyrektywa OPENMP SIMD może również przyjąć następujące klauzule, aby zwiększyć obsługę wektorów:

Dyrektywa opis
simdlen(length) Określ liczbę pasów wektorowych.
safelen(length) Określ odległość zależności wektora.
linear(list[ : linear-step]) Mapowanie liniowe ze zmiennej indukcyjnej pętli do subskrypcji tablicy.
aligned(list[ : alignment]) Wyrównanie danych.
private(list) Określ prywatyzację danych.
lastprivate(list) Określ prywatyzację danych z ostateczną wartością z ostatniej iteracji.
reduction(reduction-identifier:list) Określ dostosowane operacje redukcji.
collapse(n) Zagnieżdżanie pętli coalescencji.

Uwaga

Niedozwolone klauzule SIMD są analizowane i ignorowane przez kompilator z ostrzeżeniem.

Na przykład użycie następującego kodu generuje ostrzeżenie:

   #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

Przykład

Dyrektywa SIMD OpenMP zapewnia użytkownikom sposób na nakłonienie kompilatora do optymalizacji pętli pod kątem przetwarzania wektorowego. Oznaczając pętlę dyrektywą OpenMP SIMD, użytkownicy zamierzają wykonać jednocześnie wiele iteracji pętli.

Na przykład następująca pętla jest oznaczona adnotacją dyrektywy OpenMP SIMD. Nie ma doskonałej równoległości między iteracjami pętli, ponieważ istnieje zależność wsteczna od a[i] do a[i-1], ale ze względu na dyrektywę SIMD kompilator nadal może pakować kolejne iteracje pierwszej instrukcji w jedną instrukcję wektorową i uruchamiać je równolegle.

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

W związku z tym następująca przekształcona forma wektorowa pętli jest legalna , ponieważ kompilator zachowuje sekwencyjne zachowanie każdej iteracji pętli oryginalnej. Innymi słowy, a[i] jest wykonywany po a[-1], b[i] wykonuje się po a[i], a wywołanie bar ma miejsce na końcu.

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

Nie jest nielegalne przeniesienie odwołania *c z pętli, jeśli może ono aliasować z a[i] lub b[i]. Nie jest również dozwolone zmieniać kolejności instrukcji wewnątrz jednej pierwotnej iteracji, jeśli powoduje przerwanie zależności sekwencyjnej. Na przykład następująca pętla przekształcona nie jest legalna:

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

Zobacz też

/openmp (Włącz obsługę OpenMP 2.0)