Skip to content

Commit 3dee27d

Browse files
authored
Merge pull request #5673 from tautschnig/pop_frame
goto-symex: avoid redundant operations in pop_frame
2 parents e23bf5c + 99b2957 commit 3dee27d

File tree

1 file changed

+32
-47
lines changed

1 file changed

+32
-47
lines changed

src/goto-symex/symex_function_call.cpp

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -360,57 +360,42 @@ static void pop_frame(
360360
{
361361
PRECONDITION(!state.call_stack().empty());
362362

363+
const framet &frame = state.call_stack().top();
364+
365+
// restore program counter
366+
symex_transition(state, frame.calling_location.pc, false);
367+
state.source.function_id = frame.calling_location.function_id;
368+
369+
// restore L1 renaming
370+
state.level1.restore_from(frame.old_level1);
371+
372+
// If the program is multi-threaded then the state guard is used to
373+
// accumulate assumptions (in symex_assume_l2) and must be left alone.
374+
// If however it is single-threaded then we should restore the guard, as the
375+
// guard coming out of the function may be more complex (e.g. if the callee
376+
// was { if(x) while(true) { } } then the guard may still be `!x`),
377+
// but at this point all control-flow paths have either converged or been
378+
// proven unviable, so we can stop specifying the callee's constraints when
379+
// we generate an assumption or VCC.
380+
381+
// If we're doing path exploration then we do tail-duplication, and we
382+
// actually *are* in a more-restricted context than we were when the
383+
// function began.
384+
if(state.threads.size() == 1 && !doing_path_exploration)
363385
{
364-
const framet &frame = state.call_stack().top();
365-
366-
// restore program counter
367-
symex_transition(state, frame.calling_location.pc, false);
368-
state.source.function_id = frame.calling_location.function_id;
369-
370-
// restore L1 renaming
371-
state.level1.restore_from(frame.old_level1);
372-
373-
// If the program is multi-threaded then the state guard is used to
374-
// accumulate assumptions (in symex_assume_l2) and must be left alone.
375-
// If however it is single-threaded then we should restore the guard, as the
376-
// guard coming out of the function may be more complex (e.g. if the callee
377-
// was { if(x) while(true) { } } then the guard may still be `!x`),
378-
// but at this point all control-flow paths have either converged or been
379-
// proven unviable, so we can stop specifying the callee's constraints when
380-
// we generate an assumption or VCC.
381-
382-
// If we're doing path exploration then we do tail-duplication, and we
383-
// actually *are* in a more-restricted context than we were when the
384-
// function began.
385-
if(state.threads.size() == 1 && !doing_path_exploration)
386-
{
387-
state.guard = frame.guard_at_function_start;
388-
}
389-
390-
symex_renaming_levelt::viewt view;
391-
state.get_level2().current_names.get_view(view);
392-
393-
std::vector<irep_idt> keys_to_erase;
394-
395-
for(const auto &pair : view)
396-
{
397-
const irep_idt l1_o_id = pair.second.first.get_l1_object_identifier();
398-
399-
// could use iteration over local_objects as l1_o_id is prefix
400-
if(
401-
frame.local_objects.find(l1_o_id) == frame.local_objects.end() ||
402-
(state.threads.size() > 1 &&
403-
path_storage.dirty(pair.second.first.get_object_name())))
404-
{
405-
continue;
406-
}
386+
state.guard = frame.guard_at_function_start;
387+
}
407388

408-
keys_to_erase.push_back(pair.first);
409-
}
389+
for(const irep_idt &l1_o_id : frame.local_objects)
390+
{
391+
const auto l2_entry_opt = state.get_level2().current_names.find(l1_o_id);
410392

411-
for(const irep_idt &key : keys_to_erase)
393+
if(
394+
l2_entry_opt.has_value() &&
395+
(state.threads.size() == 1 ||
396+
!path_storage.dirty(l2_entry_opt->get().first.get_object_name())))
412397
{
413-
state.drop_existing_l1_name(key);
398+
state.drop_existing_l1_name(l1_o_id);
414399
}
415400
}
416401

0 commit comments

Comments
 (0)