aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog111
-rw-r--r--gcc/reload.c476
-rw-r--r--gcc/reload.h15
-rw-r--r--gcc/reload1.c1260
4 files changed, 1375 insertions, 487 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index df1abe7..04da772 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,114 @@
+Fri Oct 16 20:40:50 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ Fix consistency problems with reg_equiv_{mem,address};
+ Improve reload inheritance;
+
+ * reload.c (reload_out_reg): New variable.
+ (loc_mentioned_in_p, remove_address_replacements): New functions.
+ (remove_replacements): Deleted.
+ (push_reload): Set reload_out_reg[i].
+ When merging, also set reload_{in,out}_reg[i], and remove
+ duplicate address reloads.
+ (combine_reloads): Copy reload_out_reg[i].
+ (find_reloads): Do make_memloc substitution also when
+ reg_equiv_memory_loc[regno] and num_not_at_initial_offset
+ are both nonzero.
+ Include *recog_operand_loc in commutativity operand changes.
+ Generate optional output reloads.
+ Delete reference to n_memlocs. Don't set *recog_operand_loc before
+ processing operands. Call make_memloc in reg_equiv_address code.
+ Set *recog_operand_loc only after processing operands, and only
+ if replace is true. Return a value.
+ When changing address reload types for operands that didn't get
+ reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
+ RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
+ Don't emit USEs for pseudo SUBREGs when not replacing.
+ (find_reloads_address): Do make_memloc substitution also when
+ reg_equiv_memory_loc[regno] and num_not_at_initial_offset
+ are both nonzero.
+ (find_reloads_toplev): Likewise.
+ Call make_memloc in reg_equiv_address code.
+ (debug_reload_to_stream): Add code to output reload_out_reg.
+ (make_memloc): Delete local variable i, ifdefed out code, and
+ references to memlocs and n_memlocs.
+ (memlocs, n_memlocs): Delete.
+ (push_secondary_reload): Clear reload_out_reg.
+ (find_reloads_address_1): Provide memrefloc argument to all calls
+ to find_reloads_address.
+ In AUTO_INC code, handle non-directly addressable equivalences properly.
+ * reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
+ (find_reloads): Add return type.
+ (remove_address_replacements, deallocate_reload_reg): Declare.
+ * reload1.c (num_not_at_initial_offset): No longer static.
+ (delete_address_reloads, delete_address_reloads_1): Likewise.
+ (deallocate_reload_reg): New function.
+ (spill_reg_stored_to): New array.
+ (eliminate_regs): Don't substitute from reg_equiv_memory_loc.
+ (eliminate_regs_in_insn): Move assignments of previous_offset and
+ max_offset fields, and recalculation of num_not_at_initial_offset
+ into new static function:
+ (update_eliminable_offsets) .
+ (reload_as_needed): Call update_eliminable_offsetss after calling
+ find_reloads.
+ Call forget_old_reloads_1 with contents of reloaded auto_inc
+ expressions if the actual addressing can't be changed to match the
+ auto_inc.
+ (choose_reload_regs): For inheritance, replace
+ reload_reg_free_before_p test with reload_reg_used_at_all test, and
+ remove stand-alone reload_reg_used_at_all test.
+ Use reload_out_reg to determine which reload regs have output reloads.
+ Treat reload_override_in more similar to inherited reloads.
+ Handle (subreg (reg... for inheritance.
+ For flag_expensive_optimizations, add an extra pass to remove
+ unnecessary reloads from known working inheritance.
+ Delete obsolete code for pseudos replaced with MEMs.
+ Handle inheritance from auto_inc expressions.
+ (emit_reload_insns): If reload_in is a MEM, set OLD to
+ reload_in_reg[j].
+ Don't reload directly from oldequiv; if it's a pseudo with a
+ stack slot, use reload_in[j].
+ Check that reload_in_reg[j] is a MEM before replacing reload_in
+ from reg_reloaded_contents.
+ Include non-spill registers in reload inheritance processing.
+ Also try to use reload_out_reg to set spill_reg_store /
+ reg_last_reload_reg.
+ In code to set new_spill_reg_store, use single_set to find out if
+ there is a single set.
+ Add code that allows to delete optional output reloads.
+ Add code to allow deletion of output reloads that use no spill reg.
+ At the end, set reload_override_in to oldequiv.
+ Also call delete_output_reload if reload_out_reg is equal to old
+ in oldequiv code.
+ Add code to call delete_output_reload for stores with no matching load.
+ Set / use spill_reg_stored_to.
+ Handle case where secondary output reload uses a temporary, but
+ actual store isn't found.
+ When looking for a store of a value not loaded in order to call
+ delete_output_reload, count_occurences should return 0 for no
+ loads; but discount inherited input reloadill_reg_stored_to.
+ Do checks for extra uses of REG. Changed all
+ callers.
+ Use delete_address_reloads.
+ (reload): Take return value of find_reloads into account.
+ If a no-op set needs more than one reload, delete it.
+ (reload_reg_free_before_p): RELOAD_FOR_INPUT
+ can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
+ for the same operand.
+ (clear_reload_reg_in_use): Check for other reloads that keep a
+ register in use.
+ (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
+ RELOAD_FOR_OPADDR_ADDR.
+ Take into account when an address address reload is only needed
+ for the address reload we are considering.
+ (count_occurrences): Use rtx_equal_p for MEMs.
+ (inc_for_reload): Return instruction that stores into RELOADREG.
+ New argument two, IN, and rtx. Changed all callers.
+ (calculate_needs_all_insns, reload_as_needed):
+ Don't clear after_call for a CLOBBER.
+ Keep track of how many hard registers need to be copied from
+ after_call, and don't clear after_call before we have seen
+ that much copies, or we see a different instruction.
+
Fri Oct 16 10:58:23 1998 Jeffrey A Law (law@cygnus.com)
* flow.c (find_basic_blocks_1): Do not delete unreachable blocks
diff --git a/gcc/reload.c b/gcc/reload.c
index 1e438e1..6f3ba43 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -181,6 +181,7 @@ char reload_optional[MAX_RELOADS];
char reload_nongroup[MAX_RELOADS];
int reload_inc[MAX_RELOADS];
rtx reload_in_reg[MAX_RELOADS];
+rtx reload_out_reg[MAX_RELOADS];
char reload_nocombine[MAX_RELOADS];
int reload_opnum[MAX_RELOADS];
enum reload_type reload_when_needed[MAX_RELOADS];
@@ -232,11 +233,6 @@ struct decomposition
HOST_WIDE_INT end; /* Ending offset or register number. */
};
-/* MEM-rtx's created for pseudo-regs in stack slots not directly addressable;
- (see reg_equiv_address). */
-static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
-static int n_memlocs;
-
#ifdef SECONDARY_MEMORY_NEEDED
/* Save MEMs needed to copy from one class of registers to another. One MEM
@@ -329,11 +325,11 @@ static int hard_reg_set_here_p PROTO((int, int, rtx));
static struct decomposition decompose PROTO((rtx));
static int immune_p PROTO((rtx, rtx, struct decomposition));
static int alternative_allows_memconst PROTO((char *, int));
-static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
+static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
static rtx make_memloc PROTO((rtx, int));
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
-static rtx subst_reg_equivs PROTO((rtx));
+static rtx subst_reg_equivs PROTO((rtx, rtx));
static rtx subst_indexed_address PROTO((rtx));
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
int, enum reload_type,int, rtx));
@@ -341,6 +337,7 @@ static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
static int find_inc_amount PROTO((rtx, rtx));
+static int loc_mentioned_in_p PROTO((rtx *, rtx));
#ifdef HAVE_SECONDARY_RELOADS
@@ -536,6 +533,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[t_reload] = 1;
reload_in_reg[t_reload] = 0;
+ reload_out_reg[t_reload] = 0;
reload_opnum[t_reload] = opnum;
reload_when_needed[t_reload] = secondary_type;
reload_secondary_in_reload[t_reload] = -1;
@@ -605,6 +603,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[s_reload] = 1;
reload_in_reg[s_reload] = 0;
+ reload_out_reg[s_reload] = 0;
reload_opnum[s_reload] = opnum;
reload_when_needed[s_reload] = secondary_type;
reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
@@ -1170,7 +1169,11 @@ push_reload (in, out, inloc, outloc, class,
}
}
- if (class == NO_REGS)
+ /* Optional output reloads are always OK even if we have no register class,
+ since the function of these reloads is only to have spill_reg_store etc.
+ set, so that the storing insn can be deleted later. */
+ if (class == NO_REGS
+ && (optional == 0 || type != RELOAD_FOR_OUTPUT))
abort ();
/* We can use an existing reload if the class is right
@@ -1281,6 +1284,7 @@ push_reload (in, out, inloc, outloc, class,
reload_inc[i] = 0;
reload_nocombine[i] = 0;
reload_in_reg[i] = inloc ? *inloc : 0;
+ reload_out_reg[i] = outloc ? *outloc : 0;
reload_opnum[i] = opnum;
reload_when_needed[i] = type;
reload_secondary_in_reload[i] = secondary_in_reload;
@@ -1315,9 +1319,32 @@ push_reload (in, out, inloc, outloc, class,
&& GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
reload_outmode[i] = outmode;
if (in != 0)
- reload_in[i] = in;
+ {
+ /* If we merge reloads for two distinct rtl expressions that
+ are identical in content, there might be duplicate address
+ reloads. Remove the extra set now, so that if we later find
+ that we can inherit this reload, we can get rid of the
+ address reloads altogether. */
+ if (reload_in[i] != in && rtx_equal_p (in, reload_in[i]))
+ {
+ /* We must keep the address reload with the lower operand
+ number alive. */
+ if (opnum > reload_opnum[i])
+ {
+ remove_address_replacements (in);
+ in = reload_in[i];
+ }
+ else
+ remove_address_replacements (reload_in[i]);
+ }
+ reload_in[i] = in;
+ reload_in_reg[i] = inloc ? *inloc : 0;
+ }
if (out != 0)
- reload_out[i] = out;
+ {
+ reload_out[i] = out;
+ reload_out_reg[i] = outloc ? *outloc : 0;
+ }
if (reg_class_subset_p (class, reload_reg_class[i]))
reload_reg_class[i] = class;
reload_optional[i] &= optional;
@@ -1506,19 +1533,67 @@ transfer_replacements (to, from)
replacements[i].what = to;
}
-/* Remove all replacements in reload FROM. */
-void
-remove_replacements (from)
- int from;
+/* IN_RTX is the value loaded by a reload that we now decided to inherit,
+ or a subpart of it. If we have any replacements registered for IN_RTX,
+ cancel the reloads that were supposed to load them.
+ Return non-zero if we canceled any reloads. */
+int
+remove_address_replacements (in_rtx)
+ rtx in_rtx;
{
int i, j;
+ char reload_flags[MAX_RELOADS];
+ int something_changed = 0;
+ bzero (reload_flags, sizeof reload_flags);
for (i = 0, j = 0; i < n_replacements; i++)
{
- if (replacements[i].what == from)
- continue;
- replacements[j++] = replacements[i];
+ if (loc_mentioned_in_p (replacements[i].where, in_rtx))
+ reload_flags[replacements[i].what] |= 1;
+ else
+ {
+ replacements[j++] = replacements[i];
+ reload_flags[replacements[i].what] |= 2;
+ }
+ }
+ /* Note that the following store must be done before the recursive calls. */
+ n_replacements = j;
+
+ for (i = n_reloads - 1; i >= 0; i--)
+ {
+ if (reload_flags[i] == 1)
+ {
+ deallocate_reload_reg (i);
+ remove_address_replacements (reload_in[i]);
+ reload_in[i] = 0;
+ something_changed = 1;
+ }
+ }
+ return something_changed;
+}
+
+/* Return non-zero if IN contains a piece of rtl that has the address LOC */
+static int
+loc_mentioned_in_p (loc, in)
+ rtx *loc, in;
+{
+ enum rtx_code code = GET_CODE (in);
+ char *fmt = GET_RTX_FORMAT (code);
+ int i, j;
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (loc == &XEXP (in, i))
+ return 1;
+ if (fmt[i] == 'e')
+ if (loc_mentioned_in_p (loc, XEXP (in, i)))
+ return 1;
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (in, i) - 1; i >= 0; i--)
+ if (loc_mentioned_in_p (loc, XVECEXP (in, i, j)))
+ return 1;
}
+ return 0;
}
/* If there is only one output reload, and it is not for an earlyclobber
@@ -1617,6 +1692,7 @@ combine_reloads ()
/* We have found a reload to combine with! */
reload_out[i] = reload_out[output_reload];
+ reload_out_reg[i] = reload_out_reg[output_reload];
reload_outmode[i] = reload_outmode[output_reload];
/* Mark the old output reload as inoperative. */
reload_out[output_reload] = 0;
@@ -2299,9 +2375,12 @@ safe_from_earlyclobber (op, clobber)
RELOAD_REG_P if nonzero is a vector indexed by hard reg number
which is nonnegative if the reg has been commandeered for reloading into.
It is copied into STATIC_RELOAD_REG_P and referenced from there
- by various subroutines. */
+ by various subroutines.
-void
+ Return TRUE if some operands need to be changed, because of swapping
+ commutative operands, reg_equiv_address substitution, or whatever. */
+
+int
find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx insn;
int replace, ind_levels;
@@ -2357,6 +2436,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx set = single_set (insn);
int goal_earlyclobber, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+ int retval = 0;
/* Cache the last regno for the last pseudo we did an output reload
for in case the next insn uses it. */
static int last_output_reload_regno = -1;
@@ -2365,7 +2445,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
this_insn_is_asm = 0; /* Tentative. */
n_reloads = 0;
n_replacements = 0;
- n_memlocs = 0;
n_earlyclobbers = 0;
replace_reloads = replace;
hard_regs_live_known = live_known;
@@ -2406,7 +2485,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
- return;
+ return 0;
case SET:
/* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
@@ -2418,7 +2497,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
- return;
+ return 0;
case PARALLEL:
case ASM_OPERANDS:
reload_n_operands = noperands = asm_noperands (body);
@@ -2458,7 +2537,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
n_alternatives = insn_n_alternatives[insn_code_number];
/* Just return "no reloads" if insn has no operands with constraints. */
if (n_alternatives == 0)
- return;
+ return 0;
insn_extract (insn);
for (i = 0; i < noperands; i++)
{
@@ -2469,7 +2548,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
if (noperands == 0)
- return;
+ return 0;
commutative = -1;
@@ -2577,9 +2656,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|| GET_CODE (recog_operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
- find_reloads (insn, replace, ind_levels, live_known,
- reload_reg_p);
- return;
+ retval = find_reloads (insn, replace, ind_levels, live_known,
+ reload_reg_p);
+ return retval;
}
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
@@ -2601,14 +2680,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels,
set != 0
- && &SET_DEST (set) == recog_operand_loc[i]);
+ && &SET_DEST (set) == recog_operand_loc[i],
+ insn);
/* If we made a MEM to load (a part of) the stackslot of a pseudo
that didn't get a hard register, emit a USE with a REG_EQUAL
note in front so that we might inherit a previous, possibly
wider reload. */
- if (GET_CODE (op) == MEM
+ if (replace
+ && GET_CODE (op) == MEM
&& GET_CODE (reg) == REG
&& (GET_MODE_SIZE (GET_MODE (reg))
>= GET_MODE_SIZE (GET_MODE (op))))
@@ -2616,15 +2697,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= gen_rtx_EXPR_LIST (REG_EQUAL,
reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
+ substed_operand[i] = recog_operand[i] = op;
}
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
/* We can get a PLUS as an "operand" as a result of register
elimination. See eliminate_regs and gen_reload. We handle
a unary operator by reloading the operand. */
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
+ substed_operand[i] = recog_operand[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
- ind_levels, 0);
+ ind_levels, 0, insn);
else if (code == REG)
{
/* This is equivalent to calling find_reloads_toplev.
@@ -2646,44 +2727,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
substed_operand[i] = recog_operand[i]
= reg_equiv_constant[regno];
}
-#if 0 /* This might screw code in reload1.c to delete prior output-reload
- that feeds this insn. */
- if (reg_equiv_mem[regno] != 0)
+ if (reg_equiv_memory_loc[regno] != 0
+ && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
+ /* We need not give a valid is_set_dest argument since the case
+ of a constant equivalence was checked above. */
substed_operand[i] = recog_operand[i]
- = reg_equiv_mem[regno];
-#endif
- if (reg_equiv_address[regno] != 0)
- {
- /* If reg_equiv_address is not a constant address, copy it,
- since it may be shared. */
- /* We must rerun eliminate_regs, in case the elimination
- offsets have changed. */
- rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno],
- 0, NULL_RTX),
- 0);
-
- if (rtx_varies_p (address))
- address = copy_rtx (address);
-
- /* Emit a USE that shows what register is being used/modified. */
- REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
- recog_operand[i]),
- insn))
- = gen_rtx_EXPR_LIST (REG_EQUAL,
- reg_equiv_memory_loc[regno],
- NULL_RTX);
-
- *recog_operand_loc[i] = recog_operand[i]
- = gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
- RTX_UNCHANGING_P (recog_operand[i])
- = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
- find_reloads_address (GET_MODE (recog_operand[i]),
- recog_operand_loc[i],
- XEXP (recog_operand[i], 0),
- &XEXP (recog_operand[i], 0),
- i, address_type[i], ind_levels, insn);
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
- }
+ = find_reloads_toplev (recog_operand[i], i, address_type[i],
+ ind_levels, 0, insn);
}
/* If the operand is still a register (we didn't replace it with an
equivalent), get the preferred class to reload it into. */
@@ -3511,7 +3561,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
- return;
+ return 0;
}
/* Jump to `finish' from above if all operands are valid already.
@@ -3546,6 +3596,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
tem = recog_operand[commutative];
recog_operand[commutative] = recog_operand[commutative + 1];
recog_operand[commutative + 1] = tem;
+ tem = *recog_operand_loc[commutative];
+ *recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
+ *recog_operand_loc[commutative+1] = tem;
for (i = 0; i < n_reloads; i++)
{
@@ -3556,14 +3609,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
}
- /* Perform whatever substitutions on the operands we are supposed
- to make due to commutativity or replacement of registers
- with equivalent constants or memory slots. */
-
for (i = 0; i < noperands; i++)
{
- *recog_operand_loc[i] = substed_operand[i];
- /* While we are looping on operands, initialize this. */
operand_reloadnum[i] = -1;
/* If this is an earlyclobber operand, we need to widen the scope.
@@ -3605,7 +3652,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
*recog_operand_loc[i] = recog_operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_operand[i]),
- i, address_type[i], ind_levels, 0);
+ i, address_type[i], ind_levels, 0, insn);
if (alternative_allows_memconst (constraints1[i],
goal_alternative_number))
goal_alternative_win[i] = 1;
@@ -3730,7 +3777,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
- return;
+ return 0;
}
}
else if (goal_alternative_matched[i] < 0
@@ -3748,13 +3795,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
- && (enum reg_class) goal_alternative[i] != NO_REGS
+ /* If this is only for an output, the optional reload would not
+ actually cause us to use a register now, just note that
+ something is stored here. */
+ && ((enum reg_class) goal_alternative[i] != NO_REGS
+ || modified[i] == RELOAD_WRITE)
&& ! no_input_reloads
- /* Optional output reloads don't do anything and we mustn't
- make in-out reloads on insns that are not permitted output
- reloads. */
+ /* An optional output reload might allow to delete INSN later.
+ We mustn't make in-out reloads on insns that are not permitted
+ output reloads.
+ If this is an asm, we can't delete it; we must not even call
+ push_reload for an optional output reload in this case,
+ because we can't be sure that the constraint allows a register,
+ and push_reload verifies the constraints for asms. */
&& (modified[i] == RELOAD_READ
- || (modified[i] == RELOAD_READ_WRITE && ! no_output_reloads)))
+ || (! no_output_reloads && ! this_insn_is_asm)))
operand_reloadnum[i]
= push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
modified[i] != RELOAD_READ ? recog_operand[i] : 0,
@@ -3770,6 +3825,24 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
(insn_code_number < 0 ? 0
: insn_operand_strict_low[insn_code_number][i]),
1, i, operand_type[i]);
+ /* If a memory reference remains, yet we can't make an optional
+ reload, check if this is actually a pseudo register reference;
+ we then need to emit a USE and/or a CLOBBER so that reload
+ inheritance will do the right thing. */
+ else if (replace && GET_CODE (operand) == MEM)
+ {
+ operand = *recog_operand_loc[i];
+
+ while (GET_CODE (operand) == SUBREG)
+ operand = XEXP (operand, 0);
+ if (GET_CODE (operand) == REG)
+ {
+ if (modified[i] != RELOAD_WRITE)
+ emit_insn_before (gen_rtx_USE (VOIDmode, operand), insn);
+ if (modified[i] != RELOAD_READ)
+ emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
+ }
+ }
}
else if (goal_alternative_matches[i] >= 0
&& goal_alternative_win[goal_alternative_matches[i]]
@@ -3801,6 +3874,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
+ /* Perform whatever substitutions on the operands we are supposed
+ to make due to commutativity or replacement of registers
+ with equivalent constants or memory slots. */
+
+ for (i = 0; i < noperands; i++)
+ {
+ /* We only do this on the last pass through reload, because it is
+ possible for some data (like reg_equiv_address) to be changed during
+ later passes. Moreover, we loose the opportunity to get a useful
+ reload_{in,out}_reg when we do these replacements. */
+
+ if (replace)
+ *recog_operand_loc[i] = substed_operand[i];
+ else
+ retval |= (substed_operand[i] != *recog_operand_loc[i]);
+ }
+
/* If this insn pattern contains any MATCH_DUP's, make sure that
they will be substituted if the operands they match are substituted.
Also do now any substitutions we already did on the operands.
@@ -3955,7 +4045,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= RELOAD_FOR_OPADDR_ADDR;
}
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+ if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
+ reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+ else
+ reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
}
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
@@ -4170,6 +4264,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen. */
register int i;
rtx body = PATTERN (insn);
+ int retval = 0;
n_reloads = 0;
n_replacements = 0;
@@ -4269,6 +4364,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (!goal_earlyclobber)
combine_reloads ();
#endif /* no REGISTER_CONSTRAINTS */
+ return retval;
}
/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
@@ -4307,15 +4403,20 @@ alternative_allows_memconst (constraint, altnum)
OPNUM and TYPE identify the purpose of the reload.
IS_SET_DEST is true if X is the destination of a SET, which is not
- appropriate to be replaced by a constant. */
+ appropriate to be replaced by a constant.
+
+ INSN, if nonzero, is the insn in which we do the reload. It is used
+ to determine if we may generate output reloads, and where to put USEs
+ for pseudos that we have to replace with stack slots. */
static rtx
-find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
+find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
rtx x;
int opnum;
enum reload_type type;
int ind_levels;
int is_set_dest;
+ rtx insn;
{
register RTX_CODE code = GET_CODE (x);
@@ -4334,23 +4435,22 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
else if (reg_equiv_mem[regno] != 0)
x = reg_equiv_mem[regno];
#endif
- else if (reg_equiv_address[regno] != 0)
+ else if (reg_equiv_memory_loc[regno]
+ && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
- /* If reg_equiv_address varies, it may be shared, so copy it. */
- /* We must rerun eliminate_regs, in case the elimination
- offsets have changed. */
- rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
- NULL_RTX),
- 0);
-
- if (rtx_varies_p (addr))
- addr = copy_rtx (addr);
-
- x = gen_rtx_MEM (GET_MODE (x), addr);
- RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
- find_reloads_address (GET_MODE (x), NULL_PTR,
- XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels, 0);
+ rtx mem = make_memloc (x, regno);
+ if (reg_equiv_address[regno]
+ || ! rtx_equal_p (mem, reg_equiv_mem[regno]))
+ {
+ /* If this is not a toplevel operand, find_reloads doesn't see
+ this substitution. We have to emit a USE of the pseudo so
+ that delete_output_reload can see it. */
+ if (replace_reloads && recog_operand[opnum] != x)
+ emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
+ x = mem;
+ find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
+ opnum, type, ind_levels, insn);
+ }
}
return x;
}
@@ -4358,7 +4458,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
{
rtx tem = x;
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels, 0);
+ opnum, type, ind_levels, insn);
return tem;
}
@@ -4452,7 +4552,8 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
|| (reg_equiv_mem[regno] != 0
&& (! strict_memory_address_p (GET_MODE (x),
XEXP (reg_equiv_mem[regno], 0))
- || ! offsettable_memref_p (reg_equiv_mem[regno])))))
+ || ! offsettable_memref_p (reg_equiv_mem[regno])
+ || num_not_at_initial_offset))))
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
/* We must rerun eliminate_regs, in case the elimination
@@ -4473,7 +4574,12 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels, 0);
+ &XEXP (x, 0), opnum, type, ind_levels, insn);
+ /* If this is not a toplevel operand, find_reloads doesn't see this
+ substitution. We have to emit a USE of the pseudo so that
+ delete_output_reload can see it. */
+ if (replace_reloads && recog_operand[opnum] != x)
+ emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn);
}
}
@@ -4482,7 +4588,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
{
if (fmt[i] == 'e')
XEXP (x, i) = find_reloads_toplev (XEXP (x, i), opnum, type,
- ind_levels, is_set_dest);
+ ind_levels, is_set_dest, insn);
}
return x;
}
@@ -4495,22 +4601,10 @@ make_memloc (ad, regno)
rtx ad;
int regno;
{
-#if 0
- register int i;
-#endif
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
- rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
-
-#if 0 /* We cannot safely reuse a memloc made here;
- if the pseudo appears twice, and its mem needs a reload,
- it gets two separate reloads assigned, but it only
- gets substituted with the second of them;
- then it can get used before that reload reg gets loaded up. */
- for (i = 0; i < n_memlocs; i++)
- if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
- return memlocs[i];
-#endif
+ rtx tem
+ = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
/* If TEM might contain a pseudo, we must copy it to avoid
modifying it when we do the substitution for the reload. */
@@ -4519,7 +4613,6 @@ make_memloc (ad, regno)
tem = gen_rtx_MEM (GET_MODE (ad), tem);
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
- memlocs[n_memlocs++] = tem;
return tem;
}
@@ -4535,7 +4628,8 @@ make_memloc (ad, regno)
supports.
INSN, if nonzero, is the insn in which we do the reload. It is used
- to determine if we may generate output reloads.
+ to determine if we may generate output reloads, and where to put USEs
+ for pseudos that we have to replace with stack slots.
Value is nonzero if this address is reloaded or replaced as a whole.
This is interesting to the caller if the address is an autoincrement.
@@ -4575,32 +4669,48 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
return 1;
}
- else if (reg_equiv_address[regno] != 0)
+ tem = reg_equiv_memory_loc[regno];
+ if (tem != 0)
{
- tem = make_memloc (ad, regno);
- find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
- &XEXP (tem, 0), opnum, ADDR_TYPE (type),
- ind_levels, insn);
- push_reload (tem, NULL_RTX, loc, NULL_PTR,
- reload_address_base_reg_class,
- GET_MODE (ad), VOIDmode, 0, 0,
- opnum, type);
- return 1;
+ if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
+ {
+ tem = make_memloc (ad, regno);
+ if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+ {
+ find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
+ &XEXP (tem, 0), opnum, ADDR_TYPE (type),
+ ind_levels, insn);
+ }
+ /* We can avoid a reload if the register's equivalent memory
+ expression is valid as an indirect memory address.
+ But not all addresses are valid in a mem used as an indirect
+ address: only reg or reg+constant. */
+
+ if (ind_levels > 0
+ && strict_memory_address_p (mode, tem)
+ && (GET_CODE (XEXP (tem, 0)) == REG
+ || (GET_CODE (XEXP (tem, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
+ && CONSTANT_P (XEXP (XEXP (tem, 0), 1)))))
+ {
+ /* TEM is not the same as what we'll be replacing the
+ pseudo with after reload, put a USE in front of INSN
+ in the final reload pass. */
+ if (replace_reloads
+ && num_not_at_initial_offset
+ && ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+ {
+ *loc = tem;
+ emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+ /* This doesn't really count as replacing the address
+ as a whole, since it is still a memory access. */
+ }
+ return 0;
+ }
+ ad = tem;
+ }
}
- /* We can avoid a reload if the register's equivalent memory expression
- is valid as an indirect memory address.
- But not all addresses are valid in a mem used as an indirect address:
- only reg or reg+constant. */
-
- else if (reg_equiv_mem[regno] != 0 && ind_levels > 0
- && strict_memory_address_p (mode, reg_equiv_mem[regno])
- && (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
- || (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
- && GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
- && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 1)))))
- return 0;
-
/* The only remaining case where we can avoid a reload is if this is a
hard register that is valid as a base register and which is not the
subject of a CLOBBER in this insn. */
@@ -4633,7 +4743,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
return 0;
subst_reg_equivs_changed = 0;
- *loc = subst_reg_equivs (ad);
+ *loc = subst_reg_equivs (ad, insn);
if (! subst_reg_equivs_changed)
return 0;
@@ -4838,7 +4948,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
registers. */
subst_reg_equivs_changed = 0;
- tem = subst_reg_equivs (tem);
+ tem = subst_reg_equivs (tem, insn);
/* Make sure that didn't make the address invalid again. */
@@ -4874,11 +4984,14 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
/* Find all pseudo regs appearing in AD
that are eliminable in favor of equivalent values
- and do not have hard regs; replace them by their equivalents. */
+ and do not have hard regs; replace them by their equivalents.
+ INSN, if nonzero, is the insn in which we do the reload. We put USEs in
+ front of it for pseudos that we have to replace with stack slots. */
static rtx
-subst_reg_equivs (ad)
+subst_reg_equivs (ad, insn)
rtx ad;
+ rtx insn;
{
register RTX_CODE code = GET_CODE (ad);
register int i;
@@ -4905,6 +5018,16 @@ subst_reg_equivs (ad)
subst_reg_equivs_changed = 1;
return reg_equiv_constant[regno];
}
+ if (reg_equiv_memory_loc[regno] && num_not_at_initial_offset)
+ {
+ rtx mem = make_memloc (ad, regno);
+ if (! rtx_equal_p (mem, reg_equiv_mem[regno]))
+ {
+ subst_reg_equivs_changed = 1;
+ emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+ return mem;
+ }
+ }
}
return ad;
@@ -4922,7 +5045,7 @@ subst_reg_equivs (ad)
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i));
+ XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i), insn);
return ad;
}
@@ -5195,19 +5318,24 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
/* Handle a register that is equivalent to a memory location
which cannot be addressed directly. */
- if (reg_equiv_address[regno] != 0)
+ if (reg_equiv_memory_loc[regno] != 0
+ && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
rtx tem = make_memloc (XEXP (x, 0), regno);
- /* First reload the memory location's address.
- We can't use ADDR_TYPE (type) here, because we need to
- write back the value after reading it, hence we actually
- need two registers. */
- find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
- &XEXP (tem, 0), opnum, type,
- ind_levels, insn);
- /* Put this inside a new increment-expression. */
- x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
- /* Proceed to reload that, as if it contained a register. */
+ if (reg_equiv_address[regno]
+ || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+ {
+ /* First reload the memory location's address.
+ We can't use ADDR_TYPE (type) here, because we need to
+ write back the value after reading it, hence we actually
+ need two registers. */
+ find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
+ &XEXP (tem, 0), opnum, type,
+ ind_levels, insn);
+ /* Put this inside a new increment-expression. */
+ x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
+ /* Proceed to reload that, as if it contained a register. */
+ }
}
/* If we have a hard register that is ok as an index,
@@ -5240,9 +5368,12 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
memory location, since this will make it harder to
reuse address reloads, and increases register pressure.
Also don't do this if we can probably update x directly. */
- rtx equiv = reg_equiv_mem[regno];
+ rtx equiv = (GET_CODE (XEXP (x, 0)) == MEM
+ ? XEXP (x, 0)
+ : reg_equiv_mem[regno]);
int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
if (insn && GET_CODE (insn) == INSN && equiv
+ && memory_operand (equiv, GET_MODE (equiv))
#ifdef HAVE_cc0
&& ! sets_cc0_p (PATTERN (insn))
#endif
@@ -5375,11 +5506,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
}
#endif
- if (reg_equiv_address[regno] != 0)
+ if (reg_equiv_memory_loc[regno]
+ && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
- x = make_memloc (x, regno);
- find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
- opnum, ADDR_TYPE (type), ind_levels, insn);
+ rtx tem = make_memloc (x, regno);
+ if (reg_equiv_address[regno] != 0
+ || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+ {
+ x = tem;
+ find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
+ &XEXP (x, 0), opnum, ADDR_TYPE (type),
+ ind_levels, insn);
+ }
}
if (reg_renumber[regno] >= 0)
@@ -6517,6 +6655,12 @@ debug_reload_to_stream (f)
print_inline_rtx (f, reload_in_reg[r], 24);
}
+ if (reload_out_reg[r] != 0)
+ {
+ fprintf (f, "\n\treload_out_reg: ");
+ print_inline_rtx (f, reload_out_reg[r], 24);
+ }
+
if (reload_reg_rtx[r] != 0)
{
fprintf (f, "\n\treload_reg_rtx: ");
diff --git a/gcc/reload.h b/gcc/reload.h
index 41d6616..e49da9a 100644
--- a/gcc/reload.h
+++ b/gcc/reload.h
@@ -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. */
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 06bc9dd..d4a5cd6 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -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,21 +1447,44 @@ 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 = 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 = 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;
- after_call = 0;
+ {
+ 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;
}
/* If needed, eliminate any eliminable registers. */
@@ -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,21 +4293,44 @@ 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 = 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 = 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;
- after_call = 0;
+ {
+ 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;
}
/* If this is a USE and CLOBBER of a MEM, ensure that any
@@ -4269,7 +4350,10 @@ reload_as_needed (live_known)
{
eliminate_regs_in_insn (insn, 1);
if (GET_CODE (insn) == NOTE)
- continue;
+ {
+ update_eliminable_offsets ();
+ continue;
+ }
}
/* If need_elim is nonzero but need_reload is zero, one might think
@@ -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)
{
- switch (type)
- {
- case RELOAD_OTHER:
- CLEAR_HARD_REG_BIT (reload_reg_used, i);
- break;
+ case RELOAD_OTHER:
+ used_in_set = &reload_reg_used;
+ break;
- case RELOAD_FOR_INPUT_ADDRESS:
- CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
- break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_OPADDR_ADDR:
+ 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);
- break;
+ case RELOAD_FOR_OTHER_ADDRESS:
+ 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);
- break;
+ case RELOAD_FOR_INPUT:
+ 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);
- break;
+ case RELOAD_FOR_OUTPUT:
+ used_in_set = &reload_reg_used_in_output[opnum];
+ break;
- case RELOAD_FOR_INSN:
- CLEAR_HARD_REG_BIT (reload_reg_used_in_insn, i);
- break;
+ case RELOAD_FOR_INSN:
+ 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]);
-
- if (reg_reloaded_contents[i] == regno
+ enum reg_class class = reload_reg_class[r], last_class;
+ rtx last_reg = reg_last_reload_reg[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],
- reload_when_needed[r],
- reload_in[r],
- reload_out[r], 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))
|| ! 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,75 +6438,57 @@ 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. */
- for (j = 0; j < n_reloads; j++)
+ /* 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--)
{
- register int r = reload_order[j];
-
- 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]),
- 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 (j = 0; j < n_reloads; j++)
{
- for (i = 0; i < n_reloads; i++)
+ register int r = reload_order[j];
+ rtx check_reg;
+
+ 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)))
{
- 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 (pass)
+ continue;
+ reload_inherited[r] = 0;
+ reload_override_in[r] = 0;
}
- }
-
- /* 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))
- 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;
}
}
@@ -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)
@@ -6335,6 +6551,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
@@ -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)
- real_oldequiv = reg_equiv_mem[REGNO (oldequiv)];
+ && 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)
- real_old = reg_equiv_mem[REGNO (old)];
+ && 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],
- reload_when_needed[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)])
- new_spill_reg_store[REGNO (s_reg)] = next;
+ {
+ 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)
+ 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))
{
- register int nregno = REGNO (reload_out[r]);
+ 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)
+ 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)))
{
- register int nregno = REGNO (reload_out[r]);
+ 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)
- reg_last_reload_reg[nregno] = 0;
+ {
+ 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,36 +8402,38 @@ 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,
- gen_rtx_PLUS (GET_MODE (incloc),
- incloc, inc)));
+ last = get_last_insn ();
+ add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
+ gen_rtx_PLUS (GET_MODE (incloc),
+ incloc, inc)));
- code = recog_memoized (add_insn);
- if (code >= 0)
- {
- insn_extract (add_insn);
- if (constrain_operands (code, 1))
+ code = recog_memoized (add_insn);
+ if (code >= 0)
{
- /* If this is a pre-increment and we have incremented the value
- where it lives, copy the incremented value to RELOADREG to
- be used as an address. */
+ insn_extract (add_insn);
+ if (constrain_operands (code, 1))
+ {
+ /* If this is a pre-increment and we have incremented the value
+ where it lives, copy the incremented value to RELOADREG to
+ be used as an address. */
- if (! post)
- emit_insn (gen_move_insn (reloadreg, incloc));
+ if (! post)
+ emit_insn (gen_move_insn (reloadreg, incloc));
- return;
+ return add_insn;
+ }
}
+ delete_insns_since (last);
}
- 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.
For pre-increment, copy INCLOC to the reload register, increment it
@@ -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);