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.

Reply via email to