1 /* Call stacks at program points.
2 Copyright (C) 2019-2021 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
24 #include "pretty-print.h"
28 #include "analyzer/call-string.h"
29 #include "ordered-hash-map.h"
34 #include "basic-block.h"
36 #include "gimple-iterator.h"
38 #include "analyzer/supergraph.h"
43 #pragma GCC diagnostic ignored "-Wformat-diag"
46 /* class call_string. */
48 /* struct call_string::element_t. */
50 /* call_string::element_t's equality operator. */
53 call_string::element_t::operator== (const call_string::element_t
&other
) const
55 return (m_caller
== other
.m_caller
&& m_callee
== other
.m_callee
);
58 /* call_string::element_t's inequality operator. */
60 call_string::element_t::operator!= (const call_string::element_t
&other
) const
62 return !(*this == other
);
66 call_string::element_t::get_caller_function () const
68 return m_caller
->get_function ();
72 call_string::element_t::get_callee_function () const
74 return m_callee
->get_function ();
77 /* call_string's copy ctor. */
79 call_string::call_string (const call_string
&other
)
80 : m_elements (other
.m_elements
.length ())
82 for (const call_string::element_t
&e
: other
.m_elements
)
83 m_elements
.quick_push (e
);
86 /* call_string's assignment operator. */
89 call_string::operator= (const call_string
&other
)
91 // would be much simpler if we could rely on vec<> assignment op
92 m_elements
.truncate (0);
93 m_elements
.reserve (other
.m_elements
.length (), true);
94 call_string::element_t
*e
;
96 FOR_EACH_VEC_ELT (other
.m_elements
, i
, e
)
97 m_elements
.quick_push (*e
);
101 /* call_string's equality operator. */
104 call_string::operator== (const call_string
&other
) const
106 if (m_elements
.length () != other
.m_elements
.length ())
108 call_string::element_t
*e
;
110 FOR_EACH_VEC_ELT (m_elements
, i
, e
)
111 if (*e
!= other
.m_elements
[i
])
116 /* Print this to PP. */
119 call_string::print (pretty_printer
*pp
) const
123 call_string::element_t
*e
;
125 FOR_EACH_VEC_ELT (m_elements
, i
, e
)
128 pp_string (pp
, ", ");
129 pp_printf (pp
, "(SN: %i -> SN: %i in %s)",
130 e
->m_callee
->m_index
, e
->m_caller
->m_index
,
131 function_name (e
->m_caller
->m_fun
));
137 /* Return a new json::array of the form
138 [{"src_snode_idx" : int,
139 "dst_snode_idx" : int,
141 ...for each element in the callstring]. */
144 call_string::to_json () const
146 json::array
*arr
= new json::array ();
148 for (const call_string::element_t
&e
: m_elements
)
150 json::object
*e_obj
= new json::object ();
151 e_obj
->set ("src_snode_idx",
152 new json::integer_number (e
.m_callee
->m_index
));
153 e_obj
->set ("dst_snode_idx",
154 new json::integer_number (e
.m_caller
->m_index
));
155 e_obj
->set ("funcname",
156 new json::string (function_name (e
.m_caller
->m_fun
)));
163 /* Generate a hash value for this call_string. */
166 call_string::hash () const
168 inchash::hash hstate
;
169 for (const call_string::element_t
&e
: m_elements
)
170 hstate
.add_ptr (e
.m_caller
);
171 return hstate
.end ();
174 /* Push the return superedge for CALL_SEDGE onto the end of this
178 call_string::push_call (const supergraph
&sg
,
179 const call_superedge
*call_sedge
)
181 gcc_assert (call_sedge
);
182 const return_superedge
*return_sedge
= call_sedge
->get_edge_for_return (sg
);
183 gcc_assert (return_sedge
);
184 call_string::element_t
e (return_sedge
->m_dest
, return_sedge
->m_src
);
185 m_elements
.safe_push (e
);
189 call_string::push_call (const supernode
*caller
,
190 const supernode
*callee
)
192 call_string::element_t
e (caller
, callee
);
193 m_elements
.safe_push (e
);
196 call_string::element_t
199 return m_elements
.pop();
202 /* Count the number of times the top-most call site appears in the
205 call_string::calc_recursion_depth () const
207 if (m_elements
.is_empty ())
209 const call_string::element_t top_return_sedge
210 = m_elements
[m_elements
.length () - 1];
213 for (const call_string::element_t
&e
: m_elements
)
214 if (e
== top_return_sedge
)
219 /* Comparator for call strings.
220 This implements a version of lexicographical order.
221 Return negative if A is before B.
222 Return positive if B is after A.
223 Return 0 if they are equal. */
226 call_string::cmp (const call_string
&a
,
227 const call_string
&b
)
229 unsigned len_a
= a
.length ();
230 unsigned len_b
= b
.length ();
235 /* Consider index i; the strings have been equal up to it. */
237 /* Have both strings run out? */
238 if (i
>= len_a
&& i
>= len_b
)
241 /* Otherwise, has just one of the strings run out? */
247 /* Otherwise, compare the node pairs. */
248 const call_string::element_t a_node_pair
= a
[i
];
249 const call_string::element_t b_node_pair
= b
[i
];
251 = a_node_pair
.m_callee
->m_index
- b_node_pair
.m_callee
->m_index
;
255 = a_node_pair
.m_caller
->m_index
- b_node_pair
.m_caller
->m_index
;
259 // TODO: test coverage for this
263 /* Return the pointer to callee of the topmost call in the stack,
264 or NULL if stack is empty. */
266 call_string::get_callee_node () const
268 if(m_elements
.is_empty ())
270 return m_elements
[m_elements
.length () - 1].m_callee
;
273 /* Return the pointer to caller of the topmost call in the stack,
274 or NULL if stack is empty. */
276 call_string::get_caller_node () const
278 if(m_elements
.is_empty ())
280 return m_elements
[m_elements
.length () - 1].m_caller
;
283 /* Assert that this object is sane. */
286 call_string::validate () const
288 /* Skip this in a release build. */
293 /* Each entry's "caller" should be the "callee" of the previous entry. */
294 call_string::element_t
*e
;
296 FOR_EACH_VEC_ELT (m_elements
, i
, e
)
299 gcc_assert (e
->get_caller_function () ==
300 m_elements
[i
- 1].get_callee_function ());
304 #endif /* #if ENABLE_ANALYZER */