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]
Other format: [Raw text]

Re: CFG branch merge 8 - SMALL_REGISTER_CLASSES versus profiling



Hi,
When profiling, we emit instructions on the edges.  In case the basic
block is broken by possibly trapping call, we emit insn right after stall
breaking SMALL_REGISTER_CLASSES machines.
We partly handle this in emit_call_edges for the fake edges by we fail
to do so for EH edges and similar stuff.

This patch, made by Zdenek, teach commit_edge_insertion to place the code
properly that is the only working sollution we were able to find :(

Bootstrapped/regtested i386
Honza

Don Feb 28 18:17:10 CET 2002  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
			      Jan Hubicka  <jh@suse.cz>

	* basic-block.h (commit_edge_insertions_watch): Declare.
	* cfgrtl.c (commit_one_edge_insertion): Support watching of calls.
	(commit_edge_insertions): Update.
	(commit_edge_insertions_watch_calls): New.

Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/basic-block.h,v
retrieving revision 1.135
diff -c -3 -p -r1.135 basic-block.h
*** basic-block.h	2002/02/28 10:10:55	1.135
--- basic-block.h	2002/02/28 17:09:41
*************** extern void free_basic_block_vars	PARAMS
*** 295,301 ****
--- 295,304 ----
  extern edge split_block			PARAMS ((basic_block, rtx));
  extern basic_block split_edge		PARAMS ((edge));
  extern void insert_insn_on_edge		PARAMS ((rtx, edge));
+ 
  extern void commit_edge_insertions	PARAMS ((void));
+ extern void commit_edge_insertions_watch_calls	PARAMS ((void));
+ 
  extern void remove_fake_edges		PARAMS ((void));
  extern void add_noreturn_fake_exit_edges	PARAMS ((void));
  extern void connect_infinite_loops_to_exit	PARAMS ((void));
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cfgrtl.c,v
retrieving revision 1.31
diff -c -3 -p -r1.31 cfgrtl.c
*** cfgrtl.c	2002/02/28 11:03:15	1.31
--- cfgrtl.c	2002/02/28 17:09:42
*************** rtx tail_recursion_label_list;
*** 74,80 ****
  
  static int can_delete_note_p		PARAMS ((rtx));
  static int can_delete_label_p		PARAMS ((rtx));
! static void commit_one_edge_insertion	PARAMS ((edge));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static rtx last_loop_beg_note		PARAMS ((rtx));
  static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
--- 74,80 ----
  
  static int can_delete_note_p		PARAMS ((rtx));
  static int can_delete_label_p		PARAMS ((rtx));
! static void commit_one_edge_insertion	PARAMS ((edge, int));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static rtx last_loop_beg_note		PARAMS ((rtx));
  static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
*************** insert_insn_on_edge (pattern, e)
*** 1271,1278 ****
  /* Update the CFG for the instructions queued on edge E.  */
  
  static void
! commit_one_edge_insertion (e)
       edge e;
  {
    rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
    basic_block bb;
--- 1271,1279 ----
  /* Update the CFG for the instructions queued on edge E.  */
  
  static void
! commit_one_edge_insertion (e, watch_calls)
       edge e;
+      int watch_calls;
  {
    rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
    basic_block bb;
*************** commit_one_edge_insertion (e)
*** 1281,1343 ****
    insns = e->insns;
    e->insns = NULL_RTX;
  
!   /* Figure out where to put these things.  If the destination has
!      one predecessor, insert there.  Except for the exit block.  */
!   if (e->dest->pred->pred_next == NULL
!       && e->dest != EXIT_BLOCK_PTR)
!     {
!       bb = e->dest;
! 
!       /* Get the location correct wrt a code label, and "nice" wrt
! 	 a basic block note, and before everything else.  */
!       tmp = bb->head;
!       if (GET_CODE (tmp) == CODE_LABEL)
! 	tmp = NEXT_INSN (tmp);
!       if (NOTE_INSN_BASIC_BLOCK_P (tmp))
! 	tmp = NEXT_INSN (tmp);
!       if (tmp == bb->head)
! 	before = tmp;
!       else
! 	after = PREV_INSN (tmp);
      }
  
!   /* If the source has one successor and the edge is not abnormal,
!      insert there.  Except for the entry block.  */
!   else if ((e->flags & EDGE_ABNORMAL) == 0
! 	   && e->src->succ->succ_next == NULL
! 	   && e->src != ENTRY_BLOCK_PTR)
!     {
!       bb = e->src;
! 
!       /* It is possible to have a non-simple jump here.  Consider a target
! 	 where some forms of unconditional jumps clobber a register.  This
! 	 happens on the fr30 for example.
! 
! 	 We know this block has a single successor, so we can just emit
! 	 the queued insns before the jump.  */
!       if (GET_CODE (bb->end) == JUMP_INSN)
! 	for (before = bb->end;
! 	     GET_CODE (PREV_INSN (before)) == NOTE
! 	     && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
! 	     before = PREV_INSN (before))
! 	  ;
!       else
  	{
! 	  /* We'd better be fallthru, or we've lost track of what's what.  */
! 	  if ((e->flags & EDGE_FALLTHRU) == 0)
! 	    abort ();
  
  	  after = bb->end;
  	}
      }
  
-   /* Otherwise we must split the edge.  */
-   else
-     {
-       bb = split_edge (e);
-       after = bb->end;
-     }
- 
    /* Now that we've found the spot, do the insertion.  */
  
    if (before)
--- 1282,1395 ----
    insns = e->insns;
    e->insns = NULL_RTX;
  
!   /* Special case -- avoid inserting code between call and storing
!      its return value.  */
!   if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next)
!     {
!       rtx insert_after = e->src->end;
!       if (insert_after
! 	  && SMALL_REGISTER_CLASSES
! 	  && GET_CODE (insert_after) == CALL_INSN
! 	  && (GET_CODE (PATTERN (insert_after)) == SET
! 	      || (GET_CODE (PATTERN (insert_after)) == PARALLEL
! 		  && GET_CODE (XVECEXP (PATTERN (insert_after), 0, 0)) ==
! 		  SET)))
! 	{
! 	  rtx return_reg;
! 	  rtx next_insert_after = next_nonnote_insn (insert_after);
! 	  rtx set;
! 
! 	  /* The first insn after the call may be a stack pop, skip it.  */
! 	  if (next_insert_after
! 	      && GET_CODE (next_insert_after) == INSN
! 	      && (set = single_set (next_insert_after))
! 	      && GET_CODE (set) == SET
! 	      && SET_DEST (set) == stack_pointer_rtx)
! 	    next_insert_after = next_nonnote_insn (next_insert_after);
! 	  if (next_insert_after && GET_CODE (next_insert_after) == INSN)
! 	    {
! 	      if (GET_CODE (PATTERN (insert_after)) == SET)
! 		return_reg = SET_DEST (PATTERN (insert_after));
! 	      else
! 		return_reg =
! 		  SET_DEST (XVECEXP (PATTERN (insert_after), 0, 0));
! 
! 	      /* Now, NEXT_INSERT_AFTER may be an instruction that uses the
! 	         return value.  However, it could also be something else,
! 	         like a CODE_LABEL, so check that the code is INSN.  */
! 	      if (next_insert_after
! 		  && GET_CODE (next_insert_after) == INSN
! 		  && reg_referenced_p (return_reg,
! 				       PATTERN (next_insert_after)))
! 		insert_after = next_insert_after;
! 	    }
! 	  if (insert_after == e->src->end)
! 	    after = e->dest->head;
! 	  else
! 	    after = insert_after;
! 	  bb = e->dest;
! 	}
      }
+   if (!before && !after)
+     {
+       /* Figure out where to put these things.  If the destination has
+          one predecessor, insert there.  Except for the exit block.  */
+       if (e->dest->pred->pred_next == NULL && e->dest != EXIT_BLOCK_PTR)
+ 	{
+ 	  bb = e->dest;
  
! 	  /* Get the location correct wrt a code label, and "nice" wrt
! 	     a basic block note, and before everything else.  */
! 	  tmp = bb->head;
! 	  if (GET_CODE (tmp) == CODE_LABEL)
! 	    tmp = NEXT_INSN (tmp);
! 	  if (NOTE_INSN_BASIC_BLOCK_P (tmp))
! 	    tmp = NEXT_INSN (tmp);
! 	  if (tmp == bb->head)
! 	    before = tmp;
! 	  else if (tmp)
! 	    after = PREV_INSN (tmp);
! 	  else
! 	    after = get_last_insn ();
! 	}
! 
!       /* If the source has one successor and the edge is not abnormal,
!          insert there.  Except for the entry block.  */
!       else if ((e->flags & EDGE_ABNORMAL) == 0
! 	       && e->src->succ->succ_next == NULL
! 	       && e->src != ENTRY_BLOCK_PTR)
  	{
! 	  bb = e->src;
! 
! 	  /* It is possible to have a non-simple jump here.  Consider a target
! 	     where some forms of unconditional jumps clobber a register.  This
! 	     happens on the fr30 for example.
! 
! 	     We know this block has a single successor, so we can just emit
! 	     the queued insns before the jump.  */
! 	  if (GET_CODE (bb->end) == JUMP_INSN)
! 	    for (before = bb->end;
! 		 GET_CODE (PREV_INSN (before)) == NOTE
! 		 && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
! 		 NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
! 	      ;
! 	  else
! 	    {
! 	      /* We'd better be fallthru, or we've lost track of what's what.  */
! 	      if ((e->flags & EDGE_FALLTHRU) == 0)
! 		abort ();
  
+ 	      after = bb->end;
+ 	    }
+ 	}
+       /* Otherwise we must split the edge.  */
+       else
+ 	{
+ 	  bb = split_edge (e);
  	  after = bb->end;
  	}
      }
  
    /* Now that we've found the spot, do the insertion.  */
  
    if (before)
*************** commit_one_edge_insertion (e)
*** 1352,1364 ****
      {
        /* ??? Remove all outgoing edges from BB and add one for EXIT.
           This is not currently a problem because this only happens
! 	 for the (single) epilogue, which already has a fallthru edge
! 	 to EXIT.  */
  
        e = bb->succ;
        if (e->dest != EXIT_BLOCK_PTR
! 	  || e->succ_next != NULL
! 	  || (e->flags & EDGE_FALLTHRU) == 0)
  	abort ();
  
        e->flags &= ~EDGE_FALLTHRU;
--- 1404,1415 ----
      {
        /* ??? Remove all outgoing edges from BB and add one for EXIT.
           This is not currently a problem because this only happens
!          for the (single) epilogue, which already has a fallthru edge
!          to EXIT.  */
  
        e = bb->succ;
        if (e->dest != EXIT_BLOCK_PTR
! 	  || e->succ_next != NULL || (e->flags & EDGE_FALLTHRU) == 0)
  	abort ();
  
        e->flags &= ~EDGE_FALLTHRU;
*************** commit_edge_insertions ()
*** 1394,1401 ****
        for (e = bb->succ; e; e = next)
  	{
  	  next = e->succ_next;
  	  if (e->insns)
! 	    commit_one_edge_insertion (e);
  	}
  
        if (++i >= n_basic_blocks)
--- 1445,1484 ----
        for (e = bb->succ; e; e = next)
  	{
  	  next = e->succ_next;
+ 	  if (e->insns)
+ 	    commit_one_edge_insertion (e, false);
+ 	}
+ 
+       if (++i >= n_basic_blocks)
+ 	break;
+       bb = BASIC_BLOCK (i);
+     }
+ }
+ 
+ /* Update the CFG for all queued instructions, taking special care of inserting
+    code on edges between call and storing its return value.  */
+ 
+ void
+ commit_edge_insertions_watch_calls ()
+ {
+   int i;
+   basic_block bb;
+ 
+ #ifdef ENABLE_CHECKING
+   verify_flow_info ();
+ #endif
+ 
+   i = -1;
+   bb = ENTRY_BLOCK_PTR;
+   while (1)
+     {
+       edge e, next;
+ 
+       for (e = bb->succ; e; e = next)
+ 	{
+ 	  next = e->succ_next;
  	  if (e->insns)
! 	    commit_one_edge_insertion (e, true);
  	}
  
        if (++i >= n_basic_blocks)
Index: profile.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/profile.c,v
retrieving revision 1.80
diff -c -3 -p -r1.80 profile.c
*** profile.c	2001/12/02 00:04:19	1.80
--- profile.c	2002/02/28 17:09:43
*************** instrument_edges (el)
*** 169,175 ****
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  
!   commit_edge_insertions ();
  }
  
  /* Output STRING to bb_file, surrounded by DELIMITER.  */
--- 169,175 ----
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  
!   commit_edge_insertions_watch_calls ();
  }
  
  /* Output STRING to bb_file, surrounded by DELIMITER.  */


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