66
77\*******************************************************************/
88
9+ #include " call_graph.h"
910#include < util/std_expr.h>
1011#include < util/xml.h>
12+ #include < algorithm>
13+ #include < iterator>
1114
12- #include " call_graph.h"
1315
1416/* ******************************************************************\
1517
@@ -70,11 +72,31 @@ void call_grapht::add(
7072 {
7173 const exprt &function_expr=to_code_function_call (i_it->code ).function ();
7274 if (function_expr.id ()==ID_symbol)
73- add (function, to_symbol_expr (function_expr).get_identifier ());
75+ add (function, to_symbol_expr (function_expr).get_identifier (), {i_it} );
7476 }
7577 }
7678}
7779
80+ /* ******************************************************************\
81+
82+ Function: call_grapht::swap
83+
84+ Inputs:
85+
86+ Outputs:
87+
88+ Purpose:
89+
90+ \*******************************************************************/
91+
92+ void call_grapht::swap (call_grapht &other)
93+ {
94+ std::swap (graph, other.graph );
95+ std::swap (map_from_edges_to_call_locations,
96+ other.map_from_edges_to_call_locations );
97+ }
98+
99+
78100/* ******************************************************************\
79101
80102Function: call_grapht::add
@@ -96,7 +118,7 @@ void call_grapht::add(
96118
97119/* ******************************************************************\
98120
99- Function: call_grapht::output_dot
121+ Function: call_grapht::add
100122
101123 Inputs:
102124
@@ -106,37 +128,60 @@ Function: call_grapht::output_dot
106128
107129\*******************************************************************/
108130
109- void call_grapht::output_dot (std::ostream &out) const
131+ void call_grapht::add (
132+ const irep_idt &caller,
133+ const irep_idt &callee,
134+ const map_from_edges_to_call_locationst::mapped_type &call_sites)
110135{
111- out << " digraph call_graph { \n " ;
112-
113- for (const auto &edge : graph )
136+ bool exists= false ;
137+ const call_grapht::call_edges_ranget range= out_edges (caller);
138+ for (auto it=range. first ; it!=range. second ; ++it )
114139 {
115- out << " \" " << edge.first << " \" -> "
116- << " \" " << edge.second << " \" "
117- << " [arrowhead=\" vee\" ];"
118- << " \n " ;
140+ if (it->second ==callee)
141+ {
142+ exists=true ;
143+ break ;
144+ }
119145 }
120-
121- out << " }\n " ;
146+ if (!exists)
147+ add (caller, callee);
148+ std::copy (
149+ call_sites.cbegin (), call_sites.cend (),
150+ std::back_inserter (map_from_edges_to_call_locations[{caller, callee}]));
122151}
123152
124153
125- void call_grapht::output_dot (
126- const goto_functionst &functions,
127- std::ostream &out) const
154+ /* ******************************************************************\
155+
156+ Function: call_grapht::output_dot
157+
158+ Inputs:
159+
160+ Outputs:
161+
162+ Purpose:
163+
164+ \*******************************************************************/
165+
166+ void call_grapht::output_dot (std::ostream &out) const
128167{
129- out << " digraph call_graph {\n " ;
130- for (const auto &elem : functions.function_map )
131- out << " \" " << elem.first << " \" ;\n " ;
132- for (grapht::const_iterator it=graph.begin ();
133- it!=graph.end ();
134- it++)
168+ out << " digraph call_graph {\n "
169+ << " node [fontsize=12 shape=box];\n " ;
170+ for (const auto &edge : graph)
135171 {
136- out << " \" " << it->first << " \" -> "
137- << " \" " << it->second << " \" "
138- << " [arrowhead=\" vee\" ];"
139- << " \n " ;
172+ out << " \" " << edge.first << " \" -> "
173+ << " \" " << edge.second << " \" "
174+ << " [label=\" {" ;
175+ bool first=true ;
176+ for (const auto instr_it :
177+ get_map_from_edges_to_call_locations ().at ({edge.first , edge.second }))
178+ {
179+ if (!first)
180+ out << " ," ;
181+ out << instr_it->location_number ;
182+ first=false ;
183+ }
184+ out << " }\" ];\n " ;
140185 }
141186 out << " }\n " ;
142187}
@@ -382,7 +427,10 @@ void compute_inverted_call_graph(
382427{
383428 assert (output_inverted_call_graph.graph .empty ());
384429 for (const auto &elem : original_call_graph.graph )
385- output_inverted_call_graph.add (elem.second , elem.first );
430+ output_inverted_call_graph.add (
431+ elem.second , elem.first ,
432+ original_call_graph.get_map_from_edges_to_call_locations ().at (
433+ {elem.first , elem.second }));
386434}
387435
388436/* ******************************************************************\
@@ -443,3 +491,91 @@ void find_leaves_below_function(
443491 std::unordered_set<irep_idt, dstring_hash> to_avoid;
444492 find_leaves_below_function (call_graph, function, to_avoid, output);
445493}
494+
495+ /* ******************************************************************\
496+
497+ Function: find_direct_or_indirect_callees_of_function
498+
499+ Inputs:
500+
501+ Outputs:
502+
503+ Purpose:
504+
505+ \*******************************************************************/
506+
507+ void find_direct_or_indirect_callees_of_function (
508+ const call_grapht &call_graph,
509+ const irep_idt &function,
510+ std::unordered_set<irep_idt, dstring_hash> &output)
511+ {
512+ std::unordered_set<irep_idt, dstring_hash> leaves;
513+ find_leaves_below_function (call_graph, function, output, leaves);
514+ output.insert (leaves.cbegin (), leaves.cend ());
515+ }
516+
517+ /* ******************************************************************\
518+
519+ Function: find_nearest_common_callees
520+
521+ Inputs:
522+
523+ Outputs:
524+
525+ Purpose:
526+
527+ \*******************************************************************/
528+
529+ void find_nearest_common_callees (
530+ const call_grapht &call_graph,
531+ const std::set<irep_idt> &functions,
532+ std::set<irep_idt> &output)
533+ {
534+ if (functions.empty ())
535+ return ;
536+ if (functions.size ()==1UL )
537+ {
538+ output.insert (*functions.cbegin ());
539+ return ;
540+ }
541+
542+ std::map<irep_idt, std::size_t > counting;
543+ for (const auto &elem : call_graph.graph )
544+ {
545+ counting[elem.first ]=0U ;
546+ counting[elem.second ]=0U ;
547+ }
548+ for (const auto &fn : functions)
549+ {
550+ std::unordered_set<irep_idt, dstring_hash> callees;
551+ find_direct_or_indirect_callees_of_function (call_graph, fn, callees);
552+ assert (callees.count (fn)==1U );
553+ for (const auto &callee : callees)
554+ ++counting[callee];
555+ }
556+
557+ std::set<irep_idt> leaves;
558+ for (const auto &elem : counting)
559+ if (elem.second !=0U )
560+ {
561+ const call_grapht::call_edges_ranget range=
562+ call_graph.out_edges (elem.first );
563+ if (range.first ==range.second )
564+ leaves.insert (elem.first );
565+ }
566+
567+ for (auto &elem : counting)
568+ if (leaves.count (elem.first )!=0UL )
569+ output.insert (elem.first );
570+ else if (elem.second !=0U && elem.second <functions.size ())
571+ {
572+ const call_grapht::call_edges_ranget range=
573+ call_graph.out_edges (elem.first );
574+ for (auto it=range.first ; it!=range.second ; ++it)
575+ {
576+ auto cit=counting.find (it->second );
577+ if (cit->second ==functions.size ())
578+ output.insert (cit->first );
579+ }
580+ }
581+ }
0 commit comments