CBMC
partial_order_concurrency.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Add constraints to equation encoding partial orders on events
4 
5 Author: Michael Tautschnig, michael.tautschnig@cs.ox.ac.uk
6 
7 \*******************************************************************/
8 
11 
13 
14 #include <util/arith_tools.h>
15 #include <util/bitvector_types.h>
16 #include <util/simplify_expr.h>
17 
19  const namespacet &_ns):ns(_ns)
20 {
21 }
22 
24 {
25 }
26 
28  symex_target_equationt &equation)
29 {
30  std::unordered_set<irep_idt> init_done;
31  bool spawn_seen=false;
32 
34 
35  for(eventst::const_iterator
36  e_it=equation.SSA_steps.begin();
37  e_it!=equation.SSA_steps.end();
38  e_it++)
39  {
40  if(e_it->is_spawn())
41  {
42  spawn_seen=true;
43  continue;
44  }
45  else if(!e_it->is_shared_read() &&
46  !e_it->is_shared_write())
47  continue;
48 
49  const irep_idt &a=address(e_it);
50 
51  if(init_done.find(a)!=init_done.end())
52  continue;
53 
54  if(spawn_seen ||
55  e_it->is_shared_read() ||
56  !e_it->guard.is_true())
57  {
58  init_steps.emplace_back(
60  SSA_stept &SSA_step = init_steps.back();
61 
62  SSA_step.guard=true_exprt();
63  // no SSA L2 index, thus nondet value
64  SSA_step.ssa_lhs = remove_level_2(e_it->ssa_lhs);
65  SSA_step.atomic_section_id=0;
66  }
67 
68  init_done.insert(a);
69  }
70 
71  equation.SSA_steps.splice(equation.SSA_steps.begin(), init_steps);
72 }
73 
75  symex_target_equationt &equation,
76  message_handlert &message_handler)
77 {
78  add_init_writes(equation);
79 
80  // a per-thread counter
81  std::map<unsigned, unsigned> counter;
82 
83  for(eventst::const_iterator
84  e_it=equation.SSA_steps.begin();
85  e_it!=equation.SSA_steps.end();
86  e_it++)
87  {
88  if(e_it->is_shared_read() ||
89  e_it->is_shared_write() ||
90  e_it->is_spawn())
91  {
92  unsigned thread_nr=e_it->source.thread_nr;
93 
94  if(!e_it->is_spawn())
95  {
96  a_rect &a_rec=address_map[address(e_it)];
97 
98  if(e_it->is_shared_read())
99  a_rec.reads.push_back(e_it);
100  else // must be write
101  a_rec.writes.push_back(e_it);
102  }
103 
104  // maps an event id to a per-thread counter
105  unsigned cnt=counter[thread_nr]++;
106  numbering[e_it]=cnt;
107  }
108  }
109 
110  messaget log{message_handler};
111  for(address_mapt::const_iterator
112  a_it=address_map.begin();
113  a_it!=address_map.end();
114  a_it++)
115  {
116  const a_rect &a_rec=a_it->second;
117  if(a_rec.reads.empty())
118  continue;
119 
120  log.statistics() << "Shared " << a_it->first << ": " << a_rec.reads.size()
121  << "R/" << a_rec.writes.size() << "W" << messaget::eom;
122  }
123 }
124 
126  event_it event,
127  axiomt axiom)
128 {
129  if(event->is_shared_write())
130  return id2string(id(event))+"$wclk$"+std::to_string(axiom);
131  else if(event->is_shared_read())
132  return id2string(id(event))+"$rclk$"+std::to_string(axiom);
133  else
134  UNREACHABLE;
135 }
136 
138  event_it event,
139  axiomt axiom)
140 {
141  PRECONDITION(!numbering.empty());
142  irep_idt identifier;
143 
144  if(event->is_shared_write())
145  identifier=rw_clock_id(event, axiom);
146  else if(event->is_shared_read())
147  identifier=rw_clock_id(event, axiom);
148  else if(event->is_spawn())
149  {
150  identifier=
151  "t"+std::to_string(event->source.thread_nr+1)+"$"+
152  std::to_string(numbering[event])+"$spwnclk$"+std::to_string(axiom);
153  }
154  else
155  UNREACHABLE;
156 
157  return symbol_exprt(identifier, clock_type);
158 }
159 
161 {
162  PRECONDITION(!numbering.empty());
163 
164  std::size_t width = address_bits(numbering.size());
165  clock_type = unsignedbv_typet(width);
166 }
167 
169  event_it e1, event_it e2, unsigned axioms)
170 {
171  const axiomt axiom_bits[]=
172  {
177  };
178 
179  exprt::operandst ops;
180  ops.reserve(sizeof(axiom_bits)/sizeof(axiomt));
181 
182  for(int i=0; i<int(sizeof(axiom_bits)/sizeof(axiomt)); ++i)
183  {
184  const axiomt ax=axiom_bits[i];
185 
186  if((axioms &ax)==0)
187  continue;
188 
189  if(e1->atomic_section_id!=0 &&
190  e1->atomic_section_id==e2->atomic_section_id)
191  ops.push_back(equal_exprt(clock(e1, ax), clock(e2, ax)));
192  else
193  ops.push_back(
194  binary_relation_exprt(clock(e1, ax), ID_lt, clock(e2, ax)));
195  }
196 
197  POSTCONDITION(!ops.empty());
198 
199  return conjunction(ops);
200 }
201 
203  symex_target_equationt &equation,
204  const exprt &cond,
205  const std::string &msg,
206  const symex_targett::sourcet &source) const
207 {
208  exprt tmp=cond;
209  simplify(tmp, ns);
210 
211  equation.constraint(tmp, msg, source);
212 }
std::size_t address_bits(const mp_integer &size)
ceil(log2(size))
Pre-defined bitvector types.
Single SSA step in the equation.
Definition: ssa_step.h:47
unsigned atomic_section_id
Definition: ssa_step.h:169
exprt guard
Definition: ssa_step.h:135
ssa_exprt ssa_lhs
Definition: ssa_step.h:139
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
static eomt eom
Definition: message.h:297
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
void add_init_writes(symex_target_equationt &)
For each shared read event and for each shared write event that appears after spawn or has false guar...
void build_event_lists(symex_target_equationt &equation, message_handlert &message_handler)
First call add_init_writes then for each shared read/write (or spawn) populate: 1) the address_map (w...
exprt before(event_it e1, event_it e2, unsigned axioms)
Build the partial order constraint for two events: if e1 and e2 are in the same atomic section then c...
irep_idt address(event_it event) const
Produce an address ID for an event.
symbol_exprt clock(event_it e, axiomt axiom)
Produce a clock symbol for some event.
void build_clock_type()
Initialize the clock_type so that it can be used to number events.
static irep_idt rw_clock_id(event_it e, axiomt axiom=AX_PROPAGATION)
Build identifier for the read/write clock variable.
void add_constraint(symex_target_equationt &equation, const exprt &cond, const std::string &msg, const symex_targett::sourcet &source) const
Simplify and add a constraint to equation.
partial_order_concurrencyt(const namespacet &_ns)
eventst::const_iterator event_it
Expression to hold a symbol (variable)
Definition: std_expr.h:131
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
virtual void constraint(const exprt &cond, const std::string &msg, const sourcet &source)
Record a global constraint: there is no guard limiting its scope.
std::list< SSA_stept > SSA_stepst
The Boolean constant true.
Definition: std_expr.h:3055
Fixed-width bit-vector with unsigned binary interpretation.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
double log(double x)
Definition: math.c:2776
Add constraints to equation encoding partial orders on events.
bool simplify(exprt &expr, const namespacet &ns)
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define POSTCONDITION(CONDITION)
Definition: invariant.h:479
ssa_exprt remove_level_2(ssa_exprt ssa)
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:66
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Identifies source in the context of symbolic execution.
Definition: symex_target.h:37