This patch completely eliminates the ptr_info_def structure. THe 3 fields are moved into a prange_storage  object, and all the routines are adjusted to pick up the fields there.   None of the API changes because everything keys off the SSA_NAME now.   Again, fairly mechanical, although I did clean up a few functions whose naming over the set had gotten kind of confusing.

I shuffled some of the bits in a prange_storage object so that this adjustment costs a bit less memory.

Bootstrapped on x86_64-pc-linux-gnu with no regressions.

Andrew

From 0cf7646e7e26bdea97966239fa71ccdf56f706a2 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <[email protected]>
Date: Thu, 22 Oct 2026 16:24:27 -0400
Subject: [PATCH 7/9] Eliminate ptr_info_def structure

This eliminates the ptr_info_def structure, and puts the three component
members directly into a prange_storage object.

Assisted-by: Claude Opus 5
Assisted-by: GPT-6.1-Sol

	* tree-core.h (struct ptr_info_def): Remove declaration.
	* tree-ssanames.cc (range_info_p): Remove.
	(range_info_fits_p): Adjust.
	(ssa_name_prange_storage): Rename from ssa_name_ptr_info and adjust.
	(set_pt_solution): New.
	(get_pt_solution): Rename from get_ptr_info and adjust.
	(ssa_name_pt_solution): Adjust.
	(set_ssa_name_pt_solution): Adjust.
	(range_info_set_range): Adjust.
	(set_range_info): Adjust.
	(set_ptr_nonnull): Adjust.
	(get_nonzero_bits_1): Adjust.
	(get_known_nonzero_bits_1 ): Adjust.
	(get_ptr_info_alignment): Adjust.
	(mark_ptr_info_alignment_unknown): Adjust.
	(set_ptr_info_alignment): Adjust.
	(set_ssa_name_ptr_info): Remove.
	(duplicate_ssa_name_ptr_info): Adjust.
	(duplicate_ssa_name_range_info): Adjust.
	(duplicate_ssa_name_fn): Adjust.
	(reset_flow_sensitive_info): Adjust.
	(flow_sensitive_info_storage::save): Adjust.
	(flow_sensitive_info_storage::restore): Adjust.
	* tree-ssanames.h (struct ptr_info_def): Remove.
	(flow_sensitive_info_storage::align): Remove.
	(flow_sensitive_info_storage::misalign): Remove.
	* value-range-storage.cc (prange_storage::prange_storage): Set
	new fields.
	* value-range-storage.h (prange_storage::ptr_info): Remove.
	(prange_storage::pt): New.
	(prange_storage::align): New.
	(prange_storage::misalign): New.
---
 gcc/tree-core.h            |   1 -
 gcc/tree-ssanames.cc       | 210 +++++++++++++++++--------------------
 gcc/tree-ssanames.h        |  33 +-----
 gcc/value-range-storage.cc |   9 +-
 gcc/value-range-storage.h  |  22 ++--
 5 files changed, 121 insertions(+), 154 deletions(-)

diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 6bab44f3c6d..bea6bb5cc11 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 struct function;
 struct real_value;
 struct fixed_value;
-struct ptr_info_def;
 struct die_struct;
 class irange;
 
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index e244c34a799..c0e5de75f59 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -73,20 +73,12 @@ unsigned int ssa_name_nodes_created;
 #define FREE_SSANAMES(fun) (fun)->gimple_df->free_ssanames
 #define FREE_SSANAMES_QUEUE(fun) (fun)->gimple_df->free_ssanames_queue
 
-/* Return TRUE if NAME has global range info.  */
-
-inline bool
-range_info_p (const_tree name)
-{
-  return SSA_NAME_RANGE_INFO (name);
-}
-
 /* Return TRUE if R fits in the global range of NAME.  */
 
 inline bool
 range_info_fits_p (tree name, const vrange &r)
 {
-  gcc_checking_assert (range_info_p (name));
+  gcc_checking_assert (SSA_NAME_RANGE_INFO (name));
   vrange_storage *mem = SSA_NAME_RANGE_INFO (name);
   return mem->fits_p (r);
 }
@@ -111,38 +103,58 @@ range_info_free (tree name)
   ggc_free (mem);
 }
 
-/* Return the aliasing information for ssa-name NAME, or NULL if there
-   is none.  Return NULL for non pointer types.  */
+/* Return NAME's pointer range storage, or NULL if none exists.  */
 
-static inline struct ptr_info_def *
-ssa_name_ptr_info (const_tree name)
+static inline prange_storage *
+ssa_name_prange_storage (const_tree name)
 {
   vrange_storage *mem = SSA_NAME_RANGE_INFO (name);
   if (!mem || mem->m_discriminator != VR_PRANGE)
     return NULL;
-  return static_cast <prange_storage *> (mem)->ptr_info;
+  return static_cast <prange_storage *> (mem);
+}
+
+/* Attach PT to NAME, creating range storage if necessary.  */
+
+static void
+set_pt_solution (tree name, pt_solution *pt)
+{
+  gcc_checking_assert (POINTER_TYPE_P (TREE_TYPE (name)));
+  if (!SSA_NAME_RANGE_INFO (name))
+    SSA_NAME_RANGE_INFO (name) = ggc_alloc_vrange_storage (TREE_TYPE (name));
+  ssa_name_prange_storage (name)->pt = pt;
 }
 
-/* Defined below.  */
-static struct ptr_info_def *get_ptr_info (tree);
+/* Return NAME's solution, creating an unknown solution if necessary.  */
 
-/* Return the points-to solution for ssa-name NAME.  Return NULL if it has
-   none or is a non pointer types.  */
+static pt_solution *
+get_pt_solution (tree name)
+{
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (name)));
+  prange_storage *s = ssa_name_prange_storage (name);
+  if (s && s->pt)
+    return s->pt;
+  pt_solution *pt = ggc_cleared_alloc<pt_solution> ();
+  pt_solution_reset (pt);
+  set_pt_solution (name, pt);
+  return pt;
+}
+
+/* Return NAME's points-to solution, or NULL if none exists.  */
 
 const pt_solution *
 ssa_name_pt_solution (const_tree name)
 {
-  struct ptr_info_def *pi = ssa_name_ptr_info (name);
-  return pi ? &pi->pt : NULL;
+  prange_storage *s = ssa_name_prange_storage (name);
+  return s ? s->pt : NULL;
 }
 
-/* Make PT the points-to solution for NAME, which must have pointer type.  */
+/* Make PT the points-to solution for NAME.  */
 
 void
 set_ssa_name_pt_solution (tree name, const pt_solution &pt)
 {
-  /* get_ptr_info asserts NAME is a pointer type.  */
-  get_ptr_info (name)->pt = pt;
+  *get_pt_solution (name) = pt;
 }
 
 /* Return the global range for NAME in R.  */
@@ -159,20 +171,29 @@ range_info_get_range (const_tree name, vrange &r)
 inline bool
 range_info_set_range (tree name, const vrange &r)
 {
-  if (!range_info_p (name) || !range_info_fits_p (name, r))
+  if (!SSA_NAME_RANGE_INFO (name) || !range_info_fits_p (name, r))
     {
-      // Aliasing info belongs to NAME, not to the prange storage object which
-      // might get reallocated.  ptr_info_def addresses may be cached
-      // elsewhere, so save and copy it back after any reallocation.
-      ptr_info_def *pi = ssa_name_ptr_info (name);
-      if (range_info_p (name))
+      // Preserve SSA-owned points-to and alignment information when the
+      // variable-sized range storage must grow.
+      pt_solution *pt = NULL;
+      unsigned int align = 0, misalign = 0;
+      if (prange_storage *old = ssa_name_prange_storage (name))
+	{
+	  pt = old->pt;
+	  align = old->align;
+	  misalign = old->misalign;
+	}
+      if (SSA_NAME_RANGE_INFO (name))
 	range_info_free (name);
 
       vrange_storage *mem = range_info_alloc (name, r);
-      if (pi && mem)
+      if (mem && (pt || align))
 	{
 	  gcc_checking_assert (mem->m_discriminator == VR_PRANGE);
-	  static_cast <prange_storage *> (mem)->ptr_info = pi;
+	  prange_storage *s = static_cast <prange_storage *> (mem);
+	  s->pt = pt;
+	  s->align = align;
+	  s->misalign = misalign;
 	}
       return mem != NULL;
     }
@@ -467,7 +488,7 @@ set_range_info (tree name, const vrange &r)
   // Pick up the current range, or VARYING if none.
   tree type = TREE_TYPE (name);
   value_range tmp (type);
-  if (range_info_p (name))
+  if (SSA_NAME_RANGE_INFO (name))
     range_info_get_range (name, tmp);
   else
     tmp.set_varying (type);
@@ -478,9 +499,9 @@ set_range_info (tree name, const vrange &r)
 
   if (POINTER_TYPE_P (type))
     {
-      // If R is nonnull and pi is not, set nonnull.
-      struct ptr_info_def *pi = get_ptr_info (name);
-      if (!tmp.contains_zero_p () && pi->pt.null)
+      // Preserve nonnullness in the points-to solution as well.
+      pt_solution *pt = get_pt_solution (name);
+      if (!tmp.contains_zero_p () && pt->null)
 	set_ptr_nonnull (name);
     }
 
@@ -508,8 +529,7 @@ void
 set_ptr_nonnull (tree name)
 {
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (name)));
-  struct ptr_info_def *pi = get_ptr_info (name);
-  pi->pt.null = 0;
+  get_pt_solution (name)->null = 0;
 }
 
 /* Update the non-zero bits bitmask of NAME.  */
@@ -574,7 +594,7 @@ get_nonzero_bits_1 (const_tree name)
       return wi::shwi (-1, precision);
     }
 
-  if (!range_info_p (name) || !irange::supports_p (TREE_TYPE (name)))
+  if (!SSA_NAME_RANGE_INFO (name) || !irange::supports_p (TREE_TYPE (name)))
     return wi::shwi (-1, precision);
 
   int_range_max tmp;
@@ -622,7 +642,7 @@ get_known_nonzero_bits_1 (const_tree name)
   if (TREE_CODE (name) != SSA_NAME || POINTER_TYPE_P (TREE_TYPE (name)))
     return wi::shwi (0, precision);
 
-  if (!range_info_p (name) || !irange::supports_p (TREE_TYPE (name)))
+  if (!SSA_NAME_RANGE_INFO (name) || !irange::supports_p (TREE_TYPE (name)))
     return wi::shwi (0, precision);
 
   int_range_max tmp;
@@ -776,7 +796,7 @@ bool
 get_ptr_info_alignment (const_tree name, unsigned int *alignp,
 			unsigned int *misalignp)
 {
-  struct ptr_info_def *pi = ssa_name_ptr_info (name);
+  prange_storage *pi = ssa_name_prange_storage (name);
 
   if (pi && pi->align)
     {
@@ -795,7 +815,7 @@ get_ptr_info_alignment (const_tree name, unsigned int *alignp,
 void
 mark_ptr_info_alignment_unknown (tree name)
 {
-  struct ptr_info_def *pi = ssa_name_ptr_info (name);
+  prange_storage *pi = ssa_name_prange_storage (name);
 
   if (pi)
     {
@@ -815,50 +835,14 @@ set_ptr_info_alignment (tree name, unsigned int align, unsigned int misalign)
   gcc_assert ((align & (align - 1)) == 0);
   gcc_assert ((misalign & ~(align - 1)) == 0);
 
-  struct ptr_info_def *pi = get_ptr_info (name);
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (name)));
+  if (!SSA_NAME_RANGE_INFO (name))
+    SSA_NAME_RANGE_INFO (name) = ggc_alloc_vrange_storage (TREE_TYPE (name));
+  prange_storage *pi = ssa_name_prange_storage (name);
   pi->align = align;
   pi->misalign = misalign;
 }
 
-/* Make PI the aliasing information for NAME.  Allocate a VARYING range if
-   NAME does not already have a range.  */
-
-static void
-set_ssa_name_ptr_info (tree name, struct ptr_info_def *pi)
-{
-  gcc_checking_assert (POINTER_TYPE_P (TREE_TYPE (name)));
-
-  if (!range_info_p (name))
-    SSA_NAME_RANGE_INFO (name) = ggc_alloc_vrange_storage (TREE_TYPE (name));
-
-  vrange_storage *mem = SSA_NAME_RANGE_INFO (name);
-  gcc_checking_assert (mem && mem->m_discriminator == VR_PRANGE);
-  static_cast <prange_storage *> (mem)->ptr_info = pi;
-}
-
-/* Return the alias information associated with pointer T.  It creates a
-   new instance if none existed.  */
-
-static struct ptr_info_def *
-get_ptr_info (tree t)
-{
-  struct ptr_info_def *pi;
-
-  gcc_assert (POINTER_TYPE_P (TREE_TYPE (t)));
-
-  pi = ssa_name_ptr_info (t);
-  if (pi == NULL)
-    {
-      // The cleared allocation leaves align and misalign zero, which is
-      // what unknown alignment is, so there is nothing more to initialize.
-      pi = ggc_cleared_alloc<ptr_info_def> ();
-      pt_solution_reset (&pi->pt);
-      set_ssa_name_ptr_info (t, pi);
-    }
-
-  return pi;
-}
-
 
 /* Creates a new SSA name using the template NAME tobe defined by
    statement STMT in function FN.  */
@@ -888,16 +872,22 @@ void
 duplicate_ssa_name_ptr_info (tree dest, tree src)
 {
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (dest)));
-  gcc_assert (!ssa_name_ptr_info (dest));
+  gcc_assert (!ssa_name_pt_solution (dest));
 
-  struct ptr_info_def *ptr_info = (src ? ssa_name_ptr_info (src) : NULL);
-  if (!ptr_info)
+  prange_storage *s = src ? ssa_name_prange_storage (src) : NULL;
+  if (!s || (!s->pt && !s->align))
     return;
 
-  struct ptr_info_def *new_ptr_info = ggc_alloc<ptr_info_def> ();
-  *new_ptr_info = *ptr_info;
-
-  set_ssa_name_ptr_info (dest, new_ptr_info);
+  /* Copy alignment independently of whether SRC has a PTA solution.  */
+  unsigned int align = s->align, misalign = s->misalign;
+  if (s->pt)
+    {
+      pt_solution *copy = ggc_alloc<pt_solution> ();
+      *copy = *s->pt;
+      set_pt_solution (dest, copy);
+    }
+  if (align)
+    set_ptr_info_alignment (dest, align, misalign);
 }
 
 /* Copy any global range and aliasing information from SRC to NAME.  */
@@ -905,9 +895,9 @@ duplicate_ssa_name_ptr_info (tree dest, tree src)
 void
 duplicate_ssa_name_range_info (tree name, tree src)
 {
-  gcc_checking_assert (!range_info_p (name));
+  gcc_checking_assert (!SSA_NAME_RANGE_INFO (name));
 
-  if (!range_info_p (src))
+  if (!SSA_NAME_RANGE_INFO (src))
     return;
 
   value_range src_range (TREE_TYPE (src));
@@ -945,7 +935,7 @@ duplicate_ssa_name_fn (struct function *fn, tree name, gimple *stmt)
 {
   tree new_name = copy_ssa_name_fn (fn, name, stmt);
 
-  if (range_info_p (name))
+  if (SSA_NAME_RANGE_INFO (name))
     duplicate_ssa_name_range_info (new_name, name);
 
   return new_name;
@@ -959,15 +949,16 @@ void
 reset_flow_sensitive_info (tree name)
 {
   /* Aliasing info is not flow sensitive, so preserve it if present.  */
-  ptr_info_def *pi = ssa_name_ptr_info (name);
+  prange_storage *s = ssa_name_prange_storage (name);
+  pt_solution *pt = s ? s->pt : NULL;
   SSA_NAME_RANGE_INFO (name) = NULL;
-  if (pi)
+  if (pt)
     {
-      set_ssa_name_ptr_info (name, pi);
+      set_pt_solution (name, pt);
       /* [E]VRP can derive context sensitive alignment info and
-	 non-nullness properties.  We must reset both.  */
-      mark_ptr_info_alignment_unknown (name);
-      pi->pt.null = 1;
+	 non-nullness properties.  We must reset both.  The alignment went
+	 with the range storage above; only the nullness is left.  */
+      pt->null = 1;
     }
 
   // Clear range info in the current range query.
@@ -1118,13 +1109,8 @@ flow_sensitive_info_storage::save (tree name)
       return;
     }
   state = -1;
-  if (!get_ptr_info_alignment (name, &align, &misalign))
-    {
-      align = 0;
-      misalign = 0;
-    }
-  auto ptr_info = ssa_name_ptr_info (name);
-  null = ptr_info ? ptr_info->pt.null : true;
+  const pt_solution *pt = ssa_name_pt_solution (name);
+  null = pt ? pt->null : true;
 }
 
 /* Restore the flow sensitive info from NAME. */
@@ -1133,6 +1119,9 @@ void
 flow_sensitive_info_storage::restore (tree name)
 {
   gcc_assert (state != 0);
+  /* The storage carries the range, its bitmask and -- for now -- the
+     alignment, so reinstating it restores all three.  Only the nullness
+     lives outside it.  */
   SSA_NAME_RANGE_INFO (name) = range_info;
   if (!POINTER_TYPE_P (TREE_TYPE (name)))
     {
@@ -1140,16 +1129,9 @@ flow_sensitive_info_storage::restore (tree name)
       return;
     }
   gcc_assert (state == -1);
-  auto ptr_info = ssa_name_ptr_info (name);
-  /* If there was no flow sensitive info on the pointer
-     just return, there is nothing to restore to.  */
-  if (!ptr_info)
-    return;
-  if (align != 0)
-    set_ptr_info_alignment (name, align, misalign);
-  else
-    mark_ptr_info_alignment_unknown (name);
-  ssa_name_ptr_info (name)->pt.null = null;
+  prange_storage *s = ssa_name_prange_storage (name);
+  if (s && s->pt)
+    s->pt->null = null;
 }
 
 /* Save off the flow sensitive info from NAME.
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index fa066f7f8ea..68afacb0f29 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -20,32 +20,6 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_TREE_SSANAMES_H
 #define GCC_TREE_SSANAMES_H
 
-/* Aliasing information for SSA_NAMEs representing pointer variables.  */
-
-struct GTY(()) ptr_info_def
-{
-  /* The points-to solution.  */
-  struct pt_solution pt;
-
-  /* Alignment and misalignment of the pointer in bytes.  Together
-     align and misalign specify low known bits of the pointer.
-     ptr & (align - 1) == misalign.  */
-
-  /* When known, this is the power-of-two byte alignment of the object this
-     pointer points into.  This is usually DECL_ALIGN_UNIT for decls and
-     MALLOC_ABI_ALIGNMENT for allocated storage.  When the alignment is not
-     known, it is zero.  Do not access directly: the only accessors are
-     get_ptr_info_alignment, set_ptr_info_alignment and
-     mark_ptr_info_alignment_unknown, and they take the SSA name rather
-     than this structure, so that the representation can move.  */
-  unsigned int align;
-
-  /* When alignment is known, the byte offset this pointer differs from the
-     above alignment.  Access only through the same helper functions as align
-     above.  */
-  unsigned int misalign;
-};
-
 /* Return NAME's points-to solution, or NULL if it has none.  Returns NULL
    for a non pointer type.  */
 extern const pt_solution *ssa_name_pt_solution (const_tree name);
@@ -157,11 +131,10 @@ private:
      -1 means a pointer type is saved.
      -2 means a pointer type is saved but no information was saved. */
   int state = 0;
-  /* The range info for non pointers */
+  /* The range info, which for a pointer also carries the bitmask and the
+     alignment, so those need no separate slot here.  */
   vrange_storage *range_info = nullptr;
-  /* Flow sensitive pointer information. */
-  unsigned int align = 0;
-  unsigned int misalign = 0;
+  /* Flow sensitive pointer information not held in the range.  */
   bool null = true;
 };
 
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index b121ffac754..35997372e7c 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -638,9 +638,12 @@ prange_storage::alloc (vrange_internal_alloc &allocator, const prange &r,
 
 prange_storage::prange_storage (const prange &r) : vrange_storage (VR_PRANGE)
 {
-  // Aliasing info is not part of the range, so it is never copied from one.
-  // Only set_ssa_name_ptr_info() in tree-ssanames.cc ever makes this non-null.
-  ptr_info = NULL;
+  // None of these is part of the range, so none is ever copied from one.
+  // Only the accessors in tree-ssanames.cc ever make them non-zero, and
+  // range_info_set_range carries them across a reallocation.
+  pt = NULL;
+  align = 0;
+  misalign = 0;
 
   unsigned num_words;
   enum prange_kind kind = prange_format (r, num_words);
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 46e98684360..f4c264d5ede 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -113,6 +113,13 @@ const unsigned int PRANGE_STORAGE_NINTS = 4;
 // Efficient memory storage for a prange.
 class GTY((tag ("VR_PRANGE"))) prange_storage : public vrange_storage
 {
+private:
+  // vrange_storage ends after four bytes but the first pointer member below
+  // needs eight-byte alignment, so there is a four-byte hole.
+  enum prange_kind m_kind : 4;
+  unsigned int m_has_bitmask : 1;
+  unsigned int m_points_to_p : 1;
+
 public:
   friend void gt_ggc_mx_vrange_storage(void *);
   friend void gt_pch_nx_vrange_storage(void *);
@@ -126,18 +133,21 @@ public:
   bool fits_p (const prange &r) const;
   void dump () const;
 
-  // Pointer aliasing information.  Managed separately, and reached only
-  // through the accessors in tree-ssanames.h.
-  struct ptr_info_def *ptr_info;
+  // The points-to solution for the SSA name is flow insensitive and is
+  // reached only through ssa_name_pt_solution.
+  struct pt_solution *pt;
+
+  // Alignment and misalignment of the pointer in bytes.  Together
+  // align and misalign specify low known bits of the pointer.
+  // ptr & (align - 1) == misalign.
+  unsigned int align;
+  unsigned int misalign;
 
 private:
   DISABLE_COPY_AND_ASSIGN (prange_storage);
   prange_storage (const prange &r);
   static enum prange_kind prange_format (const prange &r, unsigned &num_words);
 
-  enum prange_kind m_kind;
-  bool m_has_bitmask;
-  bool m_points_to_p;
   tree m_pt;
 
   // We don't use TRAILING_WIDE_INT_ACCESSOR because the getters here
-- 
2.56.0

Reply via email to