Commit cb2afeb3 by J"orn Rennecke Committed by Jeff Law

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
parent c583dd46
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
......
......@@ -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)
{
/* 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_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;
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,
retval = find_reloads (insn, replace, ind_levels, live_known,
reload_reg_p);
return;
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,6 +4045,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= RELOAD_FOR_OPADDR_ADDR;
}
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;
}
......@@ -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)
{
/* 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);
else if (reg_equiv_memory_loc[regno]
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
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,31 +4669,47 @@ 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)
{
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);
push_reload (tem, NULL_RTX, loc, NULL_PTR,
reload_address_base_reg_class,
GET_MODE (ad), VOIDmode, 0, 0,
opnum, type);
return 1;
}
/* 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. */
/* 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)))))
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;
}
}
/* 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
......@@ -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,20 +5318,25 @@ 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);
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), 0, XEXP (tem, 0),
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,
don't make a reload. If an autoincrement of a nice register
......@@ -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: ");
......
......@@ -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. */
......
......@@ -148,6 +148,11 @@ static rtx spill_reg_rtx[FIRST_PSEUDO_REGISTER];
The precise value is the insn generated to do the store. */
static rtx spill_reg_store[FIRST_PSEUDO_REGISTER];
/* This is the register that was stored with spill_reg_store. This is a
copy of reload_out / reload_out_reg when the value was stored; if
reload_out is a MEM, spill_reg_stored_to will be set to reload_out_reg. */
static rtx spill_reg_stored_to[FIRST_PSEUDO_REGISTER];
/* This table is the inverse mapping of spill_regs:
indexed by hard reg number,
it contains the position of that reg in spill_regs,
......@@ -335,7 +340,7 @@ static struct elim_table
/* Record the number of pending eliminations that have an offset not equal
to their initial offset. If non-zero, we use a new copy of each
replacement result in any insns encountered. */
static int num_not_at_initial_offset;
int num_not_at_initial_offset;
/* Count the number of registers that we may be able to eliminate. */
static int num_eliminable;
......@@ -377,6 +382,7 @@ static void delete_dead_insn PROTO((rtx));
static void alter_reg PROTO((int, int));
static void set_label_offsets PROTO((rtx, rtx, int));
static int eliminate_regs_in_insn PROTO((rtx, int));
static void update_eliminable_offsets PROTO((void));
static void mark_not_eliminable PROTO((rtx, rtx));
static void set_initial_elim_offsets PROTO((void));
static void init_elim_table PROTO((void));
......@@ -402,8 +408,10 @@ static int allocate_reload_reg PROTO((struct insn_chain *, int, int, int));
static void choose_reload_regs PROTO((struct insn_chain *, rtx));
static void merge_assigned_reloads PROTO((rtx));
static void emit_reload_insns PROTO((struct insn_chain *));
static void delete_output_reload PROTO((rtx, int, rtx));
static void inc_for_reload PROTO((rtx, rtx, int));
static void delete_output_reload PROTO((rtx, int, int));
static void delete_address_reloads PROTO((rtx, rtx));
static void delete_address_reloads_1 PROTO((rtx, rtx, rtx));
static rtx inc_for_reload PROTO((rtx, rtx, rtx, int));
static int constraint_accepts_reg_p PROTO((char *, rtx));
static void reload_cse_regs_1 PROTO((rtx));
static void reload_cse_invalidate_regno PROTO((int, enum machine_mode, int));
......@@ -582,6 +590,8 @@ compute_use_by_pseudos (to, from)
/* Set during calculate_needs if an insn needs register elimination. */
static int something_needs_elimination;
/* Set during calculate_needs if an insn needs an operand changed. */
int something_needs_operands_changed;
/* For each class, number of reload regs needed in that class.
This is the maximum over all insns of the needs in that class
......@@ -920,6 +930,7 @@ reload (first, global, dumpfile)
/* This flag is set if there are any insns that require register
eliminations. */
something_needs_elimination = 0;
something_needs_operands_changed = 0;
while (something_changed)
{
HOST_WIDE_INT starting_frame_size;
......@@ -1399,6 +1410,7 @@ calculate_needs_all_insns (global)
{
int something_changed = 0;
rtx after_call = 0;
int after_call_nregs;
struct insn_chain **pprev_reload = &insns_need_reload;
struct insn_chain *chain;
......@@ -1424,6 +1436,7 @@ calculate_needs_all_insns (global)
int old_code = INSN_CODE (insn);
rtx old_notes = REG_NOTES (insn);
int did_elimination = 0;
int operands_changed = 0;
/* Nonzero means don't use a reload reg that overlaps
the place where a function value can be returned. */
......@@ -1434,20 +1447,43 @@ calculate_needs_all_insns (global)
if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
{
after_call = SET_DEST (PATTERN (insn));
after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
GET_MODE (after_call));
}
else if (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
{
after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
GET_MODE (after_call));
}
else
after_call = 0;
}
else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
{
avoid_return_reg = after_call;
if (! --after_call_nregs)
after_call = 0;
else
{
/* If INSN copies the return register in a single chunk,
clear after_call now. */
rtx set = single_set (insn);
if (set && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
== GET_MODE_SIZE (GET_MODE (after_call))))
after_call = 0;
}
}
else
after_call = 0;
}
......@@ -1456,13 +1492,37 @@ calculate_needs_all_insns (global)
did_elimination = eliminate_regs_in_insn (insn, 0);
/* Analyze the instruction. */
find_reloads (insn, 0, spill_indirect_levels, global,
spill_reg_order);
operands_changed = find_reloads (insn, 0, spill_indirect_levels,
global, spill_reg_order);
/* If a no-op set needs more than one reload, this is likely
to be something that needs input address reloads. We
can't get rid of this cleanly later, and it is of no use
anyway, so discard it now.
We only do this when expensive_optimizations is enabled,
since this complements reload inheritance / output
reload deletion, and it can make debugging harder. */
if (flag_expensive_optimizations && n_reloads > 1)
{
rtx set = single_set (insn);
if (set
&& SET_SRC (set) == SET_DEST (set)
&& GET_CODE (SET_SRC (set)) == REG
&& REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
{
PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
continue;
}
}
if (num_eliminable)
update_eliminable_offsets ();
/* Remember for later shortcuts which insns had any reloads or
register eliminations. */
chain->need_elim = did_elimination;
chain->need_reload = n_reloads > 0;
chain->need_reload = (n_reloads > 0 | operands_changed);
/* Discard any register replacements done. */
if (did_elimination)
......@@ -1474,6 +1534,8 @@ calculate_needs_all_insns (global)
something_needs_elimination = 1;
}
something_needs_operands_changed |= operands_changed;
if (n_reloads != 0)
{
*pprev_reload = chain;
......@@ -2895,27 +2957,6 @@ eliminate_regs (x, mem_mode, insn)
}
}
else if (reg_equiv_memory_loc && reg_equiv_memory_loc[regno]
&& (reg_equiv_address[regno] || num_not_at_initial_offset))
{
/* In this case, find_reloads would attempt to either use an
incorrect address (if something is not at its initial offset)
or substitute an replaced address into an insn (which loses
if the offset is changed by some later action). So we simply
return the replaced stack slot (assuming it is changed by
elimination) and ignore the fact that this is actually a
reference to the pseudo. Ensure we make a copy of the
address in case it is shared. */
new = eliminate_regs (reg_equiv_memory_loc[regno], mem_mode, insn);
if (new != reg_equiv_memory_loc[regno])
{
if (insn != 0 && GET_CODE (insn) != EXPR_LIST
&& GET_CODE (insn) != INSN_LIST)
REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, x), insn))
= gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
return copy_rtx (new);
}
}
return x;
case PLUS:
......@@ -3123,6 +3164,7 @@ eliminate_regs (x, mem_mode, insn)
&& reg_equiv_memory_loc != 0
&& reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
{
#if 0
new = eliminate_regs (reg_equiv_memory_loc[REGNO (SUBREG_REG (x))],
mem_mode, insn);
......@@ -3143,6 +3185,9 @@ eliminate_regs (x, mem_mode, insn)
/* Ensure NEW isn't shared in case we have to reload it. */
new = copy_rtx (new);
}
#else
new = SUBREG_REG (x);
#endif
}
else
new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
......@@ -3505,7 +3550,7 @@ eliminate_regs_in_insn (insn, replace)
in the insn is the negative of the offset in FROM. Substitute
(set (reg) (reg to)) for the insn and change its code.
We have to do this here, rather than in eliminate_regs, do that we can
We have to do this here, rather than in eliminate_regs, so that we can
change the insn code. */
if (GET_CODE (SET_SRC (old_set)) == PLUS
......@@ -3592,11 +3637,7 @@ eliminate_regs_in_insn (insn, replace)
val = 1;
}
/* Loop through all elimination pairs. See if any have changed and
recalculate the number not at initial offset.
Compute the maximum offset (minimum offset if the stack does not
grow downward) for each elimination pair.
/* Loop through all elimination pairs. See if any have changed.
We also detect a cases where register elimination cannot be done,
namely, if a register would be both changed and referenced outside a MEM
......@@ -3607,7 +3648,6 @@ eliminate_regs_in_insn (insn, replace)
If anything changes, return nonzero. */
num_not_at_initial_offset = 0;
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
if (ep->previous_offset != ep->offset && ep->ref_outside_mem)
......@@ -3617,16 +3657,6 @@ eliminate_regs_in_insn (insn, replace)
if (ep->previous_offset != ep->offset)
val = 1;
ep->previous_offset = ep->offset;
if (ep->can_eliminate && ep->offset != ep->initial_offset)
num_not_at_initial_offset++;
#ifdef STACK_GROWS_DOWNWARD
ep->max_offset = MAX (ep->max_offset, ep->offset);
#else
ep->max_offset = MIN (ep->max_offset, ep->offset);
#endif
}
done:
......@@ -3644,6 +3674,32 @@ eliminate_regs_in_insn (insn, replace)
return val;
}
/* Loop through all elimination pairs.
Recalculate the number not at initial offset.
Compute the maximum offset (minimum offset if the stack does not
grow downward) for each elimination pair. */
static void
update_eliminable_offsets ()
{
struct elim_table *ep;
num_not_at_initial_offset = 0;
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
ep->previous_offset = ep->offset;
if (ep->can_eliminate && ep->offset != ep->initial_offset)
num_not_at_initial_offset++;
#ifdef STACK_GROWS_DOWNWARD
ep->max_offset = MAX (ep->max_offset, ep->offset);
#else
ep->max_offset = MIN (ep->max_offset, ep->offset);
#endif
}
}
/* Given X, a SET or CLOBBER of DEST, if DEST is the target of a register
replacement we currently believe is valid, mark it as not eliminable if X
modifies DEST in any way other than by adding a constant integer to it.
......@@ -4170,6 +4226,7 @@ reload_as_needed (live_known)
register int i;
rtx x;
rtx after_call = 0;
int after_call_nregs;
bzero ((char *) spill_reg_rtx, sizeof spill_reg_rtx);
bzero ((char *) spill_reg_store, sizeof spill_reg_store);
......@@ -4208,6 +4265,7 @@ reload_as_needed (live_known)
{
rtx insn = chain->insn;
rtx old_next = NEXT_INSN (insn);
rtx prev;
/* If we pass a label, copy the offsets from the label information
into the current offsets of each elimination. */
......@@ -4235,20 +4293,43 @@ reload_as_needed (live_known)
if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
{
after_call = SET_DEST (PATTERN (insn));
after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
GET_MODE (after_call));
}
else if (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
{
after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
GET_MODE (after_call));
}
else
after_call = 0;
}
else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
{
avoid_return_reg = after_call;
if (! --after_call_nregs)
after_call = 0;
else
{
/* If INSN copies the return register in a single chunk,
clear after_call now. */
rtx set = single_set (insn);
if (set && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
== GET_MODE_SIZE (GET_MODE (after_call))))
after_call = 0;
}
}
else
after_call = 0;
}
......@@ -4269,8 +4350,11 @@ reload_as_needed (live_known)
{
eliminate_regs_in_insn (insn, 1);
if (GET_CODE (insn) == NOTE)
{
update_eliminable_offsets ();
continue;
}
}
/* If need_elim is nonzero but need_reload is zero, one might think
that we could simply set n_reloads to 0. However, find_reloads
......@@ -4294,12 +4378,17 @@ reload_as_needed (live_known)
spill_reg_order);
}
if (num_eliminable && GET_MODE (insn) == QImode)
update_eliminable_offsets ();
if (n_reloads > 0)
{
rtx prev = PREV_INSN (insn), next = NEXT_INSN (insn);
rtx next = NEXT_INSN (insn);
rtx p;
int class;
prev = PREV_INSN (insn);
/* If this block has not had spilling done for a
particular clas and we have any non-optionals that need a
spill reg in that class, abort. */
......@@ -4371,6 +4460,54 @@ reload_as_needed (live_known)
#ifdef AUTO_INC_DEC
/* Likewise for regs altered by auto-increment in this insn.
REG_INC notes have been changed by reloading:
find_reloads_address_1 records substitutions for them,
which have been performed by subst_reloads above. */
for (i = n_reloads - 1; i >= 0; i--)
{
rtx in_reg = reload_in_reg[i];
if (in_reg)
{
enum rtx_code code = GET_CODE (in_reg);
/* PRE_INC / PRE_DEC will have the reload register ending up
with the same value as the stack slot, but that doesn't
hold true for POST_INC / POST_DEC. Either we have to
convert the memory access to a true POST_INC / POST_DEC,
or we can't use the reload register for inheritance. */
if ((code == POST_INC || code == POST_DEC)
&& TEST_HARD_REG_BIT (reg_reloaded_valid,
REGNO (reload_reg_rtx[i])))
{
rtx reload_reg = reload_reg_rtx[i];
enum machine_mode mode = GET_MODE (reload_reg);
int n = 0;
rtx p;
for (p = PREV_INSN (old_next); p != prev; p = PREV_INSN (p))
{
/* We really want to ignore REG_INC notes here, so
use PATTERN (p) as argument to reg_set_p . */
if (reg_set_p (reload_reg, PATTERN (p)))
break;
n = count_occurrences (PATTERN (p), reload_reg);
if (! n)
continue;
if (n == 1)
n = validate_replace_rtx (reload_reg,
gen_rtx (code, mode,
reload_reg), p);
break;
}
if (n == 1)
REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_INC, reload_reg,
REG_NOTES (p));
else
forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX);
}
}
}
#if 0 /* ??? Is this code obsolete now? Need to check carefully. */
/* Likewise for regs altered by auto-increment in this insn.
But note that the reg-notes are not changed by reloading:
they still contain the pseudo-regs, not the spill regs. */
for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
......@@ -4387,6 +4524,7 @@ reload_as_needed (live_known)
forget_old_reloads_1 (XEXP (x, 0), NULL_RTX);
}
#endif
#endif
}
/* A reload reg's contents are unknown after a label. */
if (GET_CODE (insn) == CODE_LABEL)
......@@ -4622,57 +4760,104 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
enum machine_mode mode;
{
int nregs = HARD_REGNO_NREGS (regno, mode);
int start_regno, end_regno;
int i;
/* A complication is that for some reload types, inheritance might
allow multiple reloads of the same types to share a reload register.
We set check_opnum if we have to check only reloads with the same
operand number, and check_any if we have to check all reloads. */
int check_opnum = 0;
int check_any = 0;
HARD_REG_SET *used_in_set;
for (i = regno; i < nregs + regno; i++)
{
switch (type)
{
case RELOAD_OTHER:
CLEAR_HARD_REG_BIT (reload_reg_used, i);
used_in_set = &reload_reg_used;
break;
case RELOAD_FOR_INPUT_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
used_in_set = &reload_reg_used_in_input_addr[opnum];
break;
case RELOAD_FOR_INPADDR_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
check_opnum = 1;
used_in_set = &reload_reg_used_in_inpaddr_addr[opnum];
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
used_in_set = &reload_reg_used_in_output_addr[opnum];
break;
case RELOAD_FOR_OUTADDR_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
check_opnum = 1;
used_in_set = &reload_reg_used_in_outaddr_addr[opnum];
break;
case RELOAD_FOR_OPERAND_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
used_in_set = &reload_reg_used_in_op_addr;
break;
case RELOAD_FOR_OPADDR_ADDR:
CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i);
check_any = 1;
used_in_set = &reload_reg_used_in_op_addr_reload;
break;
case RELOAD_FOR_OTHER_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
used_in_set = &reload_reg_used_in_other_addr;
check_any = 1;
break;
case RELOAD_FOR_INPUT:
CLEAR_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
used_in_set = &reload_reg_used_in_input[opnum];
break;
case RELOAD_FOR_OUTPUT:
CLEAR_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
used_in_set = &reload_reg_used_in_output[opnum];
break;
case RELOAD_FOR_INSN:
CLEAR_HARD_REG_BIT (reload_reg_used_in_insn, i);
used_in_set = &reload_reg_used_in_insn;
break;
default:
abort ();
}
/* We resolve conflicts with remaining reloads of the same type by
excluding the intervals of of reload registers by them from the
interval of freed reload registers. Since we only keep track of
one set of interval bounds, we might have to exclude somewhat
more then what would be necessary if we used a HARD_REG_SET here.
But this should only happen very infrequently, so there should
be no reason to worry about it. */
start_regno = regno;
end_regno = regno + nregs;
if (check_opnum || check_any)
{
for (i = n_reloads - 1; i >= 0; i--)
{
if (reload_when_needed[i] == type
&& (check_any || reload_opnum[i] == opnum)
&& reload_reg_rtx[i])
{
int conflict_start = true_regnum (reload_reg_rtx[i]);
int conflict_end
= (conflict_start
+ HARD_REGNO_NREGS (conflict_start, reload_mode[i]));
/* If there is an overlap with the first to-be-freed register,
adjust the interval start. */
if (conflict_start <= start_regno && conflict_end > start_regno)
start_regno = conflict_end;
/* Otherwise, if there is a conflict with one of the other
to-be-freed registers, adjust the interval end. */
if (conflict_start > start_regno && conflict_start < end_regno)
end_regno = conflict_start;
}
}
}
for (i = start_regno; i < end_regno; i++)
CLEAR_HARD_REG_BIT (*used_in_set, i);
}
/* 1 if reg REGNO is free as a reload reg for a reload of the sort
......@@ -4953,9 +5138,11 @@ reload_reg_free_before_p (regno, opnum, type, equiv)
/* The only things earlier are the address for this and
earlier inputs, other inputs (which we know we don't conflict
with), and addresses of RELOAD_OTHER objects. */
with), and addresses of RELOAD_OTHER objects.
We can ignore the conflict with addresses of this operand, since
when we inherit this operand, its address reloads are discarded. */
for (i = 0; i <= opnum; i++)
for (i = 0; i < opnum; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
......@@ -5268,18 +5455,26 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
case RELOAD_FOR_INPUT_ADDRESS:
time1 = opnum * 4 + 2;
break;
case RELOAD_FOR_OPADDR_ADDR:
/* opnum * 4 + 3 < opnum * 4 + 4
<= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
time1 = MAX_RECOG_OPERANDS * 4;
break;
case RELOAD_FOR_INPUT:
/* All RELOAD_FOR_INPUT reloads remain live till just before the
instruction is executed. */
time1 = (MAX_RECOG_OPERANDS - 1) * 4 + 3;
time1 = MAX_RECOG_OPERANDS * 4 + 1;
break;
case RELOAD_FOR_OPERAND_ADDRESS:
/* RELOAD_FOR_OPERAND_ADDRESS reloads are live even while the insn
is executed. */
time1 = MAX_RECOG_OPERANDS * 4 + 2;
break;
/* opnum * 4 + 3 < opnum * 4 + 4
<= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
case RELOAD_FOR_OUTPUT_ADDRESS:
time1 = MAX_RECOG_OPERANDS * 4 + opnum;
time1 = MAX_RECOG_OPERANDS * 4 + 3 + opnum;
break;
default:
time1 = MAX_RECOG_OPERANDS * 5;
time1 = MAX_RECOG_OPERANDS * 5 + 3;
}
for (i = 0; i < n_reloads; i++)
......@@ -5305,6 +5500,14 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
time2 = 0;
break;
case RELOAD_FOR_INPADDR_ADDRESS:
/* find_reloads makes sure that a
RELOAD_FOR_{INP,OP,OUT}ADDR_ADDRESS reload is only used
by at most one - the first -
RELOAD_FOR_{INPUT,OPERAND,OUTPUT}_ADDRESS . If the
address reload is inherited, the address address reload
goes away, so we can ignore this conflict. */
if (type == RELOAD_FOR_INPUT_ADDRESS && reloadnum == i + 1)
continue;
time2 = reload_opnum[i] * 4 + 1;
break;
case RELOAD_FOR_INPUT_ADDRESS:
......@@ -5313,20 +5516,32 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
case RELOAD_FOR_INPUT:
time2 = reload_opnum[i] * 4 + 3;
break;
case RELOAD_FOR_OPADDR_ADDR:
if (type == RELOAD_FOR_OPERAND_ADDRESS && reloadnum == i + 1)
continue;
time2 = MAX_RECOG_OPERANDS * 4;
break;
case RELOAD_FOR_OPERAND_ADDRESS:
time2 = MAX_RECOG_OPERANDS * 4 + 1;
break;
case RELOAD_FOR_OUTPUT:
/* All RELOAD_FOR_OUTPUT reloads become live just after the
instruction is executed. */
time2 = MAX_RECOG_OPERANDS * 4;
time2 = MAX_RECOG_OPERANDS * 4 + 3;
break;
case RELOAD_FOR_OUTADDR_ADDRESS:
if (type == RELOAD_FOR_OUTPUT_ADDRESS && reloadnum == i + 1)
continue;
/* fall through. */
/* The first RELOAD_FOR_OUTPUT_ADDRESS reload conflicts with the
RELOAD_FOR_OUTPUT reloads, so assign it the same time value. */
case RELOAD_FOR_OUTPUT_ADDRESS:
time2 = MAX_RECOG_OPERANDS * 4 + reload_opnum[i];
time2 = MAX_RECOG_OPERANDS * 4 + 3 + reload_opnum[i];
break;
case RELOAD_OTHER:
if (! reload_in[i] || rtx_equal_p (reload_in[i], value))
{
time2 = MAX_RECOG_OPERANDS * 4;
time2 = MAX_RECOG_OPERANDS * 4 + 3;
break;
}
default:
......@@ -5566,6 +5781,7 @@ choose_reload_regs (chain, avoid_return_reg)
int max_group_size = 1;
enum reg_class group_class = NO_REGS;
int inheritance;
int pass;
rtx save_reload_reg_rtx[MAX_RELOADS];
char save_reload_inherited[MAX_RELOADS];
......@@ -5823,6 +6039,7 @@ choose_reload_regs (chain, avoid_return_reg)
if (inheritance)
{
int word = 0;
register int regno = -1;
enum machine_mode mode;
......@@ -5838,33 +6055,27 @@ choose_reload_regs (chain, avoid_return_reg)
regno = REGNO (reload_in_reg[r]);
mode = GET_MODE (reload_in_reg[r]);
}
else if (GET_CODE (reload_in[r]) == MEM)
else if (GET_CODE (reload_in_reg[r]) == SUBREG
&& GET_CODE (SUBREG_REG (reload_in_reg[r])) == REG)
{
rtx prev = prev_nonnote_insn (insn), note;
if (prev && GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE
&& GET_CODE (XEXP (PATTERN (prev), 0)) == REG
&& (REGNO (XEXP (PATTERN (prev), 0))
>= FIRST_PSEUDO_REGISTER)
&& (note = find_reg_note (prev, REG_EQUAL, NULL_RTX))
&& GET_CODE (XEXP (note, 0)) == MEM)
{
rtx addr = XEXP (XEXP (note, 0), 0);
int size_diff
= (GET_MODE_SIZE (GET_MODE (addr))
- GET_MODE_SIZE (GET_MODE (reload_in[r])));
if (size_diff >= 0
&& rtx_equal_p ((BYTES_BIG_ENDIAN
? plus_constant (addr, size_diff)
: addr),
XEXP (reload_in[r], 0)))
{
regno = REGNO (XEXP (PATTERN (prev), 0));
mode = GET_MODE (reload_in[r]);
}
word = SUBREG_WORD (reload_in_reg[r]);
regno = REGNO (SUBREG_REG (reload_in_reg[r]));
if (regno < FIRST_PSEUDO_REGISTER)
regno += word;
mode = GET_MODE (reload_in_reg[r]);
}
#ifdef AUTO_INC_DEC
else if ((GET_CODE (reload_in_reg[r]) == PRE_INC
|| GET_CODE (reload_in_reg[r]) == PRE_DEC
|| GET_CODE (reload_in_reg[r]) == POST_INC
|| GET_CODE (reload_in_reg[r]) == POST_DEC)
&& GET_CODE (XEXP (reload_in_reg[r], 0)) == REG)
{
regno = REGNO (XEXP (reload_in_reg[r], 0));
mode = GET_MODE (XEXP (reload_in_reg[r], 0));
reload_out[r] = reload_in[r];
}
#endif
#if 0
/* This won't work, since REGNO can be a pseudo reg number.
Also, it takes much more hair to keep track of all the things
......@@ -5876,15 +6087,34 @@ choose_reload_regs (chain, avoid_return_reg)
if (regno >= 0 && reg_last_reload_reg[regno] != 0)
{
i = REGNO (reg_last_reload_reg[regno]);
enum reg_class class = reload_reg_class[r], last_class;
rtx last_reg = reg_last_reload_reg[regno];
if (reg_reloaded_contents[i] == regno
i = REGNO (last_reg) + word;
last_class = REGNO_REG_CLASS (i);
if ((GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (mode) + word * UNITS_PER_WORD)
&& reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
>= GET_MODE_SIZE (mode))
&& HARD_REGNO_MODE_OK (i, reload_mode[r])
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
i)
&& (TEST_HARD_REG_BIT (reg_class_contents[(int) class], i)
/* Even if we can't use this register as a reload
register, we might use it for reload_override_in,
if copying it to the desired class is cheap
enough. */
|| ((REGISTER_MOVE_COST (last_class, class)
< MEMORY_MOVE_COST (mode, class, 1))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
&& (SECONDARY_INPUT_RELOAD_CLASS (class, mode,
last_reg)
== NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
&& ! SECONDARY_MEMORY_NEEDED (last_class, class,
mode)
#endif
))
&& (reload_nregs[r] == max_group_size
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
i))
......@@ -5913,6 +6143,9 @@ choose_reload_regs (chain, avoid_return_reg)
{
int i1;
last_reg = (GET_MODE (last_reg) == mode
? last_reg : gen_rtx_REG (mode, i));
/* We found a register that contains the
value we need. If this register is the
same as an `earlyclobber' operand of the
......@@ -5935,13 +6168,20 @@ choose_reload_regs (chain, avoid_return_reg)
if we need it wider than we've got it. */
|| (GET_MODE_SIZE (reload_mode[r])
> GET_MODE_SIZE (mode))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
i)
/* If find_reloads chose reload_out as reload
register, stay with it - that leaves the
inherited register for subsequent reloads. */
|| (reload_out[r] && reload_reg_rtx
&& rtx_equal_p (reload_out[r],
reload_reg_rtx[r])))
reload_override_in[r] = reg_last_reload_reg[regno];
{
reload_override_in[r] = last_reg;
reload_inheritance_insn[r]
= reg_reloaded_insn[i];
}
else
{
int k;
......@@ -5952,7 +6192,7 @@ choose_reload_regs (chain, avoid_return_reg)
reload_opnum[r],
reload_when_needed[r],
reload_mode[r]);
reload_reg_rtx[r] = reg_last_reload_reg[regno];
reload_reg_rtx[r] = last_reg;
reload_inherited[r] = 1;
reload_inheritance_insn[r]
= reg_reloaded_insn[i];
......@@ -6003,21 +6243,15 @@ choose_reload_regs (chain, avoid_return_reg)
/* If we found a spill reg, reject it unless it is free
and of the desired class. */
if (equiv != 0
&& ((spill_reg_order[regno] >= 0
&& ! (reload_reg_free_before_p (regno, reload_opnum[r],
reload_when_needed[r], 1)
|| reload_reg_free_for_value_p (regno,
reload_opnum[r],
&& ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
&& ! reload_reg_free_for_value_p (regno, reload_opnum[r],
reload_when_needed[r],
reload_in[r],
reload_out[r], r)))
reload_out[r], r))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
regno)))
equiv = 0;
if (equiv != 0 && TEST_HARD_REG_BIT (reload_reg_used_at_all, regno))
equiv = 0;
if (equiv != 0 && ! HARD_REGNO_MODE_OK (regno, reload_mode[r]))
equiv = 0;
......@@ -6204,76 +6438,58 @@ choose_reload_regs (chain, avoid_return_reg)
/* If we thought we could inherit a reload, because it seemed that
nothing else wanted the same reload register earlier in the insn,
verify that assumption, now that all reloads have been assigned. */
verify that assumption, now that all reloads have been assigned.
Likewise for reloads where reload_override_in has been set. */
/* If doing expensive optimizations, do one preliminary pass that doesn't
cancel any inheritance, but removes reloads that have been needed only
for reloads that we know can be inherited. */
for (pass = flag_expensive_optimizations; pass >= 0; pass--)
{
for (j = 0; j < n_reloads; j++)
{
register int r = reload_order[j];
rtx check_reg;
if (reload_inherited[r] && reload_reg_rtx[r] != 0
&& ! (reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
reload_opnum[r],
reload_when_needed[r], 0)
|| reload_reg_free_for_value_p (true_regnum (reload_reg_rtx[r]),
if (reload_inherited[r] && reload_reg_rtx[r])
check_reg = reload_reg_rtx[r];
else if (reload_override_in[r]
&& (GET_CODE (reload_override_in[r]) == REG
|| GET_CODE (reload_override_in[r]) == SUBREG))
check_reg = reload_override_in[r];
else
continue;
if (! (reload_reg_free_before_p (true_regnum (check_reg),
reload_opnum[r], reload_when_needed[r],
! reload_inherited[r])
|| reload_reg_free_for_value_p (true_regnum (check_reg),
reload_opnum[r],
reload_when_needed[r],
reload_in[r],
reload_out[r], r)))
reload_inherited[r] = 0;
/* If we can inherit a RELOAD_FOR_INPUT, then we do not need its related
RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads.
??? This could be extended to other reload types, but these are
more tricky to handle:
RELOAD_FOR_OTHER_ADDRESS reloads might have been merged, so we
can't eliminate them without a check that *all* references are
now unused due to inheritance.
While RELOAD_FOR_INPADDR_ADDRESS and RELOAD_FOR_OUTADDR_ADDRESS are
not merged, we can't be sure that we have eliminated the use of
that particular reload if we have seen just one
RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS being inherited,
since there might be multiple of the latter two reloads for a single
operand.
RELOAD_FOR_OPADDR_ADDR reloads for different operands are not
merged, but might share the same register by courtesy of
reload_reg_free_for_value_p. reload_reg_used_in_op_addr_reload
does not differentiate by opnum, thus calling clear_reload_reg_in_use
for one of these reloads would mark the register as free even though
another RELOAD_FOR_OPADDR_ADDR reload might still use it. */
else if (reload_inherited[r] && reload_when_needed[r] == RELOAD_FOR_INPUT)
{
for (i = 0; i < n_reloads; i++)
{
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
&& reload_opnum[i] == reload_opnum[r]
&& reload_in[i] && reload_reg_rtx[i])
{
int regno = true_regnum (reload_reg_rtx[i]);
reload_in[i] = 0;
if (spill_reg_order[regno] >= 0)
clear_reload_reg_in_use (regno, reload_opnum[i],
reload_when_needed[i],
reload_mode[i]);
reload_reg_rtx[i] = 0;
reload_spill_index[i] = -1;
remove_replacements (i);
}
}
}
/* If we found a better place to reload from,
validate it in the same fashion, if it is a reload reg. */
if (reload_override_in[r]
&& (GET_CODE (reload_override_in[r]) == REG
|| GET_CODE (reload_override_in[r]) == SUBREG))
{
int regno = true_regnum (reload_override_in[r]);
if (spill_reg_order[regno] >= 0
&& ! reload_reg_free_before_p (regno, reload_opnum[r],
reload_when_needed[r], 1))
if (pass)
continue;
reload_inherited[r] = 0;
reload_override_in[r] = 0;
}
/* If we can inherit a RELOAD_FOR_INPUT, or can use a
reload_override_in, then we do not need its related
RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads;
likewise for other reload types.
We handle this by removing a reload when its only replacement
is mentioned in reload_in of the reload we are going to inherit.
A special case are auto_inc expressions; even if the input is
inherited, we still need the address for the output. We can
recognize them because they have RELOAD_OUT set but not
RELOAD_OUT_REG.
If we suceeded removing some reload and we are doing a preliminary
pass just to remove such reloads, make another pass, since the
removal of one reload might allow us to inherit another one. */
else if ((! reload_out[r] || reload_out_reg[r])
&& remove_address_replacements (reload_in[r]) && pass)
pass = 2;
}
}
/* Now that reload_override_in is known valid,
......@@ -6309,10 +6525,10 @@ choose_reload_regs (chain, avoid_return_reg)
/* I is nonneg if this reload uses a register.
If reload_reg_rtx[r] is 0, this is an optional reload
that we opted to ignore. */
if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG
if (reload_out_reg[r] != 0 && GET_CODE (reload_out_reg[r]) == REG
&& reload_reg_rtx[r] != 0)
{
register int nregno = REGNO (reload_out[r]);
register int nregno = REGNO (reload_out_reg[r]);
int nr = 1;
if (nregno < FIRST_PSEUDO_REGISTER)
......@@ -6336,6 +6552,24 @@ choose_reload_regs (chain, avoid_return_reg)
}
}
/* Deallocate the reload register for reload R. This is called from
remove_address_replacements. */
void
deallocate_reload_reg (r)
int r;
{
int regno;
if (! reload_reg_rtx[r])
return;
regno = true_regnum (reload_reg_rtx[r]);
reload_reg_rtx[r] = 0;
if (spill_reg_order[regno] >= 0)
clear_reload_reg_in_use (regno, reload_opnum[r], reload_when_needed[r],
reload_mode[r]);
reload_spill_index[r] = -1;
}
/* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
reloads of the same item for fear that we might not have enough reload
registers. However, normally they will get the same reload register
......@@ -6495,11 +6729,17 @@ emit_reload_insns (chain)
rtx this_reload_insn = 0;
int expect_occurrences = 1;
if (reload_spill_index[j] >= 0)
new_spill_reg_store[reload_spill_index[j]] = 0;
if (reload_reg_rtx[j]
&& REGNO (reload_reg_rtx[j]) < FIRST_PSEUDO_REGISTER)
new_spill_reg_store[REGNO (reload_reg_rtx[j])] = 0;
old = (reload_in[j] && GET_CODE (reload_in[j]) == MEM
? reload_in_reg[j] : reload_in[j]);
old = reload_in[j];
if (old != 0 && ! reload_inherited[j]
if (old != 0
/* AUTO_INC reloads need to be handled even if inherited. We got an
AUTO_INC reload if reload_out is set but reload_out_reg isn't. */
&& (! reload_inherited[j] || (reload_out[j] && ! reload_out_reg[j]))
&& ! rtx_equal_p (reload_reg_rtx[j], old)
&& reload_reg_rtx[j] != 0)
{
......@@ -6628,6 +6868,17 @@ emit_reload_insns (chain)
oldequiv = 0;
}
/* delete_output_reload is only invoked properly if old contains
the original pseudo register. Since this is replaced with a
hard reg when RELOAD_OVERRIDE_IN is set, see if we can
find the pseudo in RELOAD_IN_REG. */
if (oldequiv == 0
&& reload_override_in[j]
&& GET_CODE (reload_in_reg[j]) == REG)
{
oldequiv = old;
old = reload_in_reg[j];
}
if (oldequiv == 0)
oldequiv = old;
else if (GET_CODE (oldequiv) == REG)
......@@ -6642,11 +6893,11 @@ emit_reload_insns (chain)
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG && dead_or_set_p (insn, old)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
&& count_occurrences (PATTERN (insn), old) == 1)
delete_output_reload (insn, j, spill_reg_store[REGNO (oldequiv)]);
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
reload_out_reg[j])))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
then load RELOADREG from OLDEQUIV. Note that we cannot use
......@@ -6700,20 +6951,35 @@ emit_reload_insns (chain)
special = 0;
/* Auto-increment addresses must be reloaded in a special way. */
if (GET_CODE (oldequiv) == POST_INC
|| GET_CODE (oldequiv) == POST_DEC
|| GET_CODE (oldequiv) == PRE_INC
|| GET_CODE (oldequiv) == PRE_DEC)
if (reload_out[j] && ! reload_out_reg[j])
{
/* We are not going to bother supporting the case where a
incremented register can't be copied directly from
OLDEQUIV since this seems highly unlikely. */
if (reload_secondary_in_reload[j] >= 0)
abort ();
if (reload_inherited[j])
oldequiv = reloadreg;
old = XEXP (reload_in_reg[j], 0);
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
old)))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Prevent normal processing of this reload. */
special = 1;
/* Output a special code sequence for this case. */
inc_for_reload (reloadreg, oldequiv, reload_inc[j]);
new_spill_reg_store[REGNO (reloadreg)]
= inc_for_reload (reloadreg, oldequiv, reload_out[j],
reload_inc[j]);
}
/* If we are reloading a pseudo-register that was set by the previous
......@@ -6789,15 +7055,31 @@ emit_reload_insns (chain)
/* If OLDEQUIV is a pseudo with a MEM, get the real MEM
and similarly for OLD.
See comments in get_secondary_reload in reload.c. */
/* If it is a pseudo that cannot be replaced with its
equivalent MEM, we must fall back to reload_in, which
will have all the necessary substitutions registered. */
if (GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (oldequiv)] != 0)
&& reg_equiv_memory_loc[REGNO (oldequiv)] != 0)
{
if (reg_equiv_address[REGNO (oldequiv)]
|| num_not_at_initial_offset)
real_oldequiv = reload_in[j];
else
real_oldequiv = reg_equiv_mem[REGNO (oldequiv)];
}
if (GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (old)] != 0)
&& reg_equiv_memory_loc[REGNO (old)] != 0)
{
if (reg_equiv_address[REGNO (old)]
|| num_not_at_initial_offset)
real_old = reload_in[j];
else
real_old = reg_equiv_mem[REGNO (old)];
}
second_reload_reg = reload_reg_rtx[secondary_reload];
icode = reload_secondary_in_icode[j];
......@@ -6882,7 +7164,7 @@ emit_reload_insns (chain)
third_reload_reg)));
}
else
gen_reload (second_reload_reg, oldequiv,
gen_reload (second_reload_reg, real_oldequiv,
reload_opnum[j],
reload_when_needed[j]);
......@@ -6893,8 +7175,22 @@ emit_reload_insns (chain)
#endif
if (! special && ! rtx_equal_p (reloadreg, oldequiv))
gen_reload (reloadreg, oldequiv, reload_opnum[j],
{
rtx real_oldequiv = oldequiv;
if ((GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_memory_loc[REGNO (oldequiv)] != 0)
|| (GET_CODE (oldequiv) == SUBREG
&& GET_CODE (SUBREG_REG (oldequiv)) == REG
&& (REGNO (SUBREG_REG (oldequiv))
>= FIRST_PSEUDO_REGISTER)
&& (reg_equiv_memory_loc
[REGNO (SUBREG_REG (oldequiv))] != 0)))
real_oldequiv = reload_in[j];
gen_reload (reloadreg, real_oldequiv, reload_opnum[j],
reload_when_needed[j]);
}
}
......@@ -6902,6 +7198,11 @@ emit_reload_insns (chain)
/* End this sequence. */
*where = get_insns ();
end_sequence ();
/* Update reload_override_in so that delete_address_reloads_1
can see the actual register usage. */
if (oldequiv_reg)
reload_override_in[j] = oldequiv;
}
/* When inheriting a wider reload, we have a MEM in reload_in[j],
......@@ -6909,6 +7210,7 @@ emit_reload_insns (chain)
(mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
if (optimize && reload_inherited[j] && reload_in[j]
&& GET_CODE (reload_in[j]) == MEM
&& GET_CODE (reload_in_reg[j]) == MEM
&& reload_spill_index[j] >= 0
&& TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
{
......@@ -6922,27 +7224,26 @@ emit_reload_insns (chain)
output-reload, see if we can prove there was
actually no need to store the old value in it. */
if (optimize && reload_inherited[j] && reload_spill_index[j] >= 0
&& reload_in[j] != 0
&& GET_CODE (reload_in[j]) == REG
if (optimize
&& (reload_inherited[j] || reload_override_in[j])
&& reload_reg_rtx[j]
&& GET_CODE (reload_reg_rtx[j]) == REG
&& spill_reg_store[REGNO (reload_reg_rtx[j])] != 0
#if 0
/* There doesn't seem to be any reason to restrict this to pseudos
and doing so loses in the case where we are copying from a
register of the wrong class. */
&& REGNO (reload_in[j]) >= FIRST_PSEUDO_REGISTER
&& REGNO (spill_reg_stored_to[REGNO (reload_reg_rtx[j])])
>= FIRST_PSEUDO_REGISTER
#endif
&& spill_reg_store[reload_spill_index[j]] != 0
/* This is unsafe if some other reload uses the same reg first. */
&& reload_reg_free_before_p (reload_spill_index[j],
reload_opnum[j], reload_when_needed[j],
0)
&& dead_or_set_p (insn, reload_in[j])
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
&& (count_occurrences (PATTERN (insn), reload_in[j])
== expect_occurrences))
delete_output_reload (insn, j,
spill_reg_store[reload_spill_index[j]]);
/* The insn might have already some references to stackslots
replaced by MEMs, while reload_out_reg still names the
original pseudo. */
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (reload_reg_rtx[j])])
|| rtx_equal_p (spill_reg_stored_to[REGNO (reload_reg_rtx[j])],
reload_out_reg[j])))
delete_output_reload (insn, j, REGNO (reload_reg_rtx[j]));
/* Input-reloading is done. Now do output-reloading,
storing the value from the reload-register after the main insn
......@@ -6950,7 +7251,33 @@ emit_reload_insns (chain)
??? At some point we need to support handling output reloads of
JUMP_INSNs or insns that set cc0. */
old = reload_out[j];
/* If this is an output reload that stores something that is
not loaded in this same reload, see if we can eliminate a previous
store. */
{
rtx pseudo = reload_out_reg[j];
if (pseudo
&& GET_CODE (pseudo) == REG
&& ! rtx_equal_p (reload_in_reg[j], pseudo)
&& REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
&& reg_last_reload_reg[REGNO (pseudo)])
{
int pseudo_no = REGNO (pseudo);
int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
/* We don't need to test full validity of last_regno for
inherit here; we only want to know if the store actually
matches the pseudo. */
if (reg_reloaded_contents[last_regno] == pseudo_no
&& spill_reg_store[last_regno]
&& rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
delete_output_reload (insn, j, last_regno);
}
}
old = reload_out_reg[j];
if (old != 0
&& reload_reg_rtx[j] != old
&& reload_reg_rtx[j] != 0)
......@@ -7006,6 +7333,8 @@ emit_reload_insns (chain)
else
push_to_sequence (output_reload_insns[reload_opnum[j]]);
old = reload_out[j];
/* Determine the mode to reload in.
See comments above (for input reloading). */
......@@ -7136,21 +7465,22 @@ emit_reload_insns (chain)
if (reg_mentioned_p (reload_reg_rtx[j], pat))
{
rtx set = single_set (insn);
if (reload_spill_index[j] < 0
&& GET_CODE (pat) == SET
&& SET_SRC (pat) == reload_reg_rtx[j])
&& set
&& SET_SRC (set) == reload_reg_rtx[j])
{
int src = REGNO (SET_SRC (pat));
int src = REGNO (SET_SRC (set));
reload_spill_index[j] = src;
SET_HARD_REG_BIT (reg_is_output_reload, src);
if (find_regno_note (insn, REG_DEAD, src))
SET_HARD_REG_BIT (reg_reloaded_died, src);
}
if (reload_spill_index[j] >= 0)
if (REGNO (reload_reg_rtx[j]) < FIRST_PSEUDO_REGISTER)
{
int s = reload_secondary_out_reload[j];
rtx set = single_set (p);
set = single_set (p);
/* If this reload copies only to the secondary reload
register, the secondary reload does the actual
store. */
......@@ -7169,13 +7499,18 @@ emit_reload_insns (chain)
rtx s_reg = reload_reg_rtx[s];
rtx next = NEXT_INSN (p);
reload_out[s] = reload_out[j];
reload_out_reg[s] = reload_out_reg[j];
set = single_set (next);
if (set && SET_SRC (set) == s_reg
&& ! new_spill_reg_store[REGNO (s_reg)])
{
SET_HARD_REG_BIT (reg_is_output_reload,
REGNO (s_reg));
new_spill_reg_store[REGNO (s_reg)] = next;
}
}
else
new_spill_reg_store[reload_spill_index[j]] = p;
new_spill_reg_store[REGNO (reload_reg_rtx[j])] = p;
}
}
}
......@@ -7292,14 +7627,25 @@ emit_reload_insns (chain)
CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
/* Maybe the spill reg contains a copy of reload_out. */
if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
register int nregno = REGNO (reload_out[r]);
if (reload_out[r] != 0
&& (GET_CODE (reload_out[r]) == REG
#ifdef AUTO_INC_DEC
|| ! reload_out_reg[r]
#endif
|| GET_CODE (reload_out_reg[r]) == REG))
{
rtx out = (GET_CODE (reload_out[r]) == REG
? reload_out[r]
: reload_out_reg[r]
? reload_out_reg[r]
/* AUTO_INC */ : XEXP (reload_in_reg[r], 0));
register int nregno = REGNO (out);
int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (nregno,
GET_MODE (reload_reg_rtx[r])));
spill_reg_store[i] = new_spill_reg_store[i];
spill_reg_stored_to[i] = out;
reg_last_reload_reg[nregno] = reload_reg_rtx[r];
/* If NREGNO is a hard register, it may occupy more than
......@@ -7332,21 +7678,25 @@ emit_reload_insns (chain)
/* Maybe the spill reg contains a copy of reload_in. Only do
something if there will not be an output reload for
the register being reloaded. */
else if (reload_out[r] == 0
else if (reload_out_reg[r] == 0
&& reload_in[r] != 0
&& spill_reg_order[i] >= 0
&& ((GET_CODE (reload_in[r]) == REG
&& REGNO (reload_in[r]) >= FIRST_PSEUDO_REGISTER
&& ! reg_has_output_reload[REGNO (reload_in[r])])
|| (GET_CODE (reload_in_reg[r]) == REG
&& ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
&& ! reg_has_output_reload[REGNO (reload_in_reg[r])]))
&& ! reg_set_p (reload_reg_rtx[r], PATTERN (insn)))
{
register int nregno;
int nnr;
if (GET_CODE (reload_in[r]) == REG)
if (GET_CODE (reload_in[r]) == REG
&& REGNO (reload_in[r]) >= FIRST_PSEUDO_REGISTER)
nregno = REGNO (reload_in[r]);
else
else if (GET_CODE (reload_in_reg[r]) == REG)
nregno = REGNO (reload_in_reg[r]);
else
nregno = REGNO (XEXP (reload_in_reg[r], 0));
nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (nregno,
......@@ -7363,8 +7713,11 @@ emit_reload_insns (chain)
: 0);
/* Unless we inherited this reload, show we haven't
recently done a store. */
if (! reload_inherited[r])
recently done a store.
Previous stores of inherited auto_inc expressions
also have to be discarded. */
if (! reload_inherited[r]
|| (reload_out[r] && ! reload_out_reg[r]))
spill_reg_store[i] = 0;
for (k = 0; k < nr; k++)
......@@ -7400,11 +7753,76 @@ emit_reload_insns (chain)
that invalidates any previous reloaded copy of it.
But forget_old_reloads_1 won't get to see it, because
it thinks only about the original insn. So invalidate it here. */
if (i < 0 && reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
register int nregno = REGNO (reload_out[r]);
if (i < 0 && reload_out[r] != 0
&& (GET_CODE (reload_out[r]) == REG
|| (GET_CODE (reload_out[r]) == MEM
&& GET_CODE (reload_out_reg[r]) == REG)))
{
rtx out = (GET_CODE (reload_out[r]) == REG
? reload_out[r] : reload_out_reg[r]);
register int nregno = REGNO (out);
if (nregno >= FIRST_PSEUDO_REGISTER)
{
rtx src_reg, store_insn;
reg_last_reload_reg[nregno] = 0;
/* If we can find a hard register that is stored, record
the storing insn so that we may delete this insn with
delete_output_reload. */
src_reg = reload_reg_rtx[r];
/* If this is an optional reload, try to find the source reg
from an input reload. */
if (! src_reg)
{
rtx set = single_set (insn);
if (SET_DEST (set) == reload_out[r])
{
int k;
src_reg = SET_SRC (set);
store_insn = insn;
for (k = 0; k < n_reloads; k++)
{
if (reload_in[k] == src_reg)
{
src_reg = reload_reg_rtx[k];
break;
}
}
}
}
else
store_insn = new_spill_reg_store[REGNO (src_reg)];
if (src_reg && GET_CODE (src_reg) == REG
&& REGNO (src_reg) < FIRST_PSEUDO_REGISTER)
{
int src_regno = REGNO (src_reg);
int nr = HARD_REGNO_NREGS (src_regno, reload_mode[r]);
/* The place where to find a death note varies with
PRESERVE_DEATH_INFO_REGNO_P . The condition is not
necessarily checked exactly in the code that moves
notes, so just check both locations. */
rtx note = find_regno_note (insn, REG_DEAD, src_regno);
if (! note)
note = find_regno_note (store_insn, REG_DEAD, src_regno);
while (nr-- > 0)
{
spill_reg_store[src_regno + nr] = store_insn;
spill_reg_stored_to[src_regno + nr] = out;
reg_reloaded_contents[src_regno + nr] = nregno;
reg_reloaded_insn[src_regno + nr] = store_insn;
SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
if (note)
SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
else
CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
reg_last_reload_reg[nregno] = src_reg;
}
}
else
{
int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (reload_out[r]));
......@@ -7630,22 +8048,66 @@ gen_reload (out, in, opnum, type)
First we double-check.
INSN is the insn now being processed.
OUTPUT_RELOAD_INSN is the insn of the output reload.
J is the reload-number for this insn. */
LAST_RELOAD_REG is the hard register number for which we want to delete
the last output reload.
J is the reload-number that originally used REG. The caller has made
certain that reload J doesn't use REG any longer for input. */
static void
delete_output_reload (insn, j, output_reload_insn)
delete_output_reload (insn, j, last_reload_reg)
rtx insn;
int j;
rtx output_reload_insn;
int last_reload_reg;
{
rtx output_reload_insn = spill_reg_store[last_reload_reg];
rtx reg = spill_reg_stored_to[last_reload_reg];
int k;
int n_occurrences;
int n_inherited = 0;
register rtx i1;
rtx substed;
/* Get the raw pseudo-register referred to. */
rtx reg = reload_in[j];
while (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
substed = reg_equiv_memory_loc[REGNO (reg)];
/* This is unsafe if the operand occurs more often in the current
insn than it is inherited. */
for (k = n_reloads - 1; k >= 0; k--)
{
rtx reg2 = reload_in[k];
if (! reg2)
continue;
if (GET_CODE (reg2) == MEM || reload_override_in[k])
reg2 = reload_in_reg[k];
#ifdef AUTO_INC_DEC
if (reload_out[k] && ! reload_out_reg[k])
reg2 = XEXP (reload_in_reg[k], 0);
#endif
while (GET_CODE (reg2) == SUBREG)
reg2 = SUBREG_REG (reg2);
if (rtx_equal_p (reg2, reg))
if (reload_inherited[k] || reload_override_in[k] || k == j)
{
n_inherited++;
reg2 = reload_out_reg[k];
if (! reg2)
continue;
while (GET_CODE (reg2) == SUBREG)
reg2 = XEXP (reg2, 0);
if (rtx_equal_p (reg2, reg))
n_inherited++;
}
else
return;
}
n_occurrences = count_occurrences (PATTERN (insn), reg);
if (substed)
n_occurrences += count_occurrences (PATTERN (insn), substed);
if (n_occurrences > n_inherited)
return;
/* If the pseudo-reg we are reloading is no longer referenced
anywhere between the store into it and here,
......@@ -7660,21 +8122,14 @@ delete_output_reload (insn, j, output_reload_insn)
if ((GET_CODE (i1) == INSN || GET_CODE (i1) == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (i1)))
{
/* If this is just a single USE with an REG_EQUAL note in front
of INSN, this is no problem, because this mentions just the
address that we are using here.
But if there is more than one such USE, the insn might use
the operand directly, or another reload might do that.
This is analogous to the count_occurences check in the callers. */
int num_occurences = 0;
while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE
&& find_reg_note (i1, REG_EQUAL, NULL_RTX))
/* If this is USE in front of INSN, we only have to check that
there are no more references than accounted for by inheritance. */
while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE)
{
num_occurences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
n_occurrences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
i1 = NEXT_INSN (i1);
}
if (num_occurences == 1 && i1 == insn)
if (n_occurrences <= n_inherited && i1 == insn)
break;
return;
}
......@@ -7717,7 +8172,10 @@ delete_output_reload (insn, j, output_reload_insn)
{
/* Some other ref remains; just delete the output reload we
know to be dead. */
delete_insn (output_reload_insn);
delete_address_reloads (output_reload_insn, insn);
PUT_CODE (output_reload_insn, NOTE);
NOTE_SOURCE_FILE (output_reload_insn) = 0;
NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
return;
}
}
......@@ -7729,6 +8187,7 @@ delete_output_reload (insn, j, output_reload_insn)
if (set != 0 && SET_DEST (set) == reg)
{
delete_address_reloads (i2, insn);
/* This might be a basic block head,
thus don't use delete_insn. */
PUT_CODE (i2, NOTE);
......@@ -7745,22 +8204,178 @@ delete_output_reload (insn, j, output_reload_insn)
reg_renumber[REGNO (reg)] = REGNO (reload_reg_rtx[j]);
alter_reg (REGNO (reg), -1);
}
delete_insn (output_reload_insn);
delete_address_reloads (output_reload_insn, insn);
PUT_CODE (output_reload_insn, NOTE);
NOTE_SOURCE_FILE (output_reload_insn) = 0;
NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
}
/* We are going to delete DEAD_INSN. Recursively delete loads of
reload registers used in DEAD_INSN that are not used till CURRENT_INSN.
CURRENT_INSN is being reloaded, so we have to check its reloads too. */
static void
delete_address_reloads (dead_insn, current_insn)
rtx dead_insn, current_insn;
{
rtx set = single_set (dead_insn);
rtx set2, dst, prev, next;
if (set)
{
rtx dst = SET_DEST (set);
if (GET_CODE (dst) == MEM)
delete_address_reloads_1 (dead_insn, XEXP (dst, 0), current_insn);
}
/* If we deleted the store from a reloaded post_{in,de}c expression,
we can delete the matching adds. */
prev = PREV_INSN (dead_insn);
next = NEXT_INSN (dead_insn);
if (! prev || ! next)
return;
set = single_set (next);
set2 = single_set (prev);
if (! set || ! set2
|| GET_CODE (SET_SRC (set)) != PLUS || GET_CODE (SET_SRC (set2)) != PLUS
|| GET_CODE (XEXP (SET_SRC (set), 1)) != CONST_INT
|| GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT)
return;
dst = SET_DEST (set);
if (! rtx_equal_p (dst, SET_DEST (set2))
|| ! rtx_equal_p (dst, XEXP (SET_SRC (set), 0))
|| ! rtx_equal_p (dst, XEXP (SET_SRC (set2), 0))
|| (INTVAL (XEXP (SET_SRC (set), 1))
!= - INTVAL (XEXP (SET_SRC (set2), 1))))
return;
delete_insn (prev);
delete_insn (next);
}
/* Subfunction of delete_address_reloads: process registers found in X. */
static void
delete_address_reloads_1 (dead_insn, x, current_insn)
rtx dead_insn, x, current_insn;
{
rtx prev, set, dst, i2;
int i, j;
enum rtx_code code = GET_CODE (x);
if (code != REG)
{
char *fmt= GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
delete_address_reloads_1 (dead_insn, XEXP (x, i), current_insn);
else if (fmt[i] == 'E')
{
for (j = XVECLEN (x, i) - 1; j >=0; j--)
delete_address_reloads_1 (dead_insn, XVECEXP (x, i, j),
current_insn);
}
}
return;
}
if (spill_reg_order[REGNO (x)] < 0)
return;
/* Scan backwards for the insn that sets x. This might be a way back due
to inheritance. */
for (prev = PREV_INSN (dead_insn); prev; prev = PREV_INSN (prev))
{
code = GET_CODE (prev);
if (code == CODE_LABEL || code == JUMP_INSN)
return;
if (GET_RTX_CLASS (code) != 'i')
continue;
if (reg_set_p (x, PATTERN (prev)))
break;
if (reg_referenced_p (x, PATTERN (prev)))
return;
}
if (! prev || INSN_UID (prev) < reload_first_uid)
return;
/* Check that PREV only sets the reload register. */
set = single_set (prev);
if (! set)
return;
dst = SET_DEST (set);
if (GET_CODE (dst) != REG
|| ! rtx_equal_p (dst, x))
return;
if (! reg_set_p (dst, PATTERN (dead_insn)))
{
/* Check if DST was used in a later insn -
it might have been inherited. */
for (i2 = NEXT_INSN (dead_insn); i2; i2 = NEXT_INSN (i2))
{
if (GET_CODE (i2) == CODE_LABEL)
break;
if (GET_RTX_CLASS (GET_CODE (i2)) != 'i')
continue;
if (reg_referenced_p (dst, PATTERN (i2)))
{
/* If there is a reference to the register in the current insn,
it might be loaded in a non-inherited reload. If no other
reload uses it, that means the register is set before
referenced. */
if (i2 == current_insn)
{
for (j = n_reloads - 1; j >= 0; j--)
if ((reload_reg_rtx[j] == dst && reload_inherited[j])
|| reload_override_in[j] == dst)
return;
for (j = n_reloads - 1; j >= 0; j--)
if (reload_in[j] && reload_reg_rtx[j] == dst)
break;
if (j >= 0)
break;
}
return;
}
if (GET_CODE (i2) == JUMP_INSN)
break;
if (reg_set_p (dst, PATTERN (i2)))
break;
/* If DST is still live at CURRENT_INSN, check if it is used for
any reload. */
if (i2 == current_insn)
{
for (j = n_reloads - 1; j >= 0; j--)
if ((reload_reg_rtx[j] == dst && reload_inherited[j])
|| reload_override_in[j] == dst)
return;
/* ??? We can't finish the loop here, because dst might be
allocated to a pseudo in this block if no reload in this
block needs any of the clsses containing DST - see
spill_hard_reg. There is no easy way to tell this, so we
have to scan till the end of the basic block. */
}
}
}
delete_address_reloads_1 (prev, SET_SRC (set), current_insn);
reg_reloaded_contents[REGNO (dst)] = -1;
/* Can't use delete_insn here because PREV might be a basic block head. */
PUT_CODE (prev, NOTE);
NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (prev) = 0;
}
/* Output reload-insns to reload VALUE into RELOADREG.
VALUE is an autoincrement or autodecrement RTX whose operand
is a register or memory location;
so reloading involves incrementing that location.
IN is either identical to VALUE, or some cheaper place to reload from.
INC_AMOUNT is the number to increment or decrement by (always positive).
This cannot be deduced from VALUE. */
This cannot be deduced from VALUE.
static void
inc_for_reload (reloadreg, value, inc_amount)
Return the instruction that stores into RELOADREG. */
static rtx
inc_for_reload (reloadreg, in, value, inc_amount)
rtx reloadreg;
rtx value;
rtx in, value;
int inc_amount;
{
/* REG or MEM to be copied and incremented. */
......@@ -7771,6 +8386,8 @@ inc_for_reload (reloadreg, value, inc_amount)
rtx inc;
rtx add_insn;
int code;
rtx store;
rtx real_in = in == value ? XEXP (in, 0) : in;
/* No hard register is equivalent to this register after
inc/dec operation. If REG_LAST_RELOAD_REG were non-zero,
......@@ -7785,11 +8402,13 @@ inc_for_reload (reloadreg, value, inc_amount)
inc = GEN_INT (inc_amount);
/* If this is post-increment, first copy the location to the reload reg. */
if (post)
emit_insn (gen_move_insn (reloadreg, incloc));
if (post && real_in != reloadreg)
emit_insn (gen_move_insn (reloadreg, real_in));
/* See if we can directly increment INCLOC. Use a method similar to that
in gen_reload. */
if (in == value)
{
/* See if we can directly increment INCLOC. Use a method similar to
that in gen_reload. */
last = get_last_insn ();
add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
......@@ -7809,11 +8428,11 @@ inc_for_reload (reloadreg, value, inc_amount)
if (! post)
emit_insn (gen_move_insn (reloadreg, incloc));
return;
return add_insn;
}
}
delete_insns_since (last);
}
/* If couldn't do the increment directly, must increment in RELOADREG.
The way we do this depends on whether this is pre- or post-increment.
......@@ -7822,9 +8441,10 @@ inc_for_reload (reloadreg, value, inc_amount)
if (! post)
{
emit_insn (gen_move_insn (reloadreg, incloc));
if (in != reloadreg)
emit_insn (gen_move_insn (reloadreg, real_in));
emit_insn (gen_add2_insn (reloadreg, inc));
emit_insn (gen_move_insn (incloc, reloadreg));
store = emit_insn (gen_move_insn (incloc, reloadreg));
}
else
{
......@@ -7833,16 +8453,16 @@ inc_for_reload (reloadreg, value, inc_amount)
may not be available after the insn in an input reload, we must do
the incrementation before the insn being reloaded for.
We have already copied INCLOC to RELOADREG. Increment the copy in
We have already copied IN to RELOADREG. Increment the copy in
RELOADREG, save that back, then decrement RELOADREG so it has
the original value. */
emit_insn (gen_add2_insn (reloadreg, inc));
emit_insn (gen_move_insn (incloc, reloadreg));
store = emit_insn (gen_move_insn (incloc, reloadreg));
emit_insn (gen_add2_insn (reloadreg, GEN_INT (-inc_amount)));
}
return;
return store;
}
/* Return 1 if we are certain that the constraint-string STRING allows
......@@ -7921,6 +8541,10 @@ count_occurrences (x, find)
case CC0:
return 0;
case MEM:
if (GET_CODE (find) == MEM && rtx_equal_p (x, find))
return 1;
break;
case SET:
if (SET_DEST (x) == find)
return count_occurrences (SET_SRC (x), find);
......
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