c++ c optimization nan constantfolding

sqr c++



¿Por qué GCC implementa isnan() de manera más eficiente para C++<cmath> que C<math.h>? (1)

Si mira <cmath> para libstdc ++ incluido con gcc 4.9, obtendrá esto:

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

Una función constexpr podría estar constexpr línea y, por supuesto, la función simplemente delega el trabajo en __builtin_isnan .

El <math.h> no usa __builtin_isnan , sino que usa una implementación __isnan que es algo largo de pegar aquí, pero son líneas 430 de math.h en mi máquina ™. Dado que el estándar C99 requiere el uso de una macro para isnan y otros (sección 7.12 del estándar C99), la ''función'' se define de la siguiente manera:

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

Sin embargo, no veo ninguna razón por la cual no pueda usar __builtin_isnan lugar de __isnan así que sospecho que es un descuido. Como señala Marc Glisse en los comentarios, hay un sourceware.org/bugzilla/show_bug.cgi?id=15367 para un problema similar con isinf lugar de isnan .

Aquí está mi código:

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

Si #include <cmath> obtengo esta asamblea:

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

Esto es razonablemente inteligente: ucomisd establece la bandera de paridad si la comparación de x con ella misma está desordenada, lo que significa que x es NAN. Luego, setp copia el indicador de paridad en el resultado (solo un byte único, de ahí el inicial vacío de %eax ).

Pero si #include <math.h> obtengo esta asamblea:

jmp __isnan

Ahora el código no está en línea, y la función __isnan ciertamente no es más rápida que la instrucción ucomisd , por lo que hemos incurrido en un salto sin ningún beneficio. Obtengo lo mismo si compilo el código como C.

Ahora si cambio la llamada de __builtin_isnan() a __builtin_isnan() , obtengo la instrucción simple de instrucción ucomisd independientemente del encabezado que incluya, y también funciona en C. Del mismo modo, si acabo de return x != x

Entonces mi pregunta es, ¿por qué el encabezado C <math.h> proporciona una implementación menos eficiente de isnan() que el encabezado C ++ <cmath> ? ¿Se espera realmente que la gente use __builtin_isnan() y, de ser así, por qué?

Probé GCC 4.7.2 y 4.9.0 en x86-64 con optimización -O2 y -O2 .