11
11
12
12
#include < iosfwd>
13
13
#include < map>
14
+ #include < vector>
15
+ #include < unordered_set>
14
16
15
17
#include < goto-programs/goto_functions.h>
16
18
@@ -21,6 +23,15 @@ class call_grapht
21
23
explicit call_grapht (const goto_functionst &);
22
24
23
25
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
+
24
35
void output (std::ostream &out) const ;
25
36
void output_xml (std::ostream &out) const ;
26
37
@@ -32,6 +43,76 @@ class call_grapht
32
43
protected:
33
44
void add (const irep_idt &function,
34
45
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 ;
35
76
};
36
77
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
+
37
118
#endif // CPROVER_ANALYSES_CALL_GRAPH_H
0 commit comments