]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/122079 - PRE antic compute doesn't converge
authorRichard Biener <rguenther@suse.de>
Wed, 1 Oct 2025 12:55:17 +0000 (14:55 +0200)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 2 Oct 2025 07:12:10 +0000 (09:12 +0200)
The following re-instantiates the pruning of the ANTIC_IN value set
by the previous iterations one by reverting part of
r16-3945-gc30f58c3f7ec25.  The earlier fixes made sure the initial
value set is appropriately big to not cause this to lose optimizations.
But it seems to be still required for correctness given iteration
order means we combine ANTIC_IN sets from different generations which
can be prone to oscillations in CFG cycles.

PR tree-optimization/122079
* tree-ssa-pre.cc (compute_antic_aux): Re-instantiate
ANTIC_IN value pruning by the old solution.

* gcc.dg/torture/pr122079-2.c: New testcase.
* gcc.dg/torture/pr122079-3.c: Likewise.

gcc/testsuite/gcc.dg/torture/pr122079-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr122079-3.c [new file with mode: 0644]
gcc/tree-ssa-pre.cc

diff --git a/gcc/testsuite/gcc.dg/torture/pr122079-2.c b/gcc/testsuite/gcc.dg/torture/pr122079-2.c
new file mode 100644 (file)
index 0000000..40c36b0
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+
+int a, b, *c = &a, d, e, f;
+void g(int *p) { a = p[0]; }
+int main() {
+  int h = 0;
+i:
+  d = c[0];
+  c[0] = h;
+  if (a)
+    goto j;
+k:
+  h = c[0] - 1;
+  while (1) {
+    if (b)
+      goto i;
+    if (f)
+      goto k;
+  j:
+    if (!e) {
+      int m[] = {c[0]};
+      g(m);
+      break;
+    }
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr122079-3.c b/gcc/testsuite/gcc.dg/torture/pr122079-3.c
new file mode 100644 (file)
index 0000000..df95c71
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-tree-loop-im" } */
+
+int a, b, c;
+void d(int[]);
+void e(int f[][2]) {
+g:
+  b = f[0][1];
+  if (c)
+    goto h;
+i:
+  if (a)
+    goto g;
+  if (f[1][1])
+    goto j;
+h:
+  if (f[1][1])
+    goto i;
+  goto k;
+j:
+  b--;
+  if (b + f[0][1])
+    goto i;
+k:
+  int l[] = {f[0][1]};
+  d(l);
+}
index d08caab952a1b91517486e04002101fbfb9bd1fb..2a7dcbee52ceda7012edd164f2975362ec848a1c 100644 (file)
@@ -2084,6 +2084,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
   edge e;
   edge_iterator ei;
 
+  bool was_visited = BB_VISITED (block);
   bool changed = ! BB_VISITED (block);
   bool any_max_on_edge = false;
 
@@ -2219,6 +2220,32 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
   /* clean (ANTIC_IN (block)) is defered to after the iteration converged
      because it can cause non-convergence, see for example PR81181.  */
 
+  if (was_visited
+      && bitmap_and_into (&ANTIC_IN (block)->values, &old->values))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "warning: intersecting with old ANTIC_IN "
+                "shrinks the set\n");
+      /* Prune expressions not in the value set.  */
+      bitmap_iterator bi;
+      unsigned int i;
+      unsigned int to_clear = -1U;
+      FOR_EACH_EXPR_ID_IN_SET (ANTIC_IN (block), i, bi)
+       {
+         if (to_clear != -1U)
+           {
+             bitmap_clear_bit (&ANTIC_IN (block)->expressions, to_clear);
+             to_clear = -1U;
+           }
+         pre_expr expr = expression_for_id (i);
+         unsigned int value_id = get_expr_value_id (expr);
+         if (!bitmap_bit_p (&ANTIC_IN (block)->values, value_id))
+           to_clear = i;
+       }
+      if (to_clear != -1U)
+       bitmap_clear_bit (&ANTIC_IN (block)->expressions, to_clear);
+    }
+
   if (!bitmap_set_equal (old, ANTIC_IN (block)))
     changed = true;