CBMC
partial_order_concurrency.h
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 
12 #ifndef CPROVER_GOTO_SYMEX_PARTIAL_ORDER_CONCURRENCY_H
13 #define CPROVER_GOTO_SYMEX_PARTIAL_ORDER_CONCURRENCY_H
14 
15 #include "symex_target_equation.h"
16 
21 {
22 public:
23  explicit partial_order_concurrencyt(const namespacet &_ns);
25 
26  typedef SSA_stept eventt;
28  typedef eventst::const_iterator event_it;
29 
30  // the name of a clock variable for a shared read/write
31  enum axiomt
32  {
37  };
38 
43  static irep_idt rw_clock_id(
44  event_it e,
45  axiomt axiom=AX_PROPAGATION);
46 
47 protected:
48  const namespacet &ns;
49 
50  typedef std::vector<event_it> event_listt;
51 
52  // lists of reads and writes per address
53  struct a_rect
54  {
56  };
57 
58  typedef std::map<irep_idt, a_rect> address_mapt;
60 
69  void build_event_lists(
70  symex_target_equationt &equation,
71  message_handlert &message_handler);
72 
78 
79  // a per-thread numbering of the events
80  typedef std::map<event_it, unsigned> numberingt;
82 
86  static inline irep_idt id(event_it event)
87  {
88  return event->ssa_lhs.get_identifier();
89  }
90 
94  irep_idt address(event_it event) const
95  {
96  return remove_level_2(event->ssa_lhs).get_identifier();
97  }
98 
100 
105  symbol_exprt clock(event_it e, axiomt axiom);
106 
108  void build_clock_type();
109 
115  void add_constraint(
116  symex_target_equationt &equation,
117  const exprt &cond,
118  const std::string &msg,
119  const symex_targett::sourcet &source) const;
120 
129  exprt before(event_it e1, event_it e2, unsigned axioms);
130  virtual exprt before(event_it e1, event_it e2)=0;
131 };
132 
133 #if 0
134 #include <list>
135 #include <map>
136 #include <vector>
137 #include <string>
138 
139 #include "abstract_event_structure.h"
140 
141 class memory_model_baset;
142 
143 class numbered_evtst
144 {
145  typedef abstract_eventt evtt;
146 
147 public:
148  typedef std::vector<evtt const*> ordered_evtst;
149  // NOLINTNEXTLINE(readability/identifiers)
150  typedef ordered_evtst::const_iterator const_iterator;
151  typedef std::map<evtt const*, ordered_evtst::size_type> ordered_evts_mapt;
152 
153  void add_event(const evtt &evt)
154  {
155  const ordered_evtst::size_type offset=ordered_evts.size();
156  ordered_evts.push_back(&evt);
157  if(!ordered_evts_map.insert(std::make_pair(&evt, offset)).second)
158  UNREACHABLE;
159  assert(ordered_evts.size()==ordered_evts_map.size());
160 
161  if(evt.direction==evtt::D_SYNC ||
162  evt.direction==evtt::D_LWSYNC)
163  barriers.insert(barriers.end(), offset);
164  }
165 
166  void add_events(const_iterator first, const_iterator last)
167  {
168  ordered_evts.reserve(ordered_evts.size()+last-first);
169  for( ; first!=last; ++first)
170  add_event(**first);
171  }
172 
173  const_iterator begin() const
174  {
175  return ordered_evts.begin();
176  }
177 
178  const_iterator end() const
179  {
180  return ordered_evts.end();
181  }
182 
183  const_iterator find(const evtt &evt) const
184  {
185  ordered_evts_mapt::const_iterator entry=ordered_evts_map.find(&evt);
186  if(entry==ordered_evts_map.end())
187  return end();
188 
189  return ordered_evts.begin()+entry->second;
190  }
191 
192  std::list<const_iterator> barriers_after(const evtt &evt) const
193  {
194  const_iterator entry=find(evt);
195  if(entry==end())
196  return std::list<const_iterator>();
197 
198  std::list<const_iterator> ret;
199  ordered_evtst::size_type offset=entry-begin();
200  for(std::set<ordered_evtst::size_type>::const_iterator
201  lb=barriers.lower_bound(offset);
202  lb!=barriers.end();
203  ++lb)
204  ret.push_back(ordered_evts.begin()+*lb);
205 
206  return ret;
207  }
208 
209  std::list<const_iterator> barriers_before(const evtt &evt) const
210  {
211  const_iterator entry=find(evt);
212  if(entry==end())
213  return std::list<const_iterator>();
214 
215  std::list<const_iterator> ret;
216  ordered_evtst::size_type offset=entry-begin();
217  for(std::set<ordered_evtst::size_type>::const_iterator
218  ub=barriers.begin();
219  ub!=barriers.end() && *ub<=offset;
220  ++ub)
221  ret.push_back(ordered_evts.begin()+*ub);
222 
223  return ret;
224  }
225 
226 private:
227  ordered_evtst ordered_evts;
228  ordered_evts_mapt ordered_evts_map;
229  std::set<ordered_evtst::size_type> barriers;
230 };
231 
233 {
234 public:
235  // the is-acyclic checks
236  enum acyclict
237  {
238  AC_UNIPROC=0,
239  AC_THINAIR=1,
240  AC_GHB=2,
241  AC_PPC_WS_FENCE=3,
242  AC_N_AXIOMS=4
243  };
244 
245  typedef abstract_eventt evtt;
246  typedef std::map<evtt const*, std::map<evtt const*, exprt> > adj_matrixt;
247  typedef adj_matrixt adj_matricest[AC_N_AXIOMS];
248  typedef std::list<evtt const*> per_valuet;
249  typedef std::map<irep_idt, per_valuet> per_address_mapt;
250  typedef std::vector<numbered_evtst> numbered_per_thread_evtst;
251 
253  memory_model_baset &_memory_model,
254  symex_target_equationt &_target,
255  const namespacet &_ns,
256  messaget &_message);
257 
258  void init(const abstract_events_in_program_ordert &abstract_events_in_po);
259  void add_atomic_sections();
260 
261  // collect all partial orders
262  void add_program_order(adj_matricest &po);
263  void add_read_from(adj_matricest &rf);
264  void add_write_serialisation(adj_matricest &ws);
265  void add_from_read(
266  const adj_matricest &rf,
267  const adj_matricest &ws,
268  adj_matricest &fr);
269  void add_barriers(
270  const adj_matricest &po,
271  const adj_matricest &rf,
272  const adj_matricest &fr);
273 
274  void acyclic();
275 
276  // steps as used in PLDI Power model
277 # define S_COMMIT 0
278 # define S_R_REQ 1
279 # define S_S_ACK 1
280 # define S_PROP(t) ((t+1)<<1)
282  const acyclict check,
283  const evtt &n,
284  const unsigned step) const;
286  const acyclict check,
287  const evtt &n,
288  const unsigned step,
289  const evtt::event_dirt other_dir) const;
290 
291  symbol_exprt fresh_nondet_bool();
292  void add_constraint(
293  exprt &expr,
294  const guardt &guard,
295  const symex_targett::sourcet &source,
296  const std::string &po_name);
297  void add_atomic_sections(const acyclict check);
298  void add_partial_order_constraint(
299  const acyclict check,
300  const std::string &po_name,
301  const evtt &n1,
302  const evtt &n2,
303  const exprt &cond);
304  void add_partial_order_constraint(
305  const acyclict check,
306  const std::string &po_name,
307  const evtt &n1,
308  const unsigned n1_step,
309  const evtt::event_dirt n1_o_d,
310  const evtt &n2,
311  const unsigned n2_step,
312  const evtt::event_dirt n2_o_d,
313  const exprt &cond);
314 
315  const evtt* first_of(const evtt &e1, const evtt &e2) const;
316  const numbered_evtst &get_thread(const evtt &e) const;
317  const numbered_per_thread_evtst &get_all_threads() const
318  {
319  return per_thread_evt_no;
320  }
321 
322  const namespacet &get_ns() const { return ns; }
323  messaget &get_message() { return message; }
324  std::map<std::string, unsigned> num_concurrency_constraints;
325 
326 private:
327  memory_model_baset &memory_model;
328  symex_target_equationt &target;
329  const namespacet &ns;
330  messaget &message;
331 
332  // collect all reads and writes to each address
333  per_address_mapt reads_per_address, writes_per_address;
334 
335  // initialisation events for uninitialised globals
336  std::map<irep_idt, evtt> init_val;
337 
338  // constraints added to the formula
339  const std::string prop_var;
340  unsigned prop_cnt;
341 
342  // number events according to po per thread, including parents
343  numbered_per_thread_evtst per_thread_evt_no;
344 
345  // map between events and (symbolic) integers
346  typet node_type;
347  std::map<evtt const*, unsigned> barrier_id;
348  symbol_exprt node_symbol(
349  const evtt &evt,
350  const std::string &prefix) const;
351  std::vector<std::pair<symbol_exprt, symbol_exprt>>
352  atomic_section_bounds[AC_N_AXIOMS];
353 
354  std::list<exprt> acyclic_constraints[AC_N_AXIOMS];
355  static std::string check_to_string(const acyclict check);
356 
357  // map point-wise order to a single Boolean symbol
358  typedef std::pair<evtt const*, std::pair<unsigned, evtt::event_dirt>>
359  evt_dir_pairt;
360  typedef std::map<std::pair<evt_dir_pairt, evt_dir_pairt>,
361  symbol_exprt> pointwise_mapt;
362  pointwise_mapt edge_cache[AC_N_AXIOMS];
363  typedef std::map<evtt const*,
364  std::list<std::pair<evtt const*, std::pair<exprt, std::string> > > >
365  edge_to_guardt;
366  edge_to_guardt edge_to_guard[AC_N_AXIOMS];
367 
368  void add_sub_clock_rules();
369 
370  typedef std::map<std::pair<irep_idt, irep_idt>, symbol_exprt> clock_mapt;
371  clock_mapt clock_constraint_cache;
372  symbol_exprt add_clock_constraint(
373  const symbol_exprt &n1_sym,
374  const symbol_exprt &n2_sym,
375  const symex_targett::sourcet &source,
376  const std::string &po_name);
377  const symbol_exprt &get_partial_order_constraint(
378  const acyclict check,
379  const std::string &po_name,
380  const evtt &n1,
381  const unsigned n1_step,
382  const evtt::event_dirt n1_o_d,
383  const evtt &n2,
384  const unsigned n2_step,
385  const evtt::event_dirt n2_o_d);
386  void build_partial_order_constraint(
387  const acyclict check,
388  const std::string &po_name,
389  const evtt &n1,
390  const unsigned n1_step,
391  const evtt::event_dirt n1_o_d,
392  const evtt &n2,
393  const unsigned n2_step,
394  const evtt::event_dirt n2_o_d,
395  symbol_exprt &dest);
396 
397  // debugging output
398  std::string event_to_string(const evtt &evt) const;
399  void print_graph(
400  const adj_matrixt &graph,
401  const std::string &edge_label,
402  namespacet const &ns) const;
403 };
404 #endif
405 
406 #endif // CPROVER_GOTO_SYMEX_PARTIAL_ORDER_CONCURRENCY_H
static exprt guard(const exprt::operandst &guards, exprt cond)
Single SSA step in the equation.
Definition: ssa_step.h:47
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
Base class for implementing memory models via additional constraints for SSA equations.
std::vector< event_it > event_listt
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...
std::map< event_it, unsigned > numberingt
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.
virtual exprt before(event_it e1, event_it e2)=0
void build_clock_type()
Initialize the clock_type so that it can be used to number events.
std::map< irep_idt, a_rect > address_mapt
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)
symex_target_equationt::SSA_stepst eventst
static irep_idt id(event_it event)
Produce the symbol ID for an event.
eventst::const_iterator event_it
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
std::list< SSA_stept > SSA_stepst
The type of an expression, extends irept.
Definition: type.h:29
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
ssa_exprt remove_level_2(ssa_exprt ssa)
Identifies source in the context of symbolic execution.
Definition: symex_target.h:37
Generate Equation using Symbolic Execution.
#define size_type
Definition: unistd.c:347