@@ -12,6 +12,15 @@ Date: February 2013
12
12
// / \file
13
13
// / Range-based reaching definitions analysis (following Field- Sensitive
14
14
// / Program Dependence Analysis, Litvak et al., FSE 2010)
15
+ // /
16
+ // / This module implements the reaching definitions data-flow analysis
17
+ // / (see https://en.wikipedia.org/wiki/Reaching_definition for basic
18
+ // / introduction) on multi-threaded GOTO programs.
19
+ // /
20
+ // / The domain element is defined in a class `rd_range_domaint` and the actual
21
+ // / analysis is implemented in a class `reaching_definitions_analysist`. Beside
22
+ // / these classes there are more data structures necessary in the computation.
23
+ // / We discuss all of them in the following sub-sections.
15
24
16
25
#ifndef CPROVER_ANALYSES_REACHING_DEFINITIONS_H
17
26
#define CPROVER_ANALYSES_REACHING_DEFINITIONS_H
@@ -27,7 +36,9 @@ class is_threadedt;
27
36
class dirtyt ;
28
37
class reaching_definitions_analysist ;
29
38
30
- // requirement: V has a member "identifier" of type irep_idt
39
+ // / An instance of this class provides an assignment of unique numeric `ID` to
40
+ // / each inserted `reaching_definitiont` instance.
41
+ // / Requirement: V has a member "identifier" of type irep_idt
31
42
template <typename V>
32
43
class sparse_bitvector_analysist
33
44
{
@@ -59,18 +70,37 @@ class sparse_bitvector_analysist
59
70
60
71
protected:
61
72
typedef typename std::map<V, std::size_t > inner_mapt;
73
+ // / It is a map from an `ID` to the corresponding `reaching_definitiont`
74
+ // / instance inside the map `value_map`. Namely, the map is implemented as an
75
+ // / `std::vector` of iterators to elements of the map `value_map`. An index to
76
+ // / this vector is the `ID` of the related `reaching_definitiont` instance.
62
77
std::vector<typename inner_mapt::const_iterator> values;
78
+ // / A map from names of program variables to a set of pairs
79
+ // / (`reaching_definitiont`, `ID`). Formally, the map is defined as
80
+ // / `value_map: var_names -> (reaching_definitiont -> ID)`.
63
81
std::unordered_map<irep_idt, inner_mapt> value_map;
64
82
};
65
83
84
+ // / Identifies a GOTO instruction where a given variable is defined (i.e. it is
85
+ // / set to a certain value). It consists of these data:
66
86
struct reaching_definitiont
67
87
{
88
+ // / The name of the variable which was defined.
68
89
irep_idt identifier;
90
+ // / The iterator to the GOTO instruction where the variable has been written
91
+ // / to.
69
92
ai_domain_baset::locationt definition_at;
93
+ // / The two integers below define a range of bits (i.e. the begin and end bit
94
+ // / indices) which represent the value of the variable. So, the integers
95
+ // / represents the half-open interval `[bit_begin, bit_end)` of bits.
96
+ // / However, `bit_end` can also be set a special value `-1`, which means
97
+ // / infinite/unknown index.
70
98
range_spect bit_begin;
71
99
range_spect bit_end;
72
100
};
73
101
102
+ // / In order to use instances of this structure as keys in ordered containers,
103
+ // / such as std::map, an ordering is defined.
74
104
inline bool operator <(
75
105
const reaching_definitiont &a,
76
106
const reaching_definitiont &b)
@@ -97,6 +127,12 @@ inline bool operator<(
97
127
return false ;
98
128
}
99
129
130
+ // / Because the class is inherited from `ai_domain_baset`, its instance
131
+ // / represents an element of a domain of the reaching definitions abstract
132
+ // / interpretation analysis. Each instance is thus associated with exactly one
133
+ // / instruction in an analysed GOTO program. And so, the instance holds
134
+ // / information for individual program variables about their reaching
135
+ // / definitions, at that instruction.
100
136
class rd_range_domaint :public ai_domain_baset
101
137
{
102
138
public:
@@ -113,6 +149,18 @@ class rd_range_domaint:public ai_domain_baset
113
149
bv_container=&_bv_container;
114
150
}
115
151
152
+ // / Computes an instance obtained from the instance `*this` by transformation
153
+ // / over a GOTO instruction referenced by `from`. The method implements a
154
+ // / switch according to a type of the instruction and then calls a dedicated
155
+ // / `transform_*` method for the recognised instruction.
156
+ // / \param function_from: Just passed to `transform_function_call` and
157
+ // / `transform_end_function` callees.
158
+ // / \param from: Reference to a GOTO instruction according to which `*this`
159
+ // / instance should be transformed.
160
+ // / \param function_to: Just passed to `transform_function_call` callee.
161
+ // / \param to: Just passed to `transform_end_function` callee.
162
+ // / \param ai: A reference to 'reaching_definitions_analysist' instance.
163
+ // / \param ns: Just passed to callees.
116
164
void transform (
117
165
const irep_idt &function_from,
118
166
locationt from,
@@ -164,7 +212,18 @@ class rd_range_domaint:public ai_domain_baset
164
212
return has_values.is_false ();
165
213
}
166
214
167
- // returns true iff there is something new
215
+ // / Implements the `join` operation of two instances `*this` and other`. It
216
+ // / operates only on `this->values` and `other.values`. The keys in the
217
+ // / resulting map is the union of variable names in both `this->values` and
218
+ // / `other.values`. And for each variable `v` appearing in both maps
219
+ // / `this->values` and `other.values` the resulting mapped set
220
+ // / of `ID`s is the set union of `this->values[v]` and `other.values[v]`.
221
+ // / NOTE: The operation actually does not produce a new `join` element. The
222
+ // / instance `*this` is modified to become the `join` element.
223
+ // / \param other: The instance to be merged into `*this` as the join operation
224
+ // / \param from: Not used at all.
225
+ // / \param to: Not used at all.
226
+ // / \return Returns true iff there is something new
168
227
bool merge (
169
228
const rd_range_domaint &other,
170
229
locationt from,
@@ -187,8 +246,18 @@ class rd_range_domaint:public ai_domain_baset
187
246
}
188
247
189
248
private:
249
+ // / This (three value logic) flag determines, whether the instance represents
250
+ // / `top`, `bottom`, or any other element of the lattice, by values `TRUE`,
251
+ // / `FALSE`, and `UNKNOWN` respectively. Initially it is set to `FALSE`.
190
252
tvt has_values;
191
253
254
+ // / It points to the actual reaching definitions data of individual program
255
+ // / variables. This pointer is initially `nullptr` and it is later set (by
256
+ // / `reaching_definitions_analysist` instance using the method
257
+ // / `set_bitvector_container`) to a valid pointer, which is actually shared by
258
+ // / all `rd_range_domaint` instances. NOTE: `reaching_definitions_analysist`
259
+ // / inherits from `sparse_bitvector_analysist<reaching_definitiont>` and so
260
+ // / `this` is passed to `set_bitvector_container` for all instances.
192
261
sparse_bitvector_analysist<reaching_definitiont> *bv_container;
193
262
194
263
typedef std::set<std::size_t > values_innert;
@@ -197,13 +266,29 @@ class rd_range_domaint:public ai_domain_baset
197
266
#else
198
267
typedef std::unordered_map<irep_idt, values_innert> valuest;
199
268
#endif
269
+ // / It is an ordered map from program variable names to `ID`s of
270
+ // / `reaching_definitiont` instances stored in map pointed to by
271
+ // / `bv_container`. The map is not empty only if `has_value` is `UNKNOWN`.
272
+ // / Variables in the map are all those which are live at the associated
273
+ // / instruction.
200
274
valuest values;
201
275
202
276
#ifdef USE_DSTRING
203
277
typedef std::map<irep_idt, ranges_at_loct> export_cachet;
204
278
#else
205
279
typedef std::unordered_map<irep_idt, ranges_at_loct> export_cachet;
206
280
#endif
281
+ // / It is a helper data structure. It consists of data already stored in
282
+ // / `values` and `bv_container`. It is basically (an ordered) map from (a
283
+ // / subset of) variables in `values` to iterators to GOTO instructions where
284
+ // / the variables are defined. Moreover, each such iterator is also
285
+ // / associated with a range of bits defining the value of that variable at
286
+ // / that GOTO instruction. Both the iterators and the corresponding bit ranges
287
+ // / are simply taken from `reaching_definitiont` instances obtained for `ID`s
288
+ // / in `values[var_name]`. This data structure is actually used only in the
289
+ // / `output` method; other methods only remove outdated data from it. Since
290
+ // / the cache does not contribute to the computation, it should be either
291
+ // / moved to the `output` method or removed entirely.
207
292
mutable export_cachet export_cache;
208
293
209
294
void populate_cache (const irep_idt &identifier) const ;
0 commit comments