Commit 1b5c5873 by Richard Kenner

(expand_call): Correctly handle returning BLKmode structures in registers when...

(expand_call): Correctly handle returning BLKmode structures in
registers when the size of the structure is not a multiple of
word_size.

From-SVN: r10051
parent 8ecb1d92
......@@ -2047,6 +2047,9 @@ expand_call (exp, target, ignore)
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int i;
enum machine_mode tmpmode;
rtx src, dst;
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
int bitpos, xbitpos, big_endian_correction = 0;
if (target == 0)
{
......@@ -2055,32 +2058,43 @@ expand_call (exp, target, ignore)
preserve_temp_slots (target);
}
/* We could probably emit more efficient code for machines
which do not use strict alignment, but it doesn't seem
worth the effort at the current time. */
for (i = 0; i < n_regs; i++)
{
rtx src = operand_subword_force (valreg, i, BLKmode);
rtx dst = operand_subword (target, i, 1, BLKmode);
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
int bitpos, big_endian_correction = 0;
/* Structures whose size is not a multiple of a word are aligned
to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
machine, this means we must skip the empty high order bytes when
calculating the bit offset. */
if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
* BITS_PER_UNIT));
/* Should never happen. */
if (src == NULL || dst == NULL)
abort ();
if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
big_endian_correction
= (BITS_PER_WORD - (bytes * BITS_PER_UNIT));
/* Copy the structure BITSIZE bites at a time.
for (bitpos = 0;
bitpos < BITS_PER_WORD && bytes > 0;
bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
{
int xbitpos = bitpos + big_endian_correction;
store_bit_field (dst, bitsize, xbitpos, word_mode,
extract_bit_field (src, bitsize, bitpos, 1,
We could probably emit more efficient code for machines
which do not use strict alignment, but it doesn't seem
worth the effort at the current time. */
for (bitpos = 0, xbitpos = big_endian_correction;
bitpos < bytes * BITS_PER_UNIT;
bitpos += bitsize, xbitpos += bitsize)
{
/* We need a new source operand each time xbitpos is on a
word boundary and when xbitpos == big_endian_correction
(the first time through). */
if (xbitpos % BITS_PER_WORD == 0
|| xbitpos == big_endian_correction)
src = operand_subword_force (valreg,
xbitpos / BITS_PER_WORD,
BLKmode);
/* We need a new destination operand each time bitpos is on
a word boundary. */
if (bitpos % BITS_PER_WORD == 0)
dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, BLKmode);
/* Use xbitpos for the source extraction (right justified) and
xbitpos for the destination store (left justified). */
store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
extract_bit_field (src, bitsize,
xbitpos % BITS_PER_WORD, 1,
NULL_RTX, word_mode,
word_mode,
bitsize / BITS_PER_UNIT,
......@@ -2088,7 +2102,6 @@ expand_call (exp, target, ignore)
bitsize / BITS_PER_UNIT, BITS_PER_WORD);
}
}
}
else
target = copy_to_reg (valreg);
......
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