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.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

        PR tree-optimization/121829
        * cfgloopmanip.cc (create_preheader): Ensure we can insert
        at the end of a preheader.

        * gcc.dg/torture/pr121829.c: New testcase.
---
 gcc/cfgloopmanip.cc                     | 12 +++++++++++-
 gcc/testsuite/gcc.dg/torture/pr121829.c | 21 +++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr121829.c

diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index 2c28437b34d..808f730b95e 100644
--- a/gcc/cfgloopmanip.cc
+++ b/gcc/cfgloopmanip.cc
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-loop-manip.h"
 #include "dumpfile.h"
 #include "sreal.h"
+#include "tree-cfg.h"
+#include "tree-pass.h"
 
 static void copy_loops_to (class loop **, int,
                           class loop *);
@@ -1615,7 +1617,15 @@ create_preheader (class loop *loop, int flags)
             just a single successor and a normal edge.  */
           if ((flags & CP_SIMPLE_PREHEADERS)
              && ((single_entry->flags & EDGE_COMPLEX)
-                 || !single_succ_p (single_entry->src)))
+                 || !single_succ_p (single_entry->src)
+                 /* We document LOOPS_HAVE_PREHEADERS as to forming a
+                    natural place to move code outside of the loop, so it
+                    should not end with a control instruction.  */
+                 /* ???  This, and below JUMP_P check needs to be a new
+                    CFG hook. */
+                 || (cfun->curr_properties & PROP_gimple
+                     && !gsi_end_p (gsi_last_bb (single_entry->src))
+                     && stmt_ends_bb_p (*gsi_last_bb (single_entry->src)))))
             need_forwarder_block = true;
           /* If we want fallthru preheaders, also create forwarder block when
              preheader ends with a jump or has predecessors from loop.  */
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];
+}
-- 
2.51.0

Reply via email to