When the vectorizer removes a forwarder created earlier by split_edge
it uses redirect_edge_pred for convenience and efficiency.  That breaks
down when the edge split is originating from an asm goto as that is
a jump that needs adjustments from redirect_edge_and_branch.  The
following factores a simple vect_remove_forwarder handling this
situation appropriately.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

        PR tree-optimization/121829
        * tree-vect-loop-manip.cc (vect_remove_forwarder): New
        function.
        (slpeel_tree_duplicate_loop_to_edge_cfg): Use it.

        * gcc.dg/torture/pr121829.c: New testcase.
---
 gcc/testsuite/gcc.dg/torture/pr121829.c | 21 ++++++++++++++++
 gcc/tree-vect-loop-manip.cc             | 33 ++++++++++++++-----------
 2 files changed, 39 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr121829.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr121829.c 
b/gcc/testsuite/gcc.dg/torture/pr121829.c
new file mode 100644
index 00000000000..afcf7595a73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr121829.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+int a[1][1];
+int *b(int *);
+int c() {
+  int *d[4];
+  int **e = &d[3];
+  int f;
+  for (; f; f++)
+    d[f] = &a[1][0];
+  b(*e);
+}
+int *b(int *g) {
+  asm goto("" : : : : h);
+  int i[9];
+h:
+  int f;
+  for (f = 0; f < 9; f++)
+    i[f] = 1;
+  *g = i[4];
+}
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index 20141dbc2e5..7af70a51335 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -1459,6 +1459,21 @@ get_live_virtual_operand_on_edge (edge e)
   while (1);
 }
 
+/* Remove the single succ/pred forwarder block BB.  */
+
+static void
+vect_remove_forwarder (basic_block bb)
+{
+  edge pred = single_pred_edge (bb);
+  edge succ = single_succ_edge (bb);
+  basic_block to = single_succ (bb);
+  edge e = redirect_edge_and_branch (pred, to);
+  gcc_assert  (e == pred);
+  copy_phi_arg_into_existing_phi (succ, e);
+  delete_basic_block (bb);
+  set_immediate_dominator (CDI_DOMINATORS, to, pred->src);
+}
+
 /* Given LOOP this function generates a new copy of it and puts it
    on E which is either the entry or exit of LOOP.  If SCALAR_LOOP is
    non-NULL, assume LOOP and SCALAR_LOOP are equivalent and copy the
@@ -1858,11 +1873,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop 
*loop, edge loop_exit,
 
       /* And remove the non-necessary forwarder again.  Keep the other
          one so we have a proper pre-header for the loop at the exit edge.  */
-      redirect_edge_pred (single_succ_edge (preheader),
-                         single_pred (preheader));
-      delete_basic_block (preheader);
-      set_immediate_dominator (CDI_DOMINATORS, scalar_loop->header,
-                              loop_preheader_edge (scalar_loop)->src);
+      vect_remove_forwarder (preheader);
 
       /* Finally after wiring the new epilogue we need to update its main exit
         to the original function exit we recorded.  Other exits are already
@@ -1920,11 +1931,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop 
*loop, edge loop_exit,
       if (scalar_loop != loop)
        {
          /* Remove the non-necessary forwarder of scalar_loop again.  */
-         redirect_edge_pred (single_succ_edge (preheader),
-                             single_pred (preheader));
-         delete_basic_block (preheader);
-         set_immediate_dominator (CDI_DOMINATORS, scalar_loop->header,
-                                  loop_preheader_edge (scalar_loop)->src);
+         vect_remove_forwarder (preheader);
          preheader = split_edge (loop_preheader_edge (loop));
          entry_e = single_pred_edge (preheader);
        }
@@ -1939,11 +1946,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop 
*loop, edge loop_exit,
 
       /* And remove the non-necessary forwarder again.  Keep the other
          one so we have a proper pre-header for the loop at the exit edge.  */
-      redirect_edge_pred (single_succ_edge (new_preheader),
-                         single_pred (new_preheader));
-      delete_basic_block (new_preheader);
-      set_immediate_dominator (CDI_DOMINATORS, new_loop->header,
-                              loop_preheader_edge (new_loop)->src);
+      vect_remove_forwarder (new_preheader);
 
       /* Update dominators for multiple exits.  */
       if (multiple_exits_p)
-- 
2.43.0

Reply via email to