Как заставить GCC предположить, что выражение с плавающей точкой неотрицательно?

В некоторых случаях вы знаете, что определенное выражение с плавающей точкой всегда будет неотрицательным. Например, при вычислении длины вектора sqrt(a[0]*a[0] + ... + a[N-1]*a[N-1]) (примечание: я знаю о std::hypot, это не имеет отношения к вопросу), а выражение под квадратным корнем имеет вид явно не отрицательный. Однако GCC выводит следующую сборку для sqrt(x*x):

        mulss   xmm0, xmm0
        pxor    xmm1, xmm1
        ucomiss xmm1, xmm0
        ja      .L10
        sqrtss  xmm0, xmm0
        ret
.L10:
        jmp     sqrtf

То есть он сравнивает результат x*x с нулем, и если результат неотрицательный, он выполняет инструкцию sqrtss, в противном случае он вызывает sqrtf.

Итак, мой вопрос: как я могу заставить GCC предположить, что x*x всегда неотрицателен, так что он пропускает сравнение и вызов sqrtf, без записи встроенной сборки?

Я хочу подчеркнуть, что меня интересует локальное решение, а не такие вещи, как -ffast-math, -fno-math-errno или -ffinite-math-only (хотя они действительно решают проблему, благодаря ks1322, Гарольду, и Эрик Постпищил в комментариях).

Кроме того, «заставить GCC предполагать, что x*x неотрицателен», следует интерпретировать как assert(x*x >= 0.f), так что это также исключает случай, когда x*x является NaN.

Я в порядке с решениями для компиляторов, платформ, процессоров и т. Д.

14
задан Peter Cordes 27 August 2019 в 12:54
поделиться