/* Liveness for SSA trees.
- Copyright (C) 2003-2013 Free Software Foundation, Inc.
+ Copyright (C) 2003-2015 Free Software Foundation, Inc.
Contributed by Andrew MacLeod <amacleod@redhat.com>
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "gimple-pretty-print.h"
#include "bitmap.h"
-#include "tree-flow.h"
+#include "sbitmap.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "tree-dfa.h"
#include "timevar.h"
#include "dumpfile.h"
#include "tree-ssa-live.h"
#include "diagnostic-core.h"
#include "debug.h"
-#include "flags.h"
-#include "gimple.h"
+#include "tree-ssa.h"
+#include "lto-streamer.h"
+#include "cgraph.h"
+#include "ipa-utils.h"
#ifdef ENABLE_CHECKING
static void verify_live_on_entry (tree_live_info_p);
ssa_name or variable, and vice versa. */
+/* Hashtable helpers. */
+
+struct tree_int_map_hasher : nofree_ptr_hash <tree_int_map>
+{
+ static inline hashval_t hash (const tree_int_map *);
+ static inline bool equal (const tree_int_map *, const tree_int_map *);
+};
+
+inline hashval_t
+tree_int_map_hasher::hash (const tree_int_map *v)
+{
+ return tree_map_base_hash (v);
+}
+
+inline bool
+tree_int_map_hasher::equal (const tree_int_map *v, const tree_int_map *c)
+{
+ return tree_int_map_eq (v, c);
+}
+
+
/* This routine will initialize the basevar fields of MAP. */
static void
{
int x, num_part;
tree var;
- htab_t tree_to_index;
struct tree_int_map *m, *mapstorage;
num_part = num_var_partitions (map);
- tree_to_index = htab_create (num_part, tree_map_base_hash,
- tree_int_map_eq, NULL);
+ hash_table<tree_int_map_hasher> tree_to_index (num_part);
/* We can have at most num_part entries in the hash tables, so it's
enough to allocate so many map elements once, saving some malloc
calls. */
struct tree_int_map **slot;
unsigned baseindex;
var = partition_to_var (map, x);
- if (SSA_NAME_VAR (var))
+ if (SSA_NAME_VAR (var)
+ && (!VAR_P (SSA_NAME_VAR (var))
+ || !DECL_IGNORED_P (SSA_NAME_VAR (var))))
m->base.from = SSA_NAME_VAR (var);
else
/* This restricts what anonymous SSA names we can coalesce
as it restricts the sets we compute conflicts for.
Using TREE_TYPE to generate sets is the easies as
type equivalency also holds for SSA names with the same
- underlying decl. */
- m->base.from = TREE_TYPE (var);
+ underlying decl.
+
+ Check gimple_can_coalesce_p when changing this code. */
+ m->base.from = (TYPE_CANONICAL (TREE_TYPE (var))
+ ? TYPE_CANONICAL (TREE_TYPE (var))
+ : TREE_TYPE (var));
/* If base variable hasn't been seen, set it up. */
- slot = (struct tree_int_map **) htab_find_slot (tree_to_index,
- m, INSERT);
+ slot = tree_to_index.find_slot (m, INSERT);
if (!*slot)
{
baseindex = m - mapstorage;
map->num_basevars = m - mapstorage;
free (mapstorage);
- htab_delete (tree_to_index);
}
{
/* When a global var becomes used for the first time also walk its
initializer (non global ones don't have any). */
- if (set_is_used (t) && is_global_var (t))
+ if (set_is_used (t) && is_global_var (t)
+ && DECL_CONTEXT (t) == current_function_decl)
mark_all_vars_used (&DECL_INITIAL (t));
}
/* remove_unused_scope_block_p requires information about labels
done by the inliner. */
static bool
-remove_unused_scope_block_p (tree scope)
+remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
{
tree *t, *next;
bool unused = !TREE_USED (scope);
int nsubblocks = 0;
+ /* For ipa-polymorphic-call.c purposes, preserve blocks:
+ 1) with BLOCK_ABSTRACT_ORIGIN of a ctor/dtor or their clones */
+ if (inlined_polymorphic_ctor_dtor_block_p (scope, true))
+ {
+ in_ctor_dtor_block = true;
+ unused = false;
+ }
+ /* 2) inside such blocks, the outermost block with BLOCK_ABSTRACT_ORIGIN
+ being a FUNCTION_DECL. */
+ else if (in_ctor_dtor_block
+ && BLOCK_ABSTRACT_ORIGIN (scope)
+ && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (scope)) == FUNCTION_DECL)
+ {
+ in_ctor_dtor_block = false;
+ unused = false;
+ }
+
for (t = &BLOCK_VARS (scope); *t; t = next)
{
next = &DECL_CHAIN (*t);
}
for (t = &BLOCK_SUBBLOCKS (scope); *t ;)
- if (remove_unused_scope_block_p (*t))
+ if (remove_unused_scope_block_p (*t, in_ctor_dtor_block))
{
if (BLOCK_SUBBLOCKS (*t))
{
eliminated. */
else if (!nsubblocks)
;
- /* For terse debug info we can eliminate info on unused variables. */
- else if (debug_info_level == DINFO_LEVEL_NONE
- || debug_info_level == DINFO_LEVEL_TERSE)
+ /* When not generating debug info we can eliminate info on unused
+ variables. */
+ else if (!flag_auto_profile && debug_info_level == DINFO_LEVEL_NONE)
{
- /* Even for -g0/-g1 don't prune outer scopes from artificial
+ /* Even for -g0 don't prune outer scopes from artificial
functions, otherwise diagnostics using tree_nonartificial_location
will not be emitted properly. */
if (inlined_function_outer_scope_p (scope))
basic_block bb;
gimple_stmt_iterator gsi;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
unsigned i;
usedvars = BITMAP_ALLOC (NULL);
/* Walk the CFG marking all referenced symbols. */
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi;
size_t i;
mark_all_vars_used (gimple_op_ptr (gsi_stmt (gsi), i));
}
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gphi_iterator gpi = gsi_start_phis (bb);
+ !gsi_end_p (gpi);
+ gsi_next (&gpi))
{
use_operand_p arg_p;
ssa_op_iter i;
tree def;
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gpi.phi ();
if (virtual_operand_p (gimple_phi_result (phi)))
continue;
ignores them, and the second pass (if there were any) tries to remove
them. */
if (have_local_clobbers)
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi;
cfun->local_decls->truncate (dstidx);
}
- remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
+ remove_unused_scope_block_p (DECL_INITIAL (current_function_decl), false);
clear_unused_block_pointer ();
BITMAP_FREE (usedvars);
timevar_pop (TV_REMOVE_UNUSED);
}
-/* Obstack for globale liveness info bitmaps. We don't want to put these
- on the default obstack because these bitmaps can grow quite large and
- we'll hold on to all that memory until the end of the compiler run.
- As a bonus, delete_tree_live_info can destroy all the bitmaps by just
- releasing the whole obstack. */
-static bitmap_obstack liveness_bitmap_obstack;
-
/* Allocate and return a new live range information object base on MAP. */
static tree_live_info_p
live = XNEW (struct tree_live_info_d);
live->map = map;
- live->num_blocks = last_basic_block;
+ live->num_blocks = last_basic_block_for_fn (cfun);
- live->livein = XNEWVEC (bitmap_head, last_basic_block);
- FOR_EACH_BB (bb)
- bitmap_initialize (&live->livein[bb->index], &liveness_bitmap_obstack);
+ bitmap_obstack_initialize (&live->livein_obstack);
+ bitmap_obstack_initialize (&live->liveout_obstack);
+ live->livein = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+ FOR_EACH_BB_FN (bb, cfun)
+ bitmap_initialize (&live->livein[bb->index], &live->livein_obstack);
- live->liveout = XNEWVEC (bitmap_head, last_basic_block);
- FOR_EACH_BB (bb)
- bitmap_initialize (&live->liveout[bb->index], &liveness_bitmap_obstack);
+ live->liveout = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun));
+ FOR_EACH_BB_FN (bb, cfun)
+ bitmap_initialize (&live->liveout[bb->index], &live->liveout_obstack);
- live->work_stack = XNEWVEC (int, last_basic_block);
+ live->work_stack = XNEWVEC (int, last_basic_block_for_fn (cfun));
live->stack_top = live->work_stack;
- live->global = BITMAP_ALLOC (&liveness_bitmap_obstack);
+ live->global = BITMAP_ALLOC (NULL);
return live;
}
void
delete_tree_live_info (tree_live_info_p live)
{
- bitmap_obstack_release (&liveness_bitmap_obstack);
+ if (live->livein)
+ {
+ bitmap_obstack_release (&live->livein_obstack);
+ free (live->livein);
+ }
+ if (live->liveout)
+ {
+ bitmap_obstack_release (&live->liveout_obstack);
+ free (live->liveout);
+ }
+ BITMAP_FREE (live->global);
free (live->work_stack);
- free (live->liveout);
- free (live->livein);
free (live);
}
it each time. */
static void
-loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited,
- bitmap tmp)
+loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited)
{
edge e;
bool change;
edge_iterator ei;
basic_block pred_bb;
bitmap loe;
- gcc_assert (!bitmap_bit_p (visited, bb->index));
+ gcc_checking_assert (!bitmap_bit_p (visited, bb->index));
bitmap_set_bit (visited, bb->index);
+
loe = live_on_entry (live, bb);
FOR_EACH_EDGE (e, ei, bb->preds)
{
pred_bb = e->src;
- if (pred_bb == ENTRY_BLOCK_PTR)
+ if (pred_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
continue;
- /* TMP is variables live-on-entry from BB that aren't defined in the
+ /* Variables live-on-entry from BB that aren't defined in the
predecessor block. This should be the live on entry vars to pred.
Note that liveout is the DEFs in a block while live on entry is
- being calculated. */
- bitmap_and_compl (tmp, loe, &live->liveout[pred_bb->index]);
-
- /* Add these bits to live-on-entry for the pred. if there are any
+ being calculated.
+ Add these bits to live-on-entry for the pred. if there are any
changes, and pred_bb has been visited already, add it to the
revisit stack. */
- change = bitmap_ior_into (live_on_entry (live, pred_bb), tmp);
- if (bitmap_bit_p (visited, pred_bb->index) && change)
+ change = bitmap_ior_and_compl_into (live_on_entry (live, pred_bb),
+ loe, &live->liveout[pred_bb->index]);
+ if (change
+ && bitmap_bit_p (visited, pred_bb->index))
{
bitmap_clear_bit (visited, pred_bb->index);
*(live->stack_top)++ = pred_bb->index;
{
unsigned b;
basic_block bb;
- sbitmap visited = sbitmap_alloc (last_basic_block + 1);
- bitmap tmp = BITMAP_ALLOC (&liveness_bitmap_obstack);
+ sbitmap visited = sbitmap_alloc (last_basic_block_for_fn (cfun) + 1);
bitmap_clear (visited);
/* Visit all the blocks in reverse order and propagate live on entry values
into the predecessors blocks. */
- FOR_EACH_BB_REVERSE (bb)
- loe_visit_block (live, bb, visited, tmp);
+ FOR_EACH_BB_REVERSE_FN (bb, cfun)
+ loe_visit_block (live, bb, visited);
/* Process any blocks which require further iteration. */
while (live->stack_top != live->work_stack)
{
b = *--(live->stack_top);
- loe_visit_block (live, BASIC_BLOCK (b), visited, tmp);
+ loe_visit_block (live, BASIC_BLOCK_FOR_FN (cfun, b), visited);
}
- BITMAP_FREE (tmp);
sbitmap_free (visited);
}
bitmap_set_bit (&live->liveout[def_bb->index], p);
}
else
- def_bb = ENTRY_BLOCK_PTR;
+ def_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+
+ /* An undefined local variable does not need to be very alive. */
+ if (ssa_undefined_value_p (ssa_name, false))
+ return;
/* Visit each use of SSA_NAME and if it isn't in the same block as the def,
add it to the list of live on entry blocks. */
as this is where a copy would be inserted. Check to see if it is
defined in that block, or whether its live on entry. */
int index = PHI_ARG_INDEX_FROM_USE (use);
- edge e = gimple_phi_arg_edge (use_stmt, index);
- if (e->src != ENTRY_BLOCK_PTR)
+ edge e = gimple_phi_arg_edge (as_a <gphi *> (use_stmt), index);
+ if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
{
if (e->src != def_bb)
add_block = e->src;
/* Calculate the live on exit vectors based on the entry info in LIVEINFO. */
-void
+static void
calculate_live_on_exit (tree_live_info_p liveinfo)
{
basic_block bb;
edge_iterator ei;
/* live on entry calculations used liveout vectors for defs, clear them. */
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
bitmap_clear (&liveinfo->liveout[bb->index]);
/* Set all the live-on-exit bits for uses in PHIs. */
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
size_t i;
/* Mark the PHI arguments which are live on exit to the pred block. */
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
for (i = 0; i < gimple_phi_num_args (phi); i++)
{
tree t = PHI_ARG_DEF (phi, i);
if (p == NO_PARTITION)
continue;
e = gimple_phi_arg_edge (phi, i);
- if (e->src != ENTRY_BLOCK_PTR)
+ if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
bitmap_set_bit (&liveinfo->liveout[e->src->index], p);
}
}
/* Add each successors live on entry to this bock live on exit. */
FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest != EXIT_BLOCK_PTR)
+ if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
bitmap_ior_into (&liveinfo->liveout[bb->index],
live_on_entry (liveinfo, e->dest));
}
each partition. Return a new live info object. */
tree_live_info_p
-calculate_live_ranges (var_map map)
+calculate_live_ranges (var_map map, bool want_livein)
{
tree var;
unsigned i;
tree_live_info_p live;
- bitmap_obstack_initialize (&liveness_bitmap_obstack);
live = new_tree_live_info (map);
for (i = 0; i < num_var_partitions (map); i++)
{
#endif
calculate_live_on_exit (live);
+
+ if (!want_livein)
+ {
+ bitmap_obstack_release (&live->livein_obstack);
+ free (live->livein);
+ live->livein = NULL;
+ }
+
return live;
}
{
if (t++ == 0)
{
- fprintf(f, "Partition %d (", x);
+ fprintf (f, "Partition %d (", x);
print_generic_expr (f, partition_to_var (map, p), TDF_SLIM);
fprintf (f, " - ");
}
if ((flag & LIVEDUMP_ENTRY) && live->livein)
{
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
fprintf (f, "\nLive on entry to BB%d : ", bb->index);
EXECUTE_IF_SET_IN_BITMAP (&live->livein[bb->index], 0, i, bi)
if ((flag & LIVEDUMP_EXIT) && live->liveout)
{
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
fprintf (f, "\nLive on exit from BB%d : ", bb->index);
EXECUTE_IF_SET_IN_BITMAP (&live->liveout[bb->index], 0, i, bi)
/* Check for live on entry partitions and report those with a DEF in
the program. This will typically mean an optimization has done
something wrong. */
- bb = ENTRY_BLOCK_PTR;
+ bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
num = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
{
int entry_block = e->dest->index;
- if (e->dest == EXIT_BLOCK_PTR)
+ if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
continue;
for (i = 0; i < (unsigned)num_var_partitions (map); i++)
{
else
if (d == var)
{
+ /* An undefined local variable does not need to be very
+ alive. */
+ if (ssa_undefined_value_p (var, false))
+ continue;
+
/* The only way this var shouldn't be marked live on entry is
if it occurs in a PHI argument of the block. */
size_t z;
bool ok = false;
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
for (gsi = gsi_start_phis (e->dest);
!gsi_end_p (gsi) && !ok;
gsi_next (&gsi))
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
for (z = 0; z < gimple_phi_num_args (phi); z++)
if (var == gimple_phi_arg_def (phi, z))
{