summaryrefslogtreecommitdiff
path: root/gcc/reload.c
diff options
context:
space:
mode:
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1998-10-16 19:54:38 +0000
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1998-10-16 19:54:38 +0000
commit93c7b06ecdfc0af0cf1e5b1f7f0fa427e897bb0b (patch)
treecf1f8fb6fb17ad64ddc6a0a663fac8dcb1c7dc8c /gcc/reload.c
parentdc0441c65863315a3d25563bab5246c03f968ece (diff)
downloadgcc-93c7b06ecdfc0af0cf1e5b1f7f0fa427e897bb0b.tar.gz
Fix consistency problems with reg_equiv_{mem,address};
Improve reload inheritance; * reload.c (reload_out_reg): New variable. (loc_mentioned_in_p, remove_address_replacements): New functions. (remove_replacements): Deleted. (push_reload): Set reload_out_reg[i]. When merging, also set reload_{in,out}_reg[i], and remove duplicate address reloads. (combine_reloads): Copy reload_out_reg[i]. (find_reloads): Do make_memloc substitution also when reg_equiv_memory_loc[regno] and num_not_at_initial_offset are both nonzero. Include *recog_operand_loc in commutativity operand changes. Generate optional output reloads. Delete reference to n_memlocs. Don't set *recog_operand_loc before processing operands. Call make_memloc in reg_equiv_address code. Set *recog_operand_loc only after processing operands, and only if replace is true. Return a value. When changing address reload types for operands that didn't get reloaded, use RELOAD_FOR_OPADDR_ADDRESS for RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads. Don't emit USEs for pseudo SUBREGs when not replacing. (find_reloads_address): Do make_memloc substitution also when reg_equiv_memory_loc[regno] and num_not_at_initial_offset are both nonzero. (find_reloads_toplev): Likewise. Call make_memloc in reg_equiv_address code. (debug_reload_to_stream): Add code to output reload_out_reg. (make_memloc): Delete local variable i, ifdefed out code, and references to memlocs and n_memlocs. (memlocs, n_memlocs): Delete. (push_secondary_reload): Clear reload_out_reg. (find_reloads_address_1): Provide memrefloc argument to all calls to find_reloads_address. In AUTO_INC code, handle non-directly addressable equivalences properly. * reload.h (reload_out_reg, num_not_at_initial_offset): Declare. (find_reloads): Add return type. (remove_address_replacements, deallocate_reload_reg): Declare. * reload1.c (num_not_at_initial_offset): No longer static. (delete_address_reloads, delete_address_reloads_1): Likewise. (deallocate_reload_reg): New function. (spill_reg_stored_to): New array. (eliminate_regs): Don't substitute from reg_equiv_memory_loc. (eliminate_regs_in_insn): Move assignments of previous_offset and max_offset fields, and recalculation of num_not_at_initial_offset into new static function: (update_eliminable_offsets) . (reload_as_needed): Call update_eliminable_offsetss after calling find_reloads. Call forget_old_reloads_1 with contents of reloaded auto_inc expressions if the actual addressing can't be changed to match the auto_inc. (choose_reload_regs): For inheritance, replace reload_reg_free_before_p test with reload_reg_ions. (emit_reload_insns): If reload_in is a MEM, set OLD to reload_in_reg[j]. Don't reload directly from oldequiv; if it's a pseudo with a stack slot, use reload_in[j]. Check that reload_in_reg[j] is a MEM before replacing reload_in from reg_reloaded_contents. Include non-spill registers in reload inheritance processing. Also try to use reload_out_reg to set spill_reg_store / reg_last_reload_reg. In code to set new_spill_reg_store, use single_set to find out if there is a single set. Add code that allows to delete optional output reloads. Add code to allow deletion of output reloads that use no spill reg. At the end, set reload_override_in to oldequiv. Also call delete_output_reload if reload_out_reg is equal to old in oldequiv code. Add code to call delete_output_reload for stores with no matching load. Set / use spill_reg_stored_to. Handle case where secondary output reload uses a temporary, but actual store isn't found. When looking for a store of a value not loaded in order to call delete_output_reload, count_occurences should return 0 for no loads; but discount inherited input reloadill_reg_stored_to. Do checks for extra uses of REG. Changed all callers. Use delete_address_reloads. (reload): Take return value of find_reloads into account. If a no-op set needs more than one reload, delete it. (reload_reg_free_before_p): RELOAD_FOR_INPUT can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS for the same operand. (clear_reload_reg_in_use): Check for other reloads that keep a register in use. (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS / RELOAD_FOR_OPADDR_ADDR. Take into account when an address address reload is only needed for the address reload we are considering. (count_occurrences): Use rtx_equal_p for MEMs. (inc_for_reload): Return instruction that stores into RELOADREG. New argument two, IN, and rtx. Changed all callers. (calculate_needs_all_insns, reload_as_needed): Don't clear after_call for a CLOBBER. Keep track of how many hard registers need to be copied from after_call, and don't clear after_call before we have seen that much copies, or we see a different instruction. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@23143 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reload.c')
-rw-r--r--gcc/reload.c476
1 files changed, 310 insertions, 166 deletions
diff --git a/gcc/reload.c b/gcc/reload.c
index 1e438e17b31..6f3ba43b26a 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: ");