GCC 5.3 では、次のコードでコンパイルされます-O3 -fma
float mul_add(float a, float b, float c) {
return a*b + c;
}
次のアセンブリを生成します
vfmadd132ss %xmm1, %xmm2, %xmm0
ret
-O3
GCC が既に GCC 4.8 でこれを行っていることに気付きました。
-O3 -mfma
プロデュースを使用したClang 3.7
vmulss %xmm1, %xmm0, %xmm0
vaddss %xmm2, %xmm0, %xmm0
retq
しかし、Clang 3.7 with-Ofast -mfma
は GCC with と同じコードを生成し-O3 fast
ます。
この回答-O3
から、GCCがそうしていることに驚いています
緩和された浮動小数点モデルを許可しない限り、コンパイラは分離された加算と乗算を融合することはできません。
これは、FMA には丸めが 1 つしかないのに対し、ADD + MUL には丸めが 2 つあるためです。そのため、コンパイラは融合によって厳密な IEEE 浮動小数点の動作に違反します。
ただし、このリンクからそれは言う
FLT_EVAL_METHOD の値に関係なく、任意の浮動小数点式を縮小できます。つまり、すべての中間結果が無限の範囲と精度を持っているかのように計算されます。
だから今、私は混乱し、心配しています。
- GCC は FMA を使用することで正当化され
-O3
ますか? - 融合は厳密な IEEE 浮動小数点の動作に違反しますか?
- 融合がIEEE浮動小数点の動作に違反し、GCCが戻っ
__STDC_IEC_559__
てきたので、これは矛盾していませんか?
FMAはソフトウェアでエミュレートできるため、FMAには 2 つのコンパイラ スイッチが必要なようです。
どうやら、これはオプションで制御できます-ffp-contract
。GCC ではデフォルトで-ffp-contract=fast
あり、Clang ではそうではありません。-ffp-contract=on
やnoなどのその他のオプション-ffp-contract=off
は、FMA 命令を生成しません。
たとえば、 Clang 3.7 の-O3 -mfma -ffp-contract=fast
プロデュースvfmadd132ss
.
#pragma STDC FP_CONTRACT
set toON
とset to 、、およびのいくつかの順列を確認OFF
しました。すべての場合で私も使用しました。-ffp-contract
on
off
fast
-O3 -mfma
GCC の場合、答えは簡単です。#pragma STDC FP_CONTRACT
ONもOFFも関係ありません。重要なだけ-ffp-contract
です。
GCCでfma
使う
-ffp-contract=fast
(デフォルト)。
Clangで使用fma
- と
-ffp-contract=fast
。 -ffp-contract=on
(デフォルト) と(#pragma STDC FP_CONTRACT ON
デフォルトはOFF
)。
つまり、Clang を使用するfma
と#pragma STDC FP_CONTRACT ON
(-ffp-contract=on
がデフォルトであるため) または で取得できます-ffp-contract=fast
。-ffast-math
(したがって-Ofast
)セット-ffp-contract=fast
。
MSVCとICCを調べました。
MSVC では、fma 命令を使用し/O2 /arch:AVX2 /fp:fast
ます。With MSVC/fp:precise
がデフォルトです。
ICC では fma を使用します-O3 -march=core-avx2
(実際-O1
には十分です)。これは、デフォルトで ICC が を使用するためです-fp-model fast
。しかし、ICC は-fp-model precise
. ICC で fma を無効にするには-fp-model strict
、 またはを使用します-no-fma
。
したがって、デフォルトでは、fma が有効になっている場合 ( -mfma
GCC/Clang またはICC を使用-march=core-avx2
)、GCC と ICC は fma を使用しますが、Clang と MSVC は使用しません。