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
This commit is contained in:
parent
4940cd6041
commit
285f3cf09a
@ -1,3 +1,32 @@
|
||||
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>
|
||||
|
||||
* rtlanal.c (reg_overlap_mentioned_p): Handle CONCAT.
|
||||
|
@ -90,8 +90,8 @@ static int insert_save PROTO((struct insn_chain *, int, int,
|
||||
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));
|
||||
static struct insn_chain *insert_one_insn PROTO((struct insn_chain *, int,
|
||||
enum insn_code, rtx));
|
||||
|
||||
/* Initialize for caller-save.
|
||||
|
||||
@ -373,17 +373,20 @@ save_call_clobbered_regs ()
|
||||
|
||||
if (code == CALL_INSN)
|
||||
{
|
||||
rtx x;
|
||||
int regno, nregs;
|
||||
int regno;
|
||||
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);
|
||||
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. */
|
||||
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);
|
||||
|
||||
@ -393,45 +396,6 @@ save_call_clobbered_regs ()
|
||||
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);
|
||||
@ -490,6 +454,39 @@ mark_set_regs (reg, setter, data)
|
||||
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)
|
||||
@ -568,10 +565,11 @@ insert_restore (chain, before_p, regno, maxrestore)
|
||||
int regno;
|
||||
int maxrestore;
|
||||
{
|
||||
int i;
|
||||
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
|
||||
@ -589,7 +587,7 @@ insert_restore (chain, before_p, regno, maxrestore)
|
||||
backwards to the single register case. */
|
||||
for (i = maxrestore; i > 0; i--)
|
||||
{
|
||||
int j, k;
|
||||
int j;
|
||||
int ok = 1;
|
||||
|
||||
if (regno_save_mem[regno][i] == 0)
|
||||
@ -605,24 +603,26 @@ insert_restore (chain, before_p, regno, maxrestore)
|
||||
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);
|
||||
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;
|
||||
@ -636,10 +636,11 @@ insert_save (chain, before_p, regno, to_save)
|
||||
int regno;
|
||||
HARD_REG_SET *to_save;
|
||||
{
|
||||
int i;
|
||||
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
|
||||
@ -657,7 +658,7 @@ insert_save (chain, before_p, regno, to_save)
|
||||
Work backwards to the single register case. */
|
||||
for (i = MOVE_MAX_WORDS; i > 0; i--)
|
||||
{
|
||||
int j, k;
|
||||
int j;
|
||||
int ok = 1;
|
||||
if (regno_save_mem[regno][i] == 0)
|
||||
continue;
|
||||
@ -672,30 +673,30 @@ insert_save (chain, before_p, regno, to_save)
|
||||
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);
|
||||
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 void
|
||||
static struct insn_chain *
|
||||
insert_one_insn (chain, before_p, code, pat)
|
||||
struct insn_chain *chain;
|
||||
int before_p;
|
||||
@ -721,6 +722,8 @@ insert_one_insn (chain, before_p, code, pat)
|
||||
new = new_insn_chain ();
|
||||
if (before_p)
|
||||
{
|
||||
rtx link;
|
||||
|
||||
new->prev = chain->prev;
|
||||
if (new->prev != 0)
|
||||
new->prev->next = new;
|
||||
@ -732,8 +735,29 @@ insert_one_insn (chain, before_p, code, pat)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@ -747,8 +771,13 @@ insert_one_insn (chain, before_p, code, pat)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@ -756,4 +785,5 @@ insert_one_insn (chain, before_p, code, pat)
|
||||
new->is_caller_save_insn = 1;
|
||||
|
||||
INSN_CODE (new->insn) = code;
|
||||
return new;
|
||||
}
|
||||
|
58
gcc/global.c
58
gcc/global.c
@ -303,7 +303,8 @@ static void mark_reg_live_nc PROTO((int, enum machine_mode));
|
||||
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 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.
|
||||
@ -1693,13 +1694,13 @@ mark_elimination (from, to)
|
||||
current life information. */
|
||||
static regset live_relevant_regs;
|
||||
|
||||
/* Record in live_relevant_regs that register REG became live. This
|
||||
is called via note_stores. */
|
||||
/* 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, data)
|
||||
reg_becomes_live (reg, setter, regs_set)
|
||||
rtx reg;
|
||||
rtx setter ATTRIBUTE_UNUSED;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
void *regs_set;
|
||||
{
|
||||
int regno;
|
||||
|
||||
@ -1714,26 +1715,44 @@ reg_becomes_live (reg, setter, data)
|
||||
{
|
||||
int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
|
||||
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)
|
||||
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. */
|
||||
static void
|
||||
reg_dies (regno, mode)
|
||||
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++);
|
||||
{
|
||||
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);
|
||||
{
|
||||
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,
|
||||
@ -1778,8 +1797,6 @@ build_insn_chain (first)
|
||||
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;
|
||||
@ -1789,16 +1806,18 @@ build_insn_chain (first)
|
||||
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)));
|
||||
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, NULL);
|
||||
note_stores (PATTERN (first), reg_becomes_live,
|
||||
c->dead_or_set);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
else
|
||||
COPY_REG_SET (c->live_throughout, live_relevant_regs);
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
|
||||
{
|
||||
@ -1809,7 +1828,8 @@ build_insn_chain (first)
|
||||
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)));
|
||||
reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
|
||||
c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,12 +224,9 @@ struct insn_chain
|
||||
/* 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;
|
||||
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;
|
||||
|
@ -514,8 +514,8 @@ new_insn_chain ()
|
||||
{
|
||||
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);
|
||||
c->live_throughout = OBSTACK_ALLOC_REG_SET (&reload_obstack);
|
||||
c->dead_or_set = OBSTACK_ALLOC_REG_SET (&reload_obstack);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1295,8 +1295,8 @@ maybe_fix_stack_asms ()
|
||||
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);
|
||||
CLEAR_REGNO_REG_SET (chain->live_throughout, i);
|
||||
CLEAR_REGNO_REG_SET (chain->dead_or_set, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1516,8 +1516,8 @@ order_regs_for_reload (chain)
|
||||
/* 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))
|
||||
|| 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
|
||||
@ -1525,12 +1525,12 @@ order_regs_for_reload (chain)
|
||||
CLEAR_REG_SET (&pseudos_counted);
|
||||
|
||||
EXECUTE_IF_SET_IN_REG_SET
|
||||
(chain->live_before, FIRST_PSEUDO_REGISTER, j,
|
||||
(chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
|
||||
{
|
||||
count_pseudo (j);
|
||||
});
|
||||
EXECUTE_IF_SET_IN_REG_SET
|
||||
(chain->live_after, FIRST_PSEUDO_REGISTER, j,
|
||||
(chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
|
||||
{
|
||||
count_pseudo (j);
|
||||
});
|
||||
@ -1645,12 +1645,12 @@ find_reg (chain, order, dumpfile)
|
||||
rl->regno = best_reg;
|
||||
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
@ -3489,13 +3489,13 @@ finish_spills (global, dumpfile)
|
||||
for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
|
||||
{
|
||||
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,
|
||||
&chain->used_spill_regs);
|
||||
});
|
||||
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,
|
||||
&chain->used_spill_regs);
|
||||
@ -3528,22 +3528,22 @@ finish_spills (global, dumpfile)
|
||||
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);
|
||||
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_before);
|
||||
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->live_after);
|
||||
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_before);
|
||||
compute_use_by_pseudos (&used_by_pseudos, chain->live_after);
|
||||
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);
|
||||
|
||||
@ -5033,12 +5033,12 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
|
||||
CLEAR_HARD_REG_SET (reg_used_in_insn);
|
||||
{
|
||||
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);
|
||||
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);
|
||||
compute_use_by_pseudos (®_used_in_insn, chain->live_before);
|
||||
compute_use_by_pseudos (®_used_in_insn, chain->live_after);
|
||||
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++)
|
||||
{
|
||||
|
83
gcc/stupid.c
83
gcc/stupid.c
@ -129,12 +129,13 @@ static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode,
|
||||
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_after and live_before fields
|
||||
clobbered in an insn as being live in the live_throughout field
|
||||
of the appropriate insn_chain structure. */
|
||||
|
||||
static void
|
||||
@ -161,8 +162,7 @@ find_clobbered_regs (reg, setter, data)
|
||||
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++);
|
||||
SET_REGNO_REG_SET (current_chain->live_throughout, regno++);
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ stupid_life_analysis (f, nregs, file)
|
||||
chain->insn = insn;
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; 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
|
||||
@ -336,10 +336,6 @@ stupid_life_analysis (f, nregs, file)
|
||||
|
||||
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. */
|
||||
@ -407,21 +403,14 @@ stupid_life_analysis (f, nregs, file)
|
||||
continue;
|
||||
|
||||
chain = reg_where_dead_chain[i];
|
||||
if (reg_where_dead[i] > INSN_SUID (chain->insn))
|
||||
SET_REGNO_REG_SET (chain->live_after, i);
|
||||
SET_REGNO_REG_SET (chain->dead_or_set, 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);
|
||||
}
|
||||
while ((chain = chain->prev)
|
||||
&& INSN_SUID (chain->insn) > reg_where_born_exact[i])
|
||||
SET_REGNO_REG_SET (chain->live_throughout, 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 (chain)
|
||||
SET_REGNO_REG_SET (chain->dead_or_set, i);
|
||||
}
|
||||
|
||||
if (file)
|
||||
@ -568,6 +557,32 @@ stupid_find_reg (call_preserved, class, mode,
|
||||
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. */
|
||||
@ -597,11 +612,13 @@ stupid_mark_refs (x, chain)
|
||||
>= 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)
|
||||
regno = REGNO (SUBREG_REG (SET_DEST (x)));
|
||||
else
|
||||
regno = REGNO (SET_DEST (x));
|
||||
reg = SUBREG_REG (reg);
|
||||
|
||||
regno = REGNO (reg);
|
||||
|
||||
/* For hard regs, update the where-live info. */
|
||||
if (regno < FIRST_PSEUDO_REGISTER)
|
||||
@ -609,15 +626,16 @@ stupid_mark_refs (x, chain)
|
||||
register int j
|
||||
= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
|
||||
|
||||
mark_hard_ref (reg, 0, chain);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
@ -706,15 +724,8 @@ stupid_mark_refs (x, chain)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* 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. */
|
||||
|
Loading…
Reference in New Issue
Block a user