OSDN Git Service

* gcc.target/i386/align-main-1.c (check): Mark noinline.
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index b29abf7..794df75 100644 (file)
@@ -1,6 +1,6 @@
 /* Alias analysis for GNU C
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2007 Free Software Foundation, Inc.
+   2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by John Carr (jfc@mit.edu).
 
 This file is part of GCC.
@@ -128,8 +128,7 @@ along with GCC; see the file COPYING3.  If not see
    However, this is no actual entry for alias set zero.  It is an
    error to attempt to explicitly construct a subset of zero.  */
 
-struct alias_set_entry GTY(())
-{
+struct GTY(()) alias_set_entry {
   /* The alias set number, as stored in MEM_ALIAS_SET.  */
   alias_set_type alias_set;
 
@@ -167,7 +166,6 @@ static rtx adjust_offset_for_component_ref (tree, rtx);
 static int write_dependence_p (const_rtx, const_rtx, int);
 
 static void memory_modified_1 (rtx, const_rtx, void *);
-static void record_alias_subset (alias_set_type, alias_set_type);
 
 /* Set up all info needed to perform alias analysis on memory references.  */
 
@@ -344,6 +342,43 @@ alias_sets_conflict_p (alias_set_type set1, alias_set_type set2)
   return 0;
 }
 
+static int
+walk_mems_2 (rtx *x, rtx mem)
+{
+  if (MEM_P (*x))
+    {
+      if (alias_sets_conflict_p (MEM_ALIAS_SET(*x), MEM_ALIAS_SET(mem)))
+        return 1;
+        
+      return -1;  
+    }
+  return 0;
+}
+
+static int
+walk_mems_1 (rtx *x, rtx *pat)
+{
+  if (MEM_P (*x))
+    {
+      /* Visit all MEMs in *PAT and check indepedence.  */
+      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;
+}
+
+/* Return 1 if two specified instructions have mem expr with conflict alias sets*/
+bool
+insn_alias_sets_conflict_p (rtx insn1, rtx insn2)
+{
+  /* For each pair of MEMs in INSN1 and INSN2 check their independence.  */
+  return  for_each_rtx (&PATTERN (insn1), (rtx_function) walk_mems_1,
+                        &PATTERN (insn2));
+}
+
 /* Return 1 if the two specified alias sets will always conflict.  */
 
 int
@@ -400,6 +435,9 @@ find_base_decl (tree t)
   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))
@@ -482,6 +520,98 @@ component_uses_parent_alias_set (const_tree t)
     }
 }
 
+/* Return the alias set for the memory pointed to by T, which may be
+   either a type or an expression.  Return -1 if there is nothing
+   special about dereferencing T.  */
+
+static alias_set_type
+get_deref_alias_set_1 (tree t)
+{
+  /* If we're not doing any alias analysis, just assume everything
+     aliases everything else.  */
+  if (!flag_strict_aliasing)
+    return 0;
+
+  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);
+    }
+
+  /* If we have an INDIRECT_REF via a void pointer, we don't
+     know anything about what that might alias.  Likewise if the
+     pointer is marked that way.  */
+  if (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE
+      || TYPE_REF_CAN_ALIAS_ALL (t))
+    return 0;
+
+  return -1;
+}
+
+/* Return the alias set for the memory pointed to by T, which may be
+   either a type or an expression.  */
+
+alias_set_type
+get_deref_alias_set (tree t)
+{
+  alias_set_type set = get_deref_alias_set_1 (t);
+
+  /* Fall back to the alias-set of the pointed-to type.  */
+  if (set == -1)
+    {
+      if (! TYPE_P (t))
+       t = TREE_TYPE (t);
+      set = get_alias_set (TREE_TYPE (t));
+    }
+
+  return set;
+}
+
 /* Return the alias set for T, which may be either a type or an
    expression.  Call language-specific routine for help, if needed.  */
 
@@ -522,75 +652,13 @@ get_alias_set (tree t)
          STRIP_NOPS (inner);
        }
 
-      /* Check for accesses through restrict-qualified pointers.  */
       if (INDIRECT_REF_P (inner))
        {
-         tree decl;
-
-         if (TREE_CODE (TREE_OPERAND (inner, 0)) == SSA_NAME)
-           decl = SSA_NAME_VAR (TREE_OPERAND (inner, 0));
-         else
-           decl = find_base_decl (TREE_OPERAND (inner, 0));
-
-         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);
-           }
-
-         /* If we have an INDIRECT_REF via a void pointer, we don't
-            know anything about what that might alias.  Likewise if the
-            pointer is marked that way.  */
-         else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE
-                  || (TYPE_REF_CAN_ALIAS_ALL
-                      (TREE_TYPE (TREE_OPERAND (inner, 0)))))
-           return 0;
+         set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
+         if (set != -1)
+           return set;
        }
 
-      /* For non-addressable fields we return the alias set of the
-        outermost object that could have its address taken.  If this
-        is an SFT use the precomputed value.  */
-      if (TREE_CODE (t) == STRUCT_FIELD_TAG
-         && SFT_NONADDRESSABLE_P (t))
-       return SFT_ALIAS_SET (t);
-
       /* Otherwise, pick up the outermost object that we could have a pointer
         to, processing conversions as above.  */
       while (component_uses_parent_alias_set (t))
@@ -611,8 +679,11 @@ get_alias_set (tree t)
     }
 
   /* Variant qualifiers don't affect the alias set, so get the main
-     variant. If this is a type with a known alias set, return it.  */
+     variant.  Always use the canonical type as well.
+     If this is a type with a known alias set, return it.  */
   t = TYPE_MAIN_VARIANT (t);
+  if (TYPE_CANONICAL (t))
+    t = TYPE_CANONICAL (t);
   if (TYPE_ALIAS_SET_KNOWN_P (t))
     return TYPE_ALIAS_SET (t);
 
@@ -647,6 +718,18 @@ get_alias_set (tree t)
   else if (TREE_CODE (t) == VECTOR_TYPE)
     set = get_alias_set (TREE_TYPE (t));
 
+  /* Unless the language specifies otherwise, treat array types the
+     same as their components.  This avoids the asymmetry we get
+     through recording the components.  Consider accessing a
+     character(kind=1) through a reference to a character(kind=1)[1:1].
+     Or consider if we want to assign integer(kind=4)[0:D.1387] and
+     integer(kind=4)[4] the same alias set or not.
+     Just be pragmatic here and make sure the array and its element
+     type get the same alias set assigned.  */
+  else if (TREE_CODE (t) == ARRAY_TYPE
+          && !TYPE_NONALIASED_COMPONENT (t))
+    set = get_alias_set (TREE_TYPE (t));
+
   else
     /* Otherwise make a new alias set for this type.  */
     set = new_alias_set ();
@@ -690,7 +773,7 @@ new_alias_set (void)
    It is illegal for SUPERSET to be zero; everything is implicitly a
    subset of alias set zero.  */
 
-static void
+void
 record_alias_subset (alias_set_type superset, alias_set_type subset)
 {
   alias_set_entry superset_entry;
@@ -708,7 +791,7 @@ record_alias_subset (alias_set_type superset, alias_set_type subset)
     {
       /* Create an entry for the SUPERSET, so that we have a place to
         attach the SUBSET.  */
-      superset_entry = ggc_alloc (sizeof (struct alias_set_entry));
+      superset_entry = GGC_NEW (struct alias_set_entry);
       superset_entry->alias_set = superset;
       superset_entry->children
        = splay_tree_new_ggc (splay_tree_compare_ints);
@@ -754,11 +837,6 @@ record_component_aliases (tree type)
 
   switch (TREE_CODE (type))
     {
-    case ARRAY_TYPE:
-      if (!TYPE_NONALIASED_COMPONENT (type))
-       record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
-      break;
-
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
@@ -782,6 +860,9 @@ record_component_aliases (tree type)
       record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
       break;
 
+    /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their
+       element type.  */
+
     default:
       break;
     }
@@ -830,6 +911,11 @@ find_base_value (rtx src)
 {
   unsigned int regno;
 
+#if defined (FIND_BASE_TERM)
+  /* Try machine-dependent ways to find the base term.  */
+  src = FIND_BASE_TERM (src);
+#endif
+
   switch (GET_CODE (src))
     {
     case SYMBOL_REF:
@@ -1391,12 +1477,16 @@ find_base_term (rtx x)
          return x;
       return 0;
 
+    case LO_SUM:
+      /* The standard form is (lo_sum reg sym) so look only at the
+         second operand.  */
+      return find_base_term (XEXP (x, 1));
+
     case CONST:
       x = XEXP (x, 0);
       if (GET_CODE (x) != PLUS && GET_CODE (x) != MINUS)
        return 0;
       /* Fall through.  */
-    case LO_SUM:
     case PLUS:
     case MINUS:
       {
@@ -1508,26 +1598,27 @@ base_alias_check (rtx x, rtx y, enum machine_mode x_mode,
   if (rtx_equal_p (x_base, y_base))
     return 1;
 
-  /* The base addresses of the read and write are different expressions.
-     If they are both symbols and they are not accessed via AND, there is
-     no conflict.  We can bring knowledge of object alignment into play
-     here.  For example, on alpha, "char a, b;" can alias one another,
-     though "char a; long b;" cannot.  */
+  /* The base addresses are different expressions.  If they are not accessed
+     via AND, there is no conflict.  We can bring knowledge of object
+     alignment into play here.  For example, on alpha, "char a, b;" can
+     alias one another, though "char a; long b;" cannot.  AND addesses may
+     implicitly alias surrounding objects; i.e. unaligned access in DImode
+     via AND address can alias all surrounding object types except those
+     with aligment 8 or higher.  */
+  if (GET_CODE (x) == AND && GET_CODE (y) == AND)
+    return 1;
+  if (GET_CODE (x) == AND
+      && (GET_CODE (XEXP (x, 1)) != CONST_INT
+         || (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
+         || (int) GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
+    return 1;
+
+  /* Differing symbols not accessed via AND never alias.  */
   if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS)
-    {
-      if (GET_CODE (x) == AND && GET_CODE (y) == AND)
-       return 1;
-      if (GET_CODE (x) == AND
-         && (GET_CODE (XEXP (x, 1)) != CONST_INT
-             || (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
-             || (int) GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
-       return 1;
-      /* Differing symbols never alias.  */
-      return 0;
-    }
+    return 0;
 
   /* If one address is a stack reference there can be no alias:
      stack references using different base registers do not alias,
@@ -2199,14 +2290,13 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
    Variant of true_dependence which assumes MEM has already been
    canonicalized (hence we no longer do that here).
    The mem_addr argument has been added, since true_dependence computed
-   this value prior to canonicalizing.  */
+   this value prior to canonicalizing.
+   If x_addr is non-NULL, it is used in preference of XEXP (x, 0).  */
 
 int
 canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
-                      const_rtx x, bool (*varies) (const_rtx, bool))
+                      const_rtx x, rtx x_addr, bool (*varies) (const_rtx, bool))
 {
-  rtx x_addr;
-
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
@@ -2232,7 +2322,8 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
   if (nonoverlapping_memrefs_p (x, mem))
     return 0;
 
-  x_addr = get_addr (XEXP (x, 0));
+  if (! x_addr)
+    x_addr = get_addr (XEXP (x, 0));
 
   if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
     return 0;
@@ -2409,8 +2500,8 @@ init_alias_analysis (void)
   timevar_push (TV_ALIAS_ANALYSIS);
 
   reg_known_value_size = maxreg - FIRST_PSEUDO_REGISTER;
-  reg_known_value = ggc_calloc (reg_known_value_size, sizeof (rtx));
-  reg_known_equiv_p = xcalloc (reg_known_value_size, sizeof (bool));
+  reg_known_value = GGC_CNEWVEC (rtx, reg_known_value_size);
+  reg_known_equiv_p = XCNEWVEC (bool, reg_known_value_size);
 
   /* If we have memory allocated from the previous run, use it.  */
   if (old_reg_base_value)