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