diff options
author | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-10-03 21:33:57 +0000 |
---|---|---|
committer | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-10-03 21:33:57 +0000 |
commit | 67c65562f54b79711c2faccaebb6faa31fdbdd4f (patch) | |
tree | 09c0fbd9595e9411be41c39493368c74ad3a13be /gcc | |
parent | e0820f9b2ce32cdd93ad566100054d50bc3f542a (diff) | |
download | gcc-67c65562f54b79711c2faccaebb6faa31fdbdd4f.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@72079 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/fold-const.c | 80 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 94 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20031003-1.c | 42 | ||||
-rw-r--r-- | gcc/tree.c | 11 |
6 files changed, 202 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2c5e510e82..123cb3fa84d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 250d65930a8..1cf444d3f67 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 c338b665ca0..3e0bdbfa27a 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 66b71f5113e..7e10c016b4c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 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 00000000000..b60711f732b --- /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 b82a6bf6965..c83b24052b6 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; } |