Bug 2582 - implicit cast assignment from int to float problem with x86
Summary: implicit cast assignment from int to float problem with x86
Status: RESOLVED DUPLICATE of bug 323
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2001-04-18 14:36 UTC by jmurray
Modified: 2003-07-06 19:16 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description jmurray 2001-04-18 14:36:01 UTC
We had an extensive discussion with a number of different groups on this problem but never found a good solution. We have tested this on Win98 w/ a Borland Compiler, on several versions of Linux with several versions of GCC, and on several RISC based workstations with GCC and other compilers.

This routine works as anticipated on all RISC machines regardless of the compiler but fails on all x86 based machines (that we have) with GCC. If we declare the variables volatile it works. My problem is that I have 600000 lines of code and I can't declare variables volatile everywhere or find all of the potential locations of this problem.

A routine that demonstrates the problem is below. I can provide several other examples. It was suggested previously that the floating point unit was being put into truncate mode from its default round-to mode. I don't know how to overcome this without major ramifications on the code baseline.

A summary of the routine is:

1. Assign some values to some integer variables.
2. Assign a floating point value from the division of two cast integers.
3. Assign a floating point value from the multiplication of two floats.
4. Assign an integer from a cast of a floating point product.
5. Assign an integer from a cast of a floating point number.

Result:

This is equiv to num = .35 * 20

3 results in: 7.0000000000 (actually probably 6.999999?rounded to 7.00000000)
4 results in: 6 <------- PROBLEM WITH INPLACE ASSIGNMENT
5 results in: 7 (correct answer)

Example routine:
-------------------------------------------------------
#include <stdio.h>

int main(void) {

  /* Assign some values to ints */
  int iaa = 28;
  int ibb = 80;
  int icc = 20;

  int imm, immO;
  float fll;
  float ftmp;

  fll = (float)iaa / (float)ibb;

  imm = ftmp = fll * (float)icc;

  printf("Direct assign float to float = %.10f\n", ftmp);
  printf(" Inplace assign float to int = %d\n", imm);

  immO = ftmp;
  printf("  Direct assign float to int = %d\n", immO);

  return(0);
}
-------------------------------------------------------

We can not find all of the instances of this problem and often it is undetectable in many of the normalization processes of our systems. However, the results are wrong and lead to the wrong solution.

Release:
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)

Environment:
Red Hat Linux 6.2 w/ the Linux 2.2.18 Kernel
However, this is present on all versions of Linux for x86 that we have found. We have tested on single processor, dual processor, quad processor, and octal processor with the 2.2.xx kernels and the 2.4.xx kernels and several versions of gcc and g++.

uname -a results:
Linux compaq1a 2.2.18 #1 SMP Fri Apr 6 14:55:49 EDT 2001 i686 unknown.

How-To-Repeat:
#include <stdio.h>

int main(void) {

  /* Assign some values to ints */
  int iaa = 28;
  int ibb = 80;
  int icc = 20;

  int imm, immO;
  float fll;
  float ftmp;

  fll = (float)iaa / (float)ibb;

  imm = ftmp = fll * (float)icc;

  printf("Direct assign float to float = %.10f\n", ftmp);
  printf(" Inplace assign float to int = %d\n", imm);

  immO = ftmp;
  printf("  Direct assign float to int = %d\n", immO);

  return(0);
}
Comment 1 jmurray 2001-04-18 14:36:01 UTC
Fix:
A fix is to declare the variables volatile which ultimately changes the output assembly. Alternately, you can program to force all intermediate variables to be set to an appropriate type before truncation. This is difficult for existing baselines and inplace checks.
Comment 2 jmurray 2001-04-18 18:44:08 UTC
From: Joe Murray <jmurray@dsrnet.com>
To: "'gcc-gnats@gcc.gnu.org'" <gcc-gnats@gcc.gnu.org>,
   Joe Murray
	 <jmurray@dsrnet.com>, nobody@gcc.gnu.org
Cc: gcc-prs@gcc.gnu.org, gcc-bugs@gcc.gnu.org
Subject: RE: c/2582: implicit cast assignment from int to float problem wi
	th x86
Date: Wed, 18 Apr 2001 18:44:08 -0400

 Note: Don't compile with any optimization because it precomputes all of the
 values and masks the problem. i.e. don't use any flavor of -O
 
 Joe.
 
 -----Original Message-----
 From: jmurray@dsrnet.com [mailto:jmurray@dsrnet.com]
 Sent: Wednesday, April 18, 2001 5:30 PM
 To: nobody@gcc.gnu.org
 Cc: gcc-prs@gcc.gnu.org; gcc-bugs@gcc.gnu.org
 Subject: c/2582: implicit cast assignment from int to float problem with
 x86
 
 
 
 >Number:         2582
 >Category:       c
 >Synopsis:       implicit cast assignment from int to float problem with x86
 >Confidential:   no
 >Severity:       serious
 >Priority:       medium
 >Responsible:    unassigned
 >State:          open
 >Class:          wrong-code
 >Submitter-Id:   net
 >Arrival-Date:   Wed Apr 18 14:36:01 PDT 2001
 >Closed-Date:
 >Last-Modified:
 >Originator:     Joseph Murray
 >Release:        gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2
 release)
 >Organization:
 >Environment:
 Red Hat Linux 6.2 w/ the Linux 2.2.18 Kernel
 However, this is present on all versions of Linux for x86 that we have
 found. We have tested on single processor, dual processor, quad processor,
 and octal processor with the 2.2.xx kernels and the 2.4.xx kernels and
 several versions of gcc and g++.
 
 uname -a results:
 Linux compaq1a 2.2.18 #1 SMP Fri Apr 6 14:55:49 EDT 2001 i686 unknown.
 >Description:
 We had an extensive discussion with a number of different groups on this
 problem but never found a good solution. We have tested this on Win98 w/ a
 Borland Compiler, on several versions of Linux with several versions of GCC,
 and on several RISC based workstations with GCC and other compilers.
 
 This routine works as anticipated on all RISC machines regardless of the
 compiler but fails on all x86 based machines (that we have) with GCC. If we
 declare the variables volatile it works. My problem is that I have 600000
 lines of code and I can't declare variables volatile everywhere or find all
 of the potential locations of this problem.
 
 A routine that demonstrates the problem is below. I can provide several
 other examples. It was suggested previously that the floating point unit was
 being put into truncate mode from its default round-to mode. I don't know
 how to overcome this without major ramifications on the code baseline.
 
 A summary of the routine is:
 
 1. Assign some values to some integer variables.
 2. Assign a floating point value from the division of two cast integers.
 3. Assign a floating point value from the multiplication of two floats.
 4. Assign an integer from a cast of a floating point product.
 5. Assign an integer from a cast of a floating point number.
 
 Result:
 
 This is equiv to num = .35 * 20
 
 3 results in: 7.0000000000 (actually probably 6.999999?rounded to
 7.00000000)
 4 results in: 6 <------- PROBLEM WITH INPLACE ASSIGNMENT
 5 results in: 7 (correct answer)
 
 Example routine:
 -------------------------------------------------------
 #include <stdio.h>
 
 int main(void) {
 
   /* Assign some values to ints */
   int iaa = 28;
   int ibb = 80;
   int icc = 20;
 
   int imm, immO;
   float fll;
   float ftmp;
 
   fll = (float)iaa / (float)ibb;
 
   imm = ftmp = fll * (float)icc;
 
   printf("Direct assign float to float = %.10f\n", ftmp);
   printf(" Inplace assign float to int = %d\n", imm);
 
   immO = ftmp;
   printf("  Direct assign float to int = %d\n", immO);
 
   return(0);
 }
 -------------------------------------------------------
 
 We can not find all of the instances of this problem and often it is
 undetectable in many of the normalization processes of our systems. However,
 the results are wrong and lead to the wrong solution.
 >How-To-Repeat:
 #include <stdio.h>
 
 int main(void) {
 
   /* Assign some values to ints */
   int iaa = 28;
   int ibb = 80;
   int icc = 20;
 
   int imm, immO;
   float fll;
   float ftmp;
 
   fll = (float)iaa / (float)ibb;
 
   imm = ftmp = fll * (float)icc;
 
   printf("Direct assign float to float = %.10f\n", ftmp);
   printf(" Inplace assign float to int = %d\n", imm);
 
   immO = ftmp;
   printf("  Direct assign float to int = %d\n", immO);
 
   return(0);
 }
 >Fix:
 A fix is to declare the variables volatile which ultimately changes the
 output assembly. Alternately, you can program to force all intermediate
 variables to be set to an appropriate type before truncation. This is
 difficult for existing baselines and inplace checks.
 >Release-Note:
 >Audit-Trail:
 >Unformatted:

Comment 3 jmurray 2001-04-23 12:42:43 UTC
From: Joe Murray <jmurray@dsrnet.com>
To: "'gcc-gnats@gcc.gnu.org'" <gcc-gnats@gcc.gnu.org>
Cc:  
Subject: RE: c/2582: implicit cast assignment from int to float problem wi
	th x86
Date: Mon, 23 Apr 2001 12:42:43 -0400

 All,
 
 Intel has provided the following explanation. Is there a flag in GCC that
 may do something similar? Is there a mechanism that supports forcing a
 register assignment when an exectuable is run?
 
 Intel response:
 
 Hi  Joseph,
 
 Here's what we've found.
 
 When running C language on Intel processors, the most popular compilers
 including Microsoft* Visual C++, Borland C, Turbo C and GNU would encounter
 rounding errors when doing floating point calculations. 
 
 The floating point unit located within the processor has 4 rounding modes
 (round to nearest, round down, round up and truncate) and 3 precision modes
 (24-bit, 53-bit and 64-bit). The default mode for Intel processors is round
 to nearest. Unfortunately, the rounding mode would get changed to truncate,
 resulting in a round-off error.
 
 The easiest solution would be to add a few lines of inline assembly that
 would change the round mode to round to nearest.
 
 short example;
 
 //Loads the FPU Control register to X. 
 _asm
 {
   fstsw ax
   mov x,ax
 }
 
 //Perform a bitwise OR to change rounding mode (bit 10-11) to "To nearest
 (00). //48D=0000001100000000B
 //For more information on the FPU control reference refer to the Software
 Developer's Manual
 x=x|48;
 
 //Takes X back to the FPU Control Register
 _asm
 {
  fldcw x;
 }
 
 Randy S.
 Intel(R) Technical Support Engineer
 *Other names and brands may be claimed as the property of others.
 
 
 -----Original Message-----
 From: gcc-gnats@gcc.gnu.org [mailto:gcc-gnats@gcc.gnu.org]
 Sent: Wednesday, April 18, 2001 5:36 PM
 To: jmurray@dsrnet.com
 Subject: Re: c/2582: implicit cast assignment from int to float problem
 with x86
 
 
 Thank you very much for your problem report.
 It has the internal identification `c/2582'.
 The individual assigned to look at your
 report is: unassigned. 
 
 >Category:       c
 >Responsible:    unassigned
 >Synopsis:       implicit cast assignment from int to float problem with x86
 >Arrival-Date:   Wed Apr 18 14:36:01 PDT 2001
Comment 4 Neil Booth 2001-11-03 11:46:09 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: Confirmed.  I'm not sure if it's a bug or not, but I suspect
    it is.
Comment 5 Jan Hubicka 2002-10-10 11:46:33 UTC
State-Changed-From-To: analyzed->closed
State-Changed-Why: The extended precision is property of the i386 hardware and valid according to c99. see FLT_EVAL_MODE
Comment 6 Andrew Pinski 2003-07-06 19:16:11 UTC
Reopening bug so it can be marked as a dup of ...
Comment 7 Andrew Pinski 2003-07-06 19:16:23 UTC
bug 323, which is the master bug for excessive precision.

*** This bug has been marked as a duplicate of 323 ***