tree-vrp.c (extract_range_from_unary_expr): Handle all conversions.
authorRichard Guenther <rguenther@suse.de>
Thu, 3 Apr 2008 09:33:27 +0000 (09:33 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 3 Apr 2008 09:33:27 +0000 (09:33 +0000)
2008-04-03  Richard Guenther  <rguenther@suse.de>

* tree-vrp.c (extract_range_from_unary_expr): Handle all
conversions.  Simplify code.

* gcc.dg/tree-ssa/vrp43.c: New testcase.
* gcc.dg/tree-ssa/vrp44.c: Likewise.
* gcc.dg/tree-ssa/vrp45.c: Likewise.

From-SVN: r133866

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/vrp43.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/vrp44.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/vrp45.c [new file with mode: 0644]
gcc/tree-vrp.c

index 764c6fc9cbfe2dd91ec4af4e93f2c87d882ceff2..321dfb04d0f447c7f662674f7dcf3ce1c663a341 100644 (file)
@@ -1,3 +1,8 @@
+2008-04-03  Richard Guenther  <rguenther@suse.de>
+
+       * tree-vrp.c (extract_range_from_unary_expr): Handle all
+       conversions.  Simplify code.
+
 2008-04-03  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * config/sh/sh.c (sh_output_mi_thunk): Free cfun.
index e291072c8396a8668adcd9624d5232bddb897425..59bc95a8e9e826351d668c2d070e9d7dce013b90 100644 (file)
@@ -1,3 +1,9 @@
+2008-04-03  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/vrp43.c: New testcase.
+       * gcc.dg/tree-ssa/vrp44.c: Likewise.
+       * gcc.dg/tree-ssa/vrp45.c: Likewise.
+
 2008-04-03  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/35741
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c
new file mode 100644 (file)
index 0000000..f475354
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+int __attribute__((noinline))
+foo(int i)
+{
+  if (i != 0)
+    {
+      char c = (char)i;
+      return c != 0;
+    }
+  return 0;
+}
+
+extern void abort (void);
+
+int main()
+{
+  if (foo(0xff00))
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c
new file mode 100644 (file)
index 0000000..a2df852
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+extern void link_error (void);
+
+void test1(int i)
+{
+  if (i >= -5 && i <= 8)
+    {
+      unsigned int j = i + 1;
+      if (j == -5)
+       link_error ();
+      if (j == 10)
+       link_error ();
+    }
+}
+
+void test2(unsigned int i)
+{
+  if (i >= -5 || i <= 8)
+    {
+      int j = i;
+      if (j == -6)
+       link_error ();
+      if (j == 9)
+       link_error ();
+    }
+}
+
+int main() { return 0; }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c
new file mode 100644 (file)
index 0000000..7916d2d
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+extern void link_error (void);
+
+void foo (int i)
+{
+  if (i > -128 && i < 127)
+    {
+      unsigned char k = i;
+      if (k == 0x80)
+        link_error ();
+      if (k == 0x7f)
+        link_error ();
+    }
+}
+
+int main() { return 0; }
+
index 65635285df91bf69da78e95a4003e878294a771d..9741262dba23c4eda570bae2038d0da10a0761dd 100644 (file)
@@ -2350,71 +2350,63 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
     }
 
   /* Handle unary expressions on integer ranges.  */
-  if (code == NOP_EXPR || code == CONVERT_EXPR)
+  if ((code == NOP_EXPR
+       || code == CONVERT_EXPR)
+      && INTEGRAL_TYPE_P (type)
+      && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
     {
       tree inner_type = TREE_TYPE (op0);
       tree outer_type = type;
 
-      /* If VR0 represents a simple range, then try to convert
-        the min and max values for the range to the same type
-        as OUTER_TYPE.  If the results compare equal to VR0's
-        min and max values and the new min is still less than
-        or equal to the new max, then we can safely use the newly
-        computed range for EXPR.  This allows us to compute
-        accurate ranges through many casts.  */
-      if ((vr0.type == VR_RANGE
-          && !overflow_infinity_range_p (&vr0))
-         || (vr0.type == VR_VARYING
-             && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
+      /* Always use base-types here.  This is important for the
+        correct signedness.  */
+      if (TREE_TYPE (inner_type))
+       inner_type = TREE_TYPE (inner_type);
+      if (TREE_TYPE (outer_type))
+       outer_type = TREE_TYPE (outer_type);
+
+      /* If VR0 is varying and we increase the type precision, assume
+        a full range for the following transformation.  */
+      if (vr0.type == VR_VARYING
+         && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
        {
-         tree new_min, new_max, orig_min, orig_max;
-
-         /* Convert the input operand min/max to OUTER_TYPE.   If
-            the input has no range information, then use the min/max
-            for the input's type.  */
-         if (vr0.type == VR_RANGE)
-           {
-             orig_min = vr0.min;
-             orig_max = vr0.max;
-           }
-         else
-           {
-             orig_min = TYPE_MIN_VALUE (inner_type);
-             orig_max = TYPE_MAX_VALUE (inner_type);
-           }
-
-         new_min = fold_convert (outer_type, orig_min);
-         new_max = fold_convert (outer_type, orig_max);
-
-         /* Verify the new min/max values are gimple values and
-            that they compare equal to the original input's
-            min/max values.  */
-         if (is_gimple_val (new_min)
-             && is_gimple_val (new_max)
-             && tree_int_cst_equal (new_min, orig_min)
-             && tree_int_cst_equal (new_max, orig_max)
-             && (!is_overflow_infinity (new_min)
-                 || !is_overflow_infinity (new_max))
-             && (cmp = compare_values (new_min, new_max)) <= 0
-             && cmp >= -1)
-           {
-             set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
-             return;
-           }
+         vr0.type = VR_RANGE;
+         vr0.min = TYPE_MIN_VALUE (inner_type);
+         vr0.max = TYPE_MAX_VALUE (inner_type);
        }
 
-      /* When converting types of different sizes, set the result to
-        VARYING.  Things like sign extensions and precision loss may
-        change the range.  For instance, if x_3 is of type 'long long
-        int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it
-        is impossible to know at compile time whether y_5 will be
-        ~[0, 0].  */
-      if (TYPE_SIZE (inner_type) != TYPE_SIZE (outer_type)
-         || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+      /* If VR0 is a constant range or anti-range and the conversion is
+        not truncating we can convert the min and max values and
+        canonicalize the resulting range.  Otherwise we can do the
+        conversion if the size of the range is less than what the
+        precision of the target type can represent and the range is
+        not an anti-range.  */
+      if ((vr0.type == VR_RANGE
+          || vr0.type == VR_ANTI_RANGE)
+         && TREE_CODE (vr0.min) == INTEGER_CST
+         && TREE_CODE (vr0.max) == INTEGER_CST
+         && !is_overflow_infinity (vr0.min)
+         && !is_overflow_infinity (vr0.max)
+         && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
+             || (vr0.type == VR_RANGE
+                 && integer_zerop (int_const_binop (RSHIFT_EXPR,
+                      int_const_binop (MINUS_EXPR, vr0.max, vr0.min, 0),
+                        size_int (TYPE_PRECISION (outer_type)), 0)))))
        {
-         set_value_range_to_varying (vr);
+         tree new_min, new_max;
+         new_min = force_fit_type_double (outer_type,
+                                          TREE_INT_CST_LOW (vr0.min),
+                                          TREE_INT_CST_HIGH (vr0.min), 0, 0);
+         new_max = force_fit_type_double (outer_type,
+                                          TREE_INT_CST_LOW (vr0.max),
+                                          TREE_INT_CST_HIGH (vr0.max), 0, 0);
+         set_and_canonicalize_value_range (vr, vr0.type,
+                                           new_min, new_max, NULL);
          return;
        }
+
+      set_value_range_to_varying (vr);
+      return;
     }
 
   /* Conversion of a VR_VARYING value to a wider type can result