From 555d27265ccf31df7f90eccfd81accc8a79509fc Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Sun, 26 Apr 2020 12:58:40 -0400
Subject: [PATCH 075/251] FIXME: enough interprocedural code for returning a
 value to work

---
 gcc/analyzer/region-model2.cc                | 126 ++++++++++++++-----
 gcc/analyzer/region-model2.h                 |  20 ++-
 gcc/testsuite/gcc.dg/analyzer/data-model-1.c |   8 +-
 3 files changed, 109 insertions(+), 45 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 70cd8ddbb94..d95b1e87921 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2150,10 +2150,10 @@ 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);
+    pp_printf (pp, "frame: %qs@%i", function_name (m_fun), get_stack_depth ());
   else
-    pp_printf (pp, "frame_region2(%qs, depth: %i)",
-	       function_name (m_fun), m_depth);
+    pp_printf (pp, "frame_region2(%qs, index: %i, depth: %i)",
+	       function_name (m_fun), m_index, get_stack_depth ());
 }
 
 /* Compare the fields of this frame_region2 with OTHER, returning true
@@ -2169,7 +2169,9 @@ frame_region2::compare_fields (const frame_region2 &other) const
 #endif
   if (m_fun != other.m_fun)
     return false;
-  if (m_depth != other.m_depth)
+  if (m_index != other.m_index)
+    return false;
+  if (m_calling_frame != other.m_calling_frame)
     return false;
   /* We don't compare m_locals.  */
   return true;
@@ -3267,11 +3269,11 @@ frame_region2 *
 region_model2_manager::get_frame_region (frame_region2 *calling_frame,
 					 function *fun)
 {
-  int depth = calling_frame ? calling_frame->get_depth () + 1 : 0;
+  int index = calling_frame ? calling_frame->get_index () + 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);
+			 fun, index);
   return const_cast <frame_region2 *> (m_frames.consolidate (frame_reg));
 }
 
@@ -3557,6 +3559,18 @@ void
 region_model2::dump_to_pp (pretty_printer *pp, bool summarize) const
 {
 #if 1
+  /* Dump stack.  */
+  pp_printf (pp, "stack depth: %i", get_stack_depth ());
+  pp_newline (pp);
+  for (frame_region2 *iter_frame = m_current_frame; iter_frame;
+       iter_frame = iter_frame->get_calling_frame ())
+    {
+      pp_printf (pp, "  frame (index %i): ", iter_frame->get_index ());
+      iter_frame->dump_to_pp (pp, summarize);
+      pp_newline (pp);
+    }
+
+  /* Dump store.  */
   m_store.dump_to_pp (pp, summarize, true); // FIXME
 
 #else
@@ -4779,7 +4793,8 @@ region_model2::get_lvalue_1 (path_var pv,
 		    || TREE_CODE (expr) == VAR_DECL
 		    || TREE_CODE (expr) == RESULT_DECL);
 
-	frame_region2 *frame = get_current_frame ();
+	int stack_index = pv.m_stack_depth;
+	frame_region2 *frame = get_frame_at_index (stack_index);
 	gcc_assert (frame);
 	return frame->get_region_for_local (m_mgr, expr, ctxt);
       }
@@ -6053,14 +6068,9 @@ region_model2::update_for_call_superedge (const call_superedge &call_edge,
    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
-  region2 *stack_reg = get_stack_region2 *();
-  stack_region2 *stack = get_region2 <stack_region2> (stack_reg);
-
   /* Get the region2 for the result of the call, within the caller frame.  */
   region2 *result_dst_reg;
   const gcall *call_stmt = return_edge.get_call_stmt ();
@@ -6068,17 +6078,19 @@ region_model2::update_for_return_superedge (const return_superedge &/*return_edg
   if (lhs)
     {
       /* Normally we access the top-level frame, which is:
-	   path_var (expr, stack->get_num_frames () - 1)
+	   path_var (expr, get_stack_depth () - 1)
 	 whereas here we need the caller frame, hence "- 2" here.  */
-      gcc_assert (stack->get_num_frames () >= 2);
-      result_dst_reg = get_lvalue (path_var (lhs, stack->get_num_frames () - 2),
+      gcc_assert (get_stack_depth () >= 2);
+      result_dst_reg = get_lvalue (path_var (lhs, get_stack_depth () - 2),
 				   ctxt);
     }
 
-  purge_stats stats;
-  stack->pop_frame (this, result_dst_reg, true, &stats, ctxt);
+  purge_stats2 stats;
+  pop_frame (result_dst_reg, true, &stats, ctxt);
+
   // TODO: do something with the stats?
 
+#if 0
   if (!lhs)
     {
       /* This could be a leak; try purging again, but this time,
@@ -6224,7 +6236,7 @@ region_model2::get_stack_region2 *() const
    in the new frame.
    Otherwise, populate them with unknown values.
 
-   Return the region2 *of the new frame_region2.  */
+   Return the new frame_region2.  */
 
 region2 *
 region_model2::push_frame (function *fun, vec<svalue2 *> *arg_svals,
@@ -6233,11 +6245,41 @@ region_model2::push_frame (function *fun, vec<svalue2 *> *arg_svals,
   m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
   if (arg_svals)
     {
-      gcc_unreachable ();
-      // TODO
+      /* Arguments supplied from a caller frame.  */
+      tree fndecl = fun->decl;
+      unsigned idx = 0;
+      for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
+	   iter_parm = DECL_CHAIN (iter_parm), ++idx)
+	{
+	  gcc_unreachable ();
+#if 0
+	  /* If there's a mismatching declaration, the call stmt might
+	     not have enough args.  Handle this case by leaving the
+	     rest of the params as uninitialized.  */
+	  if (idx >= arg_sids->length ())
+	    break;
+	  svalue_id arg_sid = (*arg_sids)[idx];
+	  region_id parm_rid
+	    = region->get_or_create (model, frame_rid, iter_parm,
+				     TREE_TYPE (iter_parm), ctxt);
+	  model->set_value (parm_rid, arg_sid, ctxt);
+
+	  /* Also do it for default SSA name (sharing the same unknown
+	     value).  */
+	  tree parm_default_ssa = ssa_default_def (fun, iter_parm);
+	  if (parm_default_ssa)
+	    {
+	      region_id defssa_rid
+		= region->get_or_create (model, frame_rid, parm_default_ssa,
+					 TREE_TYPE (iter_parm), ctxt);
+	      model->set_value (defssa_rid, arg_sid, ctxt);
+	    }
+#endif
+	}
     }
-  // TODO
-  //return get_root_region2 ()->push_frame (this, fun, arg_svals, ctxt);
+  /* Otherwise we have a top-level call within the analysis.  The params
+     have defined but unknown initial values.  */
+
   return m_current_frame;
 }
 
@@ -6274,12 +6316,9 @@ region_model2::pop_frame (region2 *result_dst_reg,
       if (result_dst_reg)
 	{
 	  /* Copy the result to RESULT_DST_REG.  */
-	  gcc_unreachable ();
-#if 0
-	  copy_region2 (result_dst_reg,
-			get_lvalue (result, ctxt),
-			ctxt);
-#endif
+	  copy_region (result_dst_reg,
+		       get_lvalue (result, ctxt),
+		       ctxt);
 	}
       if (purge)
 	{
@@ -6327,7 +6366,28 @@ region_model2::get_stack_depth () const
 {
   frame_region2 *frame = get_current_frame ();
   if (frame)
-    return frame->get_depth ();
+    return frame->get_stack_depth ();
+  else
+    return 0;
+}
+
+/* FIXME.  */
+
+frame_region2 *
+region_model2::get_frame_at_index (int index) const
+{
+  frame_region2 *frame = get_current_frame ();
+  if (frame)
+    {
+      gcc_assert (index >= 0);
+      gcc_assert (index <= frame->get_index ());
+      while (index != frame->get_index ())
+	{
+	  frame = frame->get_calling_frame ();
+	  gcc_assert (frame);
+	}
+      return frame;
+    }
   else
     return 0;
 }
@@ -7326,8 +7386,8 @@ test_dump ()
   region_model2_manager mgr;
   region_model2 model (&mgr);
 
-  ASSERT_DUMP_EQ (model, false, "");
-  ASSERT_DUMP_EQ (model, true, "");
+  ASSERT_DUMP_EQ (model, false, "stack depth: 0\n");
+  ASSERT_DUMP_EQ (model, true, "stack depth: 0\n");
 }
 
 /* Helper function for selftests.  Create a struct or union type named NAME,
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 0734f93bdd5..1d3f366b4fe 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1011,15 +1011,22 @@ class scope_region2 : public map_region2
 /* Concrete region2 subclass, representing a function frame on the stack,
    to contain the locals.
    The parent is the stack region; there's also a hierarchy of call-stack
-   prefixes expressed via m_calling_frame..  */
+   prefixes expressed via m_calling_frame.
+   For example, given "oldest" calling "middle" called "newest" we would have
+   - a stack depth of 3
+   - frame (A) for "oldest" with index 0 for depth 1, calling_frame == NULL
+   - frame (B) for "middle" with index 1 for depth 2, calling_frame == (A)
+   - frame (C) for "newest" with index 2 for depth 3, calling_frame == (B)
+   where the parent region for each of the frames is the "stack" region.
+   The index is the count of frames earlier than this in the stack.  */
 
 class frame_region2 : public scope_region2
 {
 public:
   frame_region2 (unsigned id, region2 *parent, frame_region2 *calling_frame,
-		 function *fun, int depth)
+		 function *fun, int index)
   : scope_region2 (id, parent), m_calling_frame (calling_frame),
-    m_fun (fun), m_depth (depth)
+    m_fun (fun), m_index (index)
   {}
   ~frame_region2 ();
 
@@ -1038,7 +1045,8 @@ public:
   /* 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; }
+  int get_index () const { return m_index; }
+  int get_stack_depth () const { return m_index + 1; }
 
   bool compare_fields (const frame_region2 &other) const;
 
@@ -1049,7 +1057,7 @@ public:
  private:
   frame_region2 *m_calling_frame;
   function *m_fun;
-  int m_depth;
+  int m_index;
   typedef hash_map<tree, region2 *> map_t;
   map_t m_locals;
   // TODO: make this not be a map_region2 anymore?
@@ -1770,7 +1778,7 @@ class region_model2
 		  bool purge, purge_stats2 *stats,
 		  region_model2_context *ctxt);
   int get_stack_depth () const;
-  function *get_function_at_depth (unsigned depth) const;
+  frame_region2 *get_frame_at_index (int index) const;
 
 #if 0
   region2_id get_globals_region2_id () const;
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
index 0613cfde8d3..e3c0339d0df 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
@@ -261,13 +261,9 @@ void test_16_alt (void)
 
   __analyzer_eval (msg != NULL); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (msg[0] == 'h'); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "status quo" { target *-*-* } .-1 } */
-  // TODO(xfail)
+  __analyzer_eval (msg[0] == 'h'); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (msg[1] == 'e'); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "status quo" { target *-*-* } .-1 } */
-  // TODO(xfail)
+  __analyzer_eval (msg[1] == 'e'); /* { dg-warning "TRUE" } */
 
   __analyzer_eval (strlen (msg) == 11); /* { dg-warning "TRUE" } */
 }
-- 
2.26.2

