+2004-11-13 Richard Henderson <rth@redhat.com>
+
+ * calls.c (precompute_register_parameters): Force all PARALLELs
+ into pseudo registers.
+ (load_register_parameters): Copy PARALLELs into hard registers.
+ * function.c (assign_parm_setup_block): Copy PARALLELS into
+ pseudo registers. Do emit_group_store in conversion_insns.
+ * expr.c (emit_group_load_1): Rename from emit_group_load, take
+ tmps as an argument. Move final copy loop ...
+ (emit_group_load): ... here. New function.
+ (emit_group_load_into_temps, emit_group_move_into_temps): New.
+ * expr.h: Declare them.
+
2004-11-14 Kazu Hirata <kazu@cs.umass.edu>
* tree-cfg.c, tree-if-conv.c, tree-ssa-loop-ivopts.c,
Set REG_PARM_SEEN if we encounter a register parameter. */
static void
-precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg_parm_seen)
+precompute_register_parameters (int num_actuals, struct arg_data *args,
+ int *reg_parm_seen)
{
int i;
TYPE_MODE (TREE_TYPE (args[i].tree_value)),
args[i].value, args[i].unsignedp);
+ /* If we're going to have to load the value by parts, pull the
+ parts into pseudos. The part extraction process can involve
+ non-trivial computation. */
+ if (GET_CODE (args[i].reg) == PARALLEL)
+ {
+ tree type = TREE_TYPE (args[i].tree_value);
+ args[i].value
+ = emit_group_load_into_temps (args[i].reg, args[i].value,
+ type, int_size_in_bytes (type));
+ }
+
/* If the value is expensive, and we are inside an appropriately
short loop, put the value into a pseudo and then put the pseudo
into the hard reg.
register parameters. This is to avoid reload conflicts while
loading the parameters registers. */
- if ((! (REG_P (args[i].value)
- || (GET_CODE (args[i].value) == SUBREG
- && REG_P (SUBREG_REG (args[i].value)))))
- && args[i].mode != BLKmode
- && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
- && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
- || optimize))
+ else if ((! (REG_P (args[i].value)
+ || (GET_CODE (args[i].value) == SUBREG
+ && REG_P (SUBREG_REG (args[i].value)))))
+ && args[i].mode != BLKmode
+ && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
+ && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
+ || optimize))
args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
}
}
locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (reg) == PARALLEL)
- {
- tree type = TREE_TYPE (args[i].tree_value);
- emit_group_load (reg, args[i].value, type,
- int_size_in_bytes (type));
- }
+ emit_group_move (reg, args[i].value);
/* If simple case, just do move. If normal partial, store_one_arg
has already loaded the register for us. In all other cases,
return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
}
-/* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
- where DST is non-consecutive registers represented by a PARALLEL.
- SSIZE represents the total size of block ORIG_SRC in bytes, or -1
- if not known. */
+/* A subroutine of emit_group_load. Arguments as for emit_group_load,
+ except that values are placed in TMPS[i], and must later be moved
+ into corrosponding XEXP (XVECEXP (DST, 0, i), 0) element. */
-void
-emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
+static void
+emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
{
- rtx *tmps, src;
+ rtx src;
int start, i;
enum machine_mode m = GET_MODE (orig_src);
/* ...and back again. */
if (imode != BLKmode)
src = gen_lowpart (imode, src);
- emit_group_load (dst, src, type, ssize);
+ emit_group_load_1 (tmps, dst, src, type, ssize);
return;
}
else
start = 1;
- tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
-
/* Process the pieces. */
for (i = start; i < XVECLEN (dst, 0); i++)
{
tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
build_int_cst (NULL_TREE, shift), tmps[i], 0);
}
+}
+
+/* Emit code to move a block SRC of type TYPE to a block DST,
+ where DST is non-consecutive registers represented by a PARALLEL.
+ SSIZE represents the total size of block ORIG_SRC in bytes, or -1
+ if not known. */
+
+void
+emit_group_load (rtx dst, rtx src, tree type, int ssize)
+{
+ rtx *tmps;
+ int i;
+
+ tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
+ emit_group_load_1 (tmps, dst, src, type, ssize);
/* Copy the extracted pieces into the proper (probable) hard regs. */
- for (i = start; i < XVECLEN (dst, 0); i++)
- emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+ for (i = 0; i < XVECLEN (dst, 0); i++)
+ {
+ rtx d = XEXP (XVECEXP (dst, 0, i), 0);
+ if (d == NULL)
+ continue;
+ emit_move_insn (d, tmps[i]);
+ }
+}
+
+/* Similar, but load SRC into new pseudos in a format that looks like
+ PARALLEL. This can later be fed to emit_group_move to get things
+ in the right place. */
+
+rtx
+emit_group_load_into_temps (rtx parallel, rtx src, tree type, int ssize)
+{
+ rtvec vec;
+ int i;
+
+ vec = rtvec_alloc (XVECLEN (parallel, 0));
+ emit_group_load_1 (&RTVEC_ELT (vec, 0), parallel, src, type, ssize);
+
+ /* Convert the vector to look just like the original PARALLEL, except
+ with the computed values. */
+ for (i = 0; i < XVECLEN (parallel, 0); i++)
+ {
+ rtx e = XVECEXP (parallel, 0, i);
+ rtx d = XEXP (e, 0);
+
+ if (d)
+ {
+ d = force_reg (GET_MODE (d), RTVEC_ELT (vec, i));
+ e = alloc_EXPR_LIST (REG_NOTE_KIND (e), d, XEXP (e, 1));
+ }
+ RTVEC_ELT (vec, i) = e;
+ }
+
+ return gen_rtx_PARALLEL (GET_MODE (parallel), vec);
}
/* Emit code to move a block SRC to block DST, where SRC and DST are
XEXP (XVECEXP (src, 0, i), 0));
}
+/* Move a group of registers represented by a PARALLEL into pseudos. */
+
+rtx
+emit_group_move_into_temps (rtx src)
+{
+ rtvec vec = rtvec_alloc (XVECLEN (src, 0));
+ int i;
+
+ for (i = 0; i < XVECLEN (src, 0); i++)
+ {
+ rtx e = XVECEXP (src, 0, i);
+ rtx d = XEXP (e, 0);
+
+ if (d)
+ e = alloc_EXPR_LIST (REG_NOTE_KIND (e), copy_to_reg (d), XEXP (e, 1));
+ RTVEC_ELT (vec, i) = e;
+ }
+
+ return gen_rtx_PARALLEL (GET_MODE (src), vec);
+}
+
/* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
where SRC is non-consecutive registers represented by a PARALLEL.
SSIZE represents the total size of block ORIG_DST, or -1 if not
PARALLEL. */
extern void emit_group_load (rtx, rtx, tree, int);
+/* Similarly, but load into new temporaries. */
+extern rtx emit_group_load_into_temps (rtx, rtx, tree, int);
+
/* Move a non-consecutive group of registers represented by a PARALLEL into
a non-consecutive group of registers represented by a PARALLEL. */
extern void emit_group_move (rtx, rtx);
+/* Move a group of registers represented by a PARALLEL into pseudos. */
+extern rtx emit_group_move_into_temps (rtx);
+
/* Store a BLKmode value from non-consecutive registers represented by a
PARALLEL. */
extern void emit_group_store (rtx, rtx, tree, int);
present and valid in DATA->STACK_RTL. */
static void
-assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
+assign_parm_setup_block (struct assign_parm_data_all *all,
+ tree parm, struct assign_parm_data_one *data)
{
rtx entry_parm = data->entry_parm;
rtx stack_parm = data->stack_parm;
+ if (GET_CODE (entry_parm) == PARALLEL)
+ entry_parm = emit_group_move_into_temps (entry_parm);
+
/* If we've a non-block object that's nevertheless passed in parts,
reconstitute it in register operations rather than on the stack. */
if (GET_CODE (entry_parm) == PARALLEL
{
rtx parmreg = gen_reg_rtx (data->nominal_mode);
+ push_to_sequence (all->conversion_insns);
+
/* For values returned in multiple registers, handle possible
incompatible calls to emit_group_store.
else
emit_group_store (parmreg, entry_parm, data->nominal_type,
int_size_in_bytes (data->nominal_type));
+
+ all->conversion_insns = get_insns ();
+ end_sequence ();
+
SET_DECL_RTL (parm, parmreg);
return;
}
/* Handle values in multiple non-contiguous locations. */
if (GET_CODE (entry_parm) == PARALLEL)
- emit_group_store (mem, entry_parm, data->passed_type, size);
+ {
+ push_to_sequence (all->conversion_insns);
+ emit_group_store (mem, entry_parm, data->passed_type, size);
+ all->conversion_insns = get_insns ();
+ end_sequence ();
+ }
else if (size == 0)
;
{
rtx tem, x;
int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
- rtx reg = gen_rtx_REG (word_mode, REGNO (data->entry_parm));
+ rtx reg = gen_lowpart (word_mode, entry_parm);
x = expand_shift (LSHIFT_EXPR, word_mode, reg,
build_int_cst (NULL_TREE, by),
emit_move_insn (tem, x);
}
else
- move_block_from_reg (REGNO (data->entry_parm), mem,
+ move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD);
}
else
- move_block_from_reg (REGNO (data->entry_parm), mem,
+ move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD);
}
emit_move_insn (tempreg, DECL_RTL (parm));
tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p);
emit_move_insn (parmreg, tempreg);
- all->conversion_insns = get_insns();
+ all->conversion_insns = get_insns ();
end_sequence ();
did_conversion = true;
assign_parm_adjust_stack_rtl (&data);
if (assign_parm_setup_block_p (&data))
- assign_parm_setup_block (parm, &data);
+ assign_parm_setup_block (&all, parm, &data);
else if (data.passed_pointer || use_register_for_decl (parm))
assign_parm_setup_reg (&all, parm, &data);
else