From 875eda9c345e57676c4f21f753274ee51025fa41 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Fri, 3 Oct 2003 21:33:57 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 13 ++++ gcc/fold-const.c | 80 ++++++++++++-------- gcc/simplify-rtx.c | 94 ++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.c-torture/execute/20031003-1.c | 42 +++++++++++ gcc/tree.c | 11 +-- 6 files changed, 202 insertions(+), 43 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/20031003-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2c5e51..123cb3f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2003-10-03 Roger Sayle + + 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 * config/mips/mips.c (mips_emit_prefetch): Restructure diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 250d659..1cf444d 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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; - - x = TREE_REAL_CST (arg1); - l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type)); - - no_upper_bound = (TYPE_MAX_VALUE (type) == NULL); - if (!no_upper_bound) - u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type)); + /* 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. */ + + HOST_WIDE_INT high, low; + + 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); diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index c338b66..3e0bdbf 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 66b71f5..7e10c01 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-10-03 Roger Sayle + + PR optimization/9325, PR java/6391 + * gcc.c-torture/execute/20031003-1.c: New test case. + 2003-10-02 Mark Mitchell PR optimization/12180 diff --git a/gcc/testsuite/gcc.c-torture/execute/20031003-1.c b/gcc/testsuite/gcc.c-torture/execute/20031003-1.c new file mode 100644 index 0000000..b60711f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20031003-1.c @@ -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; +} + diff --git a/gcc/tree.c b/gcc/tree.c index b82a6bf..c83b240 100644 --- a/gcc/tree.c +++ b/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; } -- 2.7.4