From 752518cccec50d463f9298eeb80b519822ffd7ab Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 14 Apr 2020 17:56:27 -0400
Subject: [PATCH 035/179] FIXME: start introducing region_offset

---
 gcc/analyzer/region-model2.cc | 159 +++++++++++++++++++++++++++++++++-
 gcc/analyzer/region-model2.h  |  41 ++++++++-
 2 files changed, 192 insertions(+), 8 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index b4de5a23bdd..edd3ee418a0 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -694,6 +694,13 @@ region2::kind_to_str (enum kind kind)
     }
 }
 
+/* class region2.  */
+
+region2::~region2 ()
+{
+  delete m_cached_offset;
+}
+
 /* FIXME.  */
 
 int
@@ -702,8 +709,6 @@ region2::cmp_ids (const region2 *reg1, const region2 *reg2)
   return (long)reg1->get_id () - (long)reg2->get_id ();
 }
 
-/* class region2.  */
-
 /* Equality operator for region2.
    After comparing base class fields and kind, the rest of the
    comparison is handled off to a "compare_fields" member function
@@ -838,7 +843,6 @@ region2::get_base_region () const
     {
       switch (iter->get_kind ())
 	{
-	  //case RK_element_region:
 	case RK_FIELD:
 	case RK_ELEMENT:
 	  iter = iter->get_parent_region ();
@@ -850,6 +854,85 @@ region2::get_base_region () const
   return iter;
 }
 
+region_offset
+region2::get_offset ()
+{
+  if(!m_cached_offset)
+    m_cached_offset = new region_offset (calc_offset ());
+  return *m_cached_offset;
+}
+
+/* FIXME.  */
+
+region_offset
+region2::calc_offset () const
+{
+  const region2 *iter_region = this;
+  region_offset::byte_offset_t byte_offset = 0;
+
+  while (iter_region)
+    {
+      switch (iter_region->get_kind ())
+	{
+	case RK_FIELD:
+	  {
+	    const field_region2 *field_region
+	      = (const field_region2 *)iter_region;
+	    iter_region = iter_region->get_parent_region ();
+	    gcc_unreachable ();
+	    //offset += ;
+	  }
+	  continue;
+
+	case RK_ELEMENT:
+	  {
+	    const element_region2 *element_region
+	      = (const element_region2 *)iter_region;
+	    iter_region = iter_region->get_parent_region ();
+
+	    if (tree idx_cst
+		  = element_region->get_index ()->maybe_get_constant ())
+	      {
+		gcc_assert (TREE_CODE (idx_cst) == INTEGER_CST);
+
+		tree elem_type = element_region->get_type ();
+
+		// FIXME:
+#if 0
+		/* Arithmetic on void-pointers is a GNU C extension, treating
+		   the size of a void as 1.
+		   https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html  */
+		if (TREE_CODE (elem_type) == VOID_TYPE)
+		  return offset_sid;
+#endif
+
+		HOST_WIDE_INT hwi_idx_cst = tree_to_shwi (idx_cst);
+
+		/* First, use int_size_in_bytes, to reject the case where we
+		   have an incomplete type, or a non-constant value.  */
+		HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (elem_type);
+		if (hwi_byte_size > 0)
+		  {
+		    HOST_WIDE_INT hwi_element_byte_offset
+		      = hwi_idx_cst * hwi_byte_size;
+		    byte_offset += hwi_element_byte_offset;
+		  }
+		else
+		  gcc_unreachable ();
+	      }
+	    else
+	      {
+		gcc_unreachable ();
+	      }
+	    //offset += ;
+	  }
+	  continue;
+
+	default:
+	  return region_offset (iter_region, byte_offset);
+	}
+    }
+}
 
 /* Set this region2's value to RHS_SVAL (or potentially a variant of it,
    for some kinds of casts).  */
@@ -1337,7 +1420,7 @@ region2::get_view (tree type, region_model2 *model) const
 /* region2's ctor.  */
 
 region2::region2 (unsigned id, region2 *parent, tree type)
-: m_id (id), m_parent (parent), m_type (type)
+: m_id (id), m_parent (parent), m_type (type), m_cached_offset (NULL)
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
@@ -2897,6 +2980,35 @@ binding_cluster::get_binding (region_model2_manager *mgr, region2 *reg) const
   return NULL;
 }
 
+/* Populate OUT with all bindings within this cluster that overlap REG.  */
+
+void
+binding_cluster::get_overlapping_bindings (region2 *reg,
+					   auto_vec<const binding_key *> *out)
+{
+  /* Get the size of REG.  */
+  // TODO
+
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end (); ++iter)
+    {
+      const binding_key *key = (*iter).first;
+      // TODO
+    }
+}
+
+/* FIXME.  */
+
+void
+binding_cluster::remove_overlapping_bindings (region_model2_manager *mgr,
+					      region2 *reg)
+{
+  auto_vec<const binding_key *> bindings;
+  get_overlapping_bindings (reg, &bindings);
+  // TODO
+  //gcc_unreachable ();
+}
+
 /* class region_model2_manager.  */
 
 region_model2_manager::region_model2_manager ()
@@ -5011,6 +5123,8 @@ region_model2::set_value (region_model2_manager *mgr,
   gcc_assert (rhs_sval);
 
 #if 1
+  remove_overlapping_bindings (mgr, lhs_reg);
+
   const region2 *base_reg = lhs_reg->get_base_region ();
   binding_cluster *cluster = NULL;
   binding_cluster **slot = m_cluster_map.get (base_reg);
@@ -5028,6 +5142,23 @@ region_model2::set_value (region_model2_manager *mgr,
 #endif
 }
 
+/* FIXME.  */
+
+void
+region_model2::remove_overlapping_bindings (region_model2_manager *mgr,
+					    region2 *reg)
+{
+  const region2 *base_reg = reg->get_base_region ();
+  if (reg == base_reg)
+    {
+      /* Remove whole cluster (if any).  */
+      m_cluster_map.remove (base_reg);
+      return;
+    }
+  if (binding_cluster **cluster_slot = m_cluster_map.get (base_reg))
+    (*cluster_slot)->remove_overlapping_bindings (mgr, reg);
+}
+
 /* Set the value of the region2 given by LHS to the value given
    by RHS.  */
 
@@ -8195,6 +8326,26 @@ test_array ()
   ASSERT_EQ (model.get_rvalue (&mgr, arr_1, NULL),
 	     model.get_rvalue (&mgr, int_m3, NULL));
 
+  /* Verify get_offset for "arr[0]".  */
+  {
+    region2 *arr_0_reg = model.get_lvalue (&mgr, arr_0, NULL);
+    region_offset offset = arr_0_reg->get_offset ();
+    ASSERT_EQ (offset.get_base_region (), model.get_lvalue (&mgr, arr, NULL));
+    ASSERT_EQ (offset.get_byte_offset (), 0);
+  }
+
+  /* Verify get_offset for "arr[1]".  */
+  {
+    region2 *arr_1_reg = model.get_lvalue (&mgr, arr_1, NULL);
+    region_offset offset = arr_1_reg->get_offset ();
+    ASSERT_EQ (offset.get_base_region (), model.get_lvalue (&mgr, arr, NULL));
+    ASSERT_EQ (offset.get_byte_offset (), 4);
+    // FIXME: this assumes sizeof(int) == 4 on the target
+  }
+
+  // etc
+
+
 #if 0
   /* "arr[i] = i;" - this should remove the earlier bindings.  */
   model.set_value (&mgr, arr_i, i, NULL);
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 66db7d71aa7..b55b6e4183c 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -489,6 +489,27 @@ public:
   setjmp_record m_setjmp_record;
 };
 
+/* The location of a region expressesd as an offset relative to a
+   base region.  */
+
+class region_offset
+{
+public:
+  typedef int byte_offset_t;  // FIXME
+
+  region_offset (const region2 *base_region, byte_offset_t offset)
+  : m_base_region (base_region), m_offset (offset)
+  {}
+
+  const region2 *get_base_region () const { return m_base_region; }
+  byte_offset_t get_byte_offset () const { return m_offset; }
+
+private:
+  const region2 *m_base_region;
+  byte_offset_t m_offset;
+  // FIXME: also need a "symbolic" value
+};
+
 /* Region and its subclasses.
 
    The class hierarchy looks like this (using indentation to show
@@ -510,8 +531,8 @@ public:
      root_region (RK_ROOT)
      label_region (RK_FUNCTION)
      symbolic_region (RK_SYMBOLIC)
-     field_region (RK_FIELD)
-     element_region (RK_ELEMENT).  */
+     field_region2 (RK_FIELD)
+     element_region2 (RK_ELEMENT).  */
 
 /* Abstract base class representing a chunk of memory.
 
@@ -547,7 +568,7 @@ public:
   };
   static const char *kind_to_str (enum kind);
 
-  virtual ~region2 () {}
+  virtual ~region2 ();
 
   bool operator== (const region2 &other) const;
   bool operator!= (const region2 &other) const { return !(*this == other); }
@@ -617,6 +638,8 @@ public:
 
   static int cmp_ptrs (const void *, const void *);
 
+  region_offset get_offset ();
+
  protected:
   region2 (unsigned id, region2 *parent, tree type);
 
@@ -632,10 +655,13 @@ public:
   void deactivate_any_active_view (region_model2 &model);
   void deactivate_view (region_model2 &model, region_id this_view_rid);
 #endif
+  region_offset calc_offset () const;
 
   unsigned m_id; // purely for deterministic sorting at this stage, for dumps
   region2 *m_parent;
   tree m_type;
+
+  region_offset *m_cached_offset;
 };
 
 } // namespace ana
@@ -1359,7 +1385,12 @@ public:
 
   svalue2 *get_binding (region_model2_manager *mgr, region2 *reg) const;
 
+  void remove_overlapping_bindings (region_model2_manager *mgr, region2 *reg);
+
 private:
+  void get_overlapping_bindings (region2 *reg,
+				 auto_vec<const binding_key *> *out);
+
   map_t m_map;
 };
 
@@ -1631,6 +1662,8 @@ class region_model2
 			 region_model2_context *ctxt);
   svalue2 *get_store_value (region_model2_manager *mgr, region2 *reg);
 
+  void remove_overlapping_bindings (region_model2_manager *mgr, region2 *reg);
+
 #if 0
   void copy_struct_region2 (region2_id dst_rid, struct_region2 *dst_reg,
 			   struct_region2 *src_reg, region_model2_context *ctxt);
@@ -1654,7 +1687,7 @@ class region_model2
 				       tree rhs,
 				       const gcall *call,
 				       region_model2_context *ctxt);
-#endif					 
+#endif
   void update_for_call_superedge (region_model2_manager *mgr,
 				  const call_superedge &call_edge,
 				  region_model2_context *ctxt);
-- 
2.21.0

