Commit 05322355 by Jan Hubicka Committed by Jan Hubicka

re PR tree-optimization/54937 (Invalid loop bound estimate)


	PR middle-end/54937
	* tree-ssa-loop-niter.c (record_estimate): Do not try to lower
	the bound of non-is_exit statements.
	(maybe_lower_iteration_bound): Do it here.
	(estimate_numbers_of_iterations_loop): Call it.
	* gcc.c-torture/execute/pr54937.c: New testcase.
	* gcc.dg/tree-ssa/cunroll-2.c: Update.

From-SVN: r192710
parent 1a7de201
2012-10-23 Jan Hubicka <jh@suse.cz> 2012-10-23 Jan Hubicka <jh@suse.cz>
PR middle-end/54937
* tree-ssa-loop-niter.c (record_estimate): Do not try to lower
the bound of non-is_exit statements.
(maybe_lower_iteration_bound): Do it here.
(estimate_numbers_of_iterations_loop): Call it.
2012-10-23 Jan Hubicka <jh@suse.cz>
PR middle-end/54967 PR middle-end/54967
* cfgloopmanip.c (fix_bb_placements): Add loop_closed_ssa_invalidated; * cfgloopmanip.c (fix_bb_placements): Add loop_closed_ssa_invalidated;
track basic blocks that moved out of their loops. track basic blocks that moved out of their loops.
2012-10-23 Jan Hubicka <jh@suse.cz> 2012-10-23 Jan Hubicka <jh@suse.cz>
PR middle-end/54937
* gcc.c-torture/execute/pr54937.c: New testcase.
* gcc.dg/tree-ssa/cunroll-2.c: Update.
2012-10-23 Jan Hubicka <jh@suse.cz>
PR middle-end/54967 PR middle-end/54967
* gfortran.dg/pr54967.f90: New testcase. * gfortran.dg/pr54967.f90: New testcase.
......
void exit (int);
void abort (void);
int a[1];
void (*terminate_me)(int);
__attribute__((noinline,noclone))
t(int c)
{ int i;
for (i=0;i<c;i++)
{
if (i)
terminate_me(0);
a[i]=0;
}
}
main()
{
terminate_me = exit;
t(100);
abort();
}
...@@ -12,5 +12,5 @@ test(int c) ...@@ -12,5 +12,5 @@ test(int c)
} }
} }
/* We are not able to get rid of the final conditional because the loop has two exits. */ /* We are not able to get rid of the final conditional because the loop has two exits. */
/* { dg-final { scan-tree-dump "Unrolled loop 1 completely .duplicated 2 times.." "cunroll"} } */ /* { dg-final { scan-tree-dump "Unrolled loop 1 completely .duplicated 1 times.." "cunroll"} } */
/* { dg-final { cleanup-tree-dump "cunroll" } } */ /* { dg-final { cleanup-tree-dump "cunroll" } } */
...@@ -2535,7 +2535,6 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound, ...@@ -2535,7 +2535,6 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound,
gimple at_stmt, bool is_exit, bool realistic, bool upper) gimple at_stmt, bool is_exit, bool realistic, bool upper)
{ {
double_int delta; double_int delta;
edge exit;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
...@@ -2570,14 +2569,10 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound, ...@@ -2570,14 +2569,10 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound,
} }
/* Update the number of iteration estimates according to the bound. /* Update the number of iteration estimates according to the bound.
If at_stmt is an exit or dominates the single exit from the loop, If at_stmt is an exit then the loop latch is executed at most BOUND times,
then the loop latch is executed at most BOUND times, otherwise otherwise it can be executed BOUND + 1 times. We will lower the estimate
it can be executed BOUND + 1 times. */ later if such statement must be executed on last iteration */
exit = single_exit (loop); if (is_exit)
if (is_exit
|| (exit != NULL
&& dominated_by_p (CDI_DOMINATORS,
exit->src, gimple_bb (at_stmt))))
delta = double_int_zero; delta = double_int_zero;
else else
delta = double_int_one; delta = double_int_one;
...@@ -2953,6 +2948,110 @@ gcov_type_to_double_int (gcov_type val) ...@@ -2953,6 +2948,110 @@ gcov_type_to_double_int (gcov_type val)
return ret; return ret;
} }
/* See if every path cross the loop goes through a statement that is known
to not execute at the last iteration. In that case we can decrese iteration
count by 1. */
static void
maybe_lower_iteration_bound (struct loop *loop)
{
pointer_set_t *not_executed_last_iteration = pointer_set_create ();
struct nb_iter_bound *elt;
bool found_exit = false;
VEC (basic_block, heap) *queue = NULL;
bitmap visited;
/* Collect all statements with interesting (i.e. lower than
nb_iterations_upper_bound) bound on them.
TODO: Due to the way record_estimate choose estimates to store, the bounds
will be always nb_iterations_upper_bound-1. We can change this to record
also statements not dominating the loop latch and update the walk bellow
to the shortest path algorthm. */
for (elt = loop->bounds; elt; elt = elt->next)
{
if (!elt->is_exit
&& elt->bound.ult (loop->nb_iterations_upper_bound))
{
if (!not_executed_last_iteration)
not_executed_last_iteration = pointer_set_create ();
pointer_set_insert (not_executed_last_iteration, elt->stmt);
}
}
if (!not_executed_last_iteration)
return;
/* Start DFS walk in the loop header and see if we can reach the
loop latch or any of the exits (including statements with side
effects that may terminate the loop otherwise) without visiting
any of the statements known to have undefined effect on the last
iteration. */
VEC_safe_push (basic_block, heap, queue, loop->header);
visited = BITMAP_ALLOC (NULL);
bitmap_set_bit (visited, loop->header->index);
found_exit = false;
do
{
basic_block bb = VEC_pop (basic_block, queue);
gimple_stmt_iterator gsi;
bool stmt_found = false;
/* Loop for possible exits and statements bounding the execution. */
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
if (pointer_set_contains (not_executed_last_iteration, stmt))
{
stmt_found = true;
break;
}
if (gimple_has_side_effects (stmt))
{
found_exit = true;
break;
}
}
if (found_exit)
break;
/* If no bounding statement is found, continue the walk. */
if (!stmt_found)
{
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (loop_exit_edge_p (loop, e)
|| e == loop_latch_edge (loop))
{
found_exit = true;
break;
}
if (bitmap_set_bit (visited, e->dest->index))
VEC_safe_push (basic_block, heap, queue, e->dest);
}
}
}
while (VEC_length (basic_block, queue) && !found_exit);
/* If every path through the loop reach bounding statement before exit,
then we know the last iteration of the loop will have undefined effect
and we can decrease number of iterations. */
if (!found_exit)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Reducing loop iteration estimate by 1; "
"undefined statement must be executed at the last iteration.\n");
record_niter_bound (loop, loop->nb_iterations_upper_bound - double_int_one,
false, true);
}
BITMAP_FREE (visited);
VEC_free (basic_block, heap, queue);
}
/* Records estimates on numbers of iterations of LOOP. If USE_UNDEFINED_P /* Records estimates on numbers of iterations of LOOP. If USE_UNDEFINED_P
is true also use estimates derived from undefined behavior. */ is true also use estimates derived from undefined behavior. */
...@@ -2996,6 +3095,8 @@ estimate_numbers_of_iterations_loop (struct loop *loop) ...@@ -2996,6 +3095,8 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
infer_loop_bounds_from_undefined (loop); infer_loop_bounds_from_undefined (loop);
maybe_lower_iteration_bound (loop);
/* If we have a measured profile, use it to estimate the number of /* If we have a measured profile, use it to estimate the number of
iterations. */ iterations. */
if (loop->header->count != 0) if (loop->header->count != 0)
......
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