From c360c0fb8a1dd8ef61d986671d02071075d2c0b9 Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Tue, 29 Nov 2011 22:03:09 +0100
Subject: [PATCH] re PR tree-optimization/51247 (ICE in set_value_range, at
 tree-vrp.c:417)

	PR tree-optimization/51247
	* tree-vrp.c (extract_range_from_assert): For signed 1-bit precision
	types instead of adding 1 subtract -1 and instead of subtracting 1
	add -1 to avoid overflows.

	* gcc.c-torture/compile/pr51247.c: New test.

From-SVN: r181818
---
 gcc/ChangeLog                                 |  7 +++
 gcc/testsuite/ChangeLog                       |  5 ++
 gcc/testsuite/gcc.c-torture/compile/pr51247.c | 16 ++++++
 gcc/tree-vrp.c                                | 50 +++++++++++++++----
 4 files changed, 68 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr51247.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 921b4f930498..3a802781fbc5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2011-11-29  Jakub Jelinek  <jakub@redhat.com>
+
+	PR tree-optimization/51247
+	* tree-vrp.c (extract_range_from_assert): For signed 1-bit precision
+	types instead of adding 1 subtract -1 and instead of subtracting 1
+	add -1 to avoid overflows.
+
 2011-11-29  Andrew MacLeod  <amacleod@redhat.com>
 
 	PR target/50123
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a5a39e3c4d13..3d695a220310 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-11-29  Jakub Jelinek  <jakub@redhat.com>
+
+	PR tree-optimization/51247
+	* gcc.c-torture/compile/pr51247.c: New test.
+
 2011-11-29  Andrew MacLeod  <amacleod@redhat.com>
 
 	PR target/50123
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr51247.c b/gcc/testsuite/gcc.c-torture/compile/pr51247.c
new file mode 100644
index 000000000000..16aa7f04b1af
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr51247.c
@@ -0,0 +1,16 @@
+/* PR tree-optimization/51247 */
+
+struct S { int s : 1; };
+int a;
+
+void
+foo (int x, int y)
+{
+  struct S s;
+  s.s = !!y;
+  while (1)
+    {
+      unsigned l = 94967295;
+      a = x || (s.s &= l);
+    }
+}
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 248bc61926f6..5cbc25fcb1e0 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1693,8 +1693,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 	  /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
 	  if (cond_code == LT_EXPR)
 	    {
-	      tree one = build_int_cst (TREE_TYPE (max), 1);
-	      max = fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, one);
+	      if (TYPE_PRECISION (TREE_TYPE (max)) == 1
+		  && !TYPE_UNSIGNED (TREE_TYPE (max)))
+		max = fold_build2 (PLUS_EXPR, TREE_TYPE (max), max,
+				   build_int_cst (TREE_TYPE (max), -1));
+	      else
+		max = fold_build2 (MINUS_EXPR, TREE_TYPE (max), max,
+				   build_int_cst (TREE_TYPE (max), 1));
 	      if (EXPR_P (max))
 		TREE_NO_WARNING (max) = 1;
 	    }
@@ -1728,8 +1733,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 	  /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
 	  if (cond_code == GT_EXPR)
 	    {
-	      tree one = build_int_cst (TREE_TYPE (min), 1);
-	      min = fold_build2 (PLUS_EXPR, TREE_TYPE (min), min, one);
+	      if (TYPE_PRECISION (TREE_TYPE (min)) == 1
+		  && !TYPE_UNSIGNED (TREE_TYPE (min)))
+		min = fold_build2 (MINUS_EXPR, TREE_TYPE (min), min,
+				   build_int_cst (TREE_TYPE (min), -1));
+	      else
+		min = fold_build2 (PLUS_EXPR, TREE_TYPE (min), min,
+				   build_int_cst (TREE_TYPE (min), 1));
 	      if (EXPR_P (min))
 		TREE_NO_WARNING (min) = 1;
 	    }
@@ -1915,9 +1925,19 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 		  min = positive_overflow_infinity (TREE_TYPE (var_vr->min));
 		}
 	      else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-		min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
-				   anti_max,
-				   build_int_cst (TREE_TYPE (var_vr->min), 1));
+		{
+		  if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+		      && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+		    min = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+				       anti_max,
+				       build_int_cst (TREE_TYPE (var_vr->min),
+						      -1));
+		  else
+		    min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+				       anti_max,
+				       build_int_cst (TREE_TYPE (var_vr->min),
+						      1));
+		}
 	      else
 		min = fold_build_pointer_plus_hwi (anti_max, 1);
 	      max = real_max;
@@ -1942,9 +1962,19 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 		  max = negative_overflow_infinity (TREE_TYPE (var_vr->min));
 		}
 	      else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-		max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
-				   anti_min,
-				   build_int_cst (TREE_TYPE (var_vr->min), 1));
+		{
+		  if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+		      && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+		    max = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+				       anti_min,
+				       build_int_cst (TREE_TYPE (var_vr->min),
+						      -1));
+		  else
+		    max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+				       anti_min,
+				       build_int_cst (TREE_TYPE (var_vr->min),
+						      1));
+		}
 	      else
 		max = fold_build_pointer_plus_hwi (anti_min, -1);
 	      min = real_min;
-- 
GitLab