From 27e29549a03c1c71c56abb27767d8393f7d0e65e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 13 Nov 2004 22:22:56 -0800 Subject: [PATCH] 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 --- gcc/ChangeLog | 13 +++++++ gcc/calls.c | 34 +++++++++++------- gcc/expr.c | 93 +++++++++++++++++++++++++++++++++++++++++++------- gcc/expr.h | 6 ++++ gcc/function.c | 29 ++++++++++++---- 5 files changed, 143 insertions(+), 32 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index de89cb014687..82ca433c09fe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-11-13 Richard Henderson + + * 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 * tree-cfg.c, tree-if-conv.c, tree-ssa-loop-ivopts.c, diff --git a/gcc/calls.c b/gcc/calls.c index cfcf01cf4673..e66181e9f9fc 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 6037fd12a101..59da4fdbdea5 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 21ff1f414018..feac478a5abf 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 18829019e516..e4e04d2a53d7 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 -- 2.43.5