为什么GCC比C <math.h>更有效地为C ++ <cmath>实现isnan()?</math.h> </cmath>

时间:2014-09-26 05:27:09

标签: c++ c optimization nan constantfolding

这是我的代码:

int f(double x)
{
  return isnan(x);
}

如果我#include <cmath>我得到了这个集会:

xorl    %eax, %eax
ucomisd %xmm0, %xmm0
setp    %al

这是相当聪明的:如果x与其自身的比较是无序的,则ucomisd设置奇偶校验标志,意味着x是NAN。然后setp将奇偶校验标志复制到结果中(只有一个字节,因此最初清除%eax)。

但如果我#include <math.h>我得到了这个集会:

jmp     __isnan

现在代码不是内联的,__isnan函数肯定不会更快ucomisd指令,所以我们没有任何好处。如果我将代码编译为C,我会得到同样的东西。

现在,如果我将isnan()调用更改为__builtin_isnan(),无论我包含哪个标头,都会得到简单的ucomisd指令,并且它也适用于C.同样,如果我只是return x != x

所以我的问题是,为什么C <math.h>标头提供的isnan()实现效率低于C ++ <cmath>标头?人们真的希望使用__builtin_isnan(),如果是,为什么?

我在x86-64上通过-O2-O3优化测试了GCC 4.7.2和4.9.0。

1 个答案:

答案 0 :(得分:17)

查看gcc 4.9附带的libstdc ++的<cmath>,你可以得到:

  constexpr bool
  isnan(double __x)
  { return __builtin_isnan(__x); }

可以积极地内联constexpr函数,当然,该函数只是将工作委托给__builtin_isnan

<math.h>标题不使用__builtin_isnan,而是使用__isnan实现,这种实现有点长,但是它的第430行{ {1}}在我的机器上。由于C99标准要求使用math.h等的宏(C99标准的第7.12节),因此&#39;功能&#39;定义如下:

isnan

但是,我认为没有理由不能使用#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) \ : sizeof (x) == sizeof (double) ? __isnan (x) \ : __isnanl (x)) 代替__builtin_isnan,所以我怀疑它是一种疏忽。正如Marc Glisse在评论中指出的那样,使用__isnan代替isinf的问题存在relevant bug report