summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2020-08-14 15:49:52 -0400
committerGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-17 15:08:14 -0300
commit27f2a40dadae86a9b6e1d0777dc4a0d99a3aee60 (patch)
treee7b75505738e5547574243d509694da647f10e80
parentfd151a9ade829371897e4661f11ae296ab3bb174 (diff)
downloadgcc-27f2a40dadae86a9b6e1d0777dc4a0d99a3aee60.tar.gz
analyzer: fix initialization from constant pool [PR96609,PR96616]
PR testsuite/96609 and PR analyzer/96616 report various testsuite failures seen on powerpc64, aarch64, and arm in new tests added by r11-2694-g808f4dfeb3a95f50f15e71148e5c1067f90a126d. Some of these failures (in gcc.dg/analyzer/init.c, and on arm in gcc.dg/analyzer/casts-1.c) relate to initializations from var_decls in the constant pool. I wrote the tests assuming that the gimplified stmts would initialize the locals via a gassign of code CONSTRUCTOR, whereas on these targets some of the initializations are gassign from a VAR_DECL e.g.: c = *.LC0; where "*.LC0" is a var_decl with DECL_IN_CONSTANT_POOL set. For example, in test_7: struct coord c[2] = {{3, 4}, {5, 6}}; __analyzer_eval (c[0].x == 3); /* { dg-warning "TRUE" } */ after the initialization, the store was simply recording: cluster for: c: INIT_VAL(*.LC0) when I was expecting the cluster for c to have: cluster for: c key: {kind: direct, start: 0, size: 32, next: 32} value: 'int' {(int)3} key: {kind: direct, start: 32, size: 32, next: 64} value: 'int' {(int)4} key: {kind: direct, start: 64, size: 32, next: 96} value: 'int' {(int)5} key: {kind: direct, start: 96, size: 32, next: 128} value: 'int' {(int)6} The test for c[0].x == 3 would then generate: cluster for: _2: (SUB(SUB(INIT_VAL(*.LC0), c[(int)0]), c[(int)0].x)==(int)3) which is UNKNOWN, leading to the test failing. This patch fixes the init.c and casts-1.c failures by special-casing reads from a var_decl with DECL_IN_CONSTANT_POOL set, so that they build a compound_svalue containing the bindings implied by the CONSTRUCTOR node for DECL_INITIAL. gcc/analyzer/ChangeLog: PR testsuite/96609 PR analyzer/96616 * region-model.cc (region_model::get_store_value): Call maybe_get_constant_value on decl_regions first. * region-model.h (decl_region::maybe_get_constant_value): New decl. * region.cc (decl_region::get_stack_depth): Likewise. (decl_region::maybe_get_constant_value): New. * store.cc (get_subregion_within_ctor): New. (binding_map::apply_ctor_to_region): New. * store.h (binding_map::apply_ctor_to_region): New decl.
-rw-r--r--gcc/analyzer/region-model.cc5
-rw-r--r--gcc/analyzer/region-model.h2
-rw-r--r--gcc/analyzer/region.cc27
-rw-r--r--gcc/analyzer/store.cc59
-rw-r--r--gcc/analyzer/store.h3
5 files changed, 96 insertions, 0 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 649e20438e4..3c7ea40e8d8 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1192,6 +1192,11 @@ region_model::get_rvalue (tree expr, region_model_context *ctxt)
const svalue *
region_model::get_store_value (const region *reg) const
{
+ /* Special-case: handle var_decls in the constant pool. */
+ if (const decl_region *decl_reg = reg->dyn_cast_decl_region ())
+ if (const svalue *sval = decl_reg->maybe_get_constant_value (m_mgr))
+ return sval;
+
const svalue *sval
= m_store.get_any_binding (m_mgr->get_store_manager (), reg);
if (sval)
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 33aa3461611..3d044bf8d6c 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1869,6 +1869,8 @@ public:
tree get_decl () const { return m_decl; }
int get_stack_depth () const;
+ const svalue *maybe_get_constant_value (region_model_manager *mgr) const;
+
private:
tree m_decl;
};
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index f3f577c43de..afe416b001b 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -874,6 +874,33 @@ decl_region::get_stack_depth () const
return 0;
}
+/* If the underlying decl is in the global constant pool,
+ return an svalue representing the constant value.
+ Otherwise return NULL. */
+
+const svalue *
+decl_region::maybe_get_constant_value (region_model_manager *mgr) const
+{
+ if (TREE_CODE (m_decl) == VAR_DECL
+ && DECL_IN_CONSTANT_POOL (m_decl)
+ && DECL_INITIAL (m_decl)
+ && TREE_CODE (DECL_INITIAL (m_decl)) == CONSTRUCTOR)
+ {
+ tree ctor = DECL_INITIAL (m_decl);
+ 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. */
+ binding_map map;
+ map.apply_ctor_to_region (this, ctor, mgr);
+
+ /* Return a compound svalue for the map we built. */
+ return mgr->get_or_create_compound_svalue (get_type (), map);
+ }
+ return NULL;
+}
+
/* class field_region : public region. */
/* Implementation of region::dump_to_pp vfunc for field_region. */
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 950a7784542..232920019e0 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -366,6 +366,65 @@ binding_map::dump (bool simple) const
pp_flush (&pp);
}
+/* Get the child region of PARENT_REG based upon INDEX within a
+ CONSTRUCTOR. */
+
+static const region *
+get_subregion_within_ctor (const region *parent_reg, tree index,
+ region_model_manager *mgr)
+{
+ switch (TREE_CODE (index))
+ {
+ default:
+ gcc_unreachable ();
+ case INTEGER_CST:
+ {
+ const svalue *index_sval
+ = mgr->get_or_create_constant_svalue (index);
+ return mgr->get_element_region (parent_reg,
+ TREE_TYPE (parent_reg->get_type ()),
+ index_sval);
+ }
+ break;
+ case FIELD_DECL:
+ return mgr->get_field_region (parent_reg, index);
+ }
+}
+
+/* Bind values from CONSTRUCTOR to this map, relative to
+ PARENT_REG's relationship to its base region. */
+
+void
+binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
+ region_model_manager *mgr)
+{
+ gcc_assert (parent_reg);
+ gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);
+ gcc_assert (!CONSTRUCTOR_NO_CLEARING (ctor));
+
+ unsigned ix;
+ tree index;
+ tree val;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), ix, index, val)
+ {
+ if (!index)
+ index = build_int_cst (integer_type_node, ix);
+ const region *child_reg
+ = get_subregion_within_ctor (parent_reg, index, mgr);
+ if (TREE_CODE (val) == CONSTRUCTOR)
+ apply_ctor_to_region (child_reg, val, mgr);
+ else
+ {
+ gcc_assert (CONSTANT_CLASS_P (val));
+ const svalue *cst_sval = mgr->get_or_create_constant_svalue (val);
+ const binding_key *k
+ = binding_key::make (mgr->get_store_manager (), child_reg,
+ BK_direct);
+ put (k, cst_sval);
+ }
+ }
+}
+
/* class binding_cluster. */
/* binding_cluster's copy ctor. */
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 4f251d6420f..16bad030b36 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -340,6 +340,9 @@ public:
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
void dump (bool simple) const;
+ void apply_ctor_to_region (const region *parent_reg, tree ctor,
+ region_model_manager *mgr);
+
private:
map_t m_map;
};