On Fri, 3 May 2013, Richard Biener wrote: > > 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?
The following at least gets me past bootstrapping. The rest will have to wait till monday. 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. * tree-inline.c (update_ssa_across_abnormal_edges): Also update virtual operands. * gcc.dg/torture/pr57147-1.c: New testcase. * gcc.dg/torture/pr57147-2.c: Likewise. * gcc.dg/torture/pr57147-3.c: Likewise. 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" } } */ Index: gcc/tree-inline.c =================================================================== *** gcc/tree-inline.c (revision 198577) --- gcc/tree-inline.c (working copy) *************** update_ssa_across_abnormal_edges (basic_ *** 1841,1854 **** gcc_assert ((e->flags & EDGE_EH) || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))); - if (virtual_operand_p (PHI_RESULT (phi))) - { - mark_virtual_operands_for_renaming (cfun); - continue; - } - re = find_edge (ret_bb, e->dest); ! gcc_assert (re); gcc_assert ((re->flags & (EDGE_EH | EDGE_ABNORMAL)) == (e->flags & (EDGE_EH | EDGE_ABNORMAL))); --- 1845,1852 ---- gcc_assert ((e->flags & EDGE_EH) || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))); re = find_edge (ret_bb, e->dest); ! gcc_checking_assert (re); gcc_assert ((re->flags & (EDGE_EH | EDGE_ABNORMAL)) == (e->flags & (EDGE_EH | EDGE_ABNORMAL))); Index: gcc/testsuite/gcc.dg/torture/pr57147-3.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57147-3.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57147-3.c (working copy) *************** *** 0 **** --- 1,20 ---- + /* { dg-do compile } */ + + typedef char * ptr_t; + struct __jmp_buf_tag { + }; + typedef struct __jmp_buf_tag sigjmp_buf[1]; + sigjmp_buf GC_jmp_buf; + void GC_fault_handler(int sig) + { + } + void GC_setup_temporary_fault_handler() { + GC_set_and_save_fault_handler(GC_fault_handler); + } + ptr_t GC_find_limit(ptr_t p) + { + GC_setup_temporary_fault_handler(); + if (__sigsetjmp (GC_jmp_buf, 1) == 0) + for (;;) + ; + }