我们正在运行一个科学程序,我们希望实现 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
汇编代码中使用的寄存器交互。例如,我可以在执行乘法之前打印其中一个值(例如 a),并且程序永远不会给出错误的结果。
我的问题是如何告诉 GCC 不要与 ymm 交互。我没有设法将被破坏的ymm
寄存器列表。