Почему GCC более эффективно реализует isnan () для C ++ & lt; cmath & gt; чем C & lt; math.h & gt ;?

Вот мой код:

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

Если я #include <cmath> Я получаю эту сборку:

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

Это достаточно умно: ucomisd устанавливает флаг четности, если сравнение x с самим собой неупорядочено, что означает, что x равен NAN. затем ЗАД копирует флаг четности в результат (только один байт, следовательно, начальная очистка %eax).

Но если я #include <math.h> Я получаю эту сборку:

jmp     __isnan

Теперь код не является встроенным, и __isnan Функция, конечно, не быстрее, чем ucomisd инструкция, поэтому мы понесли скачок без пользы. Я получаю то же самое, если я компилирую код как C.

Теперь, если я изменю isnan() позвонить __builtin_isnan()Я получаю простое ucomisd инструкция инструкция независимо от того, какой заголовок я включаю, и она работает в Си тоже. Точно так же, если я просто return x != x,

Итак, мой вопрос, почему C <math.h> заголовок обеспечивает менее эффективную реализацию isnan() чем C ++ <cmath> заголовок? Люди действительно должны использовать __builtin_isnan()и если да, то почему?

Я тестировал GCC 4.7.2 и 4.9.0 на x86-64 с -O2 а также -O3 оптимизация.

42

Решение

Смотря на <cmath> для libstdc ++, поставляемой с gcc 4.9, вы получите следующее:

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

constexpr функция может быть агрессивно встроена и, конечно, функция просто делегирует работу __builtin_isnan,

<math.h> заголовок не использует __builtin_isnanскорее он использует __isnan реализация, которая является своего рода долго вставлять здесь, но это строки 430 math.h на моей машине ™. Поскольку стандарт C99 требует использования макроса для isnan и др. (раздел 7.12 стандарта C99) «функция» определяется следующим образом:

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

Тем не менее, я не вижу причин, почему он не может использовать __builtin_isnan вместо __isnan так что я подозреваю, что это недосмотр. Как отмечает Марк Глисс в комментариях, есть соответствующий отчет об ошибке по аналогичной проблеме, используя isinf вместо isnan,

15

Другие решения