fenv.h vs the optimizer

Howdy all,

I've been playing around with programs that use the C11 fenv.h.

It seems that, currently, the LLVM compiler does not regard to the exception-flag side-effects of floating point operations?

When run on my macbook, the example code on FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW, FE_ALL_EXCEPT - cppreference.com does not print all the expected exceptions.

Other examples:

void foo() {
     printf("foo downward: %f\n", rint(0.5));
     printf("foo upward: %f\n", rint(0.5));

If compiled with optimization, only one call to rint() is made and the result is reused.

void bar(double a, double b) {
     a / b;
     printf("bar %f / %f is %sexact\n", a, b, fetestexcept(FE_INEXACT)? "in": "");

The compiler omits the divide as the result is unused. And so on.

Presumably this has never worked? And perhaps LLVM is no worse than other compilers in this regard?

Is there any appetite to fix it? What kind of changes would need to be made?



Presumably this has never worked? And perhaps LLVM is no worse than other compilers in this regard?

Correct, LLVM does not yet respect any of the floating point env stuff and clang does not support the related pragmas.

Is there any appetite to fix it? What kind of changes would need to be made?

It is likely to require new floating point operations and some auditing of the instructions. I think various people who were interested in Fortran support will need something similar, as the C99 floating point environment stuff was intended to make porting Fortran code easier.


LLVM has never really supported fenv.h:

Even if we added support for the rounding modes, we don’t support non-call exceptions either:

I think there is interest in addressing the rounding mode stuff, but less interest in modelling FP side effects. Medhi had some ideas around this.

Oops. Looks like I accidently dropped the mailing list when replying to this.

We’re in the process of trying to figure out a good way to harmonize FP exception handling and rounding with the related issues in vector masking. Obviously we don’t want to have completely different solutions for these closely related problems. We’re looking at ways to do something along the lines of Chandler’s proposal that will also handle the problem of false exceptions in masked vector lanes, but we want to make sure that whatever we do won’t limit the possibilities of optimizing FP code while correctly handling fenv access because we also care a lot about that.

BTW, I’m not using the royal we here. I mean to indicate that I’m working with other people here at Intel to put together something that isn’t half baked when we propose it. We were hoping to have a BOF session at the upcoming LLVM Dev Meeting to talk about this, but of course I’m happy to discuss it before then too.


I really like Chandler’s approach! By passing the state and status in and out as arguments and returns, rather than as side channels and side effects, the compiler will be able to do its normal goodness without breaking correctness :smiley:

I am a bit cautious when Chandler says that InstCombine should lower the intrinsics if it is default (i.e. round-nearest) and the flags are not used. It seems legitimate for that exact intrinsic to be used by developers who especially want round-nearest in code where they know the dynamic rounding mode may not be default…?

Here’s something to ponder: does exception trapping mean that the new intrinsic functions have side-effects? Not all targets support exception trapping. I believe ARM64 is an example mainstream target that doesn’t support exception traps. If a target doesn’t support trapping, or if the intrinsic doesn’t ask for it, then perhaps this allows the intrinsics to be const?

The standard C math functions (pow, rint, sqrt etc) are already intrinsics. Will these also be parameterised?

(I have been using Debian code search to find examples of fenv usage ‘in the wild’, and its very very sparse. However, there are a handful of examples where someone doing interval arithmetic or something, and in the cases hopefully we can parameterise the C math function intrinsics so backends can use explicit rounding ops if they have them.)