summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog21
-rw-r--r--gcc/builtins.c7
-rw-r--r--gcc/calls.c54
-rw-r--r--gcc/config/sh/sh.c2
-rw-r--r--gcc/config/sparc/sparc.c3
-rw-r--r--gcc/expr.c185
-rw-r--r--gcc/expr.h10
-rw-r--r--gcc/function.c2
8 files changed, 230 insertions, 54 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1c9311fa473..b2dcdf12dc5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index a295a9aab34..b2ad5375b77 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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;
diff --git a/gcc/calls.c b/gcc/calls.c
index 5979747a68b..2e238094ffb 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -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
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index e49881ba866..a6ce2be9d17 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -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);
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 971b6f2e5f7..4a83b8a5612 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -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
diff --git a/gcc/expr.c b/gcc/expr.c
index b95de65fb27..700b84084da 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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;
- emit_block_move (target, xinner, size);
+ /* 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);
- 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;
}
diff --git a/gcc/expr.h b/gcc/expr.h
index 76b5c809e8e..c3a1009a12a 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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. */
diff --git a/gcc/function.c b/gcc/function.c
index 5d5300192fe..f1381fb9351 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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 ();
OpenPOWER on IntegriCloud