Home | History | Annotate | Line # | Download | only in analyzer
      1      1.1  mrg /* Call stacks at program points.
      2  1.1.1.2  mrg    Copyright (C) 2019-2022 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by David Malcolm <dmalcolm (at) redhat.com>.
      4      1.1  mrg 
      5      1.1  mrg This file is part of GCC.
      6      1.1  mrg 
      7      1.1  mrg GCC is free software; you can redistribute it and/or modify it
      8      1.1  mrg under the terms of the GNU General Public License as published by
      9      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
     10      1.1  mrg any later version.
     11      1.1  mrg 
     12      1.1  mrg GCC is distributed in the hope that it will be useful, but
     13      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15      1.1  mrg General Public License for more details.
     16      1.1  mrg 
     17      1.1  mrg You should have received a copy of the GNU General Public License
     18      1.1  mrg along with GCC; see the file COPYING3.  If not see
     19      1.1  mrg <http://www.gnu.org/licenses/>.  */
     20      1.1  mrg 
     21      1.1  mrg #include "config.h"
     22      1.1  mrg #include "system.h"
     23      1.1  mrg #include "coretypes.h"
     24      1.1  mrg #include "pretty-print.h"
     25      1.1  mrg #include "tree.h"
     26      1.1  mrg #include "options.h"
     27  1.1.1.2  mrg #include "json.h"
     28      1.1  mrg #include "analyzer/call-string.h"
     29      1.1  mrg #include "ordered-hash-map.h"
     30      1.1  mrg #include "options.h"
     31      1.1  mrg #include "cgraph.h"
     32      1.1  mrg #include "function.h"
     33      1.1  mrg #include "cfg.h"
     34      1.1  mrg #include "basic-block.h"
     35      1.1  mrg #include "gimple.h"
     36      1.1  mrg #include "gimple-iterator.h"
     37      1.1  mrg #include "digraph.h"
     38      1.1  mrg #include "analyzer/supergraph.h"
     39      1.1  mrg 
     40      1.1  mrg #if ENABLE_ANALYZER
     41      1.1  mrg 
     42  1.1.1.2  mrg #if __GNUC__ >= 10
     43  1.1.1.2  mrg #pragma GCC diagnostic ignored "-Wformat-diag"
     44  1.1.1.2  mrg #endif
     45  1.1.1.2  mrg 
     46      1.1  mrg /* class call_string.  */
     47      1.1  mrg 
     48  1.1.1.2  mrg /* struct call_string::element_t.  */
     49  1.1.1.2  mrg 
     50  1.1.1.2  mrg /* call_string::element_t's equality operator.  */
     51  1.1.1.2  mrg 
     52  1.1.1.2  mrg bool
     53  1.1.1.2  mrg call_string::element_t::operator== (const call_string::element_t &other) const
     54  1.1.1.2  mrg {
     55  1.1.1.2  mrg   return (m_caller == other.m_caller && m_callee == other.m_callee);
     56  1.1.1.2  mrg }
     57  1.1.1.2  mrg 
     58  1.1.1.2  mrg /* call_string::element_t's inequality operator.  */
     59  1.1.1.2  mrg bool
     60  1.1.1.2  mrg call_string::element_t::operator!= (const call_string::element_t &other) const
     61  1.1.1.2  mrg {
     62  1.1.1.2  mrg   return !(*this == other);
     63  1.1.1.2  mrg }
     64  1.1.1.2  mrg 
     65  1.1.1.2  mrg function *
     66  1.1.1.2  mrg call_string::element_t::get_caller_function () const
     67  1.1.1.2  mrg {
     68  1.1.1.2  mrg   return m_caller->get_function ();
     69  1.1.1.2  mrg }
     70  1.1.1.2  mrg 
     71  1.1.1.2  mrg function *
     72  1.1.1.2  mrg call_string::element_t::get_callee_function () const
     73  1.1.1.2  mrg {
     74  1.1.1.2  mrg   return m_callee->get_function ();
     75  1.1.1.2  mrg }
     76  1.1.1.2  mrg 
     77      1.1  mrg /* call_string's copy ctor.  */
     78      1.1  mrg 
     79      1.1  mrg call_string::call_string (const call_string &other)
     80  1.1.1.2  mrg : m_elements (other.m_elements.length ())
     81      1.1  mrg {
     82  1.1.1.2  mrg   for (const call_string::element_t &e : other.m_elements)
     83  1.1.1.2  mrg     m_elements.quick_push (e);
     84      1.1  mrg }
     85      1.1  mrg 
     86      1.1  mrg /* call_string's assignment operator.  */
     87      1.1  mrg 
     88      1.1  mrg call_string&
     89      1.1  mrg call_string::operator= (const call_string &other)
     90      1.1  mrg {
     91      1.1  mrg   // would be much simpler if we could rely on vec<> assignment op
     92  1.1.1.2  mrg   m_elements.truncate (0);
     93  1.1.1.2  mrg   m_elements.reserve (other.m_elements.length (), true);
     94  1.1.1.2  mrg   call_string::element_t *e;
     95      1.1  mrg   int i;
     96  1.1.1.2  mrg   FOR_EACH_VEC_ELT (other.m_elements, i, e)
     97  1.1.1.2  mrg     m_elements.quick_push (*e);
     98      1.1  mrg   return *this;
     99      1.1  mrg }
    100      1.1  mrg 
    101      1.1  mrg /* call_string's equality operator.  */
    102      1.1  mrg 
    103      1.1  mrg bool
    104      1.1  mrg call_string::operator== (const call_string &other) const
    105      1.1  mrg {
    106  1.1.1.2  mrg   if (m_elements.length () != other.m_elements.length ())
    107      1.1  mrg     return false;
    108  1.1.1.2  mrg   call_string::element_t *e;
    109      1.1  mrg   int i;
    110  1.1.1.2  mrg   FOR_EACH_VEC_ELT (m_elements, i, e)
    111  1.1.1.2  mrg     if (*e != other.m_elements[i])
    112      1.1  mrg       return false;
    113      1.1  mrg   return true;
    114      1.1  mrg }
    115      1.1  mrg 
    116      1.1  mrg /* Print this to PP.  */
    117      1.1  mrg 
    118      1.1  mrg void
    119      1.1  mrg call_string::print (pretty_printer *pp) const
    120      1.1  mrg {
    121      1.1  mrg   pp_string (pp, "[");
    122      1.1  mrg 
    123  1.1.1.2  mrg   call_string::element_t *e;
    124      1.1  mrg   int i;
    125  1.1.1.2  mrg   FOR_EACH_VEC_ELT (m_elements, i, e)
    126      1.1  mrg     {
    127      1.1  mrg       if (i > 0)
    128      1.1  mrg 	pp_string (pp, ", ");
    129      1.1  mrg       pp_printf (pp, "(SN: %i -> SN: %i in %s)",
    130  1.1.1.2  mrg 		 e->m_callee->m_index, e->m_caller->m_index,
    131  1.1.1.2  mrg 		 function_name (e->m_caller->m_fun));
    132      1.1  mrg     }
    133      1.1  mrg 
    134      1.1  mrg   pp_string (pp, "]");
    135      1.1  mrg }
    136      1.1  mrg 
    137  1.1.1.2  mrg /* Return a new json::array of the form
    138  1.1.1.2  mrg    [{"src_snode_idx" : int,
    139  1.1.1.2  mrg      "dst_snode_idx" : int,
    140  1.1.1.2  mrg      "funcname" : str},
    141  1.1.1.2  mrg      ...for each element in the callstring].  */
    142  1.1.1.2  mrg 
    143  1.1.1.2  mrg json::value *
    144  1.1.1.2  mrg call_string::to_json () const
    145  1.1.1.2  mrg {
    146  1.1.1.2  mrg   json::array *arr = new json::array ();
    147  1.1.1.2  mrg 
    148  1.1.1.2  mrg   for (const call_string::element_t &e : m_elements)
    149  1.1.1.2  mrg     {
    150  1.1.1.2  mrg       json::object *e_obj = new json::object ();
    151  1.1.1.2  mrg       e_obj->set ("src_snode_idx",
    152  1.1.1.2  mrg 		  new json::integer_number (e.m_callee->m_index));
    153  1.1.1.2  mrg       e_obj->set ("dst_snode_idx",
    154  1.1.1.2  mrg 		  new json::integer_number (e.m_caller->m_index));
    155  1.1.1.2  mrg       e_obj->set ("funcname",
    156  1.1.1.2  mrg 		  new json::string (function_name (e.m_caller->m_fun)));
    157  1.1.1.2  mrg       arr->append (e_obj);
    158  1.1.1.2  mrg     }
    159  1.1.1.2  mrg 
    160  1.1.1.2  mrg   return arr;
    161  1.1.1.2  mrg }
    162  1.1.1.2  mrg 
    163      1.1  mrg /* Generate a hash value for this call_string.  */
    164      1.1  mrg 
    165      1.1  mrg hashval_t
    166      1.1  mrg call_string::hash () const
    167      1.1  mrg {
    168      1.1  mrg   inchash::hash hstate;
    169  1.1.1.2  mrg   for (const call_string::element_t &e : m_elements)
    170  1.1.1.2  mrg     hstate.add_ptr (e.m_caller);
    171      1.1  mrg   return hstate.end ();
    172      1.1  mrg }
    173      1.1  mrg 
    174      1.1  mrg /* Push the return superedge for CALL_SEDGE onto the end of this
    175      1.1  mrg    call_string.  */
    176      1.1  mrg 
    177      1.1  mrg void
    178      1.1  mrg call_string::push_call (const supergraph &sg,
    179      1.1  mrg 			const call_superedge *call_sedge)
    180      1.1  mrg {
    181      1.1  mrg   gcc_assert (call_sedge);
    182      1.1  mrg   const return_superedge *return_sedge = call_sedge->get_edge_for_return (sg);
    183      1.1  mrg   gcc_assert (return_sedge);
    184  1.1.1.2  mrg   call_string::element_t e (return_sedge->m_dest, return_sedge->m_src);
    185  1.1.1.2  mrg   m_elements.safe_push (e);
    186  1.1.1.2  mrg }
    187  1.1.1.2  mrg 
    188  1.1.1.2  mrg void
    189  1.1.1.2  mrg call_string::push_call (const supernode *caller,
    190  1.1.1.2  mrg 			const supernode *callee)
    191  1.1.1.2  mrg {
    192  1.1.1.2  mrg   call_string::element_t e (caller, callee);
    193  1.1.1.2  mrg   m_elements.safe_push (e);
    194  1.1.1.2  mrg }
    195  1.1.1.2  mrg 
    196  1.1.1.2  mrg call_string::element_t
    197  1.1.1.2  mrg call_string::pop ()
    198  1.1.1.2  mrg {
    199  1.1.1.2  mrg   return m_elements.pop();
    200      1.1  mrg }
    201      1.1  mrg 
    202      1.1  mrg /* Count the number of times the top-most call site appears in the
    203      1.1  mrg    stack.  */
    204      1.1  mrg int
    205      1.1  mrg call_string::calc_recursion_depth () const
    206      1.1  mrg {
    207  1.1.1.2  mrg   if (m_elements.is_empty ())
    208      1.1  mrg     return 0;
    209  1.1.1.2  mrg   const call_string::element_t top_return_sedge
    210  1.1.1.2  mrg     = m_elements[m_elements.length () - 1];
    211      1.1  mrg 
    212      1.1  mrg   int result = 0;
    213  1.1.1.2  mrg   for (const call_string::element_t &e : m_elements)
    214      1.1  mrg     if (e == top_return_sedge)
    215      1.1  mrg       ++result;
    216      1.1  mrg   return result;
    217      1.1  mrg }
    218      1.1  mrg 
    219      1.1  mrg /* Comparator for call strings.
    220      1.1  mrg    This implements a version of lexicographical order.
    221      1.1  mrg    Return negative if A is before B.
    222      1.1  mrg    Return positive if B is after A.
    223      1.1  mrg    Return 0 if they are equal.  */
    224      1.1  mrg 
    225      1.1  mrg int
    226      1.1  mrg call_string::cmp (const call_string &a,
    227      1.1  mrg 		  const call_string &b)
    228      1.1  mrg {
    229      1.1  mrg   unsigned len_a = a.length ();
    230      1.1  mrg   unsigned len_b = b.length ();
    231      1.1  mrg 
    232      1.1  mrg   unsigned i = 0;
    233      1.1  mrg   while (1)
    234      1.1  mrg     {
    235      1.1  mrg       /* Consider index i; the strings have been equal up to it.  */
    236      1.1  mrg 
    237      1.1  mrg       /* Have both strings run out?  */
    238      1.1  mrg       if (i >= len_a && i >= len_b)
    239      1.1  mrg 	return 0;
    240      1.1  mrg 
    241      1.1  mrg       /* Otherwise, has just one of the strings run out?  */
    242      1.1  mrg       if (i >= len_a)
    243      1.1  mrg 	return 1;
    244      1.1  mrg       if (i >= len_b)
    245      1.1  mrg 	return -1;
    246      1.1  mrg 
    247  1.1.1.2  mrg       /* Otherwise, compare the node pairs.  */
    248  1.1.1.2  mrg       const call_string::element_t a_node_pair = a[i];
    249  1.1.1.2  mrg       const call_string::element_t b_node_pair = b[i];
    250  1.1.1.2  mrg       int src_cmp
    251  1.1.1.2  mrg       	= a_node_pair.m_callee->m_index - b_node_pair.m_callee->m_index;
    252      1.1  mrg       if (src_cmp)
    253      1.1  mrg 	return src_cmp;
    254  1.1.1.2  mrg       int dest_cmp
    255  1.1.1.2  mrg       	= a_node_pair.m_caller->m_index - b_node_pair.m_caller->m_index;
    256      1.1  mrg       if (dest_cmp)
    257      1.1  mrg 	return dest_cmp;
    258      1.1  mrg       i++;
    259      1.1  mrg       // TODO: test coverage for this
    260      1.1  mrg     }
    261      1.1  mrg }
    262      1.1  mrg 
    263  1.1.1.2  mrg /* Return the pointer to callee of the topmost call in the stack,
    264  1.1.1.2  mrg    or NULL if stack is empty.  */
    265  1.1.1.2  mrg const supernode *
    266  1.1.1.2  mrg call_string::get_callee_node () const
    267  1.1.1.2  mrg {
    268  1.1.1.2  mrg   if(m_elements.is_empty ())
    269  1.1.1.2  mrg     return NULL;
    270  1.1.1.2  mrg   return m_elements[m_elements.length () - 1].m_callee;
    271  1.1.1.2  mrg }
    272  1.1.1.2  mrg 
    273  1.1.1.2  mrg /* Return the pointer to caller of the topmost call in the stack,
    274  1.1.1.2  mrg    or NULL if stack is empty.  */
    275  1.1.1.2  mrg const supernode *
    276  1.1.1.2  mrg call_string::get_caller_node () const
    277  1.1.1.2  mrg {
    278  1.1.1.2  mrg   if(m_elements.is_empty ())
    279  1.1.1.2  mrg     return NULL;
    280  1.1.1.2  mrg   return m_elements[m_elements.length () - 1].m_caller;
    281  1.1.1.2  mrg }
    282  1.1.1.2  mrg 
    283      1.1  mrg /* Assert that this object is sane.  */
    284      1.1  mrg 
    285      1.1  mrg void
    286      1.1  mrg call_string::validate () const
    287      1.1  mrg {
    288      1.1  mrg   /* Skip this in a release build.  */
    289      1.1  mrg #if !CHECKING_P
    290      1.1  mrg   return;
    291      1.1  mrg #endif
    292      1.1  mrg 
    293      1.1  mrg   /* Each entry's "caller" should be the "callee" of the previous entry.  */
    294  1.1.1.2  mrg   call_string::element_t *e;
    295      1.1  mrg   int i;
    296  1.1.1.2  mrg   FOR_EACH_VEC_ELT (m_elements, i, e)
    297      1.1  mrg     if (i > 0)
    298  1.1.1.2  mrg     {
    299  1.1.1.2  mrg       gcc_assert (e->get_caller_function () ==
    300  1.1.1.2  mrg       		  m_elements[i - 1].get_callee_function ());
    301  1.1.1.2  mrg     }
    302      1.1  mrg }
    303      1.1  mrg 
    304      1.1  mrg #endif /* #if ENABLE_ANALYZER */
    305