Skip to content

Commit f0b08e5

Browse files
authored
Merge pull request #3399 from marek-trtik/doc_reach_defs
DOC-70: Description of `rd_range_domaint` of reaching_definitions.h(cpp) module.
2 parents 38c8afe + 1fe3b1a commit f0b08e5

File tree

2 files changed

+101
-2
lines changed

2 files changed

+101
-2
lines changed

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: 87 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,37 @@ 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
91+
/// to.
6992
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.
7098
range_spect bit_begin;
7199
range_spect bit_end;
72100
};
73101

102+
/// In order to use instances of this structure as keys in ordered containers,
103+
/// such as std::map, an ordering is defined.
74104
inline bool operator<(
75105
const reaching_definitiont &a,
76106
const reaching_definitiont &b)
@@ -97,6 +127,12 @@ inline bool operator<(
97127
return false;
98128
}
99129

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.
100136
class rd_range_domaint:public ai_domain_baset
101137
{
102138
public:
@@ -113,6 +149,18 @@ class rd_range_domaint:public ai_domain_baset
113149
bv_container=&_bv_container;
114150
}
115151

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.
116164
void transform(
117165
const irep_idt &function_from,
118166
locationt from,
@@ -164,7 +212,18 @@ class rd_range_domaint:public ai_domain_baset
164212
return has_values.is_false();
165213
}
166214

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
168227
bool merge(
169228
const rd_range_domaint &other,
170229
locationt from,
@@ -187,8 +246,18 @@ class rd_range_domaint:public ai_domain_baset
187246
}
188247

189248
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`.
190252
tvt has_values;
191253

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.
192261
sparse_bitvector_analysist<reaching_definitiont> *bv_container;
193262

194263
typedef std::set<std::size_t> values_innert;
@@ -197,13 +266,29 @@ class rd_range_domaint:public ai_domain_baset
197266
#else
198267
typedef std::unordered_map<irep_idt, values_innert> valuest;
199268
#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.
200274
valuest values;
201275

202276
#ifdef USE_DSTRING
203277
typedef std::map<irep_idt, ranges_at_loct> export_cachet;
204278
#else
205279
typedef std::unordered_map<irep_idt, ranges_at_loct> export_cachet;
206280
#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.
207292
mutable export_cachet export_cache;
208293

209294
void populate_cache(const irep_idt &identifier) const;

0 commit comments

Comments
 (0)