public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] analyzer: factor out new class feasibility_state
@ 2021-03-10 17:04 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2021-03-10 17:04 UTC (permalink / raw)
  To: gcc-patches

As preparatory work for a fix to PR analyzer/96374, this patch
moves the core state-update logic from the loop in
exploded_path::feasible_p into a new class feasibility_state.

No functional change intended.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r11-7609-g44fd4dc0b684e06c6c6d08b3994df23135bf2fbc.

gcc/analyzer/ChangeLog:
	PR analyzer/96374
	* engine.cc (exploded_path::feasible_p): Move "snodes_visited" and
	"model" locals into a new class feasibility_state.  Move heart
	of per-edge processing into
	feasibility_state::maybe_update_for_edge.
	(feasibility_state::feasibility_state): New.
	(feasibility_state::maybe_update_for_edge): New, based on loop
	body in exploded_path::feasible_p.
	* exploded-graph.h (class feasibility_state): New.
---
 gcc/analyzer/engine.cc        | 251 ++++++++++++++++++++--------------
 gcc/analyzer/exploded-graph.h |  22 +++
 2 files changed, 172 insertions(+), 101 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 5339ea39712..fef482364c4 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -3404,11 +3404,10 @@ exploded_path::feasible_p (logger *logger, feasibility_problem **out,
 {
   LOG_SCOPE (logger);
 
-  auto_sbitmap snodes_visited (eg->get_supergraph ().m_nodes.length ());
-  bitmap_clear (snodes_visited);
+  feasibility_state state (eng->get_model_manager (),
+			   eg->get_supergraph ());
 
-  /* Traverse the path, updating this model.  */
-  region_model model (eng->get_model_manager ());
+  /* Traverse the path, updating this state.  */
   for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)
     {
       const exploded_edge *eedge = m_edges[edge_idx];
@@ -3417,106 +3416,23 @@ exploded_path::feasible_p (logger *logger, feasibility_problem **out,
 		     edge_idx,
 		     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 ();
-	}
-
-      /* Update state for the stmts that were processed in each enode.  */
-      for (unsigned stmt_idx = 0; stmt_idx < src_enode.m_num_processed_stmts;
-	   stmt_idx++)
-	{
-	  const gimple *stmt = src_enode.get_processed_stmt (stmt_idx);
-
-	  /* 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_assignment (assign, NULL);
-	  else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
-	    model.on_return (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 ();
-	  rejected_constraint *rc = NULL;
-	  if (!model.maybe_update_for_edge (*sedge, last_stmt, NULL, &rc))
-	    {
-	      if (logger)
-		{
-		  logger->log ("rejecting due to region model");
-		  model.dump_to_pp (logger->get_printer (), true, false);
-		}
-	      if (out)
-		*out = new feasibility_problem (edge_idx, *eedge,
-						last_stmt, rc);
-	      else
-		delete rc;
-	      return false;
-	    }
-	}
-      else
-	{
-	  /* Special-case the initial eedge from the origin node to the
-	     initial function by pushing a frame for it.  */
-	  if (edge_idx == 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_model (&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 ())
+      rejected_constraint *rc = NULL;
+      if (!state.maybe_update_for_edge (logger, eedge, &rc))
 	{
-	  const cfg_superedge *last_cfg_superedge
-	    = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
-	  const exploded_node &dst_enode = *eedge->m_dest;
-	  const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_index;
-	  if (last_cfg_superedge)
+	  gcc_assert (rc);
+	  if (out)
 	    {
-	      if (logger)
-		logger->log ("  update for phis");
-	      model.update_for_phis (src_enode.get_supernode (),
-				     last_cfg_superedge,
-				     NULL);
-	      /* If we've entering an snode that we've already visited on this
-		 epath, then we need do fix things up for loops; see the
-		 comment for store::loop_replay_fixup.
-		 Perhaps we should probably also verify the callstring,
-		 and track program_points,  but hopefully doing it by supernode
-		 is good enough.  */
-	      if (bitmap_bit_p (snodes_visited, dst_snode_idx))
-		model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
+	      const exploded_node &src_enode = *eedge->m_src;
+	      const program_point &src_point = src_enode.get_point ();
+	      const gimple *last_stmt
+		= src_point.get_supernode ()->get_last_stmt ();
+	      *out = new feasibility_problem (edge_idx, *eedge,
+					      last_stmt, rc);
 	    }
-	  bitmap_set_bit (snodes_visited, dst_snode_idx);
+	  else
+	    delete rc;
+	  return false;
 	}
 
       if (logger)
@@ -3526,7 +3442,7 @@ exploded_path::feasible_p (logger *logger, feasibility_problem **out,
 		       eedge->m_src->m_index,
 		       eedge->m_dest->m_index);
 	  logger->start_log_line ();
-	  model.dump_to_pp (logger->get_printer (), true, false);
+	  state.get_model ().dump_to_pp (logger->get_printer (), true, false);
 	  logger->end_log_line ();
 	}
     }
@@ -3587,6 +3503,139 @@ feasibility_problem::dump_to_pp (pretty_printer *pp) const
     }
 }
 
+/* class feasibility_state.  */
+
+/* Ctor for feasibility_state, at the beginning of a path.  */
+
+feasibility_state::feasibility_state (region_model_manager *manager,
+				      const supergraph &sg)
+: m_model (manager),
+  m_snodes_visited (sg.m_nodes.length ())
+{
+  bitmap_clear (m_snodes_visited);
+}
+
+/* Copy ctor for feasibility_state, for extending a path.  */
+
+feasibility_state::feasibility_state (const feasibility_state &other)
+: m_model (other.m_model),
+  m_snodes_visited (const_sbitmap (other.m_snodes_visited)->n_bits)
+{
+  bitmap_copy (m_snodes_visited, other.m_snodes_visited);
+}
+
+/* The heart of feasibility-checking.
+
+   Attempt to update this state in-place based on traversing EEDGE
+   in a path.
+   Update the model for the stmts in the src enode.
+   Attempt to add constraints for EEDGE.
+
+   If feasible, return true.
+   Otherwise, return false and write to *OUT_RC.  */
+
+bool
+feasibility_state::maybe_update_for_edge (logger *logger,
+					  const exploded_edge *eedge,
+					  rejected_constraint **out_rc)
+{
+  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 ();
+    }
+
+  /* Update state for the stmts that were processed in each enode.  */
+  for (unsigned stmt_idx = 0; stmt_idx < src_enode.m_num_processed_stmts;
+       stmt_idx++)
+    {
+      const gimple *stmt = src_enode.get_processed_stmt (stmt_idx);
+
+      /* 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))
+	m_model.on_assignment (assign, NULL);
+      else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
+	m_model.on_return (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 (!m_model.maybe_update_for_edge (*sedge, last_stmt, NULL, out_rc))
+	{
+	  if (logger)
+	    {
+	      logger->log ("rejecting due to region model");
+	      m_model.dump_to_pp (logger->get_printer (), true, false);
+	    }
+	  return false;
+	}
+    }
+  else
+    {
+      /* Special-case the initial eedge from the origin node to the
+	 initial function by pushing a frame for it.  */
+      if (src_point.get_kind () == PK_ORIGIN)
+	{
+	  gcc_assert (eedge->m_src->m_index == 0);
+	  gcc_assert (eedge->m_dest->get_point ().get_kind ()
+		      == PK_BEFORE_SUPERNODE);
+	  function *fun = eedge->m_dest->get_function ();
+	  gcc_assert (fun);
+	  m_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_model (&m_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 ();
+      const exploded_node &dst_enode = *eedge->m_dest;
+      const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_index;
+      if (last_cfg_superedge)
+	{
+	  if (logger)
+	    logger->log ("  update for phis");
+	  m_model.update_for_phis (src_enode.get_supernode (),
+				  last_cfg_superedge,
+				  NULL);
+	  /* If we've entering an snode that we've already visited on this
+	     epath, then we need do fix things up for loops; see the
+	     comment for store::loop_replay_fixup.
+	     Perhaps we should probably also verify the callstring,
+	     and track program_points,  but hopefully doing it by supernode
+	     is good enough.  */
+	  if (bitmap_bit_p (m_snodes_visited, dst_snode_idx))
+	    m_model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
+	}
+      bitmap_set_bit (m_snodes_visited, dst_snode_idx);
+    }
+  return true;
+}
+
 /* A family of cluster subclasses for use when generating .dot output for
    exploded graphs (-fdump-analyzer-exploded-graph), for grouping the
    enodes into hierarchical boxes.
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 871cb78b73a..da1cebb1aef 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -906,6 +906,28 @@ public:
   rejected_constraint *m_rc;
 };
 
+/* A class for capturing the state of a node when checking a path
+   through the exploded_graph for feasibility.  */
+
+class feasibility_state
+{
+public:
+  feasibility_state (region_model_manager *manager,
+		     const supergraph &sg);
+  feasibility_state (const feasibility_state &other);
+
+  bool maybe_update_for_edge (logger *logger,
+			      const exploded_edge *eedge,
+			      rejected_constraint **out_rc);
+
+  const region_model &get_model () const { return m_model; }
+  const auto_sbitmap &get_snodes_visited () const { return m_snodes_visited; }
+
+private:
+  region_model m_model;
+  auto_sbitmap m_snodes_visited;
+};
+
 /* Finding the shortest exploded_path within an exploded_graph.  */
 
 typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;
-- 
2.26.2


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-03-10 17:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-10 17:04 [committed] analyzer: factor out new class feasibility_state David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).