diff options
author | Richard Biener <rguenther@suse.de> | 2021-05-03 15:11:28 +0200 |
---|---|---|
committer | Richard Biener <rguenther@suse.de> | 2021-05-05 09:11:23 +0200 |
commit | 8ebf6b99952ada09bf9ea0144dcd1d46363b0464 (patch) | |
tree | 4c5614950602b44572548fc6f3e1be9e85584664 /gcc/tree-ssa-dce.c | |
parent | 61d48b1e2b5bae1e0e5e48af296facd61617139c (diff) | |
download | gcc-8ebf6b99952ada09bf9ea0144dcd1d46363b0464.zip gcc-8ebf6b99952ada09bf9ea0144dcd1d46363b0464.tar.gz gcc-8ebf6b99952ada09bf9ea0144dcd1d46363b0464.tar.bz2 |
middle-end/100394 - avoid DSE/DCE of pure call that throws
There is -fdelete-dead-exceptions now and we're tracking
nothrow and const/pure bits separately and I do remember that
const or pure does _not_ imply nothrow.
Now, in the light of the PR100382 fix which added a
stmt_unremovable_because_of_non_call_eh_p guard to DSEs "DCE"
I wondered how -fdelete-dead-exceptions applies to calls and
whether stmt_unremovable_because_of_non_call_eh_p doing
return (fun->can_throw_non_call_exceptions
&& !fun->can_delete_dead_exceptions
&& stmt_could_throw_p (fun, stmt));
really should conditionalize itself on
fun->can_throw_non_call_exceptions. In fact DCE happily elides
pure function calls that throw without a LHS (probably a
consistency bug). The following testcase shows this:
int x, y;
int __attribute__((pure,noinline)) foo () { if (x) throw 1; return y; }
int main()
{
int a[2];
x = 1;
try {
int res = foo ();
a[0] = res;
} catch (...) {
return 0;
}
return 1;
}
note that if you wrap foo () into another noinline
wrap_foo () { foo (); return 1; } function then we need to make
sure to not DCE this call either even though it only throws
externally.
2021-05-03 Richard Biener <rguenther@suse.de>
PR middle-end/100394
* calls.c (expand_call): Preserve possibly throwing calls.
* cfgexpand.c (expand_call_stmt): When a call can throw signal
RTL expansion there are side-effects.
* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Simplify,
mark all possibly throwing stmts necessary unless we can elide
dead EH.
* tree-ssa-dse.c (pass_dse::execute): Preserve exceptions unless
-fdelete-dead-exceptions.
* tree.h (DECL_PURE_P): Add note about exceptions.
* g++.dg/torture/pr100382.C: New testcase.
Diffstat (limited to 'gcc/tree-ssa-dce.c')
-rw-r--r-- | gcc/tree-ssa-dce.c | 29 |
1 files changed, 8 insertions, 21 deletions
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 096cfc8..c091868 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -199,14 +199,6 @@ mark_operand_necessary (tree op) static void mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) { - /* With non-call exceptions, we have to assume that all statements could - throw. If a statement could throw, it can be deemed necessary. */ - if (stmt_unremovable_because_of_non_call_eh_p (cfun, stmt)) - { - mark_stmt_necessary (stmt, true); - return; - } - /* Statements that are implicitly live. Most function calls, asm and return statements are required. Labels and GIMPLE_BIND nodes are kept because they are control flow, and we have no way of @@ -250,14 +242,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) return; - /* Most, but not all function calls are required. Function calls that - produce no result and have no side effects (i.e. const pure - functions) are unnecessary. */ - if (gimple_has_side_effects (stmt)) - { - mark_stmt_necessary (stmt, true); - return; - } /* IFN_GOACC_LOOP calls are necessary in that they are used to represent parameter (i.e. step, bound) of a lowered OpenACC partitioned loop. But this kind of partitioned loop might not @@ -269,8 +253,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) mark_stmt_necessary (stmt, true); return; } - if (!gimple_call_lhs (stmt)) - return; break; } @@ -312,19 +294,24 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) /* If the statement has volatile operands, it needs to be preserved. Same for statements that can alter control flow in unpredictable ways. */ - if (gimple_has_volatile_ops (stmt) || is_ctrl_altering_stmt (stmt)) + if (gimple_has_side_effects (stmt) || is_ctrl_altering_stmt (stmt)) { mark_stmt_necessary (stmt, true); return; } - if (stmt_may_clobber_global_p (stmt)) + /* If a statement could throw, it can be deemed necessary unless we + are allowed to remove dead EH. Test this after checking for + new/delete operators since we always elide their EH. */ + if (!cfun->can_delete_dead_exceptions + && stmt_could_throw_p (cfun, stmt)) { mark_stmt_necessary (stmt, true); return; } - if (gimple_vdef (stmt) && keep_all_vdefs_p ()) + if ((gimple_vdef (stmt) && keep_all_vdefs_p ()) + || stmt_may_clobber_global_p (stmt)) { mark_stmt_necessary (stmt, true); return; |