diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d451dcc193f3bd431d1f58f6db2a9857e0e78357..ce93b26a7689260eee77aebfabe56183f66b6f50 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2012-01-31  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/51528
+	* tree-sra.c (sra_modify_assign): Avoid copy-in/out for aggregate
+	assigns.
+
 2012-01-31  Jakub Jelinek  <jakub@redhat.com>
 
 	PR bootstrap/52041
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index da42f22950c1de9551993394342fea93d426519b..77c86391983371293eaf84cd2cd8e6a3aa13eb53 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2012-01-31  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/51528
+	* gcc.dg/torture/pr51528.c: New testcase.
+
 2012-01-30  Uros Bizjak  <ubizjak@gmail.com>
 
 	PR go/48501
diff --git a/gcc/testsuite/gcc.dg/torture/pr51528.c b/gcc/testsuite/gcc.dg/torture/pr51528.c
new file mode 100644
index 0000000000000000000000000000000000000000..db5f3e0cadd18d9bbddc7db0f1aeacfd95c944c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr51528.c
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-fno-early-inlining" } */
+
+extern void abort (void);
+
+union U
+{
+  int i;
+  _Bool b;
+};
+
+_Bool gb;
+
+void  __attribute__ ((noinline))
+use_bool (union U u)
+{
+  gb = u.b;
+}
+
+union U
+bar (void)
+{
+  union U u;
+  u.i = 0xFFFE;
+  return u;
+}
+
+union U  __attribute__ ((noinline))
+foo (void)
+{
+  union U u,v;
+
+  u.b = 1;
+  use_bool (u);
+  u = bar ();
+
+  return u;
+}
+
+int main (int argc, char **argv)
+{
+  union U u = foo ();
+  if (u.i != 0xFFFE)
+    abort ();
+  return 0;
+}
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index ef26894343403064255c7c816a5cd3bc13b5fcc4..e3bf38230dc7d4180f4e98060eaf5ced9dc5ad08 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -3135,9 +3135,14 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
 	      sra_stats.deleted++;
 	      return SRA_AM_REMOVED;
 	    }
+	  /* Restore the aggregate RHS from its components so the
+	     prevailing aggregate copy does the right thing.  */
 	  if (access_has_children_p (racc))
-	    generate_subtree_copies (racc->first_child, lhs, racc->offset,
-				     0, 0, gsi, false, true, loc);
+	    generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
+				     gsi, false, false, loc);
+	  /* Re-load the components of the aggregate copy destination.
+	     But use the RHS aggregate to load from to expose more
+	     optimization opportunities.  */
 	  if (access_has_children_p (lacc))
 	    generate_subtree_copies (lacc->first_child, rhs, lacc->offset,
 				     0, 0, gsi, true, true, loc);