stmt.c (expand_return): For BLKmode structure returns...

* stmt.c (expand_return): For BLKmode structure returns, copy
	the return value from memory into the return registers.  Use
	an integer mode rather than BLKmode for returning structures
	in registers.

From-SVN: r8577
This commit is contained in:
Jeff Law 1994-11-28 22:44:58 -07:00
parent 203436d9aa
commit 4c485b6355

View File

@ -2634,7 +2634,93 @@ expand_return (retval)
}
#endif /* HAVE_return */
if (cleanups
/* If the result is an aggregate that is being returned in one (or more)
registers, load the registers here. The compiler currently can't handle
copying a BLKmode value into registers. We could put this code in a
more general area (for use by everyone instead of just function
call/return), but until this feature is generally usable it is kept here
(and in expand_call). */
if (retval_rhs != 0
&& TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
&& GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
{
int i;
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;
rtx *result_pseudos = (rtx *) alloca (sizeof (rtx) * n_regs);
rtx result_reg = DECL_RTL (DECL_RESULT (current_function_decl));
rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
enum machine_mode tmpmode;
/* 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++)
{
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 compatable. */
emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
for (bitpos = 0;
bitpos < BITS_PER_WORD && bytes > 0;
bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
{
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);
}
}
/* Now that the value is in pseudos, copy it to the result reg(s). */
emit_queue ();
free_temp_slots ();
for (i = 0; i < n_regs; i++)
emit_move_insn (gen_rtx (REG, word_mode, REGNO (result_reg) + i),
result_pseudos[i]);
/* Find the smallest integer mode large enough to hold the
entire structure and use that mode instead of BLKmode
on the USE insn for the return register. */
bytes = int_size_in_bytes (TREE_TYPE (retval_rhs));
for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmpmode != MAX_MACHINE_MODE;
tmpmode = GET_MODE_WIDER_MODE (tmpmode))
{
/* Have we found a large enough mode? */
if (GET_MODE_SIZE (tmpmode) >= bytes)
break;
}
/* No suitable mode found. */
if (tmpmode == MAX_MACHINE_MODE)
abort ();
PUT_MODE (result_reg, tmpmode);
expand_value_return (result_reg);
}
else if (cleanups
&& retval_rhs != 0
&& TREE_TYPE (retval_rhs) != void_type_node
&& GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)