Skip to content

Commit 6b815c8

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 3411274 commit 6b815c8

File tree

8 files changed

+76
-26
lines changed

8 files changed

+76
-26
lines changed

src/goto-instrument/accelerate/scratch_program.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ bool scratch_programt::check_sat(bool do_slice)
3535
output(ns, "scratch", std::cout);
3636
#endif
3737

38+
global_name_mapt global_map;
3839
symex_state = util_make_unique<goto_symex_statet>(
39-
symex_targett::sourcet(goto_functionst::entry_point(), *this));
40+
symex_targett::sourcet(goto_functionst::entry_point(), *this), global_map);
4041
symex.symex_with_state(
4142
*symex_state,
4243
[this](const irep_idt &key) -> const goto_functionst::goto_functiont & {

src/goto-symex/goto_symex_state.cpp

+49-14
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ Author: Daniel Kroening, [email protected]
2929

3030
static void get_l1_name(exprt &expr);
3131

32-
goto_symex_statet::goto_symex_statet(const symex_targett::sourcet &_source)
33-
: goto_statet(_source), symex_target(nullptr), record_events(true), dirty()
32+
goto_symex_statet::goto_symex_statet(
33+
const symex_targett::sourcet &_source,
34+
global_name_mapt &global_map)
35+
: goto_statet(_source),
36+
symex_target(nullptr),
37+
record_events(true),
38+
dirty(),
39+
global_name_map(global_map)
3440
{
3541
threads.resize(1);
3642
new_frame();
@@ -183,9 +189,7 @@ void goto_symex_statet::assignment(
183189
#endif
184190

185191
// do the l2 renaming
186-
const auto level2_it =
187-
level2.current_names.emplace(l1_identifier, std::make_pair(lhs, 0)).first;
188-
symex_renaming_levelt::increase_counter(level2_it);
192+
increase_generation(l1_identifier, lhs);
189193
set_l2_indices(lhs, ns);
190194

191195
// in case we happen to be multi-threaded, record the memory access
@@ -442,10 +446,7 @@ bool goto_symex_statet::l2_thread_read_encoding(
442446

443447
if(a_s_read.second.empty())
444448
{
445-
auto level2_it =
446-
level2.current_names.emplace(l1_identifier, std::make_pair(ssa_l1, 0))
447-
.first;
448-
symex_renaming_levelt::increase_counter(level2_it);
449+
increase_generation(l1_identifier, ssa_l1);
449450
a_s_read.first=level2.current_count(l1_identifier);
450451
}
451452

@@ -481,10 +482,6 @@ bool goto_symex_statet::l2_thread_read_encoding(
481482
return true;
482483
}
483484

484-
const auto level2_it =
485-
level2.current_names.emplace(l1_identifier, std::make_pair(ssa_l1, 0))
486-
.first;
487-
488485
// No event and no fresh index, but avoid constant propagation
489486
if(!record_events)
490487
{
@@ -494,7 +491,8 @@ bool goto_symex_statet::l2_thread_read_encoding(
494491
}
495492

496493
// produce a fresh L2 name
497-
symex_renaming_levelt::increase_counter(level2_it);
494+
increase_generation(l1_identifier, ssa_l1);
495+
498496
set_l2_indices(ssa_l1, ns);
499497
expr=ssa_l1;
500498

@@ -506,6 +504,43 @@ bool goto_symex_statet::l2_thread_read_encoding(
506504
return true;
507505
}
508506

507+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
508+
/// latest generation on this path.
509+
void goto_symex_statet::increase_generation(
510+
const irep_idt l1_identifier,
511+
const ssa_exprt &lhs)
512+
{
513+
auto current_emplace_res =
514+
level2.current_names.emplace(l1_identifier, std::make_pair(lhs, 0));
515+
auto global_emplace_res =
516+
global_name_map.emplace(l1_identifier, std::make_pair(lhs, 0));
517+
518+
global_emplace_res.first->second.second++;
519+
current_emplace_res.first->second.second =
520+
global_emplace_res.first->second.second;
521+
}
522+
523+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
524+
/// latest generation on this path. Does nothing if there isn't an expression
525+
/// keyed by the l1 identifier.
526+
void goto_symex_statet::increase_generation_if_exists(const irep_idt identifier)
527+
{
528+
// If we can't find the name in the local scope, don't increase the global
529+
// even if it exists there.
530+
auto current_names_iter = level2.current_names.find(identifier);
531+
if(current_names_iter == level2.current_names.end())
532+
return;
533+
534+
// If we have a global store, increment its generation count, then assign
535+
// that new value to our local scope.
536+
auto global_names_iter = global_name_map.find(identifier);
537+
if(global_names_iter != global_name_map.end())
538+
{
539+
global_names_iter->second.second++;
540+
current_names_iter->second.second = global_names_iter->second.second;
541+
}
542+
}
543+
509544
/// thread encoding
510545
bool goto_symex_statet::l2_thread_write_encoding(
511546
const ssa_exprt &expr,

src/goto-symex/goto_symex_state.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ struct framet
132132
}
133133
};
134134

135+
using global_name_mapt = std::map<irep_idt, std::pair<ssa_exprt, unsigned>>;
136+
135137
/// Central data structure: state.
136138

137139
/// The state is a persistent data structure that symex maintains as it
@@ -143,7 +145,9 @@ struct framet
143145
class goto_symex_statet final : public goto_statet
144146
{
145147
public:
146-
explicit goto_symex_statet(const symex_targett::sourcet &);
148+
goto_symex_statet(
149+
const symex_targett::sourcet &,
150+
global_name_mapt &global_map);
147151
~goto_symex_statet();
148152

149153
/// \brief Fake "copy constructor" that initializes the `symex_target` member
@@ -319,7 +323,17 @@ class goto_symex_statet final : public goto_statet
319323
/// \brief Should the additional validation checks be run?
320324
bool run_validation_checks;
321325

326+
/// Allocates a fresh L2 name for the given L1 identifier, and makes it the
327+
// latest generation on this path.
328+
void increase_generation(const irep_idt l1_identifier, const ssa_exprt &lhs);
329+
330+
/// Increases the generation of the L1 identifier. Does nothing if there
331+
/// isn't an expression keyed by it.
332+
void increase_generation_if_exists(const irep_idt identifier);
333+
322334
private:
335+
global_name_mapt &global_name_map;
336+
323337
/// \brief Dangerous, do not use
324338
///
325339
/// Copying a state S1 to S2 risks S2 pointing to a deallocated

src/goto-symex/path_storage.h

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

101+
/// Tracks fresh L2 names across an entire symex run. This will be shared
102+
/// across all states to allocate unique generations.
103+
global_name_mapt level2_names;
104+
101105
private:
102106
// Derived classes should override these methods, allowing the base class to
103107
// enforce preconditions.

src/goto-symex/renaming_level.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ void symex_level1t::operator()(ssa_exprt &ssa_expr) const
5858
ssa_expr.set_level_1(it->second.second);
5959
}
6060

61-
void symex_level1t::restore_from(
62-
const symex_renaming_levelt::current_namest &other)
61+
void symex_level1t::restore_from(const current_namest &other)
6362
{
6463
auto it = current_names.begin();
6564
for(const auto &pair : other)

src/goto-symex/symex_dead.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,5 @@ void goto_symext::symex_dead(statet &state)
4848
state.propagation.erase(l1_identifier);
4949

5050
// L2 renaming
51-
auto level2_it = state.level2.current_names.find(l1_identifier);
52-
if(level2_it != state.level2.current_names.end())
53-
symex_renaming_levelt::increase_counter(level2_it);
51+
state.increase_generation_if_exists(l1_identifier);
5452
}

src/goto-symex/symex_decl.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
6363
// L2 renaming
6464
// inlining may yield multiple declarations of the same identifier
6565
// within the same L1 context
66-
const auto level2_it =
67-
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 0))
68-
.first;
69-
symex_renaming_levelt::increase_counter(level2_it);
66+
state.increase_generation(l1_identifier, ssa);
67+
7068
const bool record_events=state.record_events;
7169
state.record_events=false;
7270
exprt expr_l2 = state.rename(std::move(ssa), ns);

src/goto-symex/symex_main.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
294294

295295
// create and prepare the state
296296
auto state = util_make_unique<statet>(
297-
symex_targett::sourcet(entry_point_id, start_function->body));
297+
symex_targett::sourcet(entry_point_id, start_function->body),
298+
path_storage.level2_names);
298299
CHECK_RETURN(!state->threads.empty());
299300
CHECK_RETURN(!state->call_stack().empty());
300301

0 commit comments

Comments
 (0)