diff mbox series

[3/3] Enable pointer_query caching for -Wrestrict.

Message ID 20220202233530.2568647-4-msebor@redhat.com
State New
Headers show
Series Enable pointer_query caching throughout. | expand

Commit Message

Martin Sebor Feb. 2, 2022, 11:35 p.m. UTC
The third patch in the series adds a pointer_query instance to the wrestrict
pass and uses it for each invocation to check a function.

gcc/ChangeLog:

	* gimple-ssa-warn-restrict.cc (class pass_wrestrict): Outline ctor.
	(pass_wrestrict::m_ptr_qry): New member.
	(wrestrict_walk): Rename...
	(pass_wrestrict::check_block): ...to this.
	(pass_wrestrict::execute): Set up and tear down pointer_query and
	ranger.
	(builtin_memref::builtin_memref): Change ctor argument.  Simplify.
	(builtin_access::builtin_access): Same.
	(builtin_access::m_ptr_qry): New member.
	(check_call): Rename...
	(pass_wrestrict::check_call): ...to this.
	(check_bounds_or_overlap): Change argument.
	* gimple-ssa-warn-restrict.h (check_bounds_or_overlap): Same.
---
 gcc/gimple-ssa-warn-restrict.cc | 126 ++++++++++++++++----------------
 gcc/gimple-ssa-warn-restrict.h  |   2 +-
 2 files changed, 62 insertions(+), 66 deletions(-)
diff mbox series

Patch

diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
index d1beb01fe89..72418398dad 100644
--- a/gcc/gimple-ssa-warn-restrict.cc
+++ b/gcc/gimple-ssa-warn-restrict.cc
@@ -62,46 +62,63 @@  const pass_data pass_data_wrestrict = {
 class pass_wrestrict : public gimple_opt_pass
 {
  public:
-  pass_wrestrict (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_wrestrict, ctxt)
-    { }
+  pass_wrestrict (gcc::context *);
 
-  opt_pass *clone () { return new pass_wrestrict (m_ctxt); }
+  // opt_pass *clone () { return new pass_wrestrict (m_ctxt); }
 
   virtual bool gate (function *);
   virtual unsigned int execute (function *);
+
+  void check_call (gimple *);
+
+  void check_block (basic_block);
+
+  /* A pointer_query object to store information about pointers and
+     their targets in.  */
+  pointer_query m_ptr_qry;
 };
 
+pass_wrestrict::pass_wrestrict (gcc::context *ctxt)
+  : gimple_opt_pass (pass_data_wrestrict, ctxt),
+    m_ptr_qry ()
+{ }
+
 bool
 pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED)
 {
   return warn_array_bounds || warn_restrict || warn_stringop_overflow;
 }
 
-static void check_call (range_query *, gimple *);
-
-static void
-wrestrict_walk (range_query *query, basic_block bb)
+void
+pass_wrestrict::check_block (basic_block bb)
 {
   /* Iterate over statements, looking for function calls.  */
-  for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
-       gsi_next (&si))
+  for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     {
       gimple *stmt = gsi_stmt (si);
       if (!is_gimple_call (stmt))
 	continue;
 
-      check_call (query, stmt);
+      check_call (stmt);
     }
 }
 
 unsigned
 pass_wrestrict::execute (function *fun)
 {
-  gimple_ranger ranger;
+  /* Create a new ranger instance and associate it with FUN.  */
+  m_ptr_qry.rvals = enable_ranger (fun);
+
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
-    wrestrict_walk (&ranger, bb);
+    check_block (bb);
+
+  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;
 }
@@ -145,7 +162,7 @@  public:
      only the destination reference is.  */
   bool strbounded_p;
 
-  builtin_memref (range_query *, gimple *, tree, tree);
+  builtin_memref (pointer_query &, gimple *, tree, tree);
 
   tree offset_out_of_bounds (int, offset_int[3]) const;
 
@@ -153,7 +170,7 @@  private:
   /* Call statement to the built-in.  */
   gimple *stmt;
 
-  range_query *query;
+  pointer_query &m_ptr_qry;
 
   /* Ctor helper to set or extend OFFRANGE based on argument.  */
   void extend_offset_range (tree);
@@ -187,7 +204,8 @@  class builtin_access
 	    && detect_overlap != &builtin_access::no_overlap);
   }
 
-  builtin_access (range_query *, gimple *, builtin_memref &, builtin_memref &);
+  builtin_access (pointer_query &, gimple *,
+		  builtin_memref &, builtin_memref &);
 
   /* Entry point to determine overlap.  */
   bool overlap ();
@@ -225,7 +243,7 @@  class builtin_access
    a size SIZE in bytes.  If SIZE is NULL_TREE then the size is assumed
    to be unknown.  STMT is the statement in which expr appears in.  */
 
-builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
+builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr,
 				tree size)
 : ptr (expr),
   ref (),
@@ -238,7 +256,7 @@  builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
   maxobjsize (tree_to_shwi (max_object_size ())),
   strbounded_p (),
   stmt (stmt),
-  query (query)
+  m_ptr_qry (ptrqry)
 {
   /* Unfortunately, wide_int default ctor is a no-op so array members
      of the type must be set individually.  */
@@ -257,7 +275,7 @@  builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
       tree range[2];
       /* Determine the size range, allowing for the result to be [0, 0]
 	 for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX.  */
-      get_size_range (query, size, stmt, range, SR_ALLOW_ZERO);
+      get_size_range (m_ptr_qry.rvals, size, stmt, range, SR_ALLOW_ZERO);
       sizrange[0] = wi::to_offset (range[0]);
       sizrange[1] = wi::to_offset (range[1]);
       /* get_size_range returns SIZE_MAX for the maximum size.
@@ -334,23 +352,10 @@  builtin_memref::extend_offset_range (tree offset)
       /* A pointer offset is represented as sizetype but treated
 	 as signed.  */
       wide_int min, max;
-      value_range_kind rng;
+      value_range_kind rng = VR_VARYING;
       value_range vr;
-      if (query && query->range_of_expr (vr, offset, stmt))
-	{
-	  rng = vr.kind ();
-	  if (!vr.undefined_p ())
-	    {
-	      min = wi::to_wide (vr.min ());
-	      max = wi::to_wide (vr.max ());
-	    }
-	}
-      else
+      if (m_ptr_qry.rvals->range_of_expr (vr, offset, stmt))
 	{
-	  /* There is a global version here because
-	     check_bounds_or_overlap may be called from gimple
-	     fold during gimple lowering.  */
-	  get_range_query (cfun)->range_of_expr (vr, offset, stmt);
 	  rng = vr.kind ();
 	  if (!vr.undefined_p ())
 	    {
@@ -358,6 +363,7 @@  builtin_memref::extend_offset_range (tree offset)
 	      max = wi::to_wide (vr.max ());
 	    }
 	}
+
       if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
 	{
 	  /* Convert an anti-range whose upper bound is less than
@@ -674,7 +680,7 @@  builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[3]) const
 /* Create an association between the memory references DST and SRC
    for access by a call EXPR to a memory or string built-in funtion.  */
 
-builtin_access::builtin_access (range_query *query, gimple *call,
+builtin_access::builtin_access (pointer_query &ptrqry, gimple *call,
 				builtin_memref &dst,
 				builtin_memref &src)
 : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (),
@@ -766,39 +772,28 @@  builtin_access::builtin_access (range_query *query, gimple *call,
       return;
     }
 
-  const offset_int maxobjsize = dst.maxobjsize;
-
   /* Try to determine the size of the base object.  compute_objsize
      expects a pointer so create one if BASE is a non-pointer object.  */
-  tree addr;
   if (dst.basesize < 0)
     {
-      addr = dst.base;
-      if (!POINTER_TYPE_P (TREE_TYPE (addr)))
-	addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
-
-      if (tree dstsize = compute_objsize (addr, call, ostype))
-	dst.basesize = wi::to_offset (dstsize);
-      else if (POINTER_TYPE_P (TREE_TYPE (addr)))
-	dst.basesize = HOST_WIDE_INT_MIN;
+      access_ref aref;
+      if (ptrqry.get_ref (dst.base, call, &aref, ostype) && aref.base0)
+	dst.basesize = aref.sizrng[1];
       else
-	dst.basesize = maxobjsize;
+	dst.basesize = HOST_WIDE_INT_MIN;
     }
 
   if (src.base && src.basesize < 0)
     {
-      addr = src.base;
-      if (!POINTER_TYPE_P (TREE_TYPE (addr)))
-	addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
-
-      if (tree srcsize = compute_objsize (addr, call, ostype))
-	src.basesize = wi::to_offset (srcsize);
-      else if (POINTER_TYPE_P (TREE_TYPE (addr)))
-	src.basesize = HOST_WIDE_INT_MIN;
+      access_ref aref;
+      if (ptrqry.get_ref (src.base, call, &aref, ostype) && aref.base0)
+	src.basesize = aref.sizrng[1];
       else
-	src.basesize = maxobjsize;
+	src.basesize = HOST_WIDE_INT_MIN;
     }
 
+  const offset_int maxobjsize = dst.maxobjsize;
+
   /* Make adjustments for references to the same object by string
      built-in functions to reflect the constraints imposed by
      the function.  */
@@ -814,7 +809,7 @@  builtin_access::builtin_access (range_query *query, gimple *call,
 
       tree size = gimple_call_arg (call, sizeargno);
       tree range[2];
-      if (get_size_range (query, size, call, range, true))
+      if (get_size_range (ptrqry.rvals, size, call, range, true))
 	{
 	  bounds[0] = wi::to_offset (range[0]);
 	  bounds[1] = wi::to_offset (range[1]);
@@ -1895,8 +1890,8 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 /* Check a CALL statement for restrict-violations and issue warnings
    if/when appropriate.  */
 
-static void
-check_call (range_query *query, gimple *call)
+void
+pass_wrestrict::check_call (gimple *call)
 {
   /* Avoid checking the call if it has already been diagnosed for
      some reason.  */
@@ -1986,7 +1981,7 @@  check_call (range_query *query, gimple *call)
       || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
     return;
 
-  opt_code opt = check_bounds_or_overlap (query, call, dst, src, dstwr,
+  opt_code opt = check_bounds_or_overlap (m_ptr_qry, call, dst, src, dstwr,
 					  NULL_TREE);
   /* Avoid diagnosing the call again.  */
   suppress_warning (call, opt);
@@ -2006,25 +2001,26 @@  check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
 			 tree srcsize, bool bounds_only /* = false */,
 			 bool do_warn /* = true */)
 {
-  return check_bounds_or_overlap (/*range_query=*/NULL,
+  pointer_query ptrqry (get_range_query (cfun));
+  return check_bounds_or_overlap (ptrqry,
 				  call, dst, src, dstsize, srcsize,
 				  bounds_only, do_warn);
 }
 
 opt_code
-check_bounds_or_overlap (range_query *query,
+check_bounds_or_overlap (pointer_query &ptrqry,
 			 gimple *call, tree dst, tree src, tree dstsize,
 			 tree srcsize, bool bounds_only /* = false */,
 			 bool do_warn /* = true */)
 {
   tree func = gimple_call_fndecl (call);
 
-  builtin_memref dstref (query, call, dst, dstsize);
-  builtin_memref srcref (query, call, src, srcsize);
+  builtin_memref dstref (ptrqry, call, dst, dstsize);
+  builtin_memref srcref (ptrqry, call, src, srcsize);
 
   /* Create a descriptor of the access.  This may adjust both DSTREF
      and SRCREF based on one another and the kind of the access.  */
-  builtin_access acs (query, call, dstref, srcref);
+  builtin_access acs (ptrqry, call, dstref, srcref);
 
   /* Set STRICT to the value of the -Warray-bounds=N argument for
      string functions or when N > 1.  */
diff --git a/gcc/gimple-ssa-warn-restrict.h b/gcc/gimple-ssa-warn-restrict.h
index 1c60f51b500..2bdde030023 100644
--- a/gcc/gimple-ssa-warn-restrict.h
+++ b/gcc/gimple-ssa-warn-restrict.h
@@ -22,7 +22,7 @@ 
 
 extern opt_code check_bounds_or_overlap (gimple *, tree, tree, tree, tree,
 					 bool = false, bool = true);
-extern opt_code check_bounds_or_overlap (class range_query *, gimple *,
+extern opt_code check_bounds_or_overlap (class pointer_query &, gimple *,
 					 tree, tree, tree, tree,
 					 bool = false, bool = true);