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

Reply via email to