Fix consistency problems with reg_equiv_{mem,address};

Improve reload inheritance;
        * reload.c (reload_out_reg): New variable.
        (loc_mentioned_in_p, remove_address_replacements): New functions.
        (remove_replacements): Deleted.
        (push_reload): Set reload_out_reg[i].
        When merging, also set reload_{in,out}_reg[i], and remove
        duplicate address reloads.
        (combine_reloads): Copy reload_out_reg[i].
        (find_reloads): Do make_memloc substitution also when
        reg_equiv_memory_loc[regno] and num_not_at_initial_offset
        are both nonzero.
        Include *recog_operand_loc in commutativity operand changes.
        Generate optional output reloads.
        Delete reference to n_memlocs.  Don't set *recog_operand_loc before
        processing operands.  Call make_memloc in reg_equiv_address code.
        Set *recog_operand_loc only after processing operands, and only
        if replace is true.  Return a value.
        When changing address reload types for operands that didn't get
        reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
        RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
        Don't emit USEs for pseudo SUBREGs when not replacing.
        (find_reloads_address): Do make_memloc substitution also when
        reg_equiv_memory_loc[regno] and num_not_at_initial_offset
        are both nonzero.
        (find_reloads_toplev): Likewise.
        Call make_memloc in reg_equiv_address code.
        (debug_reload_to_stream): Add code to output reload_out_reg.
        (make_memloc): Delete local variable i, ifdefed out code, and
        references to memlocs and n_memlocs.
        (memlocs, n_memlocs): Delete.
        (push_secondary_reload): Clear reload_out_reg.
        (find_reloads_address_1): Provide memrefloc argument to all calls
        to find_reloads_address.
        In AUTO_INC code, handle non-directly addressable equivalences properly.
        * reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
        (find_reloads): Add return type.
        (remove_address_replacements, deallocate_reload_reg): Declare.
        * reload1.c (num_not_at_initial_offset): No longer static.
        (delete_address_reloads, delete_address_reloads_1): Likewise.
        (deallocate_reload_reg): New function.
        (spill_reg_stored_to): New array.
        (eliminate_regs): Don't substitute from reg_equiv_memory_loc.
        (eliminate_regs_in_insn): Move assignments of previous_offset and
        max_offset fields, and recalculation of num_not_at_initial_offset
        into new static function:
        (update_eliminable_offsets) .
        (reload_as_needed): Call update_eliminable_offsetss after calling
        find_reloads.
        Call forget_old_reloads_1 with contents of reloaded auto_inc
        expressions if the actual addressing can't be changed to match the
        auto_inc.
        (choose_reload_regs): For inheritance, replace
        reload_reg_free_before_p test with reload_reg_ions.
        (emit_reload_insns): If reload_in is a MEM, set OLD to
        reload_in_reg[j].
        Don't reload directly from oldequiv; if it's a pseudo with a
        stack slot, use reload_in[j].
        Check that reload_in_reg[j] is a MEM before replacing reload_in
        from reg_reloaded_contents.
        Include non-spill registers in reload inheritance processing.
        Also try to use reload_out_reg to set spill_reg_store /
        reg_last_reload_reg.
        In code to set new_spill_reg_store, use single_set to find out if
        there is a single set.
        Add code that allows to delete optional output reloads.
        Add code to allow deletion of output reloads that use no spill reg.
        At the end, set reload_override_in to oldequiv.
        Also call delete_output_reload if reload_out_reg is equal to old
        in oldequiv code.
        Add code to call delete_output_reload for stores with no matching load.
        Set / use spill_reg_stored_to.
        Handle case where secondary output reload uses a temporary, but
        actual store isn't found.
        When looking for a store of a value not loaded in order to call
        delete_output_reload, count_occurences should return 0 for no
        loads; but discount inherited input reloadill_reg_stored_to.
        Do checks for extra uses of REG.  Changed all
        callers.
        Use delete_address_reloads.
        (reload): Take return value of find_reloads into account.
        If a no-op set needs more than one reload, delete it.
        (reload_reg_free_before_p): RELOAD_FOR_INPUT
        can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
        for the same operand.
        (clear_reload_reg_in_use): Check for other reloads that keep a
        register in use.
        (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
        RELOAD_FOR_OPADDR_ADDR.
        Take into account when an address address reload is only needed
        for the address reload we are considering.
        (count_occurrences): Use rtx_equal_p for MEMs.
        (inc_for_reload): Return instruction that stores into RELOADREG.
        New argument two, IN, and rtx.  Changed all callers.
        (calculate_needs_all_insns, reload_as_needed):
        Don't clear after_call for a CLOBBER.
        Keep track of how many hard registers need to be copied from
        after_call, and don't clear after_call before we have seen
        that much copies, or we see a different instruction.

From-SVN: r23143
This commit is contained in:
J"orn Rennecke 1998-10-16 19:54:38 +00:00 committed by Jeff Law
parent c583dd46ad
commit cb2afeb31e
4 changed files with 1384 additions and 496 deletions

View File

@ -1,3 +1,114 @@
Fri Oct 16 20:40:50 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
Fix consistency problems with reg_equiv_{mem,address};
Improve reload inheritance;
* reload.c (reload_out_reg): New variable.
(loc_mentioned_in_p, remove_address_replacements): New functions.
(remove_replacements): Deleted.
(push_reload): Set reload_out_reg[i].
When merging, also set reload_{in,out}_reg[i], and remove
duplicate address reloads.
(combine_reloads): Copy reload_out_reg[i].
(find_reloads): Do make_memloc substitution also when
reg_equiv_memory_loc[regno] and num_not_at_initial_offset
are both nonzero.
Include *recog_operand_loc in commutativity operand changes.
Generate optional output reloads.
Delete reference to n_memlocs. Don't set *recog_operand_loc before
processing operands. Call make_memloc in reg_equiv_address code.
Set *recog_operand_loc only after processing operands, and only
if replace is true. Return a value.
When changing address reload types for operands that didn't get
reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
Don't emit USEs for pseudo SUBREGs when not replacing.
(find_reloads_address): Do make_memloc substitution also when
reg_equiv_memory_loc[regno] and num_not_at_initial_offset
are both nonzero.
(find_reloads_toplev): Likewise.
Call make_memloc in reg_equiv_address code.
(debug_reload_to_stream): Add code to output reload_out_reg.
(make_memloc): Delete local variable i, ifdefed out code, and
references to memlocs and n_memlocs.
(memlocs, n_memlocs): Delete.
(push_secondary_reload): Clear reload_out_reg.
(find_reloads_address_1): Provide memrefloc argument to all calls
to find_reloads_address.
In AUTO_INC code, handle non-directly addressable equivalences properly.
* reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
(find_reloads): Add return type.
(remove_address_replacements, deallocate_reload_reg): Declare.
* reload1.c (num_not_at_initial_offset): No longer static.
(delete_address_reloads, delete_address_reloads_1): Likewise.
(deallocate_reload_reg): New function.
(spill_reg_stored_to): New array.
(eliminate_regs): Don't substitute from reg_equiv_memory_loc.
(eliminate_regs_in_insn): Move assignments of previous_offset and
max_offset fields, and recalculation of num_not_at_initial_offset
into new static function:
(update_eliminable_offsets) .
(reload_as_needed): Call update_eliminable_offsetss after calling
find_reloads.
Call forget_old_reloads_1 with contents of reloaded auto_inc
expressions if the actual addressing can't be changed to match the
auto_inc.
(choose_reload_regs): For inheritance, replace
reload_reg_free_before_p test with reload_reg_used_at_all test, and
remove stand-alone reload_reg_used_at_all test.
Use reload_out_reg to determine which reload regs have output reloads.
Treat reload_override_in more similar to inherited reloads.
Handle (subreg (reg... for inheritance.
For flag_expensive_optimizations, add an extra pass to remove
unnecessary reloads from known working inheritance.
Delete obsolete code for pseudos replaced with MEMs.
Handle inheritance from auto_inc expressions.
(emit_reload_insns): If reload_in is a MEM, set OLD to
reload_in_reg[j].
Don't reload directly from oldequiv; if it's a pseudo with a
stack slot, use reload_in[j].
Check that reload_in_reg[j] is a MEM before replacing reload_in
from reg_reloaded_contents.
Include non-spill registers in reload inheritance processing.
Also try to use reload_out_reg to set spill_reg_store /
reg_last_reload_reg.
In code to set new_spill_reg_store, use single_set to find out if
there is a single set.
Add code that allows to delete optional output reloads.
Add code to allow deletion of output reloads that use no spill reg.
At the end, set reload_override_in to oldequiv.
Also call delete_output_reload if reload_out_reg is equal to old
in oldequiv code.
Add code to call delete_output_reload for stores with no matching load.
Set / use spill_reg_stored_to.
Handle case where secondary output reload uses a temporary, but
actual store isn't found.
When looking for a store of a value not loaded in order to call
delete_output_reload, count_occurences should return 0 for no
loads; but discount inherited input reloadill_reg_stored_to.
Do checks for extra uses of REG. Changed all
callers.
Use delete_address_reloads.
(reload): Take return value of find_reloads into account.
If a no-op set needs more than one reload, delete it.
(reload_reg_free_before_p): RELOAD_FOR_INPUT
can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
for the same operand.
(clear_reload_reg_in_use): Check for other reloads that keep a
register in use.
(reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
RELOAD_FOR_OPADDR_ADDR.
Take into account when an address address reload is only needed
for the address reload we are considering.
(count_occurrences): Use rtx_equal_p for MEMs.
(inc_for_reload): Return instruction that stores into RELOADREG.
New argument two, IN, and rtx. Changed all callers.
(calculate_needs_all_insns, reload_as_needed):
Don't clear after_call for a CLOBBER.
Keep track of how many hard registers need to be copied from
after_call, and don't clear after_call before we have seen
that much copies, or we see a different instruction.
Fri Oct 16 10:58:23 1998 Jeffrey A Law (law@cygnus.com)
* flow.c (find_basic_blocks_1): Do not delete unreachable blocks

View File

@ -181,6 +181,7 @@ char reload_optional[MAX_RELOADS];
char reload_nongroup[MAX_RELOADS];
int reload_inc[MAX_RELOADS];
rtx reload_in_reg[MAX_RELOADS];
rtx reload_out_reg[MAX_RELOADS];
char reload_nocombine[MAX_RELOADS];
int reload_opnum[MAX_RELOADS];
enum reload_type reload_when_needed[MAX_RELOADS];
@ -232,11 +233,6 @@ struct decomposition
HOST_WIDE_INT end; /* Ending offset or register number. */
};
/* MEM-rtx's created for pseudo-regs in stack slots not directly addressable;
(see reg_equiv_address). */
static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
static int n_memlocs;
#ifdef SECONDARY_MEMORY_NEEDED
/* Save MEMs needed to copy from one class of registers to another. One MEM
@ -329,11 +325,11 @@ static int hard_reg_set_here_p PROTO((int, int, rtx));
static struct decomposition decompose PROTO((rtx));
static int immune_p PROTO((rtx, rtx, struct decomposition));
static int alternative_allows_memconst PROTO((char *, int));
static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
static rtx make_memloc PROTO((rtx, int));
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PROTO((rtx));
static rtx subst_reg_equivs PROTO((rtx, rtx));
static rtx subst_indexed_address PROTO((rtx));
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
int, enum reload_type,int, rtx));
@ -341,6 +337,7 @@ static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
static int find_inc_amount PROTO((rtx, rtx));
static int loc_mentioned_in_p PROTO((rtx *, rtx));
#ifdef HAVE_SECONDARY_RELOADS
@ -536,6 +533,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[t_reload] = 1;
reload_in_reg[t_reload] = 0;
reload_out_reg[t_reload] = 0;
reload_opnum[t_reload] = opnum;
reload_when_needed[t_reload] = secondary_type;
reload_secondary_in_reload[t_reload] = -1;
@ -605,6 +603,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[s_reload] = 1;
reload_in_reg[s_reload] = 0;
reload_out_reg[s_reload] = 0;
reload_opnum[s_reload] = opnum;
reload_when_needed[s_reload] = secondary_type;
reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
@ -1170,7 +1169,11 @@ push_reload (in, out, inloc, outloc, class,
}
}
if (class == NO_REGS)
/* Optional output reloads are always OK even if we have no register class,
since the function of these reloads is only to have spill_reg_store etc.
set, so that the storing insn can be deleted later. */
if (class == NO_REGS
&& (optional == 0 || type != RELOAD_FOR_OUTPUT))
abort ();
/* We can use an existing reload if the class is right
@ -1281,6 +1284,7 @@ push_reload (in, out, inloc, outloc, class,
reload_inc[i] = 0;
reload_nocombine[i] = 0;
reload_in_reg[i] = inloc ? *inloc : 0;
reload_out_reg[i] = outloc ? *outloc : 0;
reload_opnum[i] = opnum;
reload_when_needed[i] = type;
reload_secondary_in_reload[i] = secondary_in_reload;
@ -1315,9 +1319,32 @@ push_reload (in, out, inloc, outloc, class,
&& GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
reload_outmode[i] = outmode;
if (in != 0)
reload_in[i] = in;
{
/* If we merge reloads for two distinct rtl expressions that
are identical in content, there might be duplicate address
reloads. Remove the extra set now, so that if we later find
that we can inherit this reload, we can get rid of the
address reloads altogether. */
if (reload_in[i] != in && rtx_equal_p (in, reload_in[i]))
{
/* We must keep the address reload with the lower operand
number alive. */
if (opnum > reload_opnum[i])
{
remove_address_replacements (in);
in = reload_in[i];
}
else
remove_address_replacements (reload_in[i]);
}
reload_in[i] = in;
reload_in_reg[i] = inloc ? *inloc : 0;
}
if (out != 0)
reload_out[i] = out;
{
reload_out[i] = out;
reload_out_reg[i] = outloc ? *outloc : 0;
}
if (reg_class_subset_p (class, reload_reg_class[i]))
reload_reg_class[i] = class;
reload_optional[i] &= optional;
@ -1506,19 +1533,67 @@ transfer_replacements (to, from)
replacements[i].what = to;
}
/* Remove all replacements in reload FROM. */
void
remove_replacements (from)
int from;
/* IN_RTX is the value loaded by a reload that we now decided to inherit,
or a subpart of it. If we have any replacements registered for IN_RTX,
cancel the reloads that were supposed to load them.
Return non-zero if we canceled any reloads. */
int
remove_address_replacements (in_rtx)
rtx in_rtx;
{
int i, j;
char reload_flags[MAX_RELOADS];
int something_changed = 0;
bzero (reload_flags, sizeof reload_flags);
for (i = 0, j = 0; i < n_replacements; i++)
{
if (replacements[i].what == from)
continue;
replacements[j++] = replacements[i];
if (loc_mentioned_in_p (replacements[i].where, in_rtx))
reload_flags[replacements[i].what] |= 1;
else
{
replacements[j++] = replacements[i];
reload_flags[replacements[i].what] |= 2;
}
}
/* Note that the following store must be done before the recursive calls. */
n_replacements = j;
for (i = n_reloads - 1; i >= 0; i--)
{
if (reload_flags[i] == 1)
{
deallocate_reload_reg (i);
remove_address_replacements (reload_in[i]);
reload_in[i] = 0;
something_changed = 1;
}
}
return something_changed;
}
/* Return non-zero if IN contains a piece of rtl that has the address LOC */
static int
loc_mentioned_in_p (loc, in)
rtx *loc, in;
{
enum rtx_code code = GET_CODE (in);
char *fmt = GET_RTX_FORMAT (code);
int i, j;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (loc == &XEXP (in, i))
return 1;
if (fmt[i] == 'e')
if (loc_mentioned_in_p (loc, XEXP (in, i)))
return 1;
else if (fmt[i] == 'E')
for (j = XVECLEN (in, i) - 1; i >= 0; i--)
if (loc_mentioned_in_p (loc, XVECEXP (in, i, j)))
return 1;
}
return 0;
}
/* If there is only one output reload, and it is not for an earlyclobber
@ -1617,6 +1692,7 @@ combine_reloads ()
/* We have found a reload to combine with! */
reload_out[i] = reload_out[output_reload];
reload_out_reg[i] = reload_out_reg[output_reload];
reload_outmode[i] = reload_outmode[output_reload];
/* Mark the old output reload as inoperative. */
reload_out[output_reload] = 0;
@ -2299,9 +2375,12 @@ safe_from_earlyclobber (op, clobber)
RELOAD_REG_P if nonzero is a vector indexed by hard reg number
which is nonnegative if the reg has been commandeered for reloading into.
It is copied into STATIC_RELOAD_REG_P and referenced from there
by various subroutines. */
by various subroutines.
void
Return TRUE if some operands need to be changed, because of swapping
commutative operands, reg_equiv_address substitution, or whatever. */
int
find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx insn;
int replace, ind_levels;
@ -2357,6 +2436,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx set = single_set (insn);
int goal_earlyclobber, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
/* Cache the last regno for the last pseudo we did an output reload
for in case the next insn uses it. */
static int last_output_reload_regno = -1;
@ -2365,7 +2445,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
this_insn_is_asm = 0; /* Tentative. */
n_reloads = 0;
n_replacements = 0;
n_memlocs = 0;
n_earlyclobbers = 0;
replace_reloads = replace;
hard_regs_live_known = live_known;
@ -2406,7 +2485,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return;
return 0;
case SET:
/* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
@ -2418,7 +2497,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
return;
return 0;
case PARALLEL:
case ASM_OPERANDS:
reload_n_operands = noperands = asm_noperands (body);
@ -2458,7 +2537,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
n_alternatives = insn_n_alternatives[insn_code_number];
/* Just return "no reloads" if insn has no operands with constraints. */
if (n_alternatives == 0)
return;
return 0;
insn_extract (insn);
for (i = 0; i < noperands; i++)
{
@ -2469,7 +2548,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
if (noperands == 0)
return;
return 0;
commutative = -1;
@ -2577,9 +2656,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|| GET_CODE (recog_operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
find_reloads (insn, replace, ind_levels, live_known,
reload_reg_p);
return;
retval = find_reloads (insn, replace, ind_levels, live_known,
reload_reg_p);
return retval;
}
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
@ -2601,14 +2680,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels,
set != 0
&& &SET_DEST (set) == recog_operand_loc[i]);
&& &SET_DEST (set) == recog_operand_loc[i],
insn);
/* If we made a MEM to load (a part of) the stackslot of a pseudo
that didn't get a hard register, emit a USE with a REG_EQUAL
note in front so that we might inherit a previous, possibly
wider reload. */
if (GET_CODE (op) == MEM
if (replace
&& GET_CODE (op) == MEM
&& GET_CODE (reg) == REG
&& (GET_MODE_SIZE (GET_MODE (reg))
>= GET_MODE_SIZE (GET_MODE (op))))
@ -2616,15 +2697,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= gen_rtx_EXPR_LIST (REG_EQUAL,
reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
substed_operand[i] = recog_operand[i] = op;
}
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
/* We can get a PLUS as an "operand" as a result of register
elimination. See eliminate_regs and gen_reload. We handle
a unary operator by reloading the operand. */
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
substed_operand[i] = recog_operand[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0);
ind_levels, 0, insn);
else if (code == REG)
{
/* This is equivalent to calling find_reloads_toplev.
@ -2646,44 +2727,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
substed_operand[i] = recog_operand[i]
= reg_equiv_constant[regno];
}
#if 0 /* This might screw code in reload1.c to delete prior output-reload
that feeds this insn. */
if (reg_equiv_mem[regno] != 0)
if (reg_equiv_memory_loc[regno] != 0
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
/* We need not give a valid is_set_dest argument since the case
of a constant equivalence was checked above. */
substed_operand[i] = recog_operand[i]
= reg_equiv_mem[regno];
#endif
if (reg_equiv_address[regno] != 0)
{
/* If reg_equiv_address is not a constant address, copy it,
since it may be shared. */
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno],
0, NULL_RTX),
0);
if (rtx_varies_p (address))
address = copy_rtx (address);
/* Emit a USE that shows what register is being used/modified. */
REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
recog_operand[i]),
insn))
= gen_rtx_EXPR_LIST (REG_EQUAL,
reg_equiv_memory_loc[regno],
NULL_RTX);
*recog_operand_loc[i] = recog_operand[i]
= gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
RTX_UNCHANGING_P (recog_operand[i])
= RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (recog_operand[i]),
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
i, address_type[i], ind_levels, insn);
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0, insn);
}
/* If the operand is still a register (we didn't replace it with an
equivalent), get the preferred class to reload it into. */
@ -3511,7 +3561,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
return 0;
}
/* Jump to `finish' from above if all operands are valid already.
@ -3546,6 +3596,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
tem = recog_operand[commutative];
recog_operand[commutative] = recog_operand[commutative + 1];
recog_operand[commutative + 1] = tem;
tem = *recog_operand_loc[commutative];
*recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
*recog_operand_loc[commutative+1] = tem;
for (i = 0; i < n_reloads; i++)
{
@ -3556,14 +3609,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
}
/* Perform whatever substitutions on the operands we are supposed
to make due to commutativity or replacement of registers
with equivalent constants or memory slots. */
for (i = 0; i < noperands; i++)
{
*recog_operand_loc[i] = substed_operand[i];
/* While we are looping on operands, initialize this. */
operand_reloadnum[i] = -1;
/* If this is an earlyclobber operand, we need to widen the scope.
@ -3605,7 +3652,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
*recog_operand_loc[i] = recog_operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_operand[i]),
i, address_type[i], ind_levels, 0);
i, address_type[i], ind_levels, 0, insn);
if (alternative_allows_memconst (constraints1[i],
goal_alternative_number))
goal_alternative_win[i] = 1;
@ -3730,7 +3777,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
return 0;
}
}
else if (goal_alternative_matched[i] < 0
@ -3748,13 +3795,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
&& (enum reg_class) goal_alternative[i] != NO_REGS
/* If this is only for an output, the optional reload would not
actually cause us to use a register now, just note that
something is stored here. */
&& ((enum reg_class) goal_alternative[i] != NO_REGS
|| modified[i] == RELOAD_WRITE)
&& ! no_input_reloads
/* Optional output reloads don't do anything and we mustn't
make in-out reloads on insns that are not permitted output
reloads. */
/* An optional output reload might allow to delete INSN later.
We mustn't make in-out reloads on insns that are not permitted
output reloads.
If this is an asm, we can't delete it; we must not even call
push_reload for an optional output reload in this case,
because we can't be sure that the constraint allows a register,
and push_reload verifies the constraints for asms. */
&& (modified[i] == RELOAD_READ
|| (modified[i] == RELOAD_READ_WRITE && ! no_output_reloads)))
|| (! no_output_reloads && ! this_insn_is_asm)))
operand_reloadnum[i]
= push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
modified[i] != RELOAD_READ ? recog_operand[i] : 0,
@ -3770,6 +3825,24 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
(insn_code_number < 0 ? 0
: insn_operand_strict_low[insn_code_number][i]),
1, i, operand_type[i]);
/* If a memory reference remains, yet we can't make an optional
reload, check if this is actually a pseudo register reference;
we then need to emit a USE and/or a CLOBBER so that reload
inheritance will do the right thing. */
else if (replace && GET_CODE (operand) == MEM)
{
operand = *recog_operand_loc[i];
while (GET_CODE (operand) == SUBREG)
operand = XEXP (operand, 0);
if (GET_CODE (operand) == REG)
{
if (modified[i] != RELOAD_WRITE)
emit_insn_before (gen_rtx_USE (VOIDmode, operand), insn);
if (modified[i] != RELOAD_READ)
emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
}
}
}
else if (goal_alternative_matches[i] >= 0
&& goal_alternative_win[goal_alternative_matches[i]]
@ -3801,6 +3874,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
/* Perform whatever substitutions on the operands we are supposed
to make due to commutativity or replacement of registers
with equivalent constants or memory slots. */
for (i = 0; i < noperands; i++)
{
/* We only do this on the last pass through reload, because it is
possible for some data (like reg_equiv_address) to be changed during
later passes. Moreover, we loose the opportunity to get a useful
reload_{in,out}_reg when we do these replacements. */
if (replace)
*recog_operand_loc[i] = substed_operand[i];
else
retval |= (substed_operand[i] != *recog_operand_loc[i]);
}
/* If this insn pattern contains any MATCH_DUP's, make sure that
they will be substituted if the operands they match are substituted.
Also do now any substitutions we already did on the operands.
@ -3955,7 +4045,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= RELOAD_FOR_OPADDR_ADDR;
}
reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
else
reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
}
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
@ -4170,6 +4264,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen. */
register int i;
rtx body = PATTERN (insn);
int retval = 0;
n_reloads = 0;
n_replacements = 0;
@ -4269,6 +4364,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (!goal_earlyclobber)
combine_reloads ();
#endif /* no REGISTER_CONSTRAINTS */
return retval;
}
/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
@ -4307,15 +4403,20 @@ alternative_allows_memconst (constraint, altnum)
OPNUM and TYPE identify the purpose of the reload.
IS_SET_DEST is true if X is the destination of a SET, which is not
appropriate to be replaced by a constant. */
appropriate to be replaced by a constant.
INSN, if nonzero, is the insn in which we do the reload. It is used
to determine if we may generate output reloads, and where to put USEs
for pseudos that we have to replace with stack slots. */
static rtx
find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
rtx x;
int opnum;
enum reload_type type;
int ind_levels;
int is_set_dest;
rtx insn;
{
register RTX_CODE code = GET_CODE (x);
@ -4334,23 +4435,22 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
else if (reg_equiv_mem[regno] != 0)
x = reg_equiv_mem[regno];
#endif
else if (reg_equiv_address[regno] != 0)
else if (reg_equiv_memory_loc[regno]
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
/* If reg_equiv_address varies, it may be shared, so copy it. */
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
NULL_RTX),
0);
if (rtx_varies_p (addr))
addr = copy_rtx (addr);
x = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
&XEXP (x, 0), opnum, type, ind_levels, 0);
rtx mem = make_memloc (x, regno);
if (reg_equiv_address[regno]
|| ! rtx_equal_p (mem, reg_equiv_mem[regno]))
{
/* If this is not a toplevel operand, find_reloads doesn't see
this substitution. We have to emit a USE of the pseudo so
that delete_output_reload can see it. */
if (replace_reloads && recog_operand[opnum] != x)
emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
x = mem;
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, insn);
}
}
return x;
}
@ -4358,7 +4458,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
{
rtx tem = x;
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, 0);
opnum, type, ind_levels, insn);
return tem;
}
@ -4452,7 +4552,8 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
|| (reg_equiv_mem[regno] != 0
&& (! strict_memory_address_p (GET_MODE (x),
XEXP (reg_equiv_mem[regno], 0))
|| ! offsettable_memref_p (reg_equiv_mem[regno])))))
|| ! offsettable_memref_p (reg_equiv_mem[regno])
|| num_not_at_initial_offset))))
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
/* We must rerun eliminate_regs, in case the elimination
@ -4473,7 +4574,12 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
&XEXP (x, 0), opnum, type, ind_levels, 0);
&XEXP (x, 0), opnum, type, ind_levels, insn);
/* If this is not a toplevel operand, find_reloads doesn't see this
substitution. We have to emit a USE of the pseudo so that
delete_output_reload can see it. */
if (replace_reloads && recog_operand[opnum] != x)
emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn);
}
}
@ -4482,7 +4588,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
{
if (fmt[i] == 'e')
XEXP (x, i) = find_reloads_toplev (XEXP (x, i), opnum, type,
ind_levels, is_set_dest);
ind_levels, is_set_dest, insn);
}
return x;
}
@ -4495,22 +4601,10 @@ make_memloc (ad, regno)
rtx ad;
int regno;
{
#if 0
register int i;
#endif
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
#if 0 /* We cannot safely reuse a memloc made here;
if the pseudo appears twice, and its mem needs a reload,
it gets two separate reloads assigned, but it only
gets substituted with the second of them;
then it can get used before that reload reg gets loaded up. */
for (i = 0; i < n_memlocs; i++)
if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
return memlocs[i];
#endif
rtx tem
= XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
/* If TEM might contain a pseudo, we must copy it to avoid
modifying it when we do the substitution for the reload. */
@ -4519,7 +4613,6 @@ make_memloc (ad, regno)
tem = gen_rtx_MEM (GET_MODE (ad), tem);
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
memlocs[n_memlocs++] = tem;
return tem;
}
@ -4535,7 +4628,8 @@ make_memloc (ad, regno)
supports.
INSN, if nonzero, is the insn in which we do the reload. It is used
to determine if we may generate output reloads.
to determine if we may generate output reloads, and where to put USEs
for pseudos that we have to replace with stack slots.
Value is nonzero if this address is reloaded or replaced as a whole.
This is interesting to the caller if the address is an autoincrement.
@ -4575,32 +4669,48 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
return 1;
}
else if (reg_equiv_address[regno] != 0)
tem = reg_equiv_memory_loc[regno];
if (tem != 0)
{
tem = make_memloc (ad, regno);
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
push_reload (tem, NULL_RTX, loc, NULL_PTR,
reload_address_base_reg_class,
GET_MODE (ad), VOIDmode, 0, 0,
opnum, type);
return 1;
if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
{
tem = make_memloc (ad, regno);
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
{
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
}
/* We can avoid a reload if the register's equivalent memory
expression is valid as an indirect memory address.
But not all addresses are valid in a mem used as an indirect
address: only reg or reg+constant. */
if (ind_levels > 0
&& strict_memory_address_p (mode, tem)
&& (GET_CODE (XEXP (tem, 0)) == REG
|| (GET_CODE (XEXP (tem, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
&& CONSTANT_P (XEXP (XEXP (tem, 0), 1)))))
{
/* TEM is not the same as what we'll be replacing the
pseudo with after reload, put a USE in front of INSN
in the final reload pass. */
if (replace_reloads
&& num_not_at_initial_offset
&& ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
*loc = tem;
emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
/* This doesn't really count as replacing the address
as a whole, since it is still a memory access. */
}
return 0;
}
ad = tem;
}
}
/* We can avoid a reload if the register's equivalent memory expression
is valid as an indirect memory address.
But not all addresses are valid in a mem used as an indirect address:
only reg or reg+constant. */
else if (reg_equiv_mem[regno] != 0 && ind_levels > 0
&& strict_memory_address_p (mode, reg_equiv_mem[regno])
&& (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
|| (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
&& GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
&& CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 1)))))
return 0;
/* The only remaining case where we can avoid a reload is if this is a
hard register that is valid as a base register and which is not the
subject of a CLOBBER in this insn. */
@ -4633,7 +4743,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
return 0;
subst_reg_equivs_changed = 0;
*loc = subst_reg_equivs (ad);
*loc = subst_reg_equivs (ad, insn);
if (! subst_reg_equivs_changed)
return 0;
@ -4838,7 +4948,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
registers. */
subst_reg_equivs_changed = 0;
tem = subst_reg_equivs (tem);
tem = subst_reg_equivs (tem, insn);
/* Make sure that didn't make the address invalid again. */
@ -4874,11 +4984,14 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
/* Find all pseudo regs appearing in AD
that are eliminable in favor of equivalent values
and do not have hard regs; replace them by their equivalents. */
and do not have hard regs; replace them by their equivalents.
INSN, if nonzero, is the insn in which we do the reload. We put USEs in
front of it for pseudos that we have to replace with stack slots. */
static rtx
subst_reg_equivs (ad)
subst_reg_equivs (ad, insn)
rtx ad;
rtx insn;
{
register RTX_CODE code = GET_CODE (ad);
register int i;
@ -4905,6 +5018,16 @@ subst_reg_equivs (ad)
subst_reg_equivs_changed = 1;
return reg_equiv_constant[regno];
}
if (reg_equiv_memory_loc[regno] && num_not_at_initial_offset)
{
rtx mem = make_memloc (ad, regno);
if (! rtx_equal_p (mem, reg_equiv_mem[regno]))
{
subst_reg_equivs_changed = 1;
emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
return mem;
}
}
}
return ad;
@ -4922,7 +5045,7 @@ subst_reg_equivs (ad)
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i));
XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i), insn);
return ad;
}
@ -5195,19 +5318,24 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
/* Handle a register that is equivalent to a memory location
which cannot be addressed directly. */
if (reg_equiv_address[regno] != 0)
if (reg_equiv_memory_loc[regno] != 0
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
rtx tem = make_memloc (XEXP (x, 0), regno);
/* First reload the memory location's address.
We can't use ADDR_TYPE (type) here, because we need to
write back the value after reading it, hence we actually
need two registers. */
find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
/* Put this inside a new increment-expression. */
x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
/* Proceed to reload that, as if it contained a register. */
if (reg_equiv_address[regno]
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
/* First reload the memory location's address.
We can't use ADDR_TYPE (type) here, because we need to
write back the value after reading it, hence we actually
need two registers. */
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
/* Put this inside a new increment-expression. */
x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
/* Proceed to reload that, as if it contained a register. */
}
}
/* If we have a hard register that is ok as an index,
@ -5240,9 +5368,12 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
memory location, since this will make it harder to
reuse address reloads, and increases register pressure.
Also don't do this if we can probably update x directly. */
rtx equiv = reg_equiv_mem[regno];
rtx equiv = (GET_CODE (XEXP (x, 0)) == MEM
? XEXP (x, 0)
: reg_equiv_mem[regno]);
int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
if (insn && GET_CODE (insn) == INSN && equiv
&& memory_operand (equiv, GET_MODE (equiv))
#ifdef HAVE_cc0
&& ! sets_cc0_p (PATTERN (insn))
#endif
@ -5375,11 +5506,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
}
#endif
if (reg_equiv_address[regno] != 0)
if (reg_equiv_memory_loc[regno]
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
x = make_memloc (x, regno);
find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
opnum, ADDR_TYPE (type), ind_levels, insn);
rtx tem = make_memloc (x, regno);
if (reg_equiv_address[regno] != 0
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
x = tem;
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
&XEXP (x, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
}
}
if (reg_renumber[regno] >= 0)
@ -6517,6 +6655,12 @@ debug_reload_to_stream (f)
print_inline_rtx (f, reload_in_reg[r], 24);
}
if (reload_out_reg[r] != 0)
{
fprintf (f, "\n\treload_out_reg: ");
print_inline_rtx (f, reload_out_reg[r], 24);
}
if (reload_reg_rtx[r] != 0)
{
fprintf (f, "\n\treload_reg_rtx: ");

View File

@ -55,6 +55,7 @@ extern enum reg_class reload_address_index_reg_class;
extern rtx reload_in[MAX_RELOADS];
extern rtx reload_out[MAX_RELOADS];
extern rtx reload_in_reg[MAX_RELOADS];
extern rtx reload_out_reg[MAX_RELOADS];
extern enum reg_class reload_reg_class[MAX_RELOADS];
extern enum machine_mode reload_inmode[MAX_RELOADS];
extern enum machine_mode reload_outmode[MAX_RELOADS];
@ -134,6 +135,8 @@ extern char indirect_symref_ok;
/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */
extern char double_reg_address_ok;
extern int num_not_at_initial_offset;
#ifdef MAX_INSN_CODE
/* These arrays record the insn_code of insns that may be needed to
perform input and output reloads of special objects. They provide a
@ -233,8 +236,11 @@ extern void clear_secondary_mem PROTO((void));
reload TO. */
extern void transfer_replacements PROTO((int, int));
/* Remove all replacements in reload FROM. */
extern void remove_replacements PROTO((int));
/* IN_RTX is the value loaded by a reload that we now decided to inherit,
or a subpart of it. If we have any replacements registered for IN_RTX,
chancel the reloads that were supposed to load them.
Return non-zero if we chanceled any reloads. */
extern int remove_address_replacements PROTO((rtx in_rtx));
/* Like rtx_equal_p except that it allows a REG and a SUBREG to match
if they are the same hard reg, and has special hacks for
@ -250,7 +256,7 @@ extern int safe_from_earlyclobber PROTO((rtx, rtx));
/* Search the body of INSN for values that need reloading and record them
with push_reload. REPLACE nonzero means record also where the values occur
so that subst_reloads can be used. */
extern void find_reloads PROTO((rtx, int, int, int, short *));
extern int find_reloads PROTO((rtx, int, int, int, short *));
/* Compute the sum of X and Y, making canonicalizations assumed in an
address, namely: sum constant integers, surround the sum of two
@ -319,6 +325,9 @@ extern rtx eliminate_regs PROTO((rtx, enum machine_mode, rtx));
OPNUM with reload type TYPE. */
extern rtx gen_reload PROTO((rtx, rtx, int, enum reload_type));
/* Deallocate the reload register used by reload number R. */
extern void deallocate_reload_reg PROTO((int r));
/* Functions in caller-save.c: */
/* Initialize for caller-save. */

File diff suppressed because it is too large Load Diff