哪个特定优化标志导致 libm 函数被视为纯函数?

问题描述 投票:0回答:1

我看到传递

-ffast-math
会导致
cmath
log
cos
函数被视为纯函数,因为编译器能够执行循环不变代码运动。举个简单的例子。

double log_demo(double x, int n) {
   double rv = 0.0l;
   for (int i = 0; i < n; i++) {
       // log only needs to be called once
       // but the compiler does not see that without specific flags
       rv += log(x);
   }
   return rv;
}

Without

-ffast-math
log(x)
在循环中计算,否则从循环中取出。在 compiler explorer here 上看到这个 - 分支目标
.L3
是循环分支目标,你可以在 gcc 的输出中看到
call log
,而循环体内没有
-ffast-math
,而在其他循环中只有
addsd
一个。

现在,我不想启用所有不安全的优化并违反 IEEE 754 规范。在不使用

-ffast-math
本身的情况下如何实现这一目标?

c gcc compiler-flags fast-math
1个回答
0
投票

您需要的旗帜是

-fno-math-errno

-ffast-math
是一组标志,而不仅仅是一个标志。其中一些标志违反了 IEEE 754。来自
man gcc

-快速数学

设置选项-fno-math-errno, -funsafe-数学优化,-仅限有限数学, -fno-舍入数学、-fno-signaling-nans、-fcx-有限范围 和-fexcess- precision =快速。

所以,事实证明 libm 中的数学函数不是纯粹的,因为它们可能会设置

errno
。因此,使它们纯净所需的标志是
-fno-math-errno
。这样做似乎使编译器将它们视为纯函数,并且编译器现在可以执行常见的优化,例如循环不变代码运动。在 编译器资源管理器中查看此内容。

当然,结果是一些与错误条件相关的信息可能会丢失。但是,数学函数中的错误应该主要是由于导致 nan 和 infs 信号的域错误造成的。例如。

man 3 log
没有提及设置
errno
,所以它很可能甚至不使用
errno

© www.soinside.com 2019 - 2024. All rights reserved.