From 05cb4e5423841f6155b09dfee5bb1a032c350ee8 Mon Sep 17 00:00:00 2001 From: "m.hayes" Date: Fri, 5 Jan 2001 03:25:58 +0000 Subject: [PATCH] * loop.h (struct loop_reg): New. (struct loop_regs): Change to use array of `struct loop_reg'. * loop.c: Replace assortment of varrays with single regs array. (count_one_set): Delete may_not_move array argument and use regs array instead. All caller's changed. (count_loop_regs_set): Delete may_not_move and single_usage arguments and use regs array instead. All caller's changed. (find_single_use_in_loop): Replace usage array argument with pointer to regs structure. All caller's changed. (loop_optimize): Delete `moved_once' array. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38700 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 +++ gcc/loop.c | 316 +++++++++++++++++++++++++++------------------------------- gcc/loop.h | 47 +++++---- 3 files changed, 186 insertions(+), 190 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ebb569bcf9c..2c117f2f446 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2001-01-05 Michael Hayes + * loop.h (struct loop_reg): New. + (struct loop_regs): Change to use array of `struct loop_reg'. + * loop.c: Replace assortment of varrays with single regs array. + (count_one_set): Delete may_not_move array argument + and use regs array instead. All caller's changed. + (count_loop_regs_set): Delete may_not_move and single_usage + arguments and use regs array instead. All caller's changed. + (find_single_use_in_loop): Replace usage array argument with pointer + to regs structure. All caller's changed. + (loop_optimize): Delete `moved_once' array. + +2001-01-05 Michael Hayes + * loop.c (prescan_loop): Set loop_info->has_nonconst_call. Use it instead of loop_info->has_call for scanning loop mems. (check_dbra_loop): Replace loop_info->has_call test with diff --git a/gcc/loop.c b/gcc/loop.c index 39e8920dc11..212f14e298e 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -152,12 +152,9 @@ static int reg_in_basic_block_p PARAMS ((rtx, rtx)); static int consec_sets_invariant_p PARAMS ((const struct loop *, rtx, int, rtx)); static int labels_in_range_p PARAMS ((rtx, int)); -static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, - varray_type, rtx *)); +static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *)); -static void count_loop_regs_set PARAMS ((const struct loop*, - varray_type, varray_type, - int *, int)); +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)); @@ -196,7 +193,7 @@ static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *, rtx *, rtx)); static void loop_ivs_free PARAMS((struct loop *)); static void strength_reduce PARAMS ((struct loop *, int, int)); -static void find_single_use_in_loop PARAMS ((rtx, rtx, varray_type)); +static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx)); static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx)); static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int)); static void record_biv PARAMS ((struct loop *, struct induction *, @@ -346,7 +343,6 @@ loop_optimize (f, dumpfile, flags) struct loops loops_data; struct loops *loops = &loops_data; struct loop_info *loops_info; - static char *moved_once; loop_dump_stream = dumpfile; @@ -373,8 +369,6 @@ loop_optimize (f, dumpfile, flags) loops->num = max_loop_num; - moved_once = (char *) xcalloc (max_reg_before_loop, sizeof (char)); - /* Get size to use for tables indexed by uids. Leave some space for labels allocated by find_and_verify_loops. */ max_uid_for_loop = get_max_uid () + 1 + max_loop_num * 32; @@ -444,9 +438,6 @@ loop_optimize (f, dumpfile, flags) for (i = max_loop_num - 1; i >= 0; i--) { struct loop *loop = &loops->array[i]; - struct loop_regs *regs = LOOP_REGS (loop); - - regs->moved_once = moved_once; if (! loop->invalid && loop->end) scan_loop (loop, flags); @@ -462,7 +453,6 @@ loop_optimize (f, dumpfile, flags) end_alias_analysis (); /* Clean up. */ - free (moved_once); free (uid_luid); free (uid_loop); free (loops_info); @@ -540,7 +530,6 @@ scan_loop (loop, flags) int threshold; /* Nonzero if we are scanning instructions in a sub-loop. */ int loop_depth = 0; - int nregs; loop->top = 0; @@ -622,42 +611,45 @@ scan_loop (loop, flags) } /* Count number of times each reg is set during this loop. Set - VARRAY_CHAR (regs->may_not_optimize, I) if it is not safe to move - out the setting of register I. Set VARRAY_RTX - (regs->single_usage, I). */ + 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 + /* 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. */ - nregs = max_reg_num () + loop_info->mems_idx + 16; - VARRAY_INT_INIT (regs->set_in_loop, nregs, "set_in_loop"); - VARRAY_INT_INIT (regs->n_times_set, nregs, "n_times_set"); - VARRAY_CHAR_INIT (regs->may_not_optimize, nregs, "may_not_optimize"); - VARRAY_RTX_INIT (regs->single_usage, nregs, "single_usage"); + regs->size = regs->num + loop_info->mems_idx + 16; + regs->array = (struct loop_reg *) + xmalloc (regs->size * sizeof (*regs->array)); - regs->num = nregs; + 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, regs->may_not_optimize, regs->single_usage, - &insn_count, nregs); + count_loop_regs_set (loop, &insn_count); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { - VARRAY_CHAR (regs->may_not_optimize, i) = 1; - VARRAY_INT (regs->set_in_loop, i) = 1; + 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 = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) + for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--) if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC) - VARRAY_CHAR (regs->may_not_optimize, i) = 1; + regs->array[i].may_not_optimize = 1; #endif - bcopy ((char *) ®s->set_in_loop->data, - (char *) ®s->n_times_set->data, nregs * sizeof (int)); + for (i = 0; i < regs->num; i++) + regs->array[i].n_times_set = regs->array[i].set_in_loop; if (loop_dump_stream) { @@ -669,7 +661,7 @@ scan_loop (loop, flags) } /* Scan through the loop finding insns that are safe to move. - Set regs->set_in_loop negative for the reg being set, so that + Set REGS->ARRAY[I].SET_IN_LOOP negative for the reg I being set, so that this reg will be considered invariant for subsequent insns. We consider whether subsequent insns use the reg in deciding whether it is worth actually moving. @@ -688,7 +680,7 @@ scan_loop (loop, flags) if (GET_CODE (p) == INSN && (set = single_set (p)) && GET_CODE (SET_DEST (set)) == REG - && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set)))) + && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize) { int tem1 = 0; int tem2 = 0; @@ -752,13 +744,11 @@ scan_loop (loop, flags) else if ((tem = loop_invariant_p (loop, src)) && (dependencies == 0 || (tem2 = loop_invariant_p (loop, dependencies)) != 0) - && (VARRAY_INT (regs->set_in_loop, - REGNO (SET_DEST (set))) == 1 + && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1 || (tem1 = consec_sets_invariant_p (loop, SET_DEST (set), - VARRAY_INT (regs->set_in_loop, - REGNO (SET_DEST (set))), + regs->array[REGNO (SET_DEST (set))].set_in_loop, p))) /* If the insn can cause a trap (such as divide by zero), can't move it unless it's guaranteed to be executed @@ -786,12 +776,12 @@ scan_loop (loop, flags) SMALL_REGISTER_CLASSES and SET_SRC is a hard register. */ if (loop_info->has_call - && VARRAY_RTX (regs->single_usage, regno) != 0 - && VARRAY_RTX (regs->single_usage, regno) != const0_rtx + && regs->array[regno].single_usage != 0 + && regs->array[regno].single_usage != const0_rtx && REGNO_FIRST_UID (regno) == INSN_UID (p) && (REGNO_LAST_UID (regno) - == INSN_UID (VARRAY_RTX (regs->single_usage, regno))) - && VARRAY_INT (regs->set_in_loop, regno) == 1 + == INSN_UID (regs->array[regno].single_usage)) + && regs->array[regno].set_in_loop == 1 && ! side_effects_p (SET_SRC (set)) && ! find_reg_note (p, REG_RETVAL, NULL_RTX) && (! SMALL_REGISTER_CLASSES @@ -801,26 +791,22 @@ scan_loop (loop, flags) a call-clobbered register and the life of REGNO might span a call. */ && ! modified_between_p (SET_SRC (set), p, - VARRAY_RTX - (regs->single_usage, regno)) - && no_labels_between_p (p, VARRAY_RTX (regs->single_usage, - regno)) + regs->array[regno].single_usage) + && no_labels_between_p (p, regs->array[regno].single_usage) && validate_replace_rtx (SET_DEST (set), SET_SRC (set), - VARRAY_RTX - (regs->single_usage, regno))) + regs->array[regno].single_usage)) { /* Replace any usage in a REG_EQUAL note. Must copy the new source, so that we don't get rtx sharing between the SET_SOURCE and REG_NOTES of insn p. */ - REG_NOTES (VARRAY_RTX (regs->single_usage, regno)) - = replace_rtx (REG_NOTES (VARRAY_RTX - (regs->single_usage, regno)), + REG_NOTES (regs->array[regno].single_usage) + = replace_rtx (REG_NOTES (regs->array[regno].single_usage), SET_DEST (set), copy_rtx (SET_SRC (set))); PUT_CODE (p, NOTE); NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (p) = 0; - VARRAY_INT (regs->set_in_loop, regno) = 0; + regs->array[regno].set_in_loop = 0; continue; } @@ -831,8 +817,7 @@ scan_loop (loop, flags) m->dependencies = dependencies; m->set_dest = SET_DEST (set); m->force = 0; - m->consec = VARRAY_INT (regs->set_in_loop, - REGNO (SET_DEST (set))) - 1; + m->consec = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1; m->done = 0; m->forces = 0; m->partial = 0; @@ -848,10 +833,10 @@ scan_loop (loop, flags) m->global = LOOP_REG_GLOBAL_P (loop, regno); m->match = 0; m->lifetime = LOOP_REG_LIFETIME (loop, regno); - m->savings = VARRAY_INT (regs->n_times_set, regno); + m->savings = regs->array[regno].n_times_set; if (find_reg_note (p, REG_RETVAL, NULL_RTX)) m->savings += libcall_benefit (p); - VARRAY_INT (regs->set_in_loop, regno) = move_insn ? -2 : -1; + regs->array[regno].set_in_loop = move_insn ? -2 : -1; /* Add M to the end of the chain MOVABLES. */ loop_movables_add (movables, m); @@ -906,7 +891,7 @@ scan_loop (loop, flags) && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1))) { register int regno = REGNO (SET_DEST (set)); - if (VARRAY_INT (regs->set_in_loop, regno) == 2) + if (regs->array[regno].set_in_loop == 2) { register struct movable *m; m = (struct movable *) xmalloc (sizeof (struct movable)); @@ -952,7 +937,7 @@ scan_loop (loop, flags) m->match = 0; m->lifetime = LOOP_REG_LIFETIME (loop, regno); m->savings = 1; - VARRAY_INT (regs->set_in_loop, regno) = -1; + regs->array[regno].set_in_loop = -1; /* Add M to the end of the chain MOVABLES. */ loop_movables_add (movables, m); } @@ -1012,7 +997,7 @@ scan_loop (loop, flags) combine_movables (movables, regs); /* Now consider each movable insn to decide whether it is worth moving. - Store 0 in regs->set_in_loop for each reg that is moved. + Store 0 in regs->array[I].set_in_loop for each reg I that is moved. Generally this increases code size, so do not move moveables when optimizing for code size. */ @@ -1021,11 +1006,11 @@ scan_loop (loop, flags) move_movables (loop, movables, threshold, insn_count); /* Now candidates that still are negative are those not moved. - Change regs->set_in_loop to indicate that those are not actually + Change regs->array[I].set_in_loop to indicate that those are not actually invariant. */ - for (i = 0; i < nregs; i++) - if (VARRAY_INT (regs->set_in_loop, i) < 0) - VARRAY_INT (regs->set_in_loop, i) = VARRAY_INT (regs->n_times_set, i); + for (i = 0; i < regs->num; i++) + if (regs->array[i].set_in_loop < 0) + regs->array[i].set_in_loop = regs->array[i].n_times_set; /* Now that we've moved some things out of the loop, we might be able to hoist even more memory references. */ @@ -1061,10 +1046,9 @@ scan_loop (loop, flags) /* The movable information is required for strength reduction. */ loop_movables_free (movables); - VARRAY_FREE (regs->single_usage); - VARRAY_FREE (regs->set_in_loop); - VARRAY_FREE (regs->n_times_set); - VARRAY_FREE (regs->may_not_optimize); + free (regs->array); + regs->array = 0; + regs->num = 0; } /* Add elements to *OUTPUT to record all the pseudo-regs @@ -1343,7 +1327,7 @@ combine_movables (movables, regs) /* Perhaps testing m->consec_sets would be more appropriate here? */ for (m = movables->head; m; m = m->next) - if (m->match == 0 && VARRAY_INT (regs->n_times_set, m->regno) == 1 + if (m->match == 0 && regs->array[m->regno].n_times_set == 1 && !m->partial) { register struct movable *m1; @@ -1355,8 +1339,8 @@ combine_movables (movables, regs) /* We want later insns to match the first one. Don't make the first one match any later ones. So start this loop at m->next. */ for (m1 = m->next; m1; m1 = m1->next) - if (m != m1 && m1->match == 0 && VARRAY_INT (regs->n_times_set, - m1->regno) == 1 + if (m != m1 && m1->match == 0 + && regs->array[m1->regno].n_times_set == 1 /* A reg used outside the loop mustn't be eliminated. */ && !m1->global /* A reg used for zero-extending mustn't be eliminated. */ @@ -1498,7 +1482,7 @@ rtx_equal_for_loop_p (x, y, movables, regs) /* If we have a register and a constant, they may sometimes be equal. */ - if (GET_CODE (x) == REG && VARRAY_INT (regs->set_in_loop, REGNO (x)) == -2 + if (GET_CODE (x) == REG && regs->array[REGNO (x)].set_in_loop == -2 && CONSTANT_P (y)) { for (m = movables->head; m; m = m->next) @@ -1506,8 +1490,7 @@ rtx_equal_for_loop_p (x, y, movables, regs) && rtx_equal_p (m->set_src, y)) return 1; } - else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop, - REGNO (y)) == -2 + else if (GET_CODE (y) == REG && regs->array[REGNO (y)].set_in_loop == -2 && CONSTANT_P (x)) { for (m = movables->head; m; m = m->next) @@ -1719,7 +1702,7 @@ move_movables (loop, movables, threshold, insn_count) if (loop_dump_stream) fprintf (loop_dump_stream, "savings %d ", savings); - if (regs->moved_once[regno] && loop_dump_stream) + if (regs->array[regno].moved_once && loop_dump_stream) fprintf (loop_dump_stream, "halved since already moved "); /* An insn MUST be moved if we already moved something else @@ -1738,9 +1721,9 @@ move_movables (loop, movables, threshold, insn_count) if (already_moved[regno] || flag_move_all_movables || (threshold * savings * m->lifetime) >= - (regs->moved_once[regno] ? insn_count * 2 : insn_count) + (regs->array[regno].moved_once ? insn_count * 2 : insn_count) || (m->forces && m->forces->done - && VARRAY_INT (regs->n_times_set, m->forces->regno) == 1)) + && regs->array[m->forces->regno].n_times_set == 1)) { int count; register struct movable *m1; @@ -2046,11 +2029,11 @@ move_movables (loop, movables, threshold, insn_count) already_moved[regno] = 1; /* This reg has been moved out of one loop. */ - regs->moved_once[regno] = 1; + regs->array[regno].moved_once = 1; /* The reg set here is now invariant. */ if (! m->partial) - VARRAY_INT (regs->set_in_loop, regno) = 0; + regs->array[regno].set_in_loop = 0; m->done = 1; @@ -2114,7 +2097,7 @@ move_movables (loop, movables, threshold, insn_count) /* The reg merged here is now invariant, if the reg it matches is invariant. */ if (! m->partial) - VARRAY_INT (regs->set_in_loop, m1->regno) = 0; + regs->array[m1->regno].set_in_loop = 0; } } else if (loop_dump_stream) @@ -3031,8 +3014,8 @@ note_set_pseudo_multiple_uses (x, y, data) /* If we do not have usage information, or if we know the register is used more than once, note that fact for check_dbra_loop. */ if (REGNO (x) >= max_reg_before_loop - || ! VARRAY_RTX (regs->single_usage, REGNO (x)) - || VARRAY_RTX (regs->single_usage, REGNO (x)) == const0_rtx) + || ! regs->array[REGNO (x)].single_usage + || regs->array[REGNO (x)].single_usage == const0_rtx) regs->multiple_uses = 1; } @@ -3100,10 +3083,10 @@ loop_invariant_p (loop, x) && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)]) return 0; - if (VARRAY_INT (regs->set_in_loop, REGNO (x)) < 0) + if (regs->array[REGNO (x)].set_in_loop < 0) return 2; - return VARRAY_INT (regs->set_in_loop, REGNO (x)) == 0; + return regs->array[REGNO (x)].set_in_loop == 0; case MEM: /* Volatile memory references must be rejected. Do this before @@ -3188,7 +3171,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn) rtx temp; /* Number of sets we have to insist on finding after INSN. */ int count = n_sets - 1; - int old = VARRAY_INT (regs->set_in_loop, regno); + int old = regs->array[regno].set_in_loop; int value = 0; int this; @@ -3196,7 +3179,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn) if (n_sets == 127) return 0; - VARRAY_INT (regs->set_in_loop, regno) = 0; + regs->array[regno].set_in_loop = 0; while (count > 0) { @@ -3235,12 +3218,12 @@ consec_sets_invariant_p (loop, reg, n_sets, insn) count--; else if (code != NOTE) { - VARRAY_INT (regs->set_in_loop, regno) = old; + regs->array[regno].set_in_loop = old; return 0; } } - VARRAY_INT (regs->set_in_loop, regno) = old; + regs->array[regno].set_in_loop = old; /* If loop_invariant_p ever returned 2, we return 2. */ return 1 + (value & 2); } @@ -3283,19 +3266,19 @@ all_sets_invariant_p (reg, insn, table) a different insn, set USAGE[REGNO] to const0_rtx. */ static void -find_single_use_in_loop (insn, x, usage) +find_single_use_in_loop (regs, insn, x) + struct loop_regs *regs; rtx insn; rtx x; - varray_type usage; { enum rtx_code code = GET_CODE (x); const char *fmt = GET_RTX_FORMAT (code); int i, j; if (code == REG) - VARRAY_RTX (usage, REGNO (x)) - = (VARRAY_RTX (usage, REGNO (x)) != 0 - && VARRAY_RTX (usage, REGNO (x)) != insn) + regs->array[REGNO (x)].single_usage + = (regs->array[REGNO (x)].single_usage != 0 + && regs->array[REGNO (x)].single_usage != insn) ? const0_rtx : insn; else if (code == SET) @@ -3305,34 +3288,34 @@ find_single_use_in_loop (insn, x, usage) show up as a potential movable so we don't care how USAGE is set for it. */ if (GET_CODE (SET_DEST (x)) != REG) - find_single_use_in_loop (insn, SET_DEST (x), usage); - find_single_use_in_loop (insn, SET_SRC (x), usage); + find_single_use_in_loop (regs, insn, SET_DEST (x)); + find_single_use_in_loop (regs, insn, SET_SRC (x)); } else for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && XEXP (x, i) != 0) - find_single_use_in_loop (insn, XEXP (x, i), usage); + find_single_use_in_loop (regs, insn, XEXP (x, i)); else if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) - find_single_use_in_loop (insn, XVECEXP (x, i, j), usage); + find_single_use_in_loop (regs, insn, XVECEXP (x, i, j)); } } /* Count and record any set in X which is contained in INSN. Update - MAY_NOT_MOVE and LAST_SET for any register set in X. */ + REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set + in X. */ static void -count_one_set (regs, insn, x, may_not_move, last_set) +count_one_set (regs, insn, x, last_set) struct loop_regs *regs; rtx insn, x; - varray_type may_not_move; rtx *last_set; { if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG) /* Don't move a reg that has an explicit clobber. It's not worth the pain to try to do it correctly. */ - VARRAY_CHAR (may_not_move, REGNO (XEXP (x, 0))) = 1; + regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1; if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) { @@ -3349,31 +3332,31 @@ count_one_set (regs, insn, x, may_not_move, last_set) in current basic block, and it was set before, it must be set in two basic blocks, so it cannot be moved out of the loop. */ - if (VARRAY_INT (regs->set_in_loop, regno) > 0 - && last_set[regno] == 0) - VARRAY_CHAR (may_not_move, regno) = 1; + if (regs->array[regno].set_in_loop > 0 + && last_set == 0) + regs->array[regno].may_not_optimize = 1; /* If this is not first setting in current basic block, see if reg was used in between previous one and this. If so, neither one can be moved. */ if (last_set[regno] != 0 && reg_used_between_p (dest, last_set[regno], insn)) - VARRAY_CHAR (may_not_move, regno) = 1; - if (VARRAY_INT (regs->set_in_loop, regno) < 127) - ++VARRAY_INT (regs->set_in_loop, regno); + regs->array[regno].may_not_optimize = 1; + if (regs->array[regno].set_in_loop < 127) + ++regs->array[regno].set_in_loop; last_set[regno] = insn; } } } -/* Increment REGS->SET_IN_LOOP at the index of each register - that is modified by an insn between FROM and TO. - If the value of an element of REGS->SET_IN_LOOP becomes 127 or more, - stop incrementing it, to avoid overflow. +/* 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 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 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. */ @@ -3382,15 +3365,12 @@ count_one_set (regs, insn, x, may_not_move, last_set) In that case, it is the insn that last set reg n. */ static void -count_loop_regs_set (loop, may_not_move, single_usage, count_ptr, nregs) +count_loop_regs_set (loop, count_ptr) const struct loop *loop; - varray_type may_not_move; - varray_type single_usage; int *count_ptr; - int nregs; { struct loop_regs *regs = LOOP_REGS (loop); - register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx)); + register rtx *last_set = (rtx *) xcalloc (regs->num, sizeof (rtx)); register rtx insn; register int count = 0; @@ -3402,26 +3382,26 @@ count_loop_regs_set (loop, may_not_move, single_usage, count_ptr, nregs) ++count; /* Record registers that have exactly one use. */ - find_single_use_in_loop (insn, PATTERN (insn), single_usage); + find_single_use_in_loop (regs, insn, PATTERN (insn)); /* Include uses in REG_EQUAL notes. */ if (REG_NOTES (insn)) - find_single_use_in_loop (insn, REG_NOTES (insn), single_usage); + 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), may_not_move, last_set); + 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), - may_not_move, last_set); + last_set); } } if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN) - memset ((char *) last_set, 0, nregs * sizeof (rtx)); + memset ((char *) last_set, 0, regs->num * sizeof (rtx)); } *count_ptr = count; @@ -3676,7 +3656,7 @@ loop_bivs_find (loop) if (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT /* Above happens if register modified by subreg, etc. */ /* Make sure it is not recognized as a basic induction var: */ - || VARRAY_INT (regs->n_times_set, bl->regno) != bl->biv_count + || regs->array[bl->regno].n_times_set != bl->biv_count /* If never incremented, it is invariant that we decided not to move. So leave it alone. */ || ! bl->incremented) @@ -4297,11 +4277,11 @@ loop_ivs_free (loop) /* Perform strength reduction and induction variable elimination. Pseudo registers created during this function will be beyond the - last valid index in several tables including regs->n_times_set and - regno_last_uid. This does not cause a problem here, because the - added registers cannot be givs outside of their loop, and hence - will never be reconsidered. But scan_loop must check regnos to - make sure they are in bounds. */ + last valid index in several tables including + REGS->ARRAY[I].N_TIMES_SET and REGNO_LAST_UID. This does not cause a + problem here, because the added registers cannot be givs outside of + their loop, and hence will never be reconsidered. But scan_loop + must check regnos to make sure they are in bounds. */ static void strength_reduce (loop, insn_count, flags) @@ -4684,7 +4664,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) if (GET_CODE (p) == INSN && (set = single_set (p)) && GET_CODE (SET_DEST (set)) == REG - && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set)))) + && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize) { rtx src_reg; rtx dest_reg; @@ -4713,7 +4693,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) /* Don't recognize a BASIC_INDUCT_VAR here. */ && dest_reg != src_reg /* This must be the only place where the register is set. */ - && (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) == 1 + && (regs->array[REGNO (dest_reg)].n_times_set == 1 /* or all sets must be consecutive and make a giv. */ || (benefit = consec_sets_giv (loop, benefit, p, src_reg, dest_reg, @@ -4728,7 +4708,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) benefit += libcall_benefit (p); /* Skip the consecutive insns, if there are any. */ - if (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) != 1) + if (regs->array[REGNO (dest_reg)].n_times_set != 1) p = last_consec_insn; record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val, @@ -6136,7 +6116,7 @@ simplify_giv_expr (loop, x, ext_val, benefit) less harmful than reducing many givs that are not really beneficial. */ { - rtx single_use = VARRAY_RTX (regs->single_usage, REGNO (x)); + rtx single_use = regs->array[REGNO (x)].single_usage; if (single_use && single_use != const0_rtx) *benefit += v->benefit; } @@ -6380,7 +6360,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT; REG_IV_INFO (ivs, REGNO (dest_reg)) = v; - count = VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) - 1; + count = regs->array[REGNO (dest_reg)].n_times_set - 1; while (count > 0) { @@ -6938,8 +6918,7 @@ combine_givs (regs, bl) DEST_ADDR targets on hosts with reg+reg addressing, though it can be seen elsewhere as well. */ if (g1->giv_type == DEST_REG - && (single_use = VARRAY_RTX (regs->single_usage, - REGNO (g1->dest_reg))) + && (single_use = regs->array[REGNO (g1->dest_reg)].single_usage) && single_use != const0_rtx) continue; @@ -8798,9 +8777,9 @@ insert_loop_mem (mem, data) return 0; } -/* Like load_mems, but also ensures that REGS->SET_IN_LOOP, - REGS->MAY_NOT_OPTIMIZE, REGS->SINGLE_USAGE, and INSN_COUNT have the correct - values after load_mems. */ +/* 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) @@ -8808,54 +8787,54 @@ load_mems_and_recount_loop_regs_set (loop, insn_count) int *insn_count; { struct loop_regs *regs = LOOP_REGS (loop); - int nregs = max_reg_num (); load_mems (loop); - /* Recalculate regs->set_in_loop and friends since load_mems may have - created new registers. */ - if (max_reg_num () > nregs) + /* Recalculate regs->array since load_mems may have created new + registers. */ + if (max_reg_num () > regs->num) { int i; int old_nregs; - old_nregs = nregs; - nregs = max_reg_num (); + 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)); + } - if ((unsigned) nregs > regs->set_in_loop->num_elements) + for (i = 0; i < regs->num; i++) { - /* Grow all the arrays. */ - VARRAY_GROW (regs->set_in_loop, nregs); - VARRAY_GROW (regs->n_times_set, nregs); - VARRAY_GROW (regs->may_not_optimize, nregs); - VARRAY_GROW (regs->single_usage, nregs); + regs->array[i].set_in_loop = 0; + regs->array[i].may_not_optimize = 0; + regs->array[i].single_usage = NULL_RTX; } - /* Clear the arrays */ - memset ((char *) ®s->set_in_loop->data, 0, nregs * sizeof (int)); - memset ((char *) ®s->may_not_optimize->data, 0, nregs * sizeof (char)); - memset ((char *) ®s->single_usage->data, 0, nregs * sizeof (rtx)); - count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage, - insn_count, nregs); + count_loop_regs_set (loop, insn_count); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { - VARRAY_CHAR (regs->may_not_optimize, i) = 1; - VARRAY_INT (regs->set_in_loop, i) = 1; + 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 = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) + for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--) if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC) - VARRAY_CHAR (regs->may_not_optimize, i) = 1; + regs->array[i].may_not_optimize = 1; #endif - /* Set regs->n_times_set for the new registers. */ - bcopy ((char *) (®s->set_in_loop->data.i[0] + old_nregs), - (char *) (®s->n_times_set->data.i[0] + old_nregs), - (nregs - old_nregs) * sizeof (int)); + /* 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; } } @@ -9042,8 +9021,7 @@ load_mems (loop) && GET_CODE (SET_DEST (set)) == REG && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER && REGNO (SET_DEST (set)) < last_max_reg - && VARRAY_INT (regs->n_times_set, - REGNO (SET_DEST (set))) == 1 + && regs->array[REGNO (SET_DEST (set))].n_times_set == 1 && rtx_equal_p (SET_SRC (set), mem)) SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set))); @@ -9057,7 +9035,7 @@ load_mems (loop) && GET_CODE (SET_SRC (set)) == REG && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER && REGNO (SET_SRC (set)) < last_max_reg - && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1 + && regs->array[REGNO (SET_SRC (set))].n_times_set == 1 && rtx_equal_p (SET_DEST (set), mem)) SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set))); diff --git a/gcc/loop.h b/gcc/loop.h index 5b576949fbc..1bdae73d9e7 100644 --- a/gcc/loop.h +++ b/gcc/loop.h @@ -18,7 +18,6 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "varray.h" #include "bitmap.h" /* Flags passed to loop_optimize. */ @@ -236,44 +235,50 @@ typedef struct loop_mem_info } loop_mem_info; -struct loop_regs -{ - int num; - /* Indexed by register number, contains the number of times the reg - is set during the loop being scanned. - During code motion, a negative value indicates a reg that has been - made a candidate; in particular -2 means that it is an candidate that - we know is equal to a constant and -1 means that it is an candidate - not known equal to a constant. - After code motion, regs moved have 0 (which is accurate now) - while the failed candidates have the original number of times set. +struct loop_reg +{ + /* Number of times the reg is set during the loop being scanned. + During code motion, a negative value indicates a reg that has + been made a candidate; in particular -2 means that it is an + candidate that we know is equal to a constant and -1 means that + it is an candidate not known equal to a constant. After code + motion, regs moved have 0 (which is accurate now) while the + failed candidates have the original number of times set. Therefore, at all times, == 0 indicates an invariant register; < 0 a conditionally invariant one. */ - varray_type set_in_loop; + int set_in_loop; /* Original value of set_in_loop; same except that this value is not set negative for a reg whose sets have been made candidates and not set to 0 for a reg that is moved. */ - varray_type n_times_set; - - /* Index by register number, 1 indicates that the register - cannot be moved or strength reduced. */ - varray_type may_not_optimize; + int n_times_set; /* Contains the insn in which a register was used if it was used exactly once; contains const0_rtx if it was used more than once. */ - varray_type single_usage; + rtx single_usage; + + /* Nonzero indicates that the register cannot be moved or strength + reduced. */ + char may_not_optimize; /* Nonzero means reg N has already been moved out of one loop. This reduces the desire to move it out of another. */ - char *moved_once; + char moved_once; +}; + - int multiple_uses; +struct loop_regs +{ + int num; /* Number of regs used in table. */ + int size; /* Size of table. */ + struct loop_reg *array; /* Register usage info. array. */ + int multiple_uses; /* Nonzero if a reg has multiple uses. */ }; + struct loop_movables { /* Head of movable chain. */ -- 2.11.0