From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2209) id 2E6393858D35; Fri, 9 Jun 2023 22:05:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2E6393858D35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1686348315; bh=Hwnae8cbdGQXXTBFk/nrht0KfwiTCWw3qU3ykvPL1Xk=; h=From:To:Subject:Date:From; b=MpRi9DqOu0a7vhlLld9Q7vV9W147eHXn/FRfko0UbxnWQvrM93nFV3FLTEjeVlKdw mC7J7xmUlWXoYDAvhyv/nzbkFeLCOdg94ppZtcOx+N/Mb/K1hDzVOziGAVECQRcEZB 3P5I2i/hNL6LQJQw5Ha5Kc8xDRy6KwdLg68sQ9/c= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: David Malcolm To: gcc-cvs@gcc.gnu.org Subject: [gcc r14-1664] analyzer: add caching to globals with initializers [PR110112] X-Act-Checkin: gcc X-Git-Author: David Malcolm X-Git-Refname: refs/heads/master X-Git-Oldrev: 067a8c7cb897b6a1ea5b1d26df8e89ccc7f0659c X-Git-Newrev: fe9771b59f576fb37e762013ef5d9b26162e3a88 Message-Id: <20230609220515.2E6393858D35@sourceware.org> Date: Fri, 9 Jun 2023 22:05:15 +0000 (GMT) List-Id: https://gcc.gnu.org/g:fe9771b59f576fb37e762013ef5d9b26162e3a88 commit r14-1664-gfe9771b59f576fb37e762013ef5d9b26162e3a88 Author: David Malcolm Date: Fri Jun 9 17:58:33 2023 -0400 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 Diff: --- gcc/analyzer/region-model.cc | 25 +--------------- gcc/analyzer/region.cc | 71 ++++++++++++++++++++++++++++++++++++++++---- gcc/analyzer/region.h | 14 ++++++++- 3 files changed, 79 insertions(+), 31 deletions(-) diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index fb96cd54940..b11cc6c5bb4 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