+2019-11-25 Richard Biener <rguenther@suse.de>
+
+ * cfgloop.h (get_loop_exit_edges): Add extra parameter denoting
+ loop body, defaulted to NULL.
+ (single_likely_exit): Add exit vector argument
+ * tree-ssa-loop-niter.h (loop_only_exit_p): Add loop body argument.
+ (number_of_iterations_exit): Likewise.
+ (number_of_iterations_exit_assumptions): Likewise.
+ * cfgloop.c (get_loop_exit_edges): Use passed in loop body
+ if not NULL.
+ * cfgloopanal.c (single_likely_exit): Use passed in exit vector.
+ * tree-ssa-loop-ivcanon.c (canonicalize_loop_induction_variables):
+ Compute exit vector around call to single_likely_exit.
+ * tree-ssa-loop-ivopts.c (tree_ssa_iv_optimize_loop): Pass down
+ loop body to loop_only_exit_p.
+ * tree-ssa-loop-niter.c (loop_only_exit_p): Get loop body from
+ caller.
+ (number_of_iterations_exit_assumptions): Get loop body from caller
+ if not NULL.
+ (number_of_iterations_exit): Pass through new loop body arg.
+ (infer_loop_bounds_from_undefined): Get loop body from caller.
+ (estimate_numbers_of_iterations): Compute loop body once.
+
2019-11-25 Richard Biener <rguenther@suse.de>
* cfganal.c (pre_and_rev_post_order_compute_fn): Use an
/* Returns the list of the exit edges of a LOOP. */
vec<edge>
-get_loop_exit_edges (const class loop *loop)
+get_loop_exit_edges (const class loop *loop, basic_block *body)
{
vec<edge> edges = vNULL;
edge e;
unsigned i;
- basic_block *body;
edge_iterator ei;
struct loop_exit *exit;
}
else
{
- body = get_loop_body (loop);
+ bool body_from_caller = true;
+ if (!body)
+ {
+ body = get_loop_body (loop);
+ body_from_caller = false;
+ }
for (i = 0; i < loop->num_nodes; i++)
FOR_EACH_EDGE (e, ei, body[i]->succs)
{
if (!flow_bb_inside_loop_p (loop, e->dest))
edges.safe_push (e);
}
- free (body);
+ if (!body_from_caller)
+ free (body);
}
return edges;
extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
int (*) (const void *, const void *, void *));
-extern vec<edge> get_loop_exit_edges (const class loop *);
+extern vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
extern edge single_exit (const class loop *);
-extern edge single_likely_exit (class loop *loop);
+extern edge single_likely_exit (class loop *loop, vec<edge>);
extern unsigned num_loop_branches (const class loop *);
extern edge loop_preheader_edge (const class loop *);
to noreturn call. */
edge
-single_likely_exit (class loop *loop)
+single_likely_exit (class loop *loop, vec<edge> exits)
{
edge found = single_exit (loop);
- vec<edge> exits;
unsigned i;
edge ex;
if (found)
return found;
- exits = get_loop_exit_edges (loop);
FOR_EACH_VEC_ELT (exits, i, ex)
{
if (probably_never_executed_edge_p (cfun, ex)
if (!found)
found = ex;
else
- {
- exits.release ();
- return NULL;
- }
+ return NULL;
}
- exits.release ();
return found;
}
by find_loop_niter_by_eval. Be sure to keep it for future. */
if (niter && TREE_CODE (niter) == INTEGER_CST)
{
+ vec<edge> exits = get_loop_exit_edges (loop);
record_niter_bound (loop, wi::to_widest (niter),
- exit == single_likely_exit (loop), true);
+ exit == single_likely_exit (loop, exits), true);
+ exits.release ();
}
/* Force re-computation of loop bounds so we can remove redundant exits. */
data->body_includes_call = loop_body_includes_call (body, loop->num_nodes);
renumber_gimple_stmt_uids_in_blocks (body, loop->num_nodes);
- data->loop_single_exit_p = exit != NULL && loop_only_exit_p (loop, exit);
+ data->loop_single_exit_p
+ = exit != NULL && loop_only_exit_p (loop, body, exit);
/* For each ssa name determines whether it behaves as an induction variable
in some loop. */
/* Returns true if EXIT is the only possible exit from LOOP. */
bool
-loop_only_exit_p (const class loop *loop, const_edge exit)
+loop_only_exit_p (const class loop *loop, basic_block *body, const_edge exit)
{
- basic_block *body;
gimple_stmt_iterator bsi;
unsigned i;
if (exit != single_exit (loop))
return false;
- body = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
{
for (bsi = gsi_start_bb (body[i]); !gsi_end_p (bsi); gsi_next (&bsi))
if (stmt_can_terminate_bb_p (gsi_stmt (bsi)))
{
- free (body);
return true;
}
}
- free (body);
return true;
}
bool
number_of_iterations_exit_assumptions (class loop *loop, edge exit,
class tree_niter_desc *niter,
- gcond **at_stmt, bool every_iteration)
+ gcond **at_stmt, bool every_iteration,
+ basic_block *body)
{
gimple *last;
gcond *stmt;
iv0.base = expand_simple_operations (iv0.base);
iv1.base = expand_simple_operations (iv1.base);
+ bool body_from_caller = true;
+ if (!body)
+ {
+ body = get_loop_body (loop);
+ body_from_caller = false;
+ }
+ bool only_exit_p = loop_only_exit_p (loop, body, exit);
+ if (!body_from_caller)
+ free (body);
if (!number_of_iterations_cond (loop, type, &iv0, code, &iv1, niter,
- loop_only_exit_p (loop, exit), safe))
+ only_exit_p, safe))
{
fold_undefer_and_ignore_overflow_warnings ();
return false;
bool
number_of_iterations_exit (class loop *loop, edge exit,
class tree_niter_desc *niter,
- bool warn, bool every_iteration)
+ bool warn, bool every_iteration,
+ basic_block *body)
{
gcond *stmt;
if (!number_of_iterations_exit_assumptions (loop, exit, niter,
- &stmt, every_iteration))
+ &stmt, every_iteration, body))
return false;
if (integer_nonzerop (niter->assumptions))
*/
static void
-infer_loop_bounds_from_undefined (class loop *loop)
+infer_loop_bounds_from_undefined (class loop *loop, basic_block *bbs)
{
unsigned i;
- basic_block *bbs;
gimple_stmt_iterator bsi;
basic_block bb;
bool reliable;
- bbs = get_loop_body (loop);
-
for (i = 0; i < loop->num_nodes; i++)
{
bb = bbs[i];
}
}
-
- free (bbs);
}
/* Compare wide ints, callback for qsort. */
diagnose those loops with -Waggressive-loop-optimizations. */
number_of_latch_executions (loop);
- exits = get_loop_exit_edges (loop);
- likely_exit = single_likely_exit (loop);
+ basic_block *body = get_loop_body (loop);
+ exits = get_loop_exit_edges (loop, body);
+ likely_exit = single_likely_exit (loop, exits);
FOR_EACH_VEC_ELT (exits, i, ex)
{
if (ex == likely_exit)
}
}
- if (!number_of_iterations_exit (loop, ex, &niter_desc, false, false))
+ if (!number_of_iterations_exit (loop, ex, &niter_desc,
+ false, false, body))
continue;
niter = niter_desc.niter;
exits.release ();
if (flag_aggressive_loop_optimizations)
- infer_loop_bounds_from_undefined (loop);
+ infer_loop_bounds_from_undefined (loop, body);
discover_iteration_bound_by_body_walk (loop);
extern tree expand_simple_operations (tree, tree = NULL);
extern tree simplify_using_initial_conditions (class loop *, tree);
-extern bool loop_only_exit_p (const class loop *, const_edge);
+extern bool loop_only_exit_p (const class loop *, basic_block *body,
+ const_edge);
extern bool number_of_iterations_exit (class loop *, edge,
class tree_niter_desc *niter, bool,
- bool every_iteration = true);
+ bool every_iteration = true,
+ basic_block * = NULL);
extern bool number_of_iterations_exit_assumptions (class loop *, edge,
class tree_niter_desc *,
- gcond **, bool = true);
+ gcond **, bool = true,
+ basic_block * = NULL);
extern tree find_loop_niter (class loop *, edge *);
extern bool finite_loop_p (class loop *);
extern tree loop_niter_by_eval (class loop *, edge);