Skip to content

Commit 9d553bb

Browse files
committed
Aggressive slicer
1 parent 7f59231 commit 9d553bb

File tree

5 files changed

+273
-0
lines changed

5 files changed

+273
-0
lines changed

src/goto-instrument/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SRC = accelerate/accelerate.cpp \
1212
accelerate/scratch_program.cpp \
1313
accelerate/trace_automaton.cpp \
1414
accelerate/util.cpp \
15+
aggressive_slicer.cpp \
1516
alignment_checks.cpp \
1617
branch.cpp \
1718
call_sequences.cpp \
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*******************************************************************\
2+
3+
Module: Aggressive slicer
4+
5+
Author: Elizabeth Polgreen, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Aggressive program slicer
11+
12+
#include "aggressive_slicer.h"
13+
#include "remove_function.h"
14+
#include <analyses/call_graph_helpers.h>
15+
#include <goto-programs/goto_model.h>
16+
#include <goto-programs/show_properties.h>
17+
#include <util/message.h>
18+
19+
void aggressive_slicert::note_functions_to_keep(irep_idt destination_function)
20+
{
21+
if(preserve_all_direct_paths)
22+
{
23+
/// Note that we have previously disconnected all nodes unreachable
24+
/// from the start function,
25+
/// which means that any reaching functions are also reachable from
26+
/// the start function.
27+
for(const auto &func :
28+
get_reaching_functions(call_graph, destination_function))
29+
functions_to_keep.insert(func);
30+
}
31+
else
32+
{
33+
for(const auto &func : get_shortest_function_path(
34+
call_graph, start_function, destination_function))
35+
functions_to_keep.insert(func);
36+
}
37+
}
38+
39+
void aggressive_slicert::get_all_functions_containing_properties()
40+
{
41+
for(const auto &fct : goto_model.goto_functions.function_map)
42+
{
43+
if(!fct.second.is_inlined())
44+
{
45+
for(const auto &ins : fct.second.body.instructions)
46+
if(ins.is_assert())
47+
{
48+
if(functions_to_keep.insert(ins.function).second)
49+
note_functions_to_keep(ins.function);
50+
}
51+
}
52+
}
53+
}
54+
55+
void aggressive_slicert::find_functions_that_contain_name_snippet()
56+
{
57+
for(const auto &name_snippet : name_snippets)
58+
{
59+
forall_goto_functions(f_it, goto_model.goto_functions)
60+
{
61+
if(id2string(f_it->first).find(name_snippet) != std::string::npos)
62+
functions_to_keep.insert(f_it->first);
63+
}
64+
}
65+
}
66+
67+
void aggressive_slicert::doit()
68+
{
69+
messaget message(message_handler);
70+
71+
functions_to_keep.insert(INITIALIZE_FUNCTION);
72+
functions_to_keep.insert(start_function);
73+
74+
// if no properties are specified, preserve all functions containing
75+
// any property
76+
if(user_specified_properties.empty())
77+
{
78+
message.debug() << "No properties given, so aggressive slicer "
79+
<< "is running over all possible properties"
80+
<< messaget::eom;
81+
get_all_functions_containing_properties();
82+
}
83+
84+
// if a name snippet is given, get list of all functions containing
85+
// name snippet to preserve
86+
if(!name_snippets.empty())
87+
find_functions_that_contain_name_snippet();
88+
89+
for(const auto &p : user_specified_properties)
90+
{
91+
auto property_loc = find_property(p, goto_model.goto_functions);
92+
if(!property_loc.has_value())
93+
throw "unable to find property in call graph";
94+
note_functions_to_keep(property_loc.value().get_function());
95+
}
96+
97+
// Add functions within distance of shortest path functions
98+
// to the list
99+
if(call_depth != 0)
100+
{
101+
for(const auto &func : get_functions_reachable_within_n_steps(
102+
call_graph, functions_to_keep, call_depth))
103+
functions_to_keep.insert(func);
104+
}
105+
106+
message.debug() << "Preserving the following functions \n";
107+
for(const auto &func : functions_to_keep)
108+
message.debug() << func << messaget::eom;
109+
110+
forall_goto_functions(f_it, goto_model.goto_functions)
111+
{
112+
if(functions_to_keep.find(f_it->first) == functions_to_keep.end())
113+
remove_function(goto_model, f_it->first, message_handler);
114+
}
115+
}
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*******************************************************************\
2+
3+
Module: Aggressive Slicer
4+
5+
Author: Elizabeth Polgreen, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Aggressive slicer
11+
/// Consider the control flow graph of the goto program and a criterion
12+
/// description of aggressive slicer here
13+
14+
#ifndef CPROVER_GOTO_INSTRUMENT_AGGRESSIVE_SLICER_H
15+
#define CPROVER_GOTO_INSTRUMENT_AGGRESSIVE_SLICER_H
16+
17+
#include <list>
18+
#include <string>
19+
#include <unordered_set>
20+
21+
#include <util/irep.h>
22+
23+
#include <analyses/call_graph.h>
24+
25+
#include <linking/static_lifetime_init.h>
26+
27+
class goto_modelt;
28+
class message_handlert;
29+
30+
/// \brief The aggressive slicer removes the body of all the functions except
31+
/// those on the shortest path, those within the call-depth of the
32+
/// shortest path, those given by name as command line argument,
33+
/// and those that contain a given irep_idt snippet
34+
/// If no properties are set by the user, we preserve all functions on
35+
/// the shortest paths to each property.
36+
class aggressive_slicert
37+
{
38+
public:
39+
aggressive_slicert(goto_modelt &_goto_model, message_handlert &_msg)
40+
: preserve_all_direct_paths(false),
41+
goto_model(_goto_model),
42+
message_handler(_msg)
43+
{
44+
start_function = goto_model.goto_functions.entry_point();
45+
call_depth = 0;
46+
call_grapht undirected_call_graph =
47+
call_grapht::create_from_root_function(goto_model, start_function, false);
48+
call_graph = undirected_call_graph.get_directed_graph();
49+
}
50+
51+
/// \brief Removes the body of all functions except those on the
52+
/// shortest path or functions
53+
/// that are reachable from functions on the shortest path within
54+
/// N calls, where N is given by the parameter "distance"
55+
void doit();
56+
57+
/// \brief Adds a list of functions to the set of functions for the aggressive
58+
/// slicer to preserve
59+
/// \param function_list: a list of functions in form
60+
/// std::list<std::string>, as returned by get_cmdline_option.
61+
void preserve_functions(const std::list<std::string> &function_list)
62+
{
63+
for(const auto &f : function_list)
64+
functions_to_keep.insert(f);
65+
};
66+
67+
std::list<std::string> user_specified_properties;
68+
std::size_t call_depth;
69+
std::list<std::string> name_snippets;
70+
bool preserve_all_direct_paths;
71+
72+
private:
73+
irep_idt start_function;
74+
goto_modelt &goto_model;
75+
message_handlert &message_handler;
76+
std::set<irep_idt> functions_to_keep;
77+
call_grapht::directed_grapht call_graph;
78+
79+
/// \brief Finds all functions whose name contains a name snippet
80+
/// and adds them to the std::unordered_set of irep_idts of functions
81+
/// for the aggressive slicer to preserve
82+
void find_functions_that_contain_name_snippet();
83+
84+
/// \brief notes functions to keep in the slice based on the program
85+
/// start function and the given destination function. Functions are noted
86+
/// according to the configuration parameters set in the aggressive
87+
/// slicer, i.e., shortest path between two functions, or all direct paths.
88+
/// Inserts functions to preserve into the functions_to_keep set
89+
/// \param destination_function name of destination function for slice
90+
void note_functions_to_keep(irep_idt destination_function);
91+
92+
/// \brief Finds all functions that contain a property,
93+
/// and adds them to the list of functions to keep. This
94+
/// function is only called if no properties are given by the user.
95+
/// This behaviour mirrors the behaviour of the other program
96+
/// slicers (reachability, global, full)
97+
void get_all_functions_containing_properties();
98+
};
99+
100+
#endif /* CPROVER_GOTO_INSTRUMENT_AGGRESSIVE_SLICER_H */

src/goto-instrument/goto_instrument_parse_options.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Author: Daniel Kroening, [email protected]
100100
#include "remove_function.h"
101101
#include "splice_call.h"
102102
#include "version.h"
103+
#include "aggressive_slicer.h"
103104

104105
/// invoke main modules
105106
int goto_instrument_parse_optionst::doit()
@@ -1457,6 +1458,46 @@ void goto_instrument_parse_optionst::instrument_goto_program()
14571458
*message_handler);
14581459
}
14591460

1461+
// aggressive slicer
1462+
if(cmdline.isset("aggressive-slice"))
1463+
{
1464+
do_indirect_call_and_rtti_removal();
1465+
1466+
status() << "Slicing away initializations of unused global variables"
1467+
<< eom;
1468+
slice_global_inits(goto_model);
1469+
1470+
status() << "Performing an aggressive slice" << eom;
1471+
aggressive_slicert aggressive_slicer(goto_model, get_message_handler());
1472+
1473+
if(cmdline.isset("aggressive-slice-call-depth"))
1474+
aggressive_slicer.call_depth =
1475+
safe_string2unsigned(cmdline.get_value("aggressive-slice-call-depth"));
1476+
1477+
if(cmdline.isset("aggressive-slice-preserve-function"))
1478+
aggressive_slicer.preserve_functions(
1479+
cmdline.get_values("aggressive-slice-preserve-function"));
1480+
1481+
if(cmdline.isset("property"))
1482+
aggressive_slicer.user_specified_properties =
1483+
cmdline.get_values("property");
1484+
1485+
if(cmdline.isset("aggressive-slice-preserve-functions-containing"))
1486+
aggressive_slicer.name_snippets =
1487+
cmdline.get_values("aggressive-slice-preserve-functions-containing");
1488+
1489+
aggressive_slicer.preserve_all_direct_paths =
1490+
cmdline.isset("aggressive-slice-preserve-all-direct-paths");
1491+
1492+
aggressive_slicer.doit();
1493+
1494+
status() << "Performing a reachability slice" << eom;
1495+
if(cmdline.isset("property"))
1496+
reachability_slicer(goto_model, cmdline.get_values("property"));
1497+
else
1498+
reachability_slicer(goto_model);
1499+
}
1500+
14601501
// recalculate numbers, etc.
14611502
goto_model.goto_functions.update();
14621503
}
@@ -1562,6 +1603,17 @@ void goto_instrument_parse_optionst::help()
15621603
" --full-slice slice away instructions that don't affect assertions\n" // NOLINT(*)
15631604
" --property id slice with respect to specific property only\n" // NOLINT(*)
15641605
" --slice-global-inits slice away initializations of unused global variables\n" // NOLINT(*)
1606+
" --aggressive-slice remove bodies of any functions not on the shortest path between\n" // NOLINT(*)
1607+
" the start function and the function containing the property(s)\n" // NOLINT(*)
1608+
" --aggressive-slice-call-depth <n>\n"
1609+
" used with aggressive-slice, preserves all functions within <n> function calls\n" // NOLINT(*)
1610+
" of the functions on the shortest path\n"
1611+
" --aggressive-slice-preserve-function <f>\n"
1612+
" force the aggressive slicer to preserve function <f>\n" // NOLINT(*)
1613+
" --aggressive-slice-preserve-function containing <f>\n"
1614+
" force the aggressive slicer to preserve all functions with names containing <f>\n" // NOLINT(*)
1615+
"--aggressive-slice-preserve-all-direct-paths \n"
1616+
" force aggressive slicer to preserve all direct paths\n" // NOLINT(*)
15651617
"\n"
15661618
"Further transformations:\n"
15671619
" --constant-propagator propagate constants and simplify expressions\n" // NOLINT(*)

src/goto-instrument/goto_instrument_parse_options.h

+5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ Author: Daniel Kroening, [email protected]
9090
"(show-threaded)(list-calls-args)" \
9191
"(undefined-function-is-assume-false)" \
9292
"(remove-function-body):"\
93+
"(aggressive-slice)" \
94+
"(aggressive-slice-call-depth):" \
95+
"(aggressive-slice-preserve-function):" \
96+
"(aggressive-slice-preserve-functions-containing):" \
97+
"(aggressive-slice-preserve-all-direct-paths)" \
9398
OPT_FLUSH \
9499
"(splice-call):" \
95100
OPT_REMOVE_CALLS_NO_BODY \

0 commit comments

Comments
 (0)