Skip to content

Commit 28dc3d7

Browse files
authored
Merge pull request #3980 from tautschnig/block-scope
L1 renaming at each declaration
2 parents 150c933 + a397a58 commit 28dc3d7

File tree

12 files changed

+101
-80
lines changed

12 files changed

+101
-80
lines changed

regression/cbmc-cover/pointer-function-parameters/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ main.c
44
^\*\* 5 of 5 covered \(100\.0%\)$
55
^Test suite:$
66
^(tmp(\$\d+)?=[^,]*, a=\(\(signed int \*\)NULL\))|(a=\(\(signed int \*\)NULL\), tmp(\$\d+)?=[^,]*)$
7-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0)$
8-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0)$
7+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0@1)$
8+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0@1)$
99
^EXIT=0$
1010
^SIGNAL=0$
1111
--
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int g;
2+
3+
int main()
4+
{
5+
for(int i = 0; i < 4; ++i)
6+
{
7+
int *x;
8+
*&x = &g;
9+
}
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/vla3/test.desc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ main.c
77
--
88
^warning: ignoring
99
--
10-
Renaming is inconsistent across loop iterations as we map L1 names to types, but
11-
do not actually introduce new L1 ids each time we declare an object.
10+
The array decision procedure does not yet handle member expressions.

src/goto-programs/goto_clean_expr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ symbol_exprt goto_convertt::make_compound_literal(
4545

4646
// The lifetime of compound literals is really that of
4747
// the block they are in.
48-
copy(code_declt(result), DECL, dest);
48+
if(!new_symbol.is_static_lifetime)
49+
copy(code_declt(result), DECL, dest);
4950

5051
code_assignt code_assign(result, expr);
5152
code_assign.add_source_location()=source_location;

src/goto-symex/goto_symex_state.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,3 +766,29 @@ void goto_symex_statet::print_backtrace(std::ostream &out) const
766766
<< frame.calling_location.pc->location_number << "\n";
767767
}
768768
}
769+
770+
void goto_symex_statet::add_object(
771+
ssa_exprt &ssa,
772+
std::size_t l1_index,
773+
const namespacet &ns)
774+
{
775+
framet &frame = call_stack().top();
776+
777+
const irep_idt l0_name = ssa.get_identifier();
778+
779+
// save old L1 name, if any
780+
auto existing_or_new_entry = level1.current_names.emplace(
781+
std::piecewise_construct,
782+
std::forward_as_tuple(l0_name),
783+
std::forward_as_tuple(ssa, l1_index));
784+
785+
if(!existing_or_new_entry.second)
786+
{
787+
frame.old_level1.emplace(l0_name, existing_or_new_entry.first->second);
788+
existing_or_new_entry.first->second = std::make_pair(ssa, l1_index);
789+
}
790+
791+
ssa = rename_ssa<L1>(std::move(ssa), ns);
792+
const bool inserted = frame.local_objects.insert(ssa.get_identifier()).second;
793+
INVARIANT(inserted, "l1_name expected to be unique by construction");
794+
}

src/goto-symex/goto_symex_state.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ class goto_symex_statet final : public goto_statet
6060

6161
symex_target_equationt *symex_target;
6262

63-
// we remember all L1 renamings
64-
std::set<irep_idt> l1_history;
65-
6663
symex_level0t level0;
6764
symex_level1t level1;
6865

@@ -141,6 +138,11 @@ class goto_symex_statet final : public goto_statet
141138
return threads[source.thread_nr].call_stack;
142139
}
143140

141+
/// Create a new instance of the L0-renamed object \p ssa. As part of this,
142+
/// turn \p ssa into an L1-renamed SSA expression. When doing so, use
143+
/// \p l1_index as the L1 index, which must not previously have been used.
144+
void add_object(ssa_exprt &ssa, std::size_t l1_index, const namespacet &ns);
145+
144146
void print_backtrace(std::ostream &) const;
145147

146148
// threads

src/goto-symex/path_storage.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,25 @@ 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)
103+
{
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);
108+
109+
return entry.first->second;
110+
}
111+
101112
private:
102113
// Derived classes should override these methods, allowing the base class to
103114
// enforce preconditions.
104115
virtual patht &private_peek() = 0;
105116
virtual void private_pop() = 0;
117+
118+
/// Storage used by \ref get_unique_index.
119+
std::unordered_map<irep_idt, std::size_t> unique_index_map;
106120
};
107121

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

src/goto-symex/symex_dead.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "goto_symex.h"
1313

14-
#include <cassert>
15-
1614
#include <util/std_expr.h>
1715

1816
#include <pointer-analysis/add_failed_symbols.h>
@@ -23,9 +21,6 @@ void goto_symext::symex_dead(statet &state)
2321

2422
const code_deadt &code = instruction.get_dead();
2523

26-
// We increase the L2 renaming to make these non-deterministic.
27-
// We also prevent propagation of old values.
28-
2924
ssa_exprt ssa = state.rename_ssa<L1>(ssa_exprt{code.symbol()}, ns);
3025

3126
// in case of pointers, put something into the value set
@@ -43,10 +38,13 @@ void goto_symext::symex_dead(statet &state)
4338

4439
const irep_idt &l1_identifier = ssa.get_identifier();
4540

46-
// prevent propagation
41+
// we cannot remove the object from the L1 renaming map, because L1 renaming
42+
// information is not local to a path, but removing it from the propagation
43+
// map is safe as 1) it is local to a path and 2) this instance can no longer
44+
// appear
4745
state.propagation.erase(l1_identifier);
48-
49-
// L2 renaming
46+
// increment the L2 index to ensure a merge on join points will propagate the
47+
// value for branches that are still live
5048
auto level2_it = state.level2.current_names.find(l1_identifier);
5149
if(level2_it != state.level2.current_names.end())
5250
symex_renaming_levelt::increase_counter(level2_it);

src/goto-symex/symex_decl.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@ void goto_symext::symex_decl(statet &state)
3434

3535
void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
3636
{
37-
// We increase the L2 renaming to make these non-deterministic.
38-
// We also prevent propagation of old values.
39-
40-
ssa_exprt ssa = state.rename_ssa<L1>(ssa_exprt{expr}, ns);
37+
// each declaration introduces a new object, which we record as a fresh L1
38+
// index
39+
40+
ssa_exprt ssa = state.rename_ssa<L0>(ssa_exprt{expr}, ns);
41+
// We use "1" as the first level-1 index, which is in line with doing so for
42+
// level-2 indices (but it's an arbitrary choice, we have just always been
43+
// doing it this way).
44+
const std::size_t fresh_l1_index =
45+
path_storage.get_unique_index(ssa.get_identifier(), 1);
46+
state.add_object(ssa, fresh_l1_index, ns);
4147
const irep_idt &l1_identifier = ssa.get_identifier();
4248

4349
// rename type to L2
@@ -57,16 +63,11 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
5763
state.value_set.assign(ssa, l1_rhs, ns, true, false);
5864
}
5965

60-
// prevent propagation
61-
state.propagation.erase(l1_identifier);
62-
6366
// L2 renaming
64-
// inlining may yield multiple declarations of the same identifier
65-
// 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);
67+
bool is_new =
68+
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 1))
69+
.second;
70+
CHECK_RETURN(is_new);
7071
const bool record_events=state.record_events;
7172
state.record_events=false;
7273
exprt expr_l2 = state.rename(std::move(ssa), ns);

src/goto-symex/symex_function_call.cpp

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Author: Daniel Kroening, [email protected]
2222
static void locality(
2323
const irep_idt &function_identifier,
2424
goto_symext::statet &state,
25+
path_storaget &path_storage,
2526
const goto_functionst::goto_functiont &goto_function,
2627
const namespacet &ns);
2728

@@ -307,7 +308,7 @@ void goto_symext::symex_function_call_code(
307308
framet &frame = state.call_stack().new_frame(state.source);
308309

309310
// preserve locality of local variables
310-
locality(identifier, state, goto_function, ns);
311+
locality(identifier, state, path_storage, goto_function, ns);
311312

312313
// assign actuals to formal parameters
313314
parameter_assignments(identifier, goto_function, state, arguments);
@@ -383,68 +384,27 @@ void goto_symext::symex_end_of_function(statet &state)
383384
pop_frame(state);
384385
}
385386

386-
/// preserves locality of local variables of a given function by applying L1
387-
/// renaming to the local identifiers
387+
/// Preserves locality of parameters of a given function by applying L1
388+
/// renaming to them.
388389
static void locality(
389390
const irep_idt &function_identifier,
390391
goto_symext::statet &state,
392+
path_storaget &path_storage,
391393
const goto_functionst::goto_functiont &goto_function,
392394
const namespacet &ns)
393395
{
394396
unsigned &frame_nr=
395397
state.threads[state.source.thread_nr].function_frame[function_identifier];
396398
frame_nr++;
397399

398-
std::set<irep_idt> local_identifiers;
399-
400-
get_local_identifiers(goto_function, local_identifiers);
401-
402-
framet &frame = state.call_stack().top();
403-
404-
for(std::set<irep_idt>::const_iterator
405-
it=local_identifiers.begin();
406-
it!=local_identifiers.end();
407-
it++)
400+
for(const auto &param : goto_function.parameter_identifiers)
408401
{
409402
// get L0 name
410403
ssa_exprt ssa =
411-
state.rename_ssa<L0>(ssa_exprt{ns.lookup(*it).symbol_expr()}, ns);
412-
const irep_idt l0_name=ssa.get_identifier();
413-
414-
// save old L1 name for popping the frame
415-
auto c_it = state.level1.current_names.find(l0_name);
416-
417-
if(c_it != state.level1.current_names.end())
418-
{
419-
frame.old_level1.emplace(l0_name, c_it->second);
420-
c_it->second = std::make_pair(ssa, frame_nr);
421-
}
422-
else
423-
{
424-
c_it = state.level1.current_names
425-
.emplace(l0_name, std::make_pair(ssa, frame_nr))
426-
.first;
427-
}
428-
429-
// do L1 renaming -- these need not be unique, as
430-
// identifiers may be shared among functions
431-
// (e.g., due to inlining or other code restructuring)
432-
433-
ssa_exprt ssa_l1 = state.rename_ssa<L1>(std::move(ssa), ns);
434-
435-
irep_idt l1_name = ssa_l1.get_identifier();
436-
unsigned offset=0;
437-
438-
while(state.l1_history.find(l1_name)!=state.l1_history.end())
439-
{
440-
symex_renaming_levelt::increase_counter(c_it);
441-
++offset;
442-
ssa_l1.set_level_1(frame_nr + offset);
443-
l1_name = ssa_l1.get_identifier();
444-
}
404+
state.rename_ssa<L0>(ssa_exprt{ns.lookup(param).symbol_expr()}, ns);
445405

446-
// now unique -- store
447-
frame.local_objects.insert(l1_name);
448-
state.l1_history.insert(l1_name);
406+
const std::size_t fresh_l1_index =
407+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
408+
state.add_object(ssa, fresh_l1_index, ns);
449409
}
450410
}

src/goto-symex/symex_start_thread.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ void goto_symext::symex_start_thread(statet &state)
6666

6767
// get L0 name for current thread
6868
lhs.set_level_0(t);
69+
const irep_idt &l0_name = lhs.get_identifier();
70+
std::size_t l1_index = path_storage.get_unique_index(l0_name, 0);
71+
CHECK_RETURN(l1_index == 0);
6972

7073
// set up L1 name
7174
auto emplace_result = state.level1.current_names.emplace(
@@ -76,7 +79,6 @@ void goto_symext::symex_start_thread(statet &state)
7679
const ssa_exprt lhs_l1 = state.rename_ssa<L1>(std::move(lhs), ns);
7780
const irep_idt l1_name = lhs_l1.get_l1_object_identifier();
7881
// store it
79-
state.l1_history.insert(l1_name);
8082
new_thread.call_stack.back().local_objects.insert(l1_name);
8183

8284
// make copy

0 commit comments

Comments
 (0)