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
|
@ -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>
|
2008-10-29 Bernd Schmidt <bernd.schmidt@analog.com>
|
||||||
|
|
||||||
* config/bfin/bfin-protos.h (WA_05000257, WA_05000283, WA_05000315,
|
* 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));
|
tree arg1 = strip_float_extensions (TREE_OPERAND (expr, 1));
|
||||||
|
|
||||||
if (FLOAT_TYPE_P (TREE_TYPE (arg0))
|
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;
|
tree newtype = type;
|
||||||
|
|
||||||
if (TYPE_MODE (TREE_TYPE (arg0)) == SDmode
|
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;
|
newtype = dfloat32_type_node;
|
||||||
if (TYPE_MODE (TREE_TYPE (arg0)) == DDmode
|
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;
|
newtype = dfloat64_type_node;
|
||||||
if (TYPE_MODE (TREE_TYPE (arg0)) == TDmode
|
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;
|
newtype = dfloat128_type_node;
|
||||||
if (newtype == dfloat32_type_node
|
if (newtype == dfloat32_type_node
|
||||||
|| newtype == dfloat64_type_node
|
|| newtype == dfloat64_type_node
|
||||||
|
@ -292,7 +296,32 @@ convert_to_real (tree type, tree expr)
|
||||||
newtype = TREE_TYPE (arg0);
|
newtype = TREE_TYPE (arg0);
|
||||||
if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
|
if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
|
||||||
newtype = TREE_TYPE (arg1);
|
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,
|
expr = build2 (TREE_CODE (expr), newtype,
|
||||||
fold (convert_to_real (newtype, arg0)),
|
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;
|
*r = u;
|
||||||
return true;
|
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. */
|
/* 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. */
|
/* 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 *);
|
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. */
|
/* In tree.c: wrap up a REAL_VALUE_TYPE in a tree node. */
|
||||||
extern tree build_real (tree, REAL_VALUE_TYPE);
|
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>
|
2008-10-29 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR middle-end/37870
|
PR middle-end/37870
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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…
Reference in New Issue