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]

ia32: check_decr_loop


As documented, 

+   /* Look for loops of the form
+      while (a--) { ... }
+      where a is not used inside the loop, and optimize them. */

It was implemented to get a few percent on a tiny loop on a benchmark.
It seems somewhat silly, except to my surprise the optimization is
triggered occasionally by real code too -- three times in cc1 itself.


r~


	* loop.h (struct iv_class): Add initial_test_insn, initial_test_jump.
	* loop.c (strength_reduce): Enhance biv initial value scan; set
	initial_test_insn and initial_test_jump at the same time.
	Call check_decr_loop.
	(record_biv): Clear initial_test_insn, initial_test_jump.
	(fixup_decr_loop_info): New.
	(check_decr_loop): New.
	(loop_emit_jump_insn_after): New.
	(loop_emit_jump_insn_before): New.
	(check_dbra_loop): Use it.
	(instrument_loop_bct): Likewise.
	
Index: loop.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/loop.c,v
retrieving revision 1.171
diff -c -p -d -r1.171 loop.c
*** loop.c	1999/08/09 13:59:46	1.171
--- loop.c	1999/08/10 02:50:04
*************** Boston, MA 02111-1307, USA.  */
*** 50,55 ****
--- 50,57 ----
  #include "loop.h"
  #include "except.h"
  #include "toplev.h"
+ #include "output.h"
+ #include "basic-block.h"
  
  /* Vector mapping INSN_UIDs to luids.
     The luids are like uids but increase monotonically always.
*************** static int general_induction_var PROTO((
*** 328,333 ****
--- 330,337 ----
  static int consec_sets_giv PROTO((int, rtx, rtx, rtx, rtx *, rtx *, rtx *));
  static int check_dbra_loop PROTO((rtx, int, rtx, struct loop_info *));
  static rtx express_from_1 PROTO((rtx, rtx, rtx));
+ static int fixup_decr_loop_info PROTO((struct iv_class *, rtx, rtx, rtx));
+ static int check_decr_loop PROTO((rtx, rtx, struct loop_info *));
  static rtx combine_givs_p PROTO((struct induction *, struct induction *));
  static void combine_givs PROTO((struct iv_class *));
  struct recombine_givs_stats;
*************** static int insert_loop_mem PROTO((rtx *,
*** 347,352 ****
--- 351,359 ----
  static int replace_loop_mem PROTO((rtx *, void *));
  static int replace_label PROTO((rtx *, void *));
  
+ static rtx loop_emit_jump_insn_before PROTO((rtx, rtx, rtx));
+ static rtx loop_emit_jump_insn_after PROTO((rtx, rtx, rtx));
+ 
  typedef struct rtx_and_int {
    rtx r;
    int i;
*************** strength_reduce (scan_start, end, loop_t
*** 3927,3971 ****
        return;
      }
  
!   /* Find initial value for each biv by searching backwards from loop_start,
       halting at first label.  Also record any test condition.  */
  
!   call_seen = 0;
!   for (p = loop_start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
!     {
!       note_insn = p;
  
!       if (GET_CODE (p) == CALL_INSN)
! 	call_seen = 1;
  
!       if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
! 	  || GET_CODE (p) == CALL_INSN)
! 	note_stores (PATTERN (p), record_initial);
  
!       /* Record any test of a biv that branches around the loop if no store
! 	 between it and the start of loop.  We only care about tests with
! 	 constants and registers and only certain of those.  */
!       if (GET_CODE (p) == JUMP_INSN
! 	  && JUMP_LABEL (p) != 0
! 	  && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end)
! 	  && (test = get_condition_for_loop (p)) != 0
! 	  && GET_CODE (XEXP (test, 0)) == REG
! 	  && REGNO (XEXP (test, 0)) < max_reg_before_loop
! 	  && (bl = reg_biv_class[REGNO (XEXP (test, 0))]) != 0
! 	  && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop_start)
! 	  && bl->init_insn == 0)
! 	{
! 	  /* If an NE test, we have an initial value!  */
! 	  if (GET_CODE (test) == NE)
! 	    {
! 	      bl->init_insn = p;
! 	      bl->init_set = gen_rtx_SET (VOIDmode,
! 					  XEXP (test, 0), XEXP (test, 1));
! 	    }
! 	  else
! 	    bl->initial_test = test;
! 	}
!     }
  
    /* Look at the each biv and see if we can say anything better about its
       initial value from any initializing insns set up above.  (This is done
--- 3934,3998 ----
        return;
      }
  
!   {
!     /* Sometimes the insn immediately after the end of the loop is an
!        unconditional jump. */
! 
!     rtx loop_dest = next_real_insn (loop_end);
!     rtx loop_dest_2 = loop_dest;
!     if (loop_dest_2
! 	&& GET_CODE (loop_dest_2) == JUMP_INSN
! 	&& simplejump_p (loop_dest_2)
! 	&& JUMP_LABEL (loop_dest_2))
!       {
! 	loop_dest_2 = next_real_insn (JUMP_LABEL (loop_dest_2));
!       }
! 
!     /* Find initial value for each biv by searching backwards from loop_start,
       halting at first label.  Also record any test condition.  */
  
!     call_seen = 0;
!     for (p = loop_start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
!       {
! 	note_insn = p;
  
! 	if (GET_CODE (p) == CALL_INSN)
! 	  call_seen = 1;
  
! 	if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
! 	    || GET_CODE (p) == CALL_INSN)
! 	  note_stores (PATTERN (p), record_initial);
  
! 	/* Record any test of a biv that branches around the loop if no store
! 	   between it and the start of loop.  We only care about tests with
! 	   constants and registers and only certain of those.  */
! 	if (GET_CODE (p) == JUMP_INSN
! 	    && JUMP_LABEL (p) != 0
! 	    && (next_real_insn (JUMP_LABEL (p)) == loop_dest
! 		|| next_real_insn (JUMP_LABEL (p)) == loop_dest_2)
! 	    && (test = get_condition_for_loop (p)) != 0
! 	    && GET_CODE (XEXP (test, 0)) == REG
! 	    && REGNO (XEXP (test, 0)) < max_reg_before_loop
! 	    && (bl = reg_biv_class[REGNO (XEXP (test, 0))]) != 0
! 	    && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop_start)
! 	    && bl->init_insn == 0)
! 	  {
! 	    /* If an NE test, we have an initial value!  */
! 	    if (GET_CODE (test) == NE)
! 	      {
! 		bl->init_insn = p;
! 		bl->init_set = gen_rtx_SET (VOIDmode,
! 					    XEXP (test, 0), XEXP (test, 1));
! 	      }
! 	    else
! 	      {
! 		get_condition (p, &bl->initial_test_insn);
! 		bl->initial_test = test;
! 		bl->initial_test_jump = p;
! 	      }
! 	  }
!       }
!   }
  
    /* Look at the each biv and see if we can say anything better about its
       initial value from any initializing insns set up above.  (This is done
*************** strength_reduce (scan_start, end, loop_t
*** 4028,4033 ****
--- 4055,4061 ----
  	      && uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
  	      && GET_CODE (src) == PLUS
  	      && GET_CODE (XEXP (src, 0)) == REG
+ 	      && REGNO (XEXP (src, 0)) != bl->regno
  	      && CONSTANT_P (XEXP (src, 1))
  	      && ((increment = biv_total_increment (bl, loop_start, loop_end))
  		  != NULL_RTX))
*************** strength_reduce (scan_start, end, loop_t
*** 4555,4560 ****
--- 4583,4593 ----
       so that "decrement and branch until zero" insn can be used.  */
    check_dbra_loop (loop_end, insn_count, loop_start, loop_info);
  
+   /* Look for loops of the form
+      while (a--) { ... }
+      where a is not used inside the loop, and optimize them. */
+   check_decr_loop (loop_end, loop_start, loop_info);
+ 
    /* Create reg_map to hold substitutions for replaceable giv regs.
       Some givs might have been made from biv increments, so look at
       reg_iv_type for a suitable size.  */
*************** record_biv (v, insn, dest_reg, inc_val, 
*** 5337,5342 ****
--- 5370,5377 ----
        bl->init_insn = 0;
        bl->init_set = 0;
        bl->initial_test = 0;
+       bl->initial_test_insn = 0;
+       bl->initial_test_jump = 0;
        bl->incremented = 0;
        bl->eliminable = 0;
        bl->nonneg = 0;
*************** check_dbra_loop (loop_end, insn_count, l
*** 8098,8112 ****
  				       XEXP (jump_label, 0));
  	      tem = gen_sequence ();
  	      end_sequence ();
! 	      emit_jump_insn_before (tem, loop_end);
! 
! 	      for (tem = PREV_INSN (loop_end);
! 		   tem && GET_CODE (tem) != JUMP_INSN;
! 		   tem = PREV_INSN (tem))
! 		;
! 
! 	      if (tem)
! 		JUMP_LABEL (tem) = XEXP (jump_label, 0);
  
  	      if (nonneg)
  		{
--- 8133,8140 ----
  				       XEXP (jump_label, 0));
  	      tem = gen_sequence ();
  	      end_sequence ();
! 	      tem = loop_emit_jump_insn_before (tem, loop_end,
! 						XEXP (jump_label, 0));
  
  	      if (nonneg)
  		{
*************** check_dbra_loop (loop_end, insn_count, l
*** 8178,8183 ****
--- 8206,8761 ----
    return 0;
  }
  
+ /* 
+    Try to fix up loops of the form
+ 
+    tmp = a;
+    a--;
+    if (! tmp)
+    	goto done;
+    loop:
+    ...
+    tmp = a;
+    a--;
+    if (tmp)
+    	goto loop;
+    done:
+ 
+    This would be converted into
+    if (! a)
+    	goto done;
+    loop:
+    ...
+    a--;
+    if (a)
+    	goto loop;
+ 
+    There are a few common variations on this theme. Sometimes the
+    temporary is not set directly to a, but to a constant value;
+    sometimes the outer decrement is not actually performed as a
+    decrement, but as a second assignment. Sometimes we do the outer
+    comparison against the biv directly instead of a temporary.
+ 
+    INNER_SET is the insn containing the inner set of the temp register
+    used to compare against. */
+ 
+ static int
+ fixup_decr_loop_info (bl, loop_start, loop_end, inner_set)
+      struct iv_class *bl;
+      rtx loop_start, loop_end;
+      rtx inner_set;
+ {
+   rtx p;
+   rtx biv_set = single_set (bl->biv->insn);
+ 
+   /* The jump insn outside the loop. */
+   rtx outer_jump_insn;
+   /* And its compare. */
+   rtx outer_compare_insn;
+   /* And the comparison. */
+   rtx outer_comparison;
+ 
+   /* The jump insn inside the loop. */
+   rtx inner_jump_insn = PREV_INSN (loop_end);
+   /* And its compare. */
+   rtx inner_compare_insn;
+   /* And its comparison. */
+   rtx inner_comparison;
+   /* The register used in the compare. */
+   rtx inner_compare_reg;
+ 
+   /* The insn we end up at after exiting the loop. */
+   rtx final_dest = NULL_RTX;
+ 
+   /* The label for the end of the loop. */
+   rtx jump_label;
+ 
+   /* If there is a decrement before the loop, this is its insn. */
+   rtx outer_decr_insn = NULL_RTX;
+ 
+   rtx real_init = NULL_RTX;
+   rtx outer_set = NULL_RTX;
+ 
+   get_condition (inner_jump_insn, &inner_compare_insn);
+   inner_compare_reg = SET_DEST (PATTERN (inner_set));
+   inner_comparison = get_condition_for_loop (inner_jump_insn);
+ 
+   {
+     /* Sometimes the loop is immediately followed by an unconditional
+        jump. */
+     rtx p = next_real_insn (loop_end);
+ 
+     if (p != NULL_RTX
+ 	&& GET_CODE (p) == JUMP_INSN
+ 	&& simplejump_p (p)
+ 	&& JUMP_LABEL (p))
+       {
+ 	final_dest = next_real_insn (JUMP_LABEL (p));
+       }
+   }
+ 
+   if (biv_set == NULL_RTX)
+     return 0;
+ 
+   /* We're decrementing the register outside the loop. bl->init_insn is
+      pointing to it. (It may not actually be a decrement. It could be
+      a constant set.) */
+   if (! rtx_equal_p (biv_set, bl->init_set))
+     {
+       if (GET_CODE (SET_SRC (biv_set)) != CONST_INT)
+ 	return 0;
+     }
+ 
+   outer_decr_insn = bl->init_insn;
+ 
+   /* Look for the outer jump. It may have been deleted, however. */
+   for (p = NEXT_INSN (bl->init_insn); p != loop_start && p; p = NEXT_INSN (p))
+     {
+       if (GET_CODE (p) == JUMP_INSN)
+ 	{
+ 	  break;
+ 	}
+     }
+ 
+   if (p && p != loop_start)
+     {
+       /* Wrong dest? */
+       if (JUMP_LABEL (p) == 0
+ 	  || (next_real_insn (JUMP_LABEL (p)) != next_real_insn (loop_end)
+ 	      && next_real_insn (JUMP_LABEL (p)) != final_dest))
+ 	{
+ 	  return 0;
+ 	}
+       outer_jump_insn = p;
+     }
+   else
+     {
+       outer_jump_insn = NULL_RTX;
+     }
+ 
+   if (outer_jump_insn != NULL_RTX)
+     {
+       /* Get the condition info for the outer jump. */
+       get_condition (outer_jump_insn, &outer_compare_insn);
+       outer_comparison = get_condition_for_loop (outer_jump_insn);
+ 
+       /* For the outer jump, we're comparing against the outer temporary
+          rather than the biv directly. Find the set for the outer
+          temporary as a sanity check. */
+ 
+       if (XEXP (outer_comparison, 0) != bl->biv->dest_reg)
+ 	{
+ 	  rtx set;
+ 
+ 	  for (outer_set = PREV_INSN (bl->init_insn);
+ 	       outer_set != NULL_RTX && GET_CODE (outer_set) != CODE_LABEL;
+ 	       outer_set = PREV_INSN (outer_set))
+ 	    {
+ 	      set = single_set (outer_set);
+ 	      if (set && SET_DEST (set) == XEXP (outer_comparison, 0))
+ 		break;
+ 	    }
+ 	  if (outer_set == NULL_RTX || GET_CODE (outer_set) == CODE_LABEL)
+ 	    return 0;
+ 
+ 	  if (SET_SRC (set) != bl->biv->dest_reg)
+ 	    {
+ 	      /* FIXME We must check the SET_SRC of the temporary to
+ 		 make sure it really is the temporary we're looking
+ 		 for. Don't believe in what the Force tells you. */
+ 	      if (GET_CODE (SET_SRC (set)) != CONST_INT)
+ 		return 0;
+ 	    }
+ 	}
+     }
+ 
+   /* Look for the actual initialization of the biv. */
+   for (p = PREV_INSN (outer_decr_insn); p && GET_CODE (p) != CODE_LABEL;
+        p = PREV_INSN (p))
+     {
+       rtx s2 = single_set (p);
+       if (s2 && SET_DEST (s2) == bl->biv->dest_reg)
+ 	{
+ 	  break;
+ 	}
+     }
+ 
+   if (p && GET_CODE (p) != CODE_LABEL)
+     {
+       real_init = p;
+     }
+   else
+     {
+       /* Didn't find it. Give up. */
+       return 0;
+     }
+ 
+   if (outer_jump_insn == NULL_RTX)
+     {
+       rtx set = single_set (real_init);
+       if (! CONSTANT_P (SET_SRC (set)))
+ 	{
+ 	  /* Be paranoid. The jump should only have been deleted if
+ 	     the initial value is a constant. */
+ 	  return 0;
+ 	}
+     }
+ 
+   /* Make sure the inner temporary reg used to compare against isn't
+      used anywhere else. */
+   for (p = NEXT_INSN (inner_set); p; p = NEXT_INSN (p))
+     {
+       if (p == inner_compare_insn)
+ 	continue;
+       if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+ 	{
+ 	  if (reg_mentioned_p (inner_compare_reg, PATTERN (p)))
+ 	    return 0;
+ 	}
+     }
+ 
+   /* Find the jump label of dest of the inner jump. */
+   jump_label = XEXP (SET_SRC (PATTERN (inner_jump_insn)), 1);
+   if (jump_label == pc_rtx)
+     jump_label = XEXP (SET_SRC (PATTERN (inner_jump_insn)), 2);
+ 
+   LABEL_NUSES (XEXP (jump_label, 0))++;
+ 
+   /* Make a new comparison against the biv register directly, and
+      replace the old compare-n-jump with it. */
+ 
+   start_sequence ();
+   emit_cmp_and_jump_insns (bl->biv->dest_reg, XEXP (inner_comparison, 1),
+ 			   GET_CODE (inner_comparison), NULL_RTX,
+ 			   GET_MODE (bl->biv->dest_reg), 0, 0,
+ 			   XEXP (jump_label, 0));
+   p = gen_sequence ();
+   end_sequence ();
+ 
+   delete_insn (inner_jump_insn);
+ 
+   if (inner_jump_insn != inner_compare_insn)
+     delete_insn (inner_compare_insn);
+ 
+   /* Don't need to set the inner temporary anymore (We could let it be
+      deleted as a dead reg). */
+   delete_insn (inner_set);
+ 
+   loop_emit_jump_insn_before (p, loop_end, XEXP (jump_label, 0));
+ 
+   delete_insn (outer_decr_insn);
+ 
+   if (outer_jump_insn != NULL_RTX)
+     {
+       if (XEXP (outer_comparison, 0) != bl->biv->dest_reg)
+ 	{
+ 	  /* Emit a new comparison directly against the biv register. */
+ 	  LABEL_NUSES (JUMP_LABEL (outer_jump_insn))++;
+ 
+ 	  start_sequence ();
+ 	  emit_cmp_and_jump_insns (bl->biv->dest_reg,
+ 				   XEXP (outer_comparison, 1),
+ 				   GET_CODE (outer_comparison), NULL_RTX,
+ 				   GET_MODE (bl->biv->dest_reg), 0, 0,
+ 				   JUMP_LABEL (outer_jump_insn));
+ 	  p = gen_sequence ();
+ 	  end_sequence ();
+ 	  loop_emit_jump_insn_after (p, outer_jump_insn,
+ 				     JUMP_LABEL (outer_jump_insn));
+ 	  delete_insn (outer_compare_insn);
+ 	  if (outer_compare_insn != outer_jump_insn)
+ 	    delete_insn (outer_jump_insn);
+ 	}
+     }
+ 
+   bl->init_insn = real_init;
+   return 1;
+ }
+ 
+ static int
+ check_decr_loop (loop_end, loop_start, loop_info)
+      rtx loop_end;
+      rtx loop_start;
+      struct loop_info *loop_info;
+ {
+   rtx jump;
+   rtx comparison;
+   rtx first_compare;
+   struct iv_class *bl;
+   rtx insn;
+   rtx jump_label;
+   int loop_compare_and_branch;
+   int compare_with_prev = 0;
+   rtx inner_set;
+   rtx initial_jump_label = NULL_RTX;
+ 
+   /* If there is more than one exit from the loop, we can't optimize
+      it. */
+   if (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+     return 0;
+ 
+   /* We're looking for
+      while (a-- != VALUE) {
+      	...
+      }
+      where a is not used except as a counter. */
+   jump = PREV_INSN (loop_end);
+   comparison = get_condition_for_loop (jump);
+   if (comparison == 0)
+     return 0;
+ 
+   /* Try to compute whether the compare/branch at the loop end is one or
+      two instructions.  */
+   get_condition (jump, &first_compare);
+   if (first_compare == jump)
+     loop_compare_and_branch = 1;
+   else if (first_compare == prev_nonnote_insn (jump))
+     loop_compare_and_branch = 2;
+   else
+     return 0;
+ 
+   /* Check all of the bivs to see if the compare uses one of them.
+      Skip bivs set more than once or that have more than one giv. Also
+      skip if the biv is used between its update and the test insn.  */
+ 
+   for (bl = loop_iv_list; bl; bl = bl->next)
+     {
+       if (bl->biv_count == 1
+ 	  && bl->incremented
+ 	  && bl->giv_count == 0
+ 	  && bl->init_insn != NULL_RTX
+ 	  && bl->biv->dest_reg == XEXP (comparison, 0)
+ 	  && ! reg_used_between_p (regno_reg_rtx[bl->regno], bl->biv->insn,
+ 				   first_compare))
+ 	break;
+     }
+ 
+   if (! bl)
+     {
+       /* The loop test may be of the form
+ 	 tmp = a;
+ 	 a--;
+ 	 if (tmp)... */
+ 
+       /* We only allow comparisons against 0 here.  (Probably being
+ 	 too paranoid.)  */
+       if (XEXP (comparison, 1) != const0_rtx)
+ 	{
+ 	  return 0;
+ 	}
+       for (bl = loop_iv_list; bl; bl = bl->next)
+ 	{
+ 	  /* We're assuming that the set of the temporary appears
+ 	     immediately before the decrement, and that it's a simple
+ 	     SET. */
+ 	  rtx set = single_set (PREV_INSN (bl->biv->insn));
+ 	  if (bl->biv_count == 1
+ 	      && bl->giv_count == 1
+ 	      && bl->incremented
+ 	      && set != NULL_RTX
+ 	      && SET_DEST (set) == XEXP (comparison, 0)
+ 	      && SET_SRC (set) == bl->biv->dest_reg)
+ 	    {
+ 	      break;
+ 	    }
+ 	}
+       if (bl == NULL)
+ 	return 0;
+       compare_with_prev = 1;
+     }
+ 
+   /* We can only optimize for a decrement of 1. */
+   if (bl->biv->mult_val != const1_rtx
+       || GET_CODE (bl->biv->add_val) != CONST_INT
+       || INTVAL (bl->biv->add_val) != -1)
+     return 0;
+ 
+   /* The biv has a test before the loop. Make sure it is what we expect. */
+   if (bl->initial_test)
+     {
+       if (! rtx_equal_p (XEXP (bl->initial_test, 0), XEXP (comparison, 0)))
+ 	return 0;
+ 
+       if (! rtx_equal_p (XEXP (bl->initial_test, 1), XEXP (comparison, 1)))
+ 	return 0;
+ 
+       if (GET_CODE (bl->initial_test) == GET_CODE (comparison))
+ 	{
+ 	  if (! compare_with_prev)
+ 	    return 0;
+ 	}
+       else
+ 	{
+ 	  if (compare_with_prev)
+ 	    return 0;
+ 	}
+     }
+ 
+   if (! compare_with_prev)
+     {
+       /* Check if we don't have a final value, or if it's already
+ 	 zero. */
+       if (loop_info->final_value == NULL_RTX
+ 	  || GET_CODE (loop_info->final_value) != CONST_INT
+ 	  || INTVAL (loop_info->final_value) == 0)
+ 	return 0;
+     }
+   else
+     {
+       if (loop_info->final_value != const0_rtx)
+ 	{
+ 	  /* The loop seems to have a final value. */
+ 	  if (loop_info->final_value != NULL_RTX)
+ 	    return 0;
+ 
+ 	  loop_info->final_value = const0_rtx;
+ 	}
+     }
+ 
+   {
+     rtx bivreg = regno_reg_rtx[bl->regno];
+     rtx p;
+     rtx compare_reg = NULL_RTX;
+ 
+     /* Make sure there are no uses except to count.  */
+     for (p = bl->init_insn ? bl->init_insn : loop_start;
+ 	 p != loop_end; p = NEXT_INSN (p))
+       {
+ 
+ 	if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+ 	  {
+ 	    rtx set = single_set (p);
+ 	  
+ 	    if (p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+ 		|| p == prev_nonnote_insn (loop_end)
+ 		|| p == bl->biv->insn
+ 		|| p == bl->init_insn
+ 		|| p == bl->initial_test_insn
+ 		|| p == bl->initial_test_jump)
+ 	      /* Don't bother about the end test or the decrement. */
+ 	      ;
+ 	    else if (set && GET_CODE (SET_DEST (set)) == REG
+ 		     && REGNO (SET_DEST (set)) == bl->regno)
+ 	      /* An insn that sets the biv is not okay.  */
+ 	      return 0;
+ 	    else if (reg_mentioned_p (bivreg, PATTERN (p)))
+ 	      {
+ 		if (compare_with_prev
+ 		    && set && REGNO (SET_SRC (set)) == bl->regno
+ 		    && SET_DEST (set) == XEXP (comparison, 0))
+ 		  {
+ 		    /* This is the inner insn that sets the temporary
+ 		       used in the loop test. */
+ 		    inner_set = p;
+ 		    compare_reg = XEXP (comparison, 0);
+ 		  }
+ 		else
+ 		  {
+ 		    return 0;
+ 		  }
+ 	      }
+ 	    else if (compare_reg && reg_mentioned_p (compare_reg, PATTERN (p)))
+ 	      {
+ 		/* The compare reg is used somewhere else, we can't
+ 		   optimize.  */
+ 		return 0;
+ 	      }
+ 	  }
+       }
+   }
+ 
+   if (compare_with_prev)
+     return fixup_decr_loop_info (bl, loop_start, loop_end, inner_set);
+ 
+   /* Determine the new initial value. */
+   if (GET_CODE (bl->initial_value) == CONST_INT)
+     {
+       bl->initial_value = 
+ 	GEN_INT (INTVAL (bl->initial_value) - INTVAL (loop_info->final_value));
+     }
+   else
+     {
+       int dummy;
+ 
+       bl->initial_value = simplify_giv_expr
+ 	(gen_rtx_MINUS (GET_MODE (bl->biv->dest_reg),
+ 			bl->initial_value,
+ 			loop_info->final_value), &dummy);
+       if (GET_CODE (bl->initial_value) == USE)
+ 	bl->initial_value = XEXP (bl->initial_value, 0);
+     }
+ 
+   insn = gen_move_insn (bl->biv->dest_reg, bl->initial_value);
+   bl->init_insn = emit_insn_after (insn, bl->init_insn);
+   
+   jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
+   if (jump_label == pc_rtx)
+     jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
+   
+   LABEL_NUSES (XEXP (jump_label, 0))++;
+ 
+   delete_insn (PREV_INSN (loop_end));
+   if (loop_compare_and_branch == 2)
+     delete_insn (first_compare);
+ 
+   start_sequence ();
+   emit_cmp_and_jump_insns (bl->biv->dest_reg, const0_rtx,
+ 			   GET_CODE (comparison), NULL_RTX,
+ 			   GET_MODE (bl->biv->dest_reg), 0, 0,
+ 			   XEXP (jump_label, 0));   
+   insn = gen_sequence ();
+   end_sequence ();
+   loop_emit_jump_insn_before (insn, loop_end, XEXP (jump_label, 0));
+ 
+   if (bl->initial_test_jump)
+     {
+       rtx initial_compare;
+       rtx initial_comparison = get_condition_for_loop (bl->initial_test_jump);
+ 
+       initial_jump_label = JUMP_LABEL (bl->initial_test_jump);
+       LABEL_NUSES (initial_jump_label)++;
+       get_condition (bl->initial_test_jump, &initial_compare);
+       start_sequence ();
+       emit_cmp_and_jump_insns (bl->biv->dest_reg, const0_rtx,
+ 			       GET_CODE (initial_comparison), NULL_RTX,
+ 			       GET_MODE (bl->biv->dest_reg), 0, 0,
+ 			       initial_jump_label);
+       insn = gen_sequence ();
+       end_sequence ();
+       insn = loop_emit_jump_insn_before (insn, initial_compare,
+ 					 initial_jump_label);
+       delete_insn (bl->initial_test_jump);
+       if (bl->initial_test_jump != initial_compare)
+ 	delete_insn (initial_compare);
+       if (GET_CODE (insn) != JUMP_INSN)
+ 	insn = NEXT_INSN (insn);
+       bl->initial_test_jump = insn;
+       bl->initial_test = get_condition_for_loop (bl->initial_test_jump);
+     }
+ 
+   /* Set the correct final value at the end of the loop.  This will be
+      deleted if it is not used. */
+   if (GET_CODE (comparison) != NE)
+     {
+       insn = gen_move_insn (bl->biv->dest_reg, 
+ 			    gen_rtx_PLUS (GET_MODE (bl->biv->dest_reg),
+ 					  bl->biv->dest_reg,
+ 					  loop_info->final_value));
+     }
+   else
+     {
+       insn = gen_move_insn (bl->biv->dest_reg, loop_info->final_value);
+     }
+ 
+   emit_insn_after (insn, initial_jump_label ? initial_jump_label : loop_end);
+ 
+   /* The loop now always terminates on zero. */
+   loop_info->final_value = const0_rtx;
+   loop_info->final_equiv_value = const0_rtx;
+ 
+   return 1;
+ }
+ 
  /* Verify whether the biv BL appears to be eliminable,
     based on the insns in the loop that refer to it.
     LOOP_START is the first insn of the loop, and END is the end insn.
*************** instrument_loop_bct (loop_start, loop_en
*** 9311,9319 ****
        /* Insert new comparison on the count register instead of the
  	 old one, generating the needed BCT pattern (that will be
  	 later recognized by assembly generation phase).  */
!       emit_jump_insn_before (gen_decrement_and_branch_on_count (counter_reg,
! 								start_label),
! 			     loop_end);
        LABEL_NUSES (start_label)++;
      }
  
--- 9889,9897 ----
        /* Insert new comparison on the count register instead of the
  	 old one, generating the needed BCT pattern (that will be
  	 later recognized by assembly generation phase).  */
!       loop_emit_jump_insn_before
! 	(gen_decrement_and_branch_on_count (counter_reg, start_label),
! 	 loop_end, start_label);
        LABEL_NUSES (start_label)++;
      }
  
*************** replace_label (x, data)
*** 9751,9753 ****
--- 10329,10368 ----
    return 0;
  }
  
+ /* Like emit_jump_insn_before, except initialize the jump insn's
+    JUMP_LABEL to LABEL.  Return the jump instruction.  */
+ 
+ static rtx
+ loop_emit_jump_insn_before (insn, before, label)
+      rtx insn, before, label;
+ {
+   rtx p, ret;
+ 
+   ret = emit_jump_insn_before (insn, before);
+   for (p = ret; p ; p = NEXT_INSN (p))
+     if (GET_CODE (p) == JUMP_INSN)
+       {
+ 	JUMP_LABEL (p) = label;
+ 	return p;
+       }
+   abort ();
+ }
+ 
+ /* Like emit_jump_insn_after, except initialize the jump insn's
+    JUMP_LABEL to LABEL.  Return the jump instruction.  */
+ 
+ static rtx
+ loop_emit_jump_insn_after (insn, after, label)
+      rtx insn, after, label;
+ {
+   rtx p, ret;
+ 
+   ret = emit_jump_insn_after (insn, after);
+   for (p = NEXT_INSN (after); p ; p = NEXT_INSN (p))
+     if (GET_CODE (p) == JUMP_INSN)
+       {
+ 	JUMP_LABEL (p) = label;
+ 	return p;
+       }
+   abort ();
+ }
Index: loop.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/loop.h,v
retrieving revision 1.18
diff -c -p -d -r1.18 loop.h
*** loop.h	1999/02/24 11:50:49	1.18
--- loop.h	1999/08/10 02:50:04
*************** struct iv_class {
*** 143,148 ****
--- 143,150 ----
    int total_benefit;		/* Sum of BENEFITs of all those givs */
    rtx initial_value;		/* Value of reg at loop start */
    rtx initial_test;		/* Test performed on BIV before loop */
+   rtx initial_test_insn;	/* Test insn performed on BIV before loop */
+   rtx initial_test_jump;	/* Jump of initial test */
    struct iv_class *next;	/* Links all class structures together */
    rtx init_insn;		/* insn which initializes biv, 0 if none. */
    rtx init_set;			/* SET of INIT_INSN, if any. */


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