https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85811
Bug ID: 85811 Summary: Invalid optimization with fmax, fabs and nan Product: gcc Version: 8.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: mpeddie at gmail dot com Target Milestone: --- Created attachment 44139 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44139&action=edit Preprocessed source file I apologize in advance if I've chosen the wrong category for this bug; I have to choose a category and don't know what's correct. The output from my small test program varies depending on whether I enable optimizations with -O. The un-preprocessed program is the following (preprocessed output attached): #include <math.h> #include <stdio.h> #include <stdlib.h> int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { const double negval = -1.0; const double nanval = 0.0 / 0.0; const double val = fmax(negval, nanval); const double absval = fabs(val); printf("fabs(%.16e) = %.16e\n", val, absval); return absval >= 0 ? 0 : 1; } With optimizations enabled, this prints fabs(-1.0000000000000000e+00) = -1.0000000000000000e+00 and returns 1. This result is wrong (the absolute value must be positive). Without optimizations, it prints fabs(1.0000000000000000e+00) = 1.0000000000000000e+00 and returns 0 as expected. If I make the arguments to fmax() depend on inputs, for example the value of argc, the program behaves correctly. If I call fmin() instead of fmax(), the program behaves correctly. If neither of the arguments to fmax() is NaN, the program behaves correctly; the correct behavior happens if one argument is -NaN, INFINITY or -INFINITY. The order of arguments to fmax() does not affect the result of the program. If I look at the generated assembly, substituting fmin() for fmax() in the test program results in an andpd instruction immediately after fmin() that isn't emitted when fmax() is called. The attached file test.i is the preprocessed source file. The test program compiles without errors or warnings and never triggers the undefined-behavior sanitizer. I've observed the same problem with gcc version 7.3.0 and 6.4.0 for x86_64 as well as gcc version 6.3.0 for arm32. I don't see the problem with gcc version 5.5.0 for x86_64. Below is the command-line invocation of gcc along with its complete output. gcc-8 -v -save-temps -O -Wall -Wextra -Werror -fsanitize=undefined -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations -lm test.c -o test Using built-in specs. COLLECT_GCC=gcc-8 COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 8.1.0-3' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 8.1.0 (Debian 8.1.0-3) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-O' '-Wall' '-Wextra' '-Werror' '-fsanitize=undefined' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' 'test' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu test.c -mtune=generic -march=x86-64 -Wall -Wextra -Werror -fsanitize=undefined -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations -O -fpch-preprocess -o test.i ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-linux-gnu/8/include /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/8/include-fixed /usr/include/x86_64-linux-gnu /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-O' '-Wall' '-Wextra' '-Werror' '-fsanitize=undefined' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' 'test' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed test.i -quiet -dumpbase test.c -mtune=generic -march=x86-64 -auxbase test -O -Wall -Wextra -Werror -version -fsanitize=undefined -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations -o test.s GNU C17 (Debian 8.1.0-3) version 8.1.0 (x86_64-linux-gnu) compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C17 (Debian 8.1.0-3) version 8.1.0 (x86_64-linux-gnu) compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: bbc65a5a9118b9b79402871f4ead4543 COLLECT_GCC_OPTIONS='-v' '-save-temps' '-O' '-Wall' '-Wextra' '-Werror' '-fsanitize=undefined' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' 'test' '-mtune=generic' '-march=x86-64' as -v --64 -o test.o test.s GNU assembler version 2.30 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.30 COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-O' '-Wall' '-Wextra' '-Werror' '-fsanitize=undefined' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' 'test' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/8/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper -plugin-opt=-fresolution=test.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o test /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/8/../../.. -lm test.o -lubsan -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/8/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-v' '-save-temps' '-O' '-Wall' '-Wextra' '-Werror' '-fsanitize=undefined' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' 'test' '-mtune=generic' '-march=x86-64'