aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c14
-rw-r--r--gcc/tree-optimize.c1
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree-ssa-pre.c132
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 */
+};