Skip to content

Commit 41a1446

Browse files
committed
Updates requested in the review: Moving comments from doc file to code.
1 parent 7dd7cfe commit 41a1446

File tree

3 files changed

+100
-142
lines changed

3 files changed

+100
-142
lines changed

src/analyses/README.md

Lines changed: 0 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -180,146 +180,6 @@ is covered in a separate subsection.
180180

181181
A basic description for how a natural loop works is here: https://web.cs.wpi.edu/~kal/PLT/PLT8.6.4.html
182182

183-
### Reaching definitions
184-
185-
This module implements the reaching definitions data-flow analysis
186-
(see https://en.wikipedia.org/wiki/Reaching_definition for basic introduction)
187-
on multi-threaded GOTO programs.
188-
189-
The domain element is defined in a class `rd_range_domaint` and the actual
190-
analysis is implemented in a class `reaching_definitions_analysist`. Beside
191-
these classes there are more data structures necessary in the computation.
192-
We discuss all of them in the following sub-sections.
193-
194-
#### Struct `reaching_definitiont`
195-
196-
Identifies a GOTO instruction where a given variable is defined (i.e. it is set
197-
to a certain value). It consists of these data:
198-
- `identifier` The name of the variable which was defined.
199-
- `definition_at` The iterator to the GOTO instruction where the variable
200-
has been written to.
201-
- `bit_begin` and `bit_end` These two integers define a range of bits (i.e. the
202-
begin and end bit indices) which represent the value of the variable. So, the
203-
integers represents the half-open interval `[bit_begin, bit_end)` of bits.
204-
However, `bit_end` can also be set a special value `-1`, which means
205-
infinite/unknown index.
206-
207-
In order to use instances of this structure as keys in ordered containers, such
208-
as std::map, an ordering is defined.
209-
210-
#### Class `sparse_bitvector_analysist`
211-
212-
An instance of this class provides an assignment of unique numeric `ID` to each
213-
inserted `reaching_definitiont` instance. Internally, the class holds two data
214-
members:
215-
216-
- `value_map` is an unordered map from names of program variables to a set
217-
of pairs (`reaching_definitiont`, `ID`). Formally, the map is defined as
218-
`value_map: var_names -> (reaching_definitiont -> ID)`.
219-
- `values` is a map from an `ID` to the corresponding `reaching_definitiont`
220-
instance inside the map `value_map`. Namely, the map is implemented as an
221-
`std::vector` of iterators to elements of the map `value_map`. An index to
222-
`values` vector is the `ID` of the related `reaching_definitiont` instance.
223-
224-
#### Class `rd_range_domaint`
225-
226-
Because the class is inherited from `ai_domain_baset`, its instance represents
227-
an element of a domain of the reaching definitions abstract interpretation
228-
analysis. Each instance is thus associated with exactly one instruction in
229-
an analysed GOTO program. And so, the instance holds information for individual
230-
program variables about their reaching definitions, at that instruction. The
231-
information is held in these data members:
232-
233-
- `has_value` This (three value logic) flag determines, whether the instance
234-
represents `top`, `bottom`, or any other element of the lattice, by values
235-
`TRUE`, `FALSE`, and `UNKNOWN` respectively. Initially it is set to `FALSE`.
236-
- `bv_container` is a pointer to a
237-
`sparse_bitvector_analysist<reaching_definitiont>` instance. It holds the
238-
actual reaching definitions data of individual program variables. This
239-
pointer is initially `nullptr` and it is later set (by
240-
`reaching_definitions_analysist` instance using the method
241-
`set_bitvector_container`) to a valid pointer, which is actually shared by
242-
all `rd_range_domaint` instances. NOTE: `reaching_definitions_analysist`
243-
inherits from `sparse_bitvector_analysist<reaching_definitiont>` and so
244-
`this` is passed to `set_bitvector_container` for all instances.
245-
- `values` is an ordered map from program variable names to `ID`s of
246-
`reaching_definitiont` instances stored in map pointed to by `bv_container`.
247-
The map is not empty only if `has_value` is `UNKNOWN`. Variables in the map
248-
are all those which are live at the associated instruction.
249-
- `export_cache` is a helper data structure. It consists of data already
250-
stored in `values` and `bv_container`. It is basically (an ordered) map from
251-
(a subset of) variables in `values` to iterators to GOTO instructions where
252-
the variables are defined. Moreover, each such iterator is also associated
253-
with a range of bits defining the value of that variable at that GOTO
254-
instruction. Both the iterators and the corresponding bit ranges are simply
255-
taken from `reaching_definitiont` instances obtained for `ID`s in
256-
`values[var_name]`. This data structure is actually used only in the `output`
257-
method; other methods only remove outdated data from it. Since the cache
258-
does not contribute to the computation, it should be either moved to the
259-
`output` method or removed entirely.
260-
261-
##### Method `merge`
262-
263-
Implements the `join` operation of two instances `a` and `b`. It operates only
264-
on `a.values` and `b.values`. The keys in the resulting map is the union of
265-
variable names in both `a.values` and `b.values`. And for each variable
266-
`v` appearing in both maps `a.values` and `b.values` the resulting mapped set
267-
of `ID`s is the set union of `a.values[v]` and `b.values[v]`.
268-
269-
NOTE: The operation actually does not produce a new `join` element. The element
270-
`a` is modified to become the `join` element.
271-
272-
##### Method `transform`
273-
274-
Computes an instance obtained from a source instance `a` by transformation over
275-
a passed GOTO instruction. The method implements a switch according to a type of
276-
instruction and then calls a dedicated `transform_*` method for the recognised
277-
instruction. The dedicated methods are described below.
278-
279-
280-
##### Method `transform_dead`
281-
282-
Computes an instance obtained from a source instance `a` by transformation over
283-
`DEAD v` GOTO instruction. The operation simply removes `v` from `a.values`.
284-
285-
##### Method `transform_start_thread`
286-
287-
TODO!
288-
289-
##### Method `transform_function_call`
290-
291-
TODO!
292-
293-
##### Method `transform_end_function`
294-
295-
TODO!
296-
297-
##### Method `transform_assign`
298-
299-
TODO!
300-
301-
##### Method `kill`
302-
303-
TODO!
304-
305-
##### Method `gen`
306-
307-
A utility function which updates internal data structures by inserting a
308-
new reaching definition record, for a passed variable name, written in given
309-
GOTO instruction (identified by an iterator), at same range of bits.
310-
311-
##### Method `populate_cache`
312-
313-
Given a variable name `v` it collects data from `bv_container` for each `ID`
314-
in `values[v]` and stores them into `export_cache[v]`. Namely, for each
315-
`reaching_definitiont` instance `rd` obtained from `bv_container` it associates
316-
`rd.definition_at` with the bit-range `(rd.bit_begin, rd.bit_end)`.
317-
318-
This function is only used to fill in the cache `export_cache` for the `output`
319-
method.
320-
321-
### Class `reaching_definitions_analysist`
322-
323183
\subsection analyses-reaching-definitions Reaching definitions (reaching_definitions_analysist)
324184

325185
To be documented.

src/analyses/reaching_definitions.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ reaching_definitions_analysist::reaching_definitions_analysist(
3535

3636
reaching_definitions_analysist::~reaching_definitions_analysist()=default;
3737

38+
/// Given the passed variable name `identifier` it collects data from
39+
/// `bv_container` for each `ID` in `values[identifier]` and stores them into
40+
/// `export_cache[identifier]`. Namely, for each `reaching_definitiont` instance
41+
/// `rd` obtained from `bv_container` it associates `rd.definition_at` with the
42+
/// bit-range `(rd.bit_begin, rd.bit_end)`.
43+
///
44+
/// This function is only used to fill in the cache `export_cache` for the
45+
/// `output` method.
3846
void rd_range_domaint::populate_cache(const irep_idt &identifier) const
3947
{
4048
assert(bv_container);
@@ -126,6 +134,8 @@ void rd_range_domaint::transform(
126134
#endif
127135
}
128136

137+
/// Computes an instance obtained from a `*this` by transformation over `DEAD v`
138+
/// GOTO instruction. The operation simply removes `v` from `this->values`.
129139
void rd_range_domaint::transform_dead(
130140
const namespacet &,
131141
locationt from)
@@ -465,6 +475,10 @@ void rd_range_domaint::kill_inf(
465475
#endif
466476
}
467477

478+
/// A utility function which updates internal data structures by inserting a
479+
/// new reaching definition record, for the variable name `identifier`, written
480+
/// in given GOTO instruction referenced by `from`, at the range of bits defined
481+
/// by `range_start` and `range_end`.
468482
bool rd_range_domaint::gen(
469483
locationt from,
470484
const irep_idt &identifier,

src/analyses/reaching_definitions.h

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ Date: February 2013
1212
/// \file
1313
/// Range-based reaching definitions analysis (following Field- Sensitive
1414
/// 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.
1524

1625
#ifndef CPROVER_ANALYSES_REACHING_DEFINITIONS_H
1726
#define CPROVER_ANALYSES_REACHING_DEFINITIONS_H
@@ -27,7 +36,9 @@ class is_threadedt;
2736
class dirtyt;
2837
class reaching_definitions_analysist;
2938

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
3142
template<typename V>
3243
class sparse_bitvector_analysist
3344
{
@@ -59,18 +70,36 @@ class sparse_bitvector_analysist
5970

6071
protected:
6172
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.
6277
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)`.
6381
std::unordered_map<irep_idt, inner_mapt> value_map;
6482
};
6583

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:
6686
struct reaching_definitiont
6787
{
88+
/// The name of the variable which was defined.
6889
irep_idt identifier;
90+
/// The iterator to the GOTO instruction where the variable has been written to.
6991
ai_domain_baset::locationt definition_at;
92+
/// The two integers below define a range of bits (i.e. the begin and end bit
93+
/// indices) which represent the value of the variable. So, the integers
94+
/// represents the half-open interval `[bit_begin, bit_end)` of bits.
95+
/// However, `bit_end` can also be set a special value `-1`, which means
96+
/// infinite/unknown index.
7097
range_spect bit_begin;
7198
range_spect bit_end;
7299
};
73100

101+
/// In order to use instances of this structure as keys in ordered containers,
102+
/// such as std::map, an ordering is defined.
74103
inline bool operator<(
75104
const reaching_definitiont &a,
76105
const reaching_definitiont &b)
@@ -97,6 +126,12 @@ inline bool operator<(
97126
return false;
98127
}
99128

129+
/// Because the class is inherited from `ai_domain_baset`, its instance
130+
/// represents an element of a domain of the reaching definitions abstract
131+
/// interpretation analysis. Each instance is thus associated with exactly one
132+
/// instruction in an analysed GOTO program. And so, the instance holds
133+
/// information for individual program variables about their reaching
134+
/// definitions, at that instruction.
100135
class rd_range_domaint:public ai_domain_baset
101136
{
102137
public:
@@ -113,6 +148,18 @@ class rd_range_domaint:public ai_domain_baset
113148
bv_container=&_bv_container;
114149
}
115150

151+
/// Computes an instance obtained from the instance `*this` by transformation
152+
/// over a GOTO instruction referenced by `from`. The method implements a
153+
/// switch according to a type of the instruction and then calls a dedicated
154+
/// transform_*` method for the recognised instruction.
155+
/// \param function_from: Just passed to `transform_function_call` and
156+
/// `transform_end_function` callees.
157+
/// \param from: Reference to a GOTO instruction according to which `*this`
158+
/// instance should be transformed.
159+
/// \param function_to: Just passed to `transform_function_call` callee.
160+
/// \param to: Just passed to `transform_end_function` callee.
161+
/// \param ai: A reference to 'reaching_definitions_analysist' instance.
162+
/// \param ns: Just passed to callees.
116163
void transform(
117164
const irep_idt &function_from,
118165
locationt from,
@@ -164,7 +211,18 @@ class rd_range_domaint:public ai_domain_baset
164211
return has_values.is_false();
165212
}
166213

167-
// returns true iff there is something new
214+
/// Implements the `join` operation of two instances `*this` and other`. It
215+
/// operates only on `this->values` and `other.values`. The keys in the
216+
/// resulting map is the union of variable names in both `this->values` and
217+
/// `other.values`. And for each variable `v` appearing in both maps
218+
/// `this->values` and `other.values` the resulting mapped set
219+
/// of `ID`s is the set union of `this->values[v]` and `other.values[v]`.
220+
/// NOTE: The operation actually does not produce a new `join` element. The
221+
/// instance `*this` is modified to become the `join` element.
222+
/// \param other: The instance to be merged into `*this` as the join operation
223+
/// \param from: Not used at all.
224+
/// \param to: Not used at all.
225+
/// \return Returns true iff there is something new
168226
bool merge(
169227
const rd_range_domaint &other,
170228
locationt from,
@@ -187,8 +245,18 @@ class rd_range_domaint:public ai_domain_baset
187245
}
188246

189247
private:
248+
/// This (three value logic) flag determines, whether the instance represents
249+
/// `top`, `bottom`, or any other element of the lattice, by values `TRUE`,
250+
/// `FALSE`, and `UNKNOWN` respectively. Initially it is set to `FALSE`.
190251
tvt has_values;
191252

253+
/// It points to the actual reaching definitions data of individual program
254+
/// variables. This pointer is initially `nullptr` and it is later set (by
255+
/// `reaching_definitions_analysist` instance using the method
256+
/// `set_bitvector_container`) to a valid pointer, which is actually shared by
257+
/// all `rd_range_domaint` instances. NOTE: `reaching_definitions_analysist`
258+
/// inherits from `sparse_bitvector_analysist<reaching_definitiont>` and so
259+
/// `this` is passed to `set_bitvector_container` for all instances.
192260
sparse_bitvector_analysist<reaching_definitiont> *bv_container;
193261

194262
typedef std::set<std::size_t> values_innert;
@@ -197,13 +265,29 @@ class rd_range_domaint:public ai_domain_baset
197265
#else
198266
typedef std::unordered_map<irep_idt, values_innert> valuest;
199267
#endif
268+
/// It is an ordered map from program variable names to `ID`s of
269+
/// `reaching_definitiont` instances stored in map pointed to by
270+
/// `bv_container`. The map is not empty only if `has_value` is `UNKNOWN`.
271+
/// Variables in the map are all those which are live at the associated
272+
/// instruction.
200273
valuest values;
201274

202275
#ifdef USE_DSTRING
203276
typedef std::map<irep_idt, ranges_at_loct> export_cachet;
204277
#else
205278
typedef std::unordered_map<irep_idt, ranges_at_loct> export_cachet;
206279
#endif
280+
/// It is a helper data structure. It consists of data already stored in
281+
/// `values` and `bv_container`. It is basically (an ordered) map from (a
282+
/// subset of) variables in `values` to iterators to GOTO instructions where
283+
/// the variables are defined. Moreover, each such iterator is also
284+
/// associated with a range of bits defining the value of that variable at
285+
/// that GOTO instruction. Both the iterators and the corresponding bit ranges
286+
/// are simply taken from `reaching_definitiont` instances obtained for `ID`s
287+
/// in `values[var_name]`. This data structure is actually used only in the
288+
/// `output` method; other methods only remove outdated data from it. Since
289+
/// the cache does not contribute to the computation, it should be either
290+
/// moved to the `output` method or removed entirely.
207291
mutable export_cachet export_cache;
208292

209293
void populate_cache(const irep_idt &identifier) const;

0 commit comments

Comments
 (0)