The following fixes part of the issue that niter analysis uses UB of stmts that might not execute due to inner infinite loops (the testcase in the PR) or due to calls terminating the program or the function. This patch addresses inner infinite loops by copying parts of the analysis loop invariant motion does. This requires enumerating the loop body in DOM order rather than DFS order.
On trunk the testcase no longer triggers the bug, but it is present on the branches where this patch fixes the issue. Bootstrap and regtest running on x86_64-unknown-linux-gnu. Any objections? The missing related bits are /* If LOOP exits from this BB stop processing. */ FOR_EACH_EDGE (e, ei, bb->succs) if (!flow_bb_inside_loop_p (loop, e->dest)) break; if (e) break; /* A loop might be infinite (TODO use simple loop analysis to disprove this if possible). */ if (bb->flags & BB_IRREDUCIBLE_LOOP) break; and of course call handling. But somehow I'd like to see relevant testcases since this all likely will cause some (too optimistic) missed optimizations. Richard. PR tree-optimization/114052 * tree-ssa-loop-niter.cc (estimate_numbers_of_iterations): Enumerate the loop body in DOM order. (infer_loop_bounds_from_undefined): Track which subloop we walk, when exiting a subloop that may be not finite terminate the walk. * gcc.dg/pr114052-1.c: New testcase. --- gcc/testsuite/gcc.dg/pr114052-1.c | 41 +++++++++++++++++++++++++++++++ gcc/tree-ssa-loop-niter.cc | 19 +++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/pr114052-1.c diff --git a/gcc/testsuite/gcc.dg/pr114052-1.c b/gcc/testsuite/gcc.dg/pr114052-1.c new file mode 100644 index 00000000000..920d32b1a65 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114052-1.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-require-effective-target alarm } */ +/* { dg-require-effective-target signal } */ +/* { dg-options "-O2" } */ + +#include <stdint.h> +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> + +volatile int y; +void __attribute__((noipa)) put(int x) +{ + if (y) + __builtin_printf ("%i\n", x); +} + +void __attribute__((noipa)) f(void) +{ + int counter = 0; + while (1) { + if (counter >= 2) continue; + put (counter++); + } +} + +void do_exit (int i) +{ + exit (0); +} + +int main() +{ + struct sigaction s; + sigemptyset (&s.sa_mask); + s.sa_handler = do_exit; + s.sa_flags = 0; + sigaction (SIGALRM, &s, NULL); + alarm (1); + f(); +} diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index de8d5ae6233..2bd349e58bd 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -4451,11 +4451,28 @@ infer_loop_bounds_from_undefined (class loop *loop, basic_block *bbs) gimple_stmt_iterator bsi; basic_block bb; bool reliable; + class loop *inn_loop = loop; for (i = 0; i < loop->num_nodes; i++) { bb = bbs[i]; + if (!flow_bb_inside_loop_p (inn_loop, bb)) + { + /* When we are leaving a possibly infinite inner loop + we have to stop processing. */ + if (!finite_loop_p (inn_loop)) + break; + /* If the loop was finite we can continue with processing + the loop we exited to. */ + inn_loop = bb->loop_father; + } + + if (bb->loop_father->header == bb) + /* Record that we enter into a subloop since it might not + be finite. */ + inn_loop = bb->loop_father; + /* If BB is not executed in each iteration of the loop, we cannot use the operations in it to infer reliable upper bound on the # of iterations of the loop. However, we can use it as a guess. @@ -4885,7 +4902,7 @@ estimate_numbers_of_iterations (class loop *loop) diagnose those loops with -Waggressive-loop-optimizations. */ number_of_latch_executions (loop); - basic_block *body = get_loop_body (loop); + basic_block *body = get_loop_body_in_dom_order (loop); auto_vec<edge> exits = get_loop_exit_edges (loop, body); likely_exit = single_likely_exit (loop, exits); FOR_EACH_VEC_ELT (exits, i, ex) -- 2.43.0