Skip to content

Commit a17d367

Browse files
authored
Merge pull request #4346 from xbauch/doc/memory_model
Reword the read_from function and add documentation to memory_model
2 parents ceeb07c + 778fac1 commit a17d367

File tree

2 files changed

+76
-77
lines changed

2 files changed

+76
-77
lines changed

src/goto-symex/memory_model.cpp

Lines changed: 53 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,26 @@ Author: Michael Tautschnig, michael.tautschnig@cs.ox.ac.uk
1313

1414
#include <util/std_expr.h>
1515

16-
memory_model_baset::memory_model_baset(const namespacet &_ns):
17-
partial_order_concurrencyt(_ns),
18-
var_cnt(0)
16+
memory_model_baset::memory_model_baset(const namespacet &_ns)
17+
: partial_order_concurrencyt(_ns), var_cnt(0)
1918
{
2019
}
2120

2221
memory_model_baset::~memory_model_baset()
2322
{
2423
}
2524

26-
symbol_exprt memory_model_baset::nondet_bool_symbol(
27-
const std::string &prefix)
25+
symbol_exprt memory_model_baset::nondet_bool_symbol(const std::string &prefix)
2826
{
2927
return symbol_exprt(
30-
"memory_model::choice_"+prefix+std::to_string(var_cnt++),
31-
bool_typet());
28+
"memory_model::choice_" + prefix + std::to_string(var_cnt++), bool_typet());
3229
}
3330

3431
bool memory_model_baset::po(event_it e1, event_it e2)
3532
{
3633
// within same thread
37-
if(e1->source.thread_nr==e2->source.thread_nr)
38-
return numbering[e1]<numbering[e2];
34+
if(e1->source.thread_nr == e2->source.thread_nr)
35+
return numbering[e1] < numbering[e2];
3936
else
4037
{
4138
// in general un-ordered, with exception of thread-spawning
@@ -49,83 +46,67 @@ void memory_model_baset::read_from(symex_target_equationt &equation)
4946
// make them match at least one
5047
// (internal or external) write.
5148

52-
for(address_mapt::const_iterator
53-
a_it=address_map.begin();
54-
a_it!=address_map.end();
55-
a_it++)
49+
for(const auto &address : address_map)
5650
{
57-
const a_rect &a_rec=a_it->second;
58-
59-
for(event_listt::const_iterator
60-
r_it=a_rec.reads.begin();
61-
r_it!=a_rec.reads.end();
62-
r_it++)
51+
for(const auto &read_event : address.second.reads)
6352
{
64-
const event_it r=*r_it;
65-
66-
exprt::operandst rf_some_operands;
67-
rf_some_operands.reserve(a_rec.writes.size());
53+
exprt::operandst rf_choice_symbols;
54+
rf_choice_symbols.reserve(address.second.writes.size());
6855

6956
// this is quadratic in #events per address
70-
for(event_listt::const_iterator
71-
w_it=a_rec.writes.begin();
72-
w_it!=a_rec.writes.end();
73-
++w_it)
57+
for(const auto &write_event : address.second.writes)
7458
{
75-
const event_it w=*w_it;
76-
7759
// rf cannot contradict program order
78-
if(po(r, w))
79-
continue; // contradicts po
80-
81-
bool is_rfi=
82-
w->source.thread_nr==r->source.thread_nr;
83-
84-
symbol_exprt s=nondet_bool_symbol("rf");
85-
86-
// record the symbol
87-
choice_symbols.emplace(std::make_pair(r, w), s);
88-
89-
// We rely on the fact that there is at least
90-
// one write event that has guard 'true'.
91-
implies_exprt read_from(s,
92-
and_exprt(w->guard,
93-
equal_exprt(r->ssa_lhs, w->ssa_lhs)));
94-
95-
// Uses only the write's guard as precondition, read's guard
96-
// follows from rf_some
97-
add_constraint(equation,
98-
read_from, is_rfi?"rfi":"rf", r->source);
99-
100-
if(!is_rfi)
60+
if(!po(read_event, write_event))
10161
{
102-
// if r reads from w, then w must have happened before r
103-
const implies_exprt cond(s, before(w, r));
104-
add_constraint(equation,
105-
cond, "rf-order", r->source);
62+
rf_choice_symbols.push_back(register_read_from_choice_symbol(
63+
read_event, write_event, equation));
10664
}
107-
108-
rf_some_operands.push_back(s);
10965
}
11066

111-
// value equals the one of some write
112-
exprt rf_some;
113-
11467
// uninitialised global symbol like symex_dynamic::dynamic_object*
11568
// or *$object
116-
if(rf_some_operands.empty())
117-
continue;
118-
else if(rf_some_operands.size()==1)
119-
rf_some=rf_some_operands.front();
120-
else
69+
if(!rf_choice_symbols.empty())
12170
{
122-
rf_some = or_exprt(std::move(rf_some_operands));
71+
// Add the read's guard, each of the writes' guards is implied
72+
// by each entry in rf_some
73+
add_constraint(
74+
equation,
75+
implies_exprt{read_event->guard, disjunction(rf_choice_symbols)},
76+
"rf-some",
77+
read_event->source);
12378
}
124-
125-
// Add the read's guard, each of the writes' guards is implied
126-
// by each entry in rf_some
127-
add_constraint(equation,
128-
implies_exprt(r->guard, rf_some), "rf-some", r->source);
12979
}
13080
}
13181
}
82+
83+
symbol_exprt memory_model_baset::register_read_from_choice_symbol(
84+
const event_it &r,
85+
const event_it &w,
86+
symex_target_equationt &equation)
87+
{
88+
symbol_exprt s = nondet_bool_symbol("rf");
89+
90+
// record the symbol
91+
choice_symbols.emplace(std::make_pair(r, w), s);
92+
93+
bool is_rfi = w->source.thread_nr == r->source.thread_nr;
94+
// Uses only the write's guard as precondition, read's guard
95+
// follows from rf_some
96+
add_constraint(
97+
equation,
98+
// We rely on the fact that there is at least
99+
// one write event that has guard 'true'.
100+
implies_exprt{s, and_exprt{w->guard, equal_exprt{r->ssa_lhs, w->ssa_lhs}}},
101+
is_rfi ? "rfi" : "rf",
102+
r->source);
103+
104+
if(!is_rfi)
105+
{
106+
// if r reads from w, then w must have happened before r
107+
add_constraint(
108+
equation, implies_exprt{s, before(w, r)}, "rf-order", r->source);
109+
}
110+
111+
return s;
112+
}

src/goto-symex/memory_model.h

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@ Author: Michael Tautschnig, michael.tautschnig@cs.ox.ac.uk
1414

1515
#include "partial_order_concurrency.h"
1616

17-
class memory_model_baset:public partial_order_concurrencyt
17+
class memory_model_baset : public partial_order_concurrencyt
1818
{
1919
public:
2020
explicit memory_model_baset(const namespacet &_ns);
2121
virtual ~memory_model_baset();
2222

23-
virtual void operator()(symex_target_equationt &)=0;
23+
virtual void operator()(symex_target_equationt &) = 0;
2424

2525
protected:
26-
// program order
26+
/// In-thread program order
27+
/// \param e1: preceding event
28+
/// \param e2: following event
29+
/// \return true if e1 precedes e2 in program order
2730
bool po(event_it e1, event_it e2);
2831

2932
// produce fresh symbols
@@ -32,12 +35,27 @@ class memory_model_baset:public partial_order_concurrencyt
3235

3336
// This gives us the choice symbol for an R-W pair;
3437
// built by the method below.
35-
typedef std::map<
36-
std::pair<event_it, event_it>, symbol_exprt> choice_symbolst;
38+
typedef std::map<std::pair<event_it, event_it>, symbol_exprt> choice_symbolst;
3739
choice_symbolst choice_symbols;
3840

41+
/// For each read `r` from every address we collect the choice symbols `S`
42+
/// via \ref register_read_from_choice_symbol (for potential read-write
43+
/// pairs) and add a constraint r.guard => \/S.
44+
/// \param equation: symex equation where the new constraint should be added
3945
void read_from(symex_target_equationt &equation);
4046

47+
/// Introduce a new choice symbol `s` for the pair (\p r, \p w)
48+
/// add constraint s => (w.guard /\ r.lhs=w.lhs)
49+
/// add constraint s => before(w,r) [if \p w is from another thread]
50+
/// \param r: read event
51+
/// \param w: write event
52+
/// \param equation: symex equation where the new constraints should be added
53+
/// \return the new choice symbol
54+
symbol_exprt register_read_from_choice_symbol(
55+
const event_it &r,
56+
const event_it &w,
57+
symex_target_equationt &equation);
58+
4159
// maps thread numbers to an event list
4260
typedef std::map<unsigned, event_listt> per_thread_mapt;
4361
};

0 commit comments

Comments
 (0)