gccにこのsqrtループを完全にベクトル化するにはどうすればよいですか?
このコードを取ると
#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
(生成コンパイラエクスプローラ)
...
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
しEDOM
ます。ICCは、デフォルトではそれを気にしないようです。
-mprefer-vector-width=512
自動ベクトル化は、意味がある場合に512ビット演算を優先します。デフォルトでは、256ビットの操作がために、少なくとも、好まれるcascadelake
とskylake-avx512
、他の現在のプロセッサと、それはおそらく将来のすべてのプロセッサのためにそのように滞在しません。
-ffast-math
フラグを追加すると、gccはYMMレジスタを使用します。例:
vsqrtpd (%rdi,%rax), %ymm0
vmovupd %ymm0, (%rcx,%rax)
デモ