diff options
author | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1995-06-23 03:01:38 +0000 |
---|---|---|
committer | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1995-06-23 03:01:38 +0000 |
commit | f710f2e5c05d33af1039920803f9321c26f4a26e (patch) | |
tree | eccc4d1255b23a4960414dcbc8fa4432bdc5cabe /gcc | |
parent | 5734f76e54c19be4df91af240445d8857ae04d67 (diff) | |
download | ppe42-gcc-f710f2e5c05d33af1039920803f9321c26f4a26e.tar.gz ppe42-gcc-f710f2e5c05d33af1039920803f9321c26f4a26e.zip |
(expand_return): Correctly handle returning BLKmode structures in
registers when the size of the structure is not a multiple of
word_size.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@10052 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/stmt.c | 79 |
1 files changed, 44 insertions, 35 deletions
diff --git a/gcc/stmt.c b/gcc/stmt.c index be018c20c6e..02ac0e655d3 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -2722,51 +2722,60 @@ expand_return (retval) && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG) { - int i; + int i, bitpos, xbitpos; int big_endian_correction = 0; int bytes = int_size_in_bytes (TREE_TYPE (retval_rhs)); int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),BITS_PER_WORD); rtx *result_pseudos = (rtx *) alloca (sizeof (rtx) * n_regs); - rtx result_reg; + rtx result_reg, src, dst; rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0); enum machine_mode tmpmode, result_reg_mode; - /* Structures smaller than 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 * BITS_PER_UNIT)); - - for (i = 0; i < n_regs; i++) + /* 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 bits at a time. */ + for (bitpos = 0, xbitpos = big_endian_correction; + bitpos < bytes * BITS_PER_UNIT; + bitpos += bitsize, xbitpos += bitsize) { - rtx reg = gen_reg_rtx (word_mode); - rtx word = operand_subword_force (result_val, i, BLKmode); - int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),BITS_PER_WORD); - int bitpos; - - result_pseudos[i] = reg; - - /* Clobber REG and move each partword into it. Ensure we don't - go past the end of the structure. Note that the loop below - works because we've already verified that padding and - endianness are compatible. */ - emit_insn (gen_rtx (CLOBBER, VOIDmode, reg)); - - for (bitpos = 0; - bitpos < BITS_PER_WORD && bytes > 0; - bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT) + /* We need a new destination pseudo each time xbitpos is + on a word boundary and when xbitpos == big_endian_corrction + (the first time through). */ + if (xbitpos % BITS_PER_WORD == 0 + || xbitpos == big_endian_correction) { - int xbitpos = bitpos + big_endian_correction; - - store_bit_field (reg, bitsize, xbitpos, word_mode, - extract_bit_field (word, bitsize, bitpos, 1, - NULL_RTX, word_mode, - word_mode, - bitsize / BITS_PER_UNIT, - BITS_PER_WORD), - bitsize / BITS_PER_UNIT, BITS_PER_WORD); + /* Generate an appropriate register. */ + dst = gen_reg_rtx (word_mode); + result_pseudos[xbitpos / BITS_PER_WORD] = dst; + + /* Clobber the destination before we move anything into it. */ + emit_insn (gen_rtx (CLOBBER, VOIDmode, dst)); } + + /* We need a new source operand each time bitpos is on a word + boundary. */ + if (bitpos % BITS_PER_WORD == 0) + src = operand_subword_force (result_val, + bitpos / BITS_PER_WORD, + BLKmode); + + /* Use bitpos for the source extraction (left justified) and + xbitpos for the destination store (right justified). */ + store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode, + extract_bit_field (src, bitsize, + bitpos % BITS_PER_WORD, 1, + NULL_RTX, word_mode, + word_mode, + bitsize / BITS_PER_UNIT, + BITS_PER_WORD), + bitsize / BITS_PER_UNIT, BITS_PER_WORD); } /* Find the smallest integer mode large enough to hold the |