diff options
Diffstat (limited to 'gcc/tree-ssa-live.c')
-rw-r--r-- | gcc/tree-ssa-live.c | 147 |
1 files changed, 119 insertions, 28 deletions
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 47315184f9a..15166cc8f5e 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -1,5 +1,5 @@ /* Liveness for SSA trees. - Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Andrew MacLeod <amacleod@redhat.com> @@ -485,10 +485,13 @@ remove_unused_scope_block_p (tree scope) next = &TREE_CHAIN (*t); /* Debug info of nested function refers to the block of the - function. */ + function. We might stil call it even if all statements + of function it was nested into was elliminated. + + TODO: We can actually look into cgraph to see if function + will be output to file. */ if (TREE_CODE (*t) == FUNCTION_DECL) unused = false; - /* Remove everything we don't generate debug info for. */ else if (DECL_IGNORED_P (*t)) { @@ -506,15 +509,24 @@ remove_unused_scope_block_p (tree scope) /* 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. */ + a lot of memory. + + For sake of -g3, we keep around those vars but we don't count this as + use of block, so innermost block with no used vars and no instructions + can be considered dead. We only want to keep around blocks user can + breakpoint into and ask about value of optimized out variables. + + Similarly we need to keep around types at least until all variables of + all nested blocks are gone. We track no information on whether given + type is used or not. */ + 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); @@ -529,41 +541,60 @@ remove_unused_scope_block_p (tree scope) { tree next = BLOCK_CHAIN (*t); tree supercontext = BLOCK_SUPERCONTEXT (*t); + *t = BLOCK_SUBBLOCKS (*t); - gcc_assert (!BLOCK_CHAIN (*t)); + while (BLOCK_CHAIN (*t)) + { + BLOCK_SUPERCONTEXT (*t) = supercontext; + t = &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); - } + *t = BLOCK_CHAIN (*t); } else { t = &BLOCK_CHAIN (*t); nsubblocks ++; } + + + if (!unused) + ; /* Outer scope is always used. */ - if (!BLOCK_SUPERCONTEXT (scope) - || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL) + else 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) + /* Innermost blocks with no live variables nor statements can be always + eliminated. */ + else if (!nsubblocks) + ; + /* If there are live subblocks and we still have some unused variables + or types declared, we must keep them. + Before inliing we must not depend on debug info verbosity to keep + DECL_UIDs stable. */ + else if (!cfun->after_inlining && BLOCK_VARS (scope)) 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))))))) + /* 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) + ; + else if (BLOCK_VARS (scope)) unused = false; + /* See if this block is important for representation of inlined function. + Inlined functions are always represented by block with + block_ultimate_origin being set to FUNCTION_DECL and DECL_SOURCE_LOCATION + set... */ + else if (inlined_function_outer_scope_p (scope)) + unused = false; + else + /* Verfify that only blocks with source location set + are entry points to the inlined functions. */ + gcc_assert (BLOCK_SOURCE_LOCATION (scope) == UNKNOWN_LOCATION); return unused; } @@ -576,6 +607,57 @@ mark_all_vars_used (tree *expr_p, void *data) walk_tree (expr_p, mark_all_vars_used_1, data, NULL); } +/* Dump scope blocks. */ + +static void +dump_scope_block (FILE *file, int indent, tree scope, int flags) +{ + tree var, t; + + fprintf (file, "\n%*s{ Scope block #%i%s%s",indent, "" , BLOCK_NUMBER (scope), + TREE_USED (scope) ? "" : " (unused)", + BLOCK_ABSTRACT (scope) ? " (abstract)": ""); + if (BLOCK_SOURCE_LOCATION (scope) != UNKNOWN_LOCATION) + { + expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (scope)); + fprintf (file, " %s:%i", s.file, s.line); + } + if (BLOCK_ABSTRACT_ORIGIN (scope)) + { + tree origin = block_ultimate_origin (scope); + if (origin) + { + fprintf (file, " Originating from :"); + if (DECL_P (origin)) + print_generic_decl (file, origin, flags); + else + fprintf (file, "#%i", BLOCK_NUMBER (origin)); + } + } + fprintf (file, " \n"); + for (var = BLOCK_VARS (scope); var; var = TREE_CHAIN (var)) + { + bool used = false; + var_ann_t ann; + + if ((ann = var_ann (var)) + && ann->used) + used = true; + + fprintf (file, "%*s",indent, ""); + print_generic_decl (file, var, flags); + fprintf (file, "%s\n", used ? "" : " (unused)"); + } + for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t)) + dump_scope_block (file, indent + 2, t, flags); + fprintf (file, "\n%*s}\n",indent, ""); +} + +void +dump_scope_blocks (FILE *file, int flags) +{ + dump_scope_block (file, 0, DECL_INITIAL (current_function_decl), flags); +} /* Remove local variables that are not referenced in the IL. */ @@ -588,8 +670,7 @@ remove_unused_locals (void) var_ann_t ann; bitmap global_unused_vars = NULL; - if (optimize) - mark_scope_block_unused (DECL_INITIAL (current_function_decl)); + mark_scope_block_unused (DECL_INITIAL (current_function_decl)); /* Assume all locals are unused. */ FOR_EACH_REFERENCED_VAR (t, rvi) @@ -642,6 +723,8 @@ remove_unused_locals (void) TREE_USED (e->goto_block) = true; } + cfun->has_local_explicit_reg_vars = false; + /* Remove unmarked local vars from local_decls. */ for (cell = &cfun->local_decls; *cell; ) { @@ -663,6 +746,10 @@ remove_unused_locals (void) continue; } } + else if (TREE_CODE (var) == VAR_DECL + && DECL_HARD_REGISTER (var) + && !is_global_var (var)) + cfun->has_local_explicit_reg_vars = true; cell = &TREE_CHAIN (*cell); } @@ -710,8 +797,12 @@ remove_unused_locals (void) && !TREE_ADDRESSABLE (t) && (optimize || DECL_ARTIFICIAL (t))) remove_referenced_var (t); - if (optimize) - remove_unused_scope_block_p (DECL_INITIAL (current_function_decl)); + remove_unused_scope_block_p (DECL_INITIAL (current_function_decl)); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Scope blocks after cleanups:\n"); + dump_scope_blocks (dump_file, dump_flags); + } } |