[PATCH] Fix loop-header copying do-while loop detection (PR85116)

Richard Biener rguenther@suse.de
Thu Apr 26 12:22:00 GMT 2018


On Thu, 26 Apr 2018, Richard Biener wrote:

> 
> In PR85116 there's a loop which isn't optimized well, first because
> it is not header copied.  The reason is the do_while_loop_p predicate is
> "strange".  The following adds the natural test - whether the single
> latch predecessor exits the loop.  It also removes the check that
> claims that a loop header with just a condition isn't a do-while loop.
> I just realized the testcase is a bit too "special" and a simple
> one with a diamond starting in the header would have been enough.
> I'll come up with that as well and add it.

I added one, note it would not have copied the header in the end
because of extra checks elsewhere.

> Bootstrap / regtest running on x86_64-unknown-linux-gnu.

This is what I have committed.

Richard.

2018-04-26  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/85116
	* tree-ssa-loop-ch.c (do_while_loop_p): A do-while loop should
	have a loop exit from the single latch predecessor.  Remove
	case of header with just condition.
	(ch_base::copy_headers): Exclude infinite loops from any
	processing.
	(pass_ch::execute): Record exits.

	* gcc.dg/tree-ssa/copy-headers-2.c: New testcase.
	* gcc.dg/tree-ssa/copy-headers-3.c: Likewise.
	* gcc.dg/tree-ssa/copy-headers-4.c: Likewise.
	* gcc.dg/tree-ssa/loadpre6.c: Adjust.

Index: gcc/tree-ssa-loop-ch.c
===================================================================
--- gcc/tree-ssa-loop-ch.c	(revision 259669)
+++ gcc/tree-ssa-loop-ch.c	(working copy)
@@ -165,17 +165,28 @@ do_while_loop_p (struct loop *loop)
       return false;
     }
 
-  /* If the header contains just a condition, it is not a do-while loop.  */
-  stmt = last_and_only_stmt (loop->header);
-  if (stmt
-      && gimple_code (stmt) == GIMPLE_COND)
+  /* If the latch does not have a single predecessor, it is not a
+     do-while loop.  */
+  if (!single_pred_p (loop->latch))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file,
-		 "Loop %i is not do-while loop: "
-		 "header contains just condition.\n", loop->num);
+		 "Loop %i is not do-while loop: latch has multiple "
+		 "predecessors.\n", loop->num);
       return false;
     }
+
+  /* If the latch predecessor doesn't exit the loop, it is not a
+     do-while loop.  */
+  if (!loop_exits_from_bb_p (loop, single_pred (loop->latch)))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	fprintf (dump_file,
+		 "Loop %i is not do-while loop: latch predecessor "
+		 "does not exit loop.\n", loop->num);
+      return false;
+    }
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "Loop %i is do-while loop\n", loop->num);
 
@@ -305,8 +316,9 @@ ch_base::copy_headers (function *fun)
       /* If the loop is already a do-while style one (either because it was
 	 written as such, or because jump threading transformed it into one),
 	 we might be in fact peeling the first iteration of the loop.  This
-	 in general is not a good idea.  */
-      if (!process_loop_p (loop))
+	 in general is not a good idea.  Also avoid touching infinite loops.  */
+      if (!loop_has_exit_edges (loop)
+	  || !process_loop_p (loop))
 	continue;
 
       /* Iterate the header copying up to limit; this takes care of the cases
@@ -392,6 +404,15 @@ ch_base::copy_headers (function *fun)
       split_edge (loop_preheader_edge (loop));
       split_edge (loop_latch_edge (loop));
 
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  if (do_while_loop_p (loop))
+	    fprintf (dump_file, "Loop %d is now do-while loop.\n", loop->num);
+	  else
+	    fprintf (dump_file, "Loop %d is still not do-while loop.\n",
+		     loop->num);
+	}
+
       changed = true;
     }
 
@@ -409,7 +430,8 @@ unsigned int
 pass_ch::execute (function *fun)
 {
   loop_optimizer_init (LOOPS_HAVE_PREHEADERS
-		       | LOOPS_HAVE_SIMPLE_LATCHES);
+		       | LOOPS_HAVE_SIMPLE_LATCHES
+		       | LOOPS_HAVE_RECORDED_EXITS);
 
   unsigned int res = copy_headers (fun);
 
Index: gcc/testsuite/gcc.dg/tree-ssa/copy-headers-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/copy-headers-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/copy-headers-2.c	(working copy)
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ch2-details" } */
+
+int *a, *b;
+int test(int n, int k)
+{
+  int it = 0;
+  while (++it < n)
+    {
+      if (it % k == 1)
+	a[it] = 0;
+      else
+	b[it] = 1;
+    }
+}
+
+/* { dg-final { scan-tree-dump "is now do-while loop" "ch2" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/copy-headers-3.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/copy-headers-3.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/copy-headers-3.c	(working copy)
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fdump-tree-ch2-details" } */
+
+int __GIMPLE (startwith("ch"))
+test2 (int n)
+{
+bb_3:
+  if (n_1(D) > 0)
+    goto bb_3;
+  else
+    goto bb_4;
+
+bb_4:
+  return;
+
+}
+
+/* { dg-final { scan-tree-dump "is do-while loop" "ch2" } } */
+/* { dg-final { scan-tree-dump-not "is not do-while loop" "ch2" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/copy-headers-4.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/copy-headers-4.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/copy-headers-4.c	(working copy)
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ch2-details" } */
+
+int *a, *b;
+int test(int n, int k)
+{
+  int it = 0;
+  do
+    {
+      if (it % k == 1)
+	a[it] = 0;
+      else
+	b[it] = 1;
+    }
+  while (++it < n);
+}
+
+/* { dg-final { scan-tree-dump-not "is not do-while loop" "ch2" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/loadpre6.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/loadpre6.c	(revision 259669)
+++ gcc/testsuite/gcc.dg/tree-ssa/loadpre6.c	(working copy)
@@ -75,4 +75,4 @@ main (void)
 
 /* { dg-final { scan-tree-dump-not "= unexpanded_var_list;" "fre1" } } */
 /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
-/* { dg-final { scan-tree-dump-times "Insertions: 2" 1 "pre" } } */
+/* { dg-final { scan-tree-dump-times "Insertions: 1" 1 "pre" } } */



More information about the Gcc-patches mailing list