[backport gcc-4.9/trunk r198096 ] List-Archive: Date: Wed, 17 Apr 2013 13:53:43 +0200 (CEST) From: Richard Biener Subject: [PATCH] Fix PR56982, handle setjmp like non-local labels This fixes PR56982 by properly modeling the control-flow of setjmp. It basically behaves as a non-local goto target so this patch treats it so - it makes it start a basic-block and get abnormal edges from possible sources of non-local gotos. The patch also fixes the bug that longjmp is marked as "leaf". Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk? What about release branches (after it had some time to settle on trunk of course)? Thanks, Richard. gcc/ 2013-04-19 Richard Biener PR tree-optimization/56982 * builtins.def (BUILT_IN_LONGJMP): longjmp is not a leaf function. * gimplify.c (gimplify_call_expr): Notice special calls. (gimplify_modify_expr): Likewise. * tree-cfg.c (make_abnormal_goto_edges): Handle setjmp-like abnormal control flow receivers. (call_can_make_abnormal_goto): Handle cfun->calls_setjmp in the same way as cfun->has_nonlocal_labels. (gimple_purge_dead_abnormal_call_edges): Likewise. (stmt_starts_bb_p): Make setjmp-like abnormal control flow receivers start a basic-block. gcc/testsuite/ 2013-04-19 Richard Biener PR tree-optimization/56982 * gcc.c-torture/execute/pr56982.c: New testcase. --- gcc-4.8.0/gcc/builtins.def.~1~ 2013-01-10 21:38:27.000000000 +0100 +++ gcc-4.8.0/gcc/builtins.def 2013-04-20 13:08:25.325268757 +0200 @@ -715,7 +715,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISLESSG DEF_GCC_BUILTIN (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST) -DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST) +DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LIST) /* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed. */ DEF_LIB_BUILTIN (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST) --- gcc-4.8.0/gcc/gimplify.c.~1~ 2013-01-28 15:05:40.000000000 +0100 +++ gcc-4.8.0/gcc/gimplify.c 2013-04-20 13:08:25.335268715 +0200 @@ -2729,6 +2729,7 @@ gimplify_call_expr (tree *expr_p, gimple gimple_stmt_iterator gsi; call = gimple_build_call_from_tree (*expr_p); gimple_call_set_fntype (call, TREE_TYPE (fnptrtype)); + notice_special_calls (call); gimplify_seq_add_stmt (pre_p, call); gsi = gsi_last (*pre_p); fold_stmt (&gsi); @@ -4963,6 +4964,7 @@ gimplify_modify_expr (tree *expr_p, gimp STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p)); assign = gimple_build_call_from_tree (*from_p); gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype)); + notice_special_calls (assign); if (!gimple_call_noreturn_p (assign)) gimple_call_set_lhs (assign, *to_p); } --- gcc-4.8.0/gcc/testsuite/gcc.c-torture/execute/pr56982.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8.0/gcc/testsuite/gcc.c-torture/execute/pr56982.c 2013-04-20 13:08:25.325268757 +0200 @@ -0,0 +1,43 @@ +#include +#include + +static sigjmp_buf env; +void *stderr; +void baz (void) +{ + __asm__ volatile ("" : : : "memory"); +} + +static inline int g(int x) +{ + if (x) + { + baz(); + return 0; + } + else + { + baz(); + return 1; + } +} + +int f(int *e) +{ + if (*e) + return 1; + + int x = setjmp(env); + int n = g(x); + if (n == 0) + exit(0); + if (x) + abort(); + longjmp(env, 42); +} + +int main(int argc, char** argv) +{ + int v = 0; + return f(&v); +} --- gcc-4.8.0/gcc/tree-cfg.c.~1~ 2013-03-08 14:46:18.000000000 +0100 +++ gcc-4.8.0/gcc/tree-cfg.c 2013-04-20 13:08:25.335268715 +0200 @@ -967,25 +967,35 @@ make_abnormal_goto_edges (basic_block bb gimple_stmt_iterator gsi; FOR_EACH_BB (target_bb) - for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple label_stmt = gsi_stmt (gsi); - tree target; + { + for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple label_stmt = gsi_stmt (gsi); + tree target; - if (gimple_code (label_stmt) != GIMPLE_LABEL) - break; + if (gimple_code (label_stmt) != GIMPLE_LABEL) + break; - target = gimple_label_label (label_stmt); + target = gimple_label_label (label_stmt); - /* Make an edge to every label block that has been marked as a - potential target for a computed goto or a non-local goto. */ - if ((FORCED_LABEL (target) && !for_call) - || (DECL_NONLOCAL (target) && for_call)) - { + /* Make an edge to every label block that has been marked as a + potential target for a computed goto or a non-local goto. */ + if ((FORCED_LABEL (target) && !for_call) + || (DECL_NONLOCAL (target) && for_call)) + { + make_edge (bb, target_bb, EDGE_ABNORMAL); + break; + } + } + if (!gsi_end_p (gsi)) + { + /* Make an edge to every setjmp-like call. */ + gimple call_stmt = gsi_stmt (gsi); + if (is_gimple_call (call_stmt) + && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE)) make_edge (bb, target_bb, EDGE_ABNORMAL); - break; - } - } + } + } } /* Create edges for a goto statement at block BB. */ @@ -2147,7 +2157,8 @@ call_can_make_abnormal_goto (gimple t) { /* If the function has no non-local labels, then a call cannot make an abnormal transfer of control. */ - if (!cfun->has_nonlocal_label) + if (!cfun->has_nonlocal_label + && !cfun->calls_setjmp) return false; /* Likewise if the call has no side effects. */ @@ -2302,6 +2313,11 @@ stmt_starts_bb_p (gimple stmt, gimple pr else return true; } + else if (gimple_code (stmt) == GIMPLE_CALL + && gimple_call_flags (stmt) & ECF_RETURNS_TWICE) + /* setjmp acts similar to a nonlocal GOTO target and thus should + start a new block. */ + return true; return false; } @@ -7466,7 +7482,8 @@ gimple_purge_dead_abnormal_call_edges (b edge_iterator ei; gimple stmt = last_stmt (bb); - if (!cfun->has_nonlocal_label) + if (!cfun->has_nonlocal_label + && !cfun->calls_setjmp) return false; if (stmt && stmt_can_make_abnormal_goto (stmt))