This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR56982, handle setjmp like non-local labels
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 17 Apr 2013 13:53:43 +0200 (CEST)
- 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.
2013-04-17 Richard Biener <rguenther@suse.de>
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.
Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c (revision 198021)
--- gcc/gimplify.c (working copy)
*************** gimplify_call_expr (tree *expr_p, gimple
*** 2729,2734 ****
--- 2729,2735 ----
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);
*************** gimplify_modify_expr (tree *expr_p, gimp
*** 4968,4973 ****
--- 4969,4975 ----
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);
}
Index: gcc/tree-cfg.c
===================================================================
*** gcc/tree-cfg.c (revision 198021)
--- gcc/tree-cfg.c (working copy)
*************** make_abnormal_goto_edges (basic_block bb
*** 967,991 ****
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;
! 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;
! }
! }
}
/* Create edges for a goto statement at block BB. */
--- 971,1005 ----
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;
! 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. */
*************** call_can_make_abnormal_goto (gimple t)
*** 2147,2153 ****
{
/* If the function has no non-local labels, then a call cannot make an
abnormal transfer of control. */
! if (!cfun->has_nonlocal_label)
return false;
/* Likewise if the call has no side effects. */
--- 2161,2168 ----
{
/* If the function has no non-local labels, then a call cannot make an
abnormal transfer of control. */
! if (!cfun->has_nonlocal_label
! && !cfun->calls_setjmp)
return false;
/* Likewise if the call has no side effects. */
*************** stmt_starts_bb_p (gimple stmt, gimple pr
*** 2302,2307 ****
--- 2317,2327 ----
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;
}
*************** gimple_purge_dead_abnormal_call_edges (b
*** 7532,7538 ****
edge_iterator ei;
gimple stmt = last_stmt (bb);
! if (!cfun->has_nonlocal_label)
return false;
if (stmt && stmt_can_make_abnormal_goto (stmt))
--- 7568,7575 ----
edge_iterator ei;
gimple stmt = last_stmt (bb);
! if (!cfun->has_nonlocal_label
! && !cfun->calls_setjmp)
return false;
if (stmt && stmt_can_make_abnormal_goto (stmt))
Index: gcc/builtins.def
===================================================================
*** gcc/builtins.def (revision 198021)
--- gcc/builtins.def (working copy)
*************** DEF_GCC_BUILTIN (BUILT_IN_ISLESSG
*** 715,721 ****
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)
/* [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)
--- 715,721 ----
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_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)
Index: gcc/testsuite/gcc.c-torture/execute/pr56982.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr56982.c (revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr56982.c (working copy)
***************
*** 0 ****
--- 1,43 ----
+ #include <stdlib.h>
+ #include <setjmp.h>
+
+ 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);
+ }