用于乘法复数的汇编代码/ AVX指令.(GCC内联装配)

Jea*_*las 7 c assembly gcc avx complex-numbers

我们正在运行一个科学计划,我们希望实现AVX功能.整个程序(用Fortran + C编写)将被矢量化,目前我正在尝试在GCC内联汇编中实现复数乘法.

汇编代码采用4个复数,并同时执行两次复数乘法:

v2complex cmult(v2complex *a, v2complex *b) {
    v2complex ret;
    asm (
        "vmovupd %2,%%ymm1;"
        "vmovupd %2, %%ymm2;"
        "vmovddup %%ymm2, %%ymm2;"
        "vshufpd $15,%%ymm1,%%ymm1,%%ymm1;"
        "vmulpd %1, %%ymm2, %%ymm2;"
        "vmulpd %1, %%ymm1, %%ymm1;"
        "vshufpd $5,%%ymm1,%%ymm1, %%ymm1;"
        "vaddsubpd %%ymm1, %%ymm2,%%ymm1;"
        "vmovupd %%ymm1, %0;"
        :
        "=m"(ret)
        :
        "m" (*a),
        "m" (*b)
        );
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

其中a和b是256位双精度:

typedef union v2complex {
    __m256d v;
    complex c[2];
} v2complex;
Run Code Online (Sandbox Code Playgroud)

问题是代码主要产生正确的结果,但有时它会失败.

我对集会很新,但我试图自己解决这个问题.似乎C程序(优化的-O3)与ymm汇编代码中使用的寄存器相互作用.例如,我可以在执行乘法之前打印其中一个值(例如a),程序永远不会给出错误的结果.

我的问题是如何告诉GCC不要与ymm互动.我没有设法把它ymm放到破坏的寄存器列表中.

Ste*_*non 7

正如你猜测的那样,问题是你没有告诉海湾合作委员会哪些登记你是在破坏.如果他们还不支持将YMM寄存器放入clobber列表中,我会感到惊讶; 您使用的是什么版本的GCC?

无论如何,将相应的XMM寄存器放入clobber列表中几乎肯定是足够的:

: "=m" (ret) : "m" (*a), "m" (*b) : "%xmm1", "%xmm2");
Run Code Online (Sandbox Code Playgroud)

其他一些说明:

  • 您正在两次加载两个输入,效率很低.没有理由这样做.
  • 我会"r" (a), "r" (b)用作约束并写下我的负载vmovupd (%2), %%ymm1.生成的代码可能没什么区别,但似乎更具惯用性.
  • vzeroupper在执行任何SSE代码之前,不要忘记放置以下AVX代码以避免(大)停顿.