Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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:fastestá 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 simdpara 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);
}