analyzer: add caching to globals with initializers [PR110112]

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)

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.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2023-06-09 17:58:33 -04:00
parent 067a8c7cb8
commit fe9771b59f
3 changed files with 79 additions and 31 deletions

View file

@ -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);

View file

@ -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

View file

@ -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