OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index 68a8272..6a73d64 100644 (file)
@@ -1,5 +1,6 @@
 /* Alias analysis for GNU C
-   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
    Contributed by John Carr (jfc@mit.edu).
 
 This file is part of GCC.
@@ -21,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "tm_p.h"
@@ -36,7 +39,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "splay-tree.h"
 #include "ggc.h"
 #include "langhooks.h"
+#include "timevar.h"
 #include "target.h"
+#include "cgraph.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
@@ -61,7 +66,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
    To see whether two alias sets can point to the same memory, we must
    see if either alias set is a subset of the other. We need not trace
-   past immediate descendents, however, since we propagate all
+   past immediate descendants, however, since we propagate all
    grandchildren up one level.
 
    Alias set zero is implicitly a superset of all other alias sets.
@@ -74,7 +79,7 @@ typedef struct alias_set_entry
   HOST_WIDE_INT alias_set;
 
   /* The children of the alias set.  These are not just the immediate
-     children, but, in fact, all descendents.  So, if we have:
+     children, but, in fact, all descendants.  So, if we have:
 
        struct T { struct S s; float f; }
 
@@ -93,7 +98,6 @@ rtx get_addr                          PARAMS ((rtx));
 static int memrefs_conflict_p          PARAMS ((int, rtx, int, rtx,
                                                 HOST_WIDE_INT));
 static void record_set                 PARAMS ((rtx, rtx, void *));
-static rtx find_base_term              PARAMS ((rtx));
 static int base_alias_check            PARAMS ((rtx, rtx, enum machine_mode,
                                                 enum machine_mode));
 static rtx find_base_value             PARAMS ((rtx));
@@ -116,6 +120,7 @@ static int nonlocal_referenced_p_1      PARAMS ((rtx *, void *));
 static int nonlocal_referenced_p        PARAMS ((rtx));
 static int nonlocal_set_p_1             PARAMS ((rtx *, void *));
 static int nonlocal_set_p               PARAMS ((rtx));
+static void memory_modified_1          PARAMS ((rtx, rtx, void *));
 
 /* Set up all info needed to perform alias analysis on memory references.  */
 
@@ -199,7 +204,7 @@ char *reg_known_equiv_p;
 
 /* True when scanning insns from the start of the rtl to the
    NOTE_INSN_FUNCTION_BEG note.  */
-static int copying_arguments;
+static bool copying_arguments;
 
 /* The splay-tree used to store the various alias set entries.  */
 static splay_tree alias_sets;
@@ -332,8 +337,8 @@ objects_must_conflict_p (t1, t2)
      then they may not conflict.  */
   if ((t1 != 0 && readonly_fields_p (t1))
       || (t2 != 0 && readonly_fields_p (t2))
-      || (t1 != 0 && TYPE_READONLY (t1))
-      || (t2 != 0 && TYPE_READONLY (t2)))
+      || (t1 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t1))
+      || (t2 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t2)))
     return 0;
 
   /* If they are the same type, they must conflict.  */
@@ -781,9 +786,17 @@ find_base_value (src)
         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 >= FIRST_PSEUDO_REGISTER || fixed_regs[regno])
-         && regno < reg_base_value_size
-         && reg_base_value[regno])
-       return reg_base_value[regno];
+         && regno < reg_base_value_size)
+       {
+         /* If we're inside init_alias_analysis, use new_reg_base_value
+            to reduce the number of relaxation iterations.  */
+         if (new_reg_base_value && new_reg_base_value[regno]
+             && REG_N_SETS (regno) == 1)
+           return new_reg_base_value[regno];
+
+         if (reg_base_value[regno])
+           return reg_base_value[regno];
+       }
 
       return src;
 
@@ -923,6 +936,7 @@ record_set (dest, set, data)
 {
   unsigned regno;
   rtx src;
+  int n;
 
   if (GET_CODE (dest) != REG)
     return;
@@ -932,6 +946,22 @@ record_set (dest, set, data)
   if (regno >= reg_base_value_size)
     abort ();
 
+  /* If this spans multiple hard registers, then we must indicate that every
+     register has an unusable value.  */
+  if (regno < FIRST_PSEUDO_REGISTER)
+    n = HARD_REGNO_NREGS (regno, GET_MODE (dest));
+  else
+    n = 1;
+  if (n != 1)
+    {
+      while (--n >= 0)
+       {
+         reg_seen[regno + n] = 1;
+         new_reg_base_value[regno + n] = 0;
+       }
+      return;
+    }
+
   if (set)
     {
       /* A CLOBBER wipes out any old value but does not prevent a previously
@@ -1087,6 +1117,7 @@ canon_rtx (x)
 }
 
 /* Return 1 if X and Y are identical-looking rtx's.
+   Expect that X and Y has been already canonicalized.
 
    We use the data in reg_known_value above to see if two registers with
    different numbers are, in fact, equivalent.  */
@@ -1105,9 +1136,6 @@ rtx_equal_for_memref_p (x, y)
   if (x == 0 || y == 0)
     return 0;
 
-  x = canon_rtx (x);
-  y = canon_rtx (y);
-
   if (x == y)
     return 1;
 
@@ -1146,24 +1174,42 @@ rtx_equal_for_memref_p (x, y)
 
     case ADDRESSOF:
       return (XINT (x, 1) == XINT (y, 1)
-             && rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0)));
+             && rtx_equal_for_memref_p (XEXP (x, 0),
+                                        XEXP (y, 0)));
 
     default:
       break;
     }
 
-  /* For commutative operations, the RTX match if the operand match in any
-     order.  Also handle the simple binary and unary cases without a loop.  */
-  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+  /* canon_rtx knows how to handle plus.  No need to canonicalize.  */
+  if (code == PLUS)
     return ((rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
             && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)))
            || (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 1))
                && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 0))));
+  /* For commutative operations, the RTX match if the operand match in any
+     order.  Also handle the simple binary and unary cases without a loop.  */
+  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+    {
+      rtx xop0 = canon_rtx (XEXP (x, 0));
+      rtx yop0 = canon_rtx (XEXP (y, 0));
+      rtx yop1 = canon_rtx (XEXP (y, 1));
+
+      return ((rtx_equal_for_memref_p (xop0, yop0)
+              && rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)), yop1))
+             || (rtx_equal_for_memref_p (xop0, yop1)
+                 && rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)), yop0)));
+    }
   else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
-    return (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
-           && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)));
+    {
+      return (rtx_equal_for_memref_p (canon_rtx (XEXP (x, 0)),
+                                     canon_rtx (XEXP (y, 0)))
+             && rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)),
+                                        canon_rtx (XEXP (y, 1))));
+    }
   else if (GET_RTX_CLASS (code) == '1')
-    return rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0));
+    return rtx_equal_for_memref_p (canon_rtx (XEXP (x, 0)),
+                                  canon_rtx (XEXP (y, 0)));
 
   /* Compare the elements.  If any pair of corresponding elements
      fail to match, return 0 for the whole things.
@@ -1187,13 +1233,14 @@ rtx_equal_for_memref_p (x, y)
 
          /* And the corresponding elements must match.  */
          for (j = 0; j < XVECLEN (x, i); j++)
-           if (rtx_equal_for_memref_p (XVECEXP (x, i, j),
-                                       XVECEXP (y, i, j)) == 0)
+           if (rtx_equal_for_memref_p (canon_rtx (XVECEXP (x, i, j)),
+                                       canon_rtx (XVECEXP (y, i, j))) == 0)
              return 0;
          break;
 
        case 'e':
-         if (rtx_equal_for_memref_p (XEXP (x, i), XEXP (y, i)) == 0)
+         if (rtx_equal_for_memref_p (canon_rtx (XEXP (x, i)),
+                                     canon_rtx (XEXP (y, i))) == 0)
            return 0;
          break;
 
@@ -1251,7 +1298,7 @@ find_symbolic_term (x)
   return 0;
 }
 
-static rtx
+rtx
 find_base_term (x)
      rtx x;
 {
@@ -1518,9 +1565,11 @@ addr_side_effect_eval (addr, size, n_refs)
     }
 
   if (offset)
-    addr = gen_rtx_PLUS (GET_MODE (addr), XEXP (addr, 0), GEN_INT (offset));
+    addr = gen_rtx_PLUS (GET_MODE (addr), XEXP (addr, 0),
+                        GEN_INT (offset));
   else
     addr = XEXP (addr, 0);
+  addr = canon_rtx (addr);
 
   return addr;
 }
@@ -1530,6 +1579,7 @@ addr_side_effect_eval (addr, size, n_refs)
    C is nonzero, we are testing aliases between X and Y + C.
    XSIZE is the size in bytes of the X reference,
    similarly YSIZE is the size in bytes for Y.
+   Expect that canon_rtx has been already called for X and Y.
 
    If XSIZE or YSIZE is zero, we do not know the amount of memory being
    referenced (the reference was BLKmode), so make the most pessimistic
@@ -1557,13 +1607,13 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
   else if (GET_CODE (x) == LO_SUM)
     x = XEXP (x, 1);
   else
-    x = canon_rtx (addr_side_effect_eval (x, xsize, 0));
+    x = addr_side_effect_eval (x, xsize, 0);
   if (GET_CODE (y) == HIGH)
     y = XEXP (y, 0);
   else if (GET_CODE (y) == LO_SUM)
     y = XEXP (y, 1);
   else
-    y = canon_rtx (addr_side_effect_eval (y, ysize, 0));
+    y = addr_side_effect_eval (y, ysize, 0);
 
   if (rtx_equal_for_memref_p (x, y))
     {
@@ -1686,7 +1736,7 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
     {
       if (GET_CODE (y) == AND || ysize < -INTVAL (XEXP (x, 1)))
        xsize = -1;
-      return memrefs_conflict_p (xsize, XEXP (x, 0), ysize, y, c);
+      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)
     {
@@ -1696,7 +1746,7 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
         a following reference, so we do nothing with that for now.  */
       if (GET_CODE (x) == AND || xsize < -INTVAL (XEXP (y, 1)))
        ysize = -1;
-      return memrefs_conflict_p (xsize, x, ysize, XEXP (y, 0), c);
+      return memrefs_conflict_p (xsize, x, ysize, canon_rtx (XEXP (y, 0)), c);
     }
 
   if (GET_CODE (x) == ADDRESSOF)
@@ -1924,7 +1974,7 @@ adjust_offset_for_component_ref (x, offset)
   return GEN_INT (ioffset);
 }
 
-/* Return nonzero if we can deterimine the exprs corresponding to memrefs
+/* Return nonzero if we can determine the exprs corresponding to memrefs
    X and Y and they do not overlap.  */
 
 static int
@@ -2199,8 +2249,8 @@ canon_true_dependence (mem, mem_mode, mem_addr, x, varies)
                                              varies);
 }
 
-/* Returns non-zero if a write to X might alias a previous read from
-   (or, if WRITEP is non-zero, a write to) MEM.  */
+/* Returns nonzero if a write to X might alias a previous read from
+   (or, if WRITEP is nonzero, a write to) MEM.  */
 
 static int
 write_dependence_p (mem, x, writep)
@@ -2389,14 +2439,13 @@ nonlocal_mentioned_p_1 (loc, data)
   return 0;
 }
 
-/* Returns non-zero if X might mention something which is not
+/* Returns nonzero if X might mention something which is not
    local to the function and is not constant.  */
 
 static int
 nonlocal_mentioned_p (x)
      rtx x;
 {
-
   if (INSN_P (x))
     {
       if (GET_CODE (x) == CALL_INSN)
@@ -2487,14 +2536,13 @@ nonlocal_referenced_p_1 (loc, data)
   return 0;
 }
 
-/* Returns non-zero if X might reference something which is not
+/* Returns nonzero if X might reference something which is not
    local to the function and is not constant.  */
 
 static int
 nonlocal_referenced_p (x)
      rtx x;
 {
-
   if (INSN_P (x))
     {
       if (GET_CODE (x) == CALL_INSN)
@@ -2567,14 +2615,13 @@ nonlocal_set_p_1 (loc, data)
   return 0;
 }
 
-/* Returns non-zero if X might set something which is not
+/* Returns nonzero if X might set something which is not
    local to the function and is not constant.  */
 
 static int
 nonlocal_set_p (x)
      rtx x;
 {
-
   if (INSN_P (x))
     {
       if (GET_CODE (x) == CALL_INSN)
@@ -2592,7 +2639,7 @@ nonlocal_set_p (x)
   return for_each_rtx (&x, nonlocal_set_p_1, NULL);
 }
 
-/* Mark the function if it is constant.  */
+/* Mark the function if it is pure or constant.  */
 
 void
 mark_constant_function ()
@@ -2603,7 +2650,6 @@ mark_constant_function ()
   if (TREE_READONLY (current_function_decl)
       || DECL_IS_PURE (current_function_decl)
       || TREE_THIS_VOLATILE (current_function_decl)
-      || TYPE_MODE (TREE_TYPE (current_function_decl)) == VOIDmode
       || current_function_has_nonlocal_goto
       || !(*targetm.binds_local_p) (current_function_decl))
     return;
@@ -2638,9 +2684,15 @@ mark_constant_function ()
   if (insn)
     ;
   else if (nonlocal_memory_referenced)
-    DECL_IS_PURE (current_function_decl) = 1;
+    {
+      cgraph_rtl_info (current_function_decl)->pure_function = 1;
+      DECL_IS_PURE (current_function_decl) = 1;
+    }
   else
-    TREE_READONLY (current_function_decl) = 1;
+    {
+      cgraph_rtl_info (current_function_decl)->const_function = 1;
+      TREE_READONLY (current_function_decl) = 1;
+    }
 }
 \f
 
@@ -2675,6 +2727,35 @@ init_alias_once ()
   alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
 }
 
+/* Set MEMORY_MODIFIED when X modifies DATA (that is assumed
+   to be memory reference.  */
+static bool memory_modified;
+static void
+memory_modified_1 (x, pat, data)
+       rtx x, pat ATTRIBUTE_UNUSED;
+       void *data;
+{
+  if (GET_CODE (x) == MEM)
+    {
+      if (anti_dependence (x, (rtx)data) || output_dependence (x, (rtx)data))
+       memory_modified = true;
+    }
+}
+
+
+/* Return true when INSN possibly modify memory contents of MEM
+   (ie address can be modified).  */
+bool
+memory_modified_in_insn_p (mem, insn)
+     rtx mem, insn;
+{
+  if (!INSN_P (insn))
+    return false;
+  memory_modified = false;
+  note_stores (PATTERN (insn), memory_modified_1, mem);
+  return memory_modified;
+}
+
 /* Initialize the aliasing machinery.  Initialize the REG_KNOWN_VALUE
    array.  */
 
@@ -2687,6 +2768,8 @@ init_alias_analysis ()
   unsigned int ui;
   rtx insn;
 
+  timevar_push (TV_ALIAS_ANALYSIS);
+
   reg_known_value_size = maxreg;
 
   reg_known_value
@@ -2705,7 +2788,7 @@ init_alias_analysis ()
 
   new_reg_base_value = (rtx *) xmalloc (reg_base_value_size * sizeof (rtx));
   reg_seen = (char *) xmalloc (reg_base_value_size);
-  if (! reload_completed && flag_unroll_loops)
+  if (! reload_completed && flag_old_unroll_loops)
     {
       /* ??? Why are we realloc'ing if we're just going to zero it?  */
       alias_invariant = (rtx *)xrealloc (alias_invariant,
@@ -2744,7 +2827,7 @@ init_alias_analysis ()
 
       /* We're at the start of the function each iteration through the
         loop, so we're copying arguments.  */
-      copying_arguments = 1;
+      copying_arguments = true;
 
       /* Wipe the potential alias information clean for this pass.  */
       memset ((char *) new_reg_base_value, 0, reg_base_value_size * sizeof (rtx));
@@ -2834,7 +2917,7 @@ init_alias_analysis ()
            }
          else if (GET_CODE (insn) == NOTE
                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
-           copying_arguments = 0;
+           copying_arguments = false;
        }
 
       /* Now propagate values from new_reg_base_value to reg_base_value.  */
@@ -2892,6 +2975,7 @@ init_alias_analysis ()
   new_reg_base_value = 0;
   free (reg_seen);
   reg_seen = 0;
+  timevar_pop (TV_ALIAS_ANALYSIS);
 }
 
 void