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; +}
