re PR tree-optimization/55079 (false positive -Warray-bounds (also seen at -O3 bootstrap))
PR middle-end/55079 * tree-ssa-loop-niter.c (number_of_iterations_exit): Update MAX field if NITER was folded to contant. (record_estimate): Sanity check. * tree-ssa-loop-ivcanon.c (remove_exits_and_undefined_stmts): New function. (remove_redundant_iv_test): New function. (loops_to_unloop, loops_to_unloop_nunroll): New static vars. (unloop_loops): Break out from ... (try_unroll_loop_completely): ... here; Pass in MAXITER; use remove_exits_and_undefined_stmts; do not unloop. (canonicalize_loop_induction_variables): Compute MAXITER; use remove_redundant_iv_test; remove loop_close_ssa_invalidated and irred_invalidated arguments. (canonicalize_induction_variables): Compute fresh bound estimates; unloop; walk from innermost. (tree_unroll_loops_completely): Likewise. * gcc.dg/tree-ssa/cunroll-10.c: New testcase. * gcc.dg/tree-ssa/cunroll-9.c: New testcase. From-SVN: r193098
This commit is contained in:
parent
7ee840b6bf
commit
f2a1b46987
6 changed files with 286 additions and 70 deletions
|
@ -1,3 +1,23 @@
|
|||
2012-11-02 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
PR middle-end/55079
|
||||
* tree-ssa-loop-niter.c (number_of_iterations_exit): Update
|
||||
MAX field if NITER was folded to contant.
|
||||
(record_estimate): Sanity check.
|
||||
* tree-ssa-loop-ivcanon.c (remove_exits_and_undefined_stmts): New
|
||||
function.
|
||||
(remove_redundant_iv_test): New function.
|
||||
(loops_to_unloop, loops_to_unloop_nunroll): New static vars.
|
||||
(unloop_loops): Break out from ...
|
||||
(try_unroll_loop_completely): ... here; Pass in MAXITER; use
|
||||
remove_exits_and_undefined_stmts; do not unloop.
|
||||
(canonicalize_loop_induction_variables): Compute MAXITER;
|
||||
use remove_redundant_iv_test; remove loop_close_ssa_invalidated
|
||||
and irred_invalidated arguments.
|
||||
(canonicalize_induction_variables): Compute fresh bound estimates;
|
||||
unloop; walk from innermost.
|
||||
(tree_unroll_loops_completely): Likewise.
|
||||
|
||||
2012-11-02 Vladimir Makarov <vmakarov@redhat.com>
|
||||
|
||||
PR middle-end/55130
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2012-11-02 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* gcc.dg/tree-ssa/cunroll-10.c: New testcase.
|
||||
* gcc.dg/tree-ssa/cunroll-9.c: New testcase.
|
||||
|
||||
2012-11-02 Vladimir Makarov <vmakarov@redhat.com>
|
||||
|
||||
PR middle-end/55130
|
||||
|
|
13
gcc/testsuite/gcc.dg/tree-ssa/cunroll-10.c
Normal file
13
gcc/testsuite/gcc.dg/tree-ssa/cunroll-10.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -Warray-bounds -fdump-tree-cunroll-details" } */
|
||||
int a[3];
|
||||
int b[4];
|
||||
main()
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<4;i++)
|
||||
if (b[i]==2)
|
||||
a[i]++;
|
||||
}
|
||||
/* { dg-final { scan-tree-dump-times "Forced statement unreachable" 2 "cunroll" } } */
|
||||
/* { dg-final { cleanup-tree-dump "cunroll" } } */
|
22
gcc/testsuite/gcc.dg/tree-ssa/cunroll-9.c
Normal file
22
gcc/testsuite/gcc.dg/tree-ssa/cunroll-9.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-cunrolli" } */
|
||||
void abort (void);
|
||||
int a[10];
|
||||
int b[11];
|
||||
t (int n)
|
||||
{
|
||||
int i;
|
||||
int sum = 0;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (i > 1000)
|
||||
abort ();
|
||||
if (q ())
|
||||
sum += a[i];
|
||||
else
|
||||
sum += b[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
/* { dg-final { scan-tree-dump-times 1 "Removed pointless exit:" "cunroli" } } */
|
||||
/* { dg-final { cleanup-tree-dump "cunroli" } } */
|
|
@ -389,33 +389,192 @@ loop_edge_to_cancel (struct loop *loop)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Tries to unroll LOOP completely, i.e. NITER times.
|
||||
UL determines which loops we are allowed to unroll.
|
||||
EXIT is the exit of the loop that should be eliminated.
|
||||
/* Remove all tests for exits that are known to be taken after LOOP was
|
||||
peeled NPEELED times. Put gcc_unreachable before every statement
|
||||
known to not be executed. */
|
||||
|
||||
static bool
|
||||
remove_exits_and_undefined_stmts (struct loop *loop, unsigned int npeeled)
|
||||
{
|
||||
struct nb_iter_bound *elt;
|
||||
bool changed = false;
|
||||
|
||||
for (elt = loop->bounds; elt; elt = elt->next)
|
||||
{
|
||||
/* If statement is known to be undefined after peeling, turn it
|
||||
into unreachable (or trap when debugging experience is supposed
|
||||
to be good). */
|
||||
if (!elt->is_exit
|
||||
&& elt->bound.ult (double_int::from_uhwi (npeeled)))
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (elt->stmt);
|
||||
gimple stmt = gimple_build_call
|
||||
(builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
|
||||
|
||||
gimple_set_location (stmt, gimple_location (elt->stmt));
|
||||
gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
|
||||
changed = true;
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Forced statement unreachable: ");
|
||||
print_gimple_stmt (dump_file, elt->stmt, 0, 0);
|
||||
}
|
||||
}
|
||||
/* If we know the exit will be taken after peeling, update. */
|
||||
else if (elt->is_exit
|
||||
&& elt->bound.ule (double_int::from_uhwi (npeeled)))
|
||||
{
|
||||
basic_block bb = gimple_bb (elt->stmt);
|
||||
edge exit_edge = EDGE_SUCC (bb, 0);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Forced exit to be taken: ");
|
||||
print_gimple_stmt (dump_file, elt->stmt, 0, 0);
|
||||
}
|
||||
if (!loop_exit_edge_p (loop, exit_edge))
|
||||
exit_edge = EDGE_SUCC (bb, 1);
|
||||
gcc_checking_assert (loop_exit_edge_p (loop, exit_edge));
|
||||
if (exit_edge->flags & EDGE_TRUE_VALUE)
|
||||
gimple_cond_make_true (elt->stmt);
|
||||
else
|
||||
gimple_cond_make_false (elt->stmt);
|
||||
update_stmt (elt->stmt);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* Remove all exits that are known to be never taken because of the loop bound
|
||||
discovered. */
|
||||
|
||||
static bool
|
||||
remove_redundant_iv_tests (struct loop *loop)
|
||||
{
|
||||
struct nb_iter_bound *elt;
|
||||
bool changed = false;
|
||||
|
||||
if (!loop->any_upper_bound)
|
||||
return false;
|
||||
for (elt = loop->bounds; elt; elt = elt->next)
|
||||
{
|
||||
/* Exit is pointless if it won't be taken before loop reaches
|
||||
upper bound. */
|
||||
if (elt->is_exit && loop->any_upper_bound
|
||||
&& loop->nb_iterations_upper_bound.ult (elt->bound))
|
||||
{
|
||||
basic_block bb = gimple_bb (elt->stmt);
|
||||
edge exit_edge = EDGE_SUCC (bb, 0);
|
||||
struct tree_niter_desc niter;
|
||||
|
||||
if (!loop_exit_edge_p (loop, exit_edge))
|
||||
exit_edge = EDGE_SUCC (bb, 1);
|
||||
|
||||
/* Only when we know the actual number of iterations, not
|
||||
just a bound, we can remove the exit. */
|
||||
if (!number_of_iterations_exit (loop, exit_edge,
|
||||
&niter, false, false))
|
||||
gcc_unreachable ();
|
||||
if (!integer_onep (niter.assumptions)
|
||||
|| !integer_zerop (niter.may_be_zero)
|
||||
|| !niter.niter
|
||||
|| TREE_CODE (niter.niter) != INTEGER_CST
|
||||
|| !loop->nb_iterations_upper_bound.ult
|
||||
(tree_to_double_int (niter.niter)))
|
||||
continue;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Removed pointless exit: ");
|
||||
print_gimple_stmt (dump_file, elt->stmt, 0, 0);
|
||||
}
|
||||
if (exit_edge->flags & EDGE_TRUE_VALUE)
|
||||
gimple_cond_make_false (elt->stmt);
|
||||
else
|
||||
gimple_cond_make_true (elt->stmt);
|
||||
update_stmt (elt->stmt);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* Stores loops that will be unlooped after we process whole loop tree. */
|
||||
static VEC(loop_p, heap) *loops_to_unloop;
|
||||
static VEC(int, heap) *loops_to_unloop_nunroll;
|
||||
|
||||
/* Cancel all fully unrolled loops by putting __builtin_unreachable
|
||||
on the latch edge.
|
||||
We do it after all unrolling since unlooping moves basic blocks
|
||||
across loop boundaries trashing loop closed SSA form as well
|
||||
as SCEV info needed to be intact during unrolling.
|
||||
|
||||
IRRED_INVALIDATED is used to bookkeep if information about
|
||||
irreducible regions may become invalid as a result
|
||||
of the transformation.
|
||||
LOOP_CLOSED_SSA_INVALIDATED is used to bookkepp the case
|
||||
when we need to go into loop closed SSA form. */
|
||||
|
||||
void
|
||||
unloop_loops (bitmap loop_closed_ssa_invalidated,
|
||||
bool *irred_invalidated)
|
||||
{
|
||||
while (VEC_length (loop_p, loops_to_unloop))
|
||||
{
|
||||
struct loop *loop = VEC_pop (loop_p, loops_to_unloop);
|
||||
int n_unroll = VEC_pop (int, loops_to_unloop_nunroll);
|
||||
basic_block latch = loop->latch;
|
||||
edge latch_edge = loop_latch_edge (loop);
|
||||
int flags = latch_edge->flags;
|
||||
location_t locus = latch_edge->goto_locus;
|
||||
gimple stmt;
|
||||
gimple_stmt_iterator gsi;
|
||||
|
||||
remove_exits_and_undefined_stmts (loop, n_unroll);
|
||||
|
||||
/* Unloop destroys the latch edge. */
|
||||
unloop (loop, irred_invalidated, loop_closed_ssa_invalidated);
|
||||
|
||||
/* Create new basic block for the latch edge destination and wire
|
||||
it in. */
|
||||
stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
|
||||
latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
|
||||
latch_edge->probability = 0;
|
||||
latch_edge->count = 0;
|
||||
latch_edge->flags |= flags;
|
||||
latch_edge->goto_locus = locus;
|
||||
|
||||
latch_edge->dest->loop_father = current_loops->tree_root;
|
||||
latch_edge->dest->count = 0;
|
||||
latch_edge->dest->frequency = 0;
|
||||
set_immediate_dominator (CDI_DOMINATORS, latch_edge->dest, latch_edge->src);
|
||||
|
||||
gsi = gsi_start_bb (latch_edge->dest);
|
||||
gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
|
||||
}
|
||||
VEC_free (loop_p, heap, loops_to_unloop);
|
||||
loops_to_unloop = NULL;
|
||||
VEC_free (int, heap, loops_to_unloop_nunroll);
|
||||
loops_to_unloop_nunroll = NULL;
|
||||
}
|
||||
|
||||
/* Tries to unroll LOOP completely, i.e. NITER times.
|
||||
UL determines which loops we are allowed to unroll.
|
||||
EXIT is the exit of the loop that should be eliminated.
|
||||
MAXITER specfy bound on number of iterations, -1 if it is
|
||||
not known or too large for HOST_WIDE_INT. */
|
||||
|
||||
static bool
|
||||
try_unroll_loop_completely (struct loop *loop,
|
||||
edge exit, tree niter,
|
||||
enum unroll_level ul,
|
||||
bool *irred_invalidated,
|
||||
bitmap loop_closed_ssa_invalidated)
|
||||
HOST_WIDE_INT maxiter)
|
||||
{
|
||||
unsigned HOST_WIDE_INT n_unroll, ninsns, max_unroll, unr_insns;
|
||||
gimple cond;
|
||||
struct loop_size size;
|
||||
bool n_unroll_found = false;
|
||||
HOST_WIDE_INT maxiter;
|
||||
basic_block latch;
|
||||
edge latch_edge;
|
||||
location_t locus;
|
||||
int flags;
|
||||
gimple stmt;
|
||||
gimple_stmt_iterator gsi;
|
||||
edge edge_to_cancel = NULL;
|
||||
int num = loop->num;
|
||||
|
||||
|
@ -445,7 +604,6 @@ try_unroll_loop_completely (struct loop *loop,
|
|||
exit = NULL;
|
||||
|
||||
/* See if we can improve our estimate by using recorded loop bounds. */
|
||||
maxiter = max_loop_iterations_int (loop);
|
||||
if (maxiter >= 0
|
||||
&& (!n_unroll_found || (unsigned HOST_WIDE_INT)maxiter < n_unroll))
|
||||
{
|
||||
|
@ -545,6 +703,7 @@ try_unroll_loop_completely (struct loop *loop,
|
|||
free_original_copy_tables ();
|
||||
}
|
||||
|
||||
|
||||
/* Remove the conditional from the last copy of the loop. */
|
||||
if (edge_to_cancel)
|
||||
{
|
||||
|
@ -557,37 +716,10 @@ try_unroll_loop_completely (struct loop *loop,
|
|||
/* Do not remove the path. Doing so may remove outer loop
|
||||
and confuse bookkeeping code in tree_unroll_loops_completelly. */
|
||||
}
|
||||
/* We did not manage to cancel the loop.
|
||||
The loop latch remains reachable even if it will never be reached
|
||||
at runtime. We must redirect it to somewhere, so create basic
|
||||
block containg __builtin_unreachable call for this reason. */
|
||||
else
|
||||
{
|
||||
latch = loop->latch;
|
||||
latch_edge = loop_latch_edge (loop);
|
||||
flags = latch_edge->flags;
|
||||
locus = latch_edge->goto_locus;
|
||||
|
||||
/* Unloop destroys the latch edge. */
|
||||
unloop (loop, irred_invalidated, loop_closed_ssa_invalidated);
|
||||
|
||||
/* Create new basic block for the latch edge destination and wire
|
||||
it in. */
|
||||
stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
|
||||
latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
|
||||
latch_edge->probability = 0;
|
||||
latch_edge->count = 0;
|
||||
latch_edge->flags |= flags;
|
||||
latch_edge->goto_locus = locus;
|
||||
|
||||
latch_edge->dest->loop_father = current_loops->tree_root;
|
||||
latch_edge->dest->count = 0;
|
||||
latch_edge->dest->frequency = 0;
|
||||
set_immediate_dominator (CDI_DOMINATORS, latch_edge->dest, latch_edge->src);
|
||||
|
||||
gsi = gsi_start_bb (latch_edge->dest);
|
||||
gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
|
||||
}
|
||||
/* Store the loop for later unlooping and exit removal. */
|
||||
VEC_safe_push (loop_p, heap, loops_to_unloop, loop);
|
||||
VEC_safe_push (int, heap, loops_to_unloop_nunroll, n_unroll);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
|
@ -614,19 +746,17 @@ try_unroll_loop_completely (struct loop *loop,
|
|||
CREATE_IV is true if we may create a new iv. UL determines
|
||||
which loops we are allowed to completely unroll. If TRY_EVAL is true, we try
|
||||
to determine the number of iterations of a loop by direct evaluation.
|
||||
Returns true if cfg is changed.
|
||||
|
||||
IRRED_INVALIDATED is used to keep if irreducible reginos needs to be recomputed. */
|
||||
Returns true if cfg is changed. */
|
||||
|
||||
static bool
|
||||
canonicalize_loop_induction_variables (struct loop *loop,
|
||||
bool create_iv, enum unroll_level ul,
|
||||
bool try_eval,
|
||||
bool *irred_invalidated,
|
||||
bitmap loop_closed_ssa_invalidated)
|
||||
bool try_eval)
|
||||
{
|
||||
edge exit = NULL;
|
||||
tree niter;
|
||||
HOST_WIDE_INT maxiter;
|
||||
bool modified = false;
|
||||
|
||||
niter = number_of_latch_executions (loop);
|
||||
if (TREE_CODE (niter) == INTEGER_CST)
|
||||
|
@ -657,6 +787,9 @@ canonicalize_loop_induction_variables (struct loop *loop,
|
|||
if (niter && TREE_CODE (niter) == INTEGER_CST)
|
||||
record_niter_bound (loop, tree_to_double_int (niter), false, true);
|
||||
|
||||
/* Force re-computation of loop bounds so we can remove redundant exits. */
|
||||
maxiter = max_loop_iterations_int (loop);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS)
|
||||
&& TREE_CODE (niter) == INTEGER_CST)
|
||||
{
|
||||
|
@ -665,21 +798,25 @@ canonicalize_loop_induction_variables (struct loop *loop,
|
|||
fprintf (dump_file, " times.\n");
|
||||
}
|
||||
if (dump_file && (dump_flags & TDF_DETAILS)
|
||||
&& max_loop_iterations_int (loop) >= 0)
|
||||
&& maxiter >= 0)
|
||||
{
|
||||
fprintf (dump_file, "Loop %d iterates at most %i times.\n", loop->num,
|
||||
(int)max_loop_iterations_int (loop));
|
||||
(int)maxiter);
|
||||
}
|
||||
|
||||
if (try_unroll_loop_completely (loop, exit, niter, ul, irred_invalidated,
|
||||
loop_closed_ssa_invalidated))
|
||||
/* Remove exits that are known to be never taken based on loop bound.
|
||||
Needs to be called after compilation of max_loop_iterations_int that
|
||||
populates the loop bounds. */
|
||||
modified |= remove_redundant_iv_tests (loop);
|
||||
|
||||
if (try_unroll_loop_completely (loop, exit, niter, ul, maxiter))
|
||||
return true;
|
||||
|
||||
if (create_iv
|
||||
&& niter && !chrec_contains_undetermined (niter))
|
||||
create_canonical_iv (loop, exit, niter);
|
||||
|
||||
return false;
|
||||
return modified;
|
||||
}
|
||||
|
||||
/* The main entry point of the pass. Adds canonical induction variables
|
||||
|
@ -694,16 +831,18 @@ canonicalize_induction_variables (void)
|
|||
bool irred_invalidated = false;
|
||||
bitmap loop_closed_ssa_invalidated = BITMAP_ALLOC (NULL);
|
||||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
free_numbers_of_iterations_estimates ();
|
||||
estimate_numbers_of_iterations ();
|
||||
|
||||
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
|
||||
{
|
||||
changed |= canonicalize_loop_induction_variables (loop,
|
||||
true, UL_SINGLE_ITER,
|
||||
true,
|
||||
&irred_invalidated,
|
||||
loop_closed_ssa_invalidated);
|
||||
true);
|
||||
}
|
||||
gcc_assert (!need_ssa_update_p (cfun));
|
||||
|
||||
unloop_loops (loop_closed_ssa_invalidated, &irred_invalidated);
|
||||
if (irred_invalidated
|
||||
&& loops_state_satisfies_p (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS))
|
||||
mark_irreducible_loops ();
|
||||
|
@ -822,7 +961,10 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
|||
if (loops_state_satisfies_p (LOOP_CLOSED_SSA))
|
||||
loop_closed_ssa_invalidated = BITMAP_ALLOC (NULL);
|
||||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
free_numbers_of_iterations_estimates ();
|
||||
estimate_numbers_of_iterations ();
|
||||
|
||||
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
|
||||
{
|
||||
struct loop *loop_father = loop_outer (loop);
|
||||
|
||||
|
@ -835,8 +977,7 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
|||
ul = UL_NO_GROWTH;
|
||||
|
||||
if (canonicalize_loop_induction_variables
|
||||
(loop, false, ul, !flag_tree_loop_ivcanon,
|
||||
&irred_invalidated, loop_closed_ssa_invalidated))
|
||||
(loop, false, ul, !flag_tree_loop_ivcanon))
|
||||
{
|
||||
changed = true;
|
||||
/* If we'll continue unrolling, we need to propagate constants
|
||||
|
@ -856,8 +997,16 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
|||
struct loop **iter;
|
||||
unsigned i;
|
||||
|
||||
/* We can not use TODO_update_ssa_no_phi because VOPS gets confused. */
|
||||
/* Be sure to skip unlooped loops while procesing father_stack
|
||||
array. */
|
||||
FOR_EACH_VEC_ELT (loop_p, loops_to_unloop, i, iter)
|
||||
(*iter)->aux = NULL;
|
||||
FOR_EACH_VEC_ELT (loop_p, father_stack, i, iter)
|
||||
if (!(*iter)->aux)
|
||||
*iter = NULL;
|
||||
unloop_loops (loop_closed_ssa_invalidated, &irred_invalidated);
|
||||
|
||||
/* We can not use TODO_update_ssa_no_phi because VOPS gets confused. */
|
||||
if (loop_closed_ssa_invalidated
|
||||
&& !bitmap_empty_p (loop_closed_ssa_invalidated))
|
||||
rewrite_into_loop_closed_ssa (loop_closed_ssa_invalidated,
|
||||
|
@ -867,14 +1016,15 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
|||
|
||||
/* Propagate the constants within the new basic blocks. */
|
||||
FOR_EACH_VEC_ELT (loop_p, father_stack, i, iter)
|
||||
{
|
||||
unsigned j;
|
||||
basic_block *body = get_loop_body_in_dom_order (*iter);
|
||||
for (j = 0; j < (*iter)->num_nodes; j++)
|
||||
propagate_constants_for_unrolling (body[j]);
|
||||
free (body);
|
||||
(*iter)->aux = NULL;
|
||||
}
|
||||
if (*iter)
|
||||
{
|
||||
unsigned j;
|
||||
basic_block *body = get_loop_body_in_dom_order (*iter);
|
||||
for (j = 0; j < (*iter)->num_nodes; j++)
|
||||
propagate_constants_for_unrolling (body[j]);
|
||||
free (body);
|
||||
(*iter)->aux = NULL;
|
||||
}
|
||||
VEC_truncate (loop_p, father_stack, 0);
|
||||
|
||||
/* This will take care of removing completely unrolled loops
|
||||
|
|
|
@ -1880,6 +1880,10 @@ number_of_iterations_exit (struct loop *loop, edge exit,
|
|||
|
||||
fold_undefer_and_ignore_overflow_warnings ();
|
||||
|
||||
/* If NITER has simplified into a constant, update MAX. */
|
||||
if (TREE_CODE (niter->niter) == INTEGER_CST)
|
||||
niter->max = tree_to_double_int (niter->niter);
|
||||
|
||||
if (integer_onep (niter->assumptions))
|
||||
return true;
|
||||
|
||||
|
@ -2556,6 +2560,8 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound,
|
|||
real number of iterations. */
|
||||
if (TREE_CODE (bound) != INTEGER_CST)
|
||||
realistic = false;
|
||||
else
|
||||
gcc_checking_assert (i_bound == tree_to_double_int (bound));
|
||||
if (!upper && !realistic)
|
||||
return;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue