Commit aac5cc16 by Richard Henderson Committed by Richard Henderson

expr.c (emit_group_load, [...]): Rewrite considering the size and alignment of…

expr.c (emit_group_load, [...]): Rewrite considering the size and alignment of the structure being manipulated.

        * expr.c (emit_group_load, emit_group_store): Rewrite considering
        the size and alignment of the structure being manipulated.
        * expr.c, calls.c, function.c: Update all callers.
        * expr.h: Update prototypes.
        * cse.c (invalidate): Cope with parallels.

From-SVN: r20867
parent 1eac9f59
Wed Jul 1 05:04:41 1998 Richard Henderson <rth@cygnus.com>
* expr.c (emit_group_load, emit_group_store): Rewrite considering
the size and alignment of the structure being manipulated.
* expr.c, calls.c, function.c: Update all callers.
* expr.h: Update prototypes.
* cse.c (invalidate): Cope with parallels.
Wed Jul 1 04:22:23 1998 Richard Henderson <rth@cygnus.com> Wed Jul 1 04:22:23 1998 Richard Henderson <rth@cygnus.com>
* sparc.c (function_arg_record_value): Take a MODE arg with which to * sparc.c (function_arg_record_value): Take a MODE arg with which to
......
...@@ -1922,7 +1922,12 @@ expand_call (exp, target, ignore) ...@@ -1922,7 +1922,12 @@ expand_call (exp, target, ignore)
locations. The Irix 6 ABI has examples of this. */ locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (reg) == PARALLEL) if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, args[i].value); {
emit_group_load (reg, args[i].value,
int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
(TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
/ BITS_PER_UNIT));
}
/* If simple case, just do move. If normal partial, store_one_arg /* If simple case, just do move. If normal partial, store_one_arg
has already loaded the register for us. In all other cases, has already loaded the register for us. In all other cases,
...@@ -2089,15 +2094,17 @@ expand_call (exp, target, ignore) ...@@ -2089,15 +2094,17 @@ expand_call (exp, target, ignore)
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
else if (GET_CODE (valreg) == PARALLEL) else if (GET_CODE (valreg) == PARALLEL)
{ {
int bytes = int_size_in_bytes (TREE_TYPE (exp));
if (target == 0) if (target == 0)
{ {
int bytes = int_size_in_bytes (TREE_TYPE (exp));
target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0); target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0);
MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp)); MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
preserve_temp_slots (target); preserve_temp_slots (target);
} }
emit_group_store (target, valreg); emit_group_store (target, valreg, bytes,
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
} }
else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
&& GET_MODE (target) == GET_MODE (valreg)) && GET_MODE (target) == GET_MODE (valreg))
......
...@@ -1609,6 +1609,24 @@ invalidate (x, full_mode) ...@@ -1609,6 +1609,24 @@ invalidate (x, full_mode)
return; return;
} }
/* If X is a parallel, invalidate all of its elements. */
if (GET_CODE (x) == PARALLEL)
{
for (i = XVECLEN (x, 0) - 1; i >= 0 ; --i)
invalidate (XVECEXP (x, 0, i), VOIDmode);
return;
}
/* If X is an expr_list, this is part of a disjoint return value;
extract the location in question ignoring the offset. */
if (GET_CODE (x) == EXPR_LIST)
{
invalidate (XEXP (x, 0), VOIDmode);
return;
}
/* X is not a register; it must be a memory reference with /* X is not a register; it must be a memory reference with
a nonvarying address. Remove all hash table elements a nonvarying address. Remove all hash table elements
that refer to overlapping pieces of memory. */ that refer to overlapping pieces of memory. */
......
...@@ -1822,103 +1822,187 @@ move_block_from_reg (regno, x, nregs, size) ...@@ -1822,103 +1822,187 @@ move_block_from_reg (regno, x, nregs, size)
} }
} }
/* Emit code to move a block Y to a block X, where X is non-consecutive /* Emit code to move a block SRC to a block DST, where DST is non-consecutive
registers represented by a PARALLEL. */ registers represented by a PARALLEL. SSIZE represents the total size of
block SRC in bytes, or -1 if not known. ALIGN is the known alignment of
SRC in bits. */
/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatent assumption that
the balance will be in what would be the low-order memory addresses, i.e.
left justified for big endian, right justified for little endian. This
happens to be true for the targets currently using this support. If this
ever changes, a new target macro along the lines of FUNCTION_ARG_PADDING
would be needed. */
void void
emit_group_load (x, y) emit_group_load (dst, orig_src, ssize, align)
rtx x, y; rtx dst, orig_src;
int align, ssize;
{ {
rtx target_reg, source; rtx *tmps, src;
int i; int start, i;
if (GET_CODE (x) != PARALLEL) if (GET_CODE (dst) != PARALLEL)
abort (); abort ();
/* Check for a NULL entry, used to indicate that the parameter goes /* Check for a NULL entry, used to indicate that the parameter goes
both on the stack and in registers. */ both on the stack and in registers. */
if (XEXP (XVECEXP (x, 0, 0), 0)) if (XEXP (XVECEXP (dst, 0, 0), 0))
i = 0; start = 0;
else else
i = 1; start = 1;
for (; i < XVECLEN (x, 0); i++) tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (dst, 0));
{
rtx element = XVECEXP (x, 0, i); /* If we won't be loading directly from memory, protect the real source
from strange tricks we might play. */
target_reg = XEXP (element, 0); src = orig_src;
if (GET_CODE (src) != MEM)
if (GET_CODE (y) == MEM) {
source = change_address (y, GET_MODE (target_reg), src = gen_reg_rtx (GET_MODE (orig_src));
plus_constant (XEXP (y, 0), emit_move_insn (src, orig_src);
INTVAL (XEXP (element, 1)))); }
else if (XEXP (element, 1) == const0_rtx)
{ /* Process the pieces. */
if (GET_MODE (target_reg) == GET_MODE (y)) for (i = start; i < XVECLEN (dst, 0); i++)
source = y; {
/* Allow for the target_reg to be smaller than the input register enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
to allow for AIX with 4 DF arguments after a single SI arg. The int bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
last DF argument will only load 1 word into the integer registers, int bytelen = GET_MODE_SIZE (mode);
but load a DF value into the float registers. */ int shift = 0;
else if ((GET_MODE_SIZE (GET_MODE (target_reg))
<= GET_MODE_SIZE (GET_MODE (y))) /* Handle trailing fragments that run over the size of the struct. */
&& GET_MODE (target_reg) == word_mode) if (ssize >= 0 && bytepos + bytelen > ssize)
/* This might be a const_double, so we can't just use SUBREG. */ {
source = operand_subword (y, 0, 0, VOIDmode); shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
else if (GET_MODE_SIZE (GET_MODE (target_reg)) bytelen = ssize - bytepos;
== GET_MODE_SIZE (GET_MODE (y))) if (bytelen <= 0)
source = gen_lowpart (GET_MODE (target_reg), y); abort();
else }
abort ();
/* Optimize the access just a bit. */
if (GET_CODE (src) == MEM
&& align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
&& bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
{
tmps[i] = gen_reg_rtx (mode);
emit_move_insn (tmps[i],
change_address (src, mode,
plus_constant (XEXP (src, 0),
bytepos)));
} }
else else
abort (); {
tmps[i] = extract_bit_field (src, bytelen*BITS_PER_UNIT,
bytepos*BITS_PER_UNIT, 1, NULL_RTX,
mode, mode, align, ssize);
}
emit_move_insn (target_reg, source); if (BYTES_BIG_ENDIAN && shift)
{
expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
tmps[i], 0, OPTAB_WIDEN);
}
} }
emit_queue();
/* 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]);
} }
/* Emit code to move a block Y to a block X, where Y is non-consecutive /* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
registers represented by a PARALLEL. */ registers represented by a PARALLEL. SSIZE represents the total size of
block DST, or -1 if not known. ALIGN is the known alignment of DST. */
void void
emit_group_store (x, y) emit_group_store (orig_dst, src, ssize, align)
rtx x, y; rtx orig_dst, src;
int ssize, align;
{ {
rtx source_reg, target; rtx *tmps, dst;
int i; int start, i;
if (GET_CODE (y) != PARALLEL) if (GET_CODE (src) != PARALLEL)
abort (); abort ();
/* Check for a NULL entry, used to indicate that the parameter goes /* Check for a NULL entry, used to indicate that the parameter goes
both on the stack and in registers. */ both on the stack and in registers. */
if (XEXP (XVECEXP (y, 0, 0), 0)) if (XEXP (XVECEXP (src, 0, 0), 0))
i = 0; start = 0;
else else
i = 1; start = 1;
for (; i < XVECLEN (y, 0); i++) tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (src, 0));
/* Copy the (probable) hard regs into pseudos. */
for (i = start; i < XVECLEN (src, 0); i++)
{ {
rtx element = XVECEXP (y, 0, i); rtx reg = XEXP (XVECEXP (src, 0, i), 0);
tmps[i] = gen_reg_rtx (GET_MODE (reg));
emit_move_insn (tmps[i], reg);
}
emit_queue();
source_reg = XEXP (element, 0); /* If we won't be storing directly into memory, protect the real destination
from strange tricks we might play. */
dst = orig_dst;
if (GET_CODE (dst) != MEM)
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
/* Make life a bit easier for combine. */
emit_move_insn (dst, const0_rtx);
}
else if (! MEM_IN_STRUCT_P (dst))
{
/* store_bit_field requires that memory operations have
mem_in_struct_p set; we might not. */
if (GET_CODE (x) == MEM) dst = copy_rtx (orig_dst);
target = change_address (x, GET_MODE (source_reg), MEM_IN_STRUCT_P (dst) = 1;
plus_constant (XEXP (x, 0), }
INTVAL (XEXP (element, 1))));
else if (XEXP (element, 1) == const0_rtx) /* Process the pieces. */
for (i = start; i < XVECLEN (src, 0); i++)
{
int bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
enum machine_mode mode = GET_MODE (tmps[i]);
int bytelen = GET_MODE_SIZE (mode);
/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + bytelen > ssize)
{ {
target = x; if (BYTES_BIG_ENDIAN)
if (GET_MODE (target) != GET_MODE (source_reg)) {
target = gen_lowpart (GET_MODE (source_reg), target); int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
tmps[i], 0, OPTAB_WIDEN);
}
bytelen = ssize - bytepos;
} }
else
abort ();
emit_move_insn (target, source_reg); /* Optimize the access just a bit. */
if (GET_CODE (dst) == MEM
&& align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
&& bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
{
emit_move_insn (change_address (dst, mode,
plus_constant (XEXP (dst, 0),
bytepos)),
tmps[i]);
}
else
{
store_bit_field (dst, bytelen*BITS_PER_UNIT, bytepos*BITS_PER_UNIT,
mode, tmps[i], align, ssize);
}
} }
emit_queue();
/* Copy from the pseudo into the (probable) hard reg. */
if (GET_CODE (dst) == REG)
emit_move_insn (orig_dst, dst);
} }
/* Add a USE expression for REG to the (possibly empty) list pointed /* Add a USE expression for REG to the (possibly empty) list pointed
...@@ -2862,7 +2946,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, ...@@ -2862,7 +2946,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
/* Handle calls that pass values in multiple non-contiguous locations. /* Handle calls that pass values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
if (GET_CODE (reg) == PARALLEL) if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x); emit_group_load (reg, x, -1, align); /* ??? size? */
else else
move_block_to_reg (REGNO (reg), x, partial, mode); move_block_to_reg (REGNO (reg), x, partial, mode);
} }
...@@ -3071,7 +3155,8 @@ expand_assignment (to, from, want_value, suggest_reg) ...@@ -3071,7 +3155,8 @@ expand_assignment (to, from, want_value, suggest_reg)
/* Handle calls that return values in multiple non-contiguous locations. /* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
if (GET_CODE (to_rtx) == PARALLEL) if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, value); emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
else if (GET_MODE (to_rtx) == BLKmode) 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),
TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT); TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
...@@ -3476,7 +3561,8 @@ store_expr (exp, target, want_value) ...@@ -3476,7 +3561,8 @@ store_expr (exp, target, want_value)
/* Handle calls that return values in multiple non-contiguous locations. /* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
else if (GET_CODE (target) == PARALLEL) else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp); emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
else if (GET_MODE (temp) == BLKmode) else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp), emit_block_move (target, temp, expr_size (exp),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
......
...@@ -714,10 +714,10 @@ extern void move_block_from_reg PROTO((int, rtx, int, int)); ...@@ -714,10 +714,10 @@ extern void move_block_from_reg PROTO((int, rtx, int, int));
/* Load a BLKmode value into non-consecutive registers represented by a /* Load a BLKmode value into non-consecutive registers represented by a
PARALLEL. */ PARALLEL. */
extern void emit_group_load PROTO((rtx, rtx)); extern void emit_group_load PROTO((rtx, rtx, int, int));
/* Store a BLKmode value from non-consecutive registers represented by a /* Store a BLKmode value from non-consecutive registers represented by a
PARALLEL. */ PARALLEL. */
extern void emit_group_store PROTO((rtx, rtx)); extern void emit_group_store PROTO((rtx, rtx, int, int));
/* Mark REG as holding a parameter for the next CALL_INSN. */ /* Mark REG as holding a parameter for the next CALL_INSN. */
extern void use_reg PROTO((rtx *, rtx)); extern void use_reg PROTO((rtx *, rtx));
......
...@@ -3945,8 +3945,10 @@ assign_parms (fndecl, second_time) ...@@ -3945,8 +3945,10 @@ assign_parms (fndecl, second_time)
/* Handle calls that pass values in multiple non-contiguous /* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */ locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (entry_parm) == PARALLEL) if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), emit_group_store (validize_mem (stack_parm), entry_parm,
entry_parm); int_size_in_bytes (TREE_TYPE (parm)),
(TYPE_ALIGN (TREE_TYPE (parm))
/ BITS_PER_UNIT));
else else
move_block_from_reg (REGNO (entry_parm), move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm), nregs, validize_mem (stack_parm), nregs,
...@@ -4116,7 +4118,10 @@ assign_parms (fndecl, second_time) ...@@ -4116,7 +4118,10 @@ assign_parms (fndecl, second_time)
/* Handle calls that pass values in multiple non-contiguous /* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */ locations. The Irix 6 ABI has examples of this. */
if (GET_CODE (entry_parm) == PARALLEL) if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), entry_parm); emit_group_store (validize_mem (stack_parm), entry_parm,
int_size_in_bytes (TREE_TYPE (parm)),
(TYPE_ALIGN (TREE_TYPE (parm))
/ BITS_PER_UNIT));
else else
move_block_from_reg (REGNO (entry_parm), move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm), validize_mem (stack_parm),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment