diff mbox

[PR81388] Revert change in revision 238585

Message ID DB5PR0801MB27421754106CC1A6651F449CE7A70@DB5PR0801MB2742.eurprd08.prod.outlook.com
State New
Headers show

Commit Message

Bin Cheng July 20, 2017, 9:09 a.m. UTC
Hi,
I removed computation of may_be_zero in revision 238585 by assuming
"pointer + 2 < pointer" can be folded.  This is false when pointer could overflow,
as well as unsigned type (I don't know why it haven't been exposed for long
time in case of unsigned type).  As for the issue itself, any fix would require
may_be_zero to be computed, which basically leads to patch revert.
Bootstrap and test on x86_64 and AArch64, is it OK?

Thanks,
bin
2017-07-20  Bin Cheng  <bin.cheng@arm.com>

	PR tree-optimization/81388
	Revert r238585:
	2016-07-21  Bin Cheng  <bin.cheng@arm.com>

	* tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
	by removing computation of may_be_zero.

gcc/testsuite/ChangeLog
2017-07-20  Bin Cheng  <bin.cheng@arm.com>

	PR tree-optimization/81388
	* gcc.dg/tree-ssa/pr81388-1.c: New test.
	* gcc.dg/tree-ssa/pr81388-2.c: New test.

Comments

Richard Biener July 20, 2017, 10:45 a.m. UTC | #1
On Thu, Jul 20, 2017 at 11:09 AM, Bin Cheng <Bin.Cheng@arm.com> wrote:
> Hi,
> I removed computation of may_be_zero in revision 238585 by assuming
> "pointer + 2 < pointer" can be folded.  This is false when pointer could overflow,
> as well as unsigned type (I don't know why it haven't been exposed for long
> time in case of unsigned type).  As for the issue itself, any fix would require
> may_be_zero to be computed, which basically leads to patch revert.
> Bootstrap and test on x86_64 and AArch64, is it OK?

Ok for trunk/branch.

Thanks,
Richard.

> Thanks,
> bin
> 2017-07-20  Bin Cheng  <bin.cheng@arm.com>
>
>         PR tree-optimization/81388
>         Revert r238585:
>         2016-07-21  Bin Cheng  <bin.cheng@arm.com>
>
>         * tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
>         by removing computation of may_be_zero.
>
> gcc/testsuite/ChangeLog
> 2017-07-20  Bin Cheng  <bin.cheng@arm.com>
>
>         PR tree-optimization/81388
>         * gcc.dg/tree-ssa/pr81388-1.c: New test.
>         * gcc.dg/tree-ssa/pr81388-2.c: New test.
diff mbox

Patch

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
new file mode 100644
index 0000000..ecfe129
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-ivcanon-details" } */
+
+void bar();
+void foo(char *dst)
+{
+  char *const end = dst;
+  do {
+    bar();
+    dst += 2;
+  } while (dst < end);
+}
+
+/* { dg-final { scan-tree-dump-times " zero if " 1 "ivcanon" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81388-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-2.c
new file mode 100644
index 0000000..71fd289
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ivcanon-details" } */
+
+void bar();
+void foo(unsigned dst)
+{
+  unsigned end = dst;
+  do {
+    bar();
+    dst += 2;
+  } while (dst < end);
+}
+
+/* { dg-final { scan-tree-dump-times " zero if " 1 "ivcanon" } } */
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 5a7cab5..a872f5f 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -1142,8 +1142,12 @@  number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
   tree niter_type = TREE_TYPE (step);
   tree mod = fold_build2 (FLOOR_MOD_EXPR, niter_type, *delta, step);
   tree tmod;
-  tree assumption = boolean_true_node, bound;
-  tree type1 = (POINTER_TYPE_P (type)) ? sizetype : type;
+  mpz_t mmod;
+  tree assumption = boolean_true_node, bound, noloop;
+  bool ret = false, fv_comp_no_overflow;
+  tree type1 = type;
+  if (POINTER_TYPE_P (type))
+    type1 = sizetype;
 
   if (TREE_CODE (mod) != INTEGER_CST)
     return false;
@@ -1151,51 +1155,96 @@  number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
     mod = fold_build2 (MINUS_EXPR, niter_type, step, mod);
   tmod = fold_convert (type1, mod);
 
+  mpz_init (mmod);
+  wi::to_mpz (mod, mmod, UNSIGNED);
+  mpz_neg (mmod, mmod);
+
   /* If the induction variable does not overflow and the exit is taken,
-     then the computation of the final value does not overflow.  There
-     are three cases:
-       1) The case if the new final value is equal to the current one.
-       2) Induction varaible has pointer type, as the code cannot rely
-	  on the object to that the pointer points being placed at the
-	  end of the address space (and more pragmatically,
-	  TYPE_{MIN,MAX}_VALUE is not defined for pointers).
-       3) EXIT_MUST_BE_TAKEN is true, note it implies that the induction
-	  variable does not overflow.  */
-  if (!integer_zerop (mod) && !POINTER_TYPE_P (type) && !exit_must_be_taken)
+     then the computation of the final value does not overflow.  This is
+     also obviously the case if the new final value is equal to the
+     current one.  Finally, we postulate this for pointer type variables,
+     as the code cannot rely on the object to that the pointer points being
+     placed at the end of the address space (and more pragmatically,
+     TYPE_{MIN,MAX}_VALUE is not defined for pointers).  */
+  if (integer_zerop (mod) || POINTER_TYPE_P (type))
+    fv_comp_no_overflow = true;
+  else if (!exit_must_be_taken)
+    fv_comp_no_overflow = false;
+  else
+    fv_comp_no_overflow =
+	    (iv0->no_overflow && integer_nonzerop (iv0->step))
+	    || (iv1->no_overflow && integer_nonzerop (iv1->step));
+
+  if (integer_nonzerop (iv0->step))
     {
-      if (integer_nonzerop (iv0->step))
+      /* The final value of the iv is iv1->base + MOD, assuming that this
+	 computation does not overflow, and that
+	 iv0->base <= iv1->base + MOD.  */
+      if (!fv_comp_no_overflow)
 	{
-	  /* The final value of the iv is iv1->base + MOD, assuming
-	     that this computation does not overflow, and that
-	     iv0->base <= iv1->base + MOD.  */
 	  bound = fold_build2 (MINUS_EXPR, type1,
 			       TYPE_MAX_VALUE (type1), tmod);
 	  assumption = fold_build2 (LE_EXPR, boolean_type_node,
 				    iv1->base, bound);
+	  if (integer_zerop (assumption))
+	    goto end;
 	}
+      if (mpz_cmp (mmod, bnds->below) < 0)
+	noloop = boolean_false_node;
+      else if (POINTER_TYPE_P (type))
+	noloop = fold_build2 (GT_EXPR, boolean_type_node,
+			      iv0->base,
+			      fold_build_pointer_plus (iv1->base, tmod));
       else
+	noloop = fold_build2 (GT_EXPR, boolean_type_node,
+			      iv0->base,
+			      fold_build2 (PLUS_EXPR, type1,
+					   iv1->base, tmod));
+    }
+  else
+    {
+      /* The final value of the iv is iv0->base - MOD, assuming that this
+	 computation does not overflow, and that
+	 iv0->base - MOD <= iv1->base. */
+      if (!fv_comp_no_overflow)
 	{
-	  /* The final value of the iv is iv0->base - MOD, assuming
-	     that this computation does not overflow, and that
-	     iv0->base - MOD <= iv1->base.  */
 	  bound = fold_build2 (PLUS_EXPR, type1,
 			       TYPE_MIN_VALUE (type1), tmod);
 	  assumption = fold_build2 (GE_EXPR, boolean_type_node,
 				    iv0->base, bound);
+	  if (integer_zerop (assumption))
+	    goto end;
 	}
-      if (integer_zerop (assumption))
-	return false;
-      else if (!integer_nonzerop (assumption))
-	niter->assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
-					  niter->assumptions, assumption);
+      if (mpz_cmp (mmod, bnds->below) < 0)
+	noloop = boolean_false_node;
+      else if (POINTER_TYPE_P (type))
+	noloop = fold_build2 (GT_EXPR, boolean_type_node,
+			      fold_build_pointer_plus (iv0->base,
+						       fold_build1 (NEGATE_EXPR,
+								    type1, tmod)),
+			      iv1->base);
+      else
+	noloop = fold_build2 (GT_EXPR, boolean_type_node,
+			      fold_build2 (MINUS_EXPR, type1,
+					   iv0->base, tmod),
+			      iv1->base);
     }
 
-  /* Since we are transforming LT to NE and DELTA is constant, there
-     is no need to compute may_be_zero because this loop must roll.  */
-
+  if (!integer_nonzerop (assumption))
+    niter->assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+				      niter->assumptions,
+				      assumption);
+  if (!integer_zerop (noloop))
+    niter->may_be_zero = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				      niter->may_be_zero,
+				      noloop);
   bounds_add (bnds, wi::to_widest (mod), type);
   *delta = fold_build2 (PLUS_EXPR, niter_type, *delta, mod);
-  return true;
+
+  ret = true;
+end:
+  mpz_clear (mmod);
+  return ret;
 }
 
 /* Add assertions to NITER that ensure that the control variable of the loop