Commit a34ab4c9 by Eric Botcazou Committed by Eric Botcazou

expr.c (store_field): In the bitfield case...

	* 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
parent 664b1a6b
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
......
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment