OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index 0943444..719b890 100644 (file)
@@ -1,5 +1,5 @@
 /* Alias analysis for GNU C
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    Contributed by John Carr (jfc@mit.edu).
 
 This file is part of GNU CC.
@@ -20,22 +20,92 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
 #include "expr.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
+#include "output.h"
+#include "toplev.h"
+#include "splay-tree.h"
+
+/* The alias sets assigned to MEMs assist the back-end in determining
+   which MEMs can alias which other MEMs.  In general, two MEMs in
+   different alias sets to not alias each other.  There is one
+   exception, however.  Consider something like:
+
+     struct S {int i; double d; };
+
+   a store to an `S' can alias something of either type `int' or type
+   `double'.  (However, a store to an `int' cannot alias a `double'
+   and vice versa.)  We indicate this via a tree structure that looks
+   like:
+           struct S
+            /   \
+          /     \
+         |/_     _\|
+         int    double
+
+   (The arrows are directed and point downwards.)  If, when comparing
+   two alias sets, we can hold one set fixed, and trace the other set
+   downwards, and at some point find the first set, the two MEMs can
+   alias one another.  In this situation we say the alias set for
+   `struct S' is the `superset' and that those for `int' and `double'
+   are `subsets'.  
+
+   Alias set zero is implicitly a superset of all other alias sets.
+   However, this is no actual entry for alias set zero.  It is an
+   error to attempt to explicitly construct a subset of zero.  */
+
+typedef struct alias_set_entry {
+  /* The alias set number, as stored in MEM_ALIAS_SET.  */
+  int alias_set;
+
+  /* The children of the alias set.  These are not just the immediate
+     children, but, in fact, all children.  So, if we have:
+
+       struct T { struct S s; float f; } 
+
+     continuing our example above, the children here will be all of
+     `int', `double', `float', and `struct S'.  */
+  splay_tree children;
+}* alias_set_entry;
 
 static rtx canon_rtx                   PROTO((rtx));
 static int rtx_equal_for_memref_p      PROTO((rtx, rtx));
 static rtx find_symbolic_term          PROTO((rtx));
 static int memrefs_conflict_p          PROTO((int, rtx, int, rtx,
                                               HOST_WIDE_INT));
+static void record_set                 PROTO((rtx, rtx));
+static rtx find_base_term              PROTO((rtx));
+static int base_alias_check            PROTO((rtx, rtx, enum machine_mode,
+                                              enum machine_mode));
+static rtx find_base_value             PROTO((rtx));
+static int mems_in_disjoint_alias_sets_p PROTO((rtx, rtx));
+static int alias_set_compare            PROTO((splay_tree_key, 
+                                              splay_tree_key));
+static int insert_subset_children       PROTO((splay_tree_node,
+                                              void*));
+static alias_set_entry get_alias_set_entry PROTO((int));
 
 /* Set up all info needed to perform alias analysis on memory references.  */
 
 #define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
 
+/* Returns nonzero if MEM1 and MEM2 do not alias because they are in
+   different alias sets.  We ignore alias sets in functions making use
+   of variable arguments because the va_arg macros on some systems are
+   not legal ANSI C.  */
+#define DIFFERENT_ALIAS_SETS_P(MEM1, MEM2)                     \
+  mems_in_disjoint_alias_sets_p (MEM1, MEM2)
+
+/* Cap the number of passes we make over the insns propagating alias
+   information through set chains.
+
+   10 is a completely arbitrary choice.  */
+#define MAX_ALIAS_LOOP_PASSES 10
+   
 /* reg_base_value[N] gives an address to which register N is related.
    If all sets after the first add or subtract to the current value
    or otherwise modify it so it does not point to a different top level
@@ -55,7 +125,17 @@ rtx *reg_base_value;
 rtx *new_reg_base_value;
 unsigned int reg_base_value_size;      /* size of reg_base_value array */
 #define REG_BASE_VALUE(X) \
-       (REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
+  ((unsigned) REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
+
+/* Vector of known invariant relationships between registers.  Set in
+   loop unrolling.  Indexed by register number, if nonzero the value
+   is an expression describing this register in terms of another.
+
+   The length of this array is REG_BASE_VALUE_SIZE.
+
+   Because this array contains only pseudo registers it has no effect
+   after reload.  */
+static rtx *alias_invariant;
 
 /* Vector indexed by N giving the initial (unchanging) value known
    for pseudo-register N.  */
@@ -82,6 +162,167 @@ char *reg_known_equiv_p;
 
 static int copying_arguments;
 
+/* The splay-tree used to store the various alias set entries.  */
+
+static splay_tree alias_sets;
+
+/* Returns -1, 0, 1 according to whether SET1 is less than, equal to,
+   or greater than SET2.  */
+
+static int
+alias_set_compare (set1, set2)
+     splay_tree_key set1;
+     splay_tree_key set2;
+{
+  int s1 = (int) set1;
+  int s2 = (int) set2;
+
+  if (s1 < s2)
+    return -1;
+  else if (s1 > s2)
+    return 1;
+  else 
+    return 0;
+}
+
+/* Returns a pointer to the alias set entry for ALIAS_SET, if there is
+   such an entry, or NULL otherwise.  */
+
+static alias_set_entry
+get_alias_set_entry (alias_set)
+     int alias_set;
+{
+  splay_tree_node sn =  
+    splay_tree_lookup (alias_sets, (splay_tree_key) alias_set);
+
+  return sn ? ((alias_set_entry) sn->value) : ((alias_set_entry) 0);
+}
+
+/* Returns nonzero value if the alias sets for MEM1 and MEM2 are such
+   that the two MEMs cannot alias each other.  */
+
+static int 
+mems_in_disjoint_alias_sets_p (mem1, mem2)
+     rtx mem1;
+     rtx mem2;
+{
+  alias_set_entry ase;
+
+#ifdef ENABLE_CHECKING 
+/* Perform a basic sanity check.  Namely, that there are no alias sets
+   if we're not using strict aliasing.  This helps to catch bugs
+   whereby someone uses PUT_CODE, but doesn't clear MEM_ALIAS_SET, or
+   where a MEM is allocated in some way other than by the use of
+   gen_rtx_MEM, and the MEM_ALIAS_SET is not cleared.  If we begin to
+   use alias sets to indicate that spilled registers cannot alias each
+   other, we might need to remove this check.  */
+  if (!flag_strict_aliasing && 
+      (MEM_ALIAS_SET (mem1) || MEM_ALIAS_SET (mem2)))
+    abort ();
+#endif
+
+  /* The code used in varargs macros are often not conforming ANSI C,
+     which can trick the compiler into making incorrect aliasing
+     assumptions in these functions.  So, we don't use alias sets in
+     such a function.  FIXME: This should be moved into the front-end;
+     it is a language-dependent notion, and there's no reason not to
+     still use these checks to handle globals.  */
+  if (current_function_stdarg || current_function_varargs)
+    return 0;
+
+  if (!MEM_ALIAS_SET (mem1) || !MEM_ALIAS_SET (mem2))
+    /* We have no alias set information for one of the MEMs, so we
+       have to assume it can alias anything.  */
+    return 0;
+
+  if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2))
+    /* The two alias sets are the same, so they may alias.  */
+    return 0;
+
+  /* Iterate through each of the children of the first alias set,
+     comparing it with the second alias set.  */
+  ase = get_alias_set_entry (MEM_ALIAS_SET (mem1));
+  if (ase && splay_tree_lookup (ase->children,
+                               (splay_tree_key) MEM_ALIAS_SET (mem2)))
+    return  0;
+
+  /* Now do the same, but with the alias sets reversed.  */
+  ase = get_alias_set_entry (MEM_ALIAS_SET (mem2));
+  if (ase && splay_tree_lookup (ase->children,
+                               (splay_tree_key) MEM_ALIAS_SET (mem1)))
+    return  0;
+
+  /* The two MEMs are in distinct alias sets, and neither one is the
+     child of the other.  Therefore, they cannot alias.  */
+  return 1;
+}
+
+/* Insert the NODE into the splay tree given by DATA.  Used by
+   record_alias_subset via splay_tree_foreach.  */
+
+static int
+insert_subset_children (node, data)
+     splay_tree_node node;
+     void *data;
+{
+  splay_tree_insert ((splay_tree) data,
+                    node->key,
+                    node->value);
+
+  return 0;
+}
+
+/* Indicate that things in SUBSET can alias things in SUPERSET, but
+   not vice versa.  For example, in C, a store to an `int' can alias a
+   structure containing an `int', but not vice versa.  Here, the
+   structure would be the SUPERSET and `int' the SUBSET.  This
+   function should be called only once per SUPERSET/SUBSET pair.  At
+   present any given alias set may only be a subset of one superset.  
+
+   It is illegal for SUPERSET to be zero; everything is implicitly a
+   subset of alias set zero.  */
+
+void
+record_alias_subset (superset, subset)
+     int superset;
+     int subset;
+{
+  alias_set_entry superset_entry;
+  alias_set_entry subset_entry;
+
+  if (superset == 0)
+    abort ();
+
+  superset_entry = get_alias_set_entry (superset);
+  if (!superset_entry) 
+    {
+      /* Create an entry for the SUPERSET, so that we have a place to
+        attach the SUBSET.  */
+      superset_entry = 
+       (alias_set_entry) xmalloc (sizeof (struct alias_set_entry));
+      superset_entry->alias_set = superset;
+      superset_entry->children 
+       = splay_tree_new (&alias_set_compare, 0, 0);
+      splay_tree_insert (alias_sets, 
+                        (splay_tree_key) superset,
+                        (splay_tree_value) superset_entry);
+
+    }
+
+  subset_entry = get_alias_set_entry (subset);
+  if (subset_entry) 
+    /* There is an entry for the subset.  Enter all of its children
+       (if they are not already present) as children of the SUPERSET.  */
+    splay_tree_foreach (subset_entry->children,
+                       &insert_subset_children,
+                       superset_entry->children);
+
+  /* Enter the SUBSET itself as a child of the SUPERSET.  */
+  splay_tree_insert (superset_entry->children, 
+                    (splay_tree_key) subset,
+                    /*value=*/0);
+}
+
 /* Inside SRC, the source of a SET, find a base address.  */
 
 static rtx
@@ -102,10 +343,15 @@ find_base_value (src)
       if (REGNO (src) < FIRST_PSEUDO_REGISTER && copying_arguments)
        return new_reg_base_value[REGNO (src)];
 
-      /* If this REG is related to a known base value, return it.
-        This must happen after the arg register check above to avoid
-        circular set chains.  */
-      if (reg_base_value[REGNO (src)])
+      /* If a pseudo has a known base value, return it.  Do not do this
+        for hard regs since it can result in a circular dependency
+        chain for registers which have values at function entry.
+
+        The test above is not sufficient because the scheduler may move
+        a copy out of an arg reg past the NOTE_INSN_FUNCTION_BEGIN.  */
+      if (REGNO (src) >= FIRST_PSEUDO_REGISTER
+         && (unsigned) REGNO (src) < reg_base_value_size
+         && reg_base_value[REGNO (src)])
        return reg_base_value[REGNO (src)];
 
       return src;
@@ -118,7 +364,7 @@ find_base_value (src)
          && (XEXP (src, 0) == arg_pointer_rtx
              || (GET_CODE (XEXP (src, 0)) == PLUS
                  && XEXP (XEXP (src, 0), 0) == arg_pointer_rtx)))
-       return gen_rtx (ADDRESS, VOIDmode, src);
+       return gen_rtx_ADDRESS (VOIDmode, src);
       return 0;
 
     case CONST:
@@ -190,8 +436,13 @@ find_base_value (src)
        return find_base_value (XEXP (src, 0));
       return 0;
 
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:  /* used for NT/Alpha pointers */
     case HIGH:
       return find_base_value (XEXP (src, 0));
+
+    default:
+      break;
     }
 
   return 0;
@@ -203,7 +454,8 @@ find_base_value (src)
    register N has been set in this function.  */
 static char *reg_seen;
 
-/* */
+/* Addresses which are known not to alias anything else are identified
+   by a unique integer.  */
 static int unique_id;
 
 static void
@@ -238,8 +490,8 @@ record_set (dest, set)
          return;
        }
       reg_seen[regno] = 1;
-      new_reg_base_value[regno] = gen_rtx (ADDRESS, Pmode,
-                                      GEN_INT (unique_id++));
+      new_reg_base_value[regno] = gen_rtx_ADDRESS (Pmode,
+                                                  GEN_INT (unique_id++));
       return;
     }
 
@@ -276,16 +528,26 @@ record_set (dest, set)
 
 /* Called from loop optimization when a new pseudo-register is created.  */
 void
-record_base_value (regno, val)
+record_base_value (regno, val, invariant)
      int regno;
      rtx val;
+     int invariant;
 {
-  if (!flag_alias_check || regno >= reg_base_value_size)
+  if ((unsigned) regno >= reg_base_value_size)
     return;
+
+  /* If INVARIANT is true then this value also describes an invariant
+     relationship which can be used to deduce that two registers with
+     unknown values are different.  */
+  if (invariant && alias_invariant)
+    alias_invariant[regno] = val;
+
   if (GET_CODE (val) == REG)
     {
-      if (REGNO (val) < reg_base_value_size)
-       reg_base_value[regno] = reg_base_value[REGNO (val)];
+      if ((unsigned) REGNO (val) < reg_base_value_size)
+       {
+         reg_base_value[regno] = reg_base_value[REGNO (val)];
+       }
       return;
     }
   reg_base_value[regno] = find_base_value (val);
@@ -313,7 +575,7 @@ canon_rtx (x)
            return plus_constant_for_output (x1, INTVAL (x0));
          else if (GET_CODE (x1) == CONST_INT)
            return plus_constant_for_output (x0, INTVAL (x1));
-         return gen_rtx (PLUS, GET_MODE (x), x0, x1);
+         return gen_rtx_PLUS (GET_MODE (x), x0, x1);
        }
     }
   /* This gives us much better alias analysis when called from
@@ -325,10 +587,11 @@ canon_rtx (x)
       rtx addr = canon_rtx (XEXP (x, 0));
       if (addr != XEXP (x, 0))
        {
-         rtx new = gen_rtx (MEM, GET_MODE (x), addr);
+         rtx new = gen_rtx_MEM (GET_MODE (x), addr);
          MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
          RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
          MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
+         MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
          x = new;
        }
     }
@@ -378,6 +641,10 @@ rtx_equal_for_memref_p (x, y)
     return XEXP (x, 0) == XEXP (y, 0);
   if (code == SYMBOL_REF)
     return XSTR (x, 0) == XSTR (y, 0);
+  if (code == CONST_INT)
+    return INTVAL (x) == INTVAL (y);
+  if (code == ADDRESSOF)
+    return REGNO (XEXP (x, 0)) == REGNO (XEXP (y, 0)) && XINT (x, 1) == XINT (y, 1);
 
   /* For commutative operations, the RTX match if the operand match in any
      order.  Also handle the simple binary and unary cases without a loop.  */
@@ -393,25 +660,20 @@ rtx_equal_for_memref_p (x, y)
     return rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0));
 
   /* Compare the elements.  If any pair of corresponding elements
-     fail to match, return 0 for the whole things.  */
+     fail to match, return 0 for the whole things.
+
+     Limit cases to types which actually appear in addresses.  */
 
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       switch (fmt[i])
        {
-       case 'w':
-         if (XWINT (x, i) != XWINT (y, i))
-           return 0;
-         break;
-
-       case 'n':
        case 'i':
          if (XINT (x, i) != XINT (y, i))
            return 0;
          break;
 
-       case 'V':
        case 'E':
          /* Two vectors must have the same length.  */
          if (XVECLEN (x, i) != XVECLEN (y, i))
@@ -428,16 +690,7 @@ rtx_equal_for_memref_p (x, y)
            return 0;
          break;
 
-       case 'S':
-       case 's':
-         if (strcmp (XSTR (x, i), XSTR (y, i)))
-           return 0;
-         break;
-
-       case 'u':
-         /* These are just backpointers, so they don't matter.  */
-         break;
-
+       /* This can happen for an asm which clobbers memory.  */
        case '0':
          break;
 
@@ -494,9 +747,9 @@ find_base_term (x)
     case REG:
       return REG_BASE_VALUE (x);
 
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:  /* Used for Alpha/NT pointers */
     case HIGH:
-      return find_base_term (XEXP (x, 0));
-
     case PRE_INC:
     case PRE_DEC:
     case POST_INC:
@@ -536,29 +789,57 @@ find_base_term (x)
    objects, 1 if they might be pointers to the same object.  */
 
 static int
-base_alias_check (x, y)
+base_alias_check (x, y, x_mode, y_mode)
      rtx x, y;
+     enum machine_mode x_mode, y_mode;
 {
   rtx x_base = find_base_term (x);
   rtx y_base = find_base_term (y);
 
-  /* If either base address is unknown or the base addresses are equal,
-     nothing is known about aliasing.  */
+  /* If the address itself has no known base see if a known equivalent
+     value has one.  If either address still has no known base, nothing
+     is known about aliasing.  */
+  if (x_base == 0)
+    {
+      rtx x_c;
+      if (! flag_expensive_optimizations || (x_c = canon_rtx (x)) == x)
+       return 1;
+      x_base = find_base_term (x_c);
+      if (x_base == 0)
+       return 1;
+    }
+
+  if (y_base == 0)
+    {
+      rtx y_c;
+      if (! flag_expensive_optimizations || (y_c = canon_rtx (y)) == y)
+       return 1;
+      y_base = find_base_term (y_c);
+      if (y_base == 0)
+       return 1;
+    }
 
-  if (x_base == 0 || y_base == 0 || rtx_equal_p (x_base, y_base))
+  /* If the base addresses are equal nothing is known about aliasing.  */
+  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.  */
-  /* XXX: We can bring knowledge of object alignment and offset into 
-     play here.  For example, on alpha, "char a, b;" can alias one
-     another, though "char a; long b;" cannot.  Similarly, offsets
-     into strutures may be brought into play.  Given "char a, b[40];",
-     a and b[1] may overlap, but a and b[20] do not.  */
+  /* 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.  */
   if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS)
     {
-      return GET_CODE (x) == AND || GET_CODE (y) == AND;
+      if (GET_CODE (x) == AND && GET_CODE (y) == AND)
+       return 1;
+      if (GET_CODE (x) == AND
+         && (GET_CODE (XEXP (x, 1)) != CONST_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
+             || GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
+       return 1;
     }
 
   /* If one address is a stack reference there can be no alias:
@@ -593,12 +874,6 @@ base_alias_check (x, y)
    being referenced as a side effect.  This can happen when using AND to
    align memory references, as is done on the Alpha.
 
-   We recognize the following cases of non-conflicting memory:
-
-       (1) addresses involving the frame pointer cannot conflict
-           with addresses involving static variables.
-       (2) static variables with different addresses cannot conflict.
-
    Nice to notice that varying addresses cannot conflict with fp if no
    local variables had their addresses taken, but that's too hard now.  */
 
@@ -633,40 +908,8 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
       return 0;
     }
 
-  if (y == frame_pointer_rtx || y == hard_frame_pointer_rtx
-      || y == stack_pointer_rtx || y == arg_pointer_rtx)
-    {
-      rtx t = y;
-      int tsize = ysize;
-      y = x; ysize = xsize;
-      x = t; xsize = tsize;
-    }
-
-  if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-      || x == stack_pointer_rtx || x == arg_pointer_rtx)
-    {
-      rtx y1;
-
-      if (CONSTANT_P (y))
-       return 0;
-
-      if (GET_CODE (y) == PLUS
-         && canon_rtx (XEXP (y, 0)) == x
-         && (y1 = canon_rtx (XEXP (y, 1)))
-         && GET_CODE (y1) == CONST_INT)
-       {
-         c += INTVAL (y1);
-         return (xsize <= 0 || ysize <= 0
-                 || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
-       }
-
-      if (GET_CODE (y) == PLUS
-         && (y1 = canon_rtx (XEXP (y, 0)))
-         && CONSTANT_P (y1))
-       return 0;
-
-      return 1;
-    }
+  /* This code used to check for conflicts involving stack references and
+     globals but the base address alias code now handles these cases.  */
 
   if (GET_CODE (x) == PLUS)
     {
@@ -687,24 +930,18 @@ memrefs_conflict_p (xsize, x, ysize, y, 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 (GET_CODE (y1) == CONST_INT)
-             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));
+           {
+             if (GET_CODE (y1) == CONST_INT)
+               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)
            return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
 
-         /* Handle case where we cannot understand iteration operators,
-            but we notice that the base addresses are distinct objects.  */
-         /* ??? Is this still necessary? */
-         x = find_symbolic_term (x);
-         if (x == 0)
-           return 1;
-         y = find_symbolic_term (y);
-         if (y == 0)
-           return 1;
-         return rtx_equal_for_memref_p (x, y);
+         return 1;
        }
       else if (GET_CODE (x1) == CONST_INT)
        return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
@@ -749,19 +986,49 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
          c /= INTVAL (x1);
          return memrefs_conflict_p (xsize, x0, ysize, y0, c);
        }
+
+      case REG:
+       /* Are these registers known not to be equal?  */
+       if (alias_invariant)
+         {
+           unsigned int r_x = REGNO (x), r_y = REGNO (y);
+           rtx i_x, i_y;       /* invariant relationships of X and Y */
+
+           i_x = r_x >= reg_base_value_size ? 0 : alias_invariant[r_x];
+           i_y = r_y >= reg_base_value_size ? 0 : alias_invariant[r_y];
+
+           if (i_x == 0 && i_y == 0)
+             break;
+
+           if (! memrefs_conflict_p (xsize, i_x ? i_x : x,
+                                     ysize, i_y ? i_y : y, c))
+             return 0;
+         }
+       break;
+
+      default:
+       break;
       }
 
   /* Treat an access through an AND (e.g. a subword access on an Alpha)
-     as an access with indeterminate size.  */
+     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)
-    return memrefs_conflict_p (-1, XEXP (x, 0), ysize, y, c);
+    {
+      if (ysize < -INTVAL (XEXP (x, 1)))
+       xsize = -1;
+      return memrefs_conflict_p (xsize, XEXP (x, 0), ysize, y, c);
+    }
   if (GET_CODE (y) == AND && GET_CODE (XEXP (y, 1)) == CONST_INT)
     {
-      /* XXX: If we are indexing far enough into the array/structure, we
+      /* ??? If we are indexing far enough into the array/structure, we
         may yet be able to determine that we can not overlap.  But we 
         also need to that we are far enough from the end not to overlap
-        a following reference, so we do nothing for now.  */
-      return memrefs_conflict_p (xsize, x, -1, XEXP (y, 0), c);
+        a following reference, so we do nothing with that for now.  */
+      if (xsize < -INTVAL (XEXP (y, 1)))
+       ysize = -1;
+      return memrefs_conflict_p (xsize, x, ysize, XEXP (y, 0), c);
     }
 
   if (CONSTANT_P (x))
@@ -836,17 +1103,14 @@ true_dependence (mem, mem_mode, x, varies)
      rtx mem;
      enum machine_mode mem_mode;
      rtx x;
-     int (*varies)();
+     int (*varies) PROTO((rtx));
 {
-  rtx x_addr, mem_addr;
+  register rtx x_addr, mem_addr;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
-  x_addr = XEXP (x, 0);
-  mem_addr = XEXP (mem, 0);
-
-  if (flag_alias_check && ! base_alias_check (x_addr, mem_addr))
+  if (DIFFERENT_ALIAS_SETS_P (x, mem))
     return 0;
 
   /* If X is an unchanging read, then it can't possibly conflict with any
@@ -859,11 +1123,15 @@ true_dependence (mem, mem_mode, x, varies)
   if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
     return 0;
 
-  x_addr = canon_rtx (x_addr);
-  mem_addr = canon_rtx (mem_addr);
   if (mem_mode == VOIDmode)
     mem_mode = GET_MODE (mem);
 
+  if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x), mem_mode))
+    return 0;
+
+  x_addr = canon_rtx (XEXP (x, 0));
+  mem_addr = canon_rtx (XEXP (mem, 0));
+
   if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
                            SIZE_FOR_MODE (x), x_addr, 0))
     return 0;
@@ -901,29 +1169,39 @@ anti_dependence (mem, x)
      rtx mem;
      rtx x;
 {
+  rtx x_addr, mem_addr;
+
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
-  if (flag_alias_check && ! base_alias_check (XEXP (x, 0), XEXP (mem, 0)))
-    return 0;
-
   /* If MEM is an unchanging read, then it can't possibly conflict with
      the store to X, because there is at most one store to MEM, and it must
      have occurred somewhere before MEM.  */
+  if (RTX_UNCHANGING_P (mem))
+    return 0;
+
+  if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x),
+                         GET_MODE (mem)))
+    return 0;
+
   x = canon_rtx (x);
   mem = canon_rtx (mem);
-  if (RTX_UNCHANGING_P (mem))
+
+  if (DIFFERENT_ALIAS_SETS_P (x, mem))
     return 0;
 
-  return (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
-                             SIZE_FOR_MODE (x), XEXP (x, 0), 0)
+  x_addr = XEXP (x, 0);
+  mem_addr = XEXP (mem, 0);
+
+  return (memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
+                             SIZE_FOR_MODE (x), x_addr, 0)
          && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
                && GET_MODE (mem) != QImode
-               && GET_CODE (XEXP (mem, 0)) != AND
+               && GET_CODE (mem_addr) != AND
                && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
          && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
                && GET_MODE (x) != QImode
-               && GET_CODE (XEXP (x, 0)) != AND
+               && GET_CODE (x_addr) != AND
                && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem)));
 }
 
@@ -937,11 +1215,16 @@ output_dependence (mem, x)
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
-  if (flag_alias_check && !base_alias_check (XEXP (x, 0), XEXP (mem, 0)))
+  if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x),
+                         GET_MODE (mem)))
     return 0;
 
   x = canon_rtx (x);
   mem = canon_rtx (mem);
+
+  if (DIFFERENT_ALIAS_SETS_P (x, mem))
+    return 0;
+
   return (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
                              SIZE_FOR_MODE (x), XEXP (x, 0), 0)
          && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
@@ -954,15 +1237,36 @@ output_dependence (mem, x)
                && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem)));
 }
 
+
+static HARD_REG_SET argument_registers;
+
+void
+init_alias_once ()
+{
+  register int i;
+
+#ifndef OUTGOING_REGNO
+#define OUTGOING_REGNO(N) N
+#endif
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    /* Check whether this register can hold an incoming pointer
+       argument.  FUNCTION_ARG_REGNO_P tests outgoing register
+       numbers, so translate if necessary due to register windows. */
+    if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
+       && HARD_REGNO_MODE_OK (i, Pmode))
+      SET_HARD_REG_BIT (argument_registers, i);
+
+  alias_sets = splay_tree_new (&alias_set_compare, 0, 0);
+}
+
 void
 init_alias_analysis ()
 {
   int maxreg = max_reg_num ();
-  int changed;
+  int changed, pass;
   register int i;
+  register unsigned int ui;
   register rtx insn;
-  rtx note;
-  rtx set;
 
   reg_known_value_size = maxreg;
 
@@ -976,17 +1280,21 @@ init_alias_analysis ()
   bzero (reg_known_equiv_p + FIRST_PSEUDO_REGISTER,
         (maxreg - FIRST_PSEUDO_REGISTER) * sizeof (char));
 
-  if (flag_alias_check)
+  /* Overallocate reg_base_value to allow some growth during loop
+     optimization.  Loop unrolling can create a large number of
+     registers.  */
+  reg_base_value_size = maxreg * 2;
+  reg_base_value = (rtx *)oballoc (reg_base_value_size * sizeof (rtx));
+  new_reg_base_value = (rtx *)alloca (reg_base_value_size * sizeof (rtx));
+  reg_seen = (char *)alloca (reg_base_value_size);
+  bzero ((char *) reg_base_value, reg_base_value_size * sizeof (rtx));
+  if (! reload_completed && flag_unroll_loops)
     {
-      /* Overallocate reg_base_value to allow some growth during loop
-        optimization.  Loop unrolling can create a large number of
-        registers.  */
-      reg_base_value_size = maxreg * 2;
-      reg_base_value = (rtx *)oballoc (reg_base_value_size * sizeof (rtx));
-      new_reg_base_value = (rtx *)alloca (reg_base_value_size * sizeof (rtx));
-      reg_seen = (char *)alloca (reg_base_value_size);
-      bzero ((char *) reg_base_value, reg_base_value_size * sizeof (rtx));
+      alias_invariant = (rtx *)xrealloc (alias_invariant,
+                                        reg_base_value_size * sizeof (rtx));
+      bzero ((char *)alias_invariant, reg_base_value_size * sizeof (rtx));
     }
+    
 
   /* The basic idea is that each pass through this loop will use the
      "constant" information from the previous pass to propagate alias
@@ -994,13 +1302,21 @@ init_alias_analysis ()
 
      This could get expensive if the assignment chains are long.  Maybe
      we should throttle the number of iterations, possibly based on
-     the optimization level.
+     the optimization level or flag_expensive_optimizations.
 
      We could propagate more information in the first pass by making use
      of REG_N_SETS to determine immediately that the alias information
-     for a pseudo is "constant".  */
-  changed = 1;
-  while (changed)
+     for a pseudo is "constant".
+
+     A program with an uninitialized variable can cause an infinite loop
+     here.  Instead of doing a full dataflow analysis to detect such problems
+     we just cap the number of iterations for the loop.
+
+     The state of the arrays for the set chain in question does not matter
+     since the program has undefined behavior.  */
+
+  pass = 0;
+  do
     {
       /* Assume nothing will change this iteration of the loop.  */
       changed = 0;
@@ -1013,138 +1329,130 @@ init_alias_analysis ()
         loop, so we're copying arguments.  */
       copying_arguments = 1;
 
-      /* Only perform initialization of the arrays if we're actually
-        performing alias analysis. */
-      if (flag_alias_check)
-       {
-         /* Wipe the potential alias information clean for this pass.  */
-         bzero ((char *) new_reg_base_value,
-                reg_base_value_size * sizeof (rtx));
+      /* Wipe the potential alias information clean for this pass.  */
+      bzero ((char *) new_reg_base_value, reg_base_value_size * sizeof (rtx));
 
-         /* Wipe the reg_seen array clean.  */
-         bzero ((char *) reg_seen, reg_base_value_size);
+      /* Wipe the reg_seen array clean.  */
+      bzero ((char *) reg_seen, reg_base_value_size);
 
-         /* Mark all hard registers which may contain an address.
-            The stack, frame and argument pointers may contain an address.
-            An argument register which can hold a Pmode value may contain
-            an address even if it is not in BASE_REGS.
+      /* Mark all hard registers which may contain an address.
+        The stack, frame and argument pointers may contain an address.
+        An argument register which can hold a Pmode value may contain
+        an address even if it is not in BASE_REGS.
 
-            The address expression is VOIDmode for an argument and
-            Pmode for other registers.  */
-#ifndef OUTGOING_REGNO
-#define OUTGOING_REGNO(N) N
-#endif
-         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-           /* Check whether this register can hold an incoming pointer
-              argument.  FUNCTION_ARG_REGNO_P tests outgoing register
-              numbers, so translate if necessary due to register windows. */
-           if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
-               && HARD_REGNO_MODE_OK (i, Pmode))
-             new_reg_base_value[i] = gen_rtx (ADDRESS, VOIDmode,
-                                              gen_rtx (REG, Pmode, i));
-
-         new_reg_base_value[STACK_POINTER_REGNUM]
-           = gen_rtx (ADDRESS, Pmode, stack_pointer_rtx);
-         new_reg_base_value[ARG_POINTER_REGNUM]
-           = gen_rtx (ADDRESS, Pmode, arg_pointer_rtx);
-         new_reg_base_value[FRAME_POINTER_REGNUM]
-           = gen_rtx (ADDRESS, Pmode, frame_pointer_rtx);
+        The address expression is VOIDmode for an argument and
+        Pmode for other registers.  */
+
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (TEST_HARD_REG_BIT (argument_registers, i))
+         new_reg_base_value[i] = gen_rtx_ADDRESS (VOIDmode,
+                                                  gen_rtx_REG (Pmode, i));
+
+      new_reg_base_value[STACK_POINTER_REGNUM]
+       = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
+      new_reg_base_value[ARG_POINTER_REGNUM]
+       = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
+      new_reg_base_value[FRAME_POINTER_REGNUM]
+       = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
-           = gen_rtx (ADDRESS, Pmode, hard_frame_pointer_rtx);
+      new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
+       = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
 #endif
-         if (struct_value_incoming_rtx
-             && GET_CODE (struct_value_incoming_rtx) == REG)
-           new_reg_base_value[REGNO (struct_value_incoming_rtx)]
-             = gen_rtx (ADDRESS, Pmode, struct_value_incoming_rtx);
-
-         if (static_chain_rtx
-             && GET_CODE (static_chain_rtx) == REG)
-           new_reg_base_value[REGNO (static_chain_rtx)]
-             = gen_rtx (ADDRESS, Pmode, static_chain_rtx);
-       }
+      if (struct_value_incoming_rtx
+         && GET_CODE (struct_value_incoming_rtx) == REG)
+       new_reg_base_value[REGNO (struct_value_incoming_rtx)]
+         = gen_rtx_ADDRESS (Pmode, struct_value_incoming_rtx);
+
+      if (static_chain_rtx
+         && GET_CODE (static_chain_rtx) == REG)
+       new_reg_base_value[REGNO (static_chain_rtx)]
+         = gen_rtx_ADDRESS (Pmode, static_chain_rtx);
 
       /* Walk the insns adding values to the new_reg_base_value array.  */
       for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        {
-         if (flag_alias_check && GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
            {
+             rtx note, set;
              /* If this insn has a noalias note, process it,  Otherwise,
                 scan for sets.  A simple set will have no side effects
                 which could change the base value of any other register. */
-             rtx noalias_note;
+
              if (GET_CODE (PATTERN (insn)) == SET
-                 && (noalias_note = find_reg_note (insn,
-                                                   REG_NOALIAS, NULL_RTX)))
-               record_set (SET_DEST (PATTERN (insn)), 0);
+                 && (find_reg_note (insn, REG_NOALIAS, NULL_RTX)))
+               record_set (SET_DEST (PATTERN (insn)), NULL_RTX);
              else
                note_stores (PATTERN (insn), record_set);
+
+             set = single_set (insn);
+
+             if (set != 0
+                 && GET_CODE (SET_DEST (set)) == REG
+                 && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
+                 && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
+                      && REG_N_SETS (REGNO (SET_DEST (set))) == 1)
+                     || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
+                 && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
+               {
+                 int regno = REGNO (SET_DEST (set));
+                 reg_known_value[regno] = XEXP (note, 0);
+                 reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
+               }
            }
          else if (GET_CODE (insn) == NOTE
                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
            copying_arguments = 0;
+       }
 
-         if ((set = single_set (insn)) != 0
-             && GET_CODE (SET_DEST (set)) == REG
-             && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
-             && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
-                  && REG_N_SETS (REGNO (SET_DEST (set))) == 1)
-                 || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
-             && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
+      /* Now propagate values from new_reg_base_value to reg_base_value.  */
+      for (ui = 0; ui < reg_base_value_size; ui++)
+       {
+         if (new_reg_base_value[ui]
+             && new_reg_base_value[ui] != reg_base_value[ui]
+             && ! rtx_equal_p (new_reg_base_value[ui], reg_base_value[ui]))
            {
-             int regno = REGNO (SET_DEST (set));
-             reg_known_value[regno] = XEXP (note, 0);
-             reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
+             reg_base_value[ui] = new_reg_base_value[ui];
+             changed = 1;
            }
        }
-
-      /* Now propagate values from new_reg_base_value to reg_base_value.  */
-      if (flag_alias_check)
-       for (i = 0; i < reg_base_value_size; i++)
-         {
-           if (new_reg_base_value[i]
-               && new_reg_base_value[i] != reg_base_value[i]
-               && !rtx_equal_p (new_reg_base_value[i], reg_base_value[i]))
-             {
-               reg_base_value[i] = new_reg_base_value[i];
-               changed = 1;
-             }
-         }
     }
+  while (changed && ++pass < MAX_ALIAS_LOOP_PASSES);
 
   /* Fill in the remaining entries.  */
   for (i = FIRST_PSEUDO_REGISTER; i < maxreg; i++)
     if (reg_known_value[i] == 0)
       reg_known_value[i] = regno_reg_rtx[i];
 
-  if (! flag_alias_check)
-    return;
-
   /* Simplify the reg_base_value array so that no register refers to
      another register, except to special registers indirectly through
      ADDRESS expressions.
 
      In theory this loop can take as long as O(registers^2), but unless
      there are very long dependency chains it will run in close to linear
-     time.  */
+     time.
+
+     This loop may not be needed any longer now that the main loop does
+     a better job at propagating alias information.  */
+  pass = 0;
   do
     {
       changed = 0;
-      for (i = 0; i < reg_base_value_size; i++)
+      pass++;
+      for (ui = 0; ui < reg_base_value_size; ui++)
        {
-         rtx base = reg_base_value[i];
+         rtx base = reg_base_value[ui];
          if (base && GET_CODE (base) == REG)
            {
-             int base_regno = REGNO (base);
-             if (base_regno == i)              /* register set from itself */
-               reg_base_value[i] = 0;
+             unsigned int base_regno = REGNO (base);
+             if (base_regno == ui)             /* register set from itself */
+               reg_base_value[ui] = 0;
              else
-               reg_base_value[i] = reg_base_value[base_regno];
+               reg_base_value[ui] = reg_base_value[base_regno];
              changed = 1;
            }
        }
     }
-  while (changed);
+  while (changed && pass < MAX_ALIAS_LOOP_PASSES);
 
   new_reg_base_value = 0;
   reg_seen = 0;
@@ -1156,4 +1464,9 @@ end_alias_analysis ()
   reg_known_value = 0;
   reg_base_value = 0;
   reg_base_value_size = 0;
+  if (alias_invariant)
+    {
+      free ((char *)alias_invariant);
+      alias_invariant = 0;
+    }
 }