Index: fold-const.c
===================================================================
--- fold-const.c	(revision 228011)
+++ fold-const.c	(working copy)
@@ -2667,6 +2667,83 @@
     }
 }
 
+/* True if arg0, arg1 have the same base object but addressed in different
+   ways.  */
+int
+base_object_eq_p (const_tree arg0, const_tree arg1)
+{
+  if (arg0 == NULL_TREE || arg1 == NULL_TREE)
+    return 0;
+
+  if (TREE_CODE (arg0) == MEM_REF
+      && DECL_P (arg1)
+      && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR
+      && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1)
+    return 1;
+  else if (TREE_CODE (arg1) == MEM_REF
+      && DECL_P (arg0)
+      && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR
+      && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0)
+    return 1;
+
+    return 0;
+
+}
+/* True if arg0, arg1 are the same object but addressed in different ways,
+   e.g. A == MEM[&A].  e.  */
+int
+addr_eq_p (const_tree arg0, const_tree arg1)
+{
+  if (arg0 == NULL_TREE || arg1 == NULL_TREE)
+    return 0;
+
+  if (!base_object_eq_p (arg0, arg1))
+    return 0;
+
+  const_tree mem_ref;
+  const_tree other_ref;
+  if (TREE_CODE (arg0) == MEM_REF)
+    {
+      mem_ref = arg0;
+      other_ref = arg1;
+    }
+  else if (TREE_CODE (arg1) == MEM_REF)
+    {
+      mem_ref = arg1;
+      other_ref = arg0;
+     }
+  else
+    return 0;
+
+  tree offset = TREE_OPERAND (mem_ref, 1);
+  tree other = NULL_TREE;
+  switch (TREE_CODE (other_ref))
+    {
+      case ARRAY_RANGE_REF:
+      case ARRAY_REF:
+	/* Also consider A[N] == MEM_REF[ &A + (sizeof(A)*N) ].  */
+	if (TREE_CODE (TREE_OPERAND (other_ref, 1)) == INTEGER_CST)
+	  {
+	    tree size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (other_ref)));
+	    tree index = TREE_OPERAND (other_ref, 1);
+	    other = int_const_binop (MULT_EXPR, size, index);
+	    return tree_int_cst_equal (offset, other);
+	  }
+	else
+	  return 0;
+
+      case COMPONENT_REF:
+	other  = DECL_FIELD_OFFSET (TREE_OPERAND (other_ref, 1));
+	if (!other || TREE_CODE (other) != INTEGER_CST)
+	  return 0;
+
+	return tree_int_cst_equal (other, offset); 
+
+      default:
+	return integer_zerop (TREE_OPERAND (mem_ref, 1));
+    }
+}
+
 /* Return nonzero if two operands (typically of the same tree node)
    are necessarily equal.  If either argument has side-effects this
    function returns zero.  FLAGS modifies behavior as follows:
@@ -2762,19 +2839,7 @@
 	  /* If we are interested in comparing addresses ignore
 	     MEM_REF wrappings of the base that can appear just for
 	     TBAA reasons.  */
-	  if (TREE_CODE (arg0) == MEM_REF
-	      && DECL_P (arg1)
-	      && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR
-	      && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1
-	      && integer_zerop (TREE_OPERAND (arg0, 1)))
-	    return 1;
-	  else if (TREE_CODE (arg1) == MEM_REF
-		   && DECL_P (arg0)
-		   && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR
-		   && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0
-		   && integer_zerop (TREE_OPERAND (arg1, 1)))
-	    return 1;
-	  return 0;
+	  return addr_eq_p (arg0, arg1);
 	}
       else
 	return 0;
Index: fold-const.h
===================================================================
--- fold-const.h	(revision 228011)
+++ fold-const.h	(working copy)
@@ -86,6 +86,8 @@
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
 extern int operand_equal_p (const_tree, const_tree, unsigned int);
+extern int addr_eq_p (const_tree, const_tree);
+extern int base_object_eq_p (const_tree, const_tree);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
Index: emit-rtl.c
===================================================================
--- emit-rtl.c	(revision 228011)
+++ emit-rtl.c	(working copy)
@@ -316,6 +316,39 @@
   return fixed_identical (CONST_FIXED_VALUE (a), CONST_FIXED_VALUE (b));
 }
 
+/* Return true if the given memory attributes offsets are equal.  */
+
+static bool
+offsets_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
+{
+  if (!p->offset_known_p && !q->offset_known_p)
+    return false;
+
+  /* For the case of a MEM_REF and something else, the MEM_REF may
+     have a offset inside it.  */
+
+  if (p->expr != NULL_TREE && q->expr != NULL_TREE)
+    {
+      if (TREE_CODE (p->expr) == MEM_REF)
+	{
+	  if (TREE_CODE (TREE_OPERAND (p->expr, 1)) == INTEGER_CST)
+	    return !compare_tree_int (TREE_OPERAND (p->expr, 1), q->offset);
+	  else if (TREE_OPERAND (p->expr, 1) == NULL_TREE && q->offset == 0)
+	    return true;
+	}
+      else if (TREE_CODE (q->expr) == MEM_REF)
+	  {
+	    if (TREE_CODE (TREE_OPERAND (q->expr, 1)) == INTEGER_CST)
+	      return !compare_tree_int (TREE_OPERAND (q->expr, 1), p->offset);
+	    else if (TREE_OPERAND (q->expr, 1) == NULL_TREE && q->offset == 0)
+	      return true;
+	  }
+    }
+
+  return (p->offset == q->offset);
+
+}
+
 /* Return true if the given memory attributes are equal.  */
 
 bool
@@ -326,8 +359,7 @@
   if (!p || !q)
     return false;
   return (p->alias == q->alias
-	  && p->offset_known_p == q->offset_known_p
-	  && (!p->offset_known_p || p->offset == q->offset)
+	  && offsets_eq_p (p, q)
 	  && p->size_known_p == q->size_known_p
 	  && (!p->size_known_p || p->size == q->size)
 	  && p->align == q->align
@@ -334,7 +366,8 @@
 	  && p->addrspace == q->addrspace
 	  && (p->expr == q->expr
 	      || (p->expr != NULL_TREE && q->expr != NULL_TREE
-		  && operand_equal_p (p->expr, q->expr, 0))));
+		  && (operand_equal_p (p->expr, q->expr, 0)
+		      || base_object_eq_p (p->expr, q->expr)))));
 }
 
 /* Set MEM's memory attributes so that they are the same as ATTRS.  */
