From: Richard Kenner Date: Fri, 23 Jun 1995 03:01:03 +0000 (-0400) Subject: (expand_call): Correctly handle returning BLKmode structures in registers when... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1b5c58730b1fa9c5ce060cf798bdebd9a501d73a;p=gcc.git (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 --- diff --git a/gcc/calls.c b/gcc/calls.c index 8ed954fe506..4abd2c0e6ed 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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,38 +2058,48 @@ expand_call (exp, target, ignore) 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 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); - int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD); - int bitpos, big_endian_correction = 0; - - /* 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)); - - for (bitpos = 0; - bitpos < BITS_PER_WORD && bytes > 0; - bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT) - { - int xbitpos = bitpos + big_endian_correction; + + /* 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); - store_bit_field (dst, bitsize, xbitpos, word_mode, - extract_bit_field (src, bitsize, bitpos, 1, - NULL_RTX, word_mode, - word_mode, - bitsize / BITS_PER_UNIT, - BITS_PER_WORD), - bitsize / BITS_PER_UNIT, BITS_PER_WORD); - } + /* 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, + BITS_PER_WORD), + bitsize / BITS_PER_UNIT, BITS_PER_WORD); } } else