Как преодолеть "существование векторной зависимости" в icc

Я хочу векторизовать следующий цикл в C:

for(k = 0; k < SysData->numOfClaGen; k++)
            A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);

где нет псевдонима между переменными и ind0 постоянная Ни один из других указателей (A или же B) указать на ind0 и, следовательно, ind0 остается постоянным на протяжении всего цикла.

Когда я компилирую код с помощью icc, он говорит, что этот цикл не может быть векторизован из-за возможной векторной зависимости. Вот сообщение:

loop was not vectorized: existence of vector dependence.

Я сузил проблему и обнаружил, что замена ind0 на постоянное число решает проблему. Итак, я предполагаю, что ICC думает A может указывать на ind0 и поэтому, ind0 может поменяться.

Я хотел бы знать, как я могу помочь компилятору узнать, что безопасно векторизовать такой цикл.

Заранее спасибо за помощь.

3 ответа

Решение

Добавлять #pragma ivdep перед циклом for он указывает компилятору игнорировать предполагаемые векторные зависимости.

#pragma ivdep
for(k = 0; k < SysData->numOfClaGen; k++)
            A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);

для получения дополнительной информации о ivdep, см. документ ICC

Использование restrict Модификатор для указателей утверждает компилятору, что нет псевдонимов. Это ключевое слово было введено в C99. C++ не поддерживает его, но многие компиляторы C++ поддерживают __restrict в качестве эквивалентного проприетарного расширения. При использовании компилятора Intel необходимо включить использование restrict добавив флаг командной строки -restrict (Linux) или /Qrestrict (Windows). В следующей версии вашего кода цикл используется по желанию при использовании компилятора Intel версии 13.1.3.198:

#include <math.h>

struct bar {
    int numOfClaGen;
};

void foo (double * restrict A, 
          const double * restrict B,
          const double * restrict x1,
          const struct bar * restrict SysData,
          const int ind0)
{
    int k;
    for (k = 0; k < SysData->numOfClaGen; k++) {
        A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);
    }
}

Вызов компилятора следующим образом (в 64-битной системе Windows)

icl /c /Ox /QxHost /Qrestrict /Qvec-report2 vectorize.c

компилятор сообщил

vectorize.c(14): (col. 5) remark: LOOP WAS VECTORIZED.

Год назад icc был изменен на set -ansi-alias по умолчанию для Linux и Mac. Для Windows на это значение по умолчанию нельзя рассчитывать, так как оно конфликтует с использованием Microsoft. Эта опция эквивалентна gcc -fstrict-aliasing, которая используется по умолчанию с gcc 3.0. Я думаю, что гораздо лучше установить эту опцию, чем устанавливать ivdep restrict или simd для такой ограниченной проблемы. Хотя это не очень хорошо задокументировано, icc обрабатывает __restrict так же, как gcc, и не требует, чтобы параметр restrict или C99 принимал его. В принципе, он должен вступать в игру только для изменяемых объектов (A[] в приведенном выше примере). Как ни странно, __restrict имеет немного другое значение для MSVC++. Он допускает невекторную оптимизацию, которая в противном случае могла бы быть предотвращена возможными зависимостями, но не разрешает векторизацию (но это может относиться к настоящему случаю).

Другие вопросы по тегам