diff options
author | Richard Biener <rguenther@suse.de> | 2013-04-19 13:39:16 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2013-04-19 13:39:16 +0000 |
commit | f6b64c35014ca111711e753be85bb99280a1e115 (patch) | |
tree | cfb5aede3dc10b27de8a955ca7bcb7bff5699aa4 /gcc/tree-cfg.c | |
parent | 01d8bf070a2ca6a10c66a81f1b5e1c00856b5bc4 (diff) | |
download | gcc-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.c | 51 |
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)) |