This refines the fix for PR78185 after understanding that the code
regarding to the comment 'In a loop that is always entered we may
proceed anyway.  But record that we entered it and stop once we leave
it.' was supposed to protect us from leaving possibly infinite inner
loops.  The simpler fix of moving the misplaced stopping code
can then be refined to continue processing when the exited inner
loop is finite, improving invariant motion for cases like in the
added testcase.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

2021-09-02  Richard Biener  <rguent...@suse.de>

        * tree-ssa-loop-im.c (fill_always_executed_in_1): Refine
        fix for PR78185 and continue processing when leaving
        finite inner loops.

        * gcc.dg/tree-ssa/ssa-lim-16.c: New testcase.
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-16.c | 19 +++++++++++++
 gcc/tree-ssa-loop-im.c                     | 33 +++++++++++++---------
 2 files changed, 38 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-16.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-16.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-16.c
new file mode 100644
index 00000000000..741582b745f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-16.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-lim2-details" } */
+
+volatile int flag, bar;
+double foo (double *valp)
+{
+  double sum = 0;
+  for (int i = 0; i < 256; ++i)
+    {
+      for (int j = 0; j < 256; ++j)
+        bar = flag;
+      if (flag)
+        sum += 1.;
+      sum += *valp; // we should move the load of *valp out of the loop
+    }
+  return sum;
+}
+
+/* { dg-final { scan-tree-dump-times "Moving statement" 1 "lim2" } } */
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index d9f75d5025e..01f3fc2f7f0 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -3044,23 +3044,27 @@ fill_always_executed_in_1 (class loop *loop, sbitmap 
contains_call)
          edge_iterator ei;
          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 (dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
            last = bb;
 
          if (bitmap_bit_p (contains_call, bb->index))
            break;
 
+         /* If LOOP exits from this BB stop processing.  */
          FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             /* If there is an exit from this BB.  */
-             if (!flow_bb_inside_loop_p (loop, e->dest))
-               break;
-             /* Or we enter a possibly non-finite loop.  */
-             if (flow_loop_nested_p (bb->loop_father,
-                                     e->dest->loop_father)
-                 && ! finite_loop_p (e->dest->loop_father))
-               break;
-           }
+           if (!flow_bb_inside_loop_p (loop, e->dest))
+             break;
          if (e)
            break;
 
@@ -3069,22 +3073,23 @@ fill_always_executed_in_1 (class loop *loop, sbitmap 
contains_call)
          if (bb->flags & BB_IRREDUCIBLE_LOOP)
            break;
 
-         if (!flow_bb_inside_loop_p (inn_loop, bb))
-           break;
-
          if (bb->loop_father->header == bb)
            {
              if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
                break;
 
              /* In a loop that is always entered we may proceed anyway.
-                But record that we entered it and stop once we leave it.  */
+                But record that we entered it and stop once we leave it
+                since it might not be finite.  */
              inn_loop = bb->loop_father;
            }
        }
 
       while (1)
        {
+         if (dump_enabled_p ())
+           dump_printf (MSG_NOTE, "BB %d is always executed in loop %d\n",
+                        last->index, loop->num);
          SET_ALWAYS_EXECUTED_IN (last, loop);
          if (last == loop->header)
            break;
-- 
2.31.1

Reply via email to