-
Notifications
You must be signed in to change notification settings - Fork 273
Aggressive slicer #1587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aggressive slicer #1587
Changes from 11 commits
eea9fa0
46a6804
5682636
ab074ea
d351506
13ad1b0
8fb9793
50aed74
1744113
1eeacb0
a80f9a4
6ce0cd8
fbc0478
35ee9e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ Author: Daniel Kroening, [email protected] | |
\*******************************************************************/ | ||
|
||
/// \file | ||
/// Function Call Graphs | ||
/// Function Call Graph | ||
|
||
#include "call_graph.h" | ||
|
||
|
@@ -18,14 +18,9 @@ call_grapht::call_grapht() | |
{ | ||
} | ||
|
||
call_grapht::call_grapht(const goto_modelt &goto_model): | ||
call_grapht(goto_model.goto_functions) | ||
call_grapht::call_grapht(const goto_modelt &goto_model) | ||
{ | ||
} | ||
|
||
call_grapht::call_grapht(const goto_functionst &goto_functions) | ||
{ | ||
forall_goto_functions(f_it, goto_functions) | ||
forall_goto_functions(f_it, goto_model.goto_functions) | ||
{ | ||
const goto_programt &body=f_it->second.body; | ||
add(f_it->first, body); | ||
|
@@ -51,50 +46,158 @@ void call_grapht::add( | |
const irep_idt &caller, | ||
const irep_idt &callee) | ||
{ | ||
graph.insert(std::pair<irep_idt, irep_idt>(caller, callee)); | ||
std::size_t caller_idx = node_numbering.number(caller); | ||
if(caller_idx >= nodes.size()) | ||
{ | ||
node_indext node_index = add_node(); | ||
nodes[node_index].function_name = caller; | ||
} | ||
|
||
std::size_t callee_idx = node_numbering.number(callee); | ||
if(callee_idx >= nodes.size()) | ||
{ | ||
node_indext node_index = add_node(); | ||
nodes[node_index].function_name = callee; | ||
} | ||
|
||
add_edge(caller_idx, callee_idx); | ||
} | ||
|
||
|
||
void call_grapht::output_dot_node(std::ostream &out, node_indext n) const | ||
{ | ||
const nodet &node = nodes.at(n); | ||
|
||
for(const auto &edge : node.out) | ||
{ | ||
out << " \"" << node.function_name << "\" -> " << "\"" | ||
<< nodes[edge.first].function_name << "\" " << " [arrowhead=\"vee\"];" | ||
<< "\n"; | ||
} | ||
} | ||
|
||
void call_grapht::output_xml_node(std::ostream &out, node_indext n) const | ||
{ | ||
const nodet &node = nodes.at(n); | ||
|
||
for(const auto &edge : node.out) | ||
{ | ||
out << "<call_graph_edge caller=\""; | ||
xmlt::escape_attribute(id2string(node.function_name), out); | ||
out << "\" callee=\""; | ||
xmlt::escape_attribute(id2string(nodes[edge.first].function_name), out); | ||
out << "\">\n"; | ||
} | ||
} | ||
|
||
void call_grapht::output_xml(std::ostream &out) const | ||
{ | ||
for(node_indext n = 0; n < nodes.size(); n++) | ||
output_xml_node(out, n); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would asking for an output_json be unreasonable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not unreasonable, it should also be added to grapht, which doesn't have one either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That'd be lovely. |
||
|
||
/// Returns an inverted copy of this call graph | ||
/// \return Inverted (callee -> caller) call graph | ||
call_grapht call_grapht::get_inverted() const | ||
{ | ||
call_grapht result; | ||
for(const auto &caller_callee : graph) | ||
result.add(caller_callee.second, caller_callee.first); | ||
for(const auto &n : nodes) | ||
{ | ||
for(const auto &i : n.in) | ||
result.add(n.function_name, nodes[i.first].function_name); | ||
} | ||
return result; | ||
} | ||
|
||
void call_grapht::output_dot(std::ostream &out) const | ||
std::list<irep_idt> call_grapht::shortest_function_path( | ||
irep_idt src, irep_idt dest) | ||
{ | ||
out << "digraph call_graph {\n"; | ||
|
||
for(const auto &edge : graph) | ||
std::list<irep_idt> result; | ||
node_indext src_idx, dest_idx; | ||
if(!get_node_index(src, src_idx)) | ||
throw "unable to find src function in call graph"; | ||
if(!get_node_index(dest, dest_idx)) | ||
throw "unable to find destination function in call graph"; | ||
|
||
patht path; | ||
shortest_path(src_idx, dest_idx, path); | ||
for(const auto &n : path) | ||
{ | ||
out << " \"" << edge.first << "\" -> " | ||
<< "\"" << edge.second << "\" " | ||
<< " [arrowhead=\"vee\"];" | ||
<< "\n"; | ||
result.push_back(nodes[n].function_name); | ||
} | ||
|
||
out << "}\n"; | ||
return result; | ||
} | ||
|
||
void call_grapht::output(std::ostream &out) const | ||
void call_grapht::reachable_within_n_steps( | ||
std::size_t steps, | ||
std::unordered_set<irep_idt, | ||
irep_id_hash> & function_list) | ||
{ | ||
for(const auto &edge : graph) | ||
std::list<node_indext> worklist; | ||
|
||
for(const auto &f : function_list) | ||
{ | ||
out << edge.first << " -> " << edge.second << "\n"; | ||
node_indext start_index; | ||
if(get_node_index(f, start_index)) | ||
worklist.push_back(start_index); | ||
else | ||
throw "function not found in call graph"; | ||
} | ||
|
||
// mark end of level 0 | ||
worklist.push_back(std::numeric_limits<std::size_t>::max()); | ||
std::size_t depth=0; | ||
|
||
while(!worklist.empty()) | ||
{ | ||
const node_indext id = worklist.front(); | ||
worklist.pop_front(); | ||
|
||
// check if we have hit end of level | ||
if(id == std::numeric_limits<std::size_t>::max()) | ||
{ | ||
depth++; | ||
// mark end of next level | ||
if(!worklist.empty()) | ||
worklist.push_back(id); | ||
continue; | ||
} | ||
function_list.insert(nodes[id].function_name); | ||
|
||
if(depth < steps) | ||
{ | ||
for(const auto &o : nodes[id].out) | ||
{ | ||
if(function_list.find(nodes[o.first].function_name) | ||
== function_list.end()) | ||
worklist.push_back(o.first); | ||
} | ||
} | ||
} | ||
} | ||
|
||
void call_grapht::output_xml(std::ostream &out) const | ||
std::unordered_set<irep_idt, irep_id_hash> | ||
call_grapht::reachable_functions(irep_idt start_function) | ||
{ | ||
for(const auto &edge : graph) | ||
std::unordered_set<irep_idt, irep_id_hash> result; | ||
std::list<node_indext> worklist; | ||
node_indext start_index; | ||
|
||
if(get_node_index(start_function, start_index)) | ||
worklist.push_back(start_index); | ||
else | ||
throw "no start function found in call graph"; | ||
|
||
while(!worklist.empty()) | ||
{ | ||
out << "<call_graph_edge caller=\""; | ||
xmlt::escape_attribute(id2string(edge.first), out); | ||
out << "\" callee=\""; | ||
xmlt::escape_attribute(id2string(edge.second), out); | ||
out << "\">\n"; | ||
const node_indext id = worklist.front(); | ||
worklist.pop_front(); | ||
|
||
result.insert(nodes[id].function_name); | ||
for(const auto &o : nodes[id].out) | ||
{ | ||
if(result.find(nodes[o.first].function_name) == result.end()) | ||
worklist.push_back(o.first); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much work would it be to move these algorithms out into util/graph.h. It seems like this might not be the only place we want to do a shortest path or bounded depth search. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is already a branch by Smowton that combines my call graph pull request and his, so I think I should probably incorporate this change into that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. If the two of you get together on this I'd be happy to review. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,34 +7,109 @@ Author: Daniel Kroening, [email protected] | |
\*******************************************************************/ | ||
|
||
/// \file | ||
/// Function Call Graphs | ||
/// Function Call Graph | ||
|
||
#ifndef CPROVER_ANALYSES_CALL_GRAPH_H | ||
#define CPROVER_ANALYSES_CALL_GRAPH_H | ||
|
||
#include <iosfwd> | ||
#include <map> | ||
#include <unordered_set> | ||
|
||
#include <goto-programs/goto_model.h> | ||
|
||
class call_grapht | ||
#include <util/irep.h> | ||
#include <util/graph.h> | ||
#include <util/numbering.h> | ||
|
||
|
||
/// \brief Function call graph: each node represents a function | ||
/// in the GOTO model, a directed edge from A to B indicates | ||
/// that function A calls function B. | ||
/// Inherits from grapht to allow forward and | ||
/// backward traversal of the function call graph | ||
struct call_graph_nodet: public graph_nodet<empty_edget> | ||
{ | ||
typedef graph_nodet<empty_edget>::edget edget; | ||
typedef graph_nodet<empty_edget>::edgest edgest; | ||
|
||
irep_idt function_name; | ||
bool visited = false; | ||
}; | ||
|
||
class call_grapht: public grapht<call_graph_nodet> | ||
{ | ||
public: | ||
call_grapht(); | ||
explicit call_grapht(const goto_modelt &); | ||
explicit call_grapht(const goto_functionst &); | ||
|
||
void output_dot(std::ostream &out) const; | ||
void output(std::ostream &out) const; | ||
void add(const irep_idt &caller, const irep_idt &callee); | ||
void output_xml(std::ostream &out) const; | ||
|
||
typedef std::multimap<irep_idt, irep_idt> grapht; | ||
grapht graph; | ||
|
||
void add(const irep_idt &caller, const irep_idt &callee); | ||
/// \return the inverted call graph | ||
call_grapht get_inverted() const; | ||
|
||
/// \brief get the names of all functions reachable from a start function | ||
/// \param start name of initial function | ||
/// \return set of all names of the reachable functions | ||
std::unordered_set<irep_idt, irep_id_hash> | ||
reachable_functions(irep_idt start); | ||
|
||
/// \brief Function returns the shortest path on the function call graph | ||
/// between a source and a destination function | ||
/// \param src name of the starting function | ||
/// \param dest name of the destination function | ||
/// \return list of function names on the shortest path between src and dest | ||
std::list<irep_idt>shortest_function_path(irep_idt src, irep_idt dest); | ||
|
||
/// \brief get the names of all functions reachable from a list of functions | ||
/// within N function call steps. | ||
/// \param function_list list of functions to start from. Functions reachable within | ||
/// N function call steps are appended to this list | ||
/// \param steps number of function call steps | ||
void reachable_within_n_steps(std::size_t steps, | ||
std::unordered_set<irep_idt, irep_id_hash> &function_list); | ||
|
||
|
||
/// get the index of the node that corresponds to a function name | ||
/// \param[in] function_name function_name passed by reference | ||
/// \param[out] n variable for the node index to be written to | ||
/// \return true if a node with the given function name exists, | ||
/// false if it does not exist | ||
bool get_node_index(const irep_idt& function_name, node_indext &n) const | ||
{ | ||
for(node_indext idx = 0; idx < nodes.size(); idx++) | ||
{ | ||
if(nodes[idx].function_name == function_name) | ||
{ | ||
n = idx; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/// \brief get a list of functions called by a function | ||
/// \param function_name the irep_idt of the function | ||
/// \return an unordered set of all functions called by function_name | ||
std::unordered_set<irep_idt, irep_id_hash> get_successors( | ||
const irep_idt& function_name) const | ||
{ | ||
std::unordered_set<irep_idt, irep_id_hash> result; | ||
node_indext function_idx; | ||
if(!get_node_index(function_name, function_idx)) | ||
return result; | ||
|
||
for(const auto &o : nodes[function_idx].out) | ||
result.insert(nodes[o.first].function_name); | ||
return result; | ||
} | ||
|
||
|
||
protected: | ||
void output_dot_node(std::ostream &out, node_indext n) const override; | ||
void output_xml_node(std::ostream &out, node_indext n) const; | ||
numbering<irep_idt> node_numbering; | ||
void add(const irep_idt &function, | ||
const goto_programt &body); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove this constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is left over from call graph changes. Will revert