c - 融合乘加和默认舍入模式

标签 c gcc clang ieee-754 fma

在 GCC 5.3 中,以下代码使用 -O3 -fma

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

生成以下程序集

vfmadd132ss     %xmm1, %xmm2, %xmm0
ret

I noticed GCC doing this with -O3 already in GCC 4.8 .

带有 -O3 -mfma 的 Clang 3.7 产生

vmulss  %xmm1, %xmm0, %xmm0
vaddss  %xmm2, %xmm0, %xmm0
retq

但是使用 -Ofast -mfma 的 Clang 3.7 生成的代码与使用 -O3 fast 的 GCC 生成的代码相同。

我很惊讶 GCC 使用 -O3 因为来自 this answer它说

The compiler is not allowed to fuse a separated add and multiply unless you allow for a relaxed floating-point model.

This is because an FMA has only one rounding, while an ADD + MUL has two. So the compiler will violate strict IEEE floating-point behaviour by fusing.

但是,来自 this link它说

Regardless of the value of FLT_EVAL_METHOD, any floating-point expression may be contracted, that is, calculated as if all intermediate results have infinite range and precision.

所以现在我很困惑和担心。

  1. GCC 将 FMA 与 -O3 结合使用是否合理?
  2. 融合是否违反严格的 IEEE 浮点行为?
  3. 如果融合确实违反了 IEEE 浮点行为并且因为 GCC returns __STDC_IEC_559__这不是自相矛盾吗?

自 FMA can be emulated in software FMA似乎应该有两个编译器开关:一个告诉编译器在计算中使用FMA,一个告诉编译器硬件有FMA。


显然这可以通过选项 -ffp-contract 来控制。对于 GCC,默认值为 -ffp-contract=fast 而对于 Clang,则不是。 -ffp-contract=on-ffp-contract=off 等其他选项不会产生 FMA 指令。

例如,带有 -O3 -mfma -ffp-contract=fast 的 Clang 3.7 生成 vfmadd132ss


我检查了一些 #pragma STDC FP_CONTRACT 设置为 ONOFF-ffp-contract 的排列设置为 onofffast。在所有情况下,我还使用了 -O3 -mfma

有了 GCC,答案就很简单了。 #pragma STDC FP_CONTRACT ON 或 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,您可以使用 #pragma STDC FP_CONTRACT ON 获得 fma(因为 -ffp-contract=on 是默认设置) 或使用 -ffp-contract=fast-ffast-math(因此 -Ofast)设置 -ffp-contract=fast


我研究了 MSVC 和 ICC。

对于 MSVC,它使用带 /O2/arch:AVX2/fp:fast 的 fma 指令。对于 MSVC,/fp:precise 是默认值。

对于 ICC,它使用带 -O3 -march=core-avx2 的 fma(实际上 -O1 就足够了)。这是因为 ICC 默认使用 -fp-model fast。但是 ICC 即使使用 -fp-model precise 也使用 fma。要使用 ICC 禁用 fma,请使用 -fp-model strict-no-fma

因此默认情况下 GCC 和 ICC 在启用 fma 时使用 fma(GCC/Clang 使用 -mfma 或 ICC 使用 -march=core-avx2)但 Clang 和MSVC 没有。

最佳答案

它不违反 IEEE-754,因为 IEEE-754 在这一点上遵从语言:

A language standard should also define, and require implementations to provide, attributes that allow and disallow value-changing optimizations, separately or collectively, for a block. These optimizations might include, but are not limited to:

...

― Synthesis of a fusedMultiplyAdd operation from a multiplication and an addition.

在标准 C 中,STDC FP_CONTRACT pragma 提供了控制这种值更改优化的方法。因此,GCC 被许可在默认情况下执行融合,只要它允许您通过设置 STDC FP_CONTRACT OFF 来禁用优化。不支持意味着不遵守 C 标准。

关于c - 融合乘加和默认舍入模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34436233/

相关文章:

c - 警告 : declaration of 'index' shadows a global declaration

c - 如何处理 C 中的错误?

android - 在 Android 平台上调试 Linux 内核代码

c - 如何打印具有相同名称的全局变量和局部变量的值?

c - 复代数表达式的值保持为零

python - 在windows中的tensorflow中添加一个op

gcc - 安装 HUE 时命令 'gcc' 失败

python - 用 libclang 解析;无法解析某些标记(Windows 中的 Python)

c++ - 如何判断哪些函数在编译时被评估?

linux - 我想通过使用 cmake 的正确程序检测 clang 来使用 clang/clang++ 进行编译