static int max_loop_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.
-
- Therefore, at all times, == 0 indicates an invariant register;
- < 0 a conditionally invariant one. */
-
-static varray_type 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. */
-
-static varray_type n_times_set;
-
-/* Index by register number, 1 indicates that the register
- cannot be moved or strength reduced. */
-
-static varray_type may_not_optimize;
-
-/* 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. */
-
-static varray_type reg_single_usage;
-
-/* Nonzero means reg N has already been moved out of one loop.
- This reduces the desire to move it out of another. */
-
-static char *moved_once;
-
/* Bound on pseudo register number before loop optimization.
A pseudo has valid regscan info if its number is < max_reg_before_loop. */
unsigned int max_reg_before_loop;
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 ((rtx, rtx, varray_type, rtx *));
+static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx,
+ varray_type, rtx *));
static void count_loop_regs_set PARAMS ((const struct loop*,
varray_type, varray_type,
static int libcall_benefit PARAMS ((rtx));
static void ignore_some_movables PARAMS ((struct movables *));
static void force_movables PARAMS ((struct movables *));
-static void combine_movables PARAMS ((struct movables *, int));
+static void combine_movables PARAMS ((struct movables *, struct loop_regs *));
static int regs_match_p PARAMS ((rtx, rtx, struct movables *));
-static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movables *));
+static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movables *,
+ struct loop_regs *));
static void add_label_notes PARAMS ((rtx, rtx));
static void move_movables PARAMS ((struct loop *loop, struct movables *,
int, int, int));
static int check_dbra_loop PARAMS ((struct loop *, int));
static rtx express_from_1 PARAMS ((rtx, rtx, rtx));
static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
-static void combine_givs PARAMS ((struct iv_class *));
+static void combine_givs PARAMS ((struct loop_regs *, struct iv_class *));
struct recombine_givs_stats;
static int find_life_end PARAMS ((rtx, struct recombine_givs_stats *,
rtx, rtx));
struct loops loops_data;
struct loops *loops = &loops_data;
struct loop_info *loops_info;
+ static char *moved_once;
loop_dump_stream = dumpfile;
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);
struct loop *loop;
int flags;
{
+ struct loop_info *loop_info = LOOP_INFO (loop);
+ struct loop_regs *regs = LOOP_REGS (loop);
register int i;
rtx loop_start = loop->start;
rtx loop_end = loop->end;
- /* Additional information about the current loop being processed
- that is used to compute the number of loop iterations for loop
- unrolling and doloop optimization. */
- struct loop_info *loop_info = LOOP_INFO (loop);
rtx p;
/* 1 if we are scanning insns that could be executed zero times. */
int maybe_never = 0;
return;
}
- /* Count number of times each reg is set during this loop.
- Set VARRAY_CHAR (may_not_optimize, I) if it is not safe to move out
- the setting of register I. Set VARRAY_RTX (reg_single_usage, I). */
+ /* 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). */
/* Allocate extra space for REGS that might be created by
load_mems. We allocate a little extra slop as well, in the hopes
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 (set_in_loop, nregs, "set_in_loop");
- VARRAY_INT_INIT (n_times_set, nregs, "n_times_set");
- VARRAY_CHAR_INIT (may_not_optimize, nregs, "may_not_optimize");
- VARRAY_RTX_INIT (reg_single_usage, nregs, "reg_single_usage");
+ 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");
- count_loop_regs_set (loop, may_not_optimize, reg_single_usage,
+ regs->num = nregs;
+
+ count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
&insn_count, nregs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- VARRAY_CHAR (may_not_optimize, i) = 1;
- VARRAY_INT (set_in_loop, i) = 1;
+ VARRAY_CHAR (regs->may_not_optimize, i) = 1;
+ VARRAY_INT (regs->set_in_loop, i) = 1;
}
#ifdef AVOID_CCMODE_COPIES
create CCmode register copies. */
for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
- VARRAY_CHAR (may_not_optimize, i) = 1;
+ VARRAY_CHAR (regs->may_not_optimize, i) = 1;
#endif
- bcopy ((char *) &set_in_loop->data,
- (char *) &n_times_set->data, nregs * sizeof (int));
+ bcopy ((char *) ®s->set_in_loop->data,
+ (char *) ®s->n_times_set->data, nregs * sizeof (int));
if (loop_dump_stream)
{
}
/* Scan through the loop finding insns that are safe to move.
- Set set_in_loop negative for the reg being set, so that
+ Set regs->set_in_loop negative for the reg 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.
if (GET_CODE (p) == INSN
&& (set = single_set (p))
&& GET_CODE (SET_DEST (set)) == REG
- && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
+ && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
{
int tem1 = 0;
int tem2 = 0;
else if ((tem = loop_invariant_p (loop, src))
&& (dependencies == 0
|| (tem2 = loop_invariant_p (loop, dependencies)) != 0)
- && (VARRAY_INT (set_in_loop,
+ && (VARRAY_INT (regs->set_in_loop,
REGNO (SET_DEST (set))) == 1
|| (tem1
= consec_sets_invariant_p
(loop, SET_DEST (set),
- VARRAY_INT (set_in_loop, REGNO (SET_DEST (set))),
+ VARRAY_INT (regs->set_in_loop,
+ REGNO (SET_DEST (set))),
p)))
/* If the insn can cause a trap (such as divide by zero),
can't move it unless it's guaranteed to be executed
SMALL_REGISTER_CLASSES and SET_SRC is a hard register. */
if (loop_info->has_call
- && VARRAY_RTX (reg_single_usage, regno) != 0
- && VARRAY_RTX (reg_single_usage, regno) != const0_rtx
+ && VARRAY_RTX (regs->single_usage, regno) != 0
+ && VARRAY_RTX (regs->single_usage, regno) != const0_rtx
&& REGNO_FIRST_UID (regno) == INSN_UID (p)
&& (REGNO_LAST_UID (regno)
- == INSN_UID (VARRAY_RTX (reg_single_usage, regno)))
- && VARRAY_INT (set_in_loop, regno) == 1
+ == INSN_UID (VARRAY_RTX (regs->single_usage, regno)))
+ && VARRAY_INT (regs->set_in_loop, regno) == 1
&& ! side_effects_p (SET_SRC (set))
&& ! find_reg_note (p, REG_RETVAL, NULL_RTX)
&& (! SMALL_REGISTER_CLASSES
might span a call. */
&& ! modified_between_p (SET_SRC (set), p,
VARRAY_RTX
- (reg_single_usage, regno))
- && no_labels_between_p (p, VARRAY_RTX (reg_single_usage, regno))
+ (regs->single_usage, regno))
+ && no_labels_between_p (p, VARRAY_RTX (regs->single_usage,
+ regno))
&& validate_replace_rtx (SET_DEST (set), SET_SRC (set),
VARRAY_RTX
- (reg_single_usage, regno)))
+ (regs->single_usage, regno)))
{
/* 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 (reg_single_usage, regno))
+ REG_NOTES (VARRAY_RTX (regs->single_usage, regno))
= replace_rtx (REG_NOTES (VARRAY_RTX
- (reg_single_usage, regno)),
+ (regs->single_usage, regno)),
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 (set_in_loop, regno) = 0;
+ VARRAY_INT (regs->set_in_loop, regno) = 0;
continue;
}
m->dependencies = dependencies;
m->set_dest = SET_DEST (set);
m->force = 0;
- m->consec = VARRAY_INT (set_in_loop,
+ m->consec = VARRAY_INT (regs->set_in_loop,
REGNO (SET_DEST (set))) - 1;
m->done = 0;
m->forces = 0;
m->match = 0;
m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
- uid_luid[REGNO_FIRST_UID (regno)]);
- m->savings = VARRAY_INT (n_times_set, regno);
+ m->savings = VARRAY_INT (regs->n_times_set, regno);
if (find_reg_note (p, REG_RETVAL, NULL_RTX))
m->savings += libcall_benefit (p);
- VARRAY_INT (set_in_loop, regno) = move_insn ? -2 : -1;
+ VARRAY_INT (regs->set_in_loop, regno) = move_insn ? -2 : -1;
/* Add M to the end of the chain MOVABLES. */
if (movables->head == 0)
movables->head = m;
&& !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
{
register int regno = REGNO (SET_DEST (set));
- if (VARRAY_INT (set_in_loop, regno) == 2)
+ if (VARRAY_INT (regs->set_in_loop, regno) == 2)
{
register struct movable *m;
m = (struct movable *) alloca (sizeof (struct movable));
m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
- uid_luid[REGNO_FIRST_UID (regno)]);
m->savings = 1;
- VARRAY_INT (set_in_loop, regno) = -1;
+ VARRAY_INT (regs->set_in_loop, regno) = -1;
/* Add M to the end of the chain MOVABLES. */
if (movables->head == 0)
movables->head = m;
through the `match' field, and add the priorities of them
all together as the priority of the first. */
- combine_movables (movables, nregs);
+ combine_movables (movables, regs);
/* Now consider each movable insn to decide whether it is worth moving.
- Store 0 in set_in_loop for each reg that is moved.
+ Store 0 in regs->set_in_loop for each reg that is moved.
Generally this increases code size, so do not move moveables when
optimizing for code size. */
move_movables (loop, movables, threshold, insn_count, nregs);
/* Now candidates that still are negative are those not moved.
- Change set_in_loop to indicate that those are not actually invariant. */
+ Change regs->set_in_loop to indicate that those are not actually
+ invariant. */
for (i = 0; i < nregs; i++)
- if (VARRAY_INT (set_in_loop, i) < 0)
- VARRAY_INT (set_in_loop, i) = VARRAY_INT (n_times_set, i);
+ if (VARRAY_INT (regs->set_in_loop, i) < 0)
+ VARRAY_INT (regs->set_in_loop, i) = VARRAY_INT (regs->n_times_set, i);
/* Now that we've moved some things out of the loop, we might be able to
hoist even more memory references. */
delete_insn (update_end);
}
- VARRAY_FREE (reg_single_usage);
- VARRAY_FREE (set_in_loop);
- VARRAY_FREE (n_times_set);
- VARRAY_FREE (may_not_optimize);
+ VARRAY_FREE (regs->single_usage);
+ VARRAY_FREE (regs->set_in_loop);
+ VARRAY_FREE (regs->n_times_set);
+ VARRAY_FREE (regs->may_not_optimize);
}
\f
/* Add elements to *OUTPUT to record all the pseudo-regs
one register. */
static void
-combine_movables (movables, nregs)
+combine_movables (movables, regs)
struct movables *movables;
- int nregs;
+ struct loop_regs *regs;
{
+ int nregs = regs->num;
register struct movable *m;
char *matched_regs = (char *) xmalloc (nregs);
enum machine_mode mode;
/* Perhaps testing m->consec_sets would be more appropriate here? */
for (m = movables->head; m; m = m->next)
- if (m->match == 0 && VARRAY_INT (n_times_set, m->regno) == 1
+ if (m->match == 0 && VARRAY_INT (regs->n_times_set, m->regno) == 1
&& !m->partial)
{
register struct movable *m1;
/* 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 (n_times_set, m1->regno) == 1
+ if (m != m1 && m1->match == 0 && VARRAY_INT (regs->n_times_set,
+ m1->regno) == 1
/* A reg used outside the loop mustn't be eliminated. */
&& !m1->global
/* A reg used for zero-extending mustn't be eliminated. */
&& ((GET_CODE (m1->set_src) == REG
&& matched_regs[REGNO (m1->set_src)])
|| rtx_equal_for_loop_p (m->set_src, m1->set_src,
- movables))))
+ movables, regs))))
&& ((m->dependencies == m1->dependencies)
|| rtx_equal_p (m->dependencies, m1->dependencies)))
{
equivalent constant, consider them equal. */
static int
-rtx_equal_for_loop_p (x, y, movables)
+rtx_equal_for_loop_p (x, y, movables, regs)
rtx x, y;
struct movables *movables;
+ struct loop_regs * regs;
{
register int i;
register int j;
/* If we have a register and a constant, they may sometimes be
equal. */
- if (GET_CODE (x) == REG && VARRAY_INT (set_in_loop, REGNO (x)) == -2
+ if (GET_CODE (x) == REG && VARRAY_INT (regs->set_in_loop, REGNO (x)) == -2
&& CONSTANT_P (y))
{
for (m = movables->head; m; m = m->next)
&& rtx_equal_p (m->set_src, y))
return 1;
}
- else if (GET_CODE (y) == REG && VARRAY_INT (set_in_loop, REGNO (y)) == -2
+ else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop,
+ REGNO (y)) == -2
&& CONSTANT_P (x))
{
for (m = movables->head; m; m = m->next)
/* And the corresponding elements must match. */
for (j = 0; j < XVECLEN (x, i); j++)
- if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j), movables) == 0)
+ if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
+ movables, regs) == 0)
return 0;
break;
case 'e':
- if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i), movables) == 0)
+ if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i),
+ movables, regs) == 0)
return 0;
break;
int insn_count;
int nregs;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
rtx new_start = 0;
register struct movable *m;
register rtx p;
if (loop_dump_stream)
fprintf (loop_dump_stream, "savings %d ", savings);
- if (moved_once[regno] && loop_dump_stream)
+ if (regs->moved_once[regno] && loop_dump_stream)
fprintf (loop_dump_stream, "halved since already moved ");
/* An insn MUST be moved if we already moved something else
if (already_moved[regno]
|| flag_move_all_movables
|| (threshold * savings * m->lifetime) >=
- (moved_once[regno] ? insn_count * 2 : insn_count)
+ (regs->moved_once[regno] ? insn_count * 2 : insn_count)
|| (m->forces && m->forces->done
- && VARRAY_INT (n_times_set, m->forces->regno) == 1))
+ && VARRAY_INT (regs->n_times_set, m->forces->regno) == 1))
{
int count;
register struct movable *m1;
already_moved[regno] = 1;
/* This reg has been moved out of one loop. */
- moved_once[regno] = 1;
+ regs->moved_once[regno] = 1;
/* The reg set here is now invariant. */
if (! m->partial)
- VARRAY_INT (set_in_loop, regno) = 0;
+ VARRAY_INT (regs->set_in_loop, regno) = 0;
m->done = 1;
/* The reg merged here is now invariant,
if the reg it matches is invariant. */
if (! m->partial)
- VARRAY_INT (set_in_loop, m1->regno) = 0;
+ VARRAY_INT (regs->set_in_loop, m1->regno) = 0;
}
}
else if (loop_dump_stream)
rtx y ATTRIBUTE_UNUSED;
void *data;
{
+ struct loop_regs *regs = (struct loop_regs *) data;
+
if (x == 0)
return;
/* 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 (reg_single_usage, REGNO (x))
- || VARRAY_RTX (reg_single_usage, REGNO (x)) == const0_rtx)
+ || ! VARRAY_RTX (regs->single_usage, REGNO (x))
+ || VARRAY_RTX (regs->single_usage, REGNO (x)) == const0_rtx)
*((int *) data) = 1;
}
\f
register rtx x;
{
struct loop_info *loop_info = LOOP_INFO (loop);
+ struct loop_regs *regs = LOOP_REGS (loop);
register int i;
register enum rtx_code code;
register const char *fmt;
&& REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
return 0;
- if (VARRAY_INT (set_in_loop, REGNO (x)) < 0)
+ if (VARRAY_INT (regs->set_in_loop, REGNO (x)) < 0)
return 2;
- return VARRAY_INT (set_in_loop, REGNO (x)) == 0;
+ return VARRAY_INT (regs->set_in_loop, REGNO (x)) == 0;
case MEM:
/* Volatile memory references must be rejected. Do this before
int n_sets;
rtx reg, insn;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
rtx p = insn;
unsigned int regno = REGNO (reg);
rtx temp;
/* Number of sets we have to insist on finding after INSN. */
int count = n_sets - 1;
- int old = VARRAY_INT (set_in_loop, regno);
+ int old = VARRAY_INT (regs->set_in_loop, regno);
int value = 0;
int this;
if (n_sets == 127)
return 0;
- VARRAY_INT (set_in_loop, regno) = 0;
+ VARRAY_INT (regs->set_in_loop, regno) = 0;
while (count > 0)
{
count--;
else if (code != NOTE)
{
- VARRAY_INT (set_in_loop, regno) = old;
+ VARRAY_INT (regs->set_in_loop, regno) = old;
return 0;
}
}
- VARRAY_INT (set_in_loop, regno) = old;
+ VARRAY_INT (regs->set_in_loop, regno) = old;
/* If loop_invariant_p ever returned 2, we return 2. */
return 1 + (value & 2);
}
MAY_NOT_MOVE and LAST_SET for any register set in X. */
static void
-count_one_set (insn, x, may_not_move, last_set)
+count_one_set (regs, insn, x, may_not_move, last_set)
+ struct loop_regs *regs;
rtx insn, x;
varray_type may_not_move;
rtx *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 (set_in_loop, regno) > 0
+ if (VARRAY_INT (regs->set_in_loop, regno) > 0
&& last_set[regno] == 0)
VARRAY_CHAR (may_not_move, regno) = 1;
/* If this is not first setting in current basic block,
if (last_set[regno] != 0
&& reg_used_between_p (dest, last_set[regno], insn))
VARRAY_CHAR (may_not_move, regno) = 1;
- if (VARRAY_INT (set_in_loop, regno) < 127)
- ++VARRAY_INT (set_in_loop, regno);
+ if (VARRAY_INT (regs->set_in_loop, regno) < 127)
+ ++VARRAY_INT (regs->set_in_loop, regno);
last_set[regno] = insn;
}
}
}
-/* Increment SET_IN_LOOP at the index of each register
+/* 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 SET_IN_LOOP becomes 127 or more,
+ If the value of an element of REGS->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
int *count_ptr;
int nregs;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx));
register rtx insn;
register int count = 0;
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
- count_one_set (insn, PATTERN (insn), may_not_move, last_set);
+ count_one_set (regs, insn, PATTERN (insn), may_not_move, 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 (insn, XVECEXP (PATTERN (insn), 0, i),
+ count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
may_not_move, last_set);
}
}
\f
/* Perform strength reduction and induction variable elimination.
- Pseudo registers created during this function will be beyond the last
- valid index in several tables including 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. */
+ 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. */
static void
strength_reduce (loop, insn_count, flags)
int insn_count;
int flags;
{
+ struct loop_info *loop_info = LOOP_INFO (loop);
+ struct loop_regs *regs = LOOP_REGS (loop);
rtx p;
/* Temporary list pointers for traversing loop_iv_list. */
struct iv_class *bl, **backbl;
- struct loop_info *loop_info = LOOP_INFO (loop);
/* Ratio of extra register life span we can justify
for saving an instruction. More if loop doesn't call subroutines
since in that case saving an insn makes more difference
for_each_insn_in_loop (loop, check_insn_for_bivs);
/* Scan loop_iv_list to remove all regs that proved not to be bivs.
- Make a sanity check against n_times_set. */
+ Make a sanity check against regs->n_times_set. */
for (backbl = &loop_iv_list, bl = *backbl; bl; bl = bl->next)
{
if (REG_IV_TYPE (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 (n_times_set, bl->regno) != bl->biv_count
+ || VARRAY_INT (regs->n_times_set, bl->regno) != bl->biv_count
/* If never incremented, it is invariant that we decided not to
move. So leave it alone. */
|| ! bl->incremented)
have been allocated with some slop space, so we may not
actually need to reallocate them. If we do, the following
if statement will be executed just once in this loop. */
- if ((unsigned) max_reg_num () > n_times_set->num_elements)
+ if ((unsigned) max_reg_num () > regs->n_times_set->num_elements)
{
/* Grow all the remaining arrays. */
- VARRAY_GROW (set_in_loop, nregs);
- VARRAY_GROW (n_times_set, nregs);
- VARRAY_GROW (may_not_optimize, nregs);
- VARRAY_GROW (reg_single_usage, nregs);
+ 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);
}
/* Some bivs are incremented with a multi-insn sequence.
old_regno = REGNO (old_reg);
new_regno = REGNO (dest_reg);
- VARRAY_INT (set_in_loop, old_regno)--;
- VARRAY_INT (set_in_loop, new_regno) = 1;
- VARRAY_INT (n_times_set, old_regno)--;
- VARRAY_INT (n_times_set, new_regno) = 1;
- VARRAY_CHAR (may_not_optimize, new_regno) = 0;
+ VARRAY_INT (regs->set_in_loop, old_regno)--;
+ VARRAY_INT (regs->set_in_loop, new_regno) = 1;
+ VARRAY_INT (regs->n_times_set, old_regno)--;
+ VARRAY_INT (regs->n_times_set, new_regno) = 1;
+ VARRAY_CHAR (regs->may_not_optimize, new_regno) = 0;
REG_IV_TYPE (new_regno) = GENERAL_INDUCT;
REG_IV_INFO (new_regno) = v;
check_ext_dependant_givs (bl, loop_info);
/* Combine all giv's for this iv_class. */
- combine_givs (bl);
+ combine_givs (regs, bl);
/* This will be true at the end, if all givs which depend on this
biv have been strength reduced.
int not_every_iteration;
int maybe_multiple;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
rtx set;
/* Look for a general induction variable in a register. */
if (GET_CODE (p) == INSN
&& (set = single_set (p))
&& GET_CODE (SET_DEST (set)) == REG
- && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
+ && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
{
rtx src_reg;
rtx dest_reg;
/* 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 (n_times_set, REGNO (dest_reg)) == 1
+ && (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) == 1
/* or all sets must be consecutive and make a giv. */
|| (benefit = consec_sets_giv (loop, benefit, p,
src_reg, dest_reg,
benefit += libcall_benefit (p);
/* Skip the consecutive insns, if there are any. */
- if (VARRAY_INT (n_times_set, REGNO (dest_reg)) != 1)
+ if (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) != 1)
p = last_consec_insn;
record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
rtx *ext_val;
int *benefit;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
enum machine_mode mode = GET_MODE (x);
rtx arg0, arg1;
rtx tem;
less harmful than reducing many givs that are not really
beneficial. */
{
- rtx single_use = VARRAY_RTX (reg_single_usage, REGNO (x));
+ rtx single_use = VARRAY_RTX (regs->single_usage, REGNO (x));
if (single_use && single_use != const0_rtx)
*benefit += v->benefit;
}
rtx *ext_val;
rtx *last_consec_insn;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
int count;
enum rtx_code code;
int benefit;
REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT;
REG_IV_INFO (REGNO (dest_reg)) = v;
- count = VARRAY_INT (n_times_set, REGNO (dest_reg)) - 1;
+ count = VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) - 1;
while (count > 0)
{
giv. Also, update BENEFIT and related fields for cost/benefit analysis. */
static void
-combine_givs (bl)
+combine_givs (regs, bl)
+ struct loop_regs *regs;
struct iv_class *bl;
{
/* Additional benefit to add for being combined multiple times. */
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 (reg_single_usage, REGNO (g1->dest_reg)))
+ && (single_use = VARRAY_RTX (regs->single_usage,
+ REGNO (g1->dest_reg)))
&& single_use != const0_rtx)
continue;
struct iv_class *bl;
int unroll_p;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
struct induction *v, **giv_array, *last_giv;
struct recombine_givs_stats *stats;
int giv_count;
else
{
int regno = REGNO (v->dest_reg);
- int count = VARRAY_INT (n_times_set, regno) - 1;
+ int count = VARRAY_INT (regs->n_times_set, regno) - 1;
rtx p = v->insn;
/* Find the first insn that sets the giv, so that we can verify
struct loop *loop;
int insn_count;
{
+ struct loop_info *loop_info = LOOP_INFO (loop);
+ struct loop_regs *regs = LOOP_REGS (loop);
struct iv_class *bl;
rtx reg;
rtx jump_label;
int compare_and_branch;
rtx loop_start = loop->start;
rtx loop_end = loop->end;
- struct loop_info *loop_info = LOOP_INFO (loop);
/* If last insn is a conditional branch, and the insn before tests a
register value, try to optimize it. Otherwise, we can't do anything. */
that has more than one usage, then the biv has uses
other than counting since it's used to derive a value
that is used more than one time. */
- int note_set_pseudo_multiple_uses_retval = 0;
note_stores (PATTERN (p), note_set_pseudo_multiple_uses,
- ¬e_set_pseudo_multiple_uses_retval);
- if (note_set_pseudo_multiple_uses_retval)
+ regs);
+ if (regs->multiple_uses)
{
no_use_except_counting = 0;
break;
return 0;
}
-/* Like load_mems, but also ensures that SET_IN_LOOP,
- MAY_NOT_OPTIMIZE, REG_SINGLE_USAGE, and INSN_COUNT have the correct
+/* 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. */
static void
const struct loop *loop;
int *insn_count;
{
+ struct loop_regs *regs = LOOP_REGS (loop);
int nregs = max_reg_num ();
load_mems (loop);
- /* Recalculate set_in_loop and friends since load_mems may have
+ /* Recalculate regs->set_in_loop and friends since load_mems may have
created new registers. */
if (max_reg_num () > nregs)
{
old_nregs = nregs;
nregs = max_reg_num ();
- if ((unsigned) nregs > set_in_loop->num_elements)
+ if ((unsigned) nregs > regs->set_in_loop->num_elements)
{
/* Grow all the arrays. */
- VARRAY_GROW (set_in_loop, nregs);
- VARRAY_GROW (n_times_set, nregs);
- VARRAY_GROW (may_not_optimize, nregs);
- VARRAY_GROW (reg_single_usage, nregs);
+ 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);
}
/* Clear the arrays */
- bzero ((char *) &set_in_loop->data, nregs * sizeof (int));
- bzero ((char *) &may_not_optimize->data, nregs * sizeof (char));
- bzero ((char *) ®_single_usage->data, nregs * sizeof (rtx));
+ bzero ((char *) ®s->set_in_loop->data, nregs * sizeof (int));
+ bzero ((char *) ®s->may_not_optimize->data, nregs * sizeof (char));
+ bzero ((char *) ®s->single_usage->data, nregs * sizeof (rtx));
- count_loop_regs_set (loop, may_not_optimize, reg_single_usage,
+ count_loop_regs_set (loop, regs->may_not_optimize,
+ regs->single_usage,
insn_count, nregs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- VARRAY_CHAR (may_not_optimize, i) = 1;
- VARRAY_INT (set_in_loop, i) = 1;
+ VARRAY_CHAR (regs->may_not_optimize, i) = 1;
+ VARRAY_INT (regs->set_in_loop, i) = 1;
}
#ifdef AVOID_CCMODE_COPIES
create CCmode register copies. */
for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
- VARRAY_CHAR (may_not_optimize, i) = 1;
+ VARRAY_CHAR (regs->may_not_optimize, i) = 1;
#endif
- /* Set n_times_set for the new registers. */
- bcopy ((char *) (&set_in_loop->data.i[0] + old_nregs),
- (char *) (&n_times_set->data.i[0] + old_nregs),
+ /* 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));
}
}
const struct loop *loop;
{
struct loop_info *loop_info = LOOP_INFO (loop);
+ struct loop_regs *regs = LOOP_REGS (loop);
int maybe_never = 0;
int i;
rtx p;
&& GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& REGNO (SET_DEST (set)) < last_max_reg
- && VARRAY_INT (n_times_set, REGNO (SET_DEST (set))) == 1
+ && VARRAY_INT (regs->n_times_set,
+ REGNO (SET_DEST (set))) == 1
&& rtx_equal_p (SET_SRC (set), mem))
SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set)));
&& GET_CODE (SET_SRC (set)) == REG
&& REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
&& REGNO (SET_SRC (set)) < last_max_reg
- && VARRAY_INT (n_times_set, REGNO (SET_SRC (set))) == 1
+ && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1
&& rtx_equal_p (SET_DEST (set), mem))
SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));