mirror of git://gcc.gnu.org/git/gcc.git
cfgloopanal.c (count_strange_loop_iterations): New static function.
* cfgloopanal.c (count_strange_loop_iterations): New static function. (constant_iterations, count_loop_iterations, simple_loop_exit_p): Handle strange loops. From-SVN: r68930
This commit is contained in:
parent
8e9a4a4525
commit
72d4a2ad78
|
|
@ -1,3 +1,9 @@
|
||||||
|
2003-07-04 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||||
|
|
||||||
|
* cfgloopanal.c (count_strange_loop_iterations): New static function.
|
||||||
|
(constant_iterations, count_loop_iterations, simple_loop_exit_p):
|
||||||
|
Handle strange loops.
|
||||||
|
|
||||||
2003-07-04 Toon Moene <toon@moene.indiv.nluug.nl>
|
2003-07-04 Toon Moene <toon@moene.indiv.nluug.nl>
|
||||||
|
|
||||||
* install.texi: Even the g77 manpage is derived from
|
* install.texi: Even the g77 manpage is derived from
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ static bool simple_condition_p (struct loop *, rtx, regset,
|
||||||
struct loop_desc *);
|
struct loop_desc *);
|
||||||
static basic_block simple_increment (struct loops *, struct loop *, rtx *,
|
static basic_block simple_increment (struct loops *, struct loop *, rtx *,
|
||||||
struct loop_desc *);
|
struct loop_desc *);
|
||||||
|
static rtx count_strange_loop_iterations (rtx, rtx, enum rtx_code,
|
||||||
|
int, rtx, enum machine_mode);
|
||||||
|
|
||||||
/* Checks whether BB is executed exactly once in each LOOP iteration. */
|
/* Checks whether BB is executed exactly once in each LOOP iteration. */
|
||||||
bool
|
bool
|
||||||
|
|
@ -426,7 +428,7 @@ constant_iterations (struct loop_desc *desc, unsigned HOST_WIDE_INT *niter,
|
||||||
{
|
{
|
||||||
alim = XEXP (desc->lim_alts, 0);
|
alim = XEXP (desc->lim_alts, 0);
|
||||||
if (!(expr = count_loop_iterations (desc, XEXP (ainit, 0), alim)))
|
if (!(expr = count_loop_iterations (desc, XEXP (ainit, 0), alim)))
|
||||||
abort ();
|
continue;
|
||||||
if (GET_CODE (expr) == CONST_INT)
|
if (GET_CODE (expr) == CONST_INT)
|
||||||
{
|
{
|
||||||
*niter = INTVAL (expr);
|
*niter = INTVAL (expr);
|
||||||
|
|
@ -437,7 +439,7 @@ constant_iterations (struct loop_desc *desc, unsigned HOST_WIDE_INT *niter,
|
||||||
{
|
{
|
||||||
ainit = XEXP (desc->var_alts, 0);
|
ainit = XEXP (desc->var_alts, 0);
|
||||||
if (!(expr = count_loop_iterations (desc, ainit, XEXP (alim, 0))))
|
if (!(expr = count_loop_iterations (desc, ainit, XEXP (alim, 0))))
|
||||||
abort ();
|
continue;
|
||||||
if (GET_CODE (expr) == CONST_INT)
|
if (GET_CODE (expr) == CONST_INT)
|
||||||
{
|
{
|
||||||
*niter = INTVAL (expr);
|
*niter = INTVAL (expr);
|
||||||
|
|
@ -448,6 +450,123 @@ constant_iterations (struct loop_desc *desc, unsigned HOST_WIDE_INT *niter,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Attempts to determine a number of iterations of a "strange" loop.
|
||||||
|
Its induction variable starts with value INIT, is compared by COND
|
||||||
|
with LIM. If POSTINCR, it is incremented after the test. It is incremented
|
||||||
|
by STRIDE each iteration and iterates in MODE.
|
||||||
|
|
||||||
|
By "strange" we mean loops where induction variable increases in the wrong
|
||||||
|
direction wrto comparison, i.e. for (i = 6; i > 5; i++). */
|
||||||
|
static rtx
|
||||||
|
count_strange_loop_iterations (rtx init, rtx lim, enum rtx_code cond,
|
||||||
|
int postincr, rtx stride, enum machine_mode mode)
|
||||||
|
{
|
||||||
|
rtx rqmt, n_to_wrap, before_wrap, after_wrap;
|
||||||
|
rtx mode_min, mode_max;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
if (!postincr)
|
||||||
|
init = simplify_gen_binary (PLUS, mode, init, stride);
|
||||||
|
|
||||||
|
/* If we are able to prove that we don't pass the first test, we are
|
||||||
|
done. */
|
||||||
|
rqmt = simplify_gen_relational (cond, SImode, mode, init, lim);
|
||||||
|
if (rqmt == const0_rtx)
|
||||||
|
return const0_rtx;
|
||||||
|
|
||||||
|
/* And if we don't know we pass it, the things are too complicated for us. */
|
||||||
|
if (rqmt != const_true_rtx)
|
||||||
|
return NULL_RTX;
|
||||||
|
|
||||||
|
switch (cond)
|
||||||
|
{
|
||||||
|
case GE:
|
||||||
|
case GT:
|
||||||
|
case LE:
|
||||||
|
case LT:
|
||||||
|
size = GET_MODE_BITSIZE (mode);
|
||||||
|
mode_min = GEN_INT (-((unsigned HOST_WIDEST_INT) 1 << (size - 1)));
|
||||||
|
mode_max = GEN_INT (((unsigned HOST_WIDEST_INT) 1 << (size - 1)) - 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEU:
|
||||||
|
case GTU:
|
||||||
|
case LEU:
|
||||||
|
case LTU:
|
||||||
|
case EQ:
|
||||||
|
mode_min = const0_rtx;
|
||||||
|
mode_max = simplify_gen_binary (MINUS, mode, const0_rtx, const1_rtx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cond)
|
||||||
|
{
|
||||||
|
case EQ:
|
||||||
|
/* This iterates once, as init == lim. */
|
||||||
|
return const1_rtx;
|
||||||
|
|
||||||
|
/* The behavior is undefined in signed cases. Never mind, we still
|
||||||
|
try to behave sanely. */
|
||||||
|
case GE:
|
||||||
|
case GT:
|
||||||
|
case GEU:
|
||||||
|
case GTU:
|
||||||
|
if (INTVAL (stride) <= 0)
|
||||||
|
abort ();
|
||||||
|
n_to_wrap = simplify_gen_binary (MINUS, mode, mode_max, copy_rtx (init));
|
||||||
|
n_to_wrap = simplify_gen_binary (UDIV, mode, n_to_wrap, stride);
|
||||||
|
before_wrap = simplify_gen_binary (MULT, mode,
|
||||||
|
copy_rtx (n_to_wrap), stride);
|
||||||
|
before_wrap = simplify_gen_binary (PLUS, mode,
|
||||||
|
before_wrap, copy_rtx (init));
|
||||||
|
after_wrap = simplify_gen_binary (PLUS, mode,
|
||||||
|
before_wrap, stride);
|
||||||
|
if (GET_CODE (after_wrap) != CONST_INT)
|
||||||
|
{
|
||||||
|
after_wrap = simplify_gen_binary (PLUS, mode, mode_min, stride);
|
||||||
|
after_wrap = simplify_gen_binary (MINUS, mode, after_wrap, const1_rtx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LE:
|
||||||
|
case LT:
|
||||||
|
case LEU:
|
||||||
|
case LTU:
|
||||||
|
if (INTVAL (stride) >= 0)
|
||||||
|
abort ();
|
||||||
|
stride = simplify_gen_unary (NEG, mode, stride, mode);
|
||||||
|
n_to_wrap = simplify_gen_binary (MINUS, mode, copy_rtx (init), mode_min);
|
||||||
|
n_to_wrap = simplify_gen_binary (UDIV, mode, n_to_wrap, stride);
|
||||||
|
before_wrap = simplify_gen_binary (MULT, mode,
|
||||||
|
copy_rtx (n_to_wrap), stride);
|
||||||
|
before_wrap = simplify_gen_binary (MINUS, mode,
|
||||||
|
copy_rtx (init), before_wrap);
|
||||||
|
after_wrap = simplify_gen_binary (MINUS, mode,
|
||||||
|
before_wrap, stride);
|
||||||
|
if (GET_CODE (after_wrap) != CONST_INT)
|
||||||
|
{
|
||||||
|
after_wrap = simplify_gen_binary (MINUS, mode, mode_max, stride);
|
||||||
|
after_wrap = simplify_gen_binary (PLUS, mode, after_wrap, const1_rtx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is const_true_rtx and we did not take a conservative aproximation
|
||||||
|
of after_wrap above, we might iterate the calculation (but of course we
|
||||||
|
would have to take care about infinite cases). Ignore this for now. */
|
||||||
|
rqmt = simplify_gen_relational (cond, SImode, mode, after_wrap, lim);
|
||||||
|
if (rqmt != const0_rtx)
|
||||||
|
return NULL_RTX;
|
||||||
|
|
||||||
|
return simplify_gen_binary (PLUS, mode, n_to_wrap, const1_rtx);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return RTX expression representing number of iterations of loop as bounded
|
/* Return RTX expression representing number of iterations of loop as bounded
|
||||||
by test described by DESC (in the case loop really has multiple exit
|
by test described by DESC (in the case loop really has multiple exit
|
||||||
edges, fewer iterations may happen in the practice).
|
edges, fewer iterations may happen in the practice).
|
||||||
|
|
@ -482,10 +601,11 @@ count_loop_iterations (struct loop_desc *desc, rtx init, rtx lim)
|
||||||
/* Compute absolute value of the difference of initial and final value. */
|
/* Compute absolute value of the difference of initial and final value. */
|
||||||
if (INTVAL (stride) > 0)
|
if (INTVAL (stride) > 0)
|
||||||
{
|
{
|
||||||
/* Bypass nonsensical tests. */
|
/* Handle strange tests specially. */
|
||||||
if (cond == EQ || cond == GE || cond == GT || cond == GEU
|
if (cond == EQ || cond == GE || cond == GT || cond == GEU
|
||||||
|| cond == GTU)
|
|| cond == GTU)
|
||||||
return NULL;
|
return count_strange_loop_iterations (init, lim, cond, desc->postincr,
|
||||||
|
stride, GET_MODE (desc->var));
|
||||||
exp = simplify_gen_binary (MINUS, GET_MODE (desc->var),
|
exp = simplify_gen_binary (MINUS, GET_MODE (desc->var),
|
||||||
lim, init);
|
lim, init);
|
||||||
}
|
}
|
||||||
|
|
@ -494,7 +614,8 @@ count_loop_iterations (struct loop_desc *desc, rtx init, rtx lim)
|
||||||
/* Bypass nonsensical tests. */
|
/* Bypass nonsensical tests. */
|
||||||
if (cond == EQ || cond == LE || cond == LT || cond == LEU
|
if (cond == EQ || cond == LE || cond == LT || cond == LEU
|
||||||
|| cond == LTU)
|
|| cond == LTU)
|
||||||
return NULL;
|
return count_strange_loop_iterations (init, lim, cond, desc->postincr,
|
||||||
|
stride, GET_MODE (desc->var));
|
||||||
exp = simplify_gen_binary (MINUS, GET_MODE (desc->var),
|
exp = simplify_gen_binary (MINUS, GET_MODE (desc->var),
|
||||||
init, lim);
|
init, lim);
|
||||||
stride = simplify_gen_unary (NEG, GET_MODE (desc->var),
|
stride = simplify_gen_unary (NEG, GET_MODE (desc->var),
|
||||||
|
|
@ -675,10 +796,10 @@ simple_loop_exit_p (struct loops *loops, struct loop *loop, edge exit_edge,
|
||||||
desc->lim_alts = variable_initial_values (e, desc->lim);
|
desc->lim_alts = variable_initial_values (e, desc->lim);
|
||||||
|
|
||||||
/* Number of iterations. */
|
/* Number of iterations. */
|
||||||
if (!count_loop_iterations (desc, NULL, NULL))
|
|
||||||
return false;
|
|
||||||
desc->const_iter =
|
desc->const_iter =
|
||||||
constant_iterations (desc, &desc->niter, &desc->may_be_zero);
|
constant_iterations (desc, &desc->niter, &desc->may_be_zero);
|
||||||
|
if (!desc->const_iter && !count_loop_iterations (desc, NULL, NULL))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue