30
30
#include " renaming_level.h"
31
31
#include " symex_target_equation.h"
32
32
33
- // central data structure: state
33
+ // / Central data structure: state.
34
+
35
+ // / The state is a persistent data structure that symex maintains as it
36
+ // / executes. As we walk over each instruction, state will be updated reflecting
37
+ // / their effects until a branch occurs (such as an if), where parts of the
38
+ // / state will be copied into a \ref goto_statet, stored in a map for later
39
+ // / reference and then merged again (via merge_goto) once it reaches a
40
+ // / control-flow graph convergence.
34
41
class goto_symex_statet final
35
42
{
36
43
public:
@@ -54,6 +61,11 @@ class goto_symex_statet final
54
61
// / distance from entry
55
62
unsigned depth;
56
63
64
+ // A guard is a particular condition that has to pass for an instruction
65
+ // to be executed. The easiest example is an if/else: each instruction along
66
+ // the if branch will be guarded by the condition of the if (and if there
67
+ // is an else branch then instructions on it will be guarded by the negation
68
+ // of the condition of the if).
57
69
guardt guard{true_exprt{}};
58
70
symex_targett::sourcet source;
59
71
symex_target_equationt *symex_target;
@@ -65,13 +77,43 @@ class goto_symex_statet final
65
77
symex_level1t level1;
66
78
symex_level2t level2;
67
79
68
- // Map L1 names to (L2) constants
80
+ // Map L1 names to (L2) constants. Values will be evicted from this map
81
+ // when they become non-constant. This is used to propagate values that have
82
+ // been worked out to only have one possible value.
83
+ //
84
+ // "constants" can include symbols, but only in the context of an address-of
85
+ // op (i.e. &x can be propagated), and an address-taken thing should only be
86
+ // L1.
69
87
std::map<irep_idt, exprt> propagation;
70
88
void output_propagation_map (std::ostream &);
71
89
90
+ // Symex renaming levels.
72
91
enum levelt { L0=0 , L1=1 , L2=2 };
73
92
74
- // performs renaming _up to_ the given level
93
+ // / Rewrites symbol expressions in \ref exprt, applying a suffix to each
94
+ // / symbol reflecting its most recent version, which differs depending on
95
+ // / which level you requested. Each level also updates its predecessors, so
96
+ // / a L1 rename will update L1 and L0. A L2 will update L2, L1 and L0.
97
+ // /
98
+ // / What happens at each level:
99
+ // / L0. Applies a suffix giving the current thread number. (Excludes
100
+ // / guards, dynamic objects and anything not considered thread-local)
101
+ // / L1. Applies a suffix giving the current loop iteration or recursive
102
+ // / function invocation.
103
+ // / L2. Applies a suffix giving the generation of this variable.
104
+ // /
105
+ // / Renaming will not increment any of these values, just update the
106
+ // / expression with them. Levels matter when reading a variable, for
107
+ // / example: reading the value of x really means reading the particular x
108
+ // / symbol for this thread (L0 renaming, if applicable), the most recent
109
+ // / instance of x (L1 renaming), and the most recent write to x (L2 renaming).
110
+ // /
111
+ // / The above example after being renamed could look like this: 'x!0@0#42'.
112
+ // / That states it's the 42nd generation of this variable, on the first
113
+ // / thread, in the first frame.
114
+ // /
115
+ // / A full explanation of SSA (which is why we do this renaming) is in
116
+ // / the SSA section of background-concepts.md.
75
117
void rename (exprt &expr, const namespacet &ns, levelt level=L2);
76
118
void rename (
77
119
typet &type,
@@ -93,8 +135,13 @@ class goto_symex_statet final
93
135
protected:
94
136
void rename_address (exprt &expr, const namespacet &ns, levelt level);
95
137
138
+ // / Update level 0 values.
96
139
void set_l0_indices (ssa_exprt &expr, const namespacet &ns);
140
+
141
+ // / Update level 0 and 1 values.
97
142
void set_l1_indices (ssa_exprt &expr, const namespacet &ns);
143
+
144
+ // / Update level 0, 1 and 2 values.
98
145
void set_l2_indices (ssa_exprt &expr, const namespacet &ns);
99
146
100
147
// this maps L1 names to (L2) types
@@ -108,6 +155,10 @@ class goto_symex_statet final
108
155
// do dereferencing
109
156
value_sett value_set;
110
157
158
+ // / Container for data that varies per program point, e.g. the constant
159
+ // / propagator state, when state needs to branch. This is copied out of
160
+ // / goto_symex_statet at a control-flow fork and then back into it at a
161
+ // / control-flow merge.
111
162
class goto_statet
112
163
{
113
164
public:
@@ -266,6 +317,9 @@ class goto_symex_statet final
266
317
bool l2_thread_write_encoding (const ssa_exprt &expr, const namespacet &ns);
267
318
268
319
bool record_events;
320
+
321
+ // Local variables are considered 'dirty' if they've had an address taken and
322
+ // therefore may be referred to by a pointer.
269
323
incremental_dirtyt dirty;
270
324
271
325
goto_programt::const_targett saved_target;
0 commit comments