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