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

Reply via email to