This cuts down the number significantly coming from estimate_numbers_of_iterations where even loop exits may not be computed in some callers and thus the single_exit () early-outs do not work.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2019-11-21 Richard Biener <rguent...@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. Index: gcc/cfgloop.c =================================================================== --- gcc/cfgloop.c (revision 278550) +++ gcc/cfgloop.c (working copy) @@ -1203,12 +1203,11 @@ release_recorded_exits (function *fn) /* 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; @@ -1223,14 +1222,20 @@ get_loop_exit_edges (const class loop *l } 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; Index: gcc/cfgloop.h =================================================================== --- gcc/cfgloop.h (revision 278550) +++ gcc/cfgloop.h (working copy) @@ -379,9 +379,9 @@ extern basic_block *get_loop_body_in_cus 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 *); Index: gcc/cfgloopanal.c =================================================================== --- gcc/cfgloopanal.c (revision 278550) +++ gcc/cfgloopanal.c (working copy) @@ -467,16 +467,14 @@ mark_loop_exit_edges (void) 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) @@ -489,12 +487,8 @@ single_likely_exit (class loop *loop) if (!found) found = ex; else - { - exits.release (); - return NULL; - } + return NULL; } - exits.release (); return found; } Index: gcc/tree-ssa-loop-ivcanon.c =================================================================== --- gcc/tree-ssa-loop-ivcanon.c (revision 278550) +++ gcc/tree-ssa-loop-ivcanon.c (working copy) @@ -1222,8 +1222,10 @@ canonicalize_loop_induction_variables (c 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. */ Index: gcc/tree-ssa-loop-ivopts.c =================================================================== --- gcc/tree-ssa-loop-ivopts.c (revision 278550) +++ gcc/tree-ssa-loop-ivopts.c (working copy) @@ -7977,7 +7977,8 @@ tree_ssa_iv_optimize_loop (struct ivopts 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. */ Index: gcc/tree-ssa-loop-niter.c =================================================================== --- gcc/tree-ssa-loop-niter.c (revision 278550) +++ gcc/tree-ssa-loop-niter.c (working copy) @@ -2367,27 +2367,23 @@ simplify_using_outer_evolutions (class l /* 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; } @@ -2403,7 +2399,8 @@ loop_only_exit_p (const class loop *loop 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; @@ -2477,8 +2474,17 @@ number_of_iterations_exit_assumptions (c 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; @@ -2721,11 +2727,12 @@ number_of_iterations_popcount (loop_p lo 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)) @@ -3837,16 +3844,13 @@ infer_loop_bounds_from_signedness (class */ 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]; @@ -3871,8 +3875,6 @@ infer_loop_bounds_from_undefined (class } } - - free (bbs); } /* Compare wide ints, callback for qsort. */ @@ -4275,8 +4277,9 @@ estimate_numbers_of_iterations (class lo 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) @@ -4296,7 +4299,8 @@ estimate_numbers_of_iterations (class lo } } - 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; @@ -4313,7 +4317,7 @@ estimate_numbers_of_iterations (class lo 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); Index: gcc/tree-ssa-loop-niter.h =================================================================== --- gcc/tree-ssa-loop-niter.h (revision 278550) +++ gcc/tree-ssa-loop-niter.h (working copy) @@ -22,13 +22,16 @@ along with GCC; see the file COPYING3. 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);