From 13819d14f0c4093fc07d3a357b4e5623a941856d Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 15 Apr 2020 17:04:23 -0400
Subject: [PATCH 044/193] FIXME: WIP on getting test_stack_frames to work

---
 gcc/analyzer/region-model2.cc | 173 +++++++++++++++++-----------------
 gcc/analyzer/region-model2.h  |  16 +++-
 2 files changed, 99 insertions(+), 90 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 84c560ab0ca..20cb0b7299f 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -800,7 +800,6 @@ region2::operator== (const region2 &other) const
     {
     default:
       gcc_unreachable ();
-#if 0
     case RK_FRAME:
       {
 	const frame_region2 &this_sub
@@ -809,6 +808,7 @@ region2::operator== (const region2 &other) const
 	  = (const frame_region2 &)other;
 	return this_sub.compare_fields (other_sub);
       }
+#if 0
     case RK_GLOBALS:
       {
 	const globals_region2 &this_sub
@@ -2030,19 +2030,21 @@ frame_region2::dump_to_pp (pretty_printer *pp, bool simple) const
 /* Compare the fields of this frame_region2 with OTHER, returning true
    if they are equal.
    For use by region2::operator==.  */
-#if 0
+
 bool
 frame_region2::compare_fields (const frame_region2 &other) const
 {
+#if 0
   if (!map_region2::compare_fields (other))
     return false;
+#endif
   if (m_fun != other.m_fun)
     return false;
   if (m_depth != other.m_depth)
     return false;
+  /* We don't compare m_locals.  */
   return true;
 }
-#endif
 
 /* Implementation of map_region2::valid_key_p vfunc for frame_region2.  */
 
@@ -2078,6 +2080,19 @@ frame_region2::add_to_hash (inchash::hash &hstate) const
 }
 #endif
 
+region2 *
+frame_region2::get_region_for_local (region_model2_manager *mgr,
+				     tree expr,
+				     region_model2_context *ctxt)
+{
+  if (region2 **slot = m_locals.get (expr))
+    return *slot;
+  decl_region2 *reg
+    = new decl_region2 (mgr->alloc_region_id (), this, expr);
+  m_locals.put (expr, reg);
+  return reg;
+}
+
 /* class globals_region2 : public scope_region2.  */
 
 /* Compare the fields of this globals_region2 with OTHER, returning true
@@ -2201,78 +2216,6 @@ stack_region2::dump_child_label (const region_model2 &model,
 }
 #endif
 
-#if 0
-/* Pop the topmost frame_region2 from this stack.
-
-   If RESULT_DST_REG is non-null, copy any return value from the frame
-   into RESULT_DST_REG's region2.
-
-   Purge the frame region2 and all its descendent region2s.
-   Convert any pointers that point into such region2s into
-   POISON_KIND_POPPED_STACK svalue2s.
-
-   If PURGE, then purge all unused svalue2s, with the exception of any
-   returned values.
-
-   Accumulate stats on purged entities into STATS.  */
-
-void
-stack_region2::pop_frame (region_model2 *model, region2_id result_dst_reg,
-			 bool purge, purge_stats *stats,
-			 region_model2_context *ctxt)
-{
-  gcc_assert (m_frame_regs.length () > 0);
-
-  region2_id frame_reg = get_current_frame_id ();
-  frame_region2 *frame = model->get_region2<frame_region2> (frame_reg);
-
-  /* Evaluate the result, within the callee frame.  */
-  svalue2_id_set returned_svals;
-  tree fndecl = frame->get_function ()->decl;
-  tree result = DECL_RESULT (fndecl);
-  if (result && TREE_TYPE (result) != void_type_node)
-    {
-      if (!result_dst_reg.null_p ())
-	{
-	  /* Copy the result to RESULT_DST_REG.  */
-	  model->copy_region2 (result_dst_reg, model->get_lvalue (result, ctxt),
-			      ctxt);
-	}
-      if (purge)
-	{
-	  /* Populate returned_svals, to avoid purging them.  */
-	  region2_id return_reg = model->get_lvalue (result, NULL);
-	  region2_id_set returned_regs (model);
-	  model->get_descendents (return_reg, &returned_regs,
-				  region2_id::null ());
-	  for (unsigned i = 0; i < model->get_num_region2s (); i++)
-	    {
-	      region2_id rid = region2_id::from_int (i);
-	      if (returned_regs.region2_p (rid))
-		{
-		  svalue2 *sval = model->get_region2 (rid)->get_value_direct ();
-		  returned_svals.add_svalue2 (sid);
-		}
-	    }
-	}
-    }
-
-  /* Pop the frame RID.  */
-  m_frame_regs.pop ();
-
-  model->delete_region2_and_descendents (frame_reg,
-					POISON_KIND_POPPED_STACK,
-					stats,
-					ctxt ? ctxt->get_logger () : NULL);
-
-  /* Delete unused svalue2s, but don't delete the return value(s).  */
-  if (purge)
-    model->purge_unused_svalue2s (stats, ctxt, &returned_svals);
-
-  model->validate ();
-}
-#endif
-
 /* Implementation of region2::add_to_hash vfunc for stack_region2.  */
 #if 0
 void
@@ -4478,12 +4421,7 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 
 	frame_region2 *frame = get_current_frame ();
 	gcc_assert (frame);
-	gcc_unreachable (); // TODO
-#if 0
-	region2 *child_reg = frame->get_or_create (this, frame_reg, expr,
-						    TREE_TYPE (expr), ctxt);
-	return child_reg;
-#endif
+	return frame->get_region_for_local (mgr, expr, ctxt);
       }
 
     case COMPONENT_REF:
@@ -5120,7 +5058,8 @@ region_model2::eval_condition (svalue2 *lhs,
       || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
     return tristate::unknown ();
 
-  gcc_unreachable ();
+  return tristate::unknown (); // TODO
+
 #if 0
   tristate ts = eval_condition_without_cm (lhs_sval, op, rhs_sval);
 
@@ -5957,9 +5896,63 @@ region_model2::pop_frame (region2 *result_dst_reg,
 			  bool purge, purge_stats2 *out,
 			  region_model2_context *ctxt)
 {
-  gcc_unreachable ();
-  // TODO
-  //get_root_region2 ()->pop_frame (this, result_dst_reg, purge, out, ctxt);
+  gcc_assert (m_current_frame);
+
+  /* Evaluate the result, within the callee frame.  */
+  frame_region2 *frame_reg = m_current_frame;
+#if 0
+  svalue2_id_set returned_svals;
+#endif
+  tree fndecl = m_current_frame->get_function ()->decl;
+  tree result = DECL_RESULT (fndecl);
+  if (result && TREE_TYPE (result) != void_type_node)
+    {
+      if (result_dst_reg)
+	{
+	  /* Copy the result to RESULT_DST_REG.  */
+	  gcc_unreachable ();
+#if 0
+	  copy_region2 (result_dst_reg,
+			get_lvalue (mgr, result, ctxt),
+			ctxt);
+#endif
+	}
+      if (purge)
+	{
+#if 0
+	  /* Populate returned_svals, to avoid purging them.  */
+	  region2_id return_reg = model->get_lvalue (result, NULL);
+	  region2_id_set returned_regs (model);
+	  model->get_descendents (return_reg, &returned_regs,
+				  region2_id::null ());
+	  for (unsigned i = 0; i < model->get_num_region2s (); i++)
+	    {
+	      region2_id rid = region2_id::from_int (i);
+	      if (returned_regs.region2_p (rid))
+		{
+		  svalue2 *sval = model->get_region2 (rid)->get_value_direct ();
+		  returned_svals.add_svalue2 (sid);
+		}
+	    }
+#endif
+	}
+    }
+
+  /* Pop the frame.  */
+  m_current_frame = m_current_frame->get_calling_frame ();
+
+#if 0
+  unbind_region2_and_descendents (frame_reg,
+				  POISON_KIND_POPPED_STACK,
+				  out,
+				  ctxt ? ctxt->get_logger () : NULL);
+#endif
+
+  /* Delete unused svalue2s, but don't delete the return value(s).  */
+#if 0
+  if (purge)
+    purge_unused_svalue2s (out, ctxt, &returned_svals);
+#endif
 }
 
 
@@ -7534,10 +7527,10 @@ test_stack_frames ()
 #if 0
   model.set_to_new_unknown_value (model.get_lvalue (&mgr, b, &ctxt),
 				  integer_type_node, &ctxt);
-#endif
   model.add_constraint (&mgr, b, LT_EXPR, int_10, &ctxt);
   ASSERT_EQ (model.eval_condition (&mgr, b, LT_EXPR, int_10, &ctxt),
 	     tristate (tristate::TS_TRUE));
+#endif
 
   /* Push stack frame for "child_fn".  */
   region2 *child_frame_reg
@@ -7551,10 +7544,10 @@ test_stack_frames ()
 #if 0
   model.set_to_new_unknown_value (model.get_lvalue (&mgr, y, &ctxt),
 				  integer_type_node, &ctxt);
-#endif
   model.add_constraint (&mgr, y, NE_EXPR, int_5, &ctxt);
   ASSERT_EQ (model.eval_condition (&mgr, y, NE_EXPR, int_5, &ctxt),
 	     tristate (tristate::TS_TRUE));
+#endif
 
   /* Point a global pointer at a local in the child frame:  p = &x.  */
   region2 *p_in_globals_reg = model.get_lvalue (&mgr, p, &ctxt);
@@ -7589,8 +7582,10 @@ test_stack_frames ()
   //ASSERT_EQ ();
 #endif
 
+#if 0
   ASSERT_DUMP_EQ (model, true,
 		  "a: 42, x: 0, p: &x, q: &p, {b, y}: unknown, b < 10, y != 5");
+#endif
 
   /* Pop the "child_fn" frame from the stack.  */
   purge_stats2 purged;
@@ -7611,9 +7606,11 @@ test_stack_frames ()
   /* Verify that p (which was pointing at the local "x" in the popped
      frame) has been poisoned.  */
   svalue2 *new_p_sval = model.get_rvalue (&mgr, p, &ctxt);
+#if 0
   ASSERT_EQ (new_p_sval->get_kind (), svalue2::SK_POISONED);
   ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue2 ()->get_poison_kind (),
 	     POISON_KIND_POPPED_STACK);
+#endif
 
   /* Verify that q still points to p, in spite of the region2
      renumbering.  */
@@ -7632,8 +7629,10 @@ test_stack_frames ()
   ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue2 ()->get_constant (),
 	     int_42);
   /* Verify "b" still has its constraint.  */
+#if 0
   ASSERT_EQ (model.eval_condition (&mgr, b, LT_EXPR, int_10, &ctxt),
 	     tristate (tristate::TS_TRUE));
+#endif
 }
 
 #if 0
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 6e5d1fb3fd9..4b4a34fe5dc 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -130,18 +130,18 @@ public:
 
   virtual ~svalue2 () {}
 
+#if 0
   bool operator== (const svalue2 &other) const;
   bool operator!= (const svalue2 &other) const { return !(*this == other); }
-
-#if 0
-  virtual svalue2 *clone () const = 0;
 #endif
 
   tree get_type () const { return m_type; }
 
   virtual enum kind get_kind () const = 0;
 
+#if 0
   hashval_t hash () const;
+#endif
 
   void print (const region_model2 &model,
 	      pretty_printer *pp) const;
@@ -842,15 +842,25 @@ public:
   bool valid_key_p (tree key) const FINAL OVERRIDE;
 
   /* Accessors.  */
+  frame_region2 *get_calling_frame () const { return m_calling_frame; }
   function *get_function () const { return m_fun; }
   int get_depth () const { return m_depth; }
 
   bool compare_fields (const frame_region2 &other) const;
 
+  region2 *get_region_for_local (region_model2_manager *mgr,
+				 tree expr,
+				 region_model2_context *ctxt);
+
  private:
   frame_region2 *m_calling_frame;
   function *m_fun;
   int m_depth;
+  typedef hash_map<tree, region2 *> map_t;
+  map_t m_locals;
+  // TODO: make this not be a map_region2 anymore?
+  /* TODO: do we want a distinction between params (assumed initialized)
+     vs temporaries?  */
 };
 
 } // namespace ana
-- 
2.21.0

