Код сборки / инструкции AVX для умножения комплексных чисел. (Встроенный ассемблер компилятора GCC )
мы запускаем научную программу, и мы хотели бы реализовать функции AVX. Вся программа (написанная на Fortran+C) будет векторизована, и на данный момент я пытаюсь реализовать комплексное умножение чисел в встроенной сборке GCC.
код сборки принимает 4 комплексных числа и выполняет сразу два комплексных умножения:
v2complex cmult(v2complex *a, v2complex *b) {
v2complex ret;
asm (
"vmovupd %2,%%ymm1;"
"vmovupd %2, %%ymm2;"
"vmovddup %%ymm2, %%ymm2;"
"vshufpd ,%%ymm1,%%ymm1,%%ymm1;"
"vmulpd %1, %%ymm2, %%ymm2;"
"vmulpd %1, %%ymm1, %%ymm1;"
"vshufpd ,%%ymm1,%%ymm1, %%ymm1;"
"vaddsubpd %%ymm1, %%ymm2,%%ymm1;"
"vmovupd %%ymm1, %0;"
:
"=m"(ret)
:
"m" (*a),
"m" (*b)
);
return ret;
}
где a и b-256-битная двойная точность:
typedef union v2complex {
__m256d v;
complex c[2];
} v2complex;
проблема в том, что код в основном дает правильный результат, но иногда он терпит неудачу.
Я очень новичок в сборке, но я попытался разобраться в этом сам. Кажется, что программа C (optimized-O3) взаимодействует с регистрами ymm
используется в коде сборки. Например, я могу распечатать одно из значений (например, a) перед выполнением умножения, и программа никогда не дает неправильных результатов.
мой вопрос в том, как сказать GCC не взаимодействовать с ymm. Мне не удалось
Поставить ymm
для списка clobbered регистров.
2 ответов
как вы предполагаете, проблема в том, что вы не сказали GCC, какие регистры вы избиваете. Я удивлен, если они еще не поддерживают включение регистров YMM в список clobber; какую версию GCC вы используете?
в любом случае, почти наверняка будет достаточно поместить соответствующие регистры XMM в список clobber:
: "=m" (ret) : "m" (*a), "m" (*b) : "%xmm1", "%xmm2");
некоторые другие Примечания:
- вы загружаете оба входа дважды, что неэффективно. Для этого нет причин.
- я хотел бы использовать
"r" (a), "r" (b)
как ограничения и написать мои как-тоvmovupd (%2), %%ymm1
. Вероятно, нет разницы в сгенерированном коде, но он кажется более идиоматически правильным. - не забудьте поставить
vzeroupper
после кода AVX перед любым кодом SSE выполняется, чтобы избежать (больших) киосков.
Я добавляю два комментария, не отвечая непосредственно на ваш вопрос:
- я настоятельно рекомендую использовать встроенные компиляторы вместо прямой сборки. Таким образом, компилятор заботится о распределении регистров и может лучше оптимизировать ваш код (встроенные методы, инструкции по переупорядочению и т. д.)
-
Агнер Туман есть библиотека векторных классов C++ оптимизированных векторизованных операций, включая операции с комплексными числами. Даже если вы возможно, не удастся использовать его библиотеки непосредственно в коде C, его оптимизированный код может быть хорошей отправной точкой; см.
src/special/complexvec.h
на исходный код на молнии.