[PATCH] tree-optimization/119997 - &ptr->field no longer subject to PRE

Richard Biener rguenther@suse.de
Tue Apr 29 10:39:49 GMT 2025


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.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

	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.
---
 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(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-35.c

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 00000000000..1b49445fc3c
--- /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 ecf45d29e76..f6c531e4892 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 481ab8b243d..f7f50c3de99 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 94606514495..6198a1a5cdb 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 eae4b0feb4b..7e112d1a80a 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); }
-- 
2.43.0


More information about the Gcc-patches mailing list