Index: expr.c
===================================================================
--- expr.c	(revision 191198)
+++ expr.c	(working copy)
@@ -4870,8 +4870,16 @@ expand_assignment (tree to, tree from, b
       /* Handle calls that return values in multiple non-contiguous locations.
 	 The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
-	emit_group_load (to_rtx, value, TREE_TYPE (from),
-			 int_size_in_bytes (TREE_TYPE (from)));
+	{
+	  if (GET_CODE (value) == PARALLEL)
+	    emit_group_move (to_rtx, value);
+	  else
+	    emit_group_load (to_rtx, value, TREE_TYPE (from),
+			     int_size_in_bytes (TREE_TYPE (from)));
+	}
+      else if (GET_CODE (value) == PARALLEL)
+	emit_group_store (to_rtx, value, TREE_TYPE (from),
+			  int_size_in_bytes (TREE_TYPE (from)));
       else if (GET_MODE (to_rtx) == BLKmode)
 	emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
       else
@@ -4903,9 +4911,16 @@ expand_assignment (tree to, tree from, b
       else
 	temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
 
+      /* Handle calls that return values in multiple non-contiguous locations.
+	 The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
-	emit_group_load (to_rtx, temp, TREE_TYPE (from),
-			 int_size_in_bytes (TREE_TYPE (from)));
+	{
+	  if (GET_CODE (temp) == PARALLEL)
+	    emit_group_move (to_rtx, temp);
+	  else
+	    emit_group_load (to_rtx, temp, TREE_TYPE (from),
+			     int_size_in_bytes (TREE_TYPE (from)));
+	}
       else if (temp)
 	emit_move_insn (to_rtx, temp);
 
@@ -5299,16 +5314,22 @@ store_expr (tree exp, rtx target, int ca
       /* Handle calls that return values in multiple non-contiguous locations.
 	 The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (target) == PARALLEL)
-	emit_group_load (target, temp, TREE_TYPE (exp),
-			 int_size_in_bytes (TREE_TYPE (exp)));
+	{
+	  if (GET_CODE (temp) == PARALLEL)
+	    emit_group_move (target, temp);
+	  else
+	    emit_group_load (target, temp, TREE_TYPE (exp),
+			     int_size_in_bytes (TREE_TYPE (exp)));
+	}
+      else if (GET_CODE (temp) == PARALLEL)
+	emit_group_store (target, temp, TREE_TYPE (exp),
+			  int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
 	emit_block_move (target, temp, expr_size (exp),
 			 (call_param_p
 			  ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
-      else if (nontemporal
-	       && emit_storent_insn (target, temp))
-	/* If we managed to emit a nontemporal store, there is nothing else to
-	   do.  */
+      /* If we emit a nontemporal store, there is nothing else to do.  */
+      else if (nontemporal && emit_storent_insn (target, temp))
 	;
       else
 	{
@@ -6429,10 +6450,18 @@ store_field (rtx target, HOST_WIDE_INT b
 	  return const0_rtx;
 	}
 
-      /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos,
-		       bitregion_start, bitregion_end,
-		       mode, temp);
+      /* Handle calls that return values in multiple non-contiguous locations.
+	 The Irix 6 ABI has examples of this.  */
+      if (bitpos == 0
+	  && bitsize == GET_MODE_BITSIZE (mode)
+	  && GET_CODE (temp) == PARALLEL)
+	emit_group_store (target, temp, TREE_TYPE (exp),
+			  int_size_in_bytes (TREE_TYPE (exp)));
+      else
+	/* Store the value in the bitfield.  */
+	store_bit_field (target, bitsize, bitpos,
+		         bitregion_start, bitregion_end,
+		         mode, temp);
 
       return const0_rtx;
     }
Index: expr.h
===================================================================
--- expr.h	(revision 191198)
+++ expr.h	(working copy)
@@ -557,11 +557,22 @@ extern rtx change_address (rtx, enum mac
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address offset by OFFSET bytes.  */
 #define adjust_address(MEMREF, MODE, OFFSET) \
-  adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1)
+  adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1, 0)
 
 /* Likewise, but the reference is not required to be valid.  */
 #define adjust_address_nv(MEMREF, MODE, OFFSET) \
-  adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1)
+  adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1, 0)
+
+/* Return a memory reference like MEMREF, but with its mode changed
+   to MODE and its address offset by OFFSET bytes.  Assume that it's
+   for a bitfield and conservatively drop the underlying object if we
+   cannot be sure to stay within its bounds.  */
+#define adjust_bitfield_address(MEMREF, MODE, OFFSET) \
+  adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1, 1)
+
+/* Likewise, but the reference is not required to be valid.  */
+#define adjust_bitfield_address_nv(MEMREF, MODE, OFFSET) \
+  adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1, 1)
 
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address changed to ADDR, which is assumed to be
@@ -573,7 +584,8 @@ extern rtx change_address (rtx, enum mac
 #define adjust_automodify_address_nv(MEMREF, MODE, ADDR, OFFSET) \
   adjust_automodify_address_1 (MEMREF, MODE, ADDR, OFFSET, 0)
 
-extern rtx adjust_address_1 (rtx, enum machine_mode, HOST_WIDE_INT, int, int);
+extern rtx adjust_address_1 (rtx, enum machine_mode, HOST_WIDE_INT, int, int,
+			     int);
 extern rtx adjust_automodify_address_1 (rtx, enum machine_mode, rtx,
 					HOST_WIDE_INT, int);
 
Index: dse.c
===================================================================
--- dse.c	(revision 191198)
+++ dse.c	(working copy)
@@ -105,7 +105,7 @@ along with GCC; see the file COPYING3.
    the first pass could examine a block in either direction.  The
    forwards ordering is to accommodate cselib.
 
-   We a simplifying assumption: addresses fall into four broad
+   We make a simplifying assumption: addresses fall into four broad
    categories:
 
    1) base has rtx_varies_p == false, offset is constant.
@@ -114,18 +114,18 @@ along with GCC; see the file COPYING3.
    4) base has rtx_varies_p == true, offset variable.
 
    The local passes are able to process all 4 kinds of addresses.  The
-   global pass only handles (1).
+   global pass only handles 1).
 
    The global problem is formulated as follows:
 
      A store, S1, to address A, where A is not relative to the stack
      frame, can be eliminated if all paths from S1 to the end of the
-     of the function contain another store to A before a read to A.
+     function contain another store to A before a read to A.
 
      If the address A is relative to the stack frame, a store S2 to A
-     can be eliminated if there are no paths from S1 that reach the
+     can be eliminated if there are no paths from S2 that reach the
      end of the function that read A before another store to A.  In
-     this case S2 can be deleted if there are paths to from S2 to the
+     this case S2 can be deleted if there are paths from S2 to the
      end of the function that have no reads or writes to A.  This
      second case allows stores to the stack frame to be deleted that
      would otherwise die when the function returns.  This cannot be
@@ -136,7 +136,7 @@ along with GCC; see the file COPYING3.
      dataflow problem where the stores are the gens and reads are the
      kills.  Set union problems are rare and require some special
      handling given our representation of bitmaps.  A straightforward
-     implementation of requires a lot of bitmaps filled with 1s.
+     implementation requires a lot of bitmaps filled with 1s.
      These are expensive and cumbersome in our bitmap formulation so
      care has been taken to avoid large vectors filled with 1s.  See
      the comments in bb_info and in the dataflow confluence functions
Index: calls.c
===================================================================
--- calls.c	(revision 191198)
+++ calls.c	(working copy)
@@ -3272,16 +3272,8 @@ expand_call (tree exp, rtx target, int i
       else if (GET_CODE (valreg) == PARALLEL)
 	{
 	  if (target == 0)
-	    {
-	      /* This will only be assigned once, so it can be readonly.  */
-	      tree nt = build_qualified_type (rettype,
-					      (TYPE_QUALS (rettype)
-					       | TYPE_QUAL_CONST));
-
-	      target = assign_temp (nt, 1, 1);
-	    }
-
-	  if (! rtx_equal_p (target, valreg))
+	    target = emit_group_move_into_temps (valreg);
+	  else if (!rtx_equal_p (target, valreg))
 	    emit_group_store (target, valreg, rettype,
 			      int_size_in_bytes (rettype));
 
Index: expmed.c
===================================================================
--- expmed.c	(revision 191198)
+++ expmed.c	(working copy)
@@ -500,7 +500,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
 		 && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
     {
       if (MEM_P (op0))
-	op0 = adjust_address (op0, fieldmode, offset);
+	op0 = adjust_bitfield_address (op0, fieldmode, offset);
       else if (GET_MODE (op0) != fieldmode)
 	op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
 				   byte_offset);
@@ -517,7 +517,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
     if (imode != GET_MODE (op0))
       {
 	if (MEM_P (op0))
-	  op0 = adjust_address (op0, imode, 0);
+	  op0 = adjust_bitfield_address (op0, imode, 0);
 	else
 	  {
 	    gcc_assert (imode != BLKmode);
@@ -526,16 +526,6 @@ store_bit_field_1 (rtx str_rtx, unsigned
       }
   }
 
-  /* We may be accessing data outside the field, which means
-     we can alias adjacent data.  */
-  /* ?? not always for C++0x memory model ?? */
-  if (MEM_P (op0))
-    {
-      op0 = shallow_copy_rtx (op0);
-      set_mem_alias_set (op0, 0);
-      set_mem_expr (op0, 0);
-    }
-
   /* If OP0 is a register, BITPOS must count within a word.
      But as we have it, it counts within whatever size OP0 now has.
      On a bigendian machine, these are not the same, so convert.  */
@@ -718,7 +708,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
 
       /* Add OFFSET into OP0's address.  */
       if (MEM_P (xop0))
-	xop0 = adjust_address (xop0, byte_mode, offset);
+	xop0 = adjust_bitfield_address (xop0, byte_mode, offset);
 
       /* If xop0 is a register, we need it in OP_MODE
 	 to make it acceptable to the format of insv.  */
@@ -852,7 +842,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
 	  unit = GET_MODE_BITSIZE (bestmode);
 	  xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
 	  xbitpos = bitnum % unit;
-	  xop0 = adjust_address (op0, bestmode, xoffset);
+	  xop0 = adjust_bitfield_address (op0, bestmode, xoffset);
 
 	  /* Fetch that unit, store the bitfield in it, then store
 	     the unit.  */
@@ -1024,7 +1014,7 @@ store_fixed_bit_field (rtx op0, unsigned
 	 Then alter OP0 to refer to that word.  */
       bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
       offset -= (offset % (total_bits / BITS_PER_UNIT));
-      op0 = adjust_address (op0, mode, offset);
+      op0 = adjust_bitfield_address (op0, mode, offset);
     }
 
   mode = GET_MODE (op0);
@@ -1388,7 +1378,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
     if (imode != GET_MODE (op0))
       {
 	if (MEM_P (op0))
-	  op0 = adjust_address (op0, imode, 0);
+	  op0 = adjust_bitfield_address (op0, imode, 0);
 	else if (imode != BLKmode)
 	  {
 	    op0 = gen_lowpart (imode, op0);
@@ -1414,20 +1404,11 @@ extract_bit_field_1 (rtx str_rtx, unsign
 	    rtx mem = assign_stack_temp (GET_MODE (op0),
 					 GET_MODE_SIZE (GET_MODE (op0)));
 	    emit_move_insn (mem, op0);
-	    op0 = adjust_address (mem, BLKmode, 0);
+	    op0 = adjust_bitfield_address (mem, BLKmode, 0);
 	  }
       }
   }
 
-  /* We may be accessing data outside the field, which means
-     we can alias adjacent data.  */
-  if (MEM_P (op0))
-    {
-      op0 = shallow_copy_rtx (op0);
-      set_mem_alias_set (op0, 0);
-      set_mem_expr (op0, 0);
-    }
-
   /* Extraction of a full-word or multi-word value from a structure
      in a register or aligned memory can be done with just a SUBREG.
      A subword value in the least significant part of a register
@@ -1487,7 +1468,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
 		      && MEM_ALIGN (op0) % bitsize == 0)))))
     {
       if (MEM_P (op0))
-	op0 = adjust_address (op0, mode1, offset);
+	op0 = adjust_bitfield_address (op0, mode1, offset);
       else if (mode1 != GET_MODE (op0))
 	{
 	  rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
@@ -1513,6 +1494,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
 
       unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
       unsigned int i;
+      rtx last;
 
       if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target))
 	target = gen_reg_rtx (mode);
@@ -1520,6 +1502,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
       /* Indicate for flow that the entire target reg is being set.  */
       emit_clobber (target);
 
+      last = get_last_insn ();
       for (i = 0; i < nwords; i++)
 	{
 	  /* If I is 0, use the low-order word in both field and target;
@@ -1536,12 +1519,17 @@ extract_bit_field_1 (rtx str_rtx, unsign
 				     : (int) i * BITS_PER_WORD);
 	  rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
 	  rtx result_part
-	    = extract_bit_field (op0, MIN (BITS_PER_WORD,
-					   bitsize - i * BITS_PER_WORD),
-				 bitnum + bit_offset, 1, false, target_part, mode,
-				 word_mode);
+	    = extract_bit_field_1 (op0, MIN (BITS_PER_WORD,
+					     bitsize - i * BITS_PER_WORD),
+				   bitnum + bit_offset, 1, false, target_part,
+				   mode, word_mode, fallback_p);
 
 	  gcc_assert (target_part);
+	  if (!result_part)
+	    {
+	      delete_insns_since (last);
+	      return NULL;
+	    }
 
 	  if (result_part != target_part)
 	    emit_move_insn (target_part, result_part);
@@ -1629,7 +1617,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
 	xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
       if (MEM_P (xop0))
 	/* Get ref to first byte containing part of the field.  */
-	xop0 = adjust_address (xop0, byte_mode, xoffset);
+	xop0 = adjust_bitfield_address (xop0, byte_mode, xoffset);
 
       /* Now convert from counting within UNIT to counting in EXT_MODE.  */
       if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
@@ -1725,7 +1713,7 @@ extract_bit_field_1 (rtx str_rtx, unsign
 	      last = get_last_insn ();
 
 	      /* Fetch it to a register in that size.  */
-	      xop0 = adjust_address (op0, bestmode, xoffset);
+	      xop0 = adjust_bitfield_address (op0, bestmode, xoffset);
 	      xop0 = force_reg (bestmode, xop0);
 	      result = extract_bit_field_1 (xop0, bitsize, xbitpos,
 					    unsignedp, packedp, target,
@@ -1906,7 +1894,7 @@ extract_fixed_bit_field (enum machine_mo
 	  offset -= (offset % (total_bits / BITS_PER_UNIT));
 	}
 
-      op0 = adjust_address (op0, mode, offset);
+      op0 = adjust_bitfield_address (op0, mode, offset);
     }
 
   mode = GET_MODE (op0);
Index: emit-rtl.c
===================================================================
--- emit-rtl.c	(revision 191198)
+++ emit-rtl.c	(working copy)
@@ -2051,12 +2051,16 @@ change_address (rtx memref, enum machine
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address offset by OFFSET bytes.  If VALIDATE is
    nonzero, the memory address is forced to be valid.
-   If ADJUST is zero, OFFSET is only used to update MEM_ATTRS
-   and caller is responsible for adjusting MEMREF base register.  */
+   If ADJUST_ADDRESS is zero, OFFSET is only used to update MEM_ATTRS
+   and the caller is responsible for adjusting MEMREF base register.
+   If ADJUST_OBJECT is zero, the underlying object associated with the
+   memory reference is left unchanged and the caller is responsible for
+   dealing with it.  Otherwise, if the new memory reference is outside
+   the underlying object, even partially, then the object is dropped.  */
 
 rtx
 adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
-		  int validate, int adjust)
+		  int validate, int adjust_address, int adjust_object)
 {
   rtx addr = XEXP (memref, 0);
   rtx new_rtx;
@@ -2089,7 +2093,7 @@ adjust_address_1 (rtx memref, enum machi
 		>> shift);
     }
 
-  if (adjust)
+  if (adjust_address)
     {
       /* If MEMREF is a LO_SUM and the offset is within the alignment of the
 	 object, we can merge it into the LO_SUM.  */
@@ -2111,10 +2115,26 @@ adjust_address_1 (rtx memref, enum machi
   if (new_rtx == memref && offset != 0)
     new_rtx = copy_rtx (new_rtx);
 
+  /* Conservatively drop the object if we don't know where we start from.  */
+  if (adjust_object && (!attrs.offset_known_p || !attrs.size_known_p))
+    {
+      attrs.expr = NULL_TREE;
+      attrs.alias = 0;
+    }
+
   /* Compute the new values of the memory attributes due to this adjustment.
      We add the offsets and update the alignment.  */
   if (attrs.offset_known_p)
-    attrs.offset += offset;
+    {
+      attrs.offset += offset;
+
+      /* Drop the object if the new left end is not within its bounds.  */
+      if (adjust_object && attrs.offset < 0)
+	{
+	  attrs.expr = NULL_TREE;
+	  attrs.alias = 0;
+	}
+    }
 
   /* Compute the new alignment by taking the MIN of the alignment and the
      lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
@@ -2129,16 +2149,24 @@ adjust_address_1 (rtx memref, enum machi
   defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
   if (defattrs->size_known_p)
     {
+      /* Drop the object if the new right end is not within its bounds.  */
+      if (adjust_object && (attrs.offset + defattrs->size) > attrs.size)
+	{
+	  attrs.expr = NULL_TREE;
+	  attrs.alias = 0;
+	}
       attrs.size_known_p = true;
       attrs.size = defattrs->size;
     }
   else if (attrs.size_known_p)
-    attrs.size -= offset;
+    {
+      attrs.size -= offset;
+      /* ??? The store_by_pieces machinery generates negative sizes.  */
+      gcc_assert (!(adjust_object && attrs.size < 0));
+    }
 
   set_mem_attrs (new_rtx, &attrs);
 
-  /* At some point, we should validate that this offset is within the object,
-     if all the appropriate values are known.  */
   return new_rtx;
 }
 
@@ -2152,7 +2180,7 @@ adjust_automodify_address_1 (rtx memref,
 			     HOST_WIDE_INT offset, int validate)
 {
   memref = change_address_1 (memref, VOIDmode, addr, validate);
-  return adjust_address_1 (memref, mode, offset, validate, 0);
+  return adjust_address_1 (memref, mode, offset, validate, 0, 0);
 }
 
 /* Return a memory reference like MEMREF, but whose address is changed by
@@ -2234,7 +2262,7 @@ replace_equiv_address_nv (rtx memref, rt
 rtx
 widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
 {
-  rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1);
+  rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1, 0);
   struct mem_attrs attrs;
   unsigned int size = GET_MODE_SIZE (mode);
 
