OSDN Git Service

2009-09-23 Yuri Gribov <tetra2005@googlemail.com>
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index 3488382..eaa127e 100644 (file)
@@ -46,6 +46,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "ipa-type-escape.h"
 #include "df.h"
+#include "tree-ssa-alias.h"
+#include "pointer-set.h"
+#include "tree-flow.h"
 
 /* The aliasing API provided here solves related but different problems:
 
@@ -155,7 +158,6 @@ static int base_alias_check (rtx, rtx, enum machine_mode,
 static rtx find_base_value (rtx);
 static int mems_in_disjoint_alias_sets_p (const_rtx, const_rtx);
 static int insert_subset_children (splay_tree_node, void*);
-static tree find_base_decl (tree);
 static alias_set_entry get_alias_set_entry (alias_set_type);
 static const_rtx fixed_scalar_and_varying_struct_p (const_rtx, const_rtx, rtx, rtx,
                                                    bool (*) (const_rtx, bool));
@@ -250,6 +252,103 @@ DEF_VEC_ALLOC_P(alias_set_entry,gc);
 /* The splay-tree used to store the various alias set entries.  */
 static GTY (()) VEC(alias_set_entry,gc) *alias_sets;
 \f
+/* Build a decomposed reference object for querying the alias-oracle
+   from the MEM rtx and store it in *REF.
+   Returns false if MEM is not suitable for the alias-oracle.  */
+
+static bool
+ao_ref_from_mem (ao_ref *ref, const_rtx mem)
+{
+  tree expr = MEM_EXPR (mem);
+  tree base;
+
+  if (!expr)
+    return false;
+
+  ao_ref_init (ref, expr);
+
+  /* Get the base of the reference and see if we have to reject or
+     adjust it.  */
+  base = ao_ref_base (ref);
+  if (base == NULL_TREE)
+    return false;
+
+  /* If this is a pointer dereference of a non-SSA_NAME punt.
+     ???  We could replace it with a pointer to anything.  */
+  if (INDIRECT_REF_P (base)
+      && TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME)
+    return false;
+
+  /* The tree oracle doesn't like to have these.  */
+  if (TREE_CODE (base) == FUNCTION_DECL
+      || TREE_CODE (base) == LABEL_DECL)
+    return false;
+
+  /* If this is a reference based on a partitioned decl replace the
+     base with an INDIRECT_REF of the pointer representative we
+     created during stack slot partitioning.  */
+  if (TREE_CODE (base) == VAR_DECL
+      && ! TREE_STATIC (base)
+      && cfun->gimple_df->decls_to_pointers != NULL)
+    {
+      void *namep;
+      namep = pointer_map_contains (cfun->gimple_df->decls_to_pointers, base);
+      if (namep)
+       {
+         ref->base_alias_set = get_alias_set (base);
+         ref->base = build1 (INDIRECT_REF, TREE_TYPE (base), *(tree *)namep);
+       }
+    }
+
+  ref->ref_alias_set = MEM_ALIAS_SET (mem);
+
+  /* For NULL MEM_OFFSET the MEM_EXPR may have been stripped arbitrarily
+     without recording offset or extent adjustments properly.  */
+  if (MEM_OFFSET (mem) == NULL_RTX)
+    {
+      ref->offset = 0;
+      ref->max_size = -1;
+    }
+  else
+    {
+      ref->offset += INTVAL (MEM_OFFSET (mem)) * BITS_PER_UNIT;
+    }
+
+  /* NULL MEM_SIZE should not really happen with a non-NULL MEM_EXPR,
+     but just play safe here.  The size may have been adjusted together
+     with the offset, so we need to take it if it is set and not rely
+     on MEM_EXPR here (which has the size determining parts potentially
+     stripped anyway).  We lose precision for max_size which is only
+     available from the remaining MEM_EXPR.  */
+  if (MEM_SIZE (mem) == NULL_RTX)
+    {
+      ref->size = -1;
+      ref->max_size = -1;
+    }
+  else
+    {
+      ref->size = INTVAL (MEM_SIZE (mem)) * BITS_PER_UNIT;
+    }
+
+  return true;
+}
+
+/* Query the alias-oracle on whether the two memory rtx X and MEM may
+   alias.  If TBAA_P is set also apply TBAA.  Returns true if the
+   two rtxen may alias, false otherwise.  */
+
+static bool
+rtx_refs_may_alias_p (const_rtx x, const_rtx mem, bool tbaa_p)
+{
+  ao_ref ref1, ref2;
+
+  if (!ao_ref_from_mem (&ref1, x)
+      || !ao_ref_from_mem (&ref2, mem))
+    return true;
+
+  return refs_may_alias_p_1 (&ref1, &ref2, tbaa_p);
+}
+
 /* Returns a pointer to the alias set entry for ALIAS_SET, if there is
    such an entry, or NULL otherwise.  */
 
@@ -422,57 +521,6 @@ objects_must_conflict_p (tree t1, tree t2)
   return alias_sets_must_conflict_p (set1, set2);
 }
 \f
-/* T is an expression with pointer type.  Find the DECL on which this
-   expression is based.  (For example, in `a[i]' this would be `a'.)
-   If there is no such DECL, or a unique decl cannot be determined,
-   NULL_TREE is returned.  */
-
-static tree
-find_base_decl (tree t)
-{
-  tree d0, d1;
-
-  if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
-    return 0;
-
-  if (TREE_CODE (t) == SSA_NAME)
-    t = SSA_NAME_VAR (t);
-
-  /* If this is a declaration, return it.  If T is based on a restrict
-     qualified decl, return that decl.  */
-  if (DECL_P (t))
-    {
-      if (TREE_CODE (t) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (t))
-       t = DECL_GET_RESTRICT_BASE (t);
-      return t;
-    }
-
-  /* Handle general expressions.  It would be nice to deal with
-     COMPONENT_REFs here.  If we could tell that `a' and `b' were the
-     same, then `a->f' and `b->f' are also the same.  */
-  switch (TREE_CODE_CLASS (TREE_CODE (t)))
-    {
-    case tcc_unary:
-      return find_base_decl (TREE_OPERAND (t, 0));
-
-    case tcc_binary:
-      /* Return 0 if found in neither or both are the same.  */
-      d0 = find_base_decl (TREE_OPERAND (t, 0));
-      d1 = find_base_decl (TREE_OPERAND (t, 1));
-      if (d0 == d1)
-       return d0;
-      else if (d0 == 0)
-       return d1;
-      else if (d1 == 0)
-       return d0;
-      else
-       return 0;
-
-    default:
-      return 0;
-    }
-}
-
 /* Return true if all nested component references handled by
    get_inner_reference in T are such that we should use the alias set
    provided by the object at the heart of T.
@@ -532,56 +580,9 @@ get_deref_alias_set_1 (tree t)
   if (!flag_strict_aliasing)
     return 0;
 
+  /* All we care about is the type.  */
   if (! TYPE_P (t))
-    {
-      tree decl = find_base_decl (t);
-
-      if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
-       {
-         /* If we haven't computed the actual alias set, do it now.  */
-         if (DECL_POINTER_ALIAS_SET (decl) == -2)
-           {
-             tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl));
-
-             /* No two restricted pointers can point at the same thing.
-                However, a restricted pointer can point at the same thing
-                as an unrestricted pointer, if that unrestricted pointer
-                is based on the restricted pointer.  So, we make the
-                alias set for the restricted pointer a subset of the
-                alias set for the type pointed to by the type of the
-                decl.  */
-             alias_set_type pointed_to_alias_set
-                 = get_alias_set (pointed_to_type);
-
-             if (pointed_to_alias_set == 0)
-               /* It's not legal to make a subset of alias set zero.  */
-               DECL_POINTER_ALIAS_SET (decl) = 0;
-             else if (AGGREGATE_TYPE_P (pointed_to_type))
-               /* For an aggregate, we must treat the restricted
-                  pointer the same as an ordinary pointer.  If we
-                  were to make the type pointed to by the
-                  restricted pointer a subset of the pointed-to
-                  type, then we would believe that other subsets
-                  of the pointed-to type (such as fields of that
-                  type) do not conflict with the type pointed to
-                  by the restricted pointer.  */
-               DECL_POINTER_ALIAS_SET (decl)
-                   = pointed_to_alias_set;
-             else
-               {
-                 DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
-                 record_alias_subset (pointed_to_alias_set,
-                                      DECL_POINTER_ALIAS_SET (decl));
-               }
-           }
-
-         /* We use the alias set indicated in the declaration.  */
-         return DECL_POINTER_ALIAS_SET (decl);
-       }
-
-      /* Now all we care about is the type.  */
-      t = TREE_TYPE (t);
-    }
+    t = TREE_TYPE (t);
 
   /* If we have an INDIRECT_REF via a void pointer, we don't
      know anything about what that might alias.  Likewise if the
@@ -679,11 +680,20 @@ get_alias_set (tree t)
     }
 
   /* Variant qualifiers don't affect the alias set, so get the main
-     variant.  Always use the canonical type as well.
-     If this is a type with a known alias set, return it.  */
+     variant.  */
   t = TYPE_MAIN_VARIANT (t);
-  if (TYPE_CANONICAL (t))
-    t = TYPE_CANONICAL (t);
+
+  /* Always use the canonical type as well.  If this is a type that
+     requires structural comparisons to identify compatible types
+     use alias set zero.  */
+  if (TYPE_STRUCTURAL_EQUALITY_P (t))
+    return 0;
+  t = TYPE_CANONICAL (t);
+  /* Canonical types shouldn't form a tree nor should the canonical
+     type require structural equality checks.  */
+  gcc_assert (!TYPE_STRUCTURAL_EQUALITY_P (t) && TYPE_CANONICAL (t) == t);
+
+  /* If this is a type with a known alias set, return it.  */
   if (TYPE_ALIAS_SET_KNOWN_P (t))
     return TYPE_ALIAS_SET (t);
 
@@ -1018,9 +1028,9 @@ find_base_value (rtx src)
        /* Guess which operand is the base address:
           If either operand is a symbol, then it is the base.  If
           either operand is a CONST_INT, then the other is the base.  */
-       if (GET_CODE (src_1) == CONST_INT || CONSTANT_P (src_0))
+       if (CONST_INT_P (src_1) || CONSTANT_P (src_0))
          return find_base_value (src_0);
-       else if (GET_CODE (src_0) == CONST_INT || CONSTANT_P (src_1))
+       else if (CONST_INT_P (src_0) || CONSTANT_P (src_1))
          return find_base_value (src_1);
 
        return 0;
@@ -1034,7 +1044,7 @@ find_base_value (rtx src)
     case AND:
       /* If the second operand is constant set the base
         address to the first operand.  */
-      if (GET_CODE (XEXP (src, 1)) == CONST_INT && INTVAL (XEXP (src, 1)) != 0)
+      if (CONST_INT_P (XEXP (src, 1)) && INTVAL (XEXP (src, 1)) != 0)
        return find_base_value (XEXP (src, 0));
       return 0;
 
@@ -1176,7 +1186,7 @@ record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED)
          break;
        }
       case AND:
-       if (XEXP (src, 0) != dest || GET_CODE (XEXP (src, 1)) != CONST_INT)
+       if (XEXP (src, 0) != dest || !CONST_INT_P (XEXP (src, 1)))
          new_reg_base_value[regno] = 0;
        break;
       default:
@@ -1269,9 +1279,9 @@ canon_rtx (rtx x)
 
       if (x0 != XEXP (x, 0) || x1 != XEXP (x, 1))
        {
-         if (GET_CODE (x0) == CONST_INT)
+         if (CONST_INT_P (x0))
            return plus_constant (x1, INTVAL (x0));
-         else if (GET_CODE (x1) == CONST_INT)
+         else if (CONST_INT_P (x1))
            return plus_constant (x0, INTVAL (x1));
          return gen_rtx_PLUS (GET_MODE (x), x0, x1);
        }
@@ -1553,7 +1563,7 @@ find_base_term (rtx x)
       }
 
     case AND:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) != 0)
+      if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0)
        return find_base_term (XEXP (x, 0));
       return 0;
 
@@ -1616,11 +1626,11 @@ base_alias_check (rtx x, rtx y, enum machine_mode x_mode,
   if (GET_CODE (x) == AND && GET_CODE (y) == AND)
     return 1;
   if (GET_CODE (x) == AND
-      && (GET_CODE (XEXP (x, 1)) != CONST_INT
+      && (!CONST_INT_P (XEXP (x, 1))
          || (int) GET_MODE_UNIT_SIZE (y_mode) < -INTVAL (XEXP (x, 1))))
     return 1;
   if (GET_CODE (y) == AND
-      && (GET_CODE (XEXP (y, 1)) != CONST_INT
+      && (!CONST_INT_P (XEXP (y, 1))
          || (int) GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
     return 1;
 
@@ -1781,21 +1791,21 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
            return memrefs_conflict_p (xsize, x0, ysize, y0, c);
          if (rtx_equal_for_memref_p (x0, y0))
            return memrefs_conflict_p (xsize, x1, ysize, y1, c);
-         if (GET_CODE (x1) == CONST_INT)
+         if (CONST_INT_P (x1))
            {
-             if (GET_CODE (y1) == CONST_INT)
+             if (CONST_INT_P (y1))
                return memrefs_conflict_p (xsize, x0, ysize, y0,
                                           c - INTVAL (x1) + INTVAL (y1));
              else
                return memrefs_conflict_p (xsize, x0, ysize, y,
                                           c - INTVAL (x1));
            }
-         else if (GET_CODE (y1) == CONST_INT)
+         else if (CONST_INT_P (y1))
            return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
 
          return 1;
        }
-      else if (GET_CODE (x1) == CONST_INT)
+      else if (CONST_INT_P (x1))
        return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
     }
   else if (GET_CODE (y) == PLUS)
@@ -1805,7 +1815,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
       rtx y0 = XEXP (y, 0);
       rtx y1 = XEXP (y, 1);
 
-      if (GET_CODE (y1) == CONST_INT)
+      if (CONST_INT_P (y1))
        return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
       else
        return 1;
@@ -1831,7 +1841,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
                    || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
 
          /* Can't properly adjust our sizes.  */
-         if (GET_CODE (x1) != CONST_INT)
+         if (!CONST_INT_P (x1))
            return 1;
          xsize /= INTVAL (x1);
          ysize /= INTVAL (x1);
@@ -1847,13 +1857,13 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
      as an access with indeterminate size.  Assume that references
      besides AND are aligned, so if the size of the other reference is
      at least as large as the alignment, assume no other overlap.  */
-  if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT)
+  if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1)))
     {
       if (GET_CODE (y) == AND || ysize < -INTVAL (XEXP (x, 1)))
        xsize = -1;
       return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)), ysize, y, c);
     }
-  if (GET_CODE (y) == AND && GET_CODE (XEXP (y, 1)) == CONST_INT)
+  if (GET_CODE (y) == AND && CONST_INT_P (XEXP (y, 1)))
     {
       /* ??? If we are indexing far enough into the array/structure, we
         may yet be able to determine that we can not overlap.  But we
@@ -1866,7 +1876,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
 
   if (CONSTANT_P (x))
     {
-      if (GET_CODE (x) == CONST_INT && GET_CODE (y) == CONST_INT)
+      if (CONST_INT_P (x) && CONST_INT_P (y))
        {
          c += (INTVAL (y) - INTVAL (x));
          return (xsize <= 0 || ysize <= 0
@@ -1979,6 +1989,9 @@ nonoverlapping_component_refs_p (const_tree x, const_tree y)
 {
   const_tree fieldx, fieldy, typex, typey, orig_y;
 
+  if (!flag_strict_aliasing)
+    return false;
+
   do
     {
       /* The comparison has to be done at a common type, since we don't
@@ -2169,11 +2182,11 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
      we can avoid overlap is if we can deduce that they are nonoverlapping
      pieces of that decl, which is very rare.  */
   basex = MEM_P (rtlx) ? XEXP (rtlx, 0) : rtlx;
-  if (GET_CODE (basex) == PLUS && GET_CODE (XEXP (basex, 1)) == CONST_INT)
+  if (GET_CODE (basex) == PLUS && CONST_INT_P (XEXP (basex, 1)))
     offsetx = INTVAL (XEXP (basex, 1)), basex = XEXP (basex, 0);
 
   basey = MEM_P (rtly) ? XEXP (rtly, 0) : rtly;
-  if (GET_CODE (basey) == PLUS && GET_CODE (XEXP (basey, 1)) == CONST_INT)
+  if (GET_CODE (basey) == PLUS && CONST_INT_P (XEXP (basey, 1)))
     offsety = INTVAL (XEXP (basey, 1)), basey = XEXP (basey, 0);
 
   /* If the bases are different, we know they do not overlap if both
@@ -2290,8 +2303,10 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
   if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
     return 1;
 
-  return ! fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
-                                             varies);
+  if (fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr, varies))
+    return 0;
+
+  return rtx_refs_may_alias_p (x, mem, true);
 }
 
 /* Canonical true dependence: X is read after store in MEM takes place.
@@ -2354,8 +2369,10 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
   if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
     return 1;
 
-  return ! fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
-                                             varies);
+  if (fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr, varies))
+    return 0;
+
+  return rtx_refs_may_alias_p (x, mem, true);
 }
 
 /* Returns nonzero if a write to X might alias a previous read from
@@ -2415,8 +2432,11 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
     = fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
                                         rtx_addr_varies_p);
 
-  return (!(fixed_scalar == mem && !aliases_everything_p (x))
-         && !(fixed_scalar == x && !aliases_everything_p (mem)));
+  if ((fixed_scalar == mem && !aliases_everything_p (x))
+      || (fixed_scalar == x && !aliases_everything_p (mem)))
+    return 0;
+
+  return rtx_refs_may_alias_p (x, mem, false);
 }
 
 /* Anti dependence: X is written after read in MEM takes place.  */
@@ -2627,7 +2647,7 @@ init_alias_analysis (void)
                           && GET_CODE (src) == PLUS
                           && REG_P (XEXP (src, 0))
                           && (t = get_reg_known_value (REGNO (XEXP (src, 0))))
-                          && GET_CODE (XEXP (src, 1)) == CONST_INT)
+                          && CONST_INT_P (XEXP (src, 1)))
                    {
                      t = plus_constant (t, INTVAL (XEXP (src, 1)));
                      set_reg_known_value (regno, t);