mirror of git://gcc.gnu.org/git/gcc.git
Fix consistency problems with reg_equiv_{mem,address};
Improve reload inheritance;
* reload.c (reload_out_reg): New variable.
(loc_mentioned_in_p, remove_address_replacements): New functions.
(remove_replacements): Deleted.
(push_reload): Set reload_out_reg[i].
When merging, also set reload_{in,out}_reg[i], and remove
duplicate address reloads.
(combine_reloads): Copy reload_out_reg[i].
(find_reloads): Do make_memloc substitution also when
reg_equiv_memory_loc[regno] and num_not_at_initial_offset
are both nonzero.
Include *recog_operand_loc in commutativity operand changes.
Generate optional output reloads.
Delete reference to n_memlocs. Don't set *recog_operand_loc before
processing operands. Call make_memloc in reg_equiv_address code.
Set *recog_operand_loc only after processing operands, and only
if replace is true. Return a value.
When changing address reload types for operands that didn't get
reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
Don't emit USEs for pseudo SUBREGs when not replacing.
(find_reloads_address): Do make_memloc substitution also when
reg_equiv_memory_loc[regno] and num_not_at_initial_offset
are both nonzero.
(find_reloads_toplev): Likewise.
Call make_memloc in reg_equiv_address code.
(debug_reload_to_stream): Add code to output reload_out_reg.
(make_memloc): Delete local variable i, ifdefed out code, and
references to memlocs and n_memlocs.
(memlocs, n_memlocs): Delete.
(push_secondary_reload): Clear reload_out_reg.
(find_reloads_address_1): Provide memrefloc argument to all calls
to find_reloads_address.
In AUTO_INC code, handle non-directly addressable equivalences properly.
* reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
(find_reloads): Add return type.
(remove_address_replacements, deallocate_reload_reg): Declare.
* reload1.c (num_not_at_initial_offset): No longer static.
(delete_address_reloads, delete_address_reloads_1): Likewise.
(deallocate_reload_reg): New function.
(spill_reg_stored_to): New array.
(eliminate_regs): Don't substitute from reg_equiv_memory_loc.
(eliminate_regs_in_insn): Move assignments of previous_offset and
max_offset fields, and recalculation of num_not_at_initial_offset
into new static function:
(update_eliminable_offsets) .
(reload_as_needed): Call update_eliminable_offsetss after calling
find_reloads.
Call forget_old_reloads_1 with contents of reloaded auto_inc
expressions if the actual addressing can't be changed to match the
auto_inc.
(choose_reload_regs): For inheritance, replace
reload_reg_free_before_p test with reload_reg_ions.
(emit_reload_insns): If reload_in is a MEM, set OLD to
reload_in_reg[j].
Don't reload directly from oldequiv; if it's a pseudo with a
stack slot, use reload_in[j].
Check that reload_in_reg[j] is a MEM before replacing reload_in
from reg_reloaded_contents.
Include non-spill registers in reload inheritance processing.
Also try to use reload_out_reg to set spill_reg_store /
reg_last_reload_reg.
In code to set new_spill_reg_store, use single_set to find out if
there is a single set.
Add code that allows to delete optional output reloads.
Add code to allow deletion of output reloads that use no spill reg.
At the end, set reload_override_in to oldequiv.
Also call delete_output_reload if reload_out_reg is equal to old
in oldequiv code.
Add code to call delete_output_reload for stores with no matching load.
Set / use spill_reg_stored_to.
Handle case where secondary output reload uses a temporary, but
actual store isn't found.
When looking for a store of a value not loaded in order to call
delete_output_reload, count_occurences should return 0 for no
loads; but discount inherited input reloadill_reg_stored_to.
Do checks for extra uses of REG. Changed all
callers.
Use delete_address_reloads.
(reload): Take return value of find_reloads into account.
If a no-op set needs more than one reload, delete it.
(reload_reg_free_before_p): RELOAD_FOR_INPUT
can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
for the same operand.
(clear_reload_reg_in_use): Check for other reloads that keep a
register in use.
(reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
RELOAD_FOR_OPADDR_ADDR.
Take into account when an address address reload is only needed
for the address reload we are considering.
(count_occurrences): Use rtx_equal_p for MEMs.
(inc_for_reload): Return instruction that stores into RELOADREG.
New argument two, IN, and rtx. Changed all callers.
(calculate_needs_all_insns, reload_as_needed):
Don't clear after_call for a CLOBBER.
Keep track of how many hard registers need to be copied from
after_call, and don't clear after_call before we have seen
that much copies, or we see a different instruction.
From-SVN: r23143
This commit is contained in:
parent
c583dd46ad
commit
cb2afeb31e
111
gcc/ChangeLog
111
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)
|
Fri Oct 16 10:58:23 1998 Jeffrey A Law (law@cygnus.com)
|
||||||
|
|
||||||
* flow.c (find_basic_blocks_1): Do not delete unreachable blocks
|
* flow.c (find_basic_blocks_1): Do not delete unreachable blocks
|
||||||
|
|
|
||||||
476
gcc/reload.c
476
gcc/reload.c
|
|
@ -181,6 +181,7 @@ char reload_optional[MAX_RELOADS];
|
||||||
char reload_nongroup[MAX_RELOADS];
|
char reload_nongroup[MAX_RELOADS];
|
||||||
int reload_inc[MAX_RELOADS];
|
int reload_inc[MAX_RELOADS];
|
||||||
rtx reload_in_reg[MAX_RELOADS];
|
rtx reload_in_reg[MAX_RELOADS];
|
||||||
|
rtx reload_out_reg[MAX_RELOADS];
|
||||||
char reload_nocombine[MAX_RELOADS];
|
char reload_nocombine[MAX_RELOADS];
|
||||||
int reload_opnum[MAX_RELOADS];
|
int reload_opnum[MAX_RELOADS];
|
||||||
enum reload_type reload_when_needed[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. */
|
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
|
#ifdef SECONDARY_MEMORY_NEEDED
|
||||||
|
|
||||||
/* Save MEMs needed to copy from one class of registers to another. One MEM
|
/* 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 struct decomposition decompose PROTO((rtx));
|
||||||
static int immune_p PROTO((rtx, rtx, struct decomposition));
|
static int immune_p PROTO((rtx, rtx, struct decomposition));
|
||||||
static int alternative_allows_memconst PROTO((char *, int));
|
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 rtx make_memloc PROTO((rtx, int));
|
||||||
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
|
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
|
||||||
int, enum reload_type, int, 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 rtx subst_indexed_address PROTO((rtx));
|
||||||
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
|
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
|
||||||
int, enum reload_type,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 machine_mode, int,
|
||||||
enum reload_type, int));
|
enum reload_type, int));
|
||||||
static int find_inc_amount PROTO((rtx, rtx));
|
static int find_inc_amount PROTO((rtx, rtx));
|
||||||
|
static int loc_mentioned_in_p PROTO((rtx *, rtx));
|
||||||
|
|
||||||
#ifdef HAVE_SECONDARY_RELOADS
|
#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. */
|
/* Maybe we could combine these, but it seems too tricky. */
|
||||||
reload_nocombine[t_reload] = 1;
|
reload_nocombine[t_reload] = 1;
|
||||||
reload_in_reg[t_reload] = 0;
|
reload_in_reg[t_reload] = 0;
|
||||||
|
reload_out_reg[t_reload] = 0;
|
||||||
reload_opnum[t_reload] = opnum;
|
reload_opnum[t_reload] = opnum;
|
||||||
reload_when_needed[t_reload] = secondary_type;
|
reload_when_needed[t_reload] = secondary_type;
|
||||||
reload_secondary_in_reload[t_reload] = -1;
|
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. */
|
/* Maybe we could combine these, but it seems too tricky. */
|
||||||
reload_nocombine[s_reload] = 1;
|
reload_nocombine[s_reload] = 1;
|
||||||
reload_in_reg[s_reload] = 0;
|
reload_in_reg[s_reload] = 0;
|
||||||
|
reload_out_reg[s_reload] = 0;
|
||||||
reload_opnum[s_reload] = opnum;
|
reload_opnum[s_reload] = opnum;
|
||||||
reload_when_needed[s_reload] = secondary_type;
|
reload_when_needed[s_reload] = secondary_type;
|
||||||
reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
|
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 ();
|
abort ();
|
||||||
|
|
||||||
/* We can use an existing reload if the class is right
|
/* 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_inc[i] = 0;
|
||||||
reload_nocombine[i] = 0;
|
reload_nocombine[i] = 0;
|
||||||
reload_in_reg[i] = inloc ? *inloc : 0;
|
reload_in_reg[i] = inloc ? *inloc : 0;
|
||||||
|
reload_out_reg[i] = outloc ? *outloc : 0;
|
||||||
reload_opnum[i] = opnum;
|
reload_opnum[i] = opnum;
|
||||||
reload_when_needed[i] = type;
|
reload_when_needed[i] = type;
|
||||||
reload_secondary_in_reload[i] = secondary_in_reload;
|
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]))
|
&& GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
|
||||||
reload_outmode[i] = outmode;
|
reload_outmode[i] = outmode;
|
||||||
if (in != 0)
|
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)
|
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]))
|
if (reg_class_subset_p (class, reload_reg_class[i]))
|
||||||
reload_reg_class[i] = class;
|
reload_reg_class[i] = class;
|
||||||
reload_optional[i] &= optional;
|
reload_optional[i] &= optional;
|
||||||
|
|
@ -1506,19 +1533,67 @@ transfer_replacements (to, from)
|
||||||
replacements[i].what = to;
|
replacements[i].what = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all replacements in reload FROM. */
|
/* IN_RTX is the value loaded by a reload that we now decided to inherit,
|
||||||
void
|
or a subpart of it. If we have any replacements registered for IN_RTX,
|
||||||
remove_replacements (from)
|
cancel the reloads that were supposed to load them.
|
||||||
int from;
|
Return non-zero if we canceled any reloads. */
|
||||||
|
int
|
||||||
|
remove_address_replacements (in_rtx)
|
||||||
|
rtx in_rtx;
|
||||||
{
|
{
|
||||||
int i, j;
|
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++)
|
for (i = 0, j = 0; i < n_replacements; i++)
|
||||||
{
|
{
|
||||||
if (replacements[i].what == from)
|
if (loc_mentioned_in_p (replacements[i].where, in_rtx))
|
||||||
continue;
|
reload_flags[replacements[i].what] |= 1;
|
||||||
replacements[j++] = replacements[i];
|
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
|
/* 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! */
|
/* We have found a reload to combine with! */
|
||||||
reload_out[i] = reload_out[output_reload];
|
reload_out[i] = reload_out[output_reload];
|
||||||
|
reload_out_reg[i] = reload_out_reg[output_reload];
|
||||||
reload_outmode[i] = reload_outmode[output_reload];
|
reload_outmode[i] = reload_outmode[output_reload];
|
||||||
/* Mark the old output reload as inoperative. */
|
/* Mark the old output reload as inoperative. */
|
||||||
reload_out[output_reload] = 0;
|
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
|
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.
|
which is nonnegative if the reg has been commandeered for reloading into.
|
||||||
It is copied into STATIC_RELOAD_REG_P and referenced from there
|
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)
|
find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||||
rtx insn;
|
rtx insn;
|
||||||
int replace, ind_levels;
|
int replace, ind_levels;
|
||||||
|
|
@ -2357,6 +2436,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||||
rtx set = single_set (insn);
|
rtx set = single_set (insn);
|
||||||
int goal_earlyclobber, this_earlyclobber;
|
int goal_earlyclobber, this_earlyclobber;
|
||||||
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
|
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
|
||||||
|
int retval = 0;
|
||||||
/* Cache the last regno for the last pseudo we did an output reload
|
/* Cache the last regno for the last pseudo we did an output reload
|
||||||
for in case the next insn uses it. */
|
for in case the next insn uses it. */
|
||||||
static int last_output_reload_regno = -1;
|
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. */
|
this_insn_is_asm = 0; /* Tentative. */
|
||||||
n_reloads = 0;
|
n_reloads = 0;
|
||||||
n_replacements = 0;
|
n_replacements = 0;
|
||||||
n_memlocs = 0;
|
|
||||||
n_earlyclobbers = 0;
|
n_earlyclobbers = 0;
|
||||||
replace_reloads = replace;
|
replace_reloads = replace;
|
||||||
hard_regs_live_known = live_known;
|
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 ASM_INPUT:
|
||||||
case ADDR_VEC:
|
case ADDR_VEC:
|
||||||
case ADDR_DIFF_VEC:
|
case ADDR_DIFF_VEC:
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
case SET:
|
case SET:
|
||||||
/* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
|
/* 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
|
&& REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
|
||||||
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
|
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
|
||||||
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
|
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
|
||||||
return;
|
return 0;
|
||||||
case PARALLEL:
|
case PARALLEL:
|
||||||
case ASM_OPERANDS:
|
case ASM_OPERANDS:
|
||||||
reload_n_operands = noperands = asm_noperands (body);
|
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];
|
n_alternatives = insn_n_alternatives[insn_code_number];
|
||||||
/* Just return "no reloads" if insn has no operands with constraints. */
|
/* Just return "no reloads" if insn has no operands with constraints. */
|
||||||
if (n_alternatives == 0)
|
if (n_alternatives == 0)
|
||||||
return;
|
return 0;
|
||||||
insn_extract (insn);
|
insn_extract (insn);
|
||||||
for (i = 0; i < noperands; i++)
|
for (i = 0; i < noperands; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -2469,7 +2548,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noperands == 0)
|
if (noperands == 0)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
commutative = -1;
|
commutative = -1;
|
||||||
|
|
||||||
|
|
@ -2577,9 +2656,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||||
|| GET_CODE (recog_operand[i]) == PLUS))
|
|| GET_CODE (recog_operand[i]) == PLUS))
|
||||||
{
|
{
|
||||||
INSN_CODE (insn) = -1;
|
INSN_CODE (insn) = -1;
|
||||||
find_reloads (insn, replace, ind_levels, live_known,
|
retval = find_reloads (insn, replace, ind_levels, live_known,
|
||||||
reload_reg_p);
|
reload_reg_p);
|
||||||
return;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
|
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],
|
= find_reloads_toplev (recog_operand[i], i, address_type[i],
|
||||||
ind_levels,
|
ind_levels,
|
||||||
set != 0
|
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
|
/* 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
|
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
|
note in front so that we might inherit a previous, possibly
|
||||||
wider reload. */
|
wider reload. */
|
||||||
|
|
||||||
if (GET_CODE (op) == MEM
|
if (replace
|
||||||
|
&& GET_CODE (op) == MEM
|
||||||
&& GET_CODE (reg) == REG
|
&& GET_CODE (reg) == REG
|
||||||
&& (GET_MODE_SIZE (GET_MODE (reg))
|
&& (GET_MODE_SIZE (GET_MODE (reg))
|
||||||
>= GET_MODE_SIZE (GET_MODE (op))))
|
>= 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,
|
= gen_rtx_EXPR_LIST (REG_EQUAL,
|
||||||
reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
|
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')
|
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
|
||||||
/* We can get a PLUS as an "operand" as a result of register
|
/* We can get a PLUS as an "operand" as a result of register
|
||||||
elimination. See eliminate_regs and gen_reload. We handle
|
elimination. See eliminate_regs and gen_reload. We handle
|
||||||
a unary operator by reloading the operand. */
|
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],
|
= find_reloads_toplev (recog_operand[i], i, address_type[i],
|
||||||
ind_levels, 0);
|
ind_levels, 0, insn);
|
||||||
else if (code == REG)
|
else if (code == REG)
|
||||||
{
|
{
|
||||||
/* This is equivalent to calling find_reloads_toplev.
|
/* 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]
|
substed_operand[i] = recog_operand[i]
|
||||||
= reg_equiv_constant[regno];
|
= reg_equiv_constant[regno];
|
||||||
}
|
}
|
||||||
#if 0 /* This might screw code in reload1.c to delete prior output-reload
|
if (reg_equiv_memory_loc[regno] != 0
|
||||||
that feeds this insn. */
|
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
|
||||||
if (reg_equiv_mem[regno] != 0)
|
/* 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]
|
substed_operand[i] = recog_operand[i]
|
||||||
= reg_equiv_mem[regno];
|
= find_reloads_toplev (recog_operand[i], i, address_type[i],
|
||||||
#endif
|
ind_levels, 0, insn);
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* If the operand is still a register (we didn't replace it with an
|
/* If the operand is still a register (we didn't replace it with an
|
||||||
equivalent), get the preferred class to reload it into. */
|
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. */
|
/* Avoid further trouble with this insn. */
|
||||||
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
|
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
|
||||||
n_reloads = 0;
|
n_reloads = 0;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Jump to `finish' from above if all operands are valid already.
|
/* 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];
|
tem = recog_operand[commutative];
|
||||||
recog_operand[commutative] = recog_operand[commutative + 1];
|
recog_operand[commutative] = recog_operand[commutative + 1];
|
||||||
recog_operand[commutative + 1] = tem;
|
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++)
|
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++)
|
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;
|
operand_reloadnum[i] = -1;
|
||||||
|
|
||||||
/* If this is an earlyclobber operand, we need to widen the scope.
|
/* 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]
|
*recog_operand_loc[i] = recog_operand[i]
|
||||||
= find_reloads_toplev (force_const_mem (operand_mode[i],
|
= find_reloads_toplev (force_const_mem (operand_mode[i],
|
||||||
recog_operand[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],
|
if (alternative_allows_memconst (constraints1[i],
|
||||||
goal_alternative_number))
|
goal_alternative_number))
|
||||||
goal_alternative_win[i] = 1;
|
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. */
|
/* Avoid further trouble with this insn. */
|
||||||
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
|
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
|
||||||
n_reloads = 0;
|
n_reloads = 0;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (goal_alternative_matched[i] < 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
|
if ((GET_CODE (operand) == MEM
|
||||||
|| (GET_CODE (operand) == REG
|
|| (GET_CODE (operand) == REG
|
||||||
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
|
&& 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
|
&& ! no_input_reloads
|
||||||
/* Optional output reloads don't do anything and we mustn't
|
/* An optional output reload might allow to delete INSN later.
|
||||||
make in-out reloads on insns that are not permitted output
|
We mustn't make in-out reloads on insns that are not permitted
|
||||||
reloads. */
|
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
|
||||||
|| (modified[i] == RELOAD_READ_WRITE && ! no_output_reloads)))
|
|| (! no_output_reloads && ! this_insn_is_asm)))
|
||||||
operand_reloadnum[i]
|
operand_reloadnum[i]
|
||||||
= push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
|
= push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
|
||||||
modified[i] != RELOAD_READ ? 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_code_number < 0 ? 0
|
||||||
: insn_operand_strict_low[insn_code_number][i]),
|
: insn_operand_strict_low[insn_code_number][i]),
|
||||||
1, i, operand_type[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
|
else if (goal_alternative_matches[i] >= 0
|
||||||
&& goal_alternative_win[goal_alternative_matches[i]]
|
&& 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);
|
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
|
/* If this insn pattern contains any MATCH_DUP's, make sure that
|
||||||
they will be substituted if the operands they match are substituted.
|
they will be substituted if the operands they match are substituted.
|
||||||
Also do now any substitutions we already did on the operands.
|
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_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
|
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. */
|
int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen. */
|
||||||
register int i;
|
register int i;
|
||||||
rtx body = PATTERN (insn);
|
rtx body = PATTERN (insn);
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
n_reloads = 0;
|
n_reloads = 0;
|
||||||
n_replacements = 0;
|
n_replacements = 0;
|
||||||
|
|
@ -4269,6 +4364,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
||||||
if (!goal_earlyclobber)
|
if (!goal_earlyclobber)
|
||||||
combine_reloads ();
|
combine_reloads ();
|
||||||
#endif /* no REGISTER_CONSTRAINTS */
|
#endif /* no REGISTER_CONSTRAINTS */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
|
/* 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.
|
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
|
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
|
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;
|
rtx x;
|
||||||
int opnum;
|
int opnum;
|
||||||
enum reload_type type;
|
enum reload_type type;
|
||||||
int ind_levels;
|
int ind_levels;
|
||||||
int is_set_dest;
|
int is_set_dest;
|
||||||
|
rtx insn;
|
||||||
{
|
{
|
||||||
register RTX_CODE code = GET_CODE (x);
|
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)
|
else if (reg_equiv_mem[regno] != 0)
|
||||||
x = reg_equiv_mem[regno];
|
x = reg_equiv_mem[regno];
|
||||||
#endif
|
#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. */
|
rtx mem = make_memloc (x, regno);
|
||||||
/* We must rerun eliminate_regs, in case the elimination
|
if (reg_equiv_address[regno]
|
||||||
offsets have changed. */
|
|| ! rtx_equal_p (mem, reg_equiv_mem[regno]))
|
||||||
rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
|
{
|
||||||
NULL_RTX),
|
/* If this is not a toplevel operand, find_reloads doesn't see
|
||||||
0);
|
this substitution. We have to emit a USE of the pseudo so
|
||||||
|
that delete_output_reload can see it. */
|
||||||
if (rtx_varies_p (addr))
|
if (replace_reloads && recog_operand[opnum] != x)
|
||||||
addr = copy_rtx (addr);
|
emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
|
||||||
|
x = mem;
|
||||||
x = gen_rtx_MEM (GET_MODE (x), addr);
|
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
|
||||||
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
|
opnum, type, ind_levels, insn);
|
||||||
find_reloads_address (GET_MODE (x), NULL_PTR,
|
}
|
||||||
XEXP (x, 0),
|
|
||||||
&XEXP (x, 0), opnum, type, ind_levels, 0);
|
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
@ -4358,7 +4458,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
|
||||||
{
|
{
|
||||||
rtx tem = x;
|
rtx tem = x;
|
||||||
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
|
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;
|
return tem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4452,7 +4552,8 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
|
||||||
|| (reg_equiv_mem[regno] != 0
|
|| (reg_equiv_mem[regno] != 0
|
||||||
&& (! strict_memory_address_p (GET_MODE (x),
|
&& (! strict_memory_address_p (GET_MODE (x),
|
||||||
XEXP (reg_equiv_mem[regno], 0))
|
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;
|
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
|
||||||
/* We must rerun eliminate_regs, in case the elimination
|
/* 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]);
|
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
|
||||||
find_reloads_address (GET_MODE (x), NULL_PTR,
|
find_reloads_address (GET_MODE (x), NULL_PTR,
|
||||||
XEXP (x, 0),
|
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')
|
if (fmt[i] == 'e')
|
||||||
XEXP (x, i) = find_reloads_toplev (XEXP (x, i), opnum, type,
|
XEXP (x, i) = find_reloads_toplev (XEXP (x, i), opnum, type,
|
||||||
ind_levels, is_set_dest);
|
ind_levels, is_set_dest, insn);
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
@ -4495,22 +4601,10 @@ make_memloc (ad, regno)
|
||||||
rtx ad;
|
rtx ad;
|
||||||
int regno;
|
int regno;
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
register int i;
|
|
||||||
#endif
|
|
||||||
/* We must rerun eliminate_regs, in case the elimination
|
/* We must rerun eliminate_regs, in case the elimination
|
||||||
offsets have changed. */
|
offsets have changed. */
|
||||||
rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
|
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
|
|
||||||
|
|
||||||
/* If TEM might contain a pseudo, we must copy it to avoid
|
/* If TEM might contain a pseudo, we must copy it to avoid
|
||||||
modifying it when we do the substitution for the reload. */
|
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);
|
tem = gen_rtx_MEM (GET_MODE (ad), tem);
|
||||||
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
|
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
|
||||||
memlocs[n_memlocs++] = tem;
|
|
||||||
return tem;
|
return tem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4535,7 +4628,8 @@ make_memloc (ad, regno)
|
||||||
supports.
|
supports.
|
||||||
|
|
||||||
INSN, if nonzero, is the insn in which we do the reload. It is used
|
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.
|
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.
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (reg_equiv_address[regno] != 0)
|
tem = reg_equiv_memory_loc[regno];
|
||||||
|
if (tem != 0)
|
||||||
{
|
{
|
||||||
tem = make_memloc (ad, regno);
|
if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
|
||||||
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
|
{
|
||||||
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
|
tem = make_memloc (ad, regno);
|
||||||
ind_levels, insn);
|
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
|
||||||
push_reload (tem, NULL_RTX, loc, NULL_PTR,
|
{
|
||||||
reload_address_base_reg_class,
|
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
|
||||||
GET_MODE (ad), VOIDmode, 0, 0,
|
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
|
||||||
opnum, type);
|
ind_levels, insn);
|
||||||
return 1;
|
}
|
||||||
|
/* We can avoid a reload if the register's equivalent memory
|
||||||
|
expression is valid as an indirect memory address.
|
||||||
|
But not all addresses are valid in a mem used as an indirect
|
||||||
|
address: only reg or reg+constant. */
|
||||||
|
|
||||||
|
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
|
/* 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
|
hard register that is valid as a base register and which is not the
|
||||||
subject of a CLOBBER in this insn. */
|
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;
|
return 0;
|
||||||
|
|
||||||
subst_reg_equivs_changed = 0;
|
subst_reg_equivs_changed = 0;
|
||||||
*loc = subst_reg_equivs (ad);
|
*loc = subst_reg_equivs (ad, insn);
|
||||||
|
|
||||||
if (! subst_reg_equivs_changed)
|
if (! subst_reg_equivs_changed)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -4838,7 +4948,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
|
||||||
registers. */
|
registers. */
|
||||||
|
|
||||||
subst_reg_equivs_changed = 0;
|
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. */
|
/* 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
|
/* Find all pseudo regs appearing in AD
|
||||||
that are eliminable in favor of equivalent values
|
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
|
static rtx
|
||||||
subst_reg_equivs (ad)
|
subst_reg_equivs (ad, insn)
|
||||||
rtx ad;
|
rtx ad;
|
||||||
|
rtx insn;
|
||||||
{
|
{
|
||||||
register RTX_CODE code = GET_CODE (ad);
|
register RTX_CODE code = GET_CODE (ad);
|
||||||
register int i;
|
register int i;
|
||||||
|
|
@ -4905,6 +5018,16 @@ subst_reg_equivs (ad)
|
||||||
subst_reg_equivs_changed = 1;
|
subst_reg_equivs_changed = 1;
|
||||||
return reg_equiv_constant[regno];
|
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;
|
return ad;
|
||||||
|
|
||||||
|
|
@ -4922,7 +5045,7 @@ subst_reg_equivs (ad)
|
||||||
fmt = GET_RTX_FORMAT (code);
|
fmt = GET_RTX_FORMAT (code);
|
||||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||||
if (fmt[i] == 'e')
|
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;
|
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
|
/* Handle a register that is equivalent to a memory location
|
||||||
which cannot be addressed directly. */
|
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);
|
rtx tem = make_memloc (XEXP (x, 0), regno);
|
||||||
/* First reload the memory location's address.
|
if (reg_equiv_address[regno]
|
||||||
We can't use ADDR_TYPE (type) here, because we need to
|
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
|
||||||
write back the value after reading it, hence we actually
|
{
|
||||||
need two registers. */
|
/* First reload the memory location's address.
|
||||||
find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
|
We can't use ADDR_TYPE (type) here, because we need to
|
||||||
&XEXP (tem, 0), opnum, type,
|
write back the value after reading it, hence we actually
|
||||||
ind_levels, insn);
|
need two registers. */
|
||||||
/* Put this inside a new increment-expression. */
|
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
|
||||||
x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
|
&XEXP (tem, 0), opnum, type,
|
||||||
/* Proceed to reload that, as if it contained a register. */
|
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,
|
/* 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
|
memory location, since this will make it harder to
|
||||||
reuse address reloads, and increases register pressure.
|
reuse address reloads, and increases register pressure.
|
||||||
Also don't do this if we can probably update x directly. */
|
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;
|
int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
|
||||||
if (insn && GET_CODE (insn) == INSN && equiv
|
if (insn && GET_CODE (insn) == INSN && equiv
|
||||||
|
&& memory_operand (equiv, GET_MODE (equiv))
|
||||||
#ifdef HAVE_cc0
|
#ifdef HAVE_cc0
|
||||||
&& ! sets_cc0_p (PATTERN (insn))
|
&& ! sets_cc0_p (PATTERN (insn))
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -5375,11 +5506,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
rtx tem = make_memloc (x, regno);
|
||||||
find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
|
if (reg_equiv_address[regno] != 0
|
||||||
opnum, ADDR_TYPE (type), ind_levels, insn);
|
|| ! 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)
|
if (reg_renumber[regno] >= 0)
|
||||||
|
|
@ -6517,6 +6655,12 @@ debug_reload_to_stream (f)
|
||||||
print_inline_rtx (f, reload_in_reg[r], 24);
|
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)
|
if (reload_reg_rtx[r] != 0)
|
||||||
{
|
{
|
||||||
fprintf (f, "\n\treload_reg_rtx: ");
|
fprintf (f, "\n\treload_reg_rtx: ");
|
||||||
|
|
|
||||||
15
gcc/reload.h
15
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_in[MAX_RELOADS];
|
||||||
extern rtx reload_out[MAX_RELOADS];
|
extern rtx reload_out[MAX_RELOADS];
|
||||||
extern rtx reload_in_reg[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 reg_class reload_reg_class[MAX_RELOADS];
|
||||||
extern enum machine_mode reload_inmode[MAX_RELOADS];
|
extern enum machine_mode reload_inmode[MAX_RELOADS];
|
||||||
extern enum machine_mode reload_outmode[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. */
|
/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */
|
||||||
extern char double_reg_address_ok;
|
extern char double_reg_address_ok;
|
||||||
|
|
||||||
|
extern int num_not_at_initial_offset;
|
||||||
|
|
||||||
#ifdef MAX_INSN_CODE
|
#ifdef MAX_INSN_CODE
|
||||||
/* These arrays record the insn_code of insns that may be needed to
|
/* These arrays record the insn_code of insns that may be needed to
|
||||||
perform input and output reloads of special objects. They provide a
|
perform input and output reloads of special objects. They provide a
|
||||||
|
|
@ -233,8 +236,11 @@ extern void clear_secondary_mem PROTO((void));
|
||||||
reload TO. */
|
reload TO. */
|
||||||
extern void transfer_replacements PROTO((int, int));
|
extern void transfer_replacements PROTO((int, int));
|
||||||
|
|
||||||
/* Remove all replacements in reload FROM. */
|
/* IN_RTX is the value loaded by a reload that we now decided to inherit,
|
||||||
extern void remove_replacements PROTO((int));
|
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
|
/* 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
|
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
|
/* 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
|
with push_reload. REPLACE nonzero means record also where the values occur
|
||||||
so that subst_reloads can be used. */
|
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
|
/* Compute the sum of X and Y, making canonicalizations assumed in an
|
||||||
address, namely: sum constant integers, surround the sum of two
|
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. */
|
OPNUM with reload type TYPE. */
|
||||||
extern rtx gen_reload PROTO((rtx, rtx, int, enum reload_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: */
|
/* Functions in caller-save.c: */
|
||||||
|
|
||||||
/* Initialize for caller-save. */
|
/* Initialize for caller-save. */
|
||||||
|
|
|
||||||
1278
gcc/reload1.c
1278
gcc/reload1.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue