Extensão SIMD

Atualmente, o Visual C++ dá suporte ao padrão OpenMP 2.0, no entanto, o Visual Studio 2019 também agora oferece funcionalidade SIMD.

Observação

Para usar o SIMD, compile com a opção -openmp:experimental que permite recursos adicionais do OpenMP não disponíveis ao usar a opção -openmp.

A opção -openmp:experimental abrange -openmp, o que significa que todos os recursos do OpenMP 2.0 estão incluídos em seu uso.

Para obter mais informações, consulte a Extensão SIMD para C++ OpenMP no Visual Studio.

OpenMP SIMD em Visual C++

O OpenMP SIMD, introduzido no padrão OpenMP 4.0, tem como destino fazer loops compatíveis com o vetor. Ao usar a diretiva simd antes de um loop, o compilador pode ignorar dependências de vetor, tornar o loop o mais compatível possível com vetores e respeitar a intenção dos usuários de ter várias iterações de loop executadas simultaneamente.

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

O Visual C++ fornece pragmas de loop não OpenMP semelhantes como #pragma vector e #pragma ivdep, no entanto, com o OpenMP SIMD, o compilador pode fazer mais, como:

  • Sempre é permitido ignorar as dependências de vetores presentes.
  • /fp:fast está habilitado dentro do loop.
  • Loops externos e loops com chamadas de função são compatíveis com o vetor.
  • Loops aninhados podem ser mesclados em um único loop e otimizados para processamento vetorial.
  • Aceleração híbrida com #pragma omp for simd para habilitar multi-threading de granularidade grosseira e vetores de granularidade fina.

Para loops compatíveis com o vetor, o compilador permanece em silêncio, a menos que você use uma opção de log de suporte a vetores:

    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

Para loops não compatíveis com vetores, o compilador emite uma mensagem para cada uma:

    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'

Cláusulas

A diretiva OPENMP SIMD também pode usar as seguintes cláusulas para aprimorar o suporte a vetores:

Diretiva Descrição
simdlen(length) Especifique o número de canais de vetor.
safelen(length) Especifique a distância de dependência do vetor.
linear(list[ : linear-step]) O mapeamento linear da variável de indução de loop para a assinatura de matriz.
aligned(list[ : alignment]) O alinhamento de dados.
private(list) Especifique a privatização de dados.
lastprivate(list) Especifique a privatização de dados com o valor final da última iteração.
reduction(reduction-identifier:list) Especifique operações de redução personalizadas.
collapse(n) Aninhamento de loop de aglutinação.

Observação

Cláusulas SIMD não eficazes são analisadas e ignoradas pelo compilador com um aviso.

Por exemplo, o uso do código a seguir emite um aviso:

   #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

Exemplo

A diretiva OpenMP SIMD fornece aos usuários uma maneira de ditar que o compilador torne os loops compatíveis com o vetor. Ao anotar um loop com a diretiva OpenMP SIMD, os usuários pretendem ter várias iterações de loop executadas simultaneamente.

Por exemplo, o loop a seguir é anotado com a diretiva OpenMP SIMD. Não há paralelismo perfeito entre iterações de loop, pois há uma dependência anterior de a[i] para um[i-1], mas devido à diretiva SIMD, o compilador ainda tem permissão para empacotar iterações consecutivas da primeira instrução em uma instrução de vetor e executá-las em paralelo.

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

Portanto, a seguinte forma de vetor transformado do loop é legal porque o compilador mantém o comportamento sequencial de cada iteração de loop original. Em outras palavras, a[i] é executado após a[-1], b[i] é depois de a[i] e a chamada para bar acontece por último.

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

Não é legal mover a referência de memória *c para fora do loop se ela puder fazer alias com a[i] ou b[i]. Também não será legal reordenar as instruções dentro de uma iteração original se ela quebrar a dependência sequencial. Por exemplo, o loop transformado a seguir não é legal:

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

Confira também

/openmp (habilitar suporte para OpenMP 2.0)