https://gcc.gnu.org/g:1204989c4ff5061576538a51df826c6c023f18cd

commit r17-5636-g1204989c4ff5061576538a51df826c6c023f18cd
Author: Richard Biener <[email protected]>
Date:   Tue Oct 27 12:30:45 2026 +0100

    tree-optimization/128198 - PTA solver issue with node merging
    
    When we merge two graph nodes we fail to consider that bringing in
    new successors requires forwarding of the target node solution to
    those.  So make sure we mark the node as changed, even when its
    solution doesn't increase from the merged in node.
    
            PR tree-optimization/128198
            * pta-andersen.cc (merge_graph_nodes): Return whether we
            got new successor edges.
            (unify_nodes): Mark the target node changed if there were
            new successor nodes.
    
            * gcc.dg/torture/pr128198.c: New testcase.

Diff:
---
 gcc/pta-andersen.cc                     | 22 ++++++++----
 gcc/testsuite/gcc.dg/torture/pr128198.c | 60 +++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/gcc/pta-andersen.cc b/gcc/pta-andersen.cc
index 464c54b3f766..479cdc402717 100644
--- a/gcc/pta-andersen.cc
+++ b/gcc/pta-andersen.cc
@@ -557,9 +557,10 @@ clear_edges_for_node (constraint_graph_t graph, unsigned 
int node)
     BITMAP_FREE (graph->succs[node]);
 }
 
-/* Merge GRAPH nodes FROM and TO into node TO.  */
+/* Merge GRAPH nodes FROM and TO into node TO.  Return whether TO
+   received new successor edges.  */
 
-static void
+static bool
 merge_graph_nodes (constraint_graph_t graph, unsigned int to,
                   unsigned int from)
 {
@@ -576,15 +577,17 @@ merge_graph_nodes (constraint_graph_t graph, unsigned int 
to,
     }
 
   /* Merge all the successor edges.  */
+  bool new_succs = false;
   if (graph->succs[from])
     {
       if (!graph->succs[to])
        graph->succs[to] = BITMAP_ALLOC (&pta_obstack);
-      bitmap_ior_into (graph->succs[to],
-                      graph->succs[from]);
+      new_succs = bitmap_ior_into (graph->succs[to],
+                                  graph->succs[from]);
     }
 
   clear_edges_for_node (graph, from);
+  return new_succs;
 }
 
 
@@ -995,7 +998,15 @@ unify_nodes (constraint_graph_t graph, unsigned int to, 
unsigned int from,
   else
     stats.unified_vars_static++;
 
-  merge_graph_nodes (graph, to, from);
+  varinfo_t tovi = get_varinfo (to);
+  if (merge_graph_nodes (graph, to, from))
+    {
+      /* If from brings new successors and the TO solution is not a
+        subset of FROM we have to forward the TO solution along these
+        edges.  */
+      if (update_changed)
+       bitmap_set_bit (changed, to);
+    }
   if (merge_node_constraints (graph, to, from))
     {
       if (update_changed)
@@ -1013,7 +1024,6 @@ unify_nodes (constraint_graph_t graph, unsigned int to, 
unsigned int from,
     {
       /* If the solution changes because of the merging, we need to mark
         the variable as changed.  */
-      varinfo_t tovi = get_varinfo (to);
       if (bitmap_ior_into (tovi->solution, fromvi->solution))
        {
          if (update_changed)
diff --git a/gcc/testsuite/gcc.dg/torture/pr128198.c 
b/gcc/testsuite/gcc.dg/torture/pr128198.c
new file mode 100644
index 000000000000..1766e507f508
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr128198.c
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+
+typedef struct Vec { unsigned char *start, *finish; } Vec;
+
+unsigned long size = 1;  /* not a constant, to keep IPA-CP away */
+static long freed;
+
+static void create_storage(Vec *v, unsigned long n)
+{
+  unsigned char *p = 0;
+  if (n)
+    p = (unsigned char *)__builtin_malloc(n);
+  v->start = p;
+  v->finish = p ? p + n : p;
+}
+
+static void destroy(Vec *v)
+{
+  if (v->start)
+  {
+    freed += (unsigned long)v->finish - (unsigned long)v->start;
+    __builtin_free(v->start);
+    v->start = 0;
+    v->finish = nullptr;
+  }
+}
+
+static void assign(Vec *v, unsigned long n)
+{
+  if (n > (unsigned long)v->finish - (unsigned long)v->start)
+  {
+    Vec tmp = {0, 0};
+    create_storage(&tmp, n);
+    unsigned char *s = tmp.start, *f = tmp.finish;
+    tmp.start = v->start; tmp.finish = v->finish;
+    v->start = s; v->finish = f;
+    destroy(&tmp);
+  }
+}
+
+int main ()
+{
+  Vec fixed[4] = {{0, 0}};
+  for (Vec *c = fixed; c != fixed + 4; ++c)
+    assign(c, size);
+  for (Vec *c = fixed; c != fixed + 4; ++c)
+  {
+    int t = 0;
+    for (unsigned char *b = c->start,
+         *e = c->finish; b != e; ++b)
+    {
+      t++;
+      if (t >= 20)
+        __builtin_trap();
+    }
+  }
+  for (Vec *c = fixed; c != fixed + 4; ++c)
+    destroy(c);
+  return 0;
+}

Reply via email to