PR optimization/9325, PR java/6391
PR optimization/9325, PR java/6391 * fold-const.c (fold_convert): For floating point to integer conversions, return the maximum/minimum representable integer value if the real constant overflows the destination type. * tree.c (real_value_from_int_cst): Allow the type to be NULL, meaning don't truncate the result to a floating point mode. Simplify the logic by calling real_from_integer directly. * simplify-rtx.c (simplify_unary_operation): Implement the same semantics for folding floating point to integer conversions in RTL. * gcc.c-torture/execute/20031003-1.c: New test case. From-SVN: r72079
This commit is contained in:
parent
4dbe1556cc
commit
875eda9c34
@ -1,3 +1,16 @@
|
||||
2003-10-03 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
PR optimization/9325, PR java/6391
|
||||
* fold-const.c (fold_convert): For floating point to integer
|
||||
conversions, return the maximum/minimum representable integer
|
||||
value if the real constant overflows the destination type.
|
||||
* tree.c (real_value_from_int_cst): Allow the type to be NULL,
|
||||
meaning don't truncate the result to a floating point mode.
|
||||
Simplify the logic by calling real_from_integer directly.
|
||||
* simplify-rtx.c (simplify_unary_operation): Implement the
|
||||
same semantics for folding floating point to integer conversions
|
||||
in RTL.
|
||||
|
||||
2003-10-03 Chris Demetriou <cgd@broadcom.com>
|
||||
|
||||
* config/mips/mips.c (mips_emit_prefetch): Restructure
|
||||
|
@ -1599,41 +1599,63 @@ fold_convert (tree t, tree arg1)
|
||||
}
|
||||
else if (TREE_CODE (arg1) == REAL_CST)
|
||||
{
|
||||
/* Don't initialize these, use assignments.
|
||||
Initialized local aggregates don't work on old compilers. */
|
||||
REAL_VALUE_TYPE x;
|
||||
REAL_VALUE_TYPE l;
|
||||
REAL_VALUE_TYPE u;
|
||||
tree type1 = TREE_TYPE (arg1);
|
||||
int no_upper_bound;
|
||||
/* The following code implements the floating point to integer
|
||||
conversion rules required by the Java Language Specification,
|
||||
that IEEE NaNs are mapped to zero and values that overflow
|
||||
the target precision saturate, i.e. values greater than
|
||||
INT_MAX are mapped to INT_MAX, and values less than INT_MIN
|
||||
are mapped to INT_MIN. These semantics are allowed by the
|
||||
C and C++ standards that simply state that the behavior of
|
||||
FP-to-integer conversion is unspecified upon overflow. */
|
||||
|
||||
x = TREE_REAL_CST (arg1);
|
||||
l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
|
||||
HOST_WIDE_INT high, low;
|
||||
|
||||
no_upper_bound = (TYPE_MAX_VALUE (type) == NULL);
|
||||
if (!no_upper_bound)
|
||||
u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
|
||||
REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
|
||||
/* If x is NaN, return zero and show we have an overflow. */
|
||||
if (REAL_VALUE_ISNAN (x))
|
||||
{
|
||||
overflow = 1;
|
||||
high = 0;
|
||||
low = 0;
|
||||
}
|
||||
|
||||
/* See if X will be in range after truncation towards 0.
|
||||
To compensate for truncation, move the bounds away from 0,
|
||||
but reject if X exactly equals the adjusted bounds. */
|
||||
REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
|
||||
if (!no_upper_bound)
|
||||
REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
|
||||
/* If X is a NaN, use zero instead and show we have an overflow.
|
||||
Otherwise, range check. */
|
||||
if (REAL_VALUE_ISNAN (x))
|
||||
overflow = 1, x = dconst0;
|
||||
else if (! (REAL_VALUES_LESS (l, x)
|
||||
&& !no_upper_bound
|
||||
&& REAL_VALUES_LESS (x, u)))
|
||||
overflow = 1;
|
||||
|
||||
{
|
||||
HOST_WIDE_INT low, high;
|
||||
if (! overflow)
|
||||
{
|
||||
tree lt = TYPE_MIN_VALUE (type);
|
||||
REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
|
||||
REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
|
||||
if (! REAL_VALUES_LESS (l, x))
|
||||
{
|
||||
overflow = 1;
|
||||
high = TREE_INT_CST_HIGH (lt);
|
||||
low = TREE_INT_CST_LOW (lt);
|
||||
}
|
||||
}
|
||||
|
||||
if (! overflow)
|
||||
{
|
||||
tree ut = TYPE_MAX_VALUE (type);
|
||||
if (ut)
|
||||
{
|
||||
REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
|
||||
REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
|
||||
if (! REAL_VALUES_LESS (x, u))
|
||||
{
|
||||
overflow = 1;
|
||||
high = TREE_INT_CST_HIGH (ut);
|
||||
low = TREE_INT_CST_LOW (ut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! overflow)
|
||||
REAL_VALUE_TO_INT (&low, &high, x);
|
||||
t = build_int_2 (low, high);
|
||||
}
|
||||
|
||||
t = build_int_2 (low, high);
|
||||
TREE_TYPE (t) = type;
|
||||
TREE_OVERFLOW (t)
|
||||
= TREE_OVERFLOW (arg1) | force_fit_type (t, overflow);
|
||||
|
@ -775,19 +775,99 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
|
||||
else if (GET_CODE (trueop) == CONST_DOUBLE
|
||||
&& GET_MODE_CLASS (GET_MODE (trueop)) == MODE_FLOAT
|
||||
&& GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& width <= HOST_BITS_PER_WIDE_INT && width > 0)
|
||||
&& width <= 2*HOST_BITS_PER_WIDE_INT && width > 0)
|
||||
{
|
||||
HOST_WIDE_INT i;
|
||||
REAL_VALUE_TYPE d;
|
||||
REAL_VALUE_FROM_CONST_DOUBLE (d, trueop);
|
||||
/* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
|
||||
operators are intentionally left unspecified (to ease implemention
|
||||
by target backends), for consistency, this routine implements the
|
||||
same semantics for constant folding as used by the middle-end. */
|
||||
|
||||
HOST_WIDE_INT xh, xl, th, tl;
|
||||
REAL_VALUE_TYPE x, t;
|
||||
REAL_VALUE_FROM_CONST_DOUBLE (x, trueop);
|
||||
switch (code)
|
||||
{
|
||||
case FIX: i = REAL_VALUE_FIX (d); break;
|
||||
case UNSIGNED_FIX: i = REAL_VALUE_UNSIGNED_FIX (d); break;
|
||||
case FIX:
|
||||
if (REAL_VALUE_ISNAN (x))
|
||||
return const0_rtx;
|
||||
|
||||
/* Test against the signed upper bound. */
|
||||
if (width > HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
th = ((unsigned HOST_WIDE_INT) 1
|
||||
<< (width - HOST_BITS_PER_WIDE_INT - 1)) - 1;
|
||||
tl = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
th = 0;
|
||||
tl = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
|
||||
}
|
||||
real_from_integer (&t, VOIDmode, tl, th, 0);
|
||||
if (REAL_VALUES_LESS (t, x))
|
||||
{
|
||||
xh = th;
|
||||
xl = tl;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test against the signed lower bound. */
|
||||
if (width > HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
th = (HOST_WIDE_INT) -1 << (width - HOST_BITS_PER_WIDE_INT - 1);
|
||||
tl = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
th = -1;
|
||||
tl = (HOST_WIDE_INT) -1 << (width - 1);
|
||||
}
|
||||
real_from_integer (&t, VOIDmode, tl, th, 0);
|
||||
if (REAL_VALUES_LESS (x, t))
|
||||
{
|
||||
xh = th;
|
||||
xl = tl;
|
||||
break;
|
||||
}
|
||||
REAL_VALUE_TO_INT (&xl, &xh, x);
|
||||
break;
|
||||
|
||||
case UNSIGNED_FIX:
|
||||
if (REAL_VALUE_ISNAN (x) || REAL_VALUE_NEGATIVE (x))
|
||||
return const0_rtx;
|
||||
|
||||
/* Test against the unsigned upper bound. */
|
||||
if (width == 2*HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
th = -1;
|
||||
tl = -1;
|
||||
}
|
||||
else if (width >= HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
th = ((unsigned HOST_WIDE_INT) 1
|
||||
<< (width - HOST_BITS_PER_WIDE_INT)) - 1;
|
||||
tl = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
th = 0;
|
||||
tl = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
|
||||
}
|
||||
real_from_integer (&t, VOIDmode, tl, th, 1);
|
||||
if (REAL_VALUES_LESS (t, x))
|
||||
{
|
||||
xh = th;
|
||||
xl = tl;
|
||||
break;
|
||||
}
|
||||
|
||||
REAL_VALUE_TO_INT (&xl, &xh, x);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return gen_int_mode (i, mode);
|
||||
return immed_double_const (xl, xh, mode);
|
||||
}
|
||||
|
||||
/* This was formerly used only for non-IEEE float.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2003-10-03 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
PR optimization/9325, PR java/6391
|
||||
* gcc.c-torture/execute/20031003-1.c: New test case.
|
||||
|
||||
2003-10-02 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR optimization/12180
|
||||
|
42
gcc/testsuite/gcc.c-torture/execute/20031003-1.c
Normal file
42
gcc/testsuite/gcc.c-torture/execute/20031003-1.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* PR optimization/9325 */
|
||||
|
||||
extern void abort (void);
|
||||
|
||||
int f1()
|
||||
{
|
||||
return (int)2147483648.0f;
|
||||
}
|
||||
|
||||
int f2()
|
||||
{
|
||||
return (int)(float)(2147483647);
|
||||
}
|
||||
|
||||
int f3()
|
||||
{
|
||||
float a = 2147483648.0f;
|
||||
return (int)a;
|
||||
}
|
||||
|
||||
int f4()
|
||||
{
|
||||
int a = 2147483647;
|
||||
float b = (float)a;
|
||||
return (int)b;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (f1() != 2147483647)
|
||||
abort ();
|
||||
if (f2() != 2147483647)
|
||||
abort ();
|
||||
#ifdef __OPTIMIZE__
|
||||
if (f3() != 2147483647)
|
||||
abort ();
|
||||
if (f4() != 2147483647)
|
||||
abort ();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
11
gcc/tree.c
11
gcc/tree.c
@ -488,7 +488,7 @@ build_real (tree type, REAL_VALUE_TYPE d)
|
||||
and whose value is the integer value of the INTEGER_CST node I. */
|
||||
|
||||
REAL_VALUE_TYPE
|
||||
real_value_from_int_cst (tree type ATTRIBUTE_UNUSED, tree i)
|
||||
real_value_from_int_cst (tree type, tree i)
|
||||
{
|
||||
REAL_VALUE_TYPE d;
|
||||
|
||||
@ -496,12 +496,9 @@ real_value_from_int_cst (tree type ATTRIBUTE_UNUSED, tree i)
|
||||
bitwise comparisons to see if two values are the same. */
|
||||
memset (&d, 0, sizeof d);
|
||||
|
||||
if (! TREE_UNSIGNED (TREE_TYPE (i)))
|
||||
REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
|
||||
TYPE_MODE (type));
|
||||
else
|
||||
REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i),
|
||||
TREE_INT_CST_HIGH (i), TYPE_MODE (type));
|
||||
real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode,
|
||||
TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
|
||||
TREE_UNSIGNED (TREE_TYPE (i)));
|
||||
return d;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user