/* Liveness for SSA trees.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Contributed by Andrew MacLeod <amacleod@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "tree-dump.h"
#include "tree-ssa-live.h"
#include "toplev.h"
+#include "debug.h"
+#include "flags.h"
#ifdef ENABLE_CHECKING
static void verify_live_on_entry (tree_live_info_p);
}
-static inline void mark_all_vars_used (tree *);
+static inline void mark_all_vars_used (tree *, void *data);
/* Helper function for mark_all_vars_used, called via walk_tree. */
static tree
mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
- void *data ATTRIBUTE_UNUSED)
+ void *data)
{
tree t = *tp;
+ enum tree_code_class c = TREE_CODE_CLASS (TREE_CODE (t));
+ tree b;
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
+ if ((IS_EXPR_CODE_CLASS (c)
+ || IS_GIMPLE_STMT_CODE_CLASS (c))
+ && (b = TREE_BLOCK (t)) != NULL)
+ TREE_USED (b) = true;
/* Ignore TREE_ORIGINAL for TARGET_MEM_REFS, as well as other
fields that do not contain vars. */
if (TREE_CODE (t) == TARGET_MEM_REF)
{
- mark_all_vars_used (&TMR_SYMBOL (t));
- mark_all_vars_used (&TMR_BASE (t));
- mark_all_vars_used (&TMR_INDEX (t));
+ mark_all_vars_used (&TMR_SYMBOL (t), data);
+ mark_all_vars_used (&TMR_BASE (t), data);
+ mark_all_vars_used (&TMR_INDEX (t), data);
*walk_subtrees = 0;
return NULL;
}
/* Only need to mark VAR_DECLS; parameters and return results are not
eliminated as unused. */
if (TREE_CODE (t) == VAR_DECL)
- set_is_used (t);
+ {
+ if (data != NULL && bitmap_bit_p ((bitmap) data, DECL_UID (t)))
+ {
+ bitmap_clear_bit ((bitmap) data, DECL_UID (t));
+ mark_all_vars_used (&DECL_INITIAL (t), data);
+ }
+ set_is_used (t);
+ }
if (IS_TYPE_OR_DECL_P (t))
*walk_subtrees = 0;
return NULL;
}
+/* Mark the scope block SCOPE and its subblocks unused when they can be
+ possibly eliminated if dead. */
+
+static void
+mark_scope_block_unused (tree scope)
+{
+ tree t;
+ TREE_USED (scope) = false;
+ if (!(*debug_hooks->ignore_block) (scope))
+ TREE_USED (scope) = true;
+ for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t))
+ mark_scope_block_unused (t);
+}
+
+/* Look if the block is dead (by possibly eliminating its dead subblocks)
+ and return true if so.
+ Block is declared dead if:
+ 1) No statements are associated with it.
+ 2) Declares no live variables
+ 3) All subblocks are dead
+ or there is precisely one subblocks and the block
+ has same abstract origin as outer block and declares
+ no variables, so it is pure wrapper.
+ When we are not outputting full debug info, we also eliminate dead variables
+ out of scope blocks to let them to be recycled by GGC and to save copying work
+ done by the inliner. */
+
+static bool
+remove_unused_scope_block_p (tree scope)
+{
+ tree *t, *next;
+ bool unused = !TREE_USED (scope);
+ var_ann_t ann;
+ int nsubblocks = 0;
+
+ for (t = &BLOCK_VARS (scope); *t; t = next)
+ {
+ next = &TREE_CHAIN (*t);
+
+ /* Debug info of nested function refers to the block of the
+ function. */
+ if (TREE_CODE (*t) == FUNCTION_DECL)
+ unused = false;
+
+ /* When we are outputting debug info, we usually want to output
+ info about optimized-out variables in the scope blocks.
+ Exception are the scope blocks not containing any instructions
+ at all so user can't get into the scopes at first place. */
+ else if ((ann = var_ann (*t)) != NULL
+ && ann->used)
+ unused = false;
+
+ /* When we are not doing full debug info, we however can keep around
+ only the used variables for cfgexpand's memory packing saving quite
+ a lot of memory. */
+ else if (debug_info_level == DINFO_LEVEL_NORMAL
+ || debug_info_level == DINFO_LEVEL_VERBOSE
+ /* Removing declarations before inlining is going to affect
+ DECL_UID that in turn is going to affect hashtables and
+ code generation. */
+ || !cfun->after_inlining)
+ unused = false;
+
+ else
+ {
+ *t = TREE_CHAIN (*t);
+ next = t;
+ }
+ }
+
+ for (t = &BLOCK_SUBBLOCKS (scope); *t ;)
+ if (remove_unused_scope_block_p (*t))
+ {
+ if (BLOCK_SUBBLOCKS (*t))
+ {
+ tree next = BLOCK_CHAIN (*t);
+ tree supercontext = BLOCK_SUPERCONTEXT (*t);
+ *t = BLOCK_SUBBLOCKS (*t);
+ gcc_assert (!BLOCK_CHAIN (*t));
+ BLOCK_CHAIN (*t) = next;
+ BLOCK_SUPERCONTEXT (*t) = supercontext;
+ t = &BLOCK_CHAIN (*t);
+ nsubblocks ++;
+ }
+ else
+ {
+ gcc_assert (!BLOCK_VARS (*t));
+ *t = BLOCK_CHAIN (*t);
+ }
+ }
+ else
+ {
+ t = &BLOCK_CHAIN (*t);
+ nsubblocks ++;
+ }
+ /* Outer scope is always used. */
+ if (!BLOCK_SUPERCONTEXT (scope)
+ || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL)
+ unused = false;
+ /* If there are more than one live subblocks, it is used. */
+ else if (nsubblocks > 1)
+ unused = false;
+ /* When there is only one subblock, see if it is just wrapper we can
+ ignore. Wrappers are not declaring any variables and not changing
+ abstract origin. */
+ else if (nsubblocks == 1
+ && (BLOCK_VARS (scope)
+ || ((debug_info_level == DINFO_LEVEL_NORMAL
+ || debug_info_level == DINFO_LEVEL_VERBOSE)
+ && ((BLOCK_ABSTRACT_ORIGIN (scope)
+ != BLOCK_ABSTRACT_ORIGIN (BLOCK_SUPERCONTEXT (scope)))))))
+ unused = false;
+ return unused;
+}
/* Mark all VAR_DECLS under *EXPR_P as used, so that they won't be
eliminated during the tree->rtl conversion process. */
static inline void
-mark_all_vars_used (tree *expr_p)
+mark_all_vars_used (tree *expr_p, void *data)
{
- walk_tree (expr_p, mark_all_vars_used_1, NULL, NULL);
+ walk_tree (expr_p, mark_all_vars_used_1, data, NULL);
}
tree t, *cell;
referenced_var_iterator rvi;
var_ann_t ann;
+ bitmap global_unused_vars = NULL;
+ mark_scope_block_unused (DECL_INITIAL (current_function_decl));
/* Assume all locals are unused. */
FOR_EACH_REFERENCED_VAR (t, rvi)
var_ann (t)->used = false;
/* Walk the statements. */
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- mark_all_vars_used (bsi_stmt_ptr (bsi));
+ mark_all_vars_used (bsi_stmt_ptr (bsi), NULL);
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
continue;
def = PHI_RESULT (phi);
- mark_all_vars_used (&def);
+ mark_all_vars_used (&def, NULL);
FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_ALL_USES)
{
tree arg = USE_FROM_PTR (arg_p);
- mark_all_vars_used (&arg);
+ mark_all_vars_used (&arg, NULL);
}
}
}
- /* Remove unmarked vars and clear used flag. */
- for (cell = &cfun->unexpanded_var_list; *cell; )
+ /* Remove unmarked local vars from local_decls. */
+ for (cell = &cfun->local_decls; *cell; )
{
tree var = TREE_VALUE (*cell);
&& (!(ann = var_ann (var))
|| !ann->used))
{
- *cell = TREE_CHAIN (*cell);
- continue;
+ if (is_global_var (var))
+ {
+ if (global_unused_vars == NULL)
+ global_unused_vars = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (global_unused_vars, DECL_UID (var));
+ }
+ else
+ {
+ *cell = TREE_CHAIN (*cell);
+ continue;
+ }
}
-
cell = &TREE_CHAIN (*cell);
}
- /* Remove unused variables from REFERENCED_VARs. As an special exception
- keep the variables that are believed to be aliased. Those can't be
- easilly removed from the alias sets and and operand caches.
- They will be removed shortly after next may_alias pass is performed. */
+ /* Remove unmarked global vars from local_decls. */
+ if (global_unused_vars != NULL)
+ {
+ for (t = cfun->local_decls; t; t = TREE_CHAIN (t))
+ {
+ tree var = TREE_VALUE (t);
+
+ if (TREE_CODE (var) == VAR_DECL
+ && is_global_var (var)
+ && (ann = var_ann (var)) != NULL
+ && ann->used)
+ mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
+ }
+
+ for (cell = &cfun->local_decls; *cell; )
+ {
+ tree var = TREE_VALUE (*cell);
+
+ if (TREE_CODE (var) == VAR_DECL
+ && is_global_var (var)
+ && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
+ *cell = TREE_CHAIN (*cell);
+ else
+ cell = &TREE_CHAIN (*cell);
+ }
+ BITMAP_FREE (global_unused_vars);
+ }
+
+ /* Remove unused variables from REFERENCED_VARs. As a special
+ exception keep the variables that are believed to be aliased.
+ Those can't be easily removed from the alias sets and operand
+ caches. They will be removed shortly after the next may_alias
+ pass is performed. */
FOR_EACH_REFERENCED_VAR (t, rvi)
if (!is_global_var (t)
&& !MTAG_P (t)
&& TREE_CODE (t) != PARM_DECL
&& TREE_CODE (t) != RESULT_DECL
&& !(ann = var_ann (t))->used
- && !ann->is_aliased && !is_call_clobbered (t) && !ann->symbol_mem_tag)
- remove_referenced_var (t);
+ && !ann->symbol_mem_tag
+ && !TREE_ADDRESSABLE (t))
+ remove_referenced_var (t);
+ remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
}
}
-/* Visit basic block BB and propogate any required live on entry bits from
+/* Visit basic block BB and propagate any required live on entry bits from
LIVE into the predecessors. VISITED is the bitmap of visited blocks.
TMP is a temporary work bitmap which is passed in to avoid reallocating
it each time. */
sbitmap_zero (visited);
- /* Visit all the blocks in reverse order and propogate live on entry values
+ /* 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);