From 538fe12ea76eb3575ebecf016819e5a7cefb7d5b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 14 Apr 2020 14:51:03 -0400
Subject: [PATCH 34/96] FIXME: start adding array handling

---
 gcc/analyzer/region-model2.cc | 195 ++++++++++++++++++++++++++++++----
 gcc/analyzer/region-model2.h  |  91 ++++++++++------
 2 files changed, 236 insertions(+), 50 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index b08e3d679f2..b4de5a23bdd 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -697,9 +697,9 @@ region2::kind_to_str (enum kind kind)
 /* FIXME.  */
 
 int
-region2::cmp_indices (const region2 *reg1, const region2 *reg2)
+region2::cmp_ids (const region2 *reg1, const region2 *reg2)
 {
-  return (long)reg1->get_idx () - (long)reg2->get_idx ();
+  return (long)reg1->get_id () - (long)reg2->get_id ();
 }
 
 /* class region2.  */
@@ -817,6 +817,14 @@ region2::operator== (const region2 &other) const
 	  = (const field_region2 &)other;
 	return this_sub.compare_fields (other_sub);
       }
+    case RK_ELEMENT:
+      {
+	const element_region2 &this_sub
+	  = (const element_region2 &)*this;
+	const element_region2 &other_sub
+	  = (const element_region2 &)other;
+	return this_sub.compare_fields (other_sub);
+      }
     }
 }
 
@@ -832,6 +840,7 @@ region2::get_base_region () const
 	{
 	  //case RK_element_region:
 	case RK_FIELD:
+	case RK_ELEMENT:
 	  iter = iter->get_parent_region ();
 	  continue;
 	default:
@@ -1327,8 +1336,8 @@ region2::get_view (tree type, region_model2 *model) const
 
 /* region2's ctor.  */
 
-region2::region2 (unsigned idx, region2 *parent, tree type)
-: m_idx (idx), m_parent (parent), m_type (type)
+region2::region2 (unsigned id, region2 *parent, tree type)
+: m_id (id), m_parent (parent), m_type (type)
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
@@ -1339,6 +1348,8 @@ region2::region2 (unsigned idx, region2 *parent, tree type)
 void
 region2::add_to_hash (inchash::hash &hstate) const
 {
+  /* We deliberatly omit the id, to avoid different IDs preventing
+     consolidation.  */
   hstate.add_ptr (m_parent);
   hstate.add_ptr (m_type);
 }
@@ -1373,7 +1384,7 @@ region2::cmp_ptrs (const void *p1, const void *p2)
   const region2 * const *reg1 = (const region2 * const *)p1;
   const region2 * const *reg2 = (const region2 * const *)p2;
 
-  return cmp_indices (*reg1, *reg2);
+  return cmp_ids (*reg1, *reg2);
 }
 
 /* Determine if a pointer to this region2 must be non-NULL.
@@ -2266,8 +2277,8 @@ heap_region2::compare_fields (const heap_region2 &) const
 
 /* root_region2's default ctor.  */
 
-root_region2::root_region2 (unsigned idx)
-: region2 (idx, NULL, NULL_TREE)
+root_region2::root_region2 (unsigned id)
+: region2 (id, NULL, NULL_TREE)
 {
 }
 
@@ -2756,6 +2767,43 @@ field_region2::dump_to_pp (pretty_printer *pp, bool simple) const
     }
 }
 
+/* class element_region2 : public region2.  */
+
+bool
+element_region2::compare_fields (const element_region2 &other) const
+{
+  return m_index == other.m_index;
+}
+
+void
+element_region2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      get_parent_region ()->dump_to_pp (pp, simple);
+      pp_string (pp, "[");
+      m_index->dump_to_pp (pp, simple);
+      pp_string (pp, "]");
+    }
+  else
+    {
+      pp_string (pp, "element_region2(");
+      get_parent_region ()->dump_to_pp (pp, simple);
+      pp_string (pp, ", ");
+      print_quoted_type (pp, get_type ());
+      pp_string (pp, ", ");
+      m_index->dump_to_pp (pp, simple);
+      pp_printf (pp, ")");
+    }
+}
+
+void
+element_region2::add_to_hash (inchash::hash &hstate) const
+{
+  region2::add_to_hash (hstate);
+  hstate.add_ptr (m_index);
+}
+
 /* class binding_key.  */
 
 /* FIXME.  */
@@ -2773,7 +2821,7 @@ binding_key::cmp_ptrs (const void *p1, const void *p2)
 int
 binding_key::cmp (const binding_key *k1, const binding_key *k2)
 {
-  if (int reg_cmp = region2::cmp_indices (k1->m_region, k2->m_region))
+  if (int reg_cmp = region2::cmp_ids (k1->m_region, k2->m_region))
     return reg_cmp;
 
   enum kind kind1 = k1->get_kind ();
@@ -2837,12 +2885,24 @@ binding_cluster::bind (region_model2_manager *mgr,
   m_map.put (binding, val);
 }
 
+svalue2 *
+binding_cluster::get_binding (region_model2_manager *mgr, region2 *reg) const
+{
+  // FIXME: what if symbolic vs concrete?
+  const binding_key *binding
+    = mgr->get_concrete_binding (reg, binding_key::BK_direct, 0);
+  svalue2 **slot = const_cast<map_t &> (m_map).get (binding);
+  if (slot)
+    return *slot;
+  return NULL;
+}
+
 /* class region_model2_manager.  */
 
 region_model2_manager::region_model2_manager ()
-: m_next_region_idx (0),
-  m_root_region (alloc_region_idx ()),
-  m_globals_region (alloc_region_idx (), &m_root_region),
+: m_next_region_id (0),
+  m_root_region (alloc_region_id ()),
+  m_globals_region (alloc_region_id (), &m_root_region),
   m_globals_map ()
 {
   // TODO
@@ -2878,7 +2938,7 @@ region_model2_manager::get_region_for_global (tree expr,
   if (slot)
     return *slot;
   decl_region2 *reg
-    = new decl_region2 (alloc_region_idx (), &m_globals_region, expr);
+    = new decl_region2 (alloc_region_id (), &m_globals_region, expr);
   m_globals_map.put (expr, reg);
   return reg;
 }
@@ -2887,11 +2947,23 @@ region2 *
 region_model2_manager::get_field_region (region2 *parent, tree field,
 					 region_model2_context *ctxt)
 {
-  // FIXME: should only alloc_region_idx if consolidation fails
-  region2 *field_reg = new field_region2 (alloc_region_idx (), parent, field);
+  // FIXME: should only alloc_region_id if consolidation fails
+  region2 *field_reg = new field_region2 (alloc_region_id (), parent, field);
   return const_cast <region2 *> (m_fields.consolidate (field_reg));
 }
 
+region2 *
+region_model2_manager::get_element_region (region2 *parent,
+					   tree element_type,
+					   svalue2 *index,
+					   region_model2_context *ctxt)
+{
+  // FIXME: should only alloc_region_id if consolidation fails
+  region2 *element_reg
+    = new element_region2 (alloc_region_id (), parent, element_type, index);
+  return const_cast <region2 *> (m_elements.consolidate (element_reg));
+}
+
 const concrete_binding *
 region_model2_manager::get_concrete_binding (region2 *region,
 					     enum binding_key::kind kind,
@@ -4303,7 +4375,6 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 						   dump_location_t ());
 #endif
 
-#if 0
     case ARRAY_REF:
       {
 	tree array = TREE_OPERAND (expr, 0);
@@ -4314,8 +4385,12 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 	gcc_assert (TREE_OPERAND (expr, 3) == NULL_TREE);
 #endif
 
-	region2 *array_reg = get_lvalue (array, ctxt);
-	svalue2 *index_sval = get_rvalue (index, ctxt);
+	region2 *array_reg = get_lvalue (mgr, array, ctxt);
+	svalue2 *index_sval = get_rvalue (mgr, index, ctxt);
+	return mgr->get_element_region (array_reg,
+					TREE_TYPE (TREE_TYPE (array)),
+					index_sval, ctxt);
+#if 0
 	region2 *base_array_reg = get_region2 (array_reg);
 	array_region2 *array_reg  = base_array_reg->dyn_cast_array_region2 ();
 	if (!array_reg)
@@ -4329,9 +4404,11 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 							 dump_location_t ());
 	  }
 	return array_reg->get_element (this, array_reg, index_sval, ctxt);
+#endif
       }
       break;
 
+#if 0
     case BIT_FIELD_REF:
       {
 	/* For now, create a view, as if a cast, ignoring the bit positions.  */
@@ -4530,12 +4607,13 @@ region_model2::get_rvalue_1 (region_model2_manager *mgr, path_var pv,
       }
       break;
 
+#endif
     case ARRAY_REF:
       {
-	region2 *element_reg = get_lvalue (pv, ctxt);
-	return get_region2 (element_reg)->get_value (*this, true, ctxt);
+	region2 *element_reg = get_lvalue (mgr, pv, ctxt);
+	return get_store_value (mgr, element_reg);
       }
-#endif
+
     case INTEGER_CST:
     case REAL_CST:
     case STRING_CST:
@@ -4582,6 +4660,23 @@ region_model2::get_rvalue (region_model2_manager *mgr, tree expr,
   return get_rvalue (mgr, path_var (expr, get_stack_depth () - 1), ctxt);
 }
 
+/* FIXME.  */
+
+svalue2 *
+region_model2::get_store_value (region_model2_manager *mgr, region2 *reg)
+{
+  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
+}
+
 /* Return an svalue2 *for a pointer to RID of type PTR_TYPE, reusing
    existing pointer values if one is available.  */
 #if 0
@@ -6855,6 +6950,8 @@ test_dump_2 ()
   model.set_value (&mgr, c_x, int_17, NULL);
   model.set_value (&mgr, c_y, int_m3, NULL);
 
+  // TODO: test get_value
+
   /* FIXME: fails due to lack of sorting!
      ...but time to implement a[0] = ; a[1] = ; a[i] = ;
      and a more sophisticated region binding/cluster implementation.  */
@@ -8061,6 +8158,63 @@ test_malloc_constraints ()
 }
 #endif
 
+static void
+test_array ()
+{
+  /* "int arr[10];"  */
+  tree tlen = size_int (10);
+  tree arr_type
+    = build_array_type (integer_type_node, build_index_type (tlen));
+  tree arr = build_global_decl ("arr", arr_type);
+
+  /* "int i;"  */
+  tree i = build_global_decl ("i", integer_type_node);
+
+  tree int_0 = build_int_cst (integer_type_node, 0);
+  tree int_1 = build_int_cst (integer_type_node, 1);
+
+  tree arr_0 = build4 (ARRAY_REF, integer_type_node,
+		       arr, int_0, NULL_TREE, NULL_TREE);
+  tree arr_1 = build4 (ARRAY_REF, integer_type_node,
+		       arr, int_1, NULL_TREE, NULL_TREE);
+  tree arr_i = build4 (ARRAY_REF, integer_type_node,
+		       arr, i, NULL_TREE, NULL_TREE);
+
+  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;
+  /* "arr[0] = 17;".  */
+  model.set_value (&mgr, arr_0, int_17, NULL);
+  /* "arr[1] = -3;".  */
+  model.set_value (&mgr, arr_1, int_m3, NULL);
+
+  ASSERT_EQ (model.get_rvalue (&mgr, arr_0, NULL),
+	     model.get_rvalue (&mgr, int_17, NULL));
+  ASSERT_EQ (model.get_rvalue (&mgr, arr_1, NULL),
+	     model.get_rvalue (&mgr, int_m3, NULL));
+
+#if 0
+  /* "arr[i] = i;" - this should remove the earlier bindings.  */
+  model.set_value (&mgr, arr_i, i, NULL);
+  // TODO: get_value for other bindings
+  // TODO: assert that there is now no binding for the other indices
+#endif
+
+  /* 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
+
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -8089,6 +8243,7 @@ analyzer_region_model2_cc_tests ()
   test_constraint_merging ();
   test_malloc_constraints ();
 #endif
+  test_array ();
 }
 
 } // namespace selftest
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 18b9bfde7e5..66db7d71aa7 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -510,7 +510,8 @@ public:
      root_region (RK_ROOT)
      label_region (RK_FUNCTION)
      symbolic_region (RK_SYMBOLIC)
-     field_region (RK_FIELD).  */
+     field_region (RK_FIELD)
+     element_region (RK_ELEMENT).  */
 
 /* Abstract base class representing a chunk of memory.
 
@@ -541,7 +542,8 @@ public:
    RK_ROOT,
    //RK_SYMBOLIC,
    RK_DECL,
-   RK_FIELD
+   RK_FIELD,
+   RK_ELEMENT
   };
   static const char *kind_to_str (enum kind);
 
@@ -554,8 +556,8 @@ public:
   virtual region2 *clone () const = 0;
 #endif
 
-  unsigned get_idx () const { return m_idx; }
-  static int cmp_indices (const region2 *reg1, const region2 *reg2);
+  unsigned get_id () const { return m_id; }
+  static int cmp_ids (const region2 *reg1, const region2 *reg2);
 
   virtual enum kind get_kind () const = 0;
   virtual map_region2 *dyn_cast_map_region2 () { return NULL; }
@@ -616,7 +618,7 @@ public:
   static int cmp_ptrs (const void *, const void *);
 
  protected:
-  region2 (unsigned idx, region2 *parent, tree type);
+  region2 (unsigned id, region2 *parent, tree type);
 
   virtual void add_to_hash (inchash::hash &hstate) const;
 #if 0
@@ -631,7 +633,7 @@ public:
   void deactivate_view (region_model2 &model, region_id this_view_rid);
 #endif
 
-  unsigned m_idx; // purely for deterministic sorting at this stage, for dumps
+  unsigned m_id; // purely for deterministic sorting at this stage, for dumps
   region2 *m_parent;
   tree m_type;
 };
@@ -658,8 +660,8 @@ public:
   typedef ordered_hash_map<tree, region2 *> map_t;
   typedef map_t::iterator iterator_t;
 
-  map_region2 (unsigned idx, region2 *parent, tree type)
-  : region2 (idx, parent, type)
+  map_region2 (unsigned id, region2 *parent, tree type)
+  : region2 (id, parent, type)
   {}
   map_region2 (const map_region2 &other);
 
@@ -740,8 +742,8 @@ class scope_region2 : public map_region2
  public:
 
  protected:
-  scope_region2 (unsigned idx, region2 *parent)
-    : map_region2 (idx, parent, NULL_TREE)
+  scope_region2 (unsigned id, region2 *parent)
+    : map_region2 (id, parent, NULL_TREE)
   {}
 
   bool compare_fields (const scope_region2 &other) const;
@@ -753,8 +755,8 @@ class scope_region2 : public map_region2
 class frame_region2 : public scope_region2
 {
 public:
-  frame_region2 (unsigned idx, region2 *parent, function *fun, int depth)
-  : scope_region2 (idx, parent), m_fun (fun), m_depth (depth)
+  frame_region2 (unsigned id, region2 *parent, function *fun, int depth)
+  : scope_region2 (id, parent), m_fun (fun), m_depth (depth)
   {}
 
   /* region2 vfuncs.  */
@@ -799,8 +801,8 @@ namespace ana {
 class globals_region2 : public scope_region2
 {
  public:
-  globals_region2 (unsigned idx, region2 *parent)
-  : scope_region2 (idx, parent)
+  globals_region2 (unsigned id, region2 *parent)
+  : scope_region2 (id, parent)
   {}
 
   /* region2 vfuncs.  */
@@ -834,8 +836,8 @@ namespace ana {
 class code_region2 : public map_region2
 {
 public:
-  code_region2 (unsigned idx, region2 *parent)
-  : map_region2 (idx, parent, NULL_TREE)
+  code_region2 (unsigned id, region2 *parent)
+  : map_region2 (id, parent, NULL_TREE)
   {}
 
   /* region2 vfuncs.  */
@@ -872,8 +874,8 @@ namespace ana {
 class function_region2 : public map_region2
 {
 public:
-  function_region2 (unsigned idx, region2 *parent, tree type)
-  : map_region2 (idx, parent, type)
+  function_region2 (unsigned id, region2 *parent, tree type)
+  : map_region2 (id, parent, type)
   {
     gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
   }
@@ -1029,7 +1031,7 @@ namespace ana {
 class root_region2 : public region2
 {
 public:
-  root_region2 (unsigned idx);
+  root_region2 (unsigned id);
 
   bool compare_fields (const root_region2 &other) const;
 
@@ -1116,7 +1118,7 @@ namespace ana {
 class symbolic_region2 : public region2
 {
 public:
-  symbolic_region2 (unsigned idx, region2 *parent, tree type, bool possibly_null)
+  symbolic_region2 (unsigned id, region2 *parent, tree type, bool possibly_null)
   : region2 (parent, type),
     m_possibly_null (possibly_null)
   {}
@@ -1150,8 +1152,8 @@ public:
 class decl_region2 : public region2
 {
 public:
-  decl_region2 (unsigned idx, region2 *parent, tree decl)
-  : region2 (idx, parent, TREE_TYPE (decl)), m_decl (decl)
+  decl_region2 (unsigned id, region2 *parent, tree decl)
+  : region2 (id, parent, TREE_TYPE (decl)), m_decl (decl)
   {}
 
 #if 0
@@ -1176,14 +1178,10 @@ private:
 class field_region2 : public region2
 {
 public:
-  field_region2 (unsigned idx, region2 *parent, tree field)
-  : region2 (idx, parent, TREE_TYPE (field)), m_field (field)
+  field_region2 (unsigned id, region2 *parent, tree field)
+  : region2 (id, parent, TREE_TYPE (field)), m_field (field)
   {}
 
-#if 0
-  region2 *clone () const FINAL OVERRIDE;
-#endif
-
   bool compare_fields (const field_region2 &other) const;
 
   enum region2::kind get_kind () const FINAL OVERRIDE { return RK_FIELD; }
@@ -1197,6 +1195,31 @@ private:
   tree m_field;
 };
 
+/* An element within an array.  */
+
+class element_region2 : public region2
+{
+public:
+  element_region2 (unsigned id, region2 *parent, tree element_type,
+		   svalue2 *index)
+  : region2 (id, parent, element_type), m_index (index)
+  {}
+
+  bool compare_fields (const element_region2 &other) const;
+
+  enum region2::kind get_kind () const FINAL OVERRIDE { return RK_ELEMENT; }
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+  svalue2 *get_index () const { return m_index; }
+
+protected:
+  void add_to_hash (inchash::hash &hstate) const OVERRIDE;
+
+private:
+  svalue2 *m_index;
+};
+
 /* A binding within a store.  */
 
 class binding_key
@@ -1334,6 +1357,8 @@ public:
 			       const region2 *, const svalue2 *) const;
 #endif
 
+  svalue2 *get_binding (region_model2_manager *mgr, region2 *reg) const;
+
 private:
   map_t m_map;
 };
@@ -1355,6 +1380,10 @@ public:
 				       region_model2_context *ctxt);
   region2 *get_field_region (region2 *parent, tree field,
 			     region_model2_context *ctxt);
+  region2 *get_element_region (region2 *parent,
+			       tree element_type,
+			       svalue2 *index,
+			       region_model2_context *ctxt);
 
   const concrete_binding *
   get_concrete_binding (region2 *region,
@@ -1366,10 +1395,10 @@ public:
 			enum binding_key::kind kind,
 			region2 *concrete_offset_region);
 
-  unsigned alloc_region_idx () { return m_next_region_idx++; }
+  unsigned alloc_region_id () { return m_next_region_id++; }
 
 private:
-  unsigned m_next_region_idx;
+  unsigned m_next_region_id;
   root_region2 m_root_region;
 
   typedef hash_map<tree, constant_svalue2 *> constants_map_t;
@@ -1386,6 +1415,7 @@ private:
   typedef hash_map<field_key_t, region2 *> fields_map_t;
   fields_map_t m_fields_map;
 #endif
+  uniq_manager<region2> m_elements;
 
   uniq_manager<concrete_binding> m_concrete_binding_key_mgr;
   uniq_manager<symbolic_binding> m_symbolic_binding_key_mgr;
@@ -1599,6 +1629,7 @@ class region_model2
 			 region_model2_context *ctxt);
   svalue2 *get_rvalue_1 (region_model2_manager *mgr, path_var pv,
 			 region_model2_context *ctxt);
+  svalue2 *get_store_value (region_model2_manager *mgr, region2 *reg);
 
 #if 0
   void copy_struct_region2 (region2_id dst_rid, struct_region2 *dst_reg,
-- 
2.21.0

