2

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?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Bram
  • 7,440
  • 3
  • 52
  • 94
  • Bram, I would say you were correct, the divps doc says `Performs a SIMD divide of the four, eight or sixteen packed single-precision floating-point values in the first source operand (the second operand) by the four, eight or sixteen packed single-precision floating-point values in the second source operand (the third operand).` This may be a compiler bug. – paxdiablo Dec 31 '18 at 00:05
  • 1
    I would think that, if it were going to use simd for two divisions, it would ensure the others (forced ones) would be valid. Maybe they never tested it with exceptions enabled. I'd suggest raising this on the clang bug site and see what they say. – paxdiablo Dec 31 '18 at 00:08
  • 1
    `gcc` and `clang` basically don't support non-default floating-point environments. You can try `-fsanitize=float-divide-by-zero` instead. – Tavian Barnes Dec 31 '18 at 00:10

1 Answers1

1

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’

Bram
  • 7,440
  • 3
  • 52
  • 94