loop.h (struct loop_mem_info): Move from loop.c (struct loop_info): Add fields store_mems...
* loop.h (struct loop_mem_info): Move from loop.c (struct loop_info): Add fields store_mems, mems, mems_idx, mems_allocated, unknown_address_altered, unknown_constant_address_altered, num_mem_sets, and first_loop_store_insn. * loop.c (loop_store_mems): Replace with field in loop_info struct. (loop_mems, loop_mems_idx, loop_mems_allocated): Likewise. (unknown_address_altered, unknown_constant_address_altered): Likewise. (num_mem_sets): Likewise. (replace_loop_mems, replace_loop_regs): New. (struct loop_replace_args): New. (load_mems): Use replace_loop_mems. (try_copy_prop): Use replace_loop_regs. (replace_loop_reg, replace_loop_mem): Use loop_replace_args structure. From-SVN: r36284
This commit is contained in:
parent
8a019bcf78
commit
afa1738b58
@ -1,3 +1,21 @@
|
||||
2000-09-11 Michael Hayes <mhayes@cygnus.com>
|
||||
|
||||
* loop.h (struct loop_mem_info): Move from loop.c
|
||||
(struct loop_info): Add fields store_mems, mems, mems_idx,
|
||||
mems_allocated, unknown_address_altered,
|
||||
unknown_constant_address_altered, num_mem_sets, and
|
||||
first_loop_store_insn.
|
||||
|
||||
* loop.c (loop_store_mems): Replace with field in loop_info struct.
|
||||
(loop_mems, loop_mems_idx, loop_mems_allocated): Likewise.
|
||||
(unknown_address_altered, unknown_constant_address_altered): Likewise.
|
||||
(num_mem_sets): Likewise.
|
||||
(replace_loop_mems, replace_loop_regs): New.
|
||||
(struct loop_replace_args): New.
|
||||
(load_mems): Use replace_loop_mems.
|
||||
(try_copy_prop): Use replace_loop_regs.
|
||||
(replace_loop_reg, replace_loop_mem): Use loop_replace_args structure.
|
||||
|
||||
2000-09-09 Stephane Carrez <Stephane.Carrez@worldnet.fr>
|
||||
|
||||
* configure.in: Recognize m6811-elf and m6812-elf.
|
||||
|
285
gcc/loop.c
285
gcc/loop.c
@ -113,49 +113,6 @@ static varray_type reg_single_usage;
|
||||
|
||||
static char *moved_once;
|
||||
|
||||
/* List of MEMs that are stored in this loop. */
|
||||
|
||||
static rtx loop_store_mems;
|
||||
|
||||
/* The insn where the first of these was found. */
|
||||
static rtx first_loop_store_insn;
|
||||
|
||||
typedef struct loop_mem_info {
|
||||
rtx mem; /* The MEM itself. */
|
||||
rtx reg; /* Corresponding pseudo, if any. */
|
||||
int optimize; /* Nonzero if we can optimize access to this MEM. */
|
||||
} loop_mem_info;
|
||||
|
||||
/* Array of MEMs that are used (read or written) in this loop, but
|
||||
cannot be aliased by anything in this loop, except perhaps
|
||||
themselves. In other words, if loop_mems[i] is altered during the
|
||||
loop, it is altered by an expression that is rtx_equal_p to it. */
|
||||
|
||||
static loop_mem_info *loop_mems;
|
||||
|
||||
/* The index of the next available slot in LOOP_MEMS. */
|
||||
|
||||
static int loop_mems_idx;
|
||||
|
||||
/* The number of elements allocated in LOOP_MEMs. */
|
||||
|
||||
static int loop_mems_allocated;
|
||||
|
||||
/* Nonzero if we don't know what MEMs were changed in the current
|
||||
loop. This happens if the loop contains a call (in which case
|
||||
`loop_info->has_call' will also be set) or if we store into more
|
||||
than NUM_STORES MEMs. */
|
||||
|
||||
static int unknown_address_altered;
|
||||
|
||||
/* The above doesn't count any readonly memory locations that are stored.
|
||||
This does. */
|
||||
|
||||
static int unknown_constant_address_altered;
|
||||
|
||||
/* Count of memory write instructions discovered in the loop. */
|
||||
static int num_mem_sets;
|
||||
|
||||
/* 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;
|
||||
@ -314,7 +271,9 @@ static void load_mems_and_recount_loop_regs_set PARAMS ((const struct loop*,
|
||||
static void load_mems PARAMS ((const struct loop *));
|
||||
static int insert_loop_mem PARAMS ((rtx *, void *));
|
||||
static int replace_loop_mem PARAMS ((rtx *, void *));
|
||||
static void replace_loop_mems PARAMS ((rtx, rtx, rtx));
|
||||
static int replace_loop_reg PARAMS ((rtx *, void *));
|
||||
static void replace_loop_regs PARAMS ((rtx insn, rtx, rtx));
|
||||
static void note_reg_stored PARAMS ((rtx, rtx, void *));
|
||||
static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
|
||||
static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
|
||||
@ -327,16 +286,18 @@ static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
|
||||
static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
|
||||
void debug_loop PARAMS ((const struct loop *));
|
||||
|
||||
typedef struct rtx_and_int {
|
||||
rtx r;
|
||||
int i;
|
||||
} rtx_and_int;
|
||||
|
||||
typedef struct rtx_pair {
|
||||
rtx r1;
|
||||
rtx r2;
|
||||
} rtx_pair;
|
||||
|
||||
typedef struct loop_replace_args
|
||||
{
|
||||
rtx match;
|
||||
rtx replacement;
|
||||
rtx insn;
|
||||
} loop_replace_args;
|
||||
|
||||
/* Nonzero iff INSN is between START and END, inclusive. */
|
||||
#define INSN_IN_RANGE_P(INSN, START, END) \
|
||||
(INSN_UID (INSN) < max_uid_for_loop \
|
||||
@ -616,12 +577,12 @@ scan_loop (loop, flags)
|
||||
int loop_depth = 0;
|
||||
int nregs;
|
||||
|
||||
loop->top = 0;
|
||||
|
||||
movables->head = 0;
|
||||
movables->last = 0;
|
||||
movables->num = 0;
|
||||
|
||||
loop->top = 0;
|
||||
|
||||
/* Determine whether this loop starts with a jump down to a test at
|
||||
the end. This will occur for a small number of loops with a test
|
||||
that is too complex to duplicate in front of the loop.
|
||||
@ -704,7 +665,7 @@ scan_loop (loop, flags)
|
||||
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_mems_idx + 16;
|
||||
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");
|
||||
@ -2332,10 +2293,10 @@ count_nonfixed_reads (loop, x)
|
||||
}
|
||||
|
||||
/* Scan a loop setting the elements `cont', `vtop', `loops_enclosed',
|
||||
`has_call', `has_volatile', and `has_tablejump' within LOOP.
|
||||
Set the global variables `unknown_address_altered',
|
||||
`unknown_constant_address_altered', and `num_mem_sets'. Also, fill
|
||||
in the array `loop_mems' and the list `loop_store_mems'. */
|
||||
`has_call', `has_volatile', `has_tablejump',
|
||||
`unknown_address_altered', `unknown_constant_address_altered', and
|
||||
`num_mem_sets' in LOOP. Also, fill in the array `mems' and the
|
||||
list `store_mems' in LOOP. */
|
||||
|
||||
static void
|
||||
prescan_loop (loop)
|
||||
@ -2359,12 +2320,12 @@ prescan_loop (loop)
|
||||
loop_info->has_multiple_exit_targets = 0;
|
||||
loop->level = 1;
|
||||
|
||||
unknown_address_altered = 0;
|
||||
unknown_constant_address_altered = 0;
|
||||
loop_store_mems = NULL_RTX;
|
||||
first_loop_store_insn = NULL_RTX;
|
||||
loop_mems_idx = 0;
|
||||
num_mem_sets = 0;
|
||||
loop_info->unknown_address_altered = 0;
|
||||
loop_info->unknown_constant_address_altered = 0;
|
||||
loop_info->store_mems = NULL_RTX;
|
||||
loop_info->first_loop_store_insn = NULL_RTX;
|
||||
loop_info->mems_idx = 0;
|
||||
loop_info->num_mem_sets = 0;
|
||||
|
||||
for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
|
||||
insn = NEXT_INSN (insn))
|
||||
@ -2385,7 +2346,7 @@ prescan_loop (loop)
|
||||
else if (GET_CODE (insn) == CALL_INSN)
|
||||
{
|
||||
if (! CONST_CALL_P (insn))
|
||||
unknown_address_altered = 1;
|
||||
loop_info->unknown_address_altered = 1;
|
||||
loop_info->has_call = 1;
|
||||
}
|
||||
else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
|
||||
@ -2401,9 +2362,9 @@ prescan_loop (loop)
|
||||
|| GET_CODE (PATTERN (insn)) == ADDR_VEC))
|
||||
loop_info->has_tablejump = 1;
|
||||
|
||||
note_stores (PATTERN (insn), note_addr_stored, NULL);
|
||||
if (! first_loop_store_insn && loop_store_mems)
|
||||
first_loop_store_insn = insn;
|
||||
note_stores (PATTERN (insn), note_addr_stored, loop_info);
|
||||
if (! loop_info->first_loop_store_insn && loop_info->store_mems)
|
||||
loop_info->first_loop_store_insn = insn;
|
||||
|
||||
if (! loop_info->has_multiple_exit_targets
|
||||
&& GET_CODE (insn) == JUMP_INSN
|
||||
@ -2463,23 +2424,25 @@ prescan_loop (loop)
|
||||
&& ! loop_info->has_multiple_exit_targets)
|
||||
for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
|
||||
insn = NEXT_INSN (insn))
|
||||
for_each_rtx (&insn, insert_loop_mem, 0);
|
||||
for_each_rtx (&insn, insert_loop_mem, loop_info);
|
||||
|
||||
/* BLKmode MEMs are added to LOOP_STORE_MEM as necessary so
|
||||
that loop_invariant_p and load_mems can use true_dependence
|
||||
to determine what is really clobbered. */
|
||||
if (unknown_address_altered)
|
||||
if (loop_info->unknown_address_altered)
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
|
||||
|
||||
loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_store_mems);
|
||||
loop_info->store_mems
|
||||
= gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
|
||||
}
|
||||
if (unknown_constant_address_altered)
|
||||
if (loop_info->unknown_constant_address_altered)
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
|
||||
|
||||
RTX_UNCHANGING_P (mem) = 1;
|
||||
loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_store_mems);
|
||||
loop_info->store_mems
|
||||
= gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3093,25 +3056,28 @@ note_addr_stored (x, y, data)
|
||||
rtx y ATTRIBUTE_UNUSED;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
struct loop_info *loop_info = data;
|
||||
|
||||
if (x == 0 || GET_CODE (x) != MEM)
|
||||
return;
|
||||
|
||||
/* Count number of memory writes.
|
||||
This affects heuristics in strength_reduce. */
|
||||
num_mem_sets++;
|
||||
|
||||
loop_info->num_mem_sets++;
|
||||
|
||||
/* BLKmode MEM means all memory is clobbered. */
|
||||
if (GET_MODE (x) == BLKmode)
|
||||
if (GET_MODE (x) == BLKmode)
|
||||
{
|
||||
if (RTX_UNCHANGING_P (x))
|
||||
unknown_constant_address_altered = 1;
|
||||
loop_info->unknown_constant_address_altered = 1;
|
||||
else
|
||||
unknown_address_altered = 1;
|
||||
|
||||
loop_info->unknown_address_altered = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, loop_store_mems);
|
||||
|
||||
loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x,
|
||||
loop_info->store_mems);
|
||||
}
|
||||
|
||||
/* X is a value modified by an INSN that references a biv inside a loop
|
||||
@ -3151,13 +3117,14 @@ note_set_pseudo_multiple_uses (x, y, data)
|
||||
The value is 2 if we refer to something only conditionally invariant.
|
||||
|
||||
A memory ref is invariant if it is not volatile and does not conflict
|
||||
with anything stored in `loop_store_mems'. */
|
||||
with anything stored in `loop_info->store_mems'. */
|
||||
|
||||
int
|
||||
loop_invariant_p (loop, x)
|
||||
const struct loop *loop;
|
||||
register rtx x;
|
||||
{
|
||||
struct loop_info *loop_info = LOOP_INFO (loop);
|
||||
register int i;
|
||||
register enum rtx_code code;
|
||||
register const char *fmt;
|
||||
@ -3221,7 +3188,7 @@ loop_invariant_p (loop, x)
|
||||
return 0;
|
||||
|
||||
/* See if there is any dependence between a store and this load. */
|
||||
mem_list_entry = loop_store_mems;
|
||||
mem_list_entry = loop_info->store_mems;
|
||||
while (mem_list_entry)
|
||||
{
|
||||
if (true_dependence (XEXP (mem_list_entry, 0), VOIDmode,
|
||||
@ -8220,7 +8187,7 @@ check_dbra_loop (loop, insn_count)
|
||||
if (no_use_except_counting)
|
||||
/* No need to worry about MEMs. */
|
||||
;
|
||||
else if (num_mem_sets <= 1)
|
||||
else if (loop_info->num_mem_sets <= 1)
|
||||
{
|
||||
for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
|
||||
if (INSN_P (p))
|
||||
@ -8232,15 +8199,15 @@ check_dbra_loop (loop, insn_count)
|
||||
This would work if the source was invariant also, however, in that
|
||||
case, the insn should have been moved out of the loop. */
|
||||
|
||||
if (num_mem_sets == 1)
|
||||
if (loop_info->num_mem_sets == 1)
|
||||
{
|
||||
struct induction *v;
|
||||
|
||||
reversible_mem_store
|
||||
= (! unknown_address_altered
|
||||
&& ! unknown_constant_address_altered
|
||||
= (! loop_info->unknown_address_altered
|
||||
&& ! loop_info->unknown_constant_address_altered
|
||||
&& ! loop_invariant_p (loop,
|
||||
XEXP (XEXP (loop_store_mems, 0),
|
||||
XEXP (XEXP (loop_info->store_mems, 0),
|
||||
0)));
|
||||
|
||||
/* If the store depends on a register that is set after the
|
||||
@ -8250,8 +8217,9 @@ check_dbra_loop (loop, insn_count)
|
||||
{
|
||||
if (v->giv_type == DEST_REG
|
||||
&& reg_mentioned_p (v->dest_reg,
|
||||
PATTERN (first_loop_store_insn))
|
||||
&& loop_insn_first_p (first_loop_store_insn, v->insn))
|
||||
PATTERN (loop_info->first_loop_store_insn))
|
||||
&& loop_insn_first_p (loop_info->first_loop_store_insn,
|
||||
v->insn))
|
||||
reversible_mem_store = 0;
|
||||
}
|
||||
}
|
||||
@ -8271,7 +8239,7 @@ check_dbra_loop (loop, insn_count)
|
||||
&& ! loop_info->has_call
|
||||
&& ! loop_info->has_volatile
|
||||
&& reversible_mem_store
|
||||
&& (bl->giv_count + bl->biv_count + num_mem_sets
|
||||
&& (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
|
||||
+ the_movables.num + compare_and_branch == insn_count)
|
||||
&& (bl == loop_iv_list && bl->next == 0))
|
||||
|| no_use_except_counting)
|
||||
@ -9544,6 +9512,7 @@ insert_loop_mem (mem, data)
|
||||
rtx *mem;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
struct loop_info *loop_info = data;
|
||||
int i;
|
||||
rtx m = *mem;
|
||||
|
||||
@ -9574,40 +9543,40 @@ insert_loop_mem (mem, data)
|
||||
}
|
||||
|
||||
/* See if we've already seen this MEM. */
|
||||
for (i = 0; i < loop_mems_idx; ++i)
|
||||
if (rtx_equal_p (m, loop_mems[i].mem))
|
||||
for (i = 0; i < loop_info->mems_idx; ++i)
|
||||
if (rtx_equal_p (m, loop_info->mems[i].mem))
|
||||
{
|
||||
if (GET_MODE (m) != GET_MODE (loop_mems[i].mem))
|
||||
if (GET_MODE (m) != GET_MODE (loop_info->mems[i].mem))
|
||||
/* The modes of the two memory accesses are different. If
|
||||
this happens, something tricky is going on, and we just
|
||||
don't optimize accesses to this MEM. */
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resize the array, if necessary. */
|
||||
if (loop_mems_idx == loop_mems_allocated)
|
||||
if (loop_info->mems_idx == loop_info->mems_allocated)
|
||||
{
|
||||
if (loop_mems_allocated != 0)
|
||||
loop_mems_allocated *= 2;
|
||||
if (loop_info->mems_allocated != 0)
|
||||
loop_info->mems_allocated *= 2;
|
||||
else
|
||||
loop_mems_allocated = 32;
|
||||
loop_info->mems_allocated = 32;
|
||||
|
||||
loop_mems = (loop_mem_info*)
|
||||
xrealloc (loop_mems,
|
||||
loop_mems_allocated * sizeof (loop_mem_info));
|
||||
loop_info->mems = (loop_mem_info*)
|
||||
xrealloc (loop_info->mems,
|
||||
loop_info->mems_allocated * sizeof (loop_mem_info));
|
||||
}
|
||||
|
||||
/* Actually insert the MEM. */
|
||||
loop_mems[loop_mems_idx].mem = m;
|
||||
loop_info->mems[loop_info->mems_idx].mem = m;
|
||||
/* We can't hoist this MEM out of the loop if it's a BLKmode MEM
|
||||
because we can't put it in a register. We still store it in the
|
||||
table, though, so that if we see the same address later, but in a
|
||||
non-BLK mode, we'll not think we can optimize it at that point. */
|
||||
loop_mems[loop_mems_idx].optimize = (GET_MODE (m) != BLKmode);
|
||||
loop_mems[loop_mems_idx].reg = NULL_RTX;
|
||||
++loop_mems_idx;
|
||||
loop_info->mems[loop_info->mems_idx].optimize = (GET_MODE (m) != BLKmode);
|
||||
loop_info->mems[loop_info->mems_idx].reg = NULL_RTX;
|
||||
++loop_info->mems_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -9678,6 +9647,7 @@ static void
|
||||
load_mems (loop)
|
||||
const struct loop *loop;
|
||||
{
|
||||
struct loop_info *loop_info = LOOP_INFO (loop);
|
||||
int maybe_never = 0;
|
||||
int i;
|
||||
rtx p;
|
||||
@ -9687,7 +9657,7 @@ load_mems (loop)
|
||||
int next_maybe_never = 0;
|
||||
int last_max_reg = max_reg_num ();
|
||||
|
||||
if (loop_mems_idx == 0)
|
||||
if (loop_info->mems_idx == 0)
|
||||
return;
|
||||
|
||||
/* Find start of the extended basic block that enters the loop. */
|
||||
@ -9736,23 +9706,23 @@ load_mems (loop)
|
||||
}
|
||||
|
||||
/* Actually move the MEMs. */
|
||||
for (i = 0; i < loop_mems_idx; ++i)
|
||||
for (i = 0; i < loop_info->mems_idx; ++i)
|
||||
{
|
||||
regset_head load_copies;
|
||||
regset_head store_copies;
|
||||
int written = 0;
|
||||
rtx reg;
|
||||
rtx mem = loop_mems[i].mem;
|
||||
rtx mem = loop_info->mems[i].mem;
|
||||
rtx mem_list_entry;
|
||||
|
||||
if (MEM_VOLATILE_P (mem)
|
||||
|| loop_invariant_p (loop, XEXP (mem, 0)) != 1)
|
||||
/* There's no telling whether or not MEM is modified. */
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
|
||||
/* Go through the MEMs written to in the loop to see if this
|
||||
one is aliased by one of them. */
|
||||
mem_list_entry = loop_store_mems;
|
||||
mem_list_entry = loop_info->store_mems;
|
||||
while (mem_list_entry)
|
||||
{
|
||||
if (rtx_equal_p (mem, XEXP (mem_list_entry, 0)))
|
||||
@ -9761,7 +9731,7 @@ load_mems (loop)
|
||||
mem, rtx_varies_p))
|
||||
{
|
||||
/* MEM is indeed aliased by this store. */
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
break;
|
||||
}
|
||||
mem_list_entry = XEXP (mem_list_entry, 1);
|
||||
@ -9769,27 +9739,27 @@ load_mems (loop)
|
||||
|
||||
if (flag_float_store && written
|
||||
&& GET_MODE_CLASS (GET_MODE (mem)) == MODE_FLOAT)
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
|
||||
/* If this MEM is written to, we must be sure that there
|
||||
are no reads from another MEM that aliases this one. */
|
||||
if (loop_mems[i].optimize && written)
|
||||
if (loop_info->mems[i].optimize && written)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < loop_mems_idx; ++j)
|
||||
for (j = 0; j < loop_info->mems_idx; ++j)
|
||||
{
|
||||
if (j == i)
|
||||
continue;
|
||||
else if (true_dependence (mem,
|
||||
VOIDmode,
|
||||
loop_mems[j].mem,
|
||||
loop_info->mems[j].mem,
|
||||
rtx_varies_p))
|
||||
{
|
||||
/* It's not safe to hoist loop_mems[i] out of
|
||||
/* It's not safe to hoist loop_info->mems[i] out of
|
||||
the loop because writes to it might not be
|
||||
seen by reads from loop_mems[j]. */
|
||||
loop_mems[i].optimize = 0;
|
||||
seen by reads from loop_info->mems[j]. */
|
||||
loop_info->mems[i].optimize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -9798,9 +9768,9 @@ load_mems (loop)
|
||||
if (maybe_never && may_trap_p (mem))
|
||||
/* We can't access the MEM outside the loop; it might
|
||||
cause a trap that wouldn't have happened otherwise. */
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
|
||||
if (!loop_mems[i].optimize)
|
||||
if (!loop_info->mems[i].optimize)
|
||||
/* We thought we were going to lift this MEM out of the
|
||||
loop, but later discovered that we could not. */
|
||||
continue;
|
||||
@ -9814,7 +9784,7 @@ load_mems (loop)
|
||||
user-variable nor used in the loop test. */
|
||||
reg = gen_reg_rtx (GET_MODE (mem));
|
||||
REG_USERVAR_P (reg) = 1;
|
||||
loop_mems[i].reg = reg;
|
||||
loop_info->mems[i].reg = reg;
|
||||
|
||||
/* Now, replace all references to the MEM with the
|
||||
corresponding pesudos. */
|
||||
@ -9823,8 +9793,6 @@ load_mems (loop)
|
||||
p != NULL_RTX;
|
||||
p = next_insn_in_loop (loop, p))
|
||||
{
|
||||
rtx_and_int ri;
|
||||
|
||||
if (INSN_P (p))
|
||||
{
|
||||
rtx set;
|
||||
@ -9859,9 +9827,8 @@ load_mems (loop)
|
||||
SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
|
||||
|
||||
/* Replace the memory reference with the shadow register. */
|
||||
ri.r = p;
|
||||
ri.i = i;
|
||||
for_each_rtx (&p, replace_loop_mem, &ri);
|
||||
replace_loop_mems (p, loop_info->mems[i].mem,
|
||||
loop_info->mems[i].reg);
|
||||
}
|
||||
|
||||
if (GET_CODE (p) == CODE_LABEL
|
||||
@ -9871,7 +9838,7 @@ load_mems (loop)
|
||||
|
||||
if (! apply_change_group ())
|
||||
/* We couldn't replace all occurrences of the MEM. */
|
||||
loop_mems[i].optimize = 0;
|
||||
loop_info->mems[i].optimize = 0;
|
||||
else
|
||||
{
|
||||
/* Load the memory immediately before LOOP->START, which is
|
||||
@ -10065,12 +10032,8 @@ try_copy_prop (loop, replacement, regno)
|
||||
if (init_insn && insn != init_insn)
|
||||
{
|
||||
struct note_reg_stored_arg arg;
|
||||
rtx array[3];
|
||||
array[0] = reg_rtx;
|
||||
array[1] = replacement;
|
||||
array[2] = insn;
|
||||
|
||||
for_each_rtx (&insn, replace_loop_reg, array);
|
||||
replace_loop_regs (insn, reg_rtx, replacement);
|
||||
if (REGNO_LAST_UID (regno) == INSN_UID (insn))
|
||||
replaced_last = 1;
|
||||
|
||||
@ -10191,8 +10154,8 @@ try_swap_copy_prop (loop, replacement, regno)
|
||||
|
||||
|
||||
/* Replace MEM with its associated pseudo register. This function is
|
||||
called from load_mems via for_each_rtx. DATA is actually an
|
||||
rtx_and_int * describing the instruction currently being scanned
|
||||
called from load_mems via for_each_rtx. DATA is actually a pointer
|
||||
to a structure describing the instruction currently being scanned
|
||||
and the MEM we are currently replacing. */
|
||||
|
||||
static int
|
||||
@ -10200,9 +10163,7 @@ replace_loop_mem (mem, data)
|
||||
rtx *mem;
|
||||
void *data;
|
||||
{
|
||||
rtx_and_int *ri;
|
||||
rtx insn;
|
||||
int i;
|
||||
loop_replace_args *args = (loop_replace_args *)data;
|
||||
rtx m = *mem;
|
||||
|
||||
if (m == NULL_RTX)
|
||||
@ -10223,25 +10184,36 @@ replace_loop_mem (mem, data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ri = (rtx_and_int *) data;
|
||||
i = ri->i;
|
||||
|
||||
if (!rtx_equal_p (loop_mems[i].mem, m))
|
||||
if (!rtx_equal_p (args->match, m))
|
||||
/* This is not the MEM we are currently replacing. */
|
||||
return 0;
|
||||
|
||||
insn = ri->r;
|
||||
|
||||
/* Actually replace the MEM. */
|
||||
validate_change (insn, mem, loop_mems[i].reg, 1);
|
||||
validate_change (args->insn, mem, args->replacement, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
replace_loop_mems (insn, mem, reg)
|
||||
rtx insn;
|
||||
rtx mem;
|
||||
rtx reg;
|
||||
{
|
||||
loop_replace_args args;
|
||||
|
||||
args.insn = insn;
|
||||
args.match = mem;
|
||||
args.replacement = reg;
|
||||
|
||||
for_each_rtx (&insn, replace_loop_mem, &args);
|
||||
}
|
||||
|
||||
|
||||
/* Replace one register with another. Called through for_each_rtx; PX points
|
||||
to the rtx being scanned. DATA is actually an array of three rtx's; the
|
||||
first one is the one to be replaced, and the second one the replacement.
|
||||
The third one is the current insn. */
|
||||
to the rtx being scanned. DATA is actually a pointer to
|
||||
a structure of arguments. */
|
||||
|
||||
static int
|
||||
replace_loop_reg (px, data)
|
||||
@ -10249,17 +10221,34 @@ replace_loop_reg (px, data)
|
||||
void *data;
|
||||
{
|
||||
rtx x = *px;
|
||||
rtx *array = (rtx *) data;
|
||||
loop_replace_args *args = (loop_replace_args *)data;
|
||||
|
||||
if (x == NULL_RTX)
|
||||
return 0;
|
||||
|
||||
if (x == array[0])
|
||||
validate_change (array[2], px, array[1], 1);
|
||||
if (x == args->match)
|
||||
validate_change (args->insn, px, args->replacement, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
replace_loop_regs (insn, reg, replacement)
|
||||
rtx insn;
|
||||
rtx reg;
|
||||
rtx replacement;
|
||||
{
|
||||
loop_replace_args args;
|
||||
|
||||
args.insn = insn;
|
||||
args.match = reg;
|
||||
args.replacement = replacement;
|
||||
|
||||
for_each_rtx (&insn, replace_loop_reg, &args);
|
||||
}
|
||||
|
||||
|
||||
/* Replace occurrences of the old exit label for the loop with the new
|
||||
one. DATA is an rtx_pair containing the old and new labels,
|
||||
respectively. */
|
||||
|
33
gcc/loop.h
33
gcc/loop.h
@ -164,6 +164,15 @@ struct iv_class {
|
||||
biv controls. */
|
||||
};
|
||||
|
||||
|
||||
typedef struct loop_mem_info
|
||||
{
|
||||
rtx mem; /* The MEM itself. */
|
||||
rtx reg; /* Corresponding pseudo, if any. */
|
||||
int optimize; /* Nonzero if we can optimize access to this MEM. */
|
||||
} loop_mem_info;
|
||||
|
||||
|
||||
/* Information required to calculate the number of loop iterations.
|
||||
This is set by loop_iterations. */
|
||||
|
||||
@ -207,6 +216,30 @@ struct loop_info
|
||||
/* The number of times the loop body was unrolled. */
|
||||
unsigned int unroll_number;
|
||||
int used_count_register;
|
||||
/* List of MEMs that are stored in this loop. */
|
||||
rtx store_mems;
|
||||
/* Array of MEMs that are used (read or written) in this loop, but
|
||||
cannot be aliased by anything in this loop, except perhaps
|
||||
themselves. In other words, if mems[i] is altered during
|
||||
the loop, it is altered by an expression that is rtx_equal_p to
|
||||
it. */
|
||||
loop_mem_info *mems;
|
||||
/* The index of the next available slot in MEMS. */
|
||||
int mems_idx;
|
||||
/* The number of elements allocated in MEMS. */
|
||||
int mems_allocated;
|
||||
/* Nonzero if we don't know what MEMs were changed in the current
|
||||
loop. This happens if the loop contains a call (in which case
|
||||
`has_call' will also be set) or if we store into more than
|
||||
NUM_STORES MEMs. */
|
||||
int unknown_address_altered;
|
||||
/* The above doesn't count any readonly memory locations that are
|
||||
stored. This does. */
|
||||
int unknown_constant_address_altered;
|
||||
/* Count of memory write instructions discovered in the loop. */
|
||||
int num_mem_sets;
|
||||
/* The insn where the first of these was found. */
|
||||
rtx first_loop_store_insn;
|
||||
};
|
||||
|
||||
/* Definitions used by the basic induction variable discovery code. */
|
||||
|
Loading…
Reference in New Issue
Block a user