OSDN Git Service

Merge from gomp-branch.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-copy.c
index 91d80a7..84f3cd1 100644 (file)
@@ -15,8 +15,8 @@ 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"
@@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "basic-block.h"
 #include "output.h"
-#include "errors.h"
 #include "expr.h"
 #include "function.h"
 #include "diagnostic.h"
@@ -166,7 +165,7 @@ may_propagate_copy_into_asm (tree dest)
    propagating NEW into ORIG, consolidate aliasing information so that
    they both share the same memory tags.  */
 
-static void
+void
 merge_alias_info (tree orig, tree new)
 {
   tree new_sym = SSA_NAME_VAR (new);
@@ -189,7 +188,9 @@ merge_alias_info (tree orig, tree new)
 #endif
 
   /* Synchronize the type tags.  If both pointers had a tag and they
-     are different, then something has gone wrong.  */
+     are different, then something has gone wrong.  Type tags can
+     always be merged because they are flow insensitive, all the SSA
+     names of the same base DECL share the same type tag.  */
   if (new_ann->type_mem_tag == NULL_TREE)
     new_ann->type_mem_tag = orig_ann->type_mem_tag;
   else if (orig_ann->type_mem_tag == NULL_TREE)
@@ -197,32 +198,41 @@ merge_alias_info (tree orig, tree new)
   else
     gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
 
-  /* Synchronize the name tags.  If NEW did not have a name tag, get
-     it from ORIG.  This happens when NEW is a compiler generated
-     temporary which still hasn't had its points-to information filled
-     in.  */
-  if (SSA_NAME_PTR_INFO (orig))
+  /* Check that flow-sensitive information is compatible.  Notice that
+     we may not merge flow-sensitive information here.  This function
+     is called when propagating equivalences dictated by the IL, like
+     a copy operation P_i = Q_j, and from equivalences dictated by
+     control-flow, like if (P_i == Q_j).
+     
+     In the former case, P_i and Q_j are equivalent in every block
+     dominated by the assignment, so their flow-sensitive information
+     is always the same.  However, in the latter case, the pointers
+     P_i and Q_j are only equivalent in one of the sub-graphs out of
+     the predicate, so their flow-sensitive information is not the
+     same in every block dominated by the predicate.
+
+     Since we cannot distinguish one case from another in this
+     function, we can only make sure that if P_i and Q_j have
+     flow-sensitive information, they should be compatible.  */
+  if (SSA_NAME_PTR_INFO (orig) && SSA_NAME_PTR_INFO (new))
     {
       struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
       struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
 
-      if (new_ptr_info == NULL)
-       duplicate_ssa_name_ptr_info (new, orig_ptr_info);
-      else if (orig_ptr_info->name_mem_tag
-              && new_ptr_info->name_mem_tag
-              && orig_ptr_info->pt_vars
-              && new_ptr_info->pt_vars)
-       {
-         /* Note that pointer NEW may actually have a different set
-            of pointed-to variables.  However, since NEW is being
-            copy-propagated into ORIG, it must always be true that
-            the pointed-to set for pointer NEW is the same, or a
-            subset, of the pointed-to set for pointer ORIG.  If this
-            isn't the case, we shouldn't have been able to do the
-            propagation of NEW into ORIG.  */
-         gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
-               orig_ptr_info->pt_vars));
-       }
+      /* Note that pointer NEW and ORIG may actually have different
+        pointed-to variables (e.g., PR 18291 represented in
+        testsuite/gcc.c-torture/compile/pr18291.c).  However, since
+        NEW is being copy-propagated into ORIG, it must always be
+        true that the pointed-to set for pointer NEW is the same, or
+        a subset, of the pointed-to set for pointer ORIG.  If this
+        isn't the case, we shouldn't have been able to do the
+        propagation of NEW into ORIG.  */
+      if (orig_ptr_info->name_mem_tag
+         && new_ptr_info->name_mem_tag
+         && orig_ptr_info->pt_vars
+         && new_ptr_info->pt_vars)
+       gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
+                                       orig_ptr_info->pt_vars));
     }
 }   
 
@@ -257,7 +267,7 @@ replace_exp_1 (use_operand_p op_p, tree val,
 
 
 /* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
-   into the operand pointed by OP_P.
+   into the operand pointed to by OP_P.
 
    Use this version for const/copy propagation as it will perform additional
    checks to ensure validity of the const/copy propagation.  */
@@ -270,7 +280,7 @@ propagate_value (use_operand_p op_p, tree val)
 
 
 /* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
-   into the tree pointed by OP_P.
+   into the tree pointed to by OP_P.
 
    Use this version for const/copy propagation when SSA operands are not
    available.  It will perform the additional checks to ensure validity of
@@ -360,9 +370,7 @@ stmt_may_generate_copy (tree stmt)
   /* If we are not doing store copy-prop, statements with loads and/or
      stores will never generate a useful copy.  */
   if (!do_store_copy_prop
-      && (NUM_VUSES (VUSE_OPS (ann)) > 0
-         || NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0
-         || NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0))
+      && !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
     return false;
 
   /* Otherwise, the only statements that generate useful copies are
@@ -477,24 +485,31 @@ static void
 dump_copy_of (FILE *dump_file, tree var)
 {
   tree val;
+  sbitmap visited;
 
   print_generic_expr (dump_file, var, dump_flags);
 
   if (TREE_CODE (var) != SSA_NAME)
     return;
-
+    
+  visited = sbitmap_alloc (num_ssa_names);
+  sbitmap_zero (visited);
+  SET_BIT (visited, SSA_NAME_VERSION (var));
+  
   fprintf (dump_file, " copy-of chain: ");
 
   val = var;
   print_generic_expr (dump_file, val, 0);
   fprintf (dump_file, " ");
-  while (copy_of[SSA_NAME_VERSION (val)].value
-         && copy_of[SSA_NAME_VERSION (val)].value != val)
+  while (copy_of[SSA_NAME_VERSION (val)].value)
     {
       fprintf (dump_file, "-> ");
       val = copy_of[SSA_NAME_VERSION (val)].value;
       print_generic_expr (dump_file, val, 0);
       fprintf (dump_file, " ");
+      if (TEST_BIT (visited, SSA_NAME_VERSION (val)))
+        break;
+      SET_BIT (visited, SSA_NAME_VERSION (val));
     }
 
   val = get_copy_of_val (var)->value;
@@ -504,6 +519,8 @@ dump_copy_of (FILE *dump_file, tree var)
     fprintf (dump_file, "[COPY]");
   else
     fprintf (dump_file, "[NOT A COPY]");
+  
+  sbitmap_free (visited);
 }
 
 
@@ -596,27 +613,18 @@ copy_prop_visit_cond_stmt (tree stmt, edge *taken_edge_p)
 {
   enum ssa_prop_result retval;
   tree cond;
-  use_optype uses;
 
   cond = COND_EXPR_COND (stmt);
-  uses = STMT_USE_OPS (stmt);
   retval = SSA_PROP_VARYING;
 
   /* The only conditionals that we may be able to compute statically
-     are predicates involving at least one SSA_NAME.  */
-  if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
-      && NUM_USES (uses) >= 1)
+     are predicates involving two SSA_NAMEs.  */
+  if (COMPARISON_CLASS_P (cond)
+      && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+      && TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME)
     {
-      unsigned i;
-      tree *orig;
-
-      /* Save the original operands.  */
-      orig = xmalloc (sizeof (tree) * NUM_USES (uses));
-      for (i = 0; i < NUM_USES (uses); i++)
-       {
-         orig[i] = USE_OP (uses, i);
-         SET_USE_OP (uses, i, get_last_copy_of (USE_OP (uses, i)));
-       }
+      tree op0 = get_last_copy_of (TREE_OPERAND (cond, 0));
+      tree op1 = get_last_copy_of (TREE_OPERAND (cond, 1));
 
       /* See if we can determine the predicate's value.  */
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -626,14 +634,20 @@ copy_prop_visit_cond_stmt (tree stmt, edge *taken_edge_p)
          print_generic_stmt (dump_file, cond, 0);
        }
 
-      *taken_edge_p = find_taken_edge (bb_for_stmt (stmt), cond);
-      if (*taken_edge_p)
-       retval = SSA_PROP_INTERESTING;
-
-      /* Restore the original operands.  */
-      for (i = 0; i < NUM_USES (uses); i++)
-       SET_USE_OP (uses, i, orig[i]);
-      free (orig);
+      /* We can fold COND and get a useful result only when we have
+        the same SSA_NAME on both sides of a comparison operator.  */
+      if (op0 == op1)
+       {
+         tree folded_cond = fold_binary (TREE_CODE (cond), boolean_type_node,
+                                         op0, op1);
+         if (folded_cond)
+           {
+             basic_block bb = bb_for_stmt (stmt);
+             *taken_edge_p = find_taken_edge (bb, folded_cond);
+             if (*taken_edge_p)
+               retval = SSA_PROP_INTERESTING;
+           }
+       }
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS) && *taken_edge_p)
@@ -824,17 +838,19 @@ copy_prop_visit_phi_node (tree phi)
 }
 
 
-/* Initialize structures used for copy propagation.  */
+/* Initialize structures used for copy propagation.   PHIS_ONLY is true
+   if we should only consider PHI nodes as generating copy propagation
+   opportunities.  */
 
 static void
-init_copy_prop (void)
+init_copy_prop (bool phis_only)
 {
   basic_block bb;
 
-  copy_of = xmalloc (num_ssa_names * sizeof (*copy_of));
+  copy_of = XNEWVEC (prop_value_t, num_ssa_names);
   memset (copy_of, 0, num_ssa_names * sizeof (*copy_of));
 
-  cached_last_copy_of = xmalloc (num_ssa_names * sizeof (*cached_last_copy_of));
+  cached_last_copy_of = XNEWVEC (tree, num_ssa_names);
   memset (cached_last_copy_of, 0, num_ssa_names * sizeof (*cached_last_copy_of));
 
   FOR_EACH_BB (bb)
@@ -852,7 +868,7 @@ init_copy_prop (void)
             lists of the propagator.  */
          if (stmt_ends_bb_p (stmt))
            DONT_SIMULATE_AGAIN (stmt) = false;
-         else if (stmt_may_generate_copy (stmt))
+         else if (!phis_only && stmt_may_generate_copy (stmt))
            DONT_SIMULATE_AGAIN (stmt) = false;
          else
            {
@@ -882,26 +898,36 @@ static void
 fini_copy_prop (void)
 {
   size_t i;
+  prop_value_t *tmp;
   
   /* Set the final copy-of value for each variable by traversing the
      copy-of chains.  */
+  tmp = XNEWVEC (prop_value_t, num_ssa_names);
+  memset (tmp, 0, num_ssa_names * sizeof (*tmp));
   for (i = 1; i < num_ssa_names; i++)
     {
       tree var = ssa_name (i);
       if (var && copy_of[i].value && copy_of[i].value != var)
-       copy_of[i].value = get_last_copy_of (var);
+       tmp[i].value = get_last_copy_of (var);
     }
 
-  substitute_and_fold (copy_of);
+  substitute_and_fold (tmp, false);
 
+  free (cached_last_copy_of);
   free (copy_of);
+  free (tmp);
 }
 
 
-/* Main entry point to the copy propagator.  The algorithm propagates
-   the value COPY-OF using ssa_propagate.  For every variable X_i,
-   COPY-OF(X_i) indicates which variable is X_i created from.  The
-   following example shows how the algorithm proceeds at a high level:
+/* Main entry point to the copy propagator.
+
+   PHIS_ONLY is true if we should only consider PHI nodes as generating
+   copy propagation opportunities. 
+
+   The algorithm propagates the value COPY-OF using ssa_propagate.  For
+   every variable X_i, COPY-OF(X_i) indicates which variable is X_i created
+   from.  The following example shows how the algorithm proceeds at a
+   high level:
 
            1   a_24 = x_1
            2   a_2 = PHI <a_24, x_1>
@@ -1001,10 +1027,10 @@ fini_copy_prop (void)
    x_53 and x_54 are both copies of x_898.  */
 
 static void
-execute_copy_prop (bool store_copy_prop)
+execute_copy_prop (bool store_copy_prop, bool phis_only)
 {
   do_store_copy_prop = store_copy_prop;
-  init_copy_prop ();
+  init_copy_prop (phis_only);
   ssa_propagate (copy_prop_visit_stmt, copy_prop_visit_phi_node);
   fini_copy_prop ();
 }
@@ -1019,7 +1045,7 @@ gate_copy_prop (void)
 static void
 do_copy_prop (void)
 {
-  execute_copy_prop (false);
+  execute_copy_prop (false, false);
 }
 
 struct tree_opt_pass pass_copy_prop =
@@ -1044,6 +1070,34 @@ struct tree_opt_pass pass_copy_prop =
 };
 
 
+static void
+do_phi_only_copy_prop (void)
+{
+  execute_copy_prop (false, true);
+}
+
+struct tree_opt_pass pass_phi_only_copy_prop =
+{
+  "phionlycopyprop",                   /* name */
+  gate_copy_prop,                      /* gate */
+  do_phi_only_copy_prop,               /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_COPY_PROP,                   /* tv_id */
+  PROP_ssa | PROP_alias | PROP_cfg,    /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_cleanup_cfg
+    | TODO_dump_func
+    | TODO_ggc_collect
+    | TODO_verify_ssa
+    | TODO_update_ssa,                 /* todo_flags_finish */
+  0                                    /* letter */
+};
+
+
 static bool
 gate_store_copy_prop (void)
 {
@@ -1058,7 +1112,7 @@ static void
 store_copy_prop (void)
 {
   /* If STORE-COPY-PROP is not enabled, we just run regular COPY-PROP.  */
-  execute_copy_prop (flag_tree_store_copy_prop != 0);
+  execute_copy_prop (flag_tree_store_copy_prop != 0, false);
 }
 
 struct tree_opt_pass pass_store_copy_prop =