Attached is the subset of the patch in part (2) below: refactor
compute_objsize_r into helpers.  It applies on top of patch 3/5.

On 12/3/21 5:00 PM, Jeff Law wrote:


On 11/8/2021 7:34 PM, Martin Sebor via Gcc-patches wrote:
The pointer-query code that implements compute_objsize() that's
in turn used by most middle end access warnings now has a few
warts in it and (at least) one bug.  With the exception of
the bug the warts aren't behind any user-visible bugs that
I know of but they do cause problems in new code I've been
implementing on top of it.  Besides fixing the one bug (just
a typo) the attached patch cleans up these latent issues:

1) It moves the bndrng member from the access_ref class to
   access_data.  As a FIXME in the code notes, the member never
   did belong in the former and only takes up space in the cache.

2) The compute_objsize_r() function is big, unwieldy, and tedious
   to step through because of all the if statements that are better
   coded as one switch statement.  This change factors out more
   of its code into smaller handler functions as has been suggested
   and done a few times before.

3) (2) exposed a few places where I fail to pass the current
   GIMPLE statement down to ranger.  This leads to worse quality
   range info, including possible false positives and negatives.
   I just spotted these problems in code review but I haven't
   taken the time to come up with test cases.  This change fixes
   these oversights as well.

4) The handling of PHI statements is also in one big, hard-to-
   follow function.  This change moves the handling of each PHI
   argument into its own handler which merges it into the previous
   argument.  This makes the code easier to work with and opens it
   to reuse also for MIN_EXPR and MAX_EXPR.  (This is primarily
   used to print informational notes after warnings.)

5) Finally, the patch factors code to dump each access_ref
   cached by the pointer_query cache out of pointer_query::dump
   and into access_ref::dump.  This helps with debugging.

These changes should have no user-visible effect and other than
a regression test for the typo (PR 103143) come with no tests.
They've been tested on x86_64-linux.
Sigh.  You've identified 6 distinct changes above.  The 5 you've enumerated plus a typo fix somewhere.  There's no reason why they need to be a single patch and many reasons why they should be a series of independent patches.    Combining them into a single patch isn't how we do things and it hides the actual bugfix in here.

Please send a fix for the typo first since that should be able to trivially go forward.  Then  a patch for item #1.  That should be trivial to review when it's pulled out from teh rest of the patch. Beyond that, your choice on ordering, but you need to break this down.




Jeff


commit 7d1d8cc18678ccaec5f274919e0c9910ccfea86e
Author: Martin Sebor <mse...@redhat.com>
Date:   Mon Dec 6 09:33:32 2021 -0700

    Refactor compute_objsize_r into helpers.
    
    gcc/ChangeLog:
    
            * pointer-query.cc (compute_objsize_r): Add an argument.
            (gimple_call_return_array): Pass a new argument to compute_objsize_r.
            (access_ref::merge_ref): Same.
            (access_ref::inform_access): Add an argument and use it.
            (access_data::access_data): Initialize new member.
            (handle_min_max_size): Pass a new argument to compute_objsize_r.
            (handle_decl): New function.
            (handle_array_ref): Pass a new argument to compute_objsize_r.
            Avoid incrementing deref.
            (set_component_ref_size): New function.
            (handle_component_ref): New function.
            (handle_mem_ref): Pass a new argument to compute_objsize_r.
            Only increment deref after successfully computing object size.
            (handle_ssa_name): New function.
            (compute_objsize_r): Move code into helpers and call them.
            (compute_objsize): Pass a new argument to compute_objsize_r.
            * pointer-query.h (access_ref::inform_access): Add an argument.
            (access_data::ostype): New member.

diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index 24fbac84ec4..3f583110c71 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -43,7 +43,7 @@
 #include "tree-ssanames.h"
 #include "target.h"
 
-static bool compute_objsize_r (tree, gimple *, int, access_ref *,
+static bool compute_objsize_r (tree, gimple *, bool, int, access_ref *,
 			       ssa_name_limit_t &, pointer_query *);
 
 /* Wrapper around the wide_int overload of get_range that accepts
@@ -199,7 +199,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
 	       of the source object.  */
 	    access_ref aref;
 	    tree src = gimple_call_arg (stmt, 1);
-	    if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)
+	    if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry)
 		&& aref.sizrng[1] < offrng[1])
 	      offrng[1] = aref.sizrng[1];
 	  }
@@ -233,7 +233,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
       {
 	access_ref aref;
 	tree src = gimple_call_arg (stmt, 1);
-	if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry))
+	if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry))
 	  offrng[1] = aref.sizrng[1] - 1;
 	else
 	  offrng[1] = HOST_WIDE_INT_M1U;
@@ -258,7 +258,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
 	       of the source object.  */
 	    access_ref aref;
 	    tree src = gimple_call_arg (stmt, 1);
-	    if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)
+	    if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry)
 		&& aref.sizrng[1] < offrng[1])
 	      offrng[1] = aref.sizrng[1];
 	  }
@@ -635,7 +635,7 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
 		       ssa_name_limit_t &snlim, pointer_query &qry)
 {
   access_ref aref;
-  if (!compute_objsize_r (arg, stmt, ostype, &aref, snlim, &qry)
+  if (!compute_objsize_r (arg, stmt, false, ostype, &aref, snlim, &qry)
       || aref.sizrng[0] < 0)
     /* This may be a PHI with all null pointer arguments.  */
     return false;
@@ -997,42 +997,45 @@ void access_ref::add_offset (const offset_int &min, const offset_int &max)
    WRITE is set for a write access and clear for a read access.  */
 
 void
-access_ref::inform_access (access_mode mode) const
+access_ref::inform_access (access_mode mode, int ostype /* = 1 */) const
 {
   const access_ref &aref = *this;
   if (!aref.ref)
     return;
 
-  if (aref.phi ())
+  if (phi ())
     {
       /* Set MAXREF to refer to the largest object and fill ALL_REFS
 	 with data for all objects referenced by the PHI arguments.  */
       access_ref maxref;
       auto_vec<access_ref> all_refs;
-      if (!get_ref (&all_refs, &maxref))
+      if (!get_ref (&all_refs, &maxref, ostype))
 	return;
 
-      /* Except for MAXREF, the rest of the arguments' offsets need not
-	 reflect one added to the PHI itself.  Determine the latter from
-	 MAXREF on which the result is based.  */
-      const offset_int orng[] =
+      if (all_refs.length ())
 	{
-	  offrng[0] - maxref.offrng[0],
-	  wi::smax (offrng[1] - maxref.offrng[1], offrng[0]),
-	};
+	  /* Except for MAXREF, the rest of the arguments' offsets need not
+	     reflect one added to the PHI itself.  Determine the latter from
+	     MAXREF on which the result is based.  */
+	  const offset_int orng[] =
+	    {
+	     offrng[0] - maxref.offrng[0],
+	     wi::smax (offrng[1] - maxref.offrng[1], offrng[0]),
+	    };
 
-      /* Add the final PHI's offset to that of each of the arguments
-	 and recurse to issue an inform message for it.  */
-      for (unsigned i = 0; i != all_refs.length (); ++i)
-	{
-	  /* Skip any PHIs; those could lead to infinite recursion.  */
-	  if (all_refs[i].phi ())
-	    continue;
+	  /* Add the final PHI's offset to that of each of the arguments
+	     and recurse to issue an inform message for it.  */
+	  for (unsigned i = 0; i != all_refs.length (); ++i)
+	    {
+	      /* Skip any PHIs; those could lead to infinite recursion.  */
+	      if (all_refs[i].phi ())
+		continue;
 
-	  all_refs[i].add_offset (orng[0], orng[1]);
-	  all_refs[i].inform_access (mode);
+	      all_refs[i].add_offset (orng[0], orng[1]);
+	      all_refs[i].inform_access (mode, ostype);
+	    }
+	  return;
 	}
-      return;
     }
 
   /* Convert offset range and avoid including a zero range since it
@@ -1244,7 +1247,7 @@ access_data::access_data (range_query *query, gimple *stmt, access_mode mode,
 			  bool minwrite /* = false */,
 			  tree maxread /* = NULL_TREE */,
 			  bool minread /* = false */)
-  : stmt (stmt), call (), dst (), src (), mode (mode)
+  : stmt (stmt), call (), dst (), src (), mode (mode), ostype ()
 {
   set_bound (dst_bndrng, maxwrite, minwrite, query, stmt);
   set_bound (src_bndrng, maxread, minread, query, stmt);
@@ -1257,7 +1260,7 @@ access_data::access_data (range_query *query, tree expr, access_mode mode,
 			  bool minwrite /* = false */,
 			  tree maxread /* = NULL_TREE */,
 			  bool minread /* = false */)
-  : stmt (), call (expr),  dst (), src (), mode (mode)
+  : stmt (), call (expr),  dst (), src (), mode (mode), ostype ()
 {
   set_bound (dst_bndrng, maxwrite, minwrite, query, stmt);
   set_bound (src_bndrng, maxread, minread, query, stmt);
@@ -1406,7 +1409,8 @@ pointer_query::get_ref (tree ptr, int ostype /* = 1 */) const
    there or compute it and insert it into the cache if it's nonnonull.  */
 
 bool
-pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref, int ostype /* = 1 */)
+pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref,
+			int ostype /* = 1 */)
 {
   const unsigned version
     = TREE_CODE (ptr) == SSA_NAME ? SSA_NAME_VERSION (ptr) : 0;
@@ -1606,7 +1610,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
      for the expression.  */
   access_ref aref[2] = { *pref, *pref };
   tree arg1 = gimple_assign_rhs1 (stmt);
-  if (!compute_objsize_r (arg1, stmt, ostype, &aref[0], snlim, qry))
+  if (!compute_objsize_r (arg1, stmt, false, ostype, &aref[0], snlim, qry))
     {
       aref[0].base0 = false;
       aref[0].offrng[0] = aref[0].offrng[1] = 0;
@@ -1615,7 +1619,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
     }
 
   tree arg2 = gimple_assign_rhs2 (stmt);
-  if (!compute_objsize_r (arg2, stmt, ostype, &aref[1], snlim, qry))
+  if (!compute_objsize_r (arg2, stmt, false, ostype, &aref[1], snlim, qry))
     {
       aref[1].base0 = false;
       aref[1].offrng[0] = aref[1].offrng[1] = 0;
@@ -1678,6 +1682,46 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
   return true;
 }
 
+/* A helper of compute_objsize_r() to determine the size of a DECL.
+   Return true on success and (possibly in the future) false on failure.  */
+
+static bool
+handle_decl (tree decl, bool addr, access_ref *pref)
+{
+  tree decl_type = TREE_TYPE (decl);
+
+  pref->ref = decl;
+
+  /* Reset the offset in case it was set by a prior call and not
+     cleared by the caller.  The offset is only adjusted after
+     the identity of the object has been determined.  */
+  pref->offrng[0] = pref->offrng[1] = 0;
+
+  if (!addr && POINTER_TYPE_P (decl_type))
+    {
+      /* Set the maximum size if the reference is to the pointer
+	 itself (as opposed to what it points to), and clear
+	 BASE0 since the offset isn't necessarily zero-based.  */
+      pref->set_max_size_range ();
+      pref->base0 = false;
+      return true;
+    }
+
+  /* Valid offsets into the object are nonnegative.  */
+  pref->base0 = true;
+
+  if (tree size = decl_init_size (decl, false))
+    if (TREE_CODE (size) == INTEGER_CST)
+      {
+	pref->sizrng[0] = wi::to_offset (size);
+	pref->sizrng[1] = pref->sizrng[0];
+	return true;
+      }
+
+  pref->set_max_size_range ();
+  return true;
+}
+
 /* A helper of compute_objsize_r() to determine the size from ARRAY_REF
    AREF.  ADDR is true if PTR is the operand of ADDR_EXPR.  Return true
    on success and false on failure.  */
@@ -1689,8 +1733,6 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
 {
   gcc_assert (TREE_CODE (aref) == ARRAY_REF);
 
-  ++pref->deref;
-
   tree arefop = TREE_OPERAND (aref, 0);
   tree reftype = TREE_TYPE (arefop);
   if (!addr && TREE_CODE (TREE_TYPE (reftype)) == POINTER_TYPE)
@@ -1698,7 +1740,7 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
        of known bound.  */
     return false;
 
-  if (!compute_objsize_r (arefop, stmt, ostype, pref, snlim, qry))
+  if (!compute_objsize_r (arefop, stmt, addr, ostype, pref, snlim, qry))
     return false;
 
   offset_int orng[2];
@@ -1759,6 +1801,96 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
   return true;
 }
 
+/* Given a COMPONENT_REF CREF, set *PREF size to the size of the referenced
+   member.  */
+
+static void
+set_component_ref_size (tree cref, access_ref *pref)
+{
+  const tree base = TREE_OPERAND (cref, 0);
+  const tree base_type = TREE_TYPE (base);
+
+  /* SAM is set for array members that might need special treatment.  */
+  special_array_member sam;
+  tree size = component_ref_size (cref, &sam);
+  if (sam == special_array_member::int_0)
+    pref->sizrng[0] = pref->sizrng[1] = 0;
+  else if (!pref->trail1special && sam == special_array_member::trail_1)
+    pref->sizrng[0] = pref->sizrng[1] = 1;
+  else if (size && TREE_CODE (size) == INTEGER_CST)
+    pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+  else
+    {
+      /* When the size of the member is unknown it's either a flexible
+	 array member or a trailing special array member (either zero
+	 length or one-element).  Set the size to the maximum minus
+	 the constant size of the base object's type.  */
+      pref->sizrng[0] = 0;
+      pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
+      if (tree base_size = TYPE_SIZE_UNIT (base_type))
+	if (TREE_CODE (base_size) == INTEGER_CST)
+	  pref->sizrng[1] -= wi::to_offset (base_size);
+    }
+}
+
+/* A helper of compute_objsize_r() to determine the size from COMPONENT_REF
+   CREF.  Return true on success and false on failure.  */
+
+static bool
+handle_component_ref (tree cref, gimple *stmt, bool addr, int ostype,
+		      access_ref *pref, ssa_name_limit_t &snlim,
+		      pointer_query *qry)
+{
+  gcc_assert (TREE_CODE (cref) == COMPONENT_REF);
+
+  const tree base = TREE_OPERAND (cref, 0);
+  const tree base_type = TREE_TYPE (base);
+  if (TREE_CODE (base_type) == UNION_TYPE)
+    /* In accesses through union types consider the entire unions
+       rather than just their members.  */
+    ostype = 0;
+
+  tree field = TREE_OPERAND (cref, 1);
+
+  if (ostype == 0)
+    {
+      /* In OSTYPE zero (for raw memory functions like memcpy), use
+	 the maximum size instead if the identity of the enclosing
+	 object cannot be determined.  */
+      if (!compute_objsize_r (base, stmt, addr, ostype, pref, snlim, qry))
+	return false;
+
+      /* Otherwise, use the size of the enclosing object and add
+	 the offset of the member to the offset computed so far.  */
+      tree offset = byte_position (field);
+      if (TREE_CODE (offset) == INTEGER_CST)
+	pref->add_offset (wi::to_offset (offset));
+      else
+	pref->add_max_offset ();
+
+      if (!pref->ref)
+	/* PREF->REF may have been already set to an SSA_NAME earlier
+	   to provide better context for diagnostics.  In that case,
+	   leave it unchanged.  */
+	pref->ref = base;
+
+      return true;
+    }
+
+  pref->ref = field;
+
+  if (!addr && POINTER_TYPE_P (TREE_TYPE (field)))
+    {
+      /* Set maximum size if the reference is to the pointer member
+	 itself (as opposed to what it points to).  */
+      pref->set_max_size_range ();
+      return true;
+    }
+
+  set_component_ref_size (cref, pref);
+  return true;
+}
+
 /* A helper of compute_objsize_r() to determine the size from MEM_REF
    MREF.  Return true on success and false on failure.  */
 
@@ -1768,10 +1900,9 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
 {
   gcc_assert (TREE_CODE (mref) == MEM_REF);
 
-  ++pref->deref;
-
-  if (VECTOR_TYPE_P (TREE_TYPE (mref)))
-    {
+  tree mreftype = TYPE_MAIN_VARIANT (TREE_TYPE (mref));
+  if (VECTOR_TYPE_P (mreftype))
+      {
       /* Hack: Handle MEM_REFs of vector types as those to complete
 	 objects; those may be synthesized from multiple assignments
 	 to consecutive data members (see PR 93200 and 96963).
@@ -1785,9 +1916,11 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
     }
 
   tree mrefop = TREE_OPERAND (mref, 0);
-  if (!compute_objsize_r (mrefop, stmt, ostype, pref, snlim, qry))
+  if (!compute_objsize_r (mrefop, stmt, false, ostype, pref, snlim, qry))
     return false;
 
+  ++pref->deref;
+
   offset_int orng[2];
   tree off = pref->eval (TREE_OPERAND (mref, 1));
   range_query *const rvals = qry ? qry->rvals : NULL;
@@ -1802,168 +1935,283 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
   return true;
 }
 
-/* Helper to compute the size of the object referenced by the PTR
-   expression which must have pointer type, using Object Size type
-   OSTYPE (only the least significant 2 bits are used).
-   On success, sets PREF->REF to the DECL of the referenced object
-   if it's unique, otherwise to null, PREF->OFFRNG to the range of
-   offsets into it, and PREF->SIZRNG to the range of sizes of
-   the object(s).
-   SNLIM is used to avoid visiting the same PHI operand multiple
-   times, and, when nonnull, RVALS to determine range information.
-   Returns true on success, false when a meaningful size (or range)
-   cannot be determined.
-
-   The function is intended for diagnostics and should not be used
-   to influence code generation or optimization.  */
+/* A helper of compute_objsize_r() to determine the size from SSA_NAME
+   PTR.  Return true on success and false on failure.  */
 
 static bool
-compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
-		   ssa_name_limit_t &snlim, pointer_query *qry)
+handle_ssa_name (tree ptr, bool addr, int ostype,
+		 access_ref *pref, ssa_name_limit_t &snlim,
+		 pointer_query *qry)
 {
-  STRIP_NOPS (ptr);
+  if (!snlim.next ())
+    return false;
 
-  const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
-  if (addr)
+  /* Only process an SSA_NAME if the recursion limit has not yet
+     been reached.  */
+  if (qry)
     {
-      --pref->deref;
-      ptr = TREE_OPERAND (ptr, 0);
+      if (++qry->depth > qry->max_depth)
+	qry->max_depth = qry->depth;
+      if (const access_ref *cache_ref = qry->get_ref (ptr, ostype))
+	{
+	  /* Add the number of DEREFerences accummulated so far.  */
+	  const int deref = pref->deref;
+	  *pref = *cache_ref;
+	  pref->deref += deref;
+	  return true;
+	}
     }
 
-  if (DECL_P (ptr))
-    {
-      pref->ref = ptr;
-
-      /* Reset the offset in case it was set by a prior call and not
-	 cleared by the caller.  The offset is only adjusted after
-	 the identity of the object has been determined.  */
-      pref->offrng[0] = pref->offrng[1] = 0;
+  gimple *stmt = SSA_NAME_DEF_STMT (ptr);
+  if (is_gimple_call (stmt))
+    {
+      /* If STMT is a call to an allocation function get the size
+	 from its argument(s).  If successful, also set *PREF->REF
+	 to PTR for the caller to include in diagnostics.  */
+      wide_int wr[2];
+      range_query *const rvals = qry ? qry->rvals : NULL;
+      if (gimple_call_alloc_size (stmt, wr, rvals))
+	{
+	  pref->ref = ptr;
+	  pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
+	  pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
+	  /* Constrain both bounds to a valid size.  */
+	  offset_int maxsize = wi::to_offset (max_object_size ());
+	  if (pref->sizrng[0] > maxsize)
+	    pref->sizrng[0] = maxsize;
+	  if (pref->sizrng[1] > maxsize)
+	    pref->sizrng[1] = maxsize;
+	}
+      else
+	{
+	  /* For functions known to return one of their pointer arguments
+	     try to determine what the returned pointer points to, and on
+	     success add OFFRNG which was set to the offset added by
+	     the function (e.g., memchr) to the overall offset.  */
+	  bool past_end;
+	  offset_int offrng[2];
+	  if (tree ret = gimple_call_return_array (stmt, offrng, &past_end,
+						   snlim, qry))
+	    {
+	      if (!compute_objsize_r (ret, stmt, addr, ostype, pref, snlim, qry))
+		return false;
+
+	      /* Cap OFFRNG[1] to at most the remaining size of
+		 the object.  */
+	      offset_int remrng[2];
+	      remrng[1] = pref->size_remaining (remrng);
+	      if (remrng[1] != 0 && !past_end)
+		/* Decrement the size for functions that never return
+		   a past-the-end pointer.  */
+		remrng[1] -= 1;
+
+	      if (remrng[1] < offrng[1])
+		offrng[1] = remrng[1];
+	      pref->add_offset (offrng[0], offrng[1]);
+	    }
+	  else
+	    {
+	      /* For other calls that might return arbitrary pointers
+		 including into the middle of objects set the size
+		 range to maximum, clear PREF->BASE0, and also set
+		 PREF->REF to include in diagnostics.  */
+	      pref->set_max_size_range ();
+	      pref->base0 = false;
+	      pref->ref = ptr;
+	    }
+	}
+      qry->put_ref (ptr, *pref, ostype);
+      return true;
+    }
 
-      if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
+  if (gimple_nop_p (stmt))
+    {
+      /* For a function argument try to determine the byte size
+	 of the array from the current function declaratation
+	 (e.g., attribute access or related).  */
+      wide_int wr[2];
+      bool static_array = false;
+      if (tree ref = gimple_parm_array_size (ptr, wr, &static_array))
 	{
-	  /* Set the maximum size if the reference is to the pointer
-	     itself (as opposed to what it points to), and clear
-	     BASE0 since the offset isn't necessarily zero-based.  */
-	  pref->set_max_size_range ();
-	  pref->base0 = false;
+	  pref->parmarray = !static_array;
+	  pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
+	  pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
+	  pref->ref = ref;
+	  qry->put_ref (ptr, *pref, ostype);
 	  return true;
 	}
 
-      /* Valid offsets into the object are nonnegative.  */
-      pref->base0 = true;
-
-      if (tree size = decl_init_size (ptr, false))
-	if (TREE_CODE (size) == INTEGER_CST)
-	  {
-	    pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
-	    return true;
-	  }
-
       pref->set_max_size_range ();
+      pref->base0 = false;
+      pref->ref = ptr;
+      qry->put_ref (ptr, *pref, ostype);
       return true;
     }
 
-  const tree_code code = TREE_CODE (ptr);
-  range_query *const rvals = qry ? qry->rvals : NULL;
-
-  if (code == BIT_FIELD_REF)
+  if (gimple_code (stmt) == GIMPLE_PHI)
     {
-      tree ref = TREE_OPERAND (ptr, 0);
-      if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+      /* Pass PTR to get_ref() via PREF.  If all PHI arguments refer
+	 to the same object the function will replace it with it.  */
+      pref->ref = ptr;
+      access_ref phi_ref = *pref;
+      if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry))
 	return false;
+      *pref = phi_ref;
+      qry->put_ref (ptr, *pref, ostype);
+      return true;
+    }
 
-      offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2)));
-      pref->add_offset (off / BITS_PER_UNIT);
+  if (!is_gimple_assign (stmt))
+    {
+      /* Clear BASE0 since the assigned pointer might point into
+	 the middle of the object, set the maximum size range and,
+	 if the SSA_NAME refers to a function argumnent, set
+	 PREF->REF to it.  */
+      pref->base0 = false;
+      pref->set_max_size_range ();
+      pref->ref = ptr;
       return true;
     }
 
-  if (code == COMPONENT_REF)
+  tree_code code = gimple_assign_rhs_code (stmt);
+
+  if (code == MAX_EXPR || code == MIN_EXPR)
     {
-      tree ref = TREE_OPERAND (ptr, 0);
-      if (TREE_CODE (TREE_TYPE (ref)) == UNION_TYPE)
-	/* In accesses through union types consider the entire unions
-	   rather than just their members.  */
-	ostype = 0;
-      tree field = TREE_OPERAND (ptr, 1);
+      if (!handle_min_max_size (ptr, ostype, pref, snlim, qry))
+	return false;
 
-      if (ostype == 0)
-	{
-	  /* In OSTYPE zero (for raw memory functions like memcpy), use
-	     the maximum size instead if the identity of the enclosing
-	     object cannot be determined.  */
-	  if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
-	    return false;
-
-	  /* Otherwise, use the size of the enclosing object and add
-	     the offset of the member to the offset computed so far.  */
-	  tree offset = byte_position (field);
-	  if (TREE_CODE (offset) == INTEGER_CST)
-	    pref->add_offset (wi::to_offset (offset));
-	  else
-	    pref->add_max_offset ();
+      qry->put_ref (ptr, *pref, ostype);
+      return true;
+    }
 
-	  if (!pref->ref)
-	    /* REF may have been already set to an SSA_NAME earlier
-	       to provide better context for diagnostics.  In that case,
-	       leave it unchanged.  */
-	    pref->ref = ref;
-	  return true;
-	}
+  tree rhs = gimple_assign_rhs1 (stmt);
 
-      pref->ref = field;
+  if (code == ASSERT_EXPR)
+    {
+      rhs = TREE_OPERAND (rhs, 0);
+      return compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry);
+    }
 
-      if (!addr && POINTER_TYPE_P (TREE_TYPE (field)))
-	{
-	  /* Set maximum size if the reference is to the pointer member
-	     itself (as opposed to what it points to).  */
-	  pref->set_max_size_range ();
-	  return true;
-	}
+  if (code == POINTER_PLUS_EXPR
+      && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE)
+    {
+      /* Compute the size of the object first. */
+      if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
+	return false;
 
-      /* SAM is set for array members that might need special treatment.  */
-      special_array_member sam;
-      tree size = component_ref_size (ptr, &sam);
-      if (sam == special_array_member::int_0)
-	pref->sizrng[0] = pref->sizrng[1] = 0;
-      else if (!pref->trail1special && sam == special_array_member::trail_1)
-	pref->sizrng[0] = pref->sizrng[1] = 1;
-      else if (size && TREE_CODE (size) == INTEGER_CST)
-	pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+      offset_int orng[2];
+      tree off = gimple_assign_rhs2 (stmt);
+      range_query *const rvals = qry ? qry->rvals : NULL;
+      if (get_offset_range (off, stmt, orng, rvals))
+	pref->add_offset (orng[0], orng[1]);
       else
-	{
-	  /* When the size of the member is unknown it's either a flexible
-	     array member or a trailing special array member (either zero
-	     length or one-element).  Set the size to the maximum minus
-	     the constant size of the type.  */
-	  pref->sizrng[0] = 0;
-	  pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
-	  if (tree recsize = TYPE_SIZE_UNIT (TREE_TYPE (ref)))
-	    if (TREE_CODE (recsize) == INTEGER_CST)
-	      pref->sizrng[1] -= wi::to_offset (recsize);
-	}
+	pref->add_max_offset ();
+
+      qry->put_ref (ptr, *pref, ostype);
       return true;
     }
 
-  if (code == ARRAY_REF)
-    return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
-
-  if (code == MEM_REF)
-    return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry);
+  if (code == ADDR_EXPR || code == SSA_NAME)
+    {
+      if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
+	return false;
+      qry->put_ref (ptr, *pref, ostype);
+      return true;
+    }
 
-  if (code == TARGET_MEM_REF)
+  if (ostype > 1 && POINTER_TYPE_P (TREE_TYPE (rhs)))
     {
-      tree ref = TREE_OPERAND (ptr, 0);
-      if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+      /* When determining the qualifiers follow the pointer but
+	 avoid caching the result.  As the pointer is added to
+	 and/or dereferenced the computed size and offset need
+	 not be meaningful for other queries involving the same
+	 pointer.  */
+      if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
 	return false;
 
-      /* TODO: Handle remaining operands.  Until then, add maximum offset.  */
-      pref->ref = ptr;
-      pref->add_max_offset ();
-      return true;
+      rhs = pref->ref;
     }
 
-  if (code == INTEGER_CST)
+  /* (This could also be an assignment from a nonlocal pointer.)  Save
+     PTR to mention in diagnostics but otherwise treat it as a pointer
+     to an unknown object.  */
+  pref->ref = rhs;
+  pref->base0 = false;
+  pref->set_max_size_range ();
+  return true;
+}
+
+/* Helper to compute the size of the object referenced by the PTR
+   expression which must have pointer type, using Object Size type
+   OSTYPE (only the least significant 2 bits are used).
+   On success, sets PREF->REF to the DECL of the referenced object
+   if it's unique, otherwise to null, PREF->OFFRNG to the range of
+   offsets into it, and PREF->SIZRNG to the range of sizes of
+   the object(s).
+   ADDR is true for an enclosing ADDR_EXPR.
+   SNLIM is used to avoid visiting the same PHI operand multiple
+   times, and, when nonnull, RVALS to determine range information.
+   Returns true on success, false when a meaningful size (or range)
+   cannot be determined.
+
+   The function is intended for diagnostics and should not be used
+   to influence code generation or optimization.  */
+
+static bool
+compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
+		   access_ref *pref, ssa_name_limit_t &snlim,
+		   pointer_query *qry)
+{
+  STRIP_NOPS (ptr);
+
+  if (DECL_P (ptr))
+    return handle_decl (ptr, addr, pref);
+
+  switch (TREE_CODE (ptr))
     {
+    case ADDR_EXPR:
+      {
+	tree ref = TREE_OPERAND (ptr, 0);
+	if (!compute_objsize_r (ref, stmt, true, ostype, pref, snlim, qry))
+	  return false;
+
+	--pref->deref;
+	return true;
+      }
+
+    case BIT_FIELD_REF:
+      {
+	tree ref = TREE_OPERAND (ptr, 0);
+	if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
+	  return false;
+
+	offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2)));
+	pref->add_offset (off / BITS_PER_UNIT);
+	return true;
+      }
+
+    case ARRAY_REF:
+	return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
+
+    case COMPONENT_REF:
+      return handle_component_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
+
+    case MEM_REF:
+      return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry);
+
+    case TARGET_MEM_REF:
+      {
+	tree ref = TREE_OPERAND (ptr, 0);
+	if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
+	  return false;
+
+	/* TODO: Handle remaining operands.  Until then, add maximum offset.  */
+	pref->ref = ptr;
+	pref->add_max_offset ();
+	return true;
+      }
+
+    case INTEGER_CST:
       /* Pointer constants other than null are most likely the result
 	 of erroneous null pointer addition/subtraction.  Unless zero
 	 is a valid address set size to zero.  For null pointers, set
@@ -1984,21 +2232,17 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
 	pref->sizrng[0] = pref->sizrng[1] = 0;
 
       pref->ref = ptr;
-
       return true;
-    }
 
-  if (code == STRING_CST)
-    {
+    case STRING_CST:
       pref->sizrng[0] = pref->sizrng[1] = TREE_STRING_LENGTH (ptr);
       pref->ref = ptr;
       return true;
-    }
 
-  if (code == POINTER_PLUS_EXPR)
+    case POINTER_PLUS_EXPR:
     {
       tree ref = TREE_OPERAND (ptr, 0);
-      if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+      if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
 	return false;
 
       /* Clear DEREF since the offset is being applied to the target
@@ -2007,200 +2251,22 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
 
       offset_int orng[2];
       tree off = pref->eval (TREE_OPERAND (ptr, 1));
-      if (get_offset_range (off, stmt, orng, rvals))
+      if (get_offset_range (off, stmt, orng, qry->rvals))
 	pref->add_offset (orng[0], orng[1]);
       else
 	pref->add_max_offset ();
       return true;
     }
 
-  if (code == VIEW_CONVERT_EXPR)
-    {
+    case VIEW_CONVERT_EXPR:
       ptr = TREE_OPERAND (ptr, 0);
-      return compute_objsize_r (ptr, stmt, ostype, pref, snlim, qry);
-    }
+      return compute_objsize_r (ptr, stmt, addr, ostype, pref, snlim, qry);
 
-  if (code == SSA_NAME)
-    {
-      if (!snlim.next ())
-	return false;
+    case SSA_NAME:
+      return handle_ssa_name (ptr, addr, ostype, pref, snlim, qry);
 
-      /* Only process an SSA_NAME if the recursion limit has not yet
-	 been reached.  */
-      if (qry)
-	{
-	  if (++qry->depth)
-	    qry->max_depth = qry->depth;
-	  if (const access_ref *cache_ref = qry->get_ref (ptr))
-	    {
-	      /* If the pointer is in the cache set *PREF to what it refers
-		 to and return success.  */
-	      *pref = *cache_ref;
-	      return true;
-	    }
-	}
-
-      stmt = SSA_NAME_DEF_STMT (ptr);
-      if (is_gimple_call (stmt))
-	{
-	  /* If STMT is a call to an allocation function get the size
-	     from its argument(s).  If successful, also set *PREF->REF
-	     to PTR for the caller to include in diagnostics.  */
-	  wide_int wr[2];
-	  if (gimple_call_alloc_size (stmt, wr, rvals))
-	    {
-	      pref->ref = ptr;
-	      pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
-	      pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
-	      /* Constrain both bounds to a valid size.  */
-	      offset_int maxsize = wi::to_offset (max_object_size ());
-	      if (pref->sizrng[0] > maxsize)
-		pref->sizrng[0] = maxsize;
-	      if (pref->sizrng[1] > maxsize)
-		pref->sizrng[1] = maxsize;
-	    }
-	  else
-	    {
-	      /* For functions known to return one of their pointer arguments
-		 try to determine what the returned pointer points to, and on
-		 success add OFFRNG which was set to the offset added by
-		 the function (e.g., memchr) to the overall offset.  */
-	      bool past_end;
-	      offset_int offrng[2];
-	      if (tree ret = gimple_call_return_array (stmt, offrng,
-						       &past_end, snlim, qry))
-		{
-		  if (!compute_objsize_r (ret, stmt, ostype, pref, snlim, qry))
-		    return false;
-
-		  /* Cap OFFRNG[1] to at most the remaining size of
-		     the object.  */
-		  offset_int remrng[2];
-		  remrng[1] = pref->size_remaining (remrng);
-		  if (remrng[1] != 0 && !past_end)
-		    /* Decrement the size for functions that never return
-		       a past-the-end pointer.  */
-		    remrng[1] -= 1;
-
-		  if (remrng[1] < offrng[1])
-		    offrng[1] = remrng[1];
-		  pref->add_offset (offrng[0], offrng[1]);
-		}
-	      else
-		{
-		  /* For other calls that might return arbitrary pointers
-		     including into the middle of objects set the size
-		     range to maximum, clear PREF->BASE0, and also set
-		     PREF->REF to include in diagnostics.  */
-		  pref->set_max_size_range ();
-		  pref->base0 = false;
-		  pref->ref = ptr;
-		}
-	    }
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      if (gimple_nop_p (stmt))
-	{
-	  /* For a function argument try to determine the byte size
-	     of the array from the current function declaratation
-	     (e.g., attribute access or related).  */
-	  wide_int wr[2];
-	  bool static_array = false;
-	  if (tree ref = gimple_parm_array_size (ptr, wr, &static_array))
-	    {
-	      pref->parmarray = !static_array;
-	      pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
-	      pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
-	      pref->ref = ref;
-	      qry->put_ref (ptr, *pref);
-	      return true;
-	    }
-
-	  pref->set_max_size_range ();
-	  pref->base0 = false;
-	  pref->ref = ptr;
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      if (gimple_code (stmt) == GIMPLE_PHI)
-	{
-	  pref->ref = ptr;
-	  access_ref phi_ref = *pref;
-	  if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry))
-	    return false;
-	  *pref = phi_ref;
-	  pref->ref = ptr;
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      if (!is_gimple_assign (stmt))
-	{
-	  /* Clear BASE0 since the assigned pointer might point into
-	     the middle of the object, set the maximum size range and,
-	     if the SSA_NAME refers to a function argumnent, set
-	     PREF->REF to it.  */
-	  pref->base0 = false;
-	  pref->set_max_size_range ();
-	  pref->ref = ptr;
-	  return true;
-	}
-
-      tree_code code = gimple_assign_rhs_code (stmt);
-
-      if (code == MAX_EXPR || code == MIN_EXPR)
-	{
-	  if (!handle_min_max_size (ptr, ostype, pref, snlim, qry))
-	    return false;
-
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      tree rhs = gimple_assign_rhs1 (stmt);
-
-      if (code == ASSERT_EXPR)
-	{
-	  rhs = TREE_OPERAND (rhs, 0);
-	  return compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry);
-	}
-
-      if (code == POINTER_PLUS_EXPR
-	  && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE)
-	{
-	  /* Compute the size of the object first. */
-	  if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
-	    return false;
-
-	  offset_int orng[2];
-	  tree off = gimple_assign_rhs2 (stmt);
-	  if (get_offset_range (off, stmt, orng, rvals))
-	    pref->add_offset (orng[0], orng[1]);
-	  else
-	    pref->add_max_offset ();
-
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      if (code == ADDR_EXPR || code == SSA_NAME)
-	{
-	  if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
-	    return false;
-	  qry->put_ref (ptr, *pref);
-	  return true;
-	}
-
-      /* (This could also be an assignment from a nonlocal pointer.)  Save
-	 PTR to mention in diagnostics but otherwise treat it as a pointer
-	 to an unknown object.  */
-      pref->ref = rhs;
-      pref->base0 = false;
-      pref->set_max_size_range ();
-      return true;
+    default:
+      break;
     }
 
   /* Assume all other expressions point into an unknown object
@@ -2231,7 +2297,7 @@ compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref,
   pref->sizrng[0] = pref->sizrng[1] = -1;
 
   ssa_name_limit_t snlim;
-  if (!compute_objsize_r (ptr, stmt, ostype, pref, snlim, ptr_qry))
+  if (!compute_objsize_r (ptr, stmt, false, ostype, pref, snlim, ptr_qry))
     return NULL_TREE;
 
   offset_int maxsize = pref->size_remaining ();
diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h
index fe46f711e96..a7ac7d34370 100644
--- a/gcc/pointer-query.h
+++ b/gcc/pointer-query.h
@@ -122,7 +122,7 @@ struct access_ref
 
   /* Issue an informational message describing the target of an access
      with the given mode.  */
-  void inform_access (access_mode) const;
+  void inform_access (access_mode, int = 1) const;
 
   /* Reference to the accessed object(s).  */
   tree ref;
@@ -234,6 +234,8 @@ struct access_data
   /* Read-only for functions like memcmp or strlen, write-only
      for memset, read-write for memcpy or strcat.  */
   access_mode mode;
+  /* The object size type.  */
+  int ostype;
 };
 
 enum size_range_flags

Reply via email to