Commit 292f3869 by Richard Henderson Committed by Richard Henderson

flow.c (propagate_one_insn): Break out from propagate_block.

        * flow.c (propagate_one_insn): Break out from propagate_block.
        (init_propagate_block_info): Likewise.
        (free_propagate_block_info): Likewise.
        (propagate_block): Use them.  Export.
        * basic-block.h: Declare them all.

From-SVN: r33460
parent 7f8a79ba
2000-04-26 Richard Henderson <rth@cygnus.com>
* flow.c (propagate_one_insn): Break out from propagate_block.
(init_propagate_block_info): Likewise.
(free_propagate_block_info): Likewise.
(propagate_block): Use them. Export.
* basic-block.h: Declare them all.
2000-04-26 Richard Henderson <rth@cygnus.com>
* basic-block.h (life_analysis): Declare here ...
* output.h: ... not here.
* flow.c (life_analysis): Remove nregs parameter; replace
......
......@@ -431,6 +431,13 @@ extern void life_analysis PARAMS ((rtx, FILE *, int));
extern void update_life_info PARAMS ((sbitmap, enum update_life_extent,
int));
extern int count_or_remove_death_notes PARAMS ((sbitmap, int));
extern void propagate_block PARAMS ((basic_block, regset, regset, int));
struct propagate_block_info;
extern rtx propagate_one_insn PARAMS ((struct propagate_block_info *, rtx));
extern struct propagate_block_info *init_propagate_block_info
PARAMS ((basic_block, regset, regset, int));
extern void free_propagate_block_info PARAMS ((struct propagate_block_info *));
/* In lcm.c */
extern struct edge_list *pre_edge_lcm PARAMS ((FILE *, int, sbitmap *,
......
......@@ -329,8 +329,6 @@ static int set_phi_alternative_reg PARAMS ((rtx, int, int, void *));
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
static rtx propagate_block_delete_libcall PARAMS ((basic_block, rtx, rtx));
static void propagate_block PARAMS ((basic_block, regset,
regset, int));
static int insn_dead_p PARAMS ((struct propagate_block_info *,
rtx, int, rtx));
static int libcall_dead_p PARAMS ((struct propagate_block_info *,
......@@ -3267,89 +3265,30 @@ propagate_block_delete_libcall (bb, insn, note)
return before;
}
/* Compute the registers live at the beginning of a basic block BB from
those live at the end.
When called, REG_LIVE contains those live at the end. On return, it
contains those live at the beginning.
/* Update the life-status of regs for one insn. Return the previous insn. */
LOCAL_SET, if non-null, will be set with all registers killed by
this basic block. */
static void
propagate_block (bb, live, local_set, flags)
basic_block bb;
regset live;
regset local_set;
int flags;
rtx
propagate_one_insn (pbi, insn)
struct propagate_block_info *pbi;
rtx insn;
{
struct propagate_block_info pbi;
rtx insn, prev;
regset_head new_live_head, new_dead_head;
pbi.bb = bb;
pbi.reg_live = live;
pbi.mem_set_list = NULL_RTX;
pbi.local_set = local_set;
pbi.cc0_live = 0;
pbi.flags = flags;
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
pbi.reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
else
pbi.reg_next_use = NULL;
pbi.new_live = INITIALIZE_REG_SET (new_live_head);
pbi.new_dead = INITIALIZE_REG_SET (new_dead_head);
if (flags & PROP_REG_INFO)
{
register int i;
/* Process the regs live at the end of the block.
Mark them as not local to any one basic block. */
EXECUTE_IF_SET_IN_REG_SET (live, 0, i,
{
REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
});
}
/* Scan the block an insn at a time from end to beginning. */
for (insn = bb->end; ; insn = prev)
{
prev = PREV_INSN (insn);
if (GET_CODE (insn) == NOTE)
{
/* If this is a call to `setjmp' et al,
warn if any non-volatile datum is live. */
if ((flags & PROP_REG_INFO)
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
IOR_REG_SET (regs_live_at_setjmp, pbi.reg_live);
}
/* Update the life-status of regs for this insn.
First DEAD gets which regs are set in this insn
then LIVE gets which regs are used in this insn.
Then the regs live before the insn
are those live after, with DEAD regs turned off,
and then LIVE regs turned on. */
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
register int i;
rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
rtx prev = PREV_INSN (insn);
int flags = pbi->flags;
int insn_is_dead = 0;
int libcall_is_dead = 0;
rtx note;
int i;
if (! INSN_P (insn))
return prev;
note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
if (flags & PROP_SCAN_DEAD_CODE)
{
insn_is_dead = insn_dead_p (&pbi, PATTERN (insn), 0,
insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0,
REG_NOTES (insn));
libcall_is_dead = (insn_is_dead && note != 0
&& libcall_dead_p (&pbi, PATTERN (insn),
&& libcall_dead_p (pbi, PATTERN (insn),
note, insn));
}
......@@ -3377,22 +3316,22 @@ propagate_block (bb, live, local_set, flags)
{
if (libcall_is_dead)
{
prev = propagate_block_delete_libcall (bb, insn, note);
prev = propagate_block_delete_libcall (pbi->bb, insn, note);
insn = NEXT_INSN (prev);
}
else
propagate_block_delete_insn (bb, insn);
propagate_block_delete_insn (pbi->bb, insn);
/* CC0 is now known to be dead. Either this insn used it,
in which case it doesn't anymore, or clobbered it,
so the next insn can't use it. */
pbi.cc0_live = 0;
pbi->cc0_live = 0;
goto flushed;
return prev;
}
/* See if this is an increment or decrement that can be
merged into a following memory address. */
/* See if this is an increment or decrement that can be merged into
a following memory address. */
#ifdef AUTO_INC_DEC
{
register rtx x = single_set (insn);
......@@ -3410,25 +3349,24 @@ propagate_block (bb, live, local_set, flags)
If one is found, change the memory ref to a PRE_INC
or PRE_DEC, cancel this insn, and return 1.
Return 0 if nothing has been done. */
&& try_pre_increment_1 (&pbi, insn))
goto flushed;
&& try_pre_increment_1 (pbi, insn))
return prev;
}
#endif /* AUTO_INC_DEC */
CLEAR_REG_SET (pbi.new_live);
CLEAR_REG_SET (pbi.new_dead);
CLEAR_REG_SET (pbi->new_live);
CLEAR_REG_SET (pbi->new_dead);
/* If this is not the final pass, and this insn is copying the
value of a library call and it's dead, don't scan the
insns that perform the library call, so that the call's
arguments are not marked live. */
/* If this is not the final pass, and this insn is copying the value of
a library call and it's dead, don't scan the insns that perform the
library call, so that the call's arguments are not marked live. */
if (libcall_is_dead)
{
/* Record the death of the dest reg. */
mark_set_regs (&pbi, PATTERN (insn), insn);
mark_set_regs (pbi, PATTERN (insn), insn);
insn = XEXP (note, 0);
prev = PREV_INSN (insn);
return PREV_INSN (insn);
}
else if (GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx
......@@ -3442,37 +3380,19 @@ propagate_block (bb, live, local_set, flags)
;
else
{
/* Any regs live at the time of a call instruction
must not go in a register clobbered by calls.
Find all regs now live and record this for them. */
/* Any regs live at the time of a call instruction must not go
in a register clobbered by calls. Find all regs now live and
record this for them. */
if (GET_CODE (insn) == CALL_INSN
&& (flags & PROP_REG_INFO))
EXECUTE_IF_SET_IN_REG_SET (pbi.reg_live, 0, i,
if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
{ REG_N_CALLS_CROSSED (i)++; });
/* Record sets. Do this even for dead instructions,
since they would have killed the values if they hadn't
been deleted. */
mark_set_regs (&pbi, PATTERN (insn), insn);
/* If an insn doesn't use CC0, it becomes dead since we
assume that every insn clobbers it. So show it dead here;
mark_used_regs will set it live if it is referenced. */
pbi.cc0_live = 0;
/* Record sets. Do this even for dead instructions, since they
would have killed the values if they hadn't been deleted. */
mark_set_regs (pbi, PATTERN (insn), insn);
/* Record uses. */
if (! insn_is_dead)
mark_used_regs (&pbi, PATTERN (insn), NULL_RTX, insn);
/* Sometimes we may have inserted something before INSN
(such as a move) when we make an auto-inc. So ensure
we will scan those insns. */
#ifdef AUTO_INC_DEC
prev = PREV_INSN (insn);
#endif
if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
if (GET_CODE (insn) == CALL_INSN)
{
register int i;
rtx note, cond;
......@@ -3483,15 +3403,14 @@ propagate_block (bb, live, local_set, flags)
/* Non-constant calls clobber memory. */
if (! CONST_CALL_P (insn))
free_EXPR_LIST_list (&pbi.mem_set_list);
free_EXPR_LIST_list (&pbi->mem_set_list);
/* There may be extra registers to be clobbered. */
for (note = CALL_INSN_FUNCTION_USAGE (insn);
note;
note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == CLOBBER)
mark_set_1 (&pbi, XEXP (XEXP (note, 0), 0),
cond, insn);
mark_set_1 (pbi, XEXP (XEXP (note, 0), 0), cond, insn);
/* Calls change all call-used and global registers. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
......@@ -3499,54 +3418,167 @@ propagate_block (bb, live, local_set, flags)
&& ! fixed_regs[i])
{
int dummy;
mark_set_reg (&pbi, gen_rtx_REG (reg_raw_mode[i], i),
mark_set_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i),
cond, &dummy, &dummy);
}
}
/* If an insn doesn't use CC0, it becomes dead since we assume
that every insn clobbers it. So show it dead here;
mark_used_regs will set it live if it is referenced. */
pbi->cc0_live = 0;
/* Record uses. */
if (! insn_is_dead)
mark_used_regs (pbi, PATTERN (insn), NULL_RTX, insn);
/* Sometimes we may have inserted something before INSN (such as a move)
when we make an auto-inc. So ensure we will scan those insns. */
#ifdef AUTO_INC_DEC
prev = PREV_INSN (insn);
#endif
if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
{
register int i;
rtx note, cond;
cond = NULL_RTX;
if (GET_CODE (PATTERN (insn)) == COND_EXEC)
cond = COND_EXEC_TEST (PATTERN (insn));
/* Calls use their arguments. */
for (note = CALL_INSN_FUNCTION_USAGE (insn);
note;
note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == USE)
mark_used_regs (&pbi, XEXP (XEXP (note, 0), 0),
mark_used_regs (pbi, XEXP (XEXP (note, 0), 0),
cond, insn);
/* The stack ptr is used (honorarily) by a CALL insn. */
SET_REGNO_REG_SET (pbi.new_live, STACK_POINTER_REGNUM);
SET_REGNO_REG_SET (pbi->reg_live, STACK_POINTER_REGNUM);
/* Calls may also reference any of the global registers,
so they are made live. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
mark_used_reg (&pbi, gen_rtx_REG (reg_raw_mode[i], i),
mark_used_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i),
cond, insn);
}
}
/* Update reg_live for the registers killed and used. */
AND_COMPL_REG_SET (pbi.reg_live, pbi.new_dead);
IOR_REG_SET (pbi.reg_live, pbi.new_live);
AND_COMPL_REG_SET (pbi->reg_live, pbi->new_dead);
IOR_REG_SET (pbi->reg_live, pbi->new_live);
/* On final pass, update counts of how many insns in which
each reg is live. */
/* On final pass, update counts of how many insns in which each reg
is live. */
if (flags & PROP_REG_INFO)
EXECUTE_IF_SET_IN_REG_SET (pbi.reg_live, 0, i,
EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
{ REG_LIVE_LENGTH (i)++; });
return prev;
}
/* Initialize a propagate_block_info struct for public consumption.
Note that the structure itself is opaque to this file, but that
the user can use the regsets provided here. */
struct propagate_block_info *
init_propagate_block_info (bb, live, local_set, flags)
basic_block bb;
regset live;
regset local_set;
int flags;
{
struct propagate_block_info *pbi = xmalloc (sizeof(*pbi));
pbi->bb = bb;
pbi->reg_live = live;
pbi->mem_set_list = NULL_RTX;
pbi->local_set = local_set;
pbi->cc0_live = 0;
pbi->flags = flags;
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
pbi->reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
else
pbi->reg_next_use = NULL;
pbi->new_live = BITMAP_XMALLOC ();
pbi->new_dead = BITMAP_XMALLOC ();
return pbi;
}
/* Release a propagate_block_info struct. */
void
free_propagate_block_info (pbi)
struct propagate_block_info *pbi;
{
free_EXPR_LIST_list (&pbi->mem_set_list);
BITMAP_XFREE (pbi->new_live);
BITMAP_XFREE (pbi->new_dead);
if (pbi->reg_next_use)
free (pbi->reg_next_use);
free (pbi);
}
/* Compute the registers live at the beginning of a basic block BB from
those live at the end.
When called, REG_LIVE contains those live at the end. On return, it
contains those live at the beginning.
LOCAL_SET, if non-null, will be set with all registers killed by
this basic block. */
void
propagate_block (bb, live, local_set, flags)
basic_block bb;
regset live;
regset local_set;
int flags;
{
struct propagate_block_info *pbi;
rtx insn, prev;
pbi = init_propagate_block_info (bb, live, local_set, flags);
if (flags & PROP_REG_INFO)
{
register int i;
/* Process the regs live at the end of the block.
Mark them as not local to any one basic block. */
EXECUTE_IF_SET_IN_REG_SET (live, 0, i,
{ REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
}
flushed:
/* Scan the block an insn at a time from end to beginning. */
for (insn = bb->end; ; insn = prev)
{
/* If this is a call to `setjmp' et al, warn if any
non-volatile datum is live. */
if ((flags & PROP_REG_INFO)
&& GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
IOR_REG_SET (regs_live_at_setjmp, pbi->reg_live);
prev = propagate_one_insn (pbi, insn);
if (insn == bb->head)
break;
}
FREE_REG_SET (pbi.new_live);
FREE_REG_SET (pbi.new_dead);
free_EXPR_LIST_list (&pbi.mem_set_list);
if (pbi.reg_next_use)
free (pbi.reg_next_use);
free_propagate_block_info (pbi);
}
/* Return 1 if X (the body of an insn, or part of it) is just dead stores
(SET expressions whose destinations are registers dead after the insn).
NEEDED is the regset that says which regs are alive after the insn.
......
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