aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2013-04-19 13:39:16 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2013-04-19 13:39:16 +0000
commitf6b64c35014ca111711e753be85bb99280a1e115 (patch)
treecfb5aede3dc10b27de8a955ca7bcb7bff5699aa4 /gcc/tree-cfg.c
parent01d8bf070a2ca6a10c66a81f1b5e1c00856b5bc4 (diff)
downloadgcc-f6b64c35014ca111711e753be85bb99280a1e115.zip
gcc-f6b64c35014ca111711e753be85bb99280a1e115.tar.gz
gcc-f6b64c35014ca111711e753be85bb99280a1e115.tar.bz2
re PR tree-optimization/56982 (Bad optimization with setjmp())
2013-04-19 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. From-SVN: r198096
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c51
1 files changed, 34 insertions, 17 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 8a36976..05bac43 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;
+ 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 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))