Skip to content

Commit 85df6db

Browse files
marek-trtikpeterschrammel
authored andcommitted
Add call graph sorting and output functions
This adds an inverse-topological-order function (leaves first), and a call-graph-to-DOT function.
1 parent b40dc2b commit 85df6db

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

src/analyses/call_graph.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,28 @@ void call_grapht::output_dot(std::ostream &out) const
121121
out << "}\n";
122122
}
123123

124+
125+
void call_grapht::output_dot(
126+
goto_functionst const& functions,
127+
std::ostream &out
128+
) const
129+
{
130+
out << "digraph call_graph {\n";
131+
for (auto const& elem : functions.function_map)
132+
out << " \"" << elem.first << "\";\n";
133+
for(grapht::const_iterator it=graph.begin();
134+
it!=graph.end();
135+
it++)
136+
{
137+
out << " \"" << it->first << "\" -> "
138+
<< "\"" << it->second << "\" "
139+
<< " [arrowhead=\"vee\"];"
140+
<< "\n";
141+
}
142+
out << "}\n";
143+
}
144+
145+
124146
/*******************************************************************\
125147
126148
Function: call_grapht::output
@@ -164,3 +186,33 @@ void call_grapht::output_xml(std::ostream &out) const
164186
out << "\">\n";
165187
}
166188
}
189+
190+
191+
call_grapht::call_edges_ranget
192+
call_grapht::out_edges(irep_idt const& caller) const
193+
{
194+
return graph.equal_range(caller);
195+
}
196+
197+
198+
void inverted_partial_topological_order(
199+
call_grapht const& call_graph,
200+
irep_idt const& start_function,
201+
std::unordered_set<irep_idt,dstring_hash>& processed_functions,
202+
std::vector<irep_idt>& output
203+
)
204+
{
205+
if (processed_functions.count(start_function) != 0ULL)
206+
return;
207+
processed_functions.insert(start_function);
208+
call_grapht::call_edges_ranget const range =
209+
call_graph.out_edges(start_function);
210+
for (auto it = range.first; it != range.second; ++it)
211+
inverted_partial_topological_order(
212+
call_graph,
213+
it->second,
214+
processed_functions,
215+
output
216+
);
217+
output.push_back(start_function);
218+
}

src/analyses/call_graph.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include <iosfwd>
1313
#include <map>
14+
#include <vector>
15+
#include <unordered_set>
1416

1517
#include <goto-programs/goto_functions.h>
1618

@@ -21,6 +23,15 @@ class call_grapht
2123
explicit call_grapht(const goto_functionst &);
2224

2325
void output_dot(std::ostream &out) const;
26+
27+
/**
28+
* It writes this into the passed stream in the Graphviz's DOT format.
29+
* The method accepts also functions, because the callgraph does not
30+
* store funtions (nodes). It only stores edges (from caller to callee).
31+
* So, the resulting graph would not show not-called functions.
32+
*/
33+
void output_dot(goto_functionst const& functions, std::ostream &out) const;
34+
2435
void output(std::ostream &out) const;
2536
void output_xml(std::ostream &out) const;
2637

@@ -32,6 +43,76 @@ class call_grapht
3243
protected:
3344
void add(const irep_idt &function,
3445
const goto_programt &body);
46+
47+
public:
48+
/**
49+
* Each element of the call graph is a pair where the first element is a
50+
* name of a caller function and the second element is the name of a called
51+
* function. So, an iterator to any such element is actually an iterator to
52+
* an edge of the call graph.
53+
*/
54+
typedef grapht::const_iterator call_edge_iteratort;
55+
56+
/**
57+
* Since a call graph is implemented as a multimap, we use ranges
58+
* of call graph edges to represent out-edges from a node (a function)
59+
*/
60+
typedef std::pair<call_edge_iteratort,call_edge_iteratort> call_edges_ranget;
61+
62+
/**
63+
* It returns a range of edges represented by a pair of iterators. The
64+
* first iterator refers to the first edge in the range and the second
65+
* iterator the end of the range (that edge does NOT belong to the range).
66+
*
67+
* Usage:
68+
* irep_idt const caller_name = "foo";
69+
* call_grapht::call_edges_ranget const range =
70+
* my_call_graph.out_edges(caller_name);
71+
* std::cout << "Callees of " << caller_name << " are: ";
72+
* for (auto it = range.first; it != range.second; ++it)
73+
* std::cout << it->second << ", ";
74+
*/
75+
call_edges_ranget out_edges(irep_idt const& caller) const;
3576
};
3677

78+
/**
79+
* For DAG call graphs it computes an inverted topological order of all
80+
* functions in the call graph. Otherwise, it computes only a partial
81+
* inverted topological order (all loops are broken at some (randomly)
82+
* chosen edge to get a DAG). The topolocical order is stored in the
83+
* 'output' vector.
84+
*
85+
* Since the algorithm is implemented using DFS, those 'breaks' are
86+
* implemented naturally by a set of processed (vidited) functions.
87+
*
88+
* The function actually performs only one DFS from a passed 'start_function'.
89+
* So, to get whole inverted (partial) topological order of all functions in
90+
* the call graph, this function has to be called for all functions in the
91+
* program.
92+
*
93+
* NOTE: The order is 'inverted'. It means that
94+
*
95+
* Typical usage:
96+
* // Let's assume there is 'goto_modelt GM' and 'call_grapht CG'
97+
* std::vector<irep_idt> result; // Here we will store the topological order.
98+
* {
99+
* std::unordered_set<irep_idt,dstring_hash> processed;
100+
* for (auto const& elem : GM.goto_functions.function_map)
101+
* partial_topological_order(CG,elem.first,processed,result);
102+
* // Now we reverse the result to get the classic (partial)
103+
* // topological order instead of the inverted one.
104+
* std::reverse(result.begin(),result.end());
105+
* }
106+
* std::cout << "A (partial) topological order of my call graph is: ";
107+
* for (irep_idt const& fn_name : result)
108+
* std::cout << fn_name << ", ";
109+
*/
110+
void inverted_partial_topological_order(
111+
call_grapht const& call_graph,
112+
irep_idt const& start_function,
113+
std::unordered_set<irep_idt,dstring_hash>& processed_functions,
114+
std::vector<irep_idt>& output
115+
);
116+
117+
37118
#endif // CPROVER_ANALYSES_CALL_GRAPH_H

0 commit comments

Comments
 (0)