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]

jump threading over CFG.



Hi,
another pass I can replace easilly is jump_threading.  The new implementation
is stronger, as it is able to forward the fallthru edges.  So for example
following testcase is threaded:

main(int t)
{
   if (t)
    return 0;
   if (!t)
    return 1;
}

In the future we may use similar code to do basic block duplication in the
case branch corelation is discovered.

I've made some functions global, as I am calling them from flow.c and they lie
in jump.c.  Once I am finished with jump replacing, I plan to break flow.c into
separate files (probably cfg/cfgcleanup/cfgbuild/like/flow), so I will get them
local again.  I believe keeping functions at place for the moment makes patches
more readable.

Bootstrapped/regtested i586.

Honza

Thu Jul 12 19:16:57 CEST 2001  Jan Hubicka  <jh@suse.cz>

	* jump.c (mark_modified_reg, same_regs, num_same_regs, modified_regs,
	modified_mem): Make global.
	(thread_jumps): Kill.
	* rtl.h (mark_modified_reg, same_regs, num_same_regs, modified_regs,
	modified_mem): Declare.
	* toplev.c (rest_of_compilation): Pass CLEANUP_EXPENSIVE to the
	cleanup_cfg when needed; kill calls to thread_jumps.
	* flow.c (try_forward_edges): Use thread_jump when needed.
	(thread_jump): New.
	(try_optimize_cfg): Pass MODE to try_forward_edges.

Index: jump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/jump.c,v
retrieving revision 1.179
diff -c -3 -p -r1.179 jump.c
*** jump.c	2001/07/11 19:42:34	1.179
--- jump.c	2001/07/12 17:11:54
*************** static void invert_exp_1		PARAMS ((rtx))
*** 121,127 ****
  static int invert_exp			PARAMS ((rtx));
  static void delete_from_jump_chain	PARAMS ((rtx));
  static int delete_labelref_insn		PARAMS ((rtx, rtx, int));
- static void mark_modified_reg		PARAMS ((rtx, rtx, void *));
  static void redirect_tablejump		PARAMS ((rtx, rtx));
  static void jump_optimize_1		PARAMS ((rtx, int, int, int, int, int));
  static int returnjump_p_1	        PARAMS ((rtx *, void *));
--- 121,126 ----
--- 308,313 ----
*************** true_regnum (x)
*** 3762,3784 ****
     pending equivalences.  If nonzero, the expressions really aren't the
     same.  */
  
! static int *same_regs;
  
! static int num_same_regs;
  
  /* Track any registers modified between the target of the first jump and
     the second jump.  They never compare equal.  */
  
! static char *modified_regs;
  
  /* Record if memory was modified.  */
  
! static int modified_mem;
  
  /* Called via note_stores on each insn between the target of the first
     branch and the second branch.  It marks any changed registers.  */
  
! static void
  mark_modified_reg (dest, x, data)
       rtx dest;
       rtx x;
--- 3761,3783 ----
     pending equivalences.  If nonzero, the expressions really aren't the
     same.  */
  
! int *same_regs;
  
! int num_same_regs;
  
  /* Track any registers modified between the target of the first jump and
     the second jump.  They never compare equal.  */
  
! char *modified_regs;
  
  /* Record if memory was modified.  */
  
! int modified_mem;
  
  /* Called via note_stores on each insn between the target of the first
     branch and the second branch.  It marks any changed registers.  */
  
! void
  mark_modified_reg (dest, x, data)
       rtx dest;
       rtx x;
*************** mark_modified_reg (dest, x, data)
*** 3810,4016 ****
        modified_regs[regno + i] = 1;
  }
  
- /* F is the first insn in the chain of insns.  */
- 
- void
- thread_jumps (f, max_reg, flag_before_loop)
-      rtx f;
-      int max_reg;
-      int flag_before_loop;
- {
-   /* Basic algorithm is to find a conditional branch,
-      the label it may branch to, and the branch after
-      that label.  If the two branches test the same condition,
-      walk back from both branch paths until the insn patterns
-      differ, or code labels are hit.  If we make it back to
-      the target of the first branch, then we know that the first branch
-      will either always succeed or always fail depending on the relative
-      senses of the two branches.  So adjust the first branch accordingly
-      in this case.  */
- 
-   rtx label, b1, b2, t1, t2;
-   enum rtx_code code1, code2;
-   rtx b1op0, b1op1, b2op0, b2op1;
-   int changed = 1;
-   int i;
-   int *all_reset;
-   enum rtx_code reversed_code1, reversed_code2;
- 
-   /* Allocate register tables and quick-reset table.  */
-   modified_regs = (char *) xmalloc (max_reg * sizeof (char));
-   same_regs = (int *) xmalloc (max_reg * sizeof (int));
-   all_reset = (int *) xmalloc (max_reg * sizeof (int));
-   for (i = 0; i < max_reg; i++)
-     all_reset[i] = -1;
- 
-   while (changed)
-     {
-       changed = 0;
- 
-       for (b1 = f; b1; b1 = NEXT_INSN (b1))
- 	{
- 	  rtx set;
- 	  rtx set2;
- 
- 	  /* Get to a candidate branch insn.  */
- 	  if (GET_CODE (b1) != JUMP_INSN
- 	      || ! any_condjump_p (b1) || JUMP_LABEL (b1) == 0)
- 	    continue;
- 
- 	  memset (modified_regs, 0, max_reg * sizeof (char));
- 	  modified_mem = 0;
- 
- 	  memcpy (same_regs, all_reset, max_reg * sizeof (int));
- 	  num_same_regs = 0;
- 
- 	  label = JUMP_LABEL (b1);
- 
- 	  /* Look for a branch after the target.  Record any registers and
- 	     memory modified between the target and the branch.  Stop when we
- 	     get to a label since we can't know what was changed there.  */
- 	  for (b2 = NEXT_INSN (label); b2; b2 = NEXT_INSN (b2))
- 	    {
- 	      if (GET_CODE (b2) == CODE_LABEL)
- 		break;
- 
- 	      else if (GET_CODE (b2) == JUMP_INSN)
- 		{
- 		  /* If this is an unconditional jump and is the only use of
- 		     its target label, we can follow it.  */
- 		  if (any_uncondjump_p (b2)
- 		      && onlyjump_p (b2)
- 		      && JUMP_LABEL (b2) != 0
- 		      && LABEL_NUSES (JUMP_LABEL (b2)) == 1)
- 		    {
- 		      b2 = JUMP_LABEL (b2);
- 		      continue;
- 		    }
- 		  else
- 		    break;
- 		}
- 
- 	      if (GET_CODE (b2) != CALL_INSN && GET_CODE (b2) != INSN)
- 		continue;
- 
- 	      if (GET_CODE (b2) == CALL_INSN)
- 		{
- 		  modified_mem = 1;
- 		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- 		    if (call_used_regs[i] && ! fixed_regs[i]
- 			&& i != STACK_POINTER_REGNUM
- 			&& i != FRAME_POINTER_REGNUM
- 			&& i != HARD_FRAME_POINTER_REGNUM
- 			&& i != ARG_POINTER_REGNUM)
- 		      modified_regs[i] = 1;
- 		}
- 
- 	      note_stores (PATTERN (b2), mark_modified_reg, NULL);
- 	    }
- 
- 	  /* Check the next candidate branch insn from the label
- 	     of the first.  */
- 	  if (b2 == 0
- 	      || GET_CODE (b2) != JUMP_INSN
- 	      || b2 == b1
- 	      || !any_condjump_p (b2)
- 	      || !onlyjump_p (b2))
- 	    continue;
- 	  set = pc_set (b1);
- 	  set2 = pc_set (b2);
- 
- 	  /* Get the comparison codes and operands, reversing the
- 	     codes if appropriate.  If we don't have comparison codes,
- 	     we can't do anything.  */
- 	  b1op0 = XEXP (XEXP (SET_SRC (set), 0), 0);
- 	  b1op1 = XEXP (XEXP (SET_SRC (set), 0), 1);
- 	  code1 = GET_CODE (XEXP (SET_SRC (set), 0));
- 	  reversed_code1 = code1;
- 	  if (XEXP (SET_SRC (set), 1) == pc_rtx)
- 	    code1 = reversed_comparison_code (XEXP (SET_SRC (set), 0), b1);
- 	  else
- 	    reversed_code1 = reversed_comparison_code (XEXP (SET_SRC (set), 0), b1);
- 
- 	  b2op0 = XEXP (XEXP (SET_SRC (set2), 0), 0);
- 	  b2op1 = XEXP (XEXP (SET_SRC (set2), 0), 1);
- 	  code2 = GET_CODE (XEXP (SET_SRC (set2), 0));
- 	  reversed_code2 = code2;
- 	  if (XEXP (SET_SRC (set2), 1) == pc_rtx)
- 	    code2 = reversed_comparison_code (XEXP (SET_SRC (set2), 0), b2);
- 	  else
- 	    reversed_code2 = reversed_comparison_code (XEXP (SET_SRC (set2), 0), b2);
- 
- 	  /* If they test the same things and knowing that B1 branches
- 	     tells us whether or not B2 branches, check if we
- 	     can thread the branch.  */
- 	  if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
- 	      && rtx_equal_for_thread_p (b1op1, b2op1, b2)
- 	      && (comparison_dominates_p (code1, code2)
- 		  || comparison_dominates_p (code1, reversed_code2)))
- 
- 	    {
- 	      t1 = prev_nonnote_insn (b1);
- 	      t2 = prev_nonnote_insn (b2);
- 
- 	      while (t1 != 0 && t2 != 0)
- 		{
- 		  if (t2 == label)
- 		    {
- 		      /* We have reached the target of the first branch.
- 		         If there are no pending register equivalents,
- 			 we know that this branch will either always
- 			 succeed (if the senses of the two branches are
- 			 the same) or always fail (if not).  */
- 		      rtx new_label;
- 
- 		      if (num_same_regs != 0)
- 			break;
- 
- 		      if (comparison_dominates_p (code1, code2))
- 			new_label = JUMP_LABEL (b2);
- 		      else
- 			new_label = get_label_after (b2);
- 
- 		      if (JUMP_LABEL (b1) != new_label)
- 			{
- 			  rtx prev = PREV_INSN (new_label);
- 
- 			  if (flag_before_loop
- 			      && GET_CODE (prev) == NOTE
- 			      && NOTE_LINE_NUMBER (prev) == NOTE_INSN_LOOP_BEG)
- 			    {
- 			      /* Don't thread to the loop label.  If a loop
- 				 label is reused, loop optimization will
- 				 be disabled for that loop.  */
- 			      new_label = gen_label_rtx ();
- 			      emit_label_after (new_label, PREV_INSN (prev));
- 			    }
- 			  changed |= redirect_jump (b1, new_label, 1);
- 			}
- 		      break;
- 		    }
- 
- 		  /* If either of these is not a normal insn (it might be
- 		     a JUMP_INSN, CALL_INSN, or CODE_LABEL) we fail.  (NOTEs
- 		     have already been skipped above.)  Similarly, fail
- 		     if the insns are different.  */
- 		  if (GET_CODE (t1) != INSN || GET_CODE (t2) != INSN
- 		      || recog_memoized (t1) != recog_memoized (t2)
- 		      || ! rtx_equal_for_thread_p (PATTERN (t1),
- 						   PATTERN (t2), t2))
- 		    break;
- 
- 		  t1 = prev_nonnote_insn (t1);
- 		  t2 = prev_nonnote_insn (t2);
- 		}
- 	    }
- 	}
-     }
- 
-   /* Clean up.  */
-   free (modified_regs);
-   free (same_regs);
-   free (all_reset);
- }
  
  /* This is like RTX_EQUAL_P except that it knows about our handling of
     possibly equivalent registers and knows to consider volatile and
--- 3809,3814 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.483
diff -c -3 -p -r1.483 toplev.c
*** toplev.c	2001/07/12 05:56:24	1.483
--- toplev.c	2001/07/12 17:11:56
*************** rest_of_compilation (decl)
*** 3033,3039 ****
    if (optimize > 0)
      {
        find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!       cleanup_cfg (CLEANUP_EXPENSIVE);
  
        /* ??? Run if-conversion before delete_null_pointer_checks,
           since the later does not preserve the CFG.  This should
--- 3033,3040 ----
    if (optimize > 0)
      {
        find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!       cleanup_cfg (CLEANUP_EXPENSIVE
! 		   | (flag_thread_jumps ? CLEANUP_THREADING : 0));
  
        /* ??? Run if-conversion before delete_null_pointer_checks,
           since the later does not preserve the CFG.  This should
*************** rest_of_compilation (decl)
*** 3072,3084 ****
  
        reg_scan (insns, max_reg_num (), 1);
  
-       if (flag_thread_jumps)
- 	{
- 	  timevar_push (TV_JUMP);
- 	  thread_jumps (insns, max_reg_num (), 1);
- 	  timevar_pop (TV_JUMP);
- 	}
- 
        tem = cse_main (insns, max_reg_num (), 0, rtl_dump_file);
  
        /* If we are not running more CSE passes, then we are no longer
--- 3073,3078 ----
*************** rest_of_compilation (decl)
*** 3098,3111 ****
        delete_trivially_dead_insns (insns, max_reg_num ());
  
        /* Try to identify useless null pointer tests and delete them.  */
!       if (flag_delete_null_pointer_checks)
  	{
  	  timevar_push (TV_JUMP);
  	  find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
  
! 	  cleanup_cfg (CLEANUP_EXPENSIVE);
  
! 	  delete_null_pointer_checks (insns);
  	  timevar_pop (TV_JUMP);
  	}
  
--- 3092,3107 ----
        delete_trivially_dead_insns (insns, max_reg_num ());
  
        /* Try to identify useless null pointer tests and delete them.  */
!       if (flag_delete_null_pointer_checks || flag_thread_jumps)
  	{
  	  timevar_push (TV_JUMP);
  	  find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
  
! 	  cleanup_cfg (CLEANUP_EXPENSIVE
! 		       | (flag_thread_jumps ? CLEANUP_THREADING : 0));
  
! 	  if (flag_delete_null_pointer_checks)
! 	    delete_null_pointer_checks (insns);
  	  timevar_pop (TV_JUMP);
  	}
  
*************** rest_of_compilation (decl)
*** 3260,3275 ****
  	    }
  	}
  
-       if (flag_thread_jumps)
- 	{
- 	  /* This pass of jump threading straightens out code
- 	     that was kinked by loop optimization.  */
- 	  timevar_push (TV_JUMP);
- 	  reg_scan (insns, max_reg_num (), 0);
- 	  thread_jumps (insns, max_reg_num (), 0);
- 	  timevar_pop (TV_JUMP);
- 	}
- 
        close_dump_file (DFI_cse2, print_rtl, insns);
        timevar_pop (TV_CSE2);
  
--- 3256,3261 ----
*************** rest_of_compilation (decl)
*** 3287,3293 ****
    open_dump_file (DFI_cfg, decl);
  
    find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
    check_function_return_warnings ();
  
    /* It may make more sense to mark constant functions after dead code is
--- 3273,3280 ----
    open_dump_file (DFI_cfg, decl);
  
    find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0
! 	       | (flag_thread_jumps ? CLEANUP_THREADING : 0));
    check_function_return_warnings ();
  
    /* It may make more sense to mark constant functions after dead code is
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.h,v
retrieving revision 1.270
diff -c -3 -p -r1.270 rtl.h
*** rtl.h	2001/07/11 20:35:50	1.270
--- rtl.h	2001/07/12 17:11:56
*************** extern void jump_optimize_minimal	PARAMS
*** 1720,1725 ****
--- 1720,1726 ----
  extern void rebuild_jump_labels		PARAMS ((rtx));
  extern void thread_jumps		PARAMS ((rtx, int, int));
  extern int rtx_equal_for_thread_p	PARAMS ((rtx, rtx, rtx));
+ extern void mark_modified_reg		PARAMS ((rtx, rtx, void *));
  extern int can_reverse_comparison_p	PARAMS ((rtx, rtx));
  extern enum rtx_code reversed_comparison_code PARAMS ((rtx, rtx));
  extern enum rtx_code reversed_comparison_code_parts PARAMS ((enum rtx_code,
*************** extern enum rtx_code reversed_comparison
*** 1727,1732 ****
--- 1728,1738 ----
  extern void delete_for_peephole		PARAMS ((rtx, rtx));
  extern int condjump_in_parallel_p	PARAMS ((rtx));
  extern void never_reached_warning	PARAMS ((rtx));
+ 
+ extern char *modified_regs;
+ extern int modified_mem;
+ extern int *same_regs;
+ extern int num_same_regs;
  
  /* Flags for jump_optimize() */
  #define JUMP_CROSS_JUMP			1
Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.421
diff -c -3 -p -r1.421 flow.c
*** flow.c	2001/07/12 16:01:33	1.421
--- flow.c	2001/07/12 17:12:00
*************** static bool forwarder_block_p		PARAMS ((
*** 396,402 ****
  static bool can_fallthru		PARAMS ((basic_block, basic_block));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static bool try_simplify_condjump	PARAMS ((basic_block));
! static bool try_forward_edges		PARAMS ((basic_block));
  static void tidy_fallthru_edges		PARAMS ((void));
  static int verify_wide_reg_1		PARAMS ((rtx *, void *));
  static void verify_wide_reg		PARAMS ((int, rtx, rtx));
--- 396,403 ----
  static bool can_fallthru		PARAMS ((basic_block, basic_block));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static bool try_simplify_condjump	PARAMS ((basic_block));
! static bool try_forward_edges		PARAMS ((basic_block, int));
! static edge thread_jump			PARAMS ((edge, basic_block));
  static void tidy_fallthru_edges		PARAMS ((void));
  static int verify_wide_reg_1		PARAMS ((rtx *, void *));
  static void verify_wide_reg		PARAMS ((int, rtx, rtx));
*************** try_simplify_condjump (src)
*** 3077,3125 ****
    flow_delete_block (next_block);
    return true;
  }
  
  /* Attempt to forward edges leaving basic block B.
     Return nonzero if sucessfull.  */
  
  static bool
! try_forward_edges (b)
       basic_block b;
  {
    bool changed = 0;
!   edge e;
    for (e = b->succ; e; e = e->succ_next)
      {
        basic_block target = e->dest, first = e->dest;
        int counter = 0;
  
        /* Look for the real destination of jump.
           Avoid inifinite loop in the infinite empty loop by counting
           up to n_basic_blocks.  */
!       while (forwarder_block_p (target)
! 	     && target->succ->dest != EXIT_BLOCK_PTR
! 	     && counter < n_basic_blocks)
! 	{
! 	  /* Bypass trivial infinite loops.  */
! 	  if (target == target->succ->dest)
! 	    counter = n_basic_blocks;
! 	  target = target->succ->dest, counter++;
  	}
  
        if (target != first && counter < n_basic_blocks
! 	  && redirect_edge_and_branch (e, target))
  	{
  	  while (first != target)
  	    {
  	      first->count -= e->count;
- 	      first->succ->count -= e->count;
  	      first->frequency -= ((e->probability * b->frequency
  				    + REG_BR_PROB_BASE / 2)
  				   / REG_BR_PROB_BASE);
! 	      first = first->succ->dest;
  	    }
  	  /* We've possibly removed the edge.  */
  	  changed = 1;
  	  e = b->succ;
  	}
        else if (rtl_dump_file && counter == n_basic_blocks)
  	fprintf (rtl_dump_file, "Infinite loop in BB %i.\n", target->index);
--- 3078,3281 ----
    flow_delete_block (next_block);
    return true;
  }
+ /* Attempt to prove that the basic block B will have no side effects and
+    allways continues in the same edge if reached via E.  Return the edge
+    if exist, NULL otherwise.  */
  
+ static edge
+ thread_jump (e, b)
+      edge e;
+      basic_block b;
+ {
+   rtx set1, set2, cond1, cond2, insn, t1, t2;
+   enum rtx_code code1, code2, reversed_code2;
+   bool reverse1 = false;
+   int max_reg = max_reg_num ();
+   int i;
+ 
+   /* At the moment, we do handle only conditional jumps, but later we may
+      want to extend this code to tablejumps and others.  */
+   if (!e->src->succ->succ_next || e->src->succ->succ_next->succ_next)
+     return NULL;
+   if (!b->succ || !b->succ->succ_next || b->succ->succ_next->succ_next)
+     return NULL;
+ 
+   /* Second branch must end with onlyjump, as we will eliminate the jump.  */
+   if (!any_condjump_p (e->src->end) || !any_condjump_p (b->end)
+       || !onlyjump_p (b->end))
+     return NULL;
+ 
+   set1 = pc_set (e->src->end);
+   set2 = pc_set (b->end);
+   if (((e->flags & EDGE_FALLTHRU) != 0)
+       != (XEXP (SET_SRC (set1), 0) == pc_rtx))
+     reverse1 = true;
+ 
+   cond1 = XEXP (SET_SRC (set1), 0);
+   cond2 = XEXP (SET_SRC (set2), 0);
+   if (reverse1)
+     code1 = reversed_comparison_code (cond1, b->end);
+   else
+     code1 = GET_CODE (cond1);
+ 
+   code2 = GET_CODE (cond2);
+   reversed_code2 = reversed_comparison_code (cond2, b->end);
+ 
+   if (!comparison_dominates_p (code1, code2)
+       && !comparison_dominates_p (code1, reversed_code2))
+     return 0;
+ 
+   /* Allocate register tables.
+      ??? In case this shows to be performance critical, we can
+      do the allocation once in cleanup_cfg.  */
+   modified_regs = (char *) xmalloc (max_reg * sizeof (char));
+   same_regs = (int *) xmalloc (max_reg * sizeof (int));
+   for (i = 0; i < max_reg; i++)
+     same_regs[i] = -1;
+   memset (modified_regs, 0, max_reg * sizeof (char));
+   modified_mem = 0;
+   num_same_regs = 0;
+ 
+   /* Notice the stores and equivalencies.  */
+   for (insn = NEXT_INSN (b->head);; insn = NEXT_INSN (insn))
+     {
+       if (GET_CODE (insn) == JUMP_INSN)
+ 	break;
+ 
+       if (GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != INSN)
+ 	continue;
+ 
+       if (GET_CODE (insn) == CALL_INSN)
+ 	{
+ 	  modified_mem = 1;
+ 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ 	    if (call_used_regs[i] && !fixed_regs[i]
+ 		&& i != STACK_POINTER_REGNUM
+ 		&& i != FRAME_POINTER_REGNUM
+ 		&& i != HARD_FRAME_POINTER_REGNUM && i != ARG_POINTER_REGNUM)
+ 	      modified_regs[i] = 1;
+ 	}
+ 
+       note_stores (PATTERN (insn), mark_modified_reg, NULL);
+     }
+ 
+   if (!rtx_equal_for_thread_p (XEXP (cond1, 0), XEXP (cond2, 0), b->end)
+       || !rtx_equal_for_thread_p (XEXP (cond1, 1), XEXP (cond2, 1), b->end))
+     goto failed;
+   t1 = prev_nonnote_insn (e->src->end);
+   t2 = prev_nonnote_insn (b->end);
+ 
+   while (t2 != b->head && GET_CODE (t2) != CODE_LABEL)
+     {
+       if (!t1)
+ 	goto failed;
+ 
+       /* If either of these is not a normal insn (it might be
+          a JUMP_INSN, CALL_INSN, or CODE_LABEL) we fail.  (NOTEs
+          have already been skipped above.)  Similarly, fail
+          if the insns are different.  */
+       if (GET_CODE (t1) != INSN || GET_CODE (t2) != INSN
+ 	  || recog_memoized (t1) != recog_memoized (t2)
+ 	  || !rtx_equal_for_thread_p (PATTERN (t1), PATTERN (t2), t2))
+ 	goto failed;
+ 
+       t1 = prev_nonnote_insn (t1);
+       t2 = prev_nonnote_insn (t2);
+     }
+ 
+   /* We have reached the target of the first branch.
+      If there are no pending register equivalents,
+      we know that this branch will either always
+      succeed (if the senses of the two branches are
+      the same) or always fail (if not).  */
+ 
+   if (num_same_regs != 0)
+     goto failed;
+ 
+   free (modified_regs);
+   free (same_regs);
+   if ((comparison_dominates_p (code1, code2) != 0)
+       != (XEXP (SET_SRC (set2), 0) == pc_rtx))
+     return BRANCH_EDGE (b);
+   else
+     return FALLTHRU_EDGE (b);
+ 
+ failed:
+   free (modified_regs);
+   free (same_regs);
+   return NULL;
+ }
+ 
  /* Attempt to forward edges leaving basic block B.
     Return nonzero if sucessfull.  */
  
  static bool
! try_forward_edges (b, mode)
       basic_block b;
+      int mode;
  {
    bool changed = 0;
!   edge e, threaded_edge;
    for (e = b->succ; e; e = e->succ_next)
      {
        basic_block target = e->dest, first = e->dest;
        int counter = 0;
+       bool threaded = false;
  
        /* Look for the real destination of jump.
           Avoid inifinite loop in the infinite empty loop by counting
           up to n_basic_blocks.  */
!       while (counter < n_basic_blocks)
! 	{
! 	  if (forwarder_block_p (target)
! 	      && target->succ->dest != EXIT_BLOCK_PTR)
! 	    {
! 	      /* Bypass trivial infinite loops.  */
! 	      if (target == target->succ->dest)
! 		counter = n_basic_blocks;
! 	      target = target->succ->dest, counter++;
! 	    }
! 	  /* Allow to thread only over one edge at time to simplify updating
! 	     of probabilities.  */
! 	  else if ((mode & CLEANUP_THREADING) && !threaded)
! 	    {
! 	      threaded_edge = thread_jump (e, target);
! 	      if (threaded_edge)
! 		{
! 		  counter++;
! 		  target = threaded_edge->dest;
! 		  threaded = true;
! 		}
! 	      else
! 		break;
! 	    }
! 	  else
! 	    break;
  	}
  
        if (target != first && counter < n_basic_blocks
! 	  && (threaded ? redirect_edge_and_branch_force (e, target), true
! 	      : redirect_edge_and_branch (e, target)))
  	{
  	  while (first != target)
  	    {
+ 	      edge t;
  	      first->count -= e->count;
  	      first->frequency -= ((e->probability * b->frequency
  				    + REG_BR_PROB_BASE / 2)
  				   / REG_BR_PROB_BASE);
! 	      if (first->succ->succ_next)
! 		t = threaded_edge;
! 	      else
! 		t = first->succ;
! 	      t->count -= e->count;
! 	      first = t->dest;
  	    }
  	  /* We've possibly removed the edge.  */
  	  changed = 1;
  	  e = b->succ;
+ 	  if (threaded && rtl_dump_file)
+ 	    fprintf (rtl_dump_file, "Conditionals threaded.\n", target->index);
  	}
        else if (rtl_dump_file && counter == n_basic_blocks)
  	fprintf (rtl_dump_file, "Infinite loop in BB %i.\n", target->index);
*************** try_optimize_cfg (mode)
*** 3710,3716 ****
  	      && redirect_edge_and_branch (b->succ, b->succ->dest))
  	    changed_here = 1;
  
! 	  if (try_forward_edges (b))
  	    changed_here = 1;
  
  	  if ((mode & CLEANUP_CROSSJUMP) && try_crossjump_bb (mode, b))
--- 3866,3872 ----
  	      && redirect_edge_and_branch (b->succ, b->succ->dest))
  	    changed_here = 1;
  
! 	  if (try_forward_edges (b, mode))
  	    changed_here = 1;
  
  	  if ((mode & CLEANUP_CROSSJUMP) && try_crossjump_bb (mode, b))


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