rtx insns;
{
enum rtx_code code = GET_CODE (x);
- int i;
+ int i, j;
char *fmt;
rtx insn;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- add_label_notes (XEXP (x, i), insns);
+ {
+ if (fmt[i] == 'e')
+ add_label_notes (XEXP (x, i), insns);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ add_label_notes (XVECEXP (x, i, j), insns);
+ }
}
\f
/* Scan MOVABLES, and move the insns that deserve to be moved.
/* This is 1 if current insn is not executed at least once for every loop
iteration. */
int not_every_iteration = 0;
+ /* This is 1 if current insn may be executed more than once for every
+ loop iteration. */
+ int maybe_multiple = 0;
/* Temporary list pointers for traversing loop_iv_list. */
struct iv_class *bl, **backbl;
/* Ratio of extra register life span we can justify
= (struct induction *) alloca (sizeof (struct induction));
record_biv (v, p, dest_reg, inc_val, mult_val,
- not_every_iteration);
+ not_every_iteration, maybe_multiple);
reg_iv_type[REGNO (dest_reg)] = BASIC_INDUCT;
}
else if (REGNO (dest_reg) < max_reg_before_loop)
}
}
+ /* Past CODE_LABEL, we get to insns that may be executed multiple
+ times. The only way we can be sure that they can't is if every
+ every jump insn between here and the end of the loop either
+ returns, exits the loop, or is a forward jump. */
+
+ if (GET_CODE (p) == CODE_LABEL)
+ {
+ rtx insn = p;
+
+ maybe_multiple = 0;
+
+ while (1)
+ {
+ insn = NEXT_INSN (insn);
+ if (insn == scan_start)
+ break;
+ if (insn == end)
+ {
+ if (loop_top != 0)
+ insn = NEXT_INSN (loop_top);
+ else
+ break;
+ if (insn == scan_start)
+ break;
+ }
+
+ if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) != RETURN
+ && (! condjump_p (insn)
+ || (JUMP_LABEL (insn) != 0
+ && (INSN_UID (JUMP_LABEL (insn)) > max_uid_for_loop
+ || (INSN_LUID (JUMP_LABEL (insn))
+ < INSN_LUID (insn))))))
+ {
+ maybe_multiple = 1;
+ break;
+ }
+ }
+ }
+
/* Past a label or a jump, we get to insns for which we can't count
on whether or how many times they will be executed during each
iteration. */
/* Update the status of whether giv can derive other givs. This can
change when we pass a label or an insn that updates a biv. */
- if (GET_CODE (p) == INSN || GET_CODE (p) == CODE_LABEL)
+ if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
+ || GET_CODE (p) == CODE_LABEL)
update_giv_derive (p);
/* Past a label or a jump, we get to insns for which we can't count
MULT_VAL is const1_rtx if the biv is being incremented here, in which case
INC_VAL is the increment. Otherwise, MULT_VAL is const0_rtx and the biv is
- being set to INC_VAL. */
+ being set to INC_VAL.
+
+ NOT_EVERY_ITERATION is nonzero if this biv update is not know to be
+ executed every iteration; MAYBE_MULTIPLE is nonzero if this biv update
+ can be executed more than once per iteration. If MAYBE_MULTIPLE
+ and NOT_EVERY_ITERATION are both zero, we know that the biv update is
+ executed exactly once per iteration. */
static void
-record_biv (v, insn, dest_reg, inc_val, mult_val, not_every_iteration)
+record_biv (v, insn, dest_reg, inc_val, mult_val,
+ not_every_iteration, maybe_multiple)
struct induction *v;
rtx insn;
rtx dest_reg;
rtx inc_val;
rtx mult_val;
int not_every_iteration;
+ int maybe_multiple;
{
struct iv_class *bl;
v->add_val = inc_val;
v->mode = GET_MODE (dest_reg);
v->always_computable = ! not_every_iteration;
+ v->maybe_multiple = maybe_multiple;
/* Add this to the reg's iv_class, creating a class
if this is the first incrementation of the reg. */
v->location = location;
v->cant_derive = 0;
v->combined_with = 0;
+ v->maybe_multiple = 0;
v->maybe_dead = 0;
v->derive_adjustment = 0;
v->same = 0;
/* Search all IV classes, then all bivs, and finally all givs.
- There are two cases we are concerned with. First we have the situation
+ There are three cases we are concerned with. First we have the situation
of a giv that is only updated conditionally. In that case, it may not
derive any givs after a label is passed.
a branch here (actually, we need to pass both a jump and a label, but
this extra tracking doesn't seem worth it).
- If this is a giv update, we must adjust the giv status to show that a
+ If this is a jump, we are concerned about any biv update that may be
+ executed multiple times. We are actually only concerned about
+ backward jumps, but it is probably not worth performing the test
+ on the jump again here.
+
+ If this is a biv update, we must adjust the giv status to show that a
subsequent biv update was performed. If this adjustment cannot be done,
the giv cannot derive further givs. */
for (bl = loop_iv_list; bl; bl = bl->next)
for (biv = bl->biv; biv; biv = biv->next_iv)
- if (GET_CODE (p) == CODE_LABEL || biv->insn == p)
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || biv->insn == p)
{
for (giv = bl->giv; giv; giv = giv->next_iv)
{
else
giv->cant_derive = 1;
}
- else if (GET_CODE (p) == CODE_LABEL && ! biv->always_computable)
+ else if ((GET_CODE (p) == CODE_LABEL && ! biv->always_computable)
+ || (GET_CODE (p) == JUMP_INSN && biv->maybe_multiple))
giv->cant_derive = 1;
}
}