flow.c rearrangement to support peep2 improvements
Zack Weinberg
zack@wolery.cumb.org
Sun Apr 23 22:08:00 GMT 2000
I have a patch that gets rid of peep2's use of resource.c, which
causes a quadratic bottleneck when lots of peepholes trigger in one
block. That patch needs some work. This chunk of it, however, does
not - it simply moves the guts of propagate_block to a separate
function that can be called independently. There should be no
behavioral changes whatsoever.
zw
* flow.c (propagate_block): Split out per-insn logic to new
function, propagate_block_1.
(calc_live_before): New interface.
* basic-block.h: Prototype calc_live_before.
===================================================================
Index: basic-block.h
--- basic-block.h 2000/04/17 16:48:59 1.62
+++ basic-block.h 2000/04/24 05:06:21
@@ -453,6 +453,7 @@ extern void expected_value_to_br_prob PA
/* In flow.c */
extern void reorder_basic_blocks PARAMS ((void));
+extern void calc_live_before PARAMS ((basic_block, rtx, regset));
extern void dump_bb PARAMS ((basic_block, FILE *));
extern void debug_bb PARAMS ((basic_block));
extern void debug_bb_n PARAMS ((int));
===================================================================
Index: flow.c
--- flow.c 2000/04/22 18:47:52 1.255
+++ flow.c 2000/04/24 05:06:23
@@ -334,6 +334,8 @@ static int set_phi_alternative_reg
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 rtx propagate_block_1 PARAMS ((struct propagate_block_info *,
+ rtx));
static void propagate_block PARAMS ((basic_block, regset,
regset, int));
static int insn_dead_p PARAMS ((struct propagate_block_info *,
@@ -3286,6 +3288,206 @@ propagate_block_delete_libcall (bb, insn
return before;
}
+/* Subroutine of propagate_block, separated for readability and also
+ so it can be used from calc_live_before. Given the live registers
+ after some insn, compute the live registers before that insn. May
+ also delete dead code, convert to autoinc/autodec, etc. depending
+ on the flags. Returns the previous 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. */
+static rtx
+propagate_block_1 (pbi, insn)
+ struct propagate_block_info *pbi;
+ rtx insn;
+{
+ int i;
+ rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+ int insn_is_dead = 0;
+ int libcall_is_dead = 0;
+ int flags = pbi->flags;
+
+ 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 an instruction consists of just dead store(s) on final pass,
+ delete it. */
+ if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
+ {
+ /* 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;
+
+ if (libcall_is_dead)
+ return propagate_block_delete_libcall (pbi->bb, insn, note);
+ else
+ {
+ rtx prev = PREV_INSN (insn);
+ propagate_block_delete_insn (pbi->bb, insn);
+ return prev;
+ }
+ }
+
+ /* See if this is an increment or decrement that can be
+ merged into a following memory address. */
+#ifdef AUTO_INC_DEC
+ if (!reload_completed && (flags & PROP_AUTOINC))
+ {
+ rtx x = single_set (insn);
+
+ /* Does this instruction increment or decrement a register? */
+ if (x != NULL_RTX)
+ {
+ rtx src = SET_SRC (x);
+ rtx dest = SET_DEST (x);
+ if (GET_CODE (dest) == REG
+ && (GET_CODE (src) == PLUS || GET_CODE (dest) == MINUS)
+ && XEXP (src, 0) == dest
+ && GET_CODE (XEXP (src, 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. */
+ if (try_pre_increment_1 (pbi, insn))
+ return PREV_INSN (insn);
+ }
+ }
+ }
+#endif /* AUTO_INC_DEC */
+
+ 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);
+ }
+ 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);
+
+ 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));
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+ }
+
+
+ /* 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);
+
+ /* 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)++; });
+
+ return PREV_INSN (insn);
+}
+
/* Compute the registers live at the beginning of a basic block BB from
those live at the end.
@@ -3337,10 +3539,9 @@ propagate_block (bb, live, local_set, fl
for (insn = bb->end; ; insn = prev)
{
- prev = PREV_INSN (insn);
-
if (GET_CODE (insn) == NOTE)
{
+ prev = PREV_INSN (insn);
/* If this is a call to `setjmp' et al,
warn if any non-volatile datum is live. */
@@ -3348,211 +3549,11 @@ propagate_block (bb, live, local_set, fl
&& 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 libcall_is_dead = 0;
-
- 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 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);
-
- /* 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;
-
- goto flushed;
- }
-
- /* 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 */
-
- 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);
- 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
-
- 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));
-
- /* 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);
- }
-
- /* 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);
- }
- }
+ prev = propagate_block_1 (&pbi, insn);
+ else
+ prev = PREV_INSN (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);
-
- /* 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;
}
@@ -3832,6 +3833,28 @@ regno_clobbered_at_setjmp (regno)
return ((REG_N_SETS (regno) > 1
|| REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, regno))
&& REGNO_REG_SET_P (regs_live_at_setjmp, regno));
+}
+
+/* Given a basic block, an insn, and the set of regs live after that insn,
+ determine the regs live before that insn. This is essentially a public
+ interface to propagate_block_1. */
+
+void
+calc_live_before (bb, insn, live)
+ basic_block bb;
+ rtx insn;
+ regset live;
+{
+ struct propagate_block_info pbi;
+
+ pbi.bb = bb;
+ pbi.reg_live = live;
+ pbi.mem_set_list = NULL_RTX;
+ pbi.local_set = 0;
+ pbi.cc0_live = 0;
+ pbi.flags = 0;
+
+ propagate_block_1 (&pbi, insn);
}
/* INSN references memory, possibly using autoincrement addressing modes.
More information about the Gcc-patches
mailing list