gccにこのsqrtループを完全にベクトル化するにはどうすればよいですか?

Aug 23 2020

このコードを取ると

#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=high512ビットレジスタを使用するオプションを追加できます(compiler-explorer)。

...
  vrsqrt14pd %zmm4, %zmm1 #7.12
...

回答

3 harold Aug 23 2020 at 07:26

XMMは128ビットレジスタです

それよりも悪いのは、最後に(スカラー、倍精度)でvsqrtsd示されているように、ベクトル演算でさえありませんsd。XMMレジスタは、そのようなスカラー浮動小数点演算でも使用されますが、レジスタの下位64ビットまたは32ビットのみに有用なデータが含まれ、残りはゼロになります。

欠落しているオプションは-fno-math-errno(このフラグはによっても暗示され-ffast-math、追加の効果があります)および(オプションで)-mprefer-vector-width=512です。

-fno-math-errnoerrno数学演算、特に平方根の設定をオフにします。これは、負の入力が。に設定せずにNaNになることを意味errnoEDOMます。ICCは、デフォルトではそれを気にしないようです。

-mprefer-vector-width=512自動ベクトル化は、意味がある場合に512ビット演算を優先します。デフォルトでは、256ビットの操作がために、少なくとも、好まれるcascadelakeskylake-avx512、他の現在のプロセッサと、それはおそらく将来のすべてのプロセッサのためにそのように滞在しません。

1 cigien Aug 23 2020 at 07:20

-ffast-mathフラグを追加すると、gccはYMMレジスタを使用します。例:

vsqrtpd (%rdi,%rax), %ymm0
vmovupd %ymm0, (%rcx,%rax)

デモ