re PR tree-optimization/37709 (inlining causes explosion in debug info)

PR tree-optimization/37709                                              
	* tree.c (block_ultimate_origin): Move here from dwarf2out.             
	* tree.h (block_ultimate_origin): Declare.                              
	* dwarf2out.c (block_ultimate_origin): Move to tree.c                   
	* tree-ssa-live.c (remove_unused_scope_block_p):
	Eliminate blocks containig no instructions nor live variables nor
	nested blocks.
	(dump_scope_block): New function.
	(remove_unused_locals): Enable removal of dead blocks by default;
	enable dumping at TDF_DETAILS.

From-SVN: r144381
This commit is contained in:
Jan Hubicka 2009-02-23 14:10:53 +01:00 committed by Jan Hubicka
parent 791c5e4821
commit 61e043223d
6 changed files with 117 additions and 60 deletions

View File

@ -1,3 +1,16 @@
2009-02-23 Jan Hubicka <jh@suse.cz>
PR tree-optimization/37709
* tree.c (block_ultimate_origin): Move here from dwarf2out.
* tree.h (block_ultimate_origin): Declare.
* dwarf2out.c (block_ultimate_origin): Move to tree.c
* tree-ssa-live.c (remove_unused_scope_block_p):
Eliminate blocks containig no instructions nor live variables nor
nested blocks.
(dump_scope_block): New function.
(remove_unused_locals): Enable removal of dead blocks by default;
enable dumping at TDF_DETAILS.
2008-02-21 H.J. Lu <hongjiu.lu@intel.com>
* config/i386/i386.c (classify_argument): Don't allow COImode

View File

@ -3593,7 +3593,7 @@ dbxout_block (tree block, int depth, tree args)
while (block)
{
/* Ignore blocks never expanded or otherwise marked as real. */
if (TREE_USED (block) && TREE_ASM_WRITTEN (block))
if (TREE_ASM_WRITTEN (block))
{
int did_output;
int blocknum = BLOCK_NUMBER (block);

View File

@ -4947,7 +4947,6 @@ static const char *dwarf_tag_name (unsigned);
static const char *dwarf_attr_name (unsigned);
static const char *dwarf_form_name (unsigned);
static tree decl_ultimate_origin (const_tree);
static tree block_ultimate_origin (const_tree);
static tree decl_class_context (tree);
static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
static inline enum dw_val_class AT_class (dw_attr_ref);
@ -5772,51 +5771,6 @@ decl_ultimate_origin (const_tree decl)
return DECL_ABSTRACT_ORIGIN (decl);
}
/* Determine the "ultimate origin" of a block. The block may be an inlined
instance of an inlined instance of a block which is local to an inline
function, so we have to trace all of the way back through the origin chain
to find out what sort of node actually served as the original seed for the
given block. */
static tree
block_ultimate_origin (const_tree block)
{
tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
/* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
nodes in the function to point to themselves; ignore that if
we're trying to output the abstract instance of this function. */
if (BLOCK_ABSTRACT (block) && immediate_origin == block)
return NULL_TREE;
if (immediate_origin == NULL_TREE)
return NULL_TREE;
else
{
tree ret_val;
tree lookahead = immediate_origin;
do
{
ret_val = lookahead;
lookahead = (TREE_CODE (ret_val) == BLOCK
? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
}
while (lookahead != NULL && lookahead != ret_val);
/* The block's abstract origin chain may not be the *ultimate* origin of
the block. It could lead to a DECL that has an abstract origin set.
If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
will give us if it has one). Note that DECL's abstract origins are
supposed to be the most distant ancestor (or so decl_ultimate_origin
claims), so we don't need to loop following the DECL origins. */
if (DECL_P (ret_val))
return DECL_ORIGIN (ret_val);
return ret_val;
}
}
/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
of a virtual function may refer to a base class, so we check the 'this'
parameter. */

View File

@ -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);
@ -537,10 +549,7 @@ remove_unused_scope_block_p (tree scope)
nsubblocks ++;
}
else
{
gcc_assert (!BLOCK_VARS (*t));
*t = BLOCK_CHAIN (*t);
}
*t = BLOCK_CHAIN (*t);
}
else
{
@ -576,6 +585,38 @@ 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%*sScope block #%i %s\n",indent, "" , BLOCK_NUMBER (scope),
TREE_USED (scope) ? "" : "(unused)");
if (BLOCK_ABSTRACT_ORIGIN (scope) && DECL_P (block_ultimate_origin (scope)))
{
fprintf (file, "\n%*sOriginating from ",indent + 1, "");
print_generic_decl (file, block_ultimate_origin (scope), flags);
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);
}
/* Remove local variables that are not referenced in the IL. */
@ -588,8 +629,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)
@ -716,8 +756,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_block (dump_file, 0, DECL_INITIAL (current_function_decl), false);
}
}

View File

@ -9199,4 +9199,49 @@ build_target_option_node (void)
return t;
}
/* Determine the "ultimate origin" of a block. The block may be an inlined
instance of an inlined instance of a block which is local to an inline
function, so we have to trace all of the way back through the origin chain
to find out what sort of node actually served as the original seed for the
given block. */
tree
block_ultimate_origin (const_tree block)
{
tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
/* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
nodes in the function to point to themselves; ignore that if
we're trying to output the abstract instance of this function. */
if (BLOCK_ABSTRACT (block) && immediate_origin == block)
return NULL_TREE;
if (immediate_origin == NULL_TREE)
return NULL_TREE;
else
{
tree ret_val;
tree lookahead = immediate_origin;
do
{
ret_val = lookahead;
lookahead = (TREE_CODE (ret_val) == BLOCK
? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
}
while (lookahead != NULL && lookahead != ret_val);
/* The block's abstract origin chain may not be the *ultimate* origin of
the block. It could lead to a DECL that has an abstract origin set.
If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
will give us if it has one). Note that DECL's abstract origins are
supposed to be the most distant ancestor (or so decl_ultimate_origin
claims), so we don't need to loop following the DECL origins. */
if (DECL_P (ret_val))
return DECL_ORIGIN (ret_val);
return ret_val;
}
}
#include "gt-tree.h"

View File

@ -5022,6 +5022,7 @@ extern bool gimple_alloca_call_p (const_gimple);
extern bool alloca_call_p (const_tree);
extern bool must_pass_in_stack_var_size (enum machine_mode, const_tree);
extern bool must_pass_in_stack_var_size_or_pad (enum machine_mode, const_tree);
extern tree block_ultimate_origin (const_tree);
/* In attribs.c. */