This file is indexed.

/usr/share/acl2-6.3/parallel.lisp is in acl2-source 6.3-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
; ACL2 Version 6.3 -- A Computational Logic for Applicative Common Lisp
; Copyright (C) 2013, Regents of the University of Texas

; This version of ACL2 is a descendent of ACL2 Version 1.9, Copyright
; (C) 1997 Computational Logic, Inc.  See the documentation topic NOTE-2-0.

; This program is free software; you can redistribute it and/or modify
; it under the terms of the LICENSE file distributed with ACL2.

; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; LICENSE for more details.

; Written by:  Matt Kaufmann               and J Strother Moore
; email:       Kaufmann@cs.utexas.edu      and Moore@cs.utexas.edu
; Department of Computer Science
; University of Texas at Austin
; Austin, TX 78701 U.S.A.

; We thank David L. Rager for contributing an initial version of this file.

(in-package "ACL2")

; Section: To Consider.  The following might be good to address as time
; permits.

;   Change the piece of work list to an array (perhaps result in a faster
;   library because of less garbage.

;   Make removing closures from the queue destructive, in particular with
;   regard to early termination.

;   Recycle locks, perhaps for example in wait-on-condition-variable-lockless.
;   See this same comment in parallel-raw.lisp.

;   Provide a way for the user to modify *core-count*, including inside the
;   ACL2 loop.  If we allow for changing *core-count*, then we need to think
;   about allowing for changing variables that depend on it, e.g.,
;   *unassigned-and-active-work-count-limit* (perhaps by changing them to
;   zero-ary functions).

;   Modify the coefficient (currently 2) in the definition of
;   *unassigned-and-active-work-count-limit*.  Evaluate such modifications with
;   testing, of course.

; End of Section "To Consider".

(defdoc deflock

  ":Doc-Section ACL2::Parallel-programming

  define a wrapper macro that provides mutual exclusion in ACL2(p)~/

  This ~il[documentation] topic relates to the experimental extension of
  ACL2 supporting parallel evaluation and proof; ~pl[parallelism].

  ~bv[]
  Example Form:
  (deflock *my-lock*)

  General Form:
  (deflock *symbol*)
  ~ev[]
  where ~c[*symbol*] is a symbol whose first and last characters are both the
  character ~c[#\\*].

  A call of this macro generates a definition of another macro, named
  ~c[with-<modified-lock-symbol>], where ~c[<modified-lock-symbol>] is the
  given symbol with the leading and trailing ~c[*] characters removed.  This
  newly defined macro will guarantee mutually exclusive execution when called
  in the body of the raw Lisp definition of a function, as is typically the
  case for ~il[guard]-verified functions, for ~c[:]~ilc[program] mode
  functions, and for calls of macro ~ilc[top-level].
  (~l[guard-evaluation-table] for details of how raw Lisp code might not be
  invoked when guard-checking (~pl[set-guard-checking]) has value ~c[:none] or
  ~c[:all].)

  To see how mutual exclusion is guaranteed, consider the raw Lisp code
  generated for the macro, ~c[with-<modified-lock-symbol>], that is introduced
  by a call of ~c[deflock].  This code uses a lock (with the given ~c[*symbol*]
  as its name), which guarantees that for any two forms that are each in the
  scope of a call of ~c[with-<modified-lock-symbol>], the forms do not execute
  concurrently.

  Note that a call of ~c[deflock] expands into the application of ~c[progn] to
  two events, as illustrated below.
  ~bv[]
  ACL2 !>:trans1 (deflock *my-cw-lock*)
   (PROGN (TABLE LOCK-TABLE '*MY-CW-LOCK* T)
          (DEFMACRO WITH-MY-CW-LOCK (&REST ARGS)
                    (LIST* 'WITH-LOCK '*MY-CW-LOCK* ARGS)))
  ACL2 !>
  ~ev[]
  Thus, ~c[deflock] forms are legal embedded event forms
  (~pl[embedded-event-form]) for ~il[books] as well as ~ilc[encapsulate] and
  ~ilc[progn] ~il[events].

  The following log shows a lock in action.  Recall that locks work as expected
  in ~il[guard]-verified and ~c[:]~ilc[program] mode functions; they do not,
  however, work in ~c[:]~ilc[logic] mode functions that have not been
  guard-verified, as illustrated below.

  ~bv[]
  ACL2 !>(deflock *my-cw-lock*)
  [[.. output omitted ..]]
   WITH-MY-CW-LOCK
  ACL2 !>(defun foo (n)
           (declare (xargs :guard (natp n) :verify-guards nil))
           (plet ((x1 (with-my-cw-lock (cw \"~~x0\" (make-list n))))
                  (x2 (with-my-cw-lock (cw \"~~x0\" (make-list n)))))
                 (and (null x1) (null x2))))
  [[.. output omitted ..]]
   FOO
  ACL2 !>(foo 20)
  (NIL NIL NIL NIL( NIL NIL NIL NIL NIL NILNIL  NIL NILNIL  NIL NILNIL
       NIL NILNIL NIL  NIL NILNIL  NIL NIL
  NIL      NILNIL  NIL NILNIL )
  NIL NIL NIL NIL NIL NIL NIL NIL)
  T
  ACL2 !>(verify-guards foo)
  [[.. output omitted ..]]
   FOO
  ACL2 !>(foo 20)
  (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL
       NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
  (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL
       NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
  T
  ACL2 !>
  ~ev[]~/~/")

(defdoc compiling-acl2p

; Keep this documentation in sync with comments above the error in
; acl2-init.lisp about it being "illegal to build the parallel
; version", and also with the error message about supported Lisps in
; set-parallel-execution-fn.

  ":Doc-Section ACL2::Parallelism

  compiling ACL2(p)~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].
  ~l[parallelism-tutorial] for an introduction to parallel programming in ACL2.

  You can build an experimental version of ACL2 that supports parallel
  execution in the following host Common Lisp implementations:
  ~bq[]
  * CCL (OpenMCL)

  * Lispworks 6.0

  * SBCL with threads (feature ~c[:sb-thread])~eq[]

  The command below will compile ACL2 to support parallel execution, including
  parallel execution during proofs.  Any non-empty string may be used in place
  of ~c[t], and the value of ~c[LISP] (shown here as ~c[ccl]) is any Lisp
  executable on which one can build ACL2(p) (~pl[parallelism]).
  ~bv[]
  make ACL2_PAR=t LISP=ccl
  ~ev[]

  So for example, to make an executable image and also documentation (which
  will appear in subdirectories ~c[doc/EMACS] and ~c[doc/HTML]), using the Lisp
  executable ~c[ccl]:
  ~bv[]
  make large DOC ACL2_PAR=t LISP=ccl
  ~ev[]~/~/")

(defdoc parallel

; Just in case someone types :doc parallel.

  ":Doc-Section Miscellaneous

  evaluating forms in parallel~/

  ~l[parallelism].~/~/")

(defdoc parallelism-build

  ":Doc-Section Miscellaneous

  building an ACL2 executable with parallel execution enabled~/

  ~l[compiling-acl2p].~/~/")

(defun set-parallel-execution-fn (val ctx state)
  (declare (xargs :guard (member-eq val '(t nil :bogus-parallelism-ok))))
  (cond
   ((eq (f-get-global 'parallel-execution-enabled state)
        val)
    (pprogn (observation ctx
                         "No change in enabling of parallel execution.")
            (value nil)))
   (t
    #-acl2-par
    (er soft ctx
        "Parallelism can only be enabled in CCL, threaded SBCL, or Lispworks. ~
         ~ Additionally, the feature :ACL2-PAR must be set when compiling ~
         ACL2 (for example, by using `make' with argument `ACL2_PAR=t').  ~
         Either the current Lisp is neither CCL nor threaded SBCL nor ~
         Lispworks, or this feature is missing.  Consequently, parallelism ~
         will remain disabled.  Note that you can submit parallelism ~
         primitives at the top level when parallel execution is disabled, ~
         although they will not result in any parallel execution.~%")
    #+acl2-par
    (let ((observation-string
           (case val
             ((nil)
              "Disabling parallel execution.  Parallelism primitives may ~
               still be used, but during execution they will degrade to ~
               their serial equivalents.")
             ((t)
              "Parallel execution is enabled, but parallelism primitives may ~
               only be called within function definitions or macro top-level, ~
               not at the top level of the ACL2 read-eval-print loop.  See ~
               :DOC parallelism-at-the-top-level.")
             (otherwise ; :bogus-parallelism-ok
              "Parallel execution is enabled.  Parallelism primitives may be ~
               called directly in the top-level loop, but without use of the ~
               macro top-level, they will execute serially.  See :DOC ~
               parallelism-at-the-top-level."))))
      (pprogn
       (f-put-global 'parallel-execution-enabled val state)
       (observation ctx observation-string)
       (value val))))))

(defmacro set-parallel-execution (value)

; Parallelism blemish: cause an error if the user tries to go into a state
; where waterfall-parallelism is enabled but parallel-execution is disabled.

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): enabling parallel execution for four parallelism primitives~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].
  ~l[parallelism-tutorial] for an introduction to parallel execution in ACL2.

  ~bv[]
  General Forms:
  (set-parallel-execution nil) ; default for images not built for parallelism
  (set-parallel-execution t)   ; default for images built for parallelism
  (set-parallel-execution :bogus-parallelism-ok)
  ~ev[]
  ~/

  ~c[Set-parallel-execution] takes an argument that specifies the enabling or
  disabling of ~il[parallel] execution for the primitives ~ilc[pand],
  ~ilc[por], ~ilc[plet], and ~ilc[pargs] (but not ~ilc[spec-mv-let], whose
  parallel execution remains enabled).  However, without using
  ~ilc[top-level], calls of parallelism primitives made explicitly in the ACL2
  top-level loop, as opposed to inside function bodies, will never cause
  parallel execution; ~pl[parallelism-at-the-top-level].  Parallel execution
  is determined by the value of the argument to ~c[set-parallel-execution], as
  follows.

  Value ~c[t]:~nl[]
  All parallelism primitives used in bodies of function definitions are given
  the opportunity to execute in parallel.  However, the use of parallelism
  primitives directly in the ACL2 top-level loop causes an error.

  Value ~c[:bogus-parallelism-ok]:~nl[]
  Parallel execution is enabled, as for value ~c[t].  However, the use of
  parallelism primitives directly in the ACL2 top-level loop does not cause an
  error, but rather, simply results in serial execution for these primitives.

  Value ~c[nil]:~nl[]
  All parallelism primitives degrade to their serial equivalents, including
  their calls made directly in the ACL2 top-level loop.  Thus, uses of
  parallelism primitives do not in themselves cause errors.~/

  :cited-by parallel-programming"

  (declare (xargs :guard (member-equal value
                                       '(t 't nil 'nil
                                           :bogus-parallelism-ok
                                           ':bogus-parallelism-ok))))
  `(let ((val ,value)
         (ctx 'set-parallel-execution))
     (set-parallel-execution-fn
      (cond ((consp val) (cadr val))
            (t val))
      ctx
      state)))

(defdoc parallel-execution

  ":Doc-Section Parallel-programming

  for ACL2(p): configure parallel execution~/

  ~l[set-parallel-execution] for how to configure parallel execution for calls
  of ~ilc[plet], ~ilc[pargs], ~ilc[pand], ~ilc[por] (but not
  ~ilc[spec-mv-let]).~/~/")

(defun waterfall-printing-value-for-parallelism-value (value)

; Warning: We assume the the value of this function on input nil is :full.  If
; that changes, then we will need to replace the definition of
; waterfall-printing-full in front of the defproxy event below for
; waterfall-printing, as well as the corresponding defattach event in
; boot-strap-pass-2.lisp.

  (declare (xargs :guard (member-eq value *waterfall-parallelism-values*)))
  (cond ((eq value nil)
         :full)
        ((eq value :full)
         :very-limited)
        ((eq value :top-level)
         :very-limited)
        ((eq value :resource-based)
         :very-limited)
        ((eq value :resource-and-timing-based)
         :very-limited)
        (t
         (assert$ (eq value :pseudo-parallel)
                  :very-limited))))

; Parallelism wart: figure out if :bdd hints are supported.  Given the call of
; error-in-parallelism-mode@par in waterfall-step, it seems that they might not
; be; yet, regressions may have passed with them.  One possible outcome: If
; tests fail for contributed book directory books/bdd/, you might just modify
; translate-bdd-hint to cause a nice error if watefall parallelism is enabled,
; and also mention that (once again) in :doc
; unsupported-waterfall-parallelism-features.  Note that bdd-clause might be
; the function that actually performs the bdd hint, and that bdd-clause doesn't
; return state.  So, aside from the place in waterfall-step, bdd hints might be
; fine.

(defdoc unsupported-waterfall-parallelism-features

; For a discussion of the wormhole issue referenced in the :doc string below,
; see waterfall-print-clause-id@par.

; Parallelism no-fix: the problem below related to interrupts is potentially
; somewhat serious, but probably quite rare.  Moreover, it seems potentially
; quite difficult to fix, as it would likely involve multi-threaded Lisp issues
; as well as acl2-unwind-protect issues.

  ":Doc-Section ACL2::Parallel-proof

  proof features not supported with waterfall-parallelism enabled~/

  For a general introduction to ACL2(p), an experimental extension of ACL2 that
  supports parallel execution and proof, ~pl[parallelism].  Please note that
  although this extension is usable and, we hope, robust in its behavior, there
  are still known issues to address beyond those listed explicitly below.
  While we expect ACL2(p) to perform correctly, it may never have the same
  level of attention to correctness as is given to ACL2; ~pl[parallelism],
  specifically the ``IMPORTANT NOTE'' there.

  Below we list proof features of ACL2 that are not yet supported when parallel
  execution is enabled for the primary ACL2 proof process, generally known as
  ``the waterfall'', typically by calling ~ilc[set-waterfall-parallelism].

  Please note that this topic is limited to the case that such waterfall
  parallelism is enabled.  We believe that all ACL2 proof procedures are
  supported when waterfall parallelism is disabled, even in executables that
  support parallelism (~pl[compiling-acl2p]).

  Without a trust tag (~pl[defttag]): We support ~il[clause-processor]s,
  ~il[computed-hints], and ~il[custom-keyword-hints] that do not modify
  ~il[state], but we do not permit ~il[override-hints], regardless of whether
  they modify state.  With a trust tag, the user can use ~il[clause-processor]s
  that modify state and can also use ~il[override-hints]
  (~pl[set-waterfall-parallelism-hacks-enabled] for a convenient mechanism for
  adding a trust tag).  ~l[error-triples-and-parallelism] for a discussion of
  how to avoid modifying state in such situations.  Regardless of whether a
  trust tag is active: We do not support checkers of ~il[custom-keyword-hints]
  to be anything but the default checker.

  GNU Make versions 3.81 and 3.82 formerly caused a lot of problems (version
  3.80 somewhat less so), at least on Linux, when certifying books with ACL2
  built on a host Lisp of CCL using `make'.  CCL was updated around March 23,
  2011 to fix this problem, so if you get segfaults (for example) with CCL, try
  updating your CCL installation.

  Book certification should generally work but may present some issues,
  including the following.
  ~bq[]
  o The standard `make'-based process for book certification will not use
  ~il[waterfall-parallelism], which is disabled by default (even when
  ~il[compiling-acl2p] by using the ~c[ACL2_PAR] flag).
  ~l[books-certification] and ~pl[books-certification-classic], which explain
  that ~il[acl2-customization] files are ignored during that process unless
  specified explicitly on the command line or in the environment.

  o A book certified with ACL2(p) might subsequently cause an error when
  included with ACL2.  As of this writing, however, we have only seen this for
  a book in which ~ilc[deftheory-static] is used.

  o In general, ACL2(p) is primarily intended to support more rapid interactive
  development.  While we are unaware of an unsoundness likely to affect an
  ACL2(p) user, we suggest using ACL2 for final book certification, rather than
  ACL2(p), to lower the risk of unsound book certification.
  ~eq[]

  Proof output can contain repeated printing of the same subgoal name.

  ~il[Gag-mode] isn't officially supported, although it has proved helpful to
  use ACL2(p) in conjunction with ~c[(set-gag-mode t)] (because this setting
  suppresses the output that occurs outside the waterfall).  This being said,
  ACL2(p) also prints key checkpoints (for example
  ~pl[introduction-to-key-checkpoints]), but with a notion of ``key
  checkpoint'' that does not take into account whether the goal is later proved
  by induction.  ~l[acl2p-key-checkpoints] for further explanation of these
  key checkpoints.  Note that ~ilc[pso] is also not supported.

  The ~c[:]~ilc[brr] utility is not supported.

  The ~ilc[accumulated-persistence] utility is not supported.

  Tracking for ~il[forward-chaining-reports] is not supported
  (~pl[set-fc-criteria]).

  Time limits (~pl[with-prover-time-limit]) aren't supported.

  The timing information printed at the end of a proof attempt, which is
  intended to represent cpu time (not wall-clock time), may be somewhat
  inaccurate when ~il[waterfall-parallelism] is non-~c[nil].  Consider using
  ~ilc[time$] to obtain timing information.

  The use of ~ilc[wormhole]s is not recommended, as there may be race
  conditions.

  Output specific to ~c[:OR] ~il[hints] is disabled.

  Proof trees are likely not to work as originally designed.

  The use of ~ilc[set-inhibit-output-lst] may not fully inhibit proof output.

  Reporting of ~il[splitter] rules is currently unsupported when
  waterfall-parallelism is on.

  Interrupting a proof attempt is not yet properly supported.  At a minimum,
  interrupts are trickier with waterfall parallelism enabled.  For one, the
  user typically needs to issue the interrupt twice before the proof attempt is
  actually interrupted.  Additionally, on rare occasions the theorem is
  registered as proved, even though the prover did not finish the proof.  If
  this occurs, issue a ~c[:u] (~pl[ubt]) and you will likely be at a stable
  state.

  Also with regards to interrupting a proof attempt, sometimes the user may
  need to issue a ~c[:q] and ~c[lp] to reset properly the parallelism
  implementation to a stable state.  The primary symptom that the user is
  experiencing this issue is that threads will continue to compute in the
  background, even though there should be no proof attempt in progress.  The
  user can observe this symptom by examining the CPU utilization of their ACL2
  process, for example on Linux/Unix with the shell process ~c[top].  Lisp
  usage greater than a few percent is indicative of this problem.

  Because of how ACL2 ~il[arrays] are designed, the user may find that, in
  practice, ACL2 arrays work (but perhaps with some ~il[slow-array-warning]
  messages).  However, we are aware of race conditions that can cause
  problems.

  Instead of dynamically monitoring rewrites, ~il[dmr] instead dynamically
  outputs information helpful for debugging the performance of proof
  parallelism.  The instructions concerning how to see this debugging
  information are the same as the instructions for enabling ~il[dmr]
  mode.

  If you are working with LispWorks 6.0 or 6.0.1, then you may see messages
  about misaligned conses.  The state of the system may be corrupted after such
  a message has been printed.  This LispWorks bug is fixed in LispWorks 6.1.

  The waterfall parallelism mode ~c[:resource-and-timing-based] is not fully
  supported when the host Lisp is other than CCL.  It may work, but we have not
  attempted to address a potential race condition.

  Proof output for splitter rules (~pl[splitter]) is currently unsupported when
  waterfall-parallelism is enabled.

  (Comment for ACL2(h) users; ~pl[hons-and-memoization].)  Memoization may not
  work as intended when executing in parallel (including the waterfall).  In an
  effort to be helpful to the user, the functions automatically memoized by
  ACL2(h) are unmemoized when setting waterfall parallelism to anything but
  ~c[nil].  Those exact functions are again memoized once waterfall parallelism
  is disabled.  Additionally, any functions memoized within the ACL2 loop (by a
  call of ~ilc[memoize]) are also unmemoized when enabling waterfall
  parallelism and once again memoized when disabling waterfall parallelism.
  This is implemented by returning the memoization state to what it was before
  enabling waterfall parallelism.  As such, the user should be aware that any
  changes made to the memoization state while waterfall parallelism is enabled
  will be lost once waterfall parallelism is disabled.~/~/")

(defdoc unsupported-parallelism-features

  ":Doc-Section ACL2::Parallelism

  ACL2 features not supported in ACL2(p)~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].
  ~l[parallelism-tutorial] for an introduction to parallel programming in ACL2.

  For proof features of ACL2 that are not yet supported when parallel
  execution is enabled for the primary ACL2 proof process, generally known as
  ``the waterfall'', ~pl[unsupported-waterfall-parallelism-features].

  Please note that this topic discusses ACL2 features that are disabled when
  using ACL2(p) (~pl[compiling-acl2p]).  These features are disabled
  regardless of whether waterfall parallelism is enabled.

  Calls of ~ilc[observation-cw] simply convert to calls of ~ilc[cw], so
  suppressing ~ilc[observation]s (~pl[set-inhibit-output-lst]) will not
  suppress these messages.

  Memoization is not supported when executing in parallel.
  ~l[Unsupported-waterfall-parallelism-features] for memoization details
  related to waterfall parallelism.

  Since, as of April 2012, garbage collection is inherently sequential, ACL2(p)
  minimizes the use of garbage collection by setting a high garbage collection
  threshold.  As a result, ACL2(p) is not expected to perform well on machines
  with less memory than this threshold (1 gigabyte, as of April 2012).

  In CCL, the underlying parallel execution engine is tuned for the number of
  CPU cores (or hardware threads) actually available in the machine.  SBCL and
  LispWorks are tuned for a machine with 16 CPU cores.

  CCL is considered to be the ``flagship Lisp'' for parallel execution in ACL2.
  The SBCL and LispWorks implementations are thought to be generally stable.
  However, due to their relatively less common use, the SBCL and LispWorks
  implementations are likely less robust than the CCL implementation.

  The ~ilc[time-tracker] utility is a no-op for ACL2(p).~/~/")

(defdoc waterfall-printing

  ":Doc-Section Parallel-proof

  for ACL2(p): configuring the printing within the parallelized waterfall~/

  ~l[set-waterfall-printing].~/~/")

(defdoc waterfall-parallelism

  ":Doc-Section Parallel-proof

  for ACL2(p): configuring the parallel execution of the waterfall~/

  ~l[set-waterfall-parallelism].~/~/")

(defun print-set-waterfall-parallelism-notice (val print-val state)

; Warning: This function should only be called inside the ACL2 loop, because of
; the calls of observation-cw.

  (declare (xargs :guard (and (member-eq val *waterfall-parallelism-values*)
                              (keywordp print-val))))
  (let ((str
         (case val
           ((nil)
            "Disabling parallel execution of the waterfall.")
           (:full
            "Parallelizing the proof of every subgoal.")
           (:top-level
            "Parallelizing the proof of top-level subgoals only.")
           (:pseudo-parallel
            "Running the version of the waterfall prepared for parallel ~
             execution (stateless).  However, we will execute this version of ~
             the waterfall serially.")
           (:resource-and-timing-based
            "Parallelizing the proof of every subgoal that was determined to ~
             take a non-trivial amount of time in a previous proof attempt.")
           (otherwise ; :resource-based
            "Parallelizing the proof of every subgoal, as long as CPU core ~
             resources are available."))))

; Keep the following ending "~%" in sync with set-waterfall-parallelism.

    (observation nil
                 "~@0  Setting waterfall-parallelism to ~s1.  Setting ~
                  waterfall-printing to ~s2 (see :DOC ~
                  set-waterfall-printing).~%"
                 str
                 (symbol-name val)
                 (symbol-name print-val))))

(defun check-for-no-override-hints (ctx state)

; Although this macro is intended for #+acl2-par, we need it unconditionally
; because it is called in set-waterfall-parallelism, which might be called
; outside ACL2(p); see the note about a call of observation in
; set-waterfall-parallelism-fn.

  (let ((wrld (w state)))
    (cond
     ((and (not (cdr (assoc-eq 'hacks-enabled
                               (table-alist 'waterfall-parallelism-table
                                            wrld))))
           (cdr (assoc-eq :override (table-alist 'default-hints-table
                                                 wrld))))
      (er soft ctx

; Override hints must be removed because set-waterfall-parallelism performs a
; defattach, which spawns some proof effort.  If there are override-hints
; available for use during this proof, apply-override-hints will see them and
; attempt to use them.  Since override-hints are not permitted without enabling
; waterfall-parallelism-hacks, in this case, we must cause an error.

          "Before changing the status of waterfall-parallelism, either (1) ~
           override hints must be removed from the default-hints-table or (2) ~
           waterfall-parallelism hacks must be enabled.  (1) can be achieved ~
           by calling ~x0.  (2) can be achived by calling ~x1."
          '(set-override-hints nil)
          '(set-waterfall-parallelism-hacks-enabled t)))
     (t (value nil)))))

(defun set-waterfall-parallelism-fn (val ctx state)
  (prog2$
   (and val

; We avoid a possible hard error, e.g. from (mini-proveall), when parallelism
; and accumulated-persistence are both turned on.  A corresponding bit of code
; is in accumulated-persistence.  We do similarly, just to be safe, for
; forward-chaining-reports; see also set-fc-criteria-fn.

; Warning: Keep the following two wormhole-eval calls in sync with the
; definitions of accumulated-persistence and set-fc-criteria-fn.

        (prog2$ (wormhole-eval 'accumulated-persistence
                               '(lambda (whs) (set-wormhole-data whs nil))
                               nil)
                (wormhole-eval 'fc-wormhole
                               '(lambda (whs)
                                  (set-wormhole-data
                                   whs
                                   (put-assoc-eq :CRITERIA nil (wormhole-data
                                                                whs))))
                               nil)))
   (cond ((eq val (f-get-global 'waterfall-parallelism state))
          (pprogn (observation ctx
                               "Ignoring call to set-waterfall-parallelism ~
                                since the new value is the same as the ~
                                current value.~%~%")
                  (value :ignored)))
         ((member-eq val *waterfall-parallelism-values*)
          (let ((val (if (eq val t) ; t is a alias for :resource-based
                         :resource-based
                       val)))
            #+acl2-par
            (cond
             ((null (f-get-global 'parallel-execution-enabled state))
              (er soft ctx
                  "Parallel execution must be enabled before enabling ~
                   waterfall parallelism.  See :DOC set-parallel-execution"))
             (t
              (pprogn #+(and hons (not acl2-loop-only))
                      (progn
                        (cond ((null val)
                               (acl2h-init-memoizations))
                              (t
                               (acl2h-init-unmemoizations)))
                        state)
                      (f-put-global 'waterfall-parallelism val state)
                      (progn$
                       #-acl2-loop-only
                       (funcall ; avoid undefined function warning
                        'initialize-dmr-interval-used)
                       (value val)))))
            #-acl2-par

; Once upon a time we issued an error here instead of an observation.  In
; response to feedback from Dave Greve, we have changed it to an observation so
; that users can call set-waterfall-parallelism inside books (presumably via
; make-event) without causing their certification to stop when using #-acl2-par
; builds of ACL2.

            (pprogn
             (observation ctx

; We make this an observation instead of a warning, because it's probably
; pretty obvious to the user whether they're using an image that was built with
; the acl2-par feature.

                          "Parallelism can only be enabled in CCL, threaded ~
                           SBCL, or Lispworks.  Additionally, the feature ~
                           :ACL2-PAR must be set when compiling ACL2 (for ~
                           example, by using `make' with argument ~
                           `ACL2_PAR=t'). ~ Either the current Lisp is ~
                           neither CCL nor threaded SBCL nor Lispworks, or ~
                           this feature is missing.  Consequently, this ~
                           attempt to set waterfall-parallelism to ~x0 will ~
                           be ignored.~%~%"
                          val)
             (value :ignored))))
         (t (er soft ctx
                "Illegal value for set-waterfall-parallelism: ~x0.  The legal ~
                 values are ~&1."
                val *waterfall-parallelism-values*)))))

; Parallelism blemish: make a macro via deflast called
; with-waterfall-parallelism that enables waterfall parallelism for a given
; form, in particular an event form like calls of defun and defthm.  It's low
; priority, since it can easily be added as a book later -- though maybe it
; would be nice to have this as an event constructor, like with-output.  But
; while doing proofs with ACL2(hp), Rager would have found this convenient.

(defmacro set-waterfall-parallelism1 (val)
  `(let* ((val ,val)
          (ctx 'set-waterfall-parallelism))
     (er-progn
      (check-for-no-override-hints ctx state)
      (er-let* ((val (set-waterfall-parallelism-fn val ctx state)))
               (cond ((eq val :ignored)
                      (value val))
                     (t (let ((print-val
                               (waterfall-printing-value-for-parallelism-value
                                val)))
                          (pprogn
                           (print-set-waterfall-parallelism-notice
                            val print-val state)
                           (er-progn
                            (set-waterfall-printing-fn print-val ctx state)
                            (value (list val print-val)))))))))))

(table saved-memoize-table nil nil
       :guard

; It is tempting to install a table guard of (memoize-table-chk key val world).
; However, that won't work, for example because it will prohibit adding an
; entry to this table for a function that is currently memoized -- an act that
; is the point of this table!  So instead we rely solely on the checks done
; when putting entries in memoize-table.

       t)

(defmacro save-memo-table ()
  '(with-output
    :off (summary event)
    (table saved-memoize-table
           nil
           (table-alist 'memoize-table world)
           :clear)))

(defun clear-memo-table-events (alist acc)
  (declare (xargs :guard (true-list-listp alist)))
  (cond ((endp alist) acc)
        (t (clear-memo-table-events
            (cdr alist)
            (cons `(table memoize-table ',(caar alist) nil)
                  acc)))))

(defmacro clear-memo-table ()
  `(with-output
    :off (summary event)
    (make-event
     (let ((alist (table-alist 'memoize-table (w state))))
       (cons 'progn
             (clear-memo-table-events alist nil))))))

(defmacro save-and-clear-memoization-settings ()

  ":Doc-Section Events

  save and remove the current memoization settings~/

  For background on memoization, ~pl[memoize].

  ~bv[]
  General Form:
  (save-and-clear-memoization-settings)
  ~ev[]

  Calls of this macro achieve two changes.  The first copies the current
  memoization settings into an ACL2 ~il[table], and the second unmemoizes all
  functions that were memoized by calls of ~ilc[memoize].  Also
  ~pl[restore-memoization-settings].~/~/

  :cite hons-and-memoization
  :cited-by hons-and-memoization"

  '(with-output
    :off (summary event)
    (progn (save-memo-table)
           (clear-memo-table))))

(defun set-memo-table-events (alist acc)
  (declare (xargs :guard (true-list-listp alist)))
  (cond ((endp alist) acc)
        (t (set-memo-table-events
            (cdr alist)
            (cons `(table memoize-table ',(caar alist) ',(cdar alist))
                  acc)))))

(defmacro restore-memoization-settings ()

  ":Doc-Section Events

  restore the saved memoization settings~/

  For background on memoization, ~pl[memoize].

  ~bv[]
  General Form:
  (restore-memoization-settings)
  ~ev[]

  Calls of this macro restore the memoization settings saved by
  ~ilc[save-and-clear-memoization-settings].~/~/

  :cite hons-and-memoization
  :cited-by hons-and-memoization"

  `(with-output
    :off (summary event)
    (make-event
     (let ((alist (table-alist 'saved-memoize-table (w state))))
       (cons 'progn
             (set-memo-table-events alist nil))))))

(defmacro set-waterfall-parallelism (val)

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): configuring the parallel execution of the waterfall~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  General Forms:
  (set-waterfall-parallelism nil)        ; never parallelize (serial execution)
  (set-waterfall-parallelism :full)      ; always parallelize
  (set-waterfall-parallelism :top-level) ; parallelize top-level subgoals
  (set-waterfall-parallelism             ; parallelize if sufficient resources
    :resource-based)                     ;   (recommended setting)
  (set-waterfall-parallelism t)          ; alias for :resource-based
  (set-waterfall-parallelism             ; parallelize if sufficient resources
    :resource-and-timing-based           ;   and suggested by prior attempts
  (set-waterfall-parallelism             ; never parallelize but use parallel
    :pseudo-parallel)                    ;   code base (a debug mode)
  ~ev[]
  ~/

  ~c[Set-waterfall-parallelism] evaluates its argument, which specifies the
  enabling or disabling of the ~il[parallel] execution of ACL2's main proof
  process, the waterfall.

  It also sets ~il[state] global ~c[waterfall-printing] to an appropriate
  value.  ~l[set-waterfall-printing].

  Note that not all ACL2 features are supported when waterfall-parallelism is
  set to non-~c[nil] (~pl[unsupported-waterfall-parallelism-features]).

  A value of ~c[t] is treated the same as a value of ~c[:resource-based] and
  is provided for user convenience.

  ~c[:Resource-based] waterfall parallelism typically achieves the best
  performance in ACL2(p), while maintaining system stability, so
  ~c[:resource-based] (or equivalently, ~c[t]) is the recommended value.

  A value of ~c[nil] indicates that ACL2(p) should never prove subgoals in
  parallel.

  A value of ~c[:full] indicates that ACL2(p) should always prove independent
  subgoals in parallel.

  A value of ~c[:top-level] indicates that ACL2(p) should prove each of the
  top-level subgoals in parallel but otherwise prove subgoals in a serial
  manner.  This mode is useful when the user knows that there are enough
  top-level subgoals, many of which take a non-trivial amount of time to be
  proved, such that proving them in parallel will result in a useful reduction
  in overall proof time.

  A value of ~c[:resource-based] (or equivalently, ~c[t]) indicates that
  ACL2(p) should use its built-in heuristics to determine whether CPU core
  resources are available for parallel execution.  Note that ACL2(p) does not
  hook into the operating system to determine the workload on the machine.
  ACL2(p) works off the assumption that it is the only process using
  significant CPU resources, and it optimizes the amount of parallelism based
  on the number of CPU cores in the system.  (Note that ACL2(p) knows how to
  obtain the number of CPU cores from the operating system in CCL, but that, in
  SBCL and in Lispworks, a constant is used instead).

  During the first proof attempt of a given conjecture, a value of
  ~c[:resource-and-timing-based] results in the same behavior as with
  ~c[:resource-based].  However, on subsequent proof attempts, the time it took
  to prove each subgoal will be considered when deciding whether to parallelize
  execution.  If a particular theorem's proof is already achieving satisfactory
  speedup via ~c[:resource-based] parallelism, there is no reason to try this
  setting.  However, if the user wishes to experiment, the
  ~c[:resource-and-timing-based] setting may improve performance.  Note that
  since the initial run does not have the subgoal proof times available, this
  mode will never be better than the ~c[:resource-based] setting for
  non-interactive theorem proving.

  A value of ~c[:pseudo-parallel] results in using the parallel waterfall code,
  but with serial execution.  This setting is useful for debugging the code
  base that supports parallel execution of the waterfall.  For example, you may
  wish to use this mode if you are an ``ACL2 Hacker'' who would like to see
  comprehensible output from tracing (~pl[trace$]) the ~c[@par] versions of the
  waterfall functions.

  The following remark pertains to those using the `HONS' experimental
  extension of ACL2 (~pl[hons-and-memoization]; in particular, ~pl[memoize]).
  Since memoization is not supported when waterfall parallelism is enabled
  (~pl[unsupported-waterfall-parallelism-features]), then when
  ~c[set-waterfall-parallelism] is called with a non-~c[nil] value, all
  memoized functions are unmemoized.  When ~c[set-waterfall-parallelism] is
  again called with a ~c[nil] value, those memoization settings are restored.

  ~c[Set-waterfall-parallelism] is an embedded event form.  However, a call of
  this macro will not affect waterfall-parallelism when including a certified
  book that contains that call.  For such an effect, you may use the following
  ~ilc[make-event] form.
  ~bv[]
  (make-event (er-progn (set-waterfall-parallelism :full)
                        (value '(value-triple nil)))
              :check-expansion t)
  ~ev[]

  To enable waterfall parallelism for book certification using ACL2(p),
  ~pl[waterfall-parallelism-for-book-certification].~/

  :cited-by parallel-proof"

  `(with-output
    :off (summary event)
    (make-event
     (let ((old-val (f-get-global 'waterfall-parallelism state)))
       (declare (ignorable old-val))
       (er-let*
        ((new-val (set-waterfall-parallelism1 ,val)))
        (cond
         ((eq new-val :IGNORED)
          (value '(value-triple :IGNORED)))
         #+hons
         ((and (null old-val) (car new-val))
          (pprogn
           (observation
            'set-waterfall-parallelism

; Here and below, we start with a "~%" so that the messages printed when
; enabling and disabling waterfall parallelism have the same amount of space
; between the messages and the return value.  This "~%" is paired with the one
; at the end of the observation in print-set-waterfall-parallelism-notice.

            "~%Unmemoizing the functions that are memoized by default as part ~
             of ACL2(h) and all that have been memoized by calling memoize ~
             (see :DOC unsupported-waterfall-parallelism-features).~%")

; The functions that are memoized by default as part of hons are
; memoized/unmemoized inside set-waterfall-parallelism-fn.  We do it there,
; instead of as part of this macro, because those memoizations only occur in
; raw Lisp and have nothing to do with table events.  Since this macro is an
; ACL2-loop macro, it does not have access to acl2h-init-memoizations and
; acl2h-init-unmemoizations.

           (value '(save-and-clear-memoization-settings))))
         #+hons
         ((and old-val (null (car new-val)))
          (pprogn
           (observation
            'set-waterfall-parallelism
            "~%Memoizing the functions that are memoized by default as part ~
             of ACL2(h) and that were memoized before disabling ~
             waterfall-parallelism (see :DOC ~
             unsupported-waterfall-parallelism-features).~%")
           (value'(restore-memoization-settings))))
         (t (value '(value-triple nil)))))))))

(defdoc waterfall-parallelism-for-book-certification

  ":Doc-Section Parallelism

  for ACL2(p): using waterfall parallelism during book certification~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  There are books whose certification can be sped up significantly by using
  waterfall parallelism.  (~l[parallelism], including the caveat in its
  \"IMPORTANT NOTE\".)  One such example in the ACL2 community books is
  ~c[models/jvm/m5/apprentice.lisp], which is typically excluded from
  regressions because of how long it takes to certify.  In order to use
  waterfall parallelism during certification of a book ~c[<book-name>.lisp]
  using `make' (~pl[books-certification] and ~pl[books-certification-classic]),
  we recommend creating a file ~c[<book-name>.acl2] that includes the following
  forms.

  ~bv[]
  #+acl2-par
  (set-waterfall-parallelism t)

  (certify-book <book-name> ? t) ; other arguments may be preferable
  ~ev[]

  Note that there are books that will not certify when waterfall-parallelism is
  enabled.  See file ~c[acl2-customization-files/README] for more information,
  including how to certify essentially all books using waterfall
  parallelism.~/~/")

(defun set-waterfall-printing-fn (val ctx state)
  (cond ((member-eq val *waterfall-printing-values*)
         #+acl2-par
         (pprogn (f-put-global 'waterfall-printing val state)
                 (value val))
         #-acl2-par

; See note about making this an observation instead of an error inside
; set-waterfall-parallelism.

         (pprogn (observation ctx
                              "Customizing waterfall printing only makes ~
                               sense in the #+acl2-par builds of ACL2.  ~
                               Consequently, this attempt to set ~
                               waterfall-printing to ~x0 will be ignored.~%~%"
                              val)
                 (value :invisible)))
        (t (er soft ctx
               "Illegal value for set-waterfall-printing: ~x0.  The legal ~
                values are ~&1."
               val *waterfall-printing-values*))))

(defmacro set-waterfall-printing (val)

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): configuring the printing that occurs within the parallelized waterfall~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  General Forms:
  (set-waterfall-printing :full)    ; print everything
  (set-waterfall-printing :limited) ; print a subset that's thought to be useful
  (set-waterfall-printing :very-limited) ; print an even smaller subset
  ~ev[]
  ~/

  ~c[Set-waterfall-printing] evaluates its argument, which indicates how much
  printing should occur when executing ACL2 with the parallelized version of
  the waterfall.  It only affects the printing that occurs when parallelism
  mode is enabled for the waterfall (~pl[set-waterfall-parallelism]).

  A value of ~c[:full] is intended to print the same output as in serial mode.
  This output will be interleaved unless the waterfall-parallelism mode is one
  of ~c[nil] or ~c[:pseudo-parallel].

  A value of ~c[:limited] omits most of the output that occurs in the serial
  version of the waterfall.  Instead, the proof attempt prints key
  checkpoints (~pl[acl2p-key-checkpoints]).  The value of ~c[:limited] also
  prints messages that indicate which subgoal is currently being proved, along
  with the wall-clock time elapsed since the theorem began its proof; and if
  state global ~c['waterfall-printing-when-finished] has a non-~c[nil] value,
  then such a message will also be printed at the completion of each subgoal.
  The function ~c[print-clause-id-okp] may receive an attachment to limit such
  printing; ~pl[set-print-clause-ids].  Naturally, these subgoal numbers can
  appear out of order, because the subgoals can be proved in parallel.

  A value of ~c[:very-limited] is treated the same as ~c[:limited], except that
  instead of printing subgoal numbers, the proof attempt prints a
  period (`~c[.]') each time it starts a new subgoal.

  Note that this form cannot be used at the top level of a book, or of a
  ~ilc[progn] or ~ilc[encapsulate] event.  Here is a workaround for use in such
  contexts; of course, you may replace ~c[:very-limited] with any other legal
  argument for ~c[set-waterfall-printing].
  ~bv[]
  (make-event (er-progn (set-waterfall-printing :very-limited)
                        (value '(value-triple nil))))
  ~ev[]
  (For more about event contexts and the use of ~c[make-event],
  ~pl[make-event], in particular the section ``Restriction to Event
  Contexts.'')

  The following form has the effect described above, except that it will affect
  waterfall-printing even when including a certified book that contains it.
  ~bv[]
  (make-event (er-progn (set-waterfall-printing :very-limited)
                        (value '(value-triple nil)))
              :check-expansion t)
  ~ev[]

  Note that ~c[set-waterfall-printing] is automatically called by
  ~ilc[set-waterfall-parallelism].

  To enable the printing of information when a subgoal is finished, assign a
  non-~c[nil] value to global ~c[waterfall-printing-when-finished].  This can
  be accomplished by entering the following at the top level:
  ~bv[]
  (f-put-global 'waterfall-printing-when-finished t state)
  ~ev[]
  ~/

  :cited-by parallel-proof"

  `(set-waterfall-printing-fn ,val 'set-waterfall-printing state))

(defun set-waterfall-parallelism-hacks-enabled-guard (wrld)
  (or (ttag wrld)
      (er hard nil
          "Using waterfall parallelism hacks requires an active trust-tag. ~
           Consider using (set-waterfall-parallelism-hacks-enabled! t).  See ~
           :DOC set-waterfall-parallelism-hacks-enabled for~ more~ ~
           information.")))

(table waterfall-parallelism-table
       nil nil :guard (set-waterfall-parallelism-hacks-enabled-guard world))

(defmacro set-waterfall-parallelism-hacks-enabled (val)

; One might consider using a state global to implement
; set-waterfall-parallelism-hacks-enabled.  But as David Rager points out, this
; macro can change whether or not a proof completes.  So, we want this macro
; tied into the undoing mechanism; hence we use a table event.

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): enable waterfall-parallelism hacks~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  General Forms:
  (set-waterfall-parallelism-hacks-enabled t)
  (set-waterfall-parallelism-hacks-enabled nil)
  ~ev[]~/

  Some features (e.g., ~il[override-hints] and ~il[clause-processor]s) of
  serial ACL2 are by default not available in ACL2(p) with waterfall
  parallelism enabled, because they offer a mechanism to modify ~il[state] that
  is unsound.  To allow or (once again) disallow the use the these features in
  ACL2(p), call ~c[set-waterfall-parallelism-hacks-enabled] with argument ~c[t]
  or ~c[nil], respectively.

  ~c[Set-waterfall-parallelism-hacks-enabled] requires the use of a trust tag
  (~pl[defttag]).  One can call ~ilc[set-waterfall-parallelism-hacks-enabled!]
  instead, which will automatically install a trust tag named
  ~c[:waterfall-parallelism-hacks].

  ~l[error-triples-and-parallelism] for further related discussion.~/
  :cited-by parallel-proof"

  (declare (xargs :guard (or (equal val t) (null val))))
  `(table waterfall-parallelism-table 'hacks-enabled ,val))

(defmacro set-waterfall-parallelism-hacks-enabled! (val)

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): enabling waterfall parallelism hacks~/

  ~l[set-waterfall-parallelism-hacks-enabled].~/~/
  :cited-by parallel-proof"

  `(encapsulate
    ()

; Parallelism blemish: the following installation of ttag
; :waterfall-parallelism-hacks should probably be conditionalized upon val
; being equal to t.  Furthermore, perhaps the installation should also be
; conditionalized upon the non-existence of a prior ttag.

    (defttag :waterfall-parallelism-hacks)
    (set-waterfall-parallelism-hacks-enabled ,val)))

(defdoc parallelism-at-the-top-level

  ":Doc-Section Parallel-programming

  parallel execution in the ACL2 top-level loop~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  Calls of parallelism primitives made explicitly in the ACL2 top-level loop,
  as opposed to inside function bodies, will never cause parallel execution.
  Such calls will either execute with serial execution or will cause an error;
  ~pl[set-parallel-execution].  For a way around this restriction,
  ~pl[top-level].~/

  Consider for example the following call of ~ilc[pargs] in the ACL2
  top-level loop.  Instead of executing ~c[pargs], ACL2 macroexpands away this
  call, leaving us with serial execution of the arguments to the ~ilc[cons]
  call, or else causes an error (~pl[set-parallel-execution]).  If there is no
  error, then
  ~bv[]
  (pargs (cons (expensive-fn-1 4) (expensive-fn-2 5)))
  ~ev[]
  expands into:
  ~bv[]
  (cons (expensive-fn-1 4) (expensive-fn-2 5))
  ~ev[]

  One trivial way to enable parallel execution of a form is to surround it
  with a call to macro ~il[top-level].  Consider the following example.
  ~bv[]
  (top-level (pargs (cons (expensive-fn-1 4) (expensive-fn-2 5))))
  ~ev[]
  Then in an executable image that supports parallel execution ~-[]
  ~pl[compiling-acl2p] for instructions on how to build such an executable
  ~-[] ~c[(expensive-fn-1 4)] and ~c[(expensive-fn-2 5)] can evaluate in
  parallel.

  A second way to enable parallel execution of a form is to place it
  inside a function body.  For example, consider the following definition.
  ~bv[]
  (defun foo (x y)
    (pargs (cons (expensive-fn-1 x) (expensive-fn-2 y))))
  ~ev[]
  Then in an executable image that supports parallel execution, submission of
  the form ~c[(foo 4 5)] can cause parallel execution of
  ~c[(expensive-fn-1 4)] and ~c[(expensive-fn-2 5)].

  Note that ~il[guard]s need not be verified in order to obtain ~il[parallel]
  execution.  The only restrictions on parallel execution are to use an
  executable supporting it, to avoid calling parallelism primitives directly in
  the top-level loop, to have sufficient resources (especially, threads)
  available, and to avoid explicitly disabling parallel execution
  (~pl[set-parallel-execution]).~/")

(defdoc parallelism-tutorial
  ":Doc-Section Parallel-programming

  a tutorial on how to use the parallelism library.~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  In this topic we introduce the ACL2 parallelism primitives using the example
  of a doubly-recursive Fibonacci function, whose basic definition is as
  follows.  ~l[parallelism] for a very high-level summary of the parallelism
  capability described here, and ~pl[compiling-acl2p] for how to build an
  executable image that supports parallel execution.  Here, we assume that
  such an executable is being used.~/

  ~b[Serial Fibonacci]

  ~bv[]
  (defun fib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (+ (fib (- x 1)) (fib (- x 2))))))
  ~ev[]

  ~b[Introducing] ~ilc[Pargs]

  A simple way to introduce parallelism into this function definition is to
  wrap the addition expression with a call of ~ilc[pargs], and the arguments to
  the addition will be computed in parallel whenever resources are available.
  As a result, we end up with a very similar and thus intuitive function
  definition.  Note that we replaced ~ilc[+] by ~ilc[binary-+], since
  ~ilc[pargs] expects a function call, not a macro call.
  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (pargs (binary-+ (pfib (- x 1))
                              (pfib (- x 2)))))))
  ~ev[]

  ~b[Introducing the Granularity Problem]

  After you submit the above two versions of the Fibonacci function, test them
  with the following forms.
  ~bv[]
  (time$ (fib 10))
  (time$ (pfib 10))
  ~ev[]
  Now increase the argument by increments of 5 to 10 until you find your
  curiosity satisfied or your patience wearing thin.  You can interrupt
  evaluation if necessary and return to the ACL2 loop.  You will immediately
  notice that you have not increased execution speed, at least not by much, by
  introducing parallelism.

  First, consider the computation of ~c[(pfib 4)].  Assuming resources are
  available, ~c[(pfib 4)] will create a thread for computing ~c[(pfib 3)] and
  another thread for ~c[(pfib 2)].  It is easy to imagine that setting up each
  thread takes much longer than the entire computation of ~c[(fib 4)].

  Second, we must realize that if we have two threads available for computing
  ~c[(fib 10)], then the evaluation of ~c[(fib 8)] will probably complete
  before the evaluation of ~c[(fib 9)].  Once ~c[(fib 8)] finishes, parallelism
  resources will become available for the next recursive call made on behalf of
  ~c[(fib 9)].  If for example that call is ~c[(fib 3)], we will waste a lot of
  cycles just handing work to the thread that does this relatively small
  computation.  We need a way to ensure that parallelism resources are only
  used on problems of a \"large\" size.  Ensuring that only \"large\" problems
  are spawned is called the ``granularity problem.''

  In summary: We want to tell ACL2 that it can evaluate the arguments of
  ~ilc[pargs] in parallel only when the parameter of ~c[pfib] is greater
  than some threshold.  Our tests using CCL have suggested that 27 is a
  reasonable threshold.

  ~b[Explicit Programming for the Granularity Problem]

  One way to avoid the granularity problem is to duplicate code as follows.
  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (if (> x 27) ; the granularity test
                 (pargs (binary-+ (pfib (- x 1))
                                  (pfib (- x 2))))
               (binary-+ (pfib (- x 1))
                         (pfib (- x 2)))))))
  ~ev[]
  Duplicating code is fundamentally a bad design principle, because it can
  double the work for future maintenance.  A ``granularity form'' is an
  expression
  ~bv[]
  (declare (granularity <form>))
  ~ev[]
  that can allow threads to be spawned (without duplicating code) whenever the
  evaluation of ~c[<form>] results in a non-~c[nil] value.  It may be placed
  inside any call of a parallelism primitive, in a position documentated
  separately for each primitive.  Here is a definition of ~c[pfib] using this
  feature for a call of the parallelism primitive ~ilc[pargs].
  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (pargs
              (declare (granularity (> x 27)))
              (binary-+ (pfib (- x 1))
                        (pfib (- x 2)))))))
  ~ev[]

  Test each version as follows (or substitute your own natural number for 33).
  ~bv[]
    (time$ (fib 33))
    (time$ (pfib 33))
  ~ev[]

  ~b[Another Granularity Issue Related to Thread Limitations]

  Our implementation of parallelism primitives has the property that once a
  thread is assigned a computation, that assignment stays in effect until the
  computation is complete.  In particular, if a thread encounters a parallelism
  primitive that spawns child threads, the parent thread stays assigned,
  waiting until the child computations complete before it can continue its own
  computation.  In the meantime, the parent thread reduces the number of
  additional threads that Lisp can provide by 1, rather than being reassigned
  to do other work.

  How can this lack of reassignment affect the user?  Consider, for example,
  the application of a recursive function to a long list.  Imagine that this
  function is written so that the body contains a recursive call, for example
  as ~c[(pargs (process (car x)) (recur (cdr x)))].  Each such ~ilc[pargs] call
  that spawns child work must wait for its children, one of which is the work
  of evaluating ~c[(recur (cdr x))], to complete.  There is an ACL2 limit on
  how much pending work can be in the system, limiting the number of
  ~ilc[pargs] calls that can result in parallel execution.  For example, if
  the ACL2 limit is k and each call of ~ilc[pargs] actually spawns threads for
  evaluating  its arguments, then
  after k ~c[cdr]s there will be no further parallel execution.

  Possible solutions may include reworking of algorithms (for example to be
  tree-based rather than list-based) or using appropriate granularity forms.
  We hope that future implementations will allow thread ``re-deployment'' in
  order to mitigate this problem.  This problem applies to ~ilc[plet],
  ~ilc[pargs], ~ilc[pand], ~ilc[por], and ~ilc[spec-mv-let].

  ~b[Introducing] ~ilc[Plet]

  We can use a ~ilc[let] binding to compute the recursive calls of ~c[fib] and
  then add the bound variables together, as follows.
  ~bv[]
  (defun fib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (let ((a (fib (- x 1)))
                   (b (fib (- x 2))))
               (+ a b)))))
  ~ev[]

  By using the parallelism primitive ~ilc[plet], we can introduce parallelism
  much as we did using ~ilc[pargs], with an optional granularity form, as
  follows.
  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (plet
              (declare (granularity (> x 27)))
              ((a (pfib (- x 1)))
               (b (pfib (- x 2))))
              (+ a b)))))
  ~ev[]
  Notice that this time, we were able to use ~c[+] rather than being forced to
  use ~c[binary-+].  Unlike ~ilc[pargs], which expects a function call (not a
  macro call), ~ilc[plet] allows macros at the top level of its body.

  ~b[Introducing] ~ilc[Pand] (By Way of a Tree Validation Example)

  Consider ``genetic trees'' that contains leaves of DNA elements, in the sense
  that each tip is one of the symbols ~c[A], ~c[G], ~c[C], or ~c[T].  First we
  define the function ~c[valid-tip] which recognizes whether a tip contains one
  of these symbols.
  ~bv[]
  (defun valid-tip (tip)
    (declare (xargs :guard t))
    (or (eq tip 'A)
        (eq tip 'G)
        (eq tip 'C)
        (eq tip 'T)))
  ~ev[]

  Now we define a function that traverses the tree, checking that every tip is
  valid.
  ~bv[]
  (defun valid-tree-serial (tree)
    (declare (xargs :guard t))
    (if (atom tree)
        (valid-tip tree)
      (and (valid-tree-serial (car tree))
           (valid-tree-serial (cdr tree)))))
  ~ev[]

  We also define a parallel version.
  ~bv[]
  (defun valid-tree-parallel (tree)
    (declare (xargs :guard t))
    (if (atom tree)
        (valid-tip tree)
      (pand (valid-tree-parallel (car tree))
            (valid-tree-parallel (cdr tree)))))
  ~ev[]

  Before we can time the functions, we need to create test trees.  We have
  found that test trees need to be approximately 1 gigabyte before we clearly
  see speedup, and we make them asymmetric to demonstrate the ability of our
  implementation to adapt to asymmetric data.  We can create the trees with the
  execution of the following forms.
  ~bv[]
  (defun make-valid-binary-tree (x)
    (declare (xargs :mode :program))
    (if (< x 0)
        (cons (cons 'C 'G) (cons 'A 'T))
      (cons (make-valid-binary-tree (- x 2)) ; 2 to make asymmetric
            (make-valid-binary-tree (- x 1)))))

  (defconst *valid-tree* (make-valid-binary-tree 30)) ; takes awhile
  (defconst *invalid-tree* (cons *valid-tree* nil)) ; nil is invalid tip
  ~ev[]

  We can time our functions with the forms:
  ~bv[]
  (time$ (valid-tree-serial *valid-tree*))
  (time$ (valid-tree-parallel *valid-tree*))
  ~ev[]
  Unfortunately, the serial version runs faster than the parallelism version;
  however, there is more to this story.

  ~b[Demonstrating Early Termination with an Invalid Tree]

  Now observe this magic:
  ~bv[]
  (time$ (valid-tree-serial   *invalid-tree*))
  (time$ (valid-tree-parallel *invalid-tree*))
  ~ev[]
  The serial version took awhile, while the parallel version finished almost
  immediately.  The test for validation was split into testing the ~ilc[car]
  and the ~ilc[cdr] of the ~c[*invalid-tree*] root, and since the ~c[cdr] was
  equal to ~c[nil], its test returned immediately.  This immediate return
  quickly interrupted the computation associated with the ~c[car], and returned
  the result.

  ~b[Granularity with] ~ilc[Pand]

  We can also define a parallel version with a granularity form:
  ~bv[]
  (defun valid-tree-parallel (tree depth)
    (declare (xargs :guard (natp depth)))
    (if (atom tree)
        (valid-tip tree)
      (pand
       (declare (granularity (< depth 5)))
       (valid-tree-parallel (car tree) (1+ depth))
       (valid-tree-parallel (cdr tree) (1+ depth)))))
  ~ev[]

  We can test this form by executing our previous forms.  You will probably
  find some speedup on a machine with several cores available, but more speedup
  can likely be obtained with an expensive test on the leaves in place of
  ~c[valid-tip].
  ~bv[]
  (time$ (valid-tree-serial   *valid-tree*))
  (time$ (valid-tree-parallel *valid-tree* 0))
  ~ev[]

  ~b[Introducing] ~ilc[Por]

  ~ilc[Por] can be used in the same way as ~ilc[pand], but with early
  termination occurring when an argument evaluates to a non-~c[nil] value, in
  which case the value returned is ~c[t].  Finally, ~ilc[por] also supports the
  use of a ~il[granularity] form.~/")

(defdoc granularity
  ":Doc-Section Parallel-programming
  limit the amount of parallelism~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  Some function calls are on arguments whose evaluation time is long enough to
  warrant parallel execution, while others are not.  A granularity form can be
  used to make appropriate restrictions on the use of parallelism.~/

  For example, consider the Fibonacci function.  Experiments have suggested
  that execution time can be reduced if whenever the argument is less than 27,
  a serial version of the Fibonacci function is called.  One way to utilize
  this information is to write two definitions of the Fibonacci function, one
  serial and one parallel.
  ~bv[]
  (defun fib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (binary-+ (fib (- x 1))
                       (fib (- x 2))))))

  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          ((< x 27) (binary-+ (fib (- x 1))
                              (fib (- x 2))))
          (t (pargs (binary-+ (pfib (- x 1))
                              (pfib (- x 2)))))))
  ~ev[]
  We realize quickly that writing both of these function definitions is
  cumbersome and redundant.  This problem can be avoided by using a
  ~c[granularity] declaration with a parallelism primitive.  This form ensures
  that a call is parallelized only if resources are available and the
  granularity form evaluates to a non-~c[nil] value at the time of the call.
  Below is a definition of the Fibonacci function using a granularity form.
  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((or (zp x) (<= x 0)) 0)
          ((= x 1) 1)
          (t (pargs (declare (granularity (>= x 27)))
                    (binary-+ (pfib (- x 1))
                              (pfib (- x 2)))))))
  ~ev[]

  A granularity form can reference an extra formal parameter that describes the
  call depth of the function the user is parallelizing.  Consider for example
  the following parallel ~c[mergesort] function, based on Davis's Ordered Sets
  library.  It splits the data into symmetric chunks for computation, so we
  increment the ~c[depth] argument during the recursive call on both the
  ~c[car] and ~c[cdr].
  ~bv[]
  (include-book \"finite-set-theory/osets/sets\" :dir :system)
  (defun sets::pmergesort-exec (x depth)
    (declare (xargs :mode :program))
    (cond ((endp x) nil)
          ((endp (cdr x)) (sets::insert (car x) nil))
          (t (mv-let (part1 part2)
                     (sets::split-list x nil nil)
                     (pargs
                      (declare (granularity (< depth 2)))
                      (sets::union (sets::pmergesort-exec part1
                                                          (1+ depth))
                                   (sets::pmergesort-exec part2
                                                          (1+ depth))))))))
  ~ev[]

  A less intrusive method (i.e., not requiring an extra formal parameter like
  the ~c[depth] argument just above), which however can be less efficient,
  involves analyzing the data itself for structural properties.  For example:
  ~bv[]
  (defun some-depth-exceeds (x n)
    (declare (xargs :guard (natp n)))
    (if (atom x)
        nil
      (if (zp n)
          t
        (or (some-depth-exceeds (car x) (1- n))
            (some-depth-exceeds (cdr x) (1- n))))))

  (defun valid-tip (x)
    (declare (xargs :guard t))
    (or (eq x 'A)
        (eq x 'T)
        (eq x 'C)
        (eq x 'G)))

  (defun pvalid-tree (x)
    (declare (xargs :guard t))
    (if (atom x)
        (valid-tip x)
      (pand (declare (granularity (some-depth-exceeds x 3)))
            (pvalid-tree (car x))
            (pvalid-tree (cdr x)))))
  ~ev[]
  If you experiment with calls of ~c[pvalid-tree], you are likely to find that
  the ``speedup'' it provides over a corresponding serial version is, in fact,
  a slowdown!  The problem is likely that ~c[some-depth-exceeds] is an
  expensive function to run repeatedly.  Instead of the approach above, it is
  often handy to add an extra formal parameter in order to allow for more
  efficient granularity forms, as we have done above in the definition of
  ~c[SETS::pmergesort-exec].
  ~/")

(defdoc parallelism-performance
  ":Doc-Section Parallel-programming
  performance issues for parallel execution~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~l[granularity] for an important construct that limits the spawning of
  parallel computations, which can be important when a computation is too
  short-lived to warrant a separate thread.

  There are times in which parallelism provides no speedup because of garbage
  collection in the underlying Lisp implementation.  The following example
  illustrates this phenomenon.  If you change the ~ilc[granularity] declaration
  so that the depth bound is 3, 4, or larger instead of 2, you may still find
  no speedup.  In all cases you may find that parallelism results in a
  significantly greater time spent in garbage collection.
  ~bv[]
  (include-book \"finite-set-theory/osets/sets\" :dir :system)
  (defun sets::pmergesort-exec (x depth)
      (declare (xargs :mode :program))
      (cond ((endp x) nil)
            ((endp (cdr x)) (sets::insert (car x) nil))
            (t (mv-let (part1 part2)
                       (sets::split-list x nil nil)
                       (pargs
                        (declare (granularity (< depth 2)))
                        (sets::union (sets::pmergesort-exec part1
                                                            (1+ depth))
                                     (sets::pmergesort-exec part2
                                                            (1+ depth))))))))
  (defconst *x* (reverse (fromto 1 400000)))
  (time$ (length (sets::pmergesort-exec *x* 0)))
  (set-parallel-execution nil)
  (time$ (length (sets::pmergesort-exec *x* 0)))
  ~ev[]~/~/")

(defdoc early-termination
  ":Doc-Section Parallel-programming
  early termination for ~ilc[pand] and ~ilc[por].~/~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  The evaluation of ~c[(and expr1 expr2)] returns ~c[nil] if ~c[expr1]
  evaluates to ~c[nil], avoiding the evaluation of ~c[expr2].  More generally,
  the evaluation of ~c[(and expr1 expr2 ... exprk)] terminates with a return
  value of ~c[nil] as soon as any ~c[expri] evaluates to ~c[nil] ~-[] no
  ~c[exprj] is evaluated in this case for ~c[j > i].  This so-called ``lazy
  evaluation'' of ~ilc[and] terms can thus save some computation; roughly
  speaking, the smaller the ~c[i], the more computation is saved.

  If the above call of ~ilc[and] is replaced by its parallel version,
  ~ilc[pand], then there can be even more opportunity for skipping work.  The
  arguments to ~ilc[pand] can be evaluated in parallel, in which case the first
  such evaluation that returns with a value of ~c[nil], if any, causes the
  remaining such evaluations to abort.

  Consider the following functions that compute whether a tree is valid
  (~pl[granularity] for a discussion of the granularity form).
  ~bv[]
  (defun valid-tip (x)
    (declare (xargs :guard t))
    (or (eq x 'A)
        (eq x 'T)
        (eq x 'C)
        (eq x 'G)))

  (defun pvalid-tree (x depth)
    (declare (xargs :guard (natp depth)))
    (if (atom x)
        (valid-tip x)
      (pand (declare (granularity (< depth 10)))
            (pvalid-tree (car x) (1+ depth))
            (pvalid-tree (cdr x) (1+ depth)))))
  ~ev[]

  We would like to stop execution as soon as any tip is found to be invalid.
  So, when computing the conjunction of terms by using ~ilc[pand], once one of
  those terms evaluates to ~c[nil], the computations for the other terms are
  aborted and the ~ilc[pand] call returns ~c[nil].  By using ~ilc[pand], we can
  in principle attain a speedup factor greater than the number of available
  cores.

  The concept of early termination also applies to ~ilc[por], except that early
  termination occurs when an argument evaluates to non-~c[nil].~/")

(defdoc parallel-pushing-of-subgoals-for-induction

  ":Doc-Section Parallel-proof
  consequences of how parallelized proofs of subgoals are pushed for induction~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  The following discussion, concerning the naming of subgoals pushed for proof
  by induction and the timeliness of aborting when two or more goals are pushed
  for proof by induction, only applies when waterfall parallelism is enabled
  (~pl[set-waterfall-parallelism]).~/

  When two sibling subgoals (e.g. 4.5 and 4.6) both push goals to be proved by
  induction (e.g., 4.6 pushes *1 and 4.5 pushes *2), a name is assigned to the
  second pushed subgoal (e.g., *2) as if the first push hasn't happened (e.g.,
  *2 is mistakenly called *1).  In such a case, we say what the name _could_
  be.  The following non-theorem illustrates how this works.
  ~bv[]
  (set-waterfall-parallelism :full)
  (thm (equal (append (car (cons x x)) y z) (append x x y)))
  ~ev[]

  There is another consequence of the way the parallelized waterfall pushes
  subgoals for proof by induction.  Without waterfall parallelism enabled, ACL2
  sometimes decides to abort instead of pushing a goal for later proof by
  induction, preferring instead to induct on the original conjecture.  But with
  waterfall parallelism enabled, the prover no longer necessarily immediately
  aborts to prove the original conjecture.  Suppose for example that sibling
  subgoals, Subgoal 4.6 and Subgoal 4.5, each push a subgoal for induction.  If
  the waterfall is performing the proof of each of these subgoals in parallel,
  the proof will no longer abort immediately after the second push occurs, that
  is at Subgoal 4.5.  As a result, the prover will continue through Subgoal
  4.4, Subgoal 4.3, and beyond.  It is not until the results of combining the
  proof results of Subgoal 4.6 with the results from the remaining sibling
  subgoals (4.5, 4.4, and so on), that the proof attempt will abort and revert
  to prove the original conjecture by induction.  This example illustrates
  behavior that is rather like the case that ~c[:]~ilc[otf-flg] is ~c[t], in
  the sense that the abort does not happen immediately, but also rather like
  the case that ~c[:]~ilc[otf-flg] is ~c[nil], in the sense that the abort does
  occur before getting to Subgoal 3.~/")

(defun caar-is-declarep (x)

; Recognizer for expressions x for which (car x) is of the form (declare ...).

  (declare (xargs :guard t))
  (and (consp x)
       (consp (car x))
       (eq (caar x) 'declare)))

(defun declare-granularity-p (x)

; We return true when x is of the form (declare (granularity <expr>)).

  (declare (xargs :guard t))
  (and (true-listp x)
       (eql (length x) 2)
       (eq (car x) 'declare)
       (let ((gran-form (cadr x)))
         (and (true-listp gran-form)
              (eql (length gran-form) 2)
              (eq (car gran-form) 'granularity)))))

(defun check-and-parse-for-granularity-form (x)

; X is a list of forms that may begin with a granularity declaration such as
; (declare (granularity (< depth 5))).  The return signature is (erp msg
; granularity-form-exists granularity-form remainder-forms).  If there is no
; declaration then we return (mv nil nil nil nil x).  If there is error then we
; return (mv t an-error-message nil nil x).  Otherwise we return (mv nil nil t
; granularity-form (cdr x)).

; It is necessary to return whether the granularity form exists.  If we did not
; do so, there would be no mechanism for distinguishing between a non-existent
; granularity form and one that was nil.

; A granularity form declaration is the only acceptable form of declaration.
; Some examples of unaccepted declarations are type and ignore declarations.

; We use this function in both the raw and acl2-loop definitions of plet to
; macroexpand away our granularity form, as part of our effort to ensure that
; pargs is logically the identity function.

  (cond ((not (caar-is-declarep x))
         (mv nil nil nil nil x))
        ((declare-granularity-p (car x))
         (let* ((granularity-declaration (cadar x))
                (granularity-form (cadr granularity-declaration)))
           (mv nil nil t granularity-form (cdr x))))
        (t
         (mv t
             "Within a parallelism primitive, a granularity form declaration ~
              is the only acceptable form of declaration.  Some examples of ~
              unaccepted declarations are type and ignore declarations.  See ~
              :DOC granularity."
             nil
             nil
             x))))

#+(or acl2-loop-only (not acl2-par))
(defmacro pargs (&rest forms)
  ":Doc-Section Parallel-programming

  parallel evaluation of arguments in a function call~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  Example Forms:
  (pargs (binary-+ (fibonacci (- x 1)) (fibonacci (- x 2))))

  (pargs (declare (granularity (> x 35)))
         (binary-+ (fibonacci (- x 1)) (fibonacci (- x 2))))~/

  General Form:
  (pargs (declare (granularity expr)) ; optional granularity declaration
         (f arg1 ... argN))
  ~ev[]
  where ~c[N >= 0] and each ~c[argi] and ~c[expr] are arbitrary terms.
  Logically, ~c[pargs] is just the identity macro, in the sense that the above
  forms can logically be replaced by ~c[(f arg1 ... argN)].  However, this
  ~c[pargs] form may parallelize the evaluation of arguments ~c[arg1] through
  ~c[argN] before applying function ~c[f] to those results.  If the above
  ~ilc[granularity] declaration is present, then its expression (~c[expr]
  above) is first evaluated, and if the result is ~c[nil], then such
  parallelism is avoided.  Even if parallelism is not thus avoided, parallelism
  may be limited by available resources.

  Since macros can change expressions in unexpected ways, it is illegal to call
  ~c[pargs] on a form that is a macro call.  To parallelize computation of
  arguments to a macro, ~pl[plet].

  ~l[parallelism-at-the-top-level] for restrictions on evaluating parallelism
  primitives from within the ACL2 top-level loop.~/"

  (mv-let
   (erp msg gran-form-exists gran-form remainder-forms)
   (check-and-parse-for-granularity-form forms)
   (cond (erp (er hard 'pargs msg))
         ((or (and (equal (length forms) 1) (not gran-form-exists))
              (and (equal (length forms) 2) gran-form-exists))
          (let ((function-call (car remainder-forms)))
            (if gran-form-exists
                `(prog2$ ,gran-form ,function-call)
              function-call)))
         (t
          (er hard 'pargs
              "Pargs was passed the wrong number of arguments.  Without a ~
               granularity declaration, pargs takes one argument.  With a ~
               granularity declaration, pargs requires two arguments, the ~
               first of which must be of the form ~x0.  See :DOC pargs."
              '(declare (granularity expr)))))))

#+(or acl2-loop-only (not acl2-par))
(defmacro plet (&rest forms)
  ":Doc-Section Parallel-programming

  parallel version of ~ilc[let]~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  Example Forms:
  (plet ((a (fibonacci (- x 1)))
         (b (fibonacci (- x 2))))
        (+ a b))

  (plet (declare (granularity (> x 35)))
        ((a (fibonacci (- x 1)))
         (b (fibonacci (- x 2))))
        (+ a b))~/

  General Form:
  (plet (declare (granularity expr)) ; optional granularity declaration
        ((var1 val1)
         ...
         (varN valN))
        (declare ...) ... (declare ...) ; optional declarations
        body)
  ~ev[]
  The syntax of ~c[plet] is identical to the syntax of ~ilc[let], except that
  ~c[plet] permits an optional granularity declaration in the first argument
  position; ~pl[granularity].  In the logic a call of ~c[plet] macroexpands to
  the corresponding call of ~ilc[let], where the granularity declaration (if
  any) is dropped.

  ~c[Plet] cause the evaluation of each ~c[vali] above to be done in parallel
  before processing the body.  If the above ~ilc[granularity] declaration is
  present, then its expression (~c[expr] above) is first evaluated, and if the
  result is ~c[nil], then such parallelism is avoided.  Even if parallelism is
  not thus avoided, parallelism may be limited by available resources.

  ~l[parallelism-at-the-top-level] for restrictions on evaluating parallelism
  primitives from within the ACL2 top-level loop.~/"

  (mv-let (erp msg gran-form-exists gran-form remainder-forms)
          (check-and-parse-for-granularity-form forms)
          (cond (erp (er hard 'plet msg))
                (gran-form-exists
                 `(prog2$ ,gran-form
                          (let ,@remainder-forms)))
                (t `(let ,@remainder-forms)))))

(defun binary-pand (x y)

; Booleanized binary and.

  (declare (xargs :guard t :mode :logic))
  (and x y t))

#+(or acl2-loop-only (not acl2-par))
(defmacro pand (&rest forms)

; We Booleanize pand so that it is consistent with por, which must be
; Booleanized (see :DOC por).  Another nice thing about this Booleanization is
; that it emphasizes that PAND differs from AND logically, which can raise
; awareness of a guard-related difference based on the impact of lazy
; evaluation.

  ":Doc-Section Parallel-programming

  parallel, Boolean version of ~ilc[and]~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  Example Forms:
  (pand (subsetp-equal x y)
        (subsetp-equal y x))

  (pand (declare
         (granularity
          (and (> (length x) 500)
               (> (length y) 500))))
         (subsetp-equal x y)
         (subsetp-equal y x))
  ~ev[]~/

  ~bv[]
  General Form:
  (pand (declare (granularity expr)) ; optional granularity declaration
        arg1 ... argN)
  ~ev[]
  where ~c[N >= 0] and each ~c[argi] and ~c[expr] are arbitrary terms.

  ~c[Pand] evaluates its arguments in parallel.  It returns a Boolean result:
  ~c[nil] if any argument evaluates to ~c[nil], else ~c[t].  Note that
  ~c[pand] always returns a Boolean result, even though ~c[and] can return a
  non-~c[nil] value other than ~c[t], namely the value of its last argument.
  (A moment's reflection will make it clear that in order for ~ilc[por] to
  parallelize efficiently, it needs to return a Boolean value; so ~c[pand]
  returns a Boolean value for consistency with ~ilc[por].)

  Another difference between ~c[pand] and ~ilc[and] is that for a call of
  ~c[pand], even if an argument evaluates to ~c[nil], a subsequent argument
  may be evaluated.  Consider the following example (where ~c[cw] prints a
  string; ~pl[cw]).
  ~bv[]
  (defun bar ()
    (pand (equal (make-list 100000) nil) ; evaluates to nil
          (cw \"hello world~~%\")))
  ~ev[]
  When ~c[(bar)] is evaluated, the above arguments of ~c[pand] can execute in
  parallel, causing ``~c[hello world]'' to be printed to the terminal.  If we
  had used ~c[and] rather than ~c[pand], then since
  ~c[(equal (make-list 100000) nil)] evaluates to ~c[nil], the above call of
  ~ilc[cw] would be avoided and no such printing would take place.  Even with
  ~c[pand], such printing ~em[might] not take place, depending on resources,
  timing of thread creation, and whether or not parallel execution is enabled
  (~pl[set-parallel-execution]).

  Note that unlike the case for ~ilc[and], the definition of ~c[pand] does not
  provide ~c[(consp x)] as a ~il[guard] to ~c[(car x)] in the call of ~c[pand]
  below:
  ~bv[]
  (defun h (x)
    (declare (xargs :guard t))
    (pand (consp x) (equal (car x) 'foo)))
  ~ev[]
  As a result, ~il[guard] verification will fail for the above definition.  If
  ~c[pand] were replaced by ~c[and], then ~il[guard] verification would
  succeed.

  ~l[parallelism-tutorial] for another example.  Also
  ~pl[parallelism-at-the-top-level] for restrictions on evaluating parallelism
  primitives from within the ACL2 top-level loop.  Finally
  ~pl[early-termination] to read how ~c[pand] can offer more efficiency than
  ~ilc[and] by avoiding evaluation of some of its arguments.~/"

; Since we use &rest, we know forms is a true-list.

  (mv-let
   (erp msg gran-form-exists gran-form remainder-forms)
   (check-and-parse-for-granularity-form forms)
   (cond (erp (er hard 'pand msg))
         ((atom remainder-forms) t) ; (pand) == t
         ((null (cdr remainder-forms)) ; same as length == 1
          (list 'if (car remainder-forms) t nil)) ; booleanize
         (gran-form-exists
          (list 'prog2$
                gran-form
                (xxxjoin 'binary-pand remainder-forms)))
         (t (xxxjoin 'binary-pand remainder-forms)))))

(defun binary-por (x y)

; Booleanized binary or.

  (declare (xargs :guard t :mode :logic))
  (if x t (if y t nil)))

#+(or acl2-loop-only (not acl2-par))
(defmacro por (&rest forms)

; Note that por must be Booleanized if we are to support early termination,
; i.e., so that any non-nil value can cause por to return.

  ":Doc-Section Parallel-programming

  parallel, Boolean version of ~ilc[or]~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  Example Forms:
  (por (subsetp-equal x y)
       (subsetp-equal y x))

  (por (declare
        (granularity
         (and (> (length x) 500)
              (> (length y) 500))))
        (subsetp-equal x y)
        (subsetp-equal y x))
  ~ev[]~/

  ~bv[]
  General Form:
  (por (declare (granularity expr)) ; optional granularity declaration
       arg1 ... argN)
  ~ev[]
  where ~c[N >= 0] and each ~c[argi] and ~c[expr] are arbitrary terms.

  ~c[Por] evaluates its arguments in parallel.  It returns a Boolean result:
  ~c[t] if any argument evaluates to non-~c[nil], else ~c[nil].  Note that
  while ~ilc[or] returns the first non-~c[nil] value from evaluating its
  arguments left-to-right (if any such value is not ~c[nil]) ~ilc[por] always
  returns a Boolean result, in support of efficiency (~pl[early-termination])
  in light of the nondeterministic order in which argument values are returned.

  Another difference between ~c[por] and ~ilc[or] is that for a call of
  ~c[por], even if the an argument's value is not ~c[nil], a subsequent
  argument may be evaluated.  ~l[pand] for a discussion of the analogous
  property of ~c[pand].  In particular, ~il[guard]s generated from calls of
  ~c[por] may not assume for an argument that the preceding arguments evaluated
  to ~c[nil].

  ~l[parallelism-tutorial] for another example.  Also
  ~pl[parallelism-at-the-top-level] for restrictions on evaluating parallelism
  primitives from within the ACL2 top-level loop.  Finally
  ~pl[early-termination] to read how ~c[por] can offer more efficiency than
  ~ilc[or] by avoiding evaluation of some of its arguments.~/"

  (mv-let
   (erp msg gran-form-exists gran-form remainder-forms)
   (check-and-parse-for-granularity-form forms)
   (cond (erp (er hard 'por msg))
         ((atom remainder-forms) nil) ; (por) == nil
         ((null (cdr remainder-forms)) ; same as length == 1
          (list 'if (car remainder-forms) t nil))
         (gran-form-exists
          (list 'prog2$
                gran-form
                (xxxjoin 'binary-por remainder-forms)))
         (t (xxxjoin 'binary-por remainder-forms)))))

(defun or-list (x)
  (declare (xargs :guard (true-listp x) :mode :logic))
  (if (endp x)
      nil
    (if (car x)
        t
        (or-list (cdr x)))))

(defun and-list (x)
  (declare (xargs :guard (true-listp x) :mode :logic))
  (if (endp x)
      t
    (and (car x)
         (and-list (cdr x)))))

(defun cpu-core-count (state)

  ":Doc-Section ACL2::ACL2-built-ins

  the number of cpu cores~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  Unless the ACL2 executable supports parallel execution (~pl[parallelism]),
  this function returns ~c[(mv 1 state)].  Otherwise:

  ~c[(Cpu-core-count state)] returns ~c[(mv core-count state)], where
  ~c[core-count] is the number of cpu cores if ACL2 can get that information
  from the underlying Common Lisp implementation.  Otherwise an error occurs,
  unless global ~c['cpu-core-count] is assigned to a positive integer value
  (~pl[assign]), in which case that value is returned as the ~c[core-count].
  ~bv[]
  Example:
  (cpu-core-count state) ==> (mv 4 state)
  ~ev[].~/~/"

  (declare (xargs :stobjs state :guard t))
  #+(and (not acl2-loop-only) (not acl2-par))
  (when (live-state-p state)
    (return-from cpu-core-count
                 (mv 1 state)))
  #+(and (not acl2-loop-only) acl2-par)
  (when (live-state-p state)
    (return-from cpu-core-count
                 (mv (if (and (f-boundp-global 'cpu-core-count state)
                              (posp (f-get-global 'cpu-core-count state)))
                         (core-count-raw nil (f-get-global 'cpu-core-count
                                                           state))
                       (core-count-raw 'core-count))
                     state)))
  (mv-let (nullp val state)
          (read-acl2-oracle state)
          (declare (ignore nullp))
          (mv val state)))

; Preliminary code for parallelizing the rewriter

; ; We now develop code for parallelizing calls to the arguments of a call of
; ; rewrite.
;
; ; WARNING!  We believe that this approach has the following bug.  If
; ; with-prover-time-limit is used, then the main thread (which is the one
; ; calling waterfall-step) has a catch (implemented by the call there of
; ; catch-time-limit5) that will only catch throws to that tag from the SAME
; ; thread.  We will get in trouble if a spawned thread's call of rewrite does
; ; such a throw.
;
; ; Warning: Moreover, if we use this code, consider modifying the
; ; rewrite-constant to store the value of :limit in
; ; rewrite-args-granularity-table.  Otherwise, we have to go to the world with a
; ; potentially slow getprop every time we call rewrite-args-par-big-enough.
; ; Maybe that's just noise, but maybe it's expensive.
;
; ; We initially set the value of (the unique key) :limit to nil in
; ; rewrite-args-granularity-table, so that in fact we do not do such
; ; parallelization.  But we leave this infrastructure in place (see comment "or
; ; try :limit" below) in case we want to experiment with such parallelization in
; ; the future.
;
; #+acl2-par
; (table rewrite-args-granularity-table nil nil
;        :guard (and (eq key :limit)
;                    (or (null val) (natp val))))
;
; #+acl2-par
; (table rewrite-args-granularity-table :limit nil) ; or try :limit = 10
;
; #+acl2-par
; (defun rewrite-args-par-big-enough-rec (flg x bound acc)
;
; ; Flg is true when x is a list of terms; else x is a term.  Returns a number by
; ; accumulating into acc, or t if that number would exceed bound.  We assume
; ; that acc is <= bound.
;
;   (cond (flg ; x is a list
;          (cond ((null x)
;                 acc)
;                (t
;                 (let ((new-acc (rewrite-args-par-big-enough-rec
;                                 nil (car x) bound acc)))
;                   (if (eq new-acc t)
;                       t
;                     (rewrite-args-par-big-enough-rec
;                      flg (cdr x) bound new-acc))))))
;         ((variablep x)
;          acc)
;         ((fquotep x)
;          acc)
;         ((eql bound acc)
;          t)
;         ((flambdap (ffn-symb x))
;          (let ((new-acc (rewrite-args-par-big-enough-rec
;                          nil (lambda-body (ffn-symb x)) bound (1+ acc))))
;            (if (eq new-acc t)
;                t
;              (rewrite-args-par-big-enough-rec t (fargs x) bound new-acc))))
;         (t (rewrite-args-par-big-enough-rec t (fargs x) bound (1+ acc)))))
;
; #+acl2-par
; (defun rewrite-args-par-big-enough (x wrld)
;
; ; If the limit is set to nil, the function returns nil.  This allows the
; ; enabling and disabling of rewriting args in parallel.
;
;   (let ((limit (cdr (assoc-eq :limit
;                               (table-alist
;                                'rewrite-args-granularity-table
;                                wrld)))))
;     (and limit (equal t (rewrite-args-par-big-enough-rec nil x limit 0)))))
;
; ; With the additions above, we can contemplate adding something like the
; ; following to the rewrite nest below.  If we do that, then replace the call of
; ; rewrite-args in rewrite by the following:
;
; ;                    #-acl2-par
; ;                    rewrite-args
; ;                    #+acl2-par
; ;                    rewrite-args-par
;
; #+acl2-par
; (defun rewrite-args-par (args alist bkptr ; &extra formals
;                               rdepth
;                               type-alist obj geneqv wrld state fnstack
;                               ancestors backchain-limit
;                               simplify-clause-pot-lst rcnst gstack ttree)
;   (let ((pair (rewrite-entry (rewrite-args-par-rec args alist bkptr))))
;     (mv (car pair) (cdr pair))))
;
; #+acl2-par
; (defun rewrite-args-par-rec (args alist bkptr ; &extra formals
;                                   rdepth
;                                   type-alist obj geneqv wrld state fnstack
;                                   ancestors backchain-limit
;                                   simplify-clause-pot-lst rcnst gstack ttree)
;
; ; Note: In this function, the extra formal geneqv is actually a list of geneqvs
; ; or nil denoting a list of nil geneqvs.
;
; ; Unlike rewrite-args, we return (cons rewritten-args ttree) instead of
; ; (mv rewritten-args ttree).
;
;   (declare (type (unsigned-byte 29) rdepth))
;   (cond ((f-big-clock-negative-p state)
;          (cons (sublis-var-lst alist args)
;                ttree))
;         ((null args)
;          (cons nil ttree))
;         (t (plet
;             (declare (granularity t)) ; should call rewrite-args-par-big-enough
;             ((pair1
;               (mv-let (term ttree1)
;                       (rewrite-entry (rewrite (car args) alist bkptr)
;                                      :geneqv (car geneqv)
;                                      :ttree nil)
;                       (cons term ttree1)))
;              (pair2 (rewrite-entry
;                      (rewrite-args-par-rec (cdr args) alist (1+ bkptr))
;                      :geneqv (cdr geneqv))))
;             (let* ((term (car pair1))
;                    (ttree1 (cdr pair1))
;                    (rewritten-args (car pair2))
;                    (ttree2 (cdr pair2)))
;               (cons (cons term rewritten-args)
;                     (cons-tag-trees ttree1 ttree2)))))))

; Preliminary code for parallelizing the rewriter for ACL2 version 6.3.

; Note that the following code treats step-limits a little differently from how
; they are treated in the sequential version.  If we keep this treatment, we
; should add a comment here and in decrement-step-limit suggesting that if we
; change either, then we should consider changing the other.  Also note the
; commented out declare forms, which would be good to include (especially
; important for GCL) once spec-mv-let accepts them.  And finally, note that as
; of v6-2, it is necessary to unmemoize the rewriter functions when running the
; rewriter in parallel in ACL2(hp) because memoization is not thread-safe.
; This unmemoization can perhaps be done by issuing a call of (unmemoize-all)
; in raw Lisp).

; (defun rewrite-args (args alist bkptr; &extra formals
;                           rdepth step-limit
;                           type-alist obj geneqv wrld state fnstack ancestors
;                           backchain-limit
;                           simplify-clause-pot-lst rcnst gstack ttree)
;
; ; Note: In this function, the extra formal geneqv is actually a list of geneqvs
; ; or nil denoting a list of nil geneqvs.
;
;   (declare (type (unsigned-byte 29) rdepth)
;            (type (signed-byte 30) step-limit))
;   (the-mv
;    3
;    (signed-byte 30)
;    (cond ((null args)
;           (mv step-limit nil ttree))
;          (t (spec-mv-let
;              (step-limit1 rewritten-arg ttree1)
; ;            (declare (type (signed-byte 30) step-limit1))
;              (rewrite-entry (rewrite (car args) alist bkptr)
;                             :geneqv (car geneqv))
;              (mv-let
;                (step-limit2 rewritten-args ttree2)
;                (rewrite-entry (rewrite-args (cdr args) alist (1+ bkptr))
;                               :geneqv (cdr geneqv))
; ;              (declare (type (signed-byte 30) step-limit2))
;                (if t
;                    (mv (let* ((steps1 (- step-limit step-limit1))
;                               (step-limit (- step-limit2 steps1)))
;                          (declare (type (signed-byte 30) steps1 step-limit))
;                          (cond ((>= step-limit 0)
;                                 step-limit)
;                                ((step-limit-strictp state)
;                                 (step-limit-error nil))
;                                (t -1)))
;                        (cons rewritten-arg rewritten-args)
;                        (cons-tag-trees ttree1 ttree2))
;                  (mv 0
;                      nil
;                      nil))))))))

#+(or acl2-loop-only (not acl2-par))
(defmacro spec-mv-let (bindings computation body)

  ":Doc-Section Parallel-programming

  modification of ~ilc[mv-let] supporting speculative and parallel execution~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  Example Form:
  (defun pfib-with-step-count (x)
    (declare (xargs :mode :program))
    (if (or (zp x) (< x 33))
        (fib-with-step-count x)
      (spec-mv-let
       (a cnt1)
       (pfib-with-step-count (- x 1))
       (mv-let (b cnt2)
               (pfib-with-step-count (- x 2))
               (if t
                   (mv (+ a b)
                       (+ 1 cnt1 cnt2))
                 (mv \"speculative result is always needed\"
                     -1))))))~/

  General Form:
  (spec-mv-let
   (v1 ... vn)  ; bind distinct variables
   <spec>       ; evaluate speculatively; return n values
   (mv-let      ; or, use mv?-let if k=1 below
    (w1 ... wk) ; bind distinct variables
    <eager>     ; evaluate eagerly
    (if <test>  ; use results from <spec> if true
        <typical-case> ; may mention v1 ... vn
      <abort-case>)))  ; does not mention v1 ... vn
  ~ev[]

  Our design of ~c[spec-mv-let] is guided by its use in ACL2 source code to
  parallelize part of ACL2's proof process, in the experimental parallel
  extension of ACL2.  The user can think of ~c[spec-mv-let] as a speculative
  version of ~ilc[mv-let].  (In ordinary ACL2, the semantics agree with this
  description but without speculative or parallel execution.)

  Evaluation of the above general form proceeds as suggested by the comments.
  First, ~c[<spec>] is executed speculatively.  Control then passes immediately
  to the ~ilc[mv-let] call, without waiting for the result of evaluating
  ~c[<spec>].  The variables ~c[(w1 ... wk)] are bound to the result of
  evaluating ~c[<eager>], and then ~c[<test>] is evaluated.  If the value of
  ~c[<test>] is true, then the values of ~c[(v1 ... vn)] are needed, and
  ~c[<typical-case>] blocks until they are available.  If the value of
  ~c[<test>] is false, then the values of ~c[(v1 ... vn)] are not needed, and
  the evaluation of ~c[<spec>] may be aborted.

  The calls to ~c[mv-let] and to ~c[if] displayed above in the General Form are
  an essential part of the design of ~c[spec-mv-let], and are thus required.

  The following definition of ~c[fib-with-step-count] completes the example
  above:

  ~bv[]
  (defun fib-with-step-count (x)
  (declare (xargs :mode :program))
  (cond ((<= x 0)
         (mv 0 1))
        ((= x 1) (mv 1 1))
        (t (mv-let (a cnt1)
                   (fib-with-step-count (- x 1))
                   (mv-let (b cnt2)
                           (fib-with-step-count (- x 2))
                           (mv (+ a b)
                               (+ 1 cnt1 cnt2)))))))
  ~ev[]~/"

  (assert$
   (and (true-listp body)
        (equal (length body) 4)
        (or (equal (car body) 'mv-let@par)
            (equal (car body) 'mv-let)
            (equal (car body) 'mv?-let)))
   (let* ((inner-let (car body))
          (inner-bindings (cadr body))
          (inner-body (caddr body))
          (ite (cadddr body)))
     (assert$ (and (true-listp ite)
                   (equal (length ite) 4)
                   (equal (car ite) 'if))
              (let* ((test (cadr ite))
                     (true-branch (caddr ite))
                     (false-branch (cadddr ite)))
                `(check-vars-not-free

; Keep the check for variable name "the-very-obscure-feature" in sync with the
; variable name in the raw Lisp version.

                  (the-very-obscure-future)
                  (,inner-let
                   ,inner-bindings
                   ,inner-body
                   (if (check-vars-not-free ,bindings ,test)
                       (mv?-let ,bindings
                                ,computation
                                ,true-branch)
                     (check-vars-not-free ,bindings ,false-branch)))))))))

; Parallelism wart: when set-verify-guards-eagerness is 0, and there is a guard
; violation in subfunctions that are evaluating in the non-main-thread, we get
; errors that aren't user friendly (the errors occur in the non-main-threads).
; I think that the solution to this problem might necessitate catching the
; errors and re-causing them.  Hitting ctrl+c causes the main thread to abort
; waiting on the result from those threads, and allows the interactive session
; to resume.  David says that he may have already fixed this for spec-mv-let,
; and for the other parallelism primitives, the solution may be for the closure
; to bind *ld-level* to the value inherited from each thread's parent.  As of
; this writing (1/13/2012), we can see the unfortunate need for control-c in
; the following example:
; (defun f (x) (declare (xargs :guard (integerp x))) (+ x x))
; (defun g ()
;   (declare (xargs :guard t :verify-guards nil))
;   (plet ((a (f (car (make-list 1000000))))
;          (b (f (car (make-list 1000000)))))
;         (+ a b)))
; (g)

(defdoc error-triples-and-parallelism
  ":Doc-Section Parallel-programming
  how to avoid error triples in ACL2(p)~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ACL2 supports the use of error triples in many features; e.g.,
  ~ilc[computed-hints].  (For background on error triples,
  ~pl[programming-with-state].)  However, ACL2(p) does not support the use of
  error triples in some of these features (e.g., ~ilc[computed-hints]) while
  ~il[waterfall-parallelism] is enabled.~/

  You may see an error message like the following when running ACL2(p) with
  ~il[waterfall-parallelism] enabled:

  ~bv[]
  ACL2 Error in ( THM ...):  Since we are translating a form in ACL2(p)
  intended to be executed with waterfall parallelism enabled, the form
  (MY-STATE-MODIFYING-COMPUTED-HINT ID STATE) was expected to represent
  an ordinary value, not an error triple (mv erp val state), as would
  be acceptable in a serial execution of ACL2.  Therefore, the form returning
  a tuple of the form (* * STATE) is an error.  See :DOC unsupported-
  waterfall-parallelism-features and :DOC error-triples-and-parallelism
  for further explanation.
  ~ev[]

  In this particular example, the cause of the error was trying to use a
  computed hint that returned state, which is not allowed when executing the
  waterfall in parallel (~pl[unsupported-waterfall-parallelism-features] for
  other related information).

  Often, the only reason users need to return state is so they can perform
  some output during the proof process.  In this case, we suggest using one of
  the state-free output functions, like ~ilc[cw] or ~ilc[observation-cw].  If
  the user is concerned about the interleaving of their output with other
  output, these calls can be surrounded with the macro ~ilc[with-output-lock].

  Another frequent reason users return state is so they can cause a ~c[soft]
  error and halt the proof process.  In this case, we suggest instead calling
  ~ilc[er] with the ~c[hard] or ~c[hard?] severity.  By using these mechanisms,
  the user avoids modifying ~ilc[state], a requirement for much of the code
  written in ACL2(p).

  You may encounter other similar error messages when using
  ~il[computed-hints], ~il[custom-keyword-hints], or ~il[override-hints].
  Chances are that you are somehow returning an error triple when an ordinary
  value is needed.  If this turns out not to be the case, please let the ACL2
  implementors know.~/")

(defdoc with-output-lock

; Note: If you're looking for the definition of with-output-lock, you can find
; it as (deflock <comments> *output-lock*) in axioms.lisp.

  ":Doc-Section Parallel-programming

  provides a mutual-exclusion mechanism for performing output in parallel~/

  This documentation topic relates to an experimental extension of ACL2,
  ACL2(p), created initially by David L. Rager.  ~l[compiling-acl2p] for how to
  build an executable image that supports parallel execution.  Also see
  community books directory ~c[books/parallel/] for examples.~/

  One may wish to perform output while executing code in parallel.  If
  threads are allowed to print concurrently, the output will be interleaved and
  often unreadable.  To avoid this, the user can surround forms that perform
  output with the ~c[with-output-lock] macro.

  Take the following definition of ~c[pfib] as an example.

  ~bv[]
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((mbe :logic (or (zp x) (<= x 0))
                :exec (<= x 0))
           0)
          ((= x 1) 1)
          (t (plet (declare (granularity t))
                   ((a (prog2$ (cw \"Computing pfib ~~x0~~%\" (- x 1))
                               (pfib (- x 1))))
                    (b (prog2$ (cw \"Computing pfib ~~x0~~%\" (- x 2))
                               (pfib (- x 2)))))
                   (+ a b)))))
  ~ev[]

  With ~il[parallel-execution] enabled, a call of ~c[(pfib 5)]results in
  non-deterministically interleaved output, for example as follows.

  ~bv[]
  ACL2 !>(pfib 5)
  CComputing pfib 4
  omputing pfib 3
  ComCpuotmipnugt ipnfgi bp fib3
  2
  Computing pCfiobm put2i
  ng pfib 1
  Computing pfib Co1mp
  uting pfib 0
  CCoommppuuttiinngg  ppffiibb  12

  ComCpuotmipnugt ipnfgi bp fib1
  0
  CoCmopmuptuitnign gp fpifbi b 1
  0
  5
  ACL2 !>
  ~ev[]

  If the user instead surrounds the calls to ~ilc[cw] with the macro
  ~c[with-output-lock], as in the following session, the output will no longer
  be interleaved.

  ~bv[]
  ACL2 !>
  (defun pfib (x)
    (declare (xargs :guard (natp x)))
    (cond ((mbe :logic (or (zp x) (<= x 0))
                :exec (<= x 0))
           0)
          ((= x 1) 1)
          (t (plet (declare (granularity t))
                   ((a (prog2$ (with-output-lock
                                (cw \"Computing pfib ~~x0~~%\" (- x 1)))
                               (pfib (- x 1))))
                    (b (prog2$ (with-output-lock
                                (cw \"Computing pfib ~~x0~~%\" (- x 2)))
                               (pfib (- x 2)))))
                   (+ a b)))))

  <snip>

  ACL2 !>(pfib 5)
  Computing pfib 4
  Computing pfib 3
  Computing pfib 3
  Computing pfib 2
  Computing pfib 2
  Computing pfib 1
  Computing pfib 2
  Computing pfib 1
  Computing pfib 1
  Computing pfib 0
  Computing pfib 1
  Computing pfib 0
  Computing pfib 1
  Computing pfib 0
  5
  ACL2 !>
  ~ev[]
  ~/")

(defdoc acl2p-key-checkpoints

  ":Doc-Section Parallel-proof
  key checkpoints in ACL2(p)~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  For printing output, the parallel version of the waterfall follows the
  precedent of ~ilc[gag-mode].  The idea behind gag mode is to print only the
  subgoals most relevant to debugging a failed proof attempt.  These subgoals
  are called 'key checkpoints' (~pl[set-gag-mode] for the definition of ``key''
  and ``checkpoint''), and we restrict the default output mode for the parallel
  version of the waterfall to printing checkpoints similar to these key
  checkpoints.~/

  As of this writing, we are aware of exactly one discrepancy between gag
  mode's key checkpoints and the parallel version of the waterfall's
  checkpoints.  This discrepancy occurs when using ``by'' hints (~pl[hints]).
  As an example, take the following form, which attempts to prove a
  non-theorem:

  ~bv[]
  (thm (equal (append x y z) (append z (append y x)))
       :hints ((\"Subgoal *1/2'''\" :by nil)))

  ~ev[]

  With waterfall parallelism enabled, ~c[Subgoal *1/2''] will be printed as a
  key checkpoint.  This is different from using ~ilc[gag-mode] while running
  the serial version of the waterfall, which skips printing the subgoal as a
  checkpoint.

  For those familiar with the ACL2 waterfall, we note that that the parallel
  version of the waterfall prints key checkpoints that are unproved in the
  following sense: a subgoal is a key checkpoint if it leads, in the current
  call of the waterfall, to a goal that is pushed for induction.~/

  :cite set-waterfall-printing")

; Parallelism wart: it is still possible in ACL2(p) to receive an error at the
; Lisp-level when CCL cannot "create thread".  An example of a user (Kaufmann)
; encountering this error is shown below, with community book
; concurrent-programs/bakery/stutter2.  In March 2012, Kaufmann's laptop could
; sometimes exhibit this problem (a 2-core machine with 4 hardware threads).
; There are two possible ways to fix this problem.  The first is to set the
; default-total-parallelism-work-limit to a lower number so that it never
; occurs (but this costs performance).  Kaufmann suggests that we should also
; catch this particular Lisp error and instead cause an ACL2 error, similar to
; the error in function not-too-many-futures-already-in-existence.  This may be
; harder than one might intially think, because our current mechanism for
; catching errors in child threads involves catching thrown tags and then
; rethrowing them in the thread who is that child's parent.

; The error looks like the following:

;; <snip>
;;
;;.............................................................
;; ***********************************************
;; ************ ABORTING from raw Lisp ***********
;; Error:  .Can't create thread
;; ***********************************************

;; The message above might explain the error.  If not, and
;; if you didn't cause an explicit interrupt (Control-C),
;; then the root cause may be call of a :program mode
;; function that has the wrong guard specified, or even no
;; guard specified (i.e., an implicit guard of t).
;; See :DOC guards.

;; To enable breaks into the debugger (also see :DOC acl2-customization):
;; (SET-DEBUGGER-ENABLE T)
;; .
;; ***********************************************
;; ************ ABORTING from raw Lisp ***********
;; Error:  Can't create thread
;; ***********************************************

;; The message above might explain the error.  If not, and
;; if you didn't cause an explicit interrupt (Control-C),
;; then the root cause may be call of a :program mode
;; function that has the wrong guard specified, or even no
;; guard specified (i.e., an implicit guard of t).
;; See :DOC guards.

;; To enable breaks into the debugger (also see :DOC acl2-customization):
;; (SET-DEBUGGER-ENABLE T)
;; ...........................................................
;; ..................Here is the current pstack [see :DOC pstack]:
;; (CLAUSIFY REWRITE-ATM
;;          SIMPLIFY-CLAUSE SIMPLIFY-CLAUSE
;;          REWRITE-ATM SIMPLIFY-CLAUSE REWRITE-ATM
;;          PREPROCESS-CLAUSE PREPROCESS-CLAUSE
;;          SETUP-SIMPLIFY-CLAUSE-POT-LST
;;          SIMPLIFY-CLAUSE
;;          EV-FNCALL-META REWRITE-ATM
;;          EV-FNCALL-META EV-FNCALL-META
;;          EV-FNCALL-META REWRITE-ATM
;;          EV-FNCALL EV-FNCALL EV-FNCALL-META
;;          REWRITE-ATM REWRITE-ATM SIMPLIFY-CLAUSE
;;          FORWARD-CHAIN1 SIMPLIFY-CLAUSE
;;          PREPROCESS-CLAUSE EV-FNCALL-META
;;          REWRITE-ATM REWRITE-ATM REWRITE-ATM
;;          FORWARD-CHAIN1 FORWARD-CHAIN1
;;          SIMPLIFY-CLAUSE SIMPLIFY-CLAUSE
;;          SIMPLIFY-CLAUSE PREPROCESS-CLAUSE
;;          SIMPLIFY-CLAUSE SIMPLIFY-CLAUSE
;;          SIMPLIFY-CLAUSE SIMPLIFY-CLAUSE
;;          REWRITE-ATM PREPROCESS-CLAUSE
;;          SIMPLIFY-CLAUSE PREPROCESS-CLAUSE
;;          SIMPLIFY-CLAUSE PREPROCESS-CLAUSE
;;
;; <snip>

(defun set-total-parallelism-work-limit-fn (val state)
  (declare (xargs :guard (or (equal val :none)
                             (integerp val))))
  (f-put-global 'total-parallelism-work-limit val state))

(defmacro set-total-parallelism-work-limit (val)

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): set thread limit for parallelism primitives~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].  While the most
  common use of the limit described below is in parallel proof
  (~pl[parallel-proof]), it also applies to all parallelism primitives
  (~pl[parallel-programming]) except ~ilc[spec-mv-let] ~-[] though we expect
  that rather few programming applications will encouter this limit.

  ~bv[]
  General Forms:
  (set-total-parallelism-work-limit :none)     ; disable the limit
  (set-total-parallelism-work-limit <integer>) ; set limit to <integer>
  ~ev[]

  ~l[parallelism-tutorial], Section ``Another Granularity Issue Related to
  Thread Limitations'', for an explanation of how the host Lisp can run out of
  threads.  Also ~pl[set-total-parallelism-work-limit-error].~/

  If the underlying runtime system (the Operating System, the host Lisp, etc.)
  is unable to provide enough threads to finish executing the parallelism work
  given to it, the runtime system can crash in a very unpleasant
  manner (ranging from a Lisp error to completely freezing the machine).  To
  avoid this unpleasantness, ACL2(p) will attempt to avoid creating so much
  parallelism that the runtime system crashes.

  ACL2 initially uses a conservative estimate to limit the number of threads.
  To tell ACL2(p) to use a different limit, call
  ~c[set-total-parallelism-work-limit] with the new limit.  For example, if the
  current default limit is 10,000, then to allow 13,000 threads to exist, issue
  the following form at the top level.
  ~bv[]
  (set-total-parallelism-work-limit 13000)
  ~ev[]

  To disable this limit altogether, evaluate the following form:
  ~bv[]
  (set-total-parallelism-work-limit :none)
  ~ev[]

  The default value of total-parallelism-work-limit can be found by calling
  function ~c[default-total-parallelism-work-limit].  If the default value is
  too high for your system please notify the ACL2 maintainers with a limit that
  does work for your system, as they might then lower the default limit.~/

  :cited-by parallel-proof
  :cited-by parallel-programming"

  (declare (xargs :guard (or (equal val :none)
                             (integerp val))))
  `(set-total-parallelism-work-limit-fn ,val state))

(defun set-total-parallelism-work-limit-error-fn (val state)
  (declare (xargs :guard (or (equal val t)
                             (null val))))
  (f-put-global 'total-parallelism-work-limit-error val state))

(defmacro set-total-parallelism-work-limit-error (val)

; Parallelism blemish: explain something about how, unlike
; set-total-parallelism-work-limit, this one only applies to proof (not
; programming).

  ":Doc-Section switches-parameters-and-modes

  for ACL2(p): control the action taken when the thread limit is exceeded~/

  This ~il[documentation] topic relates to the experimental extension of ACL2
  supporting parallel execution and proof; ~pl[parallelism].

  ~bv[]
  General Forms:
  (set-total-parallelism-work-limit-error t)   ; cause error (default)
  (set-total-parallelism-work-limit-error nil) ; disable error and
                                               ; continue serially
  ~ev[]

  ~l[parallelism-tutorial], Section ``Another Granularity Issue Related to
  Thread Limitations'', for an explanation of how the host Lisp can run out of
  threads.  ~l[set-total-parallelism-work-limit] for further details, including
  an explanation of how to manage the limit that triggers this error.~/

  The value of state global ~c[total-parallelism-work-limit-error] dictates
  what occurs when the underlying runtime system runs reaches a limit on the
  number of threads for parallel computation.  By default, when this limit is
  reached, the ACL2(p) user will receive an error and computation will halt.
  At this point, the ACL2(p) user has the following options.

  (1) Remove the limit by evaluating the following form.
  ~bv[]
  (set-total-parallelism-work-limit :none)
  ~ev[]

  (2) Disable the error so that execution continues serially once the available
  thread resources have been exhausted.
  ~bv[]
  (set-total-parallelism-work-limit-error nil)
  ~ev[]

  (3) Increase the limit on number of threads that ACL2(p) is willing to
  create, in spite of potential risk (~pl[set-total-parallelism-work-limit]).
  In this case, the following query returns the current limit.
  ~bv[]
  (f-get-global 'total-parallelism-work-limit)
  ~ev[]
  Then to increase that limit, evaluate the following form:
  ~bv[]
  (set-total-parallelism-work-limit <new-integer-value>)
  ~ev[]

  For example, suppose that the value of ~c[total-parallelism-work-limit] was
  originally 10,000.  Then evaluation of the following form increases that
  limit to 13,000.
  ~bv[]
  (set-total-parallelism-work-limit 13000)
  ~ev[]
  ~/
  :cited-by parallel-proof"

  (declare (xargs :guard (or (equal val t)
                             (null val))))
  `(set-total-parallelism-work-limit-error-fn ,val state))