From 9ab537978f16106cb658b6605d1584e47f067386 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 14 Apr 2020 23:22:40 -0400
Subject: [PATCH 038/159] FIXME: introduce initial values

---
 gcc/analyzer/analyzer.h       |   1 +
 gcc/analyzer/region-model2.cc | 180 ++++++++++++++++++++++++++++++----
 gcc/analyzer/region-model2.h  |  76 +++++++++++++-
 3 files changed, 236 insertions(+), 21 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 16bec81a4a9..a73ffdf5696 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -60,6 +60,7 @@ class svalue2;
   class poisoned_svalue2;
   class unknown_svalue2;
   class setjmp_svalue2;
+  class initial_svalue2;
 class region2;
   class map_region2;
   class symbolic_region2;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 152800871ce..061b5fa62bf 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -662,6 +662,66 @@ poisoned_svalue2::print_details (const region_model2 &model ATTRIBUTE_UNUSED,
 /* class setjmp_svalue2's implementation is in engine.cc, so that it can use
    the declaration of exploded_node.  */
 
+/* class initial_svalue2 : public svalue2.  */
+
+/* FIXME.  */
+
+void
+initial_svalue2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      pp_string (pp, "initial value of ");
+      m_reg->dump_to_pp (pp, simple);
+    }
+  else
+    {
+      pp_string (pp, "initial_svalue2(");
+      print_quoted_type (pp, get_type ());
+      pp_string (pp, ", ");
+      m_reg->dump_to_pp (pp, simple);
+      pp_string (pp, ")");
+    }
+}
+
+/* Compare the fields of this initial_svalue2 with OTHER, returning true
+   if they are equal.
+   For use by svalue2::operator==.  */
+#if 0
+bool
+initial_svalue2::compare_fields (const initial_svalue2 &other) const
+{
+  return m_reg == other.m_reg;
+}
+#endif
+
+/* Implementation of svalue2::add_to_hash vfunc for initial_svalue2.  */
+
+#if 0
+void
+initial_svalue2::add_to_hash (inchash::hash &hstate) const
+{
+  inchash::add (m_reg, hstate);
+}
+#endif
+/* Implementation of svalue2::print_details vfunc for initial_svalue2.  */
+
+#if 0
+void
+initial_svalue2::print_details (const region_model2 &model ATTRIBUTE_UNUSED,
+			      svalue2_id this_sval ATTRIBUTE_UNUSED,
+			      pretty_printer *pp) const
+{
+  if (m_reg.null_p ())
+    pp_string (pp, "NULL");
+  else
+    {
+      pp_string (pp, "&");
+      m_reg.print (pp);
+    }
+}
+#endif
+
 /* class region2 and its various subclasses.  */
 
 /* Get a string for KIND for use in debug dumps.  */
@@ -2990,10 +3050,10 @@ binding_cluster::bind (region_model2_manager *mgr,
 }
 
 svalue2 *
-binding_cluster::get_binding (region_model2_manager *mgr, region2 *reg) const
+binding_cluster::get_binding (region_model2_manager *mgr, region2 *reg,
+			      binding_key::kind kind) const
 {
-  const binding_key *binding
-    = binding_key::make (mgr, reg, binding_key::BK_direct);
+  const binding_key *binding = binding_key::make (mgr, reg, kind);
   svalue2 **slot = const_cast<map_t &> (m_map).get (binding);
   if (slot)
     return *slot;
@@ -3097,24 +3157,34 @@ region_model2_manager::get_element_region (region2 *parent,
 }
 
 const concrete_binding *
-region_model2_manager::get_concrete_binding (const region2 *region,
+region_model2_manager::get_concrete_binding (const region2 *reg,
 					     enum binding_key::kind kind,
 					     concrete_binding::bit_offset_t offset)
 {
-  concrete_binding *b = new concrete_binding (region, kind, offset);
+  concrete_binding *b = new concrete_binding (reg, kind, offset);
   return m_concrete_binding_key_mgr.consolidate (b);
 }
 
 const symbolic_binding *
-region_model2_manager::get_symbolic_binding (const region2 *region,
+region_model2_manager::get_symbolic_binding (const region2 *reg,
 					     enum binding_key::kind kind,
 					     region2 *concrete_offset_region)
 {
   symbolic_binding *b
-    = new symbolic_binding (region, kind, concrete_offset_region);
+    = new symbolic_binding (reg, kind, concrete_offset_region);
   return m_symbolic_binding_key_mgr.consolidate (b);
 }
 
+svalue2 *
+region_model2_manager::get_or_create_initial_value (const region2 *reg)
+{
+  if (initial_svalue2 **slot = m_initial_values_map.get (reg))
+    return *slot;
+  initial_svalue2 *initial_sval = new initial_svalue2 (reg->get_type (), reg);
+  m_initial_values_map.put (reg, initial_sval);
+  return initial_sval;
+}
+
 /* class region_model2.  */
 
 /* region_model2's default ctor.  */
@@ -4740,6 +4810,10 @@ region_model2::get_rvalue_1 (region_model2_manager *mgr, path_var pv,
       break;
 
 #endif
+    case SSA_NAME:
+    case VAR_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
     case ARRAY_REF:
       {
 	region2 *element_reg = get_lvalue (mgr, pv, ctxt);
@@ -4753,10 +4827,6 @@ region_model2::get_rvalue_1 (region_model2_manager *mgr, path_var pv,
 #if 0
     case COMPONENT_REF:
     case MEM_REF:
-    case SSA_NAME:
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
       {
 	region2 *var_reg = get_lvalue (pv, ctxt);
 	return get_region2 (var_reg)->get_value (*this, true, ctxt);
@@ -4796,17 +4866,36 @@ region_model2::get_rvalue (region_model2_manager *mgr, tree expr,
 
 svalue2 *
 region_model2::get_store_value (region_model2_manager *mgr, region2 *reg)
+{
+  svalue2 *sval = get_direct_binding (mgr, reg);
+  if (sval)
+    return sval;
+
+  /* FIXME: symbolic value. */
+  return mgr->get_or_create_initial_value (reg);
+}
+
+svalue2 *
+region_model2::get_direct_binding (region_model2_manager *mgr, region2 *reg)
+{
+  return get_binding (mgr, reg, binding_key::BK_direct);
+}
+
+svalue2 *
+region_model2::get_default_binding (region_model2_manager *mgr, region2 *reg)
+{
+  return get_binding (mgr, reg, binding_key::BK_direct);
+}
+
+svalue2 *
+region_model2::get_binding (region_model2_manager *mgr, region2 *reg,
+			    binding_key::kind kind)
 {
   const region2 *base_reg = reg->get_base_region ();
   binding_cluster **cluster_slot = m_cluster_map.get (base_reg);
-  if (cluster_slot)
-    {
-      if (svalue2 *result = (*cluster_slot)->get_binding (mgr, reg))
-	return result;
-    }
-
-  /* Otherwise, no bound value.  */
-  gcc_unreachable (); // TODO
+  if (!cluster_slot)
+    return NULL;
+  return (*cluster_slot)->get_binding (mgr, reg, kind);
 }
 
 /* Return an svalue2 *for a pointer to RID of type PTR_TYPE, reusing
@@ -8325,6 +8414,58 @@ test_malloc_constraints ()
 }
 #endif
 
+static void
+test_var ()
+{
+  /* "int i;"  */
+  tree i = build_global_decl ("i", integer_type_node);
+
+  tree int_17 = build_int_cst (integer_type_node, 17);
+  tree int_m3 = build_int_cst (integer_type_node, -3);
+
+  region_model2_manager mgr;
+  region_model2 model;
+
+  region2 *i_reg = model.get_lvalue (&mgr, i, NULL);
+  ASSERT_EQ (i_reg->get_kind (), region2::RK_DECL);
+
+  /* Reading "i" should give a symbolic "initial value".  */
+  svalue2 *sval_init = model.get_rvalue (&mgr, i, NULL);
+  ASSERT_EQ (sval_init->get_kind (), svalue2::SK_INITIAL);
+  ASSERT_EQ (sval_init->dyn_cast_initial_svalue2 ()->get_region (), i_reg);
+  /* ..and doing it again should give the same "initial value".  */
+  ASSERT_EQ (model.get_rvalue (&mgr, i, NULL), sval_init);
+
+  /* "i = 17;".  */
+  model.set_value (&mgr, i, int_17, NULL);
+  ASSERT_EQ (model.get_rvalue (&mgr, i, NULL),
+	     model.get_rvalue (&mgr, int_17, NULL));
+
+  /* "i = -3;".  */
+  model.set_value (&mgr, i, int_m3, NULL);
+  ASSERT_EQ (model.get_rvalue (&mgr, i, NULL),
+	     model.get_rvalue (&mgr, int_m3, NULL));
+
+  /* Verify get_offset for "i".  */
+  {
+    region_offset offset = i_reg->get_offset ();
+    ASSERT_EQ (offset.get_base_region (), i_reg);
+    ASSERT_EQ (offset.get_bit_offset (), 0);
+  }
+
+  /* Simplified dump.  */
+#if 0
+  ASSERT_DUMP_EQ (model, true,
+		  "base region: {c} has cluster: {"
+		  "binding key: {region: c.x, kind: direct, offset: 0},"
+		  " value: {17},"
+		  " binding key: {region: c.y, kind: direct, offset: 0},"
+		  " value: {-3}"
+		  "}");
+#endif
+
+}
+
 static void
 test_array ()
 {
@@ -8440,6 +8581,7 @@ analyzer_region_model2_cc_tests ()
   test_constraint_merging ();
   test_malloc_constraints ();
 #endif
+  test_var ();
   test_array ();
 }
 
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 80d1dac9a8d..928e609f4ac 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -133,6 +133,7 @@ struct purge_stats
    The class hierarchy looks like this (using indentation to show
    inheritance, and with kinds shown for the concrete subclasses):
 
+FIXME: needs overhauling:
    svalue2
      region_svalue2 (SK_REGION)
      constant_svalue2 (SK_CONSTANT)
@@ -153,7 +154,8 @@ public:
    SK_CONSTANT,
    SK_UNKNOWN,
    SK_POISONED,
-   SK_SETJMP
+   SK_SETJMP,
+   SK_INITIAL
   };
 
   virtual ~svalue2 () {}
@@ -189,6 +191,7 @@ public:
   virtual poisoned_svalue2 *dyn_cast_poisoned_svalue2 () { return NULL; }
   virtual unknown_svalue2 *dyn_cast_unknown_svalue2 () { return NULL; }
   virtual setjmp_svalue2 *dyn_cast_setjmp_svalue2 () { return NULL; }
+  virtual initial_svalue2 *dyn_cast_initial_svalue2 () { return NULL; }
 
   tree maybe_get_constant () const;
 
@@ -494,6 +497,64 @@ public:
   setjmp_record m_setjmp_record;
 };
 
+/* Concrete subclass of svalue2 representing the initial value of a
+   specific region  */
+
+class initial_svalue2 : public svalue2
+{
+public:
+  initial_svalue2 (tree type, const region2 *reg) : svalue2 (type), m_reg (reg)
+  {
+    gcc_assert (m_reg != NULL);
+  }
+
+  enum kind get_kind () const FINAL OVERRIDE { return SK_INITIAL; }
+
+#if 0
+  void dump_dot_to_pp (const region_model2 &model,
+		       pretty_printer *pp) const
+    FINAL OVERRIDE;
+#endif
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+  initial_svalue2 *dyn_cast_initial_svalue2 () FINAL OVERRIDE { return this; }
+
+  const region2 * get_region () const { return m_reg; }
+
+#if 0
+  static void merge_values (const initial_svalue2 &region_sval_a,
+			    const initial_svalue2 &region_sval_b,
+			    svalue2_id *merged_sid,
+			    tree type,
+			    model_merger *merger);
+#endif
+
+#if 0
+  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
+#endif
+
+ private:
+#if 0
+  void print_details (const region_model2 &model, pretty_printer *pp) const
+    FINAL OVERRIDE;
+#endif
+
+  const region2 *m_reg;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <initial_svalue2 *>::test (svalue2 *sval)
+{
+  return sval->get_kind () == svalue2::SK_INITIAL;
+}
+
+namespace ana {
+
 /* The location of a region expressesd as an offset relative to a
    base region.  */
 
@@ -1396,7 +1457,8 @@ public:
 			       const region2 *, const svalue2 *) const;
 #endif
 
-  svalue2 *get_binding (region_model2_manager *mgr, region2 *reg) const;
+  svalue2 *get_binding (region_model2_manager *mgr, region2 *reg,
+			binding_key::kind kind) const;
 
   void remove_overlapping_bindings (region_model2_manager *mgr, region2 *reg);
 
@@ -1439,6 +1501,8 @@ public:
 			enum binding_key::kind kind,
 			region2 *concrete_offset_region);
 
+  svalue2 *get_or_create_initial_value (const region2 *reg);
+
   unsigned alloc_region_id () { return m_next_region_id++; }
 
 private:
@@ -1448,6 +1512,9 @@ private:
   typedef hash_map<tree, constant_svalue2 *> constants_map_t;
   constants_map_t m_constants_map;
 
+  typedef hash_map<const region2 *, initial_svalue2 *> initial_values_map_t;
+  initial_values_map_t m_initial_values_map;
+
   globals_region2 m_globals_region;
   typedef hash_map<tree, decl_region2 *> globals_map_t;
   typedef globals_map_t::iterator globals_iterator_t;
@@ -1675,6 +1742,11 @@ class region_model2
 			 region_model2_context *ctxt);
   svalue2 *get_store_value (region_model2_manager *mgr, region2 *reg);
 
+  svalue2 *get_direct_binding (region_model2_manager *mgr, region2 *reg);
+  svalue2 *get_default_binding (region_model2_manager *mgr, region2 *reg);
+  svalue2 *get_binding (region_model2_manager *mgr, region2 *reg,
+			binding_key::kind kind);
+
   void remove_overlapping_bindings (region_model2_manager *mgr, region2 *reg);
 
 #if 0
-- 
2.21.0

