diff options
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/passes.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c | 14 | ||||
-rw-r--r-- | gcc/tree-optimize.c | 1 | ||||
-rw-r--r-- | gcc/tree-pass.h | 1 | ||||
-rw-r--r-- | gcc/tree-ssa-pre.c | 132 |
6 files changed, 158 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2f8eeba..b801c83 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2005-07-12 Daniel Berlin <dberlin@dberlin.org> + + * tree-optimize.c (init_tree_optimization_passes): Add + pass_eliminate_useless_stores pass. + * tree-pass.h (pass_eliminate_useless_stores): New pass structure. + * tree-ssa-pre.c (is_copy_stmt): New function. + (follow_copies_till_vuse): Ditto. + (do_eustores): Ditto. + (gate_eustores): Ditto. + 2005-07-16 Richard Henderson <rth@redhat.com> * gcc.c (MFWRAP_SPEC): Don't wrap pthread_join or pthread_exit. diff --git a/gcc/passes.c b/gcc/passes.c index 4161723..edc75f1 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -479,6 +479,7 @@ init_optimization_passes (void) NEXT_PASS (pass_return_slot); NEXT_PASS (pass_rename_ssa_copies); NEXT_PASS (pass_early_warn_uninitialized); + NEXT_PASS (pass_eliminate_useless_stores); /* Initial scalar cleanups. */ NEXT_PASS (pass_ccp); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c new file mode 100644 index 0000000..6797ce5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-eustores-all" } */ +static int a; +int foo() +{ + int alocal; + int b; + alocal = a; + b = alocal; + a = b; +} +/* We should eliminate the store back to a. */ +/* { dg-final { scan-tree-dump-times "Eliminating useless store" 1 "eustores"} } */ +/* { dg-final { cleanup-tree-dump "eustores" } } */ diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index c29c3c6..52df0f5 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -300,7 +300,6 @@ struct tree_opt_pass pass_init_datastructures = 0 /* letter */ }; - void tree_lowering_passes (tree fn) { diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index db9a8a5..7db3751 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -282,6 +282,7 @@ extern struct tree_opt_pass pass_promote_statics; extern struct tree_opt_pass pass_return_slot; extern struct tree_opt_pass pass_reassoc; extern struct tree_opt_pass pass_rebuild_cgraph_edges; +extern struct tree_opt_pass pass_eliminate_useless_stores; /* IPA Passes */ extern struct tree_opt_pass pass_ipa_inline; diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index fbfda11..67bc6d4 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -2722,3 +2722,135 @@ struct tree_opt_pass pass_fre = TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */ 0 /* letter */ }; + +/* Return true if T is a copy statement between two ssa names. */ + +static bool +is_copy_stmt (tree t) +{ + if (!t || TREE_CODE (t) != MODIFY_EXPR) + return false; + if (TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME + && TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME) + return true; + return false; +} + +/* Starting from START, walk copy statements till we hit a statement with a + VUSE or a non-copy statement. */ + +static tree +follow_copies_till_vuse (tree start) +{ + if (is_copy_stmt (start) && ZERO_SSA_OPERANDS (start, SSA_OP_VIRTUAL_USES)) + { + tree rhs, defstmt; + + rhs = TREE_OPERAND (start, 1); + defstmt = SSA_NAME_DEF_STMT (rhs); + return follow_copies_till_vuse (defstmt); + } + return start; +} + +/* Gate and execute functions for eliminate useless stores. + The goal here is to recognize the pattern *x = ... *x, and eliminate the + store because the value hasn't changed. Store copy/const prop won't + do this because making *more* loads (IE propagating *x) is not a win, so it + ignores them. + This pass is currently geared completely towards static variable store + elimination. */ + +static void +do_eustores (void) +{ + basic_block bb; + /* For each basic block + For each statement (STMT) in the block + if STMT is a stores of the pattern *x = y + follow the chain of definitions for y, until we hit a non-copy + statement or a statement with a vuse. + if the statement we arrive at is a vuse of the operand we killed, + accessed through the same memory operation, then we have a + useless store (because it is *x = ... = *x). */ + + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); + !bsi_end_p (bsi);) + { + tree stmt = bsi_stmt (bsi); + tree startat; + tree kill; + tree found; + + if (NUM_SSA_OPERANDS (stmt, SSA_OP_VMUSTDEF) != 1 + || TREE_CODE (stmt) != MODIFY_EXPR + || TREE_CODE (TREE_OPERAND (stmt, 1)) != SSA_NAME) + { + bsi_next (&bsi); + continue; + } + + kill = MUSTDEF_KILL (MUSTDEF_OPS (stmt)); + startat = TREE_OPERAND (stmt, 1); + startat = SSA_NAME_DEF_STMT (startat); + found = follow_copies_till_vuse (startat); + + if (found && TREE_CODE (found) == MODIFY_EXPR) + { + + /* We want exactly one virtual use, and it should match up with + the use being killed. */ + + if (NUM_SSA_OPERANDS (found, SSA_OP_VUSE) != 1 + || VUSE_OP (VUSE_OPS (found)) != kill + || !operand_equal_p (TREE_OPERAND (found, 1), + TREE_OPERAND (stmt, 0), 0)) + { + bsi_next (&bsi); + continue; + } + + if (dump_file) + { + fprintf (dump_file, "Eliminating useless store "); + print_generic_stmt (dump_file, stmt, 0); + } + mark_sym_for_renaming (TREE_OPERAND (stmt, 0)); + bsi_remove (&bsi); + } + else + { + bsi_next (&bsi); + continue; + } + } + } +} + +static bool +gate_eustores(void) +{ + return flag_unit_at_a_time != 0; +} + +struct tree_opt_pass pass_eliminate_useless_stores = +{ + "eustores", /* name */ + gate_eustores, /* gate */ + do_eustores, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa | TODO_dump_func + | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */ + 0 /* letter */ +}; |