summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-03 21:33:57 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-03 21:33:57 +0000
commit67c65562f54b79711c2faccaebb6faa31fdbdd4f (patch)
tree09c0fbd9595e9411be41c39493368c74ad3a13be /gcc
parente0820f9b2ce32cdd93ad566100054d50bc3f542a (diff)
downloadgcc-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/ChangeLog13
-rw-r--r--gcc/fold-const.c80
-rw-r--r--gcc/simplify-rtx.c94
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20031003-1.c42
-rw-r--r--gcc/tree.c11
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;
}