summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1995-06-23 03:01:38 +0000
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1995-06-23 03:01:38 +0000
commitf710f2e5c05d33af1039920803f9321c26f4a26e (patch)
treeeccc4d1255b23a4960414dcbc8fa4432bdc5cabe /gcc
parent5734f76e54c19be4df91af240445d8857ae04d67 (diff)
downloadppe42-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.c79
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
OpenPOWER on IntegriCloud