Существует недостаток в векторе-векторе GCC, который, как представляется, был устранен в последних версиях GCC. В моем тестовом случае GCC 4.7.2 vectorises успешно следующего простого цикла:
В то же время GCC 4.6.1 не делает и он жалуется, что цикл содержит вызовы функций или ссылки на данные, которые не могут быть проанализированы. Ошибка в векторизаторе запускается путем parallel for
циклов, реализуемых GCC.Когда OpenMP конструкции обрабатываются и расширены, простой код цикла превращается в нечто похожее на это:
struct omp_fn_0_s
{
int N;
double *a;
double *b;
double *c;
double d;
};
void omp_fn_0(struct omp_fn_0_s *data)
{
int start, end;
int nthreads = omp_get_num_threads();
int threadid = omp_get_thread_num();
// This is just to illustrate the case - GCC uses a bit different formulas
start = (data->N * threadid)/nthreads;
end = (data->N * (threadid+1))/nthreads;
for (int i = start; i < end; i++)
data->a[i] = data->b[i] + data->c[i] * data->d;
}
...
struct omp_fn_0_s omp_data_o;
omp_data_o.N = N;
omp_data_o.a = a;
omp_data_o.b = b;
omp_data_o.c = c;
omp_data_o.d = d;
GOMP_parallel_start(omp_fn_0, &omp_data_o, 0);
omp_fn_0(&omp_data_o);
GOMP_parallel_end();
N = omp_data_o.N;
a = omp_data_o.a;
b = omp_data_o.b;
c = omp_data_o.c;
d = omp_data_o.d;
в НКУ векторных операций, прежде чем 4.7 не удается vectorise, что цикл. Это НЕ проблема с OpenMP. Его можно легко воспроизвести без кода OpenMP. Для подтверждения этого я написал следующий простой тест:
struct fun_s
{
double *restrict a;
double *restrict b;
double *restrict c;
double d;
int n;
};
void fun1(double *restrict a,
double *restrict b,
double *restrict c,
double d,
int n)
{
int i;
for (i = 0; i < n; i++)
a[i] = b[i] + c[i] * d;
}
void fun2(struct fun_s *par)
{
int i;
for (i = 0; i < par->n; i++)
par->a[i] = par->b[i] + par->c[i] * par->d;
}
Можно было бы ожидать, что оба кода (уведомление - не OpenMP здесь!) Должны vectorise одинаково хорошо из-за restrict
ключевых слов, используемых для указания того, что нет сглаживания не может произойти. К сожалению, это не относится к GCC < 4.7 - он успешно векторизовывает цикл в fun1
, но не позволяет его прорисовать в fun2
, ссылаясь на ту же причину, что и при компиляции кода OpenMP.
Причина этого заключается в том, что не может векторные операции, чтобы доказать, что par->d
не лежит в пределах памяти, par->a
, par->b
и par->c
пункта. Это не всегда так с fun1
, где возможны два случая:
d
передается в качестве аргумента значение в регистре;
d
передается как аргумент значения в стеке.
В системах x64 система V ABI предусматривает передачу первых нескольких аргументов с плавающей запятой в регистры XMM (YMM на процессорах с поддержкой AVX). Вот как передается d
в этом случае, и, следовательно, ни один указатель не может указывать на него - цикл становится векторизованным. В системах x86 ABI указывает, что аргументы передаются в стек, поэтому d
может быть сглажен любым из трех указателей. Действительно, GCC отказывается векторизовать цикл в fun1
, если ему поручено генерировать 32-разрядный код x86 с опцией -m32
.
GCC 4.7 оборачивается этим, вставляя проверки во время выполнения, которые гарантируют, что ни d
, ни par->d
не получат псевдонимы.
Избавление от d
удаляет недоказуемое не-ступенчатость и следующий код OpenMP получает vectorised от GCC 4.6.1:
#pragma omp parallel for schedule(static)
for (int i = 0; i < N; i++)
a[i] = b[i] + c[i];
Я думаю, что вы можете найти разумную информацию в [ответе] (http://stackoverflow.com/a/14717689/771663) на этот вопрос. – Massimiliano
Спасибо, что описывает, как использовать SIMD с OpenMP, но, похоже, не объясняет, почему уже работающая реализация SIMD перестает работать, когда я использую OpenMP. Разве нет возможности использовать их? – superbriggs
Это также означает, что я могу работать только на одном и том же количестве бит, они просто разделяются между числами. Выполняя это с GCC, меня не спрашивали, сколько я хотел разделить на регистр. Поскольку я использую университетский суперкомпьютер, я предположил, что аппаратные га лишние пространства для SIMD. Как я узнаю, что это правильно? – superbriggs