[pushed] analyzer: add caching to globals with initializers [PR110112]

Message ID 20230609220801.587289-1-dmalcolm@redhat.com
State Committed
Commit fe9771b59f576fb37e762013ef5d9b26162e3a88
Headers
Series [pushed] analyzer: add caching to globals with initializers [PR110112] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Patch failed to apply

Commit Message

David Malcolm June 9, 2023, 10:08 p.m. UTC
  PR analyzer/110112 notes that -fanalyzer is extremely slow on a source
file with large read-only static arrays, repeatedly building the
same compound_svalue representing the full initializer, and repeatedly
building svalues representing parts of the the full initialiazer.

This patch adds caches for both of these; together they reduce the time
taken by -fanalyzer -O2 on the testcase in the bug for an optimized
build:
  91.2s : no caches (status quo)
  32.4s : cache in decl_region::get_svalue_for_constructor
   3.7s : cache in region::get_initial_value_at_main
   3.1s : both caches (this patch)

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r14-1664-gfe9771b59f576f.

gcc/analyzer/ChangeLog:
	PR analyzer/110112
	* region-model.cc (region_model::get_initial_value_for_global):
	Move code to region::calc_initial_value_at_main.
	* region.cc (region::get_initial_value_at_main): New function.
	(region::calc_initial_value_at_main): New function, based on code
	in region_model::get_initial_value_for_global.
	(region::region): Initialize m_cached_init_sval_at_main.
	(decl_region::get_svalue_for_constructor): Add a cache, splitting
	out body to...
	(decl_region::calc_svalue_for_constructor): ...this new function.
	* region.h (region::get_initial_value_at_main): New decl.
	(region::calc_initial_value_at_main): New decl.
	(region::m_cached_init_sval_at_main): New field.
	(decl_region::decl_region): Initialize m_ctor_svalue.
	(decl_region::calc_svalue_for_constructor): New decl.
	(decl_region::m_ctor_svalue): New field.
---
 gcc/analyzer/region-model.cc | 25 +------------
 gcc/analyzer/region.cc       | 71 +++++++++++++++++++++++++++++++++---
 gcc/analyzer/region.h        | 14 ++++++-
 3 files changed, 79 insertions(+), 31 deletions(-)
  

Patch

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 3bb3df2f063..4188cc72ad2 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -2355,30 +2355,7 @@  region_model::get_initial_value_for_global (const region *reg) const
      the initial value of REG can be taken from the initialization value
      of the decl.  */
   if (called_from_main_p () || TREE_READONLY (decl))
-    {
-      /* Attempt to get the initializer value for base_reg.  */
-      if (const svalue *base_reg_init
-	    = base_reg->get_svalue_for_initializer (m_mgr))
-	{
-	  if (reg == base_reg)
-	    return base_reg_init;
-	  else
-	    {
-	      /* Get the value for REG within base_reg_init.  */
-	      binding_cluster c (base_reg);
-	      c.bind (m_mgr->get_store_manager (), base_reg, base_reg_init);
-	      const svalue *sval
-		= c.get_any_binding (m_mgr->get_store_manager (), reg);
-	      if (sval)
-		{
-		  if (reg->get_type ())
-		    sval = m_mgr->get_or_create_cast (reg->get_type (),
-						      sval);
-		  return sval;
-		}
-	    }
-	}
-    }
+    return reg->get_initial_value_at_main (m_mgr);
 
   /* Otherwise, return INIT_VAL(REG).  */
   return m_mgr->get_or_create_initial_value (reg);
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 8f0eb569b33..098b43608ef 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -272,6 +272,51 @@  region::can_have_initial_svalue_p () const
     }
 }
 
+/* For regions within a global decl, get the svalue for the initial
+   value of this region when the program starts, caching the result.  */
+
+const svalue *
+region::get_initial_value_at_main (region_model_manager *mgr) const
+{
+  if (!m_cached_init_sval_at_main)
+    m_cached_init_sval_at_main = calc_initial_value_at_main (mgr);
+  return m_cached_init_sval_at_main;
+}
+
+/* Implementation of region::get_initial_value_at_main.  */
+
+const svalue *
+region::calc_initial_value_at_main (region_model_manager *mgr) const
+{
+  const decl_region *base_reg = get_base_region ()->dyn_cast_decl_region ();
+  gcc_assert (base_reg);
+
+  /* Attempt to get the initializer value for base_reg.  */
+  if (const svalue *base_reg_init
+      = base_reg->get_svalue_for_initializer (mgr))
+    {
+      if (this == base_reg)
+	return base_reg_init;
+      else
+	{
+	  /* Get the value for REG within base_reg_init.  */
+	  binding_cluster c (base_reg);
+	  c.bind (mgr->get_store_manager (), base_reg, base_reg_init);
+	  const svalue *sval
+	    = c.get_any_binding (mgr->get_store_manager (), this);
+	  if (sval)
+	    {
+	      if (get_type ())
+		sval = mgr->get_or_create_cast (get_type (), sval);
+	      return sval;
+	    }
+	}
+    }
+
+  /* Otherwise, return INIT_VAL(REG).  */
+  return mgr->get_or_create_initial_value (this);
+}
+
 /* If this region is a decl_region, return the decl.
    Otherwise return NULL.  */
 
@@ -701,7 +746,7 @@  region::is_named_decl_p (const char *decl_name) const
 
 region::region (complexity c, unsigned id, const region *parent, tree type)
 : m_complexity (c), m_id (id), m_parent (parent), m_type (type),
-  m_cached_offset (NULL)
+  m_cached_offset (NULL), m_cached_init_sval_at_main (NULL)
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
@@ -1170,14 +1215,13 @@  decl_region::maybe_get_constant_value (region_model_manager *mgr) const
   return NULL;
 }
 
-/* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl.  */
+/* Implementation of decl_region::get_svalue_for_constructor
+   for when the cached value hasn't yet been calculated.  */
 
 const svalue *
-decl_region::get_svalue_for_constructor (tree ctor,
-					 region_model_manager *mgr) const
+decl_region::calc_svalue_for_constructor (tree ctor,
+					  region_model_manager *mgr) const
 {
-  gcc_assert (!TREE_CLOBBER_P (ctor));
-
   /* Create a binding map, applying ctor to it, using this
      decl_region as the base region when building child regions
      for offset calculations.  */
@@ -1189,6 +1233,21 @@  decl_region::get_svalue_for_constructor (tree ctor,
   return mgr->get_or_create_compound_svalue (get_type (), map);
 }
 
+/* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl.  */
+
+const svalue *
+decl_region::get_svalue_for_constructor (tree ctor,
+					 region_model_manager *mgr) const
+{
+  gcc_assert (!TREE_CLOBBER_P (ctor));
+  gcc_assert (ctor == DECL_INITIAL (m_decl));
+
+  if (!m_ctor_svalue)
+    m_ctor_svalue = calc_svalue_for_constructor (ctor, mgr);
+
+  return m_ctor_svalue;
+}
+
 /* For use on decl_regions for global variables.
 
    Get an svalue for the initial value of this region at entry to
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 5df0ae7487b..270e5042eeb 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -161,6 +161,7 @@  public:
   const frame_region *maybe_get_frame_region () const;
   enum memory_space get_memory_space () const;
   bool can_have_initial_svalue_p () const;
+  const svalue *get_initial_value_at_main (region_model_manager *mgr) const;
 
   tree maybe_get_decl () const;
 
@@ -240,6 +241,7 @@  public:
 
  private:
   region_offset calc_offset (region_model_manager *mgr) const;
+  const svalue *calc_initial_value_at_main (region_model_manager *mgr) const;
 
   complexity m_complexity;
   unsigned m_id; // purely for deterministic sorting at this stage, for dumps
@@ -247,6 +249,10 @@  public:
   tree m_type;
 
   mutable region_offset *m_cached_offset;
+
+  /* For regions within a global decl, a cache of the svalue for the initial
+     value of this region when the program starts.  */
+  mutable const svalue *m_cached_init_sval_at_main;
 };
 
 } // namespace ana
@@ -696,7 +702,8 @@  class decl_region : public region
 public:
   decl_region (unsigned id, const region *parent, tree decl)
   : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl),
-    m_tracked (calc_tracked_p (decl))
+    m_tracked (calc_tracked_p (decl)),
+    m_ctor_svalue (NULL)
   {}
 
   enum region_kind get_kind () const final override { return RK_DECL; }
@@ -716,6 +723,8 @@  public:
   const svalue *get_svalue_for_initializer (region_model_manager *mgr) const;
 
 private:
+  const svalue *calc_svalue_for_constructor (tree ctor,
+					     region_model_manager *mgr) const;
   static bool calc_tracked_p (tree decl);
 
   tree m_decl;
@@ -725,6 +734,9 @@  private:
      store objects).
      This can be debugged using -fdump-analyzer-untracked.  */
   bool m_tracked;
+
+  /* Cached result of get_svalue_for_constructor.  */
+  mutable const svalue *m_ctor_svalue;
 };
 
 } // namespace ana