OSDN Git Service

* alias.c (memrefs_conflict_p): If x and y are the same VALUE,
[pf3gnuchains/gcc-fork.git] / gcc / alias.c
index 442be82..72f8a66 100644 (file)
@@ -1,6 +1,6 @@
 /* Alias analysis for GNU C
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
 /* Alias analysis for GNU C
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2007, 2008, 2009 Free Software Foundation, Inc.
+   2007, 2008, 2009, 2010 Free Software Foundation, Inc.
    Contributed by John Carr (jfc@mit.edu).
 
 This file is part of GCC.
    Contributed by John Carr (jfc@mit.edu).
 
 This file is part of GCC.
@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "target.h"
 #include "cgraph.h"
 #include "timevar.h"
 #include "target.h"
 #include "cgraph.h"
-#include "varray.h"
 #include "tree-pass.h"
 #include "ipa-type-escape.h"
 #include "df.h"
 #include "tree-pass.h"
 #include "ipa-type-escape.h"
 #include "df.h"
@@ -273,17 +272,17 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
   if (base == NULL_TREE)
     return false;
 
   if (base == NULL_TREE)
     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 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;
 
   /* 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 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.  */
@@ -302,33 +301,44 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
 
   ref->ref_alias_set = MEM_ALIAS_SET (mem);
 
 
   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)
+  /* If MEM_OFFSET or MEM_SIZE are NULL we have to punt.
+     Keep points-to related information though.  */
+  if (!MEM_OFFSET (mem)
+      || !MEM_SIZE (mem))
     {
     {
+      ref->ref = NULL_TREE;
       ref->offset = 0;
       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;
       ref->size = -1;
       ref->max_size = -1;
+      return true;
     }
     }
-  else
-    {
-      ref->size = INTVAL (MEM_SIZE (mem)) * BITS_PER_UNIT;
-    }
+
+  /* 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;
 }
 
   return true;
 }
@@ -402,7 +412,7 @@ alias_set_subset_of (alias_set_type set1, alias_set_type set2)
   /* Otherwise, check if set1 is a subset of set2.  */
   ase = get_alias_set_entry (set2);
   if (ase != 0
   /* Otherwise, check if set1 is a subset of set2.  */
   ase = get_alias_set_entry (set2);
   if (ase != 0
-      && ((ase->has_zero_child && set1 == 0)
+      && (ase->has_zero_child
          || splay_tree_lookup (ase->children,
                                (splay_tree_key) set1)))
     return true;
          || splay_tree_lookup (ase->children,
                                (splay_tree_key) set1)))
     return true;
@@ -448,8 +458,8 @@ walk_mems_2 (rtx *x, rtx mem)
     {
       if (alias_sets_conflict_p (MEM_ALIAS_SET(*x), MEM_ALIAS_SET(mem)))
         return 1;
     {
       if (alias_sets_conflict_p (MEM_ALIAS_SET(*x), MEM_ALIAS_SET(mem)))
         return 1;
-        
-      return -1;  
+
+      return -1;
     }
   return 0;
 }
     }
   return 0;
 }
@@ -463,7 +473,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;
       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;
     }
   return 0;
@@ -636,7 +646,7 @@ get_alias_set (tree t)
      aren't types.  */
   if (! TYPE_P (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.  */
 
       /* Remove any nops, then give the language a chance to do
         something with this tree before we look at it.  */
@@ -645,8 +655,13 @@ get_alias_set (tree t)
       if (set != -1)
        return set;
 
       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 *".  */
       /* 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);
       while (handled_component_p (inner))
        {
          inner = TREE_OPERAND (inner, 0);
@@ -680,11 +695,27 @@ get_alias_set (tree t)
     }
 
   /* Variant qualifiers don't affect the alias set, so get the main
     }
 
   /* 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);
   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);
 
   if (TYPE_ALIAS_SET_KNOWN_P (t))
     return TYPE_ALIAS_SET (t);
 
@@ -1040,6 +1071,11 @@ find_base_value (rtx src)
       return 0;
 
     case TRUNCATE:
       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.  */
       if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode))
        break;
       /* Fall through.  */
@@ -1054,6 +1090,12 @@ find_base_value (rtx src)
 
     case ZERO_EXTEND:
     case SIGN_EXTEND:  /* used for NT/Alpha pointers */
 
     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));
 
       {
        rtx temp = find_base_value (XEXP (src, 0));
 
@@ -1446,6 +1488,11 @@ find_base_term (rtx x)
       return REG_BASE_VALUE (x);
 
     case TRUNCATE:
       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.  */
       if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode))
        return 0;
       /* Fall through.  */
@@ -1460,6 +1507,12 @@ find_base_term (rtx x)
 
     case ZERO_EXTEND:
     case SIGN_EXTEND:  /* Used for Alpha/NT pointers */
 
     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));
 
       {
        rtx temp = find_base_term (XEXP (x, 0));
 
@@ -1637,14 +1690,7 @@ base_alias_check (rtx x, rtx y, enum machine_mode x_mode,
       || (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode))
     return 0;
 
       || (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode))
     return 0;
 
-  if (! flag_argument_noalias)
-    return 1;
-
-  if (flag_argument_noalias > 1)
-    return 0;
-
-  /* Weak noalias assertion (arguments are distinct, but may match globals).  */
-  return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
+  return 1;
 }
 
 /* Convert the address X into something we can use.  This is done by returning
 }
 
 /* Convert the address X into something we can use.  This is done by returning
@@ -1712,8 +1758,12 @@ addr_side_effect_eval (rtx addr, int size, int n_refs)
   return addr;
 }
 
   return addr;
 }
 
-/* Return nonzero if X and Y (memory addresses) could reference the
-   same location in memory.  C is an offset accumulator.  When
+/* Return one if X and Y (memory addresses) reference the
+   same location in memory or if the references overlap.
+   Return zero if they do not overlap, else return
+   minus one in which case they still might reference the same location.
+
+   C is an offset accumulator.  When
    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.
    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.
@@ -1728,15 +1778,49 @@ addr_side_effect_eval (rtx addr, int size, int n_refs)
    align memory references, as is done on the Alpha.
 
    Nice to notice that varying addresses cannot conflict with fp if no
    align memory references, as is done on the Alpha.
 
    Nice to notice that varying addresses cannot conflict with fp if no
-   local variables had their addresses taken, but that's too hard now.  */
+   local variables had their addresses taken, but that's too hard now.
+
+   ???  Contrary to the tree alias oracle this does not return
+   one for X + non-constant and Y + non-constant when X and Y are equal.
+   If that is fixed the TBAA hack for union type-punning can be removed.  */
 
 static int
 memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
 {
   if (GET_CODE (x) == VALUE)
 
 static int
 memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
 {
   if (GET_CODE (x) == VALUE)
-    x = get_addr (x);
+    {
+      if (REG_P (y))
+       {
+         struct elt_loc_list *l;
+         for (l = CSELIB_VAL_PTR (x)->locs; l; l = l->next)
+           if (REG_P (l->loc) && rtx_equal_for_memref_p (l->loc, y))
+             break;
+         if (l)
+           x = y;
+         else
+           x = get_addr (x);
+       }
+      /* Don't call get_addr if y is the same VALUE.  */
+      else if (x != y)
+       x = get_addr (x);
+    }
   if (GET_CODE (y) == VALUE)
   if (GET_CODE (y) == VALUE)
-    y = get_addr (y);
+    {
+      if (REG_P (x))
+       {
+         struct elt_loc_list *l;
+         for (l = CSELIB_VAL_PTR (y)->locs; l; l = l->next)
+           if (REG_P (l->loc) && rtx_equal_for_memref_p (l->loc, x))
+             break;
+         if (l)
+           y = x;
+         else
+           y = get_addr (y);
+       }
+      /* Don't call get_addr if x is the same VALUE.  */
+      else if (y != x)
+       y = get_addr (y);
+    }
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
   else if (GET_CODE (x) == LO_SUM)
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
   else if (GET_CODE (x) == LO_SUM)
@@ -1794,7 +1878,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
          else if (CONST_INT_P (y1))
            return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
 
          else if (CONST_INT_P (y1))
            return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
 
-         return 1;
+         return -1;
        }
       else if (CONST_INT_P (x1))
        return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
        }
       else if (CONST_INT_P (x1))
        return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
@@ -1809,7 +1893,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
       if (CONST_INT_P (y1))
        return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
       else
       if (CONST_INT_P (y1))
        return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
       else
-       return 1;
+       return -1;
     }
 
   if (GET_CODE (x) == GET_CODE (y))
     }
 
   if (GET_CODE (x) == GET_CODE (y))
@@ -1824,7 +1908,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
          rtx x1 = canon_rtx (XEXP (x, 1));
          rtx y1 = canon_rtx (XEXP (y, 1));
          if (! rtx_equal_for_memref_p (x1, y1))
          rtx x1 = canon_rtx (XEXP (x, 1));
          rtx y1 = canon_rtx (XEXP (y, 1));
          if (! rtx_equal_for_memref_p (x1, y1))
-           return 1;
+           return -1;
          x0 = canon_rtx (XEXP (x, 0));
          y0 = canon_rtx (XEXP (y, 0));
          if (rtx_equal_for_memref_p (x0, y0))
          x0 = canon_rtx (XEXP (x, 0));
          y0 = canon_rtx (XEXP (y, 0));
          if (rtx_equal_for_memref_p (x0, y0))
@@ -1833,7 +1917,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
 
          /* Can't properly adjust our sizes.  */
          if (!CONST_INT_P (x1))
 
          /* Can't properly adjust our sizes.  */
          if (!CONST_INT_P (x1))
-           return 1;
+           return -1;
          xsize /= INTVAL (x1);
          ysize /= INTVAL (x1);
          c /= INTVAL (x1);
          xsize /= INTVAL (x1);
          ysize /= INTVAL (x1);
          c /= INTVAL (x1);
@@ -1892,9 +1976,10 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
                || (rtx_equal_for_memref_p (x, y)
                    && ((c >= 0 && xsize > c) || (c < 0 && ysize+c > 0))));
 
                || (rtx_equal_for_memref_p (x, y)
                    && ((c >= 0 && xsize > c) || (c < 0 && ysize+c > 0))));
 
-      return 1;
+      return -1;
     }
     }
-  return 1;
+
+  return -1;
 }
 
 /* Functions to compute memory dependencies.
 }
 
 /* Functions to compute memory dependencies.
@@ -2091,6 +2176,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
   if (exprx == 0 || expry == 0)
     return 0;
 
   if (exprx == 0 || expry == 0)
     return 0;
 
+  /* For spill-slot accesses make sure we have valid offsets.  */
+  if ((exprx == get_spill_slot_decl (false)
+       && ! MEM_OFFSET (x))
+      || (expry == get_spill_slot_decl (false)
+         && ! MEM_OFFSET (y)))
+    return 0;
+
   /* If both are field references, we may be able to determine something.  */
   if (TREE_CODE (exprx) == COMPONENT_REF
       && TREE_CODE (expry) == COMPONENT_REF
   /* If both are field references, we may be able to determine something.  */
   if (TREE_CODE (exprx) == COMPONENT_REF
       && TREE_CODE (expry) == COMPONENT_REF
@@ -2119,13 +2211,6 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
        exprx = t;
       }
     }
        exprx = t;
       }
     }
-  else if (INDIRECT_REF_P (exprx))
-    {
-      exprx = TREE_OPERAND (exprx, 0);
-      if (flag_argument_noalias < 2
-         || TREE_CODE (exprx) != PARM_DECL)
-       return 0;
-    }
 
   moffsety = MEM_OFFSET (y);
   if (TREE_CODE (expry) == COMPONENT_REF)
 
   moffsety = MEM_OFFSET (y);
   if (TREE_CODE (expry) == COMPONENT_REF)
@@ -2147,17 +2232,17 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
        expry = t;
       }
     }
        expry = t;
       }
     }
-  else if (INDIRECT_REF_P (expry))
-    {
-      expry = TREE_OPERAND (expry, 0);
-      if (flag_argument_noalias < 2
-         || TREE_CODE (expry) != PARM_DECL)
-       return 0;
-    }
 
   if (! DECL_P (exprx) || ! DECL_P (expry))
     return 0;
 
 
   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);
 
   rtlx = DECL_RTL (exprx);
   rtly = DECL_RTL (expry);
 
@@ -2168,6 +2253,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
       && ! rtx_equal_p (rtlx, rtly))
     return 1;
 
       && ! 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
   /* 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
@@ -2233,6 +2325,7 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
 {
   rtx x_addr, mem_addr;
   rtx base;
 {
   rtx x_addr, mem_addr;
   rtx base;
+  int ret;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
@@ -2247,23 +2340,33 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
       || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
     return 1;
 
       || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
     return 1;
 
-  if (DIFFERENT_ALIAS_SETS_P (x, mem))
-    return 0;
-
   /* Read-only memory is by definition never modified, and therefore can't
      conflict with anything.  We don't expect to find read-only set on MEM,
      but stupid user tricks can produce them, so don't die.  */
   if (MEM_READONLY_P (x))
     return 0;
 
   /* Read-only memory is by definition never modified, and therefore can't
      conflict with anything.  We don't expect to find read-only set on MEM,
      but stupid user tricks can produce them, so don't die.  */
   if (MEM_READONLY_P (x))
     return 0;
 
-  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);
 
 
   if (mem_mode == VOIDmode)
     mem_mode = GET_MODE (mem);
 
-  x_addr = get_addr (XEXP (x, 0));
-  mem_addr = get_addr (XEXP (mem, 0));
+  x_addr = XEXP (x, 0);
+  mem_addr = XEXP (mem, 0);
+  if (!((GET_CODE (x_addr) == VALUE
+        && GET_CODE (mem_addr) != VALUE
+        && reg_mentioned_p (x_addr, mem_addr))
+       || (GET_CODE (x_addr) != VALUE
+           && GET_CODE (mem_addr) == VALUE
+           && reg_mentioned_p (mem_addr, x_addr))))
+    {
+      x_addr = get_addr (x_addr);
+      mem_addr = get_addr (mem_addr);
+    }
 
   base = find_base_term (x_addr);
   if (base && (GET_CODE (base) == LABEL_REF
 
   base = find_base_term (x_addr);
   if (base && (GET_CODE (base) == LABEL_REF
@@ -2277,8 +2380,14 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
   x_addr = canon_rtx (x_addr);
   mem_addr = canon_rtx (mem_addr);
 
   x_addr = canon_rtx (x_addr);
   mem_addr = canon_rtx (mem_addr);
 
-  if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
-                           SIZE_FOR_MODE (x), x_addr, 0))
+  if ((ret = memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
+                                SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+    return ret;
+
+  if (DIFFERENT_ALIAS_SETS_P (x, mem))
+    return 0;
+
+  if (nonoverlapping_memrefs_p (mem, x))
     return 0;
 
   if (aliases_everything_p (x))
     return 0;
 
   if (aliases_everything_p (x))
@@ -2311,6 +2420,8 @@ int
 canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
                       const_rtx x, rtx x_addr, bool (*varies) (const_rtx, bool))
 {
 canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
                       const_rtx x, rtx x_addr, bool (*varies) (const_rtx, bool))
 {
+  int ret;
+
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
@@ -2324,27 +2435,42 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
       || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
     return 1;
 
       || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
     return 1;
 
-  if (DIFFERENT_ALIAS_SETS_P (x, mem))
-    return 0;
-
   /* Read-only memory is by definition never modified, and therefore can't
      conflict with anything.  We don't expect to find read-only set on MEM,
      but stupid user tricks can produce them, so don't die.  */
   if (MEM_READONLY_P (x))
     return 0;
 
   /* Read-only memory is by definition never modified, and therefore can't
      conflict with anything.  We don't expect to find read-only set on MEM,
      but stupid user tricks can produce them, so don't die.  */
   if (MEM_READONLY_P (x))
     return 0;
 
-  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)
 
   if (! x_addr)
-    x_addr = get_addr (XEXP (x, 0));
+    {
+      x_addr = XEXP (x, 0);
+      if (!((GET_CODE (x_addr) == VALUE
+            && GET_CODE (mem_addr) != VALUE
+            && reg_mentioned_p (x_addr, mem_addr))
+           || (GET_CODE (x_addr) != VALUE
+               && GET_CODE (mem_addr) == VALUE
+               && reg_mentioned_p (mem_addr, x_addr))))
+       x_addr = get_addr (x_addr);
+    }
 
   if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
     return 0;
 
   x_addr = canon_rtx (x_addr);
 
   if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
     return 0;
 
   x_addr = canon_rtx (x_addr);
-  if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
-                           SIZE_FOR_MODE (x), x_addr, 0))
+  if ((ret = memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
+                                SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+    return ret;
+
+  if (DIFFERENT_ALIAS_SETS_P (x, mem))
+    return 0;
+
+  if (nonoverlapping_memrefs_p (x, mem))
     return 0;
 
   if (aliases_everything_p (x))
     return 0;
 
   if (aliases_everything_p (x))
@@ -2375,6 +2501,7 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
   rtx x_addr, mem_addr;
   const_rtx fixed_scalar;
   rtx base;
   rtx x_addr, mem_addr;
   const_rtx fixed_scalar;
   rtx base;
+  int ret;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
 
   if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
     return 1;
@@ -2393,11 +2520,24 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
   if (!writep && MEM_READONLY_P (mem))
     return 0;
 
   if (!writep && MEM_READONLY_P (mem))
     return 0;
 
-  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));
+  x_addr = XEXP (x, 0);
+  mem_addr = XEXP (mem, 0);
+  if (!((GET_CODE (x_addr) == VALUE
+        && GET_CODE (mem_addr) != VALUE
+        && reg_mentioned_p (x_addr, mem_addr))
+       || (GET_CODE (x_addr) != VALUE
+           && GET_CODE (mem_addr) == VALUE
+           && reg_mentioned_p (mem_addr, x_addr))))
+    {
+      x_addr = get_addr (x_addr);
+      mem_addr = get_addr (mem_addr);
+    }
 
   if (! writep)
     {
 
   if (! writep)
     {
@@ -2415,8 +2555,11 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
   x_addr = canon_rtx (x_addr);
   mem_addr = canon_rtx (mem_addr);
 
   x_addr = canon_rtx (x_addr);
   mem_addr = canon_rtx (mem_addr);
 
-  if (!memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
-                          SIZE_FOR_MODE (x), x_addr, 0))
+  if ((ret = memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
+                                SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+    return ret;
+
+  if (nonoverlapping_memrefs_p (x, mem))
     return 0;
 
   fixed_scalar
     return 0;
 
   fixed_scalar