[tree-ssa] Removal of unused vars
law@redhat.com
law@redhat.com
Thu Jun 26 05:05:00 GMT 2003
This patch allows us to eliminate a large number of the unused variables
before handing the function off to the tree->rtl translators.
Note I don't say "all the unused variables". There are some cases that
can slip through, particularly if a variable has may aliases and via
optimizations becomes unused. This will likely be improved once we figure
out a better way to handling aliasing, ADDR_EXPRs and the like.
This is a minor compile-time improvement.
This has gone through the usual battery of tests.
* tree-cfg.c (remove_useless_stmts_and_vars): On the first
iteration, remove unused variables from BIND_EXPRs.
* tree-flow.h (var_ann_d): Add new field USED.
(set_is_used): Prototype.
(remove_useless_stmts_and_vars): Update prototype.
* tree-ssa-live.c (create_ssa_var_map): Note which variables
are used so that we can delete those which are not used.
* tree-ssa.c (create_temp): Mark the new temporary as being used.
(rewrite_out_of_ssa): Note if the call to remove_useless_stmts_and_vars
is the first iteration or not.
(set_is_used): New function.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.119
diff -c -3 -p -r1.1.4.119 tree-cfg.c
*** tree-cfg.c 25 Jun 2003 02:37:31 -0000 1.1.4.119
--- tree-cfg.c 26 Jun 2003 01:01:54 -0000
*************** cleanup_tree_cfg (void)
*** 1420,1426 ****
to ensure we eliminate all the useless code. */
int
! remove_useless_stmts_and_vars (tree *first_p)
{
tree_stmt_iterator i;
int repeat = 0;
--- 1420,1426 ----
to ensure we eliminate all the useless code. */
int
! remove_useless_stmts_and_vars (tree *first_p, int first_iteration)
{
tree_stmt_iterator i;
int repeat = 0;
*************** remove_useless_stmts_and_vars (tree *fir
*** 1447,1458 ****
stmt_p = tsi_stmt_ptr (i);
code = TREE_CODE (*stmt_p);
if (code == LOOP_EXPR)
! repeat |= remove_useless_stmts_and_vars (&LOOP_EXPR_BODY (*stmt_p));
else if (code == COND_EXPR)
{
tree then_clause, else_clause, cond;
! repeat |= remove_useless_stmts_and_vars (&COND_EXPR_THEN (*stmt_p));
! repeat |= remove_useless_stmts_and_vars (&COND_EXPR_ELSE (*stmt_p));
then_clause = COND_EXPR_THEN (*stmt_p);
else_clause = COND_EXPR_ELSE (*stmt_p);
--- 1447,1461 ----
stmt_p = tsi_stmt_ptr (i);
code = TREE_CODE (*stmt_p);
if (code == LOOP_EXPR)
! repeat |= remove_useless_stmts_and_vars (&LOOP_EXPR_BODY (*stmt_p),
! first_iteration);
else if (code == COND_EXPR)
{
tree then_clause, else_clause, cond;
! repeat |= remove_useless_stmts_and_vars (&COND_EXPR_THEN (*stmt_p),
! first_iteration);
! repeat |= remove_useless_stmts_and_vars (&COND_EXPR_ELSE (*stmt_p),
! first_iteration);
then_clause = COND_EXPR_THEN (*stmt_p);
else_clause = COND_EXPR_ELSE (*stmt_p);
*************** remove_useless_stmts_and_vars (tree *fir
*** 1485,1499 ****
}
}
else if (code == SWITCH_EXPR)
! repeat |= remove_useless_stmts_and_vars (&SWITCH_BODY (*stmt_p));
else if (code == CATCH_EXPR)
! repeat |= remove_useless_stmts_and_vars (&CATCH_BODY (*stmt_p));
else if (code == EH_FILTER_EXPR)
! repeat |= remove_useless_stmts_and_vars (&EH_FILTER_FAILURE (*stmt_p));
else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
{
! repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 0));
! repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 1));
/* If the handler of a TRY_CATCH or TRY_FINALLY is empty, then
we can emit the TRY block without the enclosing TRY_CATCH_EXPR
--- 1488,1507 ----
}
}
else if (code == SWITCH_EXPR)
! repeat |= remove_useless_stmts_and_vars (&SWITCH_BODY (*stmt_p),
! first_iteration);
else if (code == CATCH_EXPR)
! repeat |= remove_useless_stmts_and_vars (&CATCH_BODY (*stmt_p),
! first_iteration);
else if (code == EH_FILTER_EXPR)
! repeat |= remove_useless_stmts_and_vars (&EH_FILTER_FAILURE (*stmt_p),
! first_iteration);
else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
{
! repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 0),
! first_iteration);
! repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 1),
! first_iteration);
/* If the handler of a TRY_CATCH or TRY_FINALLY is empty, then
we can emit the TRY block without the enclosing TRY_CATCH_EXPR
*************** remove_useless_stmts_and_vars (tree *fir
*** 1527,1533 ****
{
tree block;
/* First remove anything underneath the BIND_EXPR. */
! repeat |= remove_useless_stmts_and_vars (&BIND_EXPR_BODY (*stmt_p));
/* If the BIND_EXPR has no variables, then we can pull everything
up one level and remove the BIND_EXPR, unless this is the
--- 1535,1542 ----
{
tree block;
/* First remove anything underneath the BIND_EXPR. */
! repeat |= remove_useless_stmts_and_vars (&BIND_EXPR_BODY (*stmt_p),
! first_iteration);
/* If the BIND_EXPR has no variables, then we can pull everything
up one level and remove the BIND_EXPR, unless this is the
*************** remove_useless_stmts_and_vars (tree *fir
*** 1546,1551 ****
--- 1555,1622 ----
{
*stmt_p = BIND_EXPR_BODY (*stmt_p);
repeat = 1;
+ }
+ else if (first_iteration)
+ {
+ /* If we were unable to completely eliminate the BIND_EXPR,
+ go ahead and prune out any unused variables. We do not
+ want to expand them as that is a waste of time. If we
+ happen to remove all the variables, then we may be able
+ to eliminate the BIND_EXPR as well. */
+ tree vars, prev_var;
+
+ /* Walk all the variables associated with the BIND_EXPR. */
+ for (prev_var = NULL, vars = BIND_EXPR_VARS (*stmt_p);
+ vars;
+ vars = TREE_CHAIN (vars))
+ {
+ struct var_ann_d *ann;
+
+ /* We could have function declarations and the like
+ on this list. Ignore them. */
+ if (TREE_CODE (vars) != VAR_DECL)
+ {
+ prev_var = vars;
+ continue;
+ }
+
+ /* If the variable is not aliased and has no uses, then
+ it can be eliminated. */
+ ann = var_ann (vars);
+ if (ann
+ && ! ann->may_aliases
+ && ! ann->used
+ && ! ann->has_hidden_use)
+ {
+ /* Remove the variable from the BLOCK structures. */
+ if (block)
+ remove_decl (vars,
+ (block
+ ? block
+ : DECL_INITIAL (current_function_decl)));
+
+ /* And splice the variable out of BIND_EXPR_VARS. */
+ if (prev_var)
+ TREE_CHAIN (prev_var) = TREE_CHAIN (vars);
+ else
+ BIND_EXPR_VARS (*stmt_p) = TREE_CHAIN (vars);
+ }
+ else
+ prev_var = vars;
+ }
+
+ /* If there are no variables left after removing unused
+ variables, then go ahead and remove this BIND_EXPR. */
+ if (BIND_EXPR_VARS (*stmt_p) == NULL_TREE
+ && *stmt_p != DECL_SAVED_TREE (current_function_decl)
+ && (! block
+ || ! BLOCK_ABSTRACT_ORIGIN (block)
+ || (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block))
+ != FUNCTION_DECL)))
+ {
+ *stmt_p = BIND_EXPR_BODY (*stmt_p);
+ repeat = 1;
+ }
}
}
else if (code == GOTO_EXPR)
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.86
diff -c -3 -p -r1.1.4.86 tree-flow.h
*** tree-flow.h 24 Jun 2003 02:13:57 -0000 1.1.4.86
--- tree-flow.h 26 Jun 2003 01:01:57 -0000
*************** struct var_ann_d GTY(())
*** 103,108 ****
--- 103,112 ----
operand using add_use or set_def. */
unsigned has_real_refs : 1;
+ /* Nonzero if this variable was used after SSA optimizations were
+ applied. We set this when translating out of SSA form. */
+ unsigned used : 1;
+
/* A VAR_DECL used to associated pointers with the memory location that
they are pointing to. If IS_MEM_TAG is nonzero, then MEM_TAG is the
pointer associated to this memory tag. If IS_MEM_TAG is zero, then
*************** extern tree *last_stmt_ptr (basic_block)
*** 412,418 ****
extern basic_block is_latch_block_for (basic_block);
extern edge find_taken_edge (basic_block, tree);
extern int call_expr_flags (tree);
! extern int remove_useless_stmts_and_vars (tree *);
extern int could_trap_p (tree);
/* In tree-dfa.c */
--- 416,422 ----
extern basic_block is_latch_block_for (basic_block);
extern edge find_taken_edge (basic_block, tree);
extern int call_expr_flags (tree);
! extern int remove_useless_stmts_and_vars (tree *, int);
extern int could_trap_p (tree);
/* In tree-dfa.c */
*************** extern void debug_def_blocks (void);
*** 464,469 ****
--- 468,474 ----
extern void dump_tree_ssa_stats (FILE *);
extern void debug_tree_ssa_stats (void);
extern void ssa_remove_edge (edge);
+ extern void set_is_used (tree);
/* In tree-ssa-pre.c */
extern void tree_perform_ssapre PARAMS ((tree));
Index: tree-ssa-live.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-live.c,v
retrieving revision 1.1.2.8
diff -c -3 -p -r1.1.2.8 tree-ssa-live.c
*** tree-ssa-live.c 16 Jun 2003 18:54:00 -0000 1.1.2.8
--- tree-ssa-live.c 26 Jun 2003 01:01:59 -0000
*************** create_ssa_var_map (void)
*** 306,318 ****
--- 306,335 ----
{
use = VARRAY_GENERIC_PTR (ops, x);
register_ssa_partition (map, *use);
+ set_is_used (*use);
}
dest = def_op (stmt);
if (dest)
{
register_ssa_partition (map, *dest);
+ set_is_used (*dest);
}
+
+ /* While we do not care about virtual operands for
+ out of SSA, we do need to look at them to make sure
+ we mark all the variables which are used. */
+ ops = vuse_ops (stmt);
+ for (x = 0; ops && x < VARRAY_ACTIVE_SIZE (ops); x++)
+ set_is_used (VARRAY_TREE (ops, x));
+
+ ops = vdef_ops (stmt);
+ for (x = 0; ops && x < VARRAY_ACTIVE_SIZE (ops); x++)
+ {
+ set_is_used (VDEF_OP (VARRAY_TREE (ops, x)));
+ set_is_used (VDEF_RESULT (VARRAY_TREE (ops, x)));
+ }
+
}
/* Now register elements of PHI nodes. */
*************** create_ssa_var_map (void)
*** 324,331 ****
if (var_ann (var)->has_real_refs)
{
register_ssa_partition (map, var);
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
! register_ssa_partition (map, PHI_ARG_DEF (phi, i));
}
}
}
--- 341,352 ----
if (var_ann (var)->has_real_refs)
{
register_ssa_partition (map, var);
+ set_is_used (PHI_RESULT (phi));
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
! {
! register_ssa_partition (map, PHI_ARG_DEF (phi, i));
! set_is_used (PHI_ARG_DEF (phi, i));
! }
}
}
}
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.97
diff -c -3 -p -r1.1.4.97 tree-ssa.c
*** tree-ssa.c 25 Jun 2003 02:50:01 -0000 1.1.4.97
--- tree-ssa.c 26 Jun 2003 01:02:10 -0000
*************** create_temp (tree t)
*** 877,882 ****
--- 877,883 ----
name = "temp";
tmp = create_tmp_var (type, name);
create_var_ann (tmp);
+ set_is_used (tmp);
return tmp;
}
*************** rewrite_out_of_ssa (tree fndecl)
*** 1575,1581 ****
var_map map;
tree phi, next;
elim_graph g;
! int repeat;
timevar_push (TV_TREE_SSA_TO_NORMAL);
--- 1576,1582 ----
var_map map;
tree phi, next;
elim_graph g;
! int repeat, first_iteration;
timevar_push (TV_TREE_SSA_TO_NORMAL);
*************** rewrite_out_of_ssa (tree fndecl)
*** 1688,1696 ****
/* Do some cleanups which reduce the amount of data the
tree->rtl expanders deal with. */
do
{
! repeat = remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl));
}
while (repeat);
--- 1689,1700 ----
/* Do some cleanups which reduce the amount of data the
tree->rtl expanders deal with. */
+ first_iteration = 1;
do
{
! repeat = remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl),
! first_iteration);
! first_iteration = 0;
}
while (repeat);
*************** rewrite_stmt (block_stmt_iterator si, va
*** 2298,2303 ****
--- 2302,2318 ----
register_new_def (SSA_NAME_VAR (VDEF_RESULT (vdef)),
VDEF_RESULT (vdef), block_defs_p);
}
+ }
+
+ /* Set the USED bit in the annotation for T. */
+
+ void
+ set_is_used (tree t)
+ {
+ t = get_base_symbol (t);
+ if (TREE_CODE (t) == SSA_NAME)
+ t = SSA_NAME_VAR (t);
+ var_ann (t)->used = 1;
}
More information about the Gcc-patches
mailing list