OSDN Git Service

* config/cpu/s390/atomicity.h (__exchange_and_add): Add "memory"
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-copy.c
index 1f87c1b..8350047 100644 (file)
@@ -1,5 +1,5 @@
 /* Const/copy propagation and SSA_NAME replacement support routines.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -44,7 +44,7 @@ Boston, MA 02111-1307, USA.  */
    annotations up-to-date.
 
    We require that for any copy operation where the RHS and LHS have
-   a non-null memory tag that the memory tag be the same.   It is OK
+   a non-null memory tag the memory tag be the same.   It is OK
    for one or both of the memory tags to be NULL.
 
    We also require tracking if a variable is dereferenced in a load or
@@ -55,60 +55,206 @@ Boston, MA 02111-1307, USA.  */
    APIs defined in this file.  */
 
 
-/* Given two SSA_NAMEs, replace the annotations for the one referred to by OP 
-   with VAR's annotations.
+/* Return true if we may propagate ORIG into DEST, false otherwise.  */
 
-   If OP is a pointer, copy the memory tag used originally by OP into
-   VAR.  This is needed in cases where VAR had never been dereferenced in the
-   program.
+bool
+may_propagate_copy (tree dest, tree orig)
+{
+  tree type_d = TREE_TYPE (dest);
+  tree type_o = TREE_TYPE (orig);
+
+  /* Do not copy between types for which we *do* need a conversion.  */
+  if (!tree_ssa_useless_type_conversion_1 (type_d, type_o))
+    return false;
+
+  /* FIXME.  GIMPLE is allowing pointer assignments and comparisons of
+     pointers that have different alias sets.  This means that these
+     pointers will have different memory tags associated to them.
+
+     If we allow copy propagation in these cases, statements de-referencing
+     the new pointer will now have a reference to a different memory tag
+     with potentially incorrect SSA information.
+
+     This was showing up in libjava/java/util/zip/ZipFile.java with code
+     like:
+
+       struct java.io.BufferedInputStream *T.660;
+       struct java.io.BufferedInputStream *T.647;
+       struct java.io.InputStream *is;
+       struct java.io.InputStream *is.662;
+       [ ... ]
+       T.660 = T.647;
+       is = T.660;     <-- This ought to be type-casted
+       is.662 = is;
+
+     Also, f/name.c exposed a similar problem with a COND_EXPR predicate
+     that was causing DOM to generate and equivalence with two pointers of
+     alias-incompatible types:
+
+       struct _ffename_space *n;
+       struct _ffename *ns;
+       [ ... ]
+       if (n == ns)
+         goto lab;
+       ...
+       lab:
+       return n;
+
+     I think that GIMPLE should emit the appropriate type-casts.  For the
+     time being, blocking copy-propagation in these cases is the safe thing
+     to do.  */
+  if (TREE_CODE (dest) == SSA_NAME && TREE_CODE (orig) == SSA_NAME
+      && POINTER_TYPE_P (type_d) && POINTER_TYPE_P (type_o))
+    {
+      tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag;
+      tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag;
+      if (mt_dest && mt_orig && mt_dest != mt_orig)
+       return false;
+      else if (!lang_hooks.types_compatible_p (type_d, type_o))
+       return false;
+      else if (get_alias_set (TREE_TYPE (type_d)) != 
+              get_alias_set (TREE_TYPE (type_o)))
+       return false;
+    }
+
+  /* If the destination is a SSA_NAME for a virtual operand, then we have
+     some special cases to handle.  */
+  if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest))
+    {
+      /* If both operands are SSA_NAMEs referring to virtual operands, then
+        we can always propagate.  */
+      if (TREE_CODE (orig) == SSA_NAME)
+       {
+         if (!is_gimple_reg (orig))
+           return true;
+
+#ifdef ENABLE_CHECKING
+         /* If we have one real and one virtual operand, then something has
+            gone terribly wrong.  */
+         gcc_assert (!is_gimple_reg (orig));
+#endif
+       }
+
+      /* We have a "copy" from something like a constant into a virtual
+        operand.  Reject these.  */
+      return false;
+    }
+
+  /* If ORIG flows in from an abnormal edge, it cannot be propagated.  */
+  if (TREE_CODE (orig) == SSA_NAME
+      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
+    return false;
+
+  /* If DEST is an SSA_NAME that flows from an abnormal edge, then it
+     cannot be replaced.  */
+  if (TREE_CODE (dest) == SSA_NAME
+      && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest))
+    return false;
+
+  /* Anything else is OK.  */
+  return true;
+}
+
+/* Similarly, but we know that we're propagating into an ASM_EXPR.  */
+
+bool
+may_propagate_copy_into_asm (tree dest)
+{
+  /* Hard register operands of asms are special.  Do not bypass.  */
+  return !(TREE_CODE (dest) == SSA_NAME
+          && TREE_CODE (SSA_NAME_VAR (dest)) == VAR_DECL
+          && DECL_HARD_REGISTER (SSA_NAME_VAR (dest)));
+}
+
+
+/* Given two SSA_NAMEs pointers ORIG and NEW such that we are copy
+   propagating NEW into ORIG, consolidate aliasing information so that
+   they both share the same memory tags.  */
 
-   If FOR_PROPAGATION is true, then perform additional checks to ensure
-   that const/copy propagation of var for OP is valid.  */
-   
 static void
-replace_ssa_names_ann (tree op,
-                  tree var,
-                  bool for_propagation ATTRIBUTE_UNUSED)
+merge_alias_info (tree orig, tree new)
 {
+  tree new_sym = SSA_NAME_VAR (new);
+  tree orig_sym = SSA_NAME_VAR (orig);
+  var_ann_t new_ann = var_ann (new_sym);
+  var_ann_t orig_ann = var_ann (orig_sym);
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (orig)));
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (new)));
+
 #if defined ENABLE_CHECKING
-  if (for_propagation && !may_propagate_copy (op, var))
-    abort ();
+  gcc_assert (lang_hooks.types_compatible_p (TREE_TYPE (orig),
+                                            TREE_TYPE (new)));
+
+  /* If the pointed-to alias sets are different, these two pointers
+     would never have the same memory tag.  In this case, NEW should
+     not have been propagated into ORIG.  */
+  gcc_assert (get_alias_set (TREE_TYPE (TREE_TYPE (new_sym)))
+             == get_alias_set (TREE_TYPE (TREE_TYPE (orig_sym))));
 #endif
 
-  /* If VAR doesn't have a memory tag, copy the one from the original
-     operand.  Also copy the dereferenced flags.  */
-  if (POINTER_TYPE_P (TREE_TYPE (op)))
+  /* Synchronize the type tags.  If both pointers had a tag and they
+     are different, then something has gone wrong.  */
+  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)
+    orig_ann->type_mem_tag = new_ann->type_mem_tag;
+  else
+    gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
+
+#if defined ENABLE_CHECKING
+  {
+    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 (orig_ptr_info
+       && new_ptr_info
+       && orig_ptr_info->name_mem_tag
+       && new_ptr_info->name_mem_tag
+       && orig_ptr_info->pt_vars
+       && new_ptr_info->pt_vars)
     {
-      var_ann_t new_ann = var_ann (SSA_NAME_VAR (var));
-      var_ann_t orig_ann = var_ann (SSA_NAME_VAR (op));
-
-      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)
-       orig_ann->type_mem_tag = new_ann->type_mem_tag;
-      else if (new_ann->type_mem_tag != orig_ann->type_mem_tag)
-       abort ();
+      /* 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));
     }
-
+  }
+#endif
 }   
 
 
 /* Common code for propagate_value and replace_exp.
 
-   Replace use operand OP_P with VAL.  FOR_PROPAGATION indicates if the 
+   Replace use operand OP_P with VAL.  FOR_PROPAGATION indicates if the
    replacement is done to propagate a value or not.  */
 
 static void
-replace_exp_1 (use_operand_p op_p, tree val, bool for_propagation)
+replace_exp_1 (use_operand_p op_p, tree val,
+              bool for_propagation ATTRIBUTE_UNUSED)
 {
+  tree op = USE_FROM_PTR (op_p);
+
+#if defined ENABLE_CHECKING
+  gcc_assert (!(for_propagation
+               && TREE_CODE (op) == SSA_NAME
+               && TREE_CODE (val) == SSA_NAME
+               && !may_propagate_copy (op, val)));
+#endif
+
   if (TREE_CODE (val) == SSA_NAME)
     {
-      if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
-       replace_ssa_names_ann (USE_FROM_PTR (op_p), val, for_propagation);
+      if (TREE_CODE (op) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (op)))
+       merge_alias_info (op, val);
       SET_USE (op_p, val);
     }
   else
-    SET_USE (op_p, lhd_unsave_expr_now (val));
+    SET_USE (op_p, unsave_expr_now (val));
 }
 
 
@@ -128,22 +274,28 @@ 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.
 
-   Use this version for const/copy propagation when SSA operands are not 
-   available.  It will perform the additional checks to ensure validity of 
+   Use this version for const/copy propagation when SSA operands are not
+   available.  It will perform the additional checks to ensure validity of
    the const/copy propagation, but will not update any operand information.
    Be sure to mark the stmt as modified.  */
 
 void
 propagate_tree_value (tree *op_p, tree val)
 {
+#if defined ENABLE_CHECKING
+  gcc_assert (!(TREE_CODE (val) == SSA_NAME
+               && TREE_CODE (*op_p) == SSA_NAME
+               && !may_propagate_copy (*op_p, val)));
+#endif
+
   if (TREE_CODE (val) == SSA_NAME)
     {
-      if (TREE_CODE (*op_p) == SSA_NAME)
-       replace_ssa_names_ann (*op_p, val, true);
+      if (TREE_CODE (*op_p) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (*op_p)))
+       merge_alias_info (*op_p, val);
       *op_p = val;
     }
   else
-    *op_p = lhd_unsave_expr_now (val);
+    *op_p = unsave_expr_now (val);
 }