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,32 +2058,43 @@ expand_call (exp, target, ignore) ...@@ -2055,32 +2058,43 @@ 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
which do not use strict alignment, but it doesn't seem to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
worth the effort at the current time. */ machine, this means we must skip the empty high order bytes when
for (i = 0; i < n_regs; i++) calculating the bit offset. */
{ if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
rtx src = operand_subword_force (valreg, i, BLKmode); big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
rtx dst = operand_subword (target, i, 1, BLKmode); * BITS_PER_UNIT));
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
int bitpos, big_endian_correction = 0;
/* Should never happen. */ /* Copy the structure BITSIZE bites at a time.
if (src == NULL || dst == NULL)
abort ();
if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
big_endian_correction
= (BITS_PER_WORD - (bytes * BITS_PER_UNIT));
for (bitpos = 0; We could probably emit more efficient code for machines
bitpos < BITS_PER_WORD && bytes > 0; which do not use strict alignment, but it doesn't seem
bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT) worth the effort at the current time. */
{ for (bitpos = 0, xbitpos = big_endian_correction;
int xbitpos = bitpos + big_endian_correction; bitpos < bytes * BITS_PER_UNIT;
bitpos += bitsize, xbitpos += bitsize)
store_bit_field (dst, bitsize, xbitpos, word_mode, {
extract_bit_field (src, bitsize, bitpos, 1,
/* 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, NULL_RTX, word_mode,
word_mode, word_mode,
bitsize / BITS_PER_UNIT, bitsize / BITS_PER_UNIT,
...@@ -2088,7 +2102,6 @@ expand_call (exp, target, ignore) ...@@ -2088,7 +2102,6 @@ expand_call (exp, target, ignore)
bitsize / BITS_PER_UNIT, BITS_PER_WORD); bitsize / BITS_PER_UNIT, BITS_PER_WORD);
} }
} }
}
else else
target = copy_to_reg (valreg); 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