From f6b64c35014ca111711e753be85bb99280a1e115 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 19 Apr 2013 13:39:16 +0000 Subject: [PATCH] re PR tree-optimization/56982 (Bad optimization with setjmp()) 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.c-torture/execute/pr56982.c: New testcase. From-SVN: r198096 --- gcc/ChangeLog | 15 +++++ gcc/builtins.def | 2 +- gcc/gimplify.c | 2 + gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.c-torture/execute/pr56982.c | 43 +++++++++++++++ gcc/tree-cfg.c | 55 ++++++++++++------- 6 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr56982.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8bdf2a9cf76..e2aca327abe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +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. + 2013-04-19 Richard Biener * tree-vectorizer.h (struct _slp_instance): Move load_permutation diff --git a/gcc/builtins.def b/gcc/builtins.def index 4f378fad60b..b26eb247491 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -715,7 +715,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISLESSGREATER, "islessgreater", BT_FN_INT_VAR, 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) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index a93ce7c2ad2..3a90588424c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2729,6 +2729,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) 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); @@ -4968,6 +4969,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, 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); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 58b0fca12ce..a31889a3b29 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-04-19 Richard Biener + + PR tree-optimization/56982 + * gcc.c-torture/execute/pr56982.c: New testcase. + 2013-04-19 Martin Jambor PR tree-optimization/56718 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr56982.c b/gcc/testsuite/gcc.c-torture/execute/pr56982.c new file mode 100644 index 00000000000..371a91c7f86 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr56982.c @@ -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); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 8a36976cc3b..05bac430f50 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -967,25 +967,35 @@ make_abnormal_goto_edges (basic_block bb, bool for_call) 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; - - 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_edge (bb, target_bb, EDGE_ABNORMAL); + if (gimple_code (label_stmt) != GIMPLE_LABEL) break; - } - } + + 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_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); + } + } } /* 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 prev_stmt) 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; } @@ -7532,7 +7548,8 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb) 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))