equivalence handling patch applied to local-alloc.c, reload1.c
Joern Rennecke
amylaar@cygnus.co.uk
Wed Nov 11 19:38:00 GMT 1998
Tue Nov 10 04:12:02 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
Handle equivalences that have been obscured by gcse:
* reload1.c (reload): Handle equivalences set up in multiple places.
* local-alloc.c (reg_equiv_init_insns): New variable.
(no_equiv): New function.
(update_equiv_regs): Handle equivalences set up in multiple places.
Don't ignore an insn just because its destination is likely to be
spilled.
Index: local-alloc.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/local-alloc.c,v
retrieving revision 1.24
diff -p -r1.24 local-alloc.c
*** local-alloc.c 1998/10/17 01:28:51 1.24
--- local-alloc.c 1998/11/12 03:33:20
*************** static rtx this_insn;
*** 234,239 ****
--- 234,242 ----
static rtx *reg_equiv_replacement;
+ /* Used for communication between update_equiv_regs and no_equiv. */
+ static rtx *reg_equiv_init_insns;
+
static void alloc_qty PROTO((int, enum machine_mode, int, int));
static void validate_equiv_mem_from_store PROTO((rtx, rtx));
static int validate_equiv_mem PROTO((rtx, rtx, rtx));
*************** static int contains_replace_regs PROTO((
*** 241,246 ****
--- 244,250 ----
static int memref_referenced_p PROTO((rtx, rtx));
static int memref_used_between_p PROTO((rtx, rtx, rtx));
static void update_equiv_regs PROTO((void));
+ static void no_equiv PROTO((rtx, rtx));
static void block_alloc PROTO((int));
static int qty_sugg_compare PROTO((int, int));
static int qty_sugg_compare_1 PROTO((const GENERIC_PTR, const GENERIC_PTR));
*************** memref_used_between_p (memref, start, en
*** 633,639 ****
static void
update_equiv_regs ()
{
- rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx));
/* Set when an attempt should be made to replace a register with the
associated reg_equiv_replacement entry at the end of this function. */
char *reg_equiv_replace
--- 637,642 ----
*************** update_equiv_regs ()
*** 641,649 ****
rtx insn;
int block, depth;
reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx));
! bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
--- 644,653 ----
rtx insn;
int block, depth;
+ reg_equiv_init_insns = (rtx *) alloca (max_regno * sizeof (rtx));
reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx));
! bzero ((char *) reg_equiv_init_insns, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
*************** update_equiv_regs ()
*** 657,663 ****
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx note;
! rtx set = single_set (insn);
rtx dest, src;
int regno;
--- 661,667 ----
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx note;
! rtx set;
rtx dest, src;
int regno;
*************** update_equiv_regs ()
*** 669,678 ****
loop_depth--;
}
! /* If this insn contains more (or less) than a single SET, ignore it. */
! if (set == 0)
continue;
dest = SET_DEST (set);
src = SET_SRC (set);
--- 673,706 ----
loop_depth--;
}
! if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_INC)
+ no_equiv (XEXP (note, 0), note);
+
+ set = single_set (insn);
+
+ /* If this insn contains more (or less) than a single SET,
+ only mark all destinations as having no known equivalence. */
+ if (set == 0)
+ {
+ note_stores (PATTERN (insn), no_equiv);
+ continue;
+ }
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ int i;
+
+ for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ {
+ rtx part = XVECEXP (PATTERN (insn), 0, i);
+ if (part != set)
+ note_stores (part, no_equiv);
+ }
+ }
+
dest = SET_DEST (set);
src = SET_SRC (set);
*************** update_equiv_regs ()
*** 688,722 ****
If one of the regs in the address is marked as reg_equiv_replace,
then we can't add this REG_EQUIV note. The reg_equiv_replace
optimization may move the set of this register immediately before
! insn, which puts it after reg_equiv_init_insn[regno], and hence
the mention in the REG_EQUIV note would be to an uninitialized
pseudo. */
! if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG
! && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= 0
! && reg_equiv_init_insn[regno] != 0
&& ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
! && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace)
! && validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set),
! dest)
! && ! memref_used_between_p (SET_DEST (set),
! reg_equiv_init_insn[regno], insn))
! REG_NOTES (reg_equiv_init_insn[regno])
! = gen_rtx_EXPR_LIST (REG_EQUIV, dest,
! REG_NOTES (reg_equiv_init_insn[regno]));
/* We only handle the case of a pseudo register being set
! once and only if neither the source nor the destination are
! in a register class that's likely to be spilled. */
if (GET_CODE (dest) != REG
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
! || REG_N_SETS (regno) != 1
! || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest)))
! || (GET_CODE (src) == REG
! && REGNO (src) >= FIRST_PSEUDO_REGISTER
! && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src)))))
! continue;
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
--- 716,778 ----
If one of the regs in the address is marked as reg_equiv_replace,
then we can't add this REG_EQUIV note. The reg_equiv_replace
optimization may move the set of this register immediately before
! insn, which puts it after reg_equiv_init_insns[regno], 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 (GET_CODE (dest) == MEM && GET_CODE (src) == REG
! && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= 0
! && REG_N_SETS (regno) == 1
! && reg_equiv_init_insns[regno] != 0
! && reg_equiv_init_insns[regno] != const0_rtx
&& ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
! && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace))
! {
! rtx init_insn = XEXP (reg_equiv_init_insns[regno], 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));
! }
/* 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
! values that need an ADDRESS_REGS register and set them equivalent
! to a MEM of a pseudo. The actual problem is in the over-conservative
! handling of INPADDR_ADDRESS / INPUT_ADDRESS / INPUT triples in
! calculate_needs, but we traditionally work around this problem
! here by rejecting equivalences when the destination is in a register
! that's likely spilled. This is fragile, of course, since the
! preferred class of a pseudo depends on all intructions that set
! or use it. */
!
if (GET_CODE (dest) != REG
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
! || reg_equiv_init_insns[regno] == const0_rtx
! || (CLASS_LIKELY_SPILLED_P (reg_preferred_class (regno))
! && GET_CODE (src) == MEM))
! {
! /* This might be seting a SUBREG of a pseudo, a pseudo that is
! also set somewhere else to a constant. */
! note_stores (set, no_equiv);
! continue;
! }
! /* Don't handle the equivalence if the source is in a register
! class that's likely to be spilled. */
! if (GET_CODE (src) == REG
! && REGNO (src) >= FIRST_PSEUDO_REGISTER
! && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src))))
! {
! no_equiv (dest, set);
! continue;
! }
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
*************** update_equiv_regs ()
*** 736,743 ****
note = NULL;
#endif
/* Record this insn as initializing this register. */
! reg_equiv_init_insn[regno] = insn;
/* If this register is known to be equal to a constant, record that
it is always equivalent to the constant. */
--- 792,810 ----
note = NULL;
#endif
+ if (REG_N_SETS (regno) != 1
+ && (! note
+ || ! CONSTANT_P (XEXP (note, 0))
+ || (reg_equiv_replacement[regno]
+ && ! rtx_equal_p (XEXP (note, 0),
+ reg_equiv_replacement[regno]))))
+ {
+ no_equiv (dest, set);
+ continue;
+ }
/* Record this insn as initializing this register. */
! reg_equiv_init_insns[regno]
! = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init_insns[regno]);
/* If this register is known to be equal to a constant, record that
it is always equivalent to the constant. */
*************** update_equiv_regs ()
*** 849,855 ****
if (! reg_equiv_replace[regno])
continue;
! equiv_insn = reg_equiv_init_insn[regno];
if (validate_replace_rtx (regno_reg_rtx[regno],
reg_equiv_replacement[regno], insn))
--- 916,927 ----
if (! reg_equiv_replace[regno])
continue;
! /* reg_equiv_replace[REGNO] gets set only when
! REG_N_REFS[REGNO] is 2, i.e. the register is set
! once and used once. (If it were only set, but not used,
! flow would have deleted the setting insns.) Hence
! there can only be one insn in reg_equiv_init_insns. */
! equiv_insn = XEXP (reg_equiv_init_insns[regno], 0);
if (validate_replace_rtx (regno_reg_rtx[regno],
reg_equiv_replacement[regno], insn))
*************** update_equiv_regs ()
*** 895,900 ****
--- 967,1001 ----
}
}
}
+ }
+
+ /* Mark REG as having no known equivalence.
+ Some instructions might have been proceessed before and furnished
+ with REG_EQUIV notes for this register; these notes will have to be
+ removed.
+ STORE is the piece of RTL that does the non-constant / conflicting
+ assignment - a SET, CLOBBER or REG_INC note. It is currently not used,
+ but needs to be there because this function is called from note_stores. */
+ static void
+ no_equiv (reg, store)
+ rtx reg, store;
+ {
+ int regno;
+ rtx list;
+
+ if (GET_CODE (reg) != REG)
+ return;
+ regno = REGNO (reg);
+ list = reg_equiv_init_insns[regno];
+ if (list == const0_rtx)
+ return;
+ for (; list; list = XEXP (list, 1))
+ {
+ rtx insn = XEXP (list, 0);
+ remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
+ }
+ reg_equiv_init_insns[regno] = const0_rtx;
+ reg_equiv_replacement[regno] = NULL_RTX;
}
/* Allocate hard regs to the pseudo regs used only within block number B.
Index: reload1.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/reload1.c,v
retrieving revision 1.97
diff -p -r1.97 reload1.c
*** reload1.c 1998/11/09 02:12:55 1.97
--- reload1.c 1998/11/12 03:33:23
*************** rtx *reg_equiv_mem;
*** 114,120 ****
/* Widest width in which each pseudo reg is referred to (via subreg). */
static int *reg_max_ref_width;
! /* Element N is the insn that initialized reg N from its equivalent
constant or memory slot. */
static rtx *reg_equiv_init;
--- 114,120 ----
/* Widest width in which each pseudo reg is referred to (via subreg). */
static 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;
*************** reload (first, global, dumpfile)
*** 710,716 ****
So don't mark this insn now. */
if (GET_CODE (x) != MEM
|| rtx_equal_p (SET_SRC (set), x))
! reg_equiv_init[i] = insn;
}
}
}
--- 710,717 ----
So don't mark this insn now. */
if (GET_CODE (x) != MEM
|| rtx_equal_p (SET_SRC (set), x))
! reg_equiv_init[i]
! = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
}
}
}
*************** reload (first, global, dumpfile)
*** 722,728 ****
&& 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))] = insn;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
scan_paradoxical_subregs (PATTERN (insn));
--- 723,731 ----
&& 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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
scan_paradoxical_subregs (PATTERN (insn));
*************** reload (first, global, dumpfile)
*** 971,992 ****
If that insn didn't set the register (i.e., it copied the register to
memory), just delete that insn instead of the equivalencing insn plus
anything now dead. If we call delete_dead_insn on that insn, we may
! delete the insn that actually sets the register if the register die
there and that is incorrect. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
! if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0
! && GET_CODE (reg_equiv_init[i]) != NOTE)
! {
! if (reg_set_p (regno_reg_rtx[i], PATTERN (reg_equiv_init[i])))
! delete_dead_insn (reg_equiv_init[i]);
! else
! {
! PUT_CODE (reg_equiv_init[i], NOTE);
! NOTE_SOURCE_FILE (reg_equiv_init[i]) = 0;
! NOTE_LINE_NUMBER (reg_equiv_init[i]) = NOTE_INSN_DELETED;
! }
! }
/* Use the reload registers where necessary
by generating move instructions to move the must-be-register
--- 974,1003 ----
If that insn didn't set the register (i.e., it copied the register to
memory), just delete that insn instead of the equivalencing insn plus
anything now dead. If we call delete_dead_insn on that insn, we may
! delete the insn that actually sets the register if the register dies
there and that is incorrect. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
! {
! if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0)
! {
! rtx list;
! for (list = reg_equiv_init[i]; list; list = XEXP (list, 1))
! {
! rtx equiv_insn = XEXP (list, 0);
! if (GET_CODE (equiv_insn) == NOTE)
! continue;
! if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
! delete_dead_insn (equiv_insn);
! else
! {
! PUT_CODE (equiv_insn, NOTE);
! NOTE_SOURCE_FILE (equiv_insn) = 0;
! NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
! }
! }
! }
! }
/* Use the reload registers where necessary
by generating move instructions to move the must-be-register
More information about the Gcc-patches
mailing list