Skip to content

Commit 58627be

Browse files
committed
Aggressive slicer
Aggressive slicer removes functions that may be relevant to the property/ies concerned. Preserves either all direct paths, or all functions on shortest path between start function(s) and function(s) containing property/ies. Can be configured as described in the help text.
1 parent 810b70c commit 58627be

File tree

5 files changed

+262
-0
lines changed

5 files changed

+262
-0
lines changed

src/goto-instrument/Makefile

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

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Author: Daniel Kroening, [email protected]
100100
#include "undefined_functions.h"
101101
#include "remove_function.h"
102102
#include "splice_call.h"
103+
#include "aggressive_slicer.h"
103104

104105
/// invoke main modules
105106
int goto_instrument_parse_optionst::doit()
@@ -1433,6 +1434,46 @@ void goto_instrument_parse_optionst::instrument_goto_program()
14331434
*message_handler);
14341435
}
14351436

1437+
// aggressive slicer
1438+
if(cmdline.isset("aggressive-slice"))
1439+
{
1440+
do_indirect_call_and_rtti_removal();
1441+
1442+
status() << "Slicing away initializations of unused global variables"
1443+
<< eom;
1444+
slice_global_inits(goto_model);
1445+
1446+
status() << "Performing an aggressive slice" << eom;
1447+
aggressive_slicert aggressive_slicer(goto_model, get_message_handler());
1448+
1449+
if(cmdline.isset("call-depth"))
1450+
aggressive_slicer.call_depth =
1451+
safe_string2unsigned(cmdline.get_value("call-depth"));
1452+
1453+
if(cmdline.isset("preserve-function"))
1454+
aggressive_slicer.preserve_functions(
1455+
cmdline.get_values("preserve-function"));
1456+
1457+
if(cmdline.isset("property"))
1458+
aggressive_slicer.user_specified_properties =
1459+
cmdline.get_values("property");
1460+
1461+
if(cmdline.isset("preserve-functions-containing"))
1462+
aggressive_slicer.name_snippets =
1463+
cmdline.get_values("preserve-functions-containing");
1464+
1465+
aggressive_slicer.preserve_all_direct_paths =
1466+
cmdline.isset("preserve-all-direct-paths");
1467+
1468+
aggressive_slicer.doit();
1469+
1470+
status() << "Performing a reachability slice" << eom;
1471+
if(cmdline.isset("property"))
1472+
reachability_slicer(goto_model, cmdline.get_values("property"));
1473+
else
1474+
reachability_slicer(goto_model);
1475+
}
1476+
14361477
// recalculate numbers, etc.
14371478
goto_model.goto_functions.update();
14381479
}
@@ -1535,6 +1576,14 @@ void goto_instrument_parse_optionst::help()
15351576
" --full-slice slice away instructions that don't affect assertions\n" // NOLINT(*)
15361577
" --property id slice with respect to specific property only\n" // NOLINT(*)
15371578
" --slice-global-inits slice away initializations of unused global variables\n" // NOLINT(*)
1579+
" --aggressive-slice remove bodies of any functions not on the shortest path between\n" // NOLINT(*)
1580+
" the start function and the function containing the property(s)\n" // NOLINT(*)
1581+
" --call-depth <n> used with aggressive-slice, preserves all functions within <n> function calls\n" // NOLINT(*)
1582+
" of the functions on the shortest path\n"
1583+
" --preserve-function <f> force the aggressive slicer to preserve function <f>\n" // NOLINT(*)
1584+
" --preserve-function containing <f>\n"
1585+
" force the aggressive slicer to preserve all functions with names containing <f>\n" // NOLINT(*)
1586+
"--preserve-all-direct-paths force aggressive slicer to preserve all direct paths\n"
15381587
"\n"
15391588
"Further transformations:\n"
15401589
" --constant-propagator propagate constants and simplify expressions\n" // NOLINT(*)

src/goto-instrument/goto_instrument_parse_options.h

Lines changed: 5 additions & 0 deletions
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+
"(call-depth):" \
95+
"(preserve-function):" \
96+
"(preserve-functions-containing):" \
97+
"(preserve-all-direct-paths)" \
9398
OPT_FLUSH \
9499
"(splice-call):" \
95100
OPT_REMOVE_CALLS_NO_BODY \

0 commit comments

Comments
 (0)