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]

jump threading


[sorry, wrong address last time]

Hi,
this is one of latest patches I would like to fit to 3.1 mainly because of the
bug Jeff observed in current code.

The patch is trivial update of patch I originally installed to cfg branch,
where it has been tested on sparc/mips and x86. I've bootstrapped on the
mainline i586 too.


Sun Oct 28 14:04:34 CET 2001  Jan Hubicka  <jh@suse.cz>

	* Makefile.in (cfgcleanup.o): Add cselib.h dependancy.
	* basic-block.h (CLEANUP_THREADING): New constant.
	* cfgcleanup.c: Include cselib.h
	(thread_jump, mark_effect): New functions.
	(try_forward_edges): Do jump threading when asked for.
	* jump.c (mark_modified_reg, save_regs, num_same_regs, modified_regs,
	modified_mem, thread_jumps, rtx_equal_for-thread_p): Kill.
	* rtl.h (thread_jumps, rtx_equal_for_thread_p): Kill.
	* toplev.c (rest_of_compilation): Do now call thread_jumps; use
	CLEANUP_THREAD instead.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.806
diff -c -3 -p -r1.806 Makefile.in
*** Makefile.in	2001/12/13 11:34:04	1.806
--- Makefile.in	2001/12/14 20:59:50
*************** cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SY
*** 1469,1475 ****
     function.h except.h $(GGC_H) 
  cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TIMEVAR_H)\
     $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h $(RECOG_H) toplev.h \
!    $(GGC_H) insn-config.h
  cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h
  dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) hard-reg-set.h \
--- 1469,1475 ----
     function.h except.h $(GGC_H) 
  cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TIMEVAR_H)\
     $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h $(RECOG_H) toplev.h \
!    $(GGC_H) insn-config.h cselib.h
  cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h
  dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) hard-reg-set.h \
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/basic-block.h,v
retrieving revision 1.129
diff -c -3 -p -r1.129 basic-block.h
*** basic-block.h	2001/12/12 05:01:32	1.129
--- basic-block.h	2001/12/14 20:59:50
*************** enum update_life_extent
*** 576,581 ****
--- 576,582 ----
  #define CLEANUP_PRE_LOOP	16	/* Take care to preserve syntactic loop
  					   notes.  */
  #define CLEANUP_UPDATE_LIFE	32	/* Keep life information up to date.  */
+ #define CLEANUP_THREADING	64	/* Do jump threading.  */
  /* Flags for loop discovery.  */
  
  #define LOOP_TREE		1	/* Build loop hierarchy tree.  */
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cfgcleanup.c,v
retrieving revision 1.22
diff -c -3 -p -r1.22 cfgcleanup.c
*** cfgcleanup.c	2001/12/13 11:34:05	1.22
--- cfgcleanup.c	2001/12/14 20:59:51
*************** Software Foundation, 59 Temple Place - S
*** 42,47 ****
--- 42,48 ----
  #include "flags.h"
  #include "recog.h"
  #include "toplev.h"
+ #include "cselib.h"
  
  #include "obstack.h"
  
*************** static bool merge_blocks		PARAMS ((edge,
*** 82,87 ****
--- 83,90 ----
  static bool try_optimize_cfg		PARAMS ((int));
  static bool try_simplify_condjump	PARAMS ((basic_block));
  static bool try_forward_edges		PARAMS ((int, basic_block));
+ static edge thread_jump			PARAMS ((int, edge, basic_block));
+ static bool mark_effect			PARAMS ((rtx, bitmap));
  static void notice_new_block		PARAMS ((basic_block));
  static void update_forwarder_flag	PARAMS ((basic_block));
  
*************** try_simplify_condjump (cbranch_block)
*** 178,183 ****
--- 181,334 ----
    return true;
  }
  
+ /* Attempt to prove that operation is NOOP using CSElib or mark the effect
+    on register.  Used by jump threading.  */
+ static bool
+ mark_effect (exp, nonequal)
+   rtx exp;
+   regset nonequal;
+ {
+   switch (GET_CODE (exp))
+     {
+       /* In case we do clobber the register, mark it as equal, as we know the
+          value is dead so it don't have to match.  */
+       case CLOBBER:
+ 	if (REG_P (XEXP (exp, 0)))
+ 	  CLEAR_REGNO_REG_SET (nonequal, REGNO (XEXP (exp, 0)));
+ 	return false;
+       case SET:
+ 	if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp)))
+ 	  return false;
+ 	if (GET_CODE (SET_SRC (exp)) != REG)
+ 	  return true;
+ 	SET_REGNO_REG_SET (nonequal, REGNO (SET_SRC (exp)));
+ 	return false;
+       default:
+ 	return false;
+     }
+ }
+ /* 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 (mode, e, b)
+      int mode;
+      edge e;
+      basic_block b;
+ {
+   rtx set1, set2, cond1, cond2, insn;
+   enum rtx_code code1, code2, reversed_code2;
+   bool reverse1 = false;
+   int i;
+   regset nonequal;
+   bool failed = false;
+ 
+   /* 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 NULL;
+ 
+   /* Ensure that the comparison operators are equivalent.
+      ??? This is far too pesimistic.  We should allow swapped operands,
+      different CCmodes, or for example comparisons for interval, that
+      dominate even when operands are not equivalent.  */
+   if (!rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
+       || !rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1)))
+     return NULL;
+ 
+   /* Short circuit cases where block B contains some side effects, as we can't
+      safely bypass it.  */
+   for (insn = NEXT_INSN (b->head); insn != NEXT_INSN (b->end);
+        insn = NEXT_INSN (insn))
+     if (INSN_P (insn) && side_effects_p (PATTERN (insn)))
+       return NULL;
+ 
+   cselib_init ();
+ 
+   /* First process all values computed in the source basic block.  */
+   for (insn = NEXT_INSN (e->src->head); insn != NEXT_INSN (e->src->end);
+        insn = NEXT_INSN (insn))
+     if (INSN_P (insn))
+       cselib_process_insn (insn);
+ 
+   nonequal = BITMAP_XMALLOC();
+   CLEAR_REG_SET (nonequal);
+   /* Now assume that we've continued by the edge E to B and continue
+      processing as if it were same basic block.
+    
+      Our goal is to prove that whole block is an NOOP.  */
+   for (insn = NEXT_INSN (b->head); insn != b->end && !failed;
+        insn = NEXT_INSN (insn))
+   {
+     if (INSN_P (insn))
+       {
+         rtx pat = PATTERN (insn);
+ 
+         if (GET_CODE (pat) == PARALLEL)
+ 	  {
+ 	    for (i = 0; i < XVECLEN (pat, 0); i++)
+ 	      failed |= mark_effect (XVECEXP (pat, 0, i), nonequal);
+ 	  }
+ 	else
+ 	  failed |= mark_effect (pat, nonequal);
+       }
+     cselib_process_insn (insn);
+   }
+ 
+   /* Later we should clear nonequal of dead registers.  So far we don't
+      have life information in cfg_cleanup.  */
+   if (failed)
+     goto failed;
+ 
+   /* In case liveness information is available, we need to prove equivalence
+      only of the live values.  */
+   if (mode & CLEANUP_UPDATE_LIFE)
+     AND_REG_SET (nonequal, b->global_live_at_end);
+ 
+   EXECUTE_IF_SET_IN_REG_SET (nonequal, 0, i, goto failed;);
+ 
+   BITMAP_XFREE (nonequal);
+   cselib_finish ();
+   if ((comparison_dominates_p (code1, code2) != 0)
+       != (XEXP (SET_SRC (set2), 0) == pc_rtx))
+     return BRANCH_EDGE (b);
+   else
+     return FALLTHRU_EDGE (b);
+ 
+ failed:
+   BITMAP_XFREE (nonequal);
+   cselib_finish ();
+   return NULL;
+ }
+ 
  /* Attempt to forward edges leaving basic block B.
     Return true if successful.  */
  
*************** try_forward_edges (mode, b)
*** 187,198 ****
       int mode;
  {
    bool changed = false;
!   edge e, next;
  
    for (e = b->succ; e ; e = next)
      {
        basic_block target, first;
        int counter;
  
        next = e->succ_next;
  
--- 338,350 ----
       int mode;
  {
    bool changed = false;
!   edge e, next, threaded_edge;
  
    for (e = b->succ; e ; e = next)
      {
        basic_block target, first;
        int counter;
+       bool threaded = false;
  
        next = e->succ_next;
  
*************** try_forward_edges (mode, b)
*** 207,222 ****
        target = first = e->dest;
        counter = 0;
  
!       /* Look for the real destination of the jump.
!          Avoid infinite 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;
  
  	  /* Avoid killing of loop pre-headers, as it is the place loop
  	     optimizer wants to hoist code to.
--- 359,390 ----
        target = first = e->dest;
        counter = 0;
  
!       while (counter < n_basic_blocks)
  	{
! 	  basic_block new_target = NULL;
! 	  bool new_target_threaded = false;
! 
! 	  if (FORWARDER_BLOCK_P (target)
! 	      && target->succ->dest != EXIT_BLOCK_PTR)
! 	    {
! 	      /* Bypass trivial infinite loops.  */
! 	      if (target == target->succ->dest)
! 		counter = n_basic_blocks;
! 	      new_target = target->succ->dest;
! 	    }
! 	  /* Allow to thread only over one edge at time to simplify updating
! 	     of probabilities.  */
! 	  else if ((mode & CLEANUP_THREADING) && !threaded)
! 	    {
! 	      threaded_edge = thread_jump (mode, e, target);
! 	      if (threaded_edge)
! 		{
! 		  new_target = threaded_edge->dest;
! 		  new_target_threaded = true;
! 		}
! 	    }
! 	  if (!new_target)
! 	    break;
  
  	  /* Avoid killing of loop pre-headers, as it is the place loop
  	     optimizer wants to hoist code to.
*************** try_forward_edges (mode, b)
*** 241,248 ****
  	      if (GET_CODE (insn) == NOTE)
  		break;
  	    }
! 	  target = target->succ->dest, counter++;
! 	}
  
        if (counter >= n_basic_blocks)
  	{
--- 409,418 ----
  	      if (GET_CODE (insn) == NOTE)
  		break;
  	    }
! 	  counter++;
! 	  target = new_target;
! 	  threaded |= new_target_threaded;
!   	}
  
        if (counter >= n_basic_blocks)
  	{
*************** try_forward_edges (mode, b)
*** 257,293 ****
  	  /* Save the values now, as the edge may get removed.  */
  	  gcov_type edge_count = e->count;
  	  int edge_probability = e->probability;
  
! 	  if (redirect_edge_and_branch (e, target))
  	    {
! 	      /* We successfully forwarded the edge.  Now update profile
! 		 data: for each edge we traversed in the chain, remove
! 		 the original edge's execution count.  */
! 	      int edge_frequency = ((edge_probability * b->frequency
! 				     + REG_BR_PROB_BASE / 2)
! 				    / REG_BR_PROB_BASE);
! 
! 	      if (!FORWARDER_BLOCK_P (b) && forwarder_block_p (b))
! 		BB_SET_FLAG (b, BB_FORWARDER_BLOCK);
! 	      BB_SET_FLAG (b, BB_UPDATE_LIFE);
! 
! 	      do
! 		{
! 		  first->count -= edge_count;
! 		  first->succ->count -= edge_count;
! 		  first->frequency -= edge_frequency;
! 		  first = first->succ->dest;
! 		}
! 	      while (first != target);
! 
! 	      changed = true;
  	    }
! 	  else
  	    {
  	      if (rtl_dump_file)
  		fprintf (rtl_dump_file, "Forwarding edge %i->%i to %i failed.\n",
  			 b->index, e->dest->index, target->index);
  	    }
  	}
      }
  
--- 427,473 ----
  	  /* Save the values now, as the edge may get removed.  */
  	  gcov_type edge_count = e->count;
  	  int edge_probability = e->probability;
+ 	  int edge_frequency;
  
! 	  if (threaded)
  	    {
! 	      notice_new_block (redirect_edge_and_branch_force (e, target));
! 	      if (rtl_dump_file)
! 	        fprintf (rtl_dump_file, "Conditionals threaded.\n");
  	    }
! 	  else if (!redirect_edge_and_branch (e, target))
  	    {
  	      if (rtl_dump_file)
  		fprintf (rtl_dump_file, "Forwarding edge %i->%i to %i failed.\n",
  			 b->index, e->dest->index, target->index);
+ 	      continue;
  	    }
+ 	  /* We successfully forwarded the edge.  Now update profile
+ 	     data: for each edge we traversed in the chain, remove
+ 	     the original edge's execution count.  */
+ 	  edge_frequency = ((edge_probability * b->frequency
+ 			     + REG_BR_PROB_BASE / 2)
+ 			    / REG_BR_PROB_BASE);
+ 
+ 	  if (!FORWARDER_BLOCK_P (b) && forwarder_block_p (b))
+ 	    BB_SET_FLAG (b, BB_FORWARDER_BLOCK);
+ 	  BB_SET_FLAG (b, BB_UPDATE_LIFE);
+ 
+ 	  do
+ 	    {
+ 	      edge t;
+ 	      first->count -= edge_count;
+ 	      first->succ->count -= edge_count;
+ 	      first->frequency -= edge_frequency;
+ 	      if (first->succ->succ_next)
+ 		t = threaded_edge;
+ 	      else
+ 		t = first->succ;
+ 	      first = t->dest;
+ 	    }
+ 	  while (first != target);
+ 
+ 	  changed = true;
  	}
      }
  
Index: jump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/jump.c,v
retrieving revision 1.202
diff -c -3 -p -r1.202 jump.c
*** jump.c	2001/11/21 23:41:39	1.202
--- jump.c	2001/12/14 20:59:51
*************** static void invert_exp_1		PARAMS ((rtx))
*** 69,75 ****
  static int invert_exp			PARAMS ((rtx));
  static int returnjump_p_1	        PARAMS ((rtx *, void *));
  static void delete_prior_computation    PARAMS ((rtx, rtx));
- static void mark_modified_reg		PARAMS ((rtx, rtx, void *));
  
  /* Alternate entry into the jump optimizer.  This entry point only rebuilds
     the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
--- 69,74 ----
*************** true_regnum (x)
*** 2426,2895 ****
  					   SUBREG_BYTE (x), GET_MODE (x));
      }
    return -1;
- }
- 
- /* Optimize code of the form:
- 
- 	for (x = a[i]; x; ...)
- 	  ...
- 	for (x = a[i]; x; ...)
- 	  ...
-       foo:
- 
-    Loop optimize will change the above code into
- 
- 	if (x = a[i])
- 	  for (;;)
- 	     { ...; if (! (x = ...)) break; }
- 	if (x = a[i])
- 	  for (;;)
- 	     { ...; if (! (x = ...)) break; }
-       foo:
- 
-    In general, if the first test fails, the program can branch
-    directly to `foo' and skip the second try which is doomed to fail.
-    We run this after loop optimization and before flow analysis.  */
- 
- /* When comparing the insn patterns, we track the fact that different
-    pseudo-register numbers may have been used in each computation.
-    The following array stores an equivalence -- same_regs[I] == J means
-    that pseudo register I was used in the first set of tests in a context
-    where J was used in the second set.  We also count the number of such
-    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;
-      void *data ATTRIBUTE_UNUSED;
- {
-   int regno;
-   unsigned int i;
- 
-   if (GET_CODE (dest) == SUBREG)
-     dest = SUBREG_REG (dest);
- 
-   if (GET_CODE (dest) == MEM)
-     modified_mem = 1;
- 
-   if (GET_CODE (dest) != REG)
-     return;
- 
-   regno = REGNO (dest);
-   if (regno >= FIRST_PSEUDO_REGISTER)
-     modified_regs[regno] = 1;
-   /* Don't consider a hard condition code register as modified,
-      if it is only being set.  thread_jumps will check if it is set
-      to the same value.  */
-   else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC
- 	   || GET_CODE (x) != SET
- 	   || ! rtx_equal_p (dest, SET_DEST (x))
- 	   || HARD_REGNO_NREGS (regno, GET_MODE (dest)) != 1)
-     for (i = 0; i < HARD_REGNO_NREGS (regno, GET_MODE (dest)); i++)
-       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
-    modified objects as not equal.
- 
-    YINSN is the insn containing Y.  */
- 
- int
- rtx_equal_for_thread_p (x, y, yinsn)
-      rtx x, y;
-      rtx yinsn;
- {
-   int i;
-   int j;
-   enum rtx_code code;
-   const char *fmt;
- 
-   code = GET_CODE (x);
-   /* Rtx's of different codes cannot be equal.  */
-   if (code != GET_CODE (y))
-     return 0;
- 
-   /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
-      (REG:SI x) and (REG:HI x) are NOT equivalent.  */
- 
-   if (GET_MODE (x) != GET_MODE (y))
-     return 0;
- 
-   /* For floating-point, consider everything unequal.  This is a bit
-      pessimistic, but this pass would only rarely do anything for FP
-      anyway.  */
-   if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-       && FLOAT_MODE_P (GET_MODE (x)) && ! flag_unsafe_math_optimizations)
-     return 0;
- 
-   /* For commutative operations, the RTX match if the operand match in any
-      order.  Also handle the simple binary and unary cases without a loop.  */
-   if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
-     return ((rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
- 	     && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn))
- 	    || (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 1), yinsn)
- 		&& rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 0), yinsn)));
-   else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
-     return (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
- 	    && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn));
-   else if (GET_RTX_CLASS (code) == '1')
-     return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
- 
-   /* Handle special-cases first.  */
-   switch (code)
-     {
-     case REG:
-       if (REGNO (x) == REGNO (y) && ! modified_regs[REGNO (x)])
-         return 1;
- 
-       /* If neither is user variable or hard register, check for possible
- 	 equivalence.  */
-       if (REG_USERVAR_P (x) || REG_USERVAR_P (y)
- 	  || REGNO (x) < FIRST_PSEUDO_REGISTER
- 	  || REGNO (y) < FIRST_PSEUDO_REGISTER)
- 	return 0;
- 
-       if (same_regs[REGNO (x)] == -1)
- 	{
- 	  same_regs[REGNO (x)] = REGNO (y);
- 	  num_same_regs++;
- 
- 	  /* If this is the first time we are seeing a register on the `Y'
- 	     side, see if it is the last use.  If not, we can't thread the
- 	     jump, so mark it as not equivalent.  */
- 	  if (REGNO_LAST_UID (REGNO (y)) != INSN_UID (yinsn))
- 	    return 0;
- 
- 	  return 1;
- 	}
-       else
- 	return (same_regs[REGNO (x)] == (int) REGNO (y));
- 
-       break;
- 
-     case MEM:
-       /* If memory modified or either volatile, not equivalent.
- 	 Else, check address.  */
-       if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- 	return 0;
- 
-       return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
- 
-     case ASM_INPUT:
-       if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- 	return 0;
- 
-       break;
- 
-     case SET:
-       /* Cancel a pending `same_regs' if setting equivalenced registers.
- 	 Then process source.  */
-       if (GET_CODE (SET_DEST (x)) == REG
-           && GET_CODE (SET_DEST (y)) == REG)
- 	{
- 	  if (same_regs[REGNO (SET_DEST (x))] == (int) REGNO (SET_DEST (y)))
- 	    {
- 	      same_regs[REGNO (SET_DEST (x))] = -1;
- 	      num_same_regs--;
- 	    }
- 	  else if (REGNO (SET_DEST (x)) != REGNO (SET_DEST (y)))
- 	    return 0;
- 	}
-       else
- 	{
- 	  if (rtx_equal_for_thread_p (SET_DEST (x), SET_DEST (y), yinsn) == 0)
- 	    return 0;
- 	}
- 
-       return rtx_equal_for_thread_p (SET_SRC (x), SET_SRC (y), yinsn);
- 
-     case LABEL_REF:
-       return XEXP (x, 0) == XEXP (y, 0);
- 
-     case SYMBOL_REF:
-       return XSTR (x, 0) == XSTR (y, 0);
- 
-     default:
-       break;
-     }
- 
-   if (x == y)
-     return 1;
- 
-   fmt = GET_RTX_FORMAT (code);
-   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-     {
-       switch (fmt[i])
- 	{
- 	case 'w':
- 	  if (XWINT (x, i) != XWINT (y, i))
- 	    return 0;
- 	  break;
- 
- 	case 'n':
- 	case 'i':
- 	  if (XINT (x, i) != XINT (y, i))
- 	    return 0;
- 	  break;
- 
- 	case 'V':
- 	case 'E':
- 	  /* Two vectors must have the same length.  */
- 	  if (XVECLEN (x, i) != XVECLEN (y, i))
- 	    return 0;
- 
- 	  /* And the corresponding elements must match.  */
- 	  for (j = 0; j < XVECLEN (x, i); j++)
- 	    if (rtx_equal_for_thread_p (XVECEXP (x, i, j),
- 					XVECEXP (y, i, j), yinsn) == 0)
- 	      return 0;
- 	  break;
- 
- 	case 'e':
- 	  if (rtx_equal_for_thread_p (XEXP (x, i), XEXP (y, i), yinsn) == 0)
- 	    return 0;
- 	  break;
- 
- 	case 'S':
- 	case 's':
- 	  if (strcmp (XSTR (x, i), XSTR (y, i)))
- 	    return 0;
- 	  break;
- 
- 	case 'u':
- 	  /* These are just backpointers, so they don't matter.  */
- 	  break;
- 
- 	case '0':
- 	case 't':
- 	  break;
- 
- 	  /* It is believed that rtx's at this level will never
- 	     contain anything but integers and other rtx's,
- 	     except for within LABEL_REFs and SYMBOL_REFs.  */
- 	default:
- 	  abort ();
- 	}
-     }
-   return 1;
  }
--- 2425,2428 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.h,v
retrieving revision 1.319
diff -c -3 -p -r1.319 rtl.h
*** rtl.h	2001/12/12 22:50:04	1.319
--- rtl.h	2001/12/14 20:59:52
*************** extern int true_regnum			PARAMS ((rtx));
*** 1788,1795 ****
  extern int redirect_jump_1		PARAMS ((rtx, rtx));
  extern int redirect_jump		PARAMS ((rtx, rtx, int));
  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 enum rtx_code reversed_comparison_code PARAMS ((rtx, rtx));
  extern enum rtx_code reversed_comparison_code_parts PARAMS ((enum rtx_code,
  							     rtx, rtx, rtx));
--- 1788,1793 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.557
diff -c -3 -p -r1.557 toplev.c
*** toplev.c	2001/12/13 21:37:27	1.557
--- toplev.c	2001/12/14 20:59:53
*************** rest_of_compilation (decl)
*** 2680,2686 ****
    if (optimize > 0)
      {
        find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!       cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
  
        /* ??? Run if-conversion before delete_null_pointer_checks,
           since the later does not preserve the CFG.  This should
--- 2680,2687 ----
    if (optimize > 0)
      {
        find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
!       cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP
!  		   | (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)
*** 2721,2733 ****
  
        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
--- 2722,2727 ----
*************** rest_of_compilation (decl)
*** 2750,2763 ****
        delete_trivially_dead_insns (insns, max_reg_num (), 0);
  
        /* 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 | CLEANUP_PRE_LOOP);
  
! 	  delete_null_pointer_checks (insns);
  	  /* CFG is no longer maintained up-to-date.  */
  	  free_bb_for_insn ();
  	  timevar_pop (TV_JUMP);
--- 2744,2759 ----
        delete_trivially_dead_insns (insns, max_reg_num (), 0);
  
        /* 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 | CLEANUP_PRE_LOOP
! 		       | (flag_thread_jumps ? CLEANUP_THREADING : 0));
  
! 	  if (flag_delete_null_pointer_checks)
! 	    delete_null_pointer_checks (insns);
  	  /* CFG is no longer maintained up-to-date.  */
  	  free_bb_for_insn ();
  	  timevar_pop (TV_JUMP);
*************** rest_of_compilation (decl)
*** 2928,2943 ****
  	    }
  	}
  
-       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);
  
--- 2924,2929 ----
*************** rest_of_compilation (decl)
*** 2955,2961 ****
    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
--- 2941,2948 ----
    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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]