--- gcc/expmed.c.jj	2013-05-14 10:54:58.000000000 +0200
+++ gcc/expmed.c	2013-05-21 11:59:00.275839242 +0200
@@ -1094,10 +1094,14 @@ store_split_bit_field (rtx op0, unsigned
       thispos = (bitpos + bitsdone) % unit;
 
       /* When region of bytes we can touch is restricted, decrease
-	 UNIT close to the end of the region as needed.  */
+	 UNIT close to the end of the region as needed.  If op0 is a REG
+	 or SUBREG of REG, don't do this, as there can't be data races
+	 on a register and we can expand shorter code in some cases.  */
       if (bitregion_end
 	  && unit > BITS_PER_UNIT
-	  && bitpos + bitsdone - thispos + unit > bitregion_end + 1)
+	  && bitpos + bitsdone - thispos + unit > bitregion_end + 1
+	  && !REG_P (op0)
+	  && (GET_CODE (op0) != SUBREG || !REG_P (SUBREG_REG (op0))))
 	{
 	  unit = unit / 2;
 	  continue;
@@ -1147,14 +1151,15 @@ store_split_bit_field (rtx op0, unsigned
 	 the current word starting from the base register.  */
       if (GET_CODE (op0) == SUBREG)
 	{
-	  int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+	  int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD)
+			    + (offset * unit / BITS_PER_WORD);
 	  enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
 	  if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD)
 	    word = word_offset ? const0_rtx : op0;
 	  else
 	    word = operand_subword_force (SUBREG_REG (op0), word_offset,
 					  GET_MODE (SUBREG_REG (op0)));
-	  offset = 0;
+	  offset &= BITS_PER_WORD / unit - 1;
 	}
       else if (REG_P (op0))
 	{
@@ -1162,8 +1167,9 @@ store_split_bit_field (rtx op0, unsigned
 	  if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
 	    word = offset ? const0_rtx : op0;
 	  else
-	    word = operand_subword_force (op0, offset, GET_MODE (op0));
-	  offset = 0;
+	    word = operand_subword_force (op0, offset * unit / BITS_PER_WORD,
+					  GET_MODE (op0));
+	  offset &= BITS_PER_WORD / unit - 1;
 	}
       else
 	word = op0;
--- gcc/testsuite/gcc.c-torture/execute/pr57344-1.c.jj	2013-05-21 11:38:07.828956569 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr57344-1.c	2013-05-21 11:58:21.242061844 +0200
@@ -0,0 +1,32 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+  int a : 11;
+#if __SIZEOF_INT__ * __CHAR_BIT__ >= 32
+  int b : 22;
+#else
+  int b : 13;
+#endif
+  char c;
+  int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  if (x != -3161)
+    __builtin_abort ();
+  asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+  struct S t = { 0, -3161L };
+  s[1] = t;
+  for (; i < 1; i++)
+    foo (s[1].b);
+  return 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/pr57344-2.c.jj	2013-05-21 11:38:13.536922710 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr57344-2.c	2013-05-21 11:58:36.119977546 +0200
@@ -0,0 +1,32 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+  int a : 27;
+#if __SIZEOF_INT__ * __CHAR_BIT__ >= 32
+  int b : 22;
+#else
+  int b : 13;
+#endif
+  char c;
+  int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  if (x != -3161)
+    __builtin_abort ();
+  asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+  struct S t = { 0, -3161L };
+  s[1] = t;
+  for (; i < 1; i++)
+    foo (s[1].b);
+  return 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/pr57344-3.c.jj	2013-05-21 11:43:11.157231567 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr57344-3.c	2013-05-21 11:55:33.220012554 +0200
@@ -0,0 +1,28 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+  long long int a : 43;
+  long long int b : 22;
+  char c;
+  long long int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (long long int x)
+{
+  if (x != -3161LL)
+    __builtin_abort ();
+  asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+  struct S t = { 0, -3161LL };
+  s[1] = t;
+  for (; i < 1; i++)
+    foo (s[1].b);
+  return 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/pr57344-4.c.jj	2013-05-21 11:55:09.346146134 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr57344-4.c	2013-05-21 11:53:31.000000000 +0200
@@ -0,0 +1,28 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+  long long int a : 59;
+  long long int b : 54;
+  char c;
+  long long int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (long long int x)
+{
+  if (x != -1220975898975746LL)
+    __builtin_abort ();
+  asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+  struct S t = { 0, -1220975898975746LL };
+  s[1] = t;
+  for (; i < 1; i++)
+    foo (s[1].b);
+  return 0;
+}
