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