http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57344
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Yeah, the problem is definitely in store_split_bit_field. One possible fix is: --- gcc/expmed.c.jj 2013-05-14 10:54:58.000000000 +0200 +++ gcc/expmed.c 2013-05-21 10:54:59.707793889 +0200 @@ -1094,10 +1094,15 @@ 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. + Don't do this if op0 is a REG or SUBREG, there won't be any + data races on registers and the code assumes unit is + BITS_PER_WORD. */ 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) { unit = unit / 2; continue; Another one I'm currently testing is just not assuming unit is BITS_PER_WORD in the SUBREG/REG handling code, and another one a mixture of both. I don't know if we can actually end up with a SUBREG of MEM, if yes, then the above patch is wrong, because it could introduce a data race in that case. The other fix on the other side might pessimize the case where we e.g. have a real REG or SUBREG of some REG and store some bits in a first word and bitregion_end tells us that we must not touch the last byte in the second word, but we need to touch the rest. On REGs there should be no data races. So I'm probably going with both changes together.