Commit c93c5025 by Sebastian Pop Committed by Sebastian Pop

re PR tree-optimization/20256 (Perfect nest transformation not conservative enough)

	PR middle-end/20256
	PR middle-end/26435
	* tree-loop-linear.c (linear_transform_loops): Don't test perfect_nest_p.
	Call rewrite_into_loop_closed_ssa only when something changed.
	* lambda.h (gcc_loopnest_to_lambda_loopnest): Update declaration.
	* lambda-code.c (can_convert_to_perfect_nest): Declared.
	(gcc_loopnest_to_lambda_loopnest): Removed need_perfect_nest parameter.
	Test for perfect_nest_p here.  Fix formating.
	(replace_uses_equiv_to_x_with_y): Fix formating.
	(stmt_uses_op): Removed.
	(can_convert_to_perfect_nest): Removed loopivs parameter.
	Complete the test by checking the scalar dependences.
	(perfect_nestify): Remove the test for can_convert_to_perfect_nest.
	Fix formating.

From-SVN: r113862
parent 46343456
2006-05-17 Sebastian Pop <pop@cri.ensmp.fr>
PR middle-end/20256
PR middle-end/26435
* tree-loop-linear.c (linear_transform_loops): Don't test perfect_nest_p.
Call rewrite_into_loop_closed_ssa only when something changed.
* lambda.h (gcc_loopnest_to_lambda_loopnest): Update declaration.
* lambda-code.c (can_convert_to_perfect_nest): Declared.
(gcc_loopnest_to_lambda_loopnest): Removed need_perfect_nest parameter.
Test for perfect_nest_p here. Fix formating.
(replace_uses_equiv_to_x_with_y): Fix formating.
(stmt_uses_op): Removed.
(can_convert_to_perfect_nest): Removed loopivs parameter.
Complete the test by checking the scalar dependences.
(perfect_nestify): Remove the test for can_convert_to_perfect_nest.
Fix formating.
2005-05-17 Bernd Schmidt <bernd.schmidt@analog.com> 2005-05-17 Bernd Schmidt <bernd.schmidt@analog.com>
PR bootstrap/22541 PR bootstrap/22541
......
...@@ -147,6 +147,7 @@ static lambda_lattice lambda_lattice_new (int, int); ...@@ -147,6 +147,7 @@ static lambda_lattice lambda_lattice_new (int, int);
static lambda_lattice lambda_lattice_compute_base (lambda_loopnest); static lambda_lattice lambda_lattice_compute_base (lambda_loopnest);
static tree find_induction_var_from_exit_cond (struct loop *); static tree find_induction_var_from_exit_cond (struct loop *);
static bool can_convert_to_perfect_nest (struct loop *);
/* Create a new lambda body vector. */ /* Create a new lambda body vector. */
...@@ -1457,14 +1458,13 @@ DEF_VEC_ALLOC_P(lambda_loop,heap); ...@@ -1457,14 +1458,13 @@ DEF_VEC_ALLOC_P(lambda_loop,heap);
lambda_loopnest lambda_loopnest
gcc_loopnest_to_lambda_loopnest (struct loops *currloops, gcc_loopnest_to_lambda_loopnest (struct loops *currloops,
struct loop * loop_nest, struct loop *loop_nest,
VEC(tree,heap) **inductionvars, VEC(tree,heap) **inductionvars,
VEC(tree,heap) **invariants, VEC(tree,heap) **invariants)
bool need_perfect_nest)
{ {
lambda_loopnest ret = NULL; lambda_loopnest ret = NULL;
struct loop *temp; struct loop *temp = loop_nest;
int depth = 0; int depth = depth_of_nest (loop_nest);
size_t i; size_t i;
VEC(lambda_loop,heap) *loops = NULL; VEC(lambda_loop,heap) *loops = NULL;
VEC(tree,heap) *uboundvars = NULL; VEC(tree,heap) *uboundvars = NULL;
...@@ -1472,9 +1472,11 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, ...@@ -1472,9 +1472,11 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops,
VEC(int,heap) *steps = NULL; VEC(int,heap) *steps = NULL;
lambda_loop newloop; lambda_loop newloop;
tree inductionvar = NULL; tree inductionvar = NULL;
bool perfect_nest = perfect_nest_p (loop_nest);
depth = depth_of_nest (loop_nest);
temp = loop_nest; if (!perfect_nest && !can_convert_to_perfect_nest (loop_nest))
goto fail;
while (temp) while (temp)
{ {
newloop = gcc_loop_to_lambda_loop (temp, depth, invariants, newloop = gcc_loop_to_lambda_loop (temp, depth, invariants,
...@@ -1482,12 +1484,14 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, ...@@ -1482,12 +1484,14 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops,
&lboundvars, &uboundvars, &lboundvars, &uboundvars,
&steps); &steps);
if (!newloop) if (!newloop)
return NULL; goto fail;
VEC_safe_push (tree, heap, *inductionvars, inductionvar); VEC_safe_push (tree, heap, *inductionvars, inductionvar);
VEC_safe_push (lambda_loop, heap, loops, newloop); VEC_safe_push (lambda_loop, heap, loops, newloop);
temp = temp->inner; temp = temp->inner;
} }
if (need_perfect_nest)
if (!perfect_nest)
{ {
if (!perfect_nestify (currloops, loop_nest, if (!perfect_nestify (currloops, loop_nest,
lboundvars, uboundvars, steps, *inductionvars)) lboundvars, uboundvars, steps, *inductionvars))
...@@ -1501,9 +1505,12 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, ...@@ -1501,9 +1505,12 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops,
fprintf (dump_file, fprintf (dump_file,
"Successfully converted loop nest to perfect loop nest.\n"); "Successfully converted loop nest to perfect loop nest.\n");
} }
ret = lambda_loopnest_new (depth, 2 * depth); ret = lambda_loopnest_new (depth, 2 * depth);
for (i = 0; VEC_iterate (lambda_loop, loops, i, newloop); i++) for (i = 0; VEC_iterate (lambda_loop, loops, i, newloop); i++)
LN_LOOPS (ret)[i] = newloop; LN_LOOPS (ret)[i] = newloop;
fail: fail:
VEC_free (lambda_loop, heap, loops); VEC_free (lambda_loop, heap, loops);
VEC_free (tree, heap, uboundvars); VEC_free (tree, heap, uboundvars);
...@@ -2110,13 +2117,12 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x, ...@@ -2110,13 +2117,12 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x,
{ {
tree use = USE_FROM_PTR (use_p); tree use = USE_FROM_PTR (use_p);
tree step = NULL_TREE; tree step = NULL_TREE;
tree access_fn = NULL_TREE; tree scev = instantiate_parameters (loop,
analyze_scalar_evolution (loop, use));
access_fn = instantiate_parameters if (scev != NULL_TREE && scev != chrec_dont_know)
(loop, analyze_scalar_evolution (loop, use)); step = evolution_part_in_loop_num (scev, loop->num);
if (access_fn != NULL_TREE && access_fn != chrec_dont_know)
step = evolution_part_in_loop_num (access_fn, loop->num);
if ((step && step != chrec_dont_know if ((step && step != chrec_dont_know
&& TREE_CODE (step) == INTEGER_CST && TREE_CODE (step) == INTEGER_CST
&& int_cst_value (step) == xstep) && int_cst_value (step) == xstep)
...@@ -2125,22 +2131,6 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x, ...@@ -2125,22 +2131,6 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x,
} }
} }
/* Return TRUE if STMT uses tree OP in it's uses. */
static bool
stmt_uses_op (tree stmt, tree op)
{
ssa_op_iter iter;
tree use;
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
if (use == op)
return true;
}
return false;
}
/* Return true if STMT is an exit PHI for LOOP */ /* Return true if STMT is an exit PHI for LOOP */
static bool static bool
...@@ -2210,14 +2200,12 @@ can_put_after_inner_loop (struct loop *loop, tree stmt) ...@@ -2210,14 +2200,12 @@ can_put_after_inner_loop (struct loop *loop, tree stmt)
/* Return TRUE if LOOP is an imperfect nest that we can convert to a perfect /* Return TRUE if LOOP is an imperfect nest that we can convert to a
one. LOOPIVS is a vector of induction variables, one per loop. perfect one. At the moment, we only handle imperfect nests of
ATM, we only handle imperfect nests of depth 2, where all of the statements depth 2, where all of the statements occur after the inner loop. */
occur after the inner loop. */
static bool static bool
can_convert_to_perfect_nest (struct loop *loop, can_convert_to_perfect_nest (struct loop *loop)
VEC(tree,heap) *loopivs)
{ {
basic_block *bbs; basic_block *bbs;
tree exit_condition, phi; tree exit_condition, phi;
...@@ -2237,19 +2225,13 @@ can_convert_to_perfect_nest (struct loop *loop, ...@@ -2237,19 +2225,13 @@ can_convert_to_perfect_nest (struct loop *loop,
{ {
for (bsi = bsi_start (bbs[i]); !bsi_end_p (bsi); bsi_next (&bsi)) for (bsi = bsi_start (bbs[i]); !bsi_end_p (bsi); bsi_next (&bsi))
{ {
size_t j;
tree stmt = bsi_stmt (bsi); tree stmt = bsi_stmt (bsi);
tree iv;
if (stmt == exit_condition if (stmt == exit_condition
|| not_interesting_stmt (stmt) || not_interesting_stmt (stmt)
|| stmt_is_bumper_for_loop (loop, stmt)) || stmt_is_bumper_for_loop (loop, stmt))
continue; continue;
/* If the statement uses inner loop ivs, we == screwed. */
for (j = 1; VEC_iterate (tree, loopivs, j, iv); j++)
if (stmt_uses_op (stmt, iv))
goto fail;
/* If this is a scalar operation that can be put back /* If this is a scalar operation that can be put back
into the inner loop, or after the inner loop, through into the inner loop, or after the inner loop, through
copying, then do so. This works on the theory that copying, then do so. This works on the theory that
...@@ -2258,10 +2240,65 @@ can_convert_to_perfect_nest (struct loop *loop, ...@@ -2258,10 +2240,65 @@ can_convert_to_perfect_nest (struct loop *loop,
win we get from rearranging the memory walk win we get from rearranging the memory walk
the loop is doing so that it has better the loop is doing so that it has better
cache behavior. */ cache behavior. */
if (TREE_CODE (stmt) == MODIFY_EXPR if (TREE_CODE (stmt) == MODIFY_EXPR)
&& (can_put_in_inner_loop (loop->inner, stmt) {
|| can_put_after_inner_loop (loop, stmt))) use_operand_p use_a, use_b;
continue; imm_use_iterator imm_iter;
ssa_op_iter op_iter, op_iter1;
tree op0 = TREE_OPERAND (stmt, 0);
tree scev = instantiate_parameters
(loop, analyze_scalar_evolution (loop, op0));
/* If the IV is simple, it can be duplicated. */
if (!automatically_generated_chrec_p (scev))
{
tree step = evolution_part_in_loop_num (scev, loop->num);
if (step && step != chrec_dont_know
&& TREE_CODE (step) == INTEGER_CST)
continue;
}
/* The statement should not define a variable used
in the inner loop. */
if (TREE_CODE (op0) == SSA_NAME)
FOR_EACH_IMM_USE_FAST (use_a, imm_iter, op0)
if (bb_for_stmt (USE_STMT (use_a))->loop_father
== loop->inner)
goto fail;
FOR_EACH_SSA_USE_OPERAND (use_a, stmt, op_iter, SSA_OP_USE)
{
tree node, op = USE_FROM_PTR (use_a);
/* The variables should not be used in both loops. */
FOR_EACH_IMM_USE_FAST (use_b, imm_iter, op)
if (bb_for_stmt (USE_STMT (use_b))->loop_father
== loop->inner)
goto fail;
/* The statement should not use the value of a
scalar that was modified in the loop. */
node = SSA_NAME_DEF_STMT (op);
if (TREE_CODE (node) == PHI_NODE)
FOR_EACH_PHI_ARG (use_b, node, op_iter1, SSA_OP_USE)
{
tree arg = USE_FROM_PTR (use_b);
if (TREE_CODE (arg) == SSA_NAME)
{
tree arg_stmt = SSA_NAME_DEF_STMT (arg);
if (bb_for_stmt (arg_stmt)->loop_father
== loop->inner)
goto fail;
}
}
}
if (can_put_in_inner_loop (loop->inner, stmt)
|| can_put_after_inner_loop (loop, stmt))
continue;
}
/* Otherwise, if the bb of a statement we care about isn't /* Otherwise, if the bb of a statement we care about isn't
dominated by the header of the inner loop, then we can't dominated by the header of the inner loop, then we can't
...@@ -2351,14 +2388,10 @@ perfect_nestify (struct loops *loops, ...@@ -2351,14 +2388,10 @@ perfect_nestify (struct loops *loops,
tree stmt; tree stmt;
tree oldivvar, ivvar, ivvarinced; tree oldivvar, ivvar, ivvarinced;
VEC(tree,heap) *phis = NULL; VEC(tree,heap) *phis = NULL;
if (!can_convert_to_perfect_nest (loop, loopivs)) /* Create the new loop. */
return false;
/* Create the new loop */
olddest = loop->single_exit->dest; olddest = loop->single_exit->dest;
preheaderbb = loop_split_edge_with (loop->single_exit, NULL); preheaderbb = loop_split_edge_with (loop->single_exit, NULL);
headerbb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb); headerbb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
/* Push the exit phi nodes that we are moving. */ /* Push the exit phi nodes that we are moving. */
...@@ -2490,7 +2523,7 @@ perfect_nestify (struct loops *loops, ...@@ -2490,7 +2523,7 @@ perfect_nestify (struct loops *loops,
} }
/* Make copies of this statement to put it back next /* Make copies of this statement to put it back next
to its uses. */ to its uses. */
FOR_EACH_IMM_USE_STMT (imm_stmt, imm_iter, FOR_EACH_IMM_USE_STMT (imm_stmt, imm_iter,
TREE_OPERAND (stmt, 0)) TREE_OPERAND (stmt, 0))
{ {
...@@ -2506,8 +2539,10 @@ perfect_nestify (struct loops *loops, ...@@ -2506,8 +2539,10 @@ perfect_nestify (struct loops *loops,
newname = SSA_NAME_VAR (newname); newname = SSA_NAME_VAR (newname);
newname = make_ssa_name (newname, newstmt); newname = make_ssa_name (newname, newstmt);
TREE_OPERAND (newstmt, 0) = newname; TREE_OPERAND (newstmt, 0) = newname;
FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
SET_USE (use_p, newname); SET_USE (use_p, newname);
bsi_insert_before (&tobsi, newstmt, BSI_SAME_STMT); bsi_insert_before (&tobsi, newstmt, BSI_SAME_STMT);
update_stmt (newstmt); update_stmt (newstmt);
update_stmt (imm_stmt); update_stmt (imm_stmt);
...@@ -2535,10 +2570,9 @@ perfect_nestify (struct loops *loops, ...@@ -2535,10 +2570,9 @@ perfect_nestify (struct loops *loops,
continue; continue;
} }
replace_uses_equiv_to_x_with_y (loop, stmt, replace_uses_equiv_to_x_with_y
oldivvar, (loop, stmt, oldivvar, VEC_index (int, steps, 0), ivvar);
VEC_index (int, steps, 0),
ivvar);
bsi_move_before (&bsi, &tobsi); bsi_move_before (&bsi, &tobsi);
/* If the statement has any virtual operands, they may /* If the statement has any virtual operands, they may
......
...@@ -199,8 +199,7 @@ void print_lambda_body_vector (FILE *, lambda_body_vector); ...@@ -199,8 +199,7 @@ void print_lambda_body_vector (FILE *, lambda_body_vector);
lambda_loopnest gcc_loopnest_to_lambda_loopnest (struct loops *, lambda_loopnest gcc_loopnest_to_lambda_loopnest (struct loops *,
struct loop *, struct loop *,
VEC(tree,heap) **, VEC(tree,heap) **,
VEC(tree,heap) **, VEC(tree,heap) **);
bool);
void lambda_loopnest_to_gcc_loopnest (struct loop *, void lambda_loopnest_to_gcc_loopnest (struct loop *,
VEC(tree,heap) *, VEC(tree,heap) *, VEC(tree,heap) *, VEC(tree,heap) *,
lambda_loopnest, lambda_trans_matrix); lambda_loopnest, lambda_trans_matrix);
......
...@@ -18,7 +18,6 @@ int foo(int N, int *res) ...@@ -18,7 +18,6 @@ int foo(int N, int *res)
} }
*res = sum + N; *res = sum + N;
} }
/* { dg-final { scan-tree-dump-times "converted loop nest to perfect /* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 1 "ltrans"} } */
loop nest" 1 "ltrans"} } */
/* { dg-final { scan-tree-dump-times "transformed loop" 1 "ltrans"} } */ /* { dg-final { scan-tree-dump-times "transformed loop" 1 "ltrans"} } */
/* { dg-final { cleanup-tree-dump "ltrans" } } */ /* { dg-final { cleanup-tree-dump "ltrans" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-linear -fdump-tree-ltrans-all" } */
/* { dg-require-effective-target size32plus } */
int foo()
{
int x[2][2], y[2];
int i, n, s;
/* This is a reduction: there is a scalar dependence that cannot be
removed by rewriting IVs. This code cannot and should not be
transformed into a perfect loop. */
for (n = 0; n < 2; n++)
{
s = 0;
for (i = 0; i < 2; i++)
s += x[n][i]*y[i];
s += 1;
}
return s;
}
/* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 0 "ltrans"} } */
/* { dg-final { cleanup-tree-dump "ltrans" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-linear -fdump-tree-ltrans-all" } */
/* { dg-require-effective-target size32plus } */
int foo(int *p, int n)
{
int i, j, k = 0;
/* This is a reduction: there is a scalar dependence that cannot be
removed by rewriting IVs. This code cannot and should not be
transformed into a perfect loop. */
for (i = 0; i < 2; ++i, p += n)
for (j = 0; j < 2; ++j)
k += p[j];
return k;
}
/* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 0 "ltrans"} } */
/* { dg-final { cleanup-tree-dump "ltrans" } } */
...@@ -241,6 +241,7 @@ try_interchange_loops (lambda_trans_matrix trans, ...@@ -241,6 +241,7 @@ try_interchange_loops (lambda_trans_matrix trans,
void void
linear_transform_loops (struct loops *loops) linear_transform_loops (struct loops *loops)
{ {
bool modified = false;
unsigned int i; unsigned int i;
VEC(tree,heap) *oldivs = NULL; VEC(tree,heap) *oldivs = NULL;
VEC(tree,heap) *invariants = NULL; VEC(tree,heap) *invariants = NULL;
...@@ -255,7 +256,6 @@ linear_transform_loops (struct loops *loops) ...@@ -255,7 +256,6 @@ linear_transform_loops (struct loops *loops)
lambda_loopnest before, after; lambda_loopnest before, after;
lambda_trans_matrix trans; lambda_trans_matrix trans;
bool problem = false; bool problem = false;
bool need_perfect_nest = false;
/* If it's not a loop nest, we don't want it. /* If it's not a loop nest, we don't want it.
We also don't handle sibling loops properly, We also don't handle sibling loops properly,
which are loops of the following form: which are loops of the following form:
...@@ -319,13 +319,9 @@ linear_transform_loops (struct loops *loops) ...@@ -319,13 +319,9 @@ linear_transform_loops (struct loops *loops)
continue; continue;
} }
if (!perfect_nest_p (loop_nest)) before = gcc_loopnest_to_lambda_loopnest (loops, loop_nest, &oldivs,
need_perfect_nest = true; &invariants);
before = gcc_loopnest_to_lambda_loopnest (loops,
loop_nest, &oldivs,
&invariants,
need_perfect_nest);
if (!before) if (!before)
continue; continue;
...@@ -345,6 +341,7 @@ linear_transform_loops (struct loops *loops) ...@@ -345,6 +341,7 @@ linear_transform_loops (struct loops *loops)
lambda_loopnest_to_gcc_loopnest (loop_nest, oldivs, invariants, lambda_loopnest_to_gcc_loopnest (loop_nest, oldivs, invariants,
after, trans); after, trans);
modified = true;
if (dump_file) if (dump_file)
fprintf (dump_file, "Successfully transformed loop.\n"); fprintf (dump_file, "Successfully transformed loop.\n");
...@@ -356,5 +353,7 @@ linear_transform_loops (struct loops *loops) ...@@ -356,5 +353,7 @@ linear_transform_loops (struct loops *loops)
VEC_free (tree, heap, oldivs); VEC_free (tree, heap, oldivs);
VEC_free (tree, heap, invariants); VEC_free (tree, heap, invariants);
scev_reset (); scev_reset ();
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa_full_phi);
if (modified)
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa_full_phi);
} }
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