融合乘法加法和默认舍入模式

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

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

生产以下组件

vfmadd132ss     %xmm1, %xmm2, %xmm0
ret

我注意到GCC已经在GCC 4.8中使用了-O3

-O3 -mfma 3.7与-O3 -mfma生产

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

但带有-Ofast -mfma Clang 3.7与使用-O3 fast GCC产生相同的代码。

我很惊讶GCC用-O3做,因为从这个答案中可以看出

除非您允许使用宽松的浮点模型,否则不允许编译器融合分离的加法和乘法。

这是因为FMA只有一个舍入,而ADD + MUL有两个舍入。 所以编译器会通过融合来违反严格的IEEE浮点行为。

然而,从这个链接它说

无论FLT_EVAL_METHOD的值如何,都可能会收缩任何浮点表达式,也就是说,计算好像所有中间结果都具有无限范围和精度。

所以现在我感到困惑和担忧。

  • GCC与-O3一起使用FMA是否合理?
  • 熔断是否违反严格的IEEE浮点行为?
  • 如果熔断确实违反了IEEE浮点标准,并且GCC返回__STDC_IEC_559__这不是矛盾吗?
  • 由于FMA可以在软件中仿真,因此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

  • -ffp-contract=fast (默认)。
  • 随着铿锵它使用fma

  • -ffp-contract=fast
  • -ffp-contract=on (默认)和#pragma STDC FP_CONTRACT ON (默认为OFF )。
  • 换句话说,对于Clang,您可以使用#pragma STDC FP_CONTRACT ON (因为-ffp-contract=on是默认值)或-ffp-contract=fast来获得fma-ffast-math (因此-Ofast )set -ffp-contract=fast


    我看着MSVC和ICC。

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

    使用ICC它使用与FMA -O3 -march=core-avx2 (acctually -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使用-mfma -march=core-avx2 ),但Clang和MSVC不会。


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

    语言标准还应定义并要求实现提供允许和禁止单独或集体改变块优化的属性。 这些优化可能包括但不限于:

    ...

    - 从乘法和加法合成fusedMultiplyAdd操作。

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


    当你引用允许融合的乘法 - 加法时,你忽略了重要的条件“除非编译指示FP_CONTRACT关闭”。 这是C中的一个新特性(我认为是C99引入的),并且PowerPC完全需要PowerPC,它们从一开始就融合了乘加 - 实际上,x * y等同于fma(x,y,0)和x + y等同于fma(1.0,x,y)。

    FP_CONTRACT是控制融合乘法/加法,而不是FLT_EVAL_METHOD。 虽然如果FLT_EVAL_METHOD允许更高的精度,那么合同总是合法的; 只是假装操作以非常高的精度执行,然后四舍五入。

    如果你不想要速度,但是精确度,fma函数很有用。 即使硬件不可用,它也会慢慢但正确地计算出合同结果。 如果硬件可用,应该内联。

    链接地址: http://www.djcxy.com/p/85653.html

    上一篇: Fused multiply add and default rounding modes

    下一篇: bridge and haswell SSE2/AVX/AVX2