aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-tailcall.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-05-08 19:06:46 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2019-05-08 19:06:46 +0200
commitab87ac8d53f3d903bfc9eeb0f0b5e7eed1f38cbc (patch)
tree82cfaff6222e92d237be7a60aa9a5c1f2f835b38 /gcc/tree-tailcall.c
parent69708e0afbf3a3757b9f689bb54acff1d7e8d9ec (diff)
downloadgcc-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.c57
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)