This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: hard register reload patch
- To: law at cygnus dot com
- Subject: Re: hard register reload patch
- From: Joern Rennecke <amylaar at cygnus dot co dot uk>
- Date: Tue, 14 Dec 1999 21:06:07 +0000 (GMT)
- Cc: amylaar at cygnus dot co dot uk, gcc-patches at gcc dot gnu dot org
> Otherwise I'm happy with the patch and it should be installed once the
> SUBREG issue is dealt with and we've got some initial performance #s.
I have changed the if to a while in add_stored_regs.
However, after Bernd's last checkin, I had to fix up the merged sources
by hand. The timings I have just posted were made with these merged
sources.
Here is the updated patch:
Tue Dec 14 21:03:04 1999 J"orn Rennecke <amylaar@cygnus.co.uk>
* caller-save.c (insert_one_insn): Returns struct insn_chain *.
Handle live_throughout / dead_or_set instead of live_before /
live_after.
(save_call_clobbered_regs): Get register livenessinformation from
chain->live_throughout.
(add_stored_regs): New function.
(insert_restore, insert_save): Add restored / saved registers to
dead_or_set.
* global.c (reg_dies): New parameter chain.
(reg_becomes_live): Third parameter is regs_set now.
Changed all callers.
(reg_dies): New parameter chain. Changed all callers.
(build_insn_chain): Set live_throughout instead of
live_before / live_after.
* reload.h (struct insn_chain): Replace members live_before /
live_after with live_throughout / dead_or_set.
* reload1.c (new_insn_chain): Handle live_throughout / dead_or_set
instead of live_before / live_after.
(maybe_fix_stack_asms, find_reload_regs, finish_spills): Likewise.
(order_regs_for_reload, find_reg, finish_spills): Likewise.
(choose_reload_regs_init): Likewise.
* stupid.c (current_chain, find_clobbered_regs): Delete.
(stupid_life_analysis): Set chain->live_throughout chain->dead_or_set
instead of chain->live_before / chain->live_after.
(mark_hard_ref): New function.
(stupid_mark_refs): Call mark_hard_ref. Clear chain->live_throughout.
Index: caller-save.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/caller-save.c,v
retrieving revision 1.24
diff -p -r1.24 caller-save.c
*** caller-save.c 1999/10/27 19:27:40 1.24
--- caller-save.c 1999/12/14 20:45:40
*************** static int insert_save PROTO((struct i
*** 90,97 ****
HARD_REG_SET *));
static int insert_restore PROTO((struct insn_chain *, int, int,
int));
! static void insert_one_insn PROTO((struct insn_chain *, int,
! enum insn_code, rtx));
/* Initialize for caller-save.
--- 90,97 ----
HARD_REG_SET *));
static int insert_restore PROTO((struct insn_chain *, int, int,
int));
! static struct insn_chain *insert_one_insn PROTO((struct insn_chain *, int,
! enum insn_code, rtx));
/* Initialize for caller-save.
*************** save_call_clobbered_regs ()
*** 373,389 ****
if (code == CALL_INSN)
{
! rtx x;
! int regno, nregs;
HARD_REG_SET hard_regs_to_save;
/* Use the register life information in CHAIN to compute which
! regs are live before the call. */
! REG_SET_TO_HARD_REG_SET (hard_regs_to_save, chain->live_before);
! compute_use_by_pseudos (&hard_regs_to_save, chain->live_before);
/* Record all registers set in this call insn. These don't need
! to be saved. */
CLEAR_HARD_REG_SET (this_insn_sets);
note_stores (PATTERN (insn), mark_set_regs, NULL);
--- 373,392 ----
if (code == CALL_INSN)
{
! int regno;
HARD_REG_SET hard_regs_to_save;
/* Use the register life information in CHAIN to compute which
! regs are live during the call. */
! REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
! chain->live_throughout);
! compute_use_by_pseudos (&hard_regs_to_save,
! chain->live_throughout);
/* Record all registers set in this call insn. These don't need
! to be saved. N.B. the call insn might set a subreg of a
! multi-hard-reg pseudo; then the pseudo is considered live
! during the call, but the subreg that is set isn't. */
CLEAR_HARD_REG_SET (this_insn_sets);
note_stores (PATTERN (insn), mark_set_regs, NULL);
*************** save_call_clobbered_regs ()
*** 393,437 ****
AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
AND_HARD_REG_SET (hard_regs_to_save, call_used_reg_set);
- /* Registers used for function parameters need not be saved. */
- for (x = CALL_INSN_FUNCTION_USAGE (insn); x != 0;
- x = XEXP (x, 1))
- {
- rtx y;
-
- if (GET_CODE (XEXP (x, 0)) != USE)
- continue;
- y = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (y) != REG)
- abort ();
- regno = REGNO (y);
- if (REGNO (y) >= FIRST_PSEUDO_REGISTER)
- abort ();
- nregs = HARD_REGNO_NREGS (regno, GET_MODE (y));
- while (nregs-- > 0)
- CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs);
- }
-
- /* Neither do registers for which we find a death note. */
- for (x = REG_NOTES (insn); x != 0; x = XEXP (x, 1))
- {
- rtx y = XEXP (x, 0);
-
- if (REG_NOTE_KIND (x) != REG_DEAD)
- continue;
- if (GET_CODE (y) != REG)
- abort ();
- regno = REGNO (y);
-
- if (regno >= FIRST_PSEUDO_REGISTER)
- regno = reg_renumber[regno];
- if (regno < 0)
- continue;
- nregs = HARD_REGNO_NREGS (regno, GET_MODE (y));
- while (nregs-- > 0)
- CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs);
- }
-
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
regno += insert_save (chain, 1, regno, &hard_regs_to_save);
--- 396,401 ----
*************** mark_set_regs (reg, setter, data)
*** 490,495 ****
--- 454,492 ----
SET_HARD_REG_BIT (this_insn_sets, i);
}
+ /* Here from note_stores when an insn stores a value in a register.
+ Set the proper bit or bits in the passed regset. All pseudos that have
+ been assigned hard regs have had their register number changed already,
+ so we can ignore pseudos. */
+ static void
+ add_stored_regs (reg, setter, data)
+ rtx reg;
+ rtx setter;
+ void *data;
+ {
+ register int regno, endregno, i;
+ enum machine_mode mode = GET_MODE (reg);
+ int word = 0;
+
+ if (GET_CODE (setter) == CLOBBER)
+ return;
+
+ while (GET_CODE (reg) == SUBREG)
+ {
+ word += SUBREG_WORD (reg);
+ reg = SUBREG_REG (reg);
+ }
+
+ if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+ return;
+
+ regno = REGNO (reg) + word;
+ endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+ for (i = regno; i < endregno; i++)
+ SET_REGNO_REG_SET ((regset) data, i);
+ }
+
/* Walk X and record all referenced registers in REFERENCED_REGS. */
static void
mark_referenced_regs (x)
*************** insert_restore (chain, before_p, regno,
*** 568,577 ****
int regno;
int maxrestore;
{
! int i;
rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing;
int numregs = 0;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
--- 565,575 ----
int regno;
int maxrestore;
{
! int i, k;
rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing;
int numregs = 0;
+ struct insn_chain *new;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
*************** insert_restore (chain, before_p, regno,
*** 589,595 ****
backwards to the single register case. */
for (i = maxrestore; i > 0; i--)
{
! int j, k;
int ok = 1;
if (regno_save_mem[regno][i] == 0)
--- 587,593 ----
backwards to the single register case. */
for (i = maxrestore; i > 0; i--)
{
! int j;
int ok = 1;
if (regno_save_mem[regno][i] == 0)
*************** insert_restore (chain, before_p, regno,
*** 605,629 ****
if (! ok)
continue;
- pat = gen_rtx_SET (VOIDmode,
- gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
- regno),
- regno_save_mem[regno][i]);
- code = reg_restore_code[regno][i];
-
- /* Clear status for all registers we restored. */
- for (k = 0; k < i; k++)
- {
- CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k);
- n_regs_saved--;
- }
-
numregs = i;
break;
}
! insert_one_insn (chain, before_p, code, pat);
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}
--- 603,629 ----
if (! ok)
continue;
numregs = i;
break;
}
! pat = gen_rtx_SET (VOIDmode,
! gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]),
! regno),
! regno_save_mem[regno][numregs]);
! code = reg_restore_code[regno][numregs];
! new = insert_one_insn (chain, before_p, code, pat);
!
! /* Clear status for all registers we restored. */
! for (k = 0; k < i; k++)
! {
! CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k);
! SET_REGNO_REG_SET (new->dead_or_set, regno + k);
! n_regs_saved--;
! }
+
+
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}
*************** insert_save (chain, before_p, regno, to_
*** 636,645 ****
int regno;
HARD_REG_SET *to_save;
{
! int i;
rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing;
int numregs = 0;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
--- 636,646 ----
int regno;
HARD_REG_SET *to_save;
{
! int i, k;
rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing;
int numregs = 0;
+ struct insn_chain *new;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
*************** insert_save (chain, before_p, regno, to_
*** 657,663 ****
Work backwards to the single register case. */
for (i = MOVE_MAX_WORDS; i > 0; i--)
{
! int j, k;
int ok = 1;
if (regno_save_mem[regno][i] == 0)
continue;
--- 658,664 ----
Work backwards to the single register case. */
for (i = MOVE_MAX_WORDS; i > 0; i--)
{
! int j;
int ok = 1;
if (regno_save_mem[regno][i] == 0)
continue;
*************** insert_save (chain, before_p, regno, to_
*** 672,701 ****
if (! ok)
continue;
- pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
- gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
- regno));
- code = reg_save_code[regno][i];
-
- /* Set hard_regs_saved for all the registers we saved. */
- for (k = 0; k < i; k++)
- {
- SET_HARD_REG_BIT (hard_regs_saved, regno + k);
- n_regs_saved++;
- }
-
numregs = i;
break;
}
! insert_one_insn (chain, before_p, code, pat);
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}
/* Emit a new caller-save insn and set the code. */
! static void
insert_one_insn (chain, before_p, code, pat)
struct insn_chain *chain;
int before_p;
--- 673,702 ----
if (! ok)
continue;
numregs = i;
break;
}
! pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][numregs],
! gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]),
! regno));
! code = reg_save_code[regno][numregs];
! new = insert_one_insn (chain, before_p, code, pat);
!
! /* Set hard_regs_saved and dead_or_set for all the registers we saved. */
! for (k = 0; k < numregs; k++)
! {
! SET_HARD_REG_BIT (hard_regs_saved, regno + k);
! SET_REGNO_REG_SET (new->dead_or_set, regno + k);
! n_regs_saved++;
! }
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}
/* Emit a new caller-save insn and set the code. */
! static struct insn_chain *
insert_one_insn (chain, before_p, code, pat)
struct insn_chain *chain;
int before_p;
*************** insert_one_insn (chain, before_p, code,
*** 721,726 ****
--- 722,729 ----
new = new_insn_chain ();
if (before_p)
{
+ rtx link;
+
new->prev = chain->prev;
if (new->prev != 0)
new->prev->next = new;
*************** insert_one_insn (chain, before_p, code,
*** 732,739 ****
new->insn = emit_insn_before (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved
registers from the live sets. */
! COPY_REG_SET (new->live_before, chain->live_before);
! COPY_REG_SET (new->live_after, chain->live_before);
if (chain->insn == BLOCK_HEAD (chain->block))
BLOCK_HEAD (chain->block) = new->insn;
}
--- 735,763 ----
new->insn = emit_insn_before (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved
registers from the live sets. */
! COPY_REG_SET (new->live_throughout, chain->live_throughout);
! /* Registers that die in CHAIN->INSN still live in the new insn. */
! for (link = REG_NOTES (chain->insn); link; link = XEXP (link, 1))
! {
! if (REG_NOTE_KIND (link) == REG_DEAD)
! {
! rtx reg = XEXP (link, 0);
! int regno, i;
!
! if (GET_CODE (reg) != REG)
! abort ();
!
! regno = REGNO (reg);
! if (regno >= FIRST_PSEUDO_REGISTER)
! regno = reg_renumber[regno];
! if (regno < 0)
! continue;
! for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
! i >= 0; i--)
! SET_REGNO_REG_SET (new->live_throughout, regno + i);
! }
! }
! CLEAR_REG_SET (new->dead_or_set);
if (chain->insn == BLOCK_HEAD (chain->block))
BLOCK_HEAD (chain->block) = new->insn;
}
*************** insert_one_insn (chain, before_p, code,
*** 747,754 ****
new->insn = emit_insn_after (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved
registers from the live sets, and observe REG_UNUSED notes. */
! COPY_REG_SET (new->live_before, chain->live_after);
! COPY_REG_SET (new->live_after, chain->live_after);
if (chain->insn == BLOCK_END (chain->block))
BLOCK_END (chain->block) = new->insn;
}
--- 771,783 ----
new->insn = emit_insn_after (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved
registers from the live sets, and observe REG_UNUSED notes. */
! COPY_REG_SET (new->live_throughout, chain->live_throughout);
! /* Registers that are set in CHAIN->INSN live in the new insn.
! (Unless there is a REG_UNUSED note for them, but we don't
! look for them here.) */
! note_stores (PATTERN (chain->insn), add_stored_regs,
! new->live_throughout);
! CLEAR_REG_SET (new->dead_or_set);
if (chain->insn == BLOCK_END (chain->block))
BLOCK_END (chain->block) = new->insn;
}
*************** insert_one_insn (chain, before_p, code,
*** 756,759 ****
--- 785,789 ----
new->is_caller_save_insn = 1;
INSN_CODE (new->insn) = code;
+ return new;
}
Index: global.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/global.c,v
retrieving revision 1.50
diff -p -r1.50 global.c
*** global.c 1999/12/12 01:34:39 1.50
--- global.c 1999/12/14 20:45:46
*************** static void mark_reg_live_nc PROTO((int,
*** 303,309 ****
static void set_preference PROTO((rtx, rtx));
static void dump_conflicts PROTO((FILE *));
static void reg_becomes_live PROTO((rtx, rtx, void *));
! static void reg_dies PROTO((int, enum machine_mode));
static void build_insn_chain PROTO((rtx));
/* Perform allocation of pseudo-registers not allocated by local_alloc.
--- 303,310 ----
static void set_preference PROTO((rtx, rtx));
static void dump_conflicts PROTO((FILE *));
static void reg_becomes_live PROTO((rtx, rtx, void *));
! static void reg_dies PROTO((int, enum machine_mode,
! struct insn_chain *));
static void build_insn_chain PROTO((rtx));
/* Perform allocation of pseudo-registers not allocated by local_alloc.
*************** mark_elimination (from, to)
*** 1693,1705 ****
current life information. */
static regset live_relevant_regs;
! /* Record in live_relevant_regs that register REG became live. This
! is called via note_stores. */
static void
! reg_becomes_live (reg, setter, data)
rtx reg;
rtx setter ATTRIBUTE_UNUSED;
! void *data ATTRIBUTE_UNUSED;
{
int regno;
--- 1694,1706 ----
current life information. */
static regset live_relevant_regs;
! /* Record in live_relevant_regs and REGS_SET that register REG became live.
! This is called via note_stores. */
static void
! reg_becomes_live (reg, setter, regs_set)
rtx reg;
rtx setter ATTRIBUTE_UNUSED;
! void *regs_set;
{
int regno;
*************** reg_becomes_live (reg, setter, data)
*** 1714,1739 ****
{
int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0)
! SET_REGNO_REG_SET (live_relevant_regs, regno++);
}
else if (reg_renumber[regno] >= 0)
! SET_REGNO_REG_SET (live_relevant_regs, regno);
}
/* Record in live_relevant_regs that register REGNO died. */
static void
! reg_dies (regno, mode)
int regno;
enum machine_mode mode;
{
if (regno < FIRST_PSEUDO_REGISTER)
{
int nregs = HARD_REGNO_NREGS (regno, mode);
while (nregs-- > 0)
! CLEAR_REGNO_REG_SET (live_relevant_regs, regno++);
}
else
! CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
}
/* Walk the insns of the current function and build reload_insn_chain,
--- 1715,1758 ----
{
int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0)
! {
! SET_REGNO_REG_SET (live_relevant_regs, regno);
! if (! fixed_regs[regno])
! SET_REGNO_REG_SET ((regset) regs_set, regno);
! regno++;
! }
}
else if (reg_renumber[regno] >= 0)
! {
! SET_REGNO_REG_SET (live_relevant_regs, regno);
! SET_REGNO_REG_SET ((regset) regs_set, regno);
! }
}
/* Record in live_relevant_regs that register REGNO died. */
static void
! reg_dies (regno, mode, chain)
int regno;
enum machine_mode mode;
+ struct insn_chain *chain;
{
if (regno < FIRST_PSEUDO_REGISTER)
{
int nregs = HARD_REGNO_NREGS (regno, mode);
while (nregs-- > 0)
! {
! CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
! if (! fixed_regs[regno])
! SET_REGNO_REG_SET (chain->dead_or_set, regno);
! regno++;
! }
}
else
! {
! CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
! if (reg_renumber[regno] >= 0)
! SET_REGNO_REG_SET (chain->dead_or_set, regno);
! }
}
/* Walk the insns of the current function and build reload_insn_chain,
*************** build_insn_chain (first)
*** 1778,1785 ****
c->insn = first;
c->block = b;
- COPY_REG_SET (c->live_before, live_relevant_regs);
-
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
{
rtx link;
--- 1797,1802 ----
*************** build_insn_chain (first)
*** 1789,1804 ****
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD
&& GET_CODE (XEXP (link, 0)) == REG)
! reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
/* Mark everything born in this instruction as live. */
! note_stores (PATTERN (first), reg_becomes_live, NULL);
}
!
! /* Remember which registers are live at the end of the insn, before
! killing those with REG_UNUSED notes. */
! COPY_REG_SET (c->live_after, live_relevant_regs);
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
{
--- 1806,1823 ----
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD
&& GET_CODE (XEXP (link, 0)) == REG)
! reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
! c);
!
! COPY_REG_SET (c->live_throughout, live_relevant_regs);
/* Mark everything born in this instruction as live. */
! note_stores (PATTERN (first), reg_becomes_live,
! c->dead_or_set);
}
! else
! COPY_REG_SET (c->live_throughout, live_relevant_regs);
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
{
*************** build_insn_chain (first)
*** 1809,1815 ****
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_UNUSED
&& GET_CODE (XEXP (link, 0)) == REG)
! reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
}
}
--- 1828,1835 ----
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_UNUSED
&& GET_CODE (XEXP (link, 0)) == REG)
! reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
! c);
}
}
Index: reload.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.h,v
retrieving revision 1.22
diff -p -r1.22 reload.h
*** reload.h 1999/12/13 13:21:34 1.22
--- reload.h 1999/12/14 20:45:46
*************** struct insn_chain
*** 224,235 ****
/* The rtx of the insn. */
rtx insn;
/* Register life information: record all live hard registers, and all
! live pseudos that have a hard register.
! This information is recorded for the point immediately before the insn
! (in live_before), and for the point within the insn at which all
! outputs have just been written to (in live_after). */
! regset live_before;
! regset live_after;
/* Copies of the global variables computed by find_reloads. */
struct reload *rld;
--- 224,232 ----
/* The rtx of the insn. */
rtx insn;
/* Register life information: record all live hard registers, and all
! live pseudos that have a hard register. */
! regset live_throughout;
! regset dead_or_set;
/* Copies of the global variables computed by find_reloads. */
struct reload *rld;
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
retrieving revision 1.186
diff -p -r1.186 reload1.c
*** reload1.c 1999/12/14 12:40:02 1.186
--- reload1.c 1999/12/14 20:45:49
*************** new_insn_chain ()
*** 514,521 ****
{
c = (struct insn_chain *)
obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
! c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack);
! c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack);
}
else
{
--- 514,521 ----
{
c = (struct insn_chain *)
obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
! c->live_throughout = OBSTACK_ALLOC_REG_SET (&reload_obstack);
! c->dead_or_set = OBSTACK_ALLOC_REG_SET (&reload_obstack);
}
else
{
*************** maybe_fix_stack_asms ()
*** 1295,1302 ****
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allowed, i))
{
! CLEAR_REGNO_REG_SET (chain->live_before, i);
! CLEAR_REGNO_REG_SET (chain->live_after, i);
}
}
--- 1295,1302 ----
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allowed, i))
{
! CLEAR_REGNO_REG_SET (chain->live_throughout, i);
! CLEAR_REGNO_REG_SET (chain->dead_or_set, i);
}
}
*************** order_regs_for_reload (chain)
*** 1516,1523 ****
/* Test the various reasons why we can't use a register for
spilling in this insn. */
if (fixed_regs[i]
! || REGNO_REG_SET_P (chain->live_before, i)
! || REGNO_REG_SET_P (chain->live_after, i))
SET_HARD_REG_BIT (bad_spill_regs, i);
}
/* Now find out which pseudos are allocated to it, and update
--- 1516,1523 ----
/* Test the various reasons why we can't use a register for
spilling in this insn. */
if (fixed_regs[i]
! || REGNO_REG_SET_P (chain->live_throughout, i)
! || REGNO_REG_SET_P (chain->dead_or_set, i))
SET_HARD_REG_BIT (bad_spill_regs, i);
}
/* Now find out which pseudos are allocated to it, and update
*************** order_regs_for_reload (chain)
*** 1525,1536 ****
CLEAR_REG_SET (&pseudos_counted);
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_before, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_after, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
--- 1525,1536 ----
CLEAR_REG_SET (&pseudos_counted);
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
{
count_pseudo (j);
});
*************** find_reg (chain, order, dumpfile)
*** 1645,1656 ****
rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_before, FIRST_PSEUDO_REGISTER, j,
{
count_spilled_pseudo (best_reg, rl->nregs, j);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_after, FIRST_PSEUDO_REGISTER, j,
{
count_spilled_pseudo (best_reg, rl->nregs, j);
});
--- 1645,1656 ----
rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{
count_spilled_pseudo (best_reg, rl->nregs, j);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
{
count_spilled_pseudo (best_reg, rl->nregs, j);
});
*************** finish_spills (global, dumpfile)
*** 3489,3501 ****
for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
{
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_before, FIRST_PSEUDO_REGISTER, i,
{
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_after, FIRST_PSEUDO_REGISTER, i,
{
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
--- 3489,3501 ----
for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
{
EXECUTE_IF_SET_IN_REG_SET
! (chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
{
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
});
EXECUTE_IF_SET_IN_REG_SET
! (chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
{
ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs);
*************** finish_spills (global, dumpfile)
*** 3528,3549 ****
HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2;
! AND_COMPL_REG_SET (chain->live_before, &spilled_pseudos);
! AND_COMPL_REG_SET (chain->live_after, &spilled_pseudos);
/* Mark any unallocated hard regs as available for spills. That
makes inheritance work somewhat better. */
if (chain->need_reload)
{
! REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_before);
! REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->live_after);
IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
/* Save the old value for the sanity test below. */
COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
! compute_use_by_pseudos (&used_by_pseudos, chain->live_before);
! compute_use_by_pseudos (&used_by_pseudos, chain->live_after);
COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
--- 3528,3549 ----
HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2;
! AND_COMPL_REG_SET (chain->live_throughout, &spilled_pseudos);
! AND_COMPL_REG_SET (chain->dead_or_set, &spilled_pseudos);
/* Mark any unallocated hard regs as available for spills. That
makes inheritance work somewhat better. */
if (chain->need_reload)
{
! REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_throughout);
! REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->dead_or_set);
IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
/* Save the old value for the sanity test below. */
COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
! compute_use_by_pseudos (&used_by_pseudos, chain->live_throughout);
! compute_use_by_pseudos (&used_by_pseudos, chain->dead_or_set);
COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
*************** choose_reload_regs_init (chain, save_rel
*** 5033,5044 ****
CLEAR_HARD_REG_SET (reg_used_in_insn);
{
HARD_REG_SET tmp;
! REG_SET_TO_HARD_REG_SET (tmp, chain->live_before);
IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! REG_SET_TO_HARD_REG_SET (tmp, chain->live_after);
IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! compute_use_by_pseudos (®_used_in_insn, chain->live_before);
! compute_use_by_pseudos (®_used_in_insn, chain->live_after);
}
for (i = 0; i < reload_n_operands; i++)
{
--- 5033,5044 ----
CLEAR_HARD_REG_SET (reg_used_in_insn);
{
HARD_REG_SET tmp;
! REG_SET_TO_HARD_REG_SET (tmp, chain->live_throughout);
IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! REG_SET_TO_HARD_REG_SET (tmp, chain->dead_or_set);
IOR_HARD_REG_SET (reg_used_in_insn, tmp);
! compute_use_by_pseudos (®_used_in_insn, chain->live_throughout);
! compute_use_by_pseudos (®_used_in_insn, chain->dead_or_set);
}
for (i = 0; i < reload_n_operands; i++)
{
Index: stupid.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stupid.c,v
retrieving revision 1.24
diff -p -r1.24 stupid.c
*** stupid.c 1999/11/30 12:16:55 1.24
--- stupid.c 1999/12/14 20:45:49
*************** static int stupid_find_reg PROTO((int, e
*** 129,140 ****
int, int, int));
static void stupid_mark_refs PROTO((rtx, struct insn_chain *));
static void find_clobbered_regs PROTO((rtx, rtx, void *));
/* For communication between stupid_life_analysis and find_clobbered_regs. */
static struct insn_chain *current_chain;
/* This function, called via note_stores, marks any hard registers that are
! clobbered in an insn as being live in the live_after and live_before fields
of the appropriate insn_chain structure. */
static void
--- 129,141 ----
int, int, int));
static void stupid_mark_refs PROTO((rtx, struct insn_chain *));
static void find_clobbered_regs PROTO((rtx, rtx, void *));
+ static void mark_hard_ref PROTO((rtx, int, struct insn_chain *));
/* For communication between stupid_life_analysis and find_clobbered_regs. */
static struct insn_chain *current_chain;
/* This function, called via note_stores, marks any hard registers that are
! clobbered in an insn as being live in the live_throughout field
of the appropriate insn_chain structure. */
static void
*************** find_clobbered_regs (reg, setter, data)
*** 161,168 ****
nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0)
{
! SET_REGNO_REG_SET (current_chain->live_after, regno);
! SET_REGNO_REG_SET (current_chain->live_before, regno++);
}
}
--- 162,168 ----
nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0)
{
! SET_REGNO_REG_SET (current_chain->live_throughout, regno++);
}
}
*************** stupid_life_analysis (f, nregs, file)
*** 285,291 ****
chain->insn = insn;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regs_live[i])
! SET_REGNO_REG_SET (chain->live_before, i);
}
/* Update which hard regs are currently live
--- 285,291 ----
chain->insn = insn;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regs_live[i])
! SET_REGNO_REG_SET (chain->live_throughout, i);
}
/* Update which hard regs are currently live
*************** stupid_life_analysis (f, nregs, file)
*** 336,345 ****
if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
{
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (regs_live[i])
- SET_REGNO_REG_SET (chain->live_after, i);
-
/* The regs_live array doesn't say anything about hard registers
clobbered by this insn. So we need an extra pass over the
pattern. */
--- 336,341 ----
*************** stupid_life_analysis (f, nregs, file)
*** 407,427 ****
continue;
chain = reg_where_dead_chain[i];
! if (reg_where_dead[i] > INSN_SUID (chain->insn))
! SET_REGNO_REG_SET (chain->live_after, i);
! while (INSN_SUID (chain->insn) > reg_where_born_exact[i])
! {
! SET_REGNO_REG_SET (chain->live_before, i);
! chain = chain->prev;
! if (!chain)
! break;
! SET_REGNO_REG_SET (chain->live_after, i);
! }
! if (INSN_SUID (chain->insn) == reg_where_born_exact[i]
! && reg_where_born_clobber[i])
! SET_REGNO_REG_SET (chain->live_before, i);
}
if (file)
--- 403,416 ----
continue;
chain = reg_where_dead_chain[i];
! SET_REGNO_REG_SET (chain->dead_or_set, i);
! while ((chain = chain->prev)
! && INSN_SUID (chain->insn) > reg_where_born_exact[i])
! SET_REGNO_REG_SET (chain->live_throughout, i);
! if (chain)
! SET_REGNO_REG_SET (chain->dead_or_set, i);
}
if (file)
*************** stupid_find_reg (call_preserved, class,
*** 568,573 ****
--- 557,588 ----
return -1;
}
+ /* Note that REG is being set or referenced, and add the appropriate
+ REG_DEAD / REG_UNUSED note(s). For sets, LIVE_BEFORE_P will be 0,
+ while for references, LIVE_BEFORE_P will be 1.
+ INSN is the instruction that the reg notes have to be added to. */
+ static void
+ mark_hard_ref (reg, live_before_p, chain)
+ rtx reg;
+ int live_before_p;
+ struct insn_chain *chain;
+ {
+ /* Hard reg: mark it live for continuing scan of previous insns. */
+ int regno = REGNO (reg);
+ char *live = regs_live;
+ register int j;
+ int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+
+ for (j = nregs - 1; j >= 0; j--)
+ {
+ if (! fixed_regs[regno+j]
+ && (! live_before_p || ! live[regno+j]))
+ SET_REGNO_REG_SET (chain->dead_or_set, regno+j);
+ regs_ever_live[regno+j] = 1;
+ live[regno+j] = live_before_p;
+ }
+ }
+
/* Walk X, noting all assignments and references to registers
and recording what they imply about life spans.
INSN is the current insn, supplied so we can find its suid. */
*************** stupid_mark_refs (x, chain)
*** 597,623 ****
>= FIRST_PSEUDO_REGISTER))))
{
/* Register is being assigned. */
/* If setting a SUBREG, we treat the entire reg as being set. */
if (GET_CODE (SET_DEST (x)) == SUBREG)
! regno = REGNO (SUBREG_REG (SET_DEST (x)));
! else
! regno = REGNO (SET_DEST (x));
/* For hard regs, update the where-live info. */
if (regno < FIRST_PSEUDO_REGISTER)
{
register int j
= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
while (--j >= 0)
{
- regs_ever_live[regno+j] = 1;
- regs_live[regno+j] = 0;
-
/* The following line is for unused outputs;
they do get stored even though never used again. */
MARK_LIVE_AFTER (insn, regno+j);
/* When a hard reg is clobbered, mark it in use
just before this insn, so it is live all through. */
if (code == CLOBBER && INSN_SUID (insn) > 0)
--- 612,641 ----
>= FIRST_PSEUDO_REGISTER))))
{
/* Register is being assigned. */
+ rtx reg = SET_DEST (x);
+
/* If setting a SUBREG, we treat the entire reg as being set. */
if (GET_CODE (SET_DEST (x)) == SUBREG)
! reg = SUBREG_REG (reg);
+ regno = REGNO (reg);
+
/* For hard regs, update the where-live info. */
if (regno < FIRST_PSEUDO_REGISTER)
{
register int j
= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
+ mark_hard_ref (reg, 0, chain);
+
while (--j >= 0)
{
/* The following line is for unused outputs;
they do get stored even though never used again. */
MARK_LIVE_AFTER (insn, regno+j);
+ CLEAR_REGNO_REG_SET (chain->live_throughout, regno + j);
+
/* When a hard reg is clobbered, mark it in use
just before this insn, so it is live all through. */
if (code == CLOBBER && INSN_SUID (insn) > 0)
*************** stupid_mark_refs (x, chain)
*** 706,720 ****
{
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
! {
! /* Hard reg: mark it live for continuing scan of previous insns. */
! register int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
! while (--j >= 0)
! {
! regs_ever_live[regno+j] = 1;
! regs_live[regno+j] = 1;
! }
! }
else
{
/* Pseudo reg: record first use, last use and number of uses. */
--- 724,731 ----
{
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
! /* Hard reg: mark it live for continuing scan of previous insns. */
! mark_hard_ref (x, 1, chain);
else
{
/* Pseudo reg: record first use, last use and number of uses. */