summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/tree-ssa-live.c115
2 files changed, 121 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8e01a599b99..3afc07702b5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2007-07-26 Jan Hubicka <jh@suse.cz>
+
+ * tree-ssa-live.c: Include debug.h and flags.h.
+ (mark_scope_block_unused): New function.
+ (remove_unused_scope_block_p): New function.
+ (remove_unused_locals): Remove unused blocks too.
+
2007-07-25 Ian Lance Taylor <iant@google.com>
* combine.c (combine_max_regno): Remove. Remove all uses.
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 4c32d487ccc..2c8491c239e 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -30,6 +30,8 @@ Boston, MA 02110-1301, USA. */
#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);
@@ -405,9 +407,15 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
void *data ATTRIBUTE_UNUSED)
{
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. */
@@ -431,6 +439,110 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
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 elliminate 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 reffers 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)
+ {
+ *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
+ *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. */
@@ -452,6 +564,7 @@ remove_unused_locals (void)
referenced_var_iterator rvi;
var_ann_t ann;
+ 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;
@@ -498,7 +611,6 @@ remove_unused_locals (void)
*cell = TREE_CHAIN (*cell);
continue;
}
-
cell = &TREE_CHAIN (*cell);
}
@@ -516,6 +628,7 @@ remove_unused_locals (void)
&& !ann->symbol_mem_tag
&& !TREE_ADDRESSABLE (t))
remove_referenced_var (t);
+ remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
}