tree-optimize.c (init_tree_optimization_passes): Add pass_eliminate_useless_stores...
authorDaniel Berlin <dberlin@dberlin.org>
Sun, 17 Jul 2005 17:13:53 +0000 (17:13 +0000)
committerDaniel Berlin <dberlin@gcc.gnu.org>
Sun, 17 Jul 2005 17:13:53 +0000 (17:13 +0000)
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.

From-SVN: r102112

gcc/ChangeLog
gcc/passes.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-eustores.c [new file with mode: 0644]
gcc/tree-optimize.c
gcc/tree-pass.h
gcc/tree-ssa-pre.c

index 2f8eeba2ac3690a6a7a907d6d863e3d1a2c58234..b801c83272dd0e4aed7919cee917319a275af8c4 100644 (file)
@@ -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.
index 41617232fbb9a75c939239de0ac9b6f9aa27428e..edc75f1e672a9e0508f7edec9fd1f2c40b5b9729 100644 (file)
@@ -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 (file)
index 0000000..6797ce5
--- /dev/null
@@ -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" } } */
index c29c3c6a422b6ae474f737c861fa232a68d078f9..52df0f5af6ddfbda6d238e304883f8dd35a050cf 100644 (file)
@@ -300,7 +300,6 @@ struct tree_opt_pass pass_init_datastructures =
   0                                    /* letter */
 };
 
-\f
 void
 tree_lowering_passes (tree fn)
 {
index db9a8a5af88af0cb5ce4aa724db9d49772ae1881..7db3751952faabbeab557a85a4f69397aa9d5dab 100644 (file)
@@ -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;
index fbfda11cebe12040c2d32b9e7caa4c98c9140e07..67bc6d4dd5813ca19d106040be39ed8fb09309dd 100644 (file)
@@ -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 */
+};