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]

Loop reg scanning patch



This patch simplifies the allocation and setting of the regs array
used in strength reduction by rolling two similar functions into one.

2001-01-06  Michael Hayes  <mhayes@redhat.com>

	* loop.c (count_loop_regs_set): Delete.
	(load_mems_and_recount_loop_regs_set): Delete.
	(loop_regs_scan): Merge common code from count_loop_regs_set,
	scan_loop, and load_mems_and_recount_loop_regs_set.
	(scan_loop): Call load_mems directly and loop_regs_scan
	again if new registers created.

Index: loop.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/loop.c,v
retrieving revision 1.313
diff -c -3 -p -r1.313 loop.c
*** loop.c	2001/01/05 03:25:58	1.313
--- loop.c	2001/01/05 23:52:54
*************** static int consec_sets_invariant_p PARAM
*** 153,160 ****
  					    rtx, int, rtx));
  static int labels_in_range_p PARAMS ((rtx, int));
  static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *));
- 
- static void count_loop_regs_set PARAMS ((const struct loop *, int *));
  static void note_addr_stored PARAMS ((rtx, rtx, void *));
  static void note_set_pseudo_multiple_uses PARAMS ((rtx, rtx, void *));
  static int loop_reg_used_before_p PARAMS ((const struct loop *, rtx, rtx));
--- 153,158 ----
*************** static int last_use_this_basic_block PAR
*** 230,237 ****
  static void record_initial PARAMS ((rtx, rtx, void *));
  static void update_reg_last_use PARAMS ((rtx, rtx));
  static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
! static void load_mems_and_recount_loop_regs_set PARAMS ((const struct loop*,
! 							 int *));
  static void load_mems PARAMS ((const struct loop *));
  static int insert_loop_mem PARAMS ((rtx *, void *));
  static int replace_loop_mem PARAMS ((rtx *, void *));
--- 228,234 ----
  static void record_initial PARAMS ((rtx, rtx, void *));
  static void update_reg_last_use PARAMS ((rtx, rtx));
  static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
! static void loop_regs_scan PARAMS ((const struct loop*, int, int *));
  static void load_mems PARAMS ((const struct loop *));
  static int insert_loop_mem PARAMS ((rtx *, void *));
  static int replace_loop_mem PARAMS ((rtx *, void *));
*************** scan_loop (loop, flags)
*** 609,655 ****
  		 INSN_UID (loop_start), INSN_UID (loop_end));
        return;
      }
- 
-   /* Count number of times each reg is set during this loop.  Set
-      regs->array[I].may_not_optimize if it is not safe to move out the
-      setting of register I.  Set regs->array[I].single_usage.  */
- 
-   regs->num = max_reg_num ();
- 
-   /* Allocate extra space for REGs that might be created by
-      load_mems.  We allocate a little extra slop as well, in the hopes
-      that even after the moving of movables creates some new registers
-      we won't have to reallocate these arrays.  However, we do grow
-      the arrays, if necessary, in load_mems_recount_loop_regs_set.  */
-   regs->size = regs->num + loop_info->mems_idx + 16;
-   regs->array = (struct loop_reg *) 
-     xmalloc (regs->size * sizeof (*regs->array));
- 
-   for (i = 0; i < regs->num; i++)
-     {
-       regs->array[i].set_in_loop = 0;
-       regs->array[i].may_not_optimize = 0;
-       regs->array[i].single_usage = NULL_RTX;
-     }
- 
-   count_loop_regs_set (loop, &insn_count);
- 
-   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-     {
-       regs->array[i].may_not_optimize = 1;
-       regs->array[i].set_in_loop = 1;
-     }
- 
- #ifdef AVOID_CCMODE_COPIES
-   /* Don't try to move insns which set CC registers if we should not
-      create CCmode register copies.  */
-   for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-     if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-       regs->array[i].may_not_optimize = 1;
- #endif
  
!   for (i = 0; i < regs->num; i++)
!     regs->array[i].n_times_set = regs->array[i].set_in_loop;
  
    if (loop_dump_stream)
      {
--- 606,616 ----
  		 INSN_UID (loop_start), INSN_UID (loop_end));
        return;
      }
  
!   /* Allocate extra space for REGs that might be created by load_mems.
!      We allocate a little extra slop as well, in the hopes that we
!      won't have to reallocate the regs array.  */
!   loop_regs_scan (loop, loop_info->mems_idx + 16, &insn_count);
  
    if (loop_dump_stream)
      {
*************** scan_loop (loop, flags)
*** 1014,1021 ****
  
    /* Now that we've moved some things out of the loop, we might be able to
       hoist even more memory references.  */
!   load_mems_and_recount_loop_regs_set (loop, &insn_count);
  
    for (update_start = loop_start;
         PREV_INSN (update_start)
  	 && GET_CODE (PREV_INSN (update_start)) != CODE_LABEL;
--- 975,986 ----
  
    /* Now that we've moved some things out of the loop, we might be able to
       hoist even more memory references.  */
!   load_mems (loop);
  
+   /* Recalculate regs->array if load_mems has created new registers.  */
+   if (max_reg_num () > regs->num)
+     loop_regs_scan (loop, 0, &insn_count);
+ 
    for (update_start = loop_start;
         PREV_INSN (update_start)
  	 && GET_CODE (PREV_INSN (update_start)) != CODE_LABEL;
*************** count_one_set (regs, insn, x, last_set)
*** 3347,3413 ****
  	}
      }
  }
- 
- /* Increment REGS->array[I].SET_IN_LOOP at the index I of each
-    register that is modified by an insn between FROM and TO.  If the
-    value of an element of REGS->array[I].SET_IN_LOOP becomes 127 or
-    more, stop incrementing it, to avoid overflow.
- 
-    Store in REGS->array[I].SINGLE_USAGE[I] the single insn in which
-    register I is used, if it is only used once.  Otherwise, it is set
-    to 0 (for no uses) or const0_rtx for more than one use.  This
-    parameter may be zero, in which case this processing is not done.
- 
-    Store in *COUNT_PTR the number of actual instruction
-    in the loop.  We use this to decide what is worth moving out.  */
- 
- /* last_set[n] is nonzero iff reg n has been set in the current basic block.
-    In that case, it is the insn that last set reg n.  */
- 
- static void
- count_loop_regs_set (loop, count_ptr)
-      const struct loop *loop;
-      int *count_ptr;
- {
-   struct loop_regs *regs = LOOP_REGS (loop);
-   register rtx *last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
-   register rtx insn;
-   register int count = 0;
- 
-   for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
-        insn = NEXT_INSN (insn))
-     {
-       if (INSN_P (insn))
- 	{
- 	  ++count;
- 
- 	  /* Record registers that have exactly one use.  */
- 	  find_single_use_in_loop (regs, insn, PATTERN (insn));
- 
- 	  /* Include uses in REG_EQUAL notes.  */
- 	  if (REG_NOTES (insn))
- 	    find_single_use_in_loop (regs, insn, REG_NOTES (insn));
- 
- 	  if (GET_CODE (PATTERN (insn)) == SET
- 	      || GET_CODE (PATTERN (insn)) == CLOBBER)
- 	    count_one_set (regs, insn, PATTERN (insn), last_set);
- 	  else if (GET_CODE (PATTERN (insn)) == PARALLEL)
- 	    {
- 	      register int i;
- 	      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- 		count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
- 			       last_set);
- 	    }
- 	}
- 
-       if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
- 	memset ((char *) last_set, 0, regs->num * sizeof (rtx));
-     }
-   *count_ptr = count;
- 
-   /* Clean up.  */
-   free (last_set);
- }
  
  /* Given a loop that is bounded by LOOP->START and LOOP->END and that
     is entered at LOOP->SCAN_START, return 1 if the register set in SET
--- 3312,3317 ----
*************** insert_loop_mem (mem, data)
*** 8776,8842 ****
  
    return 0;
  }
  
! /* Like load_mems, but also ensures that REGS->array[I].SET_IN_LOOP,
!    REGS->array[I].MAY_NOT_OPTIMIZE, REGS->array[I].SINGLE_USAGE, and
!    INSN_COUNT have the correct values after load_mems.  */
  
  static void
! load_mems_and_recount_loop_regs_set (loop, insn_count)
       const struct loop *loop;
!      int *insn_count;
  {
    struct loop_regs *regs = LOOP_REGS (loop);
  
!   load_mems (loop);
  
!   /* Recalculate regs->array since load_mems may have created new
!      registers.  */
!   if (max_reg_num () > regs->num)
      {
!       int i;
!       int old_nregs;
  
!       old_nregs = regs->num;
!       regs->num = max_reg_num ();
  
!       if (regs->num >= regs->size)
  	{
! 	  regs->size = regs->num;
  
! 	  /* Grow the array.  */
! 	  regs->array = (struct loop_reg *)
! 	    xrealloc (regs->array, regs->size * sizeof (*regs->array));
! 	}
  
!       for (i = 0; i < regs->num; i++)
! 	{
! 	  regs->array[i].set_in_loop = 0;
! 	  regs->array[i].may_not_optimize = 0;
! 	  regs->array[i].single_usage = NULL_RTX;
  	}
  
!       count_loop_regs_set (loop, insn_count);
  
!       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
! 	{
! 	  regs->array[i].may_not_optimize = 1;
! 	  regs->array[i].set_in_loop = 1;
! 	}
  
  #ifdef AVOID_CCMODE_COPIES
!       /* Don't try to move insns which set CC registers if we should not
! 	 create CCmode register copies.  */
!       for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
! 	if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
! 	  regs->array[i].may_not_optimize = 1;
  #endif
  
!       /* Set regs->array[I].n_times_set for the new registers.  */
!       for (i = old_nregs; i < regs->num; i++)
! 	regs->array[i].n_times_set = regs->array[i].set_in_loop;
!     }
  }
  
  /* Move MEMs into registers for the duration of the loop.  */
  
--- 8680,8795 ----
  
    return 0;
  }
+ 
+ 
+ /* Allocate REGS->ARRAY or reallocate it if it is too small.
+ 
+    Increment REGS->ARRAY[I].SET_IN_LOOP at the index I of each
+    register that is modified by an insn between FROM and TO.  If the
+    value of an element of REGS->array[I].SET_IN_LOOP becomes 127 or
+    more, stop incrementing it, to avoid overflow.
+ 
+    Store in REGS->ARRAY[I].SINGLE_USAGE the single insn in which
+    register I is used, if it is only used once.  Otherwise, it is set
+    to 0 (for no uses) or const0_rtx for more than one use.  This
+    parameter may be zero, in which case this processing is not done.
+ 
+    Set REGS->ARRAY[I].MAY_NOT_OPTIMIZE nonzero if we should not
+    optimize register I.
  
!    Store in *COUNT_PTR the number of actual instructions
!    in the loop.  We use this to decide what is worth moving out.  */
  
  static void
! loop_regs_scan (loop, extra_size, count_ptr)
       const struct loop *loop;
!      int extra_size;
!      int *count_ptr;
  {
    struct loop_regs *regs = LOOP_REGS (loop);
+   int old_nregs;
+   /* last_set[n] is nonzero iff reg n has been set in the current
+    basic block.  In that case, it is the insn that last set reg n.  */
+   rtx *last_set;
+   rtx insn;
+   int count = 0;
+   int i;
  
!   old_nregs = regs->num;
!   regs->num = max_reg_num ();
  
!   /* Grow the regs array if not allocated or too small.  */
!   if (regs->num >= regs->size)
      {
!       regs->size = regs->num + extra_size;
!       
!       regs->array = (struct loop_reg *)
! 	xrealloc (regs->array, regs->size * sizeof (*regs->array));
!     }
  
!   /* Clear fields that are scanned.  */
!   for (i = 0; i < regs->num; i++)
!     {
!       regs->array[i].set_in_loop = 0;
!       regs->array[i].may_not_optimize = 0;
!       regs->array[i].single_usage = NULL_RTX;
!     }
  
!   last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
! 
!   /* Scan the loop, recording register usage.  */
!   for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
!        insn = NEXT_INSN (insn))
!     {
!       if (INSN_P (insn))
  	{
! 	  ++count;
  
! 	  /* Record registers that have exactly one use.  */
! 	  find_single_use_in_loop (regs, insn, PATTERN (insn));
  
! 	  /* Include uses in REG_EQUAL notes.  */
! 	  if (REG_NOTES (insn))
! 	    find_single_use_in_loop (regs, insn, REG_NOTES (insn));
! 
! 	  if (GET_CODE (PATTERN (insn)) == SET
! 	      || GET_CODE (PATTERN (insn)) == CLOBBER)
! 	    count_one_set (regs, insn, PATTERN (insn), last_set);
! 	  else if (GET_CODE (PATTERN (insn)) == PARALLEL)
! 	    {
! 	      register int i;
! 	      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
! 		count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
! 			       last_set);
! 	    }
  	}
  
!       if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
! 	memset ((char *) last_set, 0, regs->num * sizeof (rtx));
!     }
  
!   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
!     {
!       regs->array[i].may_not_optimize = 1;
!       regs->array[i].set_in_loop = 1;
!     }
  
  #ifdef AVOID_CCMODE_COPIES
!   /* Don't try to move insns which set CC registers if we should not
!      create CCmode register copies.  */
!   for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
!     if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
!       regs->array[i].may_not_optimize = 1;
  #endif
+   
+   /* Set regs->array[I].n_times_set for the new registers.  */
+   for (i = old_nregs; i < regs->num; i++)
+     regs->array[i].n_times_set = regs->array[i].set_in_loop;
  
!   free (last_set);
!   *count_ptr = count;
  }
+ 
  
  /* Move MEMs into registers for the duration of the loop.  */
  

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