aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2004-11-13 22:22:56 -0800
committerRichard Henderson <rth@gcc.gnu.org>2004-11-13 22:22:56 -0800
commit27e29549a03c1c71c56abb27767d8393f7d0e65e (patch)
tree289c94268246a21e58d4318a10556bfb945f4896 /gcc
parenteaf0dc0254ab1fafb2a22b12ad336a23eae0197b (diff)
downloadgcc-27e29549a03c1c71c56abb27767d8393f7d0e65e.zip
gcc-27e29549a03c1c71c56abb27767d8393f7d0e65e.tar.gz
gcc-27e29549a03c1c71c56abb27767d8393f7d0e65e.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/calls.c34
-rw-r--r--gcc/expr.c93
-rw-r--r--gcc/expr.h6
-rw-r--r--gcc/function.c29
5 files changed, 143 insertions, 32 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index de89cb0..82ca433 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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,
diff --git a/gcc/calls.c b/gcc/calls.c
index cfcf01c..e66181e 100644
--- a/gcc/calls.c
+++ b/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,
diff --git a/gcc/expr.c b/gcc/expr.c
index 6037fd1..59da4fd 100644
--- a/gcc/expr.c
+++ b/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
diff --git a/gcc/expr.h b/gcc/expr.h
index 21ff1f4..feac478 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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);
diff --git a/gcc/function.c b/gcc/function.c
index 1882901..e4e04d2 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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