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:
Roger Sayle 2003-10-03 21:33:57 +00:00 committed by Roger Sayle
parent 4dbe1556cc
commit 875eda9c34
6 changed files with 200 additions and 41 deletions

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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

View 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;
}

View File

@ -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;
}