The following fixes a bug in gimple_purge_dead_abnormal_call_edges
which happily removes a EDGE_FALLTHRU|EDGE_ABNORMAL edge.
The CFG builder via make_edge generally seems to merge edge flags
and edges for edges between the same basic-blocks, so any
abnormal call edges we insert may shadow the edge from the
normal return.

The simplest fix is to just clear the EDGE_ABNORMAL flag in this
case.

A similar bug is in remove_fallthru_edge.  Finally we get
more decent test coverage for the non-local goto code.

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

Comments?

Richard.

2013-05-03  Richard Biener  <rguent...@suse.de>

        PR middle-end/57147
        * tree-cfg.c (gimple_purge_dead_abnormal_call_edges): If
        the edge is also fallthru, preserve it and just clear the
        abnormal flag.
        * tree-cfgcleanup.c (remove_fallthru_edge): If the edge is
        also complex, preserve that and just clear the fallthru flag.

        * gcc.dg/torture/pr57147.c: New testcase.

Index: gcc/tree-cfg.c
===================================================================
*** gcc/tree-cfg.c      (revision 198572)
--- gcc/tree-cfg.c      (working copy)
*************** gimple_purge_dead_abnormal_call_edges (b
*** 7628,7634 ****
      {
        if (e->flags & EDGE_ABNORMAL)
        {
!         remove_edge_and_dominated_blocks (e);
          changed = true;
        }
        else
--- 7648,7657 ----
      {
        if (e->flags & EDGE_ABNORMAL)
        {
!         if (e->flags & EDGE_FALLTHRU)
!           e->flags &= ~EDGE_ABNORMAL;
!         else
!           remove_edge_and_dominated_blocks (e);
          changed = true;
        }
        else
Index: gcc/tree-cfgcleanup.c
===================================================================
*** gcc/tree-cfgcleanup.c       (revision 198572)
--- gcc/tree-cfgcleanup.c       (working copy)
*************** remove_fallthru_edge (vec<edge, va_gc> *
*** 57,63 ****
    FOR_EACH_EDGE (e, ei, ev)
      if ((e->flags & EDGE_FALLTHRU) != 0)
        {
!       remove_edge_and_dominated_blocks (e);
        return true;
        }
    return false;
--- 57,66 ----
    FOR_EACH_EDGE (e, ei, ev)
      if ((e->flags & EDGE_FALLTHRU) != 0)
        {
!       if (e->flags & EDGE_COMPLEX)
!         e->flags &= ~EDGE_FALLTHRU;
!       else
!         remove_edge_and_dominated_blocks (e);
        return true;
        }
    return false;
Index: gcc/testsuite/gcc.dg/torture/pr57147-1.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr57147-1.c    (revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr57147-1.c    (working copy)
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-optimized" } */
+
+struct __jmp_buf_tag {};
+typedef struct __jmp_buf_tag jmp_buf[1];
+extern int _setjmp (struct __jmp_buf_tag __env[1]);
+
+jmp_buf g_return_jmp_buf;
+
+void SetNaClSwitchExpectations (void)
+{
+}
+void TestSyscall(void)
+{
+  SetNaClSwitchExpectations();
+  _setjmp (g_return_jmp_buf);
+}
+
+/* { dg-final { scan-tree-dump-not "builtin_unreachable" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/testsuite/gcc.dg/torture/pr57147-2.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr57147-2.c    (revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr57147-2.c    (working copy)
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-optimized" } */
+
+struct __jmp_buf_tag {};
+typedef struct __jmp_buf_tag jmp_buf[1];
+extern int _setjmp (struct __jmp_buf_tag __env[1]);
+
+jmp_buf g_return_jmp_buf;
+
+void SetNaClSwitchExpectations (void)
+{
+  __builtin_longjmp (g_return_jmp_buf, 1);
+}
+void TestSyscall(void)
+{
+  SetNaClSwitchExpectations();
+  _setjmp (g_return_jmp_buf);
+}
+
+/* { dg-final { scan-tree-dump "setjmp" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */

Reply via email to