re PR middle-end/36578 (cast to long double not taken into account when result stored to a double)
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. From-SVN: r141432
This commit is contained in:
parent
669eeb28ea
commit
20ded7a68b
10 changed files with 186 additions and 5 deletions
|
@ -1,3 +1,15 @@
|
|||
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.
|
||||
|
||||
2008-10-29 Bernd Schmidt <bernd.schmidt@analog.com>
|
||||
|
||||
* config/bfin/bfin-protos.h (WA_05000257, WA_05000283, WA_05000315,
|
||||
|
|
|
@ -263,18 +263,22 @@ convert_to_real (tree type, tree expr)
|
|||
tree arg1 = strip_float_extensions (TREE_OPERAND (expr, 1));
|
||||
|
||||
if (FLOAT_TYPE_P (TREE_TYPE (arg0))
|
||||
&& FLOAT_TYPE_P (TREE_TYPE (arg1)))
|
||||
&& FLOAT_TYPE_P (TREE_TYPE (arg1))
|
||||
&& DECIMAL_FLOAT_TYPE_P (itype) == DECIMAL_FLOAT_TYPE_P (type))
|
||||
{
|
||||
tree newtype = type;
|
||||
|
||||
if (TYPE_MODE (TREE_TYPE (arg0)) == SDmode
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == SDmode)
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == SDmode
|
||||
|| TYPE_MODE (type) == SDmode)
|
||||
newtype = dfloat32_type_node;
|
||||
if (TYPE_MODE (TREE_TYPE (arg0)) == DDmode
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == DDmode)
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == DDmode
|
||||
|| TYPE_MODE (type) == DDmode)
|
||||
newtype = dfloat64_type_node;
|
||||
if (TYPE_MODE (TREE_TYPE (arg0)) == TDmode
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == TDmode)
|
||||
|| TYPE_MODE (TREE_TYPE (arg1)) == TDmode
|
||||
|| TYPE_MODE (type) == TDmode)
|
||||
newtype = dfloat128_type_node;
|
||||
if (newtype == dfloat32_type_node
|
||||
|| newtype == dfloat64_type_node
|
||||
|
@ -292,7 +296,32 @@ convert_to_real (tree type, tree expr)
|
|||
newtype = TREE_TYPE (arg0);
|
||||
if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
|
||||
newtype = TREE_TYPE (arg1);
|
||||
if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype))
|
||||
/* Sometimes this transformation is safe (cannot
|
||||
change results through affecting double rounding
|
||||
cases) and sometimes it is not. If NEWTYPE is
|
||||
wider than TYPE, e.g. (float)((long double)double
|
||||
+ (long double)double) converted to
|
||||
(float)(double + double), the transformation is
|
||||
unsafe regardless of the details of the types
|
||||
involved; double rounding can arise if the result
|
||||
of NEWTYPE arithmetic is a NEWTYPE value half way
|
||||
between two representable TYPE values but the
|
||||
exact value is sufficiently different (in the
|
||||
right direction) for this difference to be
|
||||
visible in ITYPE arithmetic. If NEWTYPE is the
|
||||
same as TYPE, however, the transformation may be
|
||||
safe depending on the types involved: it is safe
|
||||
if the ITYPE has strictly more than twice as many
|
||||
mantissa bits as TYPE, can represent infinities
|
||||
and NaNs if the TYPE can, and has sufficient
|
||||
exponent range for the product or ratio of two
|
||||
values representable in the TYPE to be within the
|
||||
range of normal values of ITYPE. */
|
||||
if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
|
||||
&& (flag_unsafe_math_optimizations
|
||||
|| (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
|
||||
&& real_can_shorten_arithmetic (TYPE_MODE (itype),
|
||||
TYPE_MODE (type)))))
|
||||
{
|
||||
expr = build2 (TREE_CODE (expr), newtype,
|
||||
fold (convert_to_real (newtype, arg0)),
|
||||
|
|
29
gcc/real.c
29
gcc/real.c
|
@ -1266,6 +1266,35 @@ exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
|
|||
*r = u;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return true if arithmetic on values in IMODE that were promoted
|
||||
from values in TMODE is equivalent to direct arithmetic on values
|
||||
in TMODE. */
|
||||
|
||||
bool
|
||||
real_can_shorten_arithmetic (enum machine_mode imode, enum machine_mode tmode)
|
||||
{
|
||||
const struct real_format *tfmt, *ifmt;
|
||||
tfmt = REAL_MODE_FORMAT (tmode);
|
||||
ifmt = REAL_MODE_FORMAT (imode);
|
||||
/* These conditions are conservative rather than trying to catch the
|
||||
exact boundary conditions; the main case to allow is IEEE float
|
||||
and double. */
|
||||
return (ifmt->b == tfmt->b
|
||||
&& ifmt->p > 2 * tfmt->p
|
||||
&& ifmt->emin < 2 * tfmt->emin - tfmt->p - 2
|
||||
&& ifmt->emin < tfmt->emin - tfmt->emax - tfmt->p - 2
|
||||
&& ifmt->emax > 2 * tfmt->emax + 2
|
||||
&& ifmt->emax > tfmt->emax - tfmt->emin + tfmt->p + 2
|
||||
&& ifmt->round_towards_zero == tfmt->round_towards_zero
|
||||
&& (ifmt->has_sign_dependent_rounding
|
||||
== tfmt->has_sign_dependent_rounding)
|
||||
&& ifmt->has_nans >= tfmt->has_nans
|
||||
&& ifmt->has_inf >= tfmt->has_inf
|
||||
&& ifmt->has_signed_zero >= tfmt->has_signed_zero
|
||||
&& !MODE_COMPOSITE_P (tmode)
|
||||
&& !MODE_COMPOSITE_P (imode));
|
||||
}
|
||||
|
||||
/* Render R as an integer. */
|
||||
|
||||
|
|
|
@ -438,6 +438,11 @@ extern rtx const_double_from_real_value (REAL_VALUE_TYPE, enum machine_mode);
|
|||
/* Replace R by 1/R in the given machine mode, if the result is exact. */
|
||||
extern bool exact_real_inverse (enum machine_mode, REAL_VALUE_TYPE *);
|
||||
|
||||
/* Return true if arithmetic on values in IMODE that were promoted
|
||||
from values in TMODE is equivalent to direct arithmetic on values
|
||||
in TMODE. */
|
||||
bool real_can_shorten_arithmetic (enum machine_mode, enum machine_mode);
|
||||
|
||||
/* In tree.c: wrap up a REAL_VALUE_TYPE in a tree node. */
|
||||
extern tree build_real (tree, REAL_VALUE_TYPE);
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
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.
|
||||
|
||||
2008-10-29 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/37870
|
||||
|
|
20
gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c
Normal file
20
gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* Test for bug where fold changed binary operation to decimal
|
||||
depending on typedefs. */
|
||||
/* { dg-options "-std=gnu99" } */
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
|
||||
volatile double d = 1.2345675;
|
||||
|
||||
typedef const volatile _Decimal32 d32;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
_Decimal32 a = (d * d);
|
||||
d32 b = (d * d);
|
||||
if (a != b)
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
17
gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c
Normal file
17
gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* Test for bug where fold narrowed decimal floating-point
|
||||
operations. */
|
||||
/* { dg-options "-std=gnu99" } */
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
|
||||
volatile _Decimal32 f = 1.23456DF;
|
||||
volatile _Decimal64 d = 1.23456DD;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if ((double)((_Decimal64)f * (_Decimal64)f) != (double)(d * d))
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
17
gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c
Normal file
17
gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* Test for bug where fold narrowed decimal floating-point
|
||||
operations. */
|
||||
/* { dg-options "-std=gnu99" } */
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
|
||||
volatile _Decimal32 f = 1.23456DF;
|
||||
volatile _Decimal64 d = 1.23456DD;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if ((_Decimal128)((_Decimal64)f * (_Decimal64)f) != (_Decimal128)(d * d))
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
22
gcc/testsuite/gcc.target/i386/pr36578-1.c
Normal file
22
gcc/testsuite/gcc.target/i386/pr36578-1.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* Test for unsafe floating-point conversions. PR 36578. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-msse2 -mfpmath=sse" } */
|
||||
|
||||
#include "sse2-check.h"
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
volatile double d1 = 1.0;
|
||||
volatile double d2 = 0x1.00001p-53;
|
||||
volatile double d3;
|
||||
|
||||
static void
|
||||
sse2_test (void)
|
||||
{
|
||||
d3 = (double)((long double)d1 + (long double)d2);
|
||||
if (d3 != d1)
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
23
gcc/testsuite/gcc.target/i386/pr36578-2.c
Normal file
23
gcc/testsuite/gcc.target/i386/pr36578-2.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* Test for unsafe floating-point conversions. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-msse2 -mfpmath=sse" } */
|
||||
|
||||
#include "sse2-check.h"
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
volatile double d1 = 0x1.000001p0;
|
||||
volatile double d2 = 0x1p-54;
|
||||
volatile float f = 0x1.000002p0f;
|
||||
volatile float f2;
|
||||
|
||||
static void
|
||||
sse2_test (void)
|
||||
{
|
||||
f2 = (float)((long double)d1 + (long double)d2);
|
||||
if (f != f2)
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
Loading…
Add table
Reference in a new issue