Skip to content

Commit 307d2b6

Browse files
committed
Add global name map to goto_symex_state
This global name map will be used to check what generation is currently available for each level1 name, and shared across all states. This will only be used when a particular state tries to find out what the next free generation is. The main draw of this is that all branches will now assign unique generations that won't clash with assignments done across other branches. One minor downside is that in VCC's the generation number might jump sporadically (say from diffblue#4 to diffblue#40).
1 parent 4e1ffcc commit 307d2b6

10 files changed

+89
-33
lines changed

src/goto-instrument/accelerate/scratch_program.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ bool scratch_programt::check_sat(bool do_slice, guard_managert &guard_manager)
3737

3838
symex_state = util_make_unique<goto_symex_statet>(
3939
symex_targett::sourcet(goto_functionst::entry_point(), *this),
40-
guard_manager);
40+
guard_manager,
41+
[this](const irep_idt &id) {
42+
return path_storage.get_unique_l2_index(id);
43+
});
44+
4145
symex.symex_with_state(
4246
*symex_state,
4347
[this](const irep_idt &key) -> const goto_functionst::goto_functiont & {

src/goto-symex/goto_symex_state.cpp

+33-14
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ static void get_l1_name(exprt &expr);
3131

3232
goto_symex_statet::goto_symex_statet(
3333
const symex_targett::sourcet &_source,
34-
guard_managert &manager)
34+
guard_managert &manager,
35+
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider)
3536
: goto_statet(_source, manager),
3637
guard_manager(manager),
3738
symex_target(nullptr),
3839
record_events(true),
39-
dirty()
40+
dirty(),
41+
fresh_l2_name_provider(fresh_l2_name_provider)
4042
{
4143
threads.emplace_back(guard_manager);
4244
call_stack().new_frame(source);
@@ -212,9 +214,7 @@ void goto_symex_statet::assignment(
212214
#endif
213215

214216
// do the l2 renaming
215-
const auto level2_it =
216-
level2.current_names.emplace(l1_identifier, std::make_pair(lhs, 0)).first;
217-
symex_renaming_levelt::increase_counter(level2_it);
217+
increase_generation(l1_identifier, lhs);
218218
lhs = set_indices<L2>(std::move(lhs), ns).get();
219219

220220
// in case we happen to be multi-threaded, record the memory access
@@ -439,10 +439,7 @@ bool goto_symex_statet::l2_thread_read_encoding(
439439

440440
if(a_s_read.second.empty())
441441
{
442-
auto level2_it =
443-
level2.current_names.emplace(l1_identifier, std::make_pair(ssa_l1, 0))
444-
.first;
445-
symex_renaming_levelt::increase_counter(level2_it);
442+
increase_generation(l1_identifier, ssa_l1);
446443
a_s_read.first=level2.current_count(l1_identifier);
447444
}
448445
const renamedt<ssa_exprt, L2> l2_false_case = set_indices<L2>(ssa_l1, ns);
@@ -476,10 +473,6 @@ bool goto_symex_statet::l2_thread_read_encoding(
476473
return true;
477474
}
478475

479-
const auto level2_it =
480-
level2.current_names.emplace(l1_identifier, std::make_pair(ssa_l1, 0))
481-
.first;
482-
483476
// No event and no fresh index, but avoid constant propagation
484477
if(!record_events)
485478
{
@@ -488,7 +481,7 @@ bool goto_symex_statet::l2_thread_read_encoding(
488481
}
489482

490483
// produce a fresh L2 name
491-
symex_renaming_levelt::increase_counter(level2_it);
484+
increase_generation(l1_identifier, ssa_l1);
492485
expr = set_indices<L2>(std::move(ssa_l1), ns).get();
493486

494487
// and record that
@@ -499,6 +492,32 @@ bool goto_symex_statet::l2_thread_read_encoding(
499492
return true;
500493
}
501494

495+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
496+
/// latest generation on this path.
497+
void goto_symex_statet::increase_generation(
498+
const irep_idt l1_identifier,
499+
const ssa_exprt &lhs)
500+
{
501+
auto current_emplace_res =
502+
level2.current_names.emplace(l1_identifier, std::make_pair(lhs, 0));
503+
504+
current_emplace_res.first->second.second =
505+
fresh_l2_name_provider(l1_identifier);
506+
}
507+
508+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
509+
/// latest generation on this path. Does nothing if there isn't an expression
510+
/// keyed by the l1 identifier.
511+
void goto_symex_statet::increase_generation_if_exists(const irep_idt identifier)
512+
{
513+
// If we can't find the name in the local scope, this is a no-op.
514+
auto current_names_iter = level2.current_names.find(identifier);
515+
if(current_names_iter == level2.current_names.end())
516+
return;
517+
518+
current_names_iter->second.second = fresh_l2_name_provider(identifier);
519+
}
520+
502521
/// thread encoding
503522
bool goto_symex_statet::l2_thread_write_encoding(
504523
const ssa_exprt &expr,

src/goto-symex/goto_symex_state.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ Author: Daniel Kroening, [email protected]
4242
class goto_symex_statet final : public goto_statet
4343
{
4444
public:
45-
goto_symex_statet(const symex_targett::sourcet &, guard_managert &manager);
45+
goto_symex_statet(
46+
const symex_targett::sourcet &,
47+
guard_managert &manager,
48+
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider);
4649
~goto_symex_statet();
4750

4851
/// \brief Fake "copy constructor" that initializes the `symex_target` member
@@ -200,7 +203,17 @@ class goto_symex_statet final : public goto_statet
200203
unsigned total_vccs = 0;
201204
unsigned remaining_vccs = 0;
202205

206+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
207+
// latest generation on this path.
208+
void increase_generation(const irep_idt l1_identifier, const ssa_exprt &lhs);
209+
210+
/// Increases the generation of the L1 identifier. Does nothing if there
211+
/// isn't an expression keyed by it.
212+
void increase_generation_if_exists(const irep_idt identifier);
213+
203214
private:
215+
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider;
216+
204217
/// \brief Dangerous, do not use
205218
///
206219
/// Copying a state S1 to S2 risks S2 pointing to a deallocated

src/goto-symex/path_storage.h

+25-8
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,16 @@ class path_storaget
9898
/// error-handling paths.
9999
std::unordered_map<irep_idt, local_safe_pointerst> safe_pointers;
100100

101-
/// Provide a unique index for a given \p id, starting from \p minimum_index.
102-
std::size_t get_unique_index(const irep_idt &id, std::size_t minimum_index)
101+
/// Provide a unique L1 index for a given \p id, starting from
102+
/// \p minimum_index.
103+
std::size_t get_unique_l1_index(const irep_idt &id, std::size_t minimum_index)
103104
{
104-
auto entry = unique_index_map.emplace(id, minimum_index);
105-
106-
if(!entry.second)
107-
entry.first->second = std::max(entry.first->second + 1, minimum_index);
105+
return get_unique_index(l1_indices, id, minimum_index);
106+
}
108107

109-
return entry.first->second;
108+
std::size_t get_unique_l2_index(const irep_idt &id)
109+
{
110+
return get_unique_index(l2_indices, id, 1);
110111
}
111112

112113
private:
@@ -115,8 +116,24 @@ class path_storaget
115116
virtual patht &private_peek() = 0;
116117
virtual void private_pop() = 0;
117118

119+
typedef std::unordered_map<irep_idt, std::size_t> name_index_mapt;
120+
121+
std::size_t get_unique_index(
122+
name_index_mapt &unique_index_map,
123+
const irep_idt &id,
124+
std::size_t minimum_index)
125+
{
126+
auto entry = unique_index_map.emplace(id, minimum_index);
127+
128+
if(!entry.second)
129+
entry.first->second = std::max(entry.first->second + 1, minimum_index);
130+
131+
return entry.first->second;
132+
}
133+
118134
/// Storage used by \ref get_unique_index.
119-
std::unordered_map<irep_idt, std::size_t> unique_index_map;
135+
name_index_mapt l1_indices;
136+
name_index_mapt l2_indices;
120137
};
121138

122139
/// \brief LIFO save queue: depth-first search, try to finish paths

src/goto-symex/renaming_level.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ operator()(renamedt<ssa_exprt, L1> l1_expr) const
7373
return renamedt<ssa_exprt, L2>{std::move(l1_expr.value)};
7474
}
7575

76-
void symex_level1t::restore_from(
77-
const symex_renaming_levelt::current_namest &other)
76+
void symex_level1t::restore_from(const current_namest &other)
7877
{
7978
auto it = current_names.begin();
8079
for(const auto &pair : other)

src/goto-symex/symex_dead.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ void goto_symext::symex_dead(statet &state)
4343
// map is safe as 1) it is local to a path and 2) this instance can no longer
4444
// appear
4545
state.propagation.erase(l1_identifier);
46+
4647
// increment the L2 index to ensure a merge on join points will propagate the
4748
// value for branches that are still live
48-
auto level2_it = state.level2.current_names.find(l1_identifier);
49-
if(level2_it != state.level2.current_names.end())
50-
symex_renaming_levelt::increase_counter(level2_it);
49+
state.increase_generation_if_exists(l1_identifier);
5150
}

src/goto-symex/symex_decl.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
4343
ssa_exprt ssa = state.add_object(
4444
expr,
4545
[this](const irep_idt &l0_name) {
46-
return path_storage.get_unique_index(l0_name, 1);
46+
return path_storage.get_unique_l1_index(l0_name, 1);
4747
},
4848
ns);
4949
const irep_idt &l1_identifier = ssa.get_identifier();
@@ -70,6 +70,7 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
7070
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 1))
7171
.second;
7272
CHECK_RETURN(is_new);
73+
7374
const bool record_events=state.record_events;
7475
state.record_events=false;
7576
exprt expr_l2 = state.rename(std::move(ssa), ns);

src/goto-symex/symex_function_call.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ static void locality(
402402
(void)state.add_object(
403403
ns.lookup(param).symbol_expr(),
404404
[&path_storage, &frame_nr](const irep_idt &l0_name) {
405-
return path_storage.get_unique_index(l0_name, frame_nr);
405+
return path_storage.get_unique_l1_index(l0_name, frame_nr);
406406
},
407407
ns);
408408
}

src/goto-symex/symex_main.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,11 @@ std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
327327
// create and prepare the state
328328
auto state = util_make_unique<statet>(
329329
symex_targett::sourcet(entry_point_id, start_function->body),
330-
guard_manager);
330+
guard_manager,
331+
[this](const irep_idt &id) {
332+
return path_storage.get_unique_l2_index(id);
333+
});
334+
331335
CHECK_RETURN(!state->threads.empty());
332336
CHECK_RETURN(!state->call_stack().empty());
333337

src/goto-symex/symex_start_thread.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void goto_symext::symex_start_thread(statet &state)
6767
// get L0 name for current thread
6868
lhs.set_level_0(t);
6969
const irep_idt &l0_name = lhs.get_identifier();
70-
std::size_t l1_index = path_storage.get_unique_index(l0_name, 0);
70+
std::size_t l1_index = path_storage.get_unique_l1_index(l0_name, 0);
7171
CHECK_RETURN(l1_index == 0);
7272

7373
// set up L1 name

0 commit comments

Comments
 (0)