public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/arsenic/heads/analyzer_extension)] fix state-purgeing
@ 2021-07-13 13:45 Ankur saini
  0 siblings, 0 replies; only message in thread
From: Ankur saini @ 2021-07-13 13:45 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c87865d97ce664249de990ad948d2b420c948713

commit c87865d97ce664249de990ad948d2b420c948713
Author: Ankur Saini <arsenic@sourceware.org>
Date:   Sat Jul 10 19:28:49 2021 +0530

    fix state-purgeing

Diff:
---
 gcc/analyzer/call-string.cc                    |  85 ++-
 gcc/analyzer/call-string.h                     |  18 +-
 gcc/analyzer/program-point.cc                  |   8 +-
 gcc/analyzer/state-purge.cc                    | 794 ++++++++++++-------------
 gcc/testsuite/gcc.dg/analyzer/call-via-fnptr.c |  20 +
 5 files changed, 438 insertions(+), 487 deletions(-)

diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc
index 55263b26748..c94963eec58 100644
--- a/gcc/analyzer/call-string.cc
+++ b/gcc/analyzer/call-string.cc
@@ -48,10 +48,10 @@ along with GCC; see the file COPYING3.  If not see
 /* call_string's copy ctor.  */
 
 call_string::call_string (const call_string &other)
-: m_supernodes (other.m_supernodes.length ())
+: m_elements (other.m_elements.length ())
 {
-  for (const std::pair<const supernode *,const supernode *> *e : other.m_supernodes)
-    m_supernodes.quick_push (e);
+  for (const element_t &e : other.m_elements)
+    m_elements.quick_push (e);
 }
 
 /* call_string's assignment operator.  */
@@ -60,12 +60,12 @@ call_string&
 call_string::operator= (const call_string &other)
 {
   // would be much simpler if we could rely on vec<> assignment op
-  m_supernodes.truncate (0);
-  m_supernodes.reserve (other.m_supernodes.length (), true);
-  const std::pair<const supernode *,const supernode *> *e;
+  m_elements.truncate (0);
+  m_elements.reserve (other.m_elements.length (), true);
+  element_t *e;
   int i;
-  FOR_EACH_VEC_ELT (other.m_supernodes, i, e)
-    m_supernodes.quick_push (e);
+  FOR_EACH_VEC_ELT (other.m_elements, i, e)
+    m_elements.quick_push (*e);
   return *this;
 }
 
@@ -74,12 +74,12 @@ call_string::operator= (const call_string &other)
 bool
 call_string::operator== (const call_string &other) const
 {
-  if (m_supernodes.length () != other.m_supernodes.length ())
+  if (m_elements.length () != other.m_elements.length ())
     return false;
-  const std::pair<const supernode *,const supernode *> *e;
+  element_t *e;
   int i;
-  FOR_EACH_VEC_ELT (m_supernodes, i, e)
-    if (e != other.m_supernodes[i])
+  FOR_EACH_VEC_ELT (m_elements, i, e)
+    if (*e != other.m_elements[i])
       return false;
   return true;
 }
@@ -91,9 +91,9 @@ call_string::print (pretty_printer *pp) const
 {
   pp_string (pp, "[");
 
-  const std::pair<const supernode *,const supernode *> *e;
+  element_t *e;
   int i;
-  FOR_EACH_VEC_ELT (m_supernodes, i, e)
+  FOR_EACH_VEC_ELT (m_elements, i, e)
     {
       if (i > 0)
 	pp_string (pp, ", ");
@@ -116,15 +116,15 @@ call_string::to_json () const
 {
   json::array *arr = new json::array ();
 
-  for (const std::pair<const supernode *,const supernode *> *e : m_supernodes)
+  for (const element_t &e : m_elements)
     {
       json::object *e_obj = new json::object ();
       e_obj->set ("src_snode_idx",
-		  new json::integer_number (e->first->m_index));
+		  new json::integer_number (e.first->m_index));
       e_obj->set ("dst_snode_idx",
-		  new json::integer_number (e->second->m_index));
+		  new json::integer_number (e.second->m_index));
       e_obj->set ("funcname",
-		  new json::string (function_name (e->second->m_fun)));
+		  new json::string (function_name (e.second->m_fun)));
       arr->append (e_obj);
     }
 
@@ -137,8 +137,8 @@ hashval_t
 call_string::hash () const
 {
   inchash::hash hstate;
-  for (const std::pair<const supernode *,const supernode *> *e : m_supernodes)
-    hstate.add_ptr (e);
+  for (const element_t &e : m_elements)
+    hstate.add_ptr (e.second);
   return hstate.end ();
 }
 
@@ -152,26 +152,22 @@ call_string::push_call (const supergraph &sg,
   gcc_assert (call_sedge);
   const return_superedge *return_sedge = call_sedge->get_edge_for_return (sg);
   gcc_assert (return_sedge);
-  const std::pair<const supernode *,const supernode *> *e = new (std::pair<const supernode *,const supernode *>)
-    { return_sedge->m_src,
-      return_sedge->m_dest};
-  m_supernodes.safe_push (e);
+  element_t e = { return_sedge->m_src, return_sedge->m_dest };
+  m_elements.safe_push (e);
 }
 
 void
 call_string::push_call (const supernode *caller,
       const supernode *callee)
 {
-  const std::pair<const supernode *,const supernode *> *e = new (std::pair<const supernode *,const supernode *>)
-    { callee,
-      caller};
-  m_supernodes.safe_push (e);
+  element_t e = { callee, caller };
+  m_elements.safe_push (e);
 }
 
-const std::pair<const supernode *,const supernode *>
+element_t
 call_string::pop ()
 {
-  return *m_supernodes.pop();
+  return m_elements.pop();
 }
 
 /* Count the number of times the top-most call site appears in the
@@ -179,13 +175,12 @@ call_string::pop ()
 int
 call_string::calc_recursion_depth () const
 {
-  if (m_supernodes.is_empty ())
+  if (m_elements.is_empty ())
     return 0;
-  const std::pair<const supernode *,const supernode *> *top_return_sedge
-    = m_supernodes[m_supernodes.length () - 1];
+  const element_t top_return_sedge = m_elements[m_elements.length () - 1];
 
   int result = 0;
-  for (const std::pair<const supernode *,const supernode *> *e : m_supernodes)
+  for (const element_t &e : m_elements)
     if (e == top_return_sedge)
       ++result;
   return result;
@@ -220,12 +215,12 @@ call_string::cmp (const call_string &a,
 	return -1;
 
       /* Otherwise, compare the node pairs.  */
-      const std::pair<const supernode *,const supernode *> *a_node_pair = a[i];
-      const std::pair<const supernode *,const supernode *> *b_node_pair = b[i];
-      int src_cmp = a_node_pair->first->m_index - b_node_pair->first->m_index;
+      const element_t a_node_pair = a[i];
+      const element_t b_node_pair = b[i];
+      int src_cmp = a_node_pair.first->m_index - b_node_pair.first->m_index;
       if (src_cmp)
 	return src_cmp;
-      int dest_cmp = a_node_pair->second->m_index - b_node_pair->second->m_index;
+      int dest_cmp = a_node_pair.second->m_index - b_node_pair.second->m_index;
       if (dest_cmp)
 	return dest_cmp;
       i++;
@@ -237,18 +232,18 @@ call_string::cmp (const call_string &a,
 const supernode *
 call_string::get_callee_node() const
 {
-  if(m_supernodes.is_empty())
+  if(m_elements.is_empty())
     return NULL;
-  return m_supernodes[m_supernodes.length() - 1]->first;
+  return m_elements[m_elements.length() - 1].first;
 }
 
 /* return the pointer to caller of the topmost call in the stack, or NULL if stack is empty */
 const supernode * 
 call_string::get_caller_node() const
 {
-  if(m_supernodes.is_empty())
+  if(m_elements.is_empty())
     return NULL;
-  return m_supernodes[m_supernodes.length() - 1]->second;
+  return m_elements[m_elements.length() - 1].second;
 }
 
 /* Assert that this object is sane.  */
@@ -262,12 +257,12 @@ call_string::validate () const
 #endif
 
   /* Each entry's "caller" should be the "callee" of the previous entry.  */
-  const std::pair<const supernode *,const supernode *> *e;
+  element_t *e;
   int i;
-  FOR_EACH_VEC_ELT (m_supernodes, i, e)
+  FOR_EACH_VEC_ELT (m_elements, i, e)
     if (i > 0)
     {
-      gcc_assert (e->second->get_function () == m_supernodes[i - 1]->first->get_function());
+      gcc_assert (e->second->get_function () == m_elements[i - 1].first->get_function());
     }
 }
 
diff --git a/gcc/analyzer/call-string.h b/gcc/analyzer/call-string.h
index afd3b88b672..ccf544d2d4c 100644
--- a/gcc/analyzer/call-string.h
+++ b/gcc/analyzer/call-string.h
@@ -28,6 +28,8 @@ class supernode;
 class call_superedge;
 class return_superedge;
 
+ typedef std::pair<const supernode *,const supernode *> element_t;
+
 /* A string of return_superedge pointers, representing a call stack
    at a program point.
 
@@ -40,7 +42,7 @@ class return_superedge;
 class call_string
 {
 public:
-  call_string () : m_supernodes () {}
+  call_string () : m_elements () {}
   call_string (const call_string &other);
   call_string& operator= (const call_string &other);
 
@@ -52,7 +54,7 @@ public:
 
   hashval_t hash () const;
 
-  bool empty_p () const { return m_supernodes.is_empty (); }
+  bool empty_p () const { return m_elements.is_empty (); }
 
   void push_call (const supergraph &sg,
 		  const call_superedge *sedge);
@@ -60,7 +62,7 @@ public:
   void push_call (const supernode *src, 
     const supernode *dest);
 
-  const std::pair<const supernode *,const supernode *> pop ();
+  element_t pop ();
 
   int calc_recursion_depth () const;
 
@@ -71,17 +73,17 @@ public:
 
   const supernode * get_callee_node() const;
   const supernode * get_caller_node() const;
-  unsigned length () const { return m_supernodes.length (); }
-  const std::pair<const supernode *,const supernode *> *operator[] (unsigned idx) const
+
+  unsigned length () const { return m_elements.length (); }
+  element_t operator[] (unsigned idx) const
   {
-    return m_supernodes[idx];
+    return m_elements[idx];
   }
 
   void validate () const;
 
 private:
-  //auto_vec<const return_superedge *> m_return_edges;
-  auto_vec<const std::pair<const supernode *,const supernode *>*> m_supernodes;
+  auto_vec<element_t> m_elements;
 };
 
 } // namespace ana
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 9e6310435c8..1943d7f8c66 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -360,7 +360,7 @@ program_point::get_function_at_depth (unsigned depth) const
   if (depth == m_call_string.length ())
     return m_function_point.get_function ();
   else
-    return m_call_string[depth]->second->get_function ();
+    return m_call_string[depth].second->get_function ();
 }
 
 /* Assert that this object is sane.  */
@@ -377,7 +377,7 @@ program_point::validate () const
   /* The "callee" of the final entry in the callstring should be the
      function of the m_function_point.  */
   if (m_call_string.length () > 0)
-    gcc_assert (m_call_string[m_call_string.length () - 1]->first->get_function ()
+    gcc_assert (m_call_string[m_call_string.length () - 1].first->get_function ()
 		== get_function ());
 }
 
@@ -448,8 +448,8 @@ program_point::on_edge (exploded_graph &eg,
 	      logger->log ("rejecting return edge: empty call string");
 	    return false;
 	  }
-	const std::pair<const supernode *,const supernode *> top_of_stack = m_call_string.pop ();
-  std::pair<const supernode *,const supernode *> current_sedge_node_pair (succ->m_src,succ->m_dest);
+	const element_t top_of_stack = m_call_string.pop ();
+  element_t current_sedge_node_pair (succ->m_src,succ->m_dest);
 	if (top_of_stack != current_sedge_node_pair)
 	  {
 	    if (logger)
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 70a09ed581f..3c19ab0031e 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -18,77 +18,72 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#include "analyzer/state-purge.h"
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/call-string.h"
+#include "analyzer/program-point.h"
+#include "analyzer/supergraph.h"
+#include "basic-block.h"
+#include "cfg.h"
+#include "cgraph.h"
 #include "config.h"
-#include "system.h"
 #include "coretypes.h"
-#include "tree.h"
-#include "timevar.h"
-#include "tree-ssa-alias.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "stringpool.h"
-#include "tree-vrp.h"
-#include "gimple-ssa.h"
-#include "tree-ssanames.h"
-#include "tree-phinodes.h"
-#include "options.h"
-#include "ssa-iterators.h"
 #include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
+#include "digraph.h"
 #include "function.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "gimple-ssa.h"
+#include "gimple.h"
 #include "json.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/call-string.h"
-#include "digraph.h"
+#include "options.h"
 #include "ordered-hash-map.h"
-#include "cfg.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "analyzer/supergraph.h"
-#include "analyzer/program-point.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/state-purge.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "system.h"
+#include "timevar.h"
+#include "tree-phinodes.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "tree-vrp.h"
+#include "tree.h"
 
 #if ENABLE_ANALYZER
 
 /* state_purge_map's ctor.  Walk all SSA names in all functions, building
    a state_purge_per_ssa_name instance for each.  */
 
-state_purge_map::state_purge_map (const supergraph &sg,
-				  logger *logger)
-: log_user (logger), m_sg (sg)
-{
-  LOG_FUNC (logger);
-
-  auto_timevar tv (TV_ANALYZER_STATE_PURGE);
-
-  cgraph_node *node;
-  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
-  {
-    function *fun = node->get_fun ();
-    if (logger)
-      log ("function: %s", function_name (fun));
-    tree name;
-    unsigned int i;;
-    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));
-      }
-  }
+state_purge_map::state_purge_map(const supergraph &sg, logger *logger)
+    : log_user(logger), m_sg(sg) {
+    LOG_FUNC(logger);
+
+    auto_timevar tv(TV_ANALYZER_STATE_PURGE);
+
+    cgraph_node *node;
+    FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) {
+        function *fun = node->get_fun();
+        if (logger)
+            log("function: %s", function_name(fun));
+        tree name;
+        unsigned int i;
+        ;
+        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));
+        }
+    }
 }
 
 /* state_purge_map's dtor.  */
 
-state_purge_map::~state_purge_map ()
-{
-  for (iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
-    delete (*iter).second;
+state_purge_map::~state_purge_map() {
+    for (iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
+        delete (*iter).second;
 }
 
 /* state_purge_per_ssa_name's ctor.
@@ -100,323 +95,276 @@ state_purge_map::~state_purge_map ()
    We have to track program points rather than
    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 name,
-						    function *fun)
-: m_points_needing_name (), m_name (name), m_fun (fun)
-{
-  LOG_FUNC (map.get_logger ());
+state_purge_per_ssa_name::state_purge_per_ssa_name(const state_purge_map &map,
+                                                   tree name, function *fun)
+    : 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", name, fun->decl);
+    if (map.get_logger()) {
+        map.log("SSA name: %qE within %qD", name, fun->decl);
 
-      /* Show def stmt.  */
-      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));
+        /* Show def stmt.  */
+        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));
     }
 
-  auto_vec<function_point> worklist;
+    auto_vec<function_point> 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, name) {
+        if (USE_STMT(use_p)) {
+            const gimple *use_stmt = USE_STMT(use_p);
+            if (map.get_logger()) {
+                pretty_printer pp;
+                pp_gimple_stmt_1(&pp, use_stmt, 0, (dump_flags_t)0);
+                map.log("used by stmt: %s", pp_formatted_text(&pp));
+            }
+
+            const supernode *snode =
+                map.get_sg().get_supernode_for_stmt(use_stmt);
+
+            /* If it's a use within a phi node, then we care about
+               which in-edge we came from.  */
+            if (use_stmt->code == GIMPLE_PHI) {
+                for (gphi_iterator gpi =
+                         const_cast<supernode *>(snode)->start_phis();
+                     !gsi_end_p(gpi); gsi_next(&gpi)) {
+                    gphi *phi = gpi.phi();
+                    if (phi == use_stmt) {
+                        /* Find arguments (and thus in-edges) which use NAME. */
+                        for (unsigned arg_idx = 0;
+                             arg_idx < gimple_phi_num_args(phi); ++arg_idx) {
+                            if (name == gimple_phi_arg(phi, arg_idx)->def) {
+                                edge in_edge =
+                                    gimple_phi_arg_edge(phi, arg_idx);
+                                const superedge *in_sedge =
+                                    map.get_sg().get_edge_for_cfg_edge(in_edge);
+                                function_point point =
+                                    function_point::before_supernode(snode,
+                                                                     in_sedge);
+                                add_to_worklist(point, &worklist,
+                                                map.get_logger());
+                                m_points_needing_name.add(point);
+                            }
+                        }
+                    }
+                }
+            } else {
+                function_point point = before_use_stmt(map, use_stmt);
+                add_to_worklist(point, &worklist, map.get_logger());
+                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 the out-edges.  */
+                if (use_stmt == snode->get_last_stmt()) {
+                    if (map.get_logger())
+                        map.log("last stmt in BB");
+                    function_point point =
+                        function_point::after_supernode(snode);
+                    add_to_worklist(point, &worklist, map.get_logger());
+                    m_points_needing_name.add(point);
+                } else if (map.get_logger())
+                    map.log("not last stmt in BB");
+            }
+        }
+    }
 
-  /* 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, name)
+    /* Process worklist by walking backwards until we reach the def stmt.  */
     {
-      if (USE_STMT (use_p))
-	{
-	  const gimple *use_stmt = USE_STMT (use_p);
-	  if (map.get_logger ())
-	    {
-	      pretty_printer pp;
-	      pp_gimple_stmt_1 (&pp, use_stmt, 0, (dump_flags_t)0);
-	      map.log ("used by stmt: %s", pp_formatted_text (&pp));
-	    }
-
-	  const supernode *snode
-	    = map.get_sg ().get_supernode_for_stmt (use_stmt);
-
-	  /* If it's a use within a phi node, then we care about
-	     which in-edge we came from.  */
-	  if (use_stmt->code == GIMPLE_PHI)
-	    {
-	      for (gphi_iterator gpi
-		     = const_cast<supernode *> (snode)->start_phis ();
-		   !gsi_end_p (gpi); gsi_next (&gpi))
-		{
-		  gphi *phi = gpi.phi ();
-		  if (phi == use_stmt)
-		    {
-		      /* Find arguments (and thus in-edges) which use NAME.  */
-		      for (unsigned arg_idx = 0;
-			   arg_idx < gimple_phi_num_args (phi);
-			   ++arg_idx)
-			{
-			  if (name == gimple_phi_arg (phi, arg_idx)->def)
-			    {
-			      edge in_edge = gimple_phi_arg_edge (phi, arg_idx);
-			      const superedge *in_sedge
-				= map.get_sg ().get_edge_for_cfg_edge (in_edge);
-			      function_point point
-				= function_point::before_supernode
-				(snode, in_sedge);
-			      add_to_worklist (point, &worklist,
-					       map.get_logger ());
-			      m_points_needing_name.add (point);
-			    }
-			}
-		    }
-		}
-	    }
-	  else
-	    {
-	      function_point point = before_use_stmt (map, use_stmt);
-	      add_to_worklist (point, &worklist, map.get_logger ());
-	      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
-		 the out-edges.  */
-	      if (use_stmt == snode->get_last_stmt ())
-		{
-		  if (map.get_logger ())
-		    map.log ("last stmt in BB");
-		  function_point point
-		    = function_point::after_supernode (snode);
-		  add_to_worklist (point, &worklist, map.get_logger ());
-		  m_points_needing_name.add (point);
-		}
-	      else
-		if (map.get_logger ())
-		  map.log ("not last stmt in BB");
-	    }
-	}
+        log_scope s(map.get_logger(), "processing worklist");
+        while (worklist.length() > 0) {
+            function_point point = worklist.pop();
+            process_point(point, &worklist, map);
+        }
     }
 
-  /* Process worklist by walking backwards until we reach the def stmt.  */
-  {
-    log_scope s (map.get_logger (), "processing worklist");
-    while (worklist.length () > 0)
-      {
-	function_point point = worklist.pop ();
-	process_point (point, &worklist, map);
-    }
-  }
-
-  if (map.get_logger ())
-    {
-      map.log ("%qE in %qD is needed to process:", name, fun->decl);
-      /* Log m_points_needing_name, sorting it to avoid churn when comparing
-	 dumps.  */
-      auto_vec<function_point> points;
-      for (point_set_t::iterator iter = m_points_needing_name.begin ();
-	   iter != m_points_needing_name.end ();
-	   ++iter)
-	points.safe_push (*iter);
-      points.qsort (function_point::cmp_ptr);
-      unsigned i;
-      function_point *point;
-      FOR_EACH_VEC_ELT (points, i, point)
-	{
-	  map.start_log_line ();
-	  map.get_logger ()->log_partial ("  point: ");
-	  point->print (map.get_logger ()->get_printer (), format (false));
-	  map.end_log_line ();
-	}
+    if (map.get_logger()) {
+        map.log("%qE in %qD is needed to process:", name, fun->decl);
+        /* Log m_points_needing_name, sorting it to avoid churn when comparing
+           dumps.  */
+        auto_vec<function_point> points;
+        for (point_set_t::iterator iter = m_points_needing_name.begin();
+             iter != m_points_needing_name.end(); ++iter)
+            points.safe_push(*iter);
+        points.qsort(function_point::cmp_ptr);
+        unsigned i;
+        function_point *point;
+        FOR_EACH_VEC_ELT(points, i, point) {
+            map.start_log_line();
+            map.get_logger()->log_partial("  point: ");
+            point->print(map.get_logger()->get_printer(), format(false));
+            map.end_log_line();
+        }
     }
 }
 
 /* Return true if the SSA name is needed at POINT.  */
 
-bool
-state_purge_per_ssa_name::needed_at_point_p (const function_point &point) const
-{
-  return const_cast <point_set_t &> (m_points_needing_name).contains (point);
+bool state_purge_per_ssa_name::needed_at_point_p(
+    const function_point &point) const {
+    return const_cast<point_set_t &>(m_points_needing_name).contains(point);
 }
 
 /* Get the function_point representing immediately before USE_STMT.
    Subroutine of ctor.  */
 
 function_point
-state_purge_per_ssa_name::before_use_stmt (const state_purge_map &map,
-					   const gimple *use_stmt)
-{
-  gcc_assert (use_stmt->code != GIMPLE_PHI);
-
-  const supernode *supernode
-    = map.get_sg ().get_supernode_for_stmt (use_stmt);
-  unsigned int stmt_idx = supernode->get_stmt_index (use_stmt);
-  return function_point::before_stmt (supernode, stmt_idx);
+state_purge_per_ssa_name::before_use_stmt(const state_purge_map &map,
+                                          const gimple *use_stmt) {
+    gcc_assert(use_stmt->code != GIMPLE_PHI);
+
+    const supernode *supernode = map.get_sg().get_supernode_for_stmt(use_stmt);
+    unsigned int stmt_idx = supernode->get_stmt_index(use_stmt);
+    return function_point::before_stmt(supernode, stmt_idx);
 }
 
 /* Add POINT to *WORKLIST if the point has not already been seen.
    Subroutine of ctor.  */
 
-void
-state_purge_per_ssa_name::add_to_worklist (const function_point &point,
-					   auto_vec<function_point> *worklist,
-					   logger *logger)
-{
-  LOG_FUNC (logger);
-  if (logger)
-    {
-      logger->start_log_line ();
-      logger->log_partial ("point: '");
-      point.print (logger->get_printer (), format (false));
-      logger->log_partial ("' for worklist for %qE", m_name);
-      logger->end_log_line ();
+void state_purge_per_ssa_name::add_to_worklist(
+    const function_point &point, auto_vec<function_point> *worklist,
+    logger *logger) {
+    LOG_FUNC(logger);
+    if (logger) {
+        logger->start_log_line();
+        logger->log_partial("point: '");
+        point.print(logger->get_printer(), format(false));
+        logger->log_partial("' for worklist for %qE", m_name);
+        logger->end_log_line();
     }
 
-  gcc_assert (point.get_function () == m_fun);
-  if (point.get_from_edge ())
-    gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
-
-  if (m_points_needing_name.contains (point))
-    {
-      if (logger)
-	logger->log ("already seen for %qE", m_name);
-    }
-  else
-    {
-      if (logger)
-	logger->log ("not seen; adding to worklist for %qE", m_name);
-      m_points_needing_name.add (point);
-      worklist->safe_push (point);
+    gcc_assert(point.get_function() == m_fun);
+    if (point.get_from_edge())
+        gcc_assert(point.get_from_edge()->get_kind() == SUPEREDGE_CFG_EDGE);
+
+    if (m_points_needing_name.contains(point)) {
+        if (logger)
+            logger->log("already seen for %qE", m_name);
+    } else {
+        if (logger)
+            logger->log("not seen; adding to worklist for %qE", m_name);
+        m_points_needing_name.add(point);
+        worklist->safe_push(point);
     }
 }
 
 /* Process POINT, popped from WORKLIST.
    Iterate over predecessors of POINT, adding to WORKLIST.  */
 
-void
-state_purge_per_ssa_name::process_point (const function_point &point,
-					 auto_vec<function_point> *worklist,
-					 const state_purge_map &map)
-{
-  logger *logger = map.get_logger ();
-  LOG_FUNC (logger);
-  if (logger)
-    {
-      logger->start_log_line ();
-      logger->log_partial ("considering point: '");
-      point.print (logger->get_printer (), format (false));
-      logger->log_partial ("' for %qE", m_name);
-      logger->end_log_line ();
+void state_purge_per_ssa_name::process_point(const function_point &point,
+                                             auto_vec<function_point> *worklist,
+                                             const state_purge_map &map) {
+    logger *logger = map.get_logger();
+    LOG_FUNC(logger);
+    if (logger) {
+        logger->start_log_line();
+        logger->log_partial("considering point: '");
+        point.print(logger->get_printer(), format(false));
+        logger->log_partial("' for %qE", m_name);
+        logger->end_log_line();
     }
 
-  gimple *def_stmt = SSA_NAME_DEF_STMT (m_name);
+    gimple *def_stmt = SSA_NAME_DEF_STMT(m_name);
 
-  const supernode *snode = point.get_supernode ();
+    const supernode *snode = point.get_supernode();
 
-  switch (point.get_kind ())
-    {
+    switch (point.get_kind()) {
     default:
-      gcc_unreachable ();
+        gcc_unreachable();
 
     case PK_ORIGIN:
-      break;
-
-    case PK_BEFORE_SUPERNODE:
-      {
-	for (gphi_iterator gpi
-	       = const_cast<supernode *> (snode)->start_phis ();
-	     !gsi_end_p (gpi); gsi_next (&gpi))
-	  {
-	    gphi *phi = gpi.phi ();
-	    if (phi == def_stmt)
-	      {
-		if (logger)
-		  logger->log ("def stmt within phis; terminating");
-		return;
-	      }
-	  }
-
-	/* Add given pred to worklist.  */
-	if (point.get_from_edge ())
-	  {
-	    gcc_assert (point.get_from_edge ()->m_src);
-	    add_to_worklist
-	      (function_point::after_supernode (point.get_from_edge ()->m_src),
-	       worklist, logger);
-	  }
-	else
-	  {
-	    /* Add any intraprocedually edge for a call.  */
-	    if (snode->m_returning_call)
-	      {
-		cgraph_edge *cedge
-		  = supergraph_call_edge (snode->m_fun,
-					  snode->m_returning_call);
-		gcc_assert (cedge);
-		superedge *sedge
-		  = map.get_sg ().get_intraprocedural_edge_for_call (cedge);
-		gcc_assert (sedge);
-		add_to_worklist
-		  (function_point::after_supernode (sedge->m_src),
-		   worklist, logger);
-	      }
-	  }
-      }
-      break;
-
-    case PK_BEFORE_STMT:
-      {
-	if (def_stmt == point.get_stmt ())
-	  {
-	    if (logger)
-	      logger->log ("def stmt; terminating");
-	    return;
-	  }
-	if (point.get_stmt_idx () > 0)
-	  add_to_worklist (function_point::before_stmt
-			     (snode, point.get_stmt_idx () - 1),
-			   worklist, logger);
-	else
-	{
-	  /* Add before_supernode to worklist.  This captures the in-edge,
-	     so we have to do it once per in-edge.  */
-	  unsigned i;
-	  superedge *pred;
-	  FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
-	    add_to_worklist (function_point::before_supernode (snode,
-							       pred),
-			     worklist, logger);
-	}
-      }
-      break;
-
-    case PK_AFTER_SUPERNODE:
-      {
-	if (snode->m_stmts.length ())
-	  add_to_worklist
-	    (function_point::before_stmt (snode,
-					  snode->m_stmts.length () - 1),
-	     worklist, logger);
-	else
-	  {
-	    /* Add before_supernode to worklist.  This captures the in-edge,
-	       so we have to do it once per in-edge.  */
-	    unsigned i;
-	    superedge *pred;
-	    FOR_EACH_VEC_ELT (snode->m_preds, i, pred)
-	      add_to_worklist (function_point::before_supernode (snode,
-								 pred),
-			       worklist, logger);
-	    /* If it's the initial BB, add it, to ensure that we
-	       have "before supernode" for the initial ENTRY block, and don't
-	       erroneously purge SSA names for initial values of parameters.  */
-	    if (snode->entry_p ())
-	      {
-		add_to_worklist
-		  (function_point::before_supernode (snode, NULL),
-		   worklist, logger);
-	      }
-	  }
-      }
-      break;
+        break;
+
+    case PK_BEFORE_SUPERNODE: {
+        for (gphi_iterator gpi = const_cast<supernode *>(snode)->start_phis();
+             !gsi_end_p(gpi); gsi_next(&gpi)) {
+            gphi *phi = gpi.phi();
+            if (phi == def_stmt) {
+                if (logger)
+                    logger->log("def stmt within phis; terminating");
+                return;
+            }
+        }
+
+        /* Add given pred to worklist.  */
+        if (point.get_from_edge()) {
+            gcc_assert(point.get_from_edge()->m_src);
+            add_to_worklist(
+                function_point::after_supernode(point.get_from_edge()->m_src),
+                worklist, logger);
+        } else {
+            /* Add any intraprocedually edge for a call.  */
+            if (snode->m_returning_call) {
+                cgraph_edge *cedge =
+                    supergraph_call_edge(snode->m_fun, snode->m_returning_call);
+                if (!cedge) {
+                    supernode *callernode = map.get_sg().get_supernode_for_stmt(
+                        snode->m_returning_call);
+                    gcc_assert(callernode);
+                    add_to_worklist(function_point::after_supernode(callernode),
+                                    worklist, logger);
+                } else {
+                    gcc_assert(cedge);
+                    superedge *sedge =
+                        map.get_sg().get_intraprocedural_edge_for_call(cedge);
+                    gcc_assert(sedge);
+                    add_to_worklist(
+                        function_point::after_supernode(sedge->m_src), worklist,
+                        logger);
+                }
+            }
+        }
+    } break;
+
+    case PK_BEFORE_STMT: {
+        if (def_stmt == point.get_stmt()) {
+            if (logger)
+                logger->log("def stmt; terminating");
+            return;
+        }
+        if (point.get_stmt_idx() > 0)
+            add_to_worklist(
+                function_point::before_stmt(snode, point.get_stmt_idx() - 1),
+                worklist, logger);
+        else {
+            /* Add before_supernode to worklist.  This captures the in-edge,
+               so we have to do it once per in-edge.  */
+            unsigned i;
+            superedge *pred;
+            FOR_EACH_VEC_ELT(snode->m_preds, i, pred)
+            add_to_worklist(function_point::before_supernode(snode, pred),
+                            worklist, logger);
+        }
+    } break;
+
+    case PK_AFTER_SUPERNODE: {
+        if (snode->m_stmts.length())
+            add_to_worklist(
+                function_point::before_stmt(snode, snode->m_stmts.length() - 1),
+                worklist, logger);
+        else {
+            /* Add before_supernode to worklist.  This captures the in-edge,
+               so we have to do it once per in-edge.  */
+            unsigned i;
+            superedge *pred;
+            FOR_EACH_VEC_ELT(snode->m_preds, i, pred)
+            add_to_worklist(function_point::before_supernode(snode, pred),
+                            worklist, logger);
+            /* If it's the initial BB, add it, to ensure that we
+               have "before supernode" for the initial ENTRY block, and don't
+               erroneously purge SSA names for initial values of parameters.  */
+            if (snode->entry_p()) {
+                add_to_worklist(function_point::before_supernode(snode, NULL),
+                                worklist, logger);
+            }
+        }
+    } break;
     }
 }
 
@@ -428,47 +376,41 @@ state_purge_per_ssa_name::process_point (const function_point &point,
    Add an additional record showing which names are purged on entry
    to the supernode N.  */
 
-bool
-state_purge_annotator::add_node_annotations (graphviz_out *gv,
-					     const supernode &n,
-					     bool within_table) const
-{
-  if (m_map == NULL)
-    return false;
+bool state_purge_annotator::add_node_annotations(graphviz_out *gv,
+                                                 const supernode &n,
+                                                 bool within_table) const {
+    if (m_map == NULL)
+        return false;
+
+    if (within_table)
+        return false;
+
+    pretty_printer *pp = gv->get_pp();
+
+    pp_printf(pp, "annotation_for_node_%i", n.m_index);
+    pp_printf(pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
+              "lightblue");
+    pp_write_text_to_stream(pp);
+
+    // FIXME: passing in a NULL in-edge means we get no hits
+    function_point before_supernode(function_point::before_supernode(&n, NULL));
+
+    for (state_purge_map::iterator iter = m_map->begin(); iter != m_map->end();
+         ++iter) {
+        tree name = (*iter).first;
+        state_purge_per_ssa_name *per_name_data = (*iter).second;
+        if (per_name_data->get_function() == n.m_fun) {
+            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);
+        }
+        pp_newline(pp);
+    }
 
-  if (within_table)
+    pp_string(pp, "\"];\n\n");
+    pp_flush(pp);
     return false;
-
-  pretty_printer *pp = gv->get_pp ();
-
-   pp_printf (pp, "annotation_for_node_%i", n.m_index);
-   pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
-	      "lightblue");
-   pp_write_text_to_stream (pp);
-
-   // FIXME: passing in a NULL in-edge means we get no hits
-   function_point before_supernode
-     (function_point::before_supernode (&n, NULL));
-
-   for (state_purge_map::iterator iter = m_map->begin ();
-	iter != m_map->end ();
-	++iter)
-     {
-       tree name = (*iter).first;
-       state_purge_per_ssa_name *per_name_data = (*iter).second;
-       if (per_name_data->get_function () == n.m_fun)
-	 {
-	   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);
-	 }
-       pp_newline (pp);
-     }
-
-   pp_string (pp, "\"];\n\n");
-   pp_flush (pp);
-   return false;
 }
 
 /* Print V to GV as a comma-separated list in braces within a <TR>,
@@ -476,25 +418,22 @@ state_purge_annotator::add_node_annotations (graphviz_out *gv,
 
    Subroutine of state_purge_annotator::add_stmt_annotations.  */
 
-static void
-print_vec_of_names (graphviz_out *gv, const char *title,
-		    const auto_vec<tree> &v)
-{
-  pretty_printer *pp = gv->get_pp ();
-  tree name;
-  unsigned i;
-  gv->begin_trtd ();
-  pp_printf (pp, "%s: {", title);
-  FOR_EACH_VEC_ELT (v, i, name)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      pp_printf (pp, "%qE", name);
+static void print_vec_of_names(graphviz_out *gv, const char *title,
+                               const auto_vec<tree> &v) {
+    pretty_printer *pp = gv->get_pp();
+    tree name;
+    unsigned i;
+    gv->begin_trtd();
+    pp_printf(pp, "%s: {", title);
+    FOR_EACH_VEC_ELT(v, i, name) {
+        if (i > 0)
+            pp_string(pp, ", ");
+        pp_printf(pp, "%qE", name);
     }
-  pp_printf (pp, "}");
-  pp_write_text_as_html_like_dot_to_stream (pp);
-  gv->end_tdtr ();
-  pp_newline (pp);
+    pp_printf(pp, "}");
+    pp_write_text_as_html_like_dot_to_stream(pp);
+    gv->end_tdtr();
+    pp_newline(pp);
 }
 
 /* Implementation of dot_annotator::add_stmt_annotations for
@@ -502,48 +441,43 @@ print_vec_of_names (graphviz_out *gv, const char *title,
 
    Add text showing which names are purged at STMT.  */
 
-void
-state_purge_annotator::add_stmt_annotations (graphviz_out *gv,
-					     const gimple *stmt,
-					     bool within_row) const
-{
-  if (within_row)
-    return;
-
-  if (m_map == NULL)
-    return;
-
-  if (stmt->code == GIMPLE_PHI)
-    return;
-
-  pretty_printer *pp = gv->get_pp ();
-
-  pp_newline (pp);
-
-  const supernode *supernode = m_map->get_sg ().get_supernode_for_stmt (stmt);
-  unsigned int stmt_idx = supernode->get_stmt_index (stmt);
-  function_point before_stmt
-    (function_point::before_stmt (supernode, stmt_idx));
-
-  auto_vec<tree> needed;
-  auto_vec<tree> not_needed;
-  for (state_purge_map::iterator iter = m_map->begin ();
-       iter != m_map->end ();
-       ++iter)
-    {
-      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);
-	}
+void state_purge_annotator::add_stmt_annotations(graphviz_out *gv,
+                                                 const gimple *stmt,
+                                                 bool within_row) const {
+    if (within_row)
+        return;
+
+    if (m_map == NULL)
+        return;
+
+    if (stmt->code == GIMPLE_PHI)
+        return;
+
+    pretty_printer *pp = gv->get_pp();
+
+    pp_newline(pp);
+
+    const supernode *supernode = m_map->get_sg().get_supernode_for_stmt(stmt);
+    unsigned int stmt_idx = supernode->get_stmt_index(stmt);
+    function_point before_stmt(
+        function_point::before_stmt(supernode, stmt_idx));
+
+    auto_vec<tree> needed;
+    auto_vec<tree> not_needed;
+    for (state_purge_map::iterator iter = m_map->begin(); iter != m_map->end();
+         ++iter) {
+        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);
+        }
     }
 
-  print_vec_of_names (gv, "needed here", needed);
-  print_vec_of_names (gv, "not needed here", not_needed);
+    print_vec_of_names(gv, "needed here", needed);
+    print_vec_of_names(gv, "not needed here", not_needed);
 }
 
 #endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/testsuite/gcc.dg/analyzer/call-via-fnptr.c b/gcc/testsuite/gcc.dg/analyzer/call-via-fnptr.c
new file mode 100644
index 00000000000..d0e1fc22108
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/call-via-fnptr.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void fun(int *int_ptr)
+{
+    free(int_ptr);
+}
+
+int test()
+{
+    int *int_ptr = (int*)malloc(sizeof(int));
+    void (*fun_ptr)(int *) = &fun;
+    (*fun_ptr)(int_ptr);
+    return 0;
+}
+
+void test_2()
+{
+  test();
+}


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

only message in thread, other threads:[~2021-07-13 13:45 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-13 13:45 [gcc(refs/users/arsenic/heads/analyzer_extension)] fix state-purgeing Ankur saini

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).