Bug 36578 - cast to long double not taken into account when result stored to a double
Summary: cast to long double not taken into account when result stored to a double
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.3.1
: P3 normal
Target Milestone: 4.4.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2008-06-19 14:19 UTC by Vincent Lefèvre
Modified: 2008-10-29 17:12 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-06-21 16:41:36


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2008-06-19 14:19:16 UTC
The following program shows that the casts to long double are not taken into account when the result to stored to a variable of type double. This bug occurs with gcc from 3.4 to 4.3.1, but didn't occur with gcc 3.3.

The bug can be reproduced on a Linux/x86_64 machine (i.e. where the "double" type corresponds to the IEEE-754 double precision and the "long double" type corresponds to the traditional x86 extended precision) with the arguments:
  4294967219 4294967429

(these arguments allow the double rounding effect to be visible).

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char **argv)
{
  double a, b, c, d, e;
  long double al, bl, dl, el;

  if (argc != 3)
    exit (1);

  a = atof (argv[1]);
  b = atof (argv[2]);
  al = a;
  bl = b;

  c = a * b;
  d = (long double) a * (long double) b;
  e = al * bl;
  dl = (long double) a * (long double) b;
  el = al * bl;

  printf ("a  =  %.0f\n", a);
  printf ("b  =  %.0f\n", b);
  printf ("c  =  %.0f\n", c);
  printf ("d  =  %.0f\n", d);
  printf ("e  =  %.0f\n", e);
  printf ("dl =  %.0Lf\n", dl);
  printf ("el =  %.0Lf\n", el);

  return 0;
}

Incorrect result (with gcc 3.4 to gcc 4.3.1):
a  =  4294967219
b  =  4294967429
c  =  18446744314227707904
d  =  18446744314227707904
e  =  18446744314227712000
dl =  18446744314227709952
el =  18446744314227709952

Correct result (as given by gcc 3.3) is the same except:
d  =  18446744314227712000

Note: I compiled with the options -std=c99 -Wall -pedantic.
Comment 1 Vincent Lefèvre 2008-06-19 14:37:00 UTC
To make things clear, perhaps I should have added:

#if __STDC__ == 1 && __STDC_VERSION__ >= 199901 && defined(__STDC_IEC_559__)
#pragma STDC FP_CONTRACT OFF
  printf ("__STDC_IEC_559__ defined:\n"
          "The implementation shall conform to the IEEE-754 standard.\n"
          "FLT_EVAL_METHOD is %d (see ISO/IEC 9899, 5.2.4.2.2#7).\n\n",
          (int) FLT_EVAL_METHOD);
#endif

which outputs:

__STDC_IEC_559__ defined:
The implementation shall conform to the IEEE-754 standard.
FLT_EVAL_METHOD is 0 (see ISO/IEC 9899, 5.2.4.2.2#7).

So, one can't even say that the value of d is correct because it is the same as the exact result rounded to double precision. The fact that the double rounding doesn't occur is a bug here.
Comment 2 Richard Biener 2008-06-21 16:41:36 UTC
Testcase

double foo (double x, double y)
{
  return (long double)x * (long double)y;
}

where we fold the multiplication to x * y.  This is only ok with
-funsafe-math-optimizations (like any other conversions removing
FP operations).  It is of course also ok if we for some reason
know that x * y is exactly representable in both double and
long double.

It is convert_to_real doing this optimization.
Comment 3 joseph@codesourcery.com 2008-06-21 16:58:42 UTC
Subject: Re:  cast to long double not taken into account
 when result stored to a double

On Sat, 21 Jun 2008, rguenth at gcc dot gnu dot org wrote:

> It is convert_to_real doing this optimization.

convert_to_real is also responsible for the problematic conversions in 
bug 35202.  I didn't try to argue the double rounding issues for those 
conversions, only the errno issue, since I don't have an example for the 
double rounding affecting those function call conversions (and right now 
implementations of many of the functions will not typically be correctly 
rounding - but that could change if C1x follows the new IEEE 754 
revision's recommendation of many more correctly rounded functions).  But 
it is potentially an issue for the conversions of function calls as well 
as the plain arithmetic example of this bug.

Comment 4 Joseph S. Myers 2008-10-29 17:06:29 UTC
Subject: Bug 36578

Author: jsm28
Date: Wed Oct 29 17:05:42 2008
New Revision: 141432

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=141432
Log:
	PR middle-end/36578
	* convert.c (convert_to_real): Do not optimize conversions of
	binary arithmetic operations between binary and decimal
	floating-point types.  Consider mode of target type in determining
	decimal type for arithmetic.  Unless
	flag_unsafe_math_optimizations, do not optimize binary conversions
	where this may change rounding behavior.
	* real.c (real_can_shorten_arithmetic): New.
	* real.h (real_can_shorten_arithmetic): Declare.

testsuite:
	* gcc.dg/dfp/convert-bfp-13.c, gcc.dg/dfp/convert-bfp-14.c,
	gcc.dg/dfp/convert-dfp-fold-2.c, gcc.target/i386/pr36578-1.c,
	gcc.target/i386/pr36578-2.c: New tests.

Added:
    trunk/gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c
    trunk/gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c
    trunk/gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c
    trunk/gcc/testsuite/gcc.target/i386/pr36578-1.c
    trunk/gcc/testsuite/gcc.target/i386/pr36578-2.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/convert.c
    trunk/gcc/real.c
    trunk/gcc/real.h
    trunk/gcc/testsuite/ChangeLog

Comment 5 Joseph S. Myers 2008-10-29 17:12:09 UTC
Fixed for 4.4.
Comment 6 Janis Johnson 2009-02-25 22:09:16 UTC
Subject: Bug 36578

Author: janis
Date: Wed Feb 25 22:08:55 2009
New Revision: 144436

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=144436
Log:
2009-02-25  Janis Johnson  <janis187@us.ibm.com>

gcc/
	Backport from mainline:
	2008-10-29  Joseph Myers  <joseph@codesourcery.com>

	PR middle-end/36578
	* convert.c (convert_to_real): Do not optimize conversions of
	binary arithmetic operations between binary and decimal
	floating-point types.  Consider mode of target type in determining
	decimal type for arithmetic.  Unless
	flag_unsafe_math_optimizations, do not optimize binary conversions
	where this may change rounding behavior.
	* real.c (real_can_shorten_arithmetic): New.
	* real.h (real_can_shorten_arithmetic): Declare.

gcc/testsuite/
	Backport from mainline:
	2008-10-29  Joseph Myers  <joseph@codesourcery.com>

	PR middle-end/36578
	* gcc.dg/dfp/convert-bfp-13.c, gcc.dg/dfp/convert-bfp-14.c,
	gcc.dg/dfp/convert-dfp-fold-2.c, gcc.target/i386/pr36578-1.c,
	gcc.target/i386/pr36578-2.c: New tests.

Added:
    branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c
    branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c
    branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c
    branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/pr39034.c
    branches/gcc-4_3-branch/gcc/testsuite/gcc.target/i386/pr36578-1.c
    branches/gcc-4_3-branch/gcc/testsuite/gcc.target/i386/pr36578-2.c
Modified:
    branches/gcc-4_3-branch/gcc/ChangeLog
    branches/gcc-4_3-branch/gcc/convert.c
    branches/gcc-4_3-branch/gcc/real.c
    branches/gcc-4_3-branch/gcc/real.h
    branches/gcc-4_3-branch/gcc/testsuite/ChangeLog