diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-05-08 19:06:46 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-05-08 19:06:46 +0200 |
commit | ab87ac8d53f3d903bfc9eeb0f0b5e7eed1f38cbc (patch) | |
tree | 82cfaff6222e92d237be7a60aa9a5c1f2f835b38 /gcc/tree-tailcall.c | |
parent | 69708e0afbf3a3757b9f689bb54acff1d7e8d9ec (diff) | |
download | gcc-ab87ac8d53f3d903bfc9eeb0f0b5e7eed1f38cbc.zip gcc-ab87ac8d53f3d903bfc9eeb0f0b5e7eed1f38cbc.tar.gz gcc-ab87ac8d53f3d903bfc9eeb0f0b5e7eed1f38cbc.tar.bz2 |
re PR c++/59813 (tail-call elimination didn't fire for left-shift of char to cout)
PR c++/59813
PR tree-optimization/89060
* tree-ssa-live.h (live_vars_map): New typedef.
(compute_live_vars, live_vars_at_stmt, destroy_live_vars): Declare.
* tree-ssa-live.c: Include gimple-walk.h and cfganal.h.
(struct compute_live_vars_data): New type.
(compute_live_vars_visit, compute_live_vars_1, compute_live_vars,
live_vars_at_stmt, destroy_live_vars): New functions.
* tree-tailcall.c: Include tree-ssa-live.h.
(live_vars, live_vars_vec): New global variables.
(find_tail_calls): Perform variable life analysis before punting.
(tree_optimize_tail_calls_1): Clean up live_vars and live_vars_vec.
* tree-inline.h (struct copy_body_data): Add eh_landing_pad_dest
member.
* tree-inline.c (add_clobbers_to_eh_landing_pad): Remove BB argument.
Perform variable life analysis to select variables that really need
clobbers added.
(copy_edges_for_bb): Don't call add_clobbers_to_eh_landing_pad here,
instead set id->eh_landing_pad_dest and assert it is the same.
(copy_cfg_body): Call it here if id->eh_landing_pad_dest is non-NULL.
* gcc.dg/tree-ssa/pr89060.c: New test.
From-SVN: r271013
Diffstat (limited to 'gcc/tree-tailcall.c')
-rw-r--r-- | gcc/tree-tailcall.c | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index e0265b2..f483585 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "common/common-target.h" #include "ipa-utils.h" +#include "tree-ssa-live.h" /* The file implements the tail recursion elimination. It is also used to analyze the tail calls in general, passing the results to the rtl level @@ -392,6 +393,11 @@ propagate_through_phis (tree var, edge e) return var; } +/* Argument for compute_live_vars/live_vars_at_stmt and what compute_live_vars + returns. Computed lazily, but just once for the function. */ +static live_vars_map *live_vars; +static vec<bitmap_head> live_vars_vec; + /* Finds tailcalls falling into basic block BB. The list of found tailcalls is added to the start of RET. */ @@ -519,6 +525,29 @@ find_tail_calls (basic_block bb, struct tailcall **ret) tail_recursion = true; } + /* Compute live vars if not computed yet. */ + if (live_vars == NULL) + { + unsigned int cnt = 0; + FOR_EACH_LOCAL_DECL (cfun, idx, var) + if (VAR_P (var) + && auto_var_in_fn_p (var, cfun->decl) + && may_be_aliased (var)) + { + if (live_vars == NULL) + live_vars = new live_vars_map; + live_vars->put (DECL_UID (var), cnt++); + } + if (live_vars) + live_vars_vec = compute_live_vars (cfun, live_vars); + } + + /* Determine a bitmap of variables which are still in scope after the + call. */ + bitmap local_live_vars = NULL; + if (live_vars) + local_live_vars = live_vars_at_stmt (live_vars_vec, live_vars, call); + /* Make sure the tail invocation of this function does not indirectly refer to local variables. (Passing variables directly by value is OK.) */ @@ -529,9 +558,28 @@ find_tail_calls (basic_block bb, struct tailcall **ret) && may_be_aliased (var) && (ref_maybe_used_by_stmt_p (call, var) || call_may_clobber_ref_p (call, var))) - return; + { + if (!VAR_P (var)) + { + if (local_live_vars) + BITMAP_FREE (local_live_vars); + return; + } + else + { + unsigned int *v = live_vars->get (DECL_UID (var)); + if (bitmap_bit_p (local_live_vars, *v)) + { + BITMAP_FREE (local_live_vars); + return; + } + } + } } + if (local_live_vars) + BITMAP_FREE (local_live_vars); + /* Now check the statements after the call. None of them has virtual operands, so they may only depend on the call through its return value. The return value should also be dependent on each of them, @@ -1032,6 +1080,13 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) find_tail_calls (e->src, &tailcalls); } + if (live_vars) + { + destroy_live_vars (live_vars_vec); + delete live_vars; + live_vars = NULL; + } + /* Construct the phi nodes and accumulators if necessary. */ a_acc = m_acc = NULL_TREE; for (act = tailcalls; act; act = act->next) |