From 4ab561180caefa229eaae824dee8d910c069f5ee Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Mon, 8 Feb 1993 05:51:58 -0500 Subject: [PATCH] Allow passing nonaligned BLKmode structs in regs. (struct arg_data): New fields aligned_regs and n_aligned_regs. (expand_call): Set and use these fields when required. (store_one_arg): Don't pass reg to emit_push_insn if we have previously formed aligned registers. From-SVN: r3440 --- gcc/calls.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/gcc/calls.c b/gcc/calls.c index 5b9c9ca2dcc..bd122935142 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -84,6 +84,14 @@ struct arg_data /* Place that this stack area has been saved, if needed. */ rtx save_area; #endif +#ifdef STRICT_ALIGNMENT + /* If an argument's alignment does not permit direct copying into registers, + copy in smaller-sized pieces into pseudos. These are stored in a + block pointed to by this field. The next field says how many + word-sized pseudos we made. */ + rtx *aligned_regs; + int n_aligned_regs; +#endif }; #ifdef ACCUMULATE_OUTGOING_ARGS @@ -514,7 +522,7 @@ expand_call (exp, target, ignore) rtx use_insns = 0; register tree p; - register int i; + register int i, j; /* See if we can find a DECL-node for the actual function. As a result, decide whether this is a call to an integrable function. */ @@ -625,8 +633,6 @@ expand_call (exp, target, ignore) /* If inlining succeeded, return. */ if ((HOST_WIDE_INT) temp != -1) { - int i; - /* Perform all cleanups needed for the arguments of this call (i.e. destructors in C++). It is ok if these destructors clobber RETURN_VALUE_REG, because the only time we care about @@ -1529,6 +1535,63 @@ expand_call (exp, target, ignore) store_one_arg (&args[i], argblock, may_be_alloca, args_size.var != 0, fndecl, reg_parm_stack_space); +#ifdef STRICT_ALIGNMENT + /* If we have a parm that is passed in registers but not in memory + and whose alignment does not permit a direct copy into registers, + make a group of pseudos that correspond to each register that we + will later fill. */ + + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 && ! args[i].pass_on_stack + && args[i].mode == BLKmode + && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value)) + < MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) + { + int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); + + args[i].n_aligned_regs + = args[i].partial ? args[i].partial + : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; + + args[i].aligned_regs = (rtx *) alloca (sizeof (rtx) + * args[i].n_aligned_regs); + + for (j = 0; j < args[i].n_aligned_regs; j++) + { + rtx reg = gen_reg_rtx (word_mode); + rtx word = operand_subword_force (args[i].value, j, BLKmode); + int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value)); + int bitpos; + + args[i].aligned_regs[j] = 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) + { + int xbitpos = (BYTES_BIG_ENDIAN + ? bitpos = BITS_PER_WORD - bitpos - bitsize + : bitpos); + + store_bit_field (reg, bitsize, xbitpos, word_mode, + extract_bit_field (word, bitsize, xbitpos, 1, + NULL_RTX, word_mode, + word_mode, + bitsize / BITS_PER_UNIT, + BITS_PER_WORD), + bitsize / BITS_PER_UNIT, BITS_PER_WORD); + } + } + } +#endif + /* Now store any partially-in-registers parm. This is the last place a block-move can happen. */ if (reg_parm_seen) @@ -1609,6 +1672,17 @@ expand_call (exp, target, ignore) if (nregs == 0) emit_move_insn (reg, args[i].value); + +#ifdef STRICT_ALIGNMENT + /* If we have pre-computed the values to put in the registers in + the case of non-aligned structures, copy them in now. */ + + else if (args[i].n_aligned_regs != 0) + for (j = 0; j < args[i].n_aligned_regs; j++) + emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j), + args[i].aligned_regs[j]); +#endif + else if (args[i].partial == 0 || args[i].pass_on_stack) move_block_to_reg (REGNO (reg), validize_mem (args[i].value), nregs, @@ -1989,13 +2063,20 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl, this case. */ abort (); +#ifdef STRICT_ALIGNMENT + /* If this arg needs special alignment, don't load the registers + here. */ + if (arg->n_aligned_regs != 0) + reg = 0; +#endif + /* If this is being partially passed in a register, but multiple locations are specified, we assume that the one partially used is the one that is listed first. */ if (reg && GET_CODE (reg) == EXPR_LIST) reg = XEXP (reg, 0); - /* If this is being passes partially in a register, we can't evaluate + /* If this is being passed partially in a register, we can't evaluate it directly into its stack slot. Otherwise, we can. */ if (arg->value == 0) { -- 2.30.2