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
|
; C Library
;
; Copyright (C) 2022 Kestrel Institute (http://www.kestrel.edu)
; Copyright (C) 2022 Kestrel Technology LLC (http://kestreltechnology.com)
;
; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2.
;
; Author: Alessandro Coglio (coglio@kestrel.edu)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(in-package "C")
(include-book "kestrel/std/util/deftutorial" :dir :system)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftutorial atc-tutorial "ATC tutorial")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-top
(atc)
(atc-tutorial-section "Scope of the Tutorial")
(xdoc::p
"This tutorial is work in progress,
but it may be already useful in its current incomplete form.
This tutorial's goal is to provide user-level pedagogical information
on how ATC works and how to use ATC effectively.
See "
(xdoc::seetopic "atc" "the ATC manual page")
" for the ATC reference documentation.")
(xdoc::p
"In this tutorial,
we refer to the official C standard in the manner explained in "
(xdoc::seetopic "c" "the top-level XDOC topic of our C library")
".")
(atc-tutorial-section "Structure of the Tutorial")
(xdoc::p
"This tutorial consists of this top-level page
plus a number of hyperlinked pages,
all of which are subtopics of this top-level page,
listed below alphabetically for easy reference.
Starting from this top-level page,
we provide <i>Start</i> and <i>Next</i> links
to navigate sequentially through all the tutorial pages;
we also provide <i>Previous</i> links going the opposite direction.
It is recommended to follow this order
when reading this tutorial for the first time.")
(xdoc::p
"Some pages may be skipped at first reading,
because they contain additional information
that may not be necessary for a user to know in order to start using ATC;
such pages include explicit text indicating that.
However, it is recommended to read all the pages, eventually."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page motivation
"Motivation for Generating C Code from ACL2"
(xdoc::p
"(This page may be skipped at first reading.)")
(xdoc::p
"The motivation for generating C code from ACL2 is analogous to
the motivation for generating Java code from ACL2,
or for generating code in other programming language from ACL2.
The @(see java::atj-tutorial-motivation) page
provides the general motivation,
in the context of Java:
it is recommended to read that page.")
(xdoc::p
"In addition, as a specific motivation for generating C code,
it should be noted that C is widely used in certain domains,
such as embedded systems.
Some of these C applications are relatively small in size
and have strong safety and security requirements,
making them an attractive target for (ACL2-based) formal methods."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page atj-comparison
"Comparison with ATJ's Java code generation from ACL2"
(xdoc::p
"(This page may be skipped at first reading.)")
(xdoc::p
"ATC is related to "
(xdoc::seetopic "java::atj" "ATJ")
", the Java code generator for ACL2.
Aside from the obvious difference in target languages,
ATJ and ATC currently differ in their primary goals and emphases.")
(xdoc::p
"ATJ was built to recognize, and translate to reasonable Java,
essentially any ACL2 code
(provided that it has side effects known to ATJ).
ATJ also provides ways to exert finer-grained control
on the generated Java,
by using certain ACL2 types and operations
that represent Java types and operations
and that are translated to the corresponding Java constructs.
While there are plans to have ATJ generate ACL2 proofs
of the correctness of the generated code,
ATJ currently does not generate proofs.")
(xdoc::p
"In contrast, ATC is being built to recognize, and translate to C,
only certain ACL2 types and operations
that represent C types and operations
and that are translated to the corresponding Java constructs.
ATC does not attempt to translate arbitrary ACL2 to C.
From the outset, ATC also generates ACL2 proofs
of the correctness of the generated C code.")
(xdoc::p
"The fact that ATC is simpler than ATJ
facilitates the generation of proofs.
Generating proofs for ATJ is a larger task,
due to the greater complexity.")
(xdoc::p
"In the future, ATC may be extended towards
recognizing any ACL2 code and translating it to reasonable C,
analogously to ATJ;
but the plan is for ATC to always generate proofs.
Conversely, ATJ may be extended to generate proofs as well.
Thus, while eventually ATJ and ATC may provide similar features,
their starting points and tradeoffs are different,
and that will keep the two tools different for some time to come."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page approach
"Approach to Generating C Code from ACL2"
(xdoc::p
"ATC translates a subset of ACL2 to C.
The ACL2 subset is designed to be close to C,
i.e. to be essentially ``C written in ACL2'',
so that it is relatively easy to translate to C.
There is a direct translation to the C constructs
from their representation in ACL2.")
(xdoc::p
"ATC is meant to be used in conjunction with "
(xdoc::seetopic "apt::apt" "APT")
". One uses APT transformations
to refine ACL2 specifications and code
to the subset recognized by ATC, which ATC translates to C.
Thus, ATC can be used at the end of an APT derivation.")
(xdoc::p
"Currently ATC recognizes a limited subset of ACL2
and translates it to a limited subset of C.
We plan to extend ATC to increasingly larger subsets of ACL2 and C."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page proofs
"ACL2 Proofs Generated for the Generated C code"
(xdoc::p
"(This page may be skipped at first reading.)")
(xdoc::p
"Besides generating C code,
ATC also generates ACL2 proofs of
the correctness of the generated C code
with respect to the ACL2 code from which the C code is generated.
More precisely, ATC generates ACL2 theorems
that assert these correctness properties.")
(xdoc::p
"The correctness properties proved by ATC are the following:")
(xdoc::ul
(xdoc::li
"The generated C code satisfies
the compile-time constraints prescribed by [C].
In other words, the C code is compilable by compliant compilers.
This is expressed via a "
(xdoc::seetopic "static-semantics" "formal static semantics of C")
".")
(xdoc::li
"The generated C code is functionally equivalent
to the ACL2 code that represents it.
In other words, it computes the same things as the ACL2 code.
This is expressed via a "
(xdoc::seetopic "atc-dynamic-semantics"
"formal dynamic semantics of C")
".")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page int-representation
"ACL2 representation of the C @('int') type and operations"
(xdoc::p
"As stated in @(see atc-tutorial-approach),
ATC recognizes, and translates to C,
a subset of ACL2 that represents C code quite directly.
In other words, there are representations of C constructs in ACL2,
which the ATC user must know so that they can invoke ATC
on ACL2 code of the appropriate form.
This tutorial page describes how the C @('int') types and operations
are represented in ACL2;
examples of their use, and of C code generated from them,
are given in other pages.")
(atc-tutorial-section "C @('int') Type and Operations")
(xdoc::p
"According to [C:6.2.5/5] and [C:5.2.4.2.1/1],
the ``plain'' @('int') type consists of
signed integers in a range from -32767 or less to +32767 or more
(both numbers are inclusive).
The exact range depends on the C implementation, as detailed below.")
(xdoc::p
"The (C, not ACL2) representation of @('int') values in memory,
which may be visible to the C code via access as @('unsigned char[]')
(as allowed by [C]),
consists of a sign bit, some value bits, and optionally some padding bits
[C:6.2.6.2/2].
The signed representation may be
two's complement, one's complement, or sign and magnitude
[C:6.2.6.2/2].
All these choices are implementation-dependent,
and determine the range of @('int') values,
subject to the minimum range requirement stated above.")
(xdoc::p
"Two's complement representations without padding bits seem the most common,
along with 8-bit bytes
(the exact number of bits in a byte is also implementation-dependent
[C:5.2.4.2.1/1] [C:6.2.6.1/3]).
Under these assumptions, @('int') values must consist of at least 16 bits,
resulting in at least the range from -32768 to +32767.
[C:6.2.6.1/4] requires @('int') to take a whole number of bytes,
and thus the possible bit sizes are 16, 24, 32, 40, 48, etc.
[C:6.2.5/5] states that the size is
the natural one suggested by the architecture of the execution environment.
For modern Macs and PCs, experiments suggest this to be 32 bits
(the experiment consists in printing @('sizeof(int)') in a C program),
even though one might expect it to be 64 bits instead,
given that these are 64-bit machines with 64-bit operating systems.
(However, the C @('long') type appears to be 64 bits on these platforms.)")
(xdoc::p
"C provides a variety of @('int') operations,
i.e. operations on @('int') values.
These operations also apply to other arithmetic types,
but in this tutorial page we focus on the @('int') type.")
(xdoc::p
"C provides the following unary and binary @('int') operations [C:6.5]:")
(xdoc::ul
(xdoc::li "@('+') (unary) — no value change, but mirrors unary @('-')")
(xdoc::li "@('-') (unary) — arithmetic negation")
(xdoc::li "@('~') (unary) — bitwise complement")
(xdoc::li "@('!') (unary) — logical negation/complement")
(xdoc::li "@('+') (binary) — addition")
(xdoc::li "@('-') (binary) — subtraction")
(xdoc::li "@('*') (binary) — multiplication")
(xdoc::li "@('/') (binary) — division")
(xdoc::li "@('%') (binary) — remainder")
(xdoc::li "@('<<') (binary) — left shift")
(xdoc::li "@('>>') (binary) — right shift")
(xdoc::li "@('<') (binary) — less-than")
(xdoc::li "@('>') (binary) — greater-than")
(xdoc::li "@('<=') (binary) — less-than-or-equal-to")
(xdoc::li "@('>=') (binary) — greater-than-or-equal-to")
(xdoc::li "@('==') (binary) — equality")
(xdoc::li "@('!=') (binary) — non-equality")
(xdoc::li "@('&') (binary) — bitwise conjunction")
(xdoc::li "@('^') (binary) — bitwise exclusive disjunction")
(xdoc::li "@('|') (binary) — bitwise inclusive disjunction")
(xdoc::li "@('&&') (binary) — logical (short-circuit) conjunction")
(xdoc::li "@('||') (binary) — logical (short-circuit) disjunction")
(xdoc::li "@('=') (binary) — simple assignment")
(xdoc::li "@('+=') (binary) — compound assignment with @('+')")
(xdoc::li "@('-=') (binary) — compound assignment with @('-')")
(xdoc::li "@('*=') (binary) — compound assignment with @('*')")
(xdoc::li "@('/=') (binary) — compound assignment with @('/')")
(xdoc::li "@('%=') (binary) — compound assignment with @('%')")
(xdoc::li "@('<<=') (binary) — compound assignment with @('<<')")
(xdoc::li "@('>>=') (binary) — compound assignment with @('>>')")
(xdoc::li "@('&=') (binary) — compound assignment with @('&')")
(xdoc::li "@('^=') (binary) — compound assignment with @('^')")
(xdoc::li "@('|=') (binary) — compound assignment with @('|')"))
(xdoc::p
"These not only take, but also return, @('int') values.
This uniformity is also due to the fact that C represents booleans
as the @('int') values 0 (for false) and 1 (for true),
and thus the relational and equality operations,
as well as the logical conjunction and disjunction operations,
all return @('int') results [C:6.5.13] [C:6.5.14].")
(xdoc::p
"Some of the above operations yield well-defined results,
specified by [C], only under certain conditions.
For instance, the addition operation @('+') on @('int') operands
is well-defined only if the exact result is representable as an @('int')
[C:6.5/5].
An implementation may actually add definedness to these operations,
by relying on the (well-defined) behavior of the underlying hardware,
e.g. by keeping the low bits of the exact result that fit @('int')
(which is the same result prescribed by the Java language specification).")
(xdoc::p
"The @('&&') and @('||') operations
are non-strict at the expression level:
their second operand expression is not executed
if the result of the first operand expression
suffices to determine the final result
(0 for conjunction, 1 for disjunction).")
(xdoc::p
"The simple and compound assignment operations have side effects.
All the other operations are pure, i.e. without side effect.")
(atc-tutorial-section "ACL2 Representation")
(xdoc::p
"The ACL2 representation of the C @('int') type and operations
is in the files @('[books]/kestrel/c/atc/integers.lisp')
and @('[books]/kestrel/c/atc/integer-operations.lisp').
These are automatically included when ATC is included,
but one may want to include those file as part of an APT derivation
that refines some specification to the ACL2 subset handled by ATC
(see @(see atc-tutorial-approach)),
and thus before including ATC itself,
which is only needed to generate code at the end of the derivation.")
(xdoc::p
"In line with typical C implementations on Macs and PCs mentioned above,
our ACL2 representation of @('int') values
consists of signed two's complement 32-bit integers.
More precisely, we provide a fixtype @(tsee sint) (for @('signed int')),
with associated predicate @(tsee sintp) and fixer @(tsee sint-fix).
This fixtype wraps
ACL2 integers in the range from @($-2^{31}$) to @($2^{31}-1$).
The wrapping provides more abstraction:
(the ACL2 representation of) C @('int') values must be manipulated
only via the provided ACL2 functions (see below)
in the ACL2 code that ATC translates to C.")
(xdoc::p
"We plan to generalize our ACL2 representation of C @('int') values
to allow different sizes than 4 (8-bit) bytes.
This will be achieved via a static parameterization,
i.e. via (something like) a constrained nullary function
that specifies the size of @('int').
We may also further generalize the representation,
again via a static parameterization,
to cover more of the options allowed by [C].")
(xdoc::p
"We also provide ACL2 functions
corresponding to some of the operations listed above:")
(xdoc::ul
(xdoc::li "@(tsee plus-sint) — for unary @('+')")
(xdoc::li "@(tsee minus-sint) — for unary @('-')")
(xdoc::li "@(tsee bitnot-sint) — for @('~')")
(xdoc::li "@(tsee lognot-sint) — for @('!')")
(xdoc::li "@(tsee add-sint-sint) — for binary @('+')")
(xdoc::li "@(tsee sub-sint-sint) — for binary @('-')")
(xdoc::li "@(tsee mul-sint-sint) — for @('*')")
(xdoc::li "@(tsee div-sint-sint) — for @('/')")
(xdoc::li "@(tsee rem-sint-sint) — for @('%')")
(xdoc::li "@(tsee shl-sint-sint) — for @('<<')")
(xdoc::li "@(tsee shr-sint-sint) — for @('>>')")
(xdoc::li "@(tsee lt-sint-sint) — for @('<')")
(xdoc::li "@(tsee gt-sint-sint) — for @('>')")
(xdoc::li "@(tsee le-sint-sint) — for @('<=')")
(xdoc::li "@(tsee ge-sint-sint) — for @('>=')")
(xdoc::li "@(tsee eq-sint-sint) — for @('==')")
(xdoc::li "@(tsee ne-sint-sint) — for @('!=')")
(xdoc::li "@(tsee bitand-sint-sint) — for @('&')")
(xdoc::li "@(tsee bitxor-sint-sint) — for @('^')")
(xdoc::li "@(tsee bitior-sint-sint) — for @('|')"))
(xdoc::p
"These are all the strict pure operations;
the non-strict or non-pure operations are excluded,
because they are represented differently in ACL2,
as described elsewhere in this tutorial.")
(xdoc::p
"These ACL2 functions take @(tsee sint) values as inputs,
as required by their guards.
They also return @(tsee sint) values as outputs,
as proved by their return type theorems.")
(xdoc::p
"Some of these functions have additional guard conditions
that capture the conditions under which
the result is well-defined according to the [C].
For instance, the guard of @(tsee add-sint-sint) includes the condition that
the exact integer result fits in the range of the ACL2 integers
that are wrapped to form @(tsee sint) values.
More precisely, these additional guard conditions
are captured by the following predicates,
whose association to the above functions should be obvious from the names:")
(xdoc::ul
(xdoc::li "@(tsee minus-sint-okp)")
(xdoc::li "@(tsee add-sint-sint-okp)")
(xdoc::li "@(tsee sub-sint-sint-okp)")
(xdoc::li "@(tsee mul-sint-sint-okp)")
(xdoc::li "@(tsee div-sint-sint-okp)")
(xdoc::li "@(tsee rem-sint-sint-okp)")
(xdoc::li "@(tsee shl-sint-sint-okp)")
(xdoc::li "@(tsee shr-sint-sint-okp)"))
(xdoc::p
"The predicates for @('/') and @('%') include
the condition that the divisor is not 0.")
(xdoc::p
"Besides unary and binary @('int') operations,
C includes @('int') constants [C:6.4.4.1]
(more precisely, integer constants, some of which have type @('int')),
which may be regarded as (a large number of nullary) @('int') operations.
Our ACL2 representation in @('[books]/kestrel/c/atc/integers.lisp')
provides functions
@(tsee sint-dec-const),
@(tsee sint-oct-const), and
@(tsee sint-hex-const)
whose calls on suitable ACL2 quoted integer constants
represent decimal, octal, and hexadecimal @('int') constants.
The quoted integer constant arguments must be
natural numbers in the range of signed two's complement 32-bit integers:
this is enforced by the guard of the three aforementioned functions.
Note that C integer constants are always non-negative.")
(xdoc::p
"See the documentation of the fixtype and functions mentioned above
for more details.")
(xdoc::p
"In the future, we may generalize our representation of these operations
to allow for implementation-defined behaviors,
via suitable static parameterizations."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page int-programs
"ACL2 representation and generation of C @('int') programs"
(xdoc::p
"After describing
our ACL2 representation of the C @('int') type and operations
in @(see atc-tutorial-int-representation),
now we describe how that is used to represent and generate
C @('int') programs, i.e. programs that manipulate @('int') values.")
(xdoc::p
"We do that via a simple example,
but present concepts that apply more generally.
However, this page only describes the basics of
representing and generating C @('int') programs:
more advanced features are presented in subsequent tutorial pages.")
(atc-tutorial-section "Simple Example")
(xdoc::p
"Our simple example is a C program consisting of a single function:")
(xdoc::codeblock
"int f(int x, int y, int z) {"
" return (x + y) * (z - 3);"
"}")
(xdoc::p
"This function takes three @('int') values
and returns an @('int') value resulting from
their combination via @('int') operations.
The function also involves the use of an @('int') constant.")
(atc-tutorial-section "Function Correspondence")
(xdoc::p
"There is a one-to-one representational correspondence
between C and ACL2 functions.
That is, every C function is represented by an ACL2 function,
whose name must be supplied to ATC in order to generate
the corresponding C function definition
(the exact call of ATC is described later in this page).")
(xdoc::p
"Thus, for the example program above,
we need an ACL2 function to represent @('f').
This generalizes to C programs with multiple functions.")
(atc-tutorial-section "Function and Parameter Names")
(xdoc::p
"The names of the function and its parameters
are represented by ACL2 symbols
whose names are identical to the C identifiers:")
(xdoc::codeblock
"(defun |f| (|x| |y| |z|)"
" ...)")
(xdoc::p
"Note that we need the double bar notation because
the names are lowercase, consistently with the C convention.
If we omitted the double bars,
we would be representing a different C function:")
(xdoc::codeblock
"int F(int X, int Y, int Z) {"
" ..."
"}")
(xdoc::p
"This is because, without the vertical bars,
the names of the symbols are uppercase.
This is a valid C function,
but does not follow the normal C naming conventions.")
(xdoc::p
"Package names are ignored for this purpose,
e.g. both @('acl2::|f|') and @('c::|f|') represent
the C identifier @('f').")
(xdoc::p
"In the envisioned use of ATC,
the user would write ACL2 functions with more conventional ACL2 names
for both functions and parameters
(i.e. without vertical bars).
The user would then use APT transformations to turn those names
into the form required to represent C names for ATC's purposes.")
(xdoc::p
"More details about the mapping from ACL2 names to C names
are given in @(see atc-tutorial-identifiers).")
(atc-tutorial-section "Function Body")
(xdoc::p
"Given the representation of C @('int') operations (including constants)
described in @(see atc-tutorial-int-representation),
it should be easy to see how the body of the C function @('f') above
is represented as follows in ACL2:")
(xdoc::codeblock
"(defun |f| (|x| |y| |z|)"
" (c::mul-sint-sint (c::add-sint-sint |x| |y|)"
" (c::sub-sint-sint |z| (c::sint-dec-const 3))))")
(xdoc::p
"We represent the expression of the @('return') statement
that forms the body of the function @('f').
In ACL2, terms are implicitly returned,
so there is no need to represent the @('return') statement explicitly.")
(xdoc::p
"The @('c::') package prefixes are generally needed
when the function is defined in a different ACL2 package from @('\"C\"').
The package of the symbols @('|f|'), @('|x|'), etc. do not matter,
in the sense that they do not represent anything in the C code.
However the functions @(tsee sint-dec-const), @(tsee add-sint-sint), etc.
must be the ones in the @('\"C\"') package,
from the file @('[books]/kestrel/c/atc/integers.lisp').")
(xdoc::p
"In the envisioned use of ATC,
the user would not write directly a function body of the form above.
Instead, they would obtain that kind of function body
via suitable APT transformations that turn
(conventional) ACL2 types and operations
into (ACL2 representations of) C types and operations,
under suitable preconditions.")
(atc-tutorial-section "Function Input and Ouput Types")
(xdoc::p
"Given the use of @(tsee add-sint-sint) and @(tsee sub-sint-sint)
on the ACL2 parameters @('|x|'), @('|y|'), and @('|z|'),
it would not be hard to infer automatically that
these represent @('int') parameters in C.
However, the required guard verification described below
implicitly requires the guard of @('|f|') to express or imply
that @(tsee sintp) holds on the function parameters.
For clarity, we require those to be expressed, not merely implied.")
(xdoc::p
"That is, the guard must include explicit conjuncts
that spell out the C types of the function's parameters.
For the example function, these are as follows:")
(xdoc::codeblock
"(defun |f| (|x| |y| |z|)"
" (declare (xargs :guard (and (c::sintp |x|)"
" (c::sintp |y|)"
" (c::sintp |z|)"
" ...))) ; more conjuncts, described below"
" (c::mul-sint-sint (c::add-sint-sint |x| |y|)"
" (c::sub-sint-sint |z| (c::sint-dec-const 3))))")
(xdoc::p
"When generating C code for @('|f|'),
ATC looks for those conjuncts in the guard.
These may occur anywhere in the guard,
not necessarily in order,
but they must be easily extractable
by looking at the @(tsee and) tree structure of the guard:
the conjuncts of interest must be leaves in that tree,
one for each function parameter.
For instance, the following would be equally acceptable:")
(xdoc::codeblock
"(defun |f| (|x| |y| |z|)"
" (declare (xargs :guard (and (and (c::sintp |z|)"
" (c::sintp |x|))"
" (and ..."
" (c::sintp |y|))"
" ...)))"
" ...) ; body as above")
(xdoc::p
"ATC infers the output type of a function
by performing a C type analysis of the function's body.
For the function @('|f|') above,
the output type is obviously @('int'),
because the body is a call of @(tsee mul-sint-sint),
which is known to return (the ACL2 representation of) an @('int') value.
ATC does not require explicit return type theorems for the ACL2 functions
that are translated to C functions.")
(atc-tutorial-section "Guard Verification")
(xdoc::p
"ATC requires that the ACL2 functions that represent C functions
are guard-verified (which implies that they must be in logic mode).
This ensures that the ACL2 functions that represent C operations
are always applied to values whose result is well-defined
according to [C].
It also ensures that @(tsee sint-dec-const) is always applied
to a natural number representable as an @('int').")
(xdoc::p
"However, this generally requires guards to have additional conditions,
besides the @(tsee sintp) conjunts discussed above.
It should be clear that a C function like @('f')
does not yield a well-defined [C] result
for every possible value of its arguments.
For instance, sufficiently large values of @('x') and @('y')
would make the result of @('x + y') not representable as @('int'),
and thus not well-defined according to [C].")
(xdoc::p
"This should not be surprising.
It is fairly normal for programs to be correct
only under certain preconditions.
The example function @('f') above is a simple abstract example,
but in a practical development there must be natural preconditions
for the C functions that form the development;
otherwise, it would be impossible to formally prove correctness.")
(xdoc::p
"In a C program, there may be
functions that receive data from outside the program.
These functions should not assume any precondition on that data,
and diligently validate it before operating on it.
After validation, these C functions may call other C functions,
internal to the C program, in the sense that
they only receive data validated by the calling functions.
The validation provides preconditions
that may be assumed by the internal functions.")
(xdoc::p
"The example function @('f') may be regarded
as an internal function in the sense above.
For simplicity, we assume that every parameter of the function
is fairly small, more precisely not above 10 in absolute value.
The following is the function @('|f|') with the complete guard
and the hints and book inclusion and command to verify the guards:")
(xdoc::codeblock
"(encapsulate ()"
""
" (local (include-book \"arithmetic-5/top\" :dir :system))"
""
" (local (set-default-hints '((nonlinearp-default-hint"
" stable-under-simplificationp"
" hist"
" pspv))))"
""
" (defun |f| (|x| |y| |z|)"
" (declare (xargs :guard (and (c::sintp |x|)"
" (c::sintp |y|)"
" (c::sintp |z|)"
" ;; -10 <= x <= 10:"
" (<= -10 (c::sint->get |x|))"
" (<= (c::sint->get |x|) 10)"
" ;; -10 <= y <= 10:"
" (<= -10 (c::sint->get |y|))"
" (<= (c::sint->get |y|) 10)"
" ;; -10 <= z <= 10:"
" (<= -10 (c::sint->get |z|))"
" (<= (c::sint->get |z|) 10))"
" :guard-hints ((\"Goal\""
" :in-theory"
" (enable c::sint-integerp-alt-def"
" c::sintp"
" c::add-sint-sint-okp"
" c::sub-sint-sint-okp"
" c::mul-sint-sint-okp"
" c::add-sint-sint"
" c::sub-sint-sint)))))"
" (c::mul-sint-sint (c::add-sint-sint |x| |y|)"
" (c::sub-sint-sint |z| (c::sint-dec-const 3)))))")
(xdoc::p
"The proof is carried out on the ACL2 integers
obtained by unwrapping the C integers;
it uses @('arithmetic-5'), with non-linear arithmetic enabled.
There may be other ways to verify the guards of this function.
ATC does not require any specific approach:
it only requires that guards are verified in some way,
and that the types of the parameters
are explicitly expressed in the guard.")
(xdoc::p
"In the envisioned use of ATC,
the user may verify the guards of @('|f|') not directly,
but by using APT transformations that generate
a guard-verified @('|f|') of the form above.
The fact that the results of those operations
are representable in the range of @('int') given the preconditions,
could have been proved in earlier stages of the derivation,
directly on ACL2 integers.
Then suitable APT transformations may turn those
into @('int') values.
This use of APT in conjunction with ATC may be described
in upcoming tutorial pages.")
(atc-tutorial-section "Code Generation")
(xdoc::p
"Given the guard-verified ACL2 function @('|f|') above,
the C function @('f') can be generated as follows:")
(xdoc::codeblock
"(include-book \"kestrel/c/atc/atc\" :dir :system)"
"(c::atc |f| :output-file \"f.c\")")
(xdoc::p
"First, we must include ATC.
To avoid certain trust tag messages,
the @(tsee include-book) form could be augmented with a @(':ttags') option;
see the tests in @('[books]/kestrel/c/atc/tests') for examples.")
(xdoc::p
"The ATC tool is invoked on one or more ACL2 function symbols,
in this case just @('|f|').
The @(':output-file') option says where the generated output file goes,
in this case @('f.c') in the current working directory.
This option is required: there is no default.")
(xdoc::p
"The above invocation of ATC generates the C file,
as conveyed by a message printed on the screen.
The invocation also prints certain event forms on the screen;
these will be described in @(see atc-tutorial-events)
and can be ignored for now.")
(xdoc::p
"Opening the file @('f.c') reveals exactly the function @('f') above.
ATC generates it from @('|f|').
It also generates correctness theorems,
but those are examined elsewhere, as mentioned above.")
(xdoc::p
"This example can be found in @('[books]/kestrel/c/atc/tests/f.lisp').")
(atc-tutorial-section "Compilation and Execution")
(xdoc::p
"On macOS or Linux, the generated file @('f.c') can be compiled via @('gcc').
In fact, any C compiler, also on Windows, can compile the file.
However, a plain compilation command like @('gcc f.c') may fail
due to the absence of a @('main') function.
This is, of course, easy to add;
it should be added to a separate file, so that it does not get overwritten
if the above call of ATC is run again.")
(xdoc::p
"For instance, one may add a file @('f-test.c') with the following content:")
(xdoc::codeblock
"#include <stdio.h>"
""
"int main(void) {"
" int x = 3;"
" int y = -2;"
" int z = 8;"
" int r = f(x, y, z);"
" printf(\"f(%d, %d, %d) = %d\\n\", x, y, z, r);"
"}")
(xdoc::p
"This file calls the generated function on specific values,
and prints inputs and output.
The inclusion of @('stdio.h') is needed because of the use of @('printf').")
(xdoc::p
"This file is found in @('[books]/kestrel/c/atc/tests/f-test.c').")
(xdoc::p
"The two files may be compiled as follows on macOS or Linux:")
(xdoc::codeblock
"gcc -o f f.c f-test.c")
(xdoc::p
"The @('-o') option overrides the default name @('a.out') for the executable,
calling it @('f') instead.
The two file names are simply supplied to the compiler,
which will generate an executable containing
both the @('main') and the @('f') functions.")
(xdoc::p
"The executable may be run as follows:")
(xdoc::codeblock
"./f")
(xdoc::p
"This prints the following on the screen:")
(xdoc::codeblock
"f(3, -2, 8) = 5"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page identifiers
"ACL2 representation of C identifiers"
(xdoc::p
"(This page may be skipped at first reading.)")
(xdoc::p
"As mentioned in @(see atc-tutorial-int-programs),
C function and variable names are represented by
ACL2 symbols whose names are the C function and variable names.
This tutorial page explains in more detail
which and how C identifiers are represented in ACL2.")
(xdoc::p
"[C:5.2.1] describes two (possibly identical) character sets:
one in which the C code is written
(the source character set),
and one whose character values are manipulated by the C code
(the execution character set).
C identifiers consist of characters from the source set.")
(xdoc::p
"The source and execution character sets may be anything,
so long as they satisfy the requirements stated in [C:5.2.1];
they do not have to be ASCII or Unicode or anything specific.
However, they are required to contain certain characters
that have obvious ASCII counterparts.
It also seems that, given the prevalence of (supersets of) ASCII,
most C implementations will indeed use (some superset of) ASCII
for both the source and execution character set.
This certainly appears to be the case on platforms like macOS.")
(xdoc::p
"Based on the above considerations,
and the fact that the "
(xdoc::seetopic "acl2::characters" "ACL2 character set")
" is the ISO 8859-1 superset of ASCII,
ATC assumes that the C implementation supports a superset of ASCII,
and generates code that is entirely in ASCII,
for greater portability.
This means that the generated C identifiers, in particular,
must consist of ASCII characters.")
(xdoc::p
"ATC generates C code with portable ASCII identifiers,
i.e. identifiers that are both ASCII and portable.
This notion is described and motivated in @(see portable-ascii-identifiers).
It is also stated in Section `Portable ASCII C Identifiers' of "
(xdoc::seetopic "atc" "the ATC reference documentation")
". Portable ASCII identifiers are represented, in ACL2,
by symbols whose @(tsee symbol-name)s are exactly the C identifiers.
Since, as mentioned above, ACL2 characters are a superset of ASCII,
any portable ASCII C identifier may be represented by some ACL2 symbol.
The @(tsee symbol-package-name)s are ignored for this purpose:
different ACL2 symbols with the same name but different package name
represent the same C identifier
(provided that their names are legal portable ASCII C identifiers).")
(xdoc::p
"The Lisp platform on which ACL2 runs is typically case-insensitive,
in the sense that symbols may be written in uppercase or lowercase,
and either way their names are uppercase,
e.g. both @('(symbol-name \'abc)') and @('(symbol-name \'ABC)')
yield the string @('\"ABC\"').
However, enclosing a symbol in vertical bars makes it case-sensitive,
e.g. @('(symbol-name \'|abc|)') yields the string @('\"abc\"').")
(xdoc::p
"In ACL2, function and variable symbols are normally written
without vertical bars and with dashes to separate words.
Since dashes are illegal in C identifiers,
underscores should be used to separate words
in ACL2 function and variable symbols
that represent C function and variable names.
As explained above, the absence of vertical bars would result
in C identifiers with uppercase letters,
which goes against typical C conventions.
Therefore, it is best to use vertical bars around these symbols.
Examples are @('|x|'), @('|next_value|'), @('|var_k43|'), etc.
In any case, any portable ASCII C identifiers,
including ones with uppercase letters,
are representable via ACL2 symbols."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page multiple-functions
"ACL2 representation and generation of multiple C functions"
(xdoc::p
"As mentioned in @(see atc-tutorial-int-programs),
there is a one-to-one representational correspondence
between ACL2 functions and C functions.
This tutorial page explains in more details and exemplifies
the representation and generation of multiple functions.")
(xdoc::p
"Consider a C program consisting of multiple functions:")
(xdoc::codeblock
"int f(int x, int y) {"
" return x < y;"
"}"
""
"int g (int z) {"
" return f(z, ~z);"
"}"
""
"int h (int a, int b) {"
" return g(a & b);"
"}")
(xdoc::p
"(We have chosen C operations that are well-defined over all @('int')s
to avoid guards that constrain the ranges of the function parameter.)")
(xdoc::p
"[C:6.2.1] disallows forward references among function definitions.
Specifically, [C:6.2.1/4] says that an external declaration
(i.e. one that is not inside any block),
which includes function definitions,
has a file scope that terminates at the end of the file;
it seems implicit in this that the scope starts with the definition,
and includes the function's body to make (singly) recursive calls possible.
Mutually recursive C function definitions,
and generally C function definitions that call functions
defined later in a file,
are allowed via function declarations (e.g. through header files)
that are not function definitions,
where the scope of the non-definition declaration
starts before the definition.
However, currently ATC only generates C files
without header files or function declarations that are not definitions.
Thus, the generated C functions cannot have forward references.")
(xdoc::p
"These restrictions mean that the C functions exemplified above
must appear exactly in that order in the generated C file.
This order matches ACL2's event order.
The C program above is represented by
the following three ACL2 functions:")
(xdoc::codeblock
"(defun |f| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |z|) (c::sintp |y|))))"
" (c::lt-sint-sint |x| |y|))"
""
"(defun |g| (|z|)"
" (declare (xargs :guard (c::sintp |z|)))"
" (|f| |z| (c::bitnot-sint |z|)))"
""
"(defun |h| (|a| |b|)"
" (declare (xargs :guard (and (c::sintp |a|) (c::sintp |b|))))"
" (|g| (c::bitand-sint-sint |a| |b|)))")
(xdoc::p
"These three functions must necessarily appear in this order,
but of course they do not have to be contiguous events
in the ACL2 @(see world),
i.e. there may be any number of events between them.")
(xdoc::p
"The ACL2 functions to be translated to C functions
must be always supplied to ATC in order
(i.e. their order in the ACL2 @(see world) and in the C file).
ATC checks that each supplied function
only calls earlier functions in the list.
This excludes any form of recursion, mutual or single.
(This restriction may be eventually lifted, but for now it applies.)")
(xdoc::p
"For the example above, ATC must be called as follows:")
(xdoc::codeblock
"(c::atc |f| |g| |h| :output-file ...)")
(xdoc::p
"Since each function listed only calls earlier functions in the list,
this list is accepted by ATC,
and the C program above is generated.")
(xdoc::p
"As mentioned above, currently ATC generates a single C file.
As seen in previous examples,
this is specified by the @(':output-file') option,
which must be present.
The file should have extension @('.c'),
but ATC does not currently enforce that.
In technical terms, the generated C file is a translation unit [C:5.1.1.1].
More precisely, the file is a source file,
which is read (by a C implementation, e.g. compiler)
into a preprocessing translation unit,
which becomes a translation unit after preprocessing.
Since ATC currently generates files without preprocessing directives,
preprocessing translation units coincide with translation units
as far as the C code generated by ATC is concerned."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page events
"ACL2 events generated by ATC"
(xdoc::p
"(This page may be skipped at first reading.)")
(xdoc::p
"As briefly mentioned in @(see atc-tutorial-int-programs),
ATC generates some events, besides the C file.
This page describes these events in more detail.")
(xdoc::p
"These events are generated only if the @(':proofs') option is @('t'),
which is the default, i.e. if proofs are generated.
The events all pertain to the proofs.
When @(':proofs') is @('nil'), ATC only generates the C file.")
(xdoc::p
"These events are generated in an @(tsee encapsulate),
from which they are exported.
The @(tsee encapsulate) also includes
some locally generated events that support the exported events.
The option @(':print :all') can be used to see all the events,
including the local ones.")
(atc-tutorial-section "Program Constant")
(xdoc::p
"ATC generates a named constant whose value is
the AST of the generated C program.
More precisely, it is the AST of the generated translation unit,
which is a value of the fixtype @(tsee transunit) in "
(xdoc::seetopic "abstract-syntax" "the abstract syntax of C")
". The translation unit is the content of the generated file:
the AST is "
(xdoc::seetopic "atc-pretty-printer" "pretty-printed")
" to the @('.c') file.
Currently ATC generates C programs that consist of
single translation units in single C files.")
(xdoc::p
"The @(':const-name') option directly controls the name of this constant.")
(xdoc::p
"The reason for generating this constant is so that
it can be used in the generated theorems described next,
making the theorems more readable.")
(atc-tutorial-section "Static Correctness Theorem")
(xdoc::p
"ATC generates a theorem asserting that
the generated C program is statically correct,
according to the "
(xdoc::seetopic "static-semantics" "formal static semantics of C")
".")
(xdoc::p
"More precisely, ATC generates a theorem of the form")
(xdoc::codeblock
"(defthm <constant>-well-formed"
" (equal (check-transunit <constant>) :wellformed))")
(xdoc::p
"This asserts that
when @(tsee check-transunit) is applied
to the named constant described above
(i.e. the abstract syntax of the generated C program),
the result is the value @(':wellformed').
That is, the AST satisfies all the requirements
of the static semantics of C:
the code can be compiled by a C compiler,
which is a prerequisite for executing it.")
(xdoc::p
"Since the program AST is a constant
and @(tsee check-transunit) is executable,
the theorem is proved easily by execution.")
(xdoc::p
"The name of the theorem is obtained by appending @('-well-formed')
after the name of the constant for the generated program.
Currently ATC provides no option
to control directly the name of this theorem;
it can be controlled only indirectly,
via the @(':const-name') option for the constant name (see above).")
(atc-tutorial-section "Dynamic Correctness Theorems")
(xdoc::p
"ATC generates theorems asserting that
the generated C program is dynamically correct,
according to "
(xdoc::seetopic "atc-dynamic-semantics" "ATC's dynamic semantics of C")
".")
(xdoc::p
"More precisely, for each target function @('fn')
(see @(see atc-tutorial-multiple-functions) for details on
how multiple ACL2 functions are translated to corresponding C functions),
ATC generates a theorem of the form")
(xdoc::codeblock
"(defthm <constant>-<fn>-correct"
" (implies (and <guard-of-fn>"
" (compustatep compst)"
" (integerp limit)"
" (>= limit <number>))"
" (equal (exec-fun (ident \"<fn>\")"
" (list <x1> ... <xn>)"
" compst"
" (init-fun-env <constant>)"
" limit)"
" (<fn> <x1> ... <xn>))))")
(xdoc::p
"This asserts that, under the guard of @('fn'),
running the C function corresponding to @('fn')
yields the same result as @('fn').
Here, @('<x1>'), ..., @('<xn>') are the formal parameters of @('fn').")
(xdoc::p
"The variable @('compst') represents the C computation state,
described in the "
(xdoc::seetopic "atc-dynamic-semantics" "C dynamic semantics")
": the theorem applies to execution in every possible computation state.")
(xdoc::p
"The term @('(init-fun-env <constant>)') constructs the "
(xdoc::seetopic "atc-function-environments" "C function environment")
" of the generated translation unit.")
(xdoc::p
"The variable @('limit') and the @('<number>') that provides a lower bound
are motivated by the fact that the big-step execution functions
take a limit value, as explained in the "
(xdoc::seetopic "atc-dynamic-semantics" "C dynamic semantics")
". The number is calculated by ATC as sufficient to execute the function.
The theorem asserts that, for any limit value at or above that limit,
execution terminates and yields the same result as @('fn').")
(xdoc::p
"We remark that the form of the theorem above is accurate
when none of the function's arguments are pointers.
When they are, the theorem has a slightly more general form,
which will be described in upcoming tutorial pages.")
(xdoc::p
"Note that, since @('fn') does not return error values,
the theorem implies that the execution of the C code
never results in an error, including unsafe operations.
This is because the dynamic semantics is defensive,
i.e. it checks the validity of every operation before performing it,
returning an error if the operation is invalid.")
(xdoc::p
"The guard satisfaction hypothesis is critical.
Without it, the C code may return some error,
e.g. if the result of an @('int') addition does not fit in an @('int').
Also see the discussion in @(see atc-tutorial-int-representation)
about the guards of the ACL2 functions that represent C operations.")
(xdoc::p
"The dynamic semantics of C is formalized in terms of
a deep embedding of C in ACL2:
C ASTs are explicitly modeled in ACL2,
and (static and dynamic) semantics is defined on the ASTs.
In contrast, the ACL2 representation of C programs,
e.g. as described in @(tsee atc-tutorial-int-representation),
is like a shallow embedding of C in ACL2.
Thus, the correctness theorem above provides
a bridge between shallow and deep embedding.
The two embeddings are in close correspondence by design,
but the proofs are still not trivial,
because the two embeddings
are actually quite different in nature and details.")
(xdoc::p
"The correctness theorem above is proved by
expanding @('fn') (for the shallow embedding)
and symbolically executing its C counterpart (for the deep embedding).
The two converge to the same (non-error) result.")
(xdoc::p
"These correctness proofs for functions are
modular with respect to the function call graph:
theorems about the correctness of callees
are used to prove theorems about the correctness of callers.
This is achieved via locally generated theorems
that are more general than the exported ones
(the latter are not compositional).
Future versions of ATC may
export these theorems from the @(tsee encapsulate).")
(xdoc::p
"See @(tsee atc-proof-support) and @(tsee atc-implementation) for details
on the generated theorems and their proofs.")
(atc-tutorial-section "Code Generation after the Events")
(xdoc::p
"The actual code is generated (i.e. written into the file)
after the events above have been successfully processed by ACL2.
Thus, if one of the theorems above fails for some reason,
no code is generated.
The rationale is that, unless the code can be proved correct,
it should not be generated.
Of course, this is easily defated by setting @(':proofs') to @('nil').
Nonetheless, when @(':proofs') is @('t'),
it seems appropriate to generate the code after the proofs.")
(xdoc::p
"This deferral is achieved by having ATC not generate the code directly,
but by having ATC generate an event that generates the code.
Thus, ATC generates this and the events above,
putting the latter before the former,
and submits the events, in that order.
The effect is as desired."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page local-variables
"ACL2 representation of C local variables"
(xdoc::p
"So far this tutorial has shown ACL2 representations
of C functions that operate on their parameters.
This tutorial page explains how to represent C functions
that introduce and operate on local variables.")
(xdoc::p
"A C local variable declaration is represented by an ACL2 @(tsee let)
where the term to which the variable is bound
is wrapped with @(tsee declar) to indicate a variable declaration.
For examples, the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |x|) (c::sintp |y|))"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar)))))"
" (let ((|z| (c::declar (c::lt-sint-sint |x| |y|))))"
" (c::lognot-sint |z|)))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int f(int x, int y) {"
" int z = x < y;"
" return !z;"
"}")
(xdoc::p
"The @(tsee let) must bind a single variable,
which must be distinct from the function's parameters
and from any other @(tsee let) variable in scope
(the latter restriction is an over-approximation,
that is adequate to this tutorial page
but is refined in subsequent tutorial pages).
That is, it must be a new variable.
Its name must satisfy the constraints
described in @(tsee atc-tutorial-identifiers).
The type of the local variable, @('int') in this case,
is not explicitly represented in ACL2,
but it is inferred by ATC based on the term that the variable is bound to.
The @(tsee declar) wrapper is an identity function
whose only purpose is to indicate to ATC
that the @(tsee let) represents a local variable declaration
as opposed to a local variable assignment
(described in @(see atc-tutorial-assignments));
this wrapper should be normally enabled in proofs.")
(xdoc::p
"This is not limited to a single @(tsee let).
There may be nested @(tsee let)s,
which represent local variables in a sequence.
For instance, the ACL2 function"
(xdoc::codeblock
"(defun |g| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |x|) (c::sintp |y|))"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar)))))"
" (let ((|x_lt_y| (c::declar (c::lt-sint-sint |x| |y|))))"
" (let ((|x_eq_y| (c::declar (c::eq-sint-sint |x| |y|))))"
" (let ((|x_le_y| (c::declar (c::bitior-sint-sint |x_lt_y| |x_eq_y|))))"
" (c::lognot-sint |x_le_y|)))))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int g(int x, int y) {"
" int x_lt_y = x < y;"
" int x_eq_y = x == y;"
" int x_le_y = x_lt_y || x_eq_y;"
" return !x_le_y;"
"}")
(xdoc::p
"The C function above is equivalently represented by the ACL2 function")
(xdoc::codeblock
"(defun |g| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |x|) (c::sintp |y|))"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar)))))"
" (let* ((|x_lt_y| (c::declar (c::lt-sint-sint |x| |y|)))"
" (|x_eq_y| (c::declar (c::eq-sint-sint |x| |y|)))"
" (|x_le_y| (c::declar (c::bitior-sint-sint |x_lt_y| |x_eq_y|))))"
" (c::lognot-sint |x_le_y|)))")
(xdoc::p
"This form may be more readable:
the variables are not indented,
but they are at the same visual level, like the corresponding C variables.
Internally, @(tsee let*) expands into nested @(tsee let)s;
ATC examines ACL2 function bodies in "
(xdoc::seetopic "acl2::term" "translated form")
", where macros like @(tsee let*) are expanded."))
(xdoc::p
"Since @(tsee let) bindings in ACL2 always bind some term to the variable,
only C variable declarations with initializers may be represented.
This may be relaxed in the future,
as C allows uninitialized local variables;
for instance, these could be represented as @(tsee let) bindings
that bind variables to terms that do not return C values."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page assignments
"ACL2 representation of C assignments"
(xdoc::p
"In @(see atc-tutorial-local-variables) it was described
how to represent C local variable declarations
and use the variables in C expressions.
This tutorial page explains how to represent
assignments to these variables in ACL2.")
(xdoc::p
"In C, assignments are expressions that may occur at any level,
i.e. assignments may be subexpressions of other expressions at any depth.
ATC only supports assignments that are full expressions [C:6.8/4],
i.e. expressions at the top level, not subexpressions of other expressions.
Specifically, ATC supports expression statements [C:6.8.3]
whose expression is an assignment:
this way, assignments are treated as if they were statements,
keeping most expressions pure (i.e. side-effect-free)
and thus simplifying the formal model of C and generated proofs.")
(xdoc::p
"A C local variable assignment is represented by an ACL2 @(tsee let)
that binds a variable already bound, i.e. already in scope,
and where the term to which the variable is bound
is wrapped by the function @(tsee assign).
For example, the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |x|)"
" (c::sintp |y|))"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar"
" c::assign)))))"
" (let* ((|a| (c:;declar (c::bitand-sint-sint |x| |y|)))"
" (|a| (c::assign (c::bitnot-sint |a|))))"
" (c::gt-sint-sint |a| (c::sint-dec-const 0))))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int f(int x, int y) {"
" int a = x & y;"
" a = ~a;"
" return a > 0;"
"}")
(xdoc::p
"Recall that the @(tsee let*) expands to two nested @(tsee let)s.
The first one, as explained in @(see atc-tutorial-local-variables),
represents the local variable declaration with initializer;
the second one represents the assignment,
which in this case mentions the variable in the right subexpression,
but of course it may contain any expression.
The point is that the second @(tsee let) binds an ACL2 variable symbol
that is the same as the one bound by the first @(tsee let).
These are two homonymous but different variables in ACL2:
the second one shadows the first one.
However, we use the homonymy of the two ACL2 variables
to represent them as the same variable in C,
i.e. to regard the second @(tsee let) as an assignment
rather than a declaration.
After all, the C scoping rules differ from the ACL2 scoping rules:
C disallows a variable declaration with the same name as
another variable in the same scope
(but it allows shadowing in an inner scope).")
(xdoc::p
"The wrapper @(tsee assign) is the identity function,
whose sole purpose is to indicate to ATC
that the @(tsee let) represents a local variable assignment
as opposed to a local variable declaration
(described in @(see atc-tutorial-local-variables));
this wrapper should be normally enabled in proofs.")
(xdoc::p
"In ATC, we can also represent assignments to C function parameters
via @(tsee let) that bind variables
with the same names as the ACL2 function parameters,
and with the terms bound to the variables
wrapped with @(tsee assign).
For example, the ACL2 function")
(xdoc::codeblock
"(defun |g| (|a| |b|)"
" (declare (xargs :guard (and (c::sintp |a|)"
" (c::sintp |b|)"
" ;; 0 <= a <= 100:"
" (<= 0 (c::sint->get |a|))"
" (<= (c::sint->get |a|) 100))"
" :guard-hints ((\"Goal\""
" :in-theory"
" (enable c::assign"
" c::add-sint-sint-okp"
" c::sint-integerp-alt-def)))))"
" (let ((|a| (c::assign (c::add-sint-sint |a| (c::sint-dec-const 200)))))"
" (c::lt-sint-sint |b| |a|)))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int g(int a, int b) {"
" a = a + 200;"
" return b < a;"
"}")
(xdoc::p
"Even though the @(tsee let) in the function above
is not nested under another @(tsee let),
the fact remains that it binds an ACL2 variable
with the same symbol as a variable in the same scope.
(An ACL2 function parameter is, in a way, implicitly bound.)
Thus, ATC treats that as an assignment instead of a variable declaration."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page conditional-statements
"ACL2 representation of C conditional statements"
(xdoc::p
"Previous tutorial pages have shown how to represent C functions
whose bodies consists of return statements
and possibly local variable declarations and assignments
(including assignments to the function parameters).
This tutorial page explains how to represent C functions whose bodies
are (possibly nested) conditional statements.")
(xdoc::p
"If the body of an ACL2 function is an @(tsee if),
the body of the corresponding C function is an @('if-else') statement,
whose test is derived from the @(tsee if)'s first argument
and whose branches are derived from
the @(tsee if)'s second and third arguments.
If any of the second or third arguments is also an @(tsee if),
the corresponding branch is a nested @('if-else') statement.")
(xdoc::p
"However, note that @(tsee if) tests in ACL2 are (generalized) booleans,
i.e. they must return non-@('nil') for true and @('nil') for false,
while @('if') tests in C are scalars (e.g. integers),
i.e. they must return non-zero for true and zero for false.
Since @('nil') is different from the ACL2 model of any C scalar zero,
and also @('t') is different from the ACL2 model of any C scalar non-zero,
ACL2 @(tsee if) tests cannot directly represent C @('if') tests.
The file @('[books]/kestrel/c/atc/signed-ints.lisp'),
mentioned in @(see atc-tutorial-int-representation),
provides a function @(tsee boolean-from-sint)
the converts (the ACL2 representation of) a C @('int')
into an ACL2 boolean:
it returns @('t') if the @('int') is not 0;
it returns @('nil') if the @('int') is 0.
This @(tsee boolean-from-sint) must be used
as the test of an ACL2 @(tsee if),
applied to an ACL2 term representing an @('int') expression:
it represents a C @('if') test consisting of the argument expression.")
(xdoc::p
"For example, the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x| |y| |z|)"
" (declare (xargs :guard (and (c::sintp |x|)"
" (c::sintp |y|)"
" (c::sintp |z|))))"
" (if (c::boolean-from-sint |x|)"
" |y|"
" |z|))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int f(int x, int y, int z) {"
" if (x) {"
" return y;"
" } else {"
" return z;"
" }"
"}")
(xdoc::p
"As another example, the ACL2 function")
(xdoc::codeblock
"(defun |g| (|e|)"
" (declare (xargs :guard (c::sintp |e|)))"
" (if (c::boolean-from-sint (c::ge-sint-sint |e| (c::sint-dec-const 0)))"
" (if (c::boolean-from-sint"
" (c::lt-sint-sint |e| (c::sint-dec-const 1000)))"
" (c::sint-dec-const 1)"
" (c::sint-dec-const 2))"
" (c::sint-dec-const 3)))"
" )")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int g(int e) {"
" if (e >= 0) {"
" if (e < 1000) {"
" return 1;"
" } else {"
" return 2;"
" }"
" } else {"
" return 3;"
" }"
"}")
(xdoc::p
"The arguments of @(tsee boolean-from-sint) in @(tsee if) tests
may be the same ones used to describe the expressions
returned by @('int')-valued functions.
The @(tsee boolean-from-sint) just serves
to turn C @('int')s into ACL2 booleans;
it is not explicitly represented in the C code,
as shown in the examples above."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page conditional-expressions
"ACL2 representation of C conditional expressions"
(xdoc::p
"C has both conditional statements and conditional expressions.
Conditional expressions are ternary expressions of the form @('a ? b : c').
While @(see atc-tutorial-conditional-statements) explains
how to represent conditional statements in ACL2,
this tutorial page explains how to represent conditional expressions.")
(xdoc::p
"C conditional expressions are represented by ACL2 @(tsee if)s
wrapped with @(tsee condexpr).
This is the identity function, and should be normally enabled in proofs.
Its purpose is to indicate to ATC that the wrapped @(tsee if)
represents a conditional expressions instead of a conditional statements.
Given that conditional statements are more frequent
than conditional expressions in C,
using the wrapper for conditional expressions,
and no wrapper for conditional statements,
reduces verbosity while still supporting the explicit distinction.")
(xdoc::p
"For example, the ACL2 function")
(xdoc::codeblock
"(defun |h| (|x| |y|)"
" (declare (xargs :guard (and (c::sintp |x|)"
" (c::sintp |y|)"
" ;; x > 0:"
" (> (c::sint->get |x|) 0))"
" :guard-hints ((\"Goal\""
" :in-theory"
" (enable c::sub-sint-sint-okp"
" c::sint-integerp-alt-def"
" c::sint-integer-fix"
" c::sint->get)))))"
" (c::sub-sint-sint"
" |x|"
" (c::condexpr"
" (if (c::boolean-from-sint (c::ge-sint-sint |y| (c::sint-dec-const 18)))"
" (c::sint 0)"
" (c::sint 1)))))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int h(int x, int y) {"
" return x - (y >= 18 ? 0 : 1);"
"}")
(xdoc::p
"As another example, the ACL2 function")
(xdoc::codeblock
"(defun |i| (|a| |b|)"
" (declare (xargs :guard (and (c::sintp |a|)"
" (c::sintp |b|))"
" :guard-hints ((\"Goal\""
" :in-theory"
" (enable c::boolean-from-sint"
" c::sint-integerp-alt-def"
" c::sint-integer-fix"
" c::gt-sint-sint"
" c::sub-sint-sint-okp"
" c::sint->get)))))"
" (if (c::boolean-from-sint (c::gt-sint-sint |a| |b|))"
" (c::sub-sint-sint |a|"
" (c::condexpr"
" (if (c::boolean-from-sint"
" (c::eq-sint-sint |b| (c::sint-dec-const 3)))"
" (c::sint-dec-const 0)"
" (c::sint-dec-const 1))))"
" |b|))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int i(int a, int b) {"
" if (a > b) {"
" return a - (b == 3 ? 0 : 1);"
" } else {"
" return b;"
" }"
"}")
(xdoc::p
"Note that the two ACL2 @(tsee if)s are treated differently
because of the absence or presence of the @(tsee condexpr) wrapper:
the outer one represents a conditional statement,
the inner one represents a conditional expression.")
(xdoc::p
"The tests of the ACL2 @(tsee if)s that represent conditional expressions
must return ACL2 booleans,
in the same way as the @(tsee if)s that represent conditional statements.
As explained in @(see atc-tutorial-conditional-statements),
the function @(tsee boolean-from-sint) is used
to convert C @('int')s to ACL2 booleans in the tests.")
(xdoc::p
"It is important to note that representing C conditional expressions
with a ternary function defined to be equal to @(tsee if) does not work.
Such a function would have to be strict,
like all ACL2 functions except @(tsee if).
But in general conditional expressions must be non-strict."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page conditionals-with-mbt
"Treatment of ACL2 conditionals with @(tsee mbt) or @(tsee mbt$)"
(xdoc::p
"After describing how ACL2 conditionals
represent C conditional statements and expressions
(in @(see atc-tutorial-conditional-statements)
and @(see atc-tutorial-conditional-expressions)),
this tutorial page describes how certain ACL2 conditionals
do not actually represent C conditional statements and expressions.")
(xdoc::p
"These are ACL2 conditionals whose tests are
calls of @(tsee mbt) or @(tsee mbt$):
only their `then' branches represent (and are translated to) C code;
tests and `else' branches are ignored.")
(xdoc::p
"The argument of the built-in macro @(tsee mbt)
must be provably equal to @('t') for guard verification to succeed.
Similarly, the argument of the library macro @(tsee mbt$)
must be provably different from @('nil') for guard verification to succeed.
In fact, their execution is effectively skipped in guard-verified ACL2 code.
In particular, when they appear in an @(tsee if) test,
the `then' branch is always executed and the `else' branch is ignored.")
(xdoc::p
"As explained in @(see atc-tutorial-int-programs),
ATC requires the target ACL2 functions to be guard-verified.
Accordingly, as explained in @(see atc-tutorial-events),
the functional correctness theorems generated by ATC
include the target functions' guards as hypotheses.
In other words, ATC generates C code that matches the ACL2 code
under the guards, which must be verified for ATC to generate code.
Thus, the behavior of the ACL2 functions or of the C code outside the guards
is irrelevant in some precise sense:
so long as the ATC-generated code is called
on values that satisfy the guards,
the behavior is provably equivalent to the ACL2 counterpart.
(Upcoming tutorial pages will describe more precisely
this contract between ATC-generated code and external code.)")
(xdoc::p
"Given the above, it should be clear why ATC ignores
(i.e. does not generate any C code for)
@(tsee mbt) or @(tsee mbt$) tests of @(tsee if)s
and corresponding `else' branches,
treating this kind of conditionals
as if they were just their `then' branches.")
(xdoc::p
"Conditionals with @(tsee mbt) or @(tsee mbt$) tests
are sometimes used in recursive ACL2 functions
to ensure that termination can be proved.
Recall that termination proofs ignore guards,
which are extra-logical in ACL2
(i.e. not part of the logic itself,
although they give rise to proof obligations
expressed in the logic).")
(xdoc::p
"Another circumstance in which @(tsee mbt) or @(tsee mbt$) may arise
is via certain APT transformations.
For instance, the @(tsee apt::restrict) transformation
generates a new function whose body has the form
@('(if (mbt$ <test>) <then> <else>)').
As explained in @(see atc-tutorial-approach),
ATC is meant to be used in conjunction with APT,
namely by using APT to refine a specification into
forms that represent C code as recognized by ATC.
It is therefore quite possible that these APT transformations
produce @(tsee if)s with @(tsee mbt) or @(tsee mbt$) tests,
which make their way to ATC.")
(xdoc::p
"For example, both the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x|)"
" (declare (xargs :guard (c::sintp |x|)))"
" (if (mbt (c::sintp |x|))"
" (c::lt-sint-sint |x| (c::sint-dec-const 100))"
" (list :this-is-not-translated-to-c)))")
(xdoc::p
"and the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x|)"
" (declare (xargs :guard (c::sintp |x|)))"
" (if (mbt$ (c::sintp |x|))"
" (c::lt-sint-sint |x| (c::sint-dec-const 100))"
" (list :this-is-not-translated-to-c)))")
(xdoc::p
"represent the C function")
(xdoc::codeblock
"int f(int x) {"
" return x < 100;"
"}")
(xdoc::p
"which is, in fact, also equally represented by the ACL2 function")
(xdoc::codeblock
"(defun |f| (|x|)"
" (declare (xargs :guard (c::sintp |x|)))"
" (c::lt-sint-sint |x| (c::sint-dec-const 100)))"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-page conditionals-nonconcluding
"ACL2 representation of C conditional statements followed by more code"
(xdoc::p
"The preceding tutorial pages show how to represent C code
whose flow of control is ``tree-shaped'':
a function body is
a return statement,
or a local variable declaration followed by more code,
or an assignment followed by more code,
or a conditional statement whose branches have recursively the same form.
Thus, each conditional statement forks the tree,
while declarations and assignments extend the current tree branch,
and nested conditional statements fork subtrees.
Each path in the tree eventually concludes the execution of the function,
via a return statement.
This code structure excludes
conditional statements whose branches do not return,
but instead continue execution of subsequent code.")
(xdoc::p
"The execution of a C conditional statement that does not return
(but instead continues execution with the code after the statement)
generally causes side effects,
such as updating local variables or function parameters;
these are the only side effects of interest to us for now.
In a functional language like ACL2, these side effects must be explicit:
the representation of the conditional statement must yield something,
which must be used in the representation of the code after the statement.
We use @(tsee let) and @(tsee mv-let) for this purpose:
the former if one local variable or function parameter is updated;
the latter if multiple ones are updated.
These @(tsee let)s are disinguished from the ones that represent "
(xdoc::seetopic "atc-tutorial-local-variables" "local variable declarations")
" and "
(xdoc::seetopic "atc-tutorial-assignments" "assignments")
" because the term to which the variable is bound
does not have the @(tsee declar) or @(tsee assign) wrapper.
Consistently with that,
the terms to which the @(tsee mv-let) variables are bound
do not have any wrapper either.")
(xdoc::p
"For example, the ACL2 function")
(xdoc::codeblock
"(defun |j| (|x|)"
" (declare"
" (xargs"
" :guard (c::sintp |x|)"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar c::assign)))))"
" (let ((|y| (c::declar (c::sint-dec-const 0))))"
" (let ((|y| (if (c::boolean-from-sint"
" (c::lt-sint-sint |x| (c::sint-dec-const 100)))"
" (let ((|y| (c::assign"
" (c::bitior-sint-sint"
" |y|"
" (c::sint-dec-const 6666)))))"
" |y|)"
" (let ((|y| (c::assign"
" (c::bitxor-sint-sint"
" |y|"
" (c::sint-dec-const 7777)))))"
" |y|))))"
" (c::bitand-sint-sint |x| |y|))))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int j(int x) {"
" int y = 0;"
" if (x < 100) {"
" y = y | 6666;"
" } else {"
" y = y ^ 7777;"
" }"
" return x & y;"
"}")
(xdoc::p
"The first @(tsee let) represents a local variable declaration
as explained in @(see atc-tutorial-local-variables),
but the second @(tsee let) binds a homonymous variable
to an @(tsee if) that represents a side-effecting conditional statement.
The binding represents the side effects of the conditional statement,
and the body of the second @(tsee let)
(i.e. the @(tsee c::bitand-sint-sint) call)
``sees'' those side effects by referencing the bound variable.
The variable bound in the second @(tsee let) must be one in scope;
as also in the representation of "
(xdoc::seetopic "atc-tutorial-assignments" "assignments")
", it is a distinct shadowing variable in ACL2,
but it represents the same variable in C.
Indeed, the execution of a side-effecting conditional statement
is a bit like an assignment to the variable,
but performed via a statement instead of via an expression.
It is required that both branches of the @(tsee if)
end with the variable bound to the @(tsee if):
this is why both branches have a @(tsee let)
that represents an assignment that modifies the variable.
The function")
(xdoc::codeblock
"(defun |j| (|x|)"
" (declare"
" (xargs"
" :guard (c::sintp |x|)"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar c::assign)))))"
" (let ((|y| (c::declar (c::sint-dec-const 0))))"
" (let ((|y| (if (c::boolean-from-sint"
" (c::lt-sint-sint |x| (c::sint-dec-const 100)))"
" (c::bitior-sint-sint"
" |y|"
" (c::sint-dec-const 6666))"
" (c::bitxor-sint-sint"
" |y|"
" (c::sint-dec-const 7777)))))"
" (c::bitand-sint-sint |x| |y|))))")
(xdoc::p
"is equivalent to the one above in ACL2 but is rejected by ATC.
Requiring the branches to end with the bound variable
forces the assignment to be made explicit in the ACL2 representation,
thus simplifying ATC's task.
As already explained, ATC is meant to be used in conjunction with APT;
transformations could explicate these assignments automatically.")
(xdoc::p
"It is important to note that
@(tsee let)s that represent local variable declarations or assignments
cannot bind the variable (directly) to an @(tsee if),
but only to a term that represents a C expression,
wrapped with @(tsee declar) or @(tsee assign).
(The term may have the form @('(condexpr (if ...))'),
representing a conditional expression,
used as initializer of the declaration
or right-hand side of the assignment;
in this case the variable could be bound to an @(tsee if),
but only indirectly, which is why above we said `directly'.)
This kind of @(tsee let) may have bodies that are @(tsee if)s,
which represent conditional statements
that follow the declaration or assignment,
and not side-effecting conditional statements.
In contrast,
@(tsee let)s that represent side-effecting conditional statements,
as in the example above,
bind the variable directly to the @(tsee if), without wrappers.
Their bodies may be also @(tsee if)s,
but again those do not represent side-effecting conditional statemnent.")
(xdoc::p
"As another example, the ACL2 function")
(xdoc::codeblock
"(defun |k| (|x| |y|)"
" (declare"
" (xargs"
" :guard (and (c::sintp |x|)"
" (c::sintp |y|))"
" :guard-hints ((\"Goal\" :in-theory (enable c::declar c::assign)))))"
" (let* ((|a| (c::declar (c::lognot-sint |x|)))"
" (|b| (c::declar (c::bitnot-sint |x|))))"
" (mv-let (|a| |b|)"
" (if (c::boolean-from-sint |y|)"
" (let ((|a| (c::assign (c::bitnot-sint |a|))))"
" (mv |a| |b|))"
" (let* ((|b| (c::assign (c::sint-dec-const 2)))"
" (|a| (c::assign (c::sint-dec-const 14))))"
" (mv |a| |b|)))"
" (c::bitxor-sint-sint |a| |b|))))")
(xdoc::p
"represents the C function")
(xdoc::codeblock
"int k(int x, int y) {"
" int a = !x;"
" int b = ~x;"
" if (y) {"
" a = ~a;"
" } else {"
" b = 2;"
" a = 14;"
" }"
" return a ^ b;"
"}")
(xdoc::p
"The structure is the same as the previous example,
but the side effects involve two variables,
and therefore we use an @(tsee mv-let) instead of a @(tsee let).
The first two @(tsee let)s (to which the @(tsee let*) expands)
just represent local variable declarations,
but the @(tsee mv-let) represents
a conditional statement that side-effects two variables
followed by more code (a return statement in this case).
Similarly to the one-variable @(tsee let) case,
both branches of the @(tsee if) are required to end with
an @(tsee mv) of the bound variables, in the same order.
Again, this facilitates ATC's task,
and APT transformations could automatically produce terms of this form.")
(xdoc::p
"Note that, in this example,
one branch modifies only one variable,
while the other branch modifies both variables.
However, each branch must return all the variables;
for the first branch, only one is actually modified.")
(xdoc::p
"The above structures can be nested, in a way that should be obvious.
For instance, a branch of a conditional
could itself contain side-effecting conditionals.
The ability to represent side-effecting conditional statements
greatly expands the range of C code generable by ATC.")
(xdoc::p
"A branch that just returns the variable(s) without modification
represents an empty branch.
When that happens for the `else' branch,
ATC could generate an @('if') statement
instead of an @('if')-@('else') statement.
This is not supported yet, but could be supported with ease."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-atc-tutorial-topics)
|