Search code examples
floating-pointclangx86-64floating-point-exceptions

Perfectly fine division throws floating point exception


I have a mystery floating point exception. I catch it by doing:

feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );

Then the second division (last line) in this code:

const float dx = other.px[ j ] - curx;    
const float dy = other.py[ j ] - cury;
const float dsqr = dx*dx + dy*dy;
ASSERTM( dsqr > 0.0f, "dx %f dy %f dsqr %f", dx, dy, dsqr ); 
const float dist = sqrtf( dsqr );                   
ASSERTM( dist > 0.0f, "dx %f dy %f dsqr %f dist %f", dx, dy, dsqr, dist );
LOGI( "dx %f dy %f dsqr %f dist %f", dx, dy, dsqr, dist );
const float dirx = dx / dist;      
const float diry = dy / dist;

Throws a SIGFPE as follows:

enter image description here

The divisor (printed out in console, and also printed by gdb) is 1.0839119 and numerator is -1.05979919 so I don't see what is wrong with that.

For extra weirdness:

  • Does not happen in -O0 debug build.
  • Does not happen if I run the app through valgrind

Compiler:

$ clang -v
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)

And compiler options:

clang++ -DXWIN -DLANDSCAPE -DUSECOREPROFILE -Dlinux -D_POSIX_C_SOURCE=199309L -D_DEFAULT_SOURCE -DAPPVER=1.00 -DLOGTAG=minimal -I/home/bram/src/stb/ -I/home/bram/include -I/public -I/home/bram/src/dutch-blunt/src -I/home/bram/apps/GBase/src -IPI -I/home/bram/src/ThreadTracer `/home/bram/bin/sdl2-config --cflags` -g -Wall -Wshadow -Wno-conversion -Wno-missing-braces -Wno-old-style-cast -Wno-unknown-pragmas -MMD -MP -O2 -std=c++11   -c -o PI/stars.o PI/stars.cpp

Why is this FPE happening? The only reason I could think of, is that even though it is a scalar division, clang generates a SIMD division. What if the other lanes in the XMM register contain zero denominators? Do SIMD divisions generate FPEs if any of the lanes divides by zero? If so, how can I ever trap FPEs?


Solution

  • Ths clang version 10 compiler option will make sure unused lanes do not cause FP exceptions:

    -ffp-exception-behavior=maytrap

    I've tested it, and it works: it prevents spurious floating point exceptions.

    Sadly, gcc (I tested with gcc-12) does not recognize the option:

    gcc: error: unrecognized command-line option ‘-ffp-exception-behavior=maytrap’