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) ...@@ -2047,6 +2047,9 @@ expand_call (exp, target, ignore)
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int i; int i;
enum machine_mode tmpmode; 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) if (target == 0)
{ {
...@@ -2055,38 +2058,48 @@ expand_call (exp, target, ignore) ...@@ -2055,38 +2058,48 @@ expand_call (exp, target, ignore)
preserve_temp_slots (target); preserve_temp_slots (target);
} }
/* We could probably emit more efficient code for machines /* 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));
/* Copy the structure BITSIZE bites at a time.
We could probably emit more efficient code for machines
which do not use strict alignment, but it doesn't seem which do not use strict alignment, but it doesn't seem
worth the effort at the current time. */ worth the effort at the current time. */
for (i = 0; i < n_regs; i++) for (bitpos = 0, xbitpos = big_endian_correction;
bitpos < bytes * BITS_PER_UNIT;
bitpos += bitsize, xbitpos += bitsize)
{ {
rtx src = operand_subword_force (valreg, i, BLKmode);
rtx dst = operand_subword (target, i, 1, BLKmode); /* We need a new source operand each time xbitpos is on a
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD); word boundary and when xbitpos == big_endian_correction
int bitpos, big_endian_correction = 0; (the first time through). */
if (xbitpos % BITS_PER_WORD == 0
/* Should never happen. */ || xbitpos == big_endian_correction)
if (src == NULL || dst == NULL) src = operand_subword_force (valreg,
abort (); xbitpos / BITS_PER_WORD,
BLKmode);
if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
big_endian_correction /* We need a new destination operand each time bitpos is on
= (BITS_PER_WORD - (bytes * BITS_PER_UNIT)); a word boundary. */
if (bitpos % BITS_PER_WORD == 0)
for (bitpos = 0; dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, BLKmode);
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, /* Use xbitpos for the source extraction (right justified) and
extract_bit_field (src, bitsize, bitpos, 1, xbitpos for the destination store (left justified). */
NULL_RTX, word_mode, store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
word_mode, extract_bit_field (src, bitsize,
bitsize / BITS_PER_UNIT, xbitpos % BITS_PER_WORD, 1,
BITS_PER_WORD), NULL_RTX, word_mode,
bitsize / BITS_PER_UNIT, BITS_PER_WORD); word_mode,
} bitsize / BITS_PER_UNIT,
BITS_PER_WORD),
bitsize / BITS_PER_UNIT, BITS_PER_WORD);
} }
} }
else else
......
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