interesting reg, it is now easy to find a reaching definition (there may be
only one).
- Induction variable is then simply analysed by walking the use-def
+ Induction variable is then simply analyzed by walking the use-def
chains.
Usage:
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))
enum machine_mode mode;
rtx arg;
- /* Extend the constant to extend_mode of the other operand if neccesary. */
+ /* Extend the constant to extend_mode of the other operand if necessary. */
if (iv0->extend == NIL
&& iv0->mode == iv0->extend_mode
&& iv0->step == const0_rtx
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 == NIL)
+ {
+ 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);
enum machine_mode inner_mode, outer_mode;
enum rtx_code extend;
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "Analysing ");
- print_rtl (rtl_dump_file, def);
- fprintf (rtl_dump_file, " for bivness.\n");
+ fprintf (dump_file, "Analysing ");
+ print_rtl (dump_file, def);
+ fprintf (dump_file, " for bivness.\n");
}
if (!REG_P (def))
regno = REGNO (def);
if (last_def[regno] == const0_rtx)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, " not simple.\n");
+ if (dump_file)
+ fprintf (dump_file, " not simple.\n");
return false;
}
if (last_def[regno] && bivs[regno].analysed)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, " already analysed.\n");
+ if (dump_file)
+ fprintf (dump_file, " already analysed.\n");
*iv = bivs[regno];
return iv->base != NULL_RTX;
iv->delta = outer_step;
iv->first_special = inner_mode != outer_mode;
-end:
- if (rtl_dump_file)
+ end:
+ if (dump_file)
{
- fprintf (rtl_dump_file, " ");
- dump_iv_info (rtl_dump_file, iv);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " ");
+ dump_iv_info (dump_file, iv);
+ fprintf (dump_file, "\n");
}
bivs[regno] = *iv;
return iv->base != NULL_RTX;
}
-/* Analyses operand OP of INSN and stores the result to *IV. */
+/* Analyzes operand OP of INSN and stores the result to *IV. */
static bool
iv_analyze_op (rtx insn, rtx op, struct rtx_iv *iv)
unsigned regno;
bool inv = CONSTANT_P (op);
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "Analysing operand ");
- print_rtl (rtl_dump_file, op);
- fprintf (rtl_dump_file, " of insn ");
- print_rtl_single (rtl_dump_file, insn);
+ fprintf (dump_file, "Analysing operand ");
+ print_rtl (dump_file, op);
+ fprintf (dump_file, " of insn ");
+ print_rtl_single (dump_file, insn);
}
if (GET_CODE (op) == SUBREG)
inv = true;
else if (last_def[regno] == const0_rtx)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, " not simple.\n");
+ if (dump_file)
+ fprintf (dump_file, " not simple.\n");
return false;
}
}
{
iv_constant (iv, op, VOIDmode);
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, " ");
- dump_iv_info (rtl_dump_file, iv);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " ");
+ dump_iv_info (dump_file, iv);
+ fprintf (dump_file, "\n");
}
return true;
}
def_insn = iv_get_reaching_def (insn, op);
if (def_insn == const0_rtx)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, " not simple.\n");
+ if (dump_file)
+ fprintf (dump_file, " not simple.\n");
return false;
}
return iv_analyze (def_insn, op, iv);
}
-/* Analyses iv DEF defined in INSN and stores the result to *IV. */
+/* Analyzes iv DEF defined in INSN and stores the result to *IV. */
bool
iv_analyze (rtx insn, rtx def, struct rtx_iv *iv)
if (!insn)
return iv_analyze_biv (def, iv);
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "Analysing def of ");
- print_rtl (rtl_dump_file, def);
- fprintf (rtl_dump_file, " in insn ");
- print_rtl_single (rtl_dump_file, insn);
+ fprintf (dump_file, "Analysing def of ");
+ print_rtl (dump_file, def);
+ fprintf (dump_file, " in insn ");
+ print_rtl_single (dump_file, insn);
}
uid = INSN_UID (insn);
if (insn_info[uid].iv.analysed)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, " already analysed.\n");
+ if (dump_file)
+ fprintf (dump_file, " already analysed.\n");
*iv = insn_info[uid].iv;
return iv->base != NULL_RTX;
}
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;
}
*iv = iv0;
-end:
+ end:
iv->analysed = true;
insn_info[uid].iv = *iv;
- if (rtl_dump_file)
+ if (dump_file)
{
- print_rtl (rtl_dump_file, def);
- fprintf (rtl_dump_file, " in insn ");
- print_rtl_single (rtl_dump_file, insn);
- fprintf (rtl_dump_file, " is ");
- dump_iv_info (rtl_dump_file, iv);
- fprintf (rtl_dump_file, "\n");
+ print_rtl (dump_file, def);
+ fprintf (dump_file, " in insn ");
+ print_rtl_single (dump_file, insn);
+ fprintf (dump_file, " is ");
+ dump_iv_info (dump_file, iv);
+ fprintf (dump_file, "\n");
}
return iv->base != NULL_RTX;
}
}
- 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)
if (set)
{
lhs = SET_DEST (set);
- if (GET_CODE (lhs) != REG
+ if (!REG_P (lhs)
|| altered_reg_used (&lhs, altered))
ret = true;
}
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
{
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,
}
/* Transforms IV0 and IV1 compared by COND so that they are both compared as
- subregs of the same mode if possible (sometimes it is neccesary to add
+ subregs of the same mode if possible (sometimes it is necessary to add
some assumptions to DESC). */
static bool
{
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;
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)
{
obviously if the test for overflow during that transformation
passed, we cannot overflow here. Most importantly any
loop with sharp end condition and step 1 falls into this
- cathegory, so handling this case specially is definitely
+ category, so handling this case specially is definitely
worth the troubles. */
may_xform = const_true_rtx;
}
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 =
simplify_using_initial_values (loop, IOR, &desc->infinite);
simplify_using_initial_values (loop, NIL, &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)
{
unsigned HOST_WIDEST_INT val = INTVAL (desc->niter_expr);
}
/* Checks whether E is a simple exit from LOOP and stores its description
- into DESC. TODO Should replace cfgloopanal.c:simple_loop_exit_p. */
+ into DESC. */
static void
check_simple_exit (struct loop *loop, edge e, struct niter_desc *desc)
iv_number_of_iterations (loop, at, condition, desc);
}
-/* Finds a simple exit of LOOP and stores its description into DESC.
- TODO Should replace cfgloopanal.c:simple_loop_p. */
+/* Finds a simple exit of LOOP and stores its description into DESC. */
void
find_simple_exit (struct loop *loop, struct niter_desc *desc)
}
}
- if (rtl_dump_file)
+ if (dump_file)
{
if (desc->simple_p)
{
- fprintf (rtl_dump_file, "Loop %d is simple:\n", loop->num);
- fprintf (rtl_dump_file, " simple exit %d -> %d\n",
+ fprintf (dump_file, "Loop %d is simple:\n", loop->num);
+ fprintf (dump_file, " simple exit %d -> %d\n",
desc->out_edge->src->index,
desc->out_edge->dest->index);
if (desc->assumptions)
{
- fprintf (rtl_dump_file, " assumptions: ");
- print_rtl (rtl_dump_file, desc->assumptions);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " assumptions: ");
+ print_rtl (dump_file, desc->assumptions);
+ fprintf (dump_file, "\n");
}
if (desc->noloop_assumptions)
{
- fprintf (rtl_dump_file, " does not roll if: ");
- print_rtl (rtl_dump_file, desc->noloop_assumptions);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " does not roll if: ");
+ print_rtl (dump_file, desc->noloop_assumptions);
+ fprintf (dump_file, "\n");
}
if (desc->infinite)
{
- fprintf (rtl_dump_file, " infinite if: ");
- print_rtl (rtl_dump_file, desc->infinite);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " infinite if: ");
+ print_rtl (dump_file, desc->infinite);
+ fprintf (dump_file, "\n");
}
- fprintf (rtl_dump_file, " number of iterations: ");
- print_rtl (rtl_dump_file, desc->niter_expr);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " number of iterations: ");
+ print_rtl (dump_file, desc->niter_expr);
+ fprintf (dump_file, "\n");
- fprintf (rtl_dump_file, " upper bound: ");
- fprintf (rtl_dump_file, HOST_WIDEST_INT_PRINT_DEC, desc->niter_max);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, " upper bound: ");
+ fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, desc->niter_max);
+ fprintf (dump_file, "\n");
}
else
- fprintf (rtl_dump_file, "Loop %d is not simple.\n", loop->num);
+ fprintf (dump_file, "Loop %d is not simple.\n", loop->num);
}
free (body);