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
This commit is contained in:
Jan Hubicka 2012-10-23 12:00:19 +02:00 committed by Jan Hubicka
parent 1a7de2015d
commit 053223551f
5 changed files with 147 additions and 10 deletions

View File

@ -1,3 +1,11 @@
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

View File

@ -1,3 +1,9 @@
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

View File

@ -0,0 +1,22 @@
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();
}

View File

@ -12,5 +12,5 @@ test(int c)
}
}
/* 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" } } */

View File

@ -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)
{
double_int delta;
edge exit;
if (dump_file && (dump_flags & TDF_DETAILS))
{
@ -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.
If at_stmt is an exit or dominates the single exit from the loop,
then the loop latch is executed at most BOUND times, otherwise
it can be executed BOUND + 1 times. */
exit = single_exit (loop);
if (is_exit
|| (exit != NULL
&& dominated_by_p (CDI_DOMINATORS,
exit->src, gimple_bb (at_stmt))))
If at_stmt is an exit then the loop latch is executed at most BOUND times,
otherwise it can be executed BOUND + 1 times. We will lower the estimate
later if such statement must be executed on last iteration */
if (is_exit)
delta = double_int_zero;
else
delta = double_int_one;
@ -2953,6 +2948,110 @@ gcov_type_to_double_int (gcov_type val)
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
is true also use estimates derived from undefined behavior. */
@ -2996,6 +3095,8 @@ estimate_numbers_of_iterations_loop (struct loop *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
iterations. */
if (loop->header->count != 0)