使用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
Clang 3.7与-O3 -mfma
生成
vmulss %xmm1, %xmm0, %xmm0
vaddss %xmm2, %xmm0, %xmm0
retq
但是使用-Ofast -mfma
的Clang 3.7与-O3 fast
生成的代码与GCC相同。
我很惊讶GCC与-O3
合作,因为它来自this answer
除非您允许使用宽松的浮点模型,否则不允许编译器融合分离的加法和乘法。
这是因为FMA只有一个舍入,而ADD + MUL有两个舍入。因此编译器会通过融合违反严格的IEEE浮点行为。
然而,从this link开始说
无论FLT_EVAL_METHOD的值如何,任何浮点表达式都可以收缩,也就是说,计算好像所有中间结果都具有无限范围和精度。
所以现在我感到困惑和担忧。
-O3
?__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
和-O3 -mfma -ffp-contract=fast
)不会生成FMA指令。
例如,包含vfmadd132ss
的Clang 3.7会产生#pragma STDC FP_CONTRACT
。
我检查了ON
设置为OFF
和-ffp-contract
的一些排列,on
设置为off
,fast
和{{1} }}。在所有情况下,我也使用了-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,它使用带有/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不使用。
答案 0 :(得分:5)
它不违反IEEE-754,因为IEEE-754在这一点上遵循语言:
语言标准还应定义并要求实现提供允许和禁止对块进行单独或共同的值更改优化的属性。这些优化可能包括但不限于:
...
- 通过乘法和加法合成fusedMultiplyAdd运算。
在标准C中,STDC FP_CONTRACT
编译指示提供了控制此值更改优化的方法。因此,GCC默认授权执行融合,只要它允许您通过设置STDC FP_CONTRACT OFF
来禁用优化。不支持这意味着不遵守C标准。
答案 1 :(得分:4)
当你引用允许融合乘法加法时,你忽略了重要条件"除非pragma 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功能非常有用,但精度却很高。它将缓慢但正确地计算合同结果,即使它在硬件中不可用。如果它在硬件中可用,则应该内联。