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 rguent...@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