diff options
author | Richard Henderson <rth@cygnus.com> | 2000-04-26 22:03:35 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2000-04-26 22:03:35 -0700 |
commit | 292f38694a71cd35b5eb3239e39bff7bf2b244e4 (patch) | |
tree | 90175835ba5241d36507c7d8a595c87194368f89 /gcc | |
parent | 7f8a79ba7ef4483fe205890213a5584c76683d45 (diff) | |
download | gcc-292f38694a71cd35b5eb3239e39bff7bf2b244e4.zip gcc-292f38694a71cd35b5eb3239e39bff7bf2b244e4.tar.gz gcc-292f38694a71cd35b5eb3239e39bff7bf2b244e4.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/basic-block.h | 7 | ||||
-rw-r--r-- | gcc/flow.c | 518 |
3 files changed, 290 insertions, 243 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d7d2fd5..5598f71 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 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 diff --git a/gcc/basic-block.h b/gcc/basic-block.h index f8da181..f9eb268 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -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,285 +3265,319 @@ 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; + rtx prev = PREV_INSN (insn); + int flags = pbi->flags; + int insn_is_dead = 0; + int libcall_is_dead = 0; + rtx note; + int i; - if (flags & (PROP_LOG_LINKS | PROP_AUTOINC)) - pbi.reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx)); - else - pbi.reg_next_use = NULL; + if (! INSN_P (insn)) + return prev; - pbi.new_live = INITIALIZE_REG_SET (new_live_head); - pbi.new_dead = INITIALIZE_REG_SET (new_dead_head); + 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, + REG_NOTES (insn)); + libcall_is_dead = (insn_is_dead && note != 0 + && libcall_dead_p (pbi, PATTERN (insn), + note, insn)); + } + + /* We almost certainly don't want to delete prologue or epilogue + instructions. Warn about probable compiler losage. */ + if (insn_is_dead + && reload_completed + && (((HAVE_epilogue || HAVE_prologue) + && prologue_epilogue_contains (insn)) + || (HAVE_sibcall_epilogue + && sibcall_epilogue_contains (insn)))) + { + if (flags & PROP_KILL_DEAD_CODE) + { + warning ("ICE: would have deleted prologue/epilogue insn"); + if (!inhibit_warnings) + debug_rtx (insn); + } + libcall_is_dead = insn_is_dead = 0; + } - if (flags & PROP_REG_INFO) + /* If an instruction consists of just dead store(s) on final pass, + delete it. */ + if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead) { - register int i; + if (libcall_is_dead) + { + prev = propagate_block_delete_libcall (pbi->bb, insn, note); + insn = NEXT_INSN (prev); + } + else + propagate_block_delete_insn (pbi->bb, insn); - /* 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; - }); + /* 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; + + return prev; } - /* Scan the block an insn at a time from end to beginning. */ + /* 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); + + /* Does this instruction increment or decrement a register? */ + if (!reload_completed + && (flags & PROP_AUTOINC) + && x != 0 + && GET_CODE (SET_DEST (x)) == REG + && (GET_CODE (SET_SRC (x)) == PLUS + || GET_CODE (SET_SRC (x)) == MINUS) + && XEXP (SET_SRC (x), 0) == SET_DEST (x) + && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT + /* Ok, look for a following memory ref we can combine with. + 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)) + return prev; + } +#endif /* AUTO_INC_DEC */ - for (insn = bb->end; ; insn = prev) + 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 (libcall_is_dead) + { + /* Record the death of the dest reg. */ + mark_set_regs (pbi, PATTERN (insn), insn); + + insn = XEXP (note, 0); + return PREV_INSN (insn); + } + else if (GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) == stack_pointer_rtx + && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS + && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx + && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT) + /* We have an insn to pop a constant amount off the stack. + (Such insns use PLUS regardless of the direction of the stack, + and any insn to adjust the stack by a constant is always a pop.) + These insns, if not dead stores, have no effect on life. */ + ; + else { - prev = PREV_INSN (insn); + /* 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) == NOTE) - { - /* If this is a call to `setjmp' et al, - warn if any non-volatile datum is live. */ + 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)++; }); - if ((flags & PROP_REG_INFO) - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP) - IOR_REG_SET (regs_live_at_setjmp, pbi.reg_live); + /* 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 (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)); + + /* Non-constant calls clobber memory. */ + if (! CONST_CALL_P (insn)) + 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); + + /* Calls change all call-used and global registers. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (call_used_regs[i] && ! global_regs[i] + && ! fixed_regs[i]) + { + int dummy; + mark_set_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i), + cond, &dummy, &dummy); + } } - /* 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. */ + /* 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); - else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + /* 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 = find_reg_note (insn, REG_RETVAL, NULL_RTX); - int insn_is_dead = 0; - int libcall_is_dead = 0; + 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), + cond, insn); + + /* The stack ptr is used (honorarily) by a CALL insn. */ + 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), + cond, insn); + } + } - if (flags & PROP_SCAN_DEAD_CODE) - { - 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), - note, 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); - /* We almost certainly don't want to delete prologue or epilogue - instructions. Warn about probable compiler losage. */ - if (insn_is_dead - && reload_completed - && (((HAVE_epilogue || HAVE_prologue) - && prologue_epilogue_contains (insn)) - || (HAVE_sibcall_epilogue - && sibcall_epilogue_contains (insn)))) - { - if (flags & PROP_KILL_DEAD_CODE) - { - warning ("ICE: would have deleted prologue/epilogue insn"); - if (!inhibit_warnings) - debug_rtx (insn); - } - libcall_is_dead = insn_is_dead = 0; - } + /* 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, + { REG_LIVE_LENGTH (i)++; }); - /* If an instruction consists of just dead store(s) on final pass, - delete it. */ - if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead) - { - if (libcall_is_dead) - { - prev = propagate_block_delete_libcall (bb, insn, note); - insn = NEXT_INSN (prev); - } - else - propagate_block_delete_insn (bb, insn); + return prev; +} - /* 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; +/* 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. */ - goto flushed; - } +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)); - /* 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); - - /* Does this instruction increment or decrement a register? */ - if (!reload_completed - && (flags & PROP_AUTOINC) - && x != 0 - && GET_CODE (SET_DEST (x)) == REG - && (GET_CODE (SET_SRC (x)) == PLUS - || GET_CODE (SET_SRC (x)) == MINUS) - && XEXP (SET_SRC (x), 0) == SET_DEST (x) - && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT - /* Ok, look for a following memory ref we can combine with. - 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; - } -#endif /* AUTO_INC_DEC */ + 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; - CLEAR_REG_SET (pbi.new_live); - CLEAR_REG_SET (pbi.new_dead); + if (flags & (PROP_LOG_LINKS | PROP_AUTOINC)) + pbi->reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx)); + else + pbi->reg_next_use = NULL; - /* 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); + pbi->new_live = BITMAP_XMALLOC (); + pbi->new_dead = BITMAP_XMALLOC (); - insn = XEXP (note, 0); - prev = PREV_INSN (insn); - } - else if (GET_CODE (PATTERN (insn)) == SET - && SET_DEST (PATTERN (insn)) == stack_pointer_rtx - && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS - && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx - && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT) - /* We have an insn to pop a constant amount off the stack. - (Such insns use PLUS regardless of the direction of the stack, - and any insn to adjust the stack by a constant is always a pop.) - These insns, if not dead stores, have no effect on life. */ - ; - 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. */ - - 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 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 + return pbi; +} - if (! insn_is_dead && GET_CODE (insn) == CALL_INSN) - { - register int i; - rtx note, cond; +/* Release a propagate_block_info struct. */ - cond = NULL_RTX; - if (GET_CODE (PATTERN (insn)) == COND_EXEC) - cond = COND_EXEC_TEST (PATTERN (insn)); +void +free_propagate_block_info (pbi) + struct propagate_block_info *pbi; +{ + free_EXPR_LIST_list (&pbi->mem_set_list); - /* Non-constant calls clobber memory. */ - if (! CONST_CALL_P (insn)) - free_EXPR_LIST_list (&pbi.mem_set_list); + BITMAP_XFREE (pbi->new_live); + BITMAP_XFREE (pbi->new_dead); - /* 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); - - /* Calls change all call-used and global registers. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (call_used_regs[i] && ! global_regs[i] - && ! fixed_regs[i]) - { - int dummy; - mark_set_reg (&pbi, gen_rtx_REG (reg_raw_mode[i], i), - cond, &dummy, &dummy); - } - - /* 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), - cond, insn); - - /* The stack ptr is used (honorarily) by a CALL insn. */ - SET_REGNO_REG_SET (pbi.new_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), - cond, insn); - } - } + if (pbi->reg_next_use) + free (pbi->reg_next_use); - /* 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); + 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; }); + } + + /* 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); - /* 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, - { REG_LIVE_LENGTH (i)++; }); - } - flushed: 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). |