Commit a6f778b2 by Zdenek Dvorak Committed by Zdenek Dvorak

re PR tree-optimization/18527 (cannot determine number of iterations for loops with <=)

	PR tree-optimization/18527
	* tree-ssa-loop-niter.c (number_of_iterations_cond,
	number_of_iterations_special, number_of_iterations_exit):
	Move base and step of an iv to a single structure.  Add
	no_overflow flag, and use it in # of iterations analysis.
	* tree-scalar-evolution.c (analyze_scalar_evolution_in_loop): Add
	folded_casts argument.
	(simple_iv): Pass base and step in a structure.  Set no_overflow
	flag.
	(scev_const_prop): Add argument to analyze_scalar_evolution_in_loop.
	Evaluate expensiveness of computing # of iterations instead of
	the final expression.
	* tree-scalar-evolution.h (affine_iv): New structure.
	(simple_iv): Declaration changed.
	* tree-chrec.c (chrec_apply): Handle chrecs containing symbols.
	* tree-ssa-loop-ivopts.c (determine_biv_step, find_givs_in_stmt_scev,
	find_givs_in_stmt): Changed due to simple_iv change.

	* gcc.dg/tree-ssa/loop-15.c: New test.

From-SVN: r109427
parent 782e9875
2005-01-06 Zdenek Dvorak <dvorakz@suse.cz>
PR tree-optimization/18527
* tree-ssa-loop-niter.c (number_of_iterations_cond,
number_of_iterations_special, number_of_iterations_exit):
Move base and step of an iv to a single structure. Add
no_overflow flag, and use it in # of iterations analysis.
* tree-scalar-evolution.c (analyze_scalar_evolution_in_loop): Add
folded_casts argument.
(simple_iv): Pass base and step in a structure. Set no_overflow
flag.
(scev_const_prop): Add argument to analyze_scalar_evolution_in_loop.
Evaluate expensiveness of computing # of iterations instead of
the final expression.
* tree-scalar-evolution.h (affine_iv): New structure.
(simple_iv): Declaration changed.
* tree-chrec.c (chrec_apply): Handle chrecs containing symbols.
* tree-ssa-loop-ivopts.c (determine_biv_step, find_givs_in_stmt_scev,
find_givs_in_stmt): Changed due to simple_iv change.
2005-01-06 Jeff Law <law@redhat.com> 2005-01-06 Jeff Law <law@redhat.com>
PR ada/24994 PR ada/24994
......
2005-01-06 Zdenek Dvorak <dvorakz@suse.cz>
* gcc.dg/tree-ssa/loop-15.c: New test.
2005-01-05 Jerry DeLisle <jvdelisle@gcc.gnu.org> 2005-01-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR fortran/25598 PR fortran/25598
/* A test for # of iterations analysis (signed counter cannot wrap) and final
value replacement. */
/* { dg-options "-O2 -fdump-tree-vars" } */
int foo(void);
int bla(void)
{
int i, n = foo (), j;
j = 0;
/* The loop should be removed completely. */
for (i = 1; i <= n; i++)
j += n;
/* Should be replaced with return n * n; */
return j;
}
/* Since the loop is removed, there should be no addition. */
/* { dg-final { scan-tree-dump-times "\\+" 0 "vars" } } */
/* { dg-final { scan-tree-dump-times "n \\* n" 1 "vars" } } */
/* The if from the loop header copying remains in the code. */
/* { dg-final { scan-tree-dump-times "if " 1 "vars" } } */
/* { dg-final { cleanup-tree-dump "vars" } } */
...@@ -533,8 +533,7 @@ chrec_apply (unsigned var, ...@@ -533,8 +533,7 @@ chrec_apply (unsigned var,
/* When the symbols are defined in an outer loop, it is possible /* When the symbols are defined in an outer loop, it is possible
to symbolically compute the apply, since the symbols are to symbolically compute the apply, since the symbols are
constants with respect to the varying loop. */ constants with respect to the varying loop. */
|| chrec_contains_symbols_defined_in_loop (chrec, var) || chrec_contains_symbols_defined_in_loop (chrec, var))
|| chrec_contains_symbols (x))
return chrec_dont_know; return chrec_dont_know;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
...@@ -546,14 +545,10 @@ chrec_apply (unsigned var, ...@@ -546,14 +545,10 @@ chrec_apply (unsigned var,
if (evolution_function_is_affine_p (chrec)) if (evolution_function_is_affine_p (chrec))
{ {
/* "{a, +, b} (x)" -> "a + b*x". */ /* "{a, +, b} (x)" -> "a + b*x". */
if (TREE_CODE (CHREC_LEFT (chrec)) == INTEGER_CST x = chrec_convert (type, x, NULL_TREE);
&& integer_zerop (CHREC_LEFT (chrec)))
res = chrec_fold_multiply (type, CHREC_RIGHT (chrec), x); res = chrec_fold_multiply (type, CHREC_RIGHT (chrec), x);
if (!integer_zerop (CHREC_LEFT (chrec)))
else res = chrec_fold_plus (type, CHREC_LEFT (chrec), res);
res = chrec_fold_plus (type, CHREC_LEFT (chrec),
chrec_fold_multiply (type,
CHREC_RIGHT (chrec), x));
} }
else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC) else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
...@@ -563,7 +558,6 @@ chrec_apply (unsigned var, ...@@ -563,7 +558,6 @@ chrec_apply (unsigned var,
&& tree_int_cst_sgn (x) == 1) && tree_int_cst_sgn (x) == 1)
/* testsuite/.../ssa-chrec-38.c. */ /* testsuite/.../ssa-chrec-38.c. */
res = chrec_evaluate (var, chrec, x, 0); res = chrec_evaluate (var, chrec, x, 0);
else else
res = chrec_dont_know; res = chrec_dont_know;
......
...@@ -1831,19 +1831,28 @@ analyze_scalar_evolution (struct loop *loop, tree var) ...@@ -1831,19 +1831,28 @@ analyze_scalar_evolution (struct loop *loop, tree var)
/* Analyze scalar evolution of use of VERSION in USE_LOOP with respect to /* Analyze scalar evolution of use of VERSION in USE_LOOP with respect to
WRTO_LOOP (which should be a superloop of both USE_LOOP and definition WRTO_LOOP (which should be a superloop of both USE_LOOP and definition
of VERSION). */ of VERSION).
FOLDED_CASTS is set to true if resolve_mixers used
chrec_convert_aggressive (TODO -- not really, we are way too conservative
at the moment in order to keep things simple). */
static tree static tree
analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop, analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
tree version) tree version, bool *folded_casts)
{ {
bool val = false; bool val = false;
tree ev = version; tree ev = version, tmp;
if (folded_casts)
*folded_casts = false;
while (1) while (1)
{ {
ev = analyze_scalar_evolution (use_loop, ev); tmp = analyze_scalar_evolution (use_loop, ev);
ev = resolve_mixers (use_loop, ev); ev = resolve_mixers (use_loop, tmp);
if (folded_casts && tmp != ev)
*folded_casts = true;
if (use_loop == wrto_loop) if (use_loop == wrto_loop)
return ev; return ev;
...@@ -2561,33 +2570,38 @@ scev_reset (void) ...@@ -2561,33 +2570,38 @@ scev_reset (void)
} }
/* Checks whether OP behaves as a simple affine iv of LOOP in STMT and returns /* Checks whether OP behaves as a simple affine iv of LOOP in STMT and returns
its BASE and STEP if possible. If ALLOW_NONCONSTANT_STEP is true, we its base and step in IV if possible. If ALLOW_NONCONSTANT_STEP is true, we
want STEP to be invariant in LOOP. Otherwise we require it to be an want step to be invariant in LOOP. Otherwise we require it to be an
integer constant. */ integer constant. IV->no_overflow is set to true if we are sure the iv cannot
overflow (e.g. because it is computed in signed arithmetics). */
bool bool
simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step, simple_iv (struct loop *loop, tree stmt, tree op, affine_iv *iv,
bool allow_nonconstant_step) bool allow_nonconstant_step)
{ {
basic_block bb = bb_for_stmt (stmt); basic_block bb = bb_for_stmt (stmt);
tree type, ev; tree type, ev;
bool folded_casts;
*base = NULL_TREE; iv->base = NULL_TREE;
*step = NULL_TREE; iv->step = NULL_TREE;
iv->no_overflow = false;
type = TREE_TYPE (op); type = TREE_TYPE (op);
if (TREE_CODE (type) != INTEGER_TYPE if (TREE_CODE (type) != INTEGER_TYPE
&& TREE_CODE (type) != POINTER_TYPE) && TREE_CODE (type) != POINTER_TYPE)
return false; return false;
ev = analyze_scalar_evolution_in_loop (loop, bb->loop_father, op); ev = analyze_scalar_evolution_in_loop (loop, bb->loop_father, op,
&folded_casts);
if (chrec_contains_undetermined (ev)) if (chrec_contains_undetermined (ev))
return false; return false;
if (tree_does_not_contain_chrecs (ev) if (tree_does_not_contain_chrecs (ev)
&& !chrec_contains_symbols_defined_in_loop (ev, loop->num)) && !chrec_contains_symbols_defined_in_loop (ev, loop->num))
{ {
*base = ev; iv->base = ev;
iv->no_overflow = true;
return true; return true;
} }
...@@ -2595,21 +2609,24 @@ simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step, ...@@ -2595,21 +2609,24 @@ simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step,
|| CHREC_VARIABLE (ev) != (unsigned) loop->num) || CHREC_VARIABLE (ev) != (unsigned) loop->num)
return false; return false;
*step = CHREC_RIGHT (ev); iv->step = CHREC_RIGHT (ev);
if (allow_nonconstant_step) if (allow_nonconstant_step)
{ {
if (tree_contains_chrecs (*step, NULL) if (tree_contains_chrecs (iv->step, NULL)
|| chrec_contains_symbols_defined_in_loop (*step, loop->num)) || chrec_contains_symbols_defined_in_loop (iv->step, loop->num))
return false; return false;
} }
else if (TREE_CODE (*step) != INTEGER_CST) else if (TREE_CODE (iv->step) != INTEGER_CST)
return false; return false;
*base = CHREC_LEFT (ev); iv->base = CHREC_LEFT (ev);
if (tree_contains_chrecs (*base, NULL) if (tree_contains_chrecs (iv->base, NULL)
|| chrec_contains_symbols_defined_in_loop (*base, loop->num)) || chrec_contains_symbols_defined_in_loop (iv->base, loop->num))
return false; return false;
iv->no_overflow = (!folded_casts
&& !flag_wrapv
&& !TYPE_UNSIGNED (type));
return true; return true;
} }
...@@ -2722,7 +2739,7 @@ scev_const_prop (void) ...@@ -2722,7 +2739,7 @@ scev_const_prop (void)
for (i = current_loops->num - 1; i > 0; i--) for (i = current_loops->num - 1; i > 0; i--)
{ {
edge exit; edge exit;
tree def, rslt, ass; tree def, rslt, ass, niter;
block_stmt_iterator bsi; block_stmt_iterator bsi;
loop = current_loops->parray[i]; loop = current_loops->parray[i];
...@@ -2732,8 +2749,14 @@ scev_const_prop (void) ...@@ -2732,8 +2749,14 @@ scev_const_prop (void)
/* If we do not know exact number of iterations of the loop, we cannot /* If we do not know exact number of iterations of the loop, we cannot
replace the final value. */ replace the final value. */
exit = loop->single_exit; exit = loop->single_exit;
if (!exit if (!exit)
|| number_of_iterations_in_loop (loop) == chrec_dont_know) continue;
niter = number_of_iterations_in_loop (loop);
if (niter == chrec_dont_know
/* If computing the number of iterations is expensive, it may be
better not to introduce computations involving it. */
|| expression_expensive_p (niter))
continue; continue;
/* Ensure that it is possible to insert new statements somewhere. */ /* Ensure that it is possible to insert new statements somewhere. */
...@@ -2756,17 +2779,12 @@ scev_const_prop (void) ...@@ -2756,17 +2779,12 @@ scev_const_prop (void)
&& !INTEGRAL_TYPE_P (TREE_TYPE (def))) && !INTEGRAL_TYPE_P (TREE_TYPE (def)))
continue; continue;
def = analyze_scalar_evolution_in_loop (ex_loop, loop, def); def = analyze_scalar_evolution_in_loop (ex_loop, loop, def, NULL);
def = compute_overall_effect_of_inner_loop (ex_loop, def); def = compute_overall_effect_of_inner_loop (ex_loop, def);
if (!tree_does_not_contain_chrecs (def) if (!tree_does_not_contain_chrecs (def)
|| chrec_contains_symbols_defined_in_loop (def, ex_loop->num)) || chrec_contains_symbols_defined_in_loop (def, ex_loop->num))
continue; continue;
/* If computing the expression is expensive, let it remain in the
loop. */
if (expression_expensive_p (def))
continue;
/* Eliminate the phi node and replace it by a computation outside /* Eliminate the phi node and replace it by a computation outside
the loop. */ the loop. */
def = unshare_expr (def); def = unshare_expr (def);
......
...@@ -32,7 +32,19 @@ extern tree analyze_scalar_evolution (struct loop *, tree); ...@@ -32,7 +32,19 @@ extern tree analyze_scalar_evolution (struct loop *, tree);
extern tree instantiate_parameters (struct loop *, tree); extern tree instantiate_parameters (struct loop *, tree);
extern void gather_stats_on_scev_database (void); extern void gather_stats_on_scev_database (void);
extern void scev_analysis (void); extern void scev_analysis (void);
extern bool simple_iv (struct loop *, tree, tree, tree *, tree *, bool);
void scev_const_prop (void); void scev_const_prop (void);
/* Affine iv. */
typedef struct
{
/* Iv = BASE + STEP * i. */
tree base, step;
/* True if this iv does not overflow. */
bool no_overflow;
} affine_iv;
extern bool simple_iv (struct loop *, tree, tree, affine_iv *, bool);
#endif /* GCC_TREE_SCALAR_EVOLUTION_H */ #endif /* GCC_TREE_SCALAR_EVOLUTION_H */
...@@ -881,18 +881,16 @@ static tree ...@@ -881,18 +881,16 @@ static tree
determine_biv_step (tree phi) determine_biv_step (tree phi)
{ {
struct loop *loop = bb_for_stmt (phi)->loop_father; struct loop *loop = bb_for_stmt (phi)->loop_father;
tree name = PHI_RESULT (phi), base, step; tree name = PHI_RESULT (phi);
affine_iv iv;
if (!is_gimple_reg (name)) if (!is_gimple_reg (name))
return NULL_TREE; return NULL_TREE;
if (!simple_iv (loop, phi, name, &base, &step, true)) if (!simple_iv (loop, phi, name, &iv, true))
return NULL_TREE; return NULL_TREE;
if (zero_p (step)) return (zero_p (iv.step) ? NULL_TREE : iv.step);
return NULL_TREE;
return step;
} }
/* Returns true if EXP is a ssa name that occurs in an abnormal phi node. */ /* Returns true if EXP is a ssa name that occurs in an abnormal phi node. */
...@@ -1044,17 +1042,16 @@ mark_bivs (struct ivopts_data *data) ...@@ -1044,17 +1042,16 @@ mark_bivs (struct ivopts_data *data)
} }
/* Checks whether STMT defines a linear induction variable and stores its /* Checks whether STMT defines a linear induction variable and stores its
parameters to BASE and STEP. */ parameters to IV. */
static bool static bool
find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, affine_iv *iv)
tree *base, tree *step)
{ {
tree lhs; tree lhs;
struct loop *loop = data->current_loop; struct loop *loop = data->current_loop;
*base = NULL_TREE; iv->base = NULL_TREE;
*step = NULL_TREE; iv->step = NULL_TREE;
if (TREE_CODE (stmt) != MODIFY_EXPR) if (TREE_CODE (stmt) != MODIFY_EXPR)
return false; return false;
...@@ -1063,12 +1060,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, ...@@ -1063,12 +1060,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt,
if (TREE_CODE (lhs) != SSA_NAME) if (TREE_CODE (lhs) != SSA_NAME)
return false; return false;
if (!simple_iv (loop, stmt, TREE_OPERAND (stmt, 1), base, step, true)) if (!simple_iv (loop, stmt, TREE_OPERAND (stmt, 1), iv, true))
return false; return false;
*base = expand_simple_operations (*base); iv->base = expand_simple_operations (iv->base);
if (contains_abnormal_ssa_name_p (*base) if (contains_abnormal_ssa_name_p (iv->base)
|| contains_abnormal_ssa_name_p (*step)) || contains_abnormal_ssa_name_p (iv->step))
return false; return false;
return true; return true;
...@@ -1079,12 +1076,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, ...@@ -1079,12 +1076,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt,
static void static void
find_givs_in_stmt (struct ivopts_data *data, tree stmt) find_givs_in_stmt (struct ivopts_data *data, tree stmt)
{ {
tree base, step; affine_iv iv;
if (!find_givs_in_stmt_scev (data, stmt, &base, &step)) if (!find_givs_in_stmt_scev (data, stmt, &iv))
return; return;
set_iv (data, TREE_OPERAND (stmt, 0), base, step); set_iv (data, TREE_OPERAND (stmt, 0), iv.base, iv.step);
} }
/* Finds general ivs in basic block BB. */ /* Finds general ivs in basic block BB. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment