calls.c (precompute_register_parameters): Force all PARALLELs into pseudo registers.
* 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. From-SVN: r90613
This commit is contained in:
parent
eaf0dc0254
commit
27e29549a0
5 changed files with 143 additions and 32 deletions
|
@ -1,3 +1,16 @@
|
|||
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,
|
||||
|
|
34
gcc/calls.c
34
gcc/calls.c
|
@ -644,7 +644,8 @@ call_expr_flags (tree t)
|
|||
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;
|
||||
|
||||
|
@ -679,6 +680,17 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg
|
|||
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.
|
||||
|
@ -687,13 +699,13 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *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);
|
||||
}
|
||||
}
|
||||
|
@ -1454,11 +1466,7 @@ load_register_parameters (struct arg_data *args, int num_actuals,
|
|||
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,
|
||||
|
|
93
gcc/expr.c
93
gcc/expr.c
|
@ -1557,15 +1557,14 @@ gen_group_rtx (rtx orig)
|
|||
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);
|
||||
|
||||
|
@ -1585,7 +1584,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
|
|||
/* ...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;
|
||||
}
|
||||
|
||||
|
@ -1596,8 +1595,6 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
|
|||
else
|
||||
start = 1;
|
||||
|
||||
tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
|
||||
|
||||
/* Process the pieces. */
|
||||
for (i = start; i < XVECLEN (dst, 0); i++)
|
||||
{
|
||||
|
@ -1709,10 +1706,61 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
|
|||
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
|
||||
|
@ -1733,6 +1781,27 @@ emit_group_move (rtx dst, rtx src)
|
|||
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
|
||||
|
|
|
@ -387,10 +387,16 @@ extern rtx gen_group_rtx (rtx);
|
|||
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);
|
||||
|
|
|
@ -2536,11 +2536,15 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
|
|||
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
|
||||
|
@ -2550,6 +2554,8 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
|
|||
{
|
||||
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.
|
||||
|
||||
|
@ -2572,6 +2578,10 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
|
|||
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;
|
||||
}
|
||||
|
@ -2609,7 +2619,12 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
|
|||
|
||||
/* 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)
|
||||
;
|
||||
|
@ -2648,7 +2663,7 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
|
|||
{
|
||||
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),
|
||||
|
@ -2657,11 +2672,11 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -2782,7 +2797,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
|
|||
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;
|
||||
|
@ -3083,7 +3098,7 @@ assign_parms (tree fndecl)
|
|||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue