OSDN Git Service

PR c++/24686
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-pre.c
index 859bf09..425d220 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"
@@ -178,6 +177,8 @@ Boston, MA 02111-1307, USA.  */
    useful only for debugging, since we don't do identity lookups.  */
 
 
+static bool in_fre = false;
+
 /* A value set element.  Basically a single linked list of
    expressions/values.  */
 typedef struct value_set_node
@@ -1467,7 +1468,8 @@ find_or_generate_expression (basic_block block, tree expr, tree stmts)
       gcc_assert (UNARY_CLASS_P (genop)
                  || BINARY_CLASS_P (genop)
                  || COMPARISON_CLASS_P (genop)
-                 || REFERENCE_CLASS_P (genop));
+                 || REFERENCE_CLASS_P (genop)
+                 || TREE_CODE (genop) == CALL_EXPR);
       genop = create_expression_by_pieces (block, genop, stmts);
     }
   return genop;
@@ -1526,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;
        
        
@@ -1541,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;
       }
 
@@ -1550,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;
       }
 
@@ -1591,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;
@@ -1697,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);
@@ -2022,24 +2028,39 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
   
   /* This case is only for TREE_LIST's that appear as part of
      CALL_EXPR's.  Anything else is a bug, but we can't easily verify
-     this, hence tihs comment.  TREE_LIST is not handled by the
+     this, hence this comment.  TREE_LIST is not handled by the
      general case below is because they don't have a fixed length, or
      operands, so you can't access purpose/value/chain through
      TREE_OPERAND macros.  */
 
   if (code == TREE_LIST)
     {
+      tree op = NULL_TREE;
       tree temp = NULL_TREE;
       if (TREE_CHAIN (vexpr))
        temp = create_value_expr_from (TREE_CHAIN (vexpr), block, stmt);      
       TREE_CHAIN (vexpr) = temp ? temp : TREE_CHAIN (vexpr);
       
+
+      /* Recursively value-numberize reference ops.  */
+      if (REFERENCE_CLASS_P (TREE_VALUE (vexpr)))
+       {
+         tree tempop;
+         op = TREE_VALUE (vexpr);
+         tempop = create_value_expr_from (op, block, stmt);
+         op = tempop ? tempop : op;
+         
+         TREE_VALUE (vexpr)  = vn_lookup_or_add (op, stmt);
+       }
+      else
+       {
+         op = TREE_VALUE (vexpr);
+         TREE_VALUE (vexpr) = vn_lookup_or_add (TREE_VALUE (vexpr), NULL);
+       }
       /* This is the equivalent of inserting op into EXP_GEN like we
         do below */
-      if (!is_undefined_value (TREE_VALUE (vexpr)))
-       value_insert_into_set (EXP_GEN (block), TREE_VALUE (vexpr));      
-         
-      TREE_VALUE (vexpr) = vn_lookup_or_add (TREE_VALUE (vexpr), NULL);
+      if (!is_undefined_value (op))
+       value_insert_into_set (EXP_GEN (block), op);
 
       return vexpr;
     }
@@ -2107,14 +2128,85 @@ can_value_number_call (tree stmt)
   tree call = get_call_expr_in (stmt);
 
   /* This is a temporary restriction until we translate vuses through
-     phi nodes.  */
-  if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+     phi nodes.  This is only needed for PRE, of course.  */
+  if (!in_fre && !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
     return false;  
   if (call_expr_flags (call)  & (ECF_PURE | ECF_CONST))
     return true;
   return false;
 }
 
+/* Given a statement STMT and its right hand side which is a load, try
+   to look for the expression stored in the location for the load, and
+   return true if a useful equivalence was recorded for LHS.  */
+
+static bool
+try_look_through_load (tree lhs, tree mem_ref, tree stmt, basic_block block)
+{
+  tree store_stmt = NULL;
+  tree rhs;
+  ssa_op_iter i;
+  tree vuse;
+
+  FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, i, SSA_OP_VIRTUAL_USES)
+    {
+      tree def_stmt;
+
+      gcc_assert (TREE_CODE (vuse) == SSA_NAME);
+      def_stmt = SSA_NAME_DEF_STMT (vuse);
+
+      /* If there is no useful statement for this VUSE, we'll not find a
+        useful expression to return either.  Likewise, if there is a
+        statement but it is not a simple assignment or it has virtual
+        uses, we can stop right here.  Note that this means we do
+        not look through PHI nodes, which is intentional.  */
+      if (!def_stmt
+         || TREE_CODE (def_stmt) != MODIFY_EXPR
+         || !ZERO_SSA_OPERANDS (def_stmt, SSA_OP_VIRTUAL_USES))
+       return false;
+
+      /* If this is not the same statement as one we have looked at for
+        another VUSE of STMT already, we have two statements producing
+        something that reaches our STMT.  */
+      if (store_stmt && store_stmt != def_stmt)
+       return false;
+      else
+       {
+         /* Is this a store to the exact same location as the one we are
+            loading from in STMT?  */
+         if (!operand_equal_p (TREE_OPERAND (def_stmt, 0), mem_ref, 0))
+           return false;
+
+         /* Otherwise remember this statement and see if all other VUSEs
+            come from the same statement.  */
+         store_stmt = def_stmt;
+       }
+    }
+
+  /* Alright then, we have visited all VUSEs of STMT and we've determined
+     that all of them come from the same statement STORE_STMT.  See if there
+     is a useful expression we can deduce from STORE_STMT.  */
+  rhs = TREE_OPERAND (store_stmt, 1);
+  if ((TREE_CODE (rhs) == SSA_NAME
+       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
+      || is_gimple_min_invariant (rhs)
+      || TREE_CODE (rhs) == ADDR_EXPR
+      || TREE_INVARIANT (rhs))
+    {
+      
+      /* Yay!  Compute a value number for the RHS of the statement and
+        add its value to the AVAIL_OUT set for the block.  Add the LHS
+        to TMP_GEN.  */
+      add_to_sets (lhs, rhs, store_stmt, TMP_GEN (block), AVAIL_OUT (block));
+      if (TREE_CODE (rhs) == SSA_NAME
+         && !is_undefined_value (rhs))
+       value_insert_into_set (EXP_GEN (block), rhs);
+      return true;
+    }
+
+  return false;
+}
+
 /* Compute the AVAIL set for all basic blocks.
 
    This function performs value numbering of the statements in each basic
@@ -2205,6 +2297,12 @@ compute_avail (void)
              tree lhs = TREE_OPERAND (stmt, 0);
              tree rhs = TREE_OPERAND (stmt, 1);
 
+             /* Try to look through loads.  */
+             if (TREE_CODE (lhs) == SSA_NAME
+                 && !ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_USES)
+                 && try_look_through_load (lhs, rhs, stmt, block))
+               continue;
+
              STRIP_USELESS_TYPE_CONVERSION (rhs);
              if (UNARY_CLASS_P (rhs)
                  || BINARY_CLASS_P (rhs)
@@ -2226,7 +2324,8 @@ compute_avail (void)
                      continue;
                    }
                }
-             else if (TREE_CODE (rhs) == SSA_NAME
+             else if ((TREE_CODE (rhs) == SSA_NAME
+                       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
                       || is_gimple_min_invariant (rhs)
                       || TREE_CODE (rhs) == ADDR_EXPR
                       || TREE_INVARIANT (rhs)
@@ -2313,15 +2412,24 @@ 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);
 
                  /* If we removed EH side effects from the statement, clean
                     its EH information.  */
-                 if (maybe_clean_eh_stmt (stmt))
+                 if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
                    {
                      bitmap_set_bit (need_eh_cleanup,
                                      bb_for_stmt (stmt)->index);
@@ -2453,6 +2561,8 @@ static void
 init_pre (bool do_fre)
 {
   basic_block bb;
+  
+  in_fre = do_fre;
 
   inserted_exprs = NULL;
   vn_init ();
@@ -2690,3 +2800,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 */
+};