From b47ee38692ad7393bdaf2c366a6734d7dd60e951 Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguenther@suse.de>
Date: Thu, 3 Apr 2008 09:33:27 +0000
Subject: [PATCH] tree-vrp.c (extract_range_from_unary_expr): Handle all
 conversions.

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                         |   5 ++
 gcc/testsuite/ChangeLog               |   6 ++
 gcc/testsuite/gcc.dg/tree-ssa/vrp43.c |  22 ++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp44.c |  30 ++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp45.c |  19 +++++
 gcc/tree-vrp.c                        | 102 ++++++++++++--------------
 6 files changed, 129 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp43.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp44.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp45.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 764c6fc9cbfe..321dfb04d0f4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e291072c8396..59bc95a8e9e8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 000000000000..f475354dcfe1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c
@@ -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
index 000000000000..a2df852c7bf4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c
@@ -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
index 000000000000..7916d2da880a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c
@@ -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; }
+
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 65635285df91..9741262dba23 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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
-- 
GitLab