Код сборки / инструкции 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 на исходный код на молнии.