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]

crossjumping cleanup+improvement



Hi,
this patch adds code to crossjump control transfer instructions that are not
unconditional jumps nor conditional jumps except for tablejump.  The primary
motivations are possibly trapping instructions that do have multiple outgoing
edges and thus they are not crossjumped by old code, but the code works for
other cases too - like computed jumps and similar beasts.

Tablejump needs special handling, as the tables itself needs to be checked to
match (they are always different) and the code needs to be patched to replace
references to killed table by references to alive one.

I am not sure if it is worthwhile.

Honza

Sat Oct 27 16:21:33 CEST 2001  Jan Hubicka  <jh@suse.cz>
	* cfgcleanup.c (insns_match_p): Break out from ...;
	(flow_find_cross_jump): ... here;
	(outgoing_edges_match): Add parameter MODE; attempt to match everything
	except for tablejumps.
	(try_crossjump_to_edge): Accept complex edges.
	(try_crossjump_bb): Likewise.

*** ../../e2/gcc/cfgcleanup.c	Mon Oct  1 22:39:25 2001
--- cfgcleanup.c	Sat Oct 20 15:10:50 2001
*************** Software Foundation, 59 Temple Place - S
*** 47,55 ****
  
  static bool try_crossjump_to_edge	PARAMS ((int, edge, edge));
  static bool try_crossjump_bb		PARAMS ((int, basic_block));
! static bool outgoing_edges_match	PARAMS ((basic_block, basic_block));
  static int flow_find_cross_jump		PARAMS ((int, basic_block, basic_block,
  						 rtx *, rtx *));
  
  static bool delete_unreachable_blocks	PARAMS ((void));
  static bool tail_recursion_label_p	PARAMS ((rtx));
--- 47,57 ----
  
  static bool try_crossjump_to_edge	PARAMS ((int, edge, edge));
  static bool try_crossjump_bb		PARAMS ((int, basic_block));
! static bool outgoing_edges_match	PARAMS ((int,
! 						 basic_block, basic_block));
  static int flow_find_cross_jump		PARAMS ((int, basic_block, basic_block,
  						 rtx *, rtx *));
+ static bool insns_match_p		PARAMS ((int, rtx, rtx));
  
  static bool delete_unreachable_blocks	PARAMS ((void));
  static bool tail_recursion_label_p	PARAMS ((rtx));
*************** merge_blocks (e, b, c, mode)
*** 449,454 ****
--- 451,558 ----
    return false;
  }
  
+ 
+ /* Return true if I1 and I2 are equivalent and thus can be crossjumped.  */
+ 
+ static bool
+ insns_match_p (mode, i1, i2)
+ 	int mode;
+ 	rtx i1, i2;
+ {
+   rtx p1, p2;
+ 
+   /* Verify that I1 and I2 are equivalent.  */
+   if (GET_CODE (i1) != GET_CODE (i2))
+     return false;
+ 
+   p1 = PATTERN (i1);
+   p2 = PATTERN (i2);
+ 
+   if (GET_CODE (p1) != GET_CODE (p2))
+     return false;
+ 
+   /* If this is a CALL_INSN, compare register usage information.
+      If we don't check this on stack register machines, the two
+      CALL_INSNs might be merged leaving reg-stack.c with mismatching
+      numbers of stack registers in the same basic block.
+      If we don't check this on machines with delay slots, a delay slot may
+      be filled that clobbers a parameter expected by the subroutine.
+ 
+      ??? We take the simple route for now and assume that if they're
+      equal, they were constructed identically.  */
+ 
+   if (GET_CODE (i1) == CALL_INSN
+       && !rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
+ 		       CALL_INSN_FUNCTION_USAGE (i2)))
+     return false;
+ 
+ #ifdef STACK_REGS
+   /* If cross_jump_death_matters is not 0, the insn's mode
+      indicates whether or not the insn contains any stack-like
+      regs.  */
+ 
+   if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
+     {
+       /* If register stack conversion has already been done, then
+          death notes must also be compared before it is certain that
+          the two instruction streams match.  */
+ 
+       rtx note;
+       HARD_REG_SET i1_regset, i2_regset;
+ 
+       CLEAR_HARD_REG_SET (i1_regset);
+       CLEAR_HARD_REG_SET (i2_regset);
+ 
+       for (note = REG_NOTES (i1); note; note = XEXP (note, 1))
+ 	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
+ 	  SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0)));
+ 
+       for (note = REG_NOTES (i2); note; note = XEXP (note, 1))
+ 	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
+ 	  SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
+ 
+       GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
+ 
+       return false;
+ 
+     done:
+       ;
+     }
+ #endif
+ 
+   if (reload_completed
+       ? ! rtx_renumbered_equal_p (p1, p2) : ! rtx_equal_p (p1, p2))
+     {
+       /* The following code helps take care of G++ cleanups.  */
+       rtx equiv1 = find_reg_equal_equiv_note (i1);
+       rtx equiv2 = find_reg_equal_equiv_note (i2);
+ 
+       if (equiv1 && equiv2
+ 	  /* If the equivalences are not to a constant, they may
+ 	     reference pseudos that no longer exist, so we can't
+ 	     use them.  */
+ 	  && (! reload_completed
+ 	      || (CONSTANT_P (XEXP (equiv1, 0))
+ 		  && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))))
+ 	{
+ 	  rtx s1 = single_set (i1);
+ 	  rtx s2 = single_set (i2);
+ 	  if (s1 != 0 && s2 != 0
+ 	      && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
+ 	    {
+ 	      validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
+ 	      validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
+ 	      if (! rtx_renumbered_equal_p (p1, p2))
+ 		cancel_changes (0);
+ 	      else if (apply_change_group ())
+ 		return true;
+ 	    }
+ 	}
+       return false;
+     }
+   return true;
+ }
+ 
  /* Look through the insns at the end of BB1 and BB2 and find the longest
     sequence that are equivalent.  Store the first insns for that sequence
     in *F1 and *F2 and return the sequence length.
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 462,468 ****
       basic_block bb1, bb2;
       rtx *f1, *f2;
  {
!   rtx i1, i2, p1, p2, last1, last2, afterlast1, afterlast2;
    int ninsns = 0;
  
    /* Skip simple jumps at the end of the blocks.  Complex jumps still
--- 566,572 ----
       basic_block bb1, bb2;
       rtx *f1, *f2;
  {
!   rtx i1, i2, last1, last2, afterlast1, afterlast2;
    int ninsns = 0;
  
    /* Skip simple jumps at the end of the blocks.  Complex jumps still
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 489,588 ****
        if (i1 == bb1->head || i2 == bb2->head)
  	break;
  
!       /* Verify that I1 and I2 are equivalent.  */
! 
!       if (GET_CODE (i1) != GET_CODE (i2))
! 	break;
! 
!       p1 = PATTERN (i1);
!       p2 = PATTERN (i2);
! 
!       /* If this is a CALL_INSN, compare register usage information.
! 	 If we don't check this on stack register machines, the two
! 	 CALL_INSNs might be merged leaving reg-stack.c with mismatching
! 	 numbers of stack registers in the same basic block.
! 	 If we don't check this on machines with delay slots, a delay slot may
! 	 be filled that clobbers a parameter expected by the subroutine.
! 
! 	 ??? We take the simple route for now and assume that if they're
! 	 equal, they were constructed identically.  */
! 
!       if (GET_CODE (i1) == CALL_INSN
! 	  && ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
! 			    CALL_INSN_FUNCTION_USAGE (i2)))
  	break;
  
- #ifdef STACK_REGS
-       /* If cross_jump_death_matters is not 0, the insn's mode
- 	 indicates whether or not the insn contains any stack-like
- 	 regs.  */
- 
-       if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
- 	{
- 	  /* If register stack conversion has already been done, then
- 	     death notes must also be compared before it is certain that
- 	     the two instruction streams match.  */
- 
- 	  rtx note;
- 	  HARD_REG_SET i1_regset, i2_regset;
- 
- 	  CLEAR_HARD_REG_SET (i1_regset);
- 	  CLEAR_HARD_REG_SET (i2_regset);
- 
- 	  for (note = REG_NOTES (i1); note; note = XEXP (note, 1))
- 	    if (REG_NOTE_KIND (note) == REG_DEAD
- 		&& STACK_REG_P (XEXP (note, 0)))
- 	      SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0)));
- 
- 	  for (note = REG_NOTES (i2); note; note = XEXP (note, 1))
- 	    if (REG_NOTE_KIND (note) == REG_DEAD
- 		&& STACK_REG_P (XEXP (note, 0)))
- 	      SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
- 
- 	  GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
- 
- 	  break;
- 
- 	done:
- 	  ;
- 	}
- #endif
- 
-       if (GET_CODE (p1) != GET_CODE (p2))
- 	break;
- 
-       if (! rtx_renumbered_equal_p (p1, p2))
- 	{
- 	  /* The following code helps take care of G++ cleanups.  */
- 	  rtx equiv1 = find_reg_equal_equiv_note (i1);
- 	  rtx equiv2 = find_reg_equal_equiv_note (i2);
- 
- 	  if (equiv1 && equiv2
- 	      /* If the equivalences are not to a constant, they may
- 		 reference pseudos that no longer exist, so we can't
- 		 use them.  */
- 	      && CONSTANT_P (XEXP (equiv1, 0))
- 	      && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))
- 	    {
- 	      rtx s1 = single_set (i1);
- 	      rtx s2 = single_set (i2);
- 	      if (s1 != 0 && s2 != 0
- 		  && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
- 		{
- 		  validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
- 		  validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
- 		  if (! rtx_renumbered_equal_p (p1, p2))
- 		    cancel_changes (0);
- 		  else if (apply_change_group ())
- 		    goto win;
- 		}
- 	    }
- 	  break;
- 	}
- 
-     win:
        /* Don't begin a cross-jump with a USE or CLOBBER insn.  */
!       if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
  	{
  	  /* If the merged insns have different REG_EQUAL notes, then
  	     remove them.  */
--- 593,603 ----
        if (i1 == bb1->head || i2 == bb2->head)
  	break;
  
!       if (!insns_match_p (mode, i1, i2))
  	break;
  
        /* Don't begin a cross-jump with a USE or CLOBBER insn.  */
!       if (active_insn_p (i1))
  	{
  	  /* If the merged insns have different REG_EQUAL notes, then
  	     remove them.  */
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 646,655 ****
     We may assume that there exists one edge with a common destination.  */
  
  static bool
! outgoing_edges_match (bb1, bb2)
       basic_block bb1;
       basic_block bb2;
  {
    /* If BB1 has only one successor, we must be looking at an unconditional
       jump.  Which, by the assumption above, means that we only need to check
       that BB2 has one successor.  */
--- 661,675 ----
     We may assume that there exists one edge with a common destination.  */
  
  static bool
! outgoing_edges_match (mode, bb1, bb2)
!      int mode;
       basic_block bb1;
       basic_block bb2;
  {
+   int nehedges1, nehedges2;
+   edge fallthru1, fallthru2;
+   edge e1, e2;
+ 
    /* If BB1 has only one successor, we must be looking at an unconditional
       jump.  Which, by the assumption above, means that we only need to check
       that BB2 has one successor.  */
*************** outgoing_edges_match (bb1, bb2)
*** 765,774 ****
        return match;
      }
  
!   /* ??? We can handle computed jumps too.  This may be important for
!      inlined functions containing switch statements.  Also jumps w/o
!      fallthru edges can be handled by simply matching whole insn.  */
!   return false;
  }
  
  /* E1 and E2 are edges with the same destination block.  Search their
--- 785,844 ----
        return match;
      }
  
!   /* Generic case - we are seeing an computed jump, table jump or trapping
!      instruction.  */
! 
!   /* First ensure that the instructions match.  There may be many outgoing
!      edges so this test is generally cheaper.
!      ??? Currently the tablejumps will never match, as they do have
!      different tables.  */
!   if (!insns_match_p (mode, bb1->end, bb2->end))
!     return false;
! 
!   /* Search the outgoing edges, ensure that the counts do match, find possible
!      fallthru and exception handling edges since these needs more
!      validation.  */
!   for (e1 = bb1->succ, e2 = bb2->succ; e1 && e2;
!        e1 = e1->succ_next, e2 = e2->succ_next)
!     {
!       if (e1->flags & EDGE_EH)
! 	nehedges1++;
!       if (e2->flags & EDGE_EH)
! 	nehedges2++;
!       if (e1->flags & EDGE_FALLTHRU)
! 	fallthru1 = e1;
!       if (e2->flags & EDGE_FALLTHRU)
! 	fallthru2 = e2;
!     }
!   /* If number of edges of various types does not match, fail.  */
!   if (e1 || e2)
!     return false;
!   if (nehedges1 != nehedges2)
!     return false;
!   if ((fallthru1 != 0) != (fallthru2 != 0))
!     return false;
! 
!   /* fallthru edges must be forwarded to the same destination.  */
!   if (fallthru1)
!     {
!       basic_block d1 = (forwarder_block_p (fallthru1->dest)
! 	                ? fallthru1->dest->succ->dest: fallthru1->dest);
!       basic_block d2 = (forwarder_block_p (fallthru2->dest)
! 	                ? fallthru2->dest->succ->dest: fallthru2->dest);
!       if (d1 != d2)
! 	return false;
!     }
!   /* In case we do have EH edges, ensure we are in the same region.  */
!   if (nehedges1)
!     {
!       rtx n1 = find_reg_note (bb1->end, REG_EH_REGION, 0);
!       rtx n2 = find_reg_note (bb2->end, REG_EH_REGION, 0);
!       if (XEXP (n1, 0) != XEXP (n1, 1))
! 	return false;
!     }
!   /* We don't need to match the rest of edges as above checks should be enought
!      to ensure that they are equivalent.  */
!   return true;
  }
  
  /* E1 and E2 are edges with the same destination block.  Search their
*************** try_crossjump_to_edge (mode, e1, e2)
*** 827,840 ****
    if (!src1->pred || !src2->pred)
      return false;
  
-   /* Likewise with complex edges.
-      ??? We should be able to handle most complex edges later with some
-      care.  */
-   if (e1->flags & EDGE_COMPLEX)
-     return false;
- 
    /* Look for the common insn sequence, part the first ...  */
!   if (!outgoing_edges_match (src1, src2))
      return false;
  
    /* ... and part the second.  */
--- 897,904 ----
    if (!src1->pred || !src2->pred)
      return false;
  
    /* Look for the common insn sequence, part the first ...  */
!   if (!outgoing_edges_match (mode, src1, src2))
      return false;
  
    /* ... and part the second.  */
*************** try_crossjump_bb (mode, bb)
*** 966,976 ****
      {
        nexte = e->pred_next;
  
-       /* Elide complex edges now, as neither try_crossjump_to_edge
- 	 nor outgoing_edges_match can handle them.  */
-       if (e->flags & EDGE_COMPLEX)
- 	continue;
- 
        /* As noted above, first try with the fallthru predecessor.  */
        if (fallthru)
  	{
--- 1030,1035 ----
*************** try_crossjump_bb (mode, bb)
*** 1013,1023 ****
  	  if (e2 == fallthru)
  	    continue;
  
- 	  /* Again, neither try_crossjump_to_edge nor outgoing_edges_match
- 	     can handle complex edges.  */
- 	  if (e2->flags & EDGE_COMPLEX)
- 	    continue;
- 
  	  /* The "first successor" check above only prevents multiple
  	     checks of crossjump(A,B).  In order to prevent redundant
  	     checks of crossjump(B,A), require that A be the block
--- 1072,1077 ----


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