OSDN Git Service

PR tree-optimize/22348
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-pre.c
index c0b8e45..d83b5e4 100644 (file)
@@ -17,14 +17,13 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "errors.h"
 #include "ggc.h"
 #include "tree.h"
 #include "basic-block.h"
@@ -1529,8 +1528,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
 
        if (op2)          
          genop2 = find_or_generate_expression (block, op2, stmts);
-       folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr),
-                             genop0, genarglist, genop2));
+       folded = fold_build3 (TREE_CODE (expr), TREE_TYPE (expr),
+                             genop0, genarglist, genop2);
        break;
        
        
@@ -1544,8 +1543,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
        tree op2 = TREE_OPERAND (expr, 1);
        tree genop1 = find_or_generate_expression (block, op1, stmts);
        tree genop2 = find_or_generate_expression (block, op2, stmts);
-       folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr), 
-                             genop1, genop2));
+       folded = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr), 
+                             genop1, genop2);
        break;
       }
 
@@ -1553,8 +1552,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
       {
        tree op1 = TREE_OPERAND (expr, 0);
        tree genop1 = find_or_generate_expression (block, op1, stmts);
-       folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr), 
-                             genop1));
+       folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), 
+                             genop1);
        break;
       }
 
@@ -1594,6 +1593,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
      that we will return.  */
   temp = create_tmp_var (TREE_TYPE (expr), "pretmp");
   add_referenced_tmp_var (temp);
+  if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
+    DECL_COMPLEX_GIMPLE_REG_P (temp) = 1;
   newexpr = build (MODIFY_EXPR, TREE_TYPE (expr), temp, newexpr);
   name = make_ssa_name (temp, newexpr);
   TREE_OPERAND (newexpr, 0) = name;
@@ -1700,6 +1701,8 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node,
   /* Now build a phi for the new variable.  */
   temp = create_tmp_var (type, tmpname);
   add_referenced_tmp_var (temp);
+  if (TREE_CODE (type) == COMPLEX_TYPE)
+    DECL_COMPLEX_GIMPLE_REG_P (temp) = 1;
   temp = create_phi_node (temp, block);
   NECESSARY (temp) = 0; 
   VEC_safe_push (tree, heap, inserted_exprs, temp);
@@ -2331,8 +2334,17 @@ eliminate (void)
                      fprintf (dump_file, " in ");
                      print_generic_stmt (dump_file, stmt, 0);
                    }
+                 
                  if (TREE_CODE (sprime) == SSA_NAME) 
                    NECESSARY (SSA_NAME_DEF_STMT (sprime)) = 1;
+                 /* We need to make sure the new and old types actually match,
+                    which may require adding a simple cast, which fold_convert
+                    will do for us.  */
+                 if (TREE_CODE (*rhs_p) != SSA_NAME
+                     && !tree_ssa_useless_type_conversion_1 (TREE_TYPE (*rhs_p),
+                                                             TREE_TYPE (sprime)))
+                   sprime = fold_convert (TREE_TYPE (*rhs_p), sprime);
+                 
                  pre_stats.eliminations++;
                  propagate_tree_value (rhs_p, sprime);
                  update_stmt (stmt);
@@ -2710,3 +2722,136 @@ 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
+                 || !DECL_P (TREE_OPERAND (stmt, 0))
+                 || !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 */
+};