Why is GCC implementing isnan () more efficient for C ++ <cmath> than C <math.h>?

Here is my code:

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

If I #include <cmath> , I get this assembly:

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

This is reasonable: ucomisd sets the parity flag if the comparison of x with itself is unordered, that is, x is a NAN. Then setp copies the parity flag to the result (only one byte, hence the initial reset %eax ).

But if I #include <math.h> , I get this assembly:

 jmp __isnan 

Now the code is not string, and the __isnan function, of course, does not speed up the ucomisd instruction, so we suffered a jump without any benefit. I get the same if I compile code like C.

Now, if I change the call of isnan() to __builtin_isnan() , I get a simple ucomisd instruction ucomisd , regardless of which heading I include, and it also works in C. Similarly, if I just return x != x

So my question is: why does the C <math.h> header provide a less efficient implementation of isnan() than the C ++ <cmath> header? Do people intend to use __builtin_isnan() , and if so, why?

I tested GCC 4.7.2 and 4.9.0 on x86-64 with optimizations of -O2 and -O3 .

+42
c ++ optimization c nan constantfolding
Sep 26 '14 at 5:27
source share
1 answer

Looking at the <cmath> for libstdc ++ shipped with gcc 4.9, you get the following:

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

Function A constexpr can be aggressively built in and, of course, the function simply delegates work to __builtin_isnan .

The <math.h> header does not use __builtin_isnan , instead it uses the __isnan implementation, which has been inserted here for quite some time, but on my machine β„’ line 430 math.h Because the C99 standard requires the use of a macro for isnan et al (section 7.12 of the C99 standard), a β€œfunction” is defined as follows:

 #define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) \ : sizeof (x) == sizeof (double) ? __isnan (x) \ : __isnanl (x)) 

However, I see no reason why he cannot use __builtin_isnan instead of __isnan , so I suspect this is an oversight. As Mark Gliss notes in the comments, there is a corresponding error report for a similar problem, using isinf instead of isnan .

+15
Sep 26 '14 at 6:17
source share



All Articles