Прагма выравнивания памяти gcc - PullRequest
8 голосов
/ 22 апреля 2010

Есть ли у gcc прагма выравнивания памяти, похожая #pragma vector aligned в компиляторе Intel? Я хотел бы сказать компилятору оптимизировать конкретный цикл, используя выровненные инструкции load / store. во избежание путаницы речь не идет о структурной упаковке.

например:

#if defined (__INTEL_COMPILER)
#pragma vector aligned
#endif
        for (int a = 0; a < int(N); ++a) {
            q10 += Ix(a,0,0)*Iy(a,1,1)*Iz(a,0,0);
            q11 += Ix(a,0,0)*Iy(a,0,1)*Iz(a,1,0);
            q12 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,0,1);
            q13 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,1);
            q14 += Ix(a,0,0)*Iy(a,1,0)*Iz(a,0,1);
            q15 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,1,1);
        }

Спасибо

Ответы [ 3 ]

10 голосов
/ 22 апреля 2010

Вы можете сообщить GCC, что указатель указывает на выровненную память, используя typedef для создания перестроенного типа, на который вы можете объявить указатели.

Это помогает gcc, но не clang7.0 или ICC19, см. X86-64 не-AVX asm, который они излучают на Godbolt . (Только GCC складывает загрузку в операнд памяти для mulps, вместо использования отдельного movups). Вам нужно использовать __builtin_assume_aligned, если вы хотите передать переносное обещание выравнивания компиляторам GNU C, кроме самого GCC.


С http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

typedef double aligned_double __attribute__((aligned (16)));
// Note: sizeof(aligned_double) is 8, not 16
void some_function(aligned_double *x, aligned_double *y, int n)
{
    for (int i = 0; i < n; ++i) {
        // math!
    }
}

Это не сделает aligned_double 16 байт в ширину. Это просто выровняет его по 16-байтовой границе, точнее, первой будет в массиве. Глядя на разборку на моем компьютере, как только я использую директиву выравнивания, я начинаю видеть много векторных операций. В настоящее время я использую компьютер с архитектурой Power, так что это код altivec, но я думаю, что он делает то, что вы хотите.

(Примечание: я не использовал double, когда тестировал это, потому что там Altivec не поддерживает двойные числа с плавающей точкой.)

Вы можете увидеть некоторые другие примеры автовекторизации, используя атрибуты типа здесь: http://gcc.gnu.org/projects/tree-ssa/vectorization.html

5 голосов
/ 09 августа 2011

Я попробовал ваше решение с g ++ версии 4.5.2 (как для Ubuntu, так и для Windows), и оно не векторизовало цикл.

Если атрибут выравнивания удален, он векторизует цикл, используя невыровненные нагрузки.

Если функция встроена так, что к массиву можно обращаться напрямую с удаленным указателем, то она векторизируется с выровненными нагрузками.

В обоих случаях атрибут выравнивания предотвращает векторизацию. Это иронично: «align_double * x» должен был включить векторизацию, но он делает обратное.

Какой компилятор сообщил вам о векторизованных циклах? Я подозреваю, что это не был компилятор gcc?

3 голосов
/ 27 марта 2017

Имеет ли gcc прагму для выравнивания памяти, похожую на #pragma выровненный вектор

Похоже, что более новые версии GCC имеют __builtin_assume_aligned:

Встроенная функция: void * __builtin_assume_aligned (const void *exp, size_t align, ...)

Эта функция возвращает свой первый аргумент и позволяет компилятору предполагать, что возвращаемый указатель выровнен как минимум по выровненным байтам. Этот встроенный может иметь два или три аргумента, если он имеет три, третий аргумент должен иметь целочисленный тип, и если он ненулевой означает смещение смещения. Например:

void *x = __builtin_assume_aligned (arg, 16);

означает, что компилятор может предположить, что x, установленный в arg, выровнен как минимум на 16 байт, тогда как:

void *x = __builtin_assume_aligned (arg, 32, 8);

означает, что компилятор может предположить для x, установленного в arg, что (char *) x - 8 выровнен по 32 байта.

Основываясь на некоторых других вопросах и ответах по переполнению стека, примерно в 2010 году, кажется, что встроенный модуль не был доступен в GCC 3 и более ранних версиях GCC 4. Но я не знаю, где находится точка отсечения.

...