public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3300] Enable ranger and caching in pass_waccess.
@ 2021-09-01 19:46 Martin Sebor
  0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-09-01 19:46 UTC (permalink / raw)
  To: gcc-cvs

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

commit r12-3300-gece28da924ddda8b379c94c9df7cd01168f75fbb
Author: Martin Sebor <msebor@redhat.com>
Date:   Wed Sep 1 13:46:19 2021 -0600

    Enable ranger and caching in pass_waccess.
    
    gcc/ChangeLog:
    
            * gimple-ssa-warn-access.cc (get_size_range): Add argument.
            (check_access): Pass additional argument.
            (check_memop_access): Remove template and make a member function.
            (maybe_check_dealloc_call): Make a pass_waccess member function.
            (class pass_waccess): Add, rename, and remove members.
            (pass_waccess::pass_waccess): Adjust to name change.
            (pass_waccess::~pass_waccess): Same.
            (check_alloca): Make a member function.
            (check_alloc_size_call): Same.
            (check_strcat): Same.
            (check_strncat): Same.
            (check_stxcpy): Same.
            (check_stxncpy): Same.
            (check_strncmp): Same.
            (maybe_warn_rdwr_sizes): Rename...
            (pass_waccess::maybe_check_access_sizes): ...to this.
            (pass_waccess::check_call): Adjust to name changes.
            (pass_waccess::maybe_check_dealloc_call): Make a pass_waccess member
            function.
            (pass_waccess::execute): Adjust to name changes.
            * gimple-ssa-warn-access.h (check_memop_access): Remove.
            * pointer-query.cc (access_ref::phi): Handle null pointer.
            (access_ref::inform_access): Same.
            (pointer_query::put_ref): Modify a cached value, not a copy of it.
            (pointer_query::dump): New function.
            (compute_objsize_r): Avoid overwriting access_ref::bndrng.  Cache
            more results.
            * pointer-query.h (pointer_query::dump): Declare.
            * tree-ssa-strlen.c (get_range): Simplify.  Use function query.
            (dump_strlen_info): Use function query.
            (printf_strlen_execute): Factor code out into pointer_query::put_ref.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/Wstringop-overflow-11.c: Remove xfails.
            * gcc.dg/Wstringop-overflow-12.c: Same.
            * gcc.dg/Wstringop-overflow-43.c: Add xfails.
            * gcc.dg/Wstringop-overflow-73.c: New test.

Diff:
---
 gcc/gimple-ssa-warn-access.cc                | 437 ++++++++++++++-------------
 gcc/gimple-ssa-warn-access.h                 |   1 -
 gcc/pointer-query.cc                         | 127 +++++++-
 gcc/pointer-query.h                          |   3 +
 gcc/testsuite/gcc.dg/Wstringop-overflow-11.c |   8 +-
 gcc/testsuite/gcc.dg/Wstringop-overflow-12.c |   6 +-
 gcc/testsuite/gcc.dg/Wstringop-overflow-43.c |   9 +-
 gcc/testsuite/gcc.dg/Wstringop-overflow-73.c |  35 +++
 gcc/tree-ssa-strlen.c                        |  74 +----
 9 files changed, 405 insertions(+), 295 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 5a359587ed3..00c3ea0f505 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -1190,10 +1190,11 @@ warn_for_access (location_t loc, tree func, tree expr, int opt,
    by BNDRNG if nonnull and valid.  */
 
 static void
-get_size_range (tree bound, tree range[2], const offset_int bndrng[2])
+get_size_range (range_query *query, tree bound, tree range[2],
+		const offset_int bndrng[2])
 {
   if (bound)
-    get_size_range (bound, range);
+    get_size_range (query, bound, NULL, range);
 
   if (!bndrng || (bndrng[0] == 0 && bndrng[1] == HOST_WIDE_INT_M1U))
     return;
@@ -1337,7 +1338,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
 
   /* Set RANGE to that of DSTWRITE if non-null, bounded by PAD->DST.BNDRNG
      if valid.  */
-  get_size_range (dstwrite, range, pad ? pad->dst.bndrng : NULL);
+  get_size_range (NULL, dstwrite, range, pad ? pad->dst.bndrng : NULL);
 
   tree func = get_callee_fndecl (exp);
   /* Read vs write access by built-ins can be determined from the const
@@ -1431,7 +1432,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
     {
       /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
 	 PAD is nonnull and BNDRNG is valid.  */
-      get_size_range (maxread, range, pad ? pad->src.bndrng : NULL);
+      get_size_range (NULL, maxread, range, pad ? pad->src.bndrng : NULL);
 
       location_t loc = get_location (exp);
       tree size = dstsize;
@@ -1478,7 +1479,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
     {
       /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
 	 PAD is nonnull and BNDRNG is valid.  */
-      get_size_range (maxread, range, pad ? pad->src.bndrng : NULL);
+      get_size_range (NULL, maxread, range, pad ? pad->src.bndrng : NULL);
       /* Set OVERREAD for reads starting just past the end of an object.  */
       overread = pad->src.sizrng[1] - pad->src.offrng[0] < pad->src.bndrng[0];
       range[0] = wide_int_to_tree (sizetype, pad->src.bndrng[0]);
@@ -1529,41 +1530,6 @@ check_access (tree expr, tree dstwrite,
 			    mode, pad);
 }
 
-/* Helper to determine and check the sizes of the source and the destination
-   of calls to __builtin_{bzero,memcpy,mempcpy,memset} calls.  EXP is the
-   call expression, DEST is the destination argument, SRC is the source
-   argument or null, and LEN is the number of bytes.  Use Object Size type-0
-   regardless of the OPT_Wstringop_overflow_ setting.  Return true on success
-   (no overflow or invalid sizes), false otherwise.  */
-
-template <class GimpleOrTree>
-static bool
-check_memop_access (GimpleOrTree expr, tree dest, tree src, tree size)
-{
-  /* For functions like memset and memcpy that operate on raw memory
-     try to determine the size of the largest source and destination
-     object using type-0 Object Size regardless of the object size
-     type specified by the option.  */
-  access_data data (expr, access_read_write);
-  tree srcsize = src ? compute_objsize (src, 0, &data.src) : NULL_TREE;
-  tree dstsize = compute_objsize (dest, 0, &data.dst);
-
-  return check_access (expr, size, /*maxread=*/NULL_TREE,
-		       srcsize, dstsize, data.mode, &data);
-}
-
-bool
-check_memop_access (gimple *stmt, tree dest, tree src, tree size)
-{
-  return check_memop_access<gimple *>(stmt, dest, src, size);
-}
-
-bool
-check_memop_access (tree expr, tree dest, tree src, tree size)
-{
-  return check_memop_access<tree>(expr, dest, src, size);
-}
-
 /* A convenience wrapper for check_access above to check access
    by a read-only function like puts.  */
 
@@ -2111,135 +2077,6 @@ warn_dealloc_offset (location_t loc, gimple *call, const access_ref &aref)
   return true;
 }
 
-/* Issue a warning if a deallocation function such as free, realloc,
-   or C++ operator delete is called with an argument not returned by
-   a matching allocation function such as malloc or the corresponding
-   form of C++ operatorn new.  */
-
-static void
-maybe_check_dealloc_call (gcall *call)
-{
-  tree fndecl = gimple_call_fndecl (call);
-  if (!fndecl)
-    return;
-
-  unsigned argno = fndecl_dealloc_argno (fndecl);
-  if ((unsigned) call_nargs (call) <= argno)
-    return;
-
-  tree ptr = gimple_call_arg (call, argno);
-  if (integer_zerop (ptr))
-    return;
-
-  access_ref aref;
-  if (!compute_objsize (ptr, 0, &aref))
-    return;
-
-  tree ref = aref.ref;
-  if (integer_zerop (ref))
-    return;
-
-  tree dealloc_decl = fndecl;
-  location_t loc = gimple_location (call);
-
-  if (DECL_P (ref) || EXPR_P (ref))
-    {
-      /* Diagnose freeing a declared object.  */
-      if (aref.ref_declared ()
-	  && warning_at (loc, OPT_Wfree_nonheap_object,
-			 "%qD called on unallocated object %qD",
-			 dealloc_decl, ref))
-	{
-	  inform (get_location (ref), "declared here");
-	  return;
-	}
-
-      /* Diagnose freeing a pointer that includes a positive offset.
-	 Such a pointer cannot refer to the beginning of an allocated
-	 object.  A negative offset may refer to it.  */
-      if (aref.sizrng[0] != aref.sizrng[1]
-	  && warn_dealloc_offset (loc, call, aref))
-	return;
-    }
-  else if (CONSTANT_CLASS_P (ref))
-    {
-      if (warning_at (loc, OPT_Wfree_nonheap_object,
-		      "%qD called on a pointer to an unallocated "
-		      "object %qE", dealloc_decl, ref))
-	{
-	  if (TREE_CODE (ptr) == SSA_NAME)
-	    {
-	      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
-	      if (is_gimple_assign (def_stmt))
-		{
-		  location_t loc = gimple_location (def_stmt);
-		  inform (loc, "assigned here");
-		}
-	    }
-	  return;
-	}
-    }
-  else if (TREE_CODE (ref) == SSA_NAME)
-    {
-      /* Also warn if the pointer argument refers to the result
-	 of an allocation call like alloca or VLA.  */
-      gimple *def_stmt = SSA_NAME_DEF_STMT (ref);
-      if (is_gimple_call (def_stmt))
-	{
-	  bool warned = false;
-	  if (gimple_call_alloc_p (def_stmt))
-	    {
-	      if (matching_alloc_calls_p (def_stmt, dealloc_decl))
-		{
-		  if (warn_dealloc_offset (loc, call, aref))
-		    return;
-		}
-	      else
-		{
-		  tree alloc_decl = gimple_call_fndecl (def_stmt);
-		  const opt_code opt =
-		    (DECL_IS_OPERATOR_NEW_P (alloc_decl)
-		     || DECL_IS_OPERATOR_DELETE_P (dealloc_decl)
-		     ? OPT_Wmismatched_new_delete
-		     : OPT_Wmismatched_dealloc);
-		  warned = warning_at (loc, opt,
-				       "%qD called on pointer returned "
-				       "from a mismatched allocation "
-				       "function", dealloc_decl);
-		}
-	    }
-	  else if (gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA)
-		   || gimple_call_builtin_p (def_stmt,
-					     BUILT_IN_ALLOCA_WITH_ALIGN))
-	    warned = warning_at (loc, OPT_Wfree_nonheap_object,
-				 "%qD called on pointer to "
-				 "an unallocated object",
-				 dealloc_decl);
-	  else if (warn_dealloc_offset (loc, call, aref))
-	    return;
-
-	  if (warned)
-	    {
-	      tree fndecl = gimple_call_fndecl (def_stmt);
-	      inform (gimple_location (def_stmt),
-		      "returned from %qD", fndecl);
-	      return;
-	    }
-	}
-      else if (gimple_nop_p (def_stmt))
-	{
-	  ref = SSA_NAME_VAR (ref);
-	  /* Diagnose freeing a pointer that includes a positive offset.  */
-	  if (TREE_CODE (ref) == PARM_DECL
-	      && !aref.deref
-	      && aref.sizrng[0] != aref.sizrng[1]
-	      && aref.offrng[0] > 0 && aref.offrng[1] > 0
-	      && warn_dealloc_offset (loc, call, aref))
-	    return;
-	}
-    }
-}
-
 namespace {
 
 const pass_data pass_data_waccess = {
@@ -2267,6 +2104,11 @@ class pass_waccess : public gimple_opt_pass
   virtual bool gate (function *);
   virtual unsigned int execute (function *);
 
+private:
+  /* Not copyable or assignable.  */
+  pass_waccess (pass_waccess &) = delete;
+  void operator= (pass_waccess &) = delete;
+
   /* Check a call to a built-in function.  */
   bool check_builtin (gcall *);
 
@@ -2277,28 +2119,33 @@ class pass_waccess : public gimple_opt_pass
   void check (basic_block);
 
   /* Check a call to a function.  */
- void check (gcall *);
+  void check (gcall *);
 
-private:
-  /* Not copyable or assignable.  */
-  pass_waccess (pass_waccess &) = delete;
-  void operator= (pass_waccess &) = delete;
+  /* Check a call to the named built-in function.  */
+  void check_alloca (gcall *);
+  void check_alloc_size_call (gcall *);
+  void check_strcat (gcall *);
+  void check_strncat (gcall *);
+  void check_stxcpy (gcall *);
+  void check_stxncpy (gcall *);
+  void check_strncmp (gcall *);
+  void check_memop_access (gimple *, tree, tree, tree);
+
+  void maybe_check_dealloc_call (gcall *);
+  void maybe_check_access_sizes (rdwr_map *, tree, tree, gimple *);
 
   /* A pointer_query object and its cache to store information about
      pointers and their targets in.  */
-  pointer_query ptr_qry;
-  pointer_query::cache_type var_cache;
-
-  gimple_ranger *m_ranger;
+  pointer_query m_ptr_qry;
+  pointer_query::cache_type m_var_cache;
 };
 
 /* Construct the pass.  */
 
 pass_waccess::pass_waccess (gcc::context *ctxt)
   : gimple_opt_pass (pass_data_waccess, ctxt),
-    ptr_qry (m_ranger, &var_cache),
-    var_cache (),
-    m_ranger ()
+    m_ptr_qry (NULL, &m_var_cache),
+    m_var_cache ()
 {
 }
 
@@ -2306,7 +2153,7 @@ pass_waccess::pass_waccess (gcc::context *ctxt)
 
 pass_waccess::~pass_waccess ()
 {
-  ptr_qry.flush_cache ();
+  m_ptr_qry.flush_cache ();
 }
 
 /* Return true when any checks performed by the pass are enabled.  */
@@ -2494,8 +2341,8 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const tree args[2],
 
 /* Check a call to an alloca function for an excessive size.  */
 
-static void
-check_alloca (gimple *stmt)
+void
+pass_waccess::check_alloca (gcall *stmt)
 {
   if ((warn_vla_limit >= HOST_WIDE_INT_MAX
        && warn_alloc_size_limit < warn_vla_limit)
@@ -2515,8 +2362,8 @@ check_alloca (gimple *stmt)
 
 /* Check a call to an allocation function for an excessive size.  */
 
-static void
-check_alloc_size_call (gimple *stmt)
+void
+pass_waccess::check_alloc_size_call (gcall *stmt)
 {
   if (gimple_call_num_args (stmt) < 1)
     /* Avoid invalid calls to functions without a prototype.  */
@@ -2565,8 +2412,8 @@ check_alloc_size_call (gimple *stmt)
 
 /* Check a call STMT to strcat() for overflow and warn if it does.  */
 
-static void
-check_strcat (gimple *stmt)
+void
+pass_waccess::check_strcat (gcall *stmt)
 {
   if (!warn_stringop_overflow && !warn_stringop_overread)
     return;
@@ -2581,8 +2428,8 @@ check_strcat (gimple *stmt)
   access_data data (stmt, access_read_write, NULL_TREE, true,
 		    NULL_TREE, true);
   const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
-  compute_objsize (src, ost, &data.src);
-  tree destsize = compute_objsize (dest, ost, &data.dst);
+  compute_objsize (src, ost, &data.src, &m_ptr_qry);
+  tree destsize = compute_objsize (dest, ost, &data.dst, &m_ptr_qry);
 
   check_access (stmt, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE,
 		src, destsize, data.mode, &data);
@@ -2590,8 +2437,8 @@ check_strcat (gimple *stmt)
 
 /* Check a call STMT to strcat() for overflow and warn if it does.  */
 
-static void
-check_strncat (gimple *stmt)
+void
+pass_waccess::check_strncat (gcall *stmt)
 {
   if (!warn_stringop_overflow && !warn_stringop_overread)
     return;
@@ -2623,7 +2470,8 @@ check_strncat (gimple *stmt)
   /* Try to verify that the destination is big enough for the shortest
      string.  First try to determine the size of the destination object
      into which the source is being copied.  */
-  tree destsize = compute_objsize (dest, warn_stringop_overflow - 1, &data.dst);
+  const int ost = warn_stringop_overflow - 1;
+  tree destsize = compute_objsize (dest, ost, &data.dst, &m_ptr_qry);
 
   /* Add one for the terminating nul.  */
   tree srclen = (maxlen
@@ -2658,8 +2506,8 @@ check_strncat (gimple *stmt)
 /* Check a call STMT to stpcpy() or strcpy() for overflow and warn
    if it does.  */
 
-static void
-check_stxcpy (gimple *stmt)
+void
+pass_waccess::check_stxcpy (gcall *stmt)
 {
   tree dst = call_arg (stmt, 0);
   tree src = call_arg (stmt, 1);
@@ -2679,8 +2527,8 @@ check_stxcpy (gimple *stmt)
       access_data data (stmt, access_read_write, NULL_TREE, true,
 			NULL_TREE, true);
       const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
-      compute_objsize (src, ost, &data.src);
-      tree dstsize = compute_objsize (dst, ost, &data.dst);
+      compute_objsize (src, ost, &data.src, &m_ptr_qry);
+      tree dstsize = compute_objsize (dst, ost, &data.dst, &m_ptr_qry);
       check_access (stmt, /*dstwrite=*/ NULL_TREE,
 		    /*maxread=*/ NULL_TREE, /*srcstr=*/ src,
 		    dstsize, data.mode, &data);
@@ -2696,8 +2544,8 @@ check_stxcpy (gimple *stmt)
 /* Check a call STMT to stpncpy() or strncpy() for overflow and warn
    if it does.  */
 
-static void
-check_stxncpy (gimple *stmt)
+void
+pass_waccess::check_stxncpy (gcall *stmt)
 {
   if (!warn_stringop_overflow)
     return;
@@ -2709,8 +2557,8 @@ check_stxncpy (gimple *stmt)
 
   access_data data (stmt, access_read_write, len, true, len, true);
   const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
-  compute_objsize (src, ost, &data.src);
-  tree dstsize = compute_objsize (dst, ost, &data.dst);
+  compute_objsize (src, ost, &data.src, &m_ptr_qry);
+  tree dstsize = compute_objsize (dst, ost, &data.dst, &m_ptr_qry);
 
   check_access (stmt, /*dstwrite=*/len,
 		/*maxread=*/len, src, dstsize, data.mode, &data);
@@ -2719,8 +2567,8 @@ check_stxncpy (gimple *stmt)
 /* Check a call STMT to stpncpy() or strncpy() for overflow and warn
    if it does.  */
 
-static void
-check_strncmp (gimple *stmt)
+void
+pass_waccess::check_strncmp (gcall *stmt)
 {
   if (!warn_stringop_overread)
     return;
@@ -2764,7 +2612,7 @@ check_strncmp (gimple *stmt)
   /* Determine the range of the bound first and bail if it fails; it's
      cheaper than computing the size of the objects.  */
   tree bndrng[2] = { NULL_TREE, NULL_TREE };
-  get_size_range (bound, bndrng, adata1.src.bndrng);
+  get_size_range (m_ptr_qry.rvals, bound, bndrng, adata1.src.bndrng);
   if (!bndrng[0] || integer_zerop (bndrng[0]))
     return;
 
@@ -2775,8 +2623,8 @@ check_strncmp (gimple *stmt)
 
   /* compute_objsize almost never fails (and ultimately should never
      fail).  Don't bother to handle the rare case when it does.  */
-  if (!compute_objsize (arg1, 1, &adata1.src)
-      || !compute_objsize (arg2, 1, &adata2.src))
+  if (!compute_objsize (arg1, 1, &adata1.src, &m_ptr_qry)
+      || !compute_objsize (arg2, 1, &adata2.src, &m_ptr_qry))
     return;
 
   /* Compute the size of the remaining space in each array after
@@ -2810,6 +2658,29 @@ check_strncmp (gimple *stmt)
     }
 }
 
+/* Determine and check the sizes of the source and the destination
+   of calls to __builtin_{bzero,memcpy,mempcpy,memset} calls.  STMT is
+   the call statement, DEST is the destination argument, SRC is the source
+   argument or null, and SIZE is the number of bytes being accessed.  Use
+   Object Size type-0 regardless of the OPT_Wstringop_overflow_ setting.
+   Return true on success (no overflow or invalid sizes), false otherwise.  */
+
+void
+pass_waccess::check_memop_access (gimple *stmt, tree dest, tree src, tree size)
+{
+  /* For functions like memset and memcpy that operate on raw memory
+     try to determine the size of the largest source and destination
+     object using type-0 Object Size regardless of the object size
+     type specified by the option.  */
+  access_data data (stmt, access_read_write);
+  tree srcsize
+    = src ? compute_objsize (src, 0, &data.src, &m_ptr_qry) : NULL_TREE;
+  tree dstsize = compute_objsize (dest, 0, &data.dst, &m_ptr_qry);
+
+  check_access (stmt, size, /*maxread=*/NULL_TREE,
+		srcsize, dstsize, data.mode, &data);
+}
+
 /* Check call STMT to a built-in function for invalid accesses.  Return
    true if a call has been handled.  */
 
@@ -2968,8 +2839,9 @@ append_attrname (const std::pair<int, attr_access> &access,
    arguments and diagnose past-the-end accesses and related problems
    in the function call EXP.  */
 
-static void
-maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, gimple *stmt)
+void
+pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
+					gimple *stmt)
 {
   auto_diagnostic_group adg;
 
@@ -3028,7 +2900,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, gimple *stmt)
       /* Format the value or range to avoid an explosion of messages.  */
       char sizstr[80];
       tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) };
-      if (get_size_range (access_size, sizrng, true))
+      if (get_size_range (m_ptr_qry.rvals, access_size, NULL, sizrng, 1))
 	{
 	  char *s0 = print_generic_expr_to_str (sizrng[0]);
 	  if (tree_int_cst_equal (sizrng[0], sizrng[1]))
@@ -3160,7 +3032,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, gimple *stmt)
 			NULL_TREE, false);
       access_ref* const pobj = (access.second.mode == access_write_only
 				? &data.dst : &data.src);
-      tree objsize = compute_objsize (ptr, 1, pobj);
+      tree objsize = compute_objsize (ptr, 1, pobj, &m_ptr_qry);
 
       /* The size of the destination or source object.  */
       tree dstsize = NULL_TREE, srcsize = NULL_TREE;
@@ -3276,7 +3148,7 @@ pass_waccess::check_call (gcall *stmt)
 
   /* Check attribute access arguments.  */
   tree fndecl = gimple_call_fndecl (stmt);
-  maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, stmt);
+  maybe_check_access_sizes (&rdwr_idx, fndecl, fntype, stmt);
 
   check_alloc_size_call (stmt);
   return true;
@@ -3294,6 +3166,138 @@ check_nonstring_args (gcall *stmt)
   maybe_warn_nonstring_arg (fndecl, stmt);
 }
 
+/* Issue a warning if a deallocation function such as free, realloc,
+   or C++ operator delete is called with an argument not returned by
+   a matching allocation function such as malloc or the corresponding
+   form of C++ operatorn new.  */
+
+void
+pass_waccess::maybe_check_dealloc_call (gcall *call)
+{
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+    return;
+
+  unsigned argno = fndecl_dealloc_argno (fndecl);
+  if ((unsigned) call_nargs (call) <= argno)
+    return;
+
+  tree ptr = gimple_call_arg (call, argno);
+  if (integer_zerop (ptr))
+    return;
+
+  access_ref aref;
+  if (!compute_objsize (ptr, 0, &aref, &m_ptr_qry))
+    return;
+
+  tree ref = aref.ref;
+  if (integer_zerop (ref))
+    return;
+
+  tree dealloc_decl = fndecl;
+  location_t loc = gimple_location (call);
+
+  if (DECL_P (ref) || EXPR_P (ref))
+    {
+      /* Diagnose freeing a declared object.  */
+      if (aref.ref_declared ()
+	  && warning_at (loc, OPT_Wfree_nonheap_object,
+			 "%qD called on unallocated object %qD",
+			 dealloc_decl, ref))
+	{
+	  inform (get_location (ref), "declared here");
+	  return;
+	}
+
+      /* Diagnose freeing a pointer that includes a positive offset.
+	 Such a pointer cannot refer to the beginning of an allocated
+	 object.  A negative offset may refer to it.  */
+      if (aref.sizrng[0] != aref.sizrng[1]
+	  && warn_dealloc_offset (loc, call, aref))
+	return;
+    }
+  else if (CONSTANT_CLASS_P (ref))
+    {
+      if (warning_at (loc, OPT_Wfree_nonheap_object,
+		      "%qD called on a pointer to an unallocated "
+		      "object %qE", dealloc_decl, ref))
+	{
+	  if (TREE_CODE (ptr) == SSA_NAME)
+	    {
+	      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+	      if (is_gimple_assign (def_stmt))
+		{
+		  location_t loc = gimple_location (def_stmt);
+		  inform (loc, "assigned here");
+		}
+	    }
+	  return;
+	}
+    }
+  else if (TREE_CODE (ref) == SSA_NAME)
+    {
+      /* Also warn if the pointer argument refers to the result
+	 of an allocation call like alloca or VLA.  */
+      gimple *def_stmt = SSA_NAME_DEF_STMT (ref);
+      if (!def_stmt)
+	return;
+
+      if (is_gimple_call (def_stmt))
+	{
+	  bool warned = false;
+	  if (gimple_call_alloc_p (def_stmt))
+	    {
+	      if (matching_alloc_calls_p (def_stmt, dealloc_decl))
+		{
+		  if (warn_dealloc_offset (loc, call, aref))
+		    return;
+		}
+	      else
+		{
+		  tree alloc_decl = gimple_call_fndecl (def_stmt);
+		  const opt_code opt =
+		    (DECL_IS_OPERATOR_NEW_P (alloc_decl)
+		     || DECL_IS_OPERATOR_DELETE_P (dealloc_decl)
+		     ? OPT_Wmismatched_new_delete
+		     : OPT_Wmismatched_dealloc);
+		  warned = warning_at (loc, opt,
+				       "%qD called on pointer returned "
+				       "from a mismatched allocation "
+				       "function", dealloc_decl);
+		}
+	    }
+	  else if (gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA)
+		   || gimple_call_builtin_p (def_stmt,
+					     BUILT_IN_ALLOCA_WITH_ALIGN))
+	    warned = warning_at (loc, OPT_Wfree_nonheap_object,
+				 "%qD called on pointer to "
+				 "an unallocated object",
+				 dealloc_decl);
+	  else if (warn_dealloc_offset (loc, call, aref))
+	    return;
+
+	  if (warned)
+	    {
+	      tree fndecl = gimple_call_fndecl (def_stmt);
+	      inform (gimple_location (def_stmt),
+		      "returned from %qD", fndecl);
+	      return;
+	    }
+	}
+      else if (gimple_nop_p (def_stmt))
+	{
+	  ref = SSA_NAME_VAR (ref);
+	  /* Diagnose freeing a pointer that includes a positive offset.  */
+	  if (TREE_CODE (ref) == PARM_DECL
+	      && !aref.deref
+	      && aref.sizrng[0] != aref.sizrng[1]
+	      && aref.offrng[0] > 0 && aref.offrng[1] > 0
+	      && warn_dealloc_offset (loc, call, aref))
+	    return;
+	}
+    }
+}
+
 /* Check call STMT for invalid accesses.  */
 
 void
@@ -3329,14 +3333,21 @@ unsigned
 pass_waccess::execute (function *fun)
 {
   /* Create a new ranger instance and associate it with FUN.  */
-  m_ranger = enable_ranger (fun);
+  m_ptr_qry.rvals = enable_ranger (fun);
 
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     check (bb);
 
-  /* Release the ranger instance and replace it with a global ranger.  */
+  if (dump_file)
+    m_ptr_qry.dump (dump_file, (dump_flags & TDF_DETAILS) != 0);
+
+  m_ptr_qry.flush_cache ();
+
+  /* Release the ranger instance and replace it with a global ranger.
+     Also reset the pointer since calling disable_ranger() deletes it.  */
   disable_ranger (fun);
+  m_ptr_qry.rvals = NULL;
 
   return 0;
 }
diff --git a/gcc/gimple-ssa-warn-access.h b/gcc/gimple-ssa-warn-access.h
index 1cd3a28c421..00f5bb1a7b2 100644
--- a/gcc/gimple-ssa-warn-access.h
+++ b/gcc/gimple-ssa-warn-access.h
@@ -45,7 +45,6 @@ class access_data;
 extern bool check_access (tree, tree, tree, tree, tree, access_mode,
 			  const access_data * = NULL);
 
-extern bool check_memop_access (tree, tree, tree, tree);
 extern bool check_read_access (gimple *, tree, tree = NULL_TREE, int ost = 1);
 extern bool check_read_access (tree, tree, tree = NULL_TREE, int = 1);
 
diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index ba8f8a9dc69..4ad28796e57 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -34,10 +34,13 @@
 #include "stringpool.h"
 #include "attribs.h"
 #include "gimple-fold.h"
+#include "gimple-ssa.h"
 #include "intl.h"
 #include "attr-fnspec.h"
 #include "gimple-range.h"
 #include "pointer-query.h"
+#include "tree-pretty-print.h"
+#include "tree-ssanames.h"
 
 static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &,
 			       pointer_query *);
@@ -307,7 +310,7 @@ get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2],
   enum value_range_kind range_type;
 
   if (!query)
-    query = get_global_range_query ();
+    query = get_range_query (cfun);
 
   if (integral)
     {
@@ -628,7 +631,7 @@ access_ref::phi () const
     return NULL;
 
   gimple *def_stmt = SSA_NAME_DEF_STMT (ref);
-  if (gimple_code (def_stmt) != GIMPLE_PHI)
+  if (!def_stmt || gimple_code (def_stmt) != GIMPLE_PHI)
     return NULL;
 
   return as_a <gphi *> (def_stmt);
@@ -1038,6 +1041,9 @@ access_ref::inform_access (access_mode mode) const
   if (TREE_CODE (ref) == SSA_NAME)
     {
       gimple *stmt = SSA_NAME_DEF_STMT (ref);
+      if (!stmt)
+	return;
+
       if (is_gimple_call (stmt))
 	{
 	  loc = gimple_location (stmt);
@@ -1339,7 +1345,7 @@ pointer_query::put_ref (tree ptr, const access_ref &ref, int ostype /* = 1 */)
   if (var_cache->access_refs.length () <= cache_idx)
     var_cache->access_refs.safe_grow_cleared (cache_idx + 1);
 
-  access_ref cache_ref = var_cache->access_refs[cache_idx - 1];
+  access_ref &cache_ref = var_cache->access_refs[cache_idx];
   if (cache_ref.ref)
   {
     gcc_checking_assert (cache_ref.ref == ref.ref);
@@ -1360,6 +1366,102 @@ pointer_query::flush_cache ()
   var_cache->access_refs.release ();
 }
 
+/* Dump statistics and, optionally, cache contents to DUMP_FILE.  */
+
+void
+pointer_query::dump (FILE *dump_file, bool contents /* = false */)
+{
+  unsigned nused = 0, nrefs = 0;
+  unsigned nidxs = var_cache->indices.length ();
+  for (unsigned i = 0; i != nidxs; ++i)
+    {
+      unsigned ari = var_cache->indices[i];
+      if (!ari)
+	continue;
+
+      ++nused;
+
+      const access_ref &aref = var_cache->access_refs[ari];
+      if (!aref.ref)
+	continue;
+
+      ++nrefs;
+    }
+
+  fprintf (dump_file, "pointer_query counters:\n"
+	   "  index cache size:   %u\n"
+	   "  index entries:      %u\n"
+	   "  access cache size:  %u\n"
+	   "  access entries:     %u\n"
+	   "  hits:               %u\n"
+	   "  misses:             %u\n"
+	   "  failures:           %u\n"
+	   "  max_depth:          %u\n",
+	   nidxs, nused,
+	   var_cache->access_refs.length (), nrefs,
+	   hits, misses, failures, max_depth);
+
+  if (!contents || !nidxs)
+    return;
+
+  fputs ("\npointer_query cache contents:\n", dump_file);
+
+  for (unsigned i = 0; i != nidxs; ++i)
+    {
+      unsigned ari = var_cache->indices[i];
+      if (!ari)
+	continue;
+
+      const access_ref &aref = var_cache->access_refs[ari];
+      if (!aref.ref)
+	continue;
+
+      /* The level-1 cache index corresponds to the SSA_NAME_VERSION
+	 shifted left by one and ORed with the Object Size Type in
+	 the lowest bit.  Print the two separately.  */
+      unsigned ver = i >> 1;
+      unsigned ost = i & 1;
+
+      fprintf (dump_file, "  %u.%u[%u]: ", ver, ost, ari);
+      if (tree name = ssa_name (ver))
+	{
+	  print_generic_expr (dump_file, name);
+	  fputs (" = ", dump_file);
+	}
+      else
+	fprintf (dump_file, "  _%u = ", ver);
+
+      if (gphi *phi = aref.phi ())
+	{
+	  fputs ("PHI <", dump_file);
+	  unsigned nargs = gimple_phi_num_args (phi);
+	  for (unsigned i = 0; i != nargs; ++i)
+	    {
+	      tree arg = gimple_phi_arg_def (phi, i);
+	      print_generic_expr (dump_file, arg);
+	      if (i + 1 < nargs)
+		fputs (", ", dump_file);
+	    }
+	  fputc ('>', dump_file);
+	}
+      else
+	print_generic_expr (dump_file, aref.ref);
+
+      if (aref.offrng[0] != aref.offrng[1])
+	fprintf (dump_file, " + [%lli, %lli]",
+		 (long long) aref.offrng[0].to_shwi (),
+		 (long long) aref.offrng[1].to_shwi ());
+      else if (aref.offrng[0] != 0)
+	fprintf (dump_file, " %c %lli",
+		 aref.offrng[0] < 0 ? '-' : '+',
+		 (long long) aref.offrng[0].to_shwi ());
+
+      fputc ('\n', dump_file);
+    }
+
+  fputc ('\n', dump_file);
+}
+
 /* A helper of compute_objsize_r() to determine the size from an assignment
    statement STMT with the RHS of either MIN_EXPR or MAX_EXPR.  */
 
@@ -1782,8 +1884,14 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
 	  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.  */
+		 to and return success.
+		 FIXME: BNDRNG is determined by each access and so it doesn't
+		 belong in access_ref.  Until the design is changed, keep it
+		 unchanged here.  */
+	      const offset_int bndrng[2] = { pref->bndrng[0], pref->bndrng[1] };
 	      *pref = *cache_ref;
+	      pref->bndrng[0] = bndrng[0];
+	      pref->bndrng[1] = bndrng[1];
 	      return true;
 	    }
 	}
@@ -1928,13 +2036,18 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
 	    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)
-	return compute_objsize_r (rhs, ostype, pref, snlim, qry);
+      if (code == ADDR_EXPR || code == SSA_NAME)
+	{
+	  if (!compute_objsize_r (rhs, 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
diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h
index eb7e90dde03..3c8172c652d 100644
--- a/gcc/pointer-query.h
+++ b/gcc/pointer-query.h
@@ -186,6 +186,9 @@ public:
   /* Flush the cache.  */
   void flush_cache ();
 
+  /* Dump statistics and optionally cache contents to DUMP_FILE.  */
+  void dump (FILE *, bool = false);
+
   /* A Ranger instance.  May be null to use global ranges.  */
   range_query *rvals;
   /* Cache of SSA_NAMEs.  May be null to disable caching.  */
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-11.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-11.c
index ec3c97e8102..cf536527fb9 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-11.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-11.c
@@ -56,7 +56,7 @@ void test_memset_array_cst_range_off (void)
   T (2, SR ( 1, 2), 4);
   T (2, SR ( 1, 2), 5);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 
-  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" { xfail *-*-* } } */
+  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" } */
   T (2, UR ( 1, 2), 7);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
   T (7, UR (-7, 0), 7);
   T (7, UR (-7, 0), 9);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
@@ -134,7 +134,7 @@ void test_memcpy_array_cst_range_off (const void *s)
   T (2, SR ( 1, 2), 4);
   T (2, SR ( 1, 2), 5);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 
-  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" { xfail *-*-* } } */
+  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" } */
   T (2, UR ( 1, 2), 7);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
   T (7, UR (-7, 0), 7);
   T (7, UR (-7, 0), 9);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
@@ -211,7 +211,7 @@ void test_strcpy_array_cst_range_off (void)
   T (2, SR ( 1, 2), 3);
   T (2, SR ( 1, 2), 4);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 
-  T (2, SR ( 0, 1), 5);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" { xfail *-*-* } } */
+  T (2, SR ( 0, 1), 5);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" } */
   T (2, UR ( 1, 2), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
   T (7, UR (-7, 0), 6);
   T (7, UR (-7, 0), 8);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
@@ -277,7 +277,7 @@ void test_strncpy_array_cst_range_off (const char *s)
   T (2, SR ( 1, 2), 4);
   T (2, SR ( 1, 2), 5);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 
-  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" { xfail *-*-* } } */
+  T (2, SR ( 0, 1), 6);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr89428" } */
   T (2, UR ( 1, 2), 7);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
   T (7, UR (-7, 0), 7);
   T (7, UR (-7, 0), 9);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
index 7c3dc8c0544..1ba77209887 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
@@ -25,9 +25,7 @@ void test_memcpy_array_cst_range_off (const void *s)
   T (d + UR (1, 2), 5);
 
   T (d + UR (0, 1), 6);
-  /* The warning below should be "writing" but the [0, 1] range
-     is somehow lost and get_range_info() returns VR_VARYING.  */
-  T (d + UR (0, 1), 7);       /* { dg-warning ".memcpy. writing 7 bytes into a region of size 6 overflows the destination" "pr89428" { xfail *-*-* } } */
+  T (d + UR (0, 1), 7);       /* { dg-warning ".memcpy. writing 7 bytes into a region of size 6 overflows the destination" "pr89428" } */
   T (d + UR (1, 2), 6);       /* { dg-warning ".memcpy. writing 6 bytes into a region of size 5 overflows the destination" } */
   T (d + UR (1, 2), 7);       /* { dg-warning "writing 7 bytes into a region of size 5 " } */
 
@@ -66,7 +64,7 @@ void test_memset_array_unsigned_off (void)
   T (d + UR (1, 2), 5);
 
   T (d + UR (0, 1), 6);
-  T (d + UR (0, 1), 7);       /* { dg-warning ".memset. writing 6 bytes into a region of size 5 overflows the destination" "pr89428" { xfail *-*-* } } */
+  T (d + UR (0, 1), 7);       /* { dg-warning ".memset. writing 7 bytes into a region of size 6 overflows the destination" "pr89428" } */
   T (d + UR (1, 2), 6);       /* { dg-warning ".memset. writing 6 bytes into a region of size 5 overflows the destination" } */
   T (d + UR (1, 2), 7);       /* { dg-warning "writing 7 bytes into a region of size 5 " } */
 
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
index 6d045c58bf6..91006618fa6 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
@@ -161,8 +161,11 @@ void warn_memset_reversed_range (void)
 
   /* Since the offset is excessive, either starting before &a11[0]
      ot just past &a[11], the region size in the warning should
-     probably be zero, but accept other sizes too.  */
-  T1 (p, SAR (INT_MIN, -11), n11);      // { dg-warning "writing 11 or more bytes into a region of size \\d+" }
+     probably be zero, but accept other sizes too.
+
+     The problem isn't detected anymore because the offset is in
+     the anti-range ~[INT_MIN, -11] which isn't handled.  */
+  T1 (p, SAR (INT_MIN, -11), n11);      // { dg-warning "writing 11 or more bytes into a region of size \\d+" "" { xfail *-*-* } }
 
   /* The following are represented as ordinary ranges with reversed bounds
      and those are handled. */
@@ -170,7 +173,7 @@ void warn_memset_reversed_range (void)
   T1 (p, SAR (INT_MIN,   1), n11);      // { dg-warning "writing 11 or more bytes into a region of size 0" }
   T1 (p, SAR (INT_MIN,   0), n11);      // { dg-warning "writing 11 or more bytes into a region of size 0" }
   /* Also represented as a true anti-range.  */
-  T1 (p, SAR (    -12, -11), n11);      // { dg-warning "writing 11 or more bytes into a region of size \\d+" }
+  T1 (p, SAR (    -12, -11), n11);      // { dg-warning "writing 11 or more bytes into a region of size \\d+" "" { xfail *-*-* } }
   T1 (p, SAR (    -12,  -1), n11);      // { dg-warning "writing 11 or more bytes into a region of size 0" }
   T1 (p, SAR (    -11,   0), n11);      // { dg-warning "writing 11 or more bytes into a region of size 0" }
   T1 (p, SAR (    -11,  11), n11);      // { dg-warning "writing 11 or more bytes into a region of size 0" }
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-73.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-73.c
new file mode 100644
index 00000000000..0bb4afecc7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-73.c
@@ -0,0 +1,35 @@
+/*
+  { dg-do compile }
+  { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+int memcmp (const void*, const void*, size_t);
+int strncmp (const char*, const char*, size_t);
+char* stpncpy (char*, const char*, size_t);
+char* strncpy (char*, const char*, size_t);
+
+extern char a4[4], b5[5];
+
+struct A { char a4[4]; };
+
+extern volatile int i;
+extern void* volatile ptr;
+
+void test_stpncpy (struct A *p)
+{
+  ptr = stpncpy (a4, b5, 4);
+  ptr = stpncpy (a4, b5, 5);      // { dg-warning "writing 5 bytes" }
+
+  ptr = stpncpy (p->a4, b5, 4);
+  ptr = stpncpy (p->a4, b5, 5);   // { dg-warning "writing 5 bytes" }
+}
+
+void test_strncpy (struct A *p)
+{
+  ptr = strncpy (a4, b5, 4);
+  ptr = strncpy (a4, b5, 5);      // { dg-warning "writing 5 bytes" }
+
+  ptr = strncpy (p->a4, b5, 4);
+  ptr = strncpy (p->a4, b5, 5);   // { dg-warning "writing 5 bytes" }
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 15391da8104..7c93958e9ad 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -200,61 +200,29 @@ static bool handle_assign (gimple_stmt_iterator *, tree, bool *,
 /* Sets MINMAX to either the constant value or the range VAL is in
    and returns either the constant value or VAL on success or null
    when the range couldn't be determined.  Uses RVALS when nonnull
-   to determine the range, otherwise uses global range info.  */
+   to determine the range, otherwise uses CFUN or global range info,
+   whichever is nonnull.  */
 
 tree
 get_range (tree val, gimple *stmt, wide_int minmax[2],
 	   range_query *rvals /* = NULL */)
 {
-  if (TREE_CODE (val) == INTEGER_CST)
-    {
-      minmax[0] = minmax[1] = wi::to_wide (val);
-      return val;
-    }
-
-  if (TREE_CODE (val) != SSA_NAME)
-    return NULL_TREE;
+  if (!rvals)
+    rvals = get_range_query (cfun);
 
   value_range vr;
-  if (rvals && stmt)
-    {
-      if (!rvals->range_of_expr (vr, val, stmt))
-	return NULL_TREE;
-      value_range_kind rng = vr.kind ();
-      if (rng != VR_RANGE)
-	return NULL_TREE;
-
-      minmax[0] = wi::to_wide (vr.min ());
-      minmax[1] = wi::to_wide (vr.max ());
-      return val;
-    }
-
-  // ?? This entire function should use get_range_query or get_global_range_query (),
-  // instead of doing something different for RVALS and global ranges.
-
-  if (!get_global_range_query ()->range_of_expr (vr, val) || vr.undefined_p ())
+  if (!rvals->range_of_expr (vr, val, stmt))
     return NULL_TREE;
 
-  minmax[0] = wi::to_wide (vr.min ());
-  minmax[1] = wi::to_wide (vr.max ());
   value_range_kind rng = vr.kind ();
   if (rng == VR_RANGE)
-    /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
-    return val;
-
-  if (rng == VR_ANTI_RANGE)
     {
-      /* An anti-range is the same as an ordinary range with inverted
-	 bounds (where MINMAX[1] < MINMAX[0] is true) that may result
-	 from the conversion of a signed anti-range to unsigned.  */
-      wide_int tmp = minmax[0];
-      minmax[0] = minmax[1] + 1;
-      minmax[1] = wi::sub (tmp, 1);
+      /* Only handle straight ranges.  */
+      minmax[0] = wi::to_wide (vr.min ());
+      minmax[1] = wi::to_wide (vr.max ());
       return val;
     }
 
-  /* Do not handle anti-ranges and instead make use of the on-demand
-     VRP if/when it becomes available (hopefully in GCC 11).  */
   return NULL_TREE;
 }
 
@@ -943,8 +911,8 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 		      else
 			{
 			  value_range vr;
-			  get_global_range_query ()->range_of_expr (vr,
-							     si->nonzero_chars);
+			  get_range_query (cfun)
+			    ->range_of_expr (vr, si->nonzero_chars);
 			  rng = vr.kind ();
 			  if (!vr.undefined_p ())
 			    {
@@ -5820,27 +5788,7 @@ printf_strlen_execute (function *fun, bool warn_only)
   walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      unsigned nused = 0;
-      unsigned nidxs = walker.ptr_qry.var_cache->indices.length ();
-      for (unsigned i = 0; i != nidxs; ++i)
-	if (walker.ptr_qry.var_cache->indices[i])
-	  ++nused;
-
-      fprintf (dump_file, "pointer_query counters\n"
-	       "  index cache size:  %u\n"
-	       "  utilization:       %u%%\n"
-	       "  access cache size: %u\n"
-	       "  hits:              %u\n"
-	       "  misses:            %u\n"
-	       "  failures:          %u\n"
-	       "  max_depth:         %u\n",
-	       nidxs,
-	       nidxs == 0 ? 0 : (nused * 100) / nidxs,
-	       walker.ptr_qry.var_cache->access_refs.length (),
-	       walker.ptr_qry.hits, walker.ptr_qry.misses,
-	       walker.ptr_qry.failures, walker.ptr_qry.max_depth);
-    }
+    walker.ptr_qry.dump (dump_file);
 
   ssa_ver_to_stridx.release ();
   strinfo_pool.release ();


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-09-01 19:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-01 19:46 [gcc r12-3300] Enable ranger and caching in pass_waccess Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).