summaryrefslogtreecommitdiff
path: root/gcc/simplify-rtx.c
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/simplify-rtx.c
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/simplify-rtx.c')
-rw-r--r--gcc/simplify-rtx.c94
1 files changed, 87 insertions, 7 deletions
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.