https://gcc.gnu.org/g:5a3ad9374a73df7df7e8a00b1c06fbf30ad7298c
commit r17-3944-g5a3ad9374a73df7df7e8a00b1c06fbf30ad7298c Author: Philipp Tomsich <[email protected]> Date: Sun Jul 26 14:03:26 2026 +0200 tree-data-ref: use DR_PTR_INFO points-to info in dr_may_alias_p [PR127201] Pointer SSA names created after the last points-to computation (e.g. by PRE re-materializing a load, gated on flag_tree_pre || flag_code_hoisting) carry no SSA_NAME_PTR_INFO. When dr_analyze_innermost re-expresses a data reference's base, DR_BASE_OBJECT can root at such a name, and ptr_derefs_may_alias_p then returns may-alias for lack of information. dr_analyze_alias already records that original solution in DR_PTR_INFO. Intersect the recorded solutions with pt_solutions_intersect before falling back to the rewritten base object. This is valid for cross-iteration queries because a points-to solution covers every dynamic value of the SSA name. The vectorizer already relies on this when it stamps DR_PTR_INFO onto the data-ref pointers it synthesizes (vect_duplicate_ssa_name_ptr_info). On SPEC CPU 2026's 722.palm_r, file advec_ws.fppized.f90, this removed (in one run measured on Aarch64) approx. 28.5% of the required runtime alias checks (3952 -> 2824) and all 18 in the hot loop, which then vectorized with no versioning at all. Bootstrapped and tested on x86_64-pc-linux-gnu. PR tree-optimization/127201 gcc/ChangeLog: * tree-data-ref.cc (dr_may_alias_p): Consult DR_PTR_INFO of both data references before falling back to base-object analysis. gcc/testsuite/ChangeLog: * gcc.dg/vect/vect-alias-check-ptr-info-1.c: New test. * gcc.dg/vect/vect-alias-check-ptr-info-2.c: New test. Diff: --- .../gcc.dg/vect/vect-alias-check-ptr-info-1.c | 42 +++++++++++++++++ .../gcc.dg/vect/vect-alias-check-ptr-info-2.c | 52 ++++++++++++++++++++++ gcc/tree-data-ref.cc | 12 +++++ 3 files changed, 106 insertions(+) diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-1.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-1.c new file mode 100644 index 000000000000..9c65922311ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-1.c @@ -0,0 +1,42 @@ +/* Base pointers re-materialized by PRE after the last points-to run carry + no SSA_NAME_PTR_INFO; dr_may_alias_p must fall back to the points-to + solution recorded on the data reference (DR_PTR_INFO) instead of + emitting runtime alias checks between provably disjoint objects. */ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_double } */ +/* { dg-additional-options "-O3 -ffast-math" } */ + +struct desc { double *data; long span; }; +struct desc g; +int lo, hi; +double res; + +void +f (int c) +{ + int n = hi - lo + 2; + double t[n], u[n]; /* VLAs -> __builtin_alloca_with_align */ + + /* g.data is loaded on both arms, so PRE materialises it as a fresh + "pretmp" pointer SSA name -- after the last points-to run. */ + if (c) + res = g.data[0]; + else + res = g.data[1]; + + for (int k = 2; k < n - 2; k++) + { + u[k] = g.data[k + 1] + g.data[k]; + t[k] = u[k] * (37.0 * (g.data[k + 1] + g.data[k]) + - 8.0 * (g.data[k + 2] + g.data[k - 1])); + } + + double s = 0; + for (int k = 2; k < n - 2; k++) + s += t[k] + u[k]; + res += s; +} + +/* The local VLAs cannot alias the global-reached g.data; no runtime + alias checks may be required. */ +/* { dg-final { scan-tree-dump-not "versioning for alias required" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-2.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-2.c new file mode 100644 index 000000000000..5bb4dac69e3a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-ptr-info-2.c @@ -0,0 +1,52 @@ +/* An info-less pointer (re-materialized by PRE after the last points-to + run) may still point to a non-escaped local; the dependence against + that local must be preserved. Execution test: the store stream + through 'tab[idx & 1]' aliases 't' when idx is even. */ +/* { dg-do run } */ +/* { dg-additional-options "-O3 -ffast-math" } */ + +extern void abort (void); + +double res; +int lo, hi, idx; + +void __attribute__ ((noipa)) +f (int c) +{ + int n = hi - lo + 2; + double t[n], u[n]; + double *tab[2] = { t, u }; + + /* Load tab[idx&1] on both arms so PRE hoists it into a pretmp. */ + if (c) + res = tab[idx & 1][0]; + else + res = tab[idx & 1][1]; + + for (int k = 0; k < n; k++) + t[k] = u[k] = k; + + for (int k = 3; k < n - 2; k++) + { + tab[idx & 1][k] = t[k - 1] + 1.0; /* stores TO t when idx is even */ + res += t[k]; /* must observe those stores */ + } + + double s = 0; + for (int k = 2; k < n - 2; k++) + s += t[k] + u[k]; + res += s; +} + +int +main (void) +{ + lo = 0; hi = 14; idx = 0; /* idx even: store stream aliases t */ + res = 0; + f (1); + double expect = 0.0 + (3+4+5+6+7+8+9+10+11+12+13) + + 2.0 * (2+3+4+5+6+7+8+9+10+11+12+13); + if (res != expect) + abort (); + return 0; +} diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc index 8e9d78713482..db77e4ead727 100644 --- a/gcc/tree-data-ref.cc +++ b/gcc/tree-data-ref.cc @@ -3059,6 +3059,18 @@ dr_may_alias_p (const struct data_reference *a, const struct data_reference *b, return false; } + /* Try the points-to information recorded for the base pointers the + references were originally analyzed from. DR_BASE_OBJECT can be less + precise, rooting at another SSA name or at one created after points-to + information was computed and thus without SSA_NAME_PTR_INFO. A + recorded solution is not revalidated. It covers every dynamic value + of its SSA name, so it holds for cross-iteration queries as well. */ + struct ptr_info_def *pi_a = DR_PTR_INFO (a); + struct ptr_info_def *pi_b = DR_PTR_INFO (b); + if (pi_a && pi_b + && !pt_solutions_intersect (&pi_a->pt, &pi_b->pt)) + return false; + if ((TREE_CODE (addr_a) == MEM_REF || TREE_CODE (addr_a) == TARGET_MEM_REF) && (TREE_CODE (addr_b) == MEM_REF || TREE_CODE (addr_b) == TARGET_MEM_REF) /* For cross-iteration dependences the cliques must be valid for the
