https://gcc.gnu.org/g:fc62834533f357125b9c1934f80c2ba249adbf9e

commit r16-281-gfc62834533f357125b9c1934f80c2ba249adbf9e
Author: Richard Biener <rguent...@suse.de>
Date:   Tue Apr 29 11:06:36 2025 +0200

    tree-optimization/119997 - &ptr->field no longer subject to PRE
    
    The following makes PRE handle &ptr->field the same as VN by
    treating it as a POINTER_PLUS_EXPR when possible and thus as
    'nary'.  To facilitate this the patch splits out vn_pp_nary_for_addr
    and adds const overloads for vec::last.  The patch also avoids
    handling an effective zero offset as POINTER_PLUS_EXPR.
    
            PR tree-optimization/119997
            * vec.h (vec<T, A, vl_embed>::last): Provide const overload.
            (vec<T, va_heap, vl_ptr>::last): Likewise.
            * tree-ssa-sccvn.h (vn_pp_nary_for_addr): Declare.
            * tree-ssa-sccvn.cc (vn_pp_nary_for_addr): Split out from ...
            (vn_reference_lookup): ... here.
            (vn_reference_insert): ... and duplicate here.  Do not handle
            zero offset as POINTER_PLUS_EXPR.
            * tree-ssa-pre.cc (compute_avail): Implement
            ADDR_EXPR-as-POINTER_PLUS_EXPR special casing.
    
            * gcc.dg/tree-ssa/ssa-pre-35.c: New testcase.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-35.c | 15 ++++++
 gcc/tree-ssa-pre.cc                        | 27 ++++++++++
 gcc/tree-ssa-sccvn.cc                      | 81 ++++++++++++++----------------
 gcc/tree-ssa-sccvn.h                       |  1 +
 gcc/vec.h                                  | 11 ++++
 5 files changed, 93 insertions(+), 42 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-35.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-35.c
new file mode 100644
index 000000000000..1b49445fc3c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-35.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-pre-stats" } */
+
+void bar (int *);
+
+struct X { int a[2]; };
+void foo (struct X *p, int b)
+{
+  if (b)
+    bar ((int *)p + 1);
+  bar (&p->a[1]);
+}
+
+/* We should PRE and hoist &p->a[1] as (int *)p + 1.  */
+/* { dg-final { scan-tree-dump "HOIST inserted: 1" "pre" } } */
diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc
index ecf45d29e769..f6c531e4892d 100644
--- a/gcc/tree-ssa-pre.cc
+++ b/gcc/tree-ssa-pre.cc
@@ -4133,6 +4133,33 @@ compute_avail (function *fun)
                      vec<vn_reference_op_s> operands
                        = vn_reference_operands_for_lookup (rhs1);
                      vn_reference_t ref;
+
+                     /* We handle &MEM[ptr + 5].b[1].c as
+                        POINTER_PLUS_EXPR.  */
+                     if (operands[0].opcode == ADDR_EXPR
+                         && operands.last ().opcode == SSA_NAME)
+                       {
+                         tree ops[2];
+                         if (vn_pp_nary_for_addr (operands, ops))
+                           {
+                             vn_nary_op_t nary;
+                             vn_nary_op_lookup_pieces (2, POINTER_PLUS_EXPR,
+                                                       TREE_TYPE (rhs1), ops,
+                                                       &nary);
+                             operands.release ();
+                             if (nary && !nary->predicated_values)
+                               {
+                                 unsigned value_id = nary->value_id;
+                                 if (value_id_constant_p (value_id))
+                                   continue;
+                                 result = get_or_alloc_expr_for_nary
+                                     (nary, value_id, gimple_location (stmt));
+                                 break;
+                               }
+                             continue;
+                           }
+                       }
+
                      vn_reference_lookup_pieces (gimple_vuse (stmt), set,
                                                  base_set, TREE_TYPE (rhs1),
                                                  operands, &ref, VN_WALK);
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 481ab8b243d7..f7f50c3de994 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -3998,6 +3998,41 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type 
set,
   return NULL_TREE;
 }
 
+/* When OPERANDS is an ADDR_EXPR that can be possibly expressed as a
+   POINTER_PLUS_EXPR return true and fill in its operands in OPS.  */
+
+bool
+vn_pp_nary_for_addr (const vec<vn_reference_op_s>& operands, tree ops[2])
+{
+  gcc_assert (operands[0].opcode == ADDR_EXPR
+             && operands.last ().opcode == SSA_NAME);
+  poly_int64 off = 0;
+  vn_reference_op_t vro;
+  unsigned i;
+  for (i = 1; operands.iterate (i, &vro); ++i)
+    {
+      if (vro->opcode == SSA_NAME)
+       break;
+      else if (known_eq (vro->off, -1))
+       break;
+      off += vro->off;
+    }
+  if (i == operands.length () - 1
+      && maybe_ne (off, 0)
+      /* Make sure we the offset we accumulated in a 64bit int
+        fits the address computation carried out in target
+        offset precision.  */
+      && (off.coeffs[0]
+         == sext_hwi (off.coeffs[0], TYPE_PRECISION (sizetype))))
+    {
+      gcc_assert (operands[i-1].opcode == MEM_REF);
+      ops[0] = operands[i].op0;
+      ops[1] = wide_int_to_tree (sizetype, off);
+      return true;
+    }
+  return false;
+}
+
 /* Lookup OP in the current hash table, and return the resulting value
    number if it exists in the hash table.  Return NULL_TREE if it does
    not exist in the hash table or if the result field of the structure
@@ -4034,28 +4069,9 @@ vn_reference_lookup (tree op, tree vuse, vn_lookup_kind 
kind,
       && operands[0].opcode == ADDR_EXPR
       && operands.last ().opcode == SSA_NAME)
     {
-      poly_int64 off = 0;
-      vn_reference_op_t vro;
-      unsigned i;
-      for (i = 1; operands.iterate (i, &vro); ++i)
+      tree ops[2];
+      if (vn_pp_nary_for_addr (operands, ops))
        {
-         if (vro->opcode == SSA_NAME)
-           break;
-         else if (known_eq (vro->off, -1))
-           break;
-         off += vro->off;
-       }
-      if (i == operands.length () - 1
-         /* Make sure we the offset we accumulated in a 64bit int
-            fits the address computation carried out in target
-            offset precision.  */
-         && (off.coeffs[0]
-             == sext_hwi (off.coeffs[0], TYPE_PRECISION (sizetype))))
-       {
-         gcc_assert (operands[i-1].opcode == MEM_REF);
-         tree ops[2];
-         ops[0] = operands[i].op0;
-         ops[1] = wide_int_to_tree (sizetype, off);
          tree res = vn_nary_op_lookup_pieces (2, POINTER_PLUS_EXPR,
                                               TREE_TYPE (op), ops, NULL);
          if (res)
@@ -4178,28 +4194,9 @@ vn_reference_insert (tree op, tree result, tree vuse, 
tree vdef)
       && operands[0].opcode == ADDR_EXPR
       && operands.last ().opcode == SSA_NAME)
     {
-      poly_int64 off = 0;
-      vn_reference_op_t vro;
-      unsigned i;
-      for (i = 1; operands.iterate (i, &vro); ++i)
+      tree ops[2];
+      if (vn_pp_nary_for_addr (operands, ops))
        {
-         if (vro->opcode == SSA_NAME)
-           break;
-         else if (known_eq (vro->off, -1))
-           break;
-         off += vro->off;
-       }
-      if (i == operands.length () - 1
-         /* Make sure we the offset we accumulated in a 64bit int
-            fits the address computation carried out in target
-            offset precision.  */
-         && (off.coeffs[0]
-             == sext_hwi (off.coeffs[0], TYPE_PRECISION (sizetype))))
-       {
-         gcc_assert (operands[i-1].opcode == MEM_REF);
-         tree ops[2];
-         ops[0] = operands[i].op0;
-         ops[1] = wide_int_to_tree (sizetype, off);
          vn_nary_op_insert_pieces (2, POINTER_PLUS_EXPR,
                                    TREE_TYPE (op), ops, result,
                                    VN_INFO (result)->value_id);
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 946065144953..6198a1a5cdb1 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -255,6 +255,7 @@ vn_nary_op_t alloc_vn_nary_op_noinit (unsigned int, struct 
obstack *);
 unsigned int vn_nary_length_from_stmt (gimple *);
 void init_vn_nary_op_from_stmt (vn_nary_op_t, gassign *);
 hashval_t vn_nary_op_compute_hash (const vn_nary_op_t);
+bool vn_pp_nary_for_addr (const vec<vn_reference_op_s>&, tree[2]);
 tree vn_nary_op_lookup_stmt (gimple *, vn_nary_op_t *);
 tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
                               tree, tree *, vn_nary_op_t *);
diff --git a/gcc/vec.h b/gcc/vec.h
index eae4b0feb4bc..7e112d1a80a6 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -611,6 +611,7 @@ public:
   const T *end () const { return address () + length (); }
   const T &operator[] (unsigned) const;
   T &operator[] (unsigned);
+  const T &last (void) const;
   T &last (void);
   bool space (unsigned) const;
   bool iterate (unsigned, T *) const;
@@ -914,6 +915,14 @@ vec<T, A, vl_embed>::operator[] (unsigned ix)
 
 /* Get the final element of the vector, which must not be empty.  */
 
+template<typename T, typename A>
+inline const T &
+vec<T, A, vl_embed>::last (void) const
+{
+  gcc_checking_assert (m_vecpfx.m_num > 0);
+  return (*this)[m_vecpfx.m_num - 1];
+}
+
 template<typename T, typename A>
 inline T &
 vec<T, A, vl_embed>::last (void)
@@ -1588,6 +1597,8 @@ public:
   const T *end () const { return begin () + length (); }
   const T &operator[] (unsigned ix) const
   { return (*m_vec)[ix]; }
+  const T &last (void) const
+  { return m_vec->last (); }
 
   bool operator!=(const vec &other) const
   { return !(*this == other); }

Reply via email to