aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-live.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-ssa-live.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-ssa-live.c')
-rw-r--r--gcc/tree-ssa-live.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 04d7b7f..e9ae8e0 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "optinfo.h"
+#include "gimple-walk.h"
+#include "cfganal.h"
static void verify_live_on_entry (tree_live_info_p);
@@ -1194,8 +1196,149 @@ calculate_live_ranges (var_map map, bool want_livein)
return live;
}
+
+/* Data structure for compute_live_vars* functions. */
+
+struct compute_live_vars_data {
+ /* Vector of bitmaps for live vars indices at the end of basic blocks,
+ indexed by bb->index. ACTIVE[ENTRY_BLOCK] must be empty bitmap,
+ ACTIVE[EXIT_BLOCK] is used for STOP_AFTER. */
+ vec<bitmap_head> active;
+ /* Work bitmap of currently live variables. */
+ bitmap work;
+ /* Set of interesting variables. Variables with uids not in this
+ hash_map are not tracked. */
+ live_vars_map *vars;
+};
+
+/* Callback for walk_stmt_load_store_addr_ops. If OP is a VAR_DECL with
+ uid set in DATA->vars, enter its corresponding index into bitmap
+ DATA->work. */
+static bool
+compute_live_vars_visit (gimple *, tree op, tree, void *pdata)
+{
+ compute_live_vars_data *data = (compute_live_vars_data *) pdata;
+ op = get_base_address (op);
+ if (op && VAR_P (op))
+ if (unsigned int *v = data->vars->get (DECL_UID (op)))
+ bitmap_set_bit (data->work, *v);
+ return false;
+}
+
+/* Helper routine for compute_live_vars, calculating the sets of live
+ variables at the end of BB, leaving the result in DATA->work.
+ If STOP_AFTER is non-NULL, stop processing after that stmt. */
+
+static void
+compute_live_vars_1 (basic_block bb, compute_live_vars_data *data,
+ gimple *stop_after)
+{
+ edge e;
+ edge_iterator ei;
+ gimple_stmt_iterator gsi;
+ walk_stmt_load_store_addr_fn visit = compute_live_vars_visit;
+
+ bitmap_clear (data->work);
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ bitmap_ior_into (data->work, &data->active[e->src->index]);
+
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ walk_stmt_load_store_addr_ops (gsi_stmt (gsi), data, NULL, NULL, visit);
+ for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gimple_clobber_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ if (VAR_P (lhs))
+ if (unsigned int *v = data->vars->get (DECL_UID (lhs)))
+ bitmap_clear_bit (data->work, *v);
+ }
+ else if (!is_gimple_debug (stmt))
+ walk_stmt_load_store_addr_ops (stmt, data, visit, visit, visit);
+ if (stmt == stop_after)
+ break;
+ }
+}
+
+/* For function FN and live_vars_map (hash map from DECL_UIDs to a dense set of
+ indexes of automatic variables VARS, compute which of those variables are
+ (might be) live at the end of each basic block. */
+
+vec<bitmap_head>
+compute_live_vars (struct function *fn, live_vars_map *vars)
+{
+ vec<bitmap_head> active;
+ /* We approximate the live range of a stack variable by taking the first
+ mention of its name as starting point(s), and by the end-of-scope
+ death clobber added by gimplify as ending point(s) of the range.
+ This overapproximates in the case we for instance moved an address-taken
+ operation upward, without also moving a dereference to it upwards.
+ But it's conservatively correct as a variable never can hold values
+ before its name is mentioned at least once.
+
+ We then do a mostly classical bitmap liveness algorithm. */
+
+ active.create (last_basic_block_for_fn (fn));
+ active.quick_grow (last_basic_block_for_fn (fn));
+ for (int i = 0; i < last_basic_block_for_fn (fn); i++)
+ bitmap_initialize (&active[i], &bitmap_default_obstack);
+
+ bitmap work = BITMAP_ALLOC (NULL);
+
+ int *rpo = XNEWVEC (int, last_basic_block_for_fn (fn));
+ int n_bbs = pre_and_rev_post_order_compute_fn (fn, NULL, rpo, false);
+
+ bool changed = true;
+ compute_live_vars_data data = { active, work, vars };
+ while (changed)
+ {
+ int i;
+ changed = false;
+ for (i = 0; i < n_bbs; i++)
+ {
+ basic_block bb = BASIC_BLOCK_FOR_FN (fn, rpo[i]);
+ compute_live_vars_1 (bb, &data, NULL);
+ if (bitmap_ior_into (&active[bb->index], work))
+ changed = true;
+ }
+ }
+
+ free (rpo);
+ BITMAP_FREE (work);
+
+ return active;
+}
+
+/* For ACTIVE computed by compute_live_vars, compute a bitmap of variables
+ live after the STOP_AFTER statement and return that bitmap. */
+
+bitmap
+live_vars_at_stmt (vec<bitmap_head> &active, live_vars_map *vars,
+ gimple *stop_after)
+{
+ bitmap work = BITMAP_ALLOC (NULL);
+ compute_live_vars_data data = { active, work, vars };
+ basic_block bb = gimple_bb (stop_after);
+ compute_live_vars_1 (bb, &data, stop_after);
+ return work;
+}
+
+/* Destroy what compute_live_vars has returned when it is no longer needed. */
+
+void
+destroy_live_vars (vec<bitmap_head> &active)
+{
+ unsigned len = active.length ();
+ for (unsigned i = 0; i < len; i++)
+ bitmap_clear (&active[i]);
+
+ active.release ();
+}
+
/* Output partition map MAP to file F. */
void