Makefile.in (local-alloc.o): Depend on $(GGC_H) and reload.h.

* Makefile.in (local-alloc.o): Depend on $(GGC_H) and reload.h.
	* local-alloc.c: Include "ggc.h" and "reload.h".
	(struct equivalence): New member is_arg_equivalence.
	(local_alloc): Always call update_equiv_regs.
	(update_equiv_regs): Allocate reg_equiv_init; set reg_equiv_init_size.
	Detect equivalences made by stores to memory in a second pass.
	Return early if not optimizing.
	Initialize reg_equiv_init for all equivalences; treat equivalences for
	REG_EQUIV notes existing before this pass specially.
	(no_equiv): Don't clear reg_equiv_init or remove notes if the
	is_arg_equivalence field is set.
	* reload.h (reg_equiv_init, reg_equiv_init_size): Declare.
	* reload1.c (reg_equiv_init): No longer static.
	(reg_equiv_init_size): New variable.
	(reload): Don't allocate reg_equiv_init; don't free it when done but
	clear it.
	Restructure equivalence set up code not to set reg_equiv_init, but to
	clear it when we can't use an equivalence.
	Undo change disabling equivalences for MEM_READONLY_P memrefs.
	Dump equivalencing insns to dump_file.

From-SVN: r100975
This commit is contained in:
Bernd Schmidt 2005-06-15 09:35:15 +00:00 committed by Bernd Schmidt
parent ae973d6ae8
commit d7f88d8648
5 changed files with 227 additions and 139 deletions

View File

@ -1,3 +1,26 @@
2005-06-15 Bernd Schmidt <bernd.schmidt@analog.com>
* Makefile.in (local-alloc.o): Depend on $(GGC_H) and reload.h.
* local-alloc.c: Include "ggc.h" and "reload.h".
(struct equivalence): New member is_arg_equivalence.
(local_alloc): Always call update_equiv_regs.
(update_equiv_regs): Allocate reg_equiv_init; set reg_equiv_init_size.
Detect equivalences made by stores to memory in a second pass.
Return early if not optimizing.
Initialize reg_equiv_init for all equivalences; treat equivalences for
REG_EQUIV notes existing before this pass specially.
(no_equiv): Don't clear reg_equiv_init or remove notes if the
is_arg_equivalence field is set.
* reload.h (reg_equiv_init, reg_equiv_init_size): Declare.
* reload1.c (reg_equiv_init): No longer static.
(reg_equiv_init_size): New variable.
(reload): Don't allocate reg_equiv_init; don't free it when done but
clear it.
Restructure equivalence set up code not to set reg_equiv_init, but to
clear it when we can't use an equivalence.
Undo change disabling equivalences for MEM_READONLY_P memrefs.
Dump equivalencing insns to dump_file.
2005-06-14 Richard Sandiford <richard@codesourcery.com>
* config/mips/mips.c (machine_function): Add varargs_size field.

View File

@ -2241,8 +2241,8 @@ regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TM_P_H) $(EXPR_H) $(TIMEVAR_H) gt-regclass.h $(HASHTAB_H)
local-alloc.o : local-alloc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
output.h function.h $(INSN_ATTR_H) toplev.h except.h $(TM_P_H) \
$(INTEGRATE_H)
output.h function.h $(INSN_ATTR_H) toplev.h except.h reload.h $(TM_P_H) \
$(GGC_H) $(INTEGRATE_H)
bitmap.o : bitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) $(GGC_H) gt-bitmap.h bitmap.h $(OBSTACK_H)
global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \

View File

@ -76,6 +76,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h"
#include "except.h"
#include "integrate.h"
#include "reload.h"
#include "ggc.h"
/* Next quantity number available for allocation. */
@ -260,6 +262,10 @@ struct equivalence
/* The list of each instruction which initializes this register. */
rtx init_insns;
/* Nonzero if this had a preexisting REG_EQUIV note. */
int is_arg_equivalence;
};
/* reg_equiv[N] (where N is a pseudo reg number) is the equivalence
@ -344,8 +350,7 @@ local_alloc (void)
/* Promote REG_EQUAL notes to REG_EQUIV notes and adjust status of affected
registers. */
if (optimize)
update_equiv_regs ();
update_equiv_regs ();
/* This sets the maximum number of quantities we can have. Quantity
numbers start at zero and we can have one for each pseudo. */
@ -761,7 +766,9 @@ memref_used_between_p (rtx memref, rtx start, rtx end)
If such a register is only referenced once, try substituting its value
into the using insn. If it succeeds, we can eliminate the register
completely. */
completely.
Initialize the REG_EQUIV_INIT array of initializing insns. */
static void
update_equiv_regs (void)
@ -774,6 +781,8 @@ update_equiv_regs (void)
reg_equiv = xcalloc (max_regno, sizeof *reg_equiv);
INIT_REG_SET (&cleared_regs);
reg_equiv_init = ggc_alloc_cleared (max_regno * sizeof (rtx));
reg_equiv_init_size = max_regno;
init_alias_analysis ();
@ -824,44 +833,30 @@ update_equiv_regs (void)
dest = SET_DEST (set);
src = SET_SRC (set);
/* If this sets a MEM to the contents of a REG that is only used
in a single basic block, see if the register is always equivalent
to that memory location and if moving the store from INSN to the
insn that set REG is safe. If so, put a REG_EQUIV note on the
initializing insn.
Don't add a REG_EQUIV note if the insn already has one. The existing
REG_EQUIV is likely more useful than the one we are adding.
If one of the regs in the address has reg_equiv[REGNO].replace set,
then we can't add this REG_EQUIV note. The reg_equiv[REGNO].replace
optimization may move the set of this register immediately before
insn, which puts it after reg_equiv[REGNO].init_insns, and hence
the mention in the REG_EQUIV note would be to an uninitialized
pseudo. */
/* ????? This test isn't good enough; we might see a MEM with a use of
a pseudo register before we see its setting insn that will cause
reg_equiv[].replace for that pseudo to be set.
Equivalences to MEMs should be made in another pass, after the
reg_equiv[].replace information has been gathered. */
if (MEM_P (dest) && REG_P (src)
&& (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= 0
&& REG_N_SETS (regno) == 1
&& reg_equiv[regno].init_insns != 0
&& reg_equiv[regno].init_insns != const0_rtx
&& ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
REG_EQUIV, NULL_RTX)
&& ! contains_replace_regs (XEXP (dest, 0)))
/* See if this is setting up the equivalence between an argument
register and its stack slot. */
note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
if (note)
{
rtx init_insn = XEXP (reg_equiv[regno].init_insns, 0);
if (validate_equiv_mem (init_insn, src, dest)
&& ! memref_used_between_p (dest, init_insn, insn))
REG_NOTES (init_insn)
= gen_rtx_EXPR_LIST (REG_EQUIV, dest, REG_NOTES (init_insn));
gcc_assert (REG_P (dest));
regno = REGNO (dest);
/* Note that we don't want to clear reg_equiv_init even if there
are multiple sets of this register. */
reg_equiv[regno].is_arg_equivalence = 1;
/* Record for reload that this is an equivalencing insn. */
if (rtx_equal_p (src, XEXP (note, 0)))
reg_equiv_init[regno]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[regno]);
/* Continue normally in case this is a candidate for
replacements. */
}
if (!optimize)
continue;
/* We only handle the case of a pseudo register being set
once, or always to the same value. */
/* ??? The mn10200 port breaks if we add equivalences for
@ -878,7 +873,7 @@ update_equiv_regs (void)
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
|| reg_equiv[regno].init_insns == const0_rtx
|| (CLASS_LIKELY_SPILLED_P (reg_preferred_class (regno))
&& MEM_P (src)))
&& MEM_P (src) && ! reg_equiv[regno].is_arg_equivalence))
{
/* This might be setting a SUBREG of a pseudo, a pseudo that is
also set somewhere else to a constant. */
@ -944,20 +939,27 @@ update_equiv_regs (void)
if (note)
{
int regno = REGNO (dest);
rtx x = XEXP (note, 0);
/* If we haven't done so, record for reload that this is an
equivalencing insn. */
if (!reg_equiv[regno].is_arg_equivalence
&& (!MEM_P (x) || rtx_equal_p (src, x)))
reg_equiv_init[regno]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[regno]);
/* Record whether or not we created a REG_EQUIV note for a LABEL_REF.
We might end up substituting the LABEL_REF for uses of the
pseudo here or later. That kind of transformation may turn an
indirect jump into a direct jump, in which case we must rerun the
jump optimizer to ensure that the JUMP_LABEL fields are valid. */
if (GET_CODE (XEXP (note, 0)) == LABEL_REF
|| (GET_CODE (XEXP (note, 0)) == CONST
&& GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (XEXP (note, 0), 0), 0))
== LABEL_REF)))
if (GET_CODE (x) == LABEL_REF
|| (GET_CODE (x) == CONST
&& GET_CODE (XEXP (x, 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)))
recorded_label_ref = 1;
reg_equiv[regno].replacement = XEXP (note, 0);
reg_equiv[regno].replacement = x;
reg_equiv[regno].src_p = &SET_SRC (set);
reg_equiv[regno].loop_depth = loop_depth;
@ -968,7 +970,6 @@ update_equiv_regs (void)
in local-alloc! */
REG_LIVE_LENGTH (regno) *= 2;
/* If the register is referenced exactly twice, meaning it is
set once and used once, indicate that the reference may be
replaced by the equivalence we computed above. Do this
@ -978,17 +979,79 @@ update_equiv_regs (void)
and to reduce the number of registers alive across
calls. */
if (REG_N_REFS (regno) == 2
&& (rtx_equal_p (XEXP (note, 0), src)
|| ! equiv_init_varies_p (src))
&& NONJUMP_INSN_P (insn)
&& equiv_init_movable_p (PATTERN (insn), regno))
reg_equiv[regno].replace = 1;
if (REG_N_REFS (regno) == 2
&& (rtx_equal_p (x, src)
|| ! equiv_init_varies_p (src))
&& NONJUMP_INSN_P (insn)
&& equiv_init_movable_p (PATTERN (insn), regno))
reg_equiv[regno].replace = 1;
}
}
}
}
if (!optimize)
goto out;
/* A second pass, to gather additional equivalences with memory. This needs
to be done after we know which registers we are going to replace. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx set, src, dest;
unsigned regno;
if (! INSN_P (insn))
continue;
set = single_set (insn);
if (! set)
continue;
dest = SET_DEST (set);
src = SET_SRC (set);
/* If this sets a MEM to the contents of a REG that is only used
in a single basic block, see if the register is always equivalent
to that memory location and if moving the store from INSN to the
insn that set REG is safe. If so, put a REG_EQUIV note on the
initializing insn.
Don't add a REG_EQUIV note if the insn already has one. The existing
REG_EQUIV is likely more useful than the one we are adding.
If one of the regs in the address has reg_equiv[REGNO].replace set,
then we can't add this REG_EQUIV note. The reg_equiv[REGNO].replace
optimization may move the set of this register immediately before
insn, which puts it after reg_equiv[REGNO].init_insns, and hence
the mention in the REG_EQUIV note would be to an uninitialized
pseudo. */
if (MEM_P (dest) && REG_P (src)
&& (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= 0
&& REG_N_SETS (regno) == 1
&& reg_equiv[regno].init_insns != 0
&& reg_equiv[regno].init_insns != const0_rtx
&& ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
REG_EQUIV, NULL_RTX)
&& ! contains_replace_regs (XEXP (dest, 0)))
{
rtx init_insn = XEXP (reg_equiv[regno].init_insns, 0);
if (validate_equiv_mem (init_insn, src, dest)
&& ! memref_used_between_p (dest, init_insn, insn))
{
REG_NOTES (init_insn)
= gen_rtx_EXPR_LIST (REG_EQUIV, dest,
REG_NOTES (init_insn));
/* This insn makes the equivalence, not the one initializing
the register. */
reg_equiv_init[regno]
= gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
}
}
}
/* Now scan all regs killed in an insn to see if any of them are
registers only used that once. If so, see if we can replace the
reference with the equivalent form. If we can, delete the
@ -1082,6 +1145,7 @@ update_equiv_regs (void)
info. */
SET_REGNO_REG_SET (&cleared_regs, regno);
clear_regnos++;
reg_equiv_init[regno] = NULL_RTX;
}
/* Move the initialization of the register to just before
INSN. Update the flow information. */
@ -1113,6 +1177,7 @@ update_equiv_regs (void)
info. */
SET_REGNO_REG_SET (&cleared_regs, regno);
clear_regnos++;
reg_equiv_init[regno] = NULL_RTX;
}
}
}
@ -1146,6 +1211,7 @@ update_equiv_regs (void)
}
}
out:
/* Clean up. */
end_alias_analysis ();
CLEAR_REG_SET (&cleared_regs);
@ -1171,13 +1237,18 @@ no_equiv (rtx reg, rtx store ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED)
list = reg_equiv[regno].init_insns;
if (list == const0_rtx)
return;
reg_equiv[regno].init_insns = const0_rtx;
reg_equiv[regno].replacement = NULL_RTX;
/* This doesn't matter for equivalences made for argument registers, we
should keep their initialization insns. */
if (reg_equiv[regno].is_arg_equivalence)
return;
reg_equiv_init[regno] = NULL_RTX;
for (; list; list = XEXP (list, 1))
{
rtx insn = XEXP (list, 0);
remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
}
reg_equiv[regno].init_insns = const0_rtx;
reg_equiv[regno].replacement = NULL_RTX;
}
/* Allocate hard regs to the pseudo regs used only within block number B.

View File

@ -170,6 +170,13 @@ extern rtx *reg_equiv_memory_loc;
extern rtx *reg_equiv_address;
extern rtx *reg_equiv_mem;
/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
extern GTY((length("reg_equiv_init_size"))) rtx *reg_equiv_init;
/* The size of the previous array, for GC purposes. */
extern GTY(()) int reg_equiv_init_size;
/* All the "earlyclobber" operands of the current insn
are recorded here. */
extern int n_earlyclobbers;

View File

@ -120,7 +120,8 @@ static unsigned int *reg_max_ref_width;
/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
static rtx *reg_equiv_init;
rtx *reg_equiv_init;
int reg_equiv_init_size;
/* Vector to remember old contents of reg_renumber before spilling. */
static short *reg_old_renumber;
@ -693,7 +694,6 @@ reload (rtx first, int global)
reg_equiv_constant = xcalloc (max_regno, sizeof (rtx));
reg_equiv_mem = xcalloc (max_regno, sizeof (rtx));
reg_equiv_init = xcalloc (max_regno, sizeof (rtx));
reg_equiv_address = xcalloc (max_regno, sizeof (rtx));
reg_max_ref_width = xcalloc (max_regno, sizeof (int));
reg_old_renumber = xcalloc (max_regno, sizeof (short));
@ -719,101 +719,88 @@ reload (rtx first, int global)
&& GET_MODE (insn) != VOIDmode)
PUT_MODE (insn, VOIDmode);
if (INSN_P (insn))
scan_paradoxical_subregs (PATTERN (insn));
if (set != 0 && REG_P (SET_DEST (set)))
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
if (note
&& (! function_invariant_p (XEXP (note, 0))
|| ! flag_pic
/* A function invariant is often CONSTANT_P but may
include a register. We promise to only pass
CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
|| (CONSTANT_P (XEXP (note, 0))
&& LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0)))))
rtx x;
if (! note)
continue;
i = REGNO (SET_DEST (set));
x = XEXP (note, 0);
if (i <= LAST_VIRTUAL_REGISTER)
continue;
if (! function_invariant_p (x)
|| ! flag_pic
/* A function invariant is often CONSTANT_P but may
include a register. We promise to only pass
CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
|| (CONSTANT_P (x)
&& LEGITIMATE_PIC_OPERAND_P (x)))
{
rtx x = XEXP (note, 0);
i = REGNO (SET_DEST (set));
if (i > LAST_VIRTUAL_REGISTER)
/* It can happen that a REG_EQUIV note contains a MEM
that is not a legitimate memory operand. As later
stages of reload assume that all addresses found
in the reg_equiv_* arrays were originally legitimate,
we ignore such REG_EQUIV notes. */
if (memory_operand (x, VOIDmode))
{
/* It can happen that a REG_EQUIV note contains a MEM
that is not a legitimate memory operand. As later
stages of reload assume that all addresses found
in the reg_equiv_* arrays were originally legitimate,
It can also happen that a REG_EQUIV note contains a
readonly memory location. If the destination pseudo
is set from some other value (typically a different
pseudo), and the destination pseudo does not get a
hard reg, then reload will replace the destination
pseudo with its equivalent memory location. This
is horribly bad as it creates a store to a readonly
memory location and a runtime segfault. To avoid
this problem we reject readonly memory locations
for equivalences. This is overly conservative as
we could find all sets of the destination pseudo
and remove them as they should be redundant. */
if (memory_operand (x, VOIDmode) && ! MEM_READONLY_P (x))
/* Always unshare the equivalence, so we can
substitute into this insn without touching the
equivalence. */
reg_equiv_memory_loc[i] = copy_rtx (x);
}
else if (function_invariant_p (x))
{
if (GET_CODE (x) == PLUS)
{
/* Always unshare the equivalence, so we can
substitute into this insn without touching the
equivalence. */
reg_equiv_memory_loc[i] = copy_rtx (x);
/* This is PLUS of frame pointer and a constant,
and might be shared. Unshare it. */
reg_equiv_constant[i] = copy_rtx (x);
num_eliminable_invariants++;
}
else if (function_invariant_p (x))
else if (x == frame_pointer_rtx
|| x == arg_pointer_rtx)
{
if (GET_CODE (x) == PLUS)
{
/* This is PLUS of frame pointer and a constant,
and might be shared. Unshare it. */
reg_equiv_constant[i] = copy_rtx (x);
num_eliminable_invariants++;
}
else if (x == frame_pointer_rtx
|| x == arg_pointer_rtx)
{
reg_equiv_constant[i] = x;
num_eliminable_invariants++;
}
else if (LEGITIMATE_CONSTANT_P (x))
reg_equiv_constant[i] = x;
else
{
reg_equiv_memory_loc[i]
= force_const_mem (GET_MODE (SET_DEST (set)), x);
if (!reg_equiv_memory_loc[i])
continue;
}
reg_equiv_constant[i] = x;
num_eliminable_invariants++;
}
else if (LEGITIMATE_CONSTANT_P (x))
reg_equiv_constant[i] = x;
else
continue;
/* If this register is being made equivalent to a MEM
and the MEM is not SET_SRC, the equivalencing insn
is one with the MEM as a SET_DEST and it occurs later.
So don't mark this insn now. */
if (!MEM_P (x)
|| rtx_equal_p (SET_SRC (set), x))
reg_equiv_init[i]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
{
reg_equiv_memory_loc[i]
= force_const_mem (GET_MODE (SET_DEST (set)), x);
if (! reg_equiv_memory_loc[i])
reg_equiv_init[i] = NULL_RTX;
}
}
else
{
reg_equiv_init[i] = NULL_RTX;
continue;
}
}
else
reg_equiv_init[i] = NULL_RTX;
}
/* If this insn is setting a MEM from a register equivalent to it,
this is the equivalencing insn. */
else if (set && MEM_P (SET_DEST (set))
&& REG_P (SET_SRC (set))
&& reg_equiv_memory_loc[REGNO (SET_SRC (set))]
&& rtx_equal_p (SET_DEST (set),
reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
reg_equiv_init[REGNO (SET_SRC (set))]
= gen_rtx_INSN_LIST (VOIDmode, insn,
reg_equiv_init[REGNO (SET_SRC (set))]);
if (INSN_P (insn))
scan_paradoxical_subregs (PATTERN (insn));
}
if (dump_file)
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (reg_equiv_init[i])
{
fprintf (dump_file, "init_insns for %u: ", i);
print_inline_rtx (dump_file, reg_equiv_init[i], 20);
fprintf (dump_file, "\n");
}
init_elim_table ();
first_label_num = get_first_label_num ();
@ -1260,7 +1247,7 @@ reload (rtx first, int global)
free (offsets_at);
free (reg_equiv_mem);
free (reg_equiv_init);
reg_equiv_init = 0;
free (reg_equiv_address);
free (reg_max_ref_width);
free (reg_old_renumber);