From 9e7c77c7933b1bb0dd07214333e52a9a896fa349 Mon Sep 17 00:00:00 2001
From: Tamar Christina <tamar.christina@arm.com>
Date: Wed, 10 Jan 2024 12:51:54 +0000
Subject: [PATCH] middle-end: Fix dominators updates when peeling with multiple
 exits [PR113144]

When we peel at_exit we are moving the new loop at the exit of the previous
loop.  This means that the blocks outside the loop dat the previous loop used to
dominate are no longer being dominated by it.

The new dominators however are hard to predict since if the loop has multiple
exits and all the exits are an "early" one then we always execute the scalar
loop.  In this case the scalar loop can completely dominate the new loop.

If we later have skip_vector then there's an additional skip edge added that
might change the dominators.

The previous patch would force an update of all blocks reachable from the new
exits.  This one updates *only* blocks that we know the scalar exits dominated.

For the examples this reduces the blocks to update from 18 to 3.

gcc/ChangeLog:

	PR tree-optimization/113144
	PR tree-optimization/113145
	* tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg):
	Update all BB that the original exits dominated.

gcc/testsuite/ChangeLog:

	PR tree-optimization/113144
	PR tree-optimization/113145
	* gcc.dg/vect/vect-early-break_94-pr113144.c: New test.
---
 .../vect/vect-early-break_94-pr113144.c       | 41 +++++++++++++++++++
 gcc/tree-vect-loop-manip.cc                   | 13 ++----
 2 files changed, 45 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_94-pr113144.c

diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_94-pr113144.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_94-pr113144.c
new file mode 100644
index 000000000000..903fe7be6621
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_94-pr113144.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-add-options vect_early_break } */
+/* { dg-require-effective-target vect_early_break } */
+/* { dg-require-effective-target vect_int } */
+
+/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
+
+long tar_atol256_max, tar_atol256_size, tar_atosl_min;
+char tar_atol256_s;
+void __errno_location();
+
+
+inline static long tar_atol256(long min) {
+  char c;
+  int sign;
+  c = tar_atol256_s;
+  sign = c;
+  while (tar_atol256_size) {
+    if (c != sign)
+      return sign ? min : tar_atol256_max;
+    c = tar_atol256_size--;
+  }
+  if ((c & 128) != (sign & 128))
+    return sign ? min : tar_atol256_max;
+  return 0;
+}
+
+inline static long tar_atol(long min) {
+  return tar_atol256(min);
+}
+
+long tar_atosl() {
+  long n = tar_atol(-1);
+  if (tar_atosl_min) {
+    __errno_location();
+    return 0;
+  }
+  if (n > 0)
+    return 0;
+  return n;
+}
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index f0ea7fc069bd..8aa7575a0e39 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -1716,8 +1716,6 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop, edge loop_exit,
 	  /* Now link the alternative exits.  */
 	  if (multiple_exits_p)
 	    {
-	      set_immediate_dominator (CDI_DOMINATORS, new_preheader,
-				       main_loop_exit_block);
 	      for (auto gsi_from = gsi_start_phis (loop->header),
 		   gsi_to = gsi_start_phis (new_preheader);
 		   !gsi_end_p (gsi_from) && !gsi_end_p (gsi_to);
@@ -1755,13 +1753,10 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop, edge loop_exit,
       if (multiple_exits_p)
 	{
 	  update_loop = new_loop;
-	  for (edge e : get_loop_exit_edges (loop))
-	    doms.safe_push (e->dest);
-	  doms.safe_push (exit_dest);
-
-	  /* Likely a fall-through edge, so update if needed.  */
-	  if (single_succ_p (exit_dest))
-	    doms.safe_push (single_succ (exit_dest));
+	  doms = get_all_dominated_blocks (CDI_DOMINATORS, loop->header);
+	  for (unsigned i = 0; i < doms.length (); ++i)
+	    if (flow_bb_inside_loop_p (loop, doms[i]))
+	      doms.unordered_remove (i);
 	}
     }
   else /* Add the copy at entry.  */
-- 
GitLab