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:
parent
791c5e4821
commit
61e043223d
6 changed files with 117 additions and 60 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
45
gcc/tree.c
45
gcc/tree.c
|
@ -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"
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue