CBMC
event_graph.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: graph of abstract events
4 
5 Author: Vincent Nimal
6 
7 Date: 2012
8 
9 \*******************************************************************/
10 
13 
14 #include "event_graph.h"
15 
16 #include <util/message.h>
17 
18 #include <fstream>
19 
20 
21 #define NB_COLOURS 14
22 static const char *colour_map[NB_COLOURS]=
23  {"red", "blue", "black", "green", "yellow",
24  "orange", "blueviolet", "cyan", "cadetblue", "magenta", "palegreen",
25  "deeppink", "indigo", "olivedrab"};
26 #define print_colour(u) colour_map[u%NB_COLOURS]
27 
28 void event_grapht::print_rec_graph(std::ofstream &file, event_idt node_id,
29  std::set<event_idt> &visited)
30 {
31  const abstract_eventt &node=operator[](node_id);
32  file << node_id << "[label=\"" << node << ", " << node.source_location <<
33  "\"];\n";
34  visited.insert(node_id);
35 
36  for(wmm_grapht::edgest::const_iterator
37  it=po_out(node_id).begin();
38  it!=po_out(node_id).end(); ++it)
39  {
40  file << node_id << "->" << it->first << "[]\n";
41  file << "{rank=same; " << node_id << "; " << it->first << "}\n";
42  if(visited.find(it->first)==visited.end())
43  print_rec_graph(file, it->first, visited);
44  }
45 
46  for(wmm_grapht::edgest::const_iterator
47  it=com_out(node_id).begin();
48  it!=com_out(node_id).end(); ++it)
49  {
50  file << node_id << "->" << it->first << "[style=\"dotted\"]\n";
51  if(visited.find(it->first)==visited.end())
52  print_rec_graph(file, it->first, visited);
53  }
54 }
55 
57 {
58  PRECONDITION(!po_order.empty());
59  std::set<event_idt> visited;
60  event_idt root=po_order.front();
61  std::ofstream file;
62  file.open("graph.dot");
63  file << "digraph G {\n";
64  file << "rankdir=LR;\n";
65  print_rec_graph(file, root, visited);
66  file << "}\n";
67 }
68 
73 void event_grapht::explore_copy_segment(std::set<event_idt> &explored,
74  event_idt begin, event_idt end) const
75 {
76  // std::cout << "explores " << begin << " against " << end << '\n';
77  if(explored.find(begin)!=explored.end())
78  return;
79 
80  explored.insert(begin);
81 
82  if(begin==end)
83  return;
84 
85  for(wmm_grapht::edgest::const_iterator it=po_out(begin).begin();
86  it!=po_out(begin).end();
87  ++it)
88  explore_copy_segment(explored, it->first, end);
89 }
90 
92 {
93  const abstract_eventt &begin_event=operator[](begin);
94  const abstract_eventt &end_event=operator[](end);
95 
96  /* not sure -- we should allow cross function cycles */
97  if(
98  begin_event.source_location.get_file() !=
99  end_event.source_location.get_file() ||
100  begin_event.function_id != end_event.function_id)
101  return end;
102 
103  if(duplicated_bodies.find(std::make_pair(begin_event, end_event))
104  !=duplicated_bodies.end())
105  return end;
106 
107  duplicated_bodies.insert(std::make_pair(begin_event, end_event));
108 
109  message.status() << "tries to duplicate between "
110  << begin_event.source_location
111  << " and " << end_event.source_location << messaget::eom;
112  std::set<event_idt> covered;
113 
114  /* collects the nodes of the subgraph */
115  explore_copy_segment(covered, begin, end);
116 
117  if(covered.empty())
118  return end;
119 
120 // for(std::set<event_idt>::const_iterator it=covered.begin();
121 // it!=covered.end(); ++it)
122 // std::cout << "covered: " << *it << '\n';
123 
124  std::map<event_idt, event_idt> orig2copy;
125 
126  /* duplicates nodes */
127  for(std::set<event_idt>::const_iterator it=covered.begin();
128  it!=covered.end();
129  ++it)
130  {
131  const event_idt new_node=add_node();
132  operator[](new_node)(operator[](*it));
133  orig2copy[*it]=new_node;
134  }
135 
136  /* nested loops -- replicates the po_s back-edges */
137  // actually not necessary, as they have been treated before
138  // (working on back-edges...)
139 
140  /* replicates the po_s forward-edges -- O(#E^2) */
141  for(std::set<event_idt>::const_iterator it_i=covered.begin();
142  it_i!=covered.end();
143  ++it_i)
144  {
145  for(std::set<event_idt>::const_iterator it_j=covered.begin();
146  it_j!=covered.end();
147  ++it_j)
148  {
149  /* skips potential back-edges */
150  if(*it_j >= *it_i)
151  continue;
152 
153  if(has_po_edge(*it_j, *it_i))
154  add_po_edge(orig2copy[*it_j], orig2copy[*it_i]);
155  }
156  }
157 
158  /* appends the copy to the original, and returns the end of the copy */
159  add_po_edge(end, orig2copy[begin]);
160 
161  // TODO: to move to goto2graph, after po_s construction
162  /* replicates the cmp-edges -- O(#E x #G) */
163  for(std::set<event_idt>::const_iterator it_i=covered.begin();
164  it_i!=covered.end();
165  ++it_i)
166  {
167  for(event_idt it_j=0;
168  it_j<size();
169  ++it_j)
170  {
171  /* skips potential back-edges */
172  if(it_j >= *it_i)
173  continue;
174 
175  if(has_com_edge(it_j, *it_i))
176  {
177  add_com_edge(it_j, orig2copy[*it_i]);
178  add_com_edge(orig2copy[*it_i], it_j);
179  }
180  }
181  }
182  // end
183 
184  return orig2copy[end];
185 }
186 
188  const_iterator s_it,
189  const abstract_eventt &first,
190  const abstract_eventt &second) const
191 {
192  bool AC=false;
193  const_iterator AC_it=s_it;
194  ++AC_it;
195  for(; AC_it!=end(); ++AC_it)
196  {
197  const abstract_eventt &AC_evt=egraph[*AC_it];
199  {
200  AC=true;
201  break;
202  }
203  if(AC_evt.thread!=second.thread)
204  break;
205  }
206 
207  if(AC)
208  return true;
209 
210  if(AC_it==end() && egraph[front()].thread==second.thread)
211  {
212  for(AC_it=begin(); ; ++AC_it)
213  {
214  const abstract_eventt &AC_evt=egraph[*AC_it];
216  {
217  AC=true;
218  break;
219  }
220  if(AC_evt==first || AC_evt.thread!=second.thread)
221  break;
222  }
223  }
224 
225  return AC;
226 }
227 
229  const_iterator it,
230  const abstract_eventt &first,
231  const abstract_eventt &second) const
232 {
233  bool BC=false;
234  /* no fence before the first element? (BC) */
235  const_iterator BC_it;
236  if(it==begin())
237  {
238  BC_it=end();
239  --BC_it;
240  }
241  else
242  {
243  BC_it=it;
244  --BC_it;
245  }
246  for(; BC_it!=begin(); --BC_it)
247  {
248  const abstract_eventt &BC_evt=egraph[*BC_it];
250  {
251  BC=true;
252  break;
253  }
254  if(BC_evt.thread!=first.thread)
255  break;
256  }
257 
258  if(BC)
259  return true;
260 
261  if(BC_it==begin() && egraph[back()].thread==first.thread)
262  {
263  BC_it=end();
264  --BC_it;
265  for(; ; --BC_it)
266  {
267  const abstract_eventt &BC_evt=egraph[*BC_it];
269  {
270  BC=true;
271  break;
272  }
273  if(BC_evt==second || BC_evt.thread!=first.thread)
274  break;
275  }
276  }
277 
278  return BC;
279 }
280 
282 {
283  egraph.message.debug() << "cycle is safe?" << messaget::eom;
284  bool unsafe_met=false;
285 
286  /* critical cycles contain at least 4 events */
287  if(size()<4)
288  return false;
289 
290  /* critical cycles contain at least 2 threads */
291  unsigned thread=egraph[*begin()].thread;
292  const_iterator th_it;
293  for(th_it=begin();
294  th_it!=end() && thread==egraph[*th_it].thread; ++th_it)
295  thread=egraph[*th_it].thread;
296  if(th_it==end())
297  return false;
298 
299  /* selects the first element of the pair */
300  const_iterator it=begin();
301  const_iterator next=it;
302  ++next;
303  for(; it!=end() && next!=end(); ++next, ++it)
304  {
305  const abstract_eventt &it_evt=egraph[*it];
306  const abstract_eventt &next_evt=egraph[*next];
307 
308  /* strong fence -- this pair is safe */
310  continue;
311 
313  continue;
314 
315  /* first element is a weak fence */
317  continue;
318 
319  /* selects the next event which is not a weak fence */
320  const_iterator s_it=next;
321 
322  for(; s_it!=end() &&
323  egraph[*s_it].operation==abstract_eventt::operationt::Lwfence;
324  ++s_it)
325  {
326  }
327 
328  if(s_it==end())
329  continue;
330 
331  const abstract_eventt &s_evt=egraph[*s_it];
332 
334  continue;
335 
336  /* if the whole cycle has been explored */
337  if(it==s_it)
338  continue;
339 
340  const abstract_eventt &first=it_evt;
341  const abstract_eventt &second=s_evt;
342  const data_dpt &data_dp=egraph.map_data_dp[first.thread];
343 
344  /* if data dp between linking the pair, safe */
345  if(first.thread==second.thread && data_dp.dp(first, second))
346  continue;
347 
348  /* AC and BC conditions */
349  if(first.thread!=second.thread && model==Power)
350  {
351  if(check_AC(s_it, first, second))
352  continue;
353 
354  if(check_BC(it, first, second))
355  continue;
356  }
357 
358  const_iterator n_it=it;
359  ++n_it;
360  if(s_it==n_it)
361  {
362  /* there is no lwfence between the pair */
363  if(first.unsafe_pair(second, model)
364  && (first.thread!=second.thread || egraph.are_po_ordered(*it, *s_it)))
365  {
366  const_iterator before_first;
367  const_iterator after_second;
368 
369  if(it==begin())
370  before_first=end();
371  else
372  before_first=it;
373  --before_first;
374 
375  n_it=s_it;
376  ++n_it;
377  if(n_it==end())
378  after_second=begin();
379  else
380  after_second=s_it;
381 
382  if(first.variable==second.variable
383  && first.thread==second.thread
384  && egraph[*before_first].thread!=first.thread
385  && egraph[*after_second].thread!=second.thread)
386  {
387  /* not unsafe */
388  }
389  else
390  {
391  if(fast)
392  return true;
393  else
394  {
395  const delayt delay(*it, *s_it, (first.thread==second.thread));
396  unsafe_pairs.insert(delay);
397  unsafe_met=true;
398  }
399  }
400  }
401  }
402  else
403  {
404  /* one (or more) lwfence between the pair */
405  if(first.unsafe_pair_lwfence(second, model)
406  && (first.thread!=second.thread || egraph.are_po_ordered(*it, *s_it)))
407  {
408  const_iterator before_first;
409  const_iterator after_second;
410 
411  if(it==begin())
412  before_first=end();
413  else
414  before_first=it;
415  --before_first;
416 
417  n_it=s_it;
418  ++n_it;
419  if(n_it==end())
420  after_second=begin();
421  else
422  after_second=s_it;
423 
424  if(first.variable==second.variable
425  && first.thread==second.thread
426  && egraph[*before_first].thread!=first.thread
427  && egraph[*after_second].thread!=second.thread)
428  {
429  /* not unsafe */
430  }
431  else
432  {
433  if(fast)
434  return true;
435  else
436  {
437  const delayt delay(*it, *s_it, (first.thread==second.thread));
438  unsafe_pairs.insert(delay);
439  unsafe_met=true;
440  }
441  }
442  }
443  }
444  }
445 
446  /* strong fence -- this pair is safe */
447  if(egraph[back()].operation==abstract_eventt::operationt::Fence
448  || egraph[front()].operation==abstract_eventt::operationt::Fence)
449  return unsafe_met;
450 
451  /* first element is a weak fence */
452  if(egraph[back()].operation==abstract_eventt::operationt::Lwfence)
453  return unsafe_met;
454 
455  /* selects the next event which is not a weak fence */
456  const_iterator s_it;
457  for(s_it=begin();
458  s_it!=end() &&
459  egraph[*s_it].operation==abstract_eventt::operationt::Lwfence;
460  s_it++)
461  {
462  }
463 
464  /* if the whole cycle has been explored */
465  if(s_it==end())
466  return unsafe_met;
467 
468  if(egraph[*s_it].operation==abstract_eventt::operationt::Fence)
469  return unsafe_met;
470 
471  const abstract_eventt &first=egraph[back()];
472  const abstract_eventt &second=egraph[*s_it];
473 
474  const data_dpt &data_dp=egraph.map_data_dp[first.thread];
475 
476  /* if data dp between linking the pair, safe */
477  if(first.thread==second.thread && data_dp.dp(first, second))
478  return unsafe_met;
479 
480  /* AC and BC conditions */
481  if(first.thread!=second.thread && model==Power)
482  {
483  if(check_AC(s_it, first, second))
484  return unsafe_met;
485 
486  if(check_BC(begin(), first, second))
487  return unsafe_met;
488  }
489 
490  if(s_it==begin())
491  {
492  /* no lwfence between the pair */
493  if(first.unsafe_pair(second, model)
494  && (first.thread!=second.thread || egraph.are_po_ordered(back(), *s_it)))
495  {
496  std::list<event_idt>::const_iterator before_first;
497  std::list<event_idt>::const_iterator after_second;
498 
499  before_first=end();
500  --before_first;
501  --before_first;
502 
503  after_second=s_it;
504  ++after_second;
505 
506  if(first.variable==second.variable
507  && first.thread==second.thread
508  && egraph[*before_first].thread!=first.thread
509  && egraph[*after_second].thread!=second.thread)
510  {
511  /* not unsafe */
512  }
513  else
514  {
515  if(!fast)
516  {
517  const delayt delay(back(), *s_it, (first.thread==second.thread));
518  unsafe_pairs.insert(delay);
519  }
520  return true;
521  }
522  }
523  }
524  else
525  {
526  /* one (or more) lwfence between the pair */
527  if(first.unsafe_pair_lwfence(second, model)
528  && (first.thread!=second.thread || egraph.are_po_ordered(back(), *s_it)))
529  {
530  std::list<event_idt>::const_iterator before_first;
531  std::list<event_idt>::const_iterator after_second;
532 
533  before_first=end();
534  --before_first;
535  --before_first;
536 
537  after_second=s_it;
538  ++after_second;
539 
540  if(first.variable==second.variable
541  && first.thread==second.thread
542  && egraph[*before_first].thread!=first.thread
543  && egraph[*after_second].thread!=second.thread)
544  {
545  /* not unsafe */
546  }
547  else
548  {
549  if(!fast)
550  {
551  const delayt delay(back(), *s_it, (first.thread==second.thread));
552  unsafe_pairs.insert(delay);
553  }
554  return true;
555  }
556  }
557  }
558 
559  return unsafe_met;
560 }
561 
564  memory_modelt model,
565  bool fast)
566 {
567  egraph.message.debug() << "cycle is safe?" << messaget::eom;
568  bool unsafe_met=false;
569  unsigned char fences_met=0;
570 
571  /* critical cycles contain at least 4 events */
572  if(size()<4)
573  return false;
574 
575  /* critical cycles contain at least 2 threads */
576  unsigned thread=egraph[*begin()].thread;
577  const_iterator th_it;
578  for(th_it=begin();
579  th_it!=end() && thread==egraph[*th_it].thread; ++th_it)
580  thread=egraph[*th_it].thread;
581  if(th_it==end())
582  return false;
583 
584  /* selects the first element of the pair */
585  for(const_iterator it=begin(); it!=end() && ++it!=end(); it++)
586  {
587  --it;
588  fences_met=0;
589 
590  /* fence -- this pair is safe */
591  if(egraph[*it].operation==abstract_eventt::operationt::ASMfence)
592  continue;
593 
594  if(egraph[*(++it)].operation==abstract_eventt::operationt::ASMfence)
595  {
596  --it;
597  continue;
598  }
599 
600  --it;
601 
602  /* selects the next event which is not a weak fence */
603  const_iterator s_it=++it;
604  --it;
605 
606  for(;
607  s_it!=end() &&
608  egraph[*s_it].operation==abstract_eventt::operationt::ASMfence;
609  s_it++)
610  fences_met |= egraph[*s_it].fence_value();
611 
612  if(s_it==end())
613  continue;
614 
615  if(egraph[*s_it].operation==abstract_eventt::operationt::ASMfence)
616  continue;
617 
618  /* if the whole cycle has been explored */
619  if(it==s_it)
620  continue;
621 
622  const abstract_eventt &first=egraph[*it];
623  const abstract_eventt &second=egraph[*s_it];
624 
625  const data_dpt &data_dp=egraph.map_data_dp[first.thread];
626 
627  /* if data dp between linking the pair, safe */
628  if(first.thread==second.thread && data_dp.dp(first, second))
629  continue;
630 
631  /* AC and BC conditions */
632  if(first.thread!=second.thread && model==Power)
633  {
634  bool AC=false;
635  bool BC=false;
636 
637  /* no fence after the second element? (AC) */
638  const_iterator AC_it=++s_it;
639  --s_it;
640  for(;
641  AC_it!=end() && egraph[*AC_it].thread==second.thread;
642  AC_it++)
643  if(egraph[*AC_it].operation==abstract_eventt::operationt::ASMfence
644  && egraph[*AC_it].is_cumul()
645  && egraph[*AC_it].is_corresponding_fence(egraph[*it], egraph[*s_it]))
646  {
647  AC=true;
648  break;
649  }
650 
651  if(AC)
652  continue;
653 
654  if(AC_it==end() && egraph[front()].thread==second.thread)
655  {
656  for(AC_it=begin();
657  !(egraph[*AC_it]==first) && egraph[*AC_it].thread==second.thread;
658  AC_it++)
659  if(egraph[*AC_it].operation==abstract_eventt::operationt::ASMfence &&
660  egraph[*AC_it].is_cumul() &&
661  egraph[*AC_it].is_corresponding_fence(egraph[*it], egraph[*s_it]))
662  {
663  AC=true;
664  break;
665  }
666  }
667 
668  if(AC)
669  continue;
670 
671  /* no fence before the first element? (BC) */
672  const_iterator BC_it;
673  if(it==begin())
674  {
675  BC_it=end();
676  BC_it--;
677  }
678  else
679  {
680  BC_it=--it;
681  ++it;
682  }
683  for( ;
684  BC_it!=begin() && egraph[*BC_it].thread==first.thread;
685  BC_it--)
686  {
687  if(egraph[*BC_it].operation==abstract_eventt::operationt::ASMfence &&
688  egraph[*BC_it].is_cumul() &&
689  egraph[*BC_it].is_corresponding_fence(egraph[*it], egraph[*s_it]))
690  {
691  BC=true;
692  break;
693  }
694  }
695 
696  if(BC)
697  continue;
698 
699  if(BC_it==begin() && egraph[back()].thread==first.thread)
700  {
701  for(BC_it=end();
702  !(egraph[*BC_it]==second) && egraph[*BC_it].thread==first.thread;
703  BC_it--)
704  if(egraph[*BC_it].operation==abstract_eventt::operationt::ASMfence &&
705  egraph[*BC_it].is_cumul() &&
706  egraph[*BC_it].is_corresponding_fence(egraph[*it], egraph[*s_it]))
707  {
708  BC=true;
709  break;
710  }
711  }
712 
713  if(BC)
714  continue;
715  }
716 
717  if(s_it==++it)
718  {
719  --it;
720 
721  /* no lwfence between the pair */
722  if(first.unsafe_pair(second, model)
723  && (first.thread!=second.thread || egraph.are_po_ordered(*it, *s_it)))
724  {
725  if(fast)
726  return true;
727  else
728  {
729  const delayt delay(*it, *s_it, (first.thread==second.thread));
730  unsafe_pairs.insert(delay);
731  unsafe_met=true;
732  }
733  }
734  }
735  else
736  {
737  --it;
738 
739  /* one (or more) lwfence between the pair */
740  if(first.unsafe_pair_asm(second, model, fences_met)
741  && (first.thread!=second.thread || egraph.are_po_ordered(*it, *s_it)))
742  {
743  if(fast)
744  return true;
745  else
746  {
747  const delayt delay(*it, *s_it, (first.thread==second.thread));
748  unsafe_pairs.insert(delay);
749  unsafe_met=true;
750  }
751  }
752  }
753  }
754 
755  /* strong fence -- this pair is safe */
756  if(egraph[back()].operation==abstract_eventt::operationt::ASMfence
757  || egraph[front()].operation==abstract_eventt::operationt::ASMfence)
758  return unsafe_met;
759 
760  fences_met=0;
761 
762  /* selects the next event which is not a weak fence */
763  const_iterator s_it;
764  for(s_it=begin();
765  s_it!=end() &&
766  egraph[*s_it].operation==abstract_eventt::operationt::ASMfence;
767  s_it++)
768  fences_met |= egraph[*s_it].fence_value();
769 
770  /* if the whole cycle has been explored */
771  if(s_it==end())
772  return unsafe_met;
773 
774  if(egraph[*s_it].operation==abstract_eventt::operationt::ASMfence)
775  return unsafe_met;
776 
777  const abstract_eventt &first=egraph[back()];
778  const abstract_eventt &second=egraph[*s_it];
779 
780  const data_dpt &data_dp=egraph.map_data_dp[first.thread];
781 
782  /* if data dp between linking the pair, safe */
783  if(first.thread==second.thread && data_dp.dp(first, second))
784  return unsafe_met;
785 
786  /* AC and BC conditions */
787  if(first.thread!=second.thread && model==Power)
788  {
789  bool AC=false;
790  bool BC=false;
791 
792  /* no fence after the second element? (AC) */
793  const_iterator AC_it=++s_it;
794  --s_it;
795  for(;
796  AC_it!=end() && egraph[*AC_it].thread==second.thread;
797  AC_it++)
798  if(egraph[*AC_it].operation==abstract_eventt::operationt::ASMfence
799  && egraph[*AC_it].is_cumul()
800  && egraph[*AC_it].is_corresponding_fence(first, second))
801  {
802  AC=true;
803  break;
804  }
805 
806  if(AC)
807  return unsafe_met;
808 
809  if(AC_it==end() && egraph[front()].thread==second.thread)
810  {
811  for(AC_it=begin();
812  !(egraph[*AC_it]==first) && egraph[*AC_it].thread==second.thread;
813  AC_it++)
814  if(egraph[*AC_it].operation==abstract_eventt::operationt::ASMfence &&
815  egraph[*AC_it].is_cumul() &&
816  egraph[*AC_it].is_corresponding_fence(first, second))
817  {
818  AC=true;
819  break;
820  }
821  }
822 
823  if(AC)
824  return unsafe_met;
825 
826  /* no fence before the first element? (BC) */
827  const_iterator BC_it=end();
828  --BC_it;
829 
830  for(;
831  BC_it!=begin() && egraph[*BC_it].thread==first.thread;
832  BC_it--)
833  if(egraph[*BC_it].operation==abstract_eventt::operationt::ASMfence
834  && egraph[*BC_it].is_cumul()
835  && egraph[*BC_it].is_corresponding_fence(first, second))
836  {
837  BC=true;
838  break;
839  }
840 
841  if(BC)
842  return unsafe_met;
843 
844  if(BC_it==begin() && egraph[back()].thread==first.thread)
845  {
846  BC_it=end();
847  BC_it--;
848  for(;
849  !(egraph[*BC_it]==second) && egraph[*BC_it].thread==first.thread;
850  BC_it--)
851  if(egraph[*BC_it].operation==abstract_eventt::operationt::ASMfence
852  && egraph[*BC_it].is_cumul()
853  && egraph[*BC_it].is_corresponding_fence(first, second))
854  {
855  BC=true;
856  break;
857  }
858  }
859 
860  if(BC)
861  return unsafe_met;
862  }
863 
864  if(s_it==begin())
865  {
866  /* no lwfence between the pair */
867  if(first.unsafe_pair(second, model)
868  && (first.thread!=second.thread || egraph.are_po_ordered(back(), *s_it)))
869  {
870  if(!fast)
871  {
872  const delayt delay(back(), *s_it, (first.thread==second.thread));
873  unsafe_pairs.insert(delay);
874  }
875  return true;
876  }
877  }
878  else
879  {
880  /* one (or more) lwfence between the pair */
881  if(first.unsafe_pair_asm(second, model, fences_met)
882  && (first.thread!=second.thread || egraph.are_po_ordered(back(), *s_it)))
883  {
884  if(!fast)
885  {
886  const delayt delay(back(), *s_it, (first.thread==second.thread));
887  unsafe_pairs.insert(delay);
888  }
889  return true;
890  }
891  }
892 
893  return unsafe_met;
894 }
895 
897 {
898  const_iterator it=begin();
899 
900  /* find the first non-fence event */
901  for(; it!=end(); ++it)
902  {
903  const abstract_eventt &it_evt=egraph[*it];
907  break;
908  }
909 
910  /* if only fences, uniproc */
911  if(it==end())
912  return false;
913 
914  const irep_idt &var=egraph[*it].variable;
915 
916  /* if it is an array access, by over-approximation, we don't have
917  uniproc in the cycle (tab[]) */
918  if(!egraph.ignore_arrays && id2string(var).find("[]")!=std::string::npos)
919  return true;
920 
921  for(; it!=end(); ++it)
922  {
923  const abstract_eventt &it_evt=egraph[*it];
924  if(it_evt.variable!=var
928  break;
929  }
930 
931  return (it!=end());
932 }
933 
935 {
936  const_iterator it=begin();
937 
938  /* find the first non-fence event */
939  for(; it!=end(); it++)
940  {
941  const abstract_eventt &it_evt=egraph[*it];
945  break;
946  }
947 
948  /* if only fences, uniproc */
949  if(it==end())
950  return false;
951 
952  const irep_idt &var=egraph[*it].variable;
953 
954  const_iterator prev=it;
955  for(; it!=end(); prev=it, ++it)
956  {
957  const abstract_eventt &it_evt=egraph[*it];
958  if(
959  !(it_evt.variable==var
960  &&(it==begin() || it_evt.operation!=abstract_eventt::operationt::Read
961  || egraph[*prev].operation!=abstract_eventt::operationt::Read))
965  break;
966  }
967 
968  return (it!=end());
969 }
970 
972 {
973  // assert(size()>2);
974  if(size()<=2)
975  return false;
976 
977  for(const_iterator it=begin(); it!=end(); ++it)
978  {
979  const_iterator n_it=it;
980  ++n_it;
981 
982  if(n_it==end())
983  break;
984 
985  const abstract_eventt &current=egraph[*it];
986  const abstract_eventt &next=egraph[*n_it];
987 
988  /* rf */
991  continue;
992 
993  /* data dependencies */
994  const data_dpt &dep=egraph.map_data_dp[current.thread];
995 
996  if(dep.dp(current, next))
997  continue;
998 
999  return true;
1000  }
1001 
1002  const abstract_eventt &current=egraph[back()];
1003  const abstract_eventt &next=egraph[front()];
1004 
1005  /* rf */
1008  return false;
1009 
1010  /* data dependencies */
1011  const data_dpt &dep=egraph.map_data_dp[current.thread];
1012 
1013  if(dep.dp(current, next))
1014  return false;
1015 
1016  return true;
1017 }
1018 
1020 {
1021  std::string cycle="Cycle: ";
1022  for(const_iterator it=begin(); it!=end(); ++it)
1023  cycle += std::to_string(egraph[*it].id) + "; ";
1024  return cycle + " End of cycle.";
1025 }
1026 
1028 {
1029  std::string name="Unsafe pairs: ";
1030  for(std::set<delayt>::const_iterator it=unsafe_pairs.begin();
1031  it!=unsafe_pairs.end();
1032  ++it)
1033  {
1034  const abstract_eventt &first=egraph[it->second];
1035  const abstract_eventt &last=egraph[it->first];
1036 
1037  if(last.variable==first.variable
1040  {
1041  name += " Rf";
1042  name += (last.thread==first.thread?"i":"e");
1043  }
1044 
1045  else if(last.variable==first.variable &&
1048  (last.thread!=first.thread || it->first > it->second))
1049  {
1050  name += " Fr";
1051  name += (last.thread==first.thread?"i":"e");
1052  }
1053  else if(last.variable==first.variable &&
1056  (last.thread!=first.thread || it->first > it->second))
1057  {
1058  /* we prefer to write Po rather than Wsi */
1059  name += " Ws";
1060  name += (last.thread==first.thread?"i":"e");
1061  }
1062  else if(last.thread==first.thread &&
1064  {
1065  name += " Po";
1066  name += (last.variable==first.variable?"s":"d") + last.get_operation()
1067  + first.get_operation();
1068  }
1069  }
1070 
1071  return name;
1072 }
1073 
1075 {
1076  std::string cycle="Cycle: ";
1077  for(const_iterator it=begin(); it!=end(); ++it)
1078  {
1079  const abstract_eventt &it_evt=egraph[*it];
1080  cycle += it_evt.get_operation() + id2string(it_evt.variable)
1081  + "; ";
1082  }
1083  return cycle+" End of cycle.";
1084 }
1085 
1087 {
1088  std::string cycle;
1089  for(const_iterator it=begin(); it!=end(); ++it)
1090  {
1091  const abstract_eventt &it_evt=egraph[*it];
1092  cycle += id2string(it_evt.variable) + " (";
1093  cycle += it_evt.source_location.as_string();
1094  cycle += " thread " + std::to_string(it_evt.thread) + ") ";
1095  }
1096  return cycle;
1097 }
1098 
1100  const critical_cyclet &reduced,
1101  std::map<std::string, std::string> &map_id2var,
1102  std::map<std::string, std::string> &map_var2id) const
1103 {
1104  std::string cycle;
1105  for(const_iterator it=reduced.begin(); it!=reduced.end(); ++it)
1106  {
1107  const abstract_eventt &it_evt=egraph[*it];
1108  const std::string var_name=id2string(it_evt.variable)
1109  + " (" + it_evt.source_location.as_string() + ")";
1110  if(map_var2id.find(var_name)!=map_var2id.end())
1111  {
1112  cycle += "t" + std::to_string(it_evt.thread) + " (";
1113  cycle += map_var2id[var_name] + ") ";
1114  }
1115  else
1116  {
1117  const std::string new_id="var@" + std::to_string(map_var2id.size());
1118  map_var2id[var_name]=new_id;
1119  map_id2var[new_id]=var_name;
1120  cycle += "t" + std::to_string(it_evt.thread) + " (";
1121  cycle += new_id + ") ";
1122  }
1123  }
1124  return cycle;
1125 }
1126 
1128  memory_modelt model,
1129  std::map<std::string, std::string> &map_id2var,
1130  std::map<std::string, std::string> &map_var2id,
1131  bool hide_internals) const
1132 {
1133  std::string cycle;
1134 
1135  PRECONDITION(size() > 2);
1136 
1137  /* removes all the internal events */
1138  if(hide_internals)
1139  {
1140  critical_cyclet reduced(egraph, id);
1141  this->hide_internals(reduced);
1142  CHECK_RETURN(reduced.size() > 0);
1143  cycle+=print_detail(reduced, map_id2var, map_var2id);
1144  cycle+=": ";
1145  cycle+=print_name(reduced, model);
1146  }
1147  else
1148  {
1149  cycle+=print_detail(*this, map_id2var, map_var2id);
1150  cycle+=": ";
1151  cycle+=print_name(*this, model);
1152  }
1153 
1154  return cycle;
1155 }
1156 
1158  critical_cyclet &reduced) const
1159 {
1160  std::set<event_idt> reduced_evts;
1161  const_iterator first_it, prev_it=end();
1162 
1163  /* finds an element first of its thread */
1164  for(first_it=begin(); first_it!=end(); ++first_it)
1165  {
1166  const abstract_eventt &first=egraph[*first_it];
1167  if(prev_it!=end() && egraph[*prev_it].thread!=first.thread
1168  && !first.is_fence())
1169  break;
1170  prev_it=first_it;
1171  }
1172  CHECK_RETURN(first_it != end());
1173  reduced.push_back(*first_it);
1174  reduced_evts.insert(*first_it);
1175 
1176  /* conserves only the extrema of threads */
1177  for(const_iterator cur_it=first_it; cur_it!=end(); ++cur_it)
1178  {
1179  const abstract_eventt &cur=egraph[*cur_it];
1180  if(cur.is_fence())
1181  continue;
1182 
1183  const_iterator next_it=cur_it;
1184  ++next_it;
1185  if(next_it==end())
1186  next_it=begin();
1187 
1188  if(cur.thread!=egraph[*next_it].thread)
1189  {
1190  if(reduced_evts.find(*cur_it)==reduced_evts.end())
1191  {
1192  reduced.push_back(*cur_it);
1193  reduced_evts.insert(*cur_it);
1194  }
1195  for(; next_it!=end() && egraph[*next_it].is_fence(); ++next_it) {}
1196  CHECK_RETURN(next_it != end());
1197  if(reduced_evts.find(*next_it)==reduced_evts.end())
1198  {
1199  reduced.push_back(*next_it);
1200  reduced_evts.insert(*next_it);
1201  }
1202  }
1203  }
1204 
1205  for(const_iterator cur_it=begin(); cur_it!=first_it; ++cur_it)
1206  {
1207  const abstract_eventt &cur=egraph[*cur_it];
1208  if(cur.is_fence())
1209  continue;
1210 
1211  const_iterator next_it=cur_it;
1212  ++next_it;
1213  CHECK_RETURN(next_it != end());
1214 
1215  if(cur.thread!=egraph[*next_it].thread)
1216  {
1217  if(reduced_evts.find(*cur_it)==reduced_evts.end())
1218  {
1219  reduced.push_back(*cur_it);
1220  reduced_evts.insert(*cur_it);
1221  }
1222  for(; next_it!=end() && egraph[*next_it].is_fence(); ++next_it) {}
1223  CHECK_RETURN(next_it != end());
1224  if(reduced_evts.find(*next_it)==reduced_evts.end())
1225  {
1226  reduced.push_back(*next_it);
1227  reduced_evts.insert(*next_it);
1228  }
1229  }
1230  }
1231 }
1232 
1234  const critical_cyclet &reduced,
1235  memory_modelt model) const
1236 {
1237  PRECONDITION(reduced.size() >= 2);
1238  unsigned extra_fence_count=0;
1239 
1240  std::string name;
1241  const_iterator prev_it=reduced.end();
1242  bool first_done=false;
1243  for(const_iterator cur_it=reduced.begin(); cur_it!=reduced.end(); ++cur_it)
1244  {
1245  const abstract_eventt &cur=egraph[*cur_it];
1246 
1247  if(prev_it!=reduced.end())
1248  {
1249  const abstract_eventt &prev=egraph[*prev_it];
1250 
1254  {
1255  ++extra_fence_count;
1256  // nothing to do
1257  }
1258 
1260  {
1261  const_iterator n_it=cur_it;
1262  bool wraparound=false;
1263  while(true)
1264  {
1265  ++n_it;
1266  if(n_it==reduced.end())
1267  {
1268  INVARIANT(!wraparound, "no prior wraparound");
1269  wraparound=true;
1270  first_done=true;
1271  ++extra_fence_count;
1272  n_it=reduced.begin();
1273  }
1274  const abstract_eventt &cand=egraph[*n_it];
1278  break;
1279  if(!wraparound)
1280  ++cur_it;
1281  if(!wraparound)
1282  ++extra_fence_count;
1283  }
1284  const abstract_eventt &succ=egraph[*n_it];
1288  "operation is read or write");
1289  name += (model==Power?" Sync":" MFence");
1290  name += (prev.variable==succ.variable?"s":"d")
1291  + prev.get_operation() + succ.get_operation();
1292  }
1293 
1295  {
1296  std::string cand_name=" LwSync";
1297  const_iterator n_it=cur_it;
1298  bool wraparound=false;
1299  while(true)
1300  {
1301  ++n_it;
1302  if(n_it==reduced.end())
1303  {
1304  INVARIANT(!wraparound, "no prior wraparound");
1305  wraparound=true;
1306  first_done=true;
1307  ++extra_fence_count;
1308  n_it=reduced.begin();
1309  }
1310  const abstract_eventt &cand=egraph[*n_it];
1314  break;
1317  cand.fence_value()&1))
1318  cand_name=(model==Power?" Sync":" MFence");
1319  if(!wraparound)
1320  ++cur_it;
1321  if(!wraparound)
1322  ++extra_fence_count;
1323  }
1324  const abstract_eventt &succ=egraph[*n_it];
1328  "operation is read or write");
1329  name += cand_name;
1330  name += (prev.variable==succ.variable?"s":"d")
1331  + prev.get_operation() + succ.get_operation();
1332  }
1333 
1335  {
1336  std::string cand_name;
1337  if(cur.fence_value()&1)
1338  cand_name=(model==Power?" Sync":" MFence");
1339  else
1340  cand_name=" LwSync";
1341  const_iterator n_it=cur_it;
1342  bool wraparound=false;
1343  while(true)
1344  {
1345  ++n_it;
1346  if(n_it==reduced.end())
1347  {
1348  INVARIANT(!wraparound, "no prior wraparound");
1349  wraparound=true;
1350  first_done=true;
1351  ++extra_fence_count;
1352  n_it=reduced.begin();
1353  }
1354  const abstract_eventt &cand=egraph[*n_it];
1358  break;
1361  cand.fence_value()&1))
1362  cand_name=(model==Power?" Sync":" MFence");
1363  if(!wraparound)
1364  ++cur_it;
1365  if(!wraparound)
1366  ++extra_fence_count;
1367  }
1368  const abstract_eventt &succ=egraph[*n_it];
1372  "operation is read or write");
1373  name += cand_name;
1374  name += (prev.variable==succ.variable?"s":"d")
1375  + prev.get_operation() + succ.get_operation();
1376  }
1377 
1378  else if(prev.variable==cur.variable
1381  {
1382  name += " Rf";
1383  name += (prev.thread==cur.thread?"i":"e");
1384  }
1385 
1386  else if(prev.variable==cur.variable
1389  && (prev.thread!=cur.thread || *prev_it > *cur_it))
1390  {
1391  name += " Fr";
1392  name += (prev.thread==cur.thread?"i":"e");
1393  }
1394 
1395  else if(prev.variable==cur.variable &&
1398  (prev.thread!=cur.thread || *prev_it > *cur_it))
1399  {
1400  /* we prefer to write Po rather than Wsi */
1401  name += " Ws";
1402  name += (prev.thread==cur.thread?"i":"e");
1403  }
1404 
1405  else if(prev.thread==cur.thread
1409  {
1410  const data_dpt &dep=egraph.map_data_dp[cur.thread];
1411 
1413  dep.dp(prev, cur))
1414  {
1415  name += " DpData";
1416  name += (prev.variable==cur.variable?"s":"d")
1417  + cur.get_operation();
1418  }
1419  else
1420  {
1421  name += " Po";
1422  name += (prev.variable==cur.variable?"s":"d") + prev.get_operation()
1423  + cur.get_operation();
1424  }
1425  }
1426 
1427  else if(cur.variable!=ID_unknown && prev.variable!=ID_unknown)
1428  UNREACHABLE;
1429  }
1430 
1431  prev_it=cur_it;
1432  }
1433 
1434  if(first_done)
1435  {
1436  auto n_events=extra_fence_count;
1437  for(std::string::const_iterator it=name.begin();
1438  it!=name.end();
1439  ++it)
1440  if(*it==' ')
1441  ++n_events;
1442  DATA_INVARIANT(n_events == reduced.size(), "number of events match");
1443 
1444  return name;
1445  }
1446 
1447  const abstract_eventt &first=egraph[reduced.front()];
1448  const abstract_eventt &last=egraph[reduced.back()];
1449 
1454  "operation is not a fence");
1455 
1459  {
1460  std::string cand_name=" LwSync";
1461  const_iterator it=reduced.begin();
1462  for( ; it!=reduced.end(); ++it)
1463  {
1464  const abstract_eventt &cand=egraph[*it];
1465 
1469  break;
1472  cand.fence_value()&1))
1473  cand_name=(model==Power?" Sync":" MFence");
1474  }
1475  CHECK_RETURN(it != reduced.begin() && it != reduced.end());
1476  const abstract_eventt &succ=egraph[*it];
1480  "operation is read or write");
1481  name += cand_name;
1482  name += (last.variable==succ.variable?"s":"d")
1483  + last.get_operation() + succ.get_operation();
1484  }
1485 
1486  else if(last.variable==first.variable
1489  {
1490  name += " Rf";
1491  name += (last.thread==first.thread?"i":"e");
1492  }
1493 
1494  else if(last.variable==first.variable
1497  && (last.thread!=first.thread || reduced.back() > reduced.front()))
1498  {
1499  name += " Fr";
1500  name += (last.thread==first.thread?"i":"e");
1501  }
1502 
1503  else if(last.variable==first.variable &&
1506  (last.thread!=first.thread || reduced.back() > reduced.front()))
1507  {
1508  /* we prefer to write Po rather than Wsi */
1509  name += " Ws";
1510  name += (last.thread==first.thread?"i":"e");
1511  }
1512 
1513  else if(last.thread==first.thread)
1514  {
1515  const data_dpt &dep=egraph.map_data_dp[last.thread];
1516 
1518  dep.dp(last, first))
1519  {
1520  name += " DpData";
1521  name += (last.variable==first.variable?"s":"d")
1522  + first.get_operation();
1523  }
1524  else
1525  {
1526  name += " Po";
1527  name += (last.variable==first.variable?"s":"d") + last.get_operation()
1528  + first.get_operation();
1529  }
1530  }
1531 
1532  else if(last.variable!=ID_unknown && first.variable!=ID_unknown)
1533  UNREACHABLE;
1534 
1535 #if 0
1536  critical_cyclet::size_type n_events=extra_fence_count;
1537  for(std::string::const_iterator it=name.begin();
1538  it!=name.end();
1539  ++it)
1540  if(*it==' ')
1541  ++n_events;
1542  assert(n_events==reduced.size());
1543 #endif
1544 
1545  return name;
1546 }
1547 
1549  std::ostream &str,
1550  unsigned colour,
1551  memory_modelt model) const
1552 {
1553  /* print vertices */
1554  for(const_iterator it=begin(); it!=end(); ++it)
1555  {
1556  const abstract_eventt &ev=egraph[*it];
1557 
1558  /* id of the cycle in comments */
1559  str << "/* " << id << " */\n";
1560 
1561  /* vertex */
1562  str << ev.id << "[label=\"\\\\lb {" << ev.id << "}" << ev.get_operation();
1563  str << "{" << ev.variable << "} {} @thread" << ev.thread << "\"];\n";
1564  }
1565 
1566  /* print edges */
1567  const_iterator prev_it=end();
1568  for(const_iterator cur_it=begin(); cur_it!=end(); ++cur_it)
1569  {
1570  const abstract_eventt &cur=egraph[*cur_it];
1571 
1572  /* id of the cycle in comments */
1573  str << "/* " << id << " */\n";
1574 
1575  /* edge */
1576  if(prev_it!=end())
1577  {
1578  const abstract_eventt &prev=egraph[*prev_it];
1579 
1580  str << prev.id << "->";
1582  {
1583  const_iterator n_it=cur_it;
1584  ++n_it;
1585  const abstract_eventt &succ=
1586  n_it!=end() ? egraph[*n_it] : egraph[front()];
1587  str << succ.id << "[label=\"";
1588  str << (model==Power?"Sync":"MFence");
1589  str << (prev.variable==cur.variable?"s":"d");
1590  str << prev.get_operation() << succ.get_operation();
1591  }
1593  {
1594  const_iterator n_it=cur_it;
1595  ++n_it;
1596  const abstract_eventt &succ=
1597  n_it!=end() ? egraph[*n_it] : egraph[front()];
1598  str << succ.id << "[label=\"";
1599  str << "LwSync" << (prev.variable==cur.variable?"s":"d");
1600  str <<prev.get_operation() << succ.get_operation();
1601  }
1602  else if(prev.variable==cur.variable
1605  {
1606  str << cur.id << "[label=\"";
1607  str << "Rf" << (prev.thread==cur.thread?"i":"e");
1608  }
1609  else if(prev.variable==cur.variable
1612  {
1613  str << cur.id << "[label=\"";
1614  str << "Fr" << (prev.thread==cur.thread?"i":"e");
1615  }
1616  else if(prev.variable==cur.variable &&
1619  prev.thread!=cur.thread)
1620  {
1621  /* we prefer to write Po rather than Wsi */
1622  str << cur.id << "[label=\"";
1623  str << "Ws" << (prev.thread==cur.thread?"i":"e");
1624  }
1625  else if(prev.thread==cur.thread &&
1627  {
1628  str << cur.id << "[label=\"";
1629  str << "Po" << (prev.variable==cur.variable?"s":"d")
1630  + prev.get_operation() + cur.get_operation();
1631  }
1632  else
1633  str << cur.id << "[label=\"?";
1634 
1635  str << "\",color=" << print_colour(colour) << "];\n";
1636  }
1637 
1638  prev_it=cur_it;
1639  }
1640 
1641  const abstract_eventt &first=egraph[front()];
1642  const abstract_eventt &last=egraph[back()];
1643 
1644  /* id of the cycle in comments */
1645  str << "/* " << id << " */\n";
1646 
1647  /* edge */
1648  str << last.id << "->";
1650  {
1651  const_iterator next=begin();
1652  ++next;
1653  const abstract_eventt &succ=egraph[*next];
1654  str << succ.id << "[label=\"";
1655  str << (model==Power?"Sync":"MFence");
1656  str << (last.variable==first.variable?"s":"d");
1657  str << last.get_operation() << succ.get_operation();
1658  }
1660  {
1661  const_iterator next=begin();
1662  ++next;
1663  const abstract_eventt &succ=egraph[*next];
1664  str << succ.id << "[label=\"";
1665  str << "LwSync" << (last.variable==first.variable?"s":"d");
1666  str << last.get_operation() << succ.get_operation();
1667  }
1668  else if(last.variable==first.variable &&
1671  {
1672  str << first.id << "[label=\"";
1673  str << "Rf" << (last.thread==first.thread?"i":"e");
1674  }
1675  else if(last.variable==first.variable &&
1678  {
1679  str << first.id << "[label=\"";
1680  str << "Fr" << (last.thread==first.thread?"i":"e");
1681  }
1682  else if(last.variable==first.variable &&
1685  last.thread!=first.thread)
1686  {
1687  /* we prefer to write Po rather than Wsi */
1688  str << first.id << "[label=\"";
1689  str << "Ws" << (last.thread==first.thread?"i":"e");
1690  }
1691  else if(last.thread==first.thread &&
1693  {
1694  str << first.id << "[label=\"";
1695  str << "Po" << (last.variable==first.variable?"s":"d");
1696  str << last.get_operation() << first.get_operation();
1697  }
1698  else
1699  str << first.id << "[label=\"?";
1700 
1701  str << "\", color=" << print_colour(colour) << "];\n";
1702 }
bool unsafe_pair(const abstract_eventt &next, memory_modelt model) const
std::string get_operation() const
bool is_fence() const
bool unsafe_pair_lwfence(const abstract_eventt &next, memory_modelt model) const
source_locationt source_location
irep_idt function_id
bool unsafe_pair_asm(const abstract_eventt &next, memory_modelt model, unsigned char met) const
operationt operation
unsigned char fence_value() const
bool dp(const abstract_eventt &e1, const abstract_eventt &e2) const
search in N^2
Definition: data_dp.cpp:76
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
std::string print_events() const
void hide_internals(critical_cyclet &reduced) const
data_typet::const_iterator const_iterator
Definition: event_graph.h:70
std::string print_unsafes() const
bool is_unsafe(memory_modelt model, bool fast=false)
checks whether there is at least one pair which is unsafe (takes fences and dependencies into account...
bool is_unsafe_asm(memory_modelt model, bool fast=false)
same as is_unsafe, but with ASM fences
bool check_AC(data_typet::const_iterator s_it, const abstract_eventt &first, const abstract_eventt &second) const
std::string print_name(const critical_cyclet &redyced, memory_modelt model) const
std::string print_all(memory_modelt model, std::map< std::string, std::string > &map_id2var, std::map< std::string, std::string > &map_var2id, bool hide_internals) const
bool check_BC(data_typet::const_iterator it, const abstract_eventt &first, const abstract_eventt &second) const
void print_dot(std::ostream &str, unsigned colour, memory_modelt model) const
std::string print_detail(const critical_cyclet &reduced, std::map< std::string, std::string > &map_id2var, std::map< std::string, std::string > &map_var2id) const
std::string print_output() const
grapht< abstract_eventt >::nodet & operator[](event_idt n)
Definition: event_graph.h:413
void print_graph()
Definition: event_graph.cpp:56
bool has_com_edge(event_idt i, event_idt j) const
Definition: event_graph.h:423
std::list< event_idt > po_order
Definition: event_graph.h:400
void explore_copy_segment(std::set< event_idt > &explored, event_idt begin, event_idt end) const
copies the segment
Definition: event_graph.cpp:73
event_idt copy_segment(event_idt begin, event_idt end)
Definition: event_graph.cpp:91
bool has_po_edge(event_idt i, event_idt j) const
Definition: event_graph.h:418
std::size_t size() const
Definition: event_graph.h:428
const wmm_grapht::edgest & com_out(event_idt n) const
Definition: event_graph.h:448
const wmm_grapht::edgest & po_out(event_idt n) const
Definition: event_graph.h:438
std::set< std::pair< const abstract_eventt &, const abstract_eventt & > > duplicated_bodies
Definition: event_graph.h:511
void add_com_edge(event_idt a, event_idt b)
Definition: event_graph.h:473
messaget & message
Definition: event_graph.h:394
void add_po_edge(event_idt a, event_idt b)
Definition: event_graph.h:453
void print_rec_graph(std::ofstream &file, event_idt node_id, std::set< event_idt > &visited)
Definition: event_graph.cpp:28
event_idt add_node()
Definition: event_graph.h:405
mstreamt & status() const
Definition: message.h:414
static eomt eom
Definition: message.h:297
const irep_idt & get_file() const
std::string as_string() const
static const char * colour_map[14]
Definition: event_graph.cpp:22
#define NB_COLOURS
Definition: event_graph.cpp:21
#define print_colour(u)
Definition: event_graph.cpp:26
graph of abstract events
wmm_grapht::node_indext event_idt
Definition: event_graph.h:32
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
#define size_type
Definition: unistd.c:347
memory_modelt
Definition: wmm.h:18
@ Power
Definition: wmm.h:23