Summary: | 'std::numeric_limits< T >::signaling_NaN()' signaling-bit is incorrect for x86 32-bit. | ||
---|---|---|---|
Product: | gcc | Reporter: | Charles L. Wilcox <zxClhzAApX1EdJwQANqrjLERmFeURQVy> |
Component: | target | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | RESOLVED WONTFIX | ||
Severity: | normal | CC: | daniel.kruegler, rguenth, tschwinge, ubizjak |
Priority: | P3 | ||
Version: | 4.8.1 | ||
Target Milestone: | --- | ||
See Also: |
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71460 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58416 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56831 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 |
||
Host: | Target: | i686-pc-linux-gnu | |
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | ||
Attachments: |
C++ test program to extract and display the signaling-bit of a signaling-NaN and a quiet-NaN.
Updated test code to print out the full signaling and quiet NaN's values in hex. Expanded unit-test code to set signaling-NaN values via 'union' aliasing. |
I haven't checked your bit arithmetics, but I have checked the full bit patterns of the resulting NaNs in hex on my mingw-64 bit system. What I'm getting for are the following results: 1) gcc 4.7.2/4.9.0 20130519 (experimental) -m32: Signaling NaN's of "f" is 7fa00000 Quiet NaN's of "f" is 7fc00000 Signaling NaN's of "d" is 7ff4000000000000 Quiet NaN's of "d" is 7ff8000000000000 2) gcc 4.7.2/4.9.0 20130519 (experimental) -m64: Signaling NaN's of "f" is 7fa00000 Quiet NaN's of "f" is 7fc00000 Signaling NaN's of "d" is 7ff4000000000000 Quiet NaN's of "d" is 7ff8000000000000 All values look consistent with valid sNaN/qNaN patterns according to the ranges listed here: http://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html What are the full bit patterns that you get by printing the signaling_NaN.bits/quiet_NaN.bits values in hex? Created attachment 30239 [details]
Updated test code to print out the full signaling and quiet NaN's values in hex.
Daniel, Unfortunately, my initial machine, a laptop, decided to commit seppuku yesterday. Fortunately, the disk survived, I ported the code to another machine I have, and am still seeing similar results there. $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-5' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.7.2 (Debian 4.7.2-5) I updated my code to print out the full contents of the NaN values in hex. My machine produces the following output: $ g++ -Wall -Wextra test-signaling-nan.cpp -m32 $ ./a.out Signaling NaN for type "f" in hex is "7fe00000". Signaling NaN's signaling-bit status for type "f" is set to "true". Quiet NaN for type "f" in hex is "7fc00000". Quiet NaN's signaling-bit status for type "f" is set to "true". Signaling NaN for type "d" in hex is "7ffc000000000000". Signaling NaN's signaling-bit status for type "d" is set to "true". Quiet NaN for type "d" in hex is "7ff8000000000000". Quiet NaN's signaling-bit status for type "d" is set to "true". $ g++ -Wall -Wextra test-signaling-nan.cpp -m64 $ ./a.out Signaling NaN for type "f" in hex is "7fa00000". Signaling NaN's signaling-bit status for type "f" is set to "false". Quiet NaN for type "f" in hex is "7fc00000". Quiet NaN's signaling-bit status for type "f" is set to "true". Signaling NaN for type "d" in hex is "7ff4000000000000". Signaling NaN's signaling-bit status for type "d" is set to "false". Quiet NaN for type "d" in hex is "7ff8000000000000". Quiet NaN's signaling-bit status for type "d" is set to "true". The resulting values on 32-bit vs. 64-bit are different, and I believe the 64-bit values are the correct ones. (In reply to Charles L. Wilcox from comment #3) > Signaling NaN for type "f" in hex is "7fe00000". I agree, this one doesn't look right to me, because that looks indeed like a valid qNaN bit pattern only. > Quiet NaN for type "f" in hex is "7fc00000". OK. > Signaling NaN for type "d" in hex is "7ffc000000000000". Similar problem here: Only a qNaN > Quiet NaN for type "d" in hex is "7ff8000000000000". OK. > $ g++ -Wall -Wextra test-signaling-nan.cpp -m64 > Signaling NaN for type "f" in hex is "7fa00000". > Quiet NaN for type "f" in hex is "7fc00000". > Signaling NaN for type "d" in hex is "7ff4000000000000". > Quiet NaN for type "d" in hex is "7ff8000000000000". All OK. > The resulting values on 32-bit vs. 64-bit are different, and I believe the > 64-bit values are the correct ones. I agree. Just to clarify that this is neither a library neither a C++ front-end issue: <limits> just uses the various __builtin_nans* (In reply to Paolo Carlini from comment #5) > Just to clarify that this is neither a library neither a C++ front-end > issue: <limits> just uses the various __builtin_nans* Paolo, I guessed this was the case from what I could tell using the debugger, but I wanted some confirmation that I was correct. Should the "Component" be changed from C++ to something else? middle-end seems more appropriate. Richard, can you help me triaging this? Thanks in advance. FWIW, I tried this with g++ 4.8 on a 32-bit only system I have; it still produces erroneous sNaN values there: $ g++-4.8 -v Using built-in specs. COLLECT_GCC=g++-4.8 COLLECT_LTO_WRAPPER=/usr/lib/gcc/i486-linux-gnu/4.8/lto-wrapper Target: i486-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 4.8.1-1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 --with-arch-directory=i386 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-targets=all --enable-multiarch --with-arch-32=i586 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.8.1 (Debian 4.8.1-1) $ g++-4.8 -Wall -Wextra test-signaling-nan.cpp $ ./a.out Signaling NaN for type "f" in hex is "7fe00000". Signaling NaN's signaling-bit status for type "f" is set to "true". Quiet NaN for type "f" in hex is "7fc00000". Quiet NaN's signaling-bit status for type "f" is set to "true". Signaling NaN for type "d" in hex is "7ffc000000000000". Signaling NaN's signaling-bit status for type "d" is set to "true". Quiet NaN for type "d" in hex is "7ff8000000000000". Quiet NaN's signaling-bit status for type "d" is set to "true". So, given a month has gone by, should I expect any response or action on this bug-report? Maybe Uros can help. (In reply to Paolo Carlini from comment #10) > Maybe Uros can help. On an x86 target using the legacy x87 instructions and the 80-bit registers, a load of a 64-bit or 32-bit value in memory into the 80-bit registers counts as a format conversion and an signaling NaN input will turn into a quiet NaN in the register format. (In reply to Uroš Bizjak from comment #11) > (In reply to Paolo Carlini from comment #10) > > Maybe Uros can help. > > On an x86 target using the legacy x87 instructions and the 80-bit registers, > a load of a 64-bit or 32-bit value in memory into the 80-bit registers > counts as a format conversion and an signaling NaN input will turn into a > quiet NaN in the register format. Also, using -msse2 -mfpmath=sse on 32bit target won't help, since 32bit ABI mandates that FP values are returned in x87 register. Your test will work when compiled with "-msse2 -mfpmath=sse -mno-fp-ret-in-387". But note that -mno-fp-ret-in-387 is a compiler option that changes ABI. The ABI is just wrong for the underlying x87 hardware as far as NaNs are concerned. Thanks Uros, you are providing plenty of detaild which I largely ignored. Thus, realistically, do you think this issue is largely unfixable? (In reply to Paolo Carlini from comment #13) > Thanks Uros, you are providing plenty of detaild which I largely ignored. > Thus, realistically, do you think this issue is largely unfixable? This issue is unfortunately unfixable. x87 and x86-32 ABI are just not designed to handle all details of IEEE 754 standard. Ok, thanks. Created attachment 30487 [details]
Expanded unit-test code to set signaling-NaN values via 'union' aliasing.
Adding code to demonstrate how to generate a signaling-NaN using the existing ABI along with the "return through the x87 register" restriction.
Okay... so why not avoid the x87 restriction and use aliasing to load the correct value? I've updated my example to show how I was doing exactly this for some unit-test code I created. (In reply to Charles L. Wilcox from comment #17) > Okay... so why not avoid the x87 restriction and use aliasing to load the > correct value? Load to x87 stack? The very moment sNaN gets loaded (using fldl or flds) will be converted to qNaN. You can do some trick here (and the compiler can pass FP value in integer registers), but there is no guarantee that the value won't move through x87 stack registers. (In reply to Uroš Bizjak from comment #11) > On an x86 target using the legacy x87 instructions and the 80-bit registers, > a load of a 64-bit or 32-bit value in memory into the 80-bit registers > counts as a format conversion and an signaling NaN input will turn into a > quiet NaN in the register format. Does this mean if a 80-bit sNaN was generated and loaded into a register it was still have the signaling bit set correctly? And if so, could this value then be down-converted to a 32 or 64-bit float? In C++: float float32_snan const = static_cast< float >( std::numeric_limits< long double >::signaling_NaN() ); double float64_snan const = static_cast< double >( std::numeric_limits< long double >::signaling_NaN() ); Or, is the "cast" here a format conversion, causing the signaling NaN to convert to a quiet NAN? (In reply to Charles L. Wilcox from comment #19) > (In reply to Uroš Bizjak from comment #11) > > On an x86 target using the legacy x87 instructions and the 80-bit registers, > > a load of a 64-bit or 32-bit value in memory into the 80-bit registers > > counts as a format conversion and an signaling NaN input will turn into a > > quiet NaN in the register format. > > Does this mean if a 80-bit sNaN was generated and loaded into a register it > was still have the signaling bit set correctly? And if so, could this value 80-bit load is not considered as a format conversion, so signalling bit will be set correctly. > then be down-converted to a 32 or 64-bit float? In C++: > float float32_snan const > = static_cast< float >( std::numeric_limits< long double > >::signaling_NaN() ); > double float64_snan const > = static_cast< double >( std::numeric_limits< long double > >::signaling_NaN() ); > Or, is the "cast" here a format conversion, causing the signaling NaN to > convert to a quiet NAN? I don't know the c++ details, but compiler can spill the value out from the register stack using 32- or 64-bit float moves. In any case, signalling bit in x87 is unreliable and should not be used. *** Bug 56831 has been marked as a duplicate of this bug. *** |
Created attachment 30234 [details] C++ test program to extract and display the signaling-bit of a signaling-NaN and a quiet-NaN. $ g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-1ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --with-cloog --enable-cloog-backend=ppl --disable-cloog-version-check --disable-ppl-version-check --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) What I expect: For 'float' and 'double' types when 'std::numeric_traits< T >::is_iec559' is 'true', 'std::numeric_traits< T >::signaling_NaN()' should generate a IEEE-754 value whose sign bit is '0', exponent bits are all '1', the highest significand bit is '0', and some other significant bit(s) are '1'. What I observe: - x86 32-bit: all expectations are met, except that the highest significand bit is '1'. ( This implies it is a quiet-NaN, not a signaling-NaN. ) - x86 64-bit: all expectations are met. My evidence: Attached is a test C++ program that extracts the IEEE-754 signaling bit value of both a signaling-NaN and a quiet-NaN, for 'float' and 'double' types, and prints the results to console. When compiling with '-m32', I see the unexpected behavior; when compiling with '-m64', I see the expected behavior. Compiler flags / command-line: - x86 32-bit: g++ -m32 -Wall -Wextra test-signaling-nan.cpp - x86 64-bit: g++ -m64 -Wall -Wextra test-signaling-nan.cpp Compilation errors / warnings: None.