1

I'm writing a C function float foo(float x) which manipulates a floating-point value. It so happens, that I can guarantee the function will only ever be called with finite values - neither NaN's, nor +inf, nor -inf. Is it possible to "tell" this to the compiler (without actually doing runtime work which ensures it, like comparing, or zeroing bits and such)? For it to be able to optimize the code based on that assumption?

Notes:

  • I'm assuming this answer would be compiler-specific, so let's focus on GCC, clang and MSVC.
  • I might also be able to guarantee the values are not denormals.
  • It would help if your answer could regard other floating-point types: _Float16/float16_t, double, long double.
4
  • Effectively it does compile on the basis that the number is valid FP IEE754. It is really the denorms arising from borderline underflow that you should be worried about - they can cripple performance code if they arise in significant numbers. See for example this on MS erfc implementation slowness. Enabling fastmath effectively makes the assumption that Nans and Infs can be safely ignored although if they do occur the hardware still deals with them. Commented Jul 20 at 15:35
  • @MartinBrown: Ah, but I don't want to enable "fast math" - I want maximum precision for mathematical functions; but I also want to benefit from my specific knowledge. Also, I'm asking for a local hint, not something global. Commented Jul 20 at 15:45
  • @einpoklum "... without actually doing runtime work" --> does you function really behave noticeable slower without that check? Losing 5%, .5%, ? Commented Jul 21 at 5:05
  • @chux : If my function runs once, then no. If it is applied for every element in a large array or matrix, then yes. Of course, depends on what's the 100%. I'm experiemnting on one aspect of a computation which involves several kernels, so even if I reduce execution time of one of them to 0, I still only save a few percentage points of my overall processing time. Anyway, the question is about the principle. Commented Jul 21 at 9:03

2 Answers 2

5
Compiler Compile-time Assumption In-Code Hint Denormal Control
GCC ≥13 -ffinite-math-only stop excution using __builtin_unreachable() Use FTZ/DAZ or -ffast-math
Clang -ffinite-math-only __builtin_assume(), __attribute__((assume)) Same as GCC
MSVC /fp:fast __assume(_finite(x)) Flush-to-zero set via flags or code

Examples:

#include <math.h>

float foo(float x) {
    __builtin_assume(isfinite(x));
    // or: __builtin_assume(!isnan(x) && x != INFINITY && x != -INFINITY);

    // Now x is assumed finite
    return x * 2.0f;
}
__attribute__((assume("finite-arg"))) float foo(float x);
clang -O2 -ffinite-math-only -fno-trapping-math foo.c -o foo
gcc  -O2 -ffinite-math-only -fno-trapping-math foo.c -o foo
float foo(float x) {
    __assume(_finite(x));
    return x * 2.0f;
}
Sign up to request clarification or add additional context in comments.

Comments

4

You can tell GCC and Clang any condition you can express in code is impossible by using their __builtin_unreachable feature:

#include <math.h>

float foo(float x)
{
    if (!isfinite(x))
        __builtin_unreachable();
    // The compiler may conclude x is not infinite or NaN when foo is called.
    …
}

Using __builtin_unreachable tells the compiler code will never reach that point. Therefore, the compiler may assume the conditions needed to reach that point are false.

1 Comment

Upvoted as well, since if a compiler (not the big-3) has an unreachable hint, but not an assume hint, you've given us a way to "implement" the latter using the former.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.