From 13e3a4c0d7e4296d29f63e0c56cbe1197b339994 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 29 Oct 2019 16:56:59 -0400
Subject: [PATCH 087/119] FIXME: start adding code_region and function_region

---
 gcc/analyzer/region-model.cc | 247 ++++++++++++++++++++++++++++++++++---------
 gcc/analyzer/region-model.h  |  96 +++++++++++++++--
 2 files changed, 286 insertions(+), 57 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 49cbdda..98594b7 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -114,6 +114,7 @@ class impl_constraint_manager : public constraint_manager
     if (constant_svalue *cst_svalue = svalue->dyn_cast_constant_svalue ())
       {
 	tree cst = cst_svalue->get_constant ();
+	// FIXME:
 	/* This could be a constant or a decl; constraint_manager is only
 	   expecting actual constants.  */
 	if (CONSTANT_CLASS_P (cst))
@@ -681,7 +682,6 @@ hashval_t
 constant_svalue::hash () const
 {
   inchash::hash hstate;
-  // FIXME: what if it's a fndecl?
   inchash::add_expr (m_cst_expr, hstate);
   return hstate.end ();
 }
@@ -728,41 +728,6 @@ constant_svalue::eval_condition (constant_svalue *lhs,
   tree lhs_const = lhs->get_constant ();
   tree rhs_const = rhs->get_constant ();
 
-  /* If one or both of the "constants" are function pointers or labels, then
-     we have equality iff the trees are equal.  */
-  if (TREE_CODE (lhs_const) == FUNCTION_DECL
-      || TREE_CODE (lhs_const) == LABEL_DECL
-      || TREE_CODE (rhs_const) == FUNCTION_DECL
-      || TREE_CODE (rhs_const) == LABEL_DECL)
-    {
-      bool eq = (lhs_const == rhs_const);
-      switch (op)
-	{
-	default:
-	  gcc_unreachable ();
-
-	case EQ_EXPR:
-	  return tristate (eq);
-
-	case GE_EXPR:
-	case LE_EXPR:
-	  if (eq)
-	    return tristate (true);
-	  else
-	    return tristate (tristate::TS_UNKNOWN);
-
-	case NE_EXPR:
-	  return tristate (lhs_const != rhs_const);
-
-	case GT_EXPR:
-	case LT_EXPR:
-	  if (eq)
-	    return tristate (false);
-	  return tristate::TS_UNKNOWN;
-	}
-    }
-
-  /* Otherwise, we have a pair of constants; compare them.  */
   gcc_assert (CONSTANT_CLASS_P (lhs_const));
   gcc_assert (CONSTANT_CLASS_P (rhs_const));
 
@@ -783,11 +748,7 @@ constant_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
 				pretty_printer *pp) const
 {
 PUSH_IGNORE_WFORMAT
-  if (TREE_CODE (m_cst_expr) == FUNCTION_DECL
-      || TREE_CODE (m_cst_expr) == LABEL_DECL)
-    pp_printf (pp, "%qD", m_cst_expr);
-  else
-    pp_printf (pp, "%qE", m_cst_expr);
+  pp_printf (pp, "%qE", m_cst_expr);
 POP_IGNORE_WFORMAT
 }
 
@@ -952,6 +913,10 @@ region_kind_to_str (enum region_kind kind)
       return "frame";
     case RK_GLOBALS:
       return "globals";
+    case RK_CODE:
+      return "code";
+    case RK_FUNCTION:
+      return "function";
     case RK_STACK:
       return "stack";
     case RK_HEAP:
@@ -1050,6 +1015,22 @@ region::operator== (const region &other) const
 	  = (const globals_region &)other;
 	return this_sub.compare_fields (other_sub);
       }
+    case RK_CODE:
+      {
+	const code_region &this_sub
+	  = (const code_region &)*this;
+	const code_region &other_sub
+	  = (const code_region &)other;
+	return this_sub.compare_fields (other_sub);
+      }
+    case RK_FUNCTION:
+      {
+	const function_region &this_sub
+	  = (const function_region &)*this;
+	const function_region &other_sub
+	  = (const function_region &)other;
+	return this_sub.compare_fields (other_sub);
+      }
     case RK_STACK:
       {
 	const stack_region &this_sub
@@ -1758,9 +1739,12 @@ map_region::dump_child_label (const region_model &model,
     {
       if (child_rid == (*iter).second)
 	{
-	  tree expr = (*iter).first;
+	  tree key = (*iter).first;
 PUSH_IGNORE_WFORMAT
-	  pp_printf (pp, "%qE: ", expr);
+	  if (DECL_P (key))
+	    pp_printf (pp, "%qD: ", key);
+	  else
+	    pp_printf (pp, "%qE: ", key);
 POP_IGNORE_WFORMAT
 	}
     }
@@ -2395,6 +2379,62 @@ globals_region::valid_key_p (tree key) const
   return TREE_CODE (key) == VAR_DECL;
 }
 
+/* class code_region : public map_region.  */
+
+/* Compare the fields of this code_region with OTHER, returning true
+   if they are equal.
+   For use by region::operator==.  */
+
+bool
+code_region::compare_fields (const code_region &other) const
+{
+  return map_region::compare_fields (other);
+}
+
+/* Implementation of region::clone vfunc for code_region.  */
+
+region *
+code_region::clone () const
+{
+  return new code_region (*this);
+}
+
+/* FIXME.  */
+
+bool
+code_region::valid_key_p (tree key) const
+{
+  return TREE_CODE (key) == FUNCTION_DECL;
+}
+
+/* class function_region : public map_region.  */
+
+/* Compare the fields of this function_region with OTHER, returning true
+   if they are equal.
+   For use by region::operator==.  */
+
+bool
+function_region::compare_fields (const function_region &other) const
+{
+  return map_region::compare_fields (other);
+}
+
+/* Implementation of region::clone vfunc for function_region.  */
+
+region *
+function_region::clone () const
+{
+  return new function_region (*this);
+}
+
+/* FIXME.  */
+
+bool
+function_region::valid_key_p (tree key) const
+{
+  return TREE_CODE (key) == LABEL_DECL;
+}
+
 /* class stack_region : public region.  */
 
 IMPL_POOL_ALLOCATOR (stack_region)
@@ -2719,6 +2759,7 @@ root_region::root_region (const root_region &other)
 : region (other),
   m_stack_rid (other.m_stack_rid),
   m_globals_rid (other.m_globals_rid),
+  m_code_rid (other.m_code_rid),
   m_heap_rid (other.m_heap_rid)
 {
 }
@@ -2734,6 +2775,8 @@ root_region::compare_fields (const root_region &other) const
     return false;
   if (m_globals_rid != other.m_globals_rid)
     return false;
+  if (m_code_rid != other.m_code_rid)
+    return false;
   if (m_heap_rid != other.m_heap_rid)
     return false;
   return true;
@@ -2770,6 +2813,8 @@ root_region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
     pp_printf (pp, "stack: ");
   else if (child_rid == m_globals_rid)
     pp_printf (pp, "globals: ");
+  else if (child_rid == m_code_rid)
+    pp_printf (pp, "code: ");
   else if (child_rid == m_heap_rid)
     pp_printf (pp, "heap: ");
 }
@@ -2928,6 +2973,26 @@ root_region::ensure_globals_region (region_model *model)
   return m_globals_rid;
 }
 
+/* Return the code region (which could be NULL).  */
+
+code_region *
+root_region::get_code_region (const region_model *model) const
+{
+  return model->get_region <code_region> (m_code_rid);
+}
+
+/* Return the region_id of the code region, creating it if doesn't
+   already exist.  */
+
+region_id
+root_region::ensure_code_region (region_model *model)
+{
+  if (m_code_rid.null_p ())
+    m_code_rid
+      = model->add_region (new code_region (model->get_root_rid ()));
+  return m_code_rid;
+}
+
 /* Return the globals region (which could be NULL).  */
 
 globals_region *
@@ -2970,6 +3035,7 @@ root_region::remap_region_ids (const region_id_map &map)
 {
   map.update (&m_stack_rid);
   map.update (&m_globals_rid);
+  map.update (&m_code_rid);
   map.update (&m_heap_rid);
 }
 
@@ -3014,6 +3080,22 @@ root_region::can_merge_p (const root_region *root_region_a,
     }
   /* otherwise, merge as "no globals".  */
 
+  map_region *code_a = root_region_a->get_code_region (merger->m_model_a);
+  map_region *code_b = root_region_b->get_code_region (merger->m_model_b);
+  if (code_a && code_b)
+    {
+      /* If both models have code regions, attempt to merge them.  */
+      region_id merged_code_rid
+	= merged_root_region->ensure_code_region (merger->m_merged_model);
+      map_region *merged_code
+	= merged_root_region->get_code_region (merger->m_merged_model);
+      if (!map_region::can_merge_p (code_a, code_b,
+				    merged_code, merged_code_rid,
+				    merger))
+	return false;
+    }
+  /* otherwise, merge as "no code".  */
+
   heap_region *heap_a = root_region_a->get_heap_region (merger->m_model_a);
   heap_region *heap_b = root_region_b->get_heap_region (merger->m_model_b);
   if (heap_a && heap_b)
@@ -3041,6 +3123,7 @@ root_region::add_to_hash (inchash::hash &hstate) const
   region::add_to_hash (hstate);
   inchash::add (m_stack_rid, hstate);
   inchash::add (m_globals_rid, hstate);
+  inchash::add (m_code_rid, hstate);
   inchash::add (m_heap_rid, hstate);
 }
 
@@ -3052,6 +3135,7 @@ root_region::walk_for_canonicalization (canonicalization *c) const
 {
   c->walk_rid (m_stack_rid);
   c->walk_rid (m_globals_rid);
+  c->walk_rid (m_code_rid);
   c->walk_rid (m_heap_rid);
 }
 
@@ -4512,9 +4596,9 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt)
 	/* "&EXPR".  */
 	tree op0 = TREE_OPERAND (expr, 0);
 	if (TREE_CODE (op0) == FUNCTION_DECL)
-	  return get_svalue_for_fndecl (op0);
+	  return get_svalue_for_fndecl (TREE_TYPE (expr), op0);
 	else if (TREE_CODE (op0) == LABEL_DECL)
-	  return get_or_create_constant_svalue (op0);
+	  return get_svalue_for_label (TREE_TYPE (expr), op0);
 	region_id expr_rid = get_lvalue (op0, ctxt);
 	return get_or_create_ptr_svalue (TREE_TYPE (expr), expr_rid);
       }
@@ -4608,15 +4692,50 @@ region_model::get_or_create_constant_svalue (tree cst_expr)
   return cst_sid;
 }
 
-/* Return an svalue_id for a constant_svalue for FNDECL,
-   creating the constant_svalue if necessary.
-   The constant_svalue instances are reused, based on pointer equality
-   of trees  */
+/* Return an svalue_id for a region_svalue for FNDECL,
+   creating the function_region if necessary.  */
+
+svalue_id
+region_model::get_svalue_for_fndecl (tree ptr_type, tree fndecl)
+{
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+  region_id function_rid = get_region_for_fndecl (fndecl);
+  return get_or_create_ptr_svalue (ptr_type, function_rid);
+}
+
+/* Return a region_id for a function_region for FNDECL,
+   creating it if necessary.  */
+
+region_id
+region_model::get_region_for_fndecl (tree fndecl)
+{
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+
+  region_id code_rid = get_root_region ()->ensure_code_region (this);
+  code_region *code = get_root_region ()->get_code_region (this);
+
+  return code->get_or_create (this, code_rid, fndecl, TREE_TYPE (fndecl));
+}
+
+/* Return an svalue_id for a region_svalue for LABEL,
+   creating the label_region if necessary.  */
 
 svalue_id
-region_model::get_svalue_for_fndecl (tree fndecl)
+region_model::get_svalue_for_label (tree ptr_type, tree label)
 {
-  return get_or_create_constant_svalue (fndecl);
+  gcc_assert (TREE_CODE (label) == LABEL_DECL);
+  region_id label_rid = get_region_for_label (label);
+  return get_or_create_ptr_svalue (ptr_type, label_rid);
+}
+
+/* Return a region_id for a label_region for LABEL,
+   creating it if necessary.  */
+
+region_id
+region_model::get_region_for_label (tree label)
+{
+  gcc_assert (TREE_CODE (label) == LABEL_DECL);
+  gcc_unreachable ();
 }
 
 /* If the type of SID's underlying value is DST_TYPE, return SID.
@@ -4877,6 +4996,29 @@ region_model::eval_condition (svalue_id lhs_sid,
       if (constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
 	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
 	  return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
+
+      /* If we have a region_svalue, we have a non-NULL pointer, so it does
+	 not equal zero.  */
+      if (lhs->dyn_cast_region_svalue ())
+	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
+	  if (zerop (cst_rhs->get_constant ()))
+	    {
+	      switch (op)
+		{
+		default:
+		  gcc_unreachable ();
+
+		case EQ_EXPR:
+		case GE_EXPR:
+		case LE_EXPR:
+		  return tristate::TS_FALSE;
+
+		case NE_EXPR:
+		case GT_EXPR:
+		case LT_EXPR:
+		  return tristate::TS_TRUE;
+		}
+	    }
     }
 
   /* Otherwise, try constraints.  */
@@ -5582,6 +5724,9 @@ make_region_for_type (region_id parent_rid, tree type)
   if (TREE_CODE (type) == UNION_TYPE)
     return new union_region (parent_rid, type);
 
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    return new function_region (parent_rid, type);
+
   /* If we have a void *, make a new symbolic region.  */
   if (type == void_type_node)
     return new symbolic_region (parent_rid);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 67ad3ce..3278563 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -604,8 +604,7 @@ is_a_helper <region_svalue *>::test (svalue *sval)
   return sval->get_kind () == SK_REGION;
 }
 
-/* Concrete subclass of svalue representing a specific constant value
-   (or a FUNCTION_DECL or LABEL_DECL).  */
+/* Concrete subclass of svalue representing a specific constant value.  */
 
 class constant_svalue : public svalue
 {
@@ -617,9 +616,7 @@ public:
   : svalue (TREE_TYPE (cst_expr)), m_cst_expr (cst_expr)
   {
     gcc_assert (cst_expr);
-    gcc_assert (TREE_CODE (cst_expr) == FUNCTION_DECL
-		|| TREE_CODE (cst_expr) == LABEL_DECL
-		|| CONSTANT_CLASS_P (cst_expr));
+    gcc_assert (CONSTANT_CLASS_P (cst_expr));
   }
 
   bool compare_fields (const constant_svalue &other) const;
@@ -804,6 +801,8 @@ enum region_kind
   RK_ARRAY,
   RK_FRAME,
   RK_GLOBALS,
+  RK_CODE,
+  RK_FUNCTION,
   RK_STACK,
   RK_HEAP,
   RK_ROOT,
@@ -827,9 +826,12 @@ extern const char *region_kind_to_str (enum region_kind);
        scope_region
          frame_region (RK_FRAME)
          globals_region (RK_GLOBALS)
+       code_region (RK_CODE)
+       function_region (RK_FUNCTION)
      stack_region (RK_STACK)
      heap_region (RK_HEAP)
      root_region (RK_ROOT)
+     label_region (RK_FUNCTION)
      symbolic_region (RK_SYMBOLIC).  */
 
 /* Abstract base class representing a chunk of memory.
@@ -1245,6 +1247,80 @@ is_a_helper <globals_region *>::test (region *reg)
   return reg->get_kind () == RK_GLOBALS;
 }
 
+/* Concrete region subclass.  A map_region representing the code, using
+   FUNCTION_DECLs for its keys.  */
+
+class code_region : public map_region
+{
+public:
+  code_region (region_id parent_rid)
+  : map_region (parent_rid, NULL_TREE)
+  {}
+  code_region (const code_region &other)
+  : map_region (other)
+  {}
+
+  /* region vfuncs.  */
+  region *clone () const FINAL OVERRIDE;
+  enum region_kind get_kind () const FINAL OVERRIDE { return RK_CODE; }
+
+  /* map_region vfunc.  */
+  bool valid_key_p (tree key) const FINAL OVERRIDE;
+
+  region_id get_element (region_model *model,
+			 region_id this_rid,
+			 svalue_id index_sid,
+			 region_model_context *ctxt);
+
+  bool compare_fields (const code_region &other) const;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <code_region *>::test (region *reg)
+{
+  return reg->get_kind () == RK_CODE;
+}
+
+/* Concrete region subclass.  A map_region representing the code for
+   a particular function, using LABEL_DECLs for its keys.  */
+
+class function_region : public map_region
+{
+public:
+  function_region (region_id parent_rid, tree type)
+  : map_region (parent_rid, type)
+  {
+    gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
+  }
+  function_region (const function_region &other)
+  : map_region (other)
+  {}
+
+  /* region vfuncs.  */
+  region *clone () const FINAL OVERRIDE;
+  enum region_kind get_kind () const FINAL OVERRIDE { return RK_FUNCTION; }
+
+  /* map_region vfunc.  */
+  bool valid_key_p (tree key) const FINAL OVERRIDE;
+
+  region_id get_element (region_model *model,
+			 region_id this_rid,
+			 svalue_id index_sid,
+			 region_model_context *ctxt);
+
+  bool compare_fields (const function_region &other) const;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <function_region *>::test (region *reg)
+{
+  return reg->get_kind () == RK_FUNCTION;
+}
+
 /* Concrete region subclass representing a stack, containing all stack
    frames, and implicitly providing a POISON_KIND_UNINIT value to all
    child regions by default.  */
@@ -1386,6 +1462,9 @@ public:
   region_id get_globals_region_id () const { return m_globals_rid; }
   globals_region *get_globals_region (const region_model *model) const;
 
+  region_id ensure_code_region (region_model *model);
+  code_region *get_code_region (const region_model *model) const;
+
   region_id ensure_heap_region (region_model *model);
   heap_region *get_heap_region (const region_model *model) const;
 
@@ -1410,6 +1489,7 @@ private:
 
   region_id m_stack_rid;
   region_id m_globals_rid;
+  region_id m_code_rid;
   region_id m_heap_rid;
 };
 
@@ -1555,7 +1635,11 @@ class region_model
 
   svalue_id get_or_create_ptr_svalue (tree ptr_type, region_id id);
   svalue_id get_or_create_constant_svalue (tree cst_expr);
-  svalue_id get_svalue_for_fndecl (tree fndecl);
+  svalue_id get_svalue_for_fndecl (tree ptr_type, tree fndecl);
+  svalue_id get_svalue_for_label (tree ptr_type, tree label);
+
+  region_id get_region_for_fndecl (tree fndecl);
+  region_id get_region_for_label (tree label);
 
   svalue_id maybe_cast (tree type, svalue_id sid);
 
-- 
1.8.5.3

