15

GCC 5.3 では、次のコードでコンパイルされます-O3 -fma

float mul_add(float a, float b, float c) {
  return a*b + c;
}

次のアセンブリを生成します

vfmadd132ss     %xmm1, %xmm2, %xmm0
ret

-O3GCC が既に 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 の値に関係なく、任意の浮動小数点式を縮小できます。つまり、すべての中間結果が無限の範囲と精度を持っているかのように計算されます。

だから今、私は混乱し、心配しています。

  1. GCC は FMA を使用することで正当化され-O3ますか?
  2. 融合は厳密な IEEE 浮動小数点の動作に違反しますか?
  3. 融合が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_CONTRACTset toONとset to 、、およびのいくつかの順列を確認OFFしました。すべての場合で私も使用しました。-ffp-contractonofffast-O3 -mfma

GCC の場合、答えは簡単です。#pragma STDC FP_CONTRACTONもOFFも関係ありません。重要なだけ-ffp-contractです。

GCCでfma使う

  1. -ffp-contract=fast(デフォルト)。

Clangで使用fma

  1. -ffp-contract=fast
  2. -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 が有効になっている場合 ( -mfmaGCC/Clang またはICC を使用-march=core-avx2)、GCC と ICC は fma を使用しますが、Clang と MSVC は使用しません。

4

2 に答える 2

6

IEEE-754 はこの点で言語に従うため、IEEE-754 に違反していません。

言語標準は、ブロックの値を変更する最適化を個別にまたは集合的に許可または禁止する属性も定義し、実装に提供を要求する必要があります。これらの最適化には以下が含まれますが、これらに限定されません。

...

― 乗算と加算からの fusedMultiplyAdd 操作の合成。

標準 C では、STDC FP_CONTRACTプラグマは、この値を変更する最適化を制御する手段を提供します。したがって、GCC は、設定によって最適化を無効にできる限り、デフォルトでフュージョンを実行するライセンスを取得していますSTDC FP_CONTRACT OFF。それをサポートしないということは、C 標準に準拠していないことを意味します。

于 2016-01-15T19:03:43.227 に答える
4

融合乗加算が許可されていると引用したとき、「プラグマ FP_CONTRACT がオフでない限り」という重要な条件を省略しました。これは C の新しい機能 (C99 で導入されたと思います) であり、最初から乗加算を融合していた PowerPC によって絶対に必要とされました。実際、x*y は fma (x, y, 0) と同等でした。 x+y は fma (1.0, x, y) と同等でした。

FP_CONTRACT は、FLT_EVAL_METHOD ではなく、融合乗算/加算を制御するものです。ただし、FLT_EVAL_METHOD がより高い精度を許可する場合、契約は常に有効です。操作が非常に高い精度で実行されてから丸められたふりをするだけです。

fma 関数は、速度ではなく精度が必要な場合に役立ちます。ハードウェアで利用できない場合でも、契約結果をゆっくりと正しく計算します。また、ハードウェアで使用できる場合はインライン化する必要があります。

于 2015-12-23T13:40:41.197 に答える