aboutsummaryrefslogtreecommitdiff
path: root/gcc/loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/loop.c')
-rw-r--r--gcc/loop.c125
1 files changed, 108 insertions, 17 deletions
diff --git a/gcc/loop.c b/gcc/loop.c
index d7abe5ff654..284d891cf21 100644
--- a/gcc/loop.c
+++ b/gcc/loop.c
@@ -1,6 +1,6 @@
/* Perform various loop optimizations, including strength reduction.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
@@ -326,10 +326,12 @@ static void update_reg_last_use PARAMS ((rtx, rtx));
static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
static void loop_regs_scan PARAMS ((const struct loop *, int));
static int count_insns_in_loop PARAMS ((const struct loop *));
+static int find_mem_in_note_1 PARAMS ((rtx *, void *));
+static rtx find_mem_in_note PARAMS ((rtx));
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 void replace_loop_mems PARAMS ((rtx, rtx, rtx, int));
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 *));
@@ -815,11 +817,17 @@ scan_loop (loop, flags)
}
}
+ /* Don't try to optimize a MODE_CC set with a constant
+ source. It probably will be combined with a conditional
+ jump. */
+ if (GET_MODE_CLASS (GET_MODE (SET_DEST (set))) == MODE_CC
+ && CONSTANT_P (src))
+ ;
/* Don't try to optimize a register that was made
by loop-optimization for an inner loop.
We don't know its life-span, so we can't compute
the benefit. */
- if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
+ else if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
;
else if (/* The register is used in basic blocks other
than the one where it is set (meaning that
@@ -3277,7 +3285,7 @@ loop_invariant_p (loop, x)
These have always been created by the unroller and are set in
the loop, hence are never invariant. */
- if (REGNO (x) >= regs->num)
+ if (REGNO (x) >= (unsigned) regs->num)
return 0;
if (regs->array[REGNO (x)].set_in_loop < 0)
@@ -4204,7 +4212,15 @@ emit_prefetch_instructions (loop)
non-constant INIT_VAL to have the same mode as REG, which
in this case we know to be Pmode. */
if (GET_MODE (init_val) != Pmode && !CONSTANT_P (init_val))
- init_val = convert_to_mode (Pmode, init_val, 0);
+ {
+ rtx seq;
+
+ start_sequence ();
+ init_val = convert_to_mode (Pmode, init_val, 0);
+ seq = get_insns ();
+ end_sequence ();
+ loop_insn_emit_before (loop, 0, loop_start, seq);
+ }
loop_iv_add_mult_emit_before (loop, init_val,
info[i].giv->mult_val,
add_val, reg, 0, loop_start);
@@ -4761,6 +4777,9 @@ loop_givs_reduce (loop, bl)
{
rtx insert_before;
+ /* Skip if location is the same as a previous one. */
+ if (tv->same)
+ continue;
if (! auto_inc_opt)
insert_before = NEXT_INSN (tv->insn);
else if (auto_inc_opt == 1)
@@ -5668,6 +5687,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
v->always_computable = ! not_every_iteration;
v->always_executed = ! not_every_iteration;
v->maybe_multiple = maybe_multiple;
+ v->same = 0;
/* Add this to the reg's iv_class, creating a class
if this is the first incrementation of the reg. */
@@ -5705,6 +5725,17 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
/* Put it in the array of biv register classes. */
REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl;
}
+ else
+ {
+ /* Check if location is the same as a previous one. */
+ struct induction *induction;
+ for (induction = bl->biv; induction; induction = induction->next_iv)
+ if (location == induction->location)
+ {
+ v->same = induction;
+ break;
+ }
+ }
/* Update IV_CLASS entry for this biv. */
v->next_iv = bl->biv;
@@ -7834,11 +7865,12 @@ loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, 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. */
+ Iterate over the sequence we just created and record them all. We
+ must do this before inserting the sequence. */
loop_regs_update (loop, seq);
+
+ loop_insn_emit_before (loop, before_bb, before_insn, seq);
}
@@ -7863,11 +7895,12 @@ loop_iv_add_mult_sink (loop, b, m, a, reg)
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. */
+ Iterate over the sequence we just created and record them all. We
+ must do this before inserting the sequence. */
loop_regs_update (loop, seq);
+
+ loop_insn_sink (loop, seq);
}
@@ -7886,11 +7919,12 @@ loop_iv_add_mult_hoist (loop, b, m, a, reg)
/* Use copy_rtx to prevent unexpected sharing of these rtx. */
seq = gen_add_mult (copy_rtx (b), copy_rtx (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. */
+ Iterate over the sequence we just created and record them all. We
+ must do this before inserting the sequence. */
loop_regs_update (loop, seq);
+
+ loop_insn_hoist (loop, seq);
}
@@ -8624,11 +8658,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
enum rtx_code code = GET_CODE (p);
basic_block where_bb = 0;
rtx where_insn = threshold >= insn_count ? 0 : p;
+ rtx note;
/* If this is a libcall that sets a giv, skip ahead to its end. */
if (GET_RTX_CLASS (code) == 'i')
{
- rtx note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
+ note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
if (note)
{
@@ -8646,6 +8681,8 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
}
}
}
+
+ /* Closely examine the insn if the biv is mentioned. */
if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (p))
&& ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
@@ -8657,6 +8694,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
bl->regno, INSN_UID (p));
break;
}
+
+ /* If we are eliminating, kill REG_EQUAL notes mentioning the biv. */
+ if (eliminate_p
+ && (note = find_reg_note (p, REG_EQUAL, NULL_RTX)) != NULL_RTX
+ && reg_mentioned_p (reg, XEXP (note, 0)))
+ remove_note (p, note);
}
if (p == loop->end)
@@ -9972,7 +10015,7 @@ load_mems (loop)
else
/* Replace the memory reference with the shadow register. */
replace_loop_mems (p, loop_info->mems[i].mem,
- loop_info->mems[i].reg);
+ loop_info->mems[i].reg, written);
}
if (GET_CODE (p) == CODE_LABEL
@@ -10345,6 +10388,33 @@ try_swap_copy_prop (loop, replacement, regno)
}
}
+/* Worker function for find_mem_in_note, called via for_each_rtx. */
+
+static int
+find_mem_in_note_1 (x, data)
+ rtx *x;
+ void *data;
+{
+ if (*x != NULL_RTX && GET_CODE (*x) == MEM)
+ {
+ rtx *res = (rtx *) data;
+ *res = *x;
+ return 1;
+ }
+ return 0;
+}
+
+/* Returns the first MEM found in NOTE by depth-first search. */
+
+static rtx
+find_mem_in_note (note)
+ rtx note;
+{
+ if (note && for_each_rtx (&note, find_mem_in_note_1, &note))
+ return note;
+ return NULL_RTX;
+}
+
/* Replace MEM with its associated pseudo register. This function is
called from load_mems via for_each_rtx. DATA is actually a pointer
to a structure describing the instruction currently being scanned
@@ -10387,10 +10457,11 @@ replace_loop_mem (mem, data)
}
static void
-replace_loop_mems (insn, mem, reg)
+replace_loop_mems (insn, mem, reg, written)
rtx insn;
rtx mem;
rtx reg;
+ int written;
{
loop_replace_args args;
@@ -10399,6 +10470,26 @@ replace_loop_mems (insn, mem, reg)
args.replacement = reg;
for_each_rtx (&insn, replace_loop_mem, &args);
+
+ /* If we hoist a mem write out of the loop, then REG_EQUAL
+ notes referring to the mem are no longer valid. */
+ if (written)
+ {
+ rtx note, sub;
+ rtx *link;
+
+ for (link = &REG_NOTES (insn); (note = *link); link = &XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) == REG_EQUAL
+ && (sub = find_mem_in_note (note))
+ && true_dependence (mem, VOIDmode, sub, rtx_varies_p))
+ {
+ /* Remove the note. */
+ validate_change (NULL_RTX, link, XEXP (note, 1), 1);
+ break;
+ }
+ }
+ }
}
/* Replace one register with another. Called through for_each_rtx; PX points