Remove word_mode hack for split bitfields
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 8 Jun 2016 12:18:27 +0000 (12:18 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 8 Jun 2016 12:18:27 +0000 (12:18 +0000)
This patch is effectively reverting a change from 1994.  The reason
I think it's a hack is that store_bit_field_1 is creating a subreg
reference to one word of a field even though it has already proven that
the field spills into the following word.  We then rely on the special
SUBREG handling in store_split_bit_field to ignore the extent of op0 and
look inside the SUBREG_REG regardless.  I don't see any reason why we can't
pass the original op0 to store_split_bit_field instead.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.

gcc/
* expmed.c (store_bit_field_1): Do not restrict a multiword op0
to one word if the field is known to overlap other words.
(extract_bit_field_1): Likewise.
(store_split_bit_field): Remove compensating code.
(extract_split_bit_field): Likewise.

From-SVN: r237211

gcc/ChangeLog
gcc/expmed.c

index df5b0dffae5965c51c183032f8e3601a955a7035..6767537e9c960809265a966854238394ad8eae37 100644 (file)
@@ -1,3 +1,11 @@
+2016-06-08  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * expmed.c (store_bit_field_1): Do not restrict a multiword op0
+       to one word if the field is known to overlap other words.
+       (extract_bit_field_1): Likewise.
+       (store_split_bit_field): Remove compensating code.
+       (extract_split_bit_field): Likewise.
+
 2016-06-08  Bernd Schmidt  <bschmidt@redhat.com>
 
        PR debug/71432
index ec968da63336d94efb534cf274222ff51ddaaf09..6645a535b3eef9624e6f3ce61d2fcf864d1cf574 100644 (file)
@@ -967,11 +967,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      If the region spans two words, defer to store_split_bit_field.  */
   if (!MEM_P (op0) && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
     {
-      op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
-                                bitnum / BITS_PER_WORD * UNITS_PER_WORD);
-      gcc_assert (op0);
-      bitnum %= BITS_PER_WORD;
-      if (bitnum + bitsize > BITS_PER_WORD)
+      if (bitnum % BITS_PER_WORD + bitsize > BITS_PER_WORD)
        {
          if (!fallback_p)
            return false;
@@ -980,6 +976,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                                 bitregion_end, value, reverse);
          return true;
        }
+      op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
+                                bitnum / BITS_PER_WORD * UNITS_PER_WORD);
+      gcc_assert (op0);
+      bitnum %= BITS_PER_WORD;
     }
 
   /* From here on we can assume that the field to be stored in fits
@@ -1383,25 +1383,8 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
                                            bitsdone, NULL_RTX, 1, false);
        }
 
-      /* If OP0 is a register, then handle OFFSET here.
-
-        When handling multiword bitfields, extract_bit_field may pass
-        down a word_mode SUBREG of a larger REG for a bitfield that actually
-        crosses a word boundary.  Thus, for a SUBREG, we must find
-        the current word starting from the base register.  */
-      if (GET_CODE (op0) == SUBREG)
-       {
-         int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD)
-                           + (offset * unit / BITS_PER_WORD);
-         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 &= BITS_PER_WORD / unit - 1;
-       }
-      else if (REG_P (op0))
+      /* If OP0 is a register, then handle OFFSET here.  */
+      if (SUBREG_P (op0) || REG_P (op0))
        {
          machine_mode op0_mode = GET_MODE (op0);
          if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
@@ -1787,10 +1770,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      If the region spans two words, defer to extract_split_bit_field.  */
   if (!MEM_P (op0) && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
     {
-      op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
-                                bitnum / BITS_PER_WORD * UNITS_PER_WORD);
-      bitnum %= BITS_PER_WORD;
-      if (bitnum + bitsize > BITS_PER_WORD)
+      if (bitnum % BITS_PER_WORD + bitsize > BITS_PER_WORD)
        {
          if (!fallback_p)
            return NULL_RTX;
@@ -1798,6 +1778,9 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                                            reverse);
          return convert_extracted_bit_field (target, mode, tmode, unsignedp);
        }
+      op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
+                                bitnum / BITS_PER_WORD * UNITS_PER_WORD);
+      bitnum %= BITS_PER_WORD;
     }
 
   /* From here on we know the desired field is smaller than a word.
@@ -2109,20 +2092,8 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
       thissize = MIN (bitsize - bitsdone, BITS_PER_WORD);
       thissize = MIN (thissize, unit - thispos);
 
-      /* If OP0 is a register, then handle OFFSET here.
-
-        When handling multiword bitfields, extract_bit_field may pass
-        down a word_mode SUBREG of a larger REG for a bitfield that actually
-        crosses a word boundary.  Thus, for a SUBREG, we must find
-        the current word starting from the base register.  */
-      if (GET_CODE (op0) == SUBREG)
-       {
-         int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
-         word = operand_subword_force (SUBREG_REG (op0), word_offset,
-                                       GET_MODE (SUBREG_REG (op0)));
-         offset = 0;
-       }
-      else if (REG_P (op0))
+      /* If OP0 is a register, then handle OFFSET here.  */
+      if (SUBREG_P (op0) || REG_P (op0))
        {
          word = operand_subword_force (op0, offset, GET_MODE (op0));
          offset = 0;