This is the mail archive of the gcc@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]

Re: Re-run of loop pass


Michael Hayes writes:
 > I've done some experimentation with this code snippet.  With
 > -funroll-loops or BCT optimisation the generated code is _attrocious_
 > since the constant iteration count cannot be determined.  The patch at
 > the end seems to fix this problem...

I've come up with a better patch that tries to determine what the
expressions for the loop initial and final values are if they are not
constant.  If the initial and final expressions are the sum of an
equivalent base register and some constants, then the initial and
final values are replaced with the constants.  The number of loop
iterations is now simply calculable and thus the loop unroll and loop
BCT optimisations are happy.

Michael.

Index: unroll.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/unroll.c,v
retrieving revision 1.32
diff -c -3 -p -r1.32 unroll.c
*** unroll.c	1998/10/14 09:02:52	1.32
--- unroll.c	1998/10/23 01:42:32
*************** final_giv_value (v, loop_start, loop_end
*** 3403,3408 ****
--- 3403,3445 ----
  }
  
  
+ static rtx
+ loop_equiv_value (loop_start, val)
+      rtx loop_start;
+      rtx val;
+ {
+   rtx insn, set;
+   
+   for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
+     {
+       if (GET_CODE (insn) == CODE_LABEL)
+ 	break;
+       
+       else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 	       && reg_set_p (val, insn))
+ 	{
+ 	  /* We found the last insn before the loop that sets the register.
+ 	     If it sets the entire register, and has a REG_EQUAL note,
+ 	     then use the value of the REG_EQUAL note.  */
+ 	  if ((set = single_set (insn))
+ 		  && (SET_DEST (set) == val))
+ 	    {
+ 	      rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ 	      
+ 	      /* Only use the REG_EQUAL note if it is a constant.
+ 		 Other things, divide in particular, will cause
+ 		 problems later if we use them.  */
+ 	      if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST
+ 		  && CONSTANT_P (XEXP (note, 0)))
+ 		val = XEXP (note, 0);
+ 	      val = SET_SRC (set);
+ 	    }
+ 	  break;
+ 	}
+     }
+   return val;
+ }
+ 
  /* Calculate the number of loop iterations.  Returns the exact number of loop
     iterations if it can be calculated, otherwise returns zero.  */
  
*************** loop_iterations (loop_start, loop_end)
*** 3474,3513 ****
       its value from the insns before the start of the loop.  */
  
    if (GET_CODE (comparison_value) == REG && invariant_p (comparison_value))
      {
!       rtx insn, set;
!     
!       for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
! 	{
! 	  if (GET_CODE (insn) == CODE_LABEL)
! 	    break;
  
! 	  else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
! 		   && reg_set_p (comparison_value, insn))
! 	    {
! 	      /* We found the last insn before the loop that sets the register.
! 		 If it sets the entire register, and has a REG_EQUAL note,
! 		 then use the value of the REG_EQUAL note.  */
! 	      if ((set = single_set (insn))
! 		  && (SET_DEST (set) == comparison_value))
! 		{
! 		  rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
! 
! 		  /* Only use the REG_EQUAL note if it is a constant.
! 		     Other things, divide in particular, will cause
! 		     problems later if we use them.  */
! 		  if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST
! 		      && CONSTANT_P (XEXP (note, 0)))
! 		    comparison_value = XEXP (note, 0);
! 		}
! 	      break;
! 	    }
  	}
      }
  
!   final_value = approx_final_value (comparison_code, comparison_value,
! 				    &unsigned_compare, &compare_dir);
! 
    /* Save the calculated values describing this loop's bounds, in case
       precondition_loop_p will need them later.  These values can not be
       recalculated inside precondition_loop_p because strength reduction
--- 3511,3562 ----
       its value from the insns before the start of the loop.  */
  
    if (GET_CODE (comparison_value) == REG && invariant_p (comparison_value))
+     comparison_value = loop_equiv_value (loop_start, comparison_value);
+ 
+   final_value = approx_final_value (comparison_code, comparison_value,
+ 				    &unsigned_compare, &compare_dir);
+ 
+   if (REG_P (initial_value))
      {
!       rtx temp = final_value;
  
!       /* INITIAL_VALUE = reg1, FINAL_VALUE = reg2 + const, where reg1 != reg2.
! 	 Try to find what reg1 is equivalent to.  Hopefully it will either
! 	 be reg2 or reg2 plus a constant.  */
!       if (GET_CODE (temp) == PLUS)
! 	temp = XEXP (temp, 0);
!       if (REG_P (temp) && REGNO (temp) != REGNO (initial_value))
! 	initial_value = loop_equiv_value (loop_start, initial_value);
!     }
! 
!   /* If have INITIAL_VALUE = reg + const1 and FINAL_VALUE = reg + const2,
!      then replace INITIAL_VALUE with const1 and FINAL_VALUE with const2.  */
!   if ((GET_CODE (initial_value) == REG || GET_CODE (initial_value) == PLUS)
!       && (GET_CODE (final_value) == REG || GET_CODE (final_value) == PLUS))
!     {
!       rtx init_val;
!       rtx fini_val;
!       rtx init_reg;
!       rtx fini_reg;
! 
!       if (GET_CODE (initial_value) == PLUS)
! 	init_val = XEXP (initial_value, 1), init_reg = XEXP (initial_value, 0);
!       else
! 	init_val = const0_rtx, init_reg = initial_value;
! 
!       if (GET_CODE (final_value) == PLUS)
! 	fini_val = XEXP (final_value, 1), fini_reg = XEXP (final_value, 0);
!       else
! 	fini_val = const0_rtx, fini_reg = final_value;
! 
!       if (init_reg == fini_reg)
! 	{
! 	  initial_value = init_val;
! 	  final_value = fini_val;
  	}
      }
  
!   
    /* Save the calculated values describing this loop's bounds, in case
       precondition_loop_p will need them later.  These values can not be
       recalculated inside precondition_loop_p because strength reduction
*************** loop_iterations (loop_start, loop_end)
*** 3554,3568 ****
  		 "Loop unrolling: Final value not constant.\n");
        return 0;
      }
- 
-   /* ?? Final value and initial value do not have to be constants.
-      Only their difference has to be constant.  When the iteration variable
-      is an array address, the final value and initial value might both
-      be addresses with the same base but different constant offsets.
-      Final value must be invariant for this to work.
- 
-      To do this, need some way to find the values of registers which are
-      invariant.  */
  
    /* Final_larger is 1 if final larger, 0 if they are equal, otherwise -1.  */
    if (unsigned_compare)
--- 3603,3608 ----


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