OSDN Git Service

PR optimization/9325, PR java/6391
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Oct 2003 21:33:57 +0000 (21:33 +0000)
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Oct 2003 21:33:57 +0000 (21:33 +0000)
* 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

gcc/ChangeLog
gcc/fold-const.c
gcc/simplify-rtx.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20031003-1.c [new file with mode: 0644]
gcc/tree.c

index e2c5e51..123cb3f 100644 (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
index 250d659..1cf444d 100644 (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;
-
-         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);
index c338b66..3e0bdbf 100644 (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.
index 66b71f5..7e10c01 100644 (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
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 (file)
index 0000000..b60711f
--- /dev/null
@@ -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;
+}
+
index b82a6bf..c83b240 100644 (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;
 }