6
6
7
7
\*******************************************************************/
8
8
9
+ #include " call_graph.h"
9
10
#include < util/std_expr.h>
10
11
#include < util/xml.h>
12
+ #include < algorithm>
13
+ #include < iterator>
11
14
12
- #include " call_graph.h"
13
15
14
16
/* ******************************************************************\
15
17
@@ -70,11 +72,31 @@ void call_grapht::add(
70
72
{
71
73
const exprt &function_expr=to_code_function_call (i_it->code ).function ();
72
74
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} );
74
76
}
75
77
}
76
78
}
77
79
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
+
78
100
/* ******************************************************************\
79
101
80
102
Function: call_grapht::add
@@ -96,7 +118,7 @@ void call_grapht::add(
96
118
97
119
/* ******************************************************************\
98
120
99
- Function: call_grapht::output_dot
121
+ Function: call_grapht::add
100
122
101
123
Inputs:
102
124
@@ -106,37 +128,60 @@ Function: call_grapht::output_dot
106
128
107
129
\*******************************************************************/
108
130
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)
110
135
{
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 )
114
139
{
115
- out << " \" " << edge.first << " \" -> "
116
- << " \" " << edge.second << " \" "
117
- << " [arrowhead=\" vee\" ];"
118
- << " \n " ;
140
+ if (it->second ==callee)
141
+ {
142
+ exists=true ;
143
+ break ;
144
+ }
119
145
}
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}]));
122
151
}
123
152
124
153
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
128
167
{
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)
135
171
{
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 " ;
140
185
}
141
186
out << " }\n " ;
142
187
}
@@ -382,7 +427,10 @@ void compute_inverted_call_graph(
382
427
{
383
428
assert (output_inverted_call_graph.graph .empty ());
384
429
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 }));
386
434
}
387
435
388
436
/* ******************************************************************\
@@ -443,3 +491,91 @@ void find_leaves_below_function(
443
491
std::unordered_set<irep_idt, dstring_hash> to_avoid;
444
492
find_leaves_below_function (call_graph, function, to_avoid, output);
445
493
}
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