diff mbox

mem-ref2 merge, core patch

Message ID alpine.LNX.2.00.1006251342390.1429@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener June 25, 2010, 11:47 a.m. UTC
This is the core changes on the mem-ref2 branch (I left out testsuite
changes and changes in optimization passes).  I did notice some
oddities in tree-cfg.c when writing the changelog and am working on
a fixup for that.  I also noticed the expand_debug_expr change to
re-fold MEM_REFs there - it seems we propagate into debug stmts
via substitute_and_fold but the resulting trees are never folded.
Either we should make sure to fold them or we should avoid
propagating non-literal constants into debug stmts.

Well - here it is for your consumption.

Main things to consider when reviewing the patch is that no
INDIRECT_REF trees should be present in valid gimple code.
Also there is a new kind of invariant addresses, &MEM[&X + CST]
which basically is another representation of a POINTER_PLUS_EXPR
of an invariant address and a constant.

Richard.

	* doc/gimple.texi (is_gimple_mem_ref_addr): Document.
	* tree-pretty-print.c (dump_generic_node): Handle MEM_REF.
	(print_call_name): Likewise.
	* tree.c (recompute_tree_invariant_for_addr_expr): Handle MEM_REF.
	(build_simple_mem_ref_loc): New function.
	(mem_ref_offset): Likewise.
	* tree.h (build_simple_mem_ref_loc): Declare.
	(build_simple_mem_ref): Define.
	(mem_ref_offset): Declare.
	* fold-const.c: Include tree-flow.h.
	(operand_equal_p): Handle MEM_REF.
	(build_fold_addr_expr_with_type_loc): Likewise.
	(fold_comparison): Likewise.
	(fold_unary_loc): Fold
	VIEW_CONVERT_EXPR <T1, MEM_REF <T2, ...>> to MEM_REF <T1, ...>.
	(fold_binary_loc): Fold MEM[&MEM[p, CST1], CST2] to MEM[p, CST1 + CST2],
	fold MEM[&a.b, CST2] to MEM[&a, offsetof (a, b) + CST2].
	* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle MEM_REF.
	(ptr_deref_may_alias_ref_p_1): Likewise.
	(ao_ref_base_alias_set): Properly differentiate base object for
	offset and TBAA.
	(ao_ref_init_from_ptr_and_size): Use MEM_REF.
	(indirect_ref_may_alias_decl_p): Handle MEM_REFs properly.
	(indirect_refs_may_alias_p): Likewise.
	(refs_may_alias_p_1): Likewise.  Remove pointer SSA name def
	chasing code.
	(ref_maybe_used_by_call_p_1): Handle MEM_REF.
	(call_may_clobber_ref_p_1): Likewise.
	* dwarf2out.c (loc_list_from_tree): Handle MEM_REF.
	* expr.c (expand_assignment): Handle MEM_REF.
	(store_expr): Handle MEM_REFs from STRING_CSTs.
	(store_field): If expanding a MEM_REF of a non-addressable
	decl use bitfield operations.
	(get_inner_reference): Handle MEM_REF.
	(expand_expr_addr_expr_1): Likewise.
	(expand_expr_real_1): Likewise.
	* tree-eh.c (tree_could_trap_p): Handle MEM_REF.
	* alias.c (ao_ref_from_mem): Handle MEM_REF.
	(get_alias_set): Likewise.  Properly handle VIEW_CONVERT_EXPRs.
	* tree-data-ref.c (dr_analyze_innermost): Handle MEM_REF.
	(dr_analyze_indices): Likewise.
	(dr_analyze_alias): Likewise.
	(object_address_invariant_in_loop_p): Likewise.
	* gimplify.c (mark_addressable): Handle MEM_REF.
	(gimplify_cond_expr): Build MEM_REFs.
	(gimplify_modify_expr_to_memcpy): Likewise.
	(gimplify_init_ctor_preeval_1): Handle MEM_REF.
	(gimple_fold_indirect_ref): Adjust.
	(gimplify_expr): Handle MEM_REF.  Gimplify INDIRECT_REF to MEM_REF.
	* tree.def (MEM_REF): New tree code.
	* tree-dfa.c: Include toplev.h.
	(get_ref_base_and_extent): Handle MEM_REF.
	(get_addr_base_and_unit_offset): New function.
	* emit-rtl.c (set_mem_attributes_minus_bitpos): Handle MEM_REF.
	* gimple-fold.c (may_propagate_address_into_dereference): Handle
	MEM_REF.
	(maybe_fold_offset_to_array_ref): Allow possibly out-of bounds
	accesses if the array has just one dimension.  Remove always true
	parameter.  Do not require type compatibility here.
	(maybe_fold_offset_to_component_ref): Remove.
	(maybe_fold_stmt_indirect): Remove.
	(maybe_fold_reference): Remove INDIRECT_REF handling.
	Fold back to non-MEM_REF.
	(maybe_fold_offset_to_address): Simplify.  Deal with type
	mismatches here.
	(maybe_fold_reference): Likewise.
	(maybe_fold_stmt_addition): Likewise.  Also handle
	&ARRAY + I in addition to &ARRAY[0] + I.
	(fold_gimple_assign): Handle ADDR_EXPR of MEM_REFs.
	(gimple_get_relevant_ref_binfo): Handle MEM_REF.
	* cfgexpand.c (expand_debug_expr): Handle MEM_REF.
	Fold MEM_REFs in debug expressions to avoid handing non-canonicalized
	MEM_EXPRs to the alias-oracle from the scheduler.
	* tree-ssa.c (useless_type_conversion_p): Make most pointer
	conversions useless.
	(warn_uninitialized_var): Handle MEM_REF.
	(maybe_rewrite_mem_ref_base): New function.
	(execute_update_addresses_taken): Implement re-writing of MEM_REFs
	to SSA form.
	* tree-inline.c (remap_gimple_op_r): Handle MEM_REF, remove
	INDIRECT_REF handling.
	(copy_tree_body_r): Handle MEM_REF.
	* gimple.c (is_gimple_addressable): Adjust.
	(is_gimple_address): Likewise.
	(is_gimple_invariant_address): ADDR_EXPRs of MEM_REFs with
	invariant base are invariant.
	(is_gimple_min_lval): Adjust.
	(is_gimple_mem_ref_addr): New function.
	(get_base_address): Handle MEM_REF.
	(count_ptr_derefs): Likewise.
	(get_base_loadstore): Likewise.
	* gimple.h (is_gimple_mem_ref_addr): Declare.
	(gimple_call_fndecl): Handle invariant MEM_REF addresses.
	* tree-cfg.c (verify_expr): Verify MEM_REFs.  Disable
	TREE_ADDRESSABLE verification.
	(verify_types_in_gimple_min_lval): Handle MEM_REF.  Disallow
	INDIRECT_REF.  Allow conversions in MEM_REF.
	(verify_types_in_gimple_reference): Verify VIEW_CONVERT_EXPR of
	a register does not change its size.
	(verify_types_in_gimple_reference): Verify MEM_REF.
	(verify_gimple_assign_single): Disallow INDIRECT_REF.
	Handle MEM_REF.
	* tree-ssa-operands.c (opf_non_addressable, opf_not_non_addressable):
	New.
	(mark_address_taken): Handle MEM_REF.
	(get_indirect_ref_operands): Pass through opf_not_non_addressable.
	(get_asm_expr_operands): Pass opf_not_non_addressable.
	(get_expr_operands): Handle opf_[not_]non_addressable.
	Handle MEM_REF.  Remove INDIRECT_REF handling.

Comments

Paolo Bonzini June 28, 2010, 10:19 a.m. UTC | #1
On 06/25/2010 01:47 PM, Richard Guenther wrote:
> +	if (integer_zerop (TREE_OPERAND (node, 1))
> +	    /* Same pointer types, but ignoring POINTER_TYPE vs.
> +	       REFERENCE_TYPE.  */
> +	&&  (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 0)))
> +		== TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1))))
> +	&&  (TYPE_MODE (TREE_TYPE (TREE_OPERAND (node, 0)))
> +		== TYPE_MODE (TREE_TYPE (TREE_OPERAND (node, 1))))
> +	&&  (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (node, 0)))
> +		== TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (node, 1))))
> +	&&  (TYPE_QUALS (TREE_TYPE (TREE_OPERAND (node, 0)))
> +		== TYPE_QUALS (TREE_TYPE (TREE_OPERAND (node, 1))))
> +	    /* Same value types ignoring qualifiers.  */
> +	&&  (TYPE_MAIN_VARIANT (TREE_TYPE (node))
> +		== TYPE_MAIN_VARIANT
> +		    (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1))))))
> +	  {
> +	    if (TREE_CODE (TREE_OPERAND (node, 0)) != ADDR_EXPR)
> +	      {
> +		pp_string (buffer, "*");
> +		dump_generic_node (buffer, TREE_OPERAND (node, 0),
> +				   spc, flags, false);
> +	      }

Maybe avoid the magic when detailed dumping is active?

What exactly are the rules for having an INDIRECT_REF or a chain of 
handled_component_p instead of a MEM_REF?

Would it make sense to change the other INDIRECT_REF_P types into flags 
on MEM_REF?

Can you expand on the (several) "#if 0/FIXME" comments?

Thanks,

Paolo
diff mbox

Patch

Index: gcc/doc/gimple.texi
===================================================================
--- gcc/doc/gimple.texi	(.../trunk)	(revision 161367)
+++ gcc/doc/gimple.texi	(.../branches/mem-ref2)	(revision 161369)
@@ -452,8 +452,8 @@  becomes
 
 The same rule holds for arguments to a @code{GIMPLE_CALL}.
 
-The target of an assignment is usually a variable, but can also be an
-@code{INDIRECT_REF} or a compound lvalue as described below.
+The target of an assignment is usually a variable, but can also be a
+@code{MEM_REF} or a compound lvalue as described below.
 
 @menu
 * Compound Expressions::
@@ -664,6 +664,11 @@  Return true if t is a valid expression t
 called by a @code{GIMPLE_CALL}.
 @end deftypefn
 
+@deftypefn {GIMPLE function} is_gimple_mem_ref_addr (tree t)
+Return true if t is a valid expression to use as first operand
+of a @code{MEM_REF} expression.
+@end deftypefn
+
 @deftypefn {GIMPLE function} is_gimple_constant (tree t)
 Return true if t is a valid gimple constant.
 @end deftypefn
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(.../trunk)	(revision 161367)
+++ gcc/tree-pretty-print.c	(.../branches/mem-ref2)	(revision 161369)
@@ -794,6 +794,55 @@  dump_generic_node (pretty_printer *buffe
       NIY;
       break;
 
+    case MEM_REF:
+      {
+	if (integer_zerop (TREE_OPERAND (node, 1))
+	    /* Same pointer types, but ignoring POINTER_TYPE vs.
+	       REFERENCE_TYPE.  */
+	    && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 0)))
+		== TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1))))
+	    && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (node, 0)))
+		== TYPE_MODE (TREE_TYPE (TREE_OPERAND (node, 1))))
+	    && (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (node, 0)))
+		== TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (node, 1))))
+	    && (TYPE_QUALS (TREE_TYPE (TREE_OPERAND (node, 0)))
+		== TYPE_QUALS (TREE_TYPE (TREE_OPERAND (node, 1))))
+	    /* Same value types ignoring qualifiers.  */
+	    && (TYPE_MAIN_VARIANT (TREE_TYPE (node))
+		== TYPE_MAIN_VARIANT
+		    (TREE_TYPE (TREE_TYPE (TREE_OPERAND (node, 1))))))
+	  {
+	    if (TREE_CODE (TREE_OPERAND (node, 0)) != ADDR_EXPR)
+	      {
+		pp_string (buffer, "*");
+		dump_generic_node (buffer, TREE_OPERAND (node, 0),
+				   spc, flags, false);
+	      }
+	    else
+	      dump_generic_node (buffer,
+				 TREE_OPERAND (TREE_OPERAND (node, 0), 0),
+				 spc, flags, false);
+	  }
+	else
+	  {
+	    pp_string (buffer, "MEM[");
+	    pp_string (buffer, "(");
+	    dump_generic_node (buffer, TREE_TYPE (TREE_OPERAND (node, 1)),
+			       spc, flags, false);
+	    pp_string (buffer, ")");
+	    dump_generic_node (buffer, TREE_OPERAND (node, 0),
+			       spc, flags, false);
+	    if (!integer_zerop (TREE_OPERAND (node, 1)))
+	      {
+		pp_string (buffer, " + ");
+		dump_generic_node (buffer, TREE_OPERAND (node, 1),
+				   spc, flags, false);
+	      }
+	    pp_string (buffer, "]");
+	  }
+	break;
+      }
+
     case TARGET_MEM_REF:
       {
 	const char *sep = "";
@@ -1100,7 +1149,25 @@  dump_generic_node (pretty_printer *buffe
     case COMPONENT_REF:
       op0 = TREE_OPERAND (node, 0);
       str = ".";
-      if (op0 && TREE_CODE (op0) == INDIRECT_REF)
+      if (op0
+	  && (TREE_CODE (op0) == INDIRECT_REF
+	      || (TREE_CODE (op0) == MEM_REF
+		  && TREE_CODE (TREE_OPERAND (op0, 0)) != ADDR_EXPR
+		  && integer_zerop (TREE_OPERAND (op0, 1))
+		  /* Same pointer types, but ignoring POINTER_TYPE vs.
+		     REFERENCE_TYPE.  */
+		  && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))
+		      == TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1))))
+		  && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 0)))
+		      == TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 1))))
+		  && (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (op0, 0)))
+		      == TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (op0, 1))))
+		  && (TYPE_QUALS (TREE_TYPE (TREE_OPERAND (op0, 0)))
+		      == TYPE_QUALS (TREE_TYPE (TREE_OPERAND (op0, 1))))
+		  /* Same value types ignoring qualifiers.  */
+		  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
+		      == TYPE_MAIN_VARIANT
+		          (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1))))))))
 	{
 	  op0 = TREE_OPERAND (op0, 0);
 	  str = "->";
@@ -2760,6 +2827,13 @@  print_call_name (pretty_printer *buffer,
 	dump_generic_node (buffer, op0, 0, flags, false);
       break;
 
+    case MEM_REF:
+      if (integer_zerop (TREE_OPERAND (op0, 1)))
+	{
+	  op0 = TREE_OPERAND (op0, 0);
+	  goto again;
+	}
+      /* Fallthru.  */
     case COMPONENT_REF:
     case SSA_NAME:
     case OBJ_TYPE_REF:

Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(.../trunk)	(revision 161367)
+++ gcc/tree.c	(.../branches/mem-ref2)	(revision 161369)
@@ -3518,7 +3518,8 @@  do { tree _node = (NODE); \
      address is constant too.  If it's a decl, its address is constant if the
      decl is static.  Everything else is not constant and, furthermore,
      taking the address of a volatile variable is not volatile.  */
-  if (TREE_CODE (node) == INDIRECT_REF)
+  if (TREE_CODE (node) == INDIRECT_REF
+      || TREE_CODE (node) == MEM_REF)
     UPDATE_FLAGS (TREE_OPERAND (node, 0));
   else if (CONSTANT_CLASS_P (node))
     ;
@@ -3832,6 +3833,42 @@  build6_stat (enum tree_code code, tree t
   return t;
 }
 
+/* Build a simple MEM_REF tree with the sematics of a plain INDIRECT_REF
+   on the pointer PTR.  */
+
+tree
+build_simple_mem_ref_loc (location_t loc, tree ptr)
+{
+  HOST_WIDE_INT offset = 0;
+  tree ptype = TREE_TYPE (ptr);
+  tree tem;
+  /* For convenience allow addresses that collapse to a simple base
+     and offset.  */
+  if (TREE_CODE (ptr) == ADDR_EXPR
+      && (handled_component_p (TREE_OPERAND (ptr, 0))
+	  || TREE_CODE (TREE_OPERAND (ptr, 0)) == MEM_REF))
+    {
+      ptr = get_addr_base_and_unit_offset (TREE_OPERAND (ptr, 0), &offset);
+      gcc_assert (ptr);
+      ptr = build_fold_addr_expr (ptr);
+      gcc_assert (is_gimple_reg (ptr) || is_gimple_min_invariant (ptr));
+    }
+  tem = build2 (MEM_REF, TREE_TYPE (ptype),
+		ptr, build_int_cst (ptype, offset));
+  SET_EXPR_LOCATION (tem, loc);
+  return tem;
+}
+
+/* Return the constant offset of a MEM_REF tree T.  */
+
+double_int
+mem_ref_offset (const_tree t)
+{
+  tree toff = TREE_OPERAND (t, 1);
+  return double_int_sext (tree_to_double_int (toff),
+			  TYPE_PRECISION (TREE_TYPE (toff)));
+}
+
 /* Similar except don't specify the TREE_TYPE
    and leave the TREE_SIDE_EFFECTS as 0.
    It is permissible for arguments to be null,
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../trunk)	(revision 161367)
+++ gcc/tree.h	(.../branches/mem-ref2)	(revision 161369)
@@ -4965,6 +4965,10 @@  extern tree build_fold_indirect_ref_loc
 #define fold_indirect_ref(T)\
         fold_indirect_ref_loc (UNKNOWN_LOCATION, T)
 extern tree fold_indirect_ref_loc (location_t, tree);
+extern tree build_simple_mem_ref_loc (location_t, tree);
+#define build_simple_mem_ref(T)\
+	build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
+extern double_int mem_ref_offset (const_tree);
 extern tree constant_boolean_node (int, tree);
 extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
 
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(.../trunk)	(revision 161367)
+++ gcc/fold-const.c	(.../branches/mem-ref2)	(revision 161369)
@@ -65,6 +65,7 @@  along with GCC; see the file COPYING3.
 #include "langhooks.h"
 #include "md5.h"
 #include "gimple.h"
+#include "tree-flow.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
@@ -2598,6 +2599,17 @@  operand_equal_p (const_tree arg0, const_
 	case IMAGPART_EXPR:
 	  return OP_SAME (0);
 
+	case MEM_REF:
+	  /* Require equal access sizes.  We can have incomplete types
+	     for array references of variable-sized arrays from the
+	     Fortran frontent though.  */
+	  return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
+		   || (TYPE_SIZE (TREE_TYPE (arg0))
+		       && TYPE_SIZE (TREE_TYPE (arg1))
+		       && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
+					   TYPE_SIZE (TREE_TYPE (arg1)), flags)))
+		  && OP_SAME (0) && OP_SAME (1));
+
 	case ARRAY_REF:
 	case ARRAY_RANGE_REF:
 	  /* Operands 2 and 3 may be null.
@@ -7607,6 +7619,9 @@  build_fold_addr_expr_with_type_loc (loca
 	  SET_EXPR_LOCATION (t, loc);
 	}
     }
+  else if (TREE_CODE (t) == MEM_REF
+      && integer_zerop (TREE_OPERAND (t, 1)))
+    return TREE_OPERAND (t, 0);
   else if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
     {
       t = build_fold_addr_expr_loc (loc, TREE_OPERAND (t, 0));
@@ -8026,6 +8041,9 @@  fold_unary_loc (location_t loc, enum tre
       if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
 	return fold_build1_loc (loc, VIEW_CONVERT_EXPR,
 			    type, TREE_OPERAND (op0, 0));
+      if (TREE_CODE (op0) == MEM_REF)
+	return fold_build2_loc (loc, MEM_REF, type,
+				TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1));
 
       /* For integral conversions with the same precision or pointer
 	 conversions use a NOP_EXPR instead.  */
@@ -8677,6 +8695,11 @@  fold_comparison (location_t loc, enum tr
       else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
 	{
 	  base0 = TREE_OPERAND (arg0, 0);
+	  if (TREE_CODE (base0) == ADDR_EXPR)
+	    {
+	      base0 = TREE_OPERAND (base0, 0);
+	      indirect_base0 = true;
+	    }
 	  offset0 = TREE_OPERAND (arg0, 1);
 	}
 
@@ -8694,6 +8717,11 @@  fold_comparison (location_t loc, enum tr
       else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
 	{
 	  base1 = TREE_OPERAND (arg1, 0);
+	  if (TREE_CODE (base1) == ADDR_EXPR)
+	    {
+	      base1 = TREE_OPERAND (base1, 0);
+	      indirect_base1 = true;
+	    }
 	  offset1 = TREE_OPERAND (arg1, 1);
 	}
 
@@ -9536,6 +9564,36 @@  fold_binary_loc (location_t loc,
 
   switch (code)
     {
+    case MEM_REF:
+      /* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2].  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (arg0, 0)) == MEM_REF)
+	{
+	  tree iref = TREE_OPERAND (arg0, 0);
+	  return fold_build2 (MEM_REF, type,
+			      TREE_OPERAND (iref, 0),
+			      int_const_binop (PLUS_EXPR, arg1,
+					       TREE_OPERAND (iref, 1), 0));
+	}
+
+      /* MEM[&a.b, CST2] -> MEM[&a, offsetof (a, b) + CST2].  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+	  && handled_component_p (TREE_OPERAND (arg0, 0)))
+	{
+	  tree base;
+	  HOST_WIDE_INT coffset;
+	  base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0),
+						&coffset);
+	  if (!base)
+	    return NULL_TREE;
+	  return fold_build2 (MEM_REF, type,
+			      build_fold_addr_expr (base),
+			      int_const_binop (PLUS_EXPR, arg1,
+					       size_int (coffset), 0));
+	}
+
+      return NULL_TREE;
+
     case POINTER_PLUS_EXPR:
       /* 0 +p index -> (type)index */
       if (integer_zerop (arg0))
Index: gcc/tree-ssa-alias.c
===================================================================
--- gcc/tree-ssa-alias.c	(.../trunk)	(revision 161367)
+++ gcc/tree-ssa-alias.c	(.../branches/mem-ref2)	(revision 161369)
@@ -182,7 +182,8 @@  ptr_deref_may_alias_decl_p (tree ptr, tr
     {
       tree base = get_base_address (TREE_OPERAND (ptr, 0));
       if (base
-	  && INDIRECT_REF_P (base))
+	  && (INDIRECT_REF_P (base)
+	      || TREE_CODE (base) == MEM_REF))
 	ptr = TREE_OPERAND (base, 0);
       else if (base
 	       && SSA_VAR_P (base))
@@ -238,7 +239,8 @@  ptr_derefs_may_alias_p (tree ptr1, tree
     {
       tree base = get_base_address (TREE_OPERAND (ptr1, 0));
       if (base
-	  && INDIRECT_REF_P (base))
+	  && (INDIRECT_REF_P (base)
+	      || TREE_CODE (base) == MEM_REF))
 	ptr1 = TREE_OPERAND (base, 0);
       else if (base
 	       && SSA_VAR_P (base))
@@ -250,7 +252,8 @@  ptr_derefs_may_alias_p (tree ptr1, tree
     {
       tree base = get_base_address (TREE_OPERAND (ptr2, 0));
       if (base
-	  && INDIRECT_REF_P (base))
+	  && (INDIRECT_REF_P (base)
+	      || TREE_CODE (base) == MEM_REF))
 	ptr2 = TREE_OPERAND (base, 0);
       else if (base
 	       && SSA_VAR_P (base))
@@ -299,7 +302,8 @@  ptr_deref_may_alias_ref_p_1 (tree ptr, a
 {
   tree base = ao_ref_base (ref);
 
-  if (INDIRECT_REF_P (base))
+  if (INDIRECT_REF_P (base)
+      || TREE_CODE (base) == MEM_REF)
     return ptr_derefs_may_alias_p (ptr, TREE_OPERAND (base, 0));
   else if (SSA_VAR_P (base))
     return ptr_deref_may_alias_decl_p (ptr, base);
@@ -470,12 +474,18 @@  ao_ref_base (ao_ref *ref)
 
 /* Returns the base object alias set of the memory reference *REF.  */
 
-static alias_set_type ATTRIBUTE_UNUSED
+static alias_set_type
 ao_ref_base_alias_set (ao_ref *ref)
 {
+  tree base_ref;
   if (ref->base_alias_set != -1)
     return ref->base_alias_set;
-  ref->base_alias_set = get_alias_set (ao_ref_base (ref));
+  if (!ref->ref)
+    return 0;
+  base_ref = ref->ref;
+  while (handled_component_p (base_ref))
+    base_ref = TREE_OPERAND (base_ref, 0);
+  ref->base_alias_set = get_alias_set (base_ref);
   return ref->base_alias_set;
 }
 
@@ -505,7 +515,8 @@  ao_ref_init_from_ptr_and_size (ao_ref *r
 					 &ref->offset, &t1, &t2);
   else
     {
-      ref->base = build1 (INDIRECT_REF, char_type_node, ptr);
+      ref->base = build2 (MEM_REF, char_type_node,
+			  ptr, build_int_cst (ptr_type_node, 0));
       ref->offset = 0;
     }
   if (size
@@ -665,33 +676,45 @@  decl_refs_may_alias_p (tree base1,
    if non-NULL are the complete memory reference trees.  */
 
 static bool
-indirect_ref_may_alias_decl_p (tree ref1, tree ptr1,
-			       HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+indirect_ref_may_alias_decl_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
+			       HOST_WIDE_INT offset1,
+			       HOST_WIDE_INT max_size1 ATTRIBUTE_UNUSED,
 			       alias_set_type ref1_alias_set,
 			       alias_set_type base1_alias_set,
-			       tree ref2, tree base2,
+			       tree ref2 ATTRIBUTE_UNUSED, tree base2,
 			       HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
 			       alias_set_type ref2_alias_set,
-			       alias_set_type base2_alias_set)
+			       alias_set_type base2_alias_set, bool tbaa_p)
 {
+  tree ptr1 = TREE_OPERAND (base1, 0);
+  tree ptrtype1;
+  HOST_WIDE_INT offset1p = offset1;
+
+  if (TREE_CODE (base1) == MEM_REF)
+    offset1p = offset1 + mem_ref_offset (base1).low * BITS_PER_UNIT;
+
   /* If only one reference is based on a variable, they cannot alias if
      the pointer access is beyond the extent of the variable access.
      (the pointer base cannot validly point to an offset less than zero
      of the variable).
      They also cannot alias if the pointer may not point to the decl.  */
-  if (max_size2 != -1
-      && !ranges_overlap_p (offset1, max_size1, 0, offset2 + max_size2))
+  if (!ranges_overlap_p (MAX (0, offset1p), -1, offset2, max_size2))
     return false;
   if (!ptr_deref_may_alias_decl_p (ptr1, base2))
     return false;
 
   /* Disambiguations that rely on strict aliasing rules follow.  */
-  if (!flag_strict_aliasing)
+  if (!flag_strict_aliasing || !tbaa_p)
     return true;
 
+  if (TREE_CODE (base1) == MEM_REF)
+    ptrtype1 = TREE_TYPE (TREE_OPERAND (base1, 1));
+  else
+    ptrtype1 = TREE_TYPE (ptr1);
+
   /* If the alias set for a pointer access is zero all bets are off.  */
   if (base1_alias_set == -1)
-    base1_alias_set = get_deref_alias_set (ptr1);
+    base1_alias_set = get_deref_alias_set (ptrtype1);
   if (base1_alias_set == 0)
     return true;
   if (base2_alias_set == -1)
@@ -699,22 +722,52 @@  indirect_ref_may_alias_decl_p (tree ref1
 
   /* If both references are through the same type, they do not alias
      if the accesses do not overlap.  This does extra disambiguation
-     for mixed/pointer accesses but requires strict aliasing.  */
-  if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
-			  TREE_TYPE (base2)) == 1)
+     for mixed/pointer accesses but requires strict aliasing.
+     For MEM_REFs we require that the component-ref offset we computed
+     is relative to the start of the type which we ensure by
+     comparing rvalue and access type and disregarding the constant
+     pointer offset.  */
+  if ((TREE_CODE (base1) != MEM_REF
+       || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1)
+      && same_type_for_tbaa (TREE_TYPE (ptrtype1), TREE_TYPE (base2)) == 1)
     return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
 
-  /* The only way to access a variable is through a pointer dereference
-     of the same alias set or a subset of it.  */
+  /* When we are trying to disambiguate an access with a pointer dereference
+     as base versus one with a decl as base we can use both the size
+     of the decl and its dynamic type for extra disambiguation.
+     ???  We do not know anything about the dynamic type of the decl
+     other than that its alias-set contains base2_alias_set as a subset
+     which does not help us here.  */
+  /* As we know nothing useful about the dynamic type of the decl just
+     use the usual conflict check rather than a subset test.
+     ???  We could introduce -fvery-strict-aliasing when the language
+     does not allow decls to have a dynamic type that differs from their
+     static type.  Then we can check 
+     !alias_set_subset_of (base1_alias_set, base2_alias_set) instead.  */
   if (base1_alias_set != base2_alias_set
-      && !alias_set_subset_of (base1_alias_set, base2_alias_set))
+      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
+    return false;
+  /* If the size of the access relevant for TBAA through the pointer
+     is bigger than the size of the decl we can't possibly access the
+     decl via that pointer.  */
+  if (DECL_SIZE (base2) && COMPLETE_TYPE_P (TREE_TYPE (ptrtype1))
+      && TREE_CODE (DECL_SIZE (base2)) == INTEGER_CST
+      && TREE_CODE (TYPE_SIZE (TREE_TYPE (ptrtype1))) == INTEGER_CST
+      /* ???  This in turn may run afoul when a decl of type T which is
+	 a member of union type U is accessed through a pointer to
+	 type U and sizeof T is smaller than sizeof U.  */
+      && TREE_CODE (TREE_TYPE (ptrtype1)) != UNION_TYPE
+      && TREE_CODE (TREE_TYPE (ptrtype1)) != QUAL_UNION_TYPE
+      && tree_int_cst_lt (DECL_SIZE (base2), TYPE_SIZE (TREE_TYPE (ptrtype1))))
     return false;
 
   /* Do access-path based disambiguation.  */
   if (ref1 && ref2
       && handled_component_p (ref1)
-      && handled_component_p (ref2))
-    return aliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+      && handled_component_p (ref2)
+      && (TREE_CODE (base1) != MEM_REF
+	  || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1))
+    return aliasing_component_refs_p (ref1, TREE_TYPE (ptrtype1),
 				      ref1_alias_set, base1_alias_set,
 				      offset1, max_size1,
 				      ref2, TREE_TYPE (base2),
@@ -732,42 +785,65 @@  indirect_ref_may_alias_decl_p (tree ref1
    if non-NULL are the complete memory reference trees. */
 
 static bool
-indirect_refs_may_alias_p (tree ref1, tree ptr1,
+indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
 			   HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
 			   alias_set_type ref1_alias_set,
 			   alias_set_type base1_alias_set,
-			   tree ref2, tree ptr2,
+			   tree ref2 ATTRIBUTE_UNUSED, tree base2,
 			   HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
 			   alias_set_type ref2_alias_set,
-			   alias_set_type base2_alias_set)
+			   alias_set_type base2_alias_set, bool tbaa_p)
 {
+  tree ptr1 = TREE_OPERAND (base1, 0);
+  tree ptr2 = TREE_OPERAND (base2, 0);
+  tree ptrtype1, ptrtype2;
+
   /* If both bases are based on pointers they cannot alias if they may not
      point to the same memory object or if they point to the same object
      and the accesses do not overlap.  */
   if (operand_equal_p (ptr1, ptr2, 0))
-    return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+    {
+      if (TREE_CODE (base1) == MEM_REF)
+	offset1 += mem_ref_offset (base1).low * BITS_PER_UNIT;
+      if (TREE_CODE (base2) == MEM_REF)
+	offset2 += mem_ref_offset (base2).low * BITS_PER_UNIT;
+      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+    }
   if (!ptr_derefs_may_alias_p (ptr1, ptr2))
     return false;
 
   /* Disambiguations that rely on strict aliasing rules follow.  */
-  if (!flag_strict_aliasing)
+  if (!flag_strict_aliasing || !tbaa_p)
     return true;
 
+  if (TREE_CODE (base1) == MEM_REF)
+    ptrtype1 = TREE_TYPE (TREE_OPERAND (base1, 1));
+  else
+    ptrtype1 = TREE_TYPE (ptr1);
+  if (TREE_CODE (base2) == MEM_REF)
+    ptrtype2 = TREE_TYPE (TREE_OPERAND (base2, 1));
+  else
+    ptrtype2 = TREE_TYPE (ptr2);
+
   /* If the alias set for a pointer access is zero all bets are off.  */
   if (base1_alias_set == -1)
-    base1_alias_set = get_deref_alias_set (ptr1);
+    base1_alias_set = get_deref_alias_set (ptrtype1);
   if (base1_alias_set == 0)
     return true;
   if (base2_alias_set == -1)
-    base2_alias_set = get_deref_alias_set (ptr2);
+    base2_alias_set = get_deref_alias_set (ptrtype2);
   if (base2_alias_set == 0)
     return true;
 
   /* If both references are through the same type, they do not alias
      if the accesses do not overlap.  This does extra disambiguation
      for mixed/pointer accesses but requires strict aliasing.  */
-  if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
-			  TREE_TYPE (TREE_TYPE (ptr2))) == 1)
+  if ((TREE_CODE (base1) != MEM_REF
+       || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1)
+      && (TREE_CODE (base2) != MEM_REF
+	  || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1)
+      && same_type_for_tbaa (TREE_TYPE (ptrtype1),
+			     TREE_TYPE (ptrtype2)) == 1)
     return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
 
   /* Do type-based disambiguation.  */
@@ -778,11 +854,15 @@  indirect_refs_may_alias_p (tree ref1, tr
   /* Do access-path based disambiguation.  */
   if (ref1 && ref2
       && handled_component_p (ref1)
-      && handled_component_p (ref2))
-    return aliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+      && handled_component_p (ref2)
+      && (TREE_CODE (base1) != MEM_REF
+	  || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1)
+      && (TREE_CODE (base2) != MEM_REF
+	  || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1))
+    return aliasing_component_refs_p (ref1, TREE_TYPE (ptrtype1),
 				      ref1_alias_set, base1_alias_set,
 				      offset1, max_size1,
-				      ref2, TREE_TYPE (TREE_TYPE (ptr2)),
+				      ref2, TREE_TYPE (ptrtype2),
 				      ref2_alias_set, base2_alias_set,
 				      offset2, max_size2, false);
 
@@ -798,18 +878,19 @@  refs_may_alias_p_1 (ao_ref *ref1, ao_ref
   HOST_WIDE_INT offset1 = 0, offset2 = 0;
   HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
   bool var1_p, var2_p, ind1_p, ind2_p;
-  alias_set_type set;
 
   gcc_assert ((!ref1->ref
 	       || SSA_VAR_P (ref1->ref)
 	       || handled_component_p (ref1->ref)
 	       || INDIRECT_REF_P (ref1->ref)
+	       || TREE_CODE (ref1->ref) == MEM_REF
 	       || TREE_CODE (ref1->ref) == TARGET_MEM_REF
 	       || TREE_CODE (ref1->ref) == CONST_DECL)
 	      && (!ref2->ref
 		  || SSA_VAR_P (ref2->ref)
 		  || handled_component_p (ref2->ref)
 		  || INDIRECT_REF_P (ref2->ref)
+		  || TREE_CODE (ref2->ref) == MEM_REF
 		  || TREE_CODE (ref2->ref) == TARGET_MEM_REF
 		  || TREE_CODE (ref2->ref) == CONST_DECL));
 
@@ -848,8 +929,9 @@  refs_may_alias_p_1 (ao_ref *ref1, ao_ref
     return decl_refs_may_alias_p (base1, offset1, max_size1,
 				  base2, offset2, max_size2);
 
-  ind1_p = INDIRECT_REF_P (base1);
-  ind2_p = INDIRECT_REF_P (base2);
+  ind1_p = INDIRECT_REF_P (base1) || (TREE_CODE (base1) == MEM_REF);
+  ind2_p = INDIRECT_REF_P (base2) || (TREE_CODE (base2) == MEM_REF);
+
   /* Canonicalize the pointer-vs-decl case.  */
   if (ind1_p && var2_p)
     {
@@ -866,59 +948,6 @@  refs_may_alias_p_1 (ao_ref *ref1, ao_ref
       ind2_p = true;
     }
 
-  /* If we are about to disambiguate pointer-vs-decl try harder to
-     see must-aliases and give leeway to some invalid cases.
-     This covers a pretty minimal set of cases only and does not
-     when called from the RTL oracle.  It handles cases like
-
-       int i = 1;
-       return *(float *)&i;
-
-     and also fixes gfortran.dg/lto/pr40725.  */
-  if (var1_p && ind2_p
-      && cfun
-      && gimple_in_ssa_p (cfun)
-      && TREE_CODE (TREE_OPERAND (base2, 0)) == SSA_NAME)
-    {
-      gimple def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base2, 0));
-      while (is_gimple_assign (def_stmt)
-	     && (gimple_assign_rhs_code (def_stmt) == SSA_NAME
-		 || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))))
-	{
-	  tree rhs = gimple_assign_rhs1 (def_stmt);
-	  HOST_WIDE_INT offset, size, max_size;
-
-	  /* Look through SSA name copies and pointer conversions.  */
-	  if (TREE_CODE (rhs) == SSA_NAME
-	      && POINTER_TYPE_P (TREE_TYPE (rhs)))
-	    {
-	      def_stmt = SSA_NAME_DEF_STMT (rhs);
-	      continue;
-	    }
-	  if (TREE_CODE (rhs) != ADDR_EXPR)
-	    break;
-
-	  /* If the pointer is defined as an address based on a decl
-	     use plain offset disambiguation and ignore TBAA.  */
-	  rhs = TREE_OPERAND (rhs, 0);
-	  rhs = get_ref_base_and_extent (rhs, &offset, &size, &max_size);
-	  if (SSA_VAR_P (rhs))
-	    {
-	      base2 = rhs;
-	      offset2 += offset;
-	      if (size != max_size
-		  || max_size == -1)
-		max_size2 = -1;
-	      return decl_refs_may_alias_p (base1, offset1, max_size1,
-					    base2, offset2, max_size2);
-	    }
-
-	  /* Do not continue looking through &p->x to limit time
-	     complexity.  */
-	  break;
-	}
-    }
-
   /* First defer to TBAA if possible.  */
   if (tbaa_p
       && flag_strict_aliasing
@@ -934,21 +963,23 @@  refs_may_alias_p_1 (ao_ref *ref1, ao_ref
     return true;
 
   /* Dispatch to the pointer-vs-decl or pointer-vs-pointer disambiguators.  */
-  set = tbaa_p ? -1 : 0;
   if (var1_p && ind2_p)
-    return indirect_ref_may_alias_decl_p (ref2->ref, TREE_OPERAND (base2, 0),
+    return indirect_ref_may_alias_decl_p (ref2->ref, base2,
 					  offset2, max_size2,
-					  ao_ref_alias_set (ref2), set,
+					  ao_ref_alias_set (ref2), -1,
 					  ref1->ref, base1,
 					  offset1, max_size1,
-					  ao_ref_alias_set (ref1), set);
+					  ao_ref_alias_set (ref1),
+					  ao_ref_base_alias_set (ref1),
+					  tbaa_p);
   else if (ind1_p && ind2_p)
-    return indirect_refs_may_alias_p (ref1->ref, TREE_OPERAND (base1, 0),
+    return indirect_refs_may_alias_p (ref1->ref, base1,
 				      offset1, max_size1,
-				      ao_ref_alias_set (ref1), set,
-				      ref2->ref, TREE_OPERAND (base2, 0),
+				      ao_ref_alias_set (ref1), -1,
+				      ref2->ref, base2,
 				      offset2, max_size2,
-				      ao_ref_alias_set (ref2), set);
+				      ao_ref_alias_set (ref2), -1,
+				      tbaa_p);
 
   gcc_unreachable ();
 }
@@ -1107,7 +1138,8 @@  ref_maybe_used_by_call_p_1 (gimple call,
       if (pt_solution_includes (gimple_call_use_set (call), base))
 	return true;
     }
-  else if (INDIRECT_REF_P (base)
+  else if ((INDIRECT_REF_P (base)
+	    || TREE_CODE (base) == MEM_REF)
 	   && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
     {
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
@@ -1278,7 +1310,8 @@  call_may_clobber_ref_p_1 (gimple call, a
 	      if (DECL_P (base)
 		  && !TREE_STATIC (base))
 		return true;
-	      else if (INDIRECT_REF_P (base)
+	      else if ((INDIRECT_REF_P (base)
+			|| TREE_CODE (base) == MEM_REF)
 		       && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
 		       && (pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0))))
 		return pi->pt.anything || pi->pt.nonlocal;
@@ -1357,7 +1390,8 @@  call_may_clobber_ref_p_1 (gimple call, a
   /* Check if the base variable is call-clobbered.  */
   if (DECL_P (base))
     return pt_solution_includes (gimple_call_clobber_set (call), base);
-  else if (INDIRECT_REF_P (base)
+  else if ((INDIRECT_REF_P (base)
+	    || TREE_CODE (base) == MEM_REF)
 	   && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
     {
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(.../trunk)	(revision 161367)
+++ gcc/dwarf2out.c	(.../branches/mem-ref2)	(revision 161369)
@@ -15159,6 +15159,11 @@  loc_list_from_tree (tree loc, int want_a
       }
       break;
 
+    case MEM_REF:
+      /* ??? FIXME.  */
+      if (!integer_zerop (TREE_OPERAND (loc, 1)))
+	return 0;
+      /* Fallthru.  */
     case INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
     case MISALIGNED_INDIRECT_REF:
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(.../trunk)	(revision 161367)
+++ gcc/expr.c	(.../branches/mem-ref2)	(revision 161369)
@@ -4211,6 +4211,10 @@  expand_assignment (tree to, tree from, b
      an array element in an unaligned packed structure field, has the same
      problem.  */
   if (handled_component_p (to)
+      /* ???  We only need to handle MEM_REF here if the access is not
+         a full access of the base object.  */
+      || (TREE_CODE (to) == MEM_REF
+	  && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR)
       || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
     {
       enum machine_mode mode1;
@@ -4684,6 +4688,51 @@  store_expr (tree exp, rtx target, int ca
 		       BLOCK_OP_NORMAL);
       return NULL_RTX;
     }
+  else if (TREE_CODE (exp) == MEM_REF
+	   && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+	   && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == STRING_CST
+	   && integer_zerop (TREE_OPERAND (exp, 1))
+	   && !nontemporal && !call_param_p
+	   && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+    {
+      /* Optimize initialization of an array with a STRING_CST.  */
+      HOST_WIDE_INT exp_len, str_copy_len;
+      rtx dest_mem;
+      tree str = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+
+      exp_len = int_expr_size (exp);
+      if (exp_len <= 0)
+	goto normal_expr;
+
+      str_copy_len = strlen (TREE_STRING_POINTER (str));
+      if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
+	goto normal_expr;
+
+      str_copy_len = TREE_STRING_LENGTH (str);
+      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+	{
+	  str_copy_len += STORE_MAX_PIECES - 1;
+	  str_copy_len &= ~(STORE_MAX_PIECES - 1);
+	}
+      str_copy_len = MIN (str_copy_len, exp_len);
+      if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
+				CONST_CAST(char *, TREE_STRING_POINTER (str)),
+				MEM_ALIGN (target), false))
+	goto normal_expr;
+
+      dest_mem = target;
+
+      dest_mem = store_by_pieces (dest_mem,
+				  str_copy_len, builtin_strncpy_read_str,
+				  CONST_CAST(char *, TREE_STRING_POINTER (str)),
+				  MEM_ALIGN (target), false,
+				  exp_len > str_copy_len ? 1 : 0);
+      if (exp_len > str_copy_len)
+	clear_storage (adjust_address (dest_mem, BLKmode, 0),
+		       GEN_INT (exp_len - str_copy_len),
+		       BLOCK_OP_NORMAL);
+      return NULL_RTX;
+    }
   else
     {
       rtx tmp_target;
@@ -5850,7 +5899,15 @@  store_field (rtx target, HOST_WIDE_INT b
 	 operations.  */
       || (bitsize >= 0
 	  && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
-	  && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
+	  && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)
+      /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+         decl we must use bitfield operations.  */
+      || (bitsize >= 0
+	  && TREE_CODE (exp) == MEM_REF
+	  && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+	  && DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+	  && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 ))
+	  && DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode))
     {
       rtx temp;
       gimple nop_def;
@@ -6111,6 +6168,24 @@  get_inner_reference (tree exp, HOST_WIDE
 	    goto done;
 	  break;
 
+	case MEM_REF:
+	  /* Hand back the decl for MEM[&decl, off].  */
+	  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+	    {
+	      tree off = TREE_OPERAND (exp, 1);
+	      if (!integer_zerop (off))
+		{
+		  double_int boff, coff = mem_ref_offset (exp);
+		  boff = double_int_lshift (coff,
+					    BITS_PER_UNIT == 8
+					    ? 3 : exact_log2 (BITS_PER_UNIT),
+					    HOST_BITS_PER_DOUBLE_INT, true);
+		  bit_offset = double_int_add (bit_offset, boff);
+		}
+	      exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+	    }
+	  goto done;
+
 	default:
 	  goto done;
 	}
@@ -6871,6 +6946,16 @@  expand_expr_addr_expr_1 (tree exp, rtx t
       /* This case will happen via recursion for &a->b.  */
       return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
 
+    case MEM_REF:
+      {
+	tree tem = TREE_OPERAND (exp, 0);
+	if (!integer_zerop (TREE_OPERAND (exp, 1)))
+	  tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
+			tem,
+			double_int_to_tree (sizetype, mem_ref_offset (exp)));
+	return expand_expr (tem, target, tmode, modifier);
+      }
+
     case CONST_DECL:
       /* Expand the initializer like constants above.  */
       return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
@@ -8682,6 +8767,71 @@  expand_expr_real_1 (tree exp, rtx target
       }
       return temp;
 
+    case MEM_REF:
+      {
+	addr_space_t as
+	  = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
+	enum machine_mode address_mode;
+	tree base = TREE_OPERAND (exp, 0);
+	/* Handle expansion of non-aliased memory with non-BLKmode.  That
+	   might end up in a register.  */
+	if (TREE_CODE (base) == ADDR_EXPR)
+	  {
+	    HOST_WIDE_INT offset = mem_ref_offset (exp).low;
+	    tree bit_offset;
+	    base = TREE_OPERAND (base, 0);
+	    if (!DECL_P (base))
+	      {
+		HOST_WIDE_INT off;
+		base = get_addr_base_and_unit_offset (base, &off);
+		gcc_assert (base);
+		offset += off;
+	      }
+	    /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+	       decl we must use bitfield operations.  */
+	    if (DECL_P (base)
+		&& !TREE_ADDRESSABLE (base)
+		&& DECL_MODE (base) != BLKmode
+		&& DECL_RTL_SET_P (base)
+		&& !MEM_P (DECL_RTL (base)))
+	      {
+		tree bftype;
+		if (offset == 0
+		    && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
+		    && (GET_MODE_BITSIZE (DECL_MODE (base))
+			== TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
+		  return expand_expr (build1 (VIEW_CONVERT_EXPR,
+					      TREE_TYPE (exp), base),
+				      target, tmode, modifier);
+		bit_offset = bitsize_int (offset * BITS_PER_UNIT);
+		bftype = TREE_TYPE (base);
+		if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+		  bftype = TREE_TYPE (exp);
+		return expand_expr (build3 (BIT_FIELD_REF, bftype,
+					    base,
+					    TYPE_SIZE (TREE_TYPE (exp)),
+					    bit_offset),
+				    target, tmode, modifier);
+	      }
+	  }
+	address_mode = targetm.addr_space.address_mode (as);
+	op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, address_mode,
+			   EXPAND_NORMAL);
+	if (!integer_zerop (TREE_OPERAND (exp, 1)))
+	  {
+	    rtx off;
+	    off = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
+	  }
+	op0 = memory_address_addr_space (mode, op0, as);
+	temp = gen_rtx_MEM (mode, op0);
+	set_mem_attributes (temp, exp, 0);
+	set_mem_addr_space (temp, as);
+	if (TREE_THIS_VOLATILE (exp))
+	  MEM_VOLATILE_P (temp) = 1;
+	return temp;
+      }
+
     case ARRAY_REF:
 
       {
Index: gcc/tree-eh.c
===================================================================
--- gcc/tree-eh.c	(.../trunk)	(revision 161367)
+++ gcc/tree-eh.c	(.../branches/mem-ref2)	(revision 161369)
@@ -2437,6 +2437,10 @@  tree_could_trap_p (tree expr)
 	return false;
       return !in_array_bounds_p (expr);
 
+    case MEM_REF:
+      if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
+	return false;
+      /* Fallthru.  */
     case INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
     case MISALIGNED_INDIRECT_REF:
Index: gcc/alias.c
===================================================================
--- gcc/alias.c	(.../trunk)	(revision 161367)
+++ gcc/alias.c	(.../branches/mem-ref2)	(revision 161369)
@@ -279,7 +279,8 @@  ao_ref_from_mem (ao_ref *ref, const_rtx
 
   /* 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)
+  if ((INDIRECT_REF_P (base)
+       || TREE_CODE (base) == MEM_REF)
       && TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME)
     return false;
 
@@ -293,10 +294,7 @@  ao_ref_from_mem (ao_ref *ref, const_rtx
       void *namep;
       namep = pointer_map_contains (cfun->gimple_df->decls_to_pointers, base);
       if (namep)
-	{
-	  ref->base_alias_set = get_alias_set (base);
-	  ref->base = build1 (INDIRECT_REF, TREE_TYPE (base), *(tree *)namep);
-	}
+	ref->base = build_simple_mem_ref (*(tree *)namep);
     }
 
   ref->ref_alias_set = MEM_ALIAS_SET (mem);
@@ -648,8 +646,8 @@  get_alias_set (tree t)
     {
       tree inner;
 
-      /* Remove any nops, then give the language a chance to do
-	 something with this tree before we look at it.  */
+      /* Give the language a chance to do something with this tree
+	 before we look at it.  */
       STRIP_NOPS (t);
       set = lang_hooks.get_alias_set (t);
       if (set != -1)
@@ -659,21 +657,41 @@  get_alias_set (tree t)
       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 *".  */
+      /* Get the base object of the reference.  */
       inner = t;
       while (handled_component_p (inner))
 	{
+	  /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
+	     the type of any component references that wrap it to
+	     determine the alias-set.  */
+	  if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
+	    t = TREE_OPERAND (inner, 0);
 	  inner = TREE_OPERAND (inner, 0);
-	  STRIP_NOPS (inner);
 	}
 
+      /* Handle pointer dereferences here, they can override the
+	 alias-set.  */
       if (INDIRECT_REF_P (inner))
 	{
 	  set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
 	  if (set != -1)
 	    return set;
 	}
+      else if (TREE_CODE (inner) == MEM_REF)
+	{
+	  set = get_deref_alias_set_1 (TREE_OPERAND (inner, 1));
+	  if (set != -1)
+	    return set;
+	}
+
+      /* If the innermost reference is a MEM_REF that has a
+	 conversion embedded treat it like a VIEW_CONVERT_EXPR above,
+	 using the memory access type for determining the alias-set.  */
+     if (TREE_CODE (inner) == MEM_REF
+	 && (TYPE_MAIN_VARIANT (TREE_TYPE (inner))
+	     != TYPE_MAIN_VARIANT
+	          (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1))))))
+       return get_deref_alias_set (TREE_OPERAND (inner, 1));
 
       /* Otherwise, pick up the outermost object that we could have a pointer
 	 to, processing conversions as above.  */
Index: gcc/tree-data-ref.c
===================================================================
--- gcc/tree-data-ref.c	(.../trunk)	(revision 161367)
+++ gcc/tree-data-ref.c	(.../branches/mem-ref2)	(revision 161369)
@@ -746,7 +746,22 @@  dr_analyze_innermost (struct data_refere
       return false;
     }
 
-  base = build_fold_addr_expr (base);
+  if (TREE_CODE (base) == MEM_REF)
+    {
+      if (!integer_zerop (TREE_OPERAND (base, 1)))
+	{
+	  if (!poffset)
+	    {
+	      double_int moff = mem_ref_offset (base);
+	      poffset = double_int_to_tree (sizetype, moff);
+	    }
+	  else
+	    poffset = size_binop (PLUS_EXPR, poffset, TREE_OPERAND (base, 1));
+	}
+      base = TREE_OPERAND (base, 0);
+    }
+  else
+    base = build_fold_addr_expr (base);
   if (in_loop)
     {
       if (!simple_iv (loop, loop_containing_stmt (stmt), base, &base_iv,
@@ -844,13 +859,18 @@  dr_analyze_indices (struct data_referenc
       aref = TREE_OPERAND (aref, 0);
     }
 
-  if (nest && INDIRECT_REF_P (aref))
+  if (nest
+      && (INDIRECT_REF_P (aref)
+	  || TREE_CODE (aref) == MEM_REF))
     {
       op = TREE_OPERAND (aref, 0);
       access_fn = analyze_scalar_evolution (loop, op);
       access_fn = instantiate_scev (before_loop, loop, access_fn);
       base = initial_condition (access_fn);
       split_constant_offset (base, &base, &off);
+      if (TREE_CODE (aref) == MEM_REF)
+	off = size_binop (PLUS_EXPR, off,
+			  fold_convert (ssizetype, TREE_OPERAND (aref, 1)));
       access_fn = chrec_replace_initial_condition (access_fn,
 			fold_convert (TREE_TYPE (base), off));
 
@@ -858,6 +878,22 @@  dr_analyze_indices (struct data_referenc
       VEC_safe_push (tree, heap, access_fns, access_fn);
     }
 
+  if (TREE_CODE (aref) == MEM_REF)
+    TREE_OPERAND (aref, 1)
+      = build_int_cst (TREE_TYPE (TREE_OPERAND (aref, 1)), 0);
+
+  if (TREE_CODE (ref) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (ref, 0)) == ADDR_EXPR
+      && integer_zerop (TREE_OPERAND (ref, 1)))
+    ref = TREE_OPERAND (TREE_OPERAND (ref, 0), 0);
+
+  /* For canonicalization purposes we'd like to strip all outermost
+     zero-offset component-refs.
+     ???  For now simply handle zero-index array-refs.  */
+  while (TREE_CODE (ref) == ARRAY_REF
+	 && integer_zerop (TREE_OPERAND (ref, 1)))
+    ref = TREE_OPERAND (ref, 0);
+
   DR_BASE_OBJECT (dr) = ref;
   DR_ACCESS_FNS (dr) = access_fns;
 }
@@ -870,7 +906,8 @@  dr_analyze_alias (struct data_reference
   tree ref = DR_REF (dr);
   tree base = get_base_address (ref), addr;
 
-  if (INDIRECT_REF_P (base))
+  if (INDIRECT_REF_P (base)
+      || TREE_CODE (base) == MEM_REF)
     {
       addr = TREE_OPERAND (base, 0);
       if (TREE_CODE (addr) == SSA_NAME)
@@ -1188,7 +1225,8 @@  object_address_invariant_in_loop_p (cons
       obj = TREE_OPERAND (obj, 0);
     }
 
-  if (!INDIRECT_REF_P (obj))
+  if (!INDIRECT_REF_P (obj)
+      && TREE_CODE (obj) != MEM_REF)
     return true;
 
   return !chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 0),
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(.../trunk)	(revision 161367)
+++ gcc/gimplify.c	(.../branches/mem-ref2)	(revision 161369)
@@ -110,10 +110,13 @@  mark_addressable (tree x)
 {
   while (handled_component_p (x))
     x = TREE_OPERAND (x, 0);
+  if (TREE_CODE (x) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
+    x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
   if (TREE_CODE (x) != VAR_DECL
       && TREE_CODE (x) != PARM_DECL
       && TREE_CODE (x) != RESULT_DECL)
-    return ;
+    return;
   TREE_ADDRESSABLE (x) = 1;
 }
 
@@ -2961,7 +2964,7 @@  gimplify_cond_expr (tree *expr_p, gimple
 	    = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
 
 	  tmp = create_tmp_var (type, "iftmp");
-	  result = build_fold_indirect_ref_loc (loc, tmp);
+	  result = build_simple_mem_ref_loc (loc, tmp);
 	}
 
       /* Build the new then clause, `tmp = then_;'.  But don't build the
@@ -3185,7 +3188,7 @@  gimplify_modify_expr_to_memcpy (tree *ex
       gimple_call_set_lhs (gs, t);
       gimplify_seq_add_stmt (seq_p, gs);
 
-      *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+      *expr_p = build_simple_mem_ref (t);
       return GS_ALL_DONE;
     }
 
@@ -3269,13 +3272,16 @@  gimplify_init_ctor_preeval_1 (tree *tp,
   /* If the constructor component is indirect, determine if we have a
      potential overlap with the lhs.  The only bits of information we
      have to go on at this point are addressability and alias sets.  */
-  if (TREE_CODE (t) == INDIRECT_REF
+  if ((INDIRECT_REF_P (t)
+       || TREE_CODE (t) == MEM_REF)
       && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
       && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
     return t;
 
   /* If the constructor component is a call, determine if it can hide a
-     potential overlap with the lhs through an INDIRECT_REF like above.  */
+     potential overlap with the lhs through an INDIRECT_REF like above.
+     ??? Ugh - this is completely broken.  In fact this whole analysis
+     doesn't look conservative.  */
   if (TREE_CODE (t) == CALL_EXPR)
     {
       tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t)));
@@ -4004,7 +4010,7 @@  gimplify_init_constructor (tree *expr_p,
 tree
 gimple_fold_indirect_ref (tree t)
 {
-  tree type = TREE_TYPE (TREE_TYPE (t));
+  tree ptype = TREE_TYPE (t), type = TREE_TYPE (ptype);
   tree sub = t;
   tree subtype;
 
@@ -4047,51 +4053,52 @@  gimple_fold_indirect_ref (tree t)
         }
     }
 
-  /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
+  /* *(p + CST) -> ...  */
   if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
     {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
-
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-	  && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
-	  && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
-	{
-	  HOST_WIDE_INT offset = tree_low_cst (op01, 0);
-	  tree part_width = TYPE_SIZE (type);
-	  unsigned HOST_WIDE_INT part_widthi
-	    = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
-	  unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
-	  tree index = bitsize_int (indexi);
-	  if (offset / part_widthi
-	      <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
-	    return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
-				part_width, index);
+      tree addr = TREE_OPERAND (sub, 0);
+      tree off = TREE_OPERAND (sub, 1);
+      tree addrtype;
+
+      STRIP_NOPS (addr);
+      addrtype = TREE_TYPE (addr);
+
+      /* ((foo*)&vectorfoo)[1] -> BIT_FIELD_REF<vectorfoo,...> */
+      if (TREE_CODE (addr) == ADDR_EXPR
+	  && TREE_CODE (TREE_TYPE (addrtype)) == VECTOR_TYPE
+	  && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
+	{
+          HOST_WIDE_INT offset = tree_low_cst (off, 0);
+          tree part_width = TYPE_SIZE (type);
+          unsigned HOST_WIDE_INT part_widthi
+            = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
+          unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+          tree index = bitsize_int (indexi);
+          if (offset / part_widthi
+              <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (addrtype)))
+            return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (addr, 0),
+                                part_width, index);
 	}
-    }
 
-  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-  if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-      && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
-    {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
-
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-	  && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
-	  && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
-	{
-	  tree size = TYPE_SIZE_UNIT (type);
-	  if (tree_int_cst_equal (size, op01))
-	    return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0));
-	}
+      /* ((foo*)&complexfoo)[1] -> __imag__ complexfoo */
+      if (TREE_CODE (addr) == ADDR_EXPR
+	  && TREE_CODE (TREE_TYPE (addrtype)) == COMPLEX_TYPE
+	  && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
+        {
+          tree size = TYPE_SIZE_UNIT (type);
+          if (tree_int_cst_equal (size, off))
+            return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (addr, 0));
+        }
+
+      /* *(p + CST) -> MEM_REF <p, CST>.  */
+      if (TREE_CODE (addr) != ADDR_EXPR
+	  || DECL_P (TREE_OPERAND (addr, 0)))
+	return fold_build2 (MEM_REF, type,
+			    addr,
+			    build_int_cst_wide (ptype,
+						TREE_INT_CST_LOW (off),
+						TREE_INT_CST_HIGH (off)));
     }
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
@@ -6558,7 +6565,8 @@  gimplify_expr (tree *expr_p, gimple_seq
            || gimple_test_f == is_gimple_mem_rhs_or_call
            || gimple_test_f == is_gimple_reg_rhs
            || gimple_test_f == is_gimple_reg_rhs_or_call
-           || gimple_test_f == is_gimple_asm_val)
+           || gimple_test_f == is_gimple_asm_val
+	   || gimple_test_f == is_gimple_mem_ref_addr)
     gcc_assert (fallback & fb_rvalue);
   else if (gimple_test_f == is_gimple_min_lval
 	   || gimple_test_f == is_gimple_lvalue)
@@ -6764,19 +6772,57 @@  gimplify_expr (tree *expr_p, gimple_seq
 	  recalculate_side_effects (*expr_p);
 	  break;
 
+	case ALIGN_INDIRECT_REF:
+	case MISALIGNED_INDIRECT_REF:
+	  /* We can only reach this through re-gimplification from
+	     tree optimizers.  */
+	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+			       is_gimple_reg, fb_rvalue);
+	  recalculate_side_effects (*expr_p);
+	  break;
+
 	case INDIRECT_REF:
-	  *expr_p = fold_indirect_ref_loc (input_location, *expr_p);
-	  if (*expr_p != save_expr)
+	  {
+	    bool volatilep = TREE_THIS_VOLATILE (*expr_p);
+	    tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
+
+	    *expr_p = fold_indirect_ref_loc (input_location, *expr_p);
+	    if (*expr_p != save_expr)
+	      {
+		ret = GS_OK;
+		break;
+	      }
+
+	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+				 is_gimple_reg, fb_rvalue);
+	    recalculate_side_effects (*expr_p);
+
+	    *expr_p = fold_build2_loc (input_location, MEM_REF,
+				       TREE_TYPE (*expr_p),
+				       TREE_OPERAND (*expr_p, 0),
+				       build_int_cst (saved_ptr_type, 0));
+	    TREE_THIS_VOLATILE (*expr_p) = volatilep;
+	    ret = GS_OK;
+	    break;
+	  }
+
+	/* We arrive here through the various re-gimplifcation paths.  */
+	case MEM_REF:
+	  /* First try re-folding the whole thing.  */
+	  tmp = fold_binary (MEM_REF, TREE_TYPE (*expr_p),
+			     TREE_OPERAND (*expr_p, 0),
+			     TREE_OPERAND (*expr_p, 1));
+	  if (tmp)
 	    {
+	      *expr_p = tmp;
+	      recalculate_side_effects (*expr_p);
 	      ret = GS_OK;
 	      break;
 	    }
-	  /* else fall through.  */
-	case ALIGN_INDIRECT_REF:
-	case MISALIGNED_INDIRECT_REF:
 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-			       is_gimple_reg, fb_rvalue);
+			       is_gimple_mem_ref_addr, fb_rvalue);
 	  recalculate_side_effects (*expr_p);
+	  ret = GS_ALL_DONE;
 	  break;
 
 	  /* Constants need not be gimplified.  */
Index: gcc/tree.def
===================================================================
--- gcc/tree.def	(.../trunk)	(revision 161367)
+++ gcc/tree.def	(.../branches/mem-ref2)	(revision 161369)
@@ -970,6 +970,16 @@  DEFTREECODE (REALIGN_LOAD_EXPR, "realign
 
 DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 6)
 
+/* Memory addressing.  Operands are a pointer and a tree constant integer
+   byte offset of the pointer type that when dereferenced yields the
+   type of the base object the pointer points into and which is used for
+   TBAA purposes.
+   The type of the MEM_REF is the type the bytes at the memory location
+   are interpreted as.
+   MEM_REF <p, c> is equivalent to ((typeof(c))p)->x... where x... is a
+   chain of component references offsetting p by c.  */
+DEFTREECODE (MEM_REF, "mem_ref", tcc_reference, 2)
+
 /* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is
    exposed to TREE_RANGE_CHECK.  */
 /* OpenMP - #pragma omp parallel [clause1 ... clauseN]
Index: gcc/tree-dfa.c
===================================================================
--- gcc/tree-dfa.c	(.../trunk)	(revision 161367)
+++ gcc/tree-dfa.c	(.../branches/mem-ref2)	(revision 161369)
@@ -23,6 +23,7 @@  along with GCC; see the file COPYING3.
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "toplev.h"
 #include "hashtab.h"
 #include "pointer-set.h"
 #include "tree.h"
@@ -867,6 +868,29 @@  get_ref_base_and_extent (tree exp, HOST_
 	case VIEW_CONVERT_EXPR:
 	  break;
 
+	case MEM_REF:
+	  /* Hand back the decl for MEM[&decl, off].  */
+	  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+	    {
+	      if (integer_zerop (TREE_OPERAND (exp, 1)))
+		exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+	      else
+		{
+		  double_int off = mem_ref_offset (exp);
+		  off = double_int_lshift (off,
+					   BITS_PER_UNIT == 8
+					   ? 3 : exact_log2 (BITS_PER_UNIT),
+					   HOST_BITS_PER_DOUBLE_INT, true);
+		  off = double_int_add (off, shwi_to_double_int (bit_offset));
+		  if (double_int_fits_in_shwi_p (off))
+		    {
+		      bit_offset = double_int_to_shwi (off);
+		      exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+		    }
+		}
+	    }
+	  goto done;
+
 	default:
 	  goto done;
 	}
@@ -913,6 +937,104 @@  get_ref_base_and_extent (tree exp, HOST_
   return exp;
 }
 
+/* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that
+   denotes the starting address of the memory access EXP.
+   Returns NULL_TREE if the offset is not constant or any component
+   is not BITS_PER_UNIT-aligned.  */
+
+tree
+get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset)
+{
+  HOST_WIDE_INT byte_offset = 0;
+
+  /* Compute cumulative byte-offset for nested component-refs and array-refs,
+     and find the ultimate containing object.  */
+  while (1)
+    {
+      switch (TREE_CODE (exp))
+	{
+	case BIT_FIELD_REF:
+	  return NULL_TREE;
+
+	case COMPONENT_REF:
+	  {
+	    tree field = TREE_OPERAND (exp, 1);
+	    tree this_offset = component_ref_field_offset (exp);
+	    HOST_WIDE_INT hthis_offset;
+
+	    if (!this_offset
+		|| TREE_CODE (this_offset) != INTEGER_CST
+		|| (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
+		    % BITS_PER_UNIT))
+	      return NULL_TREE;
+
+	    hthis_offset = TREE_INT_CST_LOW (this_offset);
+	    hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
+			     / BITS_PER_UNIT);
+	    byte_offset += hthis_offset;
+	  }
+	  break;
+
+	case ARRAY_REF:
+	case ARRAY_RANGE_REF:
+	  {
+	    tree index = TREE_OPERAND (exp, 1);
+	    tree low_bound, unit_size;
+
+	    /* If the resulting bit-offset is constant, track it.  */
+	    if (TREE_CODE (index) == INTEGER_CST
+		&& (low_bound = array_ref_low_bound (exp),
+		    TREE_CODE (low_bound) == INTEGER_CST)
+		&& (unit_size = array_ref_element_size (exp),
+		    TREE_CODE (unit_size) == INTEGER_CST))
+	      {
+		HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index);
+
+		hindex -= TREE_INT_CST_LOW (low_bound);
+		hindex *= TREE_INT_CST_LOW (unit_size);
+		byte_offset += hindex;
+	      }
+	    else
+	      return NULL_TREE;
+	  }
+	  break;
+
+	case REALPART_EXPR:
+	  break;
+
+	case IMAGPART_EXPR:
+	  byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
+	  break;
+
+	case VIEW_CONVERT_EXPR:
+	  break;
+
+	case MEM_REF:
+	  /* Hand back the decl for MEM[&decl, off].  */
+	  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+	    {
+	      if (!integer_zerop (TREE_OPERAND (exp, 1)))
+		{
+		  double_int off = mem_ref_offset (exp);
+		  gcc_assert (off.high == -1 || off.high == 0);
+		  byte_offset += double_int_to_shwi (off);
+		}
+	      exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+	    }
+	  goto done;
+
+	default:
+	  goto done;
+	}
+
+      exp = TREE_OPERAND (exp, 0);
+    }
+done:
+
+  *poffset = byte_offset;
+  return exp;
+}
+
 /* Returns true if STMT references an SSA_NAME that has
    SSA_NAME_OCCURS_IN_ABNORMAL_PHI set, otherwise false.  */
 
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(.../trunk)	(revision 161367)
+++ gcc/emit-rtl.c	(.../branches/mem-ref2)	(revision 161369)
@@ -1614,6 +1614,35 @@  set_mem_attributes_minus_bitpos (rtx ref
       || TREE_CODE (t) == ALIGN_INDIRECT_REF
       || TYPE_ALIGN_OK (type))
     align = MAX (align, TYPE_ALIGN (type));
+  else if (TREE_CODE (t) == MEM_REF)
+    {
+      HOST_WIDE_INT aoff = BITS_PER_UNIT;
+      if (host_integerp (TREE_OPERAND (t, 1), 1))
+	{
+	  HOST_WIDE_INT ioff = TREE_INT_CST_LOW (TREE_OPERAND (t, 1));
+	  aoff = (ioff & -ioff) * BITS_PER_UNIT;
+	}
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+	  && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
+	align = MAX (align,
+		     DECL_ALIGN (TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
+      else if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+	       && CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
+	{
+	  align = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
+#ifdef CONSTANT_ALIGNMENT
+	  align = CONSTANT_ALIGNMENT (TREE_OPERAND (TREE_OPERAND (t, 0), 0), align);
+#endif
+	}
+      else
+	/* This technically isn't correct.  We can't really derive
+	   alignment information from types.  */
+	align = MAX (align,
+		     TYPE_ALIGN (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1)))));
+      if (!integer_zerop (TREE_OPERAND (t, 1))
+	  && aoff < align)
+	align = aoff;
+    }
   else
     if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
       {
@@ -1654,6 +1683,9 @@  set_mem_attributes_minus_bitpos (rtx ref
 	     || TREE_CODE (base) == BIT_FIELD_REF)
 	base = TREE_OPERAND (base, 0);
 
+      if (TREE_CODE (base) == MEM_REF
+	  && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
+	base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
       if (DECL_P (base))
 	{
 	  if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS))
@@ -1774,7 +1806,7 @@  set_mem_attributes_minus_bitpos (rtx ref
 	    }
 
 	  /* If this is an indirect reference, record it.  */
-	  else if (TREE_CODE (t) == INDIRECT_REF
+	  else if (TREE_CODE (t) == MEM_REF 
 		   || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
 	    {
 	      expr = t;
@@ -1784,7 +1816,7 @@  set_mem_attributes_minus_bitpos (rtx ref
 	}
 
       /* If this is an indirect reference, record it.  */
-      else if (TREE_CODE (t) == INDIRECT_REF
+      else if (TREE_CODE (t) == MEM_REF 
 	       || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
 	{
 	  expr = t;
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(.../trunk)	(revision 161367)
+++ gcc/gimple-fold.c	(.../branches/mem-ref2)	(revision 161369)
@@ -82,7 +82,7 @@  get_symbol_constant_value (tree sym)
 bool
 may_propagate_address_into_dereference (tree addr, tree deref)
 {
-  gcc_assert (INDIRECT_REF_P (deref)
+  gcc_assert (TREE_CODE (deref) == MEM_REF
 	      && TREE_CODE (addr) == ADDR_EXPR);
 
   /* Don't propagate if ADDR's operand has incomplete type.  */
@@ -108,15 +108,12 @@  may_propagate_address_into_dereference (
 
 
 /* A subroutine of fold_stmt.  Attempts to fold *(A+O) to A[X].
-   BASE is an array type.  OFFSET is a byte displacement.  ORIG_TYPE
-   is the desired result type.
+   BASE is an array type.  OFFSET is a byte displacement.
 
    LOC is the location of the original expression.  */
 
 static tree
-maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset,
-				tree orig_type,
-				bool allow_negative_idx)
+maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset)
 {
   tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
   tree array_type, elt_type, elt_size;
@@ -145,8 +142,6 @@  maybe_fold_offset_to_array_ref (location
   if (TREE_CODE (array_type) != ARRAY_TYPE)
     return NULL_TREE;
   elt_type = TREE_TYPE (array_type);
-  if (!useless_type_conversion_p (orig_type, elt_type))
-    return NULL_TREE;
 
   /* Use signed size type for intermediate computation on the index.  */
   idx_type = ssizetype;
@@ -219,34 +214,22 @@  maybe_fold_offset_to_array_ref (location
        char *(c[4]);
        c[3][2];
      should not be simplified into (*c)[14] or tree-vrp will
-     give false warnings.  The same is true for
-       struct A { long x; char d[0]; } *a;
-       (char *)a - 4;
-     which should be not folded to &a->d[-8].  */
-  if (domain_type
-      && TYPE_MAX_VALUE (domain_type)
-      && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST)
-    {
-      tree up_bound = TYPE_MAX_VALUE (domain_type);
-
-      if (tree_int_cst_lt (up_bound, idx)
-	  /* Accesses after the end of arrays of size 0 (gcc
-	     extension) and 1 are likely intentional ("struct
-	     hack").  */
-	  && compare_tree_int (up_bound, 1) > 0)
+     give false warnings.
+     This is only an issue for multi-dimensional arrays.  */
+  if (TREE_CODE (elt_type) == ARRAY_TYPE
+      && domain_type)
+    {
+      if (TYPE_MAX_VALUE (domain_type)
+	  && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST
+	  && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), idx))
 	return NULL_TREE;
-    }
-  if (domain_type
-      && TYPE_MIN_VALUE (domain_type))
-    {
-      if (!allow_negative_idx
-	  && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
-	  && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
+      else if (TYPE_MIN_VALUE (domain_type)
+	       && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
+	       && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
+	return NULL_TREE;
+      else if (compare_tree_int (idx, 0) < 0)
 	return NULL_TREE;
     }
-  else if (!allow_negative_idx
-	   && compare_tree_int (idx, 0) < 0)
-    return NULL_TREE;
 
   {
     tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE);
@@ -256,340 +239,55 @@  maybe_fold_offset_to_array_ref (location
 }
 
 
-/* Attempt to fold *(S+O) to S.X.
-   BASE is a record type.  OFFSET is a byte displacement.  ORIG_TYPE
-   is the desired result type.
-
-   LOC is the location of the original expression.  */
-
-static tree
-maybe_fold_offset_to_component_ref (location_t loc, tree record_type,
-				    tree base, tree offset, tree orig_type)
-{
-  tree f, t, field_type, tail_array_field, field_offset;
-  tree ret;
-  tree new_base;
-
-  if (TREE_CODE (record_type) != RECORD_TYPE
-      && TREE_CODE (record_type) != UNION_TYPE
-      && TREE_CODE (record_type) != QUAL_UNION_TYPE)
-    return NULL_TREE;
-
-  /* Short-circuit silly cases.  */
-  if (useless_type_conversion_p (record_type, orig_type))
-    return NULL_TREE;
-
-  tail_array_field = NULL_TREE;
-  for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f))
-    {
-      int cmp;
-
-      if (TREE_CODE (f) != FIELD_DECL)
-	continue;
-      if (DECL_BIT_FIELD (f))
-	continue;
-
-      if (!DECL_FIELD_OFFSET (f))
-	continue;
-      field_offset = byte_position (f);
-      if (TREE_CODE (field_offset) != INTEGER_CST)
-	continue;
-
-      /* ??? Java creates "interesting" fields for representing base classes.
-	 They have no name, and have no context.  With no context, we get into
-	 trouble with nonoverlapping_component_refs_p.  Skip them.  */
-      if (!DECL_FIELD_CONTEXT (f))
-	continue;
-
-      /* The previous array field isn't at the end.  */
-      tail_array_field = NULL_TREE;
-
-      /* Check to see if this offset overlaps with the field.  */
-      cmp = tree_int_cst_compare (field_offset, offset);
-      if (cmp > 0)
-	continue;
-
-      field_type = TREE_TYPE (f);
-
-      /* Here we exactly match the offset being checked.  If the types match,
-	 then we can return that field.  */
-      if (cmp == 0
-	  && useless_type_conversion_p (orig_type, field_type))
-	{
-	  t = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
-	  return t;
-	}
-
-      /* Don't care about offsets into the middle of scalars.  */
-      if (!AGGREGATE_TYPE_P (field_type))
-	continue;
-
-      /* Check for array at the end of the struct.  This is often
-	 used as for flexible array members.  We should be able to
-	 turn this into an array access anyway.  */
-      if (TREE_CODE (field_type) == ARRAY_TYPE)
-	tail_array_field = f;
-
-      /* Check the end of the field against the offset.  */
-      if (!DECL_SIZE_UNIT (f)
-	  || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST)
-	continue;
-      t = int_const_binop (MINUS_EXPR, offset, field_offset, 1);
-      if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f)))
-	continue;
-
-      /* If we matched, then set offset to the displacement into
-	 this field.  */
-      new_base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
-      SET_EXPR_LOCATION (new_base, loc);
-
-      /* Recurse to possibly find the match.  */
-      ret = maybe_fold_offset_to_array_ref (loc, new_base, t, orig_type,
-					    f == TYPE_FIELDS (record_type));
-      if (ret)
-	return ret;
-      ret = maybe_fold_offset_to_component_ref (loc, field_type, new_base, t,
-						orig_type);
-      if (ret)
-	return ret;
-    }
-
-  if (!tail_array_field)
-    return NULL_TREE;
-
-  f = tail_array_field;
-  field_type = TREE_TYPE (f);
-  offset = int_const_binop (MINUS_EXPR, offset, byte_position (f), 1);
-
-  /* If we get here, we've got an aggregate field, and a possibly
-     nonzero offset into them.  Recurse and hope for a valid match.  */
-  base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
-  SET_EXPR_LOCATION (base, loc);
-
-  t = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type,
-				      f == TYPE_FIELDS (record_type));
-  if (t)
-    return t;
-  return maybe_fold_offset_to_component_ref (loc, field_type, base, offset,
-					     orig_type);
-}
-
-/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
-   or BASE[index] or by combination of those.
-
+/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE[index].
    LOC is the location of original expression.
 
-   Before attempting the conversion strip off existing ADDR_EXPRs and
-   handled component refs.  */
+   Before attempting the conversion strip off existing ADDR_EXPRs.  */
 
 tree
 maybe_fold_offset_to_reference (location_t loc, tree base, tree offset,
 				tree orig_type)
 {
   tree ret;
-  tree type;
 
   STRIP_NOPS (base);
   if (TREE_CODE (base) != ADDR_EXPR)
     return NULL_TREE;
 
   base = TREE_OPERAND (base, 0);
-
-  /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
-     so it needs to be removed and new COMPONENT_REF constructed.
-     The wrong COMPONENT_REF are often constructed by folding the
-     (type *)&object within the expression (type *)&object+offset  */
-  if (handled_component_p (base))
-    {
-      HOST_WIDE_INT sub_offset, size, maxsize;
-      tree newbase;
-      newbase = get_ref_base_and_extent (base, &sub_offset,
-					 &size, &maxsize);
-      gcc_assert (newbase);
-      if (size == maxsize
-	  && size != -1
-	  && !(sub_offset & (BITS_PER_UNIT - 1)))
-	{
-	  base = newbase;
-	  if (sub_offset)
-	    offset = int_const_binop (PLUS_EXPR, offset,
-				      build_int_cst (TREE_TYPE (offset),
-						     sub_offset / BITS_PER_UNIT), 1);
-	}
-    }
-  if (useless_type_conversion_p (orig_type, TREE_TYPE (base))
+  if (types_compatible_p (orig_type, TREE_TYPE (base))
       && integer_zerop (offset))
     return base;
-  type = TREE_TYPE (base);
 
-  ret = maybe_fold_offset_to_component_ref (loc, type, base, offset, orig_type);
-  if (!ret)
-    ret = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, true);
-
-  return ret;
+  ret = maybe_fold_offset_to_array_ref (loc, base, offset);
+  if (ret && types_compatible_p (orig_type, TREE_TYPE (ret)))
+    return ret;
+  return NULL_TREE;
 }
 
-/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type
-   or &BASE[index] or by combination of those.
-
-   LOC is the location of the original expression.
-
-   Before attempting the conversion strip off existing component refs.  */
+/* Attempt to express (ORIG_TYPE)ADDR+OFFSET as (*ADDR)[index].
+   LOC is the location of the original expression.  */
 
 tree
 maybe_fold_offset_to_address (location_t loc, tree addr, tree offset,
 			      tree orig_type)
 {
-  tree t;
-
-  gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
-	      && POINTER_TYPE_P (orig_type));
-
-  t = maybe_fold_offset_to_reference (loc, addr, offset,
-				      TREE_TYPE (orig_type));
-  if (t != NULL_TREE)
-    {
-      tree orig = addr;
-      tree ptr_type;
-
-      /* For __builtin_object_size to function correctly we need to
-         make sure not to fold address arithmetic so that we change
-	 reference from one array to another.  This would happen for
-	 example for
-
-	   struct X { char s1[10]; char s2[10] } s;
-	   char *foo (void) { return &s.s2[-4]; }
-
-	 where we need to avoid generating &s.s1[6].  As the C and
-	 C++ frontends create different initial trees
-	 (char *) &s.s1 + -4  vs.  &s.s1[-4]  we have to do some
-	 sophisticated comparisons here.  Note that checking for the
-	 condition after the fact is easier than trying to avoid doing
-	 the folding.  */
-      STRIP_NOPS (orig);
-      if (TREE_CODE (orig) == ADDR_EXPR)
-	orig = TREE_OPERAND (orig, 0);
-      if ((TREE_CODE (orig) == ARRAY_REF
-	   || (TREE_CODE (orig) == COMPONENT_REF
-	       && TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
-	  && (TREE_CODE (t) == ARRAY_REF
-	      || TREE_CODE (t) == COMPONENT_REF)
-	  && !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
-			       ? TREE_OPERAND (orig, 0) : orig,
-			       TREE_CODE (t) == ARRAY_REF
-			       ? TREE_OPERAND (t, 0) : t, 0))
-	return NULL_TREE;
-
-      ptr_type = build_pointer_type (TREE_TYPE (t));
-      if (!useless_type_conversion_p (orig_type, ptr_type))
-	return NULL_TREE;
-      return build_fold_addr_expr_with_type_loc (loc, t, ptr_type);
-    }
-
-  return NULL_TREE;
-}
-
-/* A subroutine of fold_stmt.  Attempt to simplify *(BASE+OFFSET).
-   Return the simplified expression, or NULL if nothing could be done.  */
-
-static tree
-maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
-{
-  tree t;
-  bool volatile_p = TREE_THIS_VOLATILE (expr);
-  location_t loc = EXPR_LOCATION (expr);
+  tree base, ret;
 
-  /* We may well have constructed a double-nested PLUS_EXPR via multiple
-     substitutions.  Fold that down to one.  Remove NON_LVALUE_EXPRs that
-     are sometimes added.  */
-  base = fold (base);
-  STRIP_TYPE_NOPS (base);
-  TREE_OPERAND (expr, 0) = base;
-
-  /* One possibility is that the address reduces to a string constant.  */
-  t = fold_read_from_constant_string (expr);
-  if (t)
-    return t;
-
-  /* Add in any offset from a POINTER_PLUS_EXPR.  */
-  if (TREE_CODE (base) == POINTER_PLUS_EXPR)
+  STRIP_NOPS (addr);
+  if (TREE_CODE (addr) != ADDR_EXPR)
+    return NULL_TREE;
+  base = TREE_OPERAND (addr, 0);
+  ret = maybe_fold_offset_to_array_ref (loc, base, offset);
+  if (ret)
     {
-      tree offset2;
-
-      offset2 = TREE_OPERAND (base, 1);
-      if (TREE_CODE (offset2) != INTEGER_CST)
+      ret = build_fold_addr_expr (ret);
+      if (!useless_type_conversion_p (orig_type, TREE_TYPE (ret)))
 	return NULL_TREE;
-      base = TREE_OPERAND (base, 0);
-
-      offset = fold_convert (sizetype,
-			     int_const_binop (PLUS_EXPR, offset, offset2, 1));
-    }
-
-  if (TREE_CODE (base) == ADDR_EXPR)
-    {
-      tree base_addr = base;
-
-      /* Strip the ADDR_EXPR.  */
-      base = TREE_OPERAND (base, 0);
-
-      /* Fold away CONST_DECL to its value, if the type is scalar.  */
-      if (TREE_CODE (base) == CONST_DECL
-	  && is_gimple_min_invariant (DECL_INITIAL (base)))
-	return DECL_INITIAL (base);
-
-      /* If there is no offset involved simply return the folded base.  */
-      if (integer_zerop (offset))
-	return base;
-
-      /* Try folding *(&B+O) to B.X.  */
-      t = maybe_fold_offset_to_reference (loc, base_addr, offset,
-					  TREE_TYPE (expr));
-      if (t)
-	{
-	  /* Preserve volatileness of the original expression.
-	     We can end up with a plain decl here which is shared
-	     and we shouldn't mess with its flags.  */
-	  if (!SSA_VAR_P (t))
-	    TREE_THIS_VOLATILE (t) = volatile_p;
-	  return t;
-	}
-    }
-  else
-    {
-      /* We can get here for out-of-range string constant accesses,
-	 such as "_"[3].  Bail out of the entire substitution search
-	 and arrange for the entire statement to be replaced by a
-	 call to __builtin_trap.  In all likelihood this will all be
-	 constant-folded away, but in the meantime we can't leave with
-	 something that get_expr_operands can't understand.  */
-
-      t = base;
-      STRIP_NOPS (t);
-      if (TREE_CODE (t) == ADDR_EXPR
-	  && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
-	{
-	  /* FIXME: Except that this causes problems elsewhere with dead
-	     code not being deleted, and we die in the rtl expanders
-	     because we failed to remove some ssa_name.  In the meantime,
-	     just return zero.  */
-	  /* FIXME2: This condition should be signaled by
-	     fold_read_from_constant_string directly, rather than
-	     re-checking for it here.  */
-	  return integer_zero_node;
-	}
-
-      /* Try folding *(B+O) to B->X.  Still an improvement.  */
-      if (POINTER_TYPE_P (TREE_TYPE (base)))
-	{
-          t = maybe_fold_offset_to_reference (loc, base, offset,
-				              TREE_TYPE (expr));
-	  if (t)
-	    return t;
-	}
+      SET_EXPR_LOCATION (ret, loc);
     }
 
-  /* Otherwise we had an offset that we could not simplify.  */
-  return NULL_TREE;
+  return ret;
 }
 
 
@@ -622,18 +320,17 @@  maybe_fold_stmt_addition (location_t loc
       /* Or op0 should now be A[0] and the non-constant offset defined
 	 via a multiplication by the array element size.  */
       if (TREE_CODE (op0) == ARRAY_REF
-	  && integer_zerop (TREE_OPERAND (op0, 1))
-	  && TREE_CODE (op1) == SSA_NAME
-	  && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (op0)), 1))
-	{
-	  gimple offset_def = SSA_NAME_DEF_STMT (op1);
-	  if (!is_gimple_assign (offset_def))
-	    return NULL_TREE;
-
 	  /* As we will end up creating a variable index array access
 	     in the outermost array dimension make sure there isn't
 	     a more inner array that the index could overflow to.  */
-	  if (TREE_CODE (TREE_OPERAND (op0, 0)) == ARRAY_REF)
+	  && TREE_CODE (TREE_OPERAND (op0, 0)) != ARRAY_REF
+	  && integer_zerop (TREE_OPERAND (op0, 1))
+	  && TREE_CODE (op1) == SSA_NAME)
+	{
+	  gimple offset_def = SSA_NAME_DEF_STMT (op1);
+	  tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+	  if (!host_integerp (elsz, 1)
+	      || !is_gimple_assign (offset_def))
 	    return NULL_TREE;
 
 	  /* Do not build array references of something that we can't
@@ -644,15 +341,14 @@  maybe_fold_stmt_addition (location_t loc
 
 	  if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
 	      && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
-	      && tree_int_cst_equal (gimple_assign_rhs2 (offset_def),
-				     TYPE_SIZE_UNIT (TREE_TYPE (op0))))
+	      && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz))
 	    return build_fold_addr_expr
 			  (build4 (ARRAY_REF, TREE_TYPE (op0),
 				   TREE_OPERAND (op0, 0),
 				   gimple_assign_rhs1 (offset_def),
 				   TREE_OPERAND (op0, 2),
 				   TREE_OPERAND (op0, 3)));
-	  else if (integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (op0)))
+	  else if (integer_onep (elsz)
 		   && gimple_assign_rhs_code (offset_def) != MULT_EXPR)
 	    return build_fold_addr_expr
 			  (build4 (ARRAY_REF, TREE_TYPE (op0),
@@ -661,6 +357,38 @@  maybe_fold_stmt_addition (location_t loc
 				   TREE_OPERAND (op0, 2),
 				   TREE_OPERAND (op0, 3)));
 	}
+      else if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
+	       /* Dto.  */
+	       && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) != ARRAY_TYPE
+	       && TREE_CODE (op1) == SSA_NAME)
+	{
+	  gimple offset_def = SSA_NAME_DEF_STMT (op1);
+	  tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op0)));
+	  if (!host_integerp (elsz, 1)
+	      || !is_gimple_assign (offset_def))
+	    return NULL_TREE;
+
+	  /* Do not build array references of something that we can't
+	     see the true number of array dimensions for.  */
+	  if (!DECL_P (op0)
+	      && !handled_component_p (op0))
+	    return NULL_TREE;
+
+	  if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
+	      && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
+	      && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz))
+	    return build_fold_addr_expr
+			  (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)),
+				   op0, gimple_assign_rhs1 (offset_def),
+				   integer_zero_node, NULL_TREE));
+	  else if (integer_onep (elsz)
+		   && gimple_assign_rhs_code (offset_def) != MULT_EXPR)
+	    return build_fold_addr_expr
+			  (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)),
+				   op0, op1,
+				   integer_zero_node, NULL_TREE));
+	}
+
       return NULL_TREE;
     }
 
@@ -715,13 +443,12 @@  maybe_fold_stmt_addition (location_t loc
     ptd_type = TREE_TYPE (TREE_TYPE (op0));
 
   /* At which point we can try some of the same things as for indirects.  */
-  t = maybe_fold_offset_to_array_ref (loc, op0, op1, ptd_type, true);
-  if (!t)
-    t = maybe_fold_offset_to_component_ref (loc, TREE_TYPE (op0), op0, op1,
-					    ptd_type);
+  t = maybe_fold_offset_to_array_ref (loc, op0, op1);
   if (t)
     {
-      t = build1 (ADDR_EXPR, res_type, t);
+      t = build_fold_addr_expr (t);
+      if (!useless_type_conversion_p (res_type, TREE_TYPE (t)))
+	return NULL_TREE;
       SET_EXPR_LOCATION (t, loc);
     }
 
@@ -759,19 +486,39 @@  maybe_fold_reference (tree expr, bool is
   while (handled_component_p (*t))
     t = &TREE_OPERAND (*t, 0);
 
-  if (TREE_CODE (*t) == INDIRECT_REF)
-    {
-      tree tem = maybe_fold_stmt_indirect (*t, TREE_OPERAND (*t, 0),
-					   integer_zero_node);
-      /* Avoid folding *"abc" = 5 into 'a' = 5.  */
-      if (is_lhs && tem && CONSTANT_CLASS_P (tem))
-	tem = NULL_TREE;
-      if (!tem
-	  && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR)
-	/* If we had a good reason for propagating the address here,
-	   make sure we end up with valid gimple.  See PR34989.  */
-	tem = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
-
+  /* Fold back MEM_REFs to reference trees.  */
+  if (TREE_CODE (*t) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
+      && integer_zerop (TREE_OPERAND (*t, 1))
+      && (TREE_THIS_VOLATILE (*t)
+	  == TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)))
+      && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*t, 1)))
+      && (TYPE_MAIN_VARIANT (TREE_TYPE (*t))
+	  == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (*t, 1)))))
+      /* We have to look out here to not drop a required conversion
+	 from the rhs to the lhs if is_lhs, but we don't have the
+	 rhs here to verify that.  Thus require strict type
+	 compatibility.  */
+      && types_compatible_p (TREE_TYPE (*t),
+			     TREE_TYPE (TREE_OPERAND
+					  (TREE_OPERAND (*t, 0), 0))))
+    {
+      tree tem;
+      *t = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
+      tem = maybe_fold_reference (expr, is_lhs);
+      if (tem)
+	return tem;
+      return expr;
+    }
+  /* Canonicalize MEM_REFs invariant address operand.  */
+  else if (TREE_CODE (*t) == MEM_REF
+	   && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
+	   && !DECL_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0))
+	   && !CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)))
+    {
+      tree tem = fold_binary (MEM_REF, TREE_TYPE (*t),
+			      TREE_OPERAND (*t, 0),
+			      TREE_OPERAND (*t, 1));
       if (tem)
 	{
 	  *t = tem;
@@ -863,10 +610,18 @@  fold_gimple_assign (gimple_stmt_iterator
 
 	else if (TREE_CODE (rhs) == ADDR_EXPR)
 	  {
-	    tree tem = maybe_fold_reference (TREE_OPERAND (rhs, 0), true);
-	    if (tem)
+	    tree ref = TREE_OPERAND (rhs, 0);
+	    tree tem = maybe_fold_reference (ref, true);
+	    if (tem
+		&& TREE_CODE (tem) == MEM_REF
+		&& integer_zerop (TREE_OPERAND (tem, 1)))
+	      result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (tem, 0));
+	    else if (tem)
 	      result = fold_convert (TREE_TYPE (rhs),
 				     build_fold_addr_expr_loc (loc, tem));
+	    else if (TREE_CODE (ref) == MEM_REF
+		     && integer_zerop (TREE_OPERAND (ref, 1)))
+	      result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (ref, 0));
 	  }
 
 	else if (TREE_CODE (rhs) == CONSTRUCTOR
@@ -1504,7 +1259,7 @@  gimple_get_relevant_ref_binfo (tree ref,
 	return TYPE_BINFO (TREE_TYPE (ref));
       else if (known_binfo
 	       && (TREE_CODE (ref) == SSA_NAME
-		   || TREE_CODE (ref) == INDIRECT_REF))
+		   || TREE_CODE (ref) == MEM_REF))
 	return known_binfo;
       else
 	return NULL_TREE;
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(.../trunk)	(revision 161367)
+++ gcc/cfgexpand.c	(.../branches/mem-ref2)	(revision 161369)
@@ -2438,6 +2438,11 @@  expand_debug_expr (tree exp)
 	return op0;
       }
 
+    case MEM_REF:
+      /* ??? FIXME.  */
+      if (!integer_zerop (TREE_OPERAND (exp, 1)))
+	return NULL;
+      /* Fallthru.  */
     case INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
     case MISALIGNED_INDIRECT_REF:
@@ -2499,10 +2504,31 @@  expand_debug_expr (tree exp)
 	HOST_WIDE_INT bitsize, bitpos;
 	tree offset;
 	int volatilep = 0;
-	tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-					&mode1, &unsignedp, &volatilep, false);
+	tree *tp = &exp;
+	tree tem;
 	rtx orig_op0;
 
+	/* First fold un-folded results from CCP.  */
+	do
+	  {
+	    while (handled_component_p (*tp))
+	      tp = &TREE_OPERAND (*tp, 0);
+	    if (TREE_CODE (*tp) == MEM_REF)
+	      {
+		tem = fold_binary (MEM_REF, TREE_TYPE (*tp),
+				   TREE_OPERAND (*tp, 0),
+				   TREE_OPERAND (*tp, 1));
+		if (!tem)
+		  break;
+		*tp = tem;
+	      }
+	    else
+	      break;
+	  }
+	while (1);
+
+	tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+				   &mode1, &unsignedp, &volatilep, false);
 	if (bitsize == 0)
 	  return NULL;
 
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c	(.../trunk)	(revision 161367)
+++ gcc/tree-ssa.c	(.../branches/mem-ref2)	(revision 161369)
@@ -1204,6 +1204,12 @@  useless_type_conversion_p (tree outer_ty
 	  != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
 	return false;
 
+      /* Do not lose casts to restrict qualified pointers.  */
+      if ((TYPE_RESTRICT (outer_type)
+	   != TYPE_RESTRICT (inner_type))
+	  && TYPE_RESTRICT (outer_type))
+	return false;
+
       /* If the outer type is (void *) or a pointer to an incomplete
 	 record type or a pointer to an unprototyped function,
 	 then the conversion is not necessary.  */
@@ -1216,12 +1222,6 @@  useless_type_conversion_p (tree outer_ty
 	      && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (outer_type)),
 					    TREE_TYPE (TREE_TYPE (inner_type)))))
 	return true;
-
-      /* Do not lose casts to restrict qualified pointers.  */
-      if ((TYPE_RESTRICT (outer_type)
-	   != TYPE_RESTRICT (inner_type))
-	  && TYPE_RESTRICT (outer_type))
-	return false;
     }
 
   /* From now on qualifiers on value types do not matter.  */
@@ -1273,41 +1273,18 @@  useless_type_conversion_p (tree outer_ty
   else if (POINTER_TYPE_P (inner_type)
 	   && POINTER_TYPE_P (outer_type))
     {
-      /* Don't lose casts between pointers to volatile and non-volatile
-	 qualified types.  Doing so would result in changing the semantics
-	 of later accesses.  For function types the volatile qualifier
-	 is used to indicate noreturn functions.  */
-      if (TREE_CODE (TREE_TYPE (outer_type)) != FUNCTION_TYPE
-	  && TREE_CODE (TREE_TYPE (outer_type)) != METHOD_TYPE
-	  && TREE_CODE (TREE_TYPE (inner_type)) != FUNCTION_TYPE
-	  && TREE_CODE (TREE_TYPE (inner_type)) != METHOD_TYPE
-	  && (TYPE_VOLATILE (TREE_TYPE (outer_type))
-	      != TYPE_VOLATILE (TREE_TYPE (inner_type)))
-	  && TYPE_VOLATILE (TREE_TYPE (outer_type)))
-	return false;
-
-      /* We require explicit conversions from incomplete target types.  */
-      if (!COMPLETE_TYPE_P (TREE_TYPE (inner_type))
-	  && COMPLETE_TYPE_P (TREE_TYPE (outer_type)))
-	return false;
-
-      /* Do not lose casts between pointers that when dereferenced access
-	 memory with different alias sets.  */
-      if (get_deref_alias_set (inner_type) != get_deref_alias_set (outer_type))
+      /* Do not lose casts to function pointer types.  */
+      if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
+	   || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
+	  && !useless_type_conversion_p (TREE_TYPE (outer_type),
+					 TREE_TYPE (inner_type)))
 	return false;
 
       /* We do not care for const qualification of the pointed-to types
 	 as const qualification has no semantic value to the middle-end.  */
 
-      /* Otherwise pointers/references are equivalent if their pointed
-	 to types are effectively the same.  We can strip qualifiers
-	 on pointed-to types for further comparison, which is done in
-	 the callee.  Note we have to use true compatibility here
-	 because addresses are subject to propagation into dereferences
-	 and thus might get the original type exposed which is equivalent
-	 to a reverse conversion.  */
-      return types_compatible_p (TREE_TYPE (outer_type),
-				 TREE_TYPE (inner_type));
+      /* Otherwise pointers/references are equivalent.  */
+      return true;
     }
 
   /* Recurse for complex types.  */
@@ -1673,8 +1650,9 @@  warn_uninitialized_var (tree *tp, int *w
   /* We do not care about LHS.  */
   if (wi->is_lhs)
     {
-      /* Except for operands of INDIRECT_REF.  */
-      if (!INDIRECT_REF_P (t))
+      /* Except for operands of dereferences.  */
+      if (!INDIRECT_REF_P (t)
+	  && TREE_CODE (t) != MEM_REF)
 	return NULL_TREE;
       t = TREE_OPERAND (t, 0);
     }
@@ -1822,6 +1800,34 @@  struct gimple_opt_pass pass_early_warn_u
  }
 };
 
+
+/* If necessary, rewrite the base of the reference tree *TP from
+   a MEM_REF to a plain or converted symbol.  */
+
+static void
+maybe_rewrite_mem_ref_base (tree *tp)
+{
+  tree sym;
+
+  while (handled_component_p (*tp))
+    tp = &TREE_OPERAND (*tp, 0);
+  if (TREE_CODE (*tp) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (*tp, 0)) == ADDR_EXPR
+      && integer_zerop (TREE_OPERAND (*tp, 1))
+      && (sym = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0))
+      && DECL_P (sym)
+      && !TREE_ADDRESSABLE (sym)
+      && symbol_marked_for_renaming (sym))
+    {
+      if (!useless_type_conversion_p (TREE_TYPE (*tp),
+				      TREE_TYPE (sym)))
+	*tp = build1 (VIEW_CONVERT_EXPR,
+			TREE_TYPE (*tp), sym);
+      else
+	*tp = sym;
+    }
+}
+
 /* Compute TREE_ADDRESSABLE and DECL_GIMPLE_REG_P for local variables.  */
 
 void
@@ -1853,17 +1859,50 @@  execute_update_addresses_taken (bool do_
 	    {
               tree lhs = gimple_get_lhs (stmt);
 
-              /* We may not rewrite TMR_SYMBOL to SSA.  */
-              if (lhs && TREE_CODE (lhs) == TARGET_MEM_REF
-                  && TMR_SYMBOL (lhs))
-                bitmap_set_bit (not_reg_needs, DECL_UID (TMR_SYMBOL (lhs)));
+              /* A plain decl does not need it set.  */
+              if (lhs && !DECL_P (lhs))
+		{
+		  if (handled_component_p (lhs))
+		    lhs = get_base_address (lhs);
+
+                  if (DECL_P (lhs))
+                    bitmap_set_bit (not_reg_needs, DECL_UID (lhs));
+		  else if (TREE_CODE (lhs) == MEM_REF
+			   && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR)
+		    {
+		      tree decl = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0);
+		      if (DECL_P (decl)
+			  && (!integer_zerop (TREE_OPERAND (lhs, 1))
+			      || (DECL_SIZE (decl)
+				  != TYPE_SIZE (TREE_TYPE (lhs)))))
+			bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+		    }
+                }
+	    }
+
+	  if (gimple_assign_single_p (stmt))
+	    {
+	      tree rhs = gimple_assign_rhs1 (stmt);
 
               /* A plain decl does not need it set.  */
-              else if (lhs && handled_component_p (lhs))
-                {
-                  var = get_base_address (lhs);
-                  if (DECL_P (var))
-                    bitmap_set_bit (not_reg_needs, DECL_UID (var));
+              if (!DECL_P (rhs))
+		{
+		  tree base = rhs;
+		  while (handled_component_p (base))
+		    base = TREE_OPERAND (base, 0);
+
+		  /* But watch out for MEM_REFs we cannot lower to a
+		     VIEW_CONVERT_EXPR.  */
+		  if (TREE_CODE (base) == MEM_REF
+		      && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
+		    {
+		      tree decl = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
+		      if (DECL_P (decl)
+			  && (!integer_zerop (TREE_OPERAND (base, 1))
+			      || (DECL_SIZE (decl)
+				  != TYPE_SIZE (TREE_TYPE (base)))))
+			bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+		    }
                 }
 	    }
 	}
@@ -1937,14 +1976,73 @@  execute_update_addresses_taken (bool do_
   if (update_vops)
     {
       FOR_EACH_BB (bb)
-	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-	    {
-	      gimple stmt = gsi_stmt (gsi);
+	for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	  {
+	    gimple stmt = gsi_stmt (gsi);
 
-	      if (gimple_references_memory_p (stmt)
-		  || is_gimple_debug (stmt))
-		update_stmt (stmt);
-	    }
+	    /* Re-write TARGET_MEM_REFs of symbols we want to
+	       rewrite into SSA form.  */
+	    if (gimple_assign_single_p (stmt))
+	      {
+		tree lhs = gimple_assign_lhs (stmt);
+		tree rhs, *rhsp = gimple_assign_rhs1_ptr (stmt);
+		tree sym;
+
+		/* We shouldn't have any fancy wrapping of
+		   component-refs on the LHS, but look through
+		   VIEW_CONVERT_EXPRs as that is easy.  */
+		while (TREE_CODE (lhs) == VIEW_CONVERT_EXPR)
+		  lhs = TREE_OPERAND (lhs, 0);
+		if (TREE_CODE (lhs) == MEM_REF
+		    && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR
+		    && integer_zerop (TREE_OPERAND (lhs, 1))
+		    && (sym = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0))
+		    && DECL_P (sym)
+		    && !TREE_ADDRESSABLE (sym)
+		    && symbol_marked_for_renaming (sym))
+		  lhs = sym;
+		else
+		  lhs = gimple_assign_lhs (stmt);
+
+		/* Rewrite the RHS and make sure the resulting assignment
+		   is validly typed.  */
+		maybe_rewrite_mem_ref_base (rhsp);
+		rhs = gimple_assign_rhs1 (stmt);
+		if (gimple_assign_lhs (stmt) != lhs
+		    && !useless_type_conversion_p (TREE_TYPE (lhs),
+						   TREE_TYPE (rhs)))
+		  rhs = fold_build1 (VIEW_CONVERT_EXPR,
+				     TREE_TYPE (lhs), rhs);
+
+		if (gimple_assign_lhs (stmt) != lhs)
+		  gimple_assign_set_lhs (stmt, lhs);
+
+		if (gimple_assign_rhs1 (stmt) != rhs)
+		  {
+		    gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+		    gimple_assign_set_rhs_from_tree (&gsi, rhs);
+		  }
+	      }
+
+	    if (gimple_code (stmt) == GIMPLE_ASM)
+	      {
+		unsigned i;
+		for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+		  {
+		    tree link = gimple_asm_output_op (stmt, i);
+		    maybe_rewrite_mem_ref_base (&TREE_VALUE (link));
+		  }
+		for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+		  {
+		    tree link = gimple_asm_input_op (stmt, i);
+		    maybe_rewrite_mem_ref_base (&TREE_VALUE (link));
+		  }
+	      }
+
+	    if (gimple_references_memory_p (stmt)
+		|| is_gimple_debug (stmt))
+	      update_stmt (stmt);
+	  }
 
       /* Update SSA form here, we are called as non-pass as well.  */
       update_ssa (TODO_update_ssa);
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c	(.../trunk)	(revision 161367)
+++ gcc/tree-inline.c	(.../branches/mem-ref2)	(revision 161369)
@@ -810,48 +810,49 @@  remap_gimple_op_r (tree *tp, int *walk_s
     {
       /* Otherwise, just copy the node.  Note that copy_tree_r already
 	 knows not to copy VAR_DECLs, etc., so this is safe.  */
-      if (TREE_CODE (*tp) == INDIRECT_REF)
+      if (TREE_CODE (*tp) == MEM_REF)
 	{
-	  /* Get rid of *& from inline substitutions that can happen when a
-	     pointer argument is an ADDR_EXPR.  */
+	  /* We need to re-canonicalize MEM_REFs from inline substitutions
+	     that can happen when a pointer argument is an ADDR_EXPR.  */
 	  tree decl = TREE_OPERAND (*tp, 0);
 	  tree *n;
 
 	  n = (tree *) pointer_map_contains (id->decl_map, decl);
 	  if (n)
 	    {
-	      tree type, new_tree, old;
-
-	      /* If we happen to get an ADDR_EXPR in n->value, strip
-		 it manually here as we'll eventually get ADDR_EXPRs
-		 which lie about their types pointed to.  In this case
-		 build_fold_indirect_ref wouldn't strip the
-		 INDIRECT_REF, but we absolutely rely on that.  As
-		 fold_indirect_ref does other useful transformations,
-		 try that first, though.  */
-	      type = TREE_TYPE (TREE_TYPE (*n));
-	      new_tree = unshare_expr (*n);
-	      old = *tp;
-	      *tp = gimple_fold_indirect_ref (new_tree);
-	      if (!*tp)
-	        {
-		  if (TREE_CODE (new_tree) == ADDR_EXPR)
-		    {
-		      *tp = fold_indirect_ref_1 (EXPR_LOCATION (new_tree),
-						 type, new_tree);
-		      /* ???  We should either assert here or build
-			 a VIEW_CONVERT_EXPR instead of blindly leaking
-			 incompatible types to our IL.  */
-		      if (! *tp)
-			*tp = TREE_OPERAND (new_tree, 0);
-		    }
-	          else
-		    {
-	              *tp = build1 (INDIRECT_REF, type, new_tree);
-		      TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
-		      TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
-		    }
+	      tree old = *tp;
+	      tree ptr = unshare_expr (*n);
+	      tree tem;
+	      if ((tem = maybe_fold_offset_to_reference (EXPR_LOCATION (*tp),
+							 ptr,
+							 TREE_OPERAND (*tp, 1),
+							 TREE_TYPE (*tp)))
+		  && TREE_THIS_VOLATILE (tem) == TREE_THIS_VOLATILE (old))
+		{
+		  tree *tem_basep = &tem;
+		  while (handled_component_p (*tem_basep))
+		    tem_basep = &TREE_OPERAND (*tem_basep, 0);
+		  if (TREE_CODE (*tem_basep) == MEM_REF)
+		    *tem_basep
+		      = build2 (MEM_REF, TREE_TYPE (*tem_basep),
+				TREE_OPERAND (*tem_basep, 0),
+				fold_convert (TREE_TYPE (TREE_OPERAND (*tp, 1)),
+					      TREE_OPERAND (*tem_basep, 1)));
+		  else
+		    *tem_basep
+		      = build2 (MEM_REF, TREE_TYPE (*tem_basep),
+				build_fold_addr_expr (*tem_basep),
+				build_int_cst
+				  (TREE_TYPE (TREE_OPERAND (*tp, 1)), 0));
+		  *tp = tem;
+		}
+	      else
+		{
+		  *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
+				     ptr, TREE_OPERAND (*tp, 1));
+		  TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
 		}
+	      TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
 	      *walk_subtrees = 0;
 	      return NULL;
 	    }
@@ -886,7 +887,7 @@  remap_gimple_op_r (tree *tp, int *walk_s
       else if (TREE_CODE (*tp) == ADDR_EXPR)
 	{
 	  /* Variable substitution need not be simple.  In particular,
-	     the INDIRECT_REF substitution above.  Make sure that
+	     the MEM_REF substitution above.  Make sure that
 	     TREE_CONSTANT and friends are up-to-date.  But make sure
 	     to not improperly set TREE_BLOCK on some sub-expressions.  */
 	  int invariant = is_gimple_min_invariant (*tp);
@@ -894,13 +895,7 @@  remap_gimple_op_r (tree *tp, int *walk_s
 	  id->block = NULL_TREE;
 	  walk_tree (&TREE_OPERAND (*tp, 0), remap_gimple_op_r, data, NULL);
 	  id->block = block;
-
-	  /* Handle the case where we substituted an INDIRECT_REF
-	     into the operand of the ADDR_EXPR.  */
-	  if (TREE_CODE (TREE_OPERAND (*tp, 0)) == INDIRECT_REF)
-	    *tp = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0);
-	  else
-	    recompute_tree_invariant_for_addr_expr (*tp);
+	  recompute_tree_invariant_for_addr_expr (*tp);
 
 	  /* If this used to be invariant, but is not any longer,
 	     then regimplification is probably needed.  */
@@ -1090,6 +1085,25 @@  copy_tree_body_r (tree *tp, int *walk_su
 	      *walk_subtrees = 0;
 	      return NULL;
 	    }
+	}
+      else if (TREE_CODE (*tp) == MEM_REF)
+	{
+	  /* We need to re-canonicalize MEM_REFs from inline substitutions
+	     that can happen when a pointer argument is an ADDR_EXPR.  */
+	  tree decl = TREE_OPERAND (*tp, 0);
+	  tree *n;
+
+	  n = (tree *) pointer_map_contains (id->decl_map, decl);
+	  if (n)
+	    {
+	      tree old = *tp;
+	      *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
+				 unshare_expr (*n), TREE_OPERAND (*tp, 1));
+	      TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
+	      TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+	      *walk_subtrees = 0;
+	      return NULL;
+	    }
 	}
 
       /* Here is the "usual case".  Copy this tree node, and then
Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c	(.../trunk)	(revision 161367)
+++ gcc/gimple.c	(.../branches/mem-ref2)	(revision 161369)
@@ -2595,7 +2595,8 @@  is_gimple_condexpr (tree t)
 bool
 is_gimple_addressable (tree t)
 {
-  return (is_gimple_id (t) || handled_component_p (t) || INDIRECT_REF_P (t));
+  return (is_gimple_id (t) || handled_component_p (t)
+	  || TREE_CODE (t) == MEM_REF);
 }
 
 /* Return true if T is a valid gimple constant.  */
@@ -2646,7 +2647,7 @@  is_gimple_address (const_tree t)
       op = TREE_OPERAND (op, 0);
     }
 
-  if (CONSTANT_CLASS_P (op) || INDIRECT_REF_P (op))
+  if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
     return true;
 
   switch (TREE_CODE (op))
@@ -2706,8 +2707,18 @@  is_gimple_invariant_address (const_tree
     return false;
 
   op = strip_invariant_refs (TREE_OPERAND (t, 0));
+  if (!op)
+    return false;
 
-  return op && (CONSTANT_CLASS_P (op) || decl_address_invariant_p (op));
+  if (TREE_CODE (op) == MEM_REF)
+    {
+      const_tree op0 = TREE_OPERAND (op, 0);
+      return (TREE_CODE (op0) == ADDR_EXPR
+	      && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
+		  || decl_address_invariant_p (TREE_OPERAND (op0, 0))));
+    }
+
+  return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
 }
 
 /* Return true if T is a gimple invariant address at IPA level
@@ -2924,7 +2935,7 @@  is_gimple_min_lval (tree t)
 {
   if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
     return false;
-  return (is_gimple_id (t) || TREE_CODE (t) == INDIRECT_REF);
+  return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
 }
 
 /* Return true if T is a typecast operation.  */
@@ -2944,6 +2955,18 @@  is_gimple_call_addr (tree t)
   return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
 }
 
+/* Return true if T is a valid address operand of a MEM_REF.  */
+
+bool
+is_gimple_mem_ref_addr (tree t)
+{
+  return (is_gimple_reg (t)
+	  || TREE_CODE (t) == INTEGER_CST
+	  || (TREE_CODE (t) == ADDR_EXPR
+	      && (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
+		  || decl_address_invariant_p (TREE_OPERAND (t, 0)))));
+}
+
 /* If T makes a function call, return the corresponding CALL_EXPR operand.
    Otherwise, return NULL_TREE.  */
 
@@ -2975,10 +2998,15 @@  get_base_address (tree t)
   while (handled_component_p (t))
     t = TREE_OPERAND (t, 0);
 
+  if (TREE_CODE (t) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
+    t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+
   if (SSA_VAR_P (t)
       || TREE_CODE (t) == STRING_CST
       || TREE_CODE (t) == CONSTRUCTOR
-      || INDIRECT_REF_P (t))
+      || INDIRECT_REF_P (t)
+      || TREE_CODE (t) == MEM_REF)
     return t;
   else
     return NULL_TREE;
@@ -4418,7 +4446,7 @@  count_ptr_derefs (tree *tp, int *walk_su
       return NULL_TREE;
     }
 
-  if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
+  if (TREE_CODE (*tp) == MEM_REF && TREE_OPERAND (*tp, 0) == count_p->ptr)
     {
       if (wi_p->is_lhs)
 	count_p->num_stores++;
@@ -4491,6 +4519,7 @@  get_base_loadstore (tree op)
     op = TREE_OPERAND (op, 0);
   if (DECL_P (op)
       || INDIRECT_REF_P (op)
+      || TREE_CODE (op) == MEM_REF
       || TREE_CODE (op) == TARGET_MEM_REF)
     return op;
   return NULL_TREE;
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(.../trunk)	(revision 161367)
+++ gcc/gimple.h	(.../branches/mem-ref2)	(revision 161369)
@@ -933,6 +933,8 @@  extern bool is_gimple_ip_invariant (cons
 extern bool is_gimple_val (tree);
 /* Returns true iff T is a GIMPLE asm statement input.  */
 extern bool is_gimple_asm_val (tree);
+/* Returns true iff T is a valid address operand of a MEM_REF.  */
+bool is_gimple_mem_ref_addr (tree);
 /* Returns true iff T is a valid rhs for a MODIFY_EXPR where the LHS is a
    GIMPLE temporary, a renamed user variable, or something else,
    respectively.  */
@@ -2037,7 +2039,18 @@  gimple_call_fndecl (const_gimple gs)
 {
   tree addr = gimple_call_fn (gs);
   if (TREE_CODE (addr) == ADDR_EXPR)
-    return TREE_OPERAND (addr, 0);
+    {
+      tree fndecl = TREE_OPERAND (addr, 0);
+      if (TREE_CODE (fndecl) == MEM_REF)
+	{
+	  if (TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
+	      && integer_zerop (TREE_OPERAND (fndecl, 1)))
+	    return TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
+	  else
+	    return NULL_TREE;
+	}
+      return TREE_OPERAND (addr, 0);
+    }
   return NULL_TREE;
 }
 
@@ -4857,8 +4870,8 @@  void gimplify_and_update_call_from_tree
 tree gimple_fold_builtin (gimple);
 bool fold_stmt (gimple_stmt_iterator *);
 bool fold_stmt_inplace (gimple);
-tree maybe_fold_offset_to_reference (location_t, tree, tree, tree);
 tree maybe_fold_offset_to_address (location_t, tree, tree, tree);
+tree maybe_fold_offset_to_reference (location_t, tree, tree, tree);
 tree maybe_fold_stmt_addition (location_t, tree, tree, tree);
 tree get_symbol_constant_value (tree);
 bool may_propagate_address_into_dereference (tree, tree);
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(.../trunk)	(revision 161367)
+++ gcc/tree-cfg.c	(.../branches/mem-ref2)	(revision 161369)
@@ -2569,6 +2569,22 @@  verify_expr (tree *tp, int *walk_subtree
 	}
       break;
 
+    case MEM_REF:
+      x = TREE_OPERAND (t, 0);
+      if (!is_gimple_reg (x) && !is_gimple_min_invariant (x))
+	{
+	  error ("MEM_REFs operand is not a register or a constant.");
+	  return x;
+	}
+      if (TREE_CODE (x) == ADDR_EXPR
+	  && !DECL_P (TREE_OPERAND (x, 0))
+	  && !CONSTANT_CLASS_P (TREE_OPERAND (x, 0)))
+	{
+	  error ("Invalid address operand of MEM_REF.");
+	  return x;
+	}
+      break;
+
     case ASSERT_EXPR:
       x = fold (ASSERT_EXPR_COND (t));
       if (x == boolean_false_node)
@@ -2621,11 +2637,14 @@  verify_expr (tree *tp, int *walk_subtree
 	      || TREE_CODE (x) == PARM_DECL
 	      || TREE_CODE (x) == RESULT_DECL))
 	  return NULL;
+#if 0
+	/* FIXME.  */
 	if (!TREE_ADDRESSABLE (x))
 	  {
 	    error ("address taken, but ADDRESSABLE bit not set");
 	    return x;
 	  }
+#endif
 	if (DECL_GIMPLE_REG_P (x))
 	  {
 	    error ("DECL_GIMPLE_REG_P set on a variable with address taken");
@@ -2815,8 +2834,10 @@  verify_types_in_gimple_min_lval (tree ex
   if (is_gimple_id (expr))
     return false;
 
-  if (!INDIRECT_REF_P (expr)
-      && TREE_CODE (expr) != TARGET_MEM_REF)
+  if (TREE_CODE (expr) != ALIGN_INDIRECT_REF
+      && TREE_CODE (expr) != MISALIGNED_INDIRECT_REF
+      && TREE_CODE (expr) != TARGET_MEM_REF
+      && TREE_CODE (expr) != MEM_REF)
     {
       error ("invalid expression for min lvalue");
       return true;
@@ -2833,6 +2854,7 @@  verify_types_in_gimple_min_lval (tree ex
       debug_generic_stmt (op);
       return true;
     }
+#if 0
   if (!useless_type_conversion_p (TREE_TYPE (expr),
 				  TREE_TYPE (TREE_TYPE (op))))
     {
@@ -2841,6 +2863,7 @@  verify_types_in_gimple_min_lval (tree ex
       debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
       return true;
     }
+#endif
 
   return false;
 }
@@ -2927,6 +2950,13 @@  verify_types_in_gimple_reference (tree e
 	      debug_generic_stmt (expr);
 	      return true;
 	    }
+	  else if (TREE_CODE (op) == SSA_NAME
+		   && TYPE_SIZE (TREE_TYPE (expr)) != TYPE_SIZE (TREE_TYPE (op)))
+	    {
+	      error ("Conversion of register to a different size.");
+	      debug_generic_stmt (expr);
+	      return true;
+	    }
 	  else if (!handled_component_p (op))
 	    return false;
 	}
@@ -2934,6 +2964,27 @@  verify_types_in_gimple_reference (tree e
       expr = op;
     }
 
+  if (TREE_CODE (expr) == MEM_REF)
+    {
+      if (!is_gimple_val (TREE_OPERAND (expr, 0))
+	  || TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST
+	  || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))))
+	{
+	  error ("Invalid operands in MEM_REF.");
+	  debug_generic_stmt (expr);
+	  return true;
+	}
+      if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
+	  && !DECL_P (TREE_OPERAND (TREE_OPERAND (expr, 0), 0))
+	  /* ???  FIXME.  We should always fold these.  */
+	  && !CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)))
+	{
+	  error ("Invalid address operand for MEM_REF.");
+	  debug_generic_stmt (expr);
+	  return true;
+	}
+    }
+
   return ((require_lvalue || !is_gimple_min_invariant (expr))
 	  && verify_types_in_gimple_min_lval (expr));
 }
@@ -3642,9 +3693,12 @@  verify_gimple_assign_single (gimple stmt
       }
 
     /* tcc_reference  */
+    case INDIRECT_REF:
+      error ("INDIRECT_REF in gimple IL");
+      return true;
+
     case COMPONENT_REF:
     case BIT_FIELD_REF:
-    case INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
     case MISALIGNED_INDIRECT_REF:
     case ARRAY_REF:
@@ -3653,6 +3707,7 @@  verify_gimple_assign_single (gimple stmt
     case REALPART_EXPR:
     case IMAGPART_EXPR:
     case TARGET_MEM_REF:
+    case MEM_REF:
       if (!is_gimple_reg (lhs)
 	  && is_gimple_reg_type (TREE_TYPE (lhs)))
 	{
Index: gcc/tree-ssa-operands.c
===================================================================
--- gcc/tree-ssa-operands.c	(.../trunk)	(revision 161367)
+++ gcc/tree-ssa-operands.c	(.../branches/mem-ref2)	(revision 161369)
@@ -127,6 +127,12 @@  static struct
    clobbering sites like function calls or ASM_EXPRs.  */
 #define opf_implicit	(1 << 2)
 
+/* Operand is in a place where address-taken does not imply addressable.  */
+#define opf_non_addressable (1 << 3)
+
+/* Operand is in a place where opf_non_addressable does not apply.  */
+#define opf_not_non_addressable (1 << 4)
+
 /* Array for building all the def operands.  */
 static VEC(tree,heap) *build_defs;
 
@@ -693,15 +699,22 @@  mark_address_taken (tree ref)
      be referenced using pointer arithmetic.  See PR 21407 and the
      ensuing mailing list discussion.  */
   var = get_base_address (ref);
-  if (var && DECL_P (var))
-    TREE_ADDRESSABLE (var) = 1;
+  if (var)
+    {
+      if (DECL_P (var))
+	TREE_ADDRESSABLE (var) = 1;
+      else if (TREE_CODE (var) == MEM_REF
+	       && TREE_CODE (TREE_OPERAND (var, 0)) == ADDR_EXPR
+	       && DECL_P (TREE_OPERAND (TREE_OPERAND (var, 0), 0)))
+	TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (var, 0), 0)) = 1;
+    }
 }
 
 
-/* A subroutine of get_expr_operands to handle INDIRECT_REF,
+/* A subroutine of get_expr_operands to handle MEM_REF,
    ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF.
 
-   STMT is the statement being processed, EXPR is the INDIRECT_REF
+   STMT is the statement being processed, EXPR is the MEM_REF
       that got us here.
 
    FLAGS is as in get_expr_operands.
@@ -725,7 +738,8 @@  get_indirect_ref_operands (gimple stmt,
   /* If requested, add a USE operand for the base pointer.  */
   if (recurse_on_base)
     get_expr_operands (stmt, pptr,
-		       opf_use | (flags & opf_no_vops));
+		       opf_non_addressable | opf_use
+		       | (flags & (opf_no_vops|opf_not_non_addressable)));
 }
 
 
@@ -802,7 +816,7 @@  get_asm_expr_operands (gimple stmt)
       if (!allows_reg && allows_mem)
 	mark_address_taken (TREE_VALUE (link));
 
-      get_expr_operands (stmt, &TREE_VALUE (link), opf_def);
+      get_expr_operands (stmt, &TREE_VALUE (link), opf_def | opf_not_non_addressable);
     }
 
   /* Gather all input operands.  */
@@ -818,7 +832,7 @@  get_asm_expr_operands (gimple stmt)
       if (!allows_reg && allows_mem)
 	mark_address_taken (TREE_VALUE (link));
 
-      get_expr_operands (stmt, &TREE_VALUE (link), 0);
+      get_expr_operands (stmt, &TREE_VALUE (link), opf_not_non_addressable);
     }
 
   /* Clobber all memory and addressable symbols for asm ("" : : : "memory");  */
@@ -862,7 +876,9 @@  get_expr_operands (gimple stmt, tree *ex
 	 reference to it, but the fact that the statement takes its
 	 address will be of interest to some passes (e.g. alias
 	 resolution).  */
-      if (!is_gimple_debug (stmt))
+      if ((!(flags & opf_non_addressable)
+	   || (flags & opf_not_non_addressable))
+	  && !is_gimple_debug (stmt))
 	mark_address_taken (TREE_OPERAND (expr, 0));
 
       /* If the address is invariant, there may be no interesting
@@ -876,7 +892,8 @@  get_expr_operands (gimple stmt, tree *ex
 	 here are ARRAY_REF indices which will always be real operands
 	 (GIMPLE does not allow non-registers as array indices).  */
       flags |= opf_no_vops;
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 0),
+			 flags | opf_not_non_addressable);
       return;
 
     case SSA_NAME:
@@ -898,7 +915,7 @@  get_expr_operands (gimple stmt, tree *ex
       /* fall through */
 
     case ALIGN_INDIRECT_REF:
-    case INDIRECT_REF:
+    case MEM_REF:
       get_indirect_ref_operands (stmt, expr, flags, true);
       return;