Skip to content

Commit 7f7b2f7

Browse files
committed
Optimise symex state management for straight-line code with GOTOs
In the situation of merge on a state that hasn't been traversed (with a false guard) try and move the names into the destination state instead of a merge or copy operation.
1 parent 522cb4a commit 7f7b2f7

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

src/goto-symex/goto_symex_state.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,29 @@ class goto_statet
7373
unsigned remaining_vccs = 0;
7474

7575
/// Constructors
76+
goto_statet() = default;
77+
goto_statet &operator=(const goto_statet &other) = default;
78+
goto_statet &operator=(goto_statet &&other) = default;
79+
goto_statet(const goto_statet &other) = default;
80+
7681
explicit goto_statet(const class goto_symex_statet &s);
7782
explicit goto_statet(const symex_targett::sourcet &_source) : source(_source)
7883
{
7984
}
85+
86+
goto_statet(goto_statet &&other) :
87+
depth(other.depth),
88+
level2(other.level2),
89+
value_set(std::move(other.value_set)),
90+
guard(std::move(other.guard)),
91+
source(std::move(other.source)),
92+
propagation(std::move(other.propagation)),
93+
atomic_section_id(other.atomic_section_id),
94+
safe_pointers(other.safe_pointers),
95+
total_vccs(other.total_vccs),
96+
remaining_vccs(other.remaining_vccs)
97+
{
98+
}
8099
};
81100

82101
// stack frames -- these are used for function calls and

src/goto-symex/symex_goto.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ void goto_symext::symex_goto(statet &state)
155155
state_pc=goto_target;
156156
}
157157

158+
// Before any storing or splitting we need to copy the current state of
159+
// level 2 names, as no matter which symex strategy we use .
160+
symex_level2t::current_namest names = *state.level2.current_names;
161+
state.level2.local_generations = state.level2.local_generations
162+
? *state.level2.local_generations
163+
: names;
164+
158165
// Normally the next instruction to execute would be state_pc and we save
159166
// new_state_pc for later. But if we're executing from a saved state, then
160167
// new_state_pc should be the state that we saved from earlier, so let's
@@ -201,6 +208,13 @@ void goto_symext::symex_goto(statet &state)
201208
// pointing to; this needs to be inverted for the branch that we're saving,
202209
// so let its truth value for `backwards` be the same as ours for `forward`.
203210

211+
jump_target.state.level2.current_names = new symex_level2t::current_namest(
212+
*jump_target.state.level2.current_names);
213+
214+
jump_target.state.level2.local_generations =
215+
state.level2.local_generations ? *state.level2.local_generations
216+
: *jump_target.state.level2.current_names;
217+
204218
log.debug() << "Saving next instruction '"
205219
<< next_instruction.state.saved_target->source_location << "'"
206220
<< log.eom;
@@ -221,7 +235,14 @@ void goto_symext::symex_goto(statet &state)
221235
framet::goto_state_listt &goto_state_list =
222236
state.top().goto_state_map[new_state_pc];
223237

224-
goto_state_list.emplace_back(state);
238+
if(new_guard.is_true())
239+
{
240+
goto_state_list.push_back(std::move(state));
241+
}
242+
else
243+
{
244+
goto_state_list.push_back(statet::goto_statet(state));
245+
}
225246

226247
symex_transition(state, state_pc, backward);
227248

@@ -472,6 +493,14 @@ static void merge_names(
472493
// initialized and therefore an invalid target.
473494

474495
// These rules only apply to dynamic objects and locals.
496+
INVARIANT(
497+
!dest_state.guard.is_false(),
498+
"if the destination state is currently unreachable we shouldn't be doing "
499+
"a per-name merge");
500+
INVARIANT(
501+
!goto_state.guard.is_false(),
502+
"an unreachable state should never have been queued for merging");
503+
475504
if(dest_state.guard.is_false())
476505
rhs = goto_state_rhs;
477506
else if(goto_state.guard.is_false())
@@ -515,21 +544,29 @@ static void merge_names(
515544
}
516545

517546
void goto_symext::phi_function(
518-
const goto_statet &goto_state,
547+
statet::goto_statet &goto_state,
519548
statet &dest_state)
520549
{
550+
// If our destination is unreachable just replace with the incoming state.
551+
if(dest_state.guard.is_false())
552+
{
553+
dest_state.level2.local_generations = std::move(goto_state.level2.local_generations);
554+
dest_state.propagation = std::move(goto_state.propagation);
555+
return;
556+
}
557+
521558
if(
522-
goto_state.level2.current_names.empty() &&
523-
dest_state.level2.current_names.empty())
559+
goto_state.level2.get_current_names().empty() &&
560+
dest_state.level2.get_current_names().empty())
524561
return;
525562

526563
guardt diff_guard = goto_state.guard;
527564
// this gets the diff between the guards
528565
diff_guard -= dest_state.guard;
529566

530567
for_each2(
531-
goto_state.level2.current_names,
532-
dest_state.level2.current_names,
568+
goto_state.level2.get_current_names(),
569+
dest_state.level2.get_current_names(),
533570
[&](const ssa_exprt &ssa, unsigned goto_count, unsigned dest_count) {
534571
merge_names(
535572
goto_state,

src/goto-symex/symex_target.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ class symex_targett
5353
pc(_goto_program.instructions.begin())
5454
{
5555
}
56+
57+
sourcet(sourcet &&other) noexcept
58+
: thread_nr(other.thread_nr),
59+
function_id(other.function_id),
60+
pc(other.pc)
61+
{
62+
}
63+
64+
sourcet(const sourcet &other) = default;
65+
sourcet &operator=(const sourcet &other) = default;
66+
sourcet &operator=(sourcet &&other) = default;
5667
};
5768

5869
enum class assignment_typet

src/pointer-analysis/value_set.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ class value_sett
4545
{
4646
}
4747

48+
value_sett(value_sett &&other) :
49+
location_number(other.location_number),
50+
values(std::move(other.values))
51+
{
52+
}
53+
54+
value_sett(const value_sett &other) = default;
55+
56+
value_sett &operator=(const value_sett &other) = default;
57+
value_sett &operator=(value_sett &&other) = default;
58+
4859
virtual ~value_sett() = default;
4960

5061
static bool field_sensitive(const irep_idt &id, const typet &type);

0 commit comments

Comments
 (0)