]> gcc.gnu.org Git - gcc.git/commitdiff
analyzer: factor out new class feasibility_state
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 10 Mar 2021 17:02:07 +0000 (12:02 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 10 Mar 2021 17:02:07 +0000 (12:02 -0500)
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.

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
gcc/analyzer/exploded-graph.h

index 5339ea39712928803c670c55241c73c4659ca3fb..fef482364c4ee1c591f3ca6929e704abf2277a8a 100644 (file)
@@ -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.
index 871cb78b73a38b93e05a26aaaea699508afa587a..da1cebb1aef857c5538efc387b9b8b30d7840476 100644 (file)
@@ -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;
This page took 0.074609 seconds and 5 git commands to generate.