expr.c (store_field): In the bitfield case...
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 10 Jan 2017 23:05:13 +0000 (23:05 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Tue, 10 Jan 2017 23:05:13 +0000 (23:05 +0000)
* expr.c (store_field): In the bitfield case, fetch the return value
from the registers before applying a single big-endian adjustment.
Always do a final load for a BLKmode value not larger than a word.

From-SVN: r244299

gcc/ChangeLog
gcc/expr.c

index ff83dea5aae9c561dfa80bedd670b0c00055f113..cc81d79a758f442af89746bd02aadcd81cf51b3e 100644 (file)
@@ -1,3 +1,9 @@
+2017-01-10  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * expr.c (store_field): In the bitfield case, fetch the return value
+       from the registers before applying a single big-endian adjustment.
+       Always do a final load for a BLKmode value not larger than a word.
+
 2017-01-10  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/77949
index e1d70c3b189d121e4d2a6ed9c08772f7d20505e9..4c54faf82875426fa4684fed9593a1907377fba9 100644 (file)
@@ -6832,13 +6832,36 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
 
       temp = expand_normal (exp);
 
-      /* If the value has a record type and an integral mode then, if BITSIZE
-        is narrower than this mode and this is for big-endian data, we must
-        first put the value into the low-order bits.  Moreover, the field may
-        be not aligned on a byte boundary; in this case, if it has reverse
-        storage order, it needs to be accessed as a scalar field with reverse
-        storage order and we must first put the value into target order.  */
-      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
+      /* Handle calls that return values in multiple non-contiguous locations.
+        The Irix 6 ABI has examples of this.  */
+      if (GET_CODE (temp) == PARALLEL)
+       {
+         HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+         machine_mode temp_mode
+           = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
+         rtx temp_target = gen_reg_rtx (temp_mode);
+         emit_group_store (temp_target, temp, TREE_TYPE (exp), size);
+         temp = temp_target;
+       }
+
+      /* Handle calls that return BLKmode values in registers.  */
+      else if (mode == BLKmode && REG_P (temp) && TREE_CODE (exp) == CALL_EXPR)
+       {
+         rtx temp_target = gen_reg_rtx (GET_MODE (temp));
+         copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
+         temp = temp_target;
+       }
+
+      /* If the value has aggregate type and an integral mode then, if BITSIZE
+        is narrower than this mode and this is for big-endian data, we first
+        need to put the value into the low-order bits for store_bit_field,
+        except when MODE is BLKmode and BITSIZE larger than the word size
+        (see the handling of fields larger than a word in store_bit_field).
+        Moreover, the field may be not aligned on a byte boundary; in this
+        case, if it has reverse storage order, it needs to be accessed as a
+        scalar field with reverse storage order and we must first put the
+        value into target order.  */
+      if (AGGREGATE_TYPE_P (TREE_TYPE (exp))
          && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT)
        {
          HOST_WIDE_INT size = GET_MODE_BITSIZE (GET_MODE (temp));
@@ -6849,7 +6872,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
            temp = flip_storage_order (GET_MODE (temp), temp);
 
          if (bitsize < size
-             && reverse ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN)
+             && reverse ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN
+             && !(mode == BLKmode && bitsize > BITS_PER_WORD))
            temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
                                 size - bitsize, NULL_RTX, 1);
        }
@@ -6859,12 +6883,10 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          && mode != TYPE_MODE (TREE_TYPE (exp)))
        temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
 
-      /* If TEMP is not a PARALLEL (see below) and its mode and that of TARGET
-        are both BLKmode, both must be in memory and BITPOS must be aligned
-        on a byte boundary.  If so, we simply do a block copy.  Likewise for
-        a BLKmode-like TARGET.  */
-      if (GET_CODE (temp) != PARALLEL
-         && GET_MODE (temp) == BLKmode
+      /* If the mode of TEMP and TARGET is BLKmode, both must be in memory
+        and BITPOS must be aligned on a byte boundary.  If so, we simply do
+        a block copy.  Likewise for a BLKmode-like TARGET.  */
+      if (GET_MODE (temp) == BLKmode
          && (GET_MODE (target) == BLKmode
              || (MEM_P (target)
                  && GET_MODE_CLASS (GET_MODE (target)) == MODE_INT
@@ -6883,31 +6905,9 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          return const0_rtx;
        }
 
-      /* Handle calls that return values in multiple non-contiguous locations.
-        The Irix 6 ABI has examples of this.  */
-      if (GET_CODE (temp) == PARALLEL)
-       {
-         HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
-         machine_mode temp_mode
-           = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
-         rtx temp_target = gen_reg_rtx (temp_mode);
-         emit_group_store (temp_target, temp, TREE_TYPE (exp), size);
-         temp = temp_target;
-       }
-
-      /* Handle calls that return BLKmode values in registers.  */
-      else if (mode == BLKmode && REG_P (temp) && TREE_CODE (exp) == CALL_EXPR)
-       {
-         rtx temp_target = gen_reg_rtx (GET_MODE (temp));
-         copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
-         temp = temp_target;
-       }
-
-      /* The behavior of store_bit_field is awkward when mode is BLKmode:
-        it always takes its value from the lsb up to the word size but
-        expects it left justified beyond it.  At this point TEMP is left
-        justified so extract the value in the former case.  */
-      if (mode == BLKmode && bitsize <= BITS_PER_WORD)
+      /* If the mode of TEMP is still BLKmode and BITSIZE not larger than the
+        word size, we need to load the value (see again store_bit_field).  */
+      if (GET_MODE (temp) == BLKmode && bitsize <= BITS_PER_WORD)
        {
          machine_mode temp_mode = smallest_mode_for_size (bitsize, MODE_INT);
          temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode,