GCC claims to follow C99 Annex F when converting a floating value to an integer type when the integral part exceeds the range of the integer type (C99 6.3.1.4 and F.4). Annex F says that in this case the conversion raises the "invalid" floating-point exception. On powerpc64-linux and x86_64-linux, however, the instruction that is used to convert double to int converts to a 64-bit integer, not a 32-bit register, so the exception is not raised. On powerpc64-linux with -m64 the instruction is fctidz (floating convert to integer doubleword with round toward zero). If I replace that instruction with fctiwz (convert to integer word) in the .s file and compile that, the code behaves as expected. Here's a small test case: #include <fenv.h> extern void abort (void); double x = 4294967296.0; unsigned int i; int main () { #pragma STDC FENV_ACCESS ON feclearexcept (FE_ALL_EXCEPT); i = x; /* value exceeds the range of 32-bit int */ if (! fetestexcept (FE_INVALID)) abort (); return 0; } I see this behavior in all powerpc64-linux compilers I've checked from 3.2 through mainline. The exception is raised for tests compiled with -m32. This is a problem for applications that try to detect such invalid conversions after checking for __STDC_IEC_559__, which claims that the implementation conforms to Annex F. A possibly-related issue is that this macro is defined in a header file provided by glibc, not by GCC.
This is related to PR21360, although that one is about the result of an out-of-range conversion.
First we don't yet implement FENV_ACCESS. There is a bug about that.
Subject: Re: New: float to int conversion doesn't raise invalid exception On Fri, 19 May 2006, janis at gcc dot gnu dot org wrote: > GCC claims to follow C99 Annex F when converting a floating value to an integer It doesn't (in that it doesn't define __STDC_IEC_559__). But it should aim to do so (provided the user doesn't specify options such as -fno-trapping-math in this case). > A possibly-related issue is that this macro is defined in a header file > provided by glibc, not by GCC. That's a bug in the combination of glibc and GCC, requiring cooperation between them to fix. The macro must be defined from the start of the translation unit without any headers needing to be included; the same also applies to __STDC_ISO_10646__ which is definitely a property of the library. My suggested solution is still as at <http://gcc.gnu.org/ml/gcc/2004-05/msg01019.html>: an implicitly included header <stdc-predef.h> that is provided by the library, makes such definitions, *does not include other glibc headers such as features.h* (because the source file may define feature test macros later before it first explicitly includes a system header), and whose absence is silently ignored by the compiler (in order to support older glibc without the header).
This has been brought up to the glibc developers in the past: http://sourceware.org/ml/libc-alpha/2005-03/msg00196.html It's unfortunate that they don't agree that "an implementation" of C consists of a combination of products, and that unless they all support Annex F, the "implementation" doesn't support it and should not define __STDC_IEC_559__.
Note that fctidz is used because we are converting to unsigned. gcc uses fctiwz if converting to int. Of course, it isn't correct to simply replace fctidz with fctiwz.. To get this right, gcc would need to generate something like the following fctidz 0,0 stfd 0,temp_slot(1) ld 9,temp_slot(1) rldicl 0,9,0,32 cmpd 0,9 beq .+8 mtfsb1 23 with the last three insns being the extras needed to set the invalid operation. Conversion to unsigned int on ppc32 will also need some tweaks. Hmm, there we are using code generated by optabs.c (search for comment "For an unsigned conversion, there is one more way to do it.") Why doesn't this code always subtract off 2**(n-1), convert, then add 2**(n-1)? That way we'd get the invalid op bits set correctly.
Oh, I suppose rounding might change the result if we always subtract off 2**(n-1).
If the value doesn't fit then the result is undefined and doesn't matter; getting the invalid flag is what's important.
It looks like several improvements were installed since then. Can somebody perhaps retry with the 4.3 branch and trunk?
4.3.2-7 still has problems (even with -frounding-math). A more complete test can be found at: http://www.tybor.com/tflt2int.c
Still present in GCC 4.5.0 20090513.
*** Bug 30580 has been marked as a duplicate of this bug. ***
(In reply to Fred J. Tydeman from comment #9) > 4.3.2-7 still has problems (even with -frounding-math). > > A more complete test can be found at: > http://www.tybor.com/tflt2int.c I get 183 failures from that test with gcc 10 on x86_64-apple-darwin10