This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

flow.c rearrangement to support peep2 improvements


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.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]