问题描述
如果我接受此代码
#include <cmath>
void compute_sqrt(const double* x,double* y,int n) {
int i;
#pragma omp simd linear(i)
for (i=0; i<n; ++i) {
y[i] = std::sqrt(x[i]);
}
}
并使用g++ -S -c -O3 -fopenmp-simd -march=cascadelake
进行编译,然后在循环(compiler-explorer)中得到类似的指令
...
vsqrtsd %xmm0,%xmm0,%xmm0
...
XMM是128位寄存器,但是层叠湖支持avx-512。有没有办法让gcc使用256(YMM)或512位(ZMM)寄存器?
通过比较,ICC默认将256个寄存器用于级联:使用icc -c -S -O3 -march=cascadelake -qopenmp-simd
编译会产生(compiler-explorer)
...
vsqrtpd 32(%rdi,%r9,8),%ymm1 #7.12
...
,您可以添加选项-qopt-zmm-usage=high
以使用512位寄存器(compiler-explorer)
...
vrsqrt14pd %zmm4,%zmm1 #7.12
...
解决方法
XMM是128位寄存器
更糟糕的是,vsqrtsd
甚至不是向量运算,如最后的sd
所示(标量,双精度)。标量浮点运算也使用XMM寄存器,但是只有寄存器的低64位或32位包含有用的数据,其余的被清零。
缺少的选项是-fno-math-errno
(-ffast-math
也暗示了此标志,它具有附加作用)和(可选)-mprefer-vector-width=512
。
-fno-math-errno
会关闭数学运算(尤其是平方根)的设置errno
,这意味着输入NaN 而的errno
设置为{{ 1}}。默认情况下,ICC显然并不关心这一点。
EDOM
使自动矢量化在可行时更喜欢512位操作。默认情况下,至少对于-mprefer-vector-width=512
和cascadelake
以及其他当前处理器而言,首选256位操作,它可能不会对所有将来的处理器保持这种状态。
如果添加-ffast-math
标志,则gcc将使用YMM寄存器,例如:
vsqrtpd (%rdi,%rax),%ymm0
vmovupd %ymm0,(%rcx,%rax)