OSDN Git Service

PR debug/42662
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index 7d9faf2..41a2f23 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,107 @@ 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;
+
+  /* If MEM_OFFSET or MEM_SIZE are NULL punt.  */
+  if (!MEM_OFFSET (mem)
+      || !MEM_SIZE (mem))
+    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);
+
+  /* If the base decl is a parameter we can have negative MEM_OFFSET in
+     case of promoted subregs on bigendian targets.  Trust the MEM_EXPR
+     here.  */
+  if (INTVAL (MEM_OFFSET (mem)) < 0
+      && ((INTVAL (MEM_SIZE (mem)) + INTVAL (MEM_OFFSET (mem)))
+         * BITS_PER_UNIT) == ref->size)
+    return true;
+
+  ref->offset += INTVAL (MEM_OFFSET (mem)) * BITS_PER_UNIT;
+  ref->size = INTVAL (MEM_SIZE (mem)) * BITS_PER_UNIT;
+
+  /* The MEM may extend into adjacent fields, so adjust max_size if
+     necessary.  */
+  if (ref->max_size != -1
+      && ref->size > ref->max_size)
+    ref->max_size = ref->size;
+
+  /* If MEM_OFFSET and MEM_SIZE get us outside of the base object of
+     the MEM_EXPR punt.  This happens for STRICT_ALIGNMENT targets a lot.  */
+  if (MEM_EXPR (mem) != get_spill_slot_decl (false)
+      && (ref->offset < 0
+         || (DECL_P (ref->base)
+             && (!host_integerp (DECL_SIZE (ref->base), 1)
+                 || (TREE_INT_CST_LOW (DECL_SIZE ((ref->base)))
+                     < (unsigned HOST_WIDE_INT)(ref->offset + ref->size))))))
+    return false;
+
+  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.  */
 
@@ -349,8 +452,8 @@ walk_mems_2 (rtx *x, rtx mem)
     {
       if (alias_sets_conflict_p (MEM_ALIAS_SET(*x), MEM_ALIAS_SET(mem)))
         return 1;
-        
-      return -1;  
+
+      return -1;
     }
   return 0;
 }
@@ -364,7 +467,7 @@ walk_mems_1 (rtx *x, rtx *pat)
       if (for_each_rtx (pat, (rtx_function) walk_mems_2, *x))
         /* Indicate that dependence was determined and stop traversal.  */
         return 1;
-        
+
       return -1;
     }
   return 0;
@@ -422,57 +525,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 +584,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
@@ -635,7 +640,7 @@ get_alias_set (tree t)
      aren't types.  */
   if (! TYPE_P (t))
     {
-      tree inner = t;
+      tree inner;
 
       /* Remove any nops, then give the language a chance to do
         something with this tree before we look at it.  */
@@ -644,8 +649,13 @@ get_alias_set (tree t)
       if (set != -1)
        return set;
 
+      /* Retrieve the original memory reference if needed.  */
+      if (TREE_CODE (t) == TARGET_MEM_REF)
+       t = TMR_ORIGINAL (t);
+
       /* First see if the actual object referenced is an INDIRECT_REF from a
         restrict-qualified pointer or a "void *".  */
+      inner = t;
       while (handled_component_p (inner))
        {
          inner = TREE_OPERAND (inner, 0);
@@ -679,11 +689,27 @@ 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))
+    {
+      /* Allow the language to specify another alias set for this
+        type.  */
+      set = lang_hooks.get_alias_set (t);
+      if (set != -1)
+       return set;
+      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);
 
@@ -1039,6 +1065,11 @@ find_base_value (rtx src)
       return 0;
 
     case TRUNCATE:
+      /* As we do not know which address space the pointer is refering to, we can
+        handle this only if the target does not support different pointer or
+        address modes depending on the address space.  */
+      if (!target_default_pointer_address_modes_p ())
+       break;
       if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode))
        break;
       /* Fall through.  */
@@ -1053,6 +1084,12 @@ find_base_value (rtx src)
 
     case ZERO_EXTEND:
     case SIGN_EXTEND:  /* used for NT/Alpha pointers */
+      /* As we do not know which address space the pointer is refering to, we can
+        handle this only if the target does not support different pointer or
+        address modes depending on the address space.  */
+      if (!target_default_pointer_address_modes_p ())
+       break;
+
       {
        rtx temp = find_base_value (XEXP (src, 0));
 
@@ -1445,6 +1482,11 @@ find_base_term (rtx x)
       return REG_BASE_VALUE (x);
 
     case TRUNCATE:
+      /* As we do not know which address space the pointer is refering to, we can
+        handle this only if the target does not support different pointer or
+        address modes depending on the address space.  */
+      if (!target_default_pointer_address_modes_p ())
+       return 0;
       if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode))
        return 0;
       /* Fall through.  */
@@ -1459,6 +1501,12 @@ find_base_term (rtx x)
 
     case ZERO_EXTEND:
     case SIGN_EXTEND:  /* Used for Alpha/NT pointers */
+      /* As we do not know which address space the pointer is refering to, we can
+        handle this only if the target does not support different pointer or
+        address modes depending on the address space.  */
+      if (!target_default_pointer_address_modes_p ())
+       return 0;
+
       {
        rtx temp = find_base_term (XEXP (x, 0));
 
@@ -1979,6 +2027,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
@@ -2154,6 +2205,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
   if (! DECL_P (exprx) || ! DECL_P (expry))
     return 0;
 
+  /* With invalid code we can end up storing into the constant pool.
+     Bail out to avoid ICEing when creating RTL for this.
+     See gfortran.dg/lto/20091028-2_0.f90.  */
+  if (TREE_CODE (exprx) == CONST_DECL
+      || TREE_CODE (expry) == CONST_DECL)
+    return 1;
+
   rtlx = DECL_RTL (exprx);
   rtly = DECL_RTL (expry);
 
@@ -2164,6 +2222,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
       && ! rtx_equal_p (rtlx, rtly))
     return 1;
 
+  /* If we have MEMs refering to different address spaces (which can
+     potentially overlap), we cannot easily tell from the addresses
+     whether the references overlap.  */
+  if (MEM_P (rtlx) && MEM_P (rtly)
+      && MEM_ADDR_SPACE (rtlx) != MEM_ADDR_SPACE (rtly))
+    return 0;
+
   /* Get the base and offsets of both decls.  If either is a register, we
      know both are and are the same, so use that as the base.  The only
      we can avoid overlap is if we can deduce that they are nonoverlapping
@@ -2255,6 +2320,12 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
   if (nonoverlapping_memrefs_p (mem, x))
     return 0;
 
+  /* If we have MEMs refering to different address spaces (which can
+     potentially overlap), we cannot easily tell from the addresses
+     whether the references overlap.  */
+  if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
+    return 1;
+
   if (mem_mode == VOIDmode)
     mem_mode = GET_MODE (mem);
 
@@ -2290,8 +2361,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.
@@ -2330,6 +2403,12 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
   if (nonoverlapping_memrefs_p (x, mem))
     return 0;
 
+  /* If we have MEMs refering to different address spaces (which can
+     potentially overlap), we cannot easily tell from the addresses
+     whether the references overlap.  */
+  if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
+    return 1;
+
   if (! x_addr)
     x_addr = get_addr (XEXP (x, 0));
 
@@ -2354,8 +2433,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
@@ -2388,6 +2469,12 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
   if (nonoverlapping_memrefs_p (x, mem))
     return 0;
 
+  /* If we have MEMs refering to different address spaces (which can
+     potentially overlap), we cannot easily tell from the addresses
+     whether the references overlap.  */
+  if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
+    return 1;
+
   x_addr = get_addr (XEXP (x, 0));
   mem_addr = get_addr (XEXP (mem, 0));
 
@@ -2415,8 +2502,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.  */