Fix VRP intersect_ranges for 1-bit precision signed types (PR tree-optimization/80443)

Message ID 20170418150648.GY1809@tucnak
State New
Headers show

Commit Message

Jakub Jelinek April 18, 2017, 3:06 p.m.
Hi!

As can be seen on the testcase, intersect_ranges in some cases attempts
to add or subtract 1 from one of the bounds.  That is fine except for
1-bit signed type, where 1 is not a value in the range of the type,
so already build_int_cst yields (OVF) constant.

The following patch fixes it by special casing those, instead of
adding/subtracting 1 for those types it subtracts/adds -1.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-04-18  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/80443
	* tree-vrp.c (intersect_ranges): For signed 1-bit precision type,
	instead of adding 1, subtract -1 and similarly instead of subtracting
	1 add -1.

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


	Jakub

Comments

Richard Biener April 18, 2017, 7:12 p.m. | #1
On April 18, 2017 5:06:48 PM GMT+02:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>As can be seen on the testcase, intersect_ranges in some cases attempts
>to add or subtract 1 from one of the bounds.  That is fine except for
>1-bit signed type, where 1 is not a value in the range of the type,
>so already build_int_cst yields (OVF) constant.
>
>The following patch fixes it by special casing those, instead of
>adding/subtracting 1 for those types it subtracts/adds -1.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ick.

OK.

Richard.

>2017-04-18  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/80443
>	* tree-vrp.c (intersect_ranges): For signed 1-bit precision type,
>	instead of adding 1, subtract -1 and similarly instead of subtracting
>	1 add -1.
>
>	* gcc.c-torture/compile/pr80443.c: New test.
>
>--- gcc/tree-vrp.c.jj	2017-03-23 15:49:55.000000000 +0100
>+++ gcc/tree-vrp.c	2017-04-18 10:09:44.560549718 +0200
>@@ -8756,20 +8756,32 @@ intersect_ranges (enum value_range_type
> 	  /* Choose the right gap if the left one is empty.  */
> 	  if (mineq)
> 	    {
>-	      if (TREE_CODE (vr1max) == INTEGER_CST)
>-		*vr0min = int_const_binop (PLUS_EXPR, vr1max,
>-					   build_int_cst (TREE_TYPE (vr1max), 1));
>-	      else
>+	      if (TREE_CODE (vr1max) != INTEGER_CST)
> 		*vr0min = vr1max;
>+	      else if (TYPE_PRECISION (TREE_TYPE (vr1max)) == 1
>+		       && !TYPE_UNSIGNED (TREE_TYPE (vr1max)))
>+		*vr0min
>+		  = int_const_binop (MINUS_EXPR, vr1max,
>+				     build_int_cst (TREE_TYPE (vr1max), -1));
>+	      else
>+		*vr0min
>+		  = int_const_binop (PLUS_EXPR, vr1max,
>+				     build_int_cst (TREE_TYPE (vr1max), 1));
> 	    }
> 	  /* Choose the left gap if the right one is empty.  */
> 	  else if (maxeq)
> 	    {
>-	      if (TREE_CODE (vr1min) == INTEGER_CST)
>-		*vr0max = int_const_binop (MINUS_EXPR, vr1min,
>-					   build_int_cst (TREE_TYPE (vr1min), 1));
>-	      else
>+	      if (TREE_CODE (vr1min) != INTEGER_CST)
> 		*vr0max = vr1min;
>+	      else if (TYPE_PRECISION (TREE_TYPE (vr1min)) == 1
>+		       && !TYPE_UNSIGNED (TREE_TYPE (vr1min)))
>+		*vr0max
>+		  = int_const_binop (PLUS_EXPR, vr1min,
>+				     build_int_cst (TREE_TYPE (vr1min), -1));
>+	      else
>+		*vr0max
>+		  = int_const_binop (MINUS_EXPR, vr1min,
>+				     build_int_cst (TREE_TYPE (vr1min), 1));
> 	    }
> 	  /* Choose the anti-range if the range is effectively varying.  */
> 	  else if (vrp_val_is_min (*vr0min)
>@@ -8811,22 +8823,34 @@ intersect_ranges (enum value_range_type
> 	  if (mineq)
> 	    {
> 	      *vr0type = VR_RANGE;
>-	      if (TREE_CODE (*vr0max) == INTEGER_CST)
>-		*vr0min = int_const_binop (PLUS_EXPR, *vr0max,
>-					   build_int_cst (TREE_TYPE (*vr0max), 1));
>-	      else
>+	      if (TREE_CODE (*vr0max) != INTEGER_CST)
> 		*vr0min = *vr0max;
>+	      else if (TYPE_PRECISION (TREE_TYPE (*vr0max)) == 1
>+		       && !TYPE_UNSIGNED (TREE_TYPE (*vr0max)))
>+		*vr0min
>+		  = int_const_binop (MINUS_EXPR, *vr0max,
>+				     build_int_cst (TREE_TYPE (*vr0max), -1));
>+	      else
>+		*vr0min
>+		  = int_const_binop (PLUS_EXPR, *vr0max,
>+				     build_int_cst (TREE_TYPE (*vr0max), 1));
> 	      *vr0max = vr1max;
> 	    }
> 	  /* Choose the left gap if the right is empty.  */
> 	  else if (maxeq)
> 	    {
> 	      *vr0type = VR_RANGE;
>-	      if (TREE_CODE (*vr0min) == INTEGER_CST)
>-		*vr0max = int_const_binop (MINUS_EXPR, *vr0min,
>-					   build_int_cst (TREE_TYPE (*vr0min), 1));
>-	      else
>+	      if (TREE_CODE (*vr0min) != INTEGER_CST)
> 		*vr0max = *vr0min;
>+	      else if (TYPE_PRECISION (TREE_TYPE (*vr0min)) == 1
>+		       && !TYPE_UNSIGNED (TREE_TYPE (*vr0min)))
>+		*vr0max
>+		  = int_const_binop (PLUS_EXPR, *vr0min,
>+				     build_int_cst (TREE_TYPE (*vr0min), -1));
>+	      else
>+		*vr0max
>+		  = int_const_binop (MINUS_EXPR, *vr0min,
>+				     build_int_cst (TREE_TYPE (*vr0min), 1));
> 	      *vr0min = vr1min;
> 	    }
> 	  /* Choose the anti-range if the range is effectively varying.  */
>--- gcc/testsuite/gcc.c-torture/compile/pr80443.c.jj	2017-04-18
>10:16:35.867952863 +0200
>+++ gcc/testsuite/gcc.c-torture/compile/pr80443.c	2017-04-18
>10:16:21.000000000 +0200
>@@ -0,0 +1,20 @@
>+/* PR tree-optimization/80443 */
>+
>+struct S { int a : 1; } b, c;
>+signed char d, e, f;
>+
>+void
>+foo ()
>+{ 
>+  while (f)
>+    { 
>+      signed char g = b.a;
>+      if (g)
>+	b.a = ~(1 + (d || c.a));
>+      if (b.a < g && b.a)
>+	g = 0;
>+      if (b.a > c.a)
>+	b.a = g;
>+      c.a = e;
>+    }
>+}
>
>	Jakub

Patch

--- gcc/tree-vrp.c.jj	2017-03-23 15:49:55.000000000 +0100
+++ gcc/tree-vrp.c	2017-04-18 10:09:44.560549718 +0200
@@ -8756,20 +8756,32 @@  intersect_ranges (enum value_range_type
 	  /* Choose the right gap if the left one is empty.  */
 	  if (mineq)
 	    {
-	      if (TREE_CODE (vr1max) == INTEGER_CST)
-		*vr0min = int_const_binop (PLUS_EXPR, vr1max,
-					   build_int_cst (TREE_TYPE (vr1max), 1));
-	      else
+	      if (TREE_CODE (vr1max) != INTEGER_CST)
 		*vr0min = vr1max;
+	      else if (TYPE_PRECISION (TREE_TYPE (vr1max)) == 1
+		       && !TYPE_UNSIGNED (TREE_TYPE (vr1max)))
+		*vr0min
+		  = int_const_binop (MINUS_EXPR, vr1max,
+				     build_int_cst (TREE_TYPE (vr1max), -1));
+	      else
+		*vr0min
+		  = int_const_binop (PLUS_EXPR, vr1max,
+				     build_int_cst (TREE_TYPE (vr1max), 1));
 	    }
 	  /* Choose the left gap if the right one is empty.  */
 	  else if (maxeq)
 	    {
-	      if (TREE_CODE (vr1min) == INTEGER_CST)
-		*vr0max = int_const_binop (MINUS_EXPR, vr1min,
-					   build_int_cst (TREE_TYPE (vr1min), 1));
-	      else
+	      if (TREE_CODE (vr1min) != INTEGER_CST)
 		*vr0max = vr1min;
+	      else if (TYPE_PRECISION (TREE_TYPE (vr1min)) == 1
+		       && !TYPE_UNSIGNED (TREE_TYPE (vr1min)))
+		*vr0max
+		  = int_const_binop (PLUS_EXPR, vr1min,
+				     build_int_cst (TREE_TYPE (vr1min), -1));
+	      else
+		*vr0max
+		  = int_const_binop (MINUS_EXPR, vr1min,
+				     build_int_cst (TREE_TYPE (vr1min), 1));
 	    }
 	  /* Choose the anti-range if the range is effectively varying.  */
 	  else if (vrp_val_is_min (*vr0min)
@@ -8811,22 +8823,34 @@  intersect_ranges (enum value_range_type
 	  if (mineq)
 	    {
 	      *vr0type = VR_RANGE;
-	      if (TREE_CODE (*vr0max) == INTEGER_CST)
-		*vr0min = int_const_binop (PLUS_EXPR, *vr0max,
-					   build_int_cst (TREE_TYPE (*vr0max), 1));
-	      else
+	      if (TREE_CODE (*vr0max) != INTEGER_CST)
 		*vr0min = *vr0max;
+	      else if (TYPE_PRECISION (TREE_TYPE (*vr0max)) == 1
+		       && !TYPE_UNSIGNED (TREE_TYPE (*vr0max)))
+		*vr0min
+		  = int_const_binop (MINUS_EXPR, *vr0max,
+				     build_int_cst (TREE_TYPE (*vr0max), -1));
+	      else
+		*vr0min
+		  = int_const_binop (PLUS_EXPR, *vr0max,
+				     build_int_cst (TREE_TYPE (*vr0max), 1));
 	      *vr0max = vr1max;
 	    }
 	  /* Choose the left gap if the right is empty.  */
 	  else if (maxeq)
 	    {
 	      *vr0type = VR_RANGE;
-	      if (TREE_CODE (*vr0min) == INTEGER_CST)
-		*vr0max = int_const_binop (MINUS_EXPR, *vr0min,
-					   build_int_cst (TREE_TYPE (*vr0min), 1));
-	      else
+	      if (TREE_CODE (*vr0min) != INTEGER_CST)
 		*vr0max = *vr0min;
+	      else if (TYPE_PRECISION (TREE_TYPE (*vr0min)) == 1
+		       && !TYPE_UNSIGNED (TREE_TYPE (*vr0min)))
+		*vr0max
+		  = int_const_binop (PLUS_EXPR, *vr0min,
+				     build_int_cst (TREE_TYPE (*vr0min), -1));
+	      else
+		*vr0max
+		  = int_const_binop (MINUS_EXPR, *vr0min,
+				     build_int_cst (TREE_TYPE (*vr0min), 1));
 	      *vr0min = vr1min;
 	    }
 	  /* Choose the anti-range if the range is effectively varying.  */
--- gcc/testsuite/gcc.c-torture/compile/pr80443.c.jj	2017-04-18 10:16:35.867952863 +0200
+++ gcc/testsuite/gcc.c-torture/compile/pr80443.c	2017-04-18 10:16:21.000000000 +0200
@@ -0,0 +1,20 @@ 
+/* PR tree-optimization/80443 */
+
+struct S { int a : 1; } b, c;
+signed char d, e, f;
+
+void
+foo ()
+{ 
+  while (f)
+    { 
+      signed char g = b.a;
+      if (g)
+	b.a = ~(1 + (d || c.a));
+      if (b.a < g && b.a)
+	g = 0;
+      if (b.a > c.a)
+	b.a = g;
+      c.a = e;
+    }
+}