1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136
|
(****************************************************************************)
(* the diy toolsuite *)
(* *)
(* Jade Alglave, University College London, UK. *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France. *)
(* *)
(* Copyright 2010-present Institut National de Recherche en Informatique et *)
(* en Automatique, ARM Ltd and the authors. All rights reserved. *)
(* *)
(* This software is governed by the CeCILL-B license under French law and *)
(* abiding by the rules of distribution of free software. You can use, *)
(* modify and/ or redistribute the software under the terms of the CeCILL-B *)
(* license as circulated by CEA, CNRS and INRIA at the following URL *)
(* "http://www.cecill.info". We also give a copy in LICENSE.txt. *)
(****************************************************************************)
(* Authors: *)
(* Jade Alglave, University College London, UK. *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France. *)
(* Hadrien Renaud, University College London, UK. *)
(****************************************************************************)
(** Produce event structures (which include variables) + constraints,
using instruction semantics *)
module type CommonConfig = sig
val verbose : int
val optace : OptAce.t
val unroll : int option
val speedcheck : Speed.t
val debug : Debug_herd.t
val observed_finals_only : bool
val initwrites : bool
val check_filter : bool
val maxphantom : int option
val variant : Variant.t -> bool
val fault_handling : Fault.Handling.t
val mte_precision : Precision.t
end
module type Config = sig
include CommonConfig
val byte : MachSize.sz
val dirty : DirtyBit.t option
end
module type S = sig
module S : Sem.Semantics
type result =
{
event_structures : (int * S.M.VC.cnstrnts * S.event_structure) list ;
overwritable_labels : Label.Set.t ;
}
(** [glommed_event_structures t] performs "instruction semantics".
* Argument [t] is a test.
* The function returns a pair whose first component is a record.
*
* It includes a set (list) of "abstract" event structures. In such
* structures, most values (and locations) are not resolved yet. Hence the
* [S.M.VC.cnstrnts] second component. Those are equations to be solved
* once some read-from relation on memory is selected by the function
* [calculate_rf_with_cnstrnts] (see below). The record also includes
* additional processing information to pass on to calculate_rf_with_cnstrnts,
* which is the set of labels that are allowed to be addressed by stores.
*
* Second component of the returned pair is the test itself,
* which can be slightly modified (noticeably in the case of
* `-variant self`, initial values of overwitable code locations
* are added.
*
* This modified test *must* be used in the following. *)
val glommed_event_structures : S.test -> result * S.test
(* A first generator,
calculate_rf_with_cnstrnts test es constraints kont res,
- test and es are test description and (abstract) event structure.
By abstract, we here mean that some values and even
memory locations in them are variables.
- constraints is a set of constraint, which
* Is solvable: ie resolution results
in either an assigment of all variables in es, or
in failure.
* expresses the constraints generated by semantics.
- kont : S.concrete -> VC.cnstrnts -> 'a -> 'a
will be called on all generated concrete event structures, resulting
in computation:
kont (esN (... (kont es1 res)))
where esK is the
+ abstract event structure with variables replaced by constants
+ [Failed] of [Warn] constraint from equations, if any
+ rfmap
+ final state (included in rfmap in fact)
*)
val calculate_rf_with_cnstrnts :
S.test -> Label.Set.t -> S.event_structure -> S.M.VC.cnstrnts ->
(S.concrete -> S.M.VC.cnstrnt option -> 'a -> 'a ) -> (* kont *)
'a -> 'a
val solve_regs :
S.test -> S.E.event_structure -> S.M.VC.cnstrnt list ->
(S.E.event_structure * S.read_from S.RFMap.t * S.M.VC.cnstrnt list) option
val solve_mem :
S.test ->S.E.event_structure -> S.read_from S.RFMap.t -> S.M.VC.cnstrnt list ->
(S.E.event_structure ->
S.read_from S.RFMap.t -> S.M.VC.cnstrnt list -> 'a -> 'a) ->
'a -> 'a
val check_sizes : S.test -> S.event_structure -> unit
val check_rfmap :
S.E.event_structure -> S.read_from S.RFMap.t -> bool
val when_unsolved :
S.test -> S.E.event_structure -> S.read_from S.RFMap.t -> S.M.VC.cnstrnt list -> 'a -> 'a
val compute_final_state :
S.test -> S.read_from S.RFMap.t -> S.E.EventSet.t -> S.A.state * S.A.FaultSet.t
val check_filter : S.test -> S.A.state * S.A.FaultSet.t -> bool
val get_loc :
S.E.event -> S.E.A.location
val make_atomic_load_store :
S.E.event_structure -> S.E.EventRel.t
end
open Printf
module Make(C:Config) (S:Sem.Semantics) : S with module S = S =
struct
module S = S
module A = S.A
module B = S.B
module AM = A.Mixed(C)
module V = A.V
module E = S.E
module EM = S.M
module VC = EM.VC
module U = MemUtils.Make(S)
module W = Warn.Make(C)
let dbg = C.debug.Debug_herd.mem
let morello = C.variant Variant.Morello
let mixed = C.variant Variant.Mixed || morello
let unaligned = C.variant Variant.Unaligned
let memtag = C.variant Variant.MemTag
(* default is checking *)
let check_mixed = not (C.variant Variant.DontCheckMixed)
let do_deps = C.variant Variant.Deps
let kvm = C.variant Variant.VMSA
let self = C.variant Variant.Ifetch
let asl = C.variant Variant.ASL
let oota = C.variant Variant.OOTA
let unroll =
match C.unroll with
| None -> Opts.unroll_default A.arch
| Some u -> u
(*****************************)
(* Event structure generator *)
(*****************************)
(* Relabeling (eiid) events so as to get memory events labeled by 0,1, etc *)
module IMap =
Map.Make
(struct
type t = E.eiid
let compare = Misc.int_compare
end)
let count_mem evts =
E.EventSet.fold
(fun e k ->
if E.is_mem e then k+1
else k)
evts 0
let build_map n_mem evts =
let build_bd e (next_mem,next_other,k) =
let key = e.E.eiid in
if E.is_mem e then
(next_mem+1,next_other,IMap.add key next_mem k)
else
(next_mem,next_other+1,IMap.add key next_other k) in
let _,_,r = E.EventSet.fold build_bd evts (0,n_mem,IMap.empty) in
r
(* Note: events from mem_accesses are not relabeled, as they are not part of final events *)
let relabel es =
let n_mem = count_mem es.E.events in
let map = build_map n_mem es.E.events in
let relabel_event e =
let id = e.E.eiid in
try { e with E.eiid = IMap.find id map }
with Not_found -> assert (E.EventSet.mem e es.E.mem_accesses) ; e in
E.map_event_structure relabel_event es
let (|*|) = EM.(|*|)
let (>>>) = EM.(>>>)
let is_back_jump addr_jmp addr_tgt = Misc.int_compare addr_jmp addr_tgt >= 0
type result =
{
event_structures : (int * S.M.VC.cnstrnts * S.event_structure) list ;
overwritable_labels : Label.Set.t ;
}
(* All (virtual) locations from init state *)
let get_all_locs_init init =
let locs =
A.state_fold
(fun loc v locs ->
let locs =
match loc with
| A.Location_global _
-> loc::locs
| A.Location_reg _ -> locs in
try
match A.V.as_virtual v with
| Some s ->
let sym = Constant.mk_sym_virtual s in
A.Location_global (A.V.Val sym)::locs
| None -> locs
with V.Undetermined -> locs)
init [] in
A.LocSet.of_list locs
(* All (virtual) memory locations reachable by a test *)
let get_all_mem_locs test =
let locs_final =
A.LocSet.filter
(function
| A.Location_global _ -> true
| A.Location_reg _ -> false)
(S.observed_locations test)
and locs_init = get_all_locs_init test.Test_herd.init_state in
let () =
if dbg then begin
let pp_locs locs =
A.LocSet.pp_str "," A.dump_location locs in
Printf.eprintf
"locs_init={%s}, locs_final={%s}\n%!"
(pp_locs locs_init)
(pp_locs locs_final)
end in
let locs = A.LocSet.union locs_final locs_init in
let locs =
List.fold_left
(fun locs (_,code,fh_code) ->
let code = match fh_code with
| Some fh_code -> code@fh_code
| None -> code in
List.fold_left
(fun locs (_,ins) ->
A.fold_addrs
(fun x ->
let loc = A.maybev_to_location x in
match loc with
| A.Location_global _ -> A.LocSet.add loc
| _ -> fun locs -> locs)
locs ins)
locs code)
locs
test.Test_herd.start_points in
let env =
A.LocSet.fold
(fun loc env ->
try
let v = A.look_address_in_state test.Test_herd.init_state loc in
(loc,v)::env
with A.LocUndetermined -> assert false)
locs [] in
env
module SM = S.Mixed(C)
type ('a,'b,'c) fetch_r = Ok of 'a * 'b | No of 'a | Segfault of 'c
let segfault =
Warn.user_error
"Segmentation fault (kidding, label %s not found)"
let glommed_event_structures (test:S.test) =
let prog = test.Test_herd.program in
let starts = test.Test_herd.start_points in
let code_segment = test.Test_herd.code_segment in
let procs = List.map (fun (p,_,_) -> p) starts in
let labels_of_instr = test.Test_herd.entry_points in
let exported_labels = S.get_exported_labels test in
let is_exported_label lbl =
Label.Full.Set.exists
(fun (_,lbl0) -> Misc.string_eq lbl lbl0)
exported_labels in
(**********************************************************)
(* In mode `-variant self` test init_state is changed: *)
(* 1. Normalize labels in values *)
(* 2. Add initialisation of overwritable instructions *)
(* Labels have to be normalized because only one memory *)
(* location holds the instruction that can be pointed to *)
(* by several labels. Read and write events *must* use a *)
(* canonical location (label). *)
(**********************************************************)
(* lbls2i -- overwritable instructions, with labels *)
(* overwritable_labels -- the set of labels of instructions *)
(* that are allowed to be overwritten *)
let lbls2i, overwritable_labels =
if self then
List.fold_left
(fun (ps, ls) (proc,code,fh_code) ->
let code = match fh_code with
| Some fh_code -> code@fh_code
| None -> code in
List.fold_left
(fun (ps, ls) (addr,i) ->
let lbls = labels_of_instr addr in
if Label.Set.exists is_exported_label lbls
then
(lbls,(proc,i))::ps,
Label.Set.union lbls ls
else ps,ls)
(ps,ls) code)
([], Label.Set.empty) starts
else (* For Adr to work *)
let lbl2code lbl =
IntMap.find (Label.Map.find lbl prog) code_segment in
let ps =
Label.Full.Set.fold
(fun (_,lab) ps ->
try begin
match lbl2code lab with
| (p,(_,i)::_) ->
(Label.Set.singleton lab,(p,i))::ps
| (_,[]) -> ps
end with Not_found -> ps)
exported_labels [] in
ps,Label.Set.empty in
let norm_lbl = (* Normalize labels, useful in `-variant self` *)
if self then
let m =
List.fold_left
(fun m (lbls,_) ->
match Label.norm lbls with
| None -> assert false (* as lbls is non-empty *)
| Some lbl0 ->
Label.Set.fold
(fun lbl m -> Label.Map.add lbl lbl0 m)
lbls m)
Label.Map.empty lbls2i in
fun lbl ->
try Label.Map.find lbl m
with
| Not_found ->
if Label.Map.mem lbl prog then
lbl
else
Warn.user_error
"Label %s is undefined, yet it is used as constant"
(Label.pp lbl)
else
(* Normalisation reduced to label existence check *)
fun lbl -> ignore (Label.Map.find lbl prog) ; lbl in
let norm_val = (* Normalize labels in values *)
if self then
fun v ->
match v with
| V.Val c -> V.Val (Constant.map_label norm_lbl c)
| _ -> v
else fun v -> v in
let test =
match lbls2i with
| [] -> test
| _::_ ->
let open Test_herd in
let init_state =
(* Change labels into their canonical representants *)
A.map_state norm_val test.init_state in
let init_state =
(* Add initialisation of overwritable instructions *)
List.fold_left
(fun env (lbls,(proc,i)) ->
match Label.norm lbls with
| None -> assert false (* as lbls is non-empty *)
| Some lbl ->
let loc =
A.Location_global
(A.V.cstToV (Constant.Label (proc, lbl)))
and v = A.V.instructionToV i in
A.state_add env loc v)
init_state lbls2i in
{ test with init_state; } in
(*****************************************************)
(* Build events monad, _i.e._ run code in some sense *)
(*****************************************************)
(* Manage labels *)
let see seen lbl =
let x = try IntMap.find lbl seen with Not_found -> 0 in
let x = x+1 in
let seen = IntMap.add lbl x seen in
x,seen in
let get_label lbl addr = match lbl with
| Some lbl -> lbl
| None ->
let lbls = labels_of_instr addr in
match Label.norm lbls with
| Some lbl -> lbl
| None -> sprintf "##%d" addr in
let tgt2lbl = function
| B.Lbl lbl -> lbl
| B.Addr addr -> get_label None addr in
let fetch_addr check_back seen proc_jmp addr_jmp lbl addr =
try
let (proc_tgt,_) as tgt = IntMap.find addr code_segment in
if (* Limit jump threshold to non determined jumps ? *)
Misc.int_eq proc_jmp proc_tgt
&& check_back
&& is_back_jump addr_jmp addr
then
let x,seen = see seen addr in
if x > unroll then begin
W.warn "loop unrolling limit reached: %s" (get_label lbl addr);
No tgt
end else
Ok (tgt,seen)
else
Ok (tgt,seen)
with Not_found ->
Segfault addr in
let fetch_code check_back seen proc_jmp addr_jmp = function
| B.Lbl lbl ->
begin try
let addr = Label.Map.find lbl prog in
fetch_addr check_back seen proc_jmp addr_jmp (Some lbl) addr
with Not_found -> segfault lbl
end
| B.Addr addr ->
fetch_addr check_back seen proc_jmp addr_jmp None addr in
(* All memory locations in a test, with initial values *)
let env0 = get_all_mem_locs test in
let addr2v proc s =
try (* Look for label to overwritable instruction *)
V.Val (Constant.Label (proc,norm_lbl s))
with
e -> (* No, look for data location *)
let v = A.V.nameToV s in
if
List.exists
(fun (a,_) ->
match a with
| A.Location_global a -> A.V.compare v a=0
| _ -> false)
env0
then v else (* No code nor data, check error *)
match e with
| Not_found ->
Warn.user_error
" Symbol %s is not a code label nor a location"
s
| e -> raise e in
(* Call instruction semantics proper *)
let wrap re_exec fetch_proc proc inst addr env m poi =
let ii =
{ A.program_order_index = poi;
proc = proc; fetch_proc; inst = inst;
labels = labels_of_instr addr;
lbl2addr = prog;
addr = addr;
addr2v=addr2v proc;
env = env;
in_handler = re_exec;
} in
if dbg then
Printf.eprintf "%s env=%s\n"
(A.dump_instruction ii.A.inst)
(A.pp_reg_state ii.A.env.A.regs) ;
if dbg && not (Label.Set.is_empty ii.A.labels) then
eprintf "Instruction %s has labels {%s}\n"
(A.dump_instruction inst)
(Label.Set.pp_str "," Label.pp ii.A.labels) ;
m ii in
let sem_instr = SM.build_semantics test in
let rec add_next_instr re_exec fetch_proc proc env seen addr inst nexts =
wrap re_exec fetch_proc proc inst addr env sem_instr >>> fun branch ->
let { A.regs=env; lx_sz=szo; fh_code } = env in
let env = A.kill_regs (A.killed inst) env
and szo =
let open MachSize in
match A.get_lx_sz inst with
| No -> szo
| St -> None
| Ld sz -> Some sz in
let env =
match branch with
| S.B.Next bds|S.B.Jump (_,bds)|S.B.IndirectJump (_,_,bds)
| B.Fault bds ->
List.fold_right
(fun (r,v) -> A.set_reg r v)
bds env
| _ -> env in
next_instr
re_exec inst fetch_proc proc { A.regs=env; lx_sz=szo; fh_code}
seen addr nexts branch
and add_code re_exec fetch_proc proc env seen nexts = match nexts with
| [] -> EM.unitcodeT true
| (addr,inst)::nexts ->
add_next_instr re_exec fetch_proc proc env seen addr inst nexts
and add_lbl re_exec check_back proc env seen addr_jmp lbl =
add_tgt re_exec check_back proc env seen addr_jmp (B.Lbl lbl)
and add_tgt re_exec check_back proc env seen addr_jmp tgt =
match fetch_code check_back seen proc addr_jmp tgt with
| No (tgt_proc,(addr,inst)::_) ->
let m ii =
EM.addT
(A.next_po_index ii.A.program_order_index)
(EM.cutoffT (tgt2lbl tgt) ii (S.B.Next [])) in
wrap
re_exec tgt_proc proc inst addr env m >>> fun _ -> EM.unitcodeT true
| No (_,[]) -> assert false (* Backward jump cannot be to end of code *)
| Ok ((tgt_proc,code),seen) -> add_code re_exec tgt_proc proc env seen code
| Segfault addr ->
let msg = Printf.sprintf
"Segmentation fault (kidding, address 0x%x does not point to code)"
addr in
EM.failcodeT (Misc.UserError msg) true
and add_fault re_exec inst fetch_proc proc env seen addr nexts =
match env.A.fh_code,re_exec with
| Some _, true ->
let e = "Fault inside a fault handler" in
EM.warncodeT e true
| Some fh_code, false ->
add_code true fetch_proc proc env seen fh_code
| None, true ->
EM.unitcodeT false
| None, false ->
let open Fault.Handling in
match C.fault_handling with
| Fatal -> EM.unitcodeT true
| Skip -> add_code false fetch_proc proc env seen nexts
| Handled ->
add_next_instr true fetch_proc proc env seen addr inst nexts
and next_instr re_exec inst fetch_proc proc env seen addr nexts b =
match b with
| S.B.Exit -> EM.unitcodeT true
| S.B.Next _ ->
add_code re_exec fetch_proc proc env seen nexts
| S.B.Jump (tgt,_) ->
add_tgt re_exec true proc env seen addr tgt
| S.B.Fault _ ->
add_fault re_exec inst fetch_proc proc env seen addr nexts
| S.B.FaultRet tgt ->
add_tgt false true proc env seen addr tgt
| S.B.CondJump (v,tgt) ->
EM.condJumpT v
(add_tgt re_exec (not (V.is_var_determined v))
proc env seen addr tgt)
(add_code re_exec fetch_proc proc env seen nexts)
| S.B.IndirectJump (v,lbls,_) ->
EM.indirectJumpT v lbls
(add_lbl re_exec true proc env seen addr)
in
(* Code monad returns a boolean. When false the code must be discarded.
See also add_instr in eventsMonad.ml *)
let jump_start proc env code =
add_code false proc proc env IntMap.empty code in
(* As name suggests, add events of one thread *)
let add_events_for_a_processor env (proc,code,fh_code) evts =
let env =
if A.opt_env then A.build_reg_state proc A.reg_defaults env
else A.reg_state_empty in
let () =
if dbg then
Printf.eprintf "Init reg state for proc %s: %s\n%!"
(Proc.pp proc) (A.pp_reg_state env) in
let evts_proc =
jump_start proc { A.regs=env; lx_sz=None; fh_code } code in
evts_proc |*| evts
in
(* Initial events, some additional events from caller in madd *)
let make_inits madd env size_env =
let module MI = EM.Mixed(C) in
if C.initwrites then
MI.initwrites madd env size_env
else
EM.zerocodeT
in
(* Build code monad for one given set of events to add *)
let set_of_all_instr_events madd =
List.fold_right
(add_events_for_a_processor test.Test_herd.init_state)
starts
(make_inits madd env0 test.Test_herd.size_env) in
let transitive_po es =
let r,e = es.E.po in
(r,E.EventRel.transitive_closure e) in
let af0 = (* locations with initial spurious update *)
if
match C.dirty with
| None -> false
| Some t -> t.DirtyBit.some_ha || t.DirtyBit.some_hd
then begin (* One spurious update per observed pte (final load) *)
if C.variant Variant.PhantomOnLoad then
let look_pt rloc k = match rloc with
| ConstrGen.Loc (A.Location_global (V.Val c as vloc))
when Constant.is_pt c -> vloc::k
| _ -> k in
A.RLocSet.fold look_pt test.Test_herd.observed []
else (* One spurious update per variable not accessed initially *)
let add_setaf0 k (loc,v) =
match loc with
| A.Location_global (V.Val c as vloc) ->
if Constant.is_pt c then
match v with
| V.Val (Constant.PteVal p)
when not (V.Cst.PteVal.is_af p) ->
vloc::k
| _ -> k
else k
| _ -> k in
List.fold_left add_setaf0 [] env0
end else [] in
let rec index xs i = match xs with
| [] ->
W.warn "%i abstract event structures\n%!" i ;
[]
| (vcl,es)::xs ->
let es = if C.debug.Debug_herd.monad then es else relabel es in
let es =
{ es with E.procs = procs; E.po = if do_deps then transitive_po es else es.E.po } in
(i,vcl,es)::index xs (i+1) in
let r =
Misc.fold_subsets_gen
(fun vloc -> EM.(|||) (SM.spurious_setaf vloc))
(EM.unitT ()) af0
(fun maf0 ->
EM.get_output (set_of_all_instr_events (EM.(|||) maf0)))
[] in
let r = match C.maxphantom with
| None -> r
| Some max ->
let count_spurious es =
E.EventSet.fold
(fun e k ->
if E.is_load e && E.is_spurious e then k+1 else k)
es 0 in
List.filter
(fun (_,es) -> count_spurious es.E.events <= max)
r in
{ event_structures=index r 0; overwritable_labels; },test
(*******************)
(* Rfmap generator *)
(*******************)
(* Step 1. make rfmap for registers and reservations *)
let get_loc e = match E.location_of e with
| Some loc -> loc
| None -> assert false
and get_read e = match E.read_of e with
| Some v -> v
| None -> assert false
and get_written e = match E.written_of e with
| Some v -> v
| None -> assert false
(* Add (local) final edges in rfm, ie for all (register) location, find the last (po+iico) store to it *)
let add_finals es =
U.LocEnv.fold
(fun loc stores k ->
let stores =
List.filter
(fun x -> not (E.EventSet.mem x (es.E.speculated))) stores in
match stores with
| [] -> k
| ew::stores ->
let last =
List.fold_right
(fun ew0 ew ->
if U.is_before_strict es ew0 ew then ew
else begin
(* If writes to a given register by a given thread
are not totally ordered, it gets weird to define
the last or 'final'register write *)
if not (U.is_before_strict es ew ew0) then
Warn.fatal
"Ambiguous po for register %s" (A.pp_location loc) ;
ew0
end)
stores ew in
S.RFMap.add (S.Final loc) (S.Store last) k)
(*******************************)
(* Compute rfmap for registers *)
(*******************************)
let map_loc_find loc m =
try U.LocEnv.find loc m
with Not_found -> []
let match_reg_events es =
let loc_loads = U.collect_reg_loads es
and loc_stores = U.collect_reg_stores es
(* Share computation of the iico relation *)
and is_before_strict = U.is_before_strict es in
(* For all loads find the right store, the one "just before" the load *)
let rfm =
U.LocEnv.fold
(fun loc loads k ->
let stores = map_loc_find loc loc_stores in
List.fold_right
(fun er k ->
let rf =
List.fold_left
(fun rf ew ->
if is_before_strict ew er then
match rf with
| S.Init -> S.Store ew
| S.Store ew0 ->
if U.is_before_strict es ew0 ew then
S.Store ew
else begin
(* store order is total *)
if not (is_before_strict ew ew0) then begin
Printf.eprintf "Not ordered stores %a and %a\n"
E.debug_event ew0
E.debug_event ew ;
assert false
end ;
rf
end
else rf)
S.Init stores in
S.RFMap.add (S.Load er) rf k)
loads k)
loc_loads S.RFMap.empty in
(* Complete with stores to final state *)
add_finals es loc_stores rfm
let get_rf_value test read rf = match rf with
| S.Init ->
let loc = get_loc read in
let look_address =
A.look_address_in_state test.Test_herd.init_state in
begin
try look_address loc with A.LocUndetermined -> assert false
end
| S.Store e -> get_written e
(* Add a constraint for two values *)
(* Optimization: adding constraint v1 := v2 should always work *)
exception Contradiction
let add_eq v1 v2 eqs =
if V.is_var_determined v1 then
if V.is_var_determined v2 then
if V.equal v1 v2 then eqs
else raise Contradiction
else (* Here, v1 and v2 necessarily differ *)
VC.Assign (v2, VC.Atom v1)::eqs
else if V.equal v1 v2 then eqs
else VC.Assign (v1, VC.Atom v2)::eqs
let pp_nosol lvl test es rfm =
let module PP = Pretty.Make(S) in
eprintf "No solution at %s level\n%!" lvl;
PP.show_es_rfm test es rfm ;
()
let solve_regs test es csn =
let rfm = match_reg_events es in
let csn =
S.RFMap.fold
(fun wt rf csn -> match wt with
| S.Final _ -> csn
| S.Load load ->
let v_loaded = get_read load in
let v_stored = get_rf_value test load rf in
try add_eq v_loaded v_stored csn
with Contradiction ->
let loc = Misc.as_some (E.location_of load) in
Printf.eprintf
"Contradiction on reg %s: loaded %s vs. stored %s\n"
(A.pp_location loc)
(A.V.pp_v v_loaded)
(A.V.pp_v v_stored) ;
assert false)
rfm csn in
if C.debug.Debug_herd.solver then
prerr_endline "++ Solve registers" ;
match VC.solve csn with
| VC.NoSolns ->
if C.debug.Debug_herd.solver then
pp_nosol "register" test es rfm ;
None
| VC.Maybe (sol,csn) ->
Some
(E.simplify_vars_in_event_structure sol es,
S.simplify_vars_in_rfmap sol rfm,
csn)
(**************************************)
(* Step 2. Generate rfmap for memory *)
(**************************************)
let get_loc_as_value e = match E.global_loc_of e with
| None -> eprintf "%a\n" E.debug_event e ; assert false
| Some v -> v
(* Compatible location are:
- either both determined and equal,
- or at least one location is undetermined. *)
let compatible_locs_mem e1 e2 =
E.event_compare e1 e2 <> 0 && (* C RMWs cannot feed themselves *)
E.compatible_accesses e1 e2 &&
begin
let loc1 = get_loc e1
and loc2 = get_loc e2 in
let ov1 = A.undetermined_vars_in_loc_opt loc1
and ov2 = A.undetermined_vars_in_loc_opt loc2 in
match ov1,ov2 with
| None,None -> E.same_location e1 e2
| (Some _,None)|(None,Some _)
| (Some _,Some _) -> true
end
(* Add a constraint for a store/load match *)
let pp_init load =
if dbg then
eprintf "Add eq load=%a, store=Init\n%!"
E.debug_event load
let pp_add load store =
if dbg then
eprintf "Add eq load=%a, store=%a\n%!"
E.debug_event load
E.debug_event store
let add_mem_eqs test rf load eqs =
let v_loaded = get_read load in
match rf with
| S.Init -> (* Tricky, if location (of load) is
not know yet, emit a specific constraint *)
let state = test.Test_herd.init_state
and loc_load = get_loc load in
pp_init load ;
begin try
let v_stored = A.look_address_in_state state loc_load in
add_eq v_stored v_loaded eqs
with A.LocUndetermined ->
VC.Assign
(v_loaded, VC.ReadInit (loc_load,state))::eqs
end
| S.Store store ->
pp_add load store ;
add_eq v_loaded (get_written store)
(add_eq
(get_loc_as_value store)
(get_loc_as_value load) eqs)
(* Our rather loose rfmaps can induce a cycle in
causality. Check this. *)
let rfmap_is_cyclic es rfm =
let iico = E.iico es in
let causality =
S.RFMap.fold
(fun load store k -> match load,store with
| S.Load er,S.Store ew -> E.EventRel.add (ew,er) k
| _,_ -> k)
rfm iico in
match E.EventRel.get_cycle causality with
| None -> prerr_endline "no cycle"; false
| Some cy ->
if C.debug.Debug_herd.rfm then begin
let debug_event chan e = fprintf chan "%i" e.E.eiid in
eprintf "cycle = %a\n" debug_event
(match cy with e::_ -> e | [] -> assert false)
end; true
(* solve_mem proper *)
(* refrain from being subtle: match a load with all compatible
stores, and there may be many *)
(* First consider loads from init, in the initwrite case
nothing to consider, as the initial stores should present
as events *)
let init = if C.initwrites then [] else [S.Init]
let map_load_init loads =
E.EventSet.fold
(fun load k -> (load,init)::k)
loads []
(*condition:
soit le load est specule, auquel cas il peut lire de partout;
soit le load n'est pas specule, auquel cas il ne peut pas lire de stores specules*)
let check_speculation es store load =
let spec = es.E.speculated in
E.EventSet.mem load spec ||
not (E.EventSet.mem store spec)
let is_spec es e = E.EventSet.mem e es.E.speculated
(* Consider all stores that may feed a load
- Compatible location.
- Not after in program order
(suppressed when uniproc is not optmised early) *)
let map_load_possible_stores test es rfm loads stores compat_locs =
let ok = match C.optace with
| OptAce.False -> fun _ _ -> true
| OptAce.True ->
let pred = U.is_before_strict es
and iico = U.iico es in
fun er ew ->
not
(E.is_explicit er && E.is_explicit ew && pred er ew
|| E.EventRel.mem (er,ew) iico)
| OptAce.Iico ->
let iico = U.iico es in
fun load store -> not (E.EventRel.mem (load,store) iico) in
let m =
E.EventSet.fold
(fun store map_load ->
List.map
(fun ((load,stores) as c) ->
if
compat_locs store load &&
check_speculation es store load &&
ok load store
then
load,S.Store store::stores
else c)
map_load)
stores (map_load_init loads) in
if dbg then begin
let pp_read_froms chan rfs =
List.iter
(fun rf -> match rf with
| S.Init -> fprintf chan "Init"
| S.Store e -> E.debug_event chan e ; fprintf chan ",")
rfs in
List.iter
(fun (load,stores) ->
eprintf "Pairing {%a} with {%a}\n"
E.debug_event load
pp_read_froms stores)
m
end ;
(* Check for loads that cannot feed on some write *)
if not do_deps && not asl then begin
List.iter
(fun (load,stores) ->
match stores with
| [] ->
begin match E.location_of load with
| Some loc ->
begin match A.symbol loc with
| Some sym ->
if S.is_non_mixed_symbol test sym then
Warn.fatal
"read on location %s does not match any write"
(A.pp_location loc)
else if check_mixed then
Warn.user_error
"mixed-size test rejected (symbol %s), consider option -variant mixed"
(A.pp_location loc)
| None ->
if dbg then begin
let module PP = Pretty.Make(S) in
eprintf
"Failed to find at least one write for load %a\n%!"
E.debug_event load ;
PP.show_es_rfm test es rfm
end ;
Warn.fatal
"Non symbolic location with no initial write: '%s'\n"
(A.pp_location loc)
end
| _ -> assert false
end
| _::_ -> ())
m
end ;
m
(* Add memory events to rfmap *)
let add_mem =
List.fold_right2
(fun er rf -> S.RFMap.add (S.Load er) rf)
let add_some_mem =
List.fold_right2
(fun er rf -> match rf with
| None -> fun rfm -> rfm
| Some rf -> S.RFMap.add (S.Load er) rf)
let add_mems =
List.fold_right2
(List.fold_right2 (fun r w -> S.RFMap.add (S.Load r) (S.Store w)))
let solve_mem_or_res test es rfm cns kont res loads stores compat_locs add_eqs =
let possible =
map_load_possible_stores test es rfm loads stores compat_locs in
let possible =
List.map
(fun (er,ws) ->
let ws = List.map (fun w -> Some w) ws in
(* Add reading from nowhere for speculated reads *)
let ws = if is_spec es er then None::ws else ws in
er,ws)
possible in
let loads,possible_stores = List.split possible in
(* Cross product fold. Probably an overkill here *)
Misc.fold_cross possible_stores
(fun stores res ->
(* stores is a list of stores that may match the loads list.
Both lists in same order [by List.split above]. *)
try
(* Add constraints now *)
if dbg then eprintf "Add equations\n" ;
let cns =
List.fold_right2
(fun load rf k -> match rf with
| None -> k (* No write, no equation *)
| Some rf -> add_eqs test rf load k)
loads stores cns in
if dbg then eprintf "\n%!" ;
(* And solve *)
if C.debug.Debug_herd.solver then
prerr_endline "++ Solve memory" ;
match VC.solve cns with
| VC.NoSolns ->
if C.debug.Debug_herd.solver then begin
let rfm = add_some_mem loads stores rfm in
pp_nosol "memory" test es rfm
end ;
res
| VC.Maybe (sol,cs) ->
(* Time to complete rfmap *)
let rfm = add_some_mem loads stores rfm in
(* And to make everything concrete *)
let es = E.simplify_vars_in_event_structure sol es
and rfm = S.simplify_vars_in_rfmap sol rfm in
kont es rfm cs res
with
| Contradiction -> (* May be raised by add_mem_eqs *)
if C.debug.Debug_herd.solver then
begin
let rfm = add_some_mem loads stores rfm in
pp_nosol "memory" test es rfm
end ;
res
| e ->
if C.debug.Debug_herd.top then begin
eprintf "Exception: %s\n%!" (Printexc.to_string e) ;
let module PP = Pretty.Make(S) in
let rfm = add_some_mem loads stores rfm in
PP.show_es_rfm test es rfm
end ;
raise e
)
res
let when_unsolved test es rfm _cs res =
(* This system in fact has no solution.
In other words, it is not possible to make
such event structures concrete.
This occurs with cyclic rfmaps *)
if C.debug.Debug_herd.solver then begin
let module PP = Pretty.Make(S) in
prerr_endline "Unsolvable system" ;
PP.show_es_rfm test es rfm ;
end ;
assert (true || rfmap_is_cyclic es rfm);
res
let solve_mem_non_mixed test es rfm cns kont res =
let compat_locs = compatible_locs_mem in
if self then
let code_store e =
E.is_store e &&
match
Misc.seq_opt A.global (E.location_of e)
with
| Some (V.Val (Constant.Label _)|V.Var _) -> true
| Some _|None -> false in
(* Select code accesses *)
let code_loads =
E.EventSet.filter E.is_ifetch es.E.events
and code_stores =
E.EventSet.filter code_store es.E.events in
let kont es rfm cns res =
(* We get here once code accesses are solved *)
let loads = E.EventSet.filter E.is_mem_load es.E.events
and stores = E.EventSet.filter E.is_mem_store es.E.events in
let loads =
(* Remove code loads that are now solved *)
E.EventSet.diff loads code_loads in
if dbg then begin
eprintf "Left loads : %a\n"E.debug_events loads ;
eprintf "All stores: %a\n"E.debug_events stores
end ;
solve_mem_or_res test es rfm cns kont res
loads stores compat_locs add_mem_eqs in
if dbg then begin
eprintf "Code loads : %a\n"E.debug_events code_loads ;
eprintf "Code stores: %a\n"E.debug_events code_stores
end ;
solve_mem_or_res test es rfm cns kont res
code_loads code_stores compat_locs add_mem_eqs
else
let loads = E.EventSet.filter E.is_mem_load es.E.events
and stores = E.EventSet.filter E.is_mem_store es.E.events in
if dbg then begin
eprintf "Loads : %a\n"E.debug_events loads ;
eprintf "Stores: %a\n"E.debug_events stores
end ;
solve_mem_or_res test es rfm cns kont res
loads stores compat_locs add_mem_eqs
(*************************************)
(* Mixed-size write-to-load matching *)
(*************************************)
exception CannotSca
(* Various utilities on symbolic addresses as locations *)
(* Absolute base of indexed symbol (i.e. array address) *)
let get_base a =
let open Constant in
match A.symbolic_data a with
| Some ({name=s;_} as sym) ->
let s = if Misc.check_ctag s then Misc.tr_ctag s else s in
A.of_symbolic_data {sym with name=s; offset=0;}
| _ -> raise CannotSca
(* Sort same_base *)
let compare_index e1 e2 =
let open Constant in
let loc1 = E.location_of e1 and loc2 = E.location_of e2 in
match Misc.seq_opt A.symbolic_data loc1,
Misc.seq_opt A.symbolic_data loc2
with
| Some {name=s1;offset=i1;_},Some {name=s2;offset=i2;_}
when Misc.string_eq s1 s2 ->
Misc.int_compare i1 i2
| Some {name=s1;_},Some {name=s2;_} when morello ->
if Misc.check_ctag s1 && Misc.string_eq (Misc.tr_ctag s1) s2 then 1
else if Misc.check_ctag s2 && Misc.string_eq s1 (Misc.tr_ctag s2) then -1
else if Misc.check_ctag s1 && Misc.check_ctag s2 && Misc.string_eq s1 s2 then 0
else raise CannotSca
| _,_ -> raise CannotSca
let sort_same_base es = List.sort compare_index es
let debug_events out es = Misc.pp_list out " " E.debug_event es
module Match
(R:sig
type read
val compare_index : read -> S.event -> int
val debug_read : out_channel -> read -> unit
end) = struct
let debug_reads out es = Misc.pp_list out " " R.debug_read es
let rec inter rs0 ws0 = match rs0 with
| [] -> [],[]
| r::rs -> begin match ws0 with
| [] -> rs0,[]
| w::ws ->
let c = R.compare_index r w in
if c < 0 then
let rs,ws = inter rs ws0 in
r::rs,ws
else if c > 0 then
let rs,ws = inter rs0 ws in
rs,ws
else
let rs,ws = inter rs ws in
rs,w::ws
end
let rec all_ws rs ws wss =
if dbg then
eprintf "Trying [%a] on [%a]\n"
debug_reads rs debug_events ws ;
let rs_diff,ws_inter = inter rs ws in
if dbg then
eprintf "Found [%a] (remains [%a])\n"
debug_events ws_inter debug_reads rs_diff ;
match ws_inter with
| [] -> next_all_ws rs wss
| _ ->
List.fold_right
(fun ws k -> (ws_inter@ws)::k)
(next_all_ws rs_diff wss)
(next_all_ws rs wss)
and next_all_ws rs wss = match rs with
| [] -> [[]]
| _ ->
begin match wss with
| [] -> []
| ws::wss -> all_ws rs ws wss
end
let find_rfs_sca s rs wss = match next_all_ws rs wss with
| _::_ as wss -> List.map sort_same_base wss
| [] -> begin match rs with
| [] -> assert false
| _::_ -> Warn.user_error "out-of-bound access on %s" s
end
end
module MatchRf =
Match
(struct
type read = S.event
let compare_index = compare_index
let debug_read = E.debug_event
end)
let byte_sz = MachSize.nbytes C.byte
let expose_sca es sca =
let open Constant in
let sca = E.EventSet.elements sca in
let sca = sort_same_base sca in
let fst = match sca with
| e::_ -> e
| [] -> assert false in
let s,idx= match E.global_loc_of fst with
| Some (V.Val (Symbolic (Virtual {name=s; offset=i;_})))
->
(if morello && Misc.check_ctag s then Misc.tr_ctag s else s),i
| _ -> raise CannotSca in
let sz = List.length sca*byte_sz in
is_spec es fst,E.get_mem_dir fst,s,idx,sz,sca
let expose_scas es =
let scas = es.E.sca in
let ms =
E.EventSetSet.fold
(fun sca k -> expose_sca es sca::k)
scas [] in
let rs,ws =
List.fold_left
(fun (rs,ws) (g,d,x,idx,sz,es) -> match d with
| Dir.W ->
let old = StringMap.safe_find [] x ws in
rs,StringMap.add x ((g,idx,sz,es)::old) ws
| Dir.R -> (g,x,idx,sz,es)::rs,ws)
([],StringMap.empty) ms in
let ws =
StringMap.map
(List.sort (fun (_,_,sz1,_) (_,_,sz2,_) -> Misc.int_compare sz1 sz2))
ws in
let ms =
List.map
(fun (gr,x,i,sz,rs) ->
let ws = try StringMap.find x ws with Not_found -> assert false in (* Because of init writes *)
let ws =
List.filter
(fun (gw,i_w,sz_w,_) ->
not (not gr && gw) &&
(* non-ghost reads cannot read from ghost writes *)
i+sz >= i_w && i < i_w+sz_w
(* write and read intersects *))
ws in
x,rs,List.map (fun (_,_,_,ws) -> ws) ws)
rs in
let ms =
List.map
(fun (x,rs,wss) -> rs,MatchRf.find_rfs_sca x rs wss)
ms in
if C.debug.Debug_herd.solver || C.debug.Debug_herd.mem then begin
eprintf "+++++++++++++++++++++++\n" ;
List.iter
(fun (rs,wss) -> eprintf "[%a] ->\n" debug_events rs ;
List.iter
(fun ws -> eprintf " [%a]\n" debug_events ws)
wss)
ms ;
flush stderr
end ;
ms
(* Non-mixed pairing for tags, if any *)
let pair_tags test es rfm =
let tags = E.EventSet.filter E.is_tag es.E.events in
let loads = E.EventSet.filter E.is_load tags
and stores = E.EventSet.filter E.is_store tags in
let m =
map_load_possible_stores test es rfm loads stores compatible_locs_mem in
m
let solve_mem_mixed test es rfm cns kont res =
let match_tags = if morello then []
else pair_tags test es rfm in
let tag_loads,tag_possible_stores = List.split match_tags in
let ms = expose_scas es in
let rss,wsss = List.split ms in
(* Cross product fold. Probably an overkill here *)
Misc.fold_cross wsss
(fun wss res ->
(* Add memory constraints now *)
try
let cns =
List.fold_right2
(fun rs ws eqs ->
List.fold_right2
(fun r w eqs ->
assert (E.same_location r w) ;
add_eq (get_read r) (get_written w) eqs)
rs ws eqs)
rss wss cns in
Misc.fold_cross tag_possible_stores
(fun tag_stores res ->
(* Add tag memory constraints *)
try
let cns =
List.fold_right2
(fun load store k -> add_mem_eqs test store load k)
tag_loads tag_stores cns in
(* And solve *)
match VC.solve cns with
| VC.NoSolns -> res
| VC.Maybe (sol,cs) ->
(* Time to complete rfmap *)
let rfm = add_mems rss wss rfm in
let rfm = add_mem tag_loads tag_stores rfm in
(* And to make everything concrete *)
let es = E.simplify_vars_in_event_structure sol es
and rfm = S.simplify_vars_in_rfmap sol rfm in
kont es rfm cs res
with
| Contradiction -> res (* can be raised by add_mem_eqs *)
| e ->
if C.debug.Debug_herd.top then begin
eprintf "Exception: %s\n%!" (Printexc.to_string e) ;
let module PP = Pretty.Make(S) in
let rfm = add_mems rss wss rfm in
PP.show_es_rfm test es rfm
end ;
raise e)
res
with Contradiction -> res) (* can be raised by add_eq *)
res
let solve_mem test es rfm cns kont res =
try
if mixed && not C.debug.Debug_herd.mixed then solve_mem_mixed test es rfm cns kont res
else solve_mem_non_mixed test es rfm cns kont res
with
| CannotSca ->
solve_mem_non_mixed test es rfm cns kont res
(*************************************)
(* Final condition invalidation mode *)
(*************************************)
module CM = S.Cons.Mixed(C)
(* Internal filter *)
let check_filter test fsc = match test.Test_herd.filter with
| None -> true
| Some p ->
not C.check_filter ||
CM.check_prop p (S.type_env test) (S.size_env test) fsc
(*************************************)
(* Final condition invalidation mode *)
(*************************************)
(*
A little optimisation: we check whether the existence/non-existence
of some vo would help in validation/invalidating the constraint
of the test.
If no, not need to go on
*)
module T = Test_herd.Make(S.A)
let final_is_relevant test fsc =
let open ConstrGen in
let cnstr = T.find_our_constraint test in
let senv = S.size_env test
and tenv = S.type_env test in
let check_prop p = CM.check_prop p tenv senv fsc in
match cnstr with
(* Looking for 'Allow' witness *)
| NotExistsState p | ExistsState p -> check_prop p
(* Looking for witness that invalidates 'Require' *)
| ForallStates p -> not (check_prop p)
(* Looking for witness that invalidates 'Forbid' *)
let worth_going test fsc = match C.speedcheck with
| Speed.True|Speed.Fast -> final_is_relevant test fsc
| Speed.False -> true
(***************************)
(* Rfmap full exploitation *)
(***************************)
(* final state *)
let tr_physical =
let open Constant in
if kvm then
(function
| A.Location_global (V.Val (Symbolic (Physical (s,idx)))) ->
let sym = { default_symbolic_data with name=s; offset=idx; } in
A.of_symbolic_data sym
| A.Location_global (V.Val (Symbolic (TagAddr (PHY,s,o)))) ->
A.Location_global (V.Val (Symbolic (TagAddr (VIR,s,o))))
| loc -> loc)
else
Misc.identity
let compute_final_state test rfm es =
let st =
S.RFMap.fold
(fun wt rf k -> match wt,rf with
| S.Final loc,S.Store ew ->
A.state_add k (tr_physical loc) (get_written ew)
| _,_ -> k)
rfm test.Test_herd.init_state in
st,
if A.FaultAtomSet.is_empty test.Test_herd.ffaults && not !Opts.dumpallfaults then
A.FaultSet.empty
else
E.EventSet.fold
(fun e k ->
match E.to_fault e with
| Some f -> A.FaultSet.add f k
| None -> k)
es A.FaultSet.empty
(* View before relations easily available, from po_iico and rfmap *)
(* Preserved Program Order, per memory location - same processor *)
let make_ppoloc po_iico_data es =
let mem_evts = E.mem_of es in
E.EventRel.of_pred mem_evts mem_evts
(fun e1 e2 ->
E.same_location e1 e2 &&
E.EventRel.mem (e1,e2) po_iico_data)
(* Store is before rfm load successor *)
let store_load rfm =
S.RFMap.fold
(fun wt rf k -> match wt,rf with
| S.Load er,S.Store ew -> E.EventRel.add (ew,er) k
| _,_ -> k)
rfm E.EventRel.empty
(* Load from init is before all stores *)
let init_load es rfm =
let loc_stores = U.collect_stores es in
S.RFMap.fold
(fun wt rf k -> match wt,rf with
| S.Load er,S.Init ->
List.fold_left
(fun k ew ->
E.EventRel.add (er,ew) k)
k (map_loc_find (get_loc er) loc_stores)
| _,_ -> k)
rfm E.EventRel.empty
(* Reconstruct load/store atomic pairs *)
let make_atomic_load_store es =
let all = E.atomics_of es.E.events in
let atms = U.collect_atomics es in
U.LocEnv.fold
(fun _loc atms k ->
let atms =
List.filter
(fun e -> not (E.is_load e && E.is_store e))
atms in (* get rid of C RMW *)
let rs,ws = List.partition E.is_load atms in
List.fold_left
(fun k r ->
let exp = E.is_explicit r in
List.fold_left
(fun k w ->
if
S.atomic_pair_allowed r w &&
U.is_before_strict es r w &&
E.is_explicit w = exp &&
not
(E.EventSet.exists
(fun e ->
E.is_explicit e = exp &&
U.is_before_strict es r e &&
U.is_before_strict es e w)
all)
then E.EventRel.add (r,w) k
else k)
k ws)
k rs)
atms E.EventRel.empty
(* Retrieve last store from rfmap *)
let get_max_store _test _es rfm loc =
try match S.RFMap.find (S.Final loc) rfm with
| S.Store ew -> Some ew
| S.Init -> None (* means no store to loc *)
with Not_found -> None
(*
let module PP = Pretty.Make(S) in
eprintf "Uncomplete rfmap: %s\n%!" (A.pp_location loc) ;
PP.show_es_rfm test es rfm ;
assert false
*)
(* Store to final state comes last *)
let last_store test es rfm =
let loc_stores = U.collect_stores_non_spec es
and loc_loads = U.collect_loads_non_spec es in
U.LocEnv.fold
(fun loc ws k ->
match get_max_store test es rfm loc with
| None -> k
| Some max ->
let loads = map_loc_find loc loc_loads in
let k =
List.fold_left
(fun k er ->
if E.event_equal er max then k (* possible with RMW *)
else match S.RFMap.find (S.Load er) rfm with
| S.Init -> E.EventRel.add (er,max) k
| S.Store my_ew ->
if E.event_equal my_ew max then k
else E.EventRel.add (er,max) k)
k loads in
List.fold_left
(fun k ew ->
if E.event_equal ew max then k
else E.EventRel.add (ew,max) k)
k ws)
loc_stores E.EventRel.empty
let keep_observed_loc =
if kvm then
let open Constant in
fun loc -> match loc with
| A.Location_global (V.Val (Symbolic (Physical _|TagAddr (PHY, _, _) as sym1))) ->
let p oloc = match oloc with
| A.Location_global (V.Val (Symbolic sym2)) ->
Constant.virt_match_phy sym2 sym1
| _ -> false in
A.LocSet.exists p
| _ -> A.LocSet.mem loc
else A.LocSet.mem
let pp_locations = A.LocSet.pp_str " " A.pp_location
let all_finals_non_mixed test es =
let loc_stores = U.remove_spec_from_map es (U.collect_mem_stores es) in
let loc_stores =
if C.observed_finals_only then
let observed_locs =
let locs = S.observed_locations test in
if mixed then
let senv = S.size_env test in
A.LocSet.map_union
(fun loc ->
let open Constant in
match loc with
| A.Location_global
(V.Val (Symbolic (Virtual {name=s;_})) as a)
->
let eas = AM.byte_eas (A.look_size senv s) a in
A.LocSet.of_list
(List.map (fun a -> A.Location_global a) eas)
| _ -> A.LocSet.singleton loc)
locs
else if morello then
A.LocSet.map_union
(fun loc ->
let open Constant in
match loc with
| A.Location_global
(A.V.Val
(Symbolic
(Virtual ({name=s; offset=0; _} as sym))))
->
A.LocSet.add
(A.of_symbolic_data {sym with name=Misc.add_ctag s})
(A.LocSet.singleton loc)
| _ -> A.LocSet.singleton loc)
locs
else locs in
if C.debug.Debug_herd.mem then begin
eprintf "Observed locs: {%s}\n" (pp_locations observed_locs)
end ;
U.LocEnv.fold
(fun loc ws k ->
if keep_observed_loc loc observed_locs then
U.LocEnv.add loc ws k
else k)
loc_stores U.LocEnv.empty
else loc_stores in
let possible_finals =
match C.optace with
| OptAce.True ->
U.LocEnv.fold
(fun _loc ws k ->
List.filter
(fun w ->
not (E.is_explicit w) ||
not
(List.exists
(fun w' ->
E.is_explicit w' && U.is_before_strict es w w') ws))
ws::k)
loc_stores []
| OptAce.False|OptAce.Iico ->
U.LocEnv.fold (fun _loc ws k -> ws::k) loc_stores [] in
if C.debug.Debug_herd.solver && Misc.consp possible_finals then begin
eprintf "+++++++++ possible finals ++++++++++++++\n" ;
List.iter
(fun ws -> eprintf "[%a]\n" debug_events ws)
possible_finals ;
flush stderr
end ;
List.map (fun ws -> List.map (fun w -> [w]) ws) (possible_finals)
let rec compare_len xs ys = match xs,ys with
| [],[] -> 0
| [],_::_ -> -1
| _::_,[] -> 1
| _::xs,_::ys -> compare_len xs ys
module MatchFinal =
Match
(struct
type read = int
let compare_index idx e =
let open Constant in
match Misc.seq_opt A.symbolic_data (E.location_of e) with
| Some {name=s; offset=i; _} ->
if Misc.check_ctag s then Misc.int_compare idx max_int (* always -1 ??? *)
else Misc.int_compare idx i
| _ -> assert false
let debug_read out = fprintf out "%i"
end)
let all_finals_mixed test es =
assert C.observed_finals_only ;
let locs = S.observed_locations test in
let locs = A.LocSet.filter A.is_global locs in
let loc_wss =
E.EventSetSet.fold
(fun sca k ->
let e = E.EventSet.choose sca in
if E.is_store e && not (E.EventSet.mem e es.E.speculated) then match E.location_of e with
| Some a ->
let a0 = get_base a in
let t = A.look_type (S.type_env test) a0 in
let a =
match t with
| TestType.TyArray _ -> raise CannotSca
| _ -> a0 in
if keep_observed_loc a locs then
let old = A.LocMap.safe_find [] a k in
A.LocMap.add a (sort_same_base (E.EventSet.elements sca)::old) k
else k
| _ -> assert false (* Only globals in sca *)
else k)
es.E.sca A.LocMap.empty in
let wsss =
A.LocMap.fold
(fun loc wss k ->
let wss = List.sort compare_len (List.map sort_same_base wss)
and rs =
let senv = S.size_env test
and o = Misc.as_some (A.offset loc) in
AM.byte_indices o (A.look_size_location senv loc) in
let rs = if morello then rs@[max_int] else rs in
MatchFinal.find_rfs_sca (A.pp_location loc) rs wss::k)
loc_wss [] in
if C.debug.Debug_herd.solver && Misc.consp wsss then begin
eprintf "+++++++++ possible finals ++++++++++++++\n" ;
List.iter
(fun wss ->
List.iter
(fun ws -> eprintf "[%a]\n" debug_events ws)
wss ;
eprintf "--------------\n")
wsss ;
flush stderr
end ;
wsss
let fold_left_left f = List.fold_left (List.fold_left f)
let all_finals test es =
try
if mixed && not C.debug.Debug_herd.mixed then
all_finals_mixed test es
else
all_finals_non_mixed test es
with CannotSca ->
all_finals_non_mixed test es
let some_same_rf_rmw rfm rmw =
let loads = U.partition_events (E.EventRel.domain rmw) in
List.exists
(fun ers ->
let rfs =
E.EventSet.fold
(fun er k ->
try S.RFMap.find (S.Load er) rfm::k
with Not_found -> assert false)
ers [] in
Misc.exists_pair S.read_from_equal rfs)
loads
let fold_mem_finals test es rfm ofail atomic_load_store kont res =
(* We can build those now *)
let evts = es.E.events in
let po_iico = U.po_iico es in
let partial_po = E.EventTransRel.to_implicitely_transitive_rel es.E.partial_po in
let ppoloc = make_ppoloc po_iico evts in
let store_load_vbf = store_load rfm
and init_load_vbf = init_load es rfm in
(* Now generate final stores *)
let possible_finals = all_finals test es in
if C.debug.Debug_herd.mem then begin
eprintf "Possible finals:\n" ;
List.iter
(fun wss ->
(List.iter
(fun ws ->
List.iter (eprintf " %a" E.debug_event) ws)
wss ;
eprintf "\n"))
possible_finals
end ;
(* Add final loads from init for all locations, cleaner *)
let loc_stores = U.collect_stores es
and loc_loads = U.collect_loads es in
let rfm =
U.LocEnv.fold
(fun loc _rs k ->
try
ignore (U.LocEnv.find loc loc_stores) ;
k
with Not_found -> S.RFMap.add (S.Final loc) S.Init k)
loc_loads rfm in
try
let pco0 =
if C.initwrites then U.compute_pco_init es
else E.EventRel.empty in
(*jade: looks ok even in specul case: writes from init are before all
other writes, including speculated writes*)
let pco =
match C.optace with
| OptAce.False|OptAce.Iico -> pco0
| OptAce.True ->
(*jade: looks compatible with speculation, but there might be some
unforeseen subtlety here so flagging it to be sure*)
let ppoloc =
E.EventRel.restrict_rel
(fun e1 e2 -> E.is_explicit e1 && E.is_explicit e2)
ppoloc in
match U.compute_pco rfm ppoloc with
| None -> raise Exit
| Some pco -> E.EventRel.union pco0 pco in
(* Cross product *)
Misc.fold_cross
possible_finals
(fun ws res ->
if C.debug.Debug_herd.mem then begin
eprintf "Finals:" ;
List.iter
(fun ws ->
List.iter
(fun e -> eprintf " %a" E.debug_event e) ws)
ws ;
eprintf "\n";
end ;
let rfm =
fold_left_left
(fun k w ->
S.RFMap.add (S.Final (get_loc w)) (S.Store w) k)
rfm ws in
let fsc = compute_final_state test rfm es.E.events in
if check_filter test fsc && worth_going test fsc then begin
if C.debug.Debug_herd.solver then begin
let module PP = Pretty.Make(S) in
let fsc,_ = fsc in eprintf "Final rfmap, final state=%s\n%!" (S.A.dump_state fsc);
PP.show_es_rfm test es rfm ;
end ;
let last_store_vbf = last_store test es rfm in
let pco =
E.EventRel.union pco
(U.restrict_to_mem_stores last_store_vbf) in
if E.EventRel.is_acyclic pco then
let conc =
{
S.str = es ;
rfmap = rfm ;
fs = fsc ;
po = po_iico ;
partial_po = partial_po;
pos = ppoloc ;
pco = pco ;
store_load_vbf = store_load_vbf ;
init_load_vbf = init_load_vbf ;
last_store_vbf = last_store_vbf ;
atomic_load_store = atomic_load_store ;
} in
kont conc ofail res
else begin
if C.debug.Debug_herd.solver then begin
let conc =
{
S.str = es ;
rfmap = rfm ;
fs = fsc ;
po = po_iico ;
partial_po = partial_po ;
pos = ppoloc ;
pco = pco ;
store_load_vbf = store_load_vbf ;
init_load_vbf = init_load_vbf ;
last_store_vbf = last_store_vbf ;
atomic_load_store = atomic_load_store ;
} in
let module PP = Pretty.Make(S) in
eprintf "PCO is cyclic, discarding candidate\n%!" ;
PP.show_legend test "PCO is cyclic" conc [("last_store_vbf",last_store_vbf); ("pco",pco);];
end ;
res
end
end else res)
res
with Exit -> res
(* Initial check of rfmap validity: no intervening writes.
Limited to memory, since generated rfmaps are correct for registers *)
(* NOTE: this is more like an optimization,
models should rule out those anyway *)
let check_rfmap es rfm =
let po_iico = U.is_before_strict es in
S.for_all_in_rfmap
(fun wt rf -> match wt with
| S.Load er when E.is_mem_load er && E.is_explicit er ->
begin match rf with
| S.Store ew ->
not (E.is_explicit ew) ||
begin
assert (not (po_iico er ew)) ;
(* ok by construction, in theory *)
not
(E.EventSet.exists
(fun e ->
E.is_store e && E.same_location e ew &&
E.is_explicit e && po_iico ew e &&
po_iico e er)
es.E.events)
end
| S.Init ->
not
(E.EventSet.exists
(fun e ->
E.is_store e && E.same_location e er &&
E.is_explicit e && po_iico e er)
es.E.events)
end
| _ -> true)
rfm
let check_sizes test es =
if check_mixed then begin
(* No need to check initial writes, correct by construction. *)
let loc_mems = U.collect_mem_non_init es in
U.LocEnv.iter
(fun loc evts ->
let open Constant in
begin match loc with
| A.Location_global (V.Val (Symbolic sym))
when not (S.is_non_mixed_symbol test sym) ->
Warn.user_error "mixed-size test rejected (symbol %s), consider option -variant mixed"
(A.pp_location loc)
| _ -> ()
end ;
begin match evts with
| [] -> ()
| e0::es ->
let sz0 = E.get_mem_size e0 in
List.iter
(fun e ->
let sz = E.get_mem_size e in
if sz0 <> sz then begin
Printf.eprintf
"Size mismatch %a vs. %a, ie %s vs. %s\n"
E.debug_event e0
E.debug_event e
(MachSize.pp sz0) (MachSize.pp sz);
Warn.user_error "Illegal mixed-size test"
end)
es
end)
loc_mems
end
let check_event_aligned test e =
let a = Misc.as_some (E.global_loc_of e) in
if not (U.is_aligned (S.type_env test) (S.size_env test) e) then begin
if dbg then eprintf "UNALIGNED: %s\n" (E.pp_action e);
Warn.user_error "Unaligned or out-of-bound access: %s, %d bytes"
(A.V.pp_v a) (E.get_mem_size e |> MachSize.nbytes)
end
(* Check alignement in the mixed-size case.
Check is performed on original memory accesses,
not on splitted sub-events. Checking sub-events would
be too permissive, as easily shown by splitting accesses
into byte accesses. *)
let check_aligned test es =
E.EventSet.iter
(fun e -> check_event_aligned test e)
es.E.mem_accesses
let check_symbolic_locations _test es =
E.EventSet.iter
(fun e -> match E.location_of e with
| Some (A.Location_global (V.Val cst)) when
Constant.is_symbol cst ||
Constant.is_label cst
-> ()
| Some (A.Location_global (V.Var _))
-> ()
| Some loc ->
Warn.user_error "Non-symbolic memory access found on '%s'"
(A.pp_location loc)
| None -> assert false)
(E.mem_of es.E.events)
let check_noifetch_limitations es =
let non_init_stores = E.EventSet.filter
(fun e -> E.is_mem_store e && not (E.is_mem_store_init e))
es.E.events in
E.EventSet.iter (fun e ->
match E.location_of e with
| Some (A.Location_global (V.Val(Constant.Label(p, lbl)))) ->
Warn.user_error
"Store to %s:%s requires instruction fetch functionality.\n\
Please use `-variant self` as an argument to herd7 to enable it."
(Proc.pp p) (Label.pp lbl)
| _ -> ()
) non_init_stores
let check_ifetch_limitations test es owls =
let stores = E.EventSet.filter E.is_mem_store es.E.events in
let program = test.Test_herd.program
and code_segment = test.Test_herd.code_segment in
E.EventSet.iter (fun e ->
match E.location_of e with
| Some (A.Location_global (V.Val(Constant.Label(p, lbl))) as loc) ->
if Label.Set.mem lbl owls then begin
if false then (* insert a proper test here *)
Warn.user_error "Illegal store to '%s'; overwrite with the given argument not supported"
(A.pp_location loc)
end else begin
if not (E.is_mem_store_init e) then begin
try
match IntMap.find (Label.Map.find lbl program) code_segment with
| (_,[]) ->
Warn.user_error
"Final label %s cannot be overwritten"
(Label.pp lbl)
| (_,(_,i)::_) ->
Warn.user_error
"Instruction %s:%s cannot be overwritten"
(Label.pp lbl)
(A.dump_instruction i)
with
| Not_found ->
Warn.user_error
"Label %s not found on %s, yet it is used as constant"
(Label.pp lbl) (Proc.pp p)
end
end
| _ ->
()
) stores
let calculate_rf_with_cnstrnts test owls es cs kont res =
match solve_regs test es cs with
| None -> res
| Some (es,rfm,cs) ->
if C.debug.Debug_herd.solver && C.verbose > 0 then begin
let module PP = Pretty.Make(S) in
prerr_endline "Reg solved" ;
PP.show_es_rfm test es rfm ;
end ;
solve_mem test es rfm cs
(fun es rfm cs res ->
let ofail = VC.get_failed cs in
match cs with
| _::_
when
(not oota)
&& (not C.initwrites || not do_deps)
&& not asl
&& Misc.is_none ofail
->
(*
Jade:
on tolere qu'il reste des equations dans le cas d'evts specules -
mais il faudrait sans doute le preciser dans la clause when ci-dessus.
Luc:
Done, or at least avoid accepting such candidates in non-deps mode.
Namely, having non-sensical candidates rejected later by model
entails a tremendous runtime penalty. *)
when_unsolved test es rfm cs res
| _ ->
check_symbolic_locations test es ;
if self then check_ifetch_limitations test es owls
else check_noifetch_limitations es;
if (mixed && not unaligned) then check_aligned test es ;
if A.reject_mixed
&& not (mixed || memtag || morello)
then
check_sizes test es ;
if C.debug.Debug_herd.solver && C.verbose > 0 then begin
let module PP = Pretty.Make(S) in
prerr_endline "Mem solved" ;
PP.show_es_rfm test es rfm
end ;
if
match C.optace with
| OptAce.False|OptAce.Iico -> true
| OptAce.True -> check_rfmap es rfm
then
(* Atomic load/store pairs *)
let atomic_load_store = make_atomic_load_store es in
if
C.variant Variant.OptRfRMW
&& some_same_rf_rmw rfm atomic_load_store
then begin
if C.debug.Debug_herd.mem then begin
let module PP = Pretty.Make(S) in
eprintf
"Atomicity violation anticipated from rf map%!" ;
PP.show_es_rfm test es rfm
end ;
res
end else
fold_mem_finals test es
rfm ofail atomic_load_store kont res
else res)
res
end
|