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> 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 ... * basic-block.h (life_analysis): Declare here ...
* output.h: ... not here. * output.h: ... not here.
* flow.c (life_analysis): Remove nregs parameter; replace * flow.c (life_analysis): Remove nregs parameter; replace
......
...@@ -431,6 +431,13 @@ extern void life_analysis PARAMS ((rtx, FILE *, int)); ...@@ -431,6 +431,13 @@ extern void life_analysis PARAMS ((rtx, FILE *, int));
extern void update_life_info PARAMS ((sbitmap, enum update_life_extent, extern void update_life_info PARAMS ((sbitmap, enum update_life_extent,
int)); int));
extern int count_or_remove_death_notes PARAMS ((sbitmap, 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 */ /* In lcm.c */
extern struct edge_list *pre_edge_lcm PARAMS ((FILE *, int, sbitmap *, 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 *)); ...@@ -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 calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
static void propagate_block_delete_insn PARAMS ((basic_block, rtx)); static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
static rtx propagate_block_delete_libcall PARAMS ((basic_block, rtx, 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 *, static int insn_dead_p PARAMS ((struct propagate_block_info *,
rtx, int, rtx)); rtx, int, rtx));
static int libcall_dead_p PARAMS ((struct propagate_block_info *, static int libcall_dead_p PARAMS ((struct propagate_block_info *,
...@@ -3267,89 +3265,30 @@ propagate_block_delete_libcall (bb, insn, note) ...@@ -3267,89 +3265,30 @@ propagate_block_delete_libcall (bb, insn, note)
return before; return before;
} }
/* Compute the registers live at the beginning of a basic block BB from /* Update the life-status of regs for one insn. Return the previous insn. */
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 rtx
this basic block. */ propagate_one_insn (pbi, insn)
struct propagate_block_info *pbi;
static void rtx insn;
propagate_block (bb, live, local_set, flags)
basic_block bb;
regset live;
regset local_set;
int flags;
{ {
struct propagate_block_info pbi; rtx prev = PREV_INSN (insn);
rtx insn, prev; int flags = pbi->flags;
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);
int insn_is_dead = 0; int insn_is_dead = 0;
int libcall_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) 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)); REG_NOTES (insn));
libcall_is_dead = (insn_is_dead && note != 0 libcall_is_dead = (insn_is_dead && note != 0
&& libcall_dead_p (&pbi, PATTERN (insn), && libcall_dead_p (pbi, PATTERN (insn),
note, insn)); note, insn));
} }
...@@ -3377,22 +3316,22 @@ propagate_block (bb, live, local_set, flags) ...@@ -3377,22 +3316,22 @@ propagate_block (bb, live, local_set, flags)
{ {
if (libcall_is_dead) 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); insn = NEXT_INSN (prev);
} }
else 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, /* CC0 is now known to be dead. Either this insn used it,
in which case it doesn't anymore, or clobbered it, in which case it doesn't anymore, or clobbered it,
so the next insn can't use 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 /* See if this is an increment or decrement that can be merged into
merged into a following memory address. */ a following memory address. */
#ifdef AUTO_INC_DEC #ifdef AUTO_INC_DEC
{ {
register rtx x = single_set (insn); register rtx x = single_set (insn);
...@@ -3410,25 +3349,24 @@ propagate_block (bb, live, local_set, flags) ...@@ -3410,25 +3349,24 @@ propagate_block (bb, live, local_set, flags)
If one is found, change the memory ref to a PRE_INC If one is found, change the memory ref to a PRE_INC
or PRE_DEC, cancel this insn, and return 1. or PRE_DEC, cancel this insn, and return 1.
Return 0 if nothing has been done. */ Return 0 if nothing has been done. */
&& try_pre_increment_1 (&pbi, insn)) && try_pre_increment_1 (pbi, insn))
goto flushed; return prev;
} }
#endif /* AUTO_INC_DEC */ #endif /* AUTO_INC_DEC */
CLEAR_REG_SET (pbi.new_live); CLEAR_REG_SET (pbi->new_live);
CLEAR_REG_SET (pbi.new_dead); CLEAR_REG_SET (pbi->new_dead);
/* If this is not the final pass, and this insn is copying the /* If this is not the final pass, and this insn is copying the value of
value of a library call and it's dead, don't scan the a library call and it's dead, don't scan the insns that perform the
insns that perform the library call, so that the call's library call, so that the call's arguments are not marked live. */
arguments are not marked live. */
if (libcall_is_dead) if (libcall_is_dead)
{ {
/* Record the death of the dest reg. */ /* 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); insn = XEXP (note, 0);
prev = PREV_INSN (insn); return PREV_INSN (insn);
} }
else if (GET_CODE (PATTERN (insn)) == SET else if (GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx && SET_DEST (PATTERN (insn)) == stack_pointer_rtx
...@@ -3442,37 +3380,19 @@ propagate_block (bb, live, local_set, flags) ...@@ -3442,37 +3380,19 @@ propagate_block (bb, live, local_set, flags)
; ;
else else
{ {
/* Any regs live at the time of a call instruction /* Any regs live at the time of a call instruction must not go
must not go in a register clobbered by calls. in a register clobbered by calls. Find all regs now live and
Find all regs now live and record this for them. */ record this for them. */
if (GET_CODE (insn) == CALL_INSN if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
&& (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_N_CALLS_CROSSED (i)++; }); { REG_N_CALLS_CROSSED (i)++; });
/* Record sets. Do this even for dead instructions, /* Record sets. Do this even for dead instructions, since they
since they would have killed the values if they hadn't would have killed the values if they hadn't been deleted. */
been deleted. */ mark_set_regs (pbi, PATTERN (insn), insn);
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 uses. */ if (GET_CODE (insn) == CALL_INSN)
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; register int i;
rtx note, cond; rtx note, cond;
...@@ -3483,15 +3403,14 @@ propagate_block (bb, live, local_set, flags) ...@@ -3483,15 +3403,14 @@ propagate_block (bb, live, local_set, flags)
/* Non-constant calls clobber memory. */ /* Non-constant calls clobber memory. */
if (! CONST_CALL_P (insn)) 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. */ /* There may be extra registers to be clobbered. */
for (note = CALL_INSN_FUNCTION_USAGE (insn); for (note = CALL_INSN_FUNCTION_USAGE (insn);
note; note;
note = XEXP (note, 1)) note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == CLOBBER) if (GET_CODE (XEXP (note, 0)) == CLOBBER)
mark_set_1 (&pbi, XEXP (XEXP (note, 0), 0), mark_set_1 (pbi, XEXP (XEXP (note, 0), 0), cond, insn);
cond, insn);
/* Calls change all call-used and global registers. */ /* Calls change all call-used and global registers. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
...@@ -3499,54 +3418,167 @@ propagate_block (bb, live, local_set, flags) ...@@ -3499,54 +3418,167 @@ propagate_block (bb, live, local_set, flags)
&& ! fixed_regs[i]) && ! fixed_regs[i])
{ {
int dummy; 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); 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. */ /* Calls use their arguments. */
for (note = CALL_INSN_FUNCTION_USAGE (insn); for (note = CALL_INSN_FUNCTION_USAGE (insn);
note; note;
note = XEXP (note, 1)) note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == USE) 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); cond, insn);
/* The stack ptr is used (honorarily) by a CALL 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, /* Calls may also reference any of the global registers,
so they are made live. */ so they are made live. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[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); cond, insn);
} }
} }
/* Update reg_live for the registers killed and used. */ /* Update reg_live for the registers killed and used. */
AND_COMPL_REG_SET (pbi.reg_live, pbi.new_dead); AND_COMPL_REG_SET (pbi->reg_live, pbi->new_dead);
IOR_REG_SET (pbi.reg_live, pbi.new_live); IOR_REG_SET (pbi->reg_live, pbi->new_live);
/* On final pass, update counts of how many insns in which /* On final pass, update counts of how many insns in which each reg
each reg is live. */ is live. */
if (flags & PROP_REG_INFO) 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)++; }); { 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) if (insn == bb->head)
break; break;
} }
FREE_REG_SET (pbi.new_live); free_propagate_block_info (pbi);
FREE_REG_SET (pbi.new_dead);
free_EXPR_LIST_list (&pbi.mem_set_list);
if (pbi.reg_next_use)
free (pbi.reg_next_use);
} }
/* Return 1 if X (the body of an insn, or part of it) is just dead stores /* 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). (SET expressions whose destinations are registers dead after the insn).
NEEDED is the regset that says which regs are alive 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