This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] - Use of powerpc 64bit instructions in 32bit ABI
- From: David Edelsohn <dje at watson dot ibm dot com>
- To: "Ulrich Weigand" <Ulrich dot Weigand at de dot ibm dot com>
- Cc: Fariborz Jahanian <fjahanian at apple dot com>, Richard Henderson <rth at redhat dot com>, ian at wasabisystems dot com, davem at redhat dot com, gcc-patches at gcc dot gnu dot org
- Date: Fri, 24 Oct 2003 13:31:41 -0400
- Subject: Re: [PATCH] - Use of powerpc 64bit instructions in 32bit ABI
>>>>> Ulrich Weigand writes:
Ulrich> Could you elaborate what the problem with struct-by-value was?
Ulrich> This appears to work fine for me by returning false from
Ulrich> FUNCTION_ARG_PASS_BY_REFERENCE and then returning a PARALLEL
Ulrich> from FUNCTION_ARG for that struct parameter.
Notice the use of UNITS_PER_WORD, BITS_PER_WORD, and word_mode in
the following functions that depend on the argument wordsize and ABI:
calls.c:load_register_parameters()
else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode)
{
size = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
nregs = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; <***
}
calls.c:store_one_arg()
/* Round its size up to a multiple
of the allocation unit for arguments. */
if (arg->locate.size.var != 0)
{
excess = 0;
size_rtx = ARGS_SIZE_RTX (arg->locate.size);
}
else
{
/* PUSH_ROUNDING has no effect on us, because
emit_push_insn for BLKmode is careful to avoid it. */
excess = (arg->locate.size.constant
- int_size_in_bytes (TREE_TYPE (pval))
+ partial * UNITS_PER_WORD); <***
size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
NULL_RTX, TYPE_MODE (sizetype), 0);
}
expr.c:emit_push_insn()
if (mode == BLKmode)
{
/* Copy a block into the stack, entirely or partially. */
rtx temp;
int used = partial * UNITS_PER_WORD; <***
...
else if (partial > 0)
{
/* Scalar partly in registers. */
int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; <***
int i;
int not_stack;
/* # words of start of argument
that we must make space for but need not store. */
int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD); <***
...
if (i >= not_stack + offset)
emit_push_insn (operand_subword_force (x, i, mode),
***> word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
* UNITS_PER_WORD)),
reg_parm_stack_space, alignment_pad);
function.c:assign_parm()
if (nominal_mode == BLKmode
#ifdef BLOCK_REG_PADDING
|| (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
&& GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD) <***
#endif
|| GET_CODE (entry_parm) == PARALLEL)
{
/* If a BLKmode arrives in registers, copy it to a stack slot.
Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (entry_parm) == REG
|| GET_CODE (entry_parm) == PARALLEL)
{
int size = int_size_in_bytes (TREE_TYPE (parm));
int size_stored = CEIL_ROUND (size, UNITS_PER_WORD); <***
...
/* If SIZE is that of a mode no bigger than a word, just use
that mode's store operation. */
else if (size <= UNITS_PER_WORD) <***
{
enum machine_mode mode
= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
if (mode != BLKmode
#ifdef BLOCK_REG_PADDING
&& (size == UNITS_PER_WORD <***
|| (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
!= (BYTES_BIG_ENDIAN ? upward : downward)))
#endif
)
{
rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
emit_move_insn (change_address (mem, mode, 0), reg);
}
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN
machine must be aligned to the left before storing
to memory. Note that the previous test doesn't
handle all cases (e.g. SIZE == 3). */
else if (size != UNITS_PER_WORD <***
#ifdef BLOCK_REG_PADDING
&& (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
== downward)
#else
&& BYTES_BIG_ENDIAN
#endif
)
{
rtx tem, x;
int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT; <***
rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm));
x = expand_binop (word_mode, ashl_optab, reg,
GEN_INT (by), 0, 1, OPTAB_WIDEN);
tem = change_address (mem, word_mode, 0);
emit_move_insn (tem, x);
}
else
move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD); <***
}
else
move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD); <***
}
SET_DECL_RTL (parm, stack_parm);
}