From a12f59c170f1cb487e7c211c59dae1ba58b9782f Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 5 Nov 2019 18:25:14 -0500
Subject: [PATCH 113/119] FIXME: WIP towards fixing the O(n^2) in state purging

---
 gcc/analyzer/state-purge.cc | 145 +++++++++++++++++++++++++-------------------
 gcc/analyzer/state-purge.h  |  19 ++++--
 2 files changed, 97 insertions(+), 67 deletions(-)

diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 60bbdb9..cc96c25 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -53,10 +53,18 @@ state_purge_map::state_purge_map (const supergraph &sg,
     function *fun = node->get_fun ();
     if (logger)
       log ("function: %s", function_name (fun));
-    tree var;
+    //printf ("function: %s\n", function_name (fun));
+    tree name;
     unsigned int i;;
-    FOR_EACH_SSA_NAME (i, var, fun)
-      m_map.put (var, new state_purge_per_ssa_name (*this, var, fun));
+    FOR_EACH_SSA_NAME (i, name, fun)
+      {
+	/* For now, don't bother tracking the .MEM SSA names.  */
+	if (tree var = SSA_NAME_VAR (name))
+	  if (TREE_CODE (var) == VAR_DECL)
+	    if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
+	      continue;
+	m_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
+      }
   }
 }
 
@@ -78,18 +86,18 @@ state_purge_map::~state_purge_map ()
    just stmts since there could be empty basic blocks on the way.  */
 
 state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
-						    tree var,
+						    tree name,
 						    function *fun)
-: m_var (var)
+: m_points_needing_name (), m_name (name), m_fun (fun)
 {
   LOG_FUNC (map.get_logger ());
 
   if (map.get_logger ())
     {
-      map.log ("SSA name: %qE within %qD", var, fun->decl);
+      map.log ("SSA name: %qE within %qD", name, fun->decl);
 
       /* Show def stmt.  */
-      const gimple *def_stmt = SSA_NAME_DEF_STMT (var);
+      const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
       pretty_printer pp;
       pp_gimple_stmt_1 (&pp, def_stmt, 0, (dump_flags_t)0);
       map.log ("def stmt: %s", pp_formatted_text (&pp));
@@ -97,11 +105,11 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 
   auto_vec<function_point> worklist;
 
-  /* Add all immediate uses of var to the worklist.
+  /* Add all immediate uses of name to the worklist.
      Compare with debug_immediate_uses.  */
   imm_use_iterator iter;
   use_operand_p use_p;
-  FOR_EACH_IMM_USE_FAST (use_p, iter, var)
+  FOR_EACH_IMM_USE_FAST (use_p, iter, name)
     {
       if (USE_STMT (use_p))
 	{
@@ -127,12 +135,12 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 		  gphi *phi = gpi.phi ();
 		  if (phi == use_stmt)
 		    {
-		      /* Find arguments (and thus in-edges) which use VAR.  */
+		      /* Find arguments (and thus in-edges) which use NAME.  */
 		      for (unsigned arg_idx = 0;
 			   arg_idx < gimple_phi_num_args (phi);
 			   ++arg_idx)
 			{
-			  if (var == gimple_phi_arg (phi, arg_idx)->def)
+			  if (name == gimple_phi_arg (phi, arg_idx)->def)
 			    {
 			      edge in_edge = gimple_phi_arg_edge (phi, arg_idx);
 			      const superedge *in_sedge
@@ -142,7 +150,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 				(snode, in_sedge);
 			      add_to_worklist (point, &worklist,
 					       map.get_logger ());
-			      m_points_needing_var.add (point);
+			      m_points_needing_name.add (point);
 			    }
 			}
 		    }
@@ -152,7 +160,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 	    {
 	      function_point point = before_use_stmt (map, use_stmt);
 	      add_to_worklist (point, &worklist, map.get_logger ());
-	      m_points_needing_var.add (point);
+	      m_points_needing_name.add (point);
 
 	      /* We also need to add uses for conditionals and switches,
 		 where the stmt "happens" at the after_supernode, for filtering
@@ -164,7 +172,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 		  function_point point
 		    = function_point::after_supernode (snode);
 		  add_to_worklist (point, &worklist, map.get_logger ());
-		  m_points_needing_var.add (point);
+		  m_points_needing_name.add (point);
 		}
 	      else
 		if (map.get_logger ())
@@ -185,9 +193,9 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 
   if (map.get_logger ())
     {
-      map.log ("%qE in %qD is needed to process:", var, fun->decl);
-      for (point_set_t::iterator iter = m_points_needing_var.begin ();
-	   iter != m_points_needing_var.end ();
+      map.log ("%qE in %qD is needed to process:", name, fun->decl);
+      for (point_set_t::iterator iter = m_points_needing_name.begin ();
+	   iter != m_points_needing_name.end ();
 	   ++iter)
 	{
 	  map.start_log_line ();
@@ -203,7 +211,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
 bool
 state_purge_per_ssa_name::needed_at_point_p (const function_point &point) const
 {
-  return const_cast <point_set_t &> (m_points_needing_var).contains (point);
+  return const_cast <point_set_t &> (m_points_needing_name).contains (point);
 }
 
 /* Get the function_point representing immediately before USE_STMT.
@@ -235,19 +243,26 @@ state_purge_per_ssa_name::add_to_worklist (const function_point &point,
       logger->start_log_line ();
       logger->log_partial ("point: '");
       point.print (logger->get_printer (), format (false));
-      logger->log_partial ("' for worklist for %qE", m_var);
+      logger->log_partial ("' for worklist for %qE", m_name);
       logger->end_log_line ();
     }
 
-  if (m_points_needing_var.contains (point))
+#if 0
+  gcc_assert (point.get_function () == m_fun);
+  if (point.get_from_edge ())
+    gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
+#endif
+
+  if (m_points_needing_name.contains (point))
     {
       if (logger)
-	logger->log ("already seen for %qE", m_var);
+	logger->log ("already seen for %qE", m_name);
     }
   else
     {
       if (logger)
-	logger->log ("not seen; adding to worklist for %qE", m_var);
+	logger->log ("not seen; adding to worklist for %qE", m_name);
+      m_points_needing_name.add (point);
       worklist->safe_push (point);
     }
 }
@@ -266,13 +281,11 @@ state_purge_per_ssa_name::process_point (const function_point &point,
       logger->start_log_line ();
       logger->log_partial ("considering point: '");
       point.print (logger->get_printer (), format (false));
-      logger->log_partial ("' for %qE", m_var);
+      logger->log_partial ("' for %qE", m_name);
       logger->end_log_line ();
     }
 
-  gimple *def_stmt = SSA_NAME_DEF_STMT (m_var);
-
-  m_points_needing_var.add (point);
+  gimple *def_stmt = SSA_NAME_DEF_STMT (m_name);
 
   const supernode *snode = point.get_supernode ();
 
@@ -374,6 +387,8 @@ state_purge_per_ssa_name::process_point (const function_point &point,
 
 /* class state_purge_annotator  : public dot_annotator.  */
 
+/* FIXME.  */
+
 void
 state_purge_annotator::add_node_annotations (pretty_printer *pp,
 					     const supernode &n) const
@@ -394,14 +409,17 @@ state_purge_annotator::add_node_annotations (pretty_printer *pp,
 	iter != m_map->end ();
 	++iter)
      {
-       tree var = (*iter).first;
-       state_purge_per_ssa_name *per_var_data = (*iter).second;
+       tree name = (*iter).first;
+       state_purge_per_ssa_name *per_name_data = (*iter).second;
+       if (per_name_data->get_function () == n.m_fun)
+	 {
 PUSH_IGNORE_WFORMAT
-       if (per_var_data->needed_at_point_p (before_supernode))
-	 pp_printf (pp, "%qE needed here", var);
-       else
-	 pp_printf (pp, "%qE not needed here", var);
+	   if (per_name_data->needed_at_point_p (before_supernode))
+	     pp_printf (pp, "%qE needed here", name);
+	   else
+	     pp_printf (pp, "%qE not needed here", name);
 POP_IGNORE_WFORMAT
+	 }
        pp_newline (pp);
      }
 
@@ -411,6 +429,29 @@ POP_IGNORE_WFORMAT
    pp_flush (pp);
 }
 
+/* FIXME.  */
+
+static void
+print_vec_of_names (pretty_printer *pp, const char *title,
+		    const auto_vec<tree> &v)
+{
+  tree name;
+  unsigned i;
+  pp_printf (pp, "%s: {", title);
+  FOR_EACH_VEC_ELT (v, i, name)
+    {
+      if (i > 0)
+	pp_string (pp, ", ");
+PUSH_IGNORE_WFORMAT
+      pp_printf (pp, "%qE", name);
+POP_IGNORE_WFORMAT
+    }
+  pp_printf (pp, "}");
+  pp_newline (pp);
+}
+
+/* FIXME.  */
+
 void
 state_purge_annotator::add_stmt_annotations (pretty_printer *pp,
 					     const gimple *stmt) const
@@ -434,35 +475,17 @@ state_purge_annotator::add_stmt_annotations (pretty_printer *pp,
        iter != m_map->end ();
        ++iter)
     {
-      tree var = (*iter).first;
-      state_purge_per_ssa_name *per_var_data = (*iter).second;
-      if (per_var_data->needed_at_point_p (before_stmt))
-	needed.safe_push (var);
-      else
-	not_needed.safe_push (var);
+      tree name = (*iter).first;
+      state_purge_per_ssa_name *per_name_data = (*iter).second;
+      if (per_name_data->get_function () == supernode->m_fun)
+	{
+	  if (per_name_data->needed_at_point_p (before_stmt))
+	    needed.safe_push (name);
+	  else
+	    not_needed.safe_push (name);
+	}
     }
 
-  tree var;
-  unsigned i;
-  pp_printf (pp, "needed here: {");
-  FOR_EACH_VEC_ELT (needed, i, var)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-PUSH_IGNORE_WFORMAT
-      pp_printf (pp, "%qE", var);
-POP_IGNORE_WFORMAT
-    }
-  pp_printf (pp, "}");
-  pp_newline (pp);
-  pp_printf (pp, "not needed here: {");
-  FOR_EACH_VEC_ELT (not_needed, i, var)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-PUSH_IGNORE_WFORMAT
-      pp_printf (pp, "%qE", var);
-POP_IGNORE_WFORMAT
-    }
-  pp_newline (pp);
+  print_vec_of_names (pp, "needed here", needed);
+  print_vec_of_names (pp, "not needed here", not_needed);
 }
diff --git a/gcc/analyzer/state-purge.h b/gcc/analyzer/state-purge.h
index bec7003..a1d73d1 100644
--- a/gcc/analyzer/state-purge.h
+++ b/gcc/analyzer/state-purge.h
@@ -87,11 +87,15 @@ public:
   state_purge_map (const supergraph &sg, logger *logger);
   ~state_purge_map ();
 
-  const state_purge_per_ssa_name &get_data_for_ssa_name (tree var) const
+  const state_purge_per_ssa_name &get_data_for_ssa_name (tree name) const
   {
-    gcc_assert (TREE_CODE (var) == SSA_NAME);
+    gcc_assert (TREE_CODE (name) == SSA_NAME);
+    if (tree var = SSA_NAME_VAR (name))
+      if (TREE_CODE (var) == VAR_DECL)
+	gcc_assert (!VAR_DECL_IS_VIRTUAL_OPERAND (var));
+
     state_purge_per_ssa_name **slot
-      = const_cast <map_t&> (m_map).get (var);
+      = const_cast <map_t&> (m_map).get (name);
     return **slot;
   }
 
@@ -118,11 +122,13 @@ class state_purge_per_ssa_name
 {
 public:
   state_purge_per_ssa_name (const state_purge_map &map,
-			    tree var,
+			    tree name,
 			    function *fun);
 
   bool needed_at_point_p (const function_point &point) const;
 
+  function *get_function () const { return m_fun; }
+
 private:
   static function_point before_use_stmt (const state_purge_map &map,
 					 const gimple *use_stmt);
@@ -136,8 +142,9 @@ private:
 		      logger *logger);
 
   typedef hash_set<function_point> point_set_t;
-  point_set_t m_points_needing_var;
-  tree m_var;
+  point_set_t m_points_needing_name;
+  tree m_name;
+  function *m_fun;
 };
 
 ////////////////////////////////////////////////////////////////////////////
-- 
1.8.5.3

