Здесь мой код:
int f(double x)
{
return isnan(x);
}
Если я #include <cmath>, я получаю эту сборку:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Это разумно: ucomisd устанавливает флаг четности, если сравнение x с самим собой неупорядочено, то есть x является NAN. Затем setp копирует флаг четности в результат (только один байт, следовательно, первоначальный сброс %eax).
Но если я #include <math.h>, я получаю эту сборку:
jmp __isnan
Теперь код не является строковым, а функция __isnan, конечно, не ускоряет инструкцию ucomisd, поэтому мы понесли скачок без пользы. Я получаю то же самое, если компилирую код как C.
Теперь, если я изменяю вызов isnan() на __builtin_isnan(), я получаю простую инструкцию инструкции ucomisd, независимо от того, какой заголовок я включаю, и он работает также в C. Аналогично, если я просто return x != x.
Итак, мой вопрос: почему заголовок C <math.h> обеспечивает менее эффективную реализацию isnan(), чем заголовок С++ <cmath>? Предполагают ли люди использовать __builtin_isnan(), и если да, то почему?
Я тестировал GCC 4.7.2 и 4.9.0 на x86-64 с оптимизацией -O2 и -O3.