]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
phiopt: Reset the number of iterations information of a loop when changing an exit...
authorAndrew Pinski <quic_apinski@quicinc.com>
Mon, 2 Dec 2024 16:35:23 +0000 (08:35 -0800)
committerAndrew Pinski <quic_apinski@quicinc.com>
Wed, 16 Apr 2025 21:25:41 +0000 (14:25 -0700)
After r12-5300-gf98f373dd822b3, phiopt could get the following bb structure:
      |
    middle-bb -----|
      |            |
      |   |----|   |
    phi<1, 2>  |   |
    cond       |   |
      |        |   |
      |--------+---|

Which was considered 2 loops. The inner loop had esimtate of upper_bound to be 8,
due to the original `for (b = 0; b <= 7; b++)`. The outer loop was already an
infinite one.
So phiopt would come along and change the condition to be unconditionally true,
we change the inner loop to being an infinite one but don't reset the estimate
on the loop and cleanup cfg comes along and changes it into one loop but also
does not reset the estimate of the loop. Then the loop unrolling uses the old estimate
and decides to add an unreachable there.o
So the fix is when phiopt changes an exit to a loop, reset the estimates, similar to
how cleanupcfg does it when merging some basic blocks.

Bootstrapped and tested on x86_64-linux-gnu.

PR tree-optimization/117243
PR tree-optimization/116749

gcc/ChangeLog:

* tree-ssa-phiopt.cc (replace_phi_edge_with_variable): Reset loop
estimates if the cond_block was an exit to a loop.

gcc/testsuite/ChangeLog:

* gcc.dg/torture/pr117243-1.c: New test.
* gcc.dg/torture/pr117243-2.c: New test.

Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
(cherry picked from commit b7c69cc072ef0da36439ebc55c513b48e68391b7)

gcc/testsuite/gcc.dg/torture/pr117243-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr117243-2.c [new file with mode: 0644]
gcc/tree-ssa-phiopt.cc

diff --git a/gcc/testsuite/gcc.dg/torture/pr117243-1.c b/gcc/testsuite/gcc.dg/torture/pr117243-1.c
new file mode 100644 (file)
index 0000000..c4bbc31
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-optimized" } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
+
+/* PR tree-optimization/117243 */
+/* foo should be an infinite but sometimes it gets optimized incorrectly into
+   an __builtin_unreachable(); which is not valid.  */
+void
+foo (unsigned int a, unsigned char b)
+{
+  lbl:
+  for (b = 0; b <= 7; b++)
+    {
+      unsigned char c[1][1];
+      int i, j;
+      for (i = 0; i < 1; i++)
+        for (j = 0; j < 1; j++)
+          c[i][j] = 1;
+      if (b)
+       goto lbl;
+    }
+}
+
+int
+main ()
+{
+  foo (1, 2);
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_unreachable " "optimized"} } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr117243-2.c b/gcc/testsuite/gcc.dg/torture/pr117243-2.c
new file mode 100644 (file)
index 0000000..d9b0d3e
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-tree-ch -fdump-tree-optimized" } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
+
+/* PR tree-optimization/117243 */
+/* PR tree-optimization/116749 */
+
+/* main1 should be an infinite but sometimes it gets optimized incorrectly into
+   an __builtin_unreachable(); which is not valid.  */
+int main1 (void)
+{
+    int g=0;
+    int l1[1];
+    int *l2 = &g;
+    int i;
+    for (i=0; i<1; i++)
+        l1[i] = (1);
+    for (g=0; g; ++g)
+    {
+        int *l3[1] = {&l1[0]};
+    }
+    *l2 = *l1;
+b:
+    for (i=0; i<2; ++i)
+    { 
+        if (i)
+            goto b;
+        if (g)
+            continue;
+    }
+    return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_unreachable " "optimized"} } */
index 3ef7d6b28fcd6a6b2e3ee0d48990c2fca22f667e..167b0b3be741ac4b0ae2af86f45a159afa8b9355 100644 (file)
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-match.h"
 #include "dbgcnt.h"
 #include "tree-ssa-propagate.h"
+#include "tree-ssa-loop-niter.h"
 
 static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
 static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
@@ -429,6 +430,17 @@ replace_phi_edge_with_variable (basic_block cond_block,
     edge_to_remove = EDGE_SUCC (cond_block, 1);
   else
     edge_to_remove = EDGE_SUCC (cond_block, 0);
+
+  /* If we are removing the cond on a loop exit,
+     reset number of iteration information of the loop. */
+  if (loop_exits_from_bb_p (cond_block->loop_father, cond_block))
+    {
+      auto loop = cond_block->loop_father;
+      free_numbers_of_iterations_estimates (loop);
+      loop->any_upper_bound = false;
+      loop->any_likely_upper_bound = false;
+    }
+
   if (EDGE_COUNT (edge_to_remove->dest->preds) == 1)
     {
       e->flags |= EDGE_FALLTHRU;