为什么c++中的fetestexcept被编译为函数调用而不是内联



我正在评估浮点异常在性能关键/热点中的使用情况(清除和查询)。代码。查看生成的二进制文件,我注意到GCC和Clang都没有将调用扩展为我期望的内联指令序列;相反,它们似乎生成了对运行时库的调用。这对我的应用程序来说是非常昂贵的。

考虑以下最小示例:

#include <fenv.h>
#pragma STDC FENV_ACCESS on
inline int fetestexcept_inline(int e)
{
unsigned int mxcsr;
asm volatile ("vstmxcsr" " %0" : "=m" (*&mxcsr));
return mxcsr & e & FE_ALL_EXCEPT;
}
double f1(double a)
{
double r = a * a;
if(r == 0 || fetestexcept_inline(FE_OVERFLOW)) return -1;
else return r;
}
double f2(double a)
{
double r = a * a;
if(r == 0 || fetestexcept(FE_OVERFLOW)) return -1;
else return r;
}

和GCC生成的输出:https://godbolt.org/z/jxjzYY

编译器似乎知道他可以为目标使用与cpu家族相关的avx指令(它使用"vmulsd")对于乘法)。然而,无论我尝试哪个优化标志,它总是会产生对glibc的更昂贵的函数调用,而不是(据我所知)应该做相应glibc函数所做的汇编。

这并不是抱怨,我对添加内联程序集很满意。我只是想知道是否有一个微妙的区别,我忽略了,这可能是内联程序集版本中的一个错误。

需要支持long double算法。fetestexcept需要合并SSE和FPU状态,因为long double操作只更新FPU状态,而不更新MXSCR寄存器。因此,内联的好处在一定程度上减少了。

最新更新