aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMichael Hayes <mhayes@redhat.com>2001-01-07 10:38:29 +0000
committerMichael Hayes <m.hayes@gcc.gnu.org>2001-01-07 10:38:29 +0000
commit96a45535c32b2f22650347c5152dd0e791e8582d (patch)
treee732de7860b16b8d7c4c01ec79928e4af7e71b4a /gcc
parent804a718aac4681c268c0b3a4a713cc5abec1f0cd (diff)
downloadgcc-96a45535c32b2f22650347c5152dd0e791e8582d.zip
gcc-96a45535c32b2f22650347c5152dd0e791e8582d.tar.gz
gcc-96a45535c32b2f22650347c5152dd0e791e8582d.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog26
-rw-r--r--gcc/basic-block.h3
-rw-r--r--gcc/hard-reg-set.h4
-rw-r--r--gcc/loop.c323
-rw-r--r--gcc/loop.h12
-rw-r--r--gcc/unroll.c86
6 files changed, 297 insertions, 157 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3258113..bcdb2ba 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,31 @@
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.
* loop.c (loop_insn_hoist, loop_insn_emit_before): New.
(move_movables, loop_givs_rescan): Use loop_insn_hoist.
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index a34dbb8..f86ff3c 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -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.
diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h
index 4a305ef..57ab2860 100644
--- a/gcc/hard-reg-set.h
+++ b/gcc/hard-reg-set.h
@@ -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 */
diff --git a/gcc/loop.c b/gcc/loop.c
index d58284f..2a2c23c 100644
--- a/gcc/loop.c
+++ b/gcc/loop.c
@@ -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;
+}
+
+
+/* Update registers created in insn sequence SEQ. */
- /* It is entirely possible that the expansion created lots of new
- registers. Iterate over the sequence we just created and
- record them all. */
+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)
diff --git a/gcc/loop.h b/gcc/loop.h
index 5a3f295..f01bd67 100644
--- a/gcc/loop.h
+++ b/gcc/loop.h
@@ -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. */
diff --git a/gcc/unroll.c b/gcc/unroll.c
index bdd6cb4..fbd5224 100644
--- a/gcc/unroll.c
+++ b/gcc/unroll.c
@@ -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,