expr.h (enum block_op_methods): New.

* expr.h (enum block_op_methods): New.
        (emit_block_move): Update prototype.
        * expr.c (block_move_libcall_safe_for_call_parm): New.
        (emit_block_move_via_loop): New.
        (emit_block_move): Use them.  New argument METHOD.
        (emit_push_insn): Always respect the given alignment.
        (expand_assignment): Update call to emit_block_move.
        (store_expr, store_field, expand_expr): Likewise.
        * builtins.c (expand_builtin_apply): Likewise.
        (expand_builtin_memcpy, expand_builtin_va_copy): Likewise.
        * function.c (expand_function_end): Likewise.
        * config/sh/sh.c (sh_initialize_trampoline): Likewise.
        * config/sparc/sparc.c (sparc_va_arg): Likewise.
        * calls.c (expand_call, emit_library_call_value_1): Likewise.
        (save_fixed_argument_area): Use emit_block_move with
        BLOCK_OP_CALL_PARM instead of move_by_pieces.
        (restore_fixed_argument_area): Likewise.
        (store_one_arg): Fix alignment parameter to emit_push_insn.

From-SVN: r56661
This commit is contained in:
Richard Henderson 2002-08-29 12:20:01 -07:00 committed by Richard Henderson
parent 08b3d1047a
commit 44bb111a78
8 changed files with 230 additions and 54 deletions

View File

@ -1,3 +1,24 @@
2002-08-29 Richard Henderson <rth@redhat.com>
* expr.h (enum block_op_methods): New.
(emit_block_move): Update prototype.
* expr.c (block_move_libcall_safe_for_call_parm): New.
(emit_block_move_via_loop): New.
(emit_block_move): Use them. New argument METHOD.
(emit_push_insn): Always respect the given alignment.
(expand_assignment): Update call to emit_block_move.
(store_expr, store_field, expand_expr): Likewise.
* builtins.c (expand_builtin_apply): Likewise.
(expand_builtin_memcpy, expand_builtin_va_copy): Likewise.
* function.c (expand_function_end): Likewise.
* config/sh/sh.c (sh_initialize_trampoline): Likewise.
* config/sparc/sparc.c (sparc_va_arg): Likewise.
* calls.c (expand_call, emit_library_call_value_1): Likewise.
(save_fixed_argument_area): Use emit_block_move with
BLOCK_OP_CALL_PARM instead of move_by_pieces.
(restore_fixed_argument_area): Likewise.
(store_one_arg): Fix alignment parameter to emit_push_insn.
2002-08-29 John David Anglin <dave@hiauly1.hia.nrc.ca>
* install.texi (hppa64-hp-hpux11*): Document installation procedure.

View File

@ -1225,7 +1225,7 @@ expand_builtin_apply (function, arguments, argsize)
set_mem_align (dest, PARM_BOUNDARY);
src = gen_rtx_MEM (BLKmode, incoming_args);
set_mem_align (src, PARM_BOUNDARY);
emit_block_move (dest, src, argsize);
emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
/* Refer to the argument block. */
apply_args_size ();
@ -2000,7 +2000,8 @@ expand_builtin_memcpy (arglist, target, mode)
set_mem_align (src_mem, src_align);
/* Copy word part most expediently. */
dest_addr = emit_block_move (dest_mem, src_mem, len_rtx);
dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
BLOCK_OP_NORMAL);
if (dest_addr == 0)
{
@ -3298,7 +3299,7 @@ expand_builtin_va_copy (arglist)
set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
/* Copy. */
emit_block_move (dstb, srcb, size);
emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
}
return const0_rtx;

View File

@ -967,11 +967,8 @@ save_fixed_argument_area (reg_parm_stack_space, argblock,
if (save_mode == BLKmode)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
/* Cannot use emit_block_move here because it can be done by a
library call which in turn gets into this place again and deadly
infinite recursion happens. */
move_by_pieces (validize_mem (save_area), stack_area, num_to_save,
PARM_BOUNDARY);
emit_block_move (validize_mem (save_area), stack_area,
GEN_INT (num_to_save), BLOCK_OP_CALL_PARM);
}
else
{
@ -1008,11 +1005,9 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save)
if (save_mode != BLKmode)
emit_move_insn (stack_area, save_area);
else
/* Cannot use emit_block_move here because it can be done by a library
call which in turn gets into this place again and deadly infinite
recursion happens. */
move_by_pieces (stack_area, validize_mem (save_area),
high_to_save - low_to_save + 1, PARM_BOUNDARY);
emit_block_move (stack_area, validize_mem (save_area),
GEN_INT (high_to_save - low_to_save + 1),
BLOCK_OP_CALL_PARM);
}
#endif /* REG_PARM_STACK_SPACE */
@ -3317,9 +3312,9 @@ expand_call (exp, target, ignore)
if (save_mode != BLKmode)
emit_move_insn (stack_area, args[i].save_area);
else
emit_block_move (stack_area,
validize_mem (args[i].save_area),
GEN_INT (args[i].size.constant));
emit_block_move (stack_area, args[i].save_area,
GEN_INT (args[i].size.constant),
BLOCK_OP_CALL_PARM);
}
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
@ -3909,8 +3904,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
set_mem_align (save_area, PARM_BOUNDARY);
emit_block_move (validize_mem (save_area), stack_area,
GEN_INT (num_to_save));
emit_block_move (save_area, stack_area, GEN_INT (num_to_save),
BLOCK_OP_CALL_PARM);
}
else
{
@ -3978,8 +3973,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
}
}
emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
argblock, GEN_INT (argvec[argnum].offset.constant),
emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY,
partial, reg, 0, argblock,
GEN_INT (argvec[argnum].offset.constant),
reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
/* Now mark the segment we just used. */
@ -4180,8 +4176,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
if (save_mode != BLKmode)
emit_move_insn (stack_area, save_area);
else
emit_block_move (stack_area, validize_mem (save_area),
GEN_INT (high_to_save - low_to_save + 1));
emit_block_move (stack_area, save_area,
GEN_INT (high_to_save - low_to_save + 1),
BLOCK_OP_CALL_PARM);
}
#endif
@ -4358,7 +4355,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
arg->save_area = assign_temp (nt, 0, 1, 1);
preserve_temp_slots (arg->save_area);
emit_block_move (validize_mem (arg->save_area), stack_area,
expr_size (arg->tree_value));
expr_size (arg->tree_value),
BLOCK_OP_CALL_PARM);
}
else
{
@ -4479,8 +4477,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0,
partial, reg, used - size, argblock,
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
PARM_BOUNDARY, partial, reg, used - size, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
@ -4574,18 +4572,18 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
{
rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
TYPE_ALIGN (TREE_TYPE (pval)), partial, reg,
excess, argblock, ARGS_SIZE_RTX (arg->offset),
reg_parm_stack_space,
MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
partial, reg, excess, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
}
}
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, excess,
argblock, ARGS_SIZE_RTX (arg->offset),
reg_parm_stack_space,
MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
partial, reg, excess, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
/* Unless this is a partially-in-register argument, the argument is now

View File

@ -7301,7 +7301,7 @@ sh_initialize_trampoline (tramp, fnaddr, cxt)
src = gen_rtx_MEM (BLKmode, tramp_templ);
set_mem_align (dst, 256);
set_mem_align (src, 64);
emit_block_move (dst, src, GEN_INT (fixed_len));
emit_block_move (dst, src, GEN_INT (fixed_len), BLOCK_OP_NORMAL);
emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (tramp, fixed_len)),
fnaddr);

View File

@ -5347,7 +5347,8 @@ sparc_va_arg (valist, type)
PUT_MODE (tmp, BLKmode);
set_mem_alias_set (tmp, 0);
dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize));
dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
BLOCK_OP_NORMAL);
if (dest_addr != NULL_RTX)
addr_rtx = dest_addr;
else

View File

@ -132,9 +132,11 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns
unsigned int));
static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
static bool block_move_libcall_safe_for_call_parm PARAMS ((void));
static bool emit_block_move_via_movstr PARAMS ((rtx, rtx, rtx, unsigned));
static rtx emit_block_move_via_libcall PARAMS ((rtx, rtx, rtx));
static tree emit_block_move_libcall_fn PARAMS ((int));
static void emit_block_move_via_loop PARAMS ((rtx, rtx, rtx, unsigned));
static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
@ -1677,16 +1679,43 @@ move_by_pieces_1 (genfun, mode, data)
Both X and Y must be MEM rtx's (perhaps inside VOLATILE) with mode BLKmode.
SIZE is an rtx that says how long they are.
ALIGN is the maximum alignment we can assume they have.
METHOD describes what kind of copy this is, and what mechanisms may be used.
Return the address of the new block, if memcpy is called and returns it,
0 otherwise. */
rtx
emit_block_move (x, y, size)
emit_block_move (x, y, size, method)
rtx x, y, size;
enum block_op_methods method;
{
bool may_use_call;
rtx retval = 0;
unsigned int align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
unsigned int align;
switch (method)
{
case BLOCK_OP_NORMAL:
may_use_call = true;
break;
case BLOCK_OP_CALL_PARM:
may_use_call = block_move_libcall_safe_for_call_parm ();
/* Make inhibit_defer_pop nonzero around the library call
to force it to pop the arguments right away. */
NO_DEFER_POP;
break;
case BLOCK_OP_NO_LIBCALL:
may_use_call = false;
break;
default:
abort ();
}
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
if (GET_MODE (x) != BLKmode)
abort ();
@ -1708,12 +1737,77 @@ emit_block_move (x, y, size)
move_by_pieces (x, y, INTVAL (size), align);
else if (emit_block_move_via_movstr (x, y, size, align))
;
else
else if (may_use_call)
retval = emit_block_move_via_libcall (x, y, size);
else
emit_block_move_via_loop (x, y, size, align);
if (method == BLOCK_OP_CALL_PARM)
OK_DEFER_POP;
return retval;
}
/* A subroutine of emit_block_move. Returns true if calling the
block move libcall will not clobber any parameters which may have
already been placed on the stack. */
static bool
block_move_libcall_safe_for_call_parm ()
{
if (PUSH_ARGS)
return true;
else
{
/* Check to see whether memcpy takes all register arguments. */
static enum {
takes_regs_uninit, takes_regs_no, takes_regs_yes
} takes_regs = takes_regs_uninit;
switch (takes_regs)
{
case takes_regs_uninit:
{
CUMULATIVE_ARGS args_so_far;
tree fn, arg;
fn = emit_block_move_libcall_fn (false);
INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0);
arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
enum machine_mode mode
= TYPE_MODE (TREE_TYPE (TREE_VALUE (arg)));
rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
if (!tmp || !REG_P (tmp))
goto fail_takes_regs;
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
NULL_TREE, 1))
goto fail_takes_regs;
#endif
FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
}
}
takes_regs = takes_regs_yes;
/* FALLTHRU */
case takes_regs_yes:
return true;
fail_takes_regs:
takes_regs = takes_regs_no;
/* FALLTHRU */
case takes_regs_no:
return false;
default:
abort ();
}
}
}
/* A subroutine of emit_block_move. Expand a movstr pattern;
return true if successful. */
@ -1919,6 +2013,59 @@ emit_block_move_libcall_fn (for_call)
return fn;
}
/* A subroutine of emit_block_move. Copy the data via an explicit
loop. This is used only when libcalls are forbidden. */
/* ??? It'd be nice to copy in hunks larger than QImode. */
static void
emit_block_move_via_loop (x, y, size, align)
rtx x, y, size;
unsigned int align ATTRIBUTE_UNUSED;
{
rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
enum machine_mode iter_mode;
iter_mode = GET_MODE (size);
if (iter_mode == VOIDmode)
iter_mode = word_mode;
top_label = gen_label_rtx ();
cmp_label = gen_label_rtx ();
iter = gen_reg_rtx (iter_mode);
emit_move_insn (iter, const0_rtx);
x_addr = force_operand (XEXP (x, 0), NULL_RTX);
y_addr = force_operand (XEXP (y, 0), NULL_RTX);
do_pending_stack_adjust ();
emit_note (NULL, NOTE_INSN_LOOP_BEG);
emit_jump (cmp_label);
emit_label (top_label);
tmp = convert_modes (Pmode, iter_mode, iter, true);
x_addr = gen_rtx_PLUS (Pmode, x_addr, tmp);
y_addr = gen_rtx_PLUS (Pmode, y_addr, tmp);
x = change_address (x, QImode, x_addr);
y = change_address (y, QImode, y_addr);
emit_move_insn (x, y);
tmp = expand_simple_binop (iter_mode, PLUS, iter, const1_rtx, iter,
true, OPTAB_LIB_WIDEN);
if (tmp != iter)
emit_move_insn (iter, tmp);
emit_note (NULL, NOTE_INSN_LOOP_CONT);
emit_label (cmp_label);
emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode,
true, top_label);
emit_note (NULL, NOTE_INSN_LOOP_END);
}
/* Copy all or part of a value X into registers starting at REGNO.
The number of registers to be filled is NREGS. */
@ -3623,16 +3770,12 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
of sibling calls. */
set_mem_alias_set (target, 0);
}
else
set_mem_align (target, align);
/* Make inhibit_defer_pop nonzero around the library call
to force it to pop the bcopy-arguments right away. */
NO_DEFER_POP;
/* ALIGN may well be better aligned than TYPE, e.g. due to
PARM_BOUNDARY. Assume the caller isn't lying. */
set_mem_align (target, align);
emit_block_move (target, xinner, size);
OK_DEFER_POP;
emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM);
}
}
else if (partial > 0)
@ -3951,7 +4094,7 @@ expand_assignment (to, from, want_value, suggest_reg)
if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)));
else if (GET_MODE (to_rtx) == BLKmode)
emit_block_move (to_rtx, value, expr_size (from));
emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
else
{
#ifdef POINTERS_EXTEND_UNSIGNED
@ -4312,7 +4455,7 @@ store_expr (exp, target, want_value)
if (GET_CODE (size) == CONST_INT
&& INTVAL (size) < TREE_STRING_LENGTH (exp))
emit_block_move (target, temp, size);
emit_block_move (target, temp, size, BLOCK_OP_NORMAL);
else
{
/* Compute the size of the data to copy from the string. */
@ -4326,7 +4469,7 @@ store_expr (exp, target, want_value)
/* Copy that much. */
copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
emit_block_move (target, temp, copy_size_rtx);
emit_block_move (target, temp, copy_size_rtx, BLOCK_OP_NORMAL);
/* Figure out how much is left in TARGET that we have to clear.
Do all calculations in ptr_mode. */
@ -4367,7 +4510,7 @@ store_expr (exp, target, want_value)
else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp));
emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL);
else
emit_move_insn (target, temp);
}
@ -5295,7 +5438,8 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
emit_block_move (target, temp,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT));
/ BITS_PER_UNIT),
BLOCK_OP_NORMAL);
return value_mode == VOIDmode ? const0_rtx : target;
}
@ -7218,7 +7362,8 @@ expand_expr (exp, target, tmode, modifier)
emit_block_move (target, op0,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT));
/ BITS_PER_UNIT),
BLOCK_OP_NORMAL);
return target;
}
@ -7634,7 +7779,8 @@ expand_expr (exp, target, tmode, modifier)
if (GET_MODE (op0) == BLKmode)
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))));
GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
BLOCK_OP_NORMAL);
else
emit_move_insn (new_with_op0_mode, op0);
@ -8856,7 +9002,8 @@ expand_expr (exp, target, tmode, modifier)
if (TYPE_ALIGN_OK (inner_type))
abort ();
emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)));
emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
BLOCK_OP_NORMAL);
op0 = new;
}

View File

@ -394,7 +394,15 @@ extern rtx convert_modes PARAMS ((enum machine_mode, enum machine_mode,
rtx, int));
/* Emit code to move a block Y to a block X. */
extern rtx emit_block_move PARAMS ((rtx, rtx, rtx));
enum block_op_methods
{
BLOCK_OP_NORMAL,
BLOCK_OP_CALL_PARM,
BLOCK_OP_NO_LIBCALL
};
extern rtx emit_block_move PARAMS ((rtx, rtx, rtx, enum block_op_methods));
/* Copy all or part of a value X into registers starting at REGNO.
The number of registers to be filled is NREGS. */

View File

@ -6807,7 +6807,7 @@ expand_function_end (filename, line, end_bindings)
#ifdef TRAMPOLINE_TEMPLATE
blktramp = replace_equiv_address (initial_trampoline, tramp);
emit_block_move (blktramp, initial_trampoline,
GEN_INT (TRAMPOLINE_SIZE));
GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
#endif
INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
seq = get_insns ();