Skip to content

Commit bba343c

Browse files
author
Lefan Zhang
authored
Merge pull request diffblue#9 from lefanz-amazon/lefan-abstraction
need_abst: implementation and tests; previous PR: fix 3 comments
2 parents d157bf7 + c39d5fc commit bba343c

File tree

5 files changed

+175
-34
lines changed

5 files changed

+175
-34
lines changed

src/goto-instrument/abstraction.cpp

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Author: Lefan Zhang, [email protected]
1515
#include <queue>
1616

1717
#include <util/std_expr.h>
18+
#include <util/expr_util.h>
19+
#include <util/format_expr.h>
1820
#include <goto-programs/initialize_goto_model.h>
1921
#include <goto-programs/link_goto_model.h>
2022

@@ -206,7 +208,6 @@ const std::unordered_set<irep_idt> find_index_symbols(const goto_functiont &goto
206208
if(it->is_function_call())
207209
{
208210
const code_function_callt fc = it->get_function_call();
209-
code_function_callt::argumentst new_arguments = fc.arguments();
210211
exprt new_lhs = fc.lhs();
211212
etr.add_expr(fc.lhs());
212213

@@ -232,7 +233,7 @@ void complete_abst_spec(const goto_functiont& goto_function, abstraction_spect &
232233
{
233234
for(const auto &ent: spec.get_abst_arrays())
234235
for(irep_idt index_name: find_index_symbols(goto_function, ent.first))
235-
if(spec.get_abst_indices().find(index_name) != spec.get_abst_indices().end())
236+
if(spec.get_abst_indices().find(index_name) == spec.get_abst_indices().end())
236237
spec.insert_entity(index_name, true);
237238
}
238239
}
@@ -274,18 +275,16 @@ find_function_calls(irep_idt func_name, goto_modelt &goto_model, const abstracti
274275
// it is a function call that we potentially need to abstract
275276
const code_function_callt fc = it->get_function_call();
276277
const irep_idt &new_func_name = to_symbol_expr(fc.function()).get_identifier();
278+
const goto_functiont &new_function = goto_model.get_goto_function(new_func_name);
277279
std::unordered_map<irep_idt, irep_idt> map;
278280
for(size_t i=0; i<fc.arguments().size(); i++)
279281
{
280282
// for each argument, we check whether we need to abstract it.
281283
const exprt &arg = fc.arguments()[i];
282284
irep_idt symbol_name = check_expr_is_symbol(arg);
283285
if(symbol_name != "" && abst_spec.has_entity(symbol_name))
284-
{
285286
// if so, we push it into the map
286-
const goto_functiont &new_function = goto_model.get_goto_function(new_func_name);
287287
map.insert({symbol_name, new_function.parameter_identifiers[i]});
288-
}
289288
}
290289
if(!map.empty()) //if map is not empty, we create a new entry in the result
291290
result.push_back(std::make_tuple(new_func_name, map));
@@ -340,11 +339,39 @@ calculate_complete_abst_specs_for_funcs(goto_modelt &goto_model, abstraction_spe
340339
complete_abst_spec(goto_model.get_goto_function(new_func_name), new_func_abst);
341340
function_spec_map.insert({new_func_name, new_func_abst});
342341
}
342+
else
343+
{
344+
// we need to compare if the structure is the same
345+
abstraction_spect new_func_abst = function_spec_map[current_func_name].update_abst_spec(current_func_name, new_func_name, name_pairs);
346+
if(!new_func_abst.compare_shape(function_spec_map[new_func_name]))
347+
throw "Same function abstracted with different shape!";
348+
}
343349
}
344350
}
345351
return function_spec_map;
346352
}
347353

354+
bool contains_an_abstracted_entity(const exprt &expr, const abstraction_spect &abst_spec)
355+
{
356+
struct match_abst_symbolt
357+
{
358+
match_abst_symbolt(const abstraction_spect &_abst_spec) : abst_spec(_abst_spec) {}
359+
// check if expr is an entity symbol that we want to abstract
360+
bool operator()(const exprt &expr)
361+
{
362+
irep_idt symbol_name = check_expr_is_symbol(expr);
363+
return symbol_name != "" && abst_spec.has_entity(symbol_name);
364+
}
365+
protected:
366+
// we assume this abst_spec's life span covers
367+
// the life span of the match_abst_symbolt object
368+
const abstraction_spect &abst_spec;
369+
};
370+
match_abst_symbolt match_abst_symbol(abst_spec);
371+
return has_subexpr(expr, match_abst_symbol);
372+
373+
}
374+
348375
void abstract_goto_program(goto_modelt &goto_model, abstraction_spect &abst_spec)
349376
{
350377
// A couple of spects are initialized from the json file. We should go from there and insert spects to other functions
@@ -353,6 +380,37 @@ void abstract_goto_program(goto_modelt &goto_model, abstraction_spect &abst_spec
353380
for(auto &p: function_spec_map)
354381
{
355382
std::cout << "=========== " << p.first << " ===========" << std::endl;
383+
std::cout << "----------- " << "Entities to be abstracted" << " -----------" << std::endl;
356384
p.second.print_entities();
385+
std::cout << "----------- " << "Exprs containing the above entities" << " -----------" << std::endl;
386+
const goto_functiont &goto_function = goto_model.get_goto_function(p.first);
387+
const abstraction_spect &abst_spec = p.second;
388+
forall_goto_program_instructions(it, goto_function.body)
389+
{
390+
// go through conditions
391+
if(it->has_condition())
392+
if(contains_an_abstracted_entity(it->get_condition(), abst_spec))
393+
format_rec(std::cout, it->get_condition()) << std::endl;
394+
395+
// go through all expressions
396+
if(it->is_function_call())
397+
{
398+
const code_function_callt fc = it->get_function_call();
399+
if(contains_an_abstracted_entity(fc.lhs(), abst_spec))
400+
format_rec(std::cout, fc.lhs()) << std::endl;
401+
402+
for(const auto &arg : fc.arguments())
403+
if(contains_an_abstracted_entity(arg, abst_spec))
404+
format_rec(std::cout, arg) << std::endl;
405+
}
406+
else if(it->is_assign())
407+
{
408+
const code_assignt as = it->get_assign();
409+
if(contains_an_abstracted_entity(as.lhs(), abst_spec))
410+
format_rec(std::cout, as.lhs()) << std::endl;
411+
if(contains_an_abstracted_entity(as.rhs(), abst_spec))
412+
format_rec(std::cout, as.rhs()) << std::endl;
413+
}
414+
}
357415
}
358416
}

src/goto-instrument/abstraction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ const std::unordered_set<irep_idt> find_index_symbols(const goto_functiont &goto
6565
std::unordered_map<irep_idt, abstraction_spect>
6666
calculate_complete_abst_specs_for_funcs(goto_modelt &goto_model, abstraction_spect &abst_spec);
6767

68+
/// \param expr: the expression to be checked
69+
/// \param abst_spec: the abstraction_spect for the current function which contains all spects
70+
/// \return whether the expr contains an entity to be abstracted
71+
bool contains_an_abstracted_entity(const exprt &expr, const abstraction_spect &abst_spec);
72+
6873
// abstract goto programs
6974
void abstract_goto_program(goto_modelt &goto_model, abstraction_spect &abst_spec);
7075

src/goto-instrument/abstraction_spect.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ abstraction_spect::abstraction_spect(
3636
const auto &related_entity = to_json_object(*it_r);
3737
spec.insert_entity(related_entity.find("name")->second.value, related_entity.find("entity")->second.value=="array");
3838
}
39+
const auto &json_shape_obj = to_json_object(entry_obj.find("shape")->second);
40+
const auto &json_shape_i_array = to_json_array(json_shape_obj.find("indices")->second);
41+
const auto &json_shape_a_array = to_json_array(json_shape_obj.find("assumptions")->second);
42+
std::vector<irep_idt> indices;
43+
std::vector<std::string> assumptions;
44+
for(auto it_i=json_shape_i_array.begin(); it_i != json_shape_i_array.end(); ++it_i)
45+
indices.push_back(to_json_string(*it_i).value);
46+
for(auto it_a=json_shape_a_array.begin(); it_a != json_shape_a_array.end(); ++it_a)
47+
assumptions.push_back(to_json_string(*it_a).value);
48+
std::string shape_type = to_json_string(json_shape_obj.find("shape-type")->second).value;
49+
spec.set_shape(indices, assumptions, shape_type);
3950
specs.push_back(spec);
4051
}
4152
}
@@ -110,8 +121,13 @@ abstraction_spect abstraction_spect::update_abst_spec(
110121
new_abst_spec.function = new_function;
111122
for(const auto &spec: specs)
112123
{
113-
new_abst_spec.specs.push_back(spec.update_abst_spec(old_function, new_function, _name_pairs));
124+
spect new_spec = spec.update_abst_spec(old_function, new_function, _name_pairs);
125+
if(!spec.compare_shape_only(new_spec))
126+
throw "The updated spect's shape should be the same as the original one";
127+
new_abst_spec.specs.push_back(new_spec);
114128
}
129+
if(specs.size() != new_abst_spec.specs.size())
130+
throw "The updated specs' size should remain the same";
115131
return new_abst_spec;
116132
}
117133

src/goto-instrument/abstraction_spect.h

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,52 @@ class abstraction_spect
3131
struct spect
3232
{
3333
public:
34+
struct abst_shapet
35+
{
36+
std::vector<irep_idt> indices;
37+
std::vector<std::string> assumptions;
38+
std::string shape_type; // e.g. "*cc*"
39+
public:
40+
abst_shapet() {}
41+
abst_shapet(
42+
std::vector<irep_idt> _indices,
43+
std::vector<std::string> _assumptions,
44+
std::string _shape_type)
45+
: indices(_indices), assumptions(_assumptions), shape_type(_shape_type) {}
46+
abst_shapet(const abst_shapet &other)
47+
: indices(other.indices),
48+
assumptions(other.assumptions),
49+
shape_type(other.shape_type)
50+
{
51+
}
52+
void add_index(const irep_idt &_index)
53+
{
54+
indices.push_back(_index);
55+
}
56+
void add_assumption(const std::string &_assumption)
57+
{
58+
assumptions.push_back(_assumption);
59+
}
60+
void set_shape_type(const std::string &_shape_type)
61+
{
62+
shape_type = _shape_type;
63+
}
64+
bool operator==(const abst_shapet &other) const
65+
{
66+
if(indices.size() != other.indices.size())
67+
return false;
68+
if(assumptions.size() != other.assumptions.size())
69+
return false;
70+
for(size_t i=0; i<indices.size(); i++)
71+
if(indices[i] != other.indices[i])
72+
return false;
73+
for(size_t i=0; i<assumptions.size(); i++)
74+
if(assumptions[i] != other.assumptions[i])
75+
return false;
76+
return (shape_type == other.shape_type);
77+
}
78+
};
79+
3480
struct entityt
3581
{
3682
//Name of the array/list being abstracted
@@ -76,19 +122,8 @@ class abstraction_spect
76122
std::unordered_map<irep_idt, entityt> abst_indices;
77123
// std::vector<entityt> abst_indices;
78124

79-
//Names of references in increasing order
80-
//Each ref is stored with path+name of the array being abstracted along
81-
//with the name of ref itself (like c1, c2)
82-
std::vector<entityt> refs_name;
83-
84-
//Assumptions on the references
85-
std::vector<exprt> assumptions;
86-
87-
//List of variables directly indexing into array being abstracted.
88-
//This list is required to handle while-loops correctly. Say ind indexes into array f
89-
//and ind is used as iterator in the while loop. Then ind has to be abstracted ind-abs
90-
//so as to reduce it's range from an potentially large value to a small abstract range.
91-
std::vector<std::string> indices;
125+
// Shape of the abstraction
126+
abst_shapet shape;
92127

93128
//Abstraction functions follow. These should be defined in the abstraction_funcs_file or
94129
//they are hard-coded ones. In abstraction_funcs_file function will begin with prefixes
@@ -109,9 +144,7 @@ class abstraction_spect
109144
: abst_func_file(_spec.abst_func_file),
110145
abst_arrays(_spec.abst_arrays),
111146
abst_indices(_spec.abst_indices),
112-
refs_name(_spec.refs_name),
113-
assumptions(_spec.assumptions),
114-
indices(_spec.indices),
147+
shape(_spec.shape),
115148
is_precise_func(_spec.is_precise_func),
116149
compare_indices_func(_spec.compare_indices_func),
117150
addition_func(_spec.addition_func),
@@ -158,6 +191,33 @@ class abstraction_spect
158191
return abst_func_file;
159192
}
160193

194+
// set the shape
195+
void set_shape(const std::vector<irep_idt> &indices, const std::vector<std::string> &assumptions, const std::string &shape_type)
196+
{
197+
shape = abst_shapet(indices, assumptions, shape_type);
198+
}
199+
200+
// compare if two spect have the same abst shape
201+
bool compare_shape(const spect &other) const
202+
{
203+
if(abst_arrays.size() != other.abst_arrays.size())
204+
return false;
205+
if(abst_indices.size() != other.abst_indices.size())
206+
return false;
207+
for(const auto &array: abst_arrays)
208+
if(other.abst_arrays.find(array.first) == other.abst_arrays.end())
209+
return false;
210+
for(const auto &index: abst_indices)
211+
if(other.abst_indices.find(index.first) == other.abst_indices.end())
212+
return false;
213+
return shape == other.shape;
214+
}
215+
216+
bool compare_shape_only(const spect &other) const
217+
{
218+
return shape == other.shape;
219+
}
220+
161221
//We need to update the abstracted array/list/var names as we cross the function boundary.
162222
//For example, if function Foo has two arrays f1 and f2 that are abstracted.
163223
//Function Bar is defined as void Bar(array b1, array b2) and suppose Foo calls Bar(f1,f2).
@@ -199,6 +259,20 @@ class abstraction_spect
199259
return false;
200260
}
201261

262+
// compare if two spect have the same structure
263+
bool compare_shape(const abstraction_spect &other) const
264+
{
265+
// In the update_abst_spec function, the result and the
266+
// original one should have the same spects in terms
267+
// of both order and shape
268+
if(specs.size() != other.specs.size())
269+
return false;
270+
for(size_t i=0; i<specs.size(); i++)
271+
if(!specs[i].compare_shape(other.specs[i]))
272+
return false;
273+
return true;
274+
}
275+
202276
// print all entities
203277
void print_entities() const;
204278
protected:

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -763,18 +763,6 @@ int goto_instrument_parse_optionst::doit()
763763
return CPROVER_EXIT_SUCCESS;
764764
}
765765

766-
if(cmdline.isset("use-abstraction"))
767-
{
768-
// std::string filename = cmdline.get_value("use-abstraction");
769-
// jsont json;
770-
// parse_json(filename, ui_message_handler, json);
771-
772-
// abstract_goto_program(goto_model, json);
773-
std::cout << "abstract" << std::endl;
774-
775-
// return CPROVER_EXIT_SUCCESS;
776-
}
777-
778766
if(
779767
cmdline.isset("show-goto-functions") ||
780768
cmdline.isset("list-goto-functions"))

0 commit comments

Comments
 (0)