return;
}
- if (iv->step == const0_rtx)
- {
- fprintf (file, "invariant ");
- print_rtl (file, iv->base);
- return;
- }
+ if (iv->step == const0_rtx
+ && !iv->first_special)
+ fprintf (file, "invariant ");
print_rtl (file, iv->base);
- fprintf (file, " + ");
- print_rtl (file, iv->step);
- fprintf (file, " * iteration");
+ if (iv->step != const0_rtx)
+ {
+ fprintf (file, " + ");
+ print_rtl (file, iv->step);
+ fprintf (file, " * iteration");
+ }
fprintf (file, " (in %s)", GET_MODE_NAME (iv->mode));
if (iv->mode != iv->extend_mode)
/* Generates a subreg to get the least significant part of EXPR (in mode
INNER_MODE) to OUTER_MODE. */
-static rtx
+rtx
lowpart_subreg (enum machine_mode outer_mode, rtx expr,
enum machine_mode inner_mode)
{
case PLUS:
case MINUS:
case MULT:
+ case ASHIFT:
op0 = XEXP (rhs, 0);
op1 = XEXP (rhs, 1);
&& !CONSTANT_P (op1))
return false;
+ if (GET_CODE (rhs) == ASHIFT
+ && CONSTANT_P (op0))
+ return false;
+
return true;
default:
unsigned regno, uid;
src = find_reg_equal_equiv_note (insn);
- if (!src)
+ if (src)
+ src = XEXP (src, 0);
+ else
src = SET_SRC (set);
if (!simple_set_p (SET_DEST (set), src))
iv->base = cst;
iv->step = const0_rtx;
iv->first_special = false;
- iv->extend = NIL;
+ iv->extend = UNKNOWN;
iv->extend_mode = iv->mode;
iv->delta = const0_rtx;
iv->mult = const1_rtx;
static bool
iv_subreg (struct rtx_iv *iv, enum machine_mode mode)
{
+ /* If iv is invariant, just calculate the new value. */
+ if (iv->step == const0_rtx
+ && !iv->first_special)
+ {
+ rtx val = get_iv_value (iv, const0_rtx);
+ val = lowpart_subreg (mode, val, iv->extend_mode);
+
+ iv->base = val;
+ iv->extend = UNKNOWN;
+ iv->mode = iv->extend_mode = mode;
+ iv->delta = const0_rtx;
+ iv->mult = const1_rtx;
+ return true;
+ }
+
if (iv->extend_mode == mode)
return true;
if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (iv->mode))
return false;
- iv->extend = NIL;
+ iv->extend = UNKNOWN;
iv->mode = mode;
iv->base = simplify_gen_binary (PLUS, iv->extend_mode, iv->delta,
static bool
iv_extend (struct rtx_iv *iv, enum rtx_code extend, enum machine_mode mode)
{
+ /* If iv is invariant, just calculate the new value. */
+ if (iv->step == const0_rtx
+ && !iv->first_special)
+ {
+ rtx val = get_iv_value (iv, const0_rtx);
+ val = simplify_gen_unary (extend, mode, val, iv->extend_mode);
+
+ iv->base = val;
+ iv->extend = UNKNOWN;
+ iv->mode = iv->extend_mode = mode;
+ iv->delta = const0_rtx;
+ iv->mult = const1_rtx;
+ return true;
+ }
+
if (mode != iv->extend_mode)
return false;
- if (iv->extend != NIL
+ if (iv->extend != UNKNOWN
&& iv->extend != extend)
return false;
static bool
iv_neg (struct rtx_iv *iv)
{
- if (iv->extend == NIL)
+ if (iv->extend == UNKNOWN)
{
iv->base = simplify_gen_unary (NEG, iv->extend_mode,
iv->base, iv->extend_mode);
rtx arg;
/* Extend the constant to extend_mode of the other operand if necessary. */
- if (iv0->extend == NIL
+ if (iv0->extend == UNKNOWN
&& iv0->mode == iv0->extend_mode
&& iv0->step == const0_rtx
&& GET_MODE_SIZE (iv0->extend_mode) < GET_MODE_SIZE (iv1->extend_mode))
iv0->base = simplify_gen_unary (ZERO_EXTEND, iv0->extend_mode,
iv0->base, iv0->mode);
}
- if (iv1->extend == NIL
+ if (iv1->extend == UNKNOWN
&& iv1->mode == iv1->extend_mode
&& iv1->step == const0_rtx
&& GET_MODE_SIZE (iv1->extend_mode) < GET_MODE_SIZE (iv0->extend_mode))
if (mode != iv1->extend_mode)
return false;
- if (iv0->extend == NIL && iv1->extend == NIL)
+ if (iv0->extend == UNKNOWN && iv1->extend == UNKNOWN)
{
if (iv0->mode != iv1->mode)
return false;
}
/* Handle addition of constant. */
- if (iv1->extend == NIL
+ if (iv1->extend == UNKNOWN
&& iv1->mode == mode
&& iv1->step == const0_rtx)
{
return true;
}
- if (iv0->extend == NIL
+ if (iv0->extend == UNKNOWN
&& iv0->mode == mode
&& iv0->step == const0_rtx)
{
&& GET_MODE (mby) != mode)
return false;
- if (iv->extend == NIL)
+ if (iv->extend == UNKNOWN)
{
iv->base = simplify_gen_binary (MULT, mode, iv->base, mby);
iv->step = simplify_gen_binary (MULT, mode, iv->step, mby);
return true;
}
+/* Evaluates shift of IV by constant CST. */
+
+static bool
+iv_shift (struct rtx_iv *iv, rtx mby)
+{
+ enum machine_mode mode = iv->extend_mode;
+
+ if (GET_MODE (mby) != VOIDmode
+ && GET_MODE (mby) != mode)
+ return false;
+
+ if (iv->extend == UNKNOWN)
+ {
+ iv->base = simplify_gen_binary (ASHIFT, mode, iv->base, mby);
+ iv->step = simplify_gen_binary (ASHIFT, mode, iv->step, mby);
+ }
+ else
+ {
+ iv->delta = simplify_gen_binary (ASHIFT, mode, iv->delta, mby);
+ iv->mult = simplify_gen_binary (ASHIFT, mode, iv->mult, mby);
+ }
+
+ return true;
+}
+
/* The recursive part of get_biv_step. Gets the value of the single value
defined in INSN wrto initial value of REG inside loop, in shape described
at get_biv_step. */
set = single_set (insn);
rhs = find_reg_equal_equiv_note (insn);
- if (!rhs)
+ if (rhs)
+ rhs = XEXP (rhs, 0);
+ else
rhs = SET_SRC (set);
lhs = SET_DEST (set);
return false;
*inner_step = const0_rtx;
- *extend = NIL;
+ *extend = UNKNOWN;
*inner_mode = outer_mode;
*outer_step = const0_rtx;
}
*inner_step = simplify_gen_binary (PLUS, outer_mode,
*inner_step, *outer_step);
*outer_step = const0_rtx;
- *extend = NIL;
+ *extend = UNKNOWN;
}
switch (code)
case SIGN_EXTEND:
case ZERO_EXTEND:
if (GET_MODE (op0) != *inner_mode
- || *extend != NIL
+ || *extend != UNKNOWN
|| *outer_step != const0_rtx)
abort ();
return false;
if (*inner_mode != *outer_mode
- && *extend == NIL)
+ && *extend == UNKNOWN)
abort ();
if (*inner_mode == *outer_mode
- && *extend != NIL)
+ && *extend != UNKNOWN)
abort ();
if (*inner_mode == *outer_mode
set = single_set (insn);
rhs = find_reg_equal_equiv_note (insn);
- if (!rhs)
+ if (rhs)
+ rhs = XEXP (rhs, 0);
+ else
rhs = SET_SRC (set);
code = GET_CODE (rhs);
mby = tmp;
}
break;
-
+
+ case ASHIFT:
+ if (CONSTANT_P (XEXP (rhs, 0)))
+ abort ();
+ op0 = XEXP (rhs, 0);
+ mby = XEXP (rhs, 1);
+ break;
+
default:
abort ();
}
goto end;
break;
+ case ASHIFT:
+ if (!iv_shift (&iv0, mby))
+ goto end;
+ break;
+
default:
break;
}
return iv->base != NULL_RTX;
}
+/* Checks whether definition of register REG in INSN a basic induction
+ variable. IV analysis must have been initialized (via a call to
+ iv_analysis_loop_init) for this function to produce a result. */
+
+bool
+biv_p (rtx insn, rtx reg)
+{
+ struct rtx_iv iv;
+
+ if (!REG_P (reg))
+ return false;
+
+ if (last_def[REGNO (reg)] != insn)
+ return false;
+
+ return iv_analyze_biv (reg, &iv);
+}
+
/* Calculates value of IV at ITERATION-th iteration. */
rtx
val = lowpart_subreg (iv->mode, val, iv->extend_mode);
- if (iv->extend == NIL)
+ if (iv->extend == UNKNOWN)
return val;
val = simplify_gen_unary (iv->extend, iv->extend_mode, val, iv->mode);
}
}
- get_mode_bounds (desc->mode, desc->signed_p, &mmin, &mmax);
+ get_mode_bounds (desc->mode, desc->signed_p, desc->mode, &mmin, &mmax);
nmax = INTVAL (mmax) - INTVAL (mmin);
if (GET_CODE (niter) == UDIV)
simplify_using_assignment (rtx insn, rtx *expr, regset altered)
{
rtx set = single_set (insn);
- rtx lhs, rhs;
+ rtx lhs = NULL_RTX, rhs;
bool ret = false;
if (set)
{
lhs = SET_DEST (set);
- if (GET_CODE (lhs) != REG
+ if (!REG_P (lhs)
|| altered_reg_used (&lhs, altered))
ret = true;
}
ret = true;
note_stores (PATTERN (insn), mark_altered, altered);
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
int i;
return;
rhs = find_reg_equal_equiv_note (insn);
- if (!rhs)
+ if (rhs)
+ rhs = XEXP (rhs, 0);
+ else
rhs = SET_SRC (set);
if (!simple_rhs_p (rhs))
static bool
implies_p (rtx a, rtx b)
{
- rtx op0, op1, r;
+ rtx op0, op1, opb0, opb1, r;
+ enum machine_mode mode;
if (GET_CODE (a) == EQ)
{
}
}
+ /* A < B implies A + 1 <= B. */
+ if ((GET_CODE (a) == GT || GET_CODE (a) == LT)
+ && (GET_CODE (b) == GE || GET_CODE (b) == LE))
+ {
+ op0 = XEXP (a, 0);
+ op1 = XEXP (a, 1);
+ opb0 = XEXP (b, 0);
+ opb1 = XEXP (b, 1);
+
+ if (GET_CODE (a) == GT)
+ {
+ r = op0;
+ op0 = op1;
+ op1 = r;
+ }
+
+ if (GET_CODE (b) == GE)
+ {
+ r = opb0;
+ opb0 = opb1;
+ opb1 = r;
+ }
+
+ mode = GET_MODE (op0);
+ if (mode != GET_MODE (opb0))
+ mode = VOIDmode;
+ else if (mode == VOIDmode)
+ {
+ mode = GET_MODE (op1);
+ if (mode != GET_MODE (opb1))
+ mode = VOIDmode;
+ }
+
+ if (mode != VOIDmode
+ && rtx_equal_p (op1, opb1)
+ && simplify_gen_binary (MINUS, mode, opb0, op0) == const1_rtx)
+ return true;
+ }
+
return false;
}
{
rtx rev, reve, exp = *expr;
- if (GET_RTX_CLASS (GET_CODE (*expr)) != '<')
+ if (!COMPARISON_P (exp))
return;
/* If some register gets altered later, we do not really speak about its
else
abort ();
- simplify_using_initial_values (loop, NIL, &head);
+ simplify_using_initial_values (loop, UNKNOWN, &head);
if (head == aggr)
{
XEXP (*expr, 0) = aggr;
return;
}
- if (op != NIL)
+ if (op != UNKNOWN)
abort ();
e = loop_preheader_edge (loop);
while (1)
{
+ basic_block tmp_bb;
+
insn = BB_END (e->src);
if (any_condjump_p (insn))
{
- /* FIXME -- slightly wrong -- what if compared register
- gets altered between start of the condition and insn? */
- rtx cond = get_condition (BB_END (e->src), NULL, false);
+ rtx cond = get_condition (BB_END (e->src), NULL, false, true);
if (cond && (e->flags & EDGE_FALLTHRU))
cond = reversed_condition (cond);
}
}
- e = e->src->pred;
- if (e->pred_next
+ /* This is a bit subtle. Store away e->src in tmp_bb, since we
+ modify `e' and this can invalidate the subsequent count of
+ e->src's predecessors by looking at the wrong block. */
+ tmp_bb = e->src;
+ e = EDGE_PRED (tmp_bb, 0);
+ if (EDGE_COUNT (tmp_bb->preds) > 1
|| e->src == ENTRY_BLOCK_PTR)
break;
}
{
rtx mmin, mmax, cond_over, cond_under;
- get_mode_bounds (mode, signed_p, &mmin, &mmax);
+ get_mode_bounds (mode, signed_p, iv->extend_mode, &mmin, &mmax);
cond_under = simplify_gen_relational (LT, SImode, iv->extend_mode,
iv->base, mmin);
cond_over = simplify_gen_relational (GT, SImode, iv->extend_mode,
break;
case NE:
- if (iv0->extend != NIL
- && iv1->extend != NIL
+ if (iv0->extend != UNKNOWN
+ && iv1->extend != UNKNOWN
&& iv0->extend != iv1->extend)
return false;
signed_p = false;
- if (iv0->extend != NIL)
+ if (iv0->extend != UNKNOWN)
signed_p = iv0->extend == SIGN_EXTEND;
- if (iv1->extend != NIL)
+ if (iv1->extend != UNKNOWN)
signed_p = iv1->extend == SIGN_EXTEND;
break;
{
rtx op0, op1, delta, step, bound, may_xform, def_insn, tmp, tmp0, tmp1;
struct rtx_iv iv0, iv1, tmp_iv;
- rtx assumption;
+ rtx assumption, may_not_xform;
enum rtx_code cond;
enum machine_mode mode, comp_mode;
- rtx mmin, mmax;
- unsigned HOST_WIDEST_INT s, size, d;
+ rtx mmin, mmax, mode_mmin, mode_mmax;
+ unsigned HOST_WIDEST_INT s, size, d, inv;
HOST_WIDEST_INT up, down, inc;
int was_sharp = false;
+ rtx old_niter;
/* The meaning of these assumptions is this:
if !assumptions
desc->niter_max = 0;
cond = GET_CODE (condition);
- if (GET_RTX_CLASS (cond) != '<')
+ if (!COMPARISON_P (condition))
abort ();
mode = GET_MODE (XEXP (condition, 0));
comp_mode = iv0.extend_mode;
mode = iv0.mode;
size = GET_MODE_BITSIZE (mode);
- get_mode_bounds (mode, (cond == LE || cond == LT), &mmin, &mmax);
+ get_mode_bounds (mode, (cond == LE || cond == LT), comp_mode, &mmin, &mmax);
+ mode_mmin = lowpart_subreg (mode, mmin, comp_mode);
+ mode_mmax = lowpart_subreg (mode, mmax, comp_mode);
if (GET_CODE (iv0.step) != CONST_INT || GET_CODE (iv1.step) != CONST_INT)
goto fail;
if (iv0.step == const0_rtx)
{
tmp = lowpart_subreg (mode, iv0.base, comp_mode);
- assumption = simplify_gen_relational (EQ, SImode, mode, tmp, mmax);
+ assumption = simplify_gen_relational (EQ, SImode, mode, tmp,
+ mode_mmax);
if (assumption == const_true_rtx)
goto zero_iter;
iv0.base = simplify_gen_binary (PLUS, comp_mode,
else
{
tmp = lowpart_subreg (mode, iv1.base, comp_mode);
- assumption = simplify_gen_relational (EQ, SImode, mode, tmp, mmin);
+ assumption = simplify_gen_relational (EQ, SImode, mode, tmp,
+ mode_mmin);
if (assumption == const_true_rtx)
goto zero_iter;
iv1.base = simplify_gen_binary (PLUS, comp_mode,
if (iv0.step == const0_rtx)
{
tmp = lowpart_subreg (mode, iv0.base, comp_mode);
- if (rtx_equal_p (tmp, mmin))
+ if (rtx_equal_p (tmp, mode_mmin))
{
desc->infinite =
alloc_EXPR_LIST (0, const_true_rtx, NULL_RTX);
else
{
tmp = lowpart_subreg (mode, iv1.base, comp_mode);
- if (rtx_equal_p (tmp, mmax))
+ if (rtx_equal_p (tmp, mode_mmax))
{
desc->infinite =
alloc_EXPR_LIST (0, const_true_rtx, NULL_RTX);
delta = lowpart_subreg (mode, delta, comp_mode);
delta = simplify_gen_binary (UMOD, mode, delta, step);
may_xform = const0_rtx;
+ may_not_xform = const_true_rtx;
if (GET_CODE (delta) == CONST_INT)
{
tmp = lowpart_subreg (mode, iv0.base, comp_mode);
may_xform = simplify_gen_relational (cond, SImode, mode,
bound, tmp);
+ may_not_xform = simplify_gen_relational (reverse_condition (cond),
+ SImode, mode,
+ bound, tmp);
}
else
{
tmp = lowpart_subreg (mode, iv1.base, comp_mode);
may_xform = simplify_gen_relational (cond, SImode, mode,
tmp, bound);
+ may_not_xform = simplify_gen_relational (reverse_condition (cond),
+ SImode, mode,
+ tmp, bound);
}
}
completely senseless. This is OK, as we would need this assumption
to determine the number of iterations anyway. */
if (may_xform != const_true_rtx)
- desc->assumptions = alloc_EXPR_LIST (0, may_xform,
- desc->assumptions);
+ {
+ /* If the step is a power of two and the final value we have
+ computed overflows, the cycle is infinite. Otherwise it
+ is nontrivial to compute the number of iterations. */
+ s = INTVAL (step);
+ if ((s & (s - 1)) == 0)
+ desc->infinite = alloc_EXPR_LIST (0, may_not_xform,
+ desc->infinite);
+ else
+ desc->assumptions = alloc_EXPR_LIST (0, may_xform,
+ desc->assumptions);
+ }
/* We are going to lose some information about upper bound on
number of iterations in this step, so record the information
if (GET_CODE (iv1.base) == CONST_INT)
up = INTVAL (iv1.base);
else
- up = INTVAL (mmax) - inc;
- down = INTVAL (GET_CODE (iv0.base) == CONST_INT ? iv0.base : mmin);
+ up = INTVAL (mode_mmax) - inc;
+ down = INTVAL (GET_CODE (iv0.base) == CONST_INT
+ ? iv0.base
+ : mode_mmin);
desc->niter_max = (up - down) / inc + 1;
if (iv0.step == const0_rtx)
desc->infinite = alloc_EXPR_LIST (0, assumption, desc->infinite);
tmp = simplify_gen_binary (UDIV, mode, tmp1, GEN_INT (d));
- tmp = simplify_gen_binary (MULT, mode,
- tmp, GEN_INT (inverse (s, size)));
+ inv = inverse (s, size);
+ inv = trunc_int_for_mode (inv, mode);
+ tmp = simplify_gen_binary (MULT, mode, tmp, GEN_INT (inv));
desc->niter_expr = simplify_gen_binary (AND, mode, tmp, bound);
}
else
tmp0 = lowpart_subreg (mode, iv0.base, comp_mode);
tmp1 = lowpart_subreg (mode, iv1.base, comp_mode);
- bound = simplify_gen_binary (MINUS, mode, mmax, step);
+ bound = simplify_gen_binary (MINUS, mode, mode_mmax,
+ lowpart_subreg (mode, step, comp_mode));
assumption = simplify_gen_relational (cond, SImode, mode,
tmp1, bound);
desc->assumptions =
tmp0 = lowpart_subreg (mode, iv0.base, comp_mode);
tmp1 = lowpart_subreg (mode, iv1.base, comp_mode);
- bound = simplify_gen_binary (MINUS, mode, mmin, step);
+ bound = simplify_gen_binary (MINUS, mode, mode_mmin,
+ lowpart_subreg (mode, step, comp_mode));
assumption = simplify_gen_relational (cond, SImode, mode,
bound, tmp0);
desc->assumptions =
desc->niter_expr = delta;
}
+ old_niter = desc->niter_expr;
+
simplify_using_initial_values (loop, AND, &desc->assumptions);
if (desc->assumptions
&& XEXP (desc->assumptions, 0) == const0_rtx)
goto fail;
simplify_using_initial_values (loop, IOR, &desc->noloop_assumptions);
simplify_using_initial_values (loop, IOR, &desc->infinite);
- simplify_using_initial_values (loop, NIL, &desc->niter_expr);
+ simplify_using_initial_values (loop, UNKNOWN, &desc->niter_expr);
/* Rerun the simplification. Consider code (created by copying loop headers)
goto fail;
simplify_using_initial_values (loop, IOR, &desc->noloop_assumptions);
simplify_using_initial_values (loop, IOR, &desc->infinite);
- simplify_using_initial_values (loop, NIL, &desc->niter_expr);
+ simplify_using_initial_values (loop, UNKNOWN, &desc->niter_expr);
+
+ if (desc->noloop_assumptions
+ && XEXP (desc->noloop_assumptions, 0) == const_true_rtx)
+ goto zero_iter;
if (GET_CODE (desc->niter_expr) == CONST_INT)
{
desc->const_iter = true;
desc->niter_max = desc->niter = val & GET_MODE_MASK (desc->mode);
}
- else if (!desc->niter_max)
- desc->niter_max = determine_max_iter (desc);
+ else
+ {
+ if (!desc->niter_max)
+ desc->niter_max = determine_max_iter (desc);
+
+ /* simplify_using_initial_values does a copy propagation on the registers
+ in the expression for the number of iterations. This prolongs life
+ ranges of registers and increases register pressure, and usually
+ brings no gain (and if it happens to do, the cse pass will take care
+ of it anyway). So prevent this behavior, unless it enabled us to
+ derive that the number of iterations is a constant. */
+ desc->niter_expr = old_niter;
+ }
return;
{
basic_block exit_bb;
rtx condition, at;
- edge ei;
+ edge ein;
exit_bb = e->src;
desc->simple_p = false;
if (!any_condjump_p (BB_END (exit_bb)))
return;
- ei = exit_bb->succ;
- if (ei == e)
- ei = ei->succ_next;
+ ein = EDGE_SUCC (exit_bb, 0);
+ if (ein == e)
+ ein = EDGE_SUCC (exit_bb, 1);
desc->out_edge = e;
- desc->in_edge = ei;
+ desc->in_edge = ein;
/* Test whether the condition is suitable. */
- if (!(condition = get_condition (BB_END (ei->src), &at, false)))
+ if (!(condition = get_condition (BB_END (ein->src), &at, false, false)))
return;
- if (ei->flags & EDGE_FALLTHRU)
+ if (ein->flags & EDGE_FALLTHRU)
{
condition = reversed_condition (condition);
if (!condition)
edge e;
struct niter_desc act;
bool any = false;
+ edge_iterator ei;
desc->simple_p = false;
body = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
{
- for (e = body[i]->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, body[i]->succs)
{
if (flow_bb_inside_loop_p (loop, e->dest))
continue;