This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Loop reg scanning patch
- To: gcc-patches at gcc dot gnu dot org
- Subject: Loop reg scanning patch
- From: Michael Hayes <mhayes at redhat dot com>
- Date: Sat, 6 Jan 2001 13:10:00 +1300 (NZDT)
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. */