我们正在运行科学计划,我们希望实施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;
}
其中a和b是256位双精度:
typedef union v2complex {
__m256d v;
complex c[2];
} v2complex;
问题在于代码主要产生正确的结果,但有时会失败。
我对集会很新,但我试图自己解决这个问题。似乎C程序(优化的-O3)与汇编代码中使用的寄存器ymm
交互。例如,我可以在执行乘法之前printf其中一个值(例如a),并且程序永远不会给出错误的结果。
我的问题是如何告诉GCC不要与ymm互动。我没有成功
将ymm
放入破坏的寄存器列表。
答案 0 :(得分:7)
正如你猜测的那样,问题是你没有告诉海湾合作委员会哪些登记你正在破坏。如果他们还不支持将YMM寄存器放入clobber列表中,我会感到惊讶;您使用的是什么版本的GCC?
无论如何,将相应的XMM寄存器放入clobber列表中几乎肯定就足够了:
: "=m" (ret) : "m" (*a), "m" (*b) : "%xmm1", "%xmm2");
其他一些说明:
"r" (a), "r" (b)
作为约束,并像vmovupd (%2), %%ymm1
一样编写我的负载。生成的代码可能没什么区别,但似乎更具惯用性。vzeroupper
之后放置AVX代码,以避免(大)档位。答案 1 :(得分:3)
我添加了两条评论,而不是直接回答您的问题:
src/special/complexvec.h
。