From f1c6789ab6c5443ccefab96c74b0e862119d1781 Mon Sep 17 00:00:00 2001
From: Tamar Christina <Tamar.Christina@arm.com>
Date: Mon, 8 Jul 2024 12:16:11 +0100
Subject: [PATCH] vect: Fix dominators when adding a guard to skip the vector
 loop [PR118211]

The alignment peeling changes exposed a latent missing dominator update
with early break vectorization, specifically when inserting the vector
skip edge, since the new edge bypasses the prolog skip block and thus
has the potential to subvert its dominance.  This patch fixes that.

gcc/ChangeLog:

	PR tree-optimization/118211
	PR tree-optimization/116126
	* tree-vect-loop-manip.cc (vect_do_peeling): Update immediate
	dominators of nodes that were dominated by the prolog skip block
	after inserting vector skip edge.  Initialize prolog variable to
	NULL to avoid bogus -Wmaybe-uninitialized during bootstrap.

gcc/testsuite/ChangeLog:

	PR tree-optimization/118211
	PR tree-optimization/116126
	* g++.dg/vect/vect-early-break_6.cc: New test.

Co-Authored-By: Alex Coplan <alex.coplan@arm.com>
---
 .../g++.dg/vect/vect-early-break_6.cc         | 25 ++++++++++++++++++
 gcc/tree-vect-loop-manip.cc                   | 26 ++++++++++++++++++-
 2 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/vect/vect-early-break_6.cc

diff --git a/gcc/testsuite/g++.dg/vect/vect-early-break_6.cc b/gcc/testsuite/g++.dg/vect/vect-early-break_6.cc
new file mode 100644
index 000000000000..fdd9af832a74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/vect-early-break_6.cc
@@ -0,0 +1,25 @@
+// { dg-do compile }
+// ICE in verify_dominators, reduced from charset.cc (libstdc++).
+
+void convert_escape(int *);
+int cpp_interpret_string_1_to, cpp_interpret_string_1_tbuf;
+char *cpp_interpret_string_1_base;
+char cpp_interpret_string_1_limit;
+void cpp_interpret_string_1() {
+  char *p;
+  for (;;) {
+    cpp_interpret_string_1_base = p;
+    while (p < &cpp_interpret_string_1_limit && *p)
+      p++;
+    if (p > cpp_interpret_string_1_base)
+      if (cpp_interpret_string_1_to)
+        goto fail;
+    if (p >= &cpp_interpret_string_1_limit)
+      break;
+    int *tbuf_ptr =
+        cpp_interpret_string_1_to ? &cpp_interpret_string_1_tbuf : __null;
+    convert_escape(tbuf_ptr);
+  }
+fail:
+  ;
+}
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index 4505e5d87ddb..9a55a5611ccc 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -3197,7 +3197,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
   prob_prolog = prob_epilog = profile_probability::guessed_always ()
 			.apply_scale (estimated_vf - 1, estimated_vf);
 
-  class loop *prolog, *epilog = NULL;
+  class loop *prolog = NULL, *epilog = NULL;
   class loop *first_loop = loop;
   bool irred_flag = loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP;
 
@@ -3464,6 +3464,30 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
 	  skip_e = guard_e;
 	  e = EDGE_PRED (guard_to, 0);
 	  e = (e != guard_e ? e : EDGE_PRED (guard_to, 1));
+
+	  /* Handle any remaining dominator updates needed after
+	     inserting the loop skip edge above.  */
+	  if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
+	      && prolog_peeling)
+	    {
+	      /* Adding a skip edge to skip a loop with multiple exits
+		 means the dominator of the join blocks for all exits shifts
+		 from the prolog skip guard to the loop skip guard.  */
+	      auto prolog_skip_bb
+		= single_pred (loop_preheader_edge (prolog)->src);
+	      auto needs_update
+		= get_dominated_by (CDI_DOMINATORS, prolog_skip_bb);
+
+	      /* Update everything except for the immediate children of
+		 the prolog skip block (the prolog and vector preheaders).
+		 Those should remain dominated by the prolog skip block itself,
+		 since the loop guard edge goes to the epilogue.  */
+	      for (auto bb : needs_update)
+		if (bb != EDGE_SUCC (prolog_skip_bb, 0)->dest
+		    && bb != EDGE_SUCC (prolog_skip_bb, 1)->dest)
+		  set_immediate_dominator (CDI_DOMINATORS, bb, guard_bb);
+	    }
+
 	  slpeel_update_phi_nodes_for_guard1 (first_loop, epilog, guard_e, e);
 
 	  /* Simply propagate profile info from guard_bb to guard_to which is
-- 
GitLab