static int consec_sets_giv PROTO((int, rtx, rtx, rtx, rtx *, rtx *, rtx *));
static int check_dbra_loop PROTO((rtx, int, rtx, struct loop_info *));
static rtx express_from_1 PROTO((rtx, rtx, rtx));
-static rtx express_from PROTO((struct induction *, struct induction *));
static rtx combine_givs_p PROTO((struct induction *, struct induction *));
static void combine_givs PROTO((struct iv_class *));
struct recombine_givs_stats;
v->auto_inc_opt = 0;
v->unrolled = 0;
v->shared = 0;
- v->derived = 0;
+ v->derived_from = 0;
v->always_computable = 1;
v->always_executed = 1;
v->replaceable = 1;
v->new_reg = gen_reg_rtx (v->mode);
- if (v->derived)
+ if (v->derived_from)
{
PATTERN (v->insn)
= replace_rtx (PATTERN (v->insn), v->dest_reg, v->new_reg);
v->auto_inc_opt = 0;
v->unrolled = 0;
v->shared = 0;
- v->derived = 0;
+ v->derived_from = 0;
v->last_use = 0;
/* The v->always_computable field is used in update_giv_derive, to
return NULL_RTX;
}
-static rtx
+rtx
express_from (g1, g2)
struct induction *g1, *g2;
{
rtx sum;
v = giv_array[stats[i].giv_number];
- if (v->giv_type != DEST_REG || v->derived || v->same)
+ if (v->giv_type != DEST_REG || v->derived_from || v->same)
continue;
if (! last_giv)
{
gen_rtx_SET (GET_MODE (v->dest_reg),
v->dest_reg, sum), 0))
{
- v->derived = 1;
+ v->derived_from = last_giv;
v->new_reg = v->dest_reg;
life_end = stats[i].end_luid;
initialized in unrolled loop. */
unsigned shared : 1;
unsigned no_const_addval : 1; /* 1 if add_val does not contain a const. */
- unsigned derived : 1; /* For a giv, 1 if we decided to derive this
- giv from another one. */
int lifetime; /* Length of life of this giv */
rtx derive_adjustment; /* If nonzero, is an adjustment to be
subtracted from add_val when this giv
struct induction *same; /* If this giv has been combined with another
giv, this points to the base giv. The base
giv will have COMBINED_WITH non-zero. */
+ struct induction *derived_from;/* For a giv, if we decided to derive this
+ giv from another one. */
HOST_WIDE_INT const_adjust; /* Used by loop unrolling, when an address giv
is split, and a constant is eliminated from
the address, the -constant is stored here
int invariant_p PROTO((rtx));
rtx get_condition_for_loop PROTO((rtx));
void emit_iv_add_mult PROTO((rtx, rtx, rtx, rtx, rtx));
+rtx express_from PROTO((struct induction *, struct induction *));
/* Forward declarations for non-static functions declared in stmt.c. */
void find_loop_tree_blocks PROTO((void));
giv_dest_reg = SET_DEST (set);
if (derived_regs[regno])
{
+ /* ??? This relies on SET_SRC (SET) to be of
+ the form (plus (reg) (const_int)), and thus
+ forces recombine_givs to restrict the kind
+ of giv derivations it does before unrolling. */
giv_src_reg = XEXP (SET_SRC (set), 0);
giv_inc = XEXP (SET_SRC (set), 1);
}
}
splittable_regs[REGNO (v->new_reg)] = value;
- derived_regs[REGNO (v->new_reg)] = v->derived;
+ derived_regs[REGNO (v->new_reg)] = v->derived_from != 0;
}
else
{
Emit insn to initialize its value before loop start. */
rtx tem = gen_reg_rtx (v->mode);
+ struct induction *same = v->same;
+ rtx new_reg = v->new_reg;
record_base_value (REGNO (tem), v->add_val, 0);
+ if (same && same->derived_from)
+ {
+ /* calculate_giv_inc doesn't work for derived givs.
+ copy_loop_body works around the problem for the
+ DEST_REG givs themselves, but it can't handle
+ DEST_ADDR givs that have been combined with
+ derived a derived DEST_REG giv.
+ So Handle V as if the giv from which V->SAME has
+ been derived has been combined with V.
+ recombine_givs only derives givs from givs that
+ are reduced the ordinary, so we need not worry
+ about same->derived_from being in turn derived. */
+
+ same = same->derived_from;
+ new_reg = express_from (same, v);
+ }
+
/* If the address giv has a constant in its new_reg value,
then this constant can be pulled out and put in value,
instead of being part of the initialization code. */
- if (GET_CODE (v->new_reg) == PLUS
- && GET_CODE (XEXP (v->new_reg, 1)) == CONST_INT)
+ if (GET_CODE (new_reg) == PLUS
+ && GET_CODE (XEXP (new_reg, 1)) == CONST_INT)
{
v->dest_reg
- = plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
+ = plus_constant (tem, INTVAL (XEXP (new_reg, 1)));
/* Only succeed if this will give valid addresses.
Try to validate both the first and the last
/* Save the negative of the eliminated const, so
that we can calculate the dest_reg's increment
value later. */
- v->const_adjust = - INTVAL (XEXP (v->new_reg, 1));
+ v->const_adjust = - INTVAL (XEXP (new_reg, 1));
- v->new_reg = XEXP (v->new_reg, 0);
+ new_reg = XEXP (new_reg, 0);
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Eliminating constant from giv %d\n",
INSN_UID (v->insn));
continue;
}
+
+ v->new_reg = new_reg;
+ v->same = same;
/* We set this after the address check, to guarantee that
the register will be initialized. */
INSN_UID (v->insn));
continue;
}
+ if (v->same && v->same->derived_from)
+ {
+ /* Handle V as if the giv from which V->SAME has
+ been derived has been combined with V. */
+
+ v->same = v->same->derived_from;
+ v->new_reg = express_from (v->same, v);
+ }
+
}
/* Store the value of dest_reg into the insn. This sharing
Make sure that it's giv is marked as splittable here. */
splittable_regs[REGNO (v->new_reg)] = value;
- derived_regs[REGNO (v->new_reg)] = v->derived;
+ derived_regs[REGNO (v->new_reg)] = v->derived_from != 0;
/* Make it appear to depend upon itself, so that the
giv will be properly split in the main loop above. */
if (! v->ignore)
count = reg_biv_class[REGNO (v->src_reg)]->biv_count;
+ if (count > 1 && v->derived_from)
+ /* In this case, there is one set where the giv insn was and one
+ set each after each biv increment. (Most are likely dead.) */
+ count++;
+
splittable_regs_updates[REGNO (v->new_reg)] = count;
}