]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-cfg: Fix up gimple_merge_blocks FORCED_LABEL handling [PR99034]
authorJakub Jelinek <jakub@redhat.com>
Fri, 19 Feb 2021 11:14:39 +0000 (12:14 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 19 Mar 2021 23:27:50 +0000 (00:27 +0100)
The verifiers require that DECL_NONLOCAL or EH_LANDING_PAD_NR
labels are always the first label if there is more than one label.

When merging blocks, we don't honor that though.
On the following testcase, we try to merge blocks:
<bb 13> [count: 0]:
<L2>:
S::~S (&s);

and
<bb 15> [count: 0]:
<L0>:
resx 1

where <L2> is landing pad and <L0> is FORCED_LABEL.  And the code puts
the FORCED_LABEL before the landing pad label, violating the verification
requirements.

The following patch fixes it by moving the FORCED_LABEL after the
DECL_NONLOCAL or EH_LANDING_PAD_NR label if it is the first label.

2021-02-19  Jakub Jelinek  <jakub@redhat.com>

PR ipa/99034
* tree-cfg.c (gimple_merge_blocks): If bb a starts with eh landing
pad or non-local label, put FORCED_LABELs from bb b after that label
rather than before it.

* g++.dg/opt/pr99034.C: New test.

(cherry picked from commit 37bde2f87267908a93c07856317a28827f8284f7)

gcc/testsuite/g++.dg/opt/pr99034.C [new file with mode: 0644]
gcc/tree-cfg.c

diff --git a/gcc/testsuite/g++.dg/opt/pr99034.C b/gcc/testsuite/g++.dg/opt/pr99034.C
new file mode 100644 (file)
index 0000000..d791a14
--- /dev/null
@@ -0,0 +1,23 @@
+// PR ipa/99034
+// { dg-do compile }
+// { dg-options "-O2" }
+
+void *b[5];
+void foo (void);
+struct S { ~S (); };
+
+static inline void
+__attribute__((always_inline))
+bar (int d)
+{
+  S s;
+  while (d)
+    foo ();
+}
+
+void
+baz (void)
+{
+  bar (2);
+  __builtin_setjmp (b);
+}
index f2f2e480330334a3853e079579aa77b712b23faa..1af59fc6fe9a88231d324a9e7a0f4109d48bab2c 100644 (file)
@@ -2133,7 +2133,17 @@ gimple_merge_blocks (basic_block a, basic_block b)
          if (FORCED_LABEL (label))
            {
              gimple_stmt_iterator dest_gsi = gsi_start_bb (a);
-             gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
+             tree first_label = NULL_TREE;
+             if (!gsi_end_p (dest_gsi))
+               if (glabel *first_label_stmt
+                   = dyn_cast <glabel *> (gsi_stmt (dest_gsi)))
+                 first_label = gimple_label_label (first_label_stmt);
+             if (first_label
+                 && (DECL_NONLOCAL (first_label)
+                     || EH_LANDING_PAD_NR (first_label) != 0))
+               gsi_insert_after (&dest_gsi, stmt, GSI_NEW_STMT);
+             else
+               gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
            }
          /* Other user labels keep around in a form of a debug stmt.  */
          else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)