4

我正在评估性能关键/“热”代码中浮点异常的使用(清除和查询)。查看生成的二进制文件,我注意到 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 函数所做的程序集。

这不是投诉,我可以添加内联程序集。我只是想知道是否可能存在我忽略的细微差异,这可能是 inline-assembly-version 中的错误。

4

1 回答 1

4

它需要支持long double算术。fetestexcept需要合并 SSE 和 FPU 状态,因为long double操作只更新 FPU 状态,而不更新 MXSCR 寄存器。因此,内联的好处有所减少。

于 2021-01-26T06:32:44.423 回答