Bug 27682 - float to int conversion doesn't raise invalid exception
Summary: float to int conversion doesn't raise invalid exception
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.0.4
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 30580 (view as bug list)
Depends on:
Blocks: 16989
  Show dependency treegraph
 
Reported: 2006-05-19 16:07 UTC by Janis Johnson
Modified: 2024-04-24 06:51 UTC (History)
7 users (show)

See Also:
Host:
Target: powerpc64-linux, x86_64-linux
Build:
Known to work:
Known to fail:
Last reconfirmed: 2006-05-29 02:48:03


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Janis Johnson 2006-05-19 16:07:27 UTC
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.
Comment 1 Janis Johnson 2006-05-19 16:13:27 UTC
This is related to PR21360, although that one is about the result of an out-of-range conversion.
Comment 2 Andrew Pinski 2006-05-19 16:21:58 UTC
First we don't yet implement FENV_ACCESS.  There is a bug about that.
Comment 3 jsm-csl@polyomino.org.uk 2006-05-19 16:35:56 UTC
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).

Comment 4 Janis Johnson 2006-05-19 17:25:13 UTC
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__.
Comment 5 Alan Modra 2006-05-29 02:48:03 UTC
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.
Comment 6 Alan Modra 2006-05-29 02:52:03 UTC
Oh, I suppose rounding might change the result if we always subtract off 2**(n-1).
Comment 7 Janis Johnson 2006-05-30 16:59:42 UTC
If the value doesn't fit then the result is undefined and doesn't matter; getting the invalid flag is what's important.
Comment 8 Bernhard Reutner-Fischer 2008-06-24 08:22:46 UTC
It looks like several improvements were installed since then. Can somebody perhaps retry with the 4.3 branch and trunk?
Comment 9 Fred J. Tydeman 2009-01-31 20:16:44 UTC
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
Comment 10 Ben Elliston 2009-05-14 03:46:48 UTC
Still present in GCC 4.5.0 20090513.
Comment 11 Andrew Pinski 2010-10-05 18:30:07 UTC
*** Bug 30580 has been marked as a duplicate of this bug. ***
Comment 12 Eric Gallager 2019-09-26 04:52:55 UTC
(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