Commit 285f3cf0 by J"orn Rennecke Committed by Joern Rennecke

caller-save.c (insert_one_insn): Returns struct insn_chain *.

	* 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.

From-SVN: r30957
parent 4940cd60
Wed Dec 15 14:55:24 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.
1999-12-15 David S. Miller <davem@redhat.com> 1999-12-15 David S. Miller <davem@redhat.com>
* rtlanal.c (reg_overlap_mentioned_p): Handle CONCAT. * rtlanal.c (reg_overlap_mentioned_p): Handle CONCAT.
......
...@@ -90,8 +90,8 @@ static int insert_save PROTO((struct insn_chain *, int, int, ...@@ -90,8 +90,8 @@ static int insert_save PROTO((struct insn_chain *, int, int,
HARD_REG_SET *)); HARD_REG_SET *));
static int insert_restore PROTO((struct insn_chain *, int, int, static int insert_restore PROTO((struct insn_chain *, int, int,
int)); int));
static void insert_one_insn PROTO((struct insn_chain *, int, static struct insn_chain *insert_one_insn PROTO((struct insn_chain *, int,
enum insn_code, rtx)); enum insn_code, rtx));
/* Initialize for caller-save. /* Initialize for caller-save.
...@@ -373,17 +373,20 @@ save_call_clobbered_regs () ...@@ -373,17 +373,20 @@ save_call_clobbered_regs ()
if (code == CALL_INSN) if (code == CALL_INSN)
{ {
rtx x; int regno;
int regno, nregs;
HARD_REG_SET hard_regs_to_save; HARD_REG_SET hard_regs_to_save;
/* Use the register life information in CHAIN to compute which /* Use the register life information in CHAIN to compute which
regs are live before the call. */ regs are live during the call. */
REG_SET_TO_HARD_REG_SET (hard_regs_to_save, chain->live_before); REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
compute_use_by_pseudos (&hard_regs_to_save, chain->live_before); 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 /* Record all registers set in this call insn. These don't need
to be saved. */ 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); CLEAR_HARD_REG_SET (this_insn_sets);
note_stores (PATTERN (insn), mark_set_regs, NULL); note_stores (PATTERN (insn), mark_set_regs, NULL);
...@@ -393,45 +396,6 @@ save_call_clobbered_regs () ...@@ -393,45 +396,6 @@ save_call_clobbered_regs ()
AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved); AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
AND_HARD_REG_SET (hard_regs_to_save, call_used_reg_set); 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++) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
regno += insert_save (chain, 1, regno, &hard_regs_to_save); regno += insert_save (chain, 1, regno, &hard_regs_to_save);
...@@ -490,6 +454,39 @@ mark_set_regs (reg, setter, data) ...@@ -490,6 +454,39 @@ mark_set_regs (reg, setter, data)
SET_HARD_REG_BIT (this_insn_sets, i); 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. */ /* Walk X and record all referenced registers in REFERENCED_REGS. */
static void static void
mark_referenced_regs (x) mark_referenced_regs (x)
...@@ -568,10 +565,11 @@ insert_restore (chain, before_p, regno, maxrestore) ...@@ -568,10 +565,11 @@ insert_restore (chain, before_p, regno, maxrestore)
int regno; int regno;
int maxrestore; int maxrestore;
{ {
int i; int i, k;
rtx pat = NULL_RTX; rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing; enum insn_code code = CODE_FOR_nothing;
int numregs = 0; int numregs = 0;
struct insn_chain *new;
/* A common failure mode if register status is not correct in the RTL /* 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 is for this routine to be called with a REGNO we didn't expect to
...@@ -589,7 +587,7 @@ insert_restore (chain, before_p, regno, maxrestore) ...@@ -589,7 +587,7 @@ insert_restore (chain, before_p, regno, maxrestore)
backwards to the single register case. */ backwards to the single register case. */
for (i = maxrestore; i > 0; i--) for (i = maxrestore; i > 0; i--)
{ {
int j, k; int j;
int ok = 1; int ok = 1;
if (regno_save_mem[regno][i] == 0) if (regno_save_mem[regno][i] == 0)
...@@ -605,24 +603,26 @@ insert_restore (chain, before_p, regno, maxrestore) ...@@ -605,24 +603,26 @@ insert_restore (chain, before_p, regno, maxrestore)
if (! ok) if (! ok)
continue; 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; numregs = i;
break; break;
} }
insert_one_insn (chain, before_p, code, pat); 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 */ /* Tell our callers how many extra registers we saved/restored */
return numregs - 1; return numregs - 1;
...@@ -636,10 +636,11 @@ insert_save (chain, before_p, regno, to_save) ...@@ -636,10 +636,11 @@ insert_save (chain, before_p, regno, to_save)
int regno; int regno;
HARD_REG_SET *to_save; HARD_REG_SET *to_save;
{ {
int i; int i, k;
rtx pat = NULL_RTX; rtx pat = NULL_RTX;
enum insn_code code = CODE_FOR_nothing; enum insn_code code = CODE_FOR_nothing;
int numregs = 0; int numregs = 0;
struct insn_chain *new;
/* A common failure mode if register status is not correct in the RTL /* 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 is for this routine to be called with a REGNO we didn't expect to
...@@ -657,7 +658,7 @@ insert_save (chain, before_p, regno, to_save) ...@@ -657,7 +658,7 @@ insert_save (chain, before_p, regno, to_save)
Work backwards to the single register case. */ Work backwards to the single register case. */
for (i = MOVE_MAX_WORDS; i > 0; i--) for (i = MOVE_MAX_WORDS; i > 0; i--)
{ {
int j, k; int j;
int ok = 1; int ok = 1;
if (regno_save_mem[regno][i] == 0) if (regno_save_mem[regno][i] == 0)
continue; continue;
...@@ -672,30 +673,30 @@ insert_save (chain, before_p, regno, to_save) ...@@ -672,30 +673,30 @@ insert_save (chain, before_p, regno, to_save)
if (! ok) if (! ok)
continue; 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; numregs = i;
break; break;
} }
insert_one_insn (chain, before_p, code, pat); 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 */ /* Tell our callers how many extra registers we saved/restored */
return numregs - 1; return numregs - 1;
} }
/* Emit a new caller-save insn and set the code. */ /* Emit a new caller-save insn and set the code. */
static void static struct insn_chain *
insert_one_insn (chain, before_p, code, pat) insert_one_insn (chain, before_p, code, pat)
struct insn_chain *chain; struct insn_chain *chain;
int before_p; int before_p;
...@@ -721,6 +722,8 @@ insert_one_insn (chain, before_p, code, pat) ...@@ -721,6 +722,8 @@ insert_one_insn (chain, before_p, code, pat)
new = new_insn_chain (); new = new_insn_chain ();
if (before_p) if (before_p)
{ {
rtx link;
new->prev = chain->prev; new->prev = chain->prev;
if (new->prev != 0) if (new->prev != 0)
new->prev->next = new; new->prev->next = new;
...@@ -732,8 +735,29 @@ insert_one_insn (chain, before_p, code, pat) ...@@ -732,8 +735,29 @@ insert_one_insn (chain, before_p, code, pat)
new->insn = emit_insn_before (pat, insn); new->insn = emit_insn_before (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved /* ??? It would be nice if we could exclude the already / still saved
registers from the live sets. */ registers from the live sets. */
COPY_REG_SET (new->live_before, chain->live_before); COPY_REG_SET (new->live_throughout, chain->live_throughout);
COPY_REG_SET (new->live_after, chain->live_before); /* 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)) if (chain->insn == BLOCK_HEAD (chain->block))
BLOCK_HEAD (chain->block) = new->insn; BLOCK_HEAD (chain->block) = new->insn;
} }
...@@ -747,8 +771,13 @@ insert_one_insn (chain, before_p, code, pat) ...@@ -747,8 +771,13 @@ insert_one_insn (chain, before_p, code, pat)
new->insn = emit_insn_after (pat, insn); new->insn = emit_insn_after (pat, insn);
/* ??? It would be nice if we could exclude the already / still saved /* ??? It would be nice if we could exclude the already / still saved
registers from the live sets, and observe REG_UNUSED notes. */ registers from the live sets, and observe REG_UNUSED notes. */
COPY_REG_SET (new->live_before, chain->live_after); COPY_REG_SET (new->live_throughout, chain->live_throughout);
COPY_REG_SET (new->live_after, chain->live_after); /* 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)) if (chain->insn == BLOCK_END (chain->block))
BLOCK_END (chain->block) = new->insn; BLOCK_END (chain->block) = new->insn;
} }
...@@ -756,4 +785,5 @@ insert_one_insn (chain, before_p, code, pat) ...@@ -756,4 +785,5 @@ insert_one_insn (chain, before_p, code, pat)
new->is_caller_save_insn = 1; new->is_caller_save_insn = 1;
INSN_CODE (new->insn) = code; INSN_CODE (new->insn) = code;
return new;
} }
...@@ -303,7 +303,8 @@ static void mark_reg_live_nc PROTO((int, enum machine_mode)); ...@@ -303,7 +303,8 @@ static void mark_reg_live_nc PROTO((int, enum machine_mode));
static void set_preference PROTO((rtx, rtx)); static void set_preference PROTO((rtx, rtx));
static void dump_conflicts PROTO((FILE *)); static void dump_conflicts PROTO((FILE *));
static void reg_becomes_live PROTO((rtx, rtx, void *)); static void reg_becomes_live PROTO((rtx, rtx, void *));
static void reg_dies PROTO((int, enum machine_mode)); static void reg_dies PROTO((int, enum machine_mode,
struct insn_chain *));
static void build_insn_chain PROTO((rtx)); static void build_insn_chain PROTO((rtx));
/* Perform allocation of pseudo-registers not allocated by local_alloc. /* Perform allocation of pseudo-registers not allocated by local_alloc.
...@@ -1693,13 +1694,13 @@ mark_elimination (from, to) ...@@ -1693,13 +1694,13 @@ mark_elimination (from, to)
current life information. */ current life information. */
static regset live_relevant_regs; static regset live_relevant_regs;
/* Record in live_relevant_regs that register REG became live. This /* Record in live_relevant_regs and REGS_SET that register REG became live.
is called via note_stores. */ This is called via note_stores. */
static void static void
reg_becomes_live (reg, setter, data) reg_becomes_live (reg, setter, regs_set)
rtx reg; rtx reg;
rtx setter ATTRIBUTE_UNUSED; rtx setter ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED; void *regs_set;
{ {
int regno; int regno;
...@@ -1714,26 +1715,44 @@ reg_becomes_live (reg, setter, data) ...@@ -1714,26 +1715,44 @@ reg_becomes_live (reg, setter, data)
{ {
int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg)); int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0) while (nregs-- > 0)
SET_REGNO_REG_SET (live_relevant_regs, regno++); {
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) else if (reg_renumber[regno] >= 0)
SET_REGNO_REG_SET (live_relevant_regs, regno); {
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. */ /* Record in live_relevant_regs that register REGNO died. */
static void static void
reg_dies (regno, mode) reg_dies (regno, mode, chain)
int regno; int regno;
enum machine_mode mode; enum machine_mode mode;
struct insn_chain *chain;
{ {
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
{ {
int nregs = HARD_REGNO_NREGS (regno, mode); int nregs = HARD_REGNO_NREGS (regno, mode);
while (nregs-- > 0) while (nregs-- > 0)
CLEAR_REGNO_REG_SET (live_relevant_regs, regno++); {
CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
if (! fixed_regs[regno])
SET_REGNO_REG_SET (chain->dead_or_set, regno);
regno++;
}
} }
else else
CLEAR_REGNO_REG_SET (live_relevant_regs, regno); {
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, /* Walk the insns of the current function and build reload_insn_chain,
...@@ -1778,8 +1797,6 @@ build_insn_chain (first) ...@@ -1778,8 +1797,6 @@ build_insn_chain (first)
c->insn = first; c->insn = first;
c->block = b; c->block = b;
COPY_REG_SET (c->live_before, live_relevant_regs);
if (GET_RTX_CLASS (GET_CODE (first)) == 'i') if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
{ {
rtx link; rtx link;
...@@ -1789,16 +1806,18 @@ build_insn_chain (first) ...@@ -1789,16 +1806,18 @@ build_insn_chain (first)
for (link = REG_NOTES (first); link; link = XEXP (link, 1)) for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD if (REG_NOTE_KIND (link) == REG_DEAD
&& GET_CODE (XEXP (link, 0)) == REG) && GET_CODE (XEXP (link, 0)) == REG)
reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0))); 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. */ /* Mark everything born in this instruction as live. */
note_stores (PATTERN (first), reg_becomes_live, NULL); note_stores (PATTERN (first), reg_becomes_live,
c->dead_or_set);
} }
else
/* Remember which registers are live at the end of the insn, before COPY_REG_SET (c->live_throughout, live_relevant_regs);
killing those with REG_UNUSED notes. */
COPY_REG_SET (c->live_after, live_relevant_regs);
if (GET_RTX_CLASS (GET_CODE (first)) == 'i') if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
{ {
...@@ -1809,7 +1828,8 @@ build_insn_chain (first) ...@@ -1809,7 +1828,8 @@ build_insn_chain (first)
for (link = REG_NOTES (first); link; link = XEXP (link, 1)) for (link = REG_NOTES (first); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_UNUSED if (REG_NOTE_KIND (link) == REG_UNUSED
&& GET_CODE (XEXP (link, 0)) == REG) && GET_CODE (XEXP (link, 0)) == REG)
reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0))); reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
c);
} }
} }
......
...@@ -224,12 +224,9 @@ struct insn_chain ...@@ -224,12 +224,9 @@ struct insn_chain
/* The rtx of the insn. */ /* The rtx of the insn. */
rtx insn; rtx insn;
/* Register life information: record all live hard registers, and all /* Register life information: record all live hard registers, and all
live pseudos that have a hard register. live pseudos that have a hard register. */
This information is recorded for the point immediately before the insn regset live_throughout;
(in live_before), and for the point within the insn at which all regset dead_or_set;
outputs have just been written to (in live_after). */
regset live_before;
regset live_after;
/* Copies of the global variables computed by find_reloads. */ /* Copies of the global variables computed by find_reloads. */
struct reload *rld; struct reload *rld;
......
...@@ -514,8 +514,8 @@ new_insn_chain () ...@@ -514,8 +514,8 @@ new_insn_chain ()
{ {
c = (struct insn_chain *) c = (struct insn_chain *)
obstack_alloc (&reload_obstack, sizeof (struct insn_chain)); obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack); c->live_throughout = OBSTACK_ALLOC_REG_SET (&reload_obstack);
c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack); c->dead_or_set = OBSTACK_ALLOC_REG_SET (&reload_obstack);
} }
else else
{ {
...@@ -1295,8 +1295,8 @@ maybe_fix_stack_asms () ...@@ -1295,8 +1295,8 @@ maybe_fix_stack_asms ()
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allowed, i)) if (TEST_HARD_REG_BIT (allowed, i))
{ {
CLEAR_REGNO_REG_SET (chain->live_before, i); CLEAR_REGNO_REG_SET (chain->live_throughout, i);
CLEAR_REGNO_REG_SET (chain->live_after, i); CLEAR_REGNO_REG_SET (chain->dead_or_set, i);
} }
} }
...@@ -1516,8 +1516,8 @@ order_regs_for_reload (chain) ...@@ -1516,8 +1516,8 @@ order_regs_for_reload (chain)
/* Test the various reasons why we can't use a register for /* Test the various reasons why we can't use a register for
spilling in this insn. */ spilling in this insn. */
if (fixed_regs[i] if (fixed_regs[i]
|| REGNO_REG_SET_P (chain->live_before, i) || REGNO_REG_SET_P (chain->live_throughout, i)
|| REGNO_REG_SET_P (chain->live_after, i)) || REGNO_REG_SET_P (chain->dead_or_set, i))
SET_HARD_REG_BIT (bad_spill_regs, i); SET_HARD_REG_BIT (bad_spill_regs, i);
} }
/* Now find out which pseudos are allocated to it, and update /* Now find out which pseudos are allocated to it, and update
...@@ -1525,12 +1525,12 @@ order_regs_for_reload (chain) ...@@ -1525,12 +1525,12 @@ order_regs_for_reload (chain)
CLEAR_REG_SET (&pseudos_counted); CLEAR_REG_SET (&pseudos_counted);
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_before, FIRST_PSEUDO_REGISTER, j, (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{ {
count_pseudo (j); count_pseudo (j);
}); });
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_after, FIRST_PSEUDO_REGISTER, j, (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
{ {
count_pseudo (j); count_pseudo (j);
}); });
...@@ -1645,12 +1645,12 @@ find_reg (chain, order, dumpfile) ...@@ -1645,12 +1645,12 @@ find_reg (chain, order, dumpfile)
rl->regno = best_reg; rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_before, FIRST_PSEUDO_REGISTER, j, (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
{ {
count_spilled_pseudo (best_reg, rl->nregs, j); count_spilled_pseudo (best_reg, rl->nregs, j);
}); });
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_after, FIRST_PSEUDO_REGISTER, j, (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
{ {
count_spilled_pseudo (best_reg, rl->nregs, j); count_spilled_pseudo (best_reg, rl->nregs, j);
}); });
...@@ -3489,13 +3489,13 @@ finish_spills (global, dumpfile) ...@@ -3489,13 +3489,13 @@ finish_spills (global, dumpfile)
for (chain = insns_need_reload; chain; chain = chain->next_need_reload) for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
{ {
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_before, FIRST_PSEUDO_REGISTER, i, (chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
{ {
ior_hard_reg_set (pseudo_forbidden_regs + i, ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs); &chain->used_spill_regs);
}); });
EXECUTE_IF_SET_IN_REG_SET EXECUTE_IF_SET_IN_REG_SET
(chain->live_after, FIRST_PSEUDO_REGISTER, i, (chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
{ {
ior_hard_reg_set (pseudo_forbidden_regs + i, ior_hard_reg_set (pseudo_forbidden_regs + i,
&chain->used_spill_regs); &chain->used_spill_regs);
...@@ -3528,22 +3528,22 @@ finish_spills (global, dumpfile) ...@@ -3528,22 +3528,22 @@ finish_spills (global, dumpfile)
HARD_REG_SET used_by_pseudos; HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2; HARD_REG_SET used_by_pseudos2;
AND_COMPL_REG_SET (chain->live_before, &spilled_pseudos); AND_COMPL_REG_SET (chain->live_throughout, &spilled_pseudos);
AND_COMPL_REG_SET (chain->live_after, &spilled_pseudos); AND_COMPL_REG_SET (chain->dead_or_set, &spilled_pseudos);
/* Mark any unallocated hard regs as available for spills. That /* Mark any unallocated hard regs as available for spills. That
makes inheritance work somewhat better. */ makes inheritance work somewhat better. */
if (chain->need_reload) if (chain->need_reload)
{ {
REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_before); REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_throughout);
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->live_after); REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->dead_or_set);
IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2); IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
/* Save the old value for the sanity test below. */ /* Save the old value for the sanity test below. */
COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs); 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_throughout);
compute_use_by_pseudos (&used_by_pseudos, chain->live_after); compute_use_by_pseudos (&used_by_pseudos, chain->dead_or_set);
COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos); COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs); AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
...@@ -5033,12 +5033,12 @@ choose_reload_regs_init (chain, save_reload_reg_rtx) ...@@ -5033,12 +5033,12 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
CLEAR_HARD_REG_SET (reg_used_in_insn); CLEAR_HARD_REG_SET (reg_used_in_insn);
{ {
HARD_REG_SET tmp; HARD_REG_SET tmp;
REG_SET_TO_HARD_REG_SET (tmp, chain->live_before); REG_SET_TO_HARD_REG_SET (tmp, chain->live_throughout);
IOR_HARD_REG_SET (reg_used_in_insn, tmp); IOR_HARD_REG_SET (reg_used_in_insn, tmp);
REG_SET_TO_HARD_REG_SET (tmp, chain->live_after); REG_SET_TO_HARD_REG_SET (tmp, chain->dead_or_set);
IOR_HARD_REG_SET (reg_used_in_insn, tmp); IOR_HARD_REG_SET (reg_used_in_insn, tmp);
compute_use_by_pseudos (&reg_used_in_insn, chain->live_before); compute_use_by_pseudos (&reg_used_in_insn, chain->live_throughout);
compute_use_by_pseudos (&reg_used_in_insn, chain->live_after); compute_use_by_pseudos (&reg_used_in_insn, chain->dead_or_set);
} }
for (i = 0; i < reload_n_operands; i++) for (i = 0; i < reload_n_operands; i++)
{ {
......
...@@ -129,12 +129,13 @@ static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode, ...@@ -129,12 +129,13 @@ static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode,
int, int, int)); int, int, int));
static void stupid_mark_refs PROTO((rtx, struct insn_chain *)); static void stupid_mark_refs PROTO((rtx, struct insn_chain *));
static void find_clobbered_regs PROTO((rtx, rtx, void *)); 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. */ /* For communication between stupid_life_analysis and find_clobbered_regs. */
static struct insn_chain *current_chain; static struct insn_chain *current_chain;
/* This function, called via note_stores, marks any hard registers that are /* 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 clobbered in an insn as being live in the live_throughout field
of the appropriate insn_chain structure. */ of the appropriate insn_chain structure. */
static void static void
...@@ -161,8 +162,7 @@ find_clobbered_regs (reg, setter, data) ...@@ -161,8 +162,7 @@ find_clobbered_regs (reg, setter, data)
nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg)); nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (nregs-- > 0) while (nregs-- > 0)
{ {
SET_REGNO_REG_SET (current_chain->live_after, regno); SET_REGNO_REG_SET (current_chain->live_throughout, regno++);
SET_REGNO_REG_SET (current_chain->live_before, regno++);
} }
} }
...@@ -285,7 +285,7 @@ stupid_life_analysis (f, nregs, file) ...@@ -285,7 +285,7 @@ stupid_life_analysis (f, nregs, file)
chain->insn = insn; chain->insn = insn;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regs_live[i]) if (regs_live[i])
SET_REGNO_REG_SET (chain->live_before, i); SET_REGNO_REG_SET (chain->live_throughout, i);
} }
/* Update which hard regs are currently live /* Update which hard regs are currently live
...@@ -336,10 +336,6 @@ stupid_life_analysis (f, nregs, file) ...@@ -336,10 +336,6 @@ stupid_life_analysis (f, nregs, file)
if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER) 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 /* The regs_live array doesn't say anything about hard registers
clobbered by this insn. So we need an extra pass over the clobbered by this insn. So we need an extra pass over the
pattern. */ pattern. */
...@@ -407,21 +403,14 @@ stupid_life_analysis (f, nregs, file) ...@@ -407,21 +403,14 @@ stupid_life_analysis (f, nregs, file)
continue; continue;
chain = reg_where_dead_chain[i]; chain = reg_where_dead_chain[i];
if (reg_where_dead[i] > INSN_SUID (chain->insn)) SET_REGNO_REG_SET (chain->dead_or_set, i);
SET_REGNO_REG_SET (chain->live_after, i);
while (INSN_SUID (chain->insn) > reg_where_born_exact[i]) while ((chain = chain->prev)
{ && INSN_SUID (chain->insn) > reg_where_born_exact[i])
SET_REGNO_REG_SET (chain->live_before, i); SET_REGNO_REG_SET (chain->live_throughout, 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] if (chain)
&& reg_where_born_clobber[i]) SET_REGNO_REG_SET (chain->dead_or_set, i);
SET_REGNO_REG_SET (chain->live_before, i);
} }
if (file) if (file)
...@@ -568,6 +557,32 @@ stupid_find_reg (call_preserved, class, mode, ...@@ -568,6 +557,32 @@ stupid_find_reg (call_preserved, class, mode,
return -1; 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 /* Walk X, noting all assignments and references to registers
and recording what they imply about life spans. and recording what they imply about life spans.
INSN is the current insn, supplied so we can find its suid. */ INSN is the current insn, supplied so we can find its suid. */
...@@ -597,11 +612,13 @@ stupid_mark_refs (x, chain) ...@@ -597,11 +612,13 @@ stupid_mark_refs (x, chain)
>= FIRST_PSEUDO_REGISTER)))) >= FIRST_PSEUDO_REGISTER))))
{ {
/* Register is being assigned. */ /* Register is being assigned. */
rtx reg = SET_DEST (x);
/* If setting a SUBREG, we treat the entire reg as being set. */ /* If setting a SUBREG, we treat the entire reg as being set. */
if (GET_CODE (SET_DEST (x)) == SUBREG) if (GET_CODE (SET_DEST (x)) == SUBREG)
regno = REGNO (SUBREG_REG (SET_DEST (x))); reg = SUBREG_REG (reg);
else
regno = REGNO (SET_DEST (x)); regno = REGNO (reg);
/* For hard regs, update the where-live info. */ /* For hard regs, update the where-live info. */
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
...@@ -609,15 +626,16 @@ stupid_mark_refs (x, chain) ...@@ -609,15 +626,16 @@ stupid_mark_refs (x, chain)
register int j register int j
= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x))); = HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
mark_hard_ref (reg, 0, chain);
while (--j >= 0) while (--j >= 0)
{ {
regs_ever_live[regno+j] = 1;
regs_live[regno+j] = 0;
/* The following line is for unused outputs; /* The following line is for unused outputs;
they do get stored even though never used again. */ they do get stored even though never used again. */
MARK_LIVE_AFTER (insn, regno+j); 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 /* When a hard reg is clobbered, mark it in use
just before this insn, so it is live all through. */ just before this insn, so it is live all through. */
if (code == CLOBBER && INSN_SUID (insn) > 0) if (code == CLOBBER && INSN_SUID (insn) > 0)
...@@ -706,15 +724,8 @@ stupid_mark_refs (x, chain) ...@@ -706,15 +724,8 @@ stupid_mark_refs (x, chain)
{ {
regno = REGNO (x); regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
{ /* Hard reg: mark it live for continuing scan of previous insns. */
/* Hard reg: mark it live for continuing scan of previous insns. */ mark_hard_ref (x, 1, chain);
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 else
{ {
/* Pseudo reg: record first use, last use and number of uses. */ /* Pseudo reg: record first use, last use and number of uses. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment