This fails the second static assert on vax-dec-netbsdelf: template<typename T> constexpr int cmp1(T x) noexcept { int ix = (bool) __builtin_isnan(x); return ix; } template<typename T> constexpr int cmp2(T x) noexcept { int ix = __builtin_isnan(x) ? 1 : 0; return ix; } constexpr double nan = __builtin_nan(""); static_assert( cmp1(nan) ); static_assert( cmp2(nan) ); extern const auto c1 = cmp1(nan); extern const auto c2 = cmp2(nan); $ gcc/cc1plus -quiet ~/tmp/ord.C /home/jwakely/tmp/ord.C:20:20: error: static assertion failed 20 | static_assert( cmp2(nan) ); | ~~~~^~~~~ If the failing static assert is commented out, the assembly code is: #NO_APP .file "ord.C" .text .section .rodata .align 2 .type _ZL3nan, @object .size _ZL3nan, 8 _ZL3nan: .long -32769 .long -1 .globl c1 .align 2 .type c1, @object .size c1, 4 c1: .long 1 .globl c2 .align 2 .type c2, @object .size c2, 4 c2: .zero 4 .ident "GCC: (GNU) 12.0.1 20220308 (experimental)" For some reason the cmp2 function returns zero. I'm using binutils configured with --target=vax-dec-netbsdelf and gcc configured with: /home/jwakely/src/gcc/configure --target vax-dec-netbsdelf --without-headers --with-newlib --disable-bootstrap --disable-nls --without-lto --without-isl --disable-libcc1 --disable-libsanitizer --disable-libitm --disable-libvtv --disable-libgomp --disable-libssp --enable-languages=c++,c --disable-libstdcxx-pch --disable-hosted-libstdcxx --prefix=/home/jwakely/gcc/vax I only did 'make all-gcc' and am running cc1plus from the build tree, as I don't have a sysroot for the target.
Confirmed with --target vax-dec-netbsdelf: $ ./cc1plus -quiet 104865.C 104865.C:20:20: error: static assertion failed 20 | static_assert( cmp2(nan) ); | ~~~~^~~~~
/* Accessor macros for format properties. */ #define MODE_HAS_NANS(MODE) \ (FLOAT_MODE_P (MODE) && FLOAT_MODE_FORMAT (MODE)->has_nans) ..... vax_f_format ... false, Hmm, -ffast-math has the same result (that is the assert happening) on any other target really.
Should `__builtin_nan' even compile on non-IEEE-754 FP targets?
They can still have NaNs.
Wrong question then. Should `__builtin_nan' even compile on non-IEEE-754 FP targets that don't have a qNaN? And I'll reply to myself. According to our manual: "-- Built-in Function: double __builtin_nan (const char *str) This is an implementation of the ISO C99 function 'nan'." and then according to ISO C99: "The nan functions return a quiet NaN, if available, with content indicated through tagp. If the implementation does not support quiet NaNs, the functions return zero." so firstly __builtin_isnan(__builtin_nan("")) is supposed to return 0 with the VAX target (because obviously 0.0 is not a NaN), and secondly the compiled program is wrong as `_ZL3nan' is supposed to be set to all-zeros (which is the representation of 0.0 datum with the VAX floating-point format), and then `c1' and `c2' must likewise be both 0. Both asserts are supposed to fail with the VAX target then (and similarly PDP-11, which has a similar FP format).
OK, maybe I should not have used __builtin_nan in the test. The bug is in the rest of the code though, isn't it? Replace the __builtin_nan with a function returning the same sNaN, does the test still fail? (I can't check myself right now).
Well, it's not clear to me whether the reserved operand as defined by the VAX floating-point architecture ought be considered an sNaN given that there is no qNaN. Also a reserved operand causes a fault with any FP instruction, even data moves (though one can move a reserved operand bit pattern with an integer move of the right width, observing that there is a single register file for both integer and FP arithmetic, and that of course FP operations can be directly performed on memory as well). In any case there's probably more than one bug here.