diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 5cd62b3..dab3565 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -173,6 +173,9 @@ struct GTY ((chain_next ("%h.next"))) loop { /* Head of the cyclic list of the exits of the loop. */ struct loop_exit *exits; + + /* True if an exit branch was moved out of the loop. */ + bool external_exits; }; /* Flags for state of loop structure. */ diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index 601223b..8448234 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -50,6 +50,8 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" #include "tree-inline.h" #include "target.h" +#include "diagnostic.h" +#include "intl.h" /* Specifies types of loops that may be unrolled. */ @@ -525,10 +527,21 @@ static bool remove_redundant_iv_tests (struct loop *loop) { struct nb_iter_bound *elt; - bool changed = false; + loop_exit *exit; + VEC(gimple, stack) *exit_stmts = VEC_alloc (gimple, stack, 16); + int exits_left = 0, num_exits = 0; if (!loop->any_upper_bound) - return false; + goto out; + + /* Count our exits. */ + for (exit = loop->exits->next; exit->e; exit = exit->next) + num_exits++; + + if (num_exits == 0) + goto out; + + exits_left = num_exits; for (elt = loop->bounds; elt; elt = elt->next) { /* Exit is pointless if it won't be taken before loop reaches @@ -555,7 +568,11 @@ remove_redundant_iv_tests (struct loop *loop) || !loop->nb_iterations_upper_bound.ult (tree_to_double_int (niter.niter))) continue; - + + exits_left--; + + VEC_safe_push (gimple, stack, exit_stmts, elt->stmt); + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Removed pointless exit: "); @@ -566,10 +583,31 @@ remove_redundant_iv_tests (struct loop *loop) else gimple_cond_make_true (elt->stmt); update_stmt (elt->stmt); - changed = true; } } - return changed; + + /* We removed all exit points, so tell the user. */ + if (exits_left == 0 && !loop->external_exits) + { + gimple stmt; + const char *wording; + unsigned i; + location_t loc; + + FOR_EACH_VEC_ELT (gimple, exit_stmts, i, stmt) + { + loc = gimple_location (stmt); + wording = N_("Loop behavior is undefined before exit condition; " + "turned into infinite loop"); + warning_at ((LOCATION_LINE (loc) > 0) ? loc : input_location, 0, + gettext (wording)); + } + } + +out: + VEC_free (gimple, stack, exit_stmts); + + return exits_left < num_exits; } /* Stores loops that will be unlooped after we process whole loop tree. */ diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c index b24f3d7..fb95ab7 100644 --- a/gcc/tree-ssa-loop-unswitch.c +++ b/gcc/tree-ssa-loop-unswitch.c @@ -234,6 +234,14 @@ tree_unswitch_single_loop (struct loop *loop, int num) cond = simplify_using_entry_checks (loop, cond); stmt = last_stmt (bbs[i]); + + /* We're switching out an exit point, so note that the loop has exits + outside its body. */ + if (loop_exit_edge_p (loop, EDGE_SUCC (bbs[i], 0)) + || loop_exit_edge_p (loop, EDGE_SUCC (bbs[i], 1))) + loop->external_exits = true; + + /* TODO If this is a loop exit statement then note it. */ if (integer_nonzerop (cond)) { /* Remove false path. */