From 07fa727ee9b0b26b67f84b1a618dd91ee01151ac Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 18 May 2020 20:54:34 -0400
Subject: [PATCH 145/377] FIXME: port sm-signal.c
 update_model_for_signal_handler to region_model2

---
 gcc/analyzer/diagnostic-manager.cc |  12 ++-
 gcc/analyzer/engine.cc             | 143 ++++++++++++++++++++++++++++-
 gcc/analyzer/exploded-graph.h      |  16 ++++
 gcc/analyzer/region-model2.cc      |  51 +++-------
 gcc/analyzer/region-model2.h       |  11 +--
 gcc/analyzer/sm-signal.cc          |  28 +++++-
 gcc/analyzer/store2.cc             |  32 +++++++
 gcc/analyzer/store2.h              |   2 +
 8 files changed, 244 insertions(+), 51 deletions(-)

diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index be39037e01f..d2f97b0fdb8 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -329,6 +329,8 @@ public:
 class dedupe_winners
 {
 public:
+  dedupe_winners (engine2 *eng) : m_engine2 (eng) {}
+
   ~dedupe_winners ()
   {
     /* Delete all keys and candidates.  */
@@ -368,7 +370,12 @@ public:
 		   sd->m_snode->m_index);
 
     feasibility_problem *p = NULL;
-    if (!dc->get_path ().feasible_p (logger, &p))
+    bool feasible;
+    if (m_engine2)
+      feasible = dc->get_path ().feasible2_p (logger, &p, m_engine2);
+    else
+      feasible = dc->get_path ().feasible_p (logger, &p);
+    if (!feasible)
       {
 	if (logger)
 	  logger->log ("rejecting %qs at EN: %i, SN: %i"
@@ -463,6 +470,7 @@ public:
   }
 
 private:
+  engine2 *m_engine2;
 
   /* This maps from each dedupe_key to a current best dedupe_candidate.  */
 
@@ -499,7 +507,7 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
      instance.  This partitions the saved diagnostics by dedupe_key,
      generating exploded_paths for them, and retaining the best one in each
      partition.  */
-  dedupe_winners best_candidates;
+  dedupe_winners best_candidates (eg.get_engine2 ());
 
   int i;
   saved_diagnostic *sd;
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index a7eacd048d6..04fb76ae68c 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1661,10 +1661,10 @@ exploded_node::on_stmt2 (exploded_graph &eg,
 				   stmt);
 
   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
-    state->m_region_model2->on_stmt (snode, stmt, &ctxt);
+    state->m_region_model2->on_stmt (stmt, &ctxt);
 
   if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
-    state->m_region_model2->on_stmt (snode, stmt/*, return_*/, &ctxt);
+    state->m_region_model2->on_stmt (stmt/*, return_*/, &ctxt);
 
   /* Track whether we have a gcall to a function that's not recognized by
      anything, for which we don't have a function body, or for which we
@@ -2177,6 +2177,21 @@ rewind_info_t::update_model (region_model *model,
 		     setjmp_point.get_stack_depth (), NULL);
 }
 
+void
+rewind_info_t::update_model2 (region_model2 *model,
+			      const exploded_edge &eedge)
+{
+  const program_point &longjmp_point = eedge.m_src->get_point ();
+  const program_point &setjmp_point = eedge.m_dest->get_point ();
+
+  gcc_assert (longjmp_point.get_stack_depth ()
+	      >= setjmp_point.get_stack_depth ());
+
+  model->on_longjmp (get_longjmp_call (),
+		     get_setjmp_call (),
+		     setjmp_point.get_stack_depth (), NULL);
+}
+
 /* Implementation of exploded_edge::custom_info_t::add_events_to_path vfunc
    for rewind_info_t.  */
 
@@ -3775,6 +3790,130 @@ exploded_path::feasible_p (logger *logger, feasibility_problem **out) const
   return true;
 }
 
+/* Check state along this path, returning true if it is feasible.
+   If OUT is non-NULL, and the path is infeasible, write a new
+   feasibility_problem to *OUT.  */
+
+bool
+exploded_path::feasible2_p (logger *logger, feasibility_problem **out,
+			    engine2 *eng) const
+{
+  LOG_SCOPE (logger);
+
+  /* Traverse the path, updating this model.  */
+  region_model2 model (eng->get_model_manager ());
+  for (unsigned i = 0; i < m_edges.length (); i++)
+    {
+      const exploded_edge *eedge = m_edges[i];
+      if (logger)
+	logger->log ("considering edge %i: EN:%i -> EN:%i",
+		     i,
+		     eedge->m_src->m_index,
+		     eedge->m_dest->m_index);
+      const exploded_node &src_enode = *eedge->m_src;
+      const program_point &src_point = src_enode.get_point ();
+      if (logger)
+	{
+	  logger->start_log_line ();
+	  src_point.print (logger->get_printer (), format (false));
+	  logger->end_log_line ();
+	}
+
+      if (const gimple *stmt = src_point.get_stmt ())
+	{
+	  /* Update cfun and input_location in case of ICE: make it easier to
+	     track down which source construct we're failing to handle.  */
+	  auto_cfun sentinel (src_point.get_function ());
+	  input_location = stmt->location;
+
+	  if (const gassign *assign = dyn_cast <const gassign *> (stmt))
+	    model.on_gassign (assign, NULL);
+	  else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
+	    model.on_greturn (return_, NULL);
+	}
+
+      const superedge *sedge = eedge->m_sedge;
+      if (sedge)
+	{
+	  if (logger)
+	    logger->log ("  sedge: SN:%i -> SN:%i %s",
+			 sedge->m_src->m_index,
+			 sedge->m_dest->m_index,
+			 sedge->get_description (false));
+
+	  const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
+	  if (!model.maybe_update_for_edge (*sedge, last_stmt, NULL))
+	    {
+	      if (logger)
+		{
+		  logger->log ("rejecting due to region model");
+		  model.dump_to_pp (logger->get_printer (), true, false);
+		}
+	      if (out)
+		{
+		  /* FIXME: ideally feasibility_problem should use a
+		     region_model2.  However, I don't think the model
+		     is used; it's for debugging.  */
+		  *out = new feasibility_problem (i, /*model, */ *eedge,
+						  last_stmt);
+		}
+	      return false;
+	    }
+	}
+      else
+	{
+	  /* Special-case the initial eedge from the origin node to the
+	     initial function by pushing a frame for it.  */
+	  if (i == 0)
+	    {
+	      gcc_assert (eedge->m_src->m_index == 0);
+	      gcc_assert (src_point.get_kind () == PK_ORIGIN);
+	      gcc_assert (eedge->m_dest->get_point ().get_kind ()
+			  == PK_BEFORE_SUPERNODE);
+	      function *fun = eedge->m_dest->get_function ();
+	      gcc_assert (fun);
+	      model.push_frame (fun, NULL, NULL);
+	      if (logger)
+		logger->log ("  pushing frame for %qD", fun->decl);
+	    }
+	  else if (eedge->m_custom_info)
+	    {
+	      eedge->m_custom_info->update_model2 (&model, *eedge);
+	    }
+	}
+
+      /* Handle phi nodes on an edge leaving a PK_BEFORE_SUPERNODE (to
+	 a PK_BEFORE_STMT, or a PK_AFTER_SUPERNODE if no stmts).
+	 This will typically not be associated with a superedge.  */
+      if (src_point.get_from_edge ())
+	{
+	  const cfg_superedge *last_cfg_superedge
+	    = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
+	  if (last_cfg_superedge)
+	    {
+	      if (logger)
+		logger->log ("  update for phis");
+	      model.update_for_phis (src_enode.get_supernode (),
+				     last_cfg_superedge,
+				     NULL);
+	    }
+	}
+
+      if (logger)
+	{
+	  logger->log ("state after edge %i: EN:%i -> EN:%i",
+		       i,
+		       eedge->m_src->m_index,
+		       eedge->m_dest->m_index);
+	  logger->start_log_line ();
+	  model.dump_to_pp (logger->get_printer (), true, false);
+	  logger->end_log_line ();
+	}
+    }
+
+  return true;
+}
+
 /* Dump this path in multiline form to PP.  */
 
 void
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 9540928beba..ad0101e825d 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -373,6 +373,8 @@ class exploded_edge : public dedge<eg_traits>
     /* Hook for updating MODEL within exploded_path::feasible_p.  */
     virtual void update_model (region_model *model,
 			       const exploded_edge &eedge) = 0;
+    virtual void update_model2 (region_model2 *model,
+				const exploded_edge &eedge) = 0;
 
     virtual void add_events_to_path (checker_path *emission_path,
 				     const exploded_edge &eedge) = 0;
@@ -422,6 +424,8 @@ public:
 
   void update_model (region_model *model,
 		     const exploded_edge &eedge) FINAL OVERRIDE;
+  void update_model2 (region_model2 *model,
+		      const exploded_edge &eedge) FINAL OVERRIDE;
 
   void add_events_to_path (checker_path *emission_path,
 			   const exploded_edge &eedge) FINAL OVERRIDE;
@@ -805,6 +809,7 @@ public:
 
   const supergraph &get_supergraph () const { return m_sg; }
   const extrinsic_state &get_ext_state () const { return m_ext_state; }
+  engine2 *get_engine2 () const { return m_ext_state.get_engine2 (); }
   const state_purge_map *get_purge_map () const { return m_purge_map; }
   const analysis_plan &get_analysis_plan () const { return m_plan; }
 
@@ -930,6 +935,8 @@ public:
   void dump () const;
 
   bool feasible_p (logger *logger, feasibility_problem **out) const;
+  bool feasible2_p (logger *logger, feasibility_problem **out,
+		    engine2 *eng) const;
 
   auto_vec<const exploded_edge *> m_edges;
 };
@@ -946,6 +953,15 @@ public:
   : m_eedge_idx (eedge_idx), m_model (model), m_eedge (eedge),
     m_last_stmt (last_stmt)
   {}
+  feasibility_problem (unsigned eedge_idx,
+		       const exploded_edge &eedge,
+		       const gimple *last_stmt)
+  : m_eedge_idx (eedge_idx), m_model (), m_eedge (eedge),
+    m_last_stmt (last_stmt)
+  {
+    /* FIXME: eventually remove this in favor of porting fully to
+       region_model2.  */
+  }
 
   unsigned m_eedge_idx;
   region_model m_model;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index fd034dd970a..d5c99f4f793 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -3310,43 +3310,23 @@ region_model2::~region_model2 ()
 }
 
 /* region_model2's assignment operator.  */
-#if 0
+
 region_model2 &
 region_model2::operator= (const region_model2 &other)
 {
-  unsigned i;
-  const svalue2 *svalue2;
-  region2 *region2;
-
-  /* Delete existing content.  */
-  FOR_EACH_VEC_ELT (m_svalue2s, i, svalue2)
-    delete svalue2;
-  m_svalue2s.truncate (0);
-
-  FOR_EACH_VEC_ELT (m_region2s, i, region2)
-    delete region2;
-  m_region2s.truncate (0);
-
-  delete m_constraints;
-
-  /* Clone the svalue2s and region2s.  */
-  m_svalue2s.reserve (other.m_svalue2s.length (), true);
-  FOR_EACH_VEC_ELT (other.m_svalue2s, i, svalue2)
-    m_svalue2s.quick_push (svalue2->clone ());
+  /* m_mgr is const.  */
+  gcc_assert (m_mgr == other.m_mgr);
 
-  m_region2s.reserve (other.m_region2s.length (), true);
-  FOR_EACH_VEC_ELT (other.m_region2s, i, region2)
-    m_region2s.quick_push (region2->clone ());
+  m_store = other.m_store;
 
-  m_root_reg = other.m_root_reg;
+  delete m_constraints2;
+  m_constraints2 = new constraint_manager2 (*other.m_constraints2);
 
-  m_constraints = other.m_constraints->clone (this);
+  m_current_frame = other.m_current_frame;
 
   return *this;
 }
 
-#endif
-
 /* Equality operator for region_model2.
 
    FIXME:
@@ -3730,8 +3710,7 @@ region_model2::validate () const
 /* FIXME.  */
 
 bool
-region_model2::on_stmt (const supernode *snode,
-			const gimple *stmt,
+region_model2::on_stmt (const gimple *stmt,
 			region_model2_context *ctxt)
 {
   switch (stmt->code)
@@ -3755,10 +3734,10 @@ region_model2::on_stmt (const supernode *snode,
       return true;
 
     case GIMPLE_ASSIGN:
-      return on_gassign (snode, as_a <const gassign *> (stmt), ctxt);
+      return on_gassign (as_a <const gassign *> (stmt), ctxt);
 
     case GIMPLE_RETURN:
-      return on_greturn (snode, as_a <const greturn *> (stmt), ctxt);
+      return on_greturn (as_a <const greturn *> (stmt), ctxt);
 
     default:
       sorry_at (stmt->location, "unhandled stmt: %qs",
@@ -3772,8 +3751,7 @@ region_model2::on_stmt (const supernode *snode,
    diagnostics.  */
 
 bool
-region_model2::on_gassign (const supernode */*snode*/,
-			   const gassign *assign,
+region_model2::on_gassign (const gassign *assign,
 			   region_model2_context *ctxt)
 {
   tree lhs = gimple_assign_lhs (assign);
@@ -4765,8 +4743,7 @@ region_model2::get_reachable_svalues (hash_set<const svalue2 *> *out)
    diagnostics.  */
 
 bool
-region_model2::on_greturn (const supernode */*snode*/,
-			   const greturn *return_stmt,
+region_model2::on_greturn (const greturn *return_stmt,
 			   region_model2_context *ctxt)
 {
   tree callee = get_current_function ()->decl;
@@ -6132,7 +6109,7 @@ region_model2::set_to_new_unknown_value (region2 *dst_reg, tree type,
 
 /* Update this model for any phis in SNODE, assuming we came from
    LAST_CFG_SUPEREDGE.  */
-#if 0
+
 void
 region_model2::update_for_phis (const supernode *snode,
 			       const cfg_superedge *last_cfg_superedge,
@@ -6153,7 +6130,7 @@ region_model2::update_for_phis (const supernode *snode,
       handle_phi (phi, lhs, src, is_back_edge, ctxt);
     }
 }
-#endif
+
 /* Attempt to update this model for taking EDGE (where the last statement
    was LAST_STMT), returning true if the edge can be taken, false
    otherwise.
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index fdf6d4ab765..f99779b0fbd 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1742,9 +1742,7 @@ class region_model2
   region_model2 (region_model2 &&other);
 #endif
 
-#if 0
   region_model2 &operator= (const region_model2 &other);
-#endif
 
   bool operator== (const region_model2 &other) const;
   bool operator!= (const region_model2 &other) const
@@ -1768,11 +1766,9 @@ class region_model2
 
   void validate () const;
 
-  bool on_stmt (const supernode *snode,
-		const gimple *stmt,
+  bool on_stmt (const gimple *stmt,
 		region_model2_context *ctxt);
-  bool on_gassign (const supernode *snode,
-		   const gassign *stmt,
+  bool on_gassign (const gassign *stmt,
 		   region_model2_context *ctxt);
 #if 0
   bool on_gcall (const supernode *snode,
@@ -1794,8 +1790,7 @@ class region_model2
   void handle_unrecognized_call (const gcall *call,
 				 region_model2_context *ctxt);
   void get_reachable_svalues (hash_set<const svalue2 *> *out);
-  bool on_greturn (const supernode *snode,
-		   const greturn *stmt,
+  bool on_greturn (const greturn *stmt,
 		   region_model2_context *ctxt);
   void on_setjmp (const gcall *stmt, const exploded_node *enode,
 		  region_model2_context *ctxt);
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index cc08353183d..269460172ec 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -175,11 +175,25 @@ static void
 update_model_for_signal_handler (region_model *model,
 				 function *handler_fun)
 {
+  gcc_assert (model);
   /* Purge all state within MODEL.  */
   *model = region_model ();
   model->push_frame (handler_fun, NULL, NULL);
 }
 
+/* Update MODEL for edges that simulate HANDLER_FUN being called as
+   an signal-handler in response to a signal.  */
+
+static void
+update_model2_for_signal_handler (region_model2 *model,
+				  function *handler_fun)
+{
+  gcc_assert (model);
+  /* Purge all state within MODEL.  */
+  *model = region_model2 (model->get_manager ());
+  model->push_frame (handler_fun, NULL, NULL);
+}
+
 /* Custom exploded_edge info: entry into a signal-handler.  */
 
 class signal_delivery_edge_info_t : public exploded_edge::custom_info_t
@@ -196,6 +210,12 @@ public:
     update_model_for_signal_handler (model, eedge.m_dest->get_function ());
   }
 
+  void update_model2 (region_model2 *model,
+		      const exploded_edge &eedge) FINAL OVERRIDE
+  {
+    update_model2_for_signal_handler (model, eedge.m_dest->get_function ());
+  }
+
   void add_events_to_path (checker_path *emission_path,
 			   const exploded_edge &eedge ATTRIBUTE_UNUSED)
     FINAL OVERRIDE
@@ -233,8 +253,12 @@ public:
 					    handler_fun);
 
     program_state state_entering_handler (eg->get_ext_state ());
-    update_model_for_signal_handler (state_entering_handler.m_region_model,
-				     handler_fun);
+    if (state_entering_handler.m_region_model)
+      update_model_for_signal_handler (state_entering_handler.m_region_model,
+				       handler_fun);
+    if (state_entering_handler.m_region_model2)
+      update_model2_for_signal_handler (state_entering_handler.m_region_model2,
+					handler_fun);
     state_entering_handler.m_checker_states[sm_idx]->set_global_state
       (m_sm.m_in_signal_handler);
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index f1eaced6e7e..6bc931b9ca3 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -695,10 +695,14 @@ store2_manager::get_symbolic_binding (const region2 *reg,
 
 /* class store2.  */
 
+/* FIXME.  */
+
 store2::store2 ()
 {
 }
 
+/* store2's copy ctor.  */
+
 store2::store2 (const store2 &other)
 {
   /* Deep copy.  TODO: replace with functional approach using immutable_map.  */
@@ -714,6 +718,8 @@ store2::store2 (const store2 &other)
     }
 }
 
+/* store2's dtor.  */
+
 store2::~store2 ()
 {
   for (cluster_map_t::iterator iter = m_cluster_map.begin ();
@@ -722,6 +728,32 @@ store2::~store2 ()
     delete (*iter).second;
 }
 
+/* store2's assignment operator.  */
+
+store2 &
+store2::operator= (const store2 &other)
+{
+  /* Delete existing cluster map.  */
+  for (cluster_map_t::iterator iter = m_cluster_map.begin ();
+       iter != m_cluster_map.end ();
+       ++iter)
+    delete (*iter).second;
+
+  /* Deep copy.  TODO: replace with functional approach using immutable_map.  */
+  for (cluster_map_t::iterator iter = other.m_cluster_map.begin ();
+       iter != other.m_cluster_map.end ();
+       ++iter)
+    {
+      const region2 *reg = (*iter).first;
+      gcc_assert (reg);
+      binding_cluster2 *c = (*iter).second;
+      gcc_assert (c);
+      m_cluster_map.put (reg, new binding_cluster2 (*c));
+    }
+}
+
+/* FIXME.  */
+
 bool
 store2::operator== (const store2 &other) const
 {
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 216f2da9254..361d198f9a8 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -280,6 +280,8 @@ public:
   store2 (const store2 &other);
   ~store2 ();
 
+  store2 &operator= (const store2 &other);
+
   bool operator== (const store2 &other) const;
   bool operator!= (const store2 &other) const
   {
-- 
2.26.2

