hard-reg-set.h: Add multiple include guard.

* hard-reg-set.h: Add multiple include guard.
	* basic-block.h (struct loop): Add `sink' field.
	* loop.h: Include sbitmap.h, hard-reg-set.h, and basic-block.h.
	(emit_iv_add_mult): Delete.
	(loop_iv_add_mult_hoist, loop_iv_add_mult_sink): Define.
	(loop_iv_add_mult_emit_before, loop_insn_sink): Define.
	(unroll_loop): Remove end_insert_before argument.
	* loop.c (loop_givs_rescan): Remove end_insert_before argument.
	(maybe_eliminate_biv_1): Likewise.
	(emit_iv_add_mult): Delete.
	(gen_add_mult, loop_regs_update): New.
	(loop_insn_emit_after, loop_insn_emit_before): New.
	(loop_insn_sink, loop_insn_sink_or_swim): New.
	(emit_iv_add_mult): Delete.
	(scan_loop): Set loop->sink.
	(loop_givs_reduce): Use loop_insn_sink and its ilk.
	(loop_givs_rescan, strength_reduce, check_dbra_loop): Likewise.
	(maybe_eliminate_biv_1): Likewise.
	(maybe_eliminate_biv_1): Add basic block argument.
	* unroll.c (unroll_loop): Remove end_insert_before argument.
	(find_splittable_regs): Likewise.
	(find_splittable_regs): Use loop_insn_sink and its ilk.
	(find_splittable_givs, final_biv_value, final_giv_value): Likewise.

From-SVN: r38766
This commit is contained in:
Michael Hayes 2001-01-07 10:38:29 +00:00 committed by Michael Hayes
parent 804a718aac
commit 96a45535c3
6 changed files with 297 additions and 157 deletions

View File

@ -1,3 +1,29 @@
2001-01-07 Michael Hayes <mhayes@redhat.com>
* hard-reg-set.h: Add multiple include guard.
* basic-block.h (struct loop): Add `sink' field.
* loop.h: Include sbitmap.h, hard-reg-set.h, and basic-block.h.
(emit_iv_add_mult): Delete.
(loop_iv_add_mult_hoist, loop_iv_add_mult_sink): Define.
(loop_iv_add_mult_emit_before, loop_insn_sink): Define.
(unroll_loop): Remove end_insert_before argument.
* loop.c (loop_givs_rescan): Remove end_insert_before argument.
(maybe_eliminate_biv_1): Likewise.
(emit_iv_add_mult): Delete.
(gen_add_mult, loop_regs_update): New.
(loop_insn_emit_after, loop_insn_emit_before): New.
(loop_insn_sink, loop_insn_sink_or_swim): New.
(emit_iv_add_mult): Delete.
(scan_loop): Set loop->sink.
(loop_givs_reduce): Use loop_insn_sink and its ilk.
(loop_givs_rescan, strength_reduce, check_dbra_loop): Likewise.
(maybe_eliminate_biv_1): Likewise.
(maybe_eliminate_biv_1): Add basic block argument.
* unroll.c (unroll_loop): Remove end_insert_before argument.
(find_splittable_regs): Likewise.
(find_splittable_regs): Use loop_insn_sink and its ilk.
(find_splittable_givs, final_biv_value, final_giv_value): Likewise.
2001-01-07 Michael Hayes <mhayes@redhat.com>
* loop.h (loop_insn_hoist): New prototype.

View File

@ -365,6 +365,9 @@ struct loop
/* Place in the loop where control enters. */
rtx scan_start;
/* The position where to sink insns out of the loop. */
rtx sink;
/* List of all LABEL_REFs which refer to code labels outside the
loop. Used by routines that need to know all loop exits, such as
final_biv_value and final_giv_value.

View File

@ -18,6 +18,8 @@ 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. */
#ifndef _HARD_REG_SET_H
#define _HARD_REG_SET_H 1
/* Define the type of a set of hard registers. */
@ -472,3 +474,5 @@ extern int n_non_fixed_regs;
/* Vector indexed by hardware reg giving its name. */
extern const char * reg_names[FIRST_PSEUDO_REGISTER];
#endif /* _HARD_REG_SET_H */

View File

@ -188,7 +188,7 @@ static int loop_giv_reduce_benefit PARAMS((struct loop *, struct iv_class *,
static void loop_givs_dead_check PARAMS((struct loop *, struct iv_class *));
static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
rtx *, 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 ((struct loop_regs *, rtx, rtx));
@ -225,7 +225,8 @@ static int product_cheap_p PARAMS ((rtx, rtx));
static int maybe_eliminate_biv PARAMS ((const struct loop *, struct iv_class *,
int, int, int));
static int maybe_eliminate_biv_1 PARAMS ((const struct loop *, rtx, rtx,
struct iv_class *, int, rtx));
struct iv_class *, int,
basic_block, rtx));
static int last_use_this_basic_block PARAMS ((rtx, rtx));
static void record_initial PARAMS ((rtx, rtx, void *));
static void update_reg_last_use PARAMS ((rtx, rtx));
@ -244,10 +245,15 @@ static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
static int replace_label PARAMS ((rtx *, void *));
static rtx check_insn_for_givs PARAMS((struct loop *, rtx, int, int));
static rtx check_insn_for_bivs PARAMS((struct loop *, rtx, int, int));
static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
static void loop_regs_update PARAMS ((const struct loop *, rtx));
static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block,
rtx, rtx));
static rtx loop_insn_emit_before PARAMS((const struct loop *, basic_block,
rtx, rtx));
static rtx loop_insn_sink_or_swim PARAMS((const struct loop *, rtx));
static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
void debug_biv PARAMS ((const struct induction *));
@ -568,6 +574,15 @@ scan_loop (loop, flags)
loop->scan_start = p;
/* If loop end is the end of the current function, then emit a
NOTE_INSN_DELETED after loop_end and set loop->sink to the dummy
note insn. This is the position we use when sinking insns out of
the loop. */
if (NEXT_INSN (loop->end) != 0)
loop->sink = NEXT_INSN (loop->end);
else
loop->sink = emit_note_after (NOTE_INSN_DELETED, loop->end);
/* Set up variables describing this loop. */
prescan_loop (loop);
threshold = (loop_info->has_call ? 1 : 2) * (1 + n_non_fixed_regs);
@ -3908,20 +3923,22 @@ loop_givs_reduce (loop, bl)
insert_before = v->insn;
if (tv->mult_val == const1_rtx)
emit_iv_add_mult (tv->add_val, v->mult_val,
v->new_reg, v->new_reg, insert_before);
loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
v->new_reg, v->new_reg,
0, insert_before);
else /* tv->mult_val == const0_rtx */
/* A multiply is acceptable here
since this is presumed to be seldom executed. */
emit_iv_add_mult (tv->add_val, v->mult_val,
v->add_val, v->new_reg, insert_before);
loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
v->add_val, v->new_reg,
0, insert_before);
}
/* Add code at loop start to initialize giv's reduced reg. */
emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
v->mult_val, v->add_val, v->new_reg,
loop->start);
loop_iv_add_mult_hoist (loop,
extend_value_for_giv (v, bl->initial_value),
v->mult_val, v->add_val, v->new_reg);
}
}
}
@ -3959,11 +3976,10 @@ loop_givs_dead_check (loop, bl)
static void
loop_givs_rescan (loop, bl, reg_map, end_insert_before)
loop_givs_rescan (loop, bl, reg_map)
struct loop *loop;
struct iv_class *bl;
rtx *reg_map;
rtx end_insert_before;
{
struct induction *v;
@ -4042,22 +4058,12 @@ loop_givs_rescan (loop, bl, reg_map, end_insert_before)
not replaceable. The correct final value is the same as the
value that the giv starts the reversed loop with. */
if (bl->reversed && ! v->replaceable)
emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
v->mult_val, v->add_val, v->dest_reg,
end_insert_before);
loop_iv_add_mult_sink (loop,
extend_value_for_giv (v, bl->initial_value),
v->mult_val, v->add_val, v->dest_reg);
else if (v->final_value)
{
/* If the loop has multiple exits, emit the insn before the
loop to ensure that it will always be executed no matter
how the loop exits. Otherwise, emit the insn after the loop,
since this is slightly more efficient. */
if (loop->exit_count)
loop_insn_hoist (loop,
gen_move_insn (v->dest_reg, v->final_value));
else
emit_insn_before (gen_move_insn (v->dest_reg, v->final_value),
end_insert_before);
}
loop_insn_sink_or_swim (loop,
gen_move_insn (v->dest_reg, v->final_value));
if (loop_dump_stream)
{
@ -4207,24 +4213,11 @@ strength_reduce (loop, insn_count, flags)
/* Map of pseudo-register replacements. */
rtx *reg_map = NULL;
int reg_map_size;
rtx end_insert_before;
int unrolled_insn_copies = 0;
rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
addr_placeholder = gen_reg_rtx (Pmode);
/* Save insn immediately after the loop_end. Insns inserted after loop_end
must be put before this insn, so that they will appear in the right
order (i.e. loop order).
If loop_end is the end of the current function, then emit a
NOTE_INSN_DELETED after loop_end and set end_insert_before to the
dummy note insn. */
if (NEXT_INSN (loop->end) != 0)
end_insert_before = NEXT_INSN (loop->end);
else
end_insert_before = emit_note_after (NOTE_INSN_DELETED, loop->end);
ivs->n_regs = max_reg_before_loop;
ivs->regs = (struct iv *) xcalloc (ivs->n_regs, sizeof (struct iv));
@ -4237,7 +4230,7 @@ strength_reduce (loop, insn_count, flags)
/* Can still unroll the loop anyways, but indicate that there is no
strength reduction info available. */
if (flags & LOOP_UNROLL)
unroll_loop (loop, insn_count, end_insert_before, 0);
unroll_loop (loop, insn_count, 0);
loop_ivs_free (loop);
return;
@ -4366,7 +4359,7 @@ strength_reduce (loop, insn_count, flags)
For each giv register that can be reduced now: if replaceable,
substitute reduced reg wherever the old giv occurs;
else add new move insn "giv_reg = reduced_reg". */
loop_givs_rescan (loop, bl, reg_map, end_insert_before);
loop_givs_rescan (loop, bl, reg_map);
/* All the givs based on the biv bl have been reduced if they
merit it. */
@ -4420,22 +4413,8 @@ strength_reduce (loop, insn_count, flags)
value, so we don't need another one. We can't calculate the
proper final value for such a biv here anyways. */
if (bl->final_value && ! bl->reversed)
{
rtx insert_before;
/* If the loop has multiple exits, emit the insn before the
loop to ensure that it will always be executed no matter
how the loop exits. Otherwise, emit the insn after the
loop, since this is slightly more efficient. */
if (loop->exit_count)
insert_before = loop->start;
else
insert_before = end_insert_before;
emit_insn_before (gen_move_insn (bl->biv->dest_reg,
bl->final_value),
end_insert_before);
}
loop_insn_sink_or_swim (loop, gen_move_insn
(bl->biv->dest_reg, bl->final_value));
if (loop_dump_stream)
fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
@ -4489,7 +4468,7 @@ strength_reduce (loop, insn_count, flags)
if ((flags & LOOP_UNROLL)
|| (loop_info->n_iterations > 0
&& unrolled_insn_copies <= insn_count))
unroll_loop (loop, insn_count, end_insert_before, 1);
unroll_loop (loop, insn_count, 1);
#ifdef HAVE_doloop_end
if (HAVE_doloop_end && (flags & LOOP_BCT) && flag_branch_on_count_reg)
@ -6863,40 +6842,38 @@ restart:
free (can_combine);
}
/* EMIT code before INSERT_BEFORE to set REG = B * M + A. */
/* Generate sequence for REG = B * M + A. */
void
emit_iv_add_mult (b, m, a, reg, insert_before)
static rtx
gen_add_mult (b, m, a, reg)
rtx b; /* initial value of basic induction variable */
rtx m; /* multiplicative constant */
rtx a; /* additive constant */
rtx reg; /* destination register */
rtx insert_before;
{
rtx seq;
rtx result;
/* Prevent unexpected sharing of these rtx. */
a = copy_rtx (a);
b = copy_rtx (b);
/* Increase the lifetime of any invariants moved further in code. */
update_reg_last_use (a, insert_before);
update_reg_last_use (b, insert_before);
update_reg_last_use (m, insert_before);
start_sequence ();
/* Use unsigned arithmetic. */
result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
if (reg != result)
emit_move_insn (reg, result);
seq = gen_sequence ();
end_sequence ();
emit_insn_before (seq, insert_before);
return seq;
}
/* It is entirely possible that the expansion created lots of new
registers. Iterate over the sequence we just created and
record them all. */
/* Update registers created in insn sequence SEQ. */
static void
loop_regs_update (loop, seq)
const struct loop *loop ATTRIBUTE_UNUSED;
rtx seq;
{
/* Update register info for alias analysis. */
if (GET_CODE (seq) == SEQUENCE)
{
@ -6916,8 +6893,99 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
}
}
/* Similar to emit_iv_add_mult, but compute cost rather than emitting
insns. */
/* EMIT code before BEFORE_BB/BEFORE_INSN to set REG = B * M + A. */
void
loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
const struct loop *loop;
rtx b; /* initial value of basic induction variable */
rtx m; /* multiplicative constant */
rtx a; /* additive constant */
rtx reg; /* destination register */
basic_block before_bb;
rtx before_insn;
{
rtx seq;
if (! before_insn)
{
loop_iv_add_mult_hoist (loop, b, m, a, reg);
return;
}
/* Use copy_rtx to prevent unexpected sharing of these rtx. */
seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
/* Increase the lifetime of any invariants moved further in code. */
update_reg_last_use (a, before_insn);
update_reg_last_use (b, before_insn);
update_reg_last_use (m, before_insn);
loop_insn_emit_before (loop, before_bb, before_insn, seq);
/* It is possible that the expansion created lots of new registers.
Iterate over the sequence we just created and record them all. */
loop_regs_update (loop, seq);
}
/* Emit insns in loop pre-header to set REG = B * M + A. */
void
loop_iv_add_mult_sink (loop, b, m, a, reg)
const struct loop *loop;
rtx b; /* initial value of basic induction variable */
rtx m; /* multiplicative constant */
rtx a; /* additive constant */
rtx reg; /* destination register */
{
rtx seq;
/* Use copy_rtx to prevent unexpected sharing of these rtx. */
seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
/* Increase the lifetime of any invariants moved further in code.
???? Is this really necessary? */
update_reg_last_use (a, loop->sink);
update_reg_last_use (b, loop->sink);
update_reg_last_use (m, loop->sink);
loop_insn_sink (loop, seq);
/* It is possible that the expansion created lots of new registers.
Iterate over the sequence we just created and record them all. */
loop_regs_update (loop, seq);
}
/* Emit insns after loop to set REG = B * M + A. */
void
loop_iv_add_mult_hoist (loop, b, m, a, reg)
const struct loop *loop;
rtx b; /* initial value of basic induction variable */
rtx m; /* multiplicative constant */
rtx a; /* additive constant */
rtx reg; /* destination register */
{
rtx seq;
/* Use copy_rtx to prevent unexpected sharing of these rtx. */
seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
loop_insn_hoist (loop, seq);
/* It is possible that the expansion created lots of new registers.
Iterate over the sequence we just created and record them all. */
loop_regs_update (loop, seq);
}
/* Similar to gen_add_mult, but compute cost rather than generating
sequence. */
static int
iv_add_mult_cost (b, m, a, reg)
rtx b; /* initial value of basic induction variable */
@ -6929,7 +6997,7 @@ iv_add_mult_cost (b, m, a, reg)
rtx last, result;
start_sequence ();
result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0);
result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
if (reg != result)
emit_move_insn (reg, result);
last = get_last_insn ();
@ -7517,8 +7585,7 @@ check_dbra_loop (loop, insn_count)
if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
|| ! bl->init_insn
|| REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
emit_insn_after (gen_move_insn (reg, final_value),
loop_end);
loop_insn_sink (loop, gen_move_insn (reg, final_value));
/* Delete compare/branch at end of loop. */
delete_insn (PREV_INSN (loop_end));
@ -7630,17 +7697,16 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
{
struct loop_ivs *ivs = LOOP_IVS (loop);
rtx reg = bl->biv->dest_reg;
rtx loop_start = loop->start;
rtx loop_end = loop->end;
rtx p;
/* Scan all insns in the loop, stopping if we find one that uses the
biv in a way that we cannot eliminate. */
for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
{
enum rtx_code code = GET_CODE (p);
rtx where = threshold >= insn_count ? loop_start : p;
basic_block where_bb = 0;
rtx where_insn = threshold >= insn_count ? 0 : p;
/* If this is a libcall that sets a giv, skip ahead to its end. */
if (GET_RTX_CLASS (code) == 'i')
@ -7666,7 +7732,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (p))
&& ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
eliminate_p, where))
eliminate_p, where_bb, where_insn))
{
if (loop_dump_stream)
fprintf (loop_dump_stream,
@ -7676,7 +7742,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
}
}
if (p == loop_end)
if (p == loop->end)
{
if (loop_dump_stream)
fprintf (loop_dump_stream, "biv %d %s eliminated.\n",
@ -7748,18 +7814,20 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
If BIV does not appear in X, return 1.
If ELIMINATE_P is non-zero, actually do the elimination. WHERE indicates
where extra insns should be added. Depending on how many items have been
moved out of the loop, it will either be before INSN or at the start of
the loop. */
If ELIMINATE_P is non-zero, actually do the elimination.
WHERE_INSN/WHERE_BB indicate where extra insns should be added.
Depending on how many items have been moved out of the loop, it
will either be before INSN (when WHERE_INSN is non-zero) or at the
start of the loop (when WHERE_INSN is zero). */
static int
maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
const struct loop *loop;
rtx x, insn;
struct iv_class *bl;
int eliminate_p;
rtx where;
basic_block where_bb;
rtx where_insn;
{
enum rtx_code code = GET_CODE (x);
rtx reg = bl->biv->dest_reg;
@ -7870,7 +7938,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
tem = gen_reg_rtx (GET_MODE (v->new_reg));
emit_insn_before (gen_move_insn (tem, copy_rtx (v->add_val)),
where);
where_insn);
/* Substitute the new register for its invariant value in
the compare expression. */
@ -7936,7 +8004,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
{
/* Otherwise, load it into a register. */
tem = gen_reg_rtx (mode);
emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
loop_iv_add_mult_emit_before (loop, arg,
v->mult_val, v->add_val,
tem, where_bb, where_insn);
validate_change (insn, &XEXP (x, arg_operand), tem, 1);
}
if (apply_change_group ())
@ -7969,7 +8039,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
v->new_reg, 1);
/* Compute value to compare against. */
emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
loop_iv_add_mult_emit_before (loop, arg,
v->mult_val, v->add_val,
tem, where_bb, where_insn);
/* Use it in this insn. */
validate_change (insn, &XEXP (x, arg_operand), tem, 1);
if (apply_change_group ())
@ -8005,8 +8077,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
v->new_reg, 1);
/* Compute value to compare against. */
emit_iv_add_mult (arg, v->mult_val, v->add_val,
tem, where);
loop_iv_add_mult_emit_before (loop, arg,
v->mult_val, v->add_val,
tem, where_bb, where_insn);
validate_change (insn, &XEXP (x, arg_operand), tem, 1);
if (apply_change_group ())
return 1;
@ -8087,14 +8160,14 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
{
case 'e':
if (! maybe_eliminate_biv_1 (loop, XEXP (x, i), insn, bl,
eliminate_p, where))
eliminate_p, where_bb, where_insn))
return 0;
break;
case 'E':
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (! maybe_eliminate_biv_1 (loop, XVECEXP (x, i, j), insn, bl,
eliminate_p, where))
eliminate_p, where_bb, where_insn))
return 0;
break;
}
@ -8152,7 +8225,7 @@ record_initial (dest, set, data)
/* If any of the registers in X are "old" and currently have a last use earlier
than INSN, update them to have a last use of INSN. Their actual last use
will be the previous insn but it will not have a valid uid_luid so we can't
use it. */
use it. X must be a source expression only. */
static void
update_reg_last_use (x, insn)
@ -8162,11 +8235,15 @@ update_reg_last_use (x, insn)
/* Check for the case where INSN does not have a valid luid. In this case,
there is no need to modify the regno_last_uid, as this can only happen
when code is inserted after the loop_end to set a pseudo's final value,
and hence this insn will never be the last use of x. */
and hence this insn will never be the last use of x.
???? This comment is not correct. See for example loop_givs_reduce.
This may insert an insn before another new insn. */
if (GET_CODE (x) == REG && REGNO (x) < max_reg_before_loop
&& INSN_UID (insn) < max_uid_for_loop
&& REGNO_LAST_LUID (REGNO (x)) < INSN_LUID (insn))
REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
{
REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
}
else
{
register int i, j;
@ -9360,6 +9437,20 @@ replace_label (x, data)
return 0;
}
/* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
(ignored in the interim). */
static rtx
loop_insn_emit_after (loop, where_bb, where_insn, pattern)
const struct loop *loop ATTRIBUTE_UNUSED;
basic_block where_bb ATTRIBUTE_UNUSED;
rtx where_insn;
rtx pattern;
{
return emit_insn_after (pattern, where_insn);
}
/* If WHERE_INSN is non-zero emit insn for PATTERN before WHERE_INSN
in basic block WHERE_BB (ignored in the interim) within the loop
otherwise hoist PATTERN into the loop pre-header. */
@ -9386,6 +9477,34 @@ loop_insn_hoist (loop, pattern)
{
return loop_insn_emit_before (loop, 0, loop->start, pattern);
}
/* Sink insn for PATTERN after the loop end. */
rtx
loop_insn_sink (loop, pattern)
const struct loop *loop;
rtx pattern;
{
return loop_insn_emit_before (loop, 0, loop->sink, pattern);
}
/* If the loop has multiple exits, emit insn for PATTERN before the
loop to ensure that it will always be executed no matter how the
loop exits. Otherwise, emit the insn for PATTERN after the loop,
since this is slightly more efficient. */
static rtx
loop_insn_sink_or_swim (loop, pattern)
const struct loop *loop;
rtx pattern;
{
if (loop->exit_count)
return loop_insn_hoist (loop, pattern);
else
return loop_insn_sink (loop, pattern);
}
static void
loop_biv_dump (v, file, verbose)

View File

@ -19,6 +19,9 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "bitmap.h"
#include "sbitmap.h"
#include "hard-reg-set.h"
#include "basic-block.h"
/* Flags passed to loop_optimize. */
#define LOOP_UNROLL 1
@ -386,11 +389,15 @@ extern FILE *loop_dump_stream;
unroll.c. */
int loop_invariant_p PARAMS ((const struct loop *, rtx));
rtx get_condition_for_loop PARAMS ((const struct loop *, rtx));
void emit_iv_add_mult PARAMS ((rtx, rtx, rtx, rtx, rtx));
void loop_iv_add_mult_hoist PARAMS ((const struct loop *, rtx, rtx, rtx, rtx));
void loop_iv_add_mult_sink PARAMS ((const struct loop *, rtx, rtx, rtx, rtx));
void loop_iv_add_mult_emit_before PARAMS ((const struct loop *, rtx,
rtx, rtx, rtx,
basic_block, rtx));
rtx express_from PARAMS ((struct induction *, struct induction *));
rtx extend_value_for_giv PARAMS ((struct induction *, rtx));
void unroll_loop PARAMS ((struct loop *, int, rtx, int));
void unroll_loop PARAMS ((struct loop *, int, int));
rtx biv_total_increment PARAMS ((struct iv_class *));
unsigned HOST_WIDE_INT loop_iterations PARAMS ((struct loop *));
int precondition_loop_p PARAMS ((const struct loop *,
@ -404,6 +411,7 @@ int back_branch_in_range_p PARAMS ((const struct loop *, rtx));
int loop_insn_first_p PARAMS ((rtx, rtx));
typedef rtx (*loop_insn_callback) PARAMS ((struct loop *, rtx, int, int));
void for_each_insn_in_loop PARAMS ((struct loop *, loop_insn_callback));
rtx loop_insn_sink PARAMS((const struct loop *, rtx));
rtx loop_insn_hoist PARAMS((const struct loop *, rtx));
/* Forward declarations for non-static functions declared in doloop.c. */

View File

@ -206,7 +206,7 @@ static void copy_loop_body PARAMS ((struct loop *, rtx, rtx,
struct inline_remap *, rtx, int,
enum unroll_types, rtx, rtx, rtx, rtx));
static int find_splittable_regs PARAMS ((const struct loop *,
enum unroll_types, rtx, int));
enum unroll_types, int));
static int find_splittable_givs PARAMS ((const struct loop *,
struct iv_class *, enum unroll_types,
rtx, int));
@ -222,19 +222,16 @@ static rtx ujump_to_loop_cont PARAMS ((rtx, rtx));
/* Try to unroll one loop and split induction variables in the loop.
The loop is described by the arguments LOOP and INSN_COUNT.
END_INSERT_BEFORE indicates where insns should be added which need
to be executed when the loop falls through. STRENGTH_REDUCTION_P
indicates whether information generated in the strength reduction
pass is available.
STRENGTH_REDUCTION_P indicates whether information generated in the
strength reduction pass is available.
This function is intended to be called from within `strength_reduce'
in loop.c. */
void
unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
unroll_loop (loop, insn_count, strength_reduce_p)
struct loop *loop;
int insn_count;
rtx end_insert_before;
int strength_reduce_p;
{
struct loop_info *loop_info = LOOP_INFO (loop);
@ -1045,7 +1042,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
sequence = gen_sequence ();
end_sequence ();
emit_insn_before (sequence, loop_start);
loop_insn_hoist (loop, sequence);
/* Only the last copy of the loop body here needs the exit
test, so set copy_end to exclude the compare/branch here,
@ -1163,8 +1160,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
if (splitting_not_safe)
temp = 0;
else
temp = find_splittable_regs (loop, unroll_type,
end_insert_before, unroll_number);
temp = find_splittable_regs (loop, unroll_type, unroll_number);
/* find_splittable_regs may have created some new registers, so must
reallocate the reg_map with the new larger size, and must realloc
@ -2431,10 +2427,9 @@ biv_total_increment (bl)
times, since multiplies by small integers (1,2,3,4) are very cheap. */
static int
find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
find_splittable_regs (loop, unroll_type, unroll_number)
const struct loop *loop;
enum unroll_types unroll_type;
rtx end_insert_before;
int unroll_number;
{
struct loop_ivs *ivs = LOOP_IVS (loop);
@ -2444,8 +2439,6 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
rtx biv_final_value;
int biv_splittable;
int result = 0;
rtx loop_start = loop->start;
rtx loop_end = loop->end;
for (bl = ivs->list; bl; bl = bl->next)
{
@ -2469,7 +2462,7 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
biv_final_value = 0;
if (unroll_type != UNROLL_COMPLETELY
&& (loop->exit_count || unroll_type == UNROLL_NAIVE)
&& (REGNO_LAST_LUID (bl->regno) >= INSN_LUID (loop_end)
&& (REGNO_LAST_LUID (bl->regno) >= INSN_LUID (loop->end)
|| ! bl->init_insn
|| INSN_UID (bl->init_insn) >= max_uid_for_loop
|| (REGNO_FIRST_LUID (bl->regno)
@ -2512,8 +2505,8 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
loop_insn_hoist (loop,
gen_move_insn (tem, bl->biv->src_reg));
if (loop_dump_stream)
fprintf (loop_dump_stream,
@ -2558,9 +2551,8 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
how the loop exits. Otherwise emit the insn after the loop,
since this is slightly more efficient. */
if (! loop->exit_count)
emit_insn_before (gen_move_insn (bl->biv->src_reg,
biv_final_value),
end_insert_before);
loop_insn_sink (loop, gen_move_insn (bl->biv->src_reg,
biv_final_value));
else
{
/* Create a new register to hold the value of the biv, and then
@ -2571,11 +2563,9 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
emit_insn_before (gen_move_insn (bl->biv->src_reg,
biv_final_value),
loop_start);
loop_insn_hoist (loop, gen_move_insn (tem, bl->biv->src_reg));
loop_insn_hoist (loop, gen_move_insn (bl->biv->src_reg,
biv_final_value));
if (loop_dump_stream)
fprintf (loop_dump_stream, "Biv %d mapped to %d for split.\n",
@ -2717,9 +2707,8 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
to its final value before loop start to ensure that this insn
will always be executed, no matter how we exit. */
tem = gen_reg_rtx (v->mode);
emit_insn_before (gen_move_insn (tem, v->dest_reg), loop_start);
emit_insn_before (gen_move_insn (v->dest_reg, final_value),
loop_start);
loop_insn_hoist (loop, gen_move_insn (tem, v->dest_reg));
loop_insn_hoist (loop, gen_move_insn (v->dest_reg, final_value));
if (loop_dump_stream)
fprintf (loop_dump_stream, "Giv %d mapped to %d for split.\n",
@ -2752,8 +2741,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop->start);
loop_insn_hoist (loop, gen_move_insn (tem, bl->biv->src_reg));
biv_initial_value = tem;
}
biv_initial_value = extend_value_for_giv (v, biv_initial_value);
@ -2795,8 +2783,8 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
{
rtx tem = gen_reg_rtx (v->mode);
record_base_value (REGNO (tem), v->add_val, 0);
emit_iv_add_mult (bl->initial_value, v->mult_val,
v->add_val, tem, loop->start);
loop_iv_add_mult_hoist (loop, bl->initial_value, v->mult_val,
v->add_val, tem);
value = tem;
}
@ -2923,17 +2911,15 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
instruction on machines with complex addressing modes.
If we can't recognize it, then delete it and emit insns
to calculate the value from scratch. */
emit_insn_before (gen_rtx_SET (VOIDmode, tem,
copy_rtx (v->new_reg)),
loop->start);
loop_insn_hoist (loop, gen_rtx_SET (VOIDmode, tem,
copy_rtx (v->new_reg)));
if (recog_memoized (PREV_INSN (loop->start)) < 0)
{
rtx sequence, ret;
/* We can't use bl->initial_value to compute the initial
value, because the loop may have been preconditioned.
We must calculate it from NEW_REG. Try using
force_operand instead of emit_iv_add_mult. */
We must calculate it from NEW_REG. */
delete_insn (PREV_INSN (loop->start));
start_sequence ();
@ -2942,7 +2928,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
emit_move_insn (tem, ret);
sequence = gen_sequence ();
end_sequence ();
emit_insn_before (sequence, loop->start);
loop_insn_hoist (loop, sequence);
if (loop_dump_stream)
fprintf (loop_dump_stream,
@ -3140,7 +3126,6 @@ final_biv_value (loop, bl)
const struct loop *loop;
struct iv_class *bl;
{
rtx loop_end = loop->end;
unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
rtx increment, tem;
@ -3182,11 +3167,8 @@ final_biv_value (loop, bl)
tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val, 0);
/* Make sure loop_end is not the last insn. */
if (NEXT_INSN (loop_end) == 0)
emit_note_after (NOTE_INSN_DELETED, loop_end);
emit_iv_add_mult (increment, GEN_INT (n_iterations),
bl->initial_value, tem, NEXT_INSN (loop_end));
loop_iv_add_mult_sink (loop, increment, GEN_INT (n_iterations),
bl->initial_value, tem);
if (loop_dump_stream)
fprintf (loop_dump_stream,
@ -3222,7 +3204,7 @@ final_giv_value (loop, v)
struct iv_class *bl;
rtx insn;
rtx increment, tem;
rtx insert_before, seq;
rtx seq;
rtx loop_end = loop->end;
unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
@ -3279,15 +3261,13 @@ final_giv_value (loop, v)
We must search from the insn that sets the giv to the end
of the loop to calculate this value. */
insert_before = NEXT_INSN (loop_end);
/* Put the final biv value in tem. */
tem = gen_reg_rtx (v->mode);
record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_iv_add_mult (extend_value_for_giv (v, increment),
GEN_INT (n_iterations),
extend_value_for_giv (v, bl->initial_value),
tem, insert_before);
loop_iv_add_mult_sink (loop, extend_value_for_giv (v, increment),
GEN_INT (n_iterations),
extend_value_for_giv (v, bl->initial_value),
tem);
/* Subtract off extra increments as we find them. */
for (insn = NEXT_INSN (v->insn); insn != loop_end;
@ -3304,12 +3284,12 @@ final_giv_value (loop, v)
OPTAB_LIB_WIDEN);
seq = gen_sequence ();
end_sequence ();
emit_insn_before (seq, insert_before);
loop_insn_sink (loop, seq);
}
}
/* Now calculate the giv's final value. */
emit_iv_add_mult (tem, v->mult_val, v->add_val, tem, insert_before);
loop_iv_add_mult_sink (loop, tem, v->mult_val, v->add_val, tem);
if (loop_dump_stream)
fprintf (loop_dump_stream,