CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
event_graph.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: graph of abstract events
4
5Author: Vincent Nimal
6
7Date: 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
22static 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
28void 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
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{
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 {
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))
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 {
179 }
180 }
181 }
182 // end
183
184 return orig2copy[end];
185}
186
189 const abstract_eventt &first,
190 const abstract_eventt &second) const
191{
192 bool AC=false;
194 ++AC_it;
195 for(; AC_it!=end(); ++AC_it)
196 {
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 {
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
230 const abstract_eventt &first,
231 const abstract_eventt &second) const
232{
233 bool BC=false;
234 /* no fence before the first element? (BC) */
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;
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
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 {
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
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 {
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
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 */
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
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
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;
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() &&
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) */
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) */
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 */
764 for(s_it=begin();
765 s_it!=end() &&
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) */
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
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 {
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());
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;
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;
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 */
1178 {
1179 const abstract_eventt &cur=egraph[*cur_it];
1180 if(cur.is_fence())
1181 continue;
1182
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
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;
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 {
1256 // nothing to do
1257 }
1258
1260 {
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;
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)
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";
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;
1308 n_it=reduced.begin();
1309 }
1310 const abstract_eventt &cand=egraph[*n_it];
1314 break;
1315 else if(cand.operation==abstract_eventt::operationt::Fence ||
1317 cand.fence_value()&1))
1318 cand_name=(model==Power?" Sync":" MFence");
1319 if(!wraparound)
1320 ++cur_it;
1321 if(!wraparound)
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";
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;
1352 n_it=reduced.begin();
1353 }
1354 const abstract_eventt &cand=egraph[*n_it];
1358 break;
1359 else if(cand.operation==abstract_eventt::operationt::Fence ||
1361 cand.fence_value()&1))
1362 cand_name=(model==Power?" Sync":" MFence");
1363 if(!wraparound)
1364 ++cur_it;
1365 if(!wraparound)
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)
1429 }
1430
1432 }
1433
1434 if(first_done)
1435 {
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;
1470 else if(cand.operation==abstract_eventt::operationt::Fence ||
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)
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 {
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 {
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
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
bool unsafe_pair_asm(const abstract_eventt &next, memory_modelt model, unsigned char met) const
operationt operation
unsigned char fence_value() const
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
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
void print_graph()
grapht< abstract_eventt >::nodet & operator[](event_idt n)
bool has_com_edge(event_idt i, event_idt j) const
std::list< event_idt > po_order
void explore_copy_segment(std::set< event_idt > &explored, event_idt begin, event_idt end) const
copies the segment
event_idt copy_segment(event_idt begin, event_idt end)
bool has_po_edge(event_idt i, event_idt j) const
std::size_t size() const
const wmm_grapht::edgest & po_out(event_idt n) const
std::set< std::pair< const abstract_eventt &, const abstract_eventt & > > duplicated_bodies
void add_com_edge(event_idt a, event_idt b)
messaget & message
const wmm_grapht::edgest & com_out(event_idt n) const
void add_po_edge(event_idt a, event_idt b)
void print_rec_graph(std::ofstream &file, event_idt node_id, std::set< event_idt > &visited)
event_idt add_node()
static eomt eom
Definition message.h:289
mstreamt & status() const
Definition message.h:406
static const char * colour_map[14]
#define NB_COLOURS
#define print_colour(u)
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:44
#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
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
memory_modelt
Definition wmm.h:18
@ Power
Definition wmm.h:23