2021-07-3 Ankur Saini <arse...@sourceware.org> * gcc/analyzer/call-string.cc: refactor callstring to work with pair of supernodes instead of super superedges * gcc/analyzer/call-string.h: make callstring work with pairs of supernodes * gcc/analyzer/program-point.cc: refactor program point to work with new call-string format --- gcc/analyzer/call-string.cc | 93 +++++++++++++++++++++-------------- gcc/analyzer/call-string.h | 20 +++++--- gcc/analyzer/program-point.cc | 9 ++-- 3 files changed, 74 insertions(+), 48 deletions(-)
diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index 9f4f77ab3a9..50dfb9e8c7c 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_return_edges (other.m_return_edges.length ()) +: m_supernodes (other.m_supernodes.length ()) { - for (const return_superedge *e : other.m_return_edges) - m_return_edges.quick_push (e); + for (const std::pair<const supernode *,const supernode *> *e : other.m_supernodes) + m_supernodes.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_return_edges.truncate (0); - m_return_edges.reserve (other.m_return_edges.length (), true); - const return_superedge *e; + m_supernodes.truncate (0); + m_supernodes.reserve (other.m_supernodes.length (), true); + const std::pair<const supernode *,const supernode *> *e; int i; - FOR_EACH_VEC_ELT (other.m_return_edges, i, e) - m_return_edges.quick_push (e); + FOR_EACH_VEC_ELT (other.m_supernodes, i, e) + m_supernodes.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_return_edges.length () != other.m_return_edges.length ()) + if (m_supernodes.length () != other.m_supernodes.length ()) return false; - const return_superedge *e; + const std::pair<const supernode *,const supernode *> *e; int i; - FOR_EACH_VEC_ELT (m_return_edges, i, e) - if (e != other.m_return_edges[i]) + FOR_EACH_VEC_ELT (m_supernodes, i, e) + if (e != other.m_supernodes[i]) return false; return true; } @@ -91,15 +91,15 @@ call_string::print (pretty_printer *pp) const { pp_string (pp, "["); - const return_superedge *e; + const std::pair<const supernode *,const supernode *> *e; int i; - FOR_EACH_VEC_ELT (m_return_edges, i, e) + FOR_EACH_VEC_ELT (m_supernodes, i, e) { if (i > 0) pp_string (pp, ", "); pp_printf (pp, "(SN: %i -> SN: %i in %s)", - e->m_src->m_index, e->m_dest->m_index, - function_name (e->m_dest->m_fun)); + e->first->m_index, e->second->m_index, + function_name (e->second->m_fun)); } pp_string (pp, "]"); @@ -109,22 +109,22 @@ call_string::print (pretty_printer *pp) const [{"src_snode_idx" : int, "dst_snode_idx" : int, "funcname" : str}, - ...for each return_superedge in the callstring]. */ + ...for each std::pair<const supernode *,const supernode *> in the callstring]. */ json::value * call_string::to_json () const { json::array *arr = new json::array (); - for (const return_superedge *e : m_return_edges) + for (const std::pair<const supernode *,const supernode *> *e : m_supernodes) { json::object *e_obj = new json::object (); e_obj->set ("src_snode_idx", - new json::integer_number (e->m_src->m_index)); + new json::integer_number (e->first->m_index)); e_obj->set ("dst_snode_idx", - new json::integer_number (e->m_dest->m_index)); + new json::integer_number (e->second->m_index)); e_obj->set ("funcname", - new json::string (function_name (e->m_dest->m_fun))); + new json::string (function_name (e->second->m_fun))); arr->append (e_obj); } @@ -137,7 +137,7 @@ hashval_t call_string::hash () const { inchash::hash hstate; - for (const return_superedge *e : m_return_edges) + for (const std::pair<const supernode *,const supernode *> *e : m_supernodes) hstate.add_ptr (e); return hstate.end (); } @@ -152,22 +152,40 @@ 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); - m_return_edges.safe_push (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); +} + +void +call_string::push_call (const supernode *src, + const supernode *dest) +{ + const std::pair<const supernode *,const supernode *> *e = new (std::pair<const supernode *,const supernode *>) + { src, + dest}; + m_supernodes.safe_push (e); +} + +const std::pair<const supernode *,const supernode *> +call_string::pop () +{ + return *m_supernodes.pop(); } /* Count the number of times the top-most call site appears in the stack. */ - int call_string::calc_recursion_depth () const { - if (m_return_edges.is_empty ()) + if (m_supernodes.is_empty ()) return 0; - const return_superedge *top_return_sedge - = m_return_edges[m_return_edges.length () - 1]; + const std::pair<const supernode *,const supernode *> *top_return_sedge + = m_supernodes[m_supernodes.length () - 1]; int result = 0; - for (const return_superedge *e : m_return_edges) + for (const std::pair<const supernode *,const supernode *> *e : m_supernodes) if (e == top_return_sedge) ++result; return result; @@ -201,13 +219,13 @@ call_string::cmp (const call_string &a, if (i >= len_b) return -1; - /* Otherwise, compare the edges. */ - const return_superedge *edge_a = a[i]; - const return_superedge *edge_b = b[i]; - int src_cmp = edge_a->m_src->m_index - edge_b->m_src->m_index; + /* 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; if (src_cmp) return src_cmp; - int dest_cmp = edge_a->m_dest->m_index - edge_b->m_dest->m_index; + int dest_cmp = a_node_pair->second->m_index - b_node_pair->second->m_index; if (dest_cmp) return dest_cmp; i++; @@ -226,12 +244,13 @@ call_string::validate () const #endif /* Each entry's "caller" should be the "callee" of the previous entry. */ - const return_superedge *e; + const std::pair<const supernode *,const supernode *> *e; int i; - FOR_EACH_VEC_ELT (m_return_edges, i, e) + FOR_EACH_VEC_ELT (m_supernodes, i, e) if (i > 0) - gcc_assert (e->get_caller_function () - == m_return_edges[i - 1]->get_callee_function ()); + { + gcc_assert (e->second->get_function () == m_supernodes[i - 1]->second->get_function()); + } } #endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/call-string.h b/gcc/analyzer/call-string.h index 7721571ed60..0134d185b90 100644 --- a/gcc/analyzer/call-string.h +++ b/gcc/analyzer/call-string.h @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see namespace ana { class supergraph; +class supernode; class call_superedge; class return_superedge; @@ -39,7 +40,7 @@ class return_superedge; class call_string { public: - call_string () : m_return_edges () {} + call_string () : m_supernodes () {} call_string (const call_string &other); call_string& operator= (const call_string &other); @@ -51,27 +52,32 @@ public: hashval_t hash () const; - bool empty_p () const { return m_return_edges.is_empty (); } + bool empty_p () const { return m_supernodes.is_empty (); } void push_call (const supergraph &sg, const call_superedge *sedge); - const return_superedge *pop () { return m_return_edges.pop (); } + + void push_call (const supernode *src, + const supernode *dest); + + const std::pair<const supernode *,const supernode *> pop (); int calc_recursion_depth () const; static int cmp (const call_string &a, const call_string &b); - unsigned length () const { return m_return_edges.length (); } - const return_superedge *operator[] (unsigned idx) const + unsigned length () const { return m_supernodes.length (); } + const std::pair<const supernode *,const supernode *> *operator[] (unsigned idx) const { - return m_return_edges[idx]; + return m_supernodes[idx]; } void validate () const; private: - auto_vec<const return_superedge *> m_return_edges; + //auto_vec<const return_superedge *> m_return_edges; + auto_vec<const std::pair<const supernode *,const supernode *>*> m_supernodes; }; } // namespace ana diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index d8cfc61975e..40afafc7ad0 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -343,7 +343,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]->get_caller_function (); + return m_call_string[depth]->second->get_function (); } /* Assert that this object is sane. */ @@ -360,7 +360,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]->get_callee_function () + gcc_assert (m_call_string[m_call_string.length () - 1]->first->get_function () == get_function ()); } @@ -431,8 +431,9 @@ program_point::on_edge (exploded_graph &eg, logger->log ("rejecting return edge: empty call string"); return false; } - const return_superedge *top_of_stack = m_call_string.pop (); - if (top_of_stack != succ) + 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); + if (top_of_stack != current_sedge_node_pair) { if (logger) logger->log ("rejecting return edge: return to wrong callsite"); -- 2.32.0 >From 95572742f1aaad1975aa35a663e8b26e671d4323 Mon Sep 17 00:00:00 2001 From: Ankur Saini <arse...@sourceware.org> Date: Sat, 10 Jul 2021 19:28:49 +0530 Subject: [PATCH 2/2] analyzer: make callstring's pairs of supernodes statically allocated [GSoC] 2021-07-10 Ankur Saini <arse...@sourceware.org> gcc/analyzer/ * call-string.cc: store a vector of std::pair of supernode* instead of pointer to them * call-string.h: create a typedef for "auto_vec<const std::pair<const supernode *,const supernode *>*> m_supernodes;" to enhance readibility * program-point.cc: refactor program point to work with new call-string format --- gcc/analyzer/call-string.cc | 99 ++++++++++++++++++++--------------- gcc/analyzer/call-string.h | 21 +++++--- gcc/analyzer/program-point.cc | 8 +-- 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index 50dfb9e8c7c..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 *src, - const supernode *dest) +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 *>) - { src, - dest}; - 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++; @@ -233,6 +228,24 @@ call_string::cmp (const call_string &a, } } +/* return the opinter to callee of the topmost call in the stack, or NULL if stack is empty */ +const supernode * +call_string::get_callee_node() const +{ + if(m_elements.is_empty()) + return NULL; + 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_elements.is_empty()) + return NULL; + return m_elements[m_elements.length() - 1].second; +} + /* Assert that this object is sane. */ void @@ -244,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]->second->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 0134d185b90..450af6da21a 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,24 +62,27 @@ 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; static int cmp (const call_string &a, const call_string &b); - unsigned length () const { return m_supernodes.length (); } - const std::pair<const supernode *,const supernode *> *operator[] (unsigned idx) const + /* Accessors */ + + const supernode * get_callee_node() const; + const supernode * get_caller_node() 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 40afafc7ad0..1b6e4780026 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -343,7 +343,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. */ @@ -360,7 +360,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 ()); } @@ -431,8 +431,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) -- 2.32.0