From 204cd6ba28cbd1232664c0e14554e7f7ceb19f52 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 15 Apr 2020 15:38:03 -0400
Subject: [PATCH 43/44] FIXME: WIP towards locals

---
 gcc/analyzer/program-state.cc |   5 +-
 gcc/analyzer/region-model2.cc | 329 ++++++++++++++--------------------
 gcc/analyzer/region-model2.h  |  64 ++++---
 3 files changed, 173 insertions(+), 225 deletions(-)

diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index a9b29efe2f2..fa3f47fdb0d 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -854,7 +854,10 @@ program_state::push_frame (const extrinsic_state &ext_state,
     }
   else if (m_region_model2)
     {
-      // TODO
+      engine2 *eng2 = ext_state.get_engine2 ();
+      region_model2_manager *mgr = eng2->get_model_manager ();
+      region_model2_context *ctxt = NULL; // FIXME
+      m_region_model2->push_frame (mgr, fun, NULL, ctxt);
     }
   else if (m_region_model)
     {
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 22cfe5e103d..84c560ab0ca 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -1228,7 +1228,7 @@ region2::get_inherited_child_sval (region2 *child,
 
 void
 region_model2::copy_region (region2 *dst_reg, region2 *src_reg,
-			    region_model2_context *ctxt)
+			    region_model2_context */*ctxt*/)
 {
   gcc_assert (dst_reg);
   gcc_assert (src_reg);
@@ -1574,15 +1574,6 @@ region2::non_null_p (const region_model2 &model) const
 #endif
 
 /* class map_region2 : public region2.  */
-#if 0
-/* map_region2's copy ctor.  */
-
-map_region2::map_region2 (const map_region2 &other)
-: region2 (other),
-  m_map (other.m_map)
-{
-}
-#endif
 
 /* Compare the fields of this map_region2 with OTHER, returning true
    if they are equal.
@@ -2026,6 +2017,16 @@ map_region2::get_value_by_name (tree identifier,
 
 /* class frame_region2 : public map_region2.  */
 
+void
+frame_region2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    pp_printf (pp, "frame: %qs@%i", function_name (m_fun), m_depth);
+  else
+    pp_printf (pp, "frame_region2(%qs, depth: %i)",
+	       function_name (m_fun), m_depth);
+}
+
 /* Compare the fields of this frame_region2 with OTHER, returning true
    if they are equal.
    For use by region2::operator==.  */
@@ -2151,18 +2152,11 @@ function_region2::valid_key_p (tree key) const
 
 /* class stack_region2 : public region2.  */
 
-/* stack_region2's copy ctor.  */
-#if 0
-stack_region2::stack_region2 (const stack_region2 &other)
-: region2 (other),
-  m_frame_regs (other.m_frame_regs.length ())
+void
+stack_region2::dump_to_pp (pretty_printer */*pp*/, bool /*simple*/) const
 {
-  int i;
-  region2_id *frame_reg;
-  FOR_EACH_VEC_ELT (other.m_frame_regs, i, frame_reg)
-    m_frame_regs.quick_push (*frame_reg);
+  gcc_unreachable ();
 }
-#endif
 
 /* Compare the fields of this stack_region2 with OTHER, returning true
    if they are equal.
@@ -2207,37 +2201,7 @@ stack_region2::dump_child_label (const region_model2 &model,
 }
 #endif
 
-/* Implementation of region2::validate vfunc for stack_region2.  */
 #if 0
-void
-stack_region2::validate (const region_model2 &model) const
-{
-  region2::validate (model);
-  int i;
-  region2_id *frame_reg;
-  FOR_EACH_VEC_ELT (m_frame_regs, i, frame_reg)
-    m_frame_regs[i].validate (model);
-}
-
-/* Push FRAME_REG (for a frame_region2) onto this stack.  */
-
-void
-stack_region2::push_frame (region2_id frame_reg)
-{
-  m_frame_regs.safe_push (frame_reg);
-}
-
-/* Get the region2_id of the top-most frame in this stack, if any.  */
-
-region2_id
-stack_region2::get_current_frame_id () const
-{
-  if (m_frame_regs.length () > 0)
-    return m_frame_regs[m_frame_regs.length () - 1];
-  else
-    return region2_id::null ();
-}
-
 /* Pop the topmost frame_region2 from this stack.
 
    If RESULT_DST_REG is non-null, copy any return value from the frame
@@ -2600,31 +2564,6 @@ root_region2::push_frame (region_model2 *model, function *fun,
   return frame_reg;
 }
 
-/* Get the region2_id of the top-most frame in this root_region2's stack,
-   if any.  */
-
-region2_id
-root_region2::get_current_frame_id (const region_model2 &model) const
-{
-  stack_region2 *stack = model.get_region2 <stack_region2> (m_stack_reg);
-  if (stack)
-    return stack->get_current_frame_id ();
-  else
-    return region2_id::null ();
-}
-
-/* Pop the topmost frame_region2 from this root_region2's stack;
-   see the comment for stack_region2::pop_frame.  */
-
-void
-root_region2::pop_frame (region_model2 *model, region2_id result_dst_reg,
-			bool purge, purge_stats *out,
-			region_model2_context *ctxt)
-{
-  stack_region2 *stack = model->get_region2 <stack_region2> (m_stack_reg);
-  stack->pop_frame (model, result_dst_reg, purge, out, ctxt);
-}
-
 /* Return the region2_id of the stack region2, creating it if doesn't
    already exist.  */
 
@@ -2643,54 +2582,6 @@ root_region2::ensure_stack_region2 (region_model2 *model)
   return m_stack_reg;
 }
 
-/* Return the stack region2 (which could be NULL).  */
-
-stack_region2 *
-root_region2::get_stack_region2 (const region_model2 *model) const
-{
-  return model->get_region2 <stack_region2> (m_stack_reg);
-}
-
-/* Return the region2_id of the globals region2, creating it if doesn't
-   already exist.  */
-
-region2_id
-root_region2::ensure_globals_region2 (region_model2 *model)
-{
-  if (m_globals_reg.null_p ())
-    m_globals_reg
-      = model->add_region2 (new globals_region2 (model->get_root_reg ()));
-  return m_globals_reg;
-}
-
-/* Return the code region2 (which could be NULL).  */
-
-code_region2 *
-root_region2::get_code_region2 (const region_model2 *model) const
-{
-  return model->get_region2 <code_region2> (m_code_reg);
-}
-
-/* Return the region2_id of the code region2, creating it if doesn't
-   already exist.  */
-
-region2_id
-root_region2::ensure_code_region2 (region_model2 *model)
-{
-  if (m_code_reg.null_p ())
-    m_code_reg
-      = model->add_region2 (new code_region2 (model->get_root_reg ()));
-  return m_code_reg;
-}
-
-/* Return the globals region2 (which could be NULL).  */
-
-globals_region2 *
-root_region2::get_globals_region2 (const region_model2 *model) const
-{
-  return model->get_region2 <globals_region2> (m_globals_reg);
-}
-
 /* Return the region2_id of the heap region2, creating it if doesn't
    already exist.  */
 
@@ -2709,14 +2600,6 @@ root_region2::ensure_heap_region2 (region_model2 *model)
   return m_heap_reg;
 }
 
-/* Return the heap region2 (which could be NULL).  */
-
-heap_region2 *
-root_region2::get_heap_region2 (const region_model2 *model) const
-{
-  return model->get_region2 <heap_region2> (m_heap_reg);
-}
-
 /* Attempt to merge ROOT_REGION2_A and ROOT_REGION2_B into
    MERGED_ROOT_REGION2 using MERGER.
    Return true if the merger is possible, false otherwise.  */
@@ -3064,8 +2947,8 @@ binding_cluster2::get_binding (region_model2_manager *mgr, region2 *reg,
 /* Populate OUT with all bindings within this cluster that overlap REG.  */
 
 void
-binding_cluster2::get_overlapping_bindings (region2 *reg,
-					   auto_vec<const binding_key2 *> *out)
+binding_cluster2::get_overlapping_bindings (region2 */*reg*/,
+					    auto_vec<const binding_key2 *> */*out*/)
 {
   /* Get the size of REG.  */
   // TODO
@@ -3073,7 +2956,7 @@ binding_cluster2::get_overlapping_bindings (region2 *reg,
   for (map_t::iterator iter = m_map.begin ();
        iter != m_map.end (); ++iter)
     {
-      const binding_key2 *key = (*iter).first;
+      //const binding_key2 *key = (*iter).first;
       // TODO
     }
 }
@@ -3081,7 +2964,7 @@ binding_cluster2::get_overlapping_bindings (region2 *reg,
 /* FIXME.  */
 
 void
-binding_cluster2::remove_overlapping_bindings (region_model2_manager *mgr,
+binding_cluster2::remove_overlapping_bindings (region_model2_manager */*mgr*/,
 					      region2 *reg)
 {
   auto_vec<const binding_key2 *> bindings;
@@ -3095,6 +2978,7 @@ binding_cluster2::remove_overlapping_bindings (region_model2_manager *mgr,
 region_model2_manager::region_model2_manager ()
 : m_next_region_id (0),
   m_root_region (alloc_region_id ()),
+  m_stack_region (alloc_region_id (), &m_root_region),
   m_globals_region (alloc_region_id (), &m_root_region),
   m_globals_map ()
 {
@@ -3157,6 +3041,18 @@ region_model2_manager::get_element_region (region2 *parent,
   return const_cast <region2 *> (m_elements.consolidate (element_reg));
 }
 
+frame_region2 *
+region_model2_manager::get_frame_region (frame_region2 *calling_frame,
+					 function *fun)
+{
+  int depth = calling_frame ? calling_frame->get_depth () + 1 : 0;
+  // FIXME: should only alloc_region_id if consolidation fails
+  frame_region2 *frame_reg
+    = new frame_region2 (alloc_region_id (), &m_stack_region, calling_frame,
+			 fun, depth);
+  return const_cast <frame_region2 *> (m_frames.consolidate (frame_reg));
+}
+
 const concrete_binding2 *
 region_model2_manager::get_concrete_binding (const region2 *reg,
 					     enum binding_key2::kind kind,
@@ -3186,6 +3082,17 @@ region_model2_manager::get_or_create_initial_value (const region2 *reg)
   return initial_sval;
 }
 
+svalue2 *
+region_model2_manager::get_ptr_svalue2 (tree ptr_type, region2 *pointee)
+{
+  // FIXME: use ptr_type here:
+  if (region_svalue2 **slot = m_pointer_values_map.get (pointee))
+    return *slot;
+  region_svalue2 *sval = new region_svalue2 (ptr_type, pointee);
+  m_pointer_values_map.put (pointee, sval);
+  return sval;
+}
+
 /* class region_model2.  */
 
 /* region_model2's default ctor.  */
@@ -3201,9 +3108,9 @@ region_model2::region_model2 ()
 /* region_model2's copy ctor.  */
 
 region_model2::region_model2 (const region_model2 &other)
-: m_current_frame (NULL)
+: m_current_frame (other.m_current_frame)
 {
-  // TODO
+  // TODO: deep copy of m_cluster_map
 }
 
 /* region_model2's dtor.  */
@@ -3766,7 +3673,7 @@ region_model2::on_stmt (region_model2_manager *mgr,
 
 bool
 region_model2::on_gassign (region_model2_manager *mgr,
-			   const supernode *snode,
+			   const supernode */*snode*/,
 			   const gassign *assign)
 {
   region_model2_context *ctxt = NULL; // FIXME
@@ -4333,7 +4240,7 @@ region_model2::handle_unrecognized_call (const gcall *call,
 
 bool
 region_model2::on_greturn (region_model2_manager *mgr,
-			   const supernode *snode,
+			   const supernode */*snode*/,
 			   const greturn *return_stmt)
 {
   region_model2_context *ctxt = NULL; // FIXME
@@ -4584,7 +4491,7 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 	/* obj.field  */
 	tree obj = TREE_OPERAND (expr, 0);
 	tree field = TREE_OPERAND (expr, 1);
-	tree obj_type = TREE_TYPE (obj);
+	//tree obj_type = TREE_TYPE (obj);
 	// FIXME:
 #if 0
 	if (TREE_CODE (obj_type) != RECORD_TYPE
@@ -4593,13 +4500,7 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv,
 						       dump_location_t ());
 #endif
 	region2 *obj_reg = get_lvalue (mgr, obj, ctxt);
-#if 0
-	region2 *struct_or_union_reg = as_a <struct_or_union_reg> (obj_reg);
-#endif
 	return mgr->get_field_region (obj_reg, field, ctxt);
-#if 0
-	return get_field_region2 (struct_or_union_reg, field, ctxt);
-#endif
       }
       break;
 #if 0
@@ -4911,7 +4812,7 @@ region_model2_manager::get_region2_for_label (tree label,
      - c/c-convert.c: convert
      - convert.h
    Only some kinds of cast are currently supported here.  */
-
+#if 0
 static tree
 build_cast (tree dst_type, tree src_expr)
 {
@@ -4952,6 +4853,7 @@ build_cast (tree dst_type, tree src_expr)
       return result;
     }
 }
+#endif
 
 /* If the type of SID's underlying value is DST_TYPE, return SID.
    Otherwise, attempt to create (or reuse) an svalue2 representing an access
@@ -5148,7 +5050,7 @@ region_model2::deref_rvalue (tree ptr, region_model2_context *ctxt)
 void
 region_model2::set_value (region_model2_manager *mgr,
 			  region2 *lhs_reg, svalue2 *rhs_sval,
-			  region_model2_context *ctxt)
+			  region_model2_context */*ctxt*/)
 {
   gcc_assert (lhs_reg);
   gcc_assert (rhs_sval);
@@ -5209,7 +5111,7 @@ region_model2::set_value (region_model2_manager *mgr,
 
 tristate
 region_model2::eval_condition (svalue2 *lhs,
-			       enum tree_code op,
+			       enum tree_code /*op*/,
 			       svalue2 *rhs) const
 {
   /* For now, make no attempt to capture constraints on floating-point
@@ -5821,7 +5723,7 @@ region_model2::maybe_update_for_edge (region_model2_manager *mgr,
    Populate the frame_region2 with child region2s for the function call's
    parameters, using values from the arguments at the callsite in the
    caller's frame.  */
-#if 1
+
 void
 region_model2::update_for_call_superedge (region_model2_manager *mgr,
 					  const call_superedge &call_edge,
@@ -5838,15 +5740,15 @@ region_model2::update_for_call_superedge (region_model2_manager *mgr,
       arg_svals.quick_push (get_rvalue (mgr, arg, ctxt));
     }
 
-  push_frame (call_edge.get_callee_function (), &arg_svals, ctxt);
+  push_frame (mgr, call_edge.get_callee_function (), &arg_svals, ctxt);
 }
-#endif
+
 /* Pop the top-most frame_region2 from the stack, and copy the return
    region2's values (if any) into the region2 for the lvalue of the LHS of
    the call (if any).  */
 void
-region_model2::update_for_return_superedge (const return_superedge &return_edge,
-					    region_model2_context *ctxt)
+region_model2::update_for_return_superedge (const return_superedge &/*return_edge*/,
+					    region_model2_context */*ctxt*/)
 {
   gcc_unreachable ();
 #if 0
@@ -5886,8 +5788,8 @@ region_model2::update_for_return_superedge (const return_superedge &return_edge,
    return value to "unknown".  A proper implementation would e.g. update
    sm-state, and presumably be reworked to support multiple outcomes.  */
 void
-region_model2::update_for_call_summary (const callgraph_superedge &cg_sedge,
-					region_model2_context *ctxt)
+region_model2::update_for_call_summary (const callgraph_superedge &/*cg_sedge*/,
+					region_model2_context */*ctxt*/)
 {
   gcc_unreachable ();
 #if 0
@@ -6021,11 +5923,19 @@ region_model2::get_stack_region2 *() const
    Return the region2 *of the new frame_region2.  */
 
 region2 *
-region_model2::push_frame (function *fun, vec<svalue2 *> *arg_svals,
-			   region_model2_context *ctxt)
+region_model2::push_frame (region_model2_manager *mgr,
+			   function *fun, vec<svalue2 *> *arg_svals,
+			   region_model2_context */*ctxt*/)
 {
-  gcc_unreachable ();
+  m_current_frame = mgr->get_frame_region (m_current_frame, fun);
+  if (arg_svals)
+    {
+      gcc_unreachable ();
+      // TODO
+    }
+  // TODO
   //return get_root_region2 ()->push_frame (this, fun, arg_svals, ctxt);
+  return m_current_frame;
 }
 
 /* Get the function of the top-most frame in this region_model2's stack.
@@ -6035,20 +5945,23 @@ function *
 region_model2::get_current_function () const
 {
   frame_region2 *frame = get_current_frame ();
+  gcc_assert (frame);
   return frame->get_function ();
 }
 
 /* Pop the topmost frame_region2 from this region_model2's stack;
    see the comment for stack_region2::pop_frame.  */
-#if 0
+
 void
 region_model2::pop_frame (region2 *result_dst_reg,
-			 bool purge, purge_stats *out,
-			 region_model2_context *ctxt)
+			  bool purge, purge_stats2 *out,
+			  region_model2_context *ctxt)
 {
-  get_root_region2 ()->pop_frame (this, result_dst_reg, purge, out, ctxt);
+  gcc_unreachable ();
+  // TODO
+  //get_root_region2 ()->pop_frame (this, result_dst_reg, purge, out, ctxt);
 }
-#endif
+
 
 /* Get the number of frames in this region_model2's stack.  */
 
@@ -7560,6 +7473,7 @@ test_compound_assignment ()
   ASSERT_EQ (model.get_rvalue (c_x, NULL), model.get_rvalue (d_x, NULL));
   ASSERT_EQ (model.get_rvalue (c_y, NULL), model.get_rvalue (d_y, NULL));
 }
+#endif
 
 /* Verify the details of pushing and popping stack frames.  */
 
@@ -7603,54 +7517,68 @@ test_stack_frames ()
   /* "q" global.  */
   tree q = build_global_decl ("q", ptr_type_node);
 
+  region_model2_manager mgr;
   test_region_model2_context ctxt;
   region_model2 model;
 
   /* Push stack frame for "parent_fn".  */
   region2 *parent_frame_reg
-    = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl), NULL, &ctxt);
-  ASSERT_EQ (model.get_current_frame *(), parent_frame_reg);
-  region2 *a_in_parent_reg = model.get_lvalue (a, &ctxt);
-  model.set_value (a_in_parent_reg, model.get_rvalue (int_42, &ctxt), &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (b, &ctxt),
+    = model.push_frame (&mgr, DECL_STRUCT_FUNCTION (parent_fndecl),
+			NULL, &ctxt);
+  ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
+  region2 *a_in_parent_reg = model.get_lvalue (&mgr, a, &ctxt);
+  model.set_value (&mgr,
+		   a_in_parent_reg,
+		   model.get_rvalue (&mgr, int_42, &ctxt),
+		   &ctxt);
+#if 0
+  model.set_to_new_unknown_value (model.get_lvalue (&mgr, b, &ctxt),
 				  integer_type_node, &ctxt);
-  model.add_constraint (b, LT_EXPR, int_10, &ctxt);
-  ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &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));
 
   /* Push stack frame for "child_fn".  */
   region2 *child_frame_reg
-    = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
-  ASSERT_EQ (model.get_current_frame *(), child_frame_reg);
-  region2 *x_in_child_reg = model.get_lvalue (x, &ctxt);
-  model.set_value (x_in_child_reg, model.get_rvalue (int_0, &ctxt), &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (y, &ctxt),
+    = model.push_frame (&mgr, DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
+  ASSERT_EQ (model.get_current_frame (), child_frame_reg);
+  region2 *x_in_child_reg = model.get_lvalue (&mgr, x, &ctxt);
+  model.set_value (&mgr,
+		   x_in_child_reg,
+		   model.get_rvalue (&mgr, int_0, &ctxt),
+		   &ctxt);
+#if 0
+  model.set_to_new_unknown_value (model.get_lvalue (&mgr, y, &ctxt),
 				  integer_type_node, &ctxt);
-  model.add_constraint (y, NE_EXPR, int_5, &ctxt);
-  ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &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));
 
   /* Point a global pointer at a local in the child frame:  p = &x.  */
-  region2 *p_in_globals_reg = model.get_lvalue (p, &ctxt);
-  model.set_value (p_in_globals_reg,
-		   model.get_or_create_ptr_svalue2 (ptr_type_node,
-						   x_in_child_reg),
+  region2 *p_in_globals_reg = model.get_lvalue (&mgr, p, &ctxt);
+  model.set_value (&mgr,
+		   p_in_globals_reg,
+		   mgr.get_ptr_svalue2 (ptr_type_node, x_in_child_reg),
 		   &ctxt);
 
   /* Point another global pointer at p: q = &p.  */
-  region2 *q_in_globals_reg = model.get_lvalue (q, &ctxt);
-  model.set_value (q_in_globals_reg,
-		   model.get_or_create_ptr_svalue2 (ptr_type_node,
-						   p_in_globals_reg),
+  region2 *q_in_globals_reg = model.get_lvalue (&mgr, q, &ctxt);
+  model.set_value (&mgr,
+		   q_in_globals_reg,
+		   mgr.get_ptr_svalue2 (ptr_type_node, p_in_globals_reg),
 		   &ctxt);
 
   /* Test get_descendents.  */
+#if 0
   region2_id_set descendents (&model);
   model.get_descendents (child_frame_reg, &descendents, region2_id::null ());
   ASSERT_TRUE (descendents.region2_p (child_frame_reg));
   ASSERT_TRUE (descendents.region2_p (x_in_child_reg));
   ASSERT_FALSE (descendents.region2_p (a_in_parent_reg));
   ASSERT_EQ (descendents.num_region2s (), 3);
+#endif
 #if 0
   auto_vec<region2_id> test_vec;
   for (region2_id_set::iterator_t iter = descendents.begin ();
@@ -7665,9 +7593,10 @@ test_stack_frames ()
 		  "a: 42, x: 0, p: &x, q: &p, {b, y}: unknown, b < 10, y != 5");
 
   /* Pop the "child_fn" frame from the stack.  */
-  purge_stats purged;
-  model.pop_frame (region2_id::null (), true, &purged, &ctxt);
+  purge_stats2 purged;
+  model.pop_frame (NULL, true, &purged, &ctxt);
 
+#if 0
   /* We should have purged the unknown values for x and y. */
   ASSERT_EQ (purged.m_num_svalue2s, 2);
 
@@ -7677,35 +7606,37 @@ test_stack_frames ()
   /* We should have purged the constraint on y.  */
   ASSERT_EQ (purged.m_num_equiv_classes, 1);
   ASSERT_EQ (purged.m_num_constraints, 1);
+#endif
 
   /* Verify that p (which was pointing at the local "x" in the popped
      frame) has been poisoned.  */
-  svalue2 *new_p_sval = model.get_svalue2 (model.get_rvalue (p, &ctxt));
-  ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
+  svalue2 *new_p_sval = model.get_rvalue (&mgr, p, &ctxt);
+  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);
 
   /* Verify that q still points to p, in spite of the region2
      renumbering.  */
-  svalue2 *new_q_sval = model.get_svalue2 (model.get_rvalue (q, &ctxt));
-  ASSERT_EQ (new_q_sval->get_kind (), SK_REGION2);
+  svalue2 *new_q_sval = model.get_rvalue (&mgr, q, &ctxt);
+  ASSERT_EQ (new_q_sval->get_kind (), svalue2::SK_REGION);
   ASSERT_EQ (new_q_sval->dyn_cast_region_svalue2 ()->get_pointee (),
-	     model.get_lvalue (p, &ctxt));
+	     model.get_lvalue (&mgr, p, &ctxt));
 
   /* Verify that top of stack has been updated.  */
-  ASSERT_EQ (model.get_current_frame *(), parent_frame_reg);
+  ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
 
   /* Verify locals in parent frame.  */
   /* Verify "a" still has its value.  */
-  svalue2 *new_a_sval = model.get_svalue2 (model.get_rvalue (a, &ctxt));
-  ASSERT_EQ (new_a_sval->get_kind (), SK_CONSTANT);
+  svalue2 *new_a_sval = model.get_rvalue (&mgr, a, &ctxt);
+  ASSERT_EQ (new_a_sval->get_kind (), svalue2::SK_CONSTANT);
   ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue2 ()->get_constant (),
 	     int_42);
   /* Verify "b" still has its constraint.  */
-  ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
+  ASSERT_EQ (model.eval_condition (&mgr, b, LT_EXPR, int_10, &ctxt),
 	     tristate (tristate::TS_TRUE));
 }
 
+#if 0
 /* Verify that get_representative_path_var works as expected, that
    we can map from region2 ids to parms and back within a recursive call
    stack.  */
@@ -8309,7 +8240,7 @@ test_malloc_constraints ()
   tree null_ptr = build_int_cst (ptr_type_node, 0);
 
   region2 *reg = model.add_new_malloc_region2 ();
-  svalue2 *sval = model.get_or_create_ptr_svalue2 (ptr_type_node, rid);
+  svalue2 *sval = mgr.get_ptr_svalue2 (ptr_type_node, rid);
   model.set_value (model.get_lvalue (p, NULL), sid, NULL);
   model.set_value (q, p, NULL);
 
@@ -8493,7 +8424,9 @@ analyzer_region_model2_cc_tests ()
   test_purge_unused_svalue2s ();
   test_assignment ();
   test_compound_assignment ();
+#endif
   test_stack_frames ();
+#if 0
   test_get_representative_path_var ();
   test_canonicalization_1 ();
   test_canonicalization_2 ();
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 90c6568087e..6e5d1fb3fd9 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -816,20 +816,22 @@ class scope_region2 : public map_region2
 };
 
 /* Concrete region2 subclass, representing a function frame on the stack,
-   to contain the locals.  */
+   to contain the locals.
+   The parent is the stack region; there's also a hierarchy of call-stack
+   prefixes expressed via m_calling_frame..  */
 
 class frame_region2 : public scope_region2
 {
 public:
-  frame_region2 (unsigned id, region2 *parent, function *fun, int depth)
-  : scope_region2 (id, parent), m_fun (fun), m_depth (depth)
+  frame_region2 (unsigned id, region2 *parent, frame_region2 *calling_frame,
+		 function *fun, int depth)
+  : scope_region2 (id, parent), m_calling_frame (calling_frame),
+    m_fun (fun), m_depth (depth)
   {}
 
   /* region2 vfuncs.  */
-#if 0
-  region2 *clone () const FINAL OVERRIDE;
-#endif
   enum kind get_kind () const FINAL OVERRIDE { return RK_FRAME; }
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
 #if 0
   void print_fields (const region_model2 &model,
 		     pretty_printer *pp) const
@@ -846,6 +848,7 @@ public:
   bool compare_fields (const frame_region2 &other) const;
 
  private:
+  frame_region2 *m_calling_frame;
   function *m_fun;
   int m_depth;
 };
@@ -975,7 +978,6 @@ is_a_helper <function_region2 *>::test (region2 *reg)
   return reg->get_kind () == region2::RK_FUNCTION;
 }
 
-#if 0
 namespace ana {
 
 /* Concrete region2 subclass representing a stack, containing all stack
@@ -985,18 +987,14 @@ namespace ana {
 class stack_region2 : public region2
 {
 public:
-  stack_region2 (region2 *parent)
-  : region2 (parent, NULL_TREE)
+  stack_region2 (unsigned id, region2 *parent)
+  : region2 (id, parent, NULL_TREE)
   {}
 
-  stack_region2 (const stack_region2 &other);
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
 
   bool compare_fields (const stack_region2 &other) const;
 
-#if 0
-  region2 *clone () const FINAL OVERRIDE;
-#endif
-
   enum kind get_kind () const FINAL OVERRIDE { return RK_STACK; }
 
 #if 0
@@ -1007,13 +1005,6 @@ public:
 #endif
 
 #if 0
-  void push_frame (region2 *frame_rid);
-  void pop_frame (region_model2 *model, region2_id result_dst_rid,
-		  bool purge, purge_stats *stats,
-		  region_model2_context *ctxt);
-  unsigned get_num_frames () const { return m_frame_rids.length (); }
-  region2_id get_frame_rid (unsigned i) const { return m_frame_rids[i]; }
-
   static bool can_merge_p (const stack_region2 *stack_region2_a,
 			   const stack_region2 *stack_region2_b,
 			   model_merger *merger);
@@ -1047,6 +1038,8 @@ is_a_helper <stack_region2 *>::test (region2 *reg)
   return reg->get_kind () == region2::RK_STACK;
 }
 
+#if 0
+
 namespace ana {
 
 /* Concrete region2 subclass: a region2 within which region2s can be
@@ -1443,7 +1436,8 @@ private:
   map_t m_map;
 };
 
-/* FIXME.  */
+/* A class responsible for owning and consolidating region2 and svalue2
+   instances.    */
 
 class region_model2_manager
 {
@@ -1465,6 +1459,9 @@ public:
 			       svalue2 *index,
 			       region_model2_context *ctxt);
 
+  frame_region2 *get_frame_region (frame_region2 *calling_frame,
+				   function *fun);
+
   const concrete_binding2 *
   get_concrete_binding (const region2 *region,
 			enum binding_key2::kind kind,
@@ -1476,19 +1473,29 @@ public:
 			region2 *concrete_offset_region);
 
   svalue2 *get_or_create_initial_value (const region2 *reg);
+  svalue2 *get_ptr_svalue2 (tree ptr_type, region2 *pointee);
 
   unsigned alloc_region_id () { return m_next_region_id++; }
 
 private:
   unsigned m_next_region_id;
   root_region2 m_root_region;
+  stack_region2 m_stack_region;
 
+  /* svalue2 consolidation.  */
   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;
 
+  typedef hash_map<const region2 *, region_svalue2 *> pointer_values_map_t;
+  pointer_values_map_t m_pointer_values_map;
+
+  uniq_manager<svalue2> m_ptr_svalues;
+
+  /* region2 consolidation.  */
+
   globals_region2 m_globals_region;
   typedef hash_map<tree, decl_region2 *> globals_map_t;
   typedef globals_map_t::iterator globals_iterator_t;
@@ -1501,6 +1508,7 @@ private:
   fields_map_t m_fields_map;
 #endif
   uniq_manager<region2> m_elements;
+  uniq_manager<frame_region2> m_frames;
 
   uniq_manager<concrete_binding2> m_concrete_binding_key_mgr;
   uniq_manager<symbolic_binding2> m_symbolic_binding_key_mgr;
@@ -1590,7 +1598,8 @@ class region_model2
 
   region2_id get_stack_region2_id () const;
 #endif
-  region2 *push_frame (function *fun, vec<svalue2 *> *arg_sids,
+  region2 *push_frame (region_model2_manager *mgr,
+		       function *fun, vec<svalue2 *> *arg_sids,
 		       region_model2_context *ctxt);
   frame_region2 *get_current_frame () const { return m_current_frame; }
   function * get_current_function () const;
@@ -1815,6 +1824,7 @@ class region_model2_context
   virtual bool can_purge_p (svalue2_id sid) = 0;
 #endif
 
+  // FIXME:
   /* Hook for clients to be notified when a range of SIDs have
      been purged, so that they can purge state relating to those
      values (and potentially emit warnings about leaks).
@@ -1873,12 +1883,12 @@ class noop_region_model2_context : public region_model2_context
 {
 public:
   void warn (pending_diagnostic *) OVERRIDE {}
-#if 0
-  int on_svalue2_purge (svalue2_id, const svalue2_id_map &) OVERRIDE
+  int on_svalue2_purge (svalue2 *) OVERRIDE
   {
     return 0;
   }
   logger *get_logger () OVERRIDE { return NULL; }
+#if 0
   void on_inherited_svalue2 (svalue2_id parent_sid ATTRIBUTE_UNUSED,
 			    svalue2_id child_sid  ATTRIBUTE_UNUSED)
     OVERRIDE
@@ -1888,20 +1898,22 @@ public:
 		svalue2_id dst_sid ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
+#endif
   void on_condition (tree lhs ATTRIBUTE_UNUSED,
 		     enum tree_code op ATTRIBUTE_UNUSED,
 		     tree rhs ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
+#if 0
   void on_unknown_change (svalue2_id sid ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
+#endif
   void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
 	       tree rhs ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
   void on_unexpected_tree_code (tree, const dump_location_t &) OVERRIDE {}
-#endif
 };
 
 /* A subclass of region_model2_context for determining if operations fail
-- 
2.21.0

