我有一个关于GNU GCC中-ffp-contract
标志的问题(见 https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)。
标志文档编写如下:
-ffp-contract=off
禁用浮点表达式收缩。-ffp-contract=fast
启用浮点表达式收缩,例如形成融合的乘加运算(如果目标具有对它们的本机支持)。-ffp-contract=on
启用浮点表达式收缩(如果语言标准允许)。这目前尚未实现并被视为等于-ffp-contract=off
。默认值为-ffp-contract=fast
。
现在的问题:
- 快速和开启有什么区别?
- 除了 FMA(或类似的熔融多子)之外还有其他收缩示例吗?
在 C89 中,不允许 FP 收缩。从 C99 开始,默认情况下,实现可能会对表达式进行 FP 收缩,但随后需要提供一个可以切换以影响收缩行为的#pragma STDC FP_CONTRACT
(cpp首选项)。
所以 GCC 开关应该是:
-ffp-contract=off
:不要做宫缩。忽略#pragma STDC FP_CONTRACT
。这是-std=c89
的默认值。-ffp-contract=on
:默认启用收缩并遵守#pragma STDC FP_CONTRACT
。这将是-std=c99
及以上版本的默认值。-
-ffp-contract=fast
:这是 GCC 默认值,即使没有任何快速数学选项。我们不在快速数学模式下声称ISO一致性,所以总是收缩是可以的,甚至是单独的表达式(参见Marc Glisse的评论)。 这是-std=gnu99
和其他 GNU 方言的默认值。
不幸的是,#pragma STDC FP_CONTRACT
尚未在GCC 中实施,因此目前gcc -ffp-contract=on
做了保持 ISO 合规性所必需的事情:什么都没有。 即开=关,因为GCC知道如何实现(快速)的唯一其他行为对on
来说太激进了。
你必须深入研究来源(或邮件列表)来了解GCC能够做什么样的收缩,但它不必局限于FMA。
参见 GCC 和 Clang on Godbolt,了解一个表达式与 2 个语句的简单测试用例。Clang默认为-ffp-contract=off
,但支持on
和fast
,如您所见。 GCC只支持off
和fast
,on
映射到off
。
C11标准对#pragma STDC FP_CONTRACT
有什么看法:
§6.5¶8:一个浮点表达式可以被收缩,即计算为 虽然这是一个单一的操作,因此省略了源代码和表达式计算方法隐含的舍入错误.89)
中的FP_CONTRACT编译指示提供了一种不允许收缩表达式的方法。否则,表达式是否以及如何收缩是实现定义的.90) 收缩表达式
中的中间运算被计算为无限范围和精度,而最终运算则四舍五入为表达式求值方法确定的格式。收缩表达式还可以省略浮点异常的引发。
此许可证专门用于允许实现利用组合多个 C 运算符的快速机器指令。由于收缩可能会破坏可预测性,甚至会降低包含表达式的准确性,因此需要明确定义并清楚地记录它们的使用。