Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Visual C++ в настоящее время поддерживает стандарт OpenMP 2.0, однако Visual Studio 2019 также предлагает функциональные возможности SIMD.
Примечание.
Чтобы использовать SIMD, скомпилируйте с помощью коммутатора -openmp:experimental
, который включает дополнительные функции OpenMP, недоступные при использовании коммутатора -openmp
.
Вложенные -openmp:experimental
элементы коммутатора -openmp
, что означает, что все функции OpenMP 2.0 включены в его использование.
Дополнительные сведения см. в разделе "Расширение SIMD для C++ OpenMP" в Visual Studio.
OpenMP SIMD в Visual C++
OpenMP SIMD, представленный в стандарте OpenMP 4.0, предназначен для создания векторных циклов. Используя simd
директиву перед циклом, компилятор может игнорировать векторные зависимости, сделать цикл понятным для вектора как можно больше, и уважать намерение пользователей выполнять несколько итераций цикла одновременно.
#pragma omp simd
for (i = 0; i < count; i++)
{
a[i] = a[i-1] + 1;
b[i] = *c + 1;
bar(i);
}
Visual C++ предоставляет аналогичные прагмы цикла, отличные от OpenMP, как #pragma vector
и #pragma ivdep
при использовании OpenMP SIMD, компилятор может сделать больше, например:
- Всегда разрешено игнорировать векторные зависимости.
-
/fp:fast
включен в цикле. - Внешние циклы и циклы с вызовами функций являются векторными.
- Вложенные циклы можно объединить в один цикл и сделать векторным.
- Гибридное ускорение с
#pragma omp for simd
включением грубого многопотокового и тонкого векторов.
Для циклов, понятных для векторов, компилятор остается безмолвным, если вы не используете переключатель журнала поддержки векторов:
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
Для невекторных циклов компилятор выдает каждое сообщение:
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'
Предложения
Директива OpenMP SIMD также может принимать следующие предложения для повышения поддержки векторов:
Директива | Описание |
---|---|
simdlen(length) |
Укажите количество векторных полос. |
safelen(length) |
Укажите расстояние зависимости вектора. |
linear(list[ : linear-step] ( |
Линейное сопоставление от индукционной переменной цикла к подписке массива. |
aligned(list[ : alignment]) |
Выравнивание данных. |
private(list) |
Укажите приватизацию данных. |
lastprivate(list) |
Укажите приватизацию данных с окончательным значением из последней итерации. |
reduction(reduction-identifier:list) |
Укажите настраиваемые операции сокращения. |
collapse(n) |
Объединение гнезда цикла. |
Примечание.
Неэффективные предложения SIMD анализируются и игнорируются компилятором с предупреждением.
Например, при использовании следующего кода возникает предупреждение:
#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
Пример
Директива OpenMP SIMD предоставляет пользователям способ диктовать компилятору векторные циклы. Заметив цикл с помощью директивы OpenMP SIMD, пользователи намерены одновременно выполнять несколько итераций цикла.
Например, следующий цикл аннотирован с помощью директивы OpenMP SIMD. Нет идеального параллелизма между итерациями цикла, так как существует обратная зависимость от a[i] до [i-1], но из-за директивы SIMD компилятор по-прежнему разрешен упаковывать последовательные итерации первой инструкции в одну векторную инструкцию и выполнять их параллельно.
#pragma omp simd
for (i = 0; i < count; i++)
{
a[i] = a[i-1] + 1;
b[i] = *c + 1;
bar(i);
}
Поэтому следующая преобразованная форма вектора цикла является законной , так как компилятор сохраняет последовательное поведение каждой исходной итерации цикла. Иными словами, a[i]
выполняется после a[-1]
b[i]
a[i]
, после и вызов, который будет происходить bar
последним.
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);
}
Это не является законным для перемещения ссылки на *c
память из цикла, если он может быть псевдонимом или a[i]
b[i]
. Это также не является законным для переупорядочения инструкций внутри одной исходной итерации, если она нарушает последовательную зависимость. Например, следующий преобразованный цикл не является законным:
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);
}