你怎样才能让 gcc 完全矢量化这个 sqrt 循环?
How can you get gcc to fully vectorize this sqrt loop?
如果我接受这个代码
#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 位寄存器,但 cascadelake 支持 avx-512。有没有办法让 gcc 使用 256 (YMM) 或 512 位 (ZMM) 寄存器?
相比之下,ICC 默认为 cascadelake 使用 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
...
如果你添加 -ffast-math
标志,gcc 将使用 YMM 寄存器,例如:
vsqrtpd (%rdi,%rax), %ymm0
vmovupd %ymm0, (%rcx,%rax)
XMMs are 128 bit registers
更糟糕的是,vsqrtsd
甚至不是向量运算,如末尾的 sd
所示(标量,双精度)。 XMM 寄存器也被这样的标量浮点运算使用,但是只有寄存器的低 64 或 32 位包含有用的数据,其余的都清零了。
缺少的选项是 -fno-math-errno
(此标志也由 -ffast-math
暗示,它具有额外的效果)和(可选)-mprefer-vector-width=512
.
-fno-math-errno
关闭数学运算的设置 errno
,特别是对于平方根,这意味着负输入结果为 NaN without setting errno
到 EDOM
。默认情况下,ICC 显然不关心这一点。
-mprefer-vector-width=512
使自动矢量化在有意义时更喜欢 512 位操作。默认情况下,首选 256 位操作,至少对于 cascadelake
和 skylake-avx512
以及其他当前处理器而言,它可能不会为所有未来的处理器保持这种状态。
如果我接受这个代码
#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 位寄存器,但 cascadelake 支持 avx-512。有没有办法让 gcc 使用 256 (YMM) 或 512 位 (ZMM) 寄存器?
相比之下,ICC 默认为 cascadelake 使用 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
...
如果你添加 -ffast-math
标志,gcc 将使用 YMM 寄存器,例如:
vsqrtpd (%rdi,%rax), %ymm0
vmovupd %ymm0, (%rcx,%rax)
XMMs are 128 bit registers
更糟糕的是,vsqrtsd
甚至不是向量运算,如末尾的 sd
所示(标量,双精度)。 XMM 寄存器也被这样的标量浮点运算使用,但是只有寄存器的低 64 或 32 位包含有用的数据,其余的都清零了。
缺少的选项是 -fno-math-errno
(此标志也由 -ffast-math
暗示,它具有额外的效果)和(可选)-mprefer-vector-width=512
.
-fno-math-errno
关闭数学运算的设置 errno
,特别是对于平方根,这意味着负输入结果为 NaN without setting errno
到 EDOM
。默认情况下,ICC 显然不关心这一点。
-mprefer-vector-width=512
使自动矢量化在有意义时更喜欢 512 位操作。默认情况下,首选 256 位操作,至少对于 cascadelake
和 skylake-avx512
以及其他当前处理器而言,它可能不会为所有未来的处理器保持这种状态。