Ecco il mio codice:Perché GCC implementa isnan() in modo più efficiente per C++ <cmath> rispetto a C <math.h>?
int f(double x)
{
return isnan(x);
}
Se mi #include <cmath>
ottengo questa assemblea:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Questa è ragionevolmente intelligente: ucomisd imposta il flag di parità se il confronto di x con se stessa è ordinata, cioè x è NAN. Quindi setp copia il flag di parità nel risultato (solo un singolo byte, quindi il valore iniziale di %eax
).
Ma se #include <math.h>
ottengo questa assemblea:
jmp __isnan
Ora il codice non è in linea, e la funzione __isnan
è certamente più veloce le istruzioni del ucomisd
, quindi abbiamo subito una salto per alcun beneficio. Ho la stessa cosa se compilo il codice come C.
Ora se cambio la chiamata isnan()
-__builtin_isnan()
, ho la semplice istruzione ucomisd
istruzione, indipendentemente da quale intestazione includo, e funziona in C anche. Allo stesso modo se ho solo return x != x
.
Quindi la mia domanda è, perché l'intestazione C <math.h>
forniscono una meno efficiente attuazione isnan()
di intestazione C++ <cmath>
? Le persone si aspettano davvero di usare __builtin_isnan()
, e se sì, perché?
Ho testato GCC 4.7.2 e 4.9.0 su x86-64 con l'ottimizzazione -O2
e -O3
.
ecco la mia speculazione: pre c99, non esiste una funzione inline in c. nessuna funzione inline significa che le funzioni devono essere invocate da jmp/call (o una sorta di branching). __builtin_isnan non fa parte di c. è probabilmente un intrinseco specifico della piattaforma. – thang
Ma sicuramente un'intestazione di sistema come "" può utilizzare i built-in specifici della piattaforma. –
Sono abbastanza sicuro che 'isnan' userebbe' __builtin_isnan' se possibile. Non vedo perché dovresti chiamarlo manualmente. – Rapptz