From ef816dbffaf97f1391d8c7d96a2d403b74aeab1c Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 17 Mar 2026 11:36:13 +0000 Subject: [PATCH 01/75] Add Simtests: snippetbased and C. --- CMakeLists.txt | 10 + test/CMakeLists.txt | 1 + .../CodeGenTests}/simple_tests.rb | 0 test/SimTests/C/CImpl/CMakeLists.txt | 13 + test/SimTests/C/CImpl/Target/CMakeLists.txt | 1 + .../C/CImpl/Target/RISCV/CMakeLists.txt | 1 + test/SimTests/C/CImpl/Target/RISCV/start.s | 39 + test/SimTests/C/CImpl/fib/CMakeLists.txt | 1 + test/SimTests/C/CImpl/fib/fib.c | 30 + test/SimTests/C/CImpl/qsort/CMakeLists.txt | 1 + test/SimTests/C/CImpl/qsort/dataset1.h | 691 ++++++++++++++++++ test/SimTests/C/CImpl/qsort/qsort.c | 179 +++++ test/SimTests/C/CMakeLists.txt | 33 + test/SimTests/CMakeLists.txt | 9 + test/SimTests/Common/CMakeLists.txt | 1 + test/SimTests/Common/RunTests.py | 41 ++ test/SimTests/SnippetBased/CMakeLists.txt | 37 + test/SimTests/SnippetBased/RunTests.sh | 0 .../SnippetBasedImpl/CMakeLists.txt | 54 ++ .../SnippetBasedImpl/InitTestGen.rb | 80 ++ .../SnippetBasedImpl/Parsers/QEMUParser.rb | 28 + .../Target/RISCV/Formatter.rb | 62 ++ .../Target/RISCV/Snippets/add-1.s | 1 + .../Target/RISCV/Snippets/addi-1.s | 1 + .../SnippetBased/SnippetBasedImpl/TestGen.rb | 85 +++ .../SnippetBasedImpl/compile-and-run.sh | 41 ++ .../SnippetBasedImpl/compile-dir.sh | 24 + 27 files changed, 1464 insertions(+) create mode 100644 test/CMakeLists.txt rename {tests/SemaTests => test/CodeGenTests}/simple_tests.rb (100%) create mode 100644 test/SimTests/C/CImpl/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/Target/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/Target/RISCV/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/Target/RISCV/start.s create mode 100644 test/SimTests/C/CImpl/fib/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/fib/fib.c create mode 100644 test/SimTests/C/CImpl/qsort/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/qsort/dataset1.h create mode 100644 test/SimTests/C/CImpl/qsort/qsort.c create mode 100644 test/SimTests/C/CMakeLists.txt create mode 100644 test/SimTests/CMakeLists.txt create mode 100644 test/SimTests/Common/CMakeLists.txt create mode 100644 test/SimTests/Common/RunTests.py create mode 100644 test/SimTests/SnippetBased/CMakeLists.txt create mode 100644 test/SimTests/SnippetBased/RunTests.sh create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Parsers/QEMUParser.rb create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Formatter.rb create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb create mode 100755 test/SimTests/SnippetBased/SnippetBasedImpl/compile-and-run.sh create mode 100755 test/SimTests/SnippetBased/SnippetBasedImpl/compile-dir.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 85689ce..634aa4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.22 FATAL_ERROR) project(protea) +set(TARGET_NAME RISCV) + +option(PROTEA_BUILD_TESTS + "Enable tests build (requires riscv gnu toolchain)" OFF) +enable_testing() if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set_property(CACHE CMAKE_INSTALL_PREFIX @@ -9,8 +14,12 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) endif() find_package(Ruby 3.4.8 EXACT REQUIRED) +find_package(Python3 3.12 EXACT REQUIRED COMPONENTS Interpreter) +message("Python found: ${Python3_EXECUTABLE}") +include(ExternalProject) include(cmake/Bundler.cmake) +include(cmake/QEMU.cmake) include(cmake/CompilerOptions.cmake) include(cmake/CPM.cmake) include(cmake/dependencies.cmake) @@ -18,3 +27,4 @@ include(cmake/dependencies.cmake) add_subdirectory(lib) add_subdirectory(sim_lib) add_subdirectory(sim_gen) +add_subdirectory(test) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..9f280e3 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(SimTests) diff --git a/tests/SemaTests/simple_tests.rb b/test/CodeGenTests/simple_tests.rb similarity index 100% rename from tests/SemaTests/simple_tests.rb rename to test/CodeGenTests/simple_tests.rb diff --git a/test/SimTests/C/CImpl/CMakeLists.txt b/test/SimTests/C/CImpl/CMakeLists.txt new file mode 100644 index 0000000..dbcd372 --- /dev/null +++ b/test/SimTests/C/CImpl/CMakeLists.txt @@ -0,0 +1,13 @@ +project(tests LANGUAGES C ASM) + +add_subdirectory(Target) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +macro(protea_add_test tar) + add_executable(${tar} ${ARGN}) + target_link_libraries(${tar} PRIVATE tests_startup) +endmacro() + +add_subdirectory(fib) +add_subdirectory(qsort) diff --git a/test/SimTests/C/CImpl/Target/CMakeLists.txt b/test/SimTests/C/CImpl/Target/CMakeLists.txt new file mode 100644 index 0000000..529c48f --- /dev/null +++ b/test/SimTests/C/CImpl/Target/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(${TARGET_NAME}) diff --git a/test/SimTests/C/CImpl/Target/RISCV/CMakeLists.txt b/test/SimTests/C/CImpl/Target/RISCV/CMakeLists.txt new file mode 100644 index 0000000..777f189 --- /dev/null +++ b/test/SimTests/C/CImpl/Target/RISCV/CMakeLists.txt @@ -0,0 +1 @@ +add_library(tests_startup OBJECT start.s) diff --git a/test/SimTests/C/CImpl/Target/RISCV/start.s b/test/SimTests/C/CImpl/Target/RISCV/start.s new file mode 100644 index 0000000..a9b0814 --- /dev/null +++ b/test/SimTests/C/CImpl/Target/RISCV/start.s @@ -0,0 +1,39 @@ +.global _start +.section .text +_start: + li x1, 0 + # li x2, 0 set via sim + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10,0 + li x11,0 + li x12,0 + li x13,0 + li x14,0 + li x15,0 + li x16,0 + li x17,0 + li x18,0 + li x19,0 + li x20,0 + li x21,0 + li x22,0 + li x23,0 + li x24,0 + li x25,0 + li x26,0 + li x27,0 + li x28,0 + li x29,0 + li x30,0 + li x31,0 + + jal main + + li a7, 93 + ecall diff --git a/test/SimTests/C/CImpl/fib/CMakeLists.txt b/test/SimTests/C/CImpl/fib/CMakeLists.txt new file mode 100644 index 0000000..feb9aaf --- /dev/null +++ b/test/SimTests/C/CImpl/fib/CMakeLists.txt @@ -0,0 +1 @@ +protea_add_test(protea_test_fib fib.c) diff --git a/test/SimTests/C/CImpl/fib/fib.c b/test/SimTests/C/CImpl/fib/fib.c new file mode 100644 index 0000000..7e56ac6 --- /dev/null +++ b/test/SimTests/C/CImpl/fib/fib.c @@ -0,0 +1,30 @@ +int verify(unsigned r, unsigned n) { + static const unsigned calculated[] = { + 1, 1, 2, 3, 5, 8, + 13, 21, 34, 55, 89, 144, + 233, 377, 610, 987, 1597, 2584, + 4181, 6765, 10946, 17711, 28657, 46368, + 75025, 121393, 196418, 317811, 514229, 832040, + 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, + 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, + 433494437, 701408733, 1134903170, 1836311903, 2971215073, 512559680, + 3483774753, 3996334433, 3185141890, 2886509027, 1776683621, 368225352, + 2144908973, 2513134325, 363076002, 2876210327, 3239286329, 1820529360, + 764848393, 2585377753, 3350226146, 1640636603, + }; + if (r == calculated[n]) { + return 0; + } + return 1; +} + +unsigned fib(unsigned n) { + if (n <= 1) { + return 1; + } + return fib(n - 1) + fib(n - 2); +} + +int main() { + return verify(fib(16), 16) || verify(fib(20), 20) || verify(fib(31), 31); +} diff --git a/test/SimTests/C/CImpl/qsort/CMakeLists.txt b/test/SimTests/C/CImpl/qsort/CMakeLists.txt new file mode 100644 index 0000000..e3ccb86 --- /dev/null +++ b/test/SimTests/C/CImpl/qsort/CMakeLists.txt @@ -0,0 +1 @@ +protea_add_test(protea_test_qsort qsort.c) diff --git a/test/SimTests/C/CImpl/qsort/dataset1.h b/test/SimTests/C/CImpl/qsort/dataset1.h new file mode 100644 index 0000000..8d28ed9 --- /dev/null +++ b/test/SimTests/C/CImpl/qsort/dataset1.h @@ -0,0 +1,691 @@ + + +#define DATA_SIZE 2048 + +type input_data[DATA_SIZE] = { + 89400484, 976015092, 1792756324, 721524505, 1214379246, 3794415, + 402845420, 2126940990, 1611680320, 786566648, 754215794, 1231249235, + 284658041, 137796456, 2041942843, 329767814, 1255524953, 465119445, + 1731949250, 301663421, 1335861008, 452888789, 14125900, 1231149357, + 2002881120, 730845665, 1913581092, 1275331596, 843738737, 1931282005, + 1492488573, 490920543, 2066865713, 25885333, 238278880, 1898582764, + 250731366, 1612593993, 637659983, 1388759892, 916073297, 1075762632, + 675549432, 937987129, 1417415680, 1508705426, 1663890071, 1746476698, + 686797873, 2109530615, 1459500136, 324215873, 1881253854, 1496277718, + 810387144, 1212974417, 1020037994, 585169793, 2017191527, 556328195, + 1160036198, 1391095995, 1223583276, 1094283114, 436580096, 190215907, + 603159718, 1513255537, 1631935240, 1440145706, 1303736105, 806638567, + 1100041120, 1185825535, 1414141069, 2014090929, 419476096, 1273955724, + 175753599, 1223475486, 574236644, 2046759770, 492507266, 1721767511, + 726141970, 1256152080, 2029909894, 1382429941, 1939683211, 791188057, + 519699747, 1051184301, 1962689485, 706913763, 1776471922, 672906535, + 2005817027, 1274190723, 2119425672, 835063788, 421198539, 1169327477, + 2064145552, 1396662140, 1218522465, 2105638337, 754247044, 2143968639, + 1395289708, 1750443194, 1412540552, 170281493, 389233190, 448284065, + 240618723, 2145930822, 1846605728, 1353999206, 140536987, 1821559709, + 619972089, 1514278798, 750919339, 2143343312, 304427548, 545066288, + 1946004194, 1538069400, 1904770864, 924541465, 567779677, 893302687, + 1239665569, 1157666831, 2105814934, 1505475223, 1636203720, 9736243, + 518073650, 1063743848, 1029176122, 215018112, 1073871430, 1858933377, + 866478506, 1491477359, 477407584, 895562064, 954441852, 638167485, + 1550159640, 614612685, 1453397990, 1334857284, 683536723, 168771888, + 481561285, 755798022, 2016161810, 1162679490, 619428858, 1390306889, + 256860662, 365275089, 1322281086, 1134185180, 1302724177, 621921213, + 837554186, 1711761015, 754896618, 1723143470, 978247260, 1548804416, + 598016845, 1631405417, 790929190, 1602517354, 770957259, 198186681, + 1256015513, 2126029304, 135012885, 583112200, 2118203528, 1834388383, + 866964848, 1695191950, 745183293, 1143511498, 1112731797, 478721193, + 1202162389, 991159735, 1952364329, 519344323, 1667102296, 770412991, + 548632788, 714042223, 1674045273, 1471598258, 1286989824, 1590771096, + 308832070, 959354209, 72802865, 670621648, 269167950, 1598436917, + 2023498746, 1198213061, 2006856683, 1029832956, 1719009954, 1198254803, + 1188748563, 1989240516, 927524181, 1711765426, 1394929399, 769005536, + 2047006719, 1915435344, 618681206, 1431814151, 42021322, 1106678970, + 107160610, 1199317660, 185592115, 1870214195, 205008108, 1834318089, + 948686793, 946311527, 1262399341, 131405125, 1321897861, 1459138745, + 821481684, 852388468, 603907009, 20643769, 1737931879, 37141933, + 2088576982, 366700722, 1761289401, 625991894, 741078359, 817417567, + 969305448, 1152416171, 1101933540, 399456957, 2074896270, 1971484382, + 747592875, 1160333307, 1738353358, 2113434968, 1896952705, 1908093581, + 1155544307, 117766047, 2034767768, 1316120929, 1507433029, 2045407567, + 765386206, 1031625002, 1220915309, 325667019, 1916602098, 16411608, + 47463938, 1379995885, 1221108420, 721046824, 1431492783, 1569479928, + 909415369, 204514903, 933673987, 1565700239, 341674967, 602907378, + 5309142, 849489374, 180599971, 1480437960, 532467027, 1958396887, + 106223060, 1025117441, 935689637, 1752088215, 1704561346, 1568395337, + 1868289345, 569949159, 1045658065, 274746405, 890461390, 507848158, + 793505636, 460893030, 1179525294, 388855203, 1113693824, 13887419, + 1909681194, 1082499152, 1466632447, 1281443423, 612289854, 373305330, + 568652142, 1383640563, 1073695485, 745777837, 624939139, 1289308008, + 1928550562, 148113917, 462743614, 1826880531, 1571598133, 1415390230, + 1480273562, 1331593955, 540006359, 261556590, 1690167792, 283430575, + 1194709162, 1781233744, 649754857, 1434046375, 1135793759, 932423857, + 1170759710, 1048943084, 692845661, 1620562432, 2036750157, 270410557, + 617995659, 1347284277, 1771614266, 30992839, 655445946, 22762734, + 1695617313, 867628573, 1577034674, 227870124, 2063408339, 1512163910, + 787913688, 1758748737, 1553547892, 2072440819, 632611704, 873623623, + 2097057488, 1879635915, 1404727477, 1840896199, 1609955669, 186112992, + 196401930, 130001148, 814302898, 1420810050, 226906236, 1435859758, + 221330186, 329049266, 820933470, 260792255, 1401058771, 210908782, + 1774652096, 886978116, 1807085904, 508041515, 767233910, 26687179, + 318750634, 910677024, 117260224, 2074840378, 301350822, 464795711, + 2053899162, 1335298265, 737518341, 777433215, 1147341731, 1981481446, + 1628389501, 1537459540, 1121432739, 1392162662, 1800522575, 644293952, + 1273223611, 1906345724, 28256901, 1467376771, 372465453, 78348530, + 135678410, 1061864942, 260267972, 1184561748, 287497702, 1154842325, + 1629914848, 2084953915, 799717076, 1382484003, 2045821218, 933603111, + 84924801, 892939912, 279252402, 651750790, 238566180, 942977997, + 1822612008, 1849675857, 939497524, 436630343, 549253917, 1028937430, + 579174666, 2124749673, 880456526, 1451442832, 1350653461, 1546104436, + 858045289, 2129513521, 1181191604, 727587915, 1619598456, 969076419, + 1212628403, 1361078114, 368541415, 333906659, 41714278, 1390274260, + 1563717683, 973769771, 1078197595, 918378387, 1672192305, 1094531762, + 92620223, 2125958841, 1620803320, 915948205, 174965839, 27377406, + 435236973, 1038830638, 1834161399, 305750851, 330474090, 730422541, + 1634445325, 840106059, 767880329, 109526756, 2027814180, 367923081, + 1983379601, 1293091635, 705851791, 226723092, 1067775613, 2082760612, + 951663731, 260670135, 1111213862, 1891630185, 1379259015, 176024101, + 594814862, 1870859970, 1689946986, 1290969161, 244975305, 1296857499, + 1811088032, 1873900475, 1949896838, 1907793490, 592006699, 1312471120, + 509744705, 869853078, 70894786, 503368137, 1686479103, 1602967659, + 1214950832, 1131661227, 768185796, 592234826, 1727583308, 949222447, + 1760851607, 487888229, 1614780688, 1618378831, 602368560, 2028116487, + 183679578, 1561251584, 986240059, 1525451290, 977907387, 432609664, + 1528031307, 116766659, 987761406, 1630293700, 90063199, 114202152, + 543952312, 855107605, 812328969, 88823122, 1092881031, 304131252, + 1505022272, 894769708, 1849495275, 1607515830, 1032748996, 472872107, + 1593359038, 1027760887, 1074205225, 1657001479, 1524491858, 387061281, + 107095939, 1038018856, 798445606, 1486594282, 1878434988, 1558695709, + 2033003588, 373226849, 2133066804, 399991238, 1132597050, 1965358941, + 1551661799, 3522194, 935939763, 2070467093, 500734709, 533101409, + 1068798385, 998931662, 1500102591, 779093898, 66579049, 1121960111, + 749415493, 502323961, 538932155, 259768753, 753296935, 87897457, + 539429964, 1675300017, 1232992084, 420106224, 1685350721, 346598567, + 1610244183, 1597506096, 1079859867, 944382193, 1770497338, 764935753, + 1776794410, 866854601, 365854486, 304211060, 344860208, 1361012693, + 1450892344, 622170346, 70003859, 1681866717, 435288306, 687941098, + 308700094, 1367731096, 1834285819, 255226842, 193873940, 1833603743, + 848402819, 152273285, 231181585, 1754447491, 1838218199, 834410115, + 229905664, 2052321529, 338532526, 77482422, 12937811, 35859252, + 1645969422, 1501181424, 438711458, 1496078411, 419109342, 1455756978, + 1234944834, 1287171290, 470090505, 1900162831, 1130850177, 1772760484, + 381571915, 1605369007, 514914429, 994291574, 1502557594, 1099847920, + 1627355806, 1148699143, 1519017268, 946489895, 106595511, 921573402, + 181567810, 1575380740, 1719573683, 1561730727, 1920182565, 1510133268, + 1102603775, 1175885101, 802730854, 185979744, 1058937717, 1716853034, + 31596852, 462857778, 1335652095, 47036070, 178901145, 1399673078, + 222529745, 128036841, 1708126014, 923768127, 1980923963, 1413860940, + 1382551511, 208160226, 1892370478, 2091626028, 1793190956, 1417601340, + 515811664, 2076612603, 993525189, 1127173529, 245334962, 134453363, + 1206302514, 1344125357, 1139159604, 651536866, 22136821, 1536213818, + 2143324534, 879878312, 1944679691, 119285206, 832081018, 1566878909, + 876130333, 656954306, 226726100, 937976428, 1202009920, 1938258683, + 2014129292, 1274436639, 1102423908, 1485740112, 879552408, 1712269139, + 650513248, 1068587688, 434850545, 382422699, 919736727, 2022291557, + 1319798607, 2139976479, 772059719, 1033910502, 1120963974, 340231765, + 1471131758, 1767380006, 47452797, 1313871880, 399114073, 1462921857, + 671848647, 31574181, 230340298, 239990424, 590690783, 1714295540, + 833019845, 398244682, 522160389, 900852, 1045627895, 1545555937, + 226986415, 208433088, 1502480836, 1611500622, 1933923245, 1588715179, + 1655277291, 1749972876, 1386258142, 935490932, 173822937, 702380578, + 348131466, 81402251, 875481479, 72939206, 2033828953, 1302272656, + 64795664, 2010549018, 1652108025, 58217952, 1871684562, 190536346, + 244709448, 949010757, 320137025, 729474445, 133790520, 740536012, + 316479300, 1191513656, 1802197319, 785398708, 1816641611, 2052328978, + 930367387, 1374125186, 303845878, 852835634, 454359988, 2131761201, + 1757028186, 536063430, 1765354961, 726869128, 1209784819, 1790557628, + 783427298, 2094085507, 1323798820, 846127236, 1065481253, 572240371, + 1745543275, 1011417836, 1970797151, 748527394, 343119399, 723323690, + 925975225, 901789102, 1726987516, 535828217, 387611445, 464171383, + 1170510314, 1166227930, 1807172811, 1942089394, 985305323, 1368235387, + 1691486500, 1568900638, 1876255297, 1249183285, 1710305778, 1763785295, + 1733366374, 1444076976, 1629633514, 2105321510, 225091211, 898893218, + 863551327, 1441811554, 546340809, 1977865396, 2116495484, 1221726287, + 293109484, 1601617797, 1568176414, 1424797596, 1256372950, 298799048, + 1708002892, 829450571, 891710357, 1994402695, 1136264020, 372280769, + 1520667645, 983043723, 1191079043, 680172541, 813511681, 395360213, + 1648575360, 1026342885, 2100497812, 422047044, 509116230, 859612092, + 2037182006, 895080280, 494367164, 1732028080, 355614494, 2141591317, + 1087251698, 580692625, 225934851, 1581062145, 1515262458, 1497680539, + 1711718534, 1774796872, 301673313, 1136356724, 653050943, 109035776, + 1709823304, 1340949553, 1365423458, 1155459206, 1203897636, 188016786, + 256210446, 633075975, 19227407, 1864952910, 1143853106, 237020443, + 1750197960, 856837002, 80321564, 1679324299, 1257507406, 1390040163, + 1590461855, 806384435, 1331383316, 2027828650, 1649392096, 1928309762, + 1027758817, 1267173039, 123889599, 95752736, 2060969286, 619461174, + 1686215900, 1817156134, 2118821565, 1596821127, 1800186189, 212821393, + 661318748, 1123331233, 146002907, 953877041, 1771924274, 929351822, + 2142357746, 356638683, 1610539590, 2001056977, 368889391, 62209567, + 1775608361, 992410365, 1336108161, 696448050, 333820982, 585804640, + 1775805177, 809604334, 93191015, 732444124, 1492071476, 1930662128, + 174082258, 340442582, 507936866, 362748128, 1607204293, 953383750, + 1599876594, 416457166, 571635069, 1356847855, 267174620, 2011827638, + 1572212863, 589049769, 2024853642, 1680251429, 914906004, 398911194, + 795915364, 1332467446, 688483428, 628445699, 578787063, 2006320950, + 1167207852, 336213879, 1640952769, 1778544166, 1617229086, 190807078, + 1968608155, 2122852959, 31153367, 1353144470, 2196420, 1395155215, + 1948121717, 69118708, 2140091269, 2530146, 1740778973, 1601247294, + 1205895814, 858150908, 1878253960, 1967705762, 2090543533, 1702425249, + 622114437, 1192155877, 1095403694, 2115445751, 1201124879, 1140728569, + 2085323316, 1291025252, 871908043, 863647665, 1245819051, 1468486929, + 631022494, 1161580432, 539942311, 1943137808, 1826628136, 259775677, + 277497333, 2140756121, 973493986, 1121800211, 1539560507, 1337406065, + 186178768, 482917205, 1459100749, 1924603748, 390743779, 1140008063, + 517767440, 1764436465, 722260205, 1400929335, 1706528514, 486165509, + 1379460673, 206653795, 3159407, 565150174, 688338919, 1223572435, + 2122262571, 513009937, 1390656632, 271906847, 1622692876, 1313115559, + 2061144988, 411864717, 437710825, 513582947, 305489695, 1713188647, + 387273799, 1901537567, 644842409, 1231932661, 356672421, 232170581, + 1636860706, 302219842, 2094591332, 1697686200, 1390477985, 1833543700, + 1203377492, 50968578, 1332379148, 1514582723, 909273561, 1914809801, + 560663378, 1032914339, 1216475831, 113462155, 1165446977, 800591831, + 1058677375, 432102601, 2131797509, 1175004233, 1602827413, 878884686, + 446372159, 257728183, 800661980, 1387864976, 2004770236, 999229412, + 1428223489, 175843632, 74887898, 630393584, 1147793249, 112648605, + 1028529524, 1891904961, 1953919896, 481563348, 436476038, 1601134240, + 72319656, 1581118537, 460420451, 1904576737, 786297537, 359735266, + 1918354829, 4031164, 1679777458, 1144017176, 1462192184, 690865719, + 1515933932, 363508800, 1480324438, 1044088643, 2036061488, 218671081, + 830595166, 381933797, 108346070, 92271196, 217762975, 1522316172, + 1021014457, 1407094080, 857894203, 1968623233, 1459620801, 1345014111, + 709651138, 520511102, 2048560397, 1768795266, 1013901419, 1709697877, + 1026380990, 1377995642, 1560142576, 542609105, 1534330971, 528024121, + 2015847175, 325324443, 1137511396, 1883999260, 1871060346, 715940689, + 167653495, 1292049996, 1172290275, 2018336444, 1951228823, 1666074170, + 1834852613, 854475547, 308857120, 502558280, 2105718728, 1624653209, + 514214340, 976063110, 227427283, 912381406, 785989696, 451448729, + 212046016, 2068743361, 117280545, 1936668087, 210748671, 1984152603, + 945948973, 1409001936, 1644353864, 1139018167, 678475375, 1279061703, + 723930558, 195379046, 1498554338, 999346398, 1665914525, 1473735214, + 1561422777, 151416112, 697817760, 1622758049, 607761482, 69889880, + 1152335090, 1063657548, 1338090388, 55461678, 1278053582, 837024327, + 1914764659, 1049475248, 161502390, 80404202, 624714335, 879380479, + 1066787659, 1375470750, 1561212123, 59384706, 966363087, 2044016080, + 1178086274, 1159745061, 291298358, 173062659, 1385675177, 652078020, + 1802327778, 1555660285, 623909040, 1579725218, 1649344003, 270814499, + 350182379, 1188076819, 893957771, 534384094, 1057003814, 230634042, + 2117880007, 778834747, 250859482, 104637677, 1328272543, 1869264274, + 1847908587, 311127477, 506466155, 1808237662, 607471900, 1558244592, + 1228817775, 720339756, 1963053072, 1011473945, 1204992245, 566166447, + 419053054, 737377568, 520329478, 1740099311, 1682700783, 1455316979, + 2118805956, 729509794, 1565610678, 722347551, 739596391, 882282387, + 926200942, 999899279, 1318032594, 122124863, 1633512617, 1269707634, + 380070610, 1043920511, 665601851, 873976891, 717911282, 2135673182, + 761851297, 1604330946, 666624765, 513561613, 1504023310, 1128895624, + 99511825, 722919148, 1047336724, 550532376, 1082864732, 289686472, + 216557804, 1174587016, 845698678, 1554106660, 577410402, 790256415, + 675663963, 2029133999, 161450336, 228960529, 743745539, 1352833750, + 2123379476, 852338021, 1291070368, 448708980, 1953450944, 923478775, + 827496819, 1126017956, 197964832, 281317274, 1171925835, 764902582, + 595717488, 2129930580, 1437147036, 1447469119, 755554593, 2130879949, + 1835203128, 1547662666, 1855359256, 965490116, 672323245, 182598318, + 216435361, 1324723894, 1144669754, 454438520, 1220523503, 1520886946, + 1797641070, 1585050246, 797060176, 1821482472, 2128078174, 973367349, + 991874801, 679519053, 1961647235, 2094159153, 391321675, 1604357658, + 576906032, 1712341869, 344515114, 1122768484, 1659079595, 1328885292, + 48775768, 247448424, 1836119534, 1564061243, 1386366954, 485818381, + 37017340, 356546370, 1675494182, 430093707, 1959222232, 1784682542, + 1839063567, 1596042792, 295666215, 403378386, 2114587535, 1515528736, + 1541546082, 1444048519, 1215103809, 1687941280, 1546057655, 1905279500, + 544899032, 2069178089, 1688652157, 1414160501, 332201519, 631936923, + 423299667, 1332937015, 545602285, 310273032, 960982228, 372501343, + 1933532372, 1711569347, 11476473, 155845605, 700725671, 1457464894, + 1325083914, 172109594, 664387510, 1705378439, 376781122, 1472567100, + 343682568, 1370528050, 265363198, 2079492652, 1803183394, 519194709, + 1538391713, 1931493432, 1183464058, 1489699243, 495097609, 801046035, + 177100916, 1292413659, 1348373925, 1550525411, 697685269, 856621012, + 1992941115, 1189141368, 221661515, 156760399, 38620214, 375863194, + 2078528215, 2103236982, 341987235, 698660475, 381094614, 1201152163, + 1275500498, 398211404, 801610475, 1087556673, 846650758, 1848681194, + 1287830283, 1400070607, 1603428054, 1233022905, 810516965, 690710531, + 1860435620, 750631050, 1271370220, 860360715, 1189323192, 1913926325, + 946425090, 1815408878, 743572345, 1902501708, 1276205250, 2005653265, + 624614472, 2108439398, 1952177514, 964348374, 1171051384, 2126963607, + 812288356, 108628319, 980702956, 714456194, 1678967663, 1935271536, + 236851791, 1541132933, 1066014062, 1607628402, 1926717418, 954942098, + 1733982669, 14239125, 1506716966, 848141854, 1178260876, 614222093, + 731606176, 1512135729, 63244522, 968848252, 1783943137, 1402735006, + 1355391150, 1659137391, 1173889730, 1042942541, 1318900244, 1149113346, + 2090025563, 1201659316, 250022739, 1035075488, 674580901, 1090386021, + 1943651015, 934048997, 2087660971, 738682048, 1305071296, 91177380, + 1708106609, 1685880008, 364589031, 1860839427, 1927367009, 906899219, + 1090443335, 892574149, 1969729134, 1874026715, 927045887, 1159898528, + 730296520, 349249331, 317980803, 225908941, 483348027, 1035956563, + 241537930, 1279981214, 1247518755, 247447060, 1793747608, 752388169, + 288054543, 2073482870, 2039012903, 617768643, 433412593, 499898207, + 1050512245, 331284679, 851322111, 1294873695, 1715379173, 1159675637, + 1029338154, 2027445678, 1653332243, 1874855959, 1234157881, 260674360, + 1042790263, 1401980800, 730090881, 1745393357, 1550721460, 1607677838, + 969500483, 778702716, 1765830270, 731763278, 1600023202, 1957728250, + 690983, 444361278, 1278777407, 1231639101, 597427397, 1087245613, + 258177907, 2093472294, 1462778368, 2067100479, 1628387880, 762564955, + 1194041213, 1348361229, 1822279764, 1826590258, 1112056034, 2088786920, + 815110420, 1957877704, 1087195269, 881982271, 1945110368, 1656527154, + 529233847, 137046551, 522408049, 1880577483, 847255974, 851716534, + 925604268, 1037521069, 461527795, 1332620900, 525605961, 1389787451, + 1127911377, 1198857033, 859385989, 706825946, 371790550, 145611377, + 655200896, 1900613055, 1333790305, 1101722351, 1278794420, 2089981667, + 1150780072, 13180701, 1502266386, 1103013140, 343038558, 1897907456, + 1612609979, 1209991461, 1740783613, 1643991754, 977454680, 787842886, + 163362230, 1087742330, 200253206, 1691676526, 360632817, 1787338655, + 35595330, 822635252, 1834254978, 1372169786, 1063768444, 973490494, + 697866347, 156498369, 169293723, 180549009, 112035400, 127867199, + 241711645, 2004664325, 23288667, 1997381015, 736455241, 1986921372, + 1570645300, 2067499753, 1463269859, 148527979, 618168829, 1715279374, + 2066440075, 2118433006, 198233440, 1835860030, 1345873587, 1902595458, + 1961619988, 1291438802, 1325008187, 836983022, 1849657867, 500376868, + 1599565995, 1705905941, 1600493361, 386733714, 1028820236, 1663100626, + 1322696419, 1482983072, 1092382563, 1667679197, 1965855212, 1063839036, + 1742032331, 300191208, 620497725, 503895325, 2094864173, 928179911, + 277942057, 1677449797, 1249086623, 799527371, 1180063064, 48311975, + 1866094167, 1405763119, 2109851473, 1594621666, 580464203, 1752598186, + 1339293088, 922186026, 1403771494, 299505702, 1345987999, 1298200648, + 2128826472, 677220745, 831273447, 741184696, 696188251, 1912065710, + 1016469330, 682018288, 353946286, 559509624, 515414188, 1852181952, + 407771887, 812094461, 1859683061, 1100089300, 498702377, 653626077, + 765701205, 150878039, 328551896, 77104822, 1775331228, 1835977906, + 706357381, 1240287664, 839507573, 1054066034, 1823053058, 701959731, + 82879528, 652404808, 866097476, 926939064, 1326017288, 1747861289, + 1173840088, 1524006589, 443704960, 835506582, 5363460, 2068343250, + 1683915700, 2080735477, 1913489530, 951256529, 1752318678, 105384223, + 1788389051, 1787391786, 1430821640, 540952308, 882484999, 690806365, + 202502890, 1593837351, 530093821, 385878401, 907401151, 378912543, + 454746323, 251514112, 1451277631, 1125822965, 21289266, 1642884452, + 804368379, 2048205721, 917508270, 1514792012, 139494505, 1143168018, + 115016418, 1730333306, 1630776459, 50748643, 1745247524, 1313640711, + 1076198976, 1820281480, 941471466, 806673335, 722162727, 1837280287, + 705508794, 2088955494, 510497580, 51692325, 893597382, 1373978529, + 1007042224, 685006165, 1471461419, 1555325521, 1215063385, 1424859828, + 657251271, 1391827090, 965562483, 604275115, 1285258674, 341475746, + 294191106, 633240394, 1897691227, 1904243956, 823532901, 1577955754, + 2016464961, 1862876260, 577384103, 1012611702, 247243083, 636485510, + 1952805989, 1447876480, 108021700, 1016615447, 2047769687, 943871886, + 787537653, 12744598, 853545598, 334037304, 553373537, 1089408490, + 497867498, 2038925801, 1434633879, 1290629443, 75922980, 957037315, + 2130252471, 477317888, 952824381, 1686570783, 459340678, 751885764, + 836307572, 2027909489, 28791588, 322748588, 1335236478, 787106123, + 113580144, 954915740, 1317077622, 1299667896, 2009244921, 1548588723, + 2049698913, 732388681, 1781891230, 2090684129, 993786972, 1959292396, + 1336513734, 691093904, 1746904676, 935573751, 1123555638, 108413311, + 1445352642, 169726789, 123352211, 1635952299, 673775121, 2042861943, + 757787251, 512494446, 119656942, 58159196, 2090570016, 486181025, + 1619641914, 432990571, 894937325, 379470588, 1890938638, 1886317932, + 1858637614, 969358207, 1230449468, 1890889527, 351741654, 214725897, + 1550012286, 308005013, 26292400, 68067591, 1383307838, 1746273091, + 1090104632, 1658037573, 2081544705, 1133473813, 1680294422, 1050373352, + 1806061681, 1713475126, 520699193, 417568373, 1355086853, 631399565, + 1742434188, 2077667592, 1709019727, 594054971, 937081176, 742185643, + 1904514273, 887841601, 1288684086, 424587711, 1497926365, 829844031, + 1384314543, 250129297, 200083737, 693737559, 1527022962, 1462501905, + 1687540458, 1156824624, 241481265, 1190890142, 1250360726, 2064308502, + 27563032, 1880483834, 1984143440, 104727360, 1324123626, 1089710430, + 1403206383, 1930880552, 773197243, 1160186023, 562994480, 1065136414, + 502237764, 1642338733, 1310177444, 1730721241, 1475638246, 615734453, + 1160537912, 928836931, 253898558, 1799210492, 1205522527, 413058646, + 1589194592, 1774218355, 43955934, 1673314595, 683393460, 1260859787, + 2098829619, 772503535, 1232567659, 758174758, 831270563, 1605294199, + 1660678300, 24379565, 1426483935, 1611558740, 1085326591, 12849216, + 455856722, 878692218, 1910978116, 1382893830, 1950124297, 950009818, + 904287249, 791384486, 1584408128, 210098472, 1110387095, 364620240, + 53868166, 772251062, 472745168, 1133910514, 1715402379, 1445225855, + 1541125975, 149171217, 972058766, 1893095488, 1487620835, 640835502, + 1470285405, 646688705, 988431201, 703130341, 1753125385, 1985895474, + 696002734, 1783233173, 1317201705, 1755204784, 532132334, 1069450170, + 249700039, 524320231, 757959820, 2109052886, 604977130, 1971654864, + 1588222158, 1533496974, 623670976, 1405668251, 1955436051, 1082881617, + 1387039848, 874153641, 1345378476, 1168465459, 2005021017, 234039217, + 473318229, 654912216, 1473166451, 997649666, 801824335, 2052343947, + 1883168929, 185658088, 1389954587, 1725541486, 885873448, 958774566, + 2054212564, 60536525, 1427504270, 1160285859, 1827651881, 1408805003, + 1684018729, 61716770, 844057079, 1011596733, 1521350211, 1581801257, + 907554175, 2022973269, 1125104871, 1312064004, 1466679625, 970194422, + 80900939, 1445279202, 335456148, 510478312, 92860378, 1646704157, + 1650899832, 1533447203, 268087516, 880688023, 1180525723, 1868151949, + 1750955971, 401446720, 540093580, 1022861633, 461442838, 1222554291, + 456462271, 94760711, 1231111410, 2145073408, 1932108837, 300618464, + 2055783490, 980863365, 1308872551, 1010427073, 1399854717, 1217804021, + 934700736, 878744414}; + +type verify_data[DATA_SIZE] = { + 690983, 900852, 2196420, 2530146, 3159407, 3522194, + 3794415, 4031164, 5309142, 5363460, 9736243, 11476473, + 12744598, 12849216, 12937811, 13180701, 13887419, 14125900, + 14239125, 16411608, 19227407, 20643769, 21289266, 22136821, + 22762734, 23288667, 24379565, 25885333, 26292400, 26687179, + 27377406, 27563032, 28256901, 28791588, 30992839, 31153367, + 31574181, 31596852, 35595330, 35859252, 37017340, 37141933, + 38620214, 41714278, 42021322, 43955934, 47036070, 47452797, + 47463938, 48311975, 48775768, 50748643, 50968578, 51692325, + 53868166, 55461678, 58159196, 58217952, 59384706, 60536525, + 61716770, 62209567, 63244522, 64795664, 66579049, 68067591, + 69118708, 69889880, 70003859, 70894786, 72319656, 72802865, + 72939206, 74887898, 75922980, 77104822, 77482422, 78348530, + 80321564, 80404202, 80900939, 81402251, 82879528, 84924801, + 87897457, 88823122, 89400484, 90063199, 91177380, 92271196, + 92620223, 92860378, 93191015, 94760711, 95752736, 99511825, + 104637677, 104727360, 105384223, 106223060, 106595511, 107095939, + 107160610, 108021700, 108346070, 108413311, 108628319, 109035776, + 109526756, 112035400, 112648605, 113462155, 113580144, 114202152, + 115016418, 116766659, 117260224, 117280545, 117766047, 119285206, + 119656942, 122124863, 123352211, 123889599, 127867199, 128036841, + 130001148, 131405125, 133790520, 134453363, 135012885, 135678410, + 137046551, 137796456, 139494505, 140536987, 145611377, 146002907, + 148113917, 148527979, 149171217, 150878039, 151416112, 152273285, + 155845605, 156498369, 156760399, 161450336, 161502390, 163362230, + 167653495, 168771888, 169293723, 169726789, 170281493, 172109594, + 173062659, 173822937, 174082258, 174965839, 175753599, 175843632, + 176024101, 177100916, 178901145, 180549009, 180599971, 181567810, + 182598318, 183679578, 185592115, 185658088, 185979744, 186112992, + 186178768, 188016786, 190215907, 190536346, 190807078, 193873940, + 195379046, 196401930, 197964832, 198186681, 198233440, 200083737, + 200253206, 202502890, 204514903, 205008108, 206653795, 208160226, + 208433088, 210098472, 210748671, 210908782, 212046016, 212821393, + 214725897, 215018112, 216435361, 216557804, 217762975, 218671081, + 221330186, 221661515, 222529745, 225091211, 225908941, 225934851, + 226723092, 226726100, 226906236, 226986415, 227427283, 227870124, + 228960529, 229905664, 230340298, 230634042, 231181585, 232170581, + 234039217, 236851791, 237020443, 238278880, 238566180, 239990424, + 240618723, 241481265, 241537930, 241711645, 244709448, 244975305, + 245334962, 247243083, 247447060, 247448424, 249700039, 250022739, + 250129297, 250731366, 250859482, 251514112, 253898558, 255226842, + 256210446, 256860662, 257728183, 258177907, 259768753, 259775677, + 260267972, 260670135, 260674360, 260792255, 261556590, 265363198, + 267174620, 268087516, 269167950, 270410557, 270814499, 271906847, + 274746405, 277497333, 277942057, 279252402, 281317274, 283430575, + 284658041, 287497702, 288054543, 289686472, 291298358, 293109484, + 294191106, 295666215, 298799048, 299505702, 300191208, 300618464, + 301350822, 301663421, 301673313, 302219842, 303845878, 304131252, + 304211060, 304427548, 305489695, 305750851, 308005013, 308700094, + 308832070, 308857120, 310273032, 311127477, 316479300, 317980803, + 318750634, 320137025, 322748588, 324215873, 325324443, 325667019, + 328551896, 329049266, 329767814, 330474090, 331284679, 332201519, + 333820982, 333906659, 334037304, 335456148, 336213879, 338532526, + 340231765, 340442582, 341475746, 341674967, 341987235, 343038558, + 343119399, 343682568, 344515114, 344860208, 346598567, 348131466, + 349249331, 350182379, 351741654, 353946286, 355614494, 356546370, + 356638683, 356672421, 359735266, 360632817, 362748128, 363508800, + 364589031, 364620240, 365275089, 365854486, 366700722, 367923081, + 368541415, 368889391, 371790550, 372280769, 372465453, 372501343, + 373226849, 373305330, 375863194, 376781122, 378912543, 379470588, + 380070610, 381094614, 381571915, 381933797, 382422699, 385878401, + 386733714, 387061281, 387273799, 387611445, 388855203, 389233190, + 390743779, 391321675, 395360213, 398211404, 398244682, 398911194, + 399114073, 399456957, 399991238, 401446720, 402845420, 403378386, + 407771887, 411864717, 413058646, 416457166, 417568373, 419053054, + 419109342, 419476096, 420106224, 421198539, 422047044, 423299667, + 424587711, 430093707, 432102601, 432609664, 432990571, 433412593, + 434850545, 435236973, 435288306, 436476038, 436580096, 436630343, + 437710825, 438711458, 443704960, 444361278, 446372159, 448284065, + 448708980, 451448729, 452888789, 454359988, 454438520, 454746323, + 455856722, 456462271, 459340678, 460420451, 460893030, 461442838, + 461527795, 462743614, 462857778, 464171383, 464795711, 465119445, + 470090505, 472745168, 472872107, 473318229, 477317888, 477407584, + 478721193, 481561285, 481563348, 482917205, 483348027, 485818381, + 486165509, 486181025, 487888229, 490920543, 492507266, 494367164, + 495097609, 497867498, 498702377, 499898207, 500376868, 500734709, + 502237764, 502323961, 502558280, 503368137, 503895325, 506466155, + 507848158, 507936866, 508041515, 509116230, 509744705, 510478312, + 510497580, 512494446, 513009937, 513561613, 513582947, 514214340, + 514914429, 515414188, 515811664, 517767440, 518073650, 519194709, + 519344323, 519699747, 520329478, 520511102, 520699193, 522160389, + 522408049, 524320231, 525605961, 528024121, 529233847, 530093821, + 532132334, 532467027, 533101409, 534384094, 535828217, 536063430, + 538932155, 539429964, 539942311, 540006359, 540093580, 540952308, + 542609105, 543952312, 544899032, 545066288, 545602285, 546340809, + 548632788, 549253917, 550532376, 553373537, 556328195, 559509624, + 560663378, 562994480, 565150174, 566166447, 567779677, 568652142, + 569949159, 571635069, 572240371, 574236644, 576906032, 577384103, + 577410402, 578787063, 579174666, 580464203, 580692625, 583112200, + 585169793, 585804640, 589049769, 590690783, 592006699, 592234826, + 594054971, 594814862, 595717488, 597427397, 598016845, 602368560, + 602907378, 603159718, 603907009, 604275115, 604977130, 607471900, + 607761482, 612289854, 614222093, 614612685, 615734453, 617768643, + 617995659, 618168829, 618681206, 619428858, 619461174, 619972089, + 620497725, 621921213, 622114437, 622170346, 623670976, 623909040, + 624614472, 624714335, 624939139, 625991894, 628445699, 630393584, + 631022494, 631399565, 631936923, 632611704, 633075975, 633240394, + 636485510, 637659983, 638167485, 640835502, 644293952, 644842409, + 646688705, 649754857, 650513248, 651536866, 651750790, 652078020, + 652404808, 653050943, 653626077, 654912216, 655200896, 655445946, + 656954306, 657251271, 661318748, 664387510, 665601851, 666624765, + 670621648, 671848647, 672323245, 672906535, 673775121, 674580901, + 675549432, 675663963, 677220745, 678475375, 679519053, 680172541, + 682018288, 683393460, 683536723, 685006165, 686797873, 687941098, + 688338919, 688483428, 690710531, 690806365, 690865719, 691093904, + 692845661, 693737559, 696002734, 696188251, 696448050, 697685269, + 697817760, 697866347, 698660475, 700725671, 701959731, 702380578, + 703130341, 705508794, 705851791, 706357381, 706825946, 706913763, + 709651138, 714042223, 714456194, 715940689, 717911282, 720339756, + 721046824, 721524505, 722162727, 722260205, 722347551, 722919148, + 723323690, 723930558, 726141970, 726869128, 727587915, 729474445, + 729509794, 730090881, 730296520, 730422541, 730845665, 731606176, + 731763278, 732388681, 732444124, 736455241, 737377568, 737518341, + 738682048, 739596391, 740536012, 741078359, 741184696, 742185643, + 743572345, 743745539, 745183293, 745777837, 747592875, 748527394, + 749415493, 750631050, 750919339, 751885764, 752388169, 753296935, + 754215794, 754247044, 754896618, 755554593, 755798022, 757787251, + 757959820, 758174758, 761851297, 762564955, 764902582, 764935753, + 765386206, 765701205, 767233910, 767880329, 768185796, 769005536, + 770412991, 770957259, 772059719, 772251062, 772503535, 773197243, + 777433215, 778702716, 778834747, 779093898, 783427298, 785398708, + 785989696, 786297537, 786566648, 787106123, 787537653, 787842886, + 787913688, 790256415, 790929190, 791188057, 791384486, 793505636, + 795915364, 797060176, 798445606, 799527371, 799717076, 800591831, + 800661980, 801046035, 801610475, 801824335, 802730854, 804368379, + 806384435, 806638567, 806673335, 809604334, 810387144, 810516965, + 812094461, 812288356, 812328969, 813511681, 814302898, 815110420, + 817417567, 820933470, 821481684, 822635252, 823532901, 827496819, + 829450571, 829844031, 830595166, 831270563, 831273447, 832081018, + 833019845, 834410115, 835063788, 835506582, 836307572, 836983022, + 837024327, 837554186, 839507573, 840106059, 843738737, 844057079, + 845698678, 846127236, 846650758, 847255974, 848141854, 848402819, + 849489374, 851322111, 851716534, 852338021, 852388468, 852835634, + 853545598, 854475547, 855107605, 856621012, 856837002, 857894203, + 858045289, 858150908, 859385989, 859612092, 860360715, 863551327, + 863647665, 866097476, 866478506, 866854601, 866964848, 867628573, + 869853078, 871908043, 873623623, 873976891, 874153641, 875481479, + 876130333, 878692218, 878744414, 878884686, 879380479, 879552408, + 879878312, 880456526, 880688023, 881982271, 882282387, 882484999, + 885873448, 886978116, 887841601, 890461390, 891710357, 892574149, + 892939912, 893302687, 893597382, 893957771, 894769708, 894937325, + 895080280, 895562064, 898893218, 901789102, 904287249, 906899219, + 907401151, 907554175, 909273561, 909415369, 910677024, 912381406, + 914906004, 915948205, 916073297, 917508270, 918378387, 919736727, + 921573402, 922186026, 923478775, 923768127, 924541465, 925604268, + 925975225, 926200942, 926939064, 927045887, 927524181, 928179911, + 928836931, 929351822, 930367387, 932423857, 933603111, 933673987, + 934048997, 934700736, 935490932, 935573751, 935689637, 935939763, + 937081176, 937976428, 937987129, 939497524, 941471466, 942977997, + 943871886, 944382193, 945948973, 946311527, 946425090, 946489895, + 948686793, 949010757, 949222447, 950009818, 951256529, 951663731, + 952824381, 953383750, 953877041, 954441852, 954915740, 954942098, + 957037315, 958774566, 959354209, 960982228, 964348374, 965490116, + 965562483, 966363087, 968848252, 969076419, 969305448, 969358207, + 969500483, 970194422, 972058766, 973367349, 973490494, 973493986, + 973769771, 976015092, 976063110, 977454680, 977907387, 978247260, + 980702956, 980863365, 983043723, 985305323, 986240059, 987761406, + 988431201, 991159735, 991874801, 992410365, 993525189, 993786972, + 994291574, 997649666, 998931662, 999229412, 999346398, 999899279, + 1007042224, 1010427073, 1011417836, 1011473945, 1011596733, 1012611702, + 1013901419, 1016469330, 1016615447, 1020037994, 1021014457, 1022861633, + 1025117441, 1026342885, 1026380990, 1027758817, 1027760887, 1028529524, + 1028820236, 1028937430, 1029176122, 1029338154, 1029832956, 1031625002, + 1032748996, 1032914339, 1033910502, 1035075488, 1035956563, 1037521069, + 1038018856, 1038830638, 1042790263, 1042942541, 1043920511, 1044088643, + 1045627895, 1045658065, 1047336724, 1048943084, 1049475248, 1050373352, + 1050512245, 1051184301, 1054066034, 1057003814, 1058677375, 1058937717, + 1061864942, 1063657548, 1063743848, 1063768444, 1063839036, 1065136414, + 1065481253, 1066014062, 1066787659, 1067775613, 1068587688, 1068798385, + 1069450170, 1073695485, 1073871430, 1074205225, 1075762632, 1076198976, + 1078197595, 1079859867, 1082499152, 1082864732, 1082881617, 1085326591, + 1087195269, 1087245613, 1087251698, 1087556673, 1087742330, 1089408490, + 1089710430, 1090104632, 1090386021, 1090443335, 1092382563, 1092881031, + 1094283114, 1094531762, 1095403694, 1099847920, 1100041120, 1100089300, + 1101722351, 1101933540, 1102423908, 1102603775, 1103013140, 1106678970, + 1110387095, 1111213862, 1112056034, 1112731797, 1113693824, 1120963974, + 1121432739, 1121800211, 1121960111, 1122768484, 1123331233, 1123555638, + 1125104871, 1125822965, 1126017956, 1127173529, 1127911377, 1128895624, + 1130850177, 1131661227, 1132597050, 1133473813, 1133910514, 1134185180, + 1135793759, 1136264020, 1136356724, 1137511396, 1139018167, 1139159604, + 1140008063, 1140728569, 1143168018, 1143511498, 1143853106, 1144017176, + 1144669754, 1147341731, 1147793249, 1148699143, 1149113346, 1150780072, + 1152335090, 1152416171, 1154842325, 1155459206, 1155544307, 1156824624, + 1157666831, 1159675637, 1159745061, 1159898528, 1160036198, 1160186023, + 1160285859, 1160333307, 1160537912, 1161580432, 1162679490, 1165446977, + 1166227930, 1167207852, 1168465459, 1169327477, 1170510314, 1170759710, + 1171051384, 1171925835, 1172290275, 1173840088, 1173889730, 1174587016, + 1175004233, 1175885101, 1178086274, 1178260876, 1179525294, 1180063064, + 1180525723, 1181191604, 1183464058, 1184561748, 1185825535, 1188076819, + 1188748563, 1189141368, 1189323192, 1190890142, 1191079043, 1191513656, + 1192155877, 1194041213, 1194709162, 1198213061, 1198254803, 1198857033, + 1199317660, 1201124879, 1201152163, 1201659316, 1202009920, 1202162389, + 1203377492, 1203897636, 1204992245, 1205522527, 1205895814, 1206302514, + 1209784819, 1209991461, 1212628403, 1212974417, 1214379246, 1214950832, + 1215063385, 1215103809, 1216475831, 1217804021, 1218522465, 1220523503, + 1220915309, 1221108420, 1221726287, 1222554291, 1223475486, 1223572435, + 1223583276, 1228817775, 1230449468, 1231111410, 1231149357, 1231249235, + 1231639101, 1231932661, 1232567659, 1232992084, 1233022905, 1234157881, + 1234944834, 1239665569, 1240287664, 1245819051, 1247518755, 1249086623, + 1249183285, 1250360726, 1255524953, 1256015513, 1256152080, 1256372950, + 1257507406, 1260859787, 1262399341, 1267173039, 1269707634, 1271370220, + 1273223611, 1273955724, 1274190723, 1274436639, 1275331596, 1275500498, + 1276205250, 1278053582, 1278777407, 1278794420, 1279061703, 1279981214, + 1281443423, 1285258674, 1286989824, 1287171290, 1287830283, 1288684086, + 1289308008, 1290629443, 1290969161, 1291025252, 1291070368, 1291438802, + 1292049996, 1292413659, 1293091635, 1294873695, 1296857499, 1298200648, + 1299667896, 1302272656, 1302724177, 1303736105, 1305071296, 1308872551, + 1310177444, 1312064004, 1312471120, 1313115559, 1313640711, 1313871880, + 1316120929, 1317077622, 1317201705, 1318032594, 1318900244, 1319798607, + 1321897861, 1322281086, 1322696419, 1323798820, 1324123626, 1324723894, + 1325008187, 1325083914, 1326017288, 1328272543, 1328885292, 1331383316, + 1331593955, 1332379148, 1332467446, 1332620900, 1332937015, 1333790305, + 1334857284, 1335236478, 1335298265, 1335652095, 1335861008, 1336108161, + 1336513734, 1337406065, 1338090388, 1339293088, 1340949553, 1344125357, + 1345014111, 1345378476, 1345873587, 1345987999, 1347284277, 1348361229, + 1348373925, 1350653461, 1352833750, 1353144470, 1353999206, 1355086853, + 1355391150, 1356847855, 1361012693, 1361078114, 1365423458, 1367731096, + 1368235387, 1370528050, 1372169786, 1373978529, 1374125186, 1375470750, + 1377995642, 1379259015, 1379460673, 1379995885, 1382429941, 1382484003, + 1382551511, 1382893830, 1383307838, 1383640563, 1384314543, 1385675177, + 1386258142, 1386366954, 1387039848, 1387864976, 1388759892, 1389787451, + 1389954587, 1390040163, 1390274260, 1390306889, 1390477985, 1390656632, + 1391095995, 1391827090, 1392162662, 1394929399, 1395155215, 1395289708, + 1396662140, 1399673078, 1399854717, 1400070607, 1400929335, 1401058771, + 1401980800, 1402735006, 1403206383, 1403771494, 1404727477, 1405668251, + 1405763119, 1407094080, 1408805003, 1409001936, 1412540552, 1413860940, + 1414141069, 1414160501, 1415390230, 1417415680, 1417601340, 1420810050, + 1424797596, 1424859828, 1426483935, 1427504270, 1428223489, 1430821640, + 1431492783, 1431814151, 1434046375, 1434633879, 1435859758, 1437147036, + 1440145706, 1441811554, 1444048519, 1444076976, 1445225855, 1445279202, + 1445352642, 1447469119, 1447876480, 1450892344, 1451277631, 1451442832, + 1453397990, 1455316979, 1455756978, 1457464894, 1459100749, 1459138745, + 1459500136, 1459620801, 1462192184, 1462501905, 1462778368, 1462921857, + 1463269859, 1466632447, 1466679625, 1467376771, 1468486929, 1470285405, + 1471131758, 1471461419, 1471598258, 1472567100, 1473166451, 1473735214, + 1475638246, 1480273562, 1480324438, 1480437960, 1482983072, 1485740112, + 1486594282, 1487620835, 1489699243, 1491477359, 1492071476, 1492488573, + 1496078411, 1496277718, 1497680539, 1497926365, 1498554338, 1500102591, + 1501181424, 1502266386, 1502480836, 1502557594, 1504023310, 1505022272, + 1505475223, 1506716966, 1507433029, 1508705426, 1510133268, 1512135729, + 1512163910, 1513255537, 1514278798, 1514582723, 1514792012, 1515262458, + 1515528736, 1515933932, 1519017268, 1520667645, 1520886946, 1521350211, + 1522316172, 1524006589, 1524491858, 1525451290, 1527022962, 1528031307, + 1533447203, 1533496974, 1534330971, 1536213818, 1537459540, 1538069400, + 1538391713, 1539560507, 1541125975, 1541132933, 1541546082, 1545555937, + 1546057655, 1546104436, 1547662666, 1548588723, 1548804416, 1550012286, + 1550159640, 1550525411, 1550721460, 1551661799, 1553547892, 1554106660, + 1555325521, 1555660285, 1558244592, 1558695709, 1560142576, 1561212123, + 1561251584, 1561422777, 1561730727, 1563717683, 1564061243, 1565610678, + 1565700239, 1566878909, 1568176414, 1568395337, 1568900638, 1569479928, + 1570645300, 1571598133, 1572212863, 1575380740, 1577034674, 1577955754, + 1579725218, 1581062145, 1581118537, 1581801257, 1584408128, 1585050246, + 1588222158, 1588715179, 1589194592, 1590461855, 1590771096, 1593359038, + 1593837351, 1594621666, 1596042792, 1596821127, 1597506096, 1598436917, + 1599565995, 1599876594, 1600023202, 1600493361, 1601134240, 1601247294, + 1601617797, 1602517354, 1602827413, 1602967659, 1603428054, 1604330946, + 1604357658, 1605294199, 1605369007, 1607204293, 1607515830, 1607628402, + 1607677838, 1609955669, 1610244183, 1610539590, 1611500622, 1611558740, + 1611680320, 1612593993, 1612609979, 1614780688, 1617229086, 1618378831, + 1619598456, 1619641914, 1620562432, 1620803320, 1622692876, 1622758049, + 1624653209, 1627355806, 1628387880, 1628389501, 1629633514, 1629914848, + 1630293700, 1630776459, 1631405417, 1631935240, 1633512617, 1634445325, + 1635952299, 1636203720, 1636860706, 1640952769, 1642338733, 1642884452, + 1643991754, 1644353864, 1645969422, 1646704157, 1648575360, 1649344003, + 1649392096, 1650899832, 1652108025, 1653332243, 1655277291, 1656527154, + 1657001479, 1658037573, 1659079595, 1659137391, 1660678300, 1663100626, + 1663890071, 1665914525, 1666074170, 1667102296, 1667679197, 1672192305, + 1673314595, 1674045273, 1675300017, 1675494182, 1677449797, 1678967663, + 1679324299, 1679777458, 1680251429, 1680294422, 1681866717, 1682700783, + 1683915700, 1684018729, 1685350721, 1685880008, 1686215900, 1686479103, + 1686570783, 1687540458, 1687941280, 1688652157, 1689946986, 1690167792, + 1691486500, 1691676526, 1695191950, 1695617313, 1697686200, 1702425249, + 1704561346, 1705378439, 1705905941, 1706528514, 1708002892, 1708106609, + 1708126014, 1709019727, 1709697877, 1709823304, 1710305778, 1711569347, + 1711718534, 1711761015, 1711765426, 1712269139, 1712341869, 1713188647, + 1713475126, 1714295540, 1715279374, 1715379173, 1715402379, 1716853034, + 1719009954, 1719573683, 1721767511, 1723143470, 1725541486, 1726987516, + 1727583308, 1730333306, 1730721241, 1731949250, 1732028080, 1733366374, + 1733982669, 1737931879, 1738353358, 1740099311, 1740778973, 1740783613, + 1742032331, 1742434188, 1745247524, 1745393357, 1745543275, 1746273091, + 1746476698, 1746904676, 1747861289, 1749972876, 1750197960, 1750443194, + 1750955971, 1752088215, 1752318678, 1752598186, 1753125385, 1754447491, + 1755204784, 1757028186, 1758748737, 1760851607, 1761289401, 1763785295, + 1764436465, 1765354961, 1765830270, 1767380006, 1768795266, 1770497338, + 1771614266, 1771924274, 1772760484, 1774218355, 1774652096, 1774796872, + 1775331228, 1775608361, 1775805177, 1776471922, 1776794410, 1778544166, + 1781233744, 1781891230, 1783233173, 1783943137, 1784682542, 1787338655, + 1787391786, 1788389051, 1790557628, 1792756324, 1793190956, 1793747608, + 1797641070, 1799210492, 1800186189, 1800522575, 1802197319, 1802327778, + 1803183394, 1806061681, 1807085904, 1807172811, 1808237662, 1811088032, + 1815408878, 1816641611, 1817156134, 1820281480, 1821482472, 1821559709, + 1822279764, 1822612008, 1823053058, 1826590258, 1826628136, 1826880531, + 1827651881, 1833543700, 1833603743, 1834161399, 1834254978, 1834285819, + 1834318089, 1834388383, 1834852613, 1835203128, 1835860030, 1835977906, + 1836119534, 1837280287, 1838218199, 1839063567, 1840896199, 1846605728, + 1847908587, 1848681194, 1849495275, 1849657867, 1849675857, 1852181952, + 1855359256, 1858637614, 1858933377, 1859683061, 1860435620, 1860839427, + 1862876260, 1864952910, 1866094167, 1868151949, 1868289345, 1869264274, + 1870214195, 1870859970, 1871060346, 1871684562, 1873900475, 1874026715, + 1874855959, 1876255297, 1878253960, 1878434988, 1879635915, 1880483834, + 1880577483, 1881253854, 1883168929, 1883999260, 1886317932, 1890889527, + 1890938638, 1891630185, 1891904961, 1892370478, 1893095488, 1896952705, + 1897691227, 1897907456, 1898582764, 1900162831, 1900613055, 1901537567, + 1902501708, 1902595458, 1904243956, 1904514273, 1904576737, 1904770864, + 1905279500, 1906345724, 1907793490, 1908093581, 1909681194, 1910978116, + 1912065710, 1913489530, 1913581092, 1913926325, 1914764659, 1914809801, + 1915435344, 1916602098, 1918354829, 1920182565, 1924603748, 1926717418, + 1927367009, 1928309762, 1928550562, 1930662128, 1930880552, 1931282005, + 1931493432, 1932108837, 1933532372, 1933923245, 1935271536, 1936668087, + 1938258683, 1939683211, 1942089394, 1943137808, 1943651015, 1944679691, + 1945110368, 1946004194, 1948121717, 1949896838, 1950124297, 1951228823, + 1952177514, 1952364329, 1952805989, 1953450944, 1953919896, 1955436051, + 1957728250, 1957877704, 1958396887, 1959222232, 1959292396, 1961619988, + 1961647235, 1962689485, 1963053072, 1965358941, 1965855212, 1967705762, + 1968608155, 1968623233, 1969729134, 1970797151, 1971484382, 1971654864, + 1977865396, 1980923963, 1981481446, 1983379601, 1984143440, 1984152603, + 1985895474, 1986921372, 1989240516, 1992941115, 1994402695, 1997381015, + 2001056977, 2002881120, 2004664325, 2004770236, 2005021017, 2005653265, + 2005817027, 2006320950, 2006856683, 2009244921, 2010549018, 2011827638, + 2014090929, 2014129292, 2015847175, 2016161810, 2016464961, 2017191527, + 2018336444, 2022291557, 2022973269, 2023498746, 2024853642, 2027445678, + 2027814180, 2027828650, 2027909489, 2028116487, 2029133999, 2029909894, + 2033003588, 2033828953, 2034767768, 2036061488, 2036750157, 2037182006, + 2038925801, 2039012903, 2041942843, 2042861943, 2044016080, 2045407567, + 2045821218, 2046759770, 2047006719, 2047769687, 2048205721, 2048560397, + 2049698913, 2052321529, 2052328978, 2052343947, 2053899162, 2054212564, + 2055783490, 2060969286, 2061144988, 2063408339, 2064145552, 2064308502, + 2066440075, 2066865713, 2067100479, 2067499753, 2068343250, 2068743361, + 2069178089, 2070467093, 2072440819, 2073482870, 2074840378, 2074896270, + 2076612603, 2077667592, 2078528215, 2079492652, 2080735477, 2081544705, + 2082760612, 2084953915, 2085323316, 2087660971, 2088576982, 2088786920, + 2088955494, 2089981667, 2090025563, 2090543533, 2090570016, 2090684129, + 2091626028, 2093472294, 2094085507, 2094159153, 2094591332, 2094864173, + 2097057488, 2098829619, 2100497812, 2103236982, 2105321510, 2105638337, + 2105718728, 2105814934, 2108439398, 2109052886, 2109530615, 2109851473, + 2113434968, 2114587535, 2115445751, 2116495484, 2117880007, 2118203528, + 2118433006, 2118805956, 2118821565, 2119425672, 2122262571, 2122852959, + 2123379476, 2124749673, 2125958841, 2126029304, 2126940990, 2126963607, + 2128078174, 2128826472, 2129513521, 2129930580, 2130252471, 2130879949, + 2131761201, 2131797509, 2133066804, 2135673182, 2139976479, 2140091269, + 2140756121, 2141591317, 2142357746, 2143324534, 2143343312, 2143968639, + 2145073408, 2145930822}; diff --git a/test/SimTests/C/CImpl/qsort/qsort.c b/test/SimTests/C/CImpl/qsort/qsort.c new file mode 100644 index 0000000..e8ffebd --- /dev/null +++ b/test/SimTests/C/CImpl/qsort/qsort.c @@ -0,0 +1,179 @@ +// See LICENSE for license details. + +//************************************************************************** +// Quicksort benchmark +//-------------------------------------------------------------------------- +// +// This benchmark uses quicksort to sort an array of integers. The +// implementation is largely adapted from Numerical Recipes for C. The +// input data (and reference data) should be generated using the +// qsort_gendata.pl perl script and dumped to a file named +// dataset1.h. + +// The INSERTION_THRESHOLD is the size of the subarray when the +// algorithm switches to using an insertion sort instead of +// quick sort. + +typedef unsigned size_t; + +#define INSERTION_THRESHOLD 10 + +// NSTACK is the required auxiliary storage. +// It must be at least 2*lg(DATA_SIZE) + +#define NSTACK 50 + +//-------------------------------------------------------------------------- +// Input/Reference Data + +#define type int +#include "dataset1.h" + +// Swap macro for swapping two values. + +#define SWAP(a, b) \ + do { \ + typeof(a) temp = (a); \ + (a) = (b); \ + (b) = temp; \ + } while (0) +#define SWAP_IF_GREATER(a, b) \ + do { \ + if ((a) > (b)) \ + SWAP(a, b); \ + } while (0) + +//-------------------------------------------------------------------------- +// Quicksort function + +static void insertion_sort(size_t n, type arr[]) { + type *i, *j; + type value; + for (i = arr + 1; i < arr + n; i++) { + value = *i; + j = i; + while (value < *(j - 1)) { + *j = *(j - 1); + if (--j == arr) { + break; + } + } + *j = value; + } +} + +static void selection_sort(size_t n, type arr[]) { + for (type *i = arr; i < arr + n - 1; i++) { + for (type *j = i + 1; j < arr + n; j++) { + SWAP_IF_GREATER(*i, *j); + } + } +} + +void sort(size_t n, type arr[]) { + type *ir = arr + n; + type *l = arr + 1; + type *stack[NSTACK]; + type **stackp = stack; + + for (;;) { + // Insertion sort when subarray small enough. + if (ir - l < INSERTION_THRESHOLD) { + insertion_sort(ir - l + 1, l - 1); + + if (stackp == stack) { + break; + } + + // Pop stack and begin a new round of partitioning. + ir = *stackp--; + l = *stackp--; + } else { + // Choose median of left, center, and right elements as + // partitioning element a. Also rearrange so that a[l-1] <= a[l] <= + // a[ir-]. + SWAP(arr[((l - arr) + (ir - arr)) / 2 - 1], l[0]); + SWAP_IF_GREATER(l[-1], ir[-1]); + SWAP_IF_GREATER(l[0], ir[-1]); + SWAP_IF_GREATER(l[-1], l[0]); + + // Initialize pointers for partitioning. + type *i = l + 1; + type *j = ir; + + // Partitioning element. + type a = l[0]; + + for (;;) { // Beginning of innermost loop. + while (*i++ < a) + ; // Scan up to find element > a. + while (*(j-- - 2) > a) + ; // Scan down to find element < a. + if (j < i) { + break; // Pointers crossed. Partitioning complete. + } + SWAP(i[-1], j[-1]); // Exchange elements. + } // End of innermost loop. + + // Insert partitioning element. + l[0] = j[-1]; + j[-1] = a; + stackp += 2; + + // Push pointers to larger subarray on stack, + // process smaller subarray immediately. + + if (ir - i + 1 >= j - l) { + stackp[0] = ir; + stackp[-1] = i; + ir = j - 1; + } else { + stackp[0] = j - 1; + stackp[-1] = l; + l = i; + } + } + } +} + +//-------------------------------------------------------------------------- +// Main + +static int verify(int n, const int *test, const int *verify) { + int i; + // Unrolled for faster verification + for (i = 0; i < n / 2 * 2; i += 2) { + int t0 = test[i], t1 = test[i + 1]; + int v0 = verify[i], v1 = verify[i + 1]; + if (t0 != v0) { + return i + 1; + } + if (t1 != v1) { + return i + 2; + } + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) { + return n; + } + return 0; +} + +int start() { +#if PREALLOCATE + // If needed we preallocate everything in the caches + sort(DATA_SIZE, verify_data); + if (verify(DATA_SIZE, input_data, input_data)) { + return 1; + } +#endif + + // Do the sort + // setStats(1); + sort(DATA_SIZE, input_data); + // setStats(0); + + // Check the results + return verify(DATA_SIZE, input_data, verify_data); +} + +int main() { start(); } diff --git a/test/SimTests/C/CMakeLists.txt b/test/SimTests/C/CMakeLists.txt new file mode 100644 index 0000000..7b4c391 --- /dev/null +++ b/test/SimTests/C/CMakeLists.txt @@ -0,0 +1,33 @@ +project(c-simtests) + +if(PROTEA_BUILD_TESTS) + string(TOLOWER ${TARGET_NAME} TARGET_NAME_LOWER) + set(TARGET_TOOLCHAIN_FILE ${protea_SOURCE_DIR}/cmake/toolchain/${TARGET_NAME_LOWER}.cmake) + set(DEFAULT_ARGS + -DTARGET_NAME=${TARGET_NAME} + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE:STRING=Release + -DCMAKE_TOOLCHAIN_FILE:PATH=${TARGET_TOOLCHAIN_FILE}) + if (DEFINED ${TARGET_NAME}_TOOLCHAIN_DIR) + list(APPEND DEFAULT_ARGS -D${TARGET_NAME}_TOOLCHAIN_DIR:PATH=${${TARGET_NAME}_TOOLCHAIN_DIR}) + endif() + + set(TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CImpl) + set(GENERATED_SIM_BIN_PATH ${protea_simgen_BINARY_DIR}/sim) + + ExternalProject_Add( + c-simtestsimpl + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CImpl + BINARY_DIR ${TESTS_BINARY_DIR} + CONFIGURE_HANDLED_BY_BUILD True + BUILD_ALWAYS True + CMAKE_ARGS ${DEFAULT_ARGS} + INSTALL_COMMAND "") + + set(RunTests ${tests-common_SOURCE_DIR}/RunTests.py) + + add_custom_target(${PROJECT_NAME} + COMMAND ${Python3_EXECUTABLE} ${RunTests} ${GENERATED_SIM_BIN_PATH} ${TESTS_BINARY_DIR}/bin/ + COMMENT "Running ${PROJECT_NAME}") + add_dependencies(${PROJECT_NAME} sim c-simtestsimpl) +endif() diff --git a/test/SimTests/CMakeLists.txt b/test/SimTests/CMakeLists.txt new file mode 100644 index 0000000..684dd7b --- /dev/null +++ b/test/SimTests/CMakeLists.txt @@ -0,0 +1,9 @@ +project(simtests) + +add_subdirectory(Common) + +add_subdirectory(C) +add_subdirectory(SnippetBased) + +add_custom_target(${PROJECT_NAME}) +add_dependencies(${PROJECT_NAME} c-simtests snippetbased-simtests) diff --git a/test/SimTests/Common/CMakeLists.txt b/test/SimTests/Common/CMakeLists.txt new file mode 100644 index 0000000..ed42ad0 --- /dev/null +++ b/test/SimTests/Common/CMakeLists.txt @@ -0,0 +1 @@ +project(tests-common) diff --git a/test/SimTests/Common/RunTests.py b/test/SimTests/Common/RunTests.py new file mode 100644 index 0000000..b0061f7 --- /dev/null +++ b/test/SimTests/Common/RunTests.py @@ -0,0 +1,41 @@ +import sys +import os +import subprocess +import re + +program = sys.argv[1] +directory = sys.argv[2] + +if not os.path.isdir(directory): + print(f"Error: Directory '{directory}' does not exist.") + sys.exit(1) + +has_error = False + +for filename in os.listdir(directory): + filepath = os.path.join(directory, filename) + if os.path.isfile(filepath): + print(f"Running {program} on {filepath}") + try: + result = subprocess.run([program, filepath], capture_output=True, text=True) + except Exception as e: + print(f"Error: Failed to run {program} on {filepath}: {e}") + has_error = True + continue + + match = re.search(r"Exiting with code (\d+)", result.stdout) + if match: + exit_code = int(match.group(1)) + if exit_code != 0: + print(f"Error: {program} reported exit code {exit_code} for file {filepath}") + has_error = True + else: + print(f"Error: Could not find exit code in output for file {filepath}") + has_error = True + +if has_error: + print("Errors detected during execution.") + sys.exit(1) +else: + print("All files processed successfully.") + sys.exit(0) diff --git a/test/SimTests/SnippetBased/CMakeLists.txt b/test/SimTests/SnippetBased/CMakeLists.txt new file mode 100644 index 0000000..bc0d9ab --- /dev/null +++ b/test/SimTests/SnippetBased/CMakeLists.txt @@ -0,0 +1,37 @@ +project(snippetbased-simtests) + +if(PROTEA_BUILD_TESTS) + string(TOLOWER ${TARGET_NAME} TARGET_NAME_LOWER) + set(TARGET_TOOLCHAIN_FILE ${protea_SOURCE_DIR}/cmake/toolchain/${TARGET_NAME_LOWER}.cmake) + set(DEFAULT_ARGS + -DTARGET_NAME=${TARGET_NAME} + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE:STRING=Release + -DCMAKE_TOOLCHAIN_FILE:PATH=${TARGET_TOOLCHAIN_FILE}) + if (DEFINED ${TARGET_NAME}_TOOLCHAIN_DIR) + list(APPEND DEFAULT_ARGS -D${TARGET_NAME}_TOOLCHAIN_DIR:PATH=${${TARGET_NAME}_TOOLCHAIN_DIR}) + endif() + + set(TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/SnippetBasedImpl) + set(OUTPUT_TESTS_DIR ${CMAKE_CURRENT_BINARY_DIR}/compiled_tests) + + set(RunTests ${tests-common_SOURCE_DIR}/RunTests.py) + set(GENERATED_SIM_BIN_PATH ${protea_simgen_BINARY_DIR}/sim) + + ExternalProject_Add( + snippetbased-simtestsimpl + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/SnippetBasedImpl + BINARY_DIR ${TESTS_BINARY_DIR} + CONFIGURE_HANDLED_BY_BUILD True + BUILD_ALWAYS True + CMAKE_ARGS ${DEFAULT_ARGS} -DQEMU_PATH=${QEMU_PATH} -DBUNDLE_PATH=${BUNDLE_PATH} -DIR_PATH=${protea_irgen_BINARY_DIR}/IR.yaml -DTARGET_NAME=${TARGET_NAME} -DOUTPUT_TESTS_DIR=${OUTPUT_TESTS_DIR} + INSTALL_COMMAND "") + + add_dependencies(snippetbased-simtestsimpl protea_irgen sim) + + add_custom_target(${PROJECT_NAME} + COMMAND ${Python3_EXECUTABLE} ${RunTests} ${GENERATED_SIM_BIN_PATH} ${OUTPUT_TESTS_DIR} + COMMENT "Running ${PROJECT_NAME}") + add_dependencies(${PROJECT_NAME} sim snippetbased-simtestsimpl) +endif() + diff --git a/test/SimTests/SnippetBased/RunTests.sh b/test/SimTests/SnippetBased/RunTests.sh new file mode 100644 index 0000000..e69de29 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt b/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt new file mode 100644 index 0000000..6a99b5f --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.22 FATAL_ERROR) + +project(tests LANGUAGES CXX C ASM) + +set(INIT_DIR "${CMAKE_CURRENT_BINARY_DIR}/init") +set(BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/init_bin") +set(QEMU_LOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/qemu_log") +set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/tests") + +add_custom_target(init-tests + ALL + COMMAND ${CMAKE_COMMAND} -E make_directory "${INIT_DIR}" + COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/InitTestGen.rb + ${IR_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/Target/${TARGET_NAME}/Snippets ${INIT_DIR} + COMMENT "Generating test .s files" +) + +set(COMPILER "${CMAKE_C_COMPILER}") +set(COMPILER_FLAGS + "${CMAKE_C_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" + CACHE INTERNAL "Compiler flags for assembling and linking" +) + +set(SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/compile-and-run.sh") +set(COMPILE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/compile-dir.sh") + +add_custom_target(run-qemu-tests + ALL + DEPENDS init-tests + COMMAND ${CMAKE_COMMAND} -E make_directory "${BIN_DIR}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${QEMU_LOG_DIR}" + COMMAND "${SCRIPT_PATH}" + "${INIT_DIR}" + "${BIN_DIR}" + "${COMPILER}" + "${QEMU_PATH}" + "${QEMU_LOG_DIR}" + "${COMPILER_FLAGS}" + COMMENT "Compile all .s files and run each with QEMU" + VERBATIM +) + +add_custom_target(gen-tests + ALL + DEPENDS run-qemu-tests + COMMAND ${CMAKE_COMMAND} -E make_directory "${OUTPUT_DIR}" + COMMAND ${BUNDLE_PATH} exec ruby "${CMAKE_CURRENT_SOURCE_DIR}/TestGen.rb" + "${IR_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/Target/${TARGET_NAME}/Snippets" "${INIT_DIR}" "${QEMU_LOG_DIR}" "${OUTPUT_DIR}") + +add_custom_target(compile-tests + ALL + DEPENDS gen-tests + COMMAND ${CMAKE_COMMAND} -E make_directory "${OUTPUT_TESTS_DIR}" + COMMAND ${COMPILE_SCRIPT_PATH} "${OUTPUT_DIR}" "${OUTPUT_TESTS_DIR}" "${COMPILER}" "${COMPILER_FLAGS}") diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb new file mode 100644 index 0000000..11e3cca --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'Utility/gen_emitter' +require 'yaml' +require_relative 'Target/RISCV/Formatter' + +module SimTest + class InitAsmGen + attr_reader :ir, :reg2value + + def initialize(ir) + @ir = ir + end + + def generate_random_values + values = {} + ir[:regfiles].each do |regfile| + regfile[:regs].each do |reg| + attrs = reg[:attrs] || [] + next if attrs.include?(:zero) || attrs.include?(:pc) + size = reg[:size] || 32 + max = (1 << size) - 1 + values[reg[:name]] = rand(0..max) + end + end + values + end + + def generate(formatter, snippet_content, output_file) + emitter = Utility::GenEmitter.new() + @reg2value = generate_random_values + + formatter.prologue(emitter) + formatter.init_register(emitter, ir, @reg2value) + + emitter.emit_line 'j _snippet' + emitter.decrease_indent + emitter.emit_line '_snippet:' + emitter.increase_indent + formatter.insert_snippet(emitter, snippet_content) + emitter.emit_line 'j _exit_snippet' + emitter.decrease_indent + emitter.emit_line '_exit_snippet:' + emitter.increase_indent + + formatter.epilogue(emitter) + File.write(output_file + 'yaml', @reg2value.to_yaml) + File.write(output_file + 's', emitter.to_s) + end + end +end + +if __FILE__ == $0 + if ARGV.size < 3 || ARGV.size > 4 + puts "Usage: #{$0} [num_tests]" + exit 1 + end + + ir_file = ARGV[0] + snippets_dir = ARGV[1] + output_directory = ARGV[2] + num_tests = ARGV[3] ? ARGV[3].to_i : 4 + + ir = YAML.load_file(ir_file, symbolize_names: true) + generator = SimTest::InitAsmGen.new(ir) + formatter = SimTest::RiscVFormatter.new + + Dir.glob(File.join(snippets_dir, '*')).each do |snippet_path| + next unless File.file?(snippet_path) + + snippet_content = File.read(snippet_path) + base = File.basename(snippet_path, '.*') + + num_tests.times do |i| + output_file = File.join(output_directory, "#{base}_#{i}.init.") + generator.generate(formatter, snippet_content, output_file) + puts "Generated: #{output_file}s (test #{i+1}/#{num_tests})" + end + end +end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Parsers/QEMUParser.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/Parsers/QEMUParser.rb new file mode 100644 index 0000000..827e82a --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Parsers/QEMUParser.rb @@ -0,0 +1,28 @@ +module SimTest + module QEMULogParser + # Parses a QEMU log file and returns the last register snapshot. + # The returned hash contains keys like "pc", "x0", "x1", ... "x31" + # with their 8โ€‘digit hexadecimal values as strings. + def self.parse(log_file) + last_snapshot = nil + current_snapshot = nil + + File.readlines(log_file).each do |line| + line.strip! + next if line.empty? + if line.start_with?('pc') + last_snapshot = current_snapshot if current_snapshot + current_snapshot = {} + else + line.scan(/([^\s]+)\s+(\h+)/) do |name, value| + simple_name = name.split('/').first + current_snapshot[simple_name.to_sym] = value.to_i(16) + end + end + end + last_snapshot = current_snapshot if current_snapshot + + last_snapshot || {} + end + end +end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Formatter.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Formatter.rb new file mode 100644 index 0000000..7d53a43 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Formatter.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module SimTest + class RiscVFormatter + def prologue(emitter) + emitter.emit_line '.global _start' + emitter.emit_line '.section .text' + emitter.emit_line '_start:' + emitter.increase_indent + end + + def init_register(emitter, ir, values) + ir[:regfiles].each do |regfile| + regfile[:regs].each do |reg| + attrs = reg[:attrs] || [] + next if attrs.include?(:zero) || attrs.include?(:pc) || reg[:name] == :x2 + + emitter.emit_line "li #{reg[:name]}, 0x#{values[reg[:name]].to_s(16)}" + end + end + end + + def insert_snippet(emitter, snippet_content) + snippet_content.each_line do |line| + emitter.emit_line line.chomp + end + end + + def insert_check(emitter, ir, ref_values) + emitter.emit_line 'addi sp, sp, -4' + emitter.emit_line 'sw x1, 4(sp)' + ir[:regfiles].each do |regfile| + regfile[:regs].each do |reg| + attrs = reg[:attrs] || [] + next if attrs.include?(:zero) || attrs.include?(:pc) || reg[:name] == :x1 || reg[:name] == :x2 + + emitter.emit_line "li x1, 0x#{ref_values[reg[:name]].to_s(16)}" + emitter.emit_line "bne x1, #{reg[:name]}, _fail" + end + end + emitter.emit_line 'lw x3, 4(sp)' + emitter.emit_line "li x1, 0x#{ref_values[:x1].to_s(16)}" + emitter.emit_line 'addi sp, sp, 4' + emitter.emit_line 'bne x1, x3, _fail' + end + + def epilogue(emitter) + emitter.emit_line 'li a0, 0' + emitter.emit_line 'li a7, 93' + emitter.emit_line 'ecall' + emitter.emit_blank_line + emitter.decrease_indent + emitter.emit_line '_fail:' + emitter.increase_indent + emitter.emit_line 'li a0, 1' + emitter.emit_line 'li a7, 93' + emitter.emit_line 'ecall' + emitter.decrease_indent + emitter.emit_blank_line + end + end +end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s new file mode 100644 index 0000000..d74fb1a --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s @@ -0,0 +1 @@ +add x10, x6, x5 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s new file mode 100644 index 0000000..cd32b26 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s @@ -0,0 +1 @@ +addi x3, x6, 10 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb new file mode 100644 index 0000000..fbc2b1d --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'Utility/gen_emitter' +require 'yaml' +require_relative 'Target/RISCV/Formatter' +require_relative 'Parsers/QEMUParser' + +module SimTest + class FinalAsmGen + attr_reader :ir + + def initialize(ir) + @ir = ir + end + + def generate(formatter, snippet_content, init_yaml_file, ref_log_file, output_file) + emitter = Utility::GenEmitter.new() + + initreg2value = YAML.load_file(init_yaml_file) + refreg2value = QEMULogParser.parse(ref_log_file) + + formatter.prologue(emitter) + formatter.init_register(emitter, @ir, initreg2value) + + emitter.emit_line 'j _snippet' + emitter.decrease_indent + emitter.emit_line '_snippet:' + emitter.increase_indent + formatter.insert_snippet(emitter, snippet_content) + emitter.emit_line 'j _exit_snippet' + emitter.decrease_indent + emitter.emit_line '_exit_snippet:' + emitter.increase_indent + + formatter.insert_check(emitter, @ir, refreg2value) + + formatter.epilogue(emitter) + File.write(output_file, emitter.to_s) + end + end +end + +if __FILE__ == $0 + if ARGV.size != 5 + puts "Usage: #{$0} " + exit 1 + end + + ir_file = ARGV[0] + snippets_dir = ARGV[1] + init_json_dir = ARGV[2] + log_dir = ARGV[3] + output_dir = ARGV[4] + + ir = YAML.load_file(ir_file, symbolize_names: true) + generator = SimTest::FinalAsmGen.new(ir) + formatter = SimTest::RiscVFormatter.new + + log_files = Dir.glob(File.join(log_dir, '*')).select { |f| File.file?(f) } + + log_files.each do |log_path| + log_basename = File.basename(log_path) + + match = log_basename.match(/^(.*)_(\d+)\.init\.log$/) + snippet = match[1] + index = match[2].to_i + + snippet_path = Dir.glob(File.join(snippets_dir, '*')).find do |f| + File.file?(f) && File.basename(f, '.*') == snippet + end + + unless snippet_path + puts "Warning: snippet file for '#{snippet}' not found in #{snippets_dir}, skipping" + next + end + + init_yaml_file = File.join(init_json_dir, "#{snippet}_#{index}.init.yaml") + + output_file = File.join(output_dir, "#{snippet}_#{index}.s") + snippet_content = File.read(snippet_path) + + generator.generate(formatter, snippet_content, init_yaml_file, log_path, output_file) + puts "Generated: #{output_file}" + end +end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/compile-and-run.sh b/test/SimTests/SnippetBased/SnippetBasedImpl/compile-and-run.sh new file mode 100755 index 0000000..7765bca --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/compile-and-run.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ $# -lt 6 ]; then + echo "Usage: $0 " + exit 1 +fi + +SRC_DIR="$1" +BIN_DIR="$2" +COMPILER="$3" +QEMU="$4" +QEMU_LOG_DIR="$5" +COMPILER_FLAGS="$6" + +# Compile each .s file +for s_file in "$SRC_DIR"/*.s; do + if [ -f "$s_file" ]; then + base=$(basename "$s_file" .s) + out_file="$BIN_DIR/$base.elf" + echo "Compiling $s_file -> $out_file" + $COMPILER $COMPILER_FLAGS "$s_file" -o "$out_file" + if [ $? -ne 0 ]; then + echo "Compilation failed for $s_file" + exit 1 + fi + fi +done + +# Run QEMU on each compiled binary +for bin_file in "$BIN_DIR"/*.elf; do + if [ -f "$bin_file" ]; then + echo "Running QEMU on $bin_file" + base_name="${bin_file##*/}" + base_name="${base_name%.elf}" + $QEMU -D "$QEMU_LOG_DIR/$base_name.log" -d cpu "$bin_file" + if [ $? -ne 0 ]; then + echo "QEMU failed on $bin_file" + exit 1 + fi + fi +done diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/compile-dir.sh b/test/SimTests/SnippetBased/SnippetBasedImpl/compile-dir.sh new file mode 100755 index 0000000..2968116 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/compile-dir.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +if [ $# -ne 4 ]; then + echo "Usage: $0 " + exit 1 +fi + +SRC_DIR="$1" +BIN_DIR="$2" +COMPILER="$3" +COMPILER_FLAGS="$4" + +for s_file in "$SRC_DIR"/*.s; do + if [ -f "$s_file" ]; then + base=$(basename "$s_file" .s) + out_file="$BIN_DIR/$base.elf" + echo "Compiling $s_file -> $out_file" + $COMPILER $COMPILER_FLAGS "$s_file" -o "$out_file" + if [ $? -ne 0 ]; then + echo "Compilation failed for $s_file" + exit 1 + fi + fi +done From 68701cbfcb079e340b22990fad0272b45c388008 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 17 Mar 2026 11:38:04 +0000 Subject: [PATCH 02/75] Add tests in workflow. --- .github/workflows/build.yml | 17 +++++----- ci-extra/build.sh | 4 +-- ci-extra/test.sh | 4 +++ cmake/QEMU.cmake | 3 ++ cmake/toolchain/riscv.cmake | 65 +++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 11 deletions(-) create mode 100755 ci-extra/test.sh create mode 100644 cmake/QEMU.cmake create mode 100644 cmake/toolchain/riscv.cmake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 173386d..707cdcc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,13 +24,15 @@ jobs: - name: Run clang-format style check uses: jidicula/clang-format-action@v4.14.0 with: - clang-format-version: '19' + clang-format-version: '20' check-path: '.' - build: + test: needs: formatting-check - name: Build + name: Test runs-on: ubuntu-22.04 + container: + image: ghcr.io/egorshamshura/protea-build:latest strategy: fail-fast: false matrix: @@ -44,11 +46,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: '3.4.8' - bundler-cache: true - - name: Build run: ci-extra/build.sh "$CMAKE_PRESET" + + - name: Run tests + run: ci-extra/test.sh "$CMAKE_PRESET" diff --git a/ci-extra/build.sh b/ci-extra/build.sh index ab70d2a..05aab0b 100755 --- a/ci-extra/build.sh +++ b/ci-extra/build.sh @@ -2,7 +2,7 @@ PRESET_NAME=$1 # Configure CMake cmake -S . \ - --preset "${PRESET_NAME}" -G Ninja + --preset "${PRESET_NAME}" -DPROTEA_BUILD_TESTS=true -DQEMU_PATH=qemu-riscv32 -G Ninja # Build -cmake --build --preset ${PRESET_NAME} --target install --parallel 12 +cmake --build --preset ${PRESET_NAME} --target all --parallel 12 diff --git a/ci-extra/test.sh b/ci-extra/test.sh new file mode 100755 index 0000000..ac3bddc --- /dev/null +++ b/ci-extra/test.sh @@ -0,0 +1,4 @@ +PRESET_NAME=$1 + +# Run tests +cmake --build --preset ${PRESET_NAME} --target simtests diff --git a/cmake/QEMU.cmake b/cmake/QEMU.cmake new file mode 100644 index 0000000..1e245d6 --- /dev/null +++ b/cmake/QEMU.cmake @@ -0,0 +1,3 @@ +if (NOT DEFINED QEMU_PATH) + set(QEMU_PATH "qemu") +endif() diff --git a/cmake/toolchain/riscv.cmake b/cmake/toolchain/riscv.cmake new file mode 100644 index 0000000..6a60de9 --- /dev/null +++ b/cmake/toolchain/riscv.cmake @@ -0,0 +1,65 @@ +# RISC-V Cross Compilation Toolchain File Usage: cmake +# -DCMAKE_TOOLCHAIN_FILE=path/to/this/file.cmake .. + +# Base settings +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv) +set(CMAKE_LINKER_TYPE DEFAULT) + +# Toolchain prefix (modify this according to your toolchain) Common prefixes: +# riscv64-unknown-elf-, riscv64-unknown-linux-gnu-, riscv32-unknown-elf- +set(RISCV_TOOLCHAIN_PREFIX + "riscv32-unknown-elf-" + CACHE STRING "RISC-V toolchain prefix") + +# Target architecture (modify these according to your needs) +set(RISCV_ARCH + "rv32i" + CACHE STRING "RISC-V architecture") +set(RISCV_ABI + "ilp32" + CACHE STRING "RISC-V ABI") + +# Cross-compilation tools +if(DEFINED RISCV_TOOLCHAIN_DIR) + set(CMAKE_C_COMPILER "${RISCV_TOOLCHAIN_DIR}/${RISCV_TOOLCHAIN_PREFIX}gcc") + set(CMAKE_CXX_COMPILER "${RISCV_TOOLCHAIN_DIR}/${RISCV_TOOLCHAIN_PREFIX}g++") + set(CMAKE_ASM_COMPILER "${RISCV_TOOLCHAIN_DIR}/${RISCV_TOOLCHAIN_PREFIX}gcc") + set(CMAKE_AR "${RISCV_TOOLCHAIN_DIR}/${RISCV_TOOLCHAIN_PREFIX}ar") + set(CMAKE_RANLIB "${RISCV_TOOLCHAIN_DIR}/${RISCV_TOOLCHAIN_PREFIX}ranlib") +else() + set(CMAKE_C_COMPILER "${RISCV_TOOLCHAIN_PREFIX}gcc") + set(CMAKE_CXX_COMPILER "${RISCV_TOOLCHAIN_PREFIX}g++") + set(CMAKE_ASM_COMPILER "${RISCV_TOOLCHAIN_PREFIX}gcc") + set(CMAKE_AR "${RISCV_TOOLCHAIN_PREFIX}ar") + set(CMAKE_RANLIB "${RISCV_TOOLCHAIN_PREFIX}ranlib") +endif() + +# Compiler flags Search settings +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Optional: Specify sysroot if needed set(CMAKE_SYSROOT +# "/path/to/riscv/sysroot") + +# Optional: Additional flags for specific use cases +set(COMMON_FLAGS + "-march=${RISCV_ARCH} -mabi=${RISCV_ABI} -Wall -Wextra -nostdlib -nodefaultlibs -nostartfiles -static -fno-builtin" +) +set(CMAKE_C_FLAGS + "${COMMON_FLAGS}" + CACHE STRING "C compiler flags") +set(CMAKE_ASM_FLAGS + "${COMMON_FLAGS}" + CACHE STRING "ASM compiler flags") + +set(CMAKE_EXE_LINKER_FLAGS_INIT + "-nostdlib -nodefaultlibs -nostartfiles -fno-builtin -static" + CACHE STRING "Linker flags") + +# Test compiler +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.6) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() From a35d6756783ffb8d545c8923952317671ef318cd Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 17 Mar 2026 11:39:32 +0000 Subject: [PATCH 03/75] Add interface functions. Small codegen fix. --- code_gen/cpp_gen.rb | 2 +- lib/ADL/base.rb | 2 + lib/ADL/builder.rb | 2 +- lib/Target/RISC-V/32I.rb | 2 +- lib/Target/RISC-V/32ILoops.rb | 194 ---------------------------------- lib/Utility/helper_cpp.rb | 2 +- lib/ir_gen.rb | 2 - 7 files changed, 6 insertions(+), 200 deletions(-) delete mode 100644 lib/Target/RISC-V/32ILoops.rb diff --git a/code_gen/cpp_gen.rb b/code_gen/cpp_gen.rb index 4388b34..b33489c 100644 --- a/code_gen/cpp_gen.rb +++ b/code_gen/cpp_gen.rb @@ -83,7 +83,7 @@ def generate_statement(operation) @emitter.emit_line("#{dst} = #{src};") when :new_var var_name = operation[:oprnds][0][:name] - var_type = Utility::HelperCpp.gen_type(operation[:oprnds][0][:type]) + var_type = Utility::HelperCpp.gen_small_type(operation[:oprnds][0][:type]) @emitter.emit_line("#{var_type} #{var_name};") when :cast dst = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] diff --git a/lib/ADL/base.rb b/lib/ADL/base.rb index 8587824..4eb5910 100644 --- a/lib/ADL/base.rb +++ b/lib/ADL/base.rb @@ -9,6 +9,7 @@ def self.serialize(msg= nil) yaml_data = YAML.dump( { regfiles: @@regfiles.map(&:to_h), + interface_functions: @@interface_functions.map(&:to_h), instructions: @@instructions.map(&:to_h), } ) @@ -19,6 +20,7 @@ def self.state yaml_data = YAML.dump( { regfiles: @@regfiles.map(&:to_h), + interface_functions: @@interface_functions.map(&:to_h), instructions: @@instructions.map(&:to_h), } ) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index 83d0313..36f9c3d 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -129,7 +129,7 @@ def Instruction(name, &block) class InterfaceBuilder include SimInfra - def function(name, output_types = [], input_types = []) + def Function(name, output_types = [], input_types = []) @@interface_functions << {:name => name, :return_types => output_types, :argument_types => input_types} end end diff --git a/lib/Target/RISC-V/32I.rb b/lib/Target/RISC-V/32I.rb index 6a67a7b..3e2d782 100644 --- a/lib/Target/RISC-V/32I.rb +++ b/lib/Target/RISC-V/32I.rb @@ -7,7 +7,7 @@ module RV32I extend SimInfra Interface { - function :sysCall + Function(:sysCall) } RegisterFile(:XRegs) { diff --git a/lib/Target/RISC-V/32ILoops.rb b/lib/Target/RISC-V/32ILoops.rb deleted file mode 100644 index 07b0b06..0000000 --- a/lib/Target/RISC-V/32ILoops.rb +++ /dev/null @@ -1,194 +0,0 @@ -require_relative "encoding" -require_relative "../../Generic/base" -require_relative "../../Generic/builder" - -module Ops - - class Add; def self.op(a, b); a.u + b.u; end; end - class Sub; def self.op(a, b); a.u - b.u; end; end - class Sll; def self.op(a, b); a.u << b.u; end; end - class Slt; def self.op(a, b); (a.s < b.s).b; end; end - class Sltu; def self.op(a, b); (a.u < b.u).b; end; end - class Xor; def self.op(a, b); a ^ b; end; end - class Srl; def self.op(a, b); a.u >> b.u; end; end - class Sra; def self.op(a, b); a.s >> b.u; end; end - class Or; def self.op(a, b); a | b; end; end - class And; def self.op(a, b); a & b; end; end - class Load8; def self.op(rs1, imm); mem[rs1 + imm, :b8].s32; end; end - class Load16; def self.op(rs1, imm); mem[rs1 + imm, :b16].s32; end; end - class Load32; def self.op(rs1, imm); mem[rs1 + imm, :b32]; end; end - class Load8U; def self.op(rs1, imm); mem[rs1 + imm, :b8].u32; end; end - class Load16U; def self.op(rs1, imm); mem[rs1 + imm, :b16].u32; end; end - -end - -module RV32I - include SimInfra - extend SimInfra - - RegisterFile(:XRegs) { - r32 :x0, zero - for x in (1..31); r32 "x" + x.to_s; end - r32 :pc - } - - Instruction(:lui) { - encoding *format_u(0b0110111) - asm { "lui {rd}, {imm}" } - code { rd[]= imm } - } - - Instruction(:auipc) { - encoding *format_u(0b0010111) - asm { "auipc {rd}, {imm}" } - code { rd[]= imm + pc } - } - - TABLE_R_FORMAT_INSTRUCTIONS = [ - [:add, format_r(0b0110011, 0b000, 0b0000000), Ops::Add], - [:sub, format_r(0b0110011, 0b000, 0b0100000), Ops::Sub], - [:sll, format_r(0b0110011, 0b001, 0b0000000), Ops::Sll], - [:slt, format_r(0b0110011, 0b010, 0b0000000), Ops::Slt], - [:sltu, format_r(0b0110011, 0b011, 0b0000000), Ops::Sltu], - [:xor, format_r(0b0110011, 0b100, 0b0000000), Ops::Xor], - [:srl, format_r(0b0110011, 0b101, 0b0000000), Ops::Srl], - [:sra, format_r(0b0110011, 0b101, 0b0100000), Ops::Sra], - [:or, format_r(0b0110011, 0b110, 0b0000000), Ops::Or], - [:and, format_r(0b0110011, 0b111, 0b0000000), Ops::And], - ] - - for insn in TABLE_R_FORMAT_INSTRUCTIONS - Instruction(insn[0]) { - encoding *insn[1] - asm { insn[0].to_s + "{rd}, {rs1}, {rs2}" } - code { rd[]= insn[2].op(rs1, rs2) } - } - end - - TABLE_I_FORMAT_INSTRUCTIONS = [ - [:addi, format_i(0b0010011, 0b000), Ops::Add], - [:xori, format_i(0b0010011, 0b100), Ops::Xor], - [:ori, format_i(0b0010011, 0b110), Ops::Or], - [:andi, format_i(0b0010011, 0b111), Ops::And], - ] - - for insn in TABLE_I_FORMAT_INSTRUCTIONS - Instruction(insn[0]) { - encoding *insn[1] - asm { insn[0].to_s + "{rd}, {rs1}, {imm}" } - code { rd[]= insn[2].op(rs1, imm) } - } - end - - Instruction(:beq) { - encoding *format_b(0b1100011, 0b000) - asm { "beq {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 == rs2, pc + imm, pc + xlen)) } - } - - Instruction(:bne) { - encoding *format_b(0b1100011, 0b001) - asm { "bne {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 != rs2, pc + imm, pc + xlen)) } - } - - Instruction(:blt) { - encoding *format_b(0b1100011, 0b100) - asm { "blt {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 < rs2, pc + imm, pc + xlen)) } - } - - Instruction(:bge) { - encoding *format_b(0b1100011, 0b101) - asm { "bge {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 > rs2, pc + imm, pc + xlen)) } - } - - Instruction(:bltu) { - encoding *format_b(0b1100011, 0b110) - asm { "bltu {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.u < rs2.u, pc + imm, pc + xlen)) } - } - - Instruction(:bgeu) { - encoding *format_b(0b1100011, 0b111) - asm { "bgeu {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.u > rs2.u, pc + imm, pc + xlen)) } - } - - Instruction(:jal) { - encoding *format_j(0b1101111) - asm { "jal {rd}, {imm}" } - code { rd[]= pc + xlen; branch(pc + imm) } - } - - Instruction(:jalr) { - encoding *format_i(0b1101111, 0b000) - asm { "jalr {rd}, {rs1}, {imm}" } - code { - let :t, :b32, pc + xlen - branch((rs1 + imm) & (~1)) - rd[]= t - } - } - - Instruction(:sb) { - encoding *format_s(0b0100011, 0b000) - asm { "sb {rs2}, {imm}({rs1})" } - code { mem[rs1 + imm]= rs2[7, 0] } - } - - Instruction(:sh) { - encoding *format_s(0b0100011, 0b001) - asm { "sh {rs2}, {imm}({rs1})" } - code { mem[rs1 + imm]= rs2[15, 0] } - } - - Instruction(:sw) { - encoding *format_s(0b0100011, 0b010) - asm { "sw {rs2}, {imm}({rs1})" } - code { mem[rs1 + imm]= rs2 } - } - - Instruction(:lb) { - encoding *format_i(0b0100011, 0b000) - asm { "lb {rd}, {imm}({rs1})" } - code { rd[]= mem[rs1 + imm, :b8].s32 } - } - - Instruction(:lh) { - encoding *format_i(0b0100011, 0b001) - asm { "lh {rd}, {imm}({rs1})" } - code { rd[]= mem[rs1 + imm, :b16].s32 } - } - - Instruction(:lw) { - encoding *format_i(0b0100011, 0b010) - asm { "lw {rd}, {imm}({rs1})" } - code { rd[]= mem[rs1 + imm, :b32] } - } - - Instruction(:lbu) { - encoding *format_i(0b0100011, 0b100) - asm { "lbu {rd}, {imm}({rs1})" } - code { rd[]= mem[rs1 + imm, :b8].u32 } - } - - Instruction(:lhu) { - encoding *format_i(0b0100011, 0b101) - asm { "lhu {rd}, {imm}({rs1})" } - code { rd[]= mem[rs1 + imm, :b16].u32 } - } - - Instruction(:ecall) { - encoding :E, [field(:c, 31, 0, 0b1110011)] - asm { "ecall" } - code { } - } - - Instruction(:ebreak) { - encoding :E, [field(:c, 31, 0, 0b100000000000001110011)] - asm { "ebreak" } - code { } - } -end diff --git a/lib/Utility/helper_cpp.rb b/lib/Utility/helper_cpp.rb index d54f32f..10541c5 100644 --- a/lib/Utility/helper_cpp.rb +++ b/lib/Utility/helper_cpp.rb @@ -15,7 +15,7 @@ def gen_type(type) def gen_small_type(type) actual_type = Utility.get_type(type) - cpp_bitsize = actual_type.bitsize % 8 == 0 ? actual_type.bitsize : (actual_type.bitsize / 8 + 1) * 8 + cpp_bitsize = [8, 1 << (actual_type.bitsize - 1).bit_length].max "#{actual_type.typeof == :s ? 'int' : 'uint'}#{cpp_bitsize}_t" end end diff --git a/lib/ir_gen.rb b/lib/ir_gen.rb index cde48e4..da09671 100644 --- a/lib/ir_gen.rb +++ b/lib/ir_gen.rb @@ -5,7 +5,5 @@ require 'ADL/builder' require 'Target/RISC-V/32I' -require 'yaml' - yaml_data = SimInfra.serialize File.write('IR.yaml', yaml_data) From b5fe8cba3cb8f04e3ded0d738d3f62570c4c1849 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 17 Mar 2026 11:41:05 +0000 Subject: [PATCH 04/75] Add target dependent file to implement interface functions. Add LLVM based clang-format. --- .clang-format | 2 ++ sim_gen/CMakeLists.txt | 5 ++-- sim_gen/CPUState/cpu_state.rb | 36 +++++++++++++++--------- sim_gen/ExecEngines/naive_interpreter.rb | 13 ++++++--- sim_lib/Target/RISCV/cpu_state_ext.cc | 16 +++++++++++ sim_lib/base_jit.cc | 8 ++++-- sim_lib/base_jit.hh | 8 ++++++ sim_lib/elf_loader.cc | 6 ++-- sim_lib/elf_loader.hh | 4 +++ sim_lib/jit_factory.cc | 6 +++- sim_lib/memory.cc | 5 ++++ sim_lib/memory.hh | 6 ++++ sim_lib/sim.cc | 15 +++++----- 13 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 .clang-format create mode 100644 sim_lib/Target/RISCV/cpu_state_ext.cc diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f6b8fdf --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: LLVM diff --git a/sim_gen/CMakeLists.txt b/sim_gen/CMakeLists.txt index db5540a..adaf7ad 100644 --- a/sim_gen/CMakeLists.txt +++ b/sim_gen/CMakeLists.txt @@ -24,7 +24,7 @@ set(PROTEA_SIMGEN_OUTPUT_FILES set(IR_YAML_FILE ${protea_irgen_BINARY_DIR}/IR.yaml) -add_custom_command( +add_custom_command(DEPENDS OUTPUT ${PROTEA_SIMGEN_OUTPUT_FILES} COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${IR_YAML_FILE} DEPENDS ${IR_YAML_FILE} @@ -38,7 +38,8 @@ add_executable(sim ${PROTEA_SIMGEN_OUTPUT_SOURCES} ${protea_simlib_SOURCE_DIR}/base_jit.cc ${protea_simlib_SOURCE_DIR}/sim.cc ${protea_simlib_SOURCE_DIR}/jit_factory.cc - ${protea_simlib_SOURCE_DIR}/memory.cc) + ${protea_simlib_SOURCE_DIR}/memory.cc + ${protea_simlib_SOURCE_DIR}/Target/${TARGET_NAME}/cpu_state_ext.cc) target_include_directories(sim PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${protea_simlib_SOURCE_DIR}) target_link_libraries(sim elfio CLI11 fmt) diff --git a/sim_gen/CPUState/cpu_state.rb b/sim_gen/CPUState/cpu_state.rb index d75201f..aef35b6 100644 --- a/sim_gen/CPUState/cpu_state.rb +++ b/sim_gen/CPUState/cpu_state.rb @@ -121,27 +121,36 @@ def generate_read_reg_functions(regfiles) def generate_do_exit_func emitter = Utility::GenEmitter.new emitter.emit_line('// Function to stop the CPU execution') - emitter.emit_line('void doExit() {') + emitter.emit_line('void doExit(isa::Word code) {') emitter.increase_indent emitter.emit_line('m_finished = true;') + emitter.emit_line("fmt::println(\"Exiting with code {}...\", code);") emitter.decrease_indent emitter.emit_line('}') emitter.increase_indent_all(2) emitter end - def generate_dump_func(regfiles) + def gen_input_args(args) + args.map { |arg| Utility::HelperCpp.gen_type(arg) }.join(', ') + end + + def generate_interface_func(interface_functions) emitter = Utility::GenEmitter.new - emitter.emit_line("void CPU::dump(std::ostream &ost) const {") - emitter.increase_indent - emitter.emit_line("fmt::println(ost, \"---CPU STATE DUMP---\");") - regfiles.each do |regfile| - regfile[:regs].each do |register| - emitter.emit_line("fmt::print(ost, \"X[{:02}] = {:#010x} \", effIdx, get#{regfile[:name]}());") + emitter.emit_line('// Interface functions') + interface_functions.each do |ifunc| + + if ifunc[:return_types].size == 0 + emitter.emit_line("void #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") + elsif ifunc[:return_types].size == 1 + emitter.emit_line("#{gen_input_args(ifunc[:return_types])} #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") + else + emitter.emit_line("std::tuple<#{gen_input_args(ifunc[:return_types])}> #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") end end - + emitter.emit_blank_line + emitter.increase_indent_all(2) emitter end end @@ -163,6 +172,7 @@ def generate_cpu_state(input_ir) readreg_funcs = Helper.generate_read_reg_functions(input_ir[:regfiles]) do_exit_func = Helper.generate_do_exit_func increase_icount_func = Helper.increase_icount_func + interface_func = Helper.generate_interface_func(input_ir[:interface_functions]) base_type = Utility::HelperCpp.gen_type input_ir[:regfiles][0][:regs][0][:size] "#ifndef GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED @@ -173,6 +183,8 @@ def generate_cpu_state(input_ir) #include #include #include +#include +#include namespace prot::memory { class Memory; @@ -199,11 +211,7 @@ class CPU final { #{setreg_funcs} #{readreg_funcs} #{pc_functions} - #{base_type} getSysCallNum() const; - #{base_type} getSysCallArg(std::size_t num) const; - #{base_type} getSysCallRet() const; - void emulateSysCall(); - +#{interface_func} #{do_exit_func} #{increase_icount_func} diff --git a/sim_gen/ExecEngines/naive_interpreter.rb b/sim_gen/ExecEngines/naive_interpreter.rb index b9fa7d1..cf5a0a7 100644 --- a/sim_gen/ExecEngines/naive_interpreter.rb +++ b/sim_gen/ExecEngines/naive_interpreter.rb @@ -60,16 +60,21 @@ def cpu_read_mem(dst, addr) "cpu.m_memory->read<#{Utility::HelperCpp.gen_small_type(dst[:type])}>(#{addr})" end - def generate_exec_function(instruction) + def generate_exec_function(instruction, funcs) emitter = Utility::GenEmitter.new operand_map = map_operands(instruction) emitter.emit_line("void do#{instruction[:name].to_s.upcase}(CPU &cpu, const Instruction &insn) {") emitter.increase_indent - + gen = CodeGen::CppGenerator.new(emitter, operand_map) + funcs_name = funcs.map { |func| func[:name] } instruction[:code][:tree].each do |node| - gen.generate_statement(node) + if funcs_name.include?(node[:name]) + emitter.emit_line("cpu.#{node[:name]}(#{node[:oprnds].map { |op| op[:name] }.join(', ')});") + else + gen.generate_statement(node) + end end emitter.decrease_indent emitter.emit_line('}') @@ -80,7 +85,7 @@ def generate_exec_function(instruction) def generate_exec_functions(input_ir) emitter = Utility::GenEmitter.new input_ir[:instructions].each do |instruction| - temp_emitter = generate_exec_function(instruction) + temp_emitter = generate_exec_function(instruction, input_ir[:interface_functions]) emitter.concat(temp_emitter) end emitter diff --git a/sim_lib/Target/RISCV/cpu_state_ext.cc b/sim_lib/Target/RISCV/cpu_state_ext.cc new file mode 100644 index 0000000..4389d9e --- /dev/null +++ b/sim_lib/Target/RISCV/cpu_state_ext.cc @@ -0,0 +1,16 @@ +#include "cpu_state.hh" + +namespace prot::state { + +void CPU::sysCall() { + switch (const auto syscallNum = getXRegs(17)) { + case 93: + doExit(getXRegs(10)); + break; + default: + throw std::runtime_error{ + fmt::format("Unknown syscall w/ num {}", syscallNum)}; + } +} + +} // namespace prot::state diff --git a/sim_lib/base_jit.cc b/sim_lib/base_jit.cc index 247b993..f2f8d2e 100644 --- a/sim_lib/base_jit.cc +++ b/sim_lib/base_jit.cc @@ -8,12 +8,13 @@ extern "C" { } namespace prot::engine { + using namespace prot::isa; using namespace prot::decoder; void JitEngine::step(CPU &cpu) { while (!cpu.m_finished) [[likely]] { - // colllect bb + // collect bb const auto pc = cpu.getPC(); auto found = m_tbCache.lookup(pc); if (found != nullptr) [[likely]] { @@ -30,7 +31,8 @@ void JitEngine::step(CPU &cpu) { auto bytes = cpu.m_memory->read(curAddr); auto inst = decode(bytes); if (!inst.has_value()) { - throw std::runtime_error{"Cannot decode bytes"}; + throw std::runtime_error{"Cannot decode bytes: " + + std::to_string(bytes)}; } bb.insns.push_back(*inst); @@ -51,6 +53,7 @@ void JitEngine::step(CPU &cpu) { interpret(cpu, bbIt->second); } } + void JitEngine::interpret(CPU &cpu, BBInfo &info) { for (const auto &insn : info.insns) { execute(cpu, insn); @@ -94,4 +97,5 @@ CodeHolder::CodeHolder(std::span src) throw std::runtime_error{"Failed to change protection"}; } } + } // namespace prot::engine diff --git a/sim_lib/base_jit.hh b/sim_lib/base_jit.hh index 637a27b..e75e0a1 100644 --- a/sim_lib/base_jit.hh +++ b/sim_lib/base_jit.hh @@ -12,7 +12,9 @@ #include namespace prot::engine { + using JitFunction = void (*)(CPU &); + class JitEngine : public Interpreter { static constexpr std::size_t kExecThreshold = 10; @@ -35,12 +37,14 @@ protected: const auto &entry = get(gpa); return entry.gpa == gpa ? entry.func : nullptr; } + void insert(std::uint32_t gpa, JitFunction func) { get(gpa) = Entry{.func = func, .gpa = gpa}; } private: const Entry &get(std::uint32_t gpa) const { return m_cache[getHash(gpa)]; } + Entry &get(std::uint32_t gpa) { return m_cache[getHash(gpa)]; } [[nodiscard]] static constexpr std::uint32_t getHash(std::uint32_t gpa) { @@ -55,10 +59,12 @@ protected: std::vector insns; std::size_t num_exec{}; }; + [[nodiscard]] const BBInfo *getBBInfo(isa::Addr pc) const; private: void interpret(CPU &cpu, BBInfo &info); + void execute(CPU &cpu, const isa::Instruction &insn) final { Interpreter::execute(cpu, insn); } @@ -94,11 +100,13 @@ public: template [[nodiscard]] auto as() const { return reinterpret_cast(m_data.get()); } + void operator()(CPU &state) const { as()(state); } private: std::unique_ptr m_data; }; + } // namespace prot::engine #endif // INCLUDE_JIT_BASE_HH_INCLUDED diff --git a/sim_lib/elf_loader.cc b/sim_lib/elf_loader.cc index 950cafa..d653ed0 100644 --- a/sim_lib/elf_loader.cc +++ b/sim_lib/elf_loader.cc @@ -1,10 +1,11 @@ #include "elf_loader.hh" -#include - #include +#include + namespace prot::elf_loader { + using namespace prot::memory; ElfLoader::~ElfLoader() = default; @@ -58,4 +59,5 @@ void ElfLoader::loadMemory(Memory &mem) const { std::byte(), seg->get_memory_size() - seg->get_file_size()); } } + } // namespace prot::elf_loader diff --git a/sim_lib/elf_loader.hh b/sim_lib/elf_loader.hh index a75a702..0dee5cc 100644 --- a/sim_lib/elf_loader.hh +++ b/sim_lib/elf_loader.hh @@ -12,11 +12,14 @@ // NOLINTNEXTLINE namespace ELFIO { + // forward decl class elfio; + } // namespace ELFIO namespace prot::elf_loader { + class ElfLoader { public: explicit ElfLoader(std::istream &stream); @@ -35,6 +38,7 @@ private: std::unique_ptr m_elf; }; + } // namespace prot::elf_loader #endif // PROT_ELF_LOADER_HH_INCLUDED diff --git a/sim_lib/jit_factory.cc b/sim_lib/jit_factory.cc index c3c3742..92590f9 100644 --- a/sim_lib/jit_factory.cc +++ b/sim_lib/jit_factory.cc @@ -1,10 +1,12 @@ #include "jit_factory.hh" + #include "base_jit.hh" #include #include namespace prot::engine { + const std::unordered_map()>> JitFactory::kFactories = { @@ -21,8 +23,9 @@ std::vector JitFactory::backends() { std::unique_ptr JitFactory::createEngine(const std::string &backend) { auto it = kFactories.find(backend); - if (it != kFactories.end()) + if (it != kFactories.end()) { return it->second(); + } throw std::invalid_argument("Undefined JIT backend: " + backend); } @@ -30,4 +33,5 @@ JitFactory::createEngine(const std::string &backend) { bool JitFactory::exist(const std::string &backend) { return kFactories.contains(backend); } + } // namespace prot::engine diff --git a/sim_lib/memory.cc b/sim_lib/memory.cc index ec37fdc..a16f3cb 100644 --- a/sim_lib/memory.cc +++ b/sim_lib/memory.cc @@ -1,4 +1,5 @@ #include "memory.hh" + #include "isa.hh" #include @@ -46,9 +47,11 @@ class PlainMemory : public Memory { uint8_t read8(isa::Addr addr) const override { return *reinterpret_cast(translateAddr(addr)); } + uint16_t read16(isa::Addr addr) const override { return *reinterpret_cast(translateAddr(addr)); } + uint32_t read32(isa::Addr addr) const override { return *reinterpret_cast(translateAddr(addr)); } @@ -56,9 +59,11 @@ class PlainMemory : public Memory { void write8(isa::Addr addr, uint8_t val) override { *reinterpret_cast(translateAddr(addr)) = val; } + void write16(isa::Addr addr, uint16_t val) override { *reinterpret_cast(translateAddr(addr)) = val; } + void write32(isa::Addr addr, uint32_t val) override { *reinterpret_cast(translateAddr(addr)) = val; } diff --git a/sim_lib/memory.hh b/sim_lib/memory.hh index 40b1cfc..a8265d9 100644 --- a/sim_lib/memory.hh +++ b/sim_lib/memory.hh @@ -2,6 +2,7 @@ #define PROT_MEMORY_HH_INCLUDED_MEMORY_HH_INCLUDED #include "isa.hh" + #include #include #include @@ -59,14 +60,19 @@ public: } virtual uint8_t read8(isa::Addr addr) const { return read(addr); } + virtual uint16_t read16(isa::Addr addr) const { return read(addr); } + virtual uint32_t read32(isa::Addr addr) const { return read(addr); } + virtual void write8(isa::Addr addr, uint8_t val) { write(addr, val); } + virtual void write16(isa::Addr addr, uint16_t val) { write(addr, val); } + virtual void write32(isa::Addr addr, uint32_t val) { write(addr, val); } diff --git a/sim_lib/sim.cc b/sim_lib/sim.cc index cc6c9a0..bf4a62b 100644 --- a/sim_lib/sim.cc +++ b/sim_lib/sim.cc @@ -1,10 +1,3 @@ -#include -#include -#include -#include -#include -#include - #include "base_jit.hh" #include "elf_loader.hh" #include "hart.hh" @@ -12,6 +5,14 @@ #include "memory.hh" #include "naive_interpreter.hh" +#include +#include +#include + +#include +#include +#include + int main(int argc, const char *argv[]) try { std::filesystem::path elfPath; constexpr prot::isa::Addr kDefaultStack = 0x7fffffff; From 747bdbcb2b2e6e14a3d40891b4cbf39bb1ca95bf Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 17 Mar 2026 11:45:06 +0000 Subject: [PATCH 05/75] Remove redundant whitespaces. Add status message. --- cmake/QEMU.cmake | 2 ++ sim_gen/ExecEngines/naive_interpreter.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/QEMU.cmake b/cmake/QEMU.cmake index 1e245d6..bdc5122 100644 --- a/cmake/QEMU.cmake +++ b/cmake/QEMU.cmake @@ -1,3 +1,5 @@ if (NOT DEFINED QEMU_PATH) set(QEMU_PATH "qemu") endif() + +message(STATUS "Using QEMU: ${QEMU_PATH}") diff --git a/sim_gen/ExecEngines/naive_interpreter.rb b/sim_gen/ExecEngines/naive_interpreter.rb index cf5a0a7..cadca79 100644 --- a/sim_gen/ExecEngines/naive_interpreter.rb +++ b/sim_gen/ExecEngines/naive_interpreter.rb @@ -66,7 +66,7 @@ def generate_exec_function(instruction, funcs) emitter.emit_line("void do#{instruction[:name].to_s.upcase}(CPU &cpu, const Instruction &insn) {") emitter.increase_indent - + gen = CodeGen::CppGenerator.new(emitter, operand_map) funcs_name = funcs.map { |func| func[:name] } instruction[:code][:tree].each do |node| From 3bacbb1d22f50f397e1073a178c71085a7185628 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Mon, 23 Mar 2026 11:19:50 +0000 Subject: [PATCH 06/75] Added --propagate-exit flag. --- sim_gen/CPUState/cpu_state.rb | 4 ++++ sim_gen/Hart/hart.rb | 2 ++ sim_lib/sim.cc | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sim_gen/CPUState/cpu_state.rb b/sim_gen/CPUState/cpu_state.rb index aef35b6..f7d97c1 100644 --- a/sim_gen/CPUState/cpu_state.rb +++ b/sim_gen/CPUState/cpu_state.rb @@ -124,6 +124,7 @@ def generate_do_exit_func emitter.emit_line('void doExit(isa::Word code) {') emitter.increase_indent emitter.emit_line('m_finished = true;') + emitter.emit_line('m_code = code;') emitter.emit_line("fmt::println(\"Exiting with code {}...\", code);") emitter.decrease_indent emitter.emit_line('}') @@ -206,6 +207,9 @@ class CPU final { // Finished flag bool m_finished{false}; + // Exit code + isa::Word m_code{0}; + explicit CPU(Memory *mem) : m_memory(mem) {} #{setreg_funcs} diff --git a/sim_gen/Hart/hart.rb b/sim_gen/Hart/hart.rb index 8002f12..cb554d1 100644 --- a/sim_gen/Hart/hart.rb +++ b/sim_gen/Hart/hart.rb @@ -52,6 +52,8 @@ class Hart { auto getIcount() const { return m_cpu->m_icount; } + auto getExitCode() const { return m_cpu->m_code; } + public: std::unique_ptr m_mem; std::unique_ptr m_cpu; diff --git a/sim_lib/sim.cc b/sim_lib/sim.cc index bf4a62b..163730e 100644 --- a/sim_lib/sim.cc +++ b/sim_lib/sim.cc @@ -18,12 +18,14 @@ int main(int argc, const char *argv[]) try { constexpr prot::isa::Addr kDefaultStack = 0x7fffffff; prot::isa::Addr stackTop = kDefaultStack; std::string jitBackend; + bool propagateExit = false; CLI::App app{"Generated simulator with JIT support"}; app.add_option("elf", elfPath, "Path to executable ELF file") ->required() ->check(CLI::ExistingFile); + app.add_flag("--propagate-exit", propagateExit, "Propagate exit code from guest to host"); app.add_option("--jit", jitBackend, "Use JIT with specified backend") ->check(CLI::IsMember(prot::engine::JitFactory::backends())); @@ -57,7 +59,7 @@ int main(int argc, const char *argv[]) try { fmt::println("MIPS: {:.2f}", hart.getIcount() / (duration.count() * 1'000'000)); - return EXIT_SUCCESS; + return propagateExit ? hart.getExitCode() : EXIT_SUCCESS; } catch (const std::exception &ex) { fmt::println(std::cerr, "Caught exception of type {}: {}", typeid(ex).name(), ex.what()); From 9136e8b20d1e3cec6a4cf592ebea6bf3dbc5efeb Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Mon, 23 Mar 2026 11:36:01 +0000 Subject: [PATCH 07/75] Start to use CTest instead of python-scripts. Add test presets in CMakePresets. --- CMakeLists.txt | 4 + CMakePresets.json | 27 ++++-- ci-extra/build.sh | 4 +- ci-extra/test.sh | 11 ++- cmake/discover_generated_tests.cmake.in | 23 +++++ sim_lib/sim.cc | 3 +- test/SimTests/C/CMakeLists.txt | 13 ++- test/SimTests/CMakeLists.txt | 8 +- test/SimTests/Common/CMakeLists.txt | 1 - test/SimTests/Common/RunTests.py | 41 --------- test/SimTests/SnippetBased/CMakeLists.txt | 12 ++- test/SimTests/SnippetBased/RunTests.sh | 0 .../SnippetBasedImpl/InitTestGen.rb | 90 ++++++++++++++----- .../SnippetBased/SnippetBasedImpl/TestGen.rb | 79 +++++++++++----- 14 files changed, 211 insertions(+), 105 deletions(-) create mode 100644 cmake/discover_generated_tests.cmake.in delete mode 100644 test/SimTests/Common/CMakeLists.txt delete mode 100644 test/SimTests/Common/RunTests.py delete mode 100644 test/SimTests/SnippetBased/RunTests.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 634aa4b..f420a2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,10 @@ include(cmake/CompilerOptions.cmake) include(cmake/CPM.cmake) include(cmake/dependencies.cmake) +if(PROTEA_BUILD_TESTS) + enable_testing() +endif() + add_subdirectory(lib) add_subdirectory(sim_lib) add_subdirectory(sim_gen) diff --git a/CMakePresets.json b/CMakePresets.json index d6d1a3f..72bd38d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,13 +8,11 @@ "configurePresets": [ { "name": "Base", - "description": "General preset that applies to all configurations", "hidden": true, "binaryDir": "${sourceDir}/build/${presetName}" }, { "name": "Default-Release", - "description": "Release build", "inherits": "Base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" @@ -22,7 +20,6 @@ }, { "name": "Default-Debug", - "description": "Debug build", "inherits": "Base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" @@ -32,13 +29,33 @@ "buildPresets": [ { "name": "Default-Release", - "description": "Build Release configuration", "configurePreset": "Default-Release" }, { "name": "Default-Debug", - "description": "Build Debug configuration", "configurePreset": "Default-Debug" } + ], + "testPresets": [ + { + "name": "Default-Release", + "configurePreset": "Default-Release", + "execution": { + "jobs": 16 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "Default-Debug", + "configurePreset": "Default-Debug", + "execution": { + "jobs": 16 + }, + "output": { + "outputOnFailure": true + } + } ] } diff --git a/ci-extra/build.sh b/ci-extra/build.sh index 05aab0b..ab70d2a 100755 --- a/ci-extra/build.sh +++ b/ci-extra/build.sh @@ -2,7 +2,7 @@ PRESET_NAME=$1 # Configure CMake cmake -S . \ - --preset "${PRESET_NAME}" -DPROTEA_BUILD_TESTS=true -DQEMU_PATH=qemu-riscv32 -G Ninja + --preset "${PRESET_NAME}" -G Ninja # Build -cmake --build --preset ${PRESET_NAME} --target all --parallel 12 +cmake --build --preset ${PRESET_NAME} --target install --parallel 12 diff --git a/ci-extra/test.sh b/ci-extra/test.sh index ac3bddc..c04a4be 100755 --- a/ci-extra/test.sh +++ b/ci-extra/test.sh @@ -1,4 +1,11 @@ PRESET_NAME=$1 -# Run tests -cmake --build --preset ${PRESET_NAME} --target simtests +cmake -S . \ + --preset "${PRESET_NAME}" \ + -DPROTEA_BUILD_TESTS=true \ + -DQEMU_PATH=qemu-riscv32 \ + -G Ninja + +cmake --build --preset "${PRESET_NAME}" --target simtests --parallel 12 + +ctest --preset "${PRESET_NAME}" diff --git a/cmake/discover_generated_tests.cmake.in b/cmake/discover_generated_tests.cmake.in new file mode 100644 index 0000000..455d904 --- /dev/null +++ b/cmake/discover_generated_tests.cmake.in @@ -0,0 +1,23 @@ +if(NOT EXISTS "@OUTPUT_TESTS_DIR@") + message(STATUS "Test directory does not exist yet: @OUTPUT_TESTS_DIR@") + return() +endif() + +file(GLOB discovered_tests "@OUTPUT_TESTS_DIR@/*") + +if(NOT discovered_tests) + message(STATUS "No generated tests found in @OUTPUT_TESTS_DIR@") +endif() + +foreach(test_file IN LISTS discovered_tests) + if(IS_DIRECTORY "${test_file}") + continue() + endif() + + get_filename_component(test_name "${test_file}" NAME) + + add_test( + "@PROJECT_NAME@.${test_name}" + "@GENERATED_SIM_BIN_PATH@" --propagate-exit "${test_file}" + ) +endforeach() diff --git a/sim_lib/sim.cc b/sim_lib/sim.cc index 163730e..95628d0 100644 --- a/sim_lib/sim.cc +++ b/sim_lib/sim.cc @@ -25,7 +25,8 @@ int main(int argc, const char *argv[]) try { app.add_option("elf", elfPath, "Path to executable ELF file") ->required() ->check(CLI::ExistingFile); - app.add_flag("--propagate-exit", propagateExit, "Propagate exit code from guest to host"); + app.add_flag("--propagate-exit", propagateExit, + "Propagate exit code from guest to host"); app.add_option("--jit", jitBackend, "Use JIT with specified backend") ->check(CLI::IsMember(prot::engine::JitFactory::backends())); diff --git a/test/SimTests/C/CMakeLists.txt b/test/SimTests/C/CMakeLists.txt index 7b4c391..b66f30a 100644 --- a/test/SimTests/C/CMakeLists.txt +++ b/test/SimTests/C/CMakeLists.txt @@ -13,6 +13,7 @@ if(PROTEA_BUILD_TESTS) endif() set(TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CImpl) + set(OUTPUT_TESTS_DIR ${CMAKE_CURRENT_BINARY_DIR}/CImpl/bin) set(GENERATED_SIM_BIN_PATH ${protea_simgen_BINARY_DIR}/sim) ExternalProject_Add( @@ -26,8 +27,12 @@ if(PROTEA_BUILD_TESTS) set(RunTests ${tests-common_SOURCE_DIR}/RunTests.py) - add_custom_target(${PROJECT_NAME} - COMMAND ${Python3_EXECUTABLE} ${RunTests} ${GENERATED_SIM_BIN_PATH} ${TESTS_BINARY_DIR}/bin/ - COMMENT "Running ${PROJECT_NAME}") - add_dependencies(${PROJECT_NAME} sim c-simtestsimpl) + set(DISCOVER_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/discover_generated_tests.cmake") + configure_file( + "${CMAKE_SOURCE_DIR}/cmake/discover_generated_tests.cmake.in" + "${DISCOVER_SCRIPT}" + @ONLY + ) + + set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES "${DISCOVER_SCRIPT}") endif() diff --git a/test/SimTests/CMakeLists.txt b/test/SimTests/CMakeLists.txt index 684dd7b..6593b78 100644 --- a/test/SimTests/CMakeLists.txt +++ b/test/SimTests/CMakeLists.txt @@ -1,9 +1,9 @@ project(simtests) -add_subdirectory(Common) - add_subdirectory(C) add_subdirectory(SnippetBased) -add_custom_target(${PROJECT_NAME}) -add_dependencies(${PROJECT_NAME} c-simtests snippetbased-simtests) +if(PROTEA_BUILD_TESTS) + add_custom_target(${PROJECT_NAME}) + add_dependencies(${PROJECT_NAME} sim c-simtestsimpl snippetbased-simtestsimpl) +endif() diff --git a/test/SimTests/Common/CMakeLists.txt b/test/SimTests/Common/CMakeLists.txt deleted file mode 100644 index ed42ad0..0000000 --- a/test/SimTests/Common/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -project(tests-common) diff --git a/test/SimTests/Common/RunTests.py b/test/SimTests/Common/RunTests.py deleted file mode 100644 index b0061f7..0000000 --- a/test/SimTests/Common/RunTests.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import os -import subprocess -import re - -program = sys.argv[1] -directory = sys.argv[2] - -if not os.path.isdir(directory): - print(f"Error: Directory '{directory}' does not exist.") - sys.exit(1) - -has_error = False - -for filename in os.listdir(directory): - filepath = os.path.join(directory, filename) - if os.path.isfile(filepath): - print(f"Running {program} on {filepath}") - try: - result = subprocess.run([program, filepath], capture_output=True, text=True) - except Exception as e: - print(f"Error: Failed to run {program} on {filepath}: {e}") - has_error = True - continue - - match = re.search(r"Exiting with code (\d+)", result.stdout) - if match: - exit_code = int(match.group(1)) - if exit_code != 0: - print(f"Error: {program} reported exit code {exit_code} for file {filepath}") - has_error = True - else: - print(f"Error: Could not find exit code in output for file {filepath}") - has_error = True - -if has_error: - print("Errors detected during execution.") - sys.exit(1) -else: - print("All files processed successfully.") - sys.exit(0) diff --git a/test/SimTests/SnippetBased/CMakeLists.txt b/test/SimTests/SnippetBased/CMakeLists.txt index bc0d9ab..7a837b8 100644 --- a/test/SimTests/SnippetBased/CMakeLists.txt +++ b/test/SimTests/SnippetBased/CMakeLists.txt @@ -29,9 +29,13 @@ if(PROTEA_BUILD_TESTS) add_dependencies(snippetbased-simtestsimpl protea_irgen sim) - add_custom_target(${PROJECT_NAME} - COMMAND ${Python3_EXECUTABLE} ${RunTests} ${GENERATED_SIM_BIN_PATH} ${OUTPUT_TESTS_DIR} - COMMENT "Running ${PROJECT_NAME}") - add_dependencies(${PROJECT_NAME} sim snippetbased-simtestsimpl) + set(DISCOVER_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/discover_generated_tests.cmake") + configure_file( + "${CMAKE_SOURCE_DIR}/cmake/discover_generated_tests.cmake.in" + "${DISCOVER_SCRIPT}" + @ONLY + ) + + set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES "${DISCOVER_SCRIPT}") endif() diff --git a/test/SimTests/SnippetBased/RunTests.sh b/test/SimTests/SnippetBased/RunTests.sh deleted file mode 100644 index e69de29..0000000 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb index 11e3cca..6d1aa4a 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/InitTestGen.rb @@ -1,17 +1,24 @@ # frozen_string_literal: true -require 'Utility/gen_emitter' +require 'optparse' require 'yaml' +require 'etc' +require 'parallel' +require 'Utility/gen_emitter' require_relative 'Target/RISCV/Formatter' module SimTest class InitAsmGen - attr_reader :ir, :reg2value + attr_reader :ir, :reg2value, :rng - def initialize(ir) + def initialize(ir, seed: nil) @ir = ir + @seed = seed || Random.new_seed + @rng = Random.new(@seed) end + def seed; @seed; end + def generate_random_values values = {} ir[:regfiles].each do |regfile| @@ -20,7 +27,7 @@ def generate_random_values next if attrs.include?(:zero) || attrs.include?(:pc) size = reg[:size] || 32 max = (1 << size) - 1 - values[reg[:name]] = rand(0..max) + values[reg[:name]] = @rng.rand(0..max) end end values @@ -44,37 +51,78 @@ def generate(formatter, snippet_content, output_file) emitter.increase_indent formatter.epilogue(emitter) - File.write(output_file + 'yaml', @reg2value.to_yaml) - File.write(output_file + 's', emitter.to_s) + + File.write("#{output_file}yaml", @reg2value.to_yaml) + File.write("#{output_file}s", emitter.to_s) end end end -if __FILE__ == $0 - if ARGV.size < 3 || ARGV.size > 4 - puts "Usage: #{$0} [num_tests]" +if __FILE__ == $PROGRAM_NAME + options = { + num_tests: 4, + seed: 42, + jobs: Etc.nprocessors + } + + parser = OptionParser.new do |opts| + opts.banner = "Usage: #{$PROGRAM_NAME} [options] " + + opts.on('-n', '--num-tests NUM', Integer, 'Number of tests per snippet (default: 4)') do |n| + options[:num_tests] = n + end + + opts.on('-s', '--seed SEED', Integer, 'Random seed for reproducibility') do |s| + options[:seed] = s + end + + opts.on('-j', '--jobs NUM', Integer, 'Number of parallel workers (default: CPU count)') do |j| + options[:jobs] = j + end + + opts.on('-h', '--help', 'Show this help message') do + puts opts + exit + end + end + + parser.parse! + + if ARGV.size != 3 + puts parser exit 1 end - ir_file = ARGV[0] - snippets_dir = ARGV[1] - output_directory = ARGV[2] - num_tests = ARGV[3] ? ARGV[3].to_i : 4 + ir_file, snippets_dir, output_directory = ARGV ir = YAML.load_file(ir_file, symbolize_names: true) - generator = SimTest::InitAsmGen.new(ir) - formatter = SimTest::RiscVFormatter.new - Dir.glob(File.join(snippets_dir, '*')).each do |snippet_path| - next unless File.file?(snippet_path) + snippet_paths = Dir.glob(File.join(snippets_dir, '*')).select { |p| File.file?(p) } + jobs = snippet_paths.each_with_index.flat_map do |snippet_path, snippet_idx| snippet_content = File.read(snippet_path) base = File.basename(snippet_path, '.*') - num_tests.times do |i| - output_file = File.join(output_directory, "#{base}_#{i}.init.") - generator.generate(formatter, snippet_content, output_file) - puts "Generated: #{output_file}s (test #{i+1}/#{num_tests})" + options[:num_tests].times.map do |i| + { + ir: ir, + snippet_content: snippet_content, + base: base, + i: i, + num_tests: options[:num_tests], + seed: options[:seed] + snippet_idx * options[:num_tests] + i, + output_directory: output_directory + } end end + + Parallel.each(jobs, in_processes: options[:jobs]) do |job| + formatter = SimTest::RiscVFormatter.new + generator = SimTest::InitAsmGen.new(job[:ir], seed: job[:seed]) + + output_file = File.join(job[:output_directory], "#{job[:base]}_#{job[:i]}.init.") + generator.generate(formatter, job[:snippet_content], output_file) + + puts "Generated: #{output_file}s (seed: #{generator.seed}, test #{job[:i] + 1}/#{job[:num_tests]})" + end end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb b/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb index fbc2b1d..1d274d2 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/TestGen.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true -require 'Utility/gen_emitter' require 'yaml' +require 'etc' +require 'parallel' +require 'optparse' +require 'Utility/gen_emitter' require_relative 'Target/RISCV/Formatter' require_relative 'Parsers/QEMUParser' @@ -14,7 +17,7 @@ def initialize(ir) end def generate(formatter, snippet_content, init_yaml_file, ref_log_file, output_file) - emitter = Utility::GenEmitter.new() + emitter = Utility::GenEmitter.new initreg2value = YAML.load_file(init_yaml_file) refreg2value = QEMULogParser.parse(ref_log_file) @@ -41,45 +44,81 @@ def generate(formatter, snippet_content, init_yaml_file, ref_log_file, output_fi end if __FILE__ == $0 + options = { + jobs: Etc.nprocessors + } + + parser = OptionParser.new do |opts| + opts.banner = "Usage: #{$0} [options] " + + opts.on('-j', '--jobs NUM', Integer, 'Number of parallel workers (default: CPU count)') do |j| + options[:jobs] = j + end + + opts.on('-h', '--help', 'Show this help message') do + puts opts + exit + end + end + + parser.parse! + if ARGV.size != 5 - puts "Usage: #{$0} " + puts parser exit 1 end ir_file = ARGV[0] snippets_dir = ARGV[1] - init_json_dir = ARGV[2] + init_yaml_dir = ARGV[2] log_dir = ARGV[3] output_dir = ARGV[4] ir = YAML.load_file(ir_file, symbolize_names: true) - generator = SimTest::FinalAsmGen.new(ir) - formatter = SimTest::RiscVFormatter.new + + snippet_map = Dir.glob(File.join(snippets_dir, '*')) + .select { |f| File.file?(f) } + .each_with_object({}) do |path, map| + map[File.basename(path, '.*')] = path + end log_files = Dir.glob(File.join(log_dir, '*')).select { |f| File.file?(f) } - log_files.each do |log_path| + jobs = log_files.filter_map do |log_path| log_basename = File.basename(log_path) - match = log_basename.match(/^(.*)_(\d+)\.init\.log$/) + snippet = match[1] index = match[2].to_i - snippet_path = Dir.glob(File.join(snippets_dir, '*')).find do |f| - File.file?(f) && File.basename(f, '.*') == snippet - end + snippet_path = snippet_map[snippet] - unless snippet_path - puts "Warning: snippet file for '#{snippet}' not found in #{snippets_dir}, skipping" - next - end + init_yaml_file = File.join(init_yaml_dir, "#{snippet}_#{index}.init.yaml") + + { + ir: ir, + snippet: snippet, + index: index, + snippet_path: snippet_path, + init_yaml_file: init_yaml_file, + log_path: log_path, + output_file: File.join(output_dir, "#{snippet}_#{index}.s") + } + end - init_yaml_file = File.join(init_json_dir, "#{snippet}_#{index}.init.yaml") + Parallel.each(jobs, in_processes: options[:jobs]) do |job| + generator = SimTest::FinalAsmGen.new(job[:ir]) + formatter = SimTest::RiscVFormatter.new + snippet_content = File.read(job[:snippet_path]) - output_file = File.join(output_dir, "#{snippet}_#{index}.s") - snippet_content = File.read(snippet_path) + generator.generate( + formatter, + snippet_content, + job[:init_yaml_file], + job[:log_path], + job[:output_file] + ) - generator.generate(formatter, snippet_content, init_yaml_file, log_path, output_file) - puts "Generated: #{output_file}" + puts "Generated: #{job[:output_file]}" end end From 17b66cb8170974c12330b3de28f7475ad2ba288a Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 24 Mar 2026 07:44:49 +0000 Subject: [PATCH 08/75] Add new presets. --- CMakeLists.txt | 2 +- CMakePresets.json | 65 ++++++++++++++++++++++++++++++++++++++ cmake/CompilerConfig.cmake | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 cmake/CompilerConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f420a2f..c8d4133 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ set(TARGET_NAME RISCV) option(PROTEA_BUILD_TESTS "Enable tests build (requires riscv gnu toolchain)" OFF) -enable_testing() if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set_property(CACHE CMAKE_INSTALL_PREFIX @@ -23,6 +22,7 @@ include(cmake/QEMU.cmake) include(cmake/CompilerOptions.cmake) include(cmake/CPM.cmake) include(cmake/dependencies.cmake) +include(cmake/CompilerConfig.cmake) if(PROTEA_BUILD_TESTS) enable_testing() diff --git a/CMakePresets.json b/CMakePresets.json index 72bd38d..0d67ae2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,6 +24,29 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } + }, + { + "name": "Default-RelWithDebInfo", + "inherits": "Base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "Default-Sanitized", + "inherits": "Base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "SANITIZED": "ON" + } + }, + { + "name": "Default-SanitizedDebug", + "inherits": "Base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "SANITIZED": "ON" + } } ], "buildPresets": [ @@ -34,6 +57,18 @@ { "name": "Default-Debug", "configurePreset": "Default-Debug" + }, + { + "name": "Default-RelWithDebInfo", + "configurePreset": "Default-RelWithDebInfo" + }, + { + "name": "Default-Sanitized", + "configurePreset": "Default-Sanitized" + }, + { + "name": "Default-SanitizedDebug", + "configurePreset": "Default-SanitizedDebug" } ], "testPresets": [ @@ -56,6 +91,36 @@ "output": { "outputOnFailure": true } + }, + { + "name": "Default-RelWithDebInfo", + "configurePreset": "Default-RelWithDebInfo", + "execution": { + "jobs": 16 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "Default-Sanitized", + "configurePreset": "Default-Sanitized", + "execution": { + "jobs": 16 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "Default-SanitizedDebug", + "configurePreset": "Default-SanitizedDebug", + "execution": { + "jobs": 16 + }, + "output": { + "outputOnFailure": true + } } ] } diff --git a/cmake/CompilerConfig.cmake b/cmake/CompilerConfig.cmake new file mode 100644 index 0000000..e7b2bff --- /dev/null +++ b/cmake/CompilerConfig.cmake @@ -0,0 +1,60 @@ +option(HARDENED "Should the standard library be hardened" OFF) +option(SANITIZED "Should the build be sanitized" OFF) + +function(configure_compiler) + set(isGCC OFF) + set(isClang OFF) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(isGCC ON) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(isClang ON) + endif() + + set(compilerOptions "") + set(compilerDefinitions "") + set(linkerOptions "") + + if(isClang) + list(APPEND compilerOptions -stdlib=libc++) + list(APPEND linkerOptions -stdlib=libc++) + message(STATUS "Using libc++ as a standard library") + endif() + + if(HARDENED) + if(isGCC) + list(APPEND compilerDefinitions _GLIBCXX_DEBUG) + message(STATUS "Enabled debug mode for libstdc++") + elseif(isClang) + list(APPEND compilerDefinitions _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) + message(STATUS "Enabled hardening mode for libc++") + else() + message(STATUS "Hardening is not supported for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'") + endif() + endif() + + if(SANITIZED) + if(isGCC OR isClang) + list(APPEND compilerOptions + -fsanitize=undefined,address + -fno-sanitize-recover=all + -fno-optimize-sibling-calls + -fno-omit-frame-pointer + ) + list(APPEND linkerOptions + -fsanitize=undefined,address + ) + message(STATUS "Enabled UBSan and ASan") + else() + message(WARNING "Sanitized builds are not supported for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'") + endif() + endif() + + message(STATUS "Setting global compiler options: ${compilerOptions}") + message(STATUS "Setting global compiler definitions: ${compilerDefinitions}") + message(STATUS "Setting global linker options: ${linkerOptions}") + + add_compile_options(${compilerOptions}) + add_compile_definitions(${compilerDefinitions}) + add_link_options(${linkerOptions}) +endfunction() From 138151cabc614b8848eed8e826073ece3c169672 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Fri, 20 Mar 2026 11:29:29 +0000 Subject: [PATCH 09/75] Describe RV32M --- cmake/toolchain/riscv.cmake | 2 +- code_gen/cpp_gen.rb | 2 + lib/ADL/scope.rb | 3 + lib/ADL/var.rb | 3 + lib/Target/RISC-V/32M.rb | 56 +++++++++++++++++++ lib/ir_gen.rb | 1 + .../Target/RISCV/Snippets/mul.s | 6 ++ 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 lib/Target/RISC-V/32M.rb create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s diff --git a/cmake/toolchain/riscv.cmake b/cmake/toolchain/riscv.cmake index 6a60de9..67e51d5 100644 --- a/cmake/toolchain/riscv.cmake +++ b/cmake/toolchain/riscv.cmake @@ -14,7 +14,7 @@ set(RISCV_TOOLCHAIN_PREFIX # Target architecture (modify these according to your needs) set(RISCV_ARCH - "rv32i" + "rv32im" CACHE STRING "RISC-V architecture") set(RISCV_ABI "ilp32" diff --git a/code_gen/cpp_gen.rb b/code_gen/cpp_gen.rb index b33489c..388b379 100644 --- a/code_gen/cpp_gen.rb +++ b/code_gen/cpp_gen.rb @@ -52,6 +52,8 @@ def generate_statement(operation) binary_operation(@emitter, operation, '-') when :mul binary_operation(@emitter, operation, '*') + when :rem + binary_operation(@emitter, operation, '%') when :div binary_operation(@emitter, operation, '/') when :shr diff --git a/lib/ADL/scope.rb b/lib/ADL/scope.rb index 57d4643..2175a7e 100644 --- a/lib/ADL/scope.rb +++ b/lib/ADL/scope.rb @@ -75,6 +75,9 @@ def binOpWType(a, b, op, t) # redefine! add & sub will never be the same def add(a, b) = binOp(a, b, :add) def sub(a, b) = binOp(a, b, :sub) + def mul(a, b) = binOp(a, b, :mul) + def div(a, b) = binOp(a, b, :div) + def rem(a, b) = binOp(a, b, :rem) def shl(a, b) = binOp(a, b, :shl) def lt(a, b) = binOpWType(a, b, :lt, :b1) def gt(a, b) = binOpWType(a, b, :gt, :b1) diff --git a/lib/ADL/var.rb b/lib/ADL/var.rb index 671f258..63321f5 100644 --- a/lib/ADL/var.rb +++ b/lib/ADL/var.rb @@ -42,6 +42,9 @@ module SimInfra class Var def +(other) = @scope.add(self, other) def -(other) = @scope.sub(self, other) + def *(other) = @scope.mul(self, other) + def /(other) = @scope.div(self, other) + def %(other) = @scope.rem(self, other) def <<(other) = @scope.shl(self, other) def <(other) = @scope.lt(self, other) def <=(other) = @scope.le(self, other) diff --git a/lib/Target/RISC-V/32M.rb b/lib/Target/RISC-V/32M.rb new file mode 100644 index 0000000..7c7a7f1 --- /dev/null +++ b/lib/Target/RISC-V/32M.rb @@ -0,0 +1,56 @@ +require_relative "encoding" +require_relative "../../ADL/base" +require_relative "../../ADL/builder" + +module RV32M + include SimInfra + extend SimInfra + + Instruction(:mul) { + encoding *format_r(0b0110011, 0b000, 0b0000001) + asm { "mul {rd}, {rs1}, {rs2}" } + code { rd[]= rs1.s * rs2.s } + } + + Instruction(:mulh) { + encoding *format_r(0b0110011, 0b001, 0b0000001) + asm { "mulh {rd}, {rs1}, {rs2}" } + code { rd[]= (rs1.s64 * rs2.s64) >> 32 } + } + + Instruction(:mulhsu) { + encoding *format_r(0b0110011, 0b010, 0b0000001) + asm { "mulhsu {rd}, {rs1}, {rs2}" } + code { rd[]= (rs1.s64 * rs2.u64.s64) >> 32 } + } + + Instruction(:mulhu) { + encoding *format_r(0b0110011, 0b011, 0b0000001) + asm { "mulhu {rd}, {rs1}, {rs2}" } + code { rd[]= (rs1.u64 * rs2.u64) >> 32 } + } + + Instruction(:div) { + encoding *format_r(0b0110011, 0b100, 0b0000001) + asm { "div {rd}, {rs1}, {rs2}" } + code { rd[]= rs1.s / rs2.s } + } + + Instruction(:divu) { + encoding *format_r(0b0110011, 0b101, 0b0000001) + asm { "divu {rd}, {rs1}, {rs2}" } + code { rd[]= rs1.u / rs2.u } + } + + Instruction(:rem) { + encoding *format_r(0b0110011, 0b110, 0b0000001) + asm { "rem {rd}, {rs1}, {rs2}" } + code { rd[]= rs1.s / rs2.s } + } + + Instruction(:remu) { + encoding *format_r(0b0110011, 0b111, 0b0000001) + asm { "remu {rd}, {rs1}, {rs2}" } + code { rd[]= rs1.u / rs2.u } + } +end diff --git a/lib/ir_gen.rb b/lib/ir_gen.rb index da09671..1a66c17 100644 --- a/lib/ir_gen.rb +++ b/lib/ir_gen.rb @@ -4,6 +4,7 @@ require 'ADL/base' require 'ADL/builder' require 'Target/RISC-V/32I' +require 'Target/RISC-V/32M' yaml_data = SimInfra.serialize File.write('IR.yaml', yaml_data) diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s new file mode 100644 index 0000000..d3fa412 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s @@ -0,0 +1,6 @@ +li a0, 200 +li a1, 300 +mul a2, a0, a1 +mulh a3, a0, a1 +mulhsu a4, a0, a1 +mulhu a5, a0, a1 From ec4518e71da27fc79c4cf075cc40d954095e6ac9 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Fri, 20 Mar 2026 11:46:14 +0000 Subject: [PATCH 10/75] Decoder fix --- sim_gen/Decoders/decoder.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sim_gen/Decoders/decoder.rb b/sim_gen/Decoders/decoder.rb index 4d2689f..e6562fa 100644 --- a/sim_gen/Decoders/decoder.rb +++ b/sim_gen/Decoders/decoder.rb @@ -56,32 +56,35 @@ def get_maj_range(lead_bits) def get_lead_bits(instructions, separ_mask = 0) lead_bits = {} max_len = instructions.map { |insn| insn[:XLEN] * 8 }.max + for bit in 0...max_len - if separ_mask & (1 << bit) != 0 - next - end - + next if (separ_mask & (1 << bit)) != 0 + count_0 = 0 count_1 = 0 - + all_have_bit = true + for insn in instructions insn_mask = calc_insn_mask(insn) insn_value = calc_insn_value(insn) - - if insn_mask & (1 << bit) == 0 - next + + if (insn_mask & (1 << bit)) == 0 + all_have_bit = false + break end - + if (insn_value & (1 << bit)) != 0 count_1 += 1 else count_0 += 1 end end - if count_0 > 0 && count_1 > 0 + + if all_have_bit && count_0 > 0 && count_1 > 0 lead_bits[bit] = [count_0, count_1] end end + lead_bits end From 3cb7de3835a6568dd5b95295bec5e7273a49f48a Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Fri, 27 Mar 2026 14:09:12 +0000 Subject: [PATCH 11/75] Small fixes. --- lib/Target/RISC-V/32M.rb | 4 ++-- sim_gen/ISA/isa.rb | 2 +- .../SnippetBasedImpl/Target/RISCV/Snippets/mul.s | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/Target/RISC-V/32M.rb b/lib/Target/RISC-V/32M.rb index 7c7a7f1..2f22a40 100644 --- a/lib/Target/RISC-V/32M.rb +++ b/lib/Target/RISC-V/32M.rb @@ -45,12 +45,12 @@ module RV32M Instruction(:rem) { encoding *format_r(0b0110011, 0b110, 0b0000001) asm { "rem {rd}, {rs1}, {rs2}" } - code { rd[]= rs1.s / rs2.s } + code { rd[]= rs1.s % rs2.s } } Instruction(:remu) { encoding *format_r(0b0110011, 0b111, 0b0000001) asm { "remu {rd}, {rs1}, {rs2}" } - code { rd[]= rs1.u / rs2.u } + code { rd[]= rs1.u % rs2.u } } end diff --git a/sim_gen/ISA/isa.rb b/sim_gen/ISA/isa.rb index bed0076..a76067e 100644 --- a/sim_gen/ISA/isa.rb +++ b/sim_gen/ISA/isa.rb @@ -58,7 +58,7 @@ def get_addr_type(instructions) def is_terminator_instruction(insn) insn[:code][:tree].each { |node| - return true if node[:name] == :branch + return true if node[:name] == :branch || node[:name] == :sysCall } false end diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s index d3fa412..2cbf877 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s @@ -4,3 +4,8 @@ mul a2, a0, a1 mulh a3, a0, a1 mulhsu a4, a0, a1 mulhu a5, a0, a1 +li a1, 2 +div a6, a0, a1 +divu a7, a0, a1 +rem t0, a0, a1 +remu t1, a0, a1 From 980f2b03b9913b24e1cb99f15db2e28cf2c5bd8b Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Fri, 27 Mar 2026 14:13:24 +0000 Subject: [PATCH 12/75] Removed on push in workflow. --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 707cdcc..50cfa0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,6 @@ name: CI on: - push: pull_request: jobs: From e121a8b14afe626691f238970c35eb14f066a3fa Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Thu, 7 May 2026 12:16:09 +0000 Subject: [PATCH 13/75] Add small improvements --- lib/ADL/builder.rb | 40 +++++++++---------- lib/Target/RISC-V/32I.rb | 16 ++++---- sim_gen/ExecEngines/naive_interpreter.rb | 16 -------- .../Target/RISCV/Snippets/add-1.s | 1 + .../Target/RISCV/Snippets/mul.s | 7 ---- 5 files changed, 29 insertions(+), 51 deletions(-) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index 36f9c3d..adc01d4 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -180,13 +180,27 @@ def self.from_h(h) end @@regfiles = [] - class RegisterFileBuilder - def initialize(name) - @info = RegisterFileInfo.new(name) - @info.regs = [] - end - attr_reader :info +class RegisterFileBuilder + attr_reader :info + + def initialize(name) + @info = RegisterFileInfo.new(name) + @info.regs = [] + end + + def method_missing(name, *args) + if name.to_s.start_with?('r') + size = name.to_s[1..].to_i + instance_eval "def #{name}(sym, *args); @info.regs << Register.new(sym, #{size}, args.size > 0 ? args : []); end", __FILE__, __LINE__ + @info.regs << Register.new(args[0], size, args.size > 1 ? args[1..] : []) + else + error "Unknown method #{name}" end + end + + def zero = :zero + def pc = :pc +end def RegisterFile(name, &block) bldr = RegisterFileBuilder.new(name) @@ -202,20 +216,6 @@ def RegFiles() # * generate precise fields module SimInfra - class RegisterFileBuilder - def r32(sym, *args) - @info.regs << Register.new(sym, 32, args[0] ? [args[0]] : []) - end - - def zero() - :zero - end - - def pc() - :pc - end - end - class InstructionInfoBuilder def code(&block) if !@info.map_code_blocks.empty? diff --git a/lib/Target/RISC-V/32I.rb b/lib/Target/RISC-V/32I.rb index 3e2d782..1b42331 100644 --- a/lib/Target/RISC-V/32I.rb +++ b/lib/Target/RISC-V/32I.rb @@ -175,50 +175,50 @@ module RV32I Instruction(:beq) { encoding *format_b(0b1100011, 0b000) asm { "beq {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 == rs2, pc + imm, pc + xlen)) } + code { branch(select(rs1 == rs2, pc + imm, pc + 4)) } } Instruction(:bne) { encoding *format_b(0b1100011, 0b001) asm { "bne {rs1}, {rs2}, {imm}" } - code { branch(select(rs1 != rs2, pc + imm, pc + xlen)) } + code { branch(select(rs1 != rs2, pc + imm, pc + 4)) } } Instruction(:blt) { encoding *format_b(0b1100011, 0b100) asm { "blt {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.s < rs2.s, pc + imm, pc + xlen)) } + code { branch(select(rs1.s < rs2.s, pc + imm, pc + 4)) } } Instruction(:bge) { encoding *format_b(0b1100011, 0b101) asm { "bge {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.s >= rs2.s, pc + imm, pc + xlen)) } + code { branch(select(rs1.s >= rs2.s, pc + imm, pc + 4)) } } Instruction(:bltu) { encoding *format_b(0b1100011, 0b110) asm { "bltu {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.u < rs2.u, pc + imm, pc + xlen)) } + code { branch(select(rs1.u < rs2.u, pc + imm, pc + 4)) } } Instruction(:bgeu) { encoding *format_b(0b1100011, 0b111) asm { "bgeu {rs1}, {rs2}, {imm}" } - code { branch(select(rs1.u >= rs2.u, pc + imm, pc + xlen)) } + code { branch(select(rs1.u >= rs2.u, pc + imm, pc + 4)) } } Instruction(:jal) { encoding *format_j(0b1101111) asm { "jal {rd}, {imm}" } - code { rd[]= pc + xlen; branch(pc + imm) } + code { rd[]= pc + 4; branch(pc + imm) } } Instruction(:jalr) { encoding *format_i(0b1100111, 0b000) asm { "jalr {rd}, {rs1}, {imm}" } code { - let :t, :b32, pc + xlen + let :t, :b32, pc + 4 branch((rs1 + imm) & (~1)) rd[]= t } diff --git a/sim_gen/ExecEngines/naive_interpreter.rb b/sim_gen/ExecEngines/naive_interpreter.rb index cadca79..ae00151 100644 --- a/sim_gen/ExecEngines/naive_interpreter.rb +++ b/sim_gen/ExecEngines/naive_interpreter.rb @@ -44,22 +44,6 @@ def map_operands(insn) operands end - def cpu_write_reg(dst) - "cpu.set#{dst[:regset]}" - end - - def cpu_read_reg(dst) - "cpu.get#{dst[:regset]}" - end - - def cpu_write_mem(addr, val) - "cpu.m_memory->write(#{addr}, #{val})" - end - - def cpu_read_mem(dst, addr) - "cpu.m_memory->read<#{Utility::HelperCpp.gen_small_type(dst[:type])}>(#{addr})" - end - def generate_exec_function(instruction, funcs) emitter = Utility::GenEmitter.new operand_map = map_operands(instruction) diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s index d74fb1a..b869fdb 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s @@ -1 +1,2 @@ add x10, x6, x5 +add x12, x4, x15 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s index 2cbf877..9fcc6c1 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s @@ -1,11 +1,4 @@ -li a0, 200 -li a1, 300 mul a2, a0, a1 mulh a3, a0, a1 mulhsu a4, a0, a1 mulhu a5, a0, a1 -li a1, 2 -div a6, a0, a1 -divu a7, a0, a1 -rem t0, a0, a1 -remu t1, a0, a1 From 05e7d15ca0c2b0594fd417e6c19fbc566c582c18 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Thu, 7 May 2026 12:28:43 +0000 Subject: [PATCH 14/75] Remove xlen field. Small cmake improvement --- lib/ADL/builder.rb | 6 +----- lib/CMakeLists.txt | 7 ++++--- sim_gen/CMakeLists.txt | 2 +- sim_gen/ExecEngines/base_exec_engine.rb | 2 +- sim_gen/ISA/isa.rb | 2 +- sim_gen/Utility/sim_utility.rb | 12 +++++++++++- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index adc01d4..9c31471 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -40,7 +40,7 @@ def self.interface_functions end class InstructionInfo - attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :XLEN, :feature + attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :feature def initialize(name, feature) @name = name; @map_code_blocks = {} @@ -52,7 +52,6 @@ def to_h name: @name, fields: @fields.map { |f| f.to_h }, frmt: @frmt, - XLEN: @XLEN, asm_str: @asm_str, code: @code.to_h, map: @map.to_h, @@ -64,7 +63,6 @@ def self.from_h(h) info = InstructionInfo.new(h[:name], h[:feature]) info.fields = h[:fields].map { |f| Field.from_h(f) } info.frmt = h[:frmt] - info.XLEN = h[:XLEN] info.asm_str = h[:asm_str] info.code = Scope.new(nil) info.code.instance_variable_set(:@tree, h[:code][:tree].map { |s| IrStmt.from_h(s) }) @@ -111,8 +109,6 @@ def encoding(frmt, fields, *args) for f in fields sum_bits += Utility.get_type(f.value.type).bitsize end - @info.XLEN = sum_bits / 8 - @info.code.instance_eval "def xlen(); return #{@info.XLEN.to_s}; end" end attr_reader :info end diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f637db6..d181620 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,9 +1,10 @@ project(protea_irgen) add_custom_command( - OUTPUT IR.yaml + OUTPUT ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb COMMENT "Running ${PROJECT_NAME}" ) -add_custom_target(${PROJECT_NAME} DEPENDS IR.yaml) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/IR.yaml DESTINATION share/) +add_custom_target(${PROJECT_NAME} DEPENDS ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml) +install(FILES ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml DESTINATION share/) diff --git a/sim_gen/CMakeLists.txt b/sim_gen/CMakeLists.txt index adaf7ad..8d0c5e8 100644 --- a/sim_gen/CMakeLists.txt +++ b/sim_gen/CMakeLists.txt @@ -27,7 +27,7 @@ set(IR_YAML_FILE ${protea_irgen_BINARY_DIR}/IR.yaml) add_custom_command(DEPENDS OUTPUT ${PROTEA_SIMGEN_OUTPUT_FILES} COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${IR_YAML_FILE} - DEPENDS ${IR_YAML_FILE} + DEPENDS protea_irgen COMMENT "Running ${PROJECT_NAME}" ) add_custom_target(${PROJECT_NAME} ALL DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) diff --git a/sim_gen/ExecEngines/base_exec_engine.rb b/sim_gen/ExecEngines/base_exec_engine.rb index a2247aa..de2c8cd 100644 --- a/sim_gen/ExecEngines/base_exec_engine.rb +++ b/sim_gen/ExecEngines/base_exec_engine.rb @@ -34,7 +34,7 @@ module TranslationUnit module_function def generate_base_exec_engine(input_ir) - max_xlen = SimGen::Helper::find_max_xlen(input_ir[:regfiles]) + max_xlen = SimGen::Helper::find_max_regsize(input_ir[:regfiles]) "#include \"base_exec_engine.hh\" #include \"memory.hh\" diff --git a/sim_gen/ISA/isa.rb b/sim_gen/ISA/isa.rb index a76067e..ab59420 100644 --- a/sim_gen/ISA/isa.rb +++ b/sim_gen/ISA/isa.rb @@ -98,7 +98,7 @@ def generate_isa_header(input_ir) instruction_struct = Helper.generate_instruction_struct(input_ir) is_terminator_function = Helper.generate_is_terminator_function(input_ir) - max_xlen = SimGen::Helper::find_max_xlen(input_ir[:regfiles]) + max_xlen = SimGen::Helper::find_max_regsize(input_ir[:regfiles]) "#ifndef GENERATED_#{input_ir[:isa_name].upcase}_ISA_HH_INCLUDED #define GENERATED_#{input_ir[:isa_name].upcase}_ISA_HH_INCLUDED diff --git a/sim_gen/Utility/sim_utility.rb b/sim_gen/Utility/sim_utility.rb index 0e75596..7d4787f 100644 --- a/sim_gen/Utility/sim_utility.rb +++ b/sim_gen/Utility/sim_utility.rb @@ -2,7 +2,7 @@ module SimGen module Helper module_function - def find_max_xlen(regfiles) + def find_max_regsize(regfiles) max_xlen = 0 regfiles.each do |regfile| regfile[:regs].each do |reg| @@ -11,5 +11,15 @@ def find_max_xlen(regfiles) end max_xlen end + + def find_max_insn_len(instructions) + max_len = 0 + instructions.each do |insn| + insn[:code][:tree].each do |node| + len_insn = node[:fields].map { |f| f[:from] - f[:to] }.sum / 8 + max_len = [max_len, len_insn].max + end + end + max_len end end From 0069758eb041de11a27611bd8d73411c7c592ade Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Thu, 7 May 2026 12:45:56 +0000 Subject: [PATCH 15/75] fix --- sim_gen/Decoders/decoder.rb | 3 +-- sim_gen/ISA/isa.rb | 2 +- sim_gen/Utility/sim_utility.rb | 7 +++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sim_gen/Decoders/decoder.rb b/sim_gen/Decoders/decoder.rb index e6562fa..c9475d0 100644 --- a/sim_gen/Decoders/decoder.rb +++ b/sim_gen/Decoders/decoder.rb @@ -55,8 +55,7 @@ def get_maj_range(lead_bits) def get_lead_bits(instructions, separ_mask = 0) lead_bits = {} - max_len = instructions.map { |insn| insn[:XLEN] * 8 }.max - + max_len = SimGen::Helper::find_max_insn_len(instructions) for bit in 0...max_len next if (separ_mask & (1 << bit)) != 0 diff --git a/sim_gen/ISA/isa.rb b/sim_gen/ISA/isa.rb index ab59420..4f4b830 100644 --- a/sim_gen/ISA/isa.rb +++ b/sim_gen/ISA/isa.rb @@ -118,7 +118,7 @@ def generate_isa_header(input_ir) inline constexpr std::size_t getILen(Opcode opc) { switch (opc) { - #{input_ir[:instructions].map { |insn| "case Opcode::k#{insn[:name].to_s.upcase}: return #{insn[:XLEN]};" }.join("\n ")} + #{input_ir[:instructions].map { |insn| "case Opcode::k#{insn[:name].to_s.upcase}: return #{insn[:fields].map { |f| f[:from] - f[:to] + 1 }.sum / 8};" }.join("\n ")} default: return 4; } } diff --git a/sim_gen/Utility/sim_utility.rb b/sim_gen/Utility/sim_utility.rb index 7d4787f..39e7276 100644 --- a/sim_gen/Utility/sim_utility.rb +++ b/sim_gen/Utility/sim_utility.rb @@ -15,11 +15,10 @@ def find_max_regsize(regfiles) def find_max_insn_len(instructions) max_len = 0 instructions.each do |insn| - insn[:code][:tree].each do |node| - len_insn = node[:fields].map { |f| f[:from] - f[:to] }.sum / 8 - max_len = [max_len, len_insn].max - end + len_insn = insn[:fields].map { |f| f[:from] - f[:to] + 1 }.sum + max_len = [max_len, len_insn].max end max_len + end end end From 6f634163cc7e224799bcd3b9f049577d98c60790 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Thu, 7 May 2026 12:49:54 +0000 Subject: [PATCH 16/75] fix --- lib/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d181620..4d58ff4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,10 +1,10 @@ project(protea_irgen) add_custom_command( - OUTPUT ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml + OUTPUT ${PROJECT_BINARY_DIR}/IR.yaml DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb COMMENT "Running ${PROJECT_NAME}" ) -add_custom_target(${PROJECT_NAME} DEPENDS ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml) -install(FILES ${CMAKE_PROJECT_BINARY_DIR}/IR.yaml DESTINATION share/) +add_custom_target(${PROJECT_NAME} DEPENDS ${PROJECT_BINARY_DIR}/IR.yaml) +install(FILES ${PROJECT_BINARY_DIR}/IR.yaml DESTINATION share/) From 1780f5232087d1b4540418b806df8bca2528da1d Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 10:24:47 +0000 Subject: [PATCH 17/75] Add some tests for sim --- sim_lib/memory.cc | 6 +- test/CodeGenTests/simple_tests.rb | 94 ------------------- test/SimTests/C/CImpl/CMakeLists.txt | 2 + .../C/CImpl/xorshift32/CMakeLists.txt | 1 + test/SimTests/C/CImpl/xorshift32/main.c | 33 +++++++ test/SimTests/C/CImpl/zfunc/CMakeLists.txt | 1 + test/SimTests/C/CImpl/zfunc/main.c | 55 +++++++++++ .../Target/RISCV/Snippets/addi-1.s | 1 + .../Target/RISCV/Snippets/div.s | 2 + .../Target/RISCV/Snippets/factorial.s | 27 ++++++ .../Target/RISCV/Snippets/fib.s | 13 +++ .../Target/RISCV/Snippets/rem.s | 2 + 12 files changed, 139 insertions(+), 98 deletions(-) delete mode 100644 test/CodeGenTests/simple_tests.rb create mode 100644 test/SimTests/C/CImpl/xorshift32/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/xorshift32/main.c create mode 100644 test/SimTests/C/CImpl/zfunc/CMakeLists.txt create mode 100644 test/SimTests/C/CImpl/zfunc/main.c create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/factorial.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s diff --git a/sim_lib/memory.cc b/sim_lib/memory.cc index a16f3cb..35c5438 100644 --- a/sim_lib/memory.cc +++ b/sim_lib/memory.cc @@ -2,9 +2,7 @@ #include "isa.hh" -#include #include -#include extern "C" { #include @@ -69,12 +67,12 @@ class PlainMemory : public Memory { } void writeBlock(std::span src, isa::Addr addr) override { - // checkRange(addr, src.size()); + checkRange(addr, src.size()); std::memcpy(translateAddr(addr), src.data(), src.size()); } void readBlock(isa::Addr addr, std::span dest) const override { - // checkRange(addr, dest.size()); + checkRange(addr, dest.size()); std::memcpy(dest.data(), translateAddr(addr), dest.size()); } diff --git a/test/CodeGenTests/simple_tests.rb b/test/CodeGenTests/simple_tests.rb deleted file mode 100644 index 506c0d1..0000000 --- a/test/CodeGenTests/simple_tests.rb +++ /dev/null @@ -1,94 +0,0 @@ -require 'code_gen/code_gen' -require 'Utility/gen_emitter' -require 'minitest/autorun' - -class SemaTestsSimple < Minitest::Test - def test_add_instruction - operation = { - name: 'add', - oprnds: [ - { name: 'rd', type: 's32', regset: nil }, - { name: 'rs1', type: 's32', regset: nil }, - { name: 'rs2', type: 's32', regset: nil } - ], - attrs: nil - } - - mapping = { - 'rd' => 'R[rd]', - 'rs1' => 'R[rs1]', - 'rs2' => 'R[rs2]' - } - - expected_code = 'R[rd] = R[rs1] + R[rs2];' - emitter = Utility::GenEmitter.new - generated_code = CodeGen.new(emitter, mapping) - generated_code.generate_statement(operation) - - assert_equal(expected_code, emitter.to_s) - end - - def test_let_instruction - operation = { - name: 'let', - oprnds: [ - { name: 'rd', type: 's32', regset: nil }, - { name: nil, type: 'iconst', value: 42 } - ], - attrs: nil - } - - mapping = { - 'rd' => 'R[rd]' - } - - expected_code = 'R[rd] = 42;' - emitter = Utility::GenEmitter.new - generated_code = CodeGen.new(emitter, mapping) - generated_code.generate_statement(operation) - - assert_equal(expected_code, emitter.to_s) - end - - def test_new_var_instruction - operation = { - name: 'new_var', - oprnds: [ - { name: 'temp', type: 's32', regset: nil } - ], - attrs: nil - } - - mapping = {} - - expected_code = 'int32_t temp;' - emitter = Utility::GenEmitter.new - generated_code = CodeGen.new(emitter, mapping) - generated_code.generate_statement(operation) - - assert_equal(expected_code, emitter.to_s) - end - - def test_cast_instruction - operation = { - name: 'cast', - oprnds: [ - { name: 'rd', type: 's32', regset: nil }, - { name: 'rs', type: 'u16', regset: nil } - ], - attrs: nil - } - - mapping = { - 'rd' => 'R[rd]', - 'rs' => 'R[rs]' - } - - expected_code = 'R[rd] = (static_cast(R[rs]) << 16) >> 16;' - emitter = Utility::GenEmitter.new - generated_code = CodeGen.new(emitter, mapping) - generated_code.generate_statement(operation) - - assert_equal(expected_code, emitter.to_s) - end -end diff --git a/test/SimTests/C/CImpl/CMakeLists.txt b/test/SimTests/C/CImpl/CMakeLists.txt index dbcd372..c8b03b0 100644 --- a/test/SimTests/C/CImpl/CMakeLists.txt +++ b/test/SimTests/C/CImpl/CMakeLists.txt @@ -11,3 +11,5 @@ endmacro() add_subdirectory(fib) add_subdirectory(qsort) +add_subdirectory(xorshift32) +add_subdirectory(zfunc) diff --git a/test/SimTests/C/CImpl/xorshift32/CMakeLists.txt b/test/SimTests/C/CImpl/xorshift32/CMakeLists.txt new file mode 100644 index 0000000..39f717c --- /dev/null +++ b/test/SimTests/C/CImpl/xorshift32/CMakeLists.txt @@ -0,0 +1 @@ +protea_add_test(protea_test_xorshift32 main.c) diff --git a/test/SimTests/C/CImpl/xorshift32/main.c b/test/SimTests/C/CImpl/xorshift32/main.c new file mode 100644 index 0000000..bde49fc --- /dev/null +++ b/test/SimTests/C/CImpl/xorshift32/main.c @@ -0,0 +1,33 @@ +#include + +volatile uint32_t seed = 2463534242u; + +constexpr uint32_t N = 1024 * 1024; +uint32_t buffer[N]; + +uint32_t xorshift32(uint32_t x) { + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; +} + +uint32_t run() { + uint32_t x = seed; + + for (uint32_t i = 0; i < N; ++i) { + x = xorshift32(x); + buffer[i] = x; + } + + uint32_t sum = 0; + + for (uint32_t i = 0; i < N; ++i) + sum ^= buffer[i]; + + return sum; +} + +int main() { + return run() == 752068848 ? 0 : 1; +} diff --git a/test/SimTests/C/CImpl/zfunc/CMakeLists.txt b/test/SimTests/C/CImpl/zfunc/CMakeLists.txt new file mode 100644 index 0000000..bf117a9 --- /dev/null +++ b/test/SimTests/C/CImpl/zfunc/CMakeLists.txt @@ -0,0 +1 @@ +protea_add_test(protea_test_zfunc main.c) diff --git a/test/SimTests/C/CImpl/zfunc/main.c b/test/SimTests/C/CImpl/zfunc/main.c new file mode 100644 index 0000000..427462b --- /dev/null +++ b/test/SimTests/C/CImpl/zfunc/main.c @@ -0,0 +1,55 @@ +#define MAXN 1024 +const char* const str = "aBaBCAcabbBAababababcbCBCcbcBABbcbBbabacbBABcb"; + +int strlen(const char* str) { + int result = 0; + while (str[result] != '\0') + ++result; + return result; +} + +void z_function(const char *s, int n, int z[]) { + z[0] = n; + + int l = 0; + int r = 0; + + for (int i = 1; i < n; ++i) { + if (i <= r) { + int k = i - l; + int rem = r - i + 1; + z[i] = (z[k] < rem) ? z[k] : rem; + } else { + z[i] = 0; + } + + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) + ++z[i]; + + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } +} + +int check_z_function(const char *s, int n, int z[]) { + + if (z[0] != n) + return 1; + for (int i = 1; i < n; ++i) { + int expected = 0; + while (i + expected < n && s[expected] == s[i + expected]) + ++expected; + if (z[i] != expected) + return 1; + } + return 0; +} + +int main() { + int z[MAXN]; + + z_function(str, strlen(str), z); + return check_z_function(str, strlen(str), z); +} diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s index cd32b26..aa94107 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s @@ -1 +1,2 @@ addi x3, x6, 10 +addi x7, x12, 1000 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s new file mode 100644 index 0000000..65c0ca4 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s @@ -0,0 +1,2 @@ +div x3, x20, x21 +divu x4, x22, x23 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/factorial.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/factorial.s new file mode 100644 index 0000000..c69dcb7 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/factorial.s @@ -0,0 +1,27 @@ + addi x10, x0, 10 + jal x1, factorial + j end +factorial: + addi x2, x2, -16 + + sw x1, 12(x2) + sw x10, 8(x2) + + addi x5, x0, 1 + ble x10, x5, base_case + addi x10, x10, -1 + jal x1, factorial + + lw x6, 8(x2) + mul x10, x10, x6 + jal x0, end_factorial + +base_case: + addi x10, x0, 1 + +end_factorial: + lw x1, 12(x2) + addi x2, x2, 16 + jalr x0, 0(x1) +end: + diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s new file mode 100644 index 0000000..436ffaf --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s @@ -0,0 +1,13 @@ + addi x5, x0, 0 # x5 = fib(0) + addi x6, x0, 1 # x6 = fib(1) + addi x7, x0, 15 # x7 = ะบะพะปะธั‡ะตัั‚ะฒะพ ั‡ะธัะตะป + +.loop: + beq x7, x0, .end + + add x28, x5, x6 # x28 = x5 + x6 + addi x5, x6, 0 # x5 = x6 + addi x6, x28, 0 # x6 = x28 + addi x7, x7, -1 + jal x0, .loop +.end: diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s new file mode 100644 index 0000000..2ad737f --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s @@ -0,0 +1,2 @@ +rem x4, x5, x6 +remu x7, x8, x9 From a7411da948aa3f262f143cb084936fa5bb9178ce Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 10:29:32 +0000 Subject: [PATCH 18/75] Clang-format --- test/SimTests/C/CImpl/xorshift32/main.c | 30 ++++--- test/SimTests/C/CImpl/zfunc/main.c | 80 +++++++++---------- .../Target/RISCV/Snippets/fib.s | 2 +- 3 files changed, 55 insertions(+), 57 deletions(-) diff --git a/test/SimTests/C/CImpl/xorshift32/main.c b/test/SimTests/C/CImpl/xorshift32/main.c index bde49fc..d0da34e 100644 --- a/test/SimTests/C/CImpl/xorshift32/main.c +++ b/test/SimTests/C/CImpl/xorshift32/main.c @@ -6,28 +6,26 @@ constexpr uint32_t N = 1024 * 1024; uint32_t buffer[N]; uint32_t xorshift32(uint32_t x) { - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - return x; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; } uint32_t run() { - uint32_t x = seed; + uint32_t x = seed; - for (uint32_t i = 0; i < N; ++i) { - x = xorshift32(x); - buffer[i] = x; - } + for (uint32_t i = 0; i < N; ++i) { + x = xorshift32(x); + buffer[i] = x; + } - uint32_t sum = 0; + uint32_t sum = 0; - for (uint32_t i = 0; i < N; ++i) - sum ^= buffer[i]; + for (uint32_t i = 0; i < N; ++i) + sum ^= buffer[i]; - return sum; + return sum; } -int main() { - return run() == 752068848 ? 0 : 1; -} +int main() { return run() == 752068848 ? 0 : 1; } diff --git a/test/SimTests/C/CImpl/zfunc/main.c b/test/SimTests/C/CImpl/zfunc/main.c index 427462b..d91e382 100644 --- a/test/SimTests/C/CImpl/zfunc/main.c +++ b/test/SimTests/C/CImpl/zfunc/main.c @@ -1,55 +1,55 @@ #define MAXN 1024 -const char* const str = "aBaBCAcabbBAababababcbCBCcbcBABbcbBbabacbBABcb"; +const char *const str = "aBaBCAcabbBAababababcbCBCcbcBABbcbBbabacbBABcb"; -int strlen(const char* str) { - int result = 0; - while (str[result] != '\0') - ++result; - return result; +int strlen(const char *str) { + int result = 0; + while (str[result] != '\0') + ++result; + return result; } void z_function(const char *s, int n, int z[]) { - z[0] = n; - - int l = 0; - int r = 0; - - for (int i = 1; i < n; ++i) { - if (i <= r) { - int k = i - l; - int rem = r - i + 1; - z[i] = (z[k] < rem) ? z[k] : rem; - } else { - z[i] = 0; - } - - while (i + z[i] < n && s[z[i]] == s[i + z[i]]) - ++z[i]; - - if (i + z[i] - 1 > r) { - l = i; - r = i + z[i] - 1; - } + z[0] = n; + + int l = 0; + int r = 0; + + for (int i = 1; i < n; ++i) { + if (i <= r) { + int k = i - l; + int rem = r - i + 1; + z[i] = (z[k] < rem) ? z[k] : rem; + } else { + z[i] = 0; } + + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) + ++z[i]; + + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } } int check_z_function(const char *s, int n, int z[]) { - if (z[0] != n) - return 1; - for (int i = 1; i < n; ++i) { - int expected = 0; - while (i + expected < n && s[expected] == s[i + expected]) - ++expected; - if (z[i] != expected) - return 1; - } - return 0; + if (z[0] != n) + return 1; + for (int i = 1; i < n; ++i) { + int expected = 0; + while (i + expected < n && s[expected] == s[i + expected]) + ++expected; + if (z[i] != expected) + return 1; + } + return 0; } int main() { - int z[MAXN]; + int z[MAXN]; - z_function(str, strlen(str), z); - return check_z_function(str, strlen(str), z); + z_function(str, strlen(str), z); + return check_z_function(str, strlen(str), z); } diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s index 436ffaf..1e2ae25 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/fib.s @@ -1,6 +1,6 @@ addi x5, x0, 0 # x5 = fib(0) addi x6, x0, 1 # x6 = fib(1) - addi x7, x0, 15 # x7 = ะบะพะปะธั‡ะตัั‚ะฒะพ ั‡ะธัะตะป + addi x7, x0, 15 # x7 = n .loop: beq x7, x0, .end From 9b0ace4e4d878e98b4610488956e0fd305e3c27d Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 10:54:22 +0000 Subject: [PATCH 19/75] Add ctests to run by cached-interp sim --- cmake/discover_generated_tests.cmake.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/discover_generated_tests.cmake.in b/cmake/discover_generated_tests.cmake.in index 455d904..5b0b616 100644 --- a/cmake/discover_generated_tests.cmake.in +++ b/cmake/discover_generated_tests.cmake.in @@ -20,4 +20,9 @@ foreach(test_file IN LISTS discovered_tests) "@PROJECT_NAME@.${test_name}" "@GENERATED_SIM_BIN_PATH@" --propagate-exit "${test_file}" ) + + add_test( + "@PROJECT_NAME@.cached-interp.${test_name}" + "@GENERATED_SIM_BIN_PATH@" --jit cached-interp --propagate-exit "${test_file}" + ) endforeach() From 74a31d23a4767ba17fe9b0f9215e8b1e6f35dea0 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 13:46:36 +0000 Subject: [PATCH 20/75] Update --- README.md | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 875e690..96c2592 100644 --- a/README.md +++ b/README.md @@ -5,23 +5,13 @@ Protea (named after Proteus, the Greek sea god known for his ability to change s ProteaIR (Protea Intermediate Representation) doesn't have canonical textual or binary representation. Instead, it is possible to serialize and deserialize it using JSON, YAML, or any other format. -Usage +Building Protea ----- -It is a monorepo managed by [Bundler](https://bundler.io/). To install dependencies, run: - -```bash -bundle install -``` - -So every ruby tool or script can be run using `bundle exec`, for example: - ```bash -bundle exec ruby tools/some_tool.rb +cmake -S . -B build -G [options] ``` - - -Tests ------ - - +Some common options: +1) -DPROTEA_BUILD_TESTS=BOOL - An option to enable tests. Tests can be run using ctests +2) -DTARGET_NAME_TOOLCHAIN_DIR="..." - A path to target's toolchain dir +3) -DQEMU_PATH="..." - A path to qemu executable From 339a8f5b7567594e11d4edf764840d5a56097963 Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 18:33:59 +0000 Subject: [PATCH 21/75] Fix div by zero handling --- lib/Target/RISC-V/32M.rb | 4 ++-- .../SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Target/RISC-V/32M.rb b/lib/Target/RISC-V/32M.rb index 2f22a40..a7f87af 100644 --- a/lib/Target/RISC-V/32M.rb +++ b/lib/Target/RISC-V/32M.rb @@ -33,13 +33,13 @@ module RV32M Instruction(:div) { encoding *format_r(0b0110011, 0b100, 0b0000001) asm { "div {rd}, {rs1}, {rs2}" } - code { rd[]= rs1.s / rs2.s } + code { rd[]= select(rs2 != 0, rs1.s / rs2.s, 0xffffffff) } } Instruction(:divu) { encoding *format_r(0b0110011, 0b101, 0b0000001) asm { "divu {rd}, {rs1}, {rs2}" } - code { rd[]= rs1.u / rs2.u } + code { rd[]= select(rs2 != 0, rs1.u / rs2.u, 0xffffffff) } } Instruction(:rem) { diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s index 65c0ca4..dabfaec 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s @@ -1,2 +1,3 @@ div x3, x20, x21 +li x23, 0 divu x4, x22, x23 From 90a9afc4ac2576e0f9ab1832987e5de75305d74a Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Sat, 9 May 2026 19:17:57 +0000 Subject: [PATCH 22/75] Fix div by zero handling --- code_gen/cpp_gen.rb | 3 ++- lib/Target/RISC-V/32M.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code_gen/cpp_gen.rb b/code_gen/cpp_gen.rb index 388b379..183f1f9 100644 --- a/code_gen/cpp_gen.rb +++ b/code_gen/cpp_gen.rb @@ -136,7 +136,8 @@ def generate_statement(operation) cond = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] true_val = @mapping[operation[:oprnds][2][:name]] || operation[:oprnds][2][:name] false_val = @mapping[operation[:oprnds][3][:name]] || operation[:oprnds][3][:name] - + true_val = true_val.nil? ? operation[:oprnds][2][:value] : true_val + false_val = false_val.nil? ? operation[:oprnds][3][:value] : false_val @emitter.emit_line("#{dst} = #{cond} ? #{true_val} : #{false_val};") end end diff --git a/lib/Target/RISC-V/32M.rb b/lib/Target/RISC-V/32M.rb index a7f87af..dcbc8fa 100644 --- a/lib/Target/RISC-V/32M.rb +++ b/lib/Target/RISC-V/32M.rb @@ -33,13 +33,13 @@ module RV32M Instruction(:div) { encoding *format_r(0b0110011, 0b100, 0b0000001) asm { "div {rd}, {rs1}, {rs2}" } - code { rd[]= select(rs2 != 0, rs1.s / rs2.s, 0xffffffff) } + code { rd[]= select(rs2 != 0, rs1.s / select(rs2 != 0, rs2.s, 1), 0xffffffff) } } Instruction(:divu) { encoding *format_r(0b0110011, 0b101, 0b0000001) asm { "divu {rd}, {rs1}, {rs2}" } - code { rd[]= select(rs2 != 0, rs1.u / rs2.u, 0xffffffff) } + code { rd[]= select(rs2 != 0, rs1.u / select(rs2 != 0, rs2.u, 1), 0xffffffff) } } Instruction(:rem) { From aaace7b4645d46054e96b46052c461c830675ddf Mon Sep 17 00:00:00 2001 From: Shamshura Egor Date: Tue, 12 May 2026 19:00:18 +0000 Subject: [PATCH 23/75] Add more snippet tests --- lib/Target/RISC-V/32I.rb | 2 +- test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt | 2 +- .../Target/RISCV/Snippets/{add-1.s => add.s} | 0 .../Target/RISCV/Snippets/{addi-1.s => addi.s} | 0 .../SnippetBasedImpl/Target/RISCV/Snippets/and.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/andi.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/auipc.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/div.s | 2 -- .../SnippetBasedImpl/Target/RISCV/Snippets/divu.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/lui.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/mul.s | 5 +---- .../SnippetBasedImpl/Target/RISCV/Snippets/mulh.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/mulhsu.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/mulhu.s | 1 + .../SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/or.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/ori.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/rem.s | 1 - .../SnippetBasedImpl/Target/RISCV/Snippets/remu.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/sll.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/slli.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/slt.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/slti.s | 2 ++ .../SnippetBasedImpl/Target/RISCV/Snippets/sltiu.s | 2 ++ .../SnippetBasedImpl/Target/RISCV/Snippets/sltu.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/sra.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/srai.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/srl.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/srli.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/sub.s | 1 + .../SnippetBasedImpl/Target/RISCV/Snippets/xor.s | 2 ++ .../SnippetBasedImpl/Target/RISCV/Snippets/xori.s | 1 + 31 files changed, 30 insertions(+), 9 deletions(-) rename test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/{add-1.s => add.s} (100%) rename test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/{addi-1.s => addi.s} (100%) create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/and.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/andi.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/auipc.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/divu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/lui.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulh.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhsu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/or.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/ori.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/remu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sll.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slli.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slt.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slti.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltiu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltu.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sra.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srai.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srl.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srli.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sub.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xor.s create mode 100644 test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xori.s diff --git a/lib/Target/RISC-V/32I.rb b/lib/Target/RISC-V/32I.rb index 1b42331..8782a77 100644 --- a/lib/Target/RISC-V/32I.rb +++ b/lib/Target/RISC-V/32I.rb @@ -127,7 +127,7 @@ module RV32I Instruction(:slti) { encoding *format_i(0b0010011, 0b010) asm { "slti {rd}, {rs1}, {imm}" } - code { rd[]= (rs1.s < imm).b32 } + code { rd[]= (rs1.s < imm.s).b32 } } Instruction(:sltiu) { diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt b/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt index 6a99b5f..432ba5e 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/CMakeLists.txt @@ -10,7 +10,7 @@ set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/tests") add_custom_target(init-tests ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${INIT_DIR}" - COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/InitTestGen.rb + COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/InitTestGen.rb -n 20 ${IR_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/Target/${TARGET_NAME}/Snippets ${INIT_DIR} COMMENT "Generating test .s files" ) diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add.s similarity index 100% rename from test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add-1.s rename to test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/add.s diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi.s similarity index 100% rename from test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi-1.s rename to test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/addi.s diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/and.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/and.s new file mode 100644 index 0000000..f3301a1 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/and.s @@ -0,0 +1 @@ +and x20, x29, x23 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/andi.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/andi.s new file mode 100644 index 0000000..b6f6a95 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/andi.s @@ -0,0 +1 @@ +andi x9, x8, -19 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/auipc.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/auipc.s new file mode 100644 index 0000000..27d8080 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/auipc.s @@ -0,0 +1 @@ +auipc x17, 20 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s index dabfaec..012b396 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/div.s @@ -1,3 +1 @@ div x3, x20, x21 -li x23, 0 -divu x4, x22, x23 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/divu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/divu.s new file mode 100644 index 0000000..d4df7b2 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/divu.s @@ -0,0 +1 @@ +divu x16, x14, x12 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/lui.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/lui.s new file mode 100644 index 0000000..c738390 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/lui.s @@ -0,0 +1 @@ +lui x10, 5 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s index 9fcc6c1..757fa79 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mul.s @@ -1,4 +1 @@ -mul a2, a0, a1 -mulh a3, a0, a1 -mulhsu a4, a0, a1 -mulhu a5, a0, a1 +mul x8, x9, x10 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulh.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulh.s new file mode 100644 index 0000000..e2166ab --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulh.s @@ -0,0 +1 @@ +mulh x23, x24, x25 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhsu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhsu.s new file mode 100644 index 0000000..2d5498b --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhsu.s @@ -0,0 +1 @@ +mulhsu x23, x13, x29 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhu.s new file mode 100644 index 0000000..5d58fe4 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/mulhu.s @@ -0,0 +1 @@ +mulhu x29, x27, x25 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/or.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/or.s new file mode 100644 index 0000000..2d17681 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/or.s @@ -0,0 +1 @@ +or x1, x3, x7 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/ori.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/ori.s new file mode 100644 index 0000000..e59d798 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/ori.s @@ -0,0 +1 @@ +ori x19, x9, -1 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s index 2ad737f..5269b50 100644 --- a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/rem.s @@ -1,2 +1 @@ rem x4, x5, x6 -remu x7, x8, x9 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/remu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/remu.s new file mode 100644 index 0000000..429a7bd --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/remu.s @@ -0,0 +1 @@ +remu x17, x11, x13 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sll.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sll.s new file mode 100644 index 0000000..a09c353 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sll.s @@ -0,0 +1 @@ +sll x9, x8, x7 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slli.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slli.s new file mode 100644 index 0000000..2e5312f --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slli.s @@ -0,0 +1 @@ +slli x6, x7, 20 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slt.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slt.s new file mode 100644 index 0000000..86ef33c --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slt.s @@ -0,0 +1 @@ +slt x19, x23, x28 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slti.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slti.s new file mode 100644 index 0000000..0c05626 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/slti.s @@ -0,0 +1,2 @@ +slti x3, x3, 20 +slti x4, x6, 8 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltiu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltiu.s new file mode 100644 index 0000000..454a5e0 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltiu.s @@ -0,0 +1,2 @@ +sltiu x3, x3, 200 +sltiu x4, x6, 80 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltu.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltu.s new file mode 100644 index 0000000..388a3bd --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sltu.s @@ -0,0 +1 @@ +sltu x19, x23, x28 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sra.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sra.s new file mode 100644 index 0000000..6ec24f7 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sra.s @@ -0,0 +1 @@ +sra x24, x22, x26 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srai.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srai.s new file mode 100644 index 0000000..e04db3d --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srai.s @@ -0,0 +1 @@ +srai x7, x7, 20 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srl.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srl.s new file mode 100644 index 0000000..4f38219 --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srl.s @@ -0,0 +1 @@ +srl x30, x29, x28 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srli.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srli.s new file mode 100644 index 0000000..95bea0b --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/srli.s @@ -0,0 +1 @@ +srli x11, x5, 2 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sub.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sub.s new file mode 100644 index 0000000..32113ba --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/sub.s @@ -0,0 +1 @@ +sub x7, x7, x20 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xor.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xor.s new file mode 100644 index 0000000..b13d11e --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xor.s @@ -0,0 +1,2 @@ +xor x10, x6, x5 +xor x12, x4, x15 diff --git a/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xori.s b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xori.s new file mode 100644 index 0000000..15fdebd --- /dev/null +++ b/test/SimTests/SnippetBased/SnippetBasedImpl/Target/RISCV/Snippets/xori.s @@ -0,0 +1 @@ +xori x5, x5, -1 From c3b5a35dcf35a6ebf62a4c1bce5f29e71e76c165 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sun, 7 Jun 2026 18:38:13 +0300 Subject: [PATCH 24/75] [lib] Memory ifaces dynamic registry supported * Memory interfaces registration was supported * Minor formatting --- lib/ADL/base.rb | 27 ++++++++++++++++++--- lib/ADL/builder.rb | 60 +++++++++++++++++++++++----------------------- lib/ADL/scope.rb | 15 ++++++++++-- 3 files changed, 67 insertions(+), 35 deletions(-) diff --git a/lib/ADL/base.rb b/lib/ADL/base.rb index 4eb5910..baa65aa 100644 --- a/lib/ADL/base.rb +++ b/lib/ADL/base.rb @@ -4,12 +4,33 @@ module SimInfra # @@instructions -array of instruction description # shows result of our tests in interactive Ruby (IRB) or standalone + @@regfiles = [] unless defined?(@@regfiles) + @@interface_functions = [] unless defined?(@@interface_functions) + @@instructions = [] unless defined?(@@instructions) + + def self.register_memory_interface(name, return_types, argument_types) + # check whether the interface has already been registered before + exists = @@interface_functions.any? do |f| + f[:name] == name && + f[:return_types] == return_types && + f[:argument_types] == argument_types + end + unless exists + @@interface_functions << { + name: name, + return_types: return_types, + argument_types: argument_types, + kind: :memory + } + end + end + def self.serialize(msg= nil) require 'yaml' yaml_data = YAML.dump( { regfiles: @@regfiles.map(&:to_h), - interface_functions: @@interface_functions.map(&:to_h), + interface_functions: @@interface_functions.map { |f| f.reject { |k| k == :kind } }, instructions: @@instructions.map(&:to_h), } ) @@ -17,10 +38,10 @@ def self.serialize(msg= nil) end def self.state - yaml_data = YAML.dump( + YAML.dump( { regfiles: @@regfiles.map(&:to_h), - interface_functions: @@interface_functions.map(&:to_h), + interface_functions: @@interface_functions.map { |f| f.reject { |k| k == :kind } }, instructions: @@instructions.map(&:to_h), } ) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index 9c31471..e15ec5d 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -29,7 +29,7 @@ def self.from_h(h) end # Basics -module SimInfra +module SimInfra def assert(condition, msg = nil); raise msg if !condition; end @@instructions = [] @@ -75,15 +75,16 @@ def self.from_h(h) class InstructionInfoBuilder include SimInfra - def initialize(name, feature) - @info = InstructionInfo.new(name, feature) - @info.code = Scope.new(nil) + def initialize(name, feature) + @info = InstructionInfo.new(name, feature) + @info.code = Scope.new(nil) @@interface_functions.each do |func| + next if func[:kind] == :memory if !func[:return_types].empty? @info.code.instance_eval "def #{func[:name]}(*args) in_s = *args.map { |a| resolve_const(a) } - in_stmt = [tmpvar(#{func[:return_types][0]})] + in_stmt = [tmpvar(#{func[:return_types][0]})] in_stmt.concat(in_s) return stmt :#{func[:name]}, in_stmt end @@ -101,10 +102,10 @@ def initialize(name, feature) end def encoding(frmt, fields, *args) - @info.fields = fields - @info.frmt= frmt - map args - + @info.fields = fields + @info.frmt= frmt + map args + sum_bits = 0 for f in fields sum_bits += Utility.get_type(f.value.type).bitsize @@ -132,7 +133,6 @@ def Function(name, output_types = [], input_types = []) def Interface(&blck) bldr = InterfaceBuilder.new() - bldr.instance_eval &blck end @@ -176,27 +176,27 @@ def self.from_h(h) end @@regfiles = [] -class RegisterFileBuilder - attr_reader :info - - def initialize(name) - @info = RegisterFileInfo.new(name) - @info.regs = [] - end - - def method_missing(name, *args) - if name.to_s.start_with?('r') - size = name.to_s[1..].to_i - instance_eval "def #{name}(sym, *args); @info.regs << Register.new(sym, #{size}, args.size > 0 ? args : []); end", __FILE__, __LINE__ - @info.regs << Register.new(args[0], size, args.size > 1 ? args[1..] : []) - else - error "Unknown method #{name}" + class RegisterFileBuilder + attr_reader :info + + def initialize(name) + @info = RegisterFileInfo.new(name) + @info.regs = [] + end + + def method_missing(name, *args) + if name.to_s.start_with?('r') + size = name.to_s[1..].to_i + instance_eval "def #{name}(sym, *args); @info.regs << Register.new(sym, #{size}, args.size > 0 ? args : []); end", __FILE__, __LINE__ + @info.regs << Register.new(args[0], size, args.size > 1 ? args[1..] : []) + else + error "Unknown method #{name}" + end + end + + def zero = :zero + def pc = :pc end - end - - def zero = :zero - def pc = :pc -end def RegisterFile(name, &block) bldr = RegisterFileBuilder.new(name) diff --git a/lib/ADL/scope.rb b/lib/ADL/scope.rb index 2175a7e..bfa1a99 100644 --- a/lib/ADL/scope.rb +++ b/lib/ADL/scope.rb @@ -106,8 +106,19 @@ def zext(a, type) = stmt(:zext, [tmpvar(type), a]) def get_reg(expr, regset, type) = rlet("_reg_#{next_counter}".to_sym, regset, type, expr) def write(rfile, reg, expr) = stmt(:write, [rfile, reg, expr]) - def writeMem(addr, expr) = stmt(:writeMem, [addr, expr]) - def readMem(addr, type) = stmt(:readMem, [tmpvar(type), addr]) + + def writeMem(addr, expr) + arg_types = [addr.type, expr.type].map { |t| t.is_a?(Symbol) ? t : t.type } + SimInfra.register_memory_interface(:writeMem, [], arg_types) + stmt(:writeMem, [addr, expr]) + end + + def readMem(addr, type) + arg_types = [addr.type] + SimInfra.register_memory_interface(:readMem, [type], arg_types) + v = tmpvar(type) + stmt(:readMem, [v, addr]) + end def read(rfile, reg) v = tmpvar(:b32) From d0c9e2f370f214ffabb8b22b2e54f7332629feb6 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 8 Jun 2026 17:04:05 +0300 Subject: [PATCH 25/75] [lib] Introduced LIRA Ruby Lib * LIRA Ruby library was added temporary into Protea until release in baseline repository --- lib/lira/arch.rb | 430 +++++++++++++++++++++++++++++++ lib/lira/arch_ser.rb | 7 + lib/lira/arch_ser_txt.rb | 155 +++++++++++ lib/lira/arch_ser_yaml.rb | 58 +++++ lib/lira/arch_utils.rb | 18 ++ lib/lira/ir.rb | 147 +++++++++++ lib/lira/ir_builder.rb | 529 ++++++++++++++++++++++++++++++++++++++ lib/lira/ir_ops.rb | 221 ++++++++++++++++ lib/lira/ir_ser_txt.rb | 39 +++ lib/lira/ir_std.rb | 94 +++++++ 10 files changed, 1698 insertions(+) create mode 100644 lib/lira/arch.rb create mode 100644 lib/lira/arch_ser.rb create mode 100644 lib/lira/arch_ser_txt.rb create mode 100644 lib/lira/arch_ser_yaml.rb create mode 100644 lib/lira/arch_utils.rb create mode 100644 lib/lira/ir.rb create mode 100644 lib/lira/ir_builder.rb create mode 100644 lib/lira/ir_ops.rb create mode 100644 lib/lira/ir_ser_txt.rb create mode 100644 lib/lira/ir_std.rb diff --git a/lib/lira/arch.rb b/lib/lira/arch.rb new file mode 100644 index 0000000..aa22577 --- /dev/null +++ b/lib/lira/arch.rb @@ -0,0 +1,430 @@ +# lira/arch.rb +require 'set' + +module Lira + class Component + attr_accessor :name, :attributes + + def initialize(name, attributes = []) + @name = name + @attributes = attributes + end + + def to_h + { name: name, attributes: attributes } + end + + def self.from_h(hash) + new(hash[:name] || hash['name'], hash[:attributes] || hash['attributes'] || []) + end + + def ==(other) + other.is_a?(Component) && name == other.name && attributes == other.attributes + end + end + + class Snippet + attr_accessor :name, :seq + + def initialize(name, seq) + @name = name + @seq = seq + end + + def to_h + { name: name, seq: seq } + end + + def self.from_h(hash) + seq = StatementSeq.from_h(hash[:seq] || hash['seq']) + new(hash[:name] || hash['name'], seq) + end + + def ==(other) + other.is_a?(Snippet) && name == other.name && seq == other.seq + end + end + + class Operation < Component + attr_accessor :inputs, :outputs, :semantic_base, :semantic_func, :semantic_func_128, :semantic_table + + def initialize(name, attributes, inputs, outputs, + semantic_base: nil, semantic_func: nil, semantic_func_128: nil, semantic_table: nil) + super(name, attributes) + @inputs = inputs + @outputs = outputs + @semantic_base = semantic_base + @semantic_func = semantic_func + @semantic_func_128 = semantic_func_128 + @semantic_table = semantic_table + end + + def to_h + super.merge( + inputs: inputs, + outputs: outputs, + semantic_base: semantic_base, + semantic_func: semantic_func, + semantic_func_128: semantic_func_128, + semantic_table: semantic_table + ) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + inputs = hash[:inputs] || hash['inputs'] + outputs = hash[:outputs] || hash['outputs'] + + semantic_base = hash[:semantic_base] || hash['semantic_base'] + semantic_base = nil if semantic_base == {} + semantic_func = hash[:semantic_func] || hash['semantic_func'] + semantic_func_128 = hash[:semantic_func_128] || hash['semantic_func_128'] + semantic_func_128 = nil if semantic_func_128 == {} + semantic_table = hash[:semantic_table] || hash['semantic_table'] + semantic_table = nil if semantic_table == {} + + new(name, attributes, inputs, outputs, + semantic_base: semantic_base, + semantic_func: semantic_func, + semantic_func_128: semantic_func_128, + semantic_table: semantic_table) + end + + def ==(other) + super(other) && + other.is_a?(Operation) && + inputs == other.inputs && + outputs == other.outputs && + semantic_base == other.semantic_base && + semantic_func == other.semantic_func && + semantic_func_128 == other.semantic_func_128 && + semantic_table == other.semantic_table + end + end + + class Register < Component + def initialize(name, attributes = []) + super(name, attributes) + end + + def to_h + super.merge() + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + new(name, attributes) + end + + def ==(other) + super(other) && other.is_a?(Register) + end + end + + class RegisterFile < Component + attr_accessor :reg_size, :regs + + def initialize(name, attributes, reg_size, regs) + super(name, attributes) + @reg_size = reg_size + @regs = regs + end + + def reg_names + @regs.map(&:name) + end + + def regs_num + @regs.length + end + + def to_h + super.merge(reg_size: reg_size.to_h, regs: regs.map(&:to_h)) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + reg_size = Shape.from_h(hash[:reg_size] || hash['reg_size']) + regs_data = hash[:regs] || hash['regs'] || [] + regs = regs_data.map { |r| Register.from_h(r) } + new(name, attributes, reg_size, regs) + end + + def ==(other) + super(other) && + other.is_a?(RegisterFile) && + reg_size == other.reg_size && + regs == other.regs + end + end + + + class EnvironmentFunction < Component + attr_accessor :inputs, :outputs + + def initialize(name, attributes, inputs, outputs) + super(name, attributes) + @inputs = inputs + @outputs = outputs + end + + def to_h + super.merge(inputs: inputs, outputs: outputs) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + inputs = hash[:inputs] || hash['inputs'] + outputs = hash[:outputs] || hash['outputs'] + new(name, attributes, inputs, outputs) + end + + def ==(other) + super(other) && + other.is_a?(EnvironmentFunction) && + inputs == other.inputs && + outputs == other.outputs + end + end + + class SystemRegisterField < Component + attr_accessor :lsb, :msb + + def initialize(name, attributes, lsb, msb) + super(name, attributes) + @lsb = lsb + @msb = msb + end + + def to_h + super.merge(lsb: lsb, msb: msb) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + lsb = hash[:lsb] || hash['lsb'] + msb = hash[:msb] || hash['msb'] + new(name, attributes, lsb, msb) + end + + def ==(other) + super(other) && + other.is_a?(SystemRegisterField) && + lsb == other.lsb && + msb == other.msb + end + end + + class SystemRegister < Component + attr_accessor :size, :fields + + def initialize(name, attributes, size, fields) + super(name, attributes) + @size = size + @fields = fields + end + + def to_h + super.merge(size: size, fields: fields.map(&:to_h)) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + size = hash[:size] || hash['size'] + fields_data = hash[:fields] || hash['fields'] + fields = fields_data.map { |f| SystemRegisterField.from_h(f) } + new(name, attributes, size, fields) + end + + def ==(other) + super(other) && + other.is_a?(SystemRegister) && + size == other.size && + fields == other.fields + end + end + + class TableInt < Component + attr_accessor :values + + def initialize(name, attributes, values) + super(name, attributes) + @values = values + end + + def to_h + super.merge(values: values) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + values = hash[:values] || hash['values'] + new(name, attributes, values) + end + + def ==(other) + super(other) && + other.is_a?(TableInt) && + values == other.values + end + end + + class InstructionEncoding + attr_accessor :encoded_size, :const_encoding_part, :decode, :encode, + :constraint_decode, :constraint_encode + + def initialize(encoded_size, const_encoding_part, decode, encode, constraint_decode, constraint_encode) + @encoded_size = encoded_size + @const_encoding_part = const_encoding_part + @decode = decode + @encode = encode + @constraint_decode = constraint_decode + @constraint_encode = constraint_encode + end + + def to_h + { + encoded_size: encoded_size, + const_encoding_part: const_encoding_part, + decode: decode, + encode: encode, + constraint_decode: constraint_decode, + constraint_encode: constraint_encode + } + end + + def self.from_h(hash) + new(hash[:encoded_size] || hash['encoded_size'], + hash[:const_encoding_part] || hash['const_encoding_part'], + hash[:decode] || hash['decode'], + hash[:encode] || hash['encode'], + hash[:constraint_decode] || hash['constraint_decode'], + hash[:constraint_encode] || hash['constraint_encode']) + end + + def ==(other) + other.is_a?(InstructionEncoding) && + encoded_size == other.encoded_size && + const_encoding_part == other.const_encoding_part && + decode == other.decode && + encode == other.encode && + constraint_decode == other.constraint_decode && + constraint_encode == other.constraint_encode + end + end + + class Instruction < Component + attr_accessor :operand_sizes, :operand_names, :encoding, :semantic + + def initialize(name, attributes, operand_sizes, operand_names, encoding, semantic) + super(name, attributes) + @operand_sizes = operand_sizes + @operand_names = operand_names + @encoding = encoding + @semantic = semantic + end + + def to_h + super.merge( + operand_sizes: operand_sizes, + operand_names: operand_names, + encoding: encoding.to_h, + semantic: semantic + ) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + operand_sizes = hash[:operand_sizes] || hash['operand_sizes'] + operand_names = hash[:operand_names] || hash['operand_names'] + encoding = InstructionEncoding.from_h(hash[:encoding] || hash['encoding']) + semantic = StatementSeq.from_h(hash[:semantic] || hash['semantic']) + new(name, attributes, operand_sizes, operand_names, encoding, semantic) + end + + def ==(other) + super(other) && + other.is_a?(Instruction) && + operand_sizes == other.operand_sizes && + operand_names == other.operand_names && + encoding == other.encoding && + semantic == other.semantic + end + end + + class Arch < Component + attr_accessor :register_files, :system_registers, :environment_functions, + :tables_int, :operations, :snippets, :instructions + + def initialize(name, attributes, + register_files: [], + system_registers: [], + environment_functions: [], + tables_int: [], + operations: [], + snippets: [], + instructions: []) + super(name, attributes) + @register_files = register_files + @system_registers = system_registers + @environment_functions = environment_functions + @tables_int = tables_int + @operations = operations + @snippets = snippets + @instructions = instructions + end + + + def to_h + super.merge( + register_files: register_files.map(&:to_h), + system_registers: system_registers.map(&:to_h), + environment_functions: environment_functions.map(&:to_h), + tables_int: tables_int.map(&:to_h), + operations: operations.map(&:to_h), + snippets: snippets.map(&:to_h), + instructions: instructions.map(&:to_h) + ) + end + + def self.from_h(hash) + name = hash[:name] || hash['name'] + attributes = hash[:attributes] || hash['attributes'] || [] + register_files = (hash[:register_files] || hash['register_files']).map { |rf| RegisterFile.from_h(rf) } + system_registers = (hash[:system_registers] || hash['system_registers']).map { |sr| SystemRegister.from_h(sr) } + environment_functions = (hash[:environment_functions] || hash['environment_functions']).map { |ef| EnvironmentFunction.from_h(ef) } + tables_int = (hash[:tables_int] || hash['tables_int']).map { |ti| TableInt.from_h(ti) } + operations = (hash[:operations] || hash['operations']).map { |op| Operation.from_h(op) } + snippets = (hash[:snippets] || hash['snippets']).map { |sn| Snippet.from_h(sn) } + instructions = (hash[:instructions] || hash['instructions']).map { |ins| Instruction.from_h(ins) } + new(name, attributes, + register_files: register_files, + system_registers: system_registers, + environment_functions: environment_functions, + tables_int: tables_int, + operations: operations, + snippets: snippets, + instructions: instructions) + end + + def ==(other) + super(other) && + other.is_a?(Arch) && + register_files == other.register_files && + system_registers == other.system_registers && + environment_functions == other.environment_functions && + tables_int == other.tables_int && + operations == other.operations && + snippets == other.snippets && + instructions == other.instructions + end + end +end diff --git a/lib/lira/arch_ser.rb b/lib/lira/arch_ser.rb new file mode 100644 index 0000000..5055630 --- /dev/null +++ b/lib/lira/arch_ser.rb @@ -0,0 +1,7 @@ +# lira/arch_ser.rb +module Lira + module SerializationFormat + TXT = :txt + YAML = :yaml + end +end diff --git a/lib/lira/arch_ser_txt.rb b/lib/lira/arch_ser_txt.rb new file mode 100644 index 0000000..302302d --- /dev/null +++ b/lib/lira/arch_ser_txt.rb @@ -0,0 +1,155 @@ +# lira/arch_ser_txt.rb +require 'json' +require 'pathname' +require 'fileutils' +require_relative 'ir' +require_relative 'arch' + +module Lira + module ArchSerTxt + module_function + + def to_serializable(obj) + case obj + when StatementSeq + IrSerTxt.serialize_statement_seq(obj) + when Array + obj.map { |item| to_serializable(item) } + when Hash + obj.transform_values { |v| to_serializable(v) } + else + if obj.respond_to?(:to_h) + obj.to_h.transform_values { |v| to_serializable(v) } + else + obj + end + end + end + + def from_serializable(klass, data, item_class = nil) + if klass == Array + if item_class + return data.map { |elem| from_serializable(item_class, elem) } + else + return data.map { |elem| from_serializable(Object, elem) } + end + end + + if klass.respond_to?(:from_h) + # ะ ะตะบัƒั€ัะธะฒะฝะพ ะฟั€ะตะพะฑั€ะฐะทัƒะตะผ ะฒัะต ะทะฝะฐั‡ะตะฝะธั ั…ะตัˆะฐ + transformed = data.transform_values { |v| from_serializable(Object, v) } + klass.from_h(transformed) + else + data + end + end + + # ะ’ัะฟะพะผะพะณะฐั‚ะตะปัŒะฝั‹ะต ะผะตั‚ะพะดั‹ ะดะปั ั€ะฐะฑะพั‚ั‹ ั JSON + def write_json(data, path) + File.write(path, JSON.pretty_generate(data)) + end + + def write_component_list(list, path) + write_json(list.map { |obj| to_serializable(obj) }, path) + end + + def write_arch(arch, folder_path) + folder_path = Pathname.new(folder_path) + FileUtils.rm_rf(folder_path) if folder_path.exist? + FileUtils.mkdir_p(folder_path) + + write_json({ 'name' => arch.name, 'attributes' => arch.attributes }, folder_path / 'arch.json') + + write_component_list(arch.register_files, folder_path / 'register_files.json') + write_component_list(arch.system_registers, folder_path / 'system_registers.json') + write_component_list(arch.environment_functions, folder_path / 'environment_functions.json') + write_component_list(arch.tables_int, folder_path / 'tables_int.json') + + index = { + 'operations' => arch.operations.map(&:name), + 'snippets' => arch.snippets.map(&:name), + 'instructions' => arch.instructions.map(&:name) + } + write_json(index, folder_path / 'index.json') + + ops_dir = folder_path / 'operations' + FileUtils.mkdir_p(ops_dir) + arch.operations.each do |op| + write_json(to_serializable(op), ops_dir / "#{op.name}.json") + end + + snippets_dir = folder_path / 'snippets' + FileUtils.mkdir_p(snippets_dir) + arch.snippets.each do |snip| + File.write(snippets_dir / "#{snip.name}.lira", IrSerTxt.serialize_statement_seq(snip.seq)) + end + + instr_dir = folder_path / 'instructions' + FileUtils.mkdir_p(instr_dir) + arch.instructions.each do |instr| + instr_dict = to_serializable(instr) + instr_dict.delete('semantic') + write_json(instr_dict, instr_dir / "#{instr.name}.json") + File.write(instr_dir / "#{instr.name}.lira", IrSerTxt.serialize_statement_seq(instr.semantic)) + end + end + + def load_json(path) + JSON.parse(File.read(path)) + end + + def load_lira(path) + IrSerTxt.deserialize_statement_seq(File.read(path)) + end + + def load_operation(folder, name) + data = load_json(folder / 'operations' / "#{name}.json") + from_serializable(Operation, data) + end + + def load_snippet(folder, name) + seq = load_lira(folder / 'snippets' / "#{name}.lira") + Snippet.new(name, seq) + end + + def load_instruction(folder, name) + data = load_json(folder / 'instructions' / "#{name}.json") + semantic = load_lira(folder / 'instructions' / "#{name}.lira") + from_serializable(Instruction, data.merge('semantic' => semantic.to_h)) + end + + def read_arch(folder_path) + folder_path = Pathname.new(folder_path) + + arch_info = load_json(folder_path / 'arch.json') + name = arch_info['name'] + attributes = arch_info['attributes'] + + register_files = from_serializable(Array, load_json(folder_path / 'register_files.json'), RegisterFile) + system_registers = from_serializable(Array, load_json(folder_path / 'system_registers.json'), SystemRegister) + environment_functions = from_serializable(Array, load_json(folder_path / 'environment_functions.json'), EnvironmentFunction) + tables_int = from_serializable(Array, load_json(folder_path / 'tables_int.json'), TableInt) + + index = load_json(folder_path / 'index.json') + op_names = index['operations'] + snippet_names = index['snippets'] + instr_names = index['instructions'] + + operations = op_names.map { |n| load_operation(folder_path, n) } + snippets = snippet_names.map { |n| load_snippet(folder_path, n) } + instructions = instr_names.map { |n| load_instruction(folder_path, n) } + + Arch.new( + name, + attributes, + register_files: register_files, + system_registers: system_registers, + environment_functions: environment_functions, + tables_int: tables_int, + operations: operations, + snippets: snippets, + instructions: instructions + ) + end + end +end diff --git a/lib/lira/arch_ser_yaml.rb b/lib/lira/arch_ser_yaml.rb new file mode 100644 index 0000000..7b35841 --- /dev/null +++ b/lib/lira/arch_ser_yaml.rb @@ -0,0 +1,58 @@ +# lira/arch_ser_yaml.rb +require 'yaml' +require_relative 'ir' +require_relative 'arch' + +module Lira + module ArchSerYaml + module_function + + def to_serializable(obj) + case obj + when StatementSeq + IrSerTxt.serialize_statement_seq(obj) + when Array + obj.map { |item| to_serializable(item) } + when Hash + obj.transform_values { |v| to_serializable(v) } + else + if obj.respond_to?(:to_h) + obj.to_h.transform_values { |v| to_serializable(v) } + else + obj + end + end + end + + def from_serializable(klass, data, item_class = nil) + if klass == Array + if item_class + return data.map { |elem| from_serializable(item_class, elem) } + else + return data.map { |elem| from_serializable(Object, elem) } + end + end + + if klass == StatementSeq + return IrSerTxt.deserialize_statement_seq(data) + end + + if klass.respond_to?(:from_h) + transformed = data.transform_values { |v| from_serializable(Object, v) } + klass.from_h(transformed) + else + data + end + end + + def write_arch(arch, filepath) + data = to_serializable(arch) + File.write(filepath, YAML.dump(data)) + end + + def read_arch(filepath) + data = YAML.load_file(filepath) + from_serializable(Arch, data) + end + end +end diff --git a/lib/lira/arch_utils.rb b/lib/lira/arch_utils.rb new file mode 100644 index 0000000..3484a42 --- /dev/null +++ b/lib/lira/arch_utils.rb @@ -0,0 +1,18 @@ +# lira/arch_utils.rb +require_relative 'arch' + +module Lira + ArchIndex = Struct.new(:rf, :sr, :env, :tables, :op, :snippet, :instr) + + def self.build_arch_index(arch) + ArchIndex.new( + arch.register_files.to_h { |rf| [rf.name, rf] }, + arch.system_registers.to_h { |sr| [sr.name, sr] }, + arch.environment_functions.to_h { |ef| [ef.name, ef] }, + arch.tables_int.to_h { |ti| [ti.name, ti] }, + arch.operations.to_h { |op| [op.name, op] }, + arch.snippets.to_h { |sn| [sn.name, sn] }, + arch.instructions.to_h { |ins| [ins.name, ins] } + ) + end +end diff --git a/lib/lira/ir.rb b/lib/lira/ir.rb new file mode 100644 index 0000000..5d83533 --- /dev/null +++ b/lib/lira/ir.rb @@ -0,0 +1,147 @@ +# lira/ir.rb +require 'set' + +module Lira + class Shape + attr_accessor :lanes_base, :lanes_mult + + def initialize(lanes_base, lanes_mult) + @lanes_base = lanes_base + @lanes_mult = lanes_mult + end + + def to_h + { lanes_base: lanes_base, lanes_mult: lanes_mult } + end + + def self.from_h(hash) + lanes_base = hash[:lanes_base] || hash['lanes_base'] + lanes_mult = hash[:lanes_mult] || hash['lanes_mult'] + lanes_mult = nil if lanes_mult == {} + new(lanes_base, lanes_mult) + end + + def ==(other) + other.is_a?(Shape) && lanes_base == other.lanes_base && lanes_mult == other.lanes_mult + end + end + + class Statement + attr_accessor :shape, :outputs, :outputs_types, :kind, :specifier, :inputs + + def initialize(shape, outputs, outputs_types, kind, specifier, inputs) + @shape = shape + @outputs = outputs + @outputs_types = outputs_types + @kind = kind + @specifier = specifier + @inputs = inputs + end + + def to_h + { + shape: shape.to_h, + outputs: outputs, + outputs_types: outputs_types, + kind: kind, + specifier: specifier, + inputs: inputs + } + end + + def self.from_h(hash) + shape = Shape.from_h(hash[:shape] || hash['shape']) + new(shape, + hash[:outputs] || hash['outputs'], + hash[:outputs_types] || hash['outputs_types'], + hash[:kind] || hash['kind'], + hash[:specifier] || hash['specifier'], + hash[:inputs] || hash['inputs']) + end + + def ==(other) + other.is_a?(Statement) && + shape == other.shape && + outputs == other.outputs && + outputs_types == other.outputs_types && + kind == other.kind && + specifier == other.specifier && + inputs == other.inputs + end + + def input(id, seq) + target = @inputs[id] + seq.stmts.each do |stmt| + return stmt if stmt.outputs.include?(target) + end + raise "input #{target} not found" + end + end + + class StatementSeq + attr_accessor :stmts + + def initialize(stmts) + @stmts = stmts + end + + def to_h + { stmts: stmts.map(&:to_h) } + end + + def self.from_h(data) + if data.is_a?(String) + IrSerTxt.deserialize_statement_seq(data) + else + stmts_data = data[:stmts] || data['stmts'] + stmts = stmts_data.map { |stmt_h| Statement.from_h(stmt_h) } + new(stmts) + end + end + + def ==(other) + other.is_a?(StatementSeq) && stmts == other.stmts + end + end + + module IrSerTxt + def self.serialize_shape(shape) + "#{shape.lanes_base}#{shape.lanes_mult || ''}" + end + + def self.deserialize_shape(s) + m = s.match(/\A(\d+)(.*)\z/) + raise "invalid shape: #{s}" unless m + Shape.new(m[1].to_i, m[2].empty? ? nil : m[2]) + end + + def self.serialize_statement(stmt) + shape_str = serialize_shape(stmt.shape) + out_parts = stmt.outputs_types.zip(stmt.outputs).flat_map { |typ, name| [typ.to_s, name] } + parts = [shape_str] + out_parts + ['=', stmt.kind, stmt.specifier] + stmt.inputs + parts.join(' ') + end + + def self.deserialize_statement(s) + m = s.match(/\A(\w+)\s+(.*?)\s*=\s*(\w+)\s+(\S+)\s*(.*)\z/) + raise "invalid statement: #{s}" unless m + shape_str, outputs_str, kind, specifier, inputs_str = m.captures + shape = deserialize_shape(shape_str) + pairs = outputs_str.split + outputs_types = (0...pairs.length).step(2).map { |i| pairs[i].to_i } + outputs = (0...pairs.length).step(2).map { |i| pairs[i+1] } + inputs = inputs_str.empty? ? [] : inputs_str.split + Statement.new(shape, outputs, outputs_types, kind, specifier, inputs) + end + + def self.serialize_statement_seq(seq) + seq.stmts.map { |s| serialize_statement(s) + ";\n" }.join + end + + def self.deserialize_statement_seq(s) + raw_stmts = s.split(';').map(&:strip).reject(&:empty?) + stmts = raw_stmts.map { |raw| deserialize_statement(raw) } + StatementSeq.new(stmts) + end + end +end diff --git a/lib/lira/ir_builder.rb b/lib/lira/ir_builder.rb new file mode 100644 index 0000000..e61a777 --- /dev/null +++ b/lib/lira/ir_builder.rb @@ -0,0 +1,529 @@ +# lira/ir_builder.rb +require_relative 'ir' +require_relative 'arch' +require_relative 'ir_ops' + +module Lira + class Value + attr_accessor :name, :width + + def initialize(name, width = 32) + @name = name + @width = width + end + + def to_s + name + end + + def inspect + "Value(#{name}, #{width})" + end + + def ==(other) + other.is_a?(Value) && name == other.name && width == other.width + end + end + + class SeqBuilder + attr_reader :stmts, :temp_counter, :op_cache + + def initialize + @stmts = [] + @temp_counter = 0 + @op_cache = {} + end + + def new_temp(width = 32) + @temp_counter += 1 + Value.new("_t#{@temp_counter}", width) + end + + def get_or_create_op(op_class, *args) + key = [op_class, args] + @op_cache[key] ||= op_class.new(*args) + end + + def add(a, b) + check_width_match(a, b) + op = get_or_create_op(Add, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def sub(a, b) + check_width_match(a, b) + op = get_or_create_op(Sub, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def mul(a, b) + check_width_match(a, b) + op = get_or_create_op(Mul, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def and_(a, b) + check_width_match(a, b) + op = get_or_create_op(And, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def orr(a, b) + check_width_match(a, b) + op = get_or_create_op(Orr, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def xor(a, b) + check_width_match(a, b) + op = get_or_create_op(Xor, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def lsl(a, b) + check_width_match(a, b) + op = get_or_create_op(Lsl, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def lsr(a, b) + check_width_match(a, b) + op = get_or_create_op(Lsr, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def asr(a, b) + check_width_match(a, b) + op = get_or_create_op(Asr, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def slt(a, b) + check_width_match(a, b) + op = get_or_create_op(Slt, a.width) + out = new_temp(1) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def extend_sign(a, to_width) + raise "extend_sign: input width #{a.width} >= output width #{to_width}" if a.width >= to_width + op = get_or_create_op(ExtendSign, a.width, to_width) + out = new_temp(to_width) + add_op(op, [a.name], [out.name]) + out + end + + def extend_zero(a, to_width) + raise "extend_zero: input width #{a.width} >= output width #{to_width}" if a.width >= to_width + op = get_or_create_op(ExtendZero, a.width, to_width) + out = new_temp(to_width) + add_op(op, [a.name], [out.name]) + out + end + + def popcnt(a) + op = get_or_create_op(Popcnt, a.width) + out = new_temp(a.width) + add_op(op, [a.name], [out.name]) + out + end + + def ctz(a) + op = get_or_create_op(Ctz, a.width) + out = new_temp(a.width) + add_op(op, [a.name], [out.name]) + out + end + + def clz(a) + op = get_or_create_op(Clz, a.width) + out = new_temp(a.width) + add_op(op, [a.name], [out.name]) + out + end + + def reverse(a) + op = get_or_create_op(Reverse, a.width) + out = new_temp(a.width) + add_op(op, [a.name], [out.name]) + out + end + + def rem_u(a, b) + check_width_match(a, b) + op = get_or_create_op(RemU, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def rem_s(a, b) + check_width_match(a, b) + op = get_or_create_op(RemS, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def ror(a, b) + check_width_match(a, b) + op = get_or_create_op(Ror, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def rol(a, b) + check_width_match(a, b) + op = get_or_create_op(Rol, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def add_overflow(a, b) + check_width_match(a, b) + op = get_or_create_op(AddOverflow, a.width) + out = new_temp(1) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def sub_overflow(a, b) + check_width_match(a, b) + op = get_or_create_op(SubOverflow, a.width) + out = new_temp(1) + add_op(op, [a.name, b.name], [out.name]) + out + end + + def div_u(a, b, default) + check_width_match(a, b) + raise "div_u: default width mismatch" if a.width != default.width + op = get_or_create_op(DivU, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name, default.name], [out.name]) + out + end + + def div_s(a, b, default) + check_width_match(a, b) + raise "div_s: default width mismatch" if a.width != default.width + op = get_or_create_op(DivS, a.width) + out = new_temp(a.width) + add_op(op, [a.name, b.name, default.name], [out.name]) + out + end + + def select(cond, true_val, false_val) + raise "select: condition must be 1-bit" unless cond.width == 1 + raise "select: true/false widths mismatch" unless true_val.width == false_val.width + op = get_or_create_op(Select, true_val.width) + out = new_temp(true_val.width) + add_op(op, [cond.name, true_val.name, false_val.name], [out.name]) + out + end + + def concat(low, high) + low_width = low.width + high_width = high.width + total_width = low_width + high_width + + high_ext = extend_zero(high, total_width) + shift_width = (low_width.bit_length + 1) rescue 1 + shift_amount = const(low_width, shift_width) + high_shifted = lsl(high_ext, shift_amount) + low_ext = extend_zero(low, total_width) + orr(low_ext, high_shifted) + end + + def extract_low(a, out_width) + raise "extract_low: output width #{out_width} > input width #{a.width}" if out_width > a.width + op = get_or_create_op(ExtractLow, a.width, out_width) + out = new_temp(out_width) + add_op(op, [a.name], [out.name]) + out + end + + def extract(value, start, out_width) + start = extend_zero(start, value.width) if start.width != value.width + shifted = lsr(value, start) + extract_low(shifted, out_width) + end + + # Register & memory + def read(rf, rsi, shape = Shape.new(1, nil)) + width = rf.reg_size.lanes_base + out = new_temp(width) + stmt = Statement.new(shape, [out.name], [width], 'read', rf.name, [rsi.to_s]) + @stmts << stmt + out + end + + def write(rf, rsi, value, shape = Shape.new(1, nil)) + stmt = Statement.new(shape, [], [], 'write', rf.name, [rsi.to_s, value.to_s]) + @stmts << stmt + end + + def const(value, width = 32) + out = new_temp(width) + stmt = Statement.new(Shape.new(1, nil), [out.name], [width], 'const', value.to_s, []) + @stmts << stmt + out + end + + def dyn_const(name, width = 32) + out = new_temp(width) + stmt = Statement.new(Shape.new(1, nil), [out.name], [width], 'dyn_const', name, []) + @stmts << stmt + out + end + + def env(env_func, inputs) + outputs = env_func.outputs.map { |w| new_temp(w) } + stmt = Statement.new( + Shape.new(1, nil), + outputs.map(&:name), + env_func.outputs, + 'env', + env_func.name, + inputs.map(&:to_s) + ) + @stmts << stmt + outputs + end + + def cond_env(env_func, cond, inputs, on_false) + outputs = env_func.outputs.map { |w| new_temp(w) } + all_inputs = [cond.to_s] + inputs.map(&:to_s) + on_false.map(&:to_s) + stmt = Statement.new( + Shape.new(1, nil), + outputs.map(&:name), + env_func.outputs, + 'cond_env', + env_func.name, + all_inputs + ) + @stmts << stmt + outputs + end + + def input(idx, width = 32) + out = new_temp(width) + stmt = Statement.new(Shape.new(1, nil), [out.name], [width], 'input', idx.to_s, []) + @stmts << stmt + out + end + + def output(value, idx) + stmt = Statement.new(Shape.new(1, nil), [], [], 'output', idx.to_s, [value.to_s]) + @stmts << stmt + end + + def add_op(operation, inputs, outputs, shape = Shape.new(1, nil)) + stmt = Statement.new(shape, outputs, operation.outputs, 'op', operation.name, inputs) + @stmts << stmt + end + + def op(operation, inputs) + raise "Operation #{operation.name} has #{operation.outputs.size} outputs, use op_multi" if operation.outputs.size != 1 + out = new_temp(operation.outputs.first) + add_op(operation, inputs.map(&:to_s), [out.name]) + out + end + + def op_multi(operation, inputs) + outputs = operation.outputs.map { |w| new_temp(w) } + add_op(operation, inputs.map(&:to_s), outputs.map(&:name)) + outputs + end + + def build + StatementSeq.new(@stmts) + end + + def +(other) + @stmts.concat(other.stmts) + @temp_counter = [@temp_counter, other.temp_counter].max + self + end + + private + + def check_width_match(a, b) + raise "width mismatch: #{a.width} vs #{b.width}" if a.width != b.width + end + end + + class BaseBuilder + attr_reader :seq + + def initialize + @seq = SeqBuilder.new + end + + def add(a, b) = @seq.add(a, b) + def sub(a, b) = @seq.sub(a, b) + def mul(a, b) = @seq.mul(a, b) + def and_(a, b) = @seq.and_(a, b) + def orr(a, b) = @seq.orr(a, b) + def xor(a, b) = @seq.xor(a, b) + def lsl(a, b) = @seq.lsl(a, b) + def lsr(a, b) = @seq.lsr(a, b) + def asr(a, b) = @seq.asr(a, b) + def slt(a, b) = @seq.slt(a, b) + def extend_sign(a, to_width) = @seq.extend_sign(a, to_width) + def extend_zero(a, to_width) = @seq.extend_zero(a, to_width) + def popcnt(a) = @seq.popcnt(a) + def ctz(a) = @seq.ctz(a) + def clz(a) = @seq.clz(a) + def reverse(a) = @seq.reverse(a) + def rem_u(a, b) = @seq.rem_u(a, b) + def rem_s(a, b) = @seq.rem_s(a, b) + def ror(a, b) = @seq.ror(a, b) + def rol(a, b) = @seq.rol(a, b) + def add_overflow(a, b) = @seq.add_overflow(a, b) + def sub_overflow(a, b) = @seq.sub_overflow(a, b) + def div_u(a, b, default) = @seq.div_u(a, b, default) + def div_s(a, b, default) = @seq.div_s(a, b, default) + def select(cond, true_val, false_val) = @seq.select(cond, true_val, false_val) + def concat(low, high) = @seq.concat(low, high) + def extract_low(a, out_width) = @seq.extract_low(a, out_width) + def extract(value, start, out_width) = @seq.extract(value, start, out_width) + + def read(rf, rsi, shape = Shape.new(1, nil)) = @seq.read(rf, rsi, shape) + def write(rf, rsi, value, shape = Shape.new(1, nil)) = @seq.write(rf, rsi, value, shape) + def const(value, width = 32) = @seq.const(value, width) + def dyn_const(name, width = 32) = @seq.dyn_const(name, width) + def env(env_func, inputs) = @seq.env(env_func, inputs) + def cond_env(env_func, cond, inputs, on_false) = @seq.cond_env(env_func, cond, inputs, on_false) + def input(idx, width = 32) = @seq.input(idx, width) + def output(value, idx) = @seq.output(value, idx) + def op(operation, inputs) = @seq.op(operation, inputs) + def op_multi(operation, inputs) = @seq.op_multi(operation, inputs) + end + + class SnippetBuilder < BaseBuilder + attr_reader :name + + def initialize(name) + super() + @name = name + end + + def build + Snippet.new(@name, @seq.build) + end + end + + class InstructionBuilder < BaseBuilder + attr_reader :name, :operand_sizes, :operand_names, :encoding + + def initialize(name, operand_sizes, operand_names, encoding) + super() + @name = name + @operand_sizes = operand_sizes + @operand_names = operand_names + @encoding = encoding + end + + def add_input_operand(idx, width = nil) + w = width || (@operand_sizes[idx] if idx < @operand_sizes.size) || 32 + input(idx, w) + end + + def build + Instruction.new( + @name, [], + @operand_sizes, @operand_names, + @encoding, + @seq.build + ) + end + end + + class ArchBuilder + attr_reader :name, :attributes, :register_files, :system_registers, + :environment_functions, :tables_int, :operations, + :snippets, :instructions + + def initialize(name, attributes = []) + @name = name + @attributes = attributes + @register_files = [] + @system_registers = [] + @environment_functions = [] + @tables_int = [] + @operations = [] + @snippets = [] + @instructions = [] + end + + def add_register_file(rf) + @register_files << rf + self + end + + def add_system_register(sr) + @system_registers << sr + self + end + + def add_env_func(env) + @environment_functions << env + self + end + + def add_table_int(table) + @tables_int << table + self + end + + def add_operation(op) + @operations << op + self + end + + def add_snippet(snippet) + @snippets << snippet + self + end + + def add_instruction(instr) + @instructions << instr + self + end + + def build + Arch.new( + @name, @attributes, + register_files: @register_files, + system_registers: @system_registers, + environment_functions: @environment_functions, + tables_int: @tables_int, + operations: @operations, + snippets: @snippets, + instructions: @instructions + ) + end + end +end diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb new file mode 100644 index 0000000..3ae4ef6 --- /dev/null +++ b/lib/lira/ir_ops.rb @@ -0,0 +1,221 @@ +# lira/ir_ops.rb +require_relative 'arch' + +module Lira + class TypeCheckError < StandardError; end + + module StdOperation + def base_name + self.class.name.split('::').last.downcase + end + + def generate_name + if outputs.size == 1 + "#{base_name}_#{outputs.first}" + else + "#{base_name}_#{outputs.join('_')}" + end + end + end + + class UnaryOp < Operation + include StdOperation + + def initialize(out_bits, name: nil, semantic_base: nil) + name ||= "#{base_name}_#{out_bits}" + semantic_base ||= base_name + super(name, [], [out_bits], [out_bits], + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 + raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 + raise TypeCheckError, "input != output" unless inputs[0] == outputs[0] + end + end + + class BinaryOp < Operation + include StdOperation + + def initialize(bits, name: nil, semantic_base: nil) + name ||= "#{base_name}_#{bits}" + semantic_base ||= base_name + super(name, [], [bits, bits], [bits], + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 + raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 + raise TypeCheckError, "output must be positive" unless outputs[0] > 0 + unless inputs[0] == inputs[1] && inputs[0] == outputs[0] + raise TypeCheckError, "mismatched widths: #{inputs} -> #{outputs[0]}" + end + end + end + + class CmpOp < Operation + include StdOperation + + def initialize(bits, out_bits = 1, name: nil, semantic_base: nil) + name ||= "#{base_name}_#{bits}" + semantic_base ||= base_name + super(name, [], [bits, bits], [out_bits], + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 + raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 + raise TypeCheckError, "output must be positive" unless outputs[0] > 0 + raise TypeCheckError, "input widths differ" unless inputs[0] == inputs[1] + end + end + + class TernaryOp < Operation + include StdOperation + + def initialize(bits, name: nil, semantic_base: nil) + name ||= "#{base_name}_#{bits}" + semantic_base ||= base_name + super(name, [], [bits, bits, bits], [bits], + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 + raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 + raise TypeCheckError, "input[2] must be positive" unless inputs[2] > 0 + raise TypeCheckError, "output must be positive" unless outputs[0] > 0 + unless inputs[0] == inputs[1] && inputs[0] == inputs[2] && inputs[0] == outputs[0] + raise TypeCheckError, "mismatched widths: #{inputs} -> #{outputs[0]}" + end + end + end + + class ExtendOp < Operation + include StdOperation + + def initialize(in_bits, out_bits, kind, name: nil) + name ||= "#{kind}_#{in_bits}_to_#{out_bits}" + super(name, [], [in_bits], [out_bits], + semantic_base: kind, semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 + raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 + raise TypeCheckError, "input >= output" unless inputs[0] < outputs[0] + end + end + + class ExtractLowOp < Operation + include StdOperation + + def initialize(in_bits, out_bits, name: nil) + name ||= "extract_low_#{in_bits}_to_#{out_bits}" + super(name, [], [in_bits], [out_bits], + semantic_base: 'extract_low', semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 + raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 + raise TypeCheckError, "output > input" unless outputs[0] <= inputs[0] + end + end + + class Not < UnaryOp; def initialize(bits); super(bits, semantic_base: 'not'); end; end + class Neg < UnaryOp; def initialize(bits); super(bits, semantic_base: 'neg'); end; end + class Add < BinaryOp; def initialize(bits); super(bits, semantic_base: 'add'); end; end + class Sub < BinaryOp; def initialize(bits); super(bits, semantic_base: 'sub'); end; end + class Mul < BinaryOp; def initialize(bits); super(bits, semantic_base: 'mul'); end; end + class And < BinaryOp; def initialize(bits); super(bits, semantic_base: 'and'); end; end + class Orr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'orr'); end; end + class Xor < BinaryOp; def initialize(bits); super(bits, semantic_base: 'xor'); end; end + class Lsl < BinaryOp; def initialize(bits); super(bits, semantic_base: 'lsl'); end; end + class Lsr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'lsr'); end; end + class Asr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'asr'); end; end + class Eq < CmpOp; def initialize(bits); super(bits, semantic_base: 'eq'); end; end + class Ne < CmpOp; def initialize(bits); super(bits, semantic_base: 'ne'); end; end + class Slt < CmpOp; def initialize(bits); super(bits, semantic_base: 'slt'); end; end + class Sle < CmpOp; def initialize(bits); super(bits, semantic_base: 'sle'); end; end + class Sgt < CmpOp; def initialize(bits); super(bits, semantic_base: 'sgt'); end; end + class Sge < CmpOp; def initialize(bits); super(bits, semantic_base: 'sge'); end; end + class Ult < CmpOp; def initialize(bits); super(bits, semantic_base: 'ult'); end; end + class Ule < CmpOp; def initialize(bits); super(bits, semantic_base: 'ule'); end; end + class Ugt < CmpOp; def initialize(bits); super(bits, semantic_base: 'ugt'); end; end + class Uge < CmpOp; def initialize(bits); super(bits, semantic_base: 'uge'); end; end + class ExtendSign < ExtendOp; def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end; end + class ExtendZero < ExtendOp; def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end; end + class ExtractLow < ExtractLowOp; def initialize(in_bits, out_bits); super(in_bits, out_bits); end; end + + class Popcnt < UnaryOp + def initialize(bits); super(bits, semantic_base: 'popcnt'); end + end + + class Ctz < UnaryOp + def initialize(bits); super(bits, semantic_base: 'ctz'); end + end + + class Clz < UnaryOp + def initialize(bits); super(bits, semantic_base: 'clz'); end + end + + class Reverse < UnaryOp + def initialize(bits); super(bits, semantic_base: 'reverse'); end + end + + class RemU < BinaryOp + def initialize(bits); super(bits, semantic_base: 'rem_u'); end + end + + class RemS < BinaryOp + def initialize(bits); super(bits, semantic_base: 'rem_s'); end + end + + class Ror < BinaryOp + def initialize(bits); super(bits, semantic_base: 'ror'); end + end + + class Rol < BinaryOp + def initialize(bits); super(bits, semantic_base: 'rol'); end + end + + class AddOverflow < CmpOp + def initialize(bits); super(bits, out_bits: 1, semantic_base: 'add_overflow'); end + end + + class SubOverflow < CmpOp + def initialize(bits); super(bits, out_bits: 1, semantic_base: 'sub_overflow'); end + end + + class DivU < TernaryOp + def initialize(bits); super(bits, semantic_base: 'div_u'); end + end + + class DivS < TernaryOp + def initialize(bits); super(bits, semantic_base: 'div_s'); end + end + + class Select < Operation + include StdOperation + def initialize(bits) + name = "select_#{bits}" + super(name, [], [1, bits, bits], [bits], + semantic_base: 'select', semantic_func: nil, semantic_table: nil) + check_signature + end + + def check_signature + raise TypeCheckError, "true/false branches mismatch" unless inputs[1] == inputs[2] && inputs[1] == outputs[0] + end + end +end diff --git a/lib/lira/ir_ser_txt.rb b/lib/lira/ir_ser_txt.rb new file mode 100644 index 0000000..e381376 --- /dev/null +++ b/lib/lira/ir_ser_txt.rb @@ -0,0 +1,39 @@ +# lira/ir_ser_txt.rb +require_relative 'ir' + +def serialize_shape(shape) + "#{shape.lanes_base}#{shape.lanes_mult}" +end + +def deserialize_shape(s) + m = s.match(/^(\d+)(.*)$/) + Shape.new(m[1].to_i, m[2].empty? ? nil : m[2]) +end + +def serialize_statement(stmt) + shape_str = serialize_shape(stmt.shape) + out_parts = stmt.outputs_types.zip(stmt.outputs).flat_map { |typ, name| [typ.to_s, name] } + parts = [shape_str] + out_parts + ['=', stmt.kind, stmt.specifier] + stmt.inputs + parts.join(' ') +end + +def deserialize_statement(s) + m = s.match(/^(\w+)\s+(.*?)\s*=\s*(\w+)\s+(\S+)\s*(.*)$/) + shape_str, outputs_str, kind, specifier, inputs_str = m.captures + shape = deserialize_shape(shape_str) + pairs = outputs_str.split + outputs_types = (0...pairs.length).step(2).map { |i| pairs[i].to_i } + outputs = (1...pairs.length).step(2).map { |i| pairs[i] } + inputs = inputs_str.empty? ? [] : inputs_str.split + Statement.new(shape, outputs, outputs_types, kind, specifier, inputs) +end + +def serialize_statement_seq(seq) + seq.stmts.map { |s| "#{serialize_statement(s)};\n" }.join +end + +def deserialize_statement_seq(s) + raw_stmts = s.split(';').map(&:strip).reject(&:empty?) + stmts = raw_stmts.map { |raw| deserialize_statement(raw) } + StatementSeq.new(stmts) +end diff --git a/lib/lira/ir_std.rb b/lib/lira/ir_std.rb new file mode 100644 index 0000000..84961c1 --- /dev/null +++ b/lib/lira/ir_std.rb @@ -0,0 +1,94 @@ +# lira/ir_std.rb +require_relative 'ir' +require_relative 'arch' + +class StmtInput + attr_accessor :id_ + + def initialize(id_) + @id_ = id_ + end +end + +class StmtOutput + attr_accessor :id_, :value + + def initialize(id_, value) + @id_ = id_ + @value = value + end +end + +class StmtRead + attr_accessor :rf, :rsi + + def initialize(rf, rsi) + @rf = rf + @rsi = rsi + end +end + +class StmtWrite + attr_accessor :rf, :rsi, :value + + def initialize(rf, rsi, value) + @rf = rf + @rsi = rsi + @value = value + end +end + +class StmtOp + attr_accessor :op, :args + + def initialize(op, args) + @op = op + @args = args + end +end + +class StmtEnv + attr_accessor :env, :args + + def initialize(env, args) + @env = env + @args = args + end +end + +class CondEnv + attr_accessor :env, :cond, :on_false, :inputs + + def initialize(env, cond, on_false, inputs) + @env = env + @cond = cond + @on_false = on_false + @inputs = inputs + end +end + +class StmtIndex; end +class StmtConst + attr_accessor :value + def initialize(value); @value = value; end +end +class StmtDynConst + attr_accessor :name + def initialize(name); @name = name; end +end +class StmtGather + attr_accessor :value, :index, :default + def initialize(value, index, default); @value = value; @index = index; @default = default; end +end +class StmtFold + attr_accessor :op, :args + def initialize(op, args); @op = op; @args = args; end +end +class StmtScan + attr_accessor :op, :args + def initialize(op, args); @op = op; @args = args; end +end +class StmtAlias + attr_accessor :semantic, :args + def initialize(semantic, args); @semantic = semantic; @args = args; end +end From c1a3654f9dff1aab14bdbe6a2655f954ec09663e Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 8 Jun 2026 17:05:00 +0300 Subject: [PATCH 26/75] [lib] LIRA Seriazalization Support --- lib/Utility/lira_utils.rb | 74 ++++++ lib/lira_gen.rb | 537 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 611 insertions(+) create mode 100644 lib/Utility/lira_utils.rb create mode 100644 lib/lira_gen.rb diff --git a/lib/Utility/lira_utils.rb b/lib/Utility/lira_utils.rb new file mode 100644 index 0000000..1209123 --- /dev/null +++ b/lib/Utility/lira_utils.rb @@ -0,0 +1,74 @@ +module ADLToLiraUtils + OP_MAP = { + add: :Add, + sub: :Sub, + mul: :Mul, + and: :And, + or: :Orr, + xor: :Xor, + shl: :Lsl, + shr: :Lsr, + ashr: :Asr + }.freeze + + CMP_OP_MAP_S = { + lt: :Slt, + gt: :Sgt, + le: :Sle, + ge: :Sge, + eq: :Eq, + ne: :Ne + }.freeze + + CMP_OP_MAP_U = { + lt: :Ult, + gt: :Ugt, + le: :Ule, + ge: :Uge, + eq: :Eq, + ne: :Ne + }.freeze + + def self.convert_type(adl_type) + return 32 if adl_type.nil? + case adl_type.to_s + when /^b(\d+)$/ then $1.to_i + when /^u(\d+)$/, /^s(\d+)$/, /^r(\d+)$/ then $1.to_i + else 32 + end + end + + def self.resolve_operand(op, builder, temp_map) + return nil if op.nil? + return temp_map[op] if temp_map.key?(op) + if op.is_a?(Integer) + return builder.const(op, 32) + end + if op.is_a?(SimInfra::Constant) + return builder.const(op.value, 32) + end + if op.is_a?(SimInfra::Var) + width = convert_type(op.type) + width = 1 if width < 1 + val = builder.seq.new_temp(width) + temp_map[op] = val + return val + end + raise "Cannot resolve operand: #{op.inspect}" + end + + def self.ensure_width(val, width, builder) + return val if val.width == width + if val.width < width + builder.extend_zero(val, width) + else + builder.extract_low(val, width) + end + end + + def self.find_env_func(arch_builder, name, input_types, output_types) + arch_builder.environment_functions.find do |ef| + ef.name == name && ef.inputs == input_types && ef.outputs == output_types + end + end +end diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb new file mode 100644 index 0000000..4a9b3fa --- /dev/null +++ b/lib/lira_gen.rb @@ -0,0 +1,537 @@ +#!/usr/bin/env ruby + +require_relative 'ADL/base' +require_relative 'ADL/builder' +require_relative 'lira/arch' +require_relative 'lira/ir' +require_relative 'lira/ir_builder' +require_relative 'lira/ir_ops' +require_relative 'lira/arch_ser_yaml' + +require_relative 'Utility/lira_utils' + +class LiraSerializer + def initialize(arch_name, arch_attributes = []) + @arch_name = arch_name + @arch_attributes = arch_attributes + @arch_builder = nil + @builder = nil + @temp_map = nil + @operand_names = nil + @operand_vars = nil + end + + def process_binary_op(name, oprnds) + op_class = Lira.const_get(ADLToLiraUtils::OP_MAP[name]) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + return nil if a.nil? || b.nil? + target_width = [a.width, b.width].max + a = ADLToLiraUtils.ensure_width(a, target_width, @builder) + b = ADLToLiraUtils.ensure_width(b, target_width, @builder) + out = @builder.seq.new_temp(target_width) + @builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + out + end + + def process_cmp_op(name, oprnds) + out = @builder.seq.new_temp(1) + op1_type = oprnds[1]&.type.to_s + unsigned = op1_type.start_with?('u') + op_map = unsigned ? ADLToLiraUtils::CMP_OP_MAP_U : ADLToLiraUtils::CMP_OP_MAP_S + op_class = Lira.const_get(op_map[name]) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + return nil if a.nil? || b.nil? + target_width = [a.width, b.width].max + a = ADLToLiraUtils.ensure_width(a, target_width, @builder) + b = ADLToLiraUtils.ensure_width(b, target_width, @builder) + @builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + out + end + + def find_register_file(name) + @arch_builder.register_files.find { |rf| rf.name == name } + end + + def process_read_reg(oprnds) + reg_var = oprnds[1] + idx = @operand_names.index(reg_var.name.to_s) + if idx + input_val = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) + @temp_map[oprnds[0]] = input_val + input_val + else + rf_name = reg_var.regset.to_s + rf = find_register_file(rf_name) + if rf.nil? + warn "Register file '#{rf_name}' not found, skipping statement" + return nil + end + out = @builder.seq.new_temp(32) + reg = reg_var.name.to_s + @builder.read(rf, reg) + @temp_map[oprnds[0]] = out + out + end + end + + def process_write_reg(oprnds) + reg_var = oprnds[0] + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + return nil if val.nil? + idx = @operand_names.index(reg_var.name.to_s) + if idx + @builder.output(val, idx) + else + rf_name = reg_var.regset.to_s + rf = find_register_file(rf_name) + if rf.nil? + warn "Register file '#{rf_name}' not found, skipping statement" + return nil + end + reg = reg_var.name.to_s + @builder.write(rf, reg, val) + end + nil + end + + def process_read_mem(oprnds) + out_type = ADLToLiraUtils.convert_type(oprnds[0].type) + out = @builder.seq.new_temp(out_type) + addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + return nil if addr.nil? + addr_width = addr.width + ef = ADLToLiraUtils.find_env_func(@arch_builder, "readMem", [addr_width], [out_type]) + if ef.nil? + warn "Environment function 'readMem' with inputs [#{addr_width}] and outputs [#{out_type}] not registered, skipping statement" + return nil + end + @builder.env(ef, [addr]) + @temp_map[oprnds[0]] = out + out + end + + def process_write_mem(oprnds) + addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @temp_map) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + return nil if addr.nil? || val.nil? + addr_width = addr.width + ef = ADLToLiraUtils.find_env_func(@arch_builder, "writeMem", [addr_width, val.width], []) + if ef.nil? + warn "Environment function 'writeMem' with inputs [#{addr_width}, #{val.width}] not registered, skipping statement" + return nil + end + @builder.env(ef, [addr, val]) + nil + end + + def process_extract(oprnds) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + return nil if val.nil? + hi = oprnds[2].value + lo = oprnds[3].value + width = hi - lo + 1 + width = 1 if width < 1 + out = @builder.seq.new_temp(width) + @builder.extract(val, @builder.const(lo, 32), width) + @temp_map[oprnds[0]] = out + out + end + + def process_cast_zext(name, oprnds) + dest_type = oprnds[0].type + dest_width = ADLToLiraUtils.convert_type(dest_type) + dest_width = 1 if dest_width < 1 + src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + return nil if src.nil? + if src.width == dest_width + out = src + else + out = @builder.seq.new_temp(dest_width) + if name == :zext || dest_type.to_s.start_with?('u') + @builder.extend_zero(src, dest_width) + else + @builder.extend_sign(src, dest_width) + end + end + @temp_map[oprnds[0]] = out + out + end + + def process_rem(oprnds) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + return nil if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + out = unsigned ? @builder.rem_u(a, b) : @builder.rem_s(a, b) + @temp_map[oprnds[0]] = out + out + end + + def process_div(oprnds) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + return nil if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + default = @builder.const(0, 32) + out = unsigned ? @builder.div_u(a, b, default) : @builder.div_s(a, b, default) + @temp_map[oprnds[0]] = out + out + end + + def stmt_to_lira(stmt) + name = stmt.name + oprnds = stmt.oprnds + + case name + when :new_var + var = oprnds[0] + width = ADLToLiraUtils.convert_type(var.type) + width = 1 if width < 1 + val = @builder.seq.new_temp(width) + @temp_map[var] = val + + when :let + lhs, rhs = oprnds + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) + @temp_map[lhs] = rhs_val if rhs_val + + when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr + out = process_binary_op(name, oprnds) + @temp_map[oprnds[0]] = out if out + + when :lt, :gt, :le, :ge, :eq, :ne + out = process_cmp_op(name, oprnds) + @temp_map[oprnds[0]] = out if out + + when :select + cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @temp_map) + return if cond.nil? || t.nil? || f.nil? + cond = ADLToLiraUtils.ensure_width(cond, 1, @builder) + out = @builder.select(cond, t, f) + @temp_map[oprnds[0]] = out + + when :extract + process_extract(oprnds) + + when :cast, :zext + process_cast_zext(name, oprnds) + + when :readReg + process_read_reg(oprnds) + + when :writeReg + process_write_reg(oprnds) + + when :readMem + process_read_mem(oprnds) + + when :writeMem + process_write_mem(oprnds) + + when :branch + target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @temp_map) + return if target.nil? + ef = ADLToLiraUtils.find_env_func(@arch_builder, "pc_write", [32], []) + if ef.nil? + warn "Environment function 'pc_write' not registered, skipping statement" + return + end + @builder.env(ef, [target]) + + when :sysCall + ef = ADLToLiraUtils.find_env_func(@arch_builder, "sysCall", [], []) + if ef.nil? + warn "Environment function 'sysCall' not registered, skipping statement" + return + end + @builder.env(ef, []) + + when :rem + process_rem(oprnds) + + when :div + process_div(oprnds) + + else + raise "Unhandled statement: #{name}" + end + end + + def generate_semantic(adl_instr) + return Lira::StatementSeq.new([]) if adl_instr.code.tree.empty? + + @builder = Lira::InstructionBuilder.new( + adl_instr.name.to_s, [], [], + Lira::InstructionEncoding.new(32, 0, [], '', '', '') + ) + @temp_map = {} + adl_instr.code.tree.each do |stmt| + stmt_to_lira(stmt) + end + @builder.seq.build + end + + def generate_decode_snippets(adl_instr, operand_vars) + decode_snippet_names = [] + operand_vars.each do |var| + snippet_name = "decode_#{adl_instr.name}_#{var.name}" + @builder = Lira::SnippetBuilder.new(snippet_name) + @temp_map = {} + enc = @builder.input(0, 32) + + adl_instr.map.tree.each do |stmt| + name = stmt.name + oprnds = stmt.oprnds + + case name + when :new_var + v = oprnds[0] + width = ADLToLiraUtils.convert_type(v.type) + width = 1 if width < 1 + val = @builder.seq.new_temp(width) + @temp_map[v] = val + + when :let + lhs, rhs = oprnds + if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') + field_name = rhs.name.to_s[2..-1] + field = adl_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + if field + lo = field.from + hi = field.to + width = hi - lo + 1 + width = 1 if width < 1 + shifted = @builder.lsr(enc, @builder.const(lo, 32)) + val = @builder.extract_low(shifted, width) + if ADLToLiraUtils.convert_type(lhs.type) != width + if lhs.type.to_s.start_with?('s') + val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) + else + val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) + end + end + @temp_map[lhs] = val + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) + @temp_map[lhs] = rhs_val if rhs_val + end + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) + @temp_map[lhs] = rhs_val if rhs_val + end + + when :cast, :zext + process_cast_zext(name, oprnds) + + when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr + out = process_binary_op(name, oprnds) + @temp_map[oprnds[0]] = out if out + + when :lt, :gt, :le, :ge, :eq, :ne + out = process_cmp_op(name, oprnds) + @temp_map[oprnds[0]] = out if out + + else + # Ignore other statements in decode snippet + end + end + + val = @temp_map[var] + @builder.output(val || @builder.const(0, 32), 0) + snippet = @builder.build + @arch_builder.add_snippet(snippet) + decode_snippet_names << snippet_name + end + decode_snippet_names + end + + def generate_encode_snippet(adl_instr, operand_vars) + snippet_name = "encode_#{adl_instr.name}" + @builder = Lira::SnippetBuilder.new(snippet_name) + + operand_values = operand_vars.each_with_index.map do |var, idx| + width = ADLToLiraUtils.convert_type(var.type) + width = 1 if width < 1 + @builder.input(idx, width) + end + + base = @builder.const(0, 32) + adl_instr.fields.each do |field| + lo = field.from + hi = field.to + width = hi - lo + 1 + width = 1 if width < 1 + field_var_name = field.value.name.to_s + value_num = field.value.value + if value_num + const_val = @builder.const(value_num, width) + const_val = ADLToLiraUtils.ensure_width(const_val, 32, @builder) + shifted = @builder.lsl(const_val, @builder.const(lo, 32)) + base = @builder.orr(base, shifted) + elsif field_var_name =~ /^f_(.+)$/ + operand_name = $1 + idx = operand_vars.index { |v| v.name.to_s == operand_name } + if idx + op_val = operand_values[idx] + op_val = ADLToLiraUtils.ensure_width(op_val, 32, @builder) + shifted = @builder.lsl(op_val, @builder.const(lo, 32)) + base = @builder.orr(base, shifted) + end + end + end + + @builder.output(base, 0) + snippet = @builder.build + @arch_builder.add_snippet(snippet) + snippet_name + end + + def collect_operand_vars(adl_instr) + operand_vars = [] + adl_instr.map.tree.each do |stmt| + if stmt.name == :new_var + var = stmt.oprnds[0] + attrs = stmt.attrs + operand_vars << var if attrs && attrs.include?(:op) + end + end + operand_vars + end + + def collect_operand_names(adl_instr) + collect_operand_vars(adl_instr).map { |v| v.name.to_s } + end + + def convert_instruction(adl_instr) + operand_vars = collect_operand_vars(adl_instr) + operand_names = collect_operand_names(adl_instr) + @operand_names = operand_names + semantic = generate_semantic(adl_instr) + + decode_snippets = [] + encode_snippet = nil + if adl_instr.map.tree.any? && operand_vars.any? + decode_snippets = generate_decode_snippets(adl_instr, operand_vars) + end + if adl_instr.fields.any? && operand_vars.any? + encode_snippet = generate_encode_snippet(adl_instr, operand_vars) + end + + const_part = 0 + adl_instr.fields.each do |field| + value_num = field.value.value + const_part |= (value_num << field.from) if value_num + end + + operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } + + encoding = Lira::InstructionEncoding.new(32, const_part, decode_snippets, encode_snippet || '', '', '') + Lira::Instruction.new(adl_instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) + end + + def build_arch + @arch_builder = Lira::ArchBuilder.new(@arch_name, @arch_attributes) + + SimInfra.class_variable_get(:@@regfiles).each do |rf| + regs = rf.regs.map do |reg| + attrs = reg.attrs.map(&:to_s) + Lira::Register.new(reg.name.to_s, attrs) + end + lira_rf = Lira::RegisterFile.new(rf.name.to_s, [], Lira::Shape.new(32, nil), regs) + @arch_builder.add_register_file(lira_rf) + end + + env_funcs = SimInfra.interface_functions.dup + env_funcs.uniq! { |f| [f[:name], f[:return_types], f[:argument_types]] } + env_funcs.each do |ef| + inputs = ef[:argument_types].map { |t| ADLToLiraUtils.convert_type(t) } + outputs = ef[:return_types].map { |t| ADLToLiraUtils.convert_type(t) } + lira_ef = Lira::EnvironmentFunction.new(ef[:name].to_s, [], inputs, outputs) + @arch_builder.add_env_func(lira_ef) + end + + unless @arch_builder.environment_functions.any? { |ef| ef.name == "pc_read" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("pc_read", [], [], [32])) + end + unless @arch_builder.environment_functions.any? { |ef| ef.name == "pc_write" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("pc_write", [], [32], [])) + end + + SimInfra.class_variable_get(:@@instructions).each do |adl_instr| + next if adl_instr.name == :fence || adl_instr.name == :ebreak + begin + lira_instr = convert_instruction(adl_instr) + @arch_builder.add_instruction(lira_instr) + rescue => e + warn "Skipping #{adl_instr.name}: #{e}" + end + end + + @arch_builder.build + end +end + +require 'optparse' +require 'pathname' + +def load_target(path) + target_path = Pathname.new(path) + if target_path.directory? + Dir.glob(target_path.join('*.rb')).sort.each do |file| + require_relative file + end + elsif target_path.file? && target_path.extname == '.rb' + require_relative target_path + else + warn "Target '#{path}' is neither a directory nor a .rb file" + exit 1 + end +end + +def extract_arch_name(loaded_modules) + target_name = nil + ObjectSpace.each_object(Module) do |mod| + if mod.is_a?(Module) && mod.name && mod.name !~ /^SimInfra/ && mod.constants.include?(:XRegs) + target_name = mod.name.to_s + break + end + end + target_name ||= "TargetArch" + [target_name, []] +end + +def main + options = { + output: 'lira.yaml', + } + + OptionParser.new do |opts| + opts.banner = "Usage: #{$0} [options]" + opts.on('-o', '--output FILE', 'Output YAML file (default: lira.yaml)') do |f| + options[:output] = f + end + opts.on('-t', '--target PATH', 'Target architecture directory or .rb file') do |p| + options[:target] = p + end + opts.on('-h', '--help', 'Show this help') do + puts opts + exit + end + end.parse! + + load_target(options[:target]) + + arch_name, arch_attrs = extract_arch_name(nil) + serializer = LiraSerializer.new(arch_name, arch_attrs) + arch = serializer.build_arch + Lira::ArchSerYaml.write_arch(arch, options[:output]) + puts "Serialized architecture to #{options[:output]}" +end + +if __FILE__ == $0 + main +end From fa564e210fde02b1be2e77c11205b063c90e8236 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 8 Jun 2026 23:46:58 +0300 Subject: [PATCH 27/75] [lib] Decode Snippets serialization caching * Decode Snippets was supported caching to make it reusable * Encode Snippets was temporarily disabled --- lib/lira_gen.rb | 334 ++++++++++++++++++++++++++---------------------- 1 file changed, 180 insertions(+), 154 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 4a9b3fa..58cc935 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -7,7 +7,7 @@ require_relative 'lira/ir_builder' require_relative 'lira/ir_ops' require_relative 'lira/arch_ser_yaml' - +require_relative 'lira/ir_ser_txt' require_relative 'Utility/lira_utils' class LiraSerializer @@ -16,15 +16,22 @@ def initialize(arch_name, arch_attributes = []) @arch_attributes = arch_attributes @arch_builder = nil @builder = nil - @temp_map = nil + @vars = nil @operand_names = nil @operand_vars = nil + + @decode_cache = {} + @decode_snip_id = 0 + + # NOTE: Temporary disabled + # @encode_cache = {} + # @encode_snip_id = 0 end def process_binary_op(name, oprnds) op_class = Lira.const_get(ADLToLiraUtils::OP_MAP[name]) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) return nil if a.nil? || b.nil? target_width = [a.width, b.width].max a = ADLToLiraUtils.ensure_width(a, target_width, @builder) @@ -40,8 +47,8 @@ def process_cmp_op(name, oprnds) unsigned = op1_type.start_with?('u') op_map = unsigned ? ADLToLiraUtils::CMP_OP_MAP_U : ADLToLiraUtils::CMP_OP_MAP_S op_class = Lira.const_get(op_map[name]) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) return nil if a.nil? || b.nil? target_width = [a.width, b.width].max a = ADLToLiraUtils.ensure_width(a, target_width, @builder) @@ -59,7 +66,7 @@ def process_read_reg(oprnds) idx = @operand_names.index(reg_var.name.to_s) if idx input_val = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) - @temp_map[oprnds[0]] = input_val + @vars[oprnds[0]] = input_val input_val else rf_name = reg_var.regset.to_s @@ -71,14 +78,14 @@ def process_read_reg(oprnds) out = @builder.seq.new_temp(32) reg = reg_var.name.to_s @builder.read(rf, reg) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end end def process_write_reg(oprnds) reg_var = oprnds[0] - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) return nil if val.nil? idx = @operand_names.index(reg_var.name.to_s) if idx @@ -99,7 +106,7 @@ def process_write_reg(oprnds) def process_read_mem(oprnds) out_type = ADLToLiraUtils.convert_type(oprnds[0].type) out = @builder.seq.new_temp(out_type) - addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) return nil if addr.nil? addr_width = addr.width ef = ADLToLiraUtils.find_env_func(@arch_builder, "readMem", [addr_width], [out_type]) @@ -108,13 +115,13 @@ def process_read_mem(oprnds) return nil end @builder.env(ef, [addr]) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end def process_write_mem(oprnds) - addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @temp_map) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) return nil if addr.nil? || val.nil? addr_width = addr.width ef = ADLToLiraUtils.find_env_func(@arch_builder, "writeMem", [addr_width, val.width], []) @@ -127,7 +134,7 @@ def process_write_mem(oprnds) end def process_extract(oprnds) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) return nil if val.nil? hi = oprnds[2].value lo = oprnds[3].value @@ -135,7 +142,7 @@ def process_extract(oprnds) width = 1 if width < 1 out = @builder.seq.new_temp(width) @builder.extract(val, @builder.const(lo, 32), width) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end @@ -143,7 +150,7 @@ def process_cast_zext(name, oprnds) dest_type = oprnds[0].type dest_width = ADLToLiraUtils.convert_type(dest_type) dest_width = 1 if dest_width < 1 - src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) + src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) return nil if src.nil? if src.width == dest_width out = src @@ -155,28 +162,28 @@ def process_cast_zext(name, oprnds) @builder.extend_sign(src, dest_width) end end - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end def process_rem(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) return nil if a.nil? || b.nil? unsigned = oprnds[1].type.to_s.start_with?('u') out = unsigned ? @builder.rem_u(a, b) : @builder.rem_s(a, b) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end def process_div(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) return nil if a.nil? || b.nil? unsigned = oprnds[1].type.to_s.start_with?('u') default = @builder.const(0, 32) out = unsigned ? @builder.div_u(a, b, default) : @builder.div_s(a, b, default) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out out end @@ -190,29 +197,29 @@ def stmt_to_lira(stmt) width = ADLToLiraUtils.convert_type(var.type) width = 1 if width < 1 val = @builder.seq.new_temp(width) - @temp_map[var] = val + @vars[var] = val when :let lhs, rhs = oprnds - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) - @temp_map[lhs] = rhs_val if rhs_val + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + @vars[lhs] = rhs_val if rhs_val when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr out = process_binary_op(name, oprnds) - @temp_map[oprnds[0]] = out if out + @vars[oprnds[0]] = out if out when :lt, :gt, :le, :ge, :eq, :ne out = process_cmp_op(name, oprnds) - @temp_map[oprnds[0]] = out if out + @vars[oprnds[0]] = out if out when :select - cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @temp_map) - t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @temp_map) - f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @temp_map) + cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) + f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @vars) return if cond.nil? || t.nil? || f.nil? cond = ADLToLiraUtils.ensure_width(cond, 1, @builder) out = @builder.select(cond, t, f) - @temp_map[oprnds[0]] = out + @vars[oprnds[0]] = out when :extract process_extract(oprnds) @@ -233,7 +240,7 @@ def stmt_to_lira(stmt) process_write_mem(oprnds) when :branch - target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @temp_map) + target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars) return if target.nil? ef = ADLToLiraUtils.find_env_func(@arch_builder, "pc_write", [32], []) if ef.nil? @@ -261,138 +268,157 @@ def stmt_to_lira(stmt) end end - def generate_semantic(adl_instr) - return Lira::StatementSeq.new([]) if adl_instr.code.tree.empty? + def generate_semantic(instr) + return Lira::StatementSeq.new([]) if instr.code.tree.empty? @builder = Lira::InstructionBuilder.new( - adl_instr.name.to_s, [], [], + instr.name.to_s, [], [], Lira::InstructionEncoding.new(32, 0, [], '', '', '') ) - @temp_map = {} - adl_instr.code.tree.each do |stmt| + @vars = {} + instr.code.tree.each do |stmt| stmt_to_lira(stmt) end @builder.seq.build end - def generate_decode_snippets(adl_instr, operand_vars) + def generate_decode_snippets(instr, operand_vars) decode_snippet_names = [] - operand_vars.each do |var| - snippet_name = "decode_#{adl_instr.name}_#{var.name}" - @builder = Lira::SnippetBuilder.new(snippet_name) - @temp_map = {} - enc = @builder.input(0, 32) - - adl_instr.map.tree.each do |stmt| - name = stmt.name - oprnds = stmt.oprnds - - case name - when :new_var - v = oprnds[0] - width = ADLToLiraUtils.convert_type(v.type) - width = 1 if width < 1 - val = @builder.seq.new_temp(width) - @temp_map[v] = val - - when :let - lhs, rhs = oprnds - if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') - field_name = rhs.name.to_s[2..-1] - field = adl_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } - if field - lo = field.from - hi = field.to - width = hi - lo + 1 - width = 1 if width < 1 - shifted = @builder.lsr(enc, @builder.const(lo, 32)) - val = @builder.extract_low(shifted, width) - if ADLToLiraUtils.convert_type(lhs.type) != width - if lhs.type.to_s.start_with?('s') - val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) - else - val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) - end + @builder = Lira::SnippetBuilder.new("temp_decode") + @vars = {} + enc = @builder.input(0, 32) + + instr.map.tree.each do |stmt| + name = stmt.name + oprnds = stmt.oprnds + + case name + when :new_var + v = oprnds[0] + width = ADLToLiraUtils.convert_type(v.type) + width = 1 if width < 1 + val = @builder.seq.new_temp(width) + @vars[v] = val + + when :let + lhs, rhs = oprnds + if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') + field_name = rhs.name.to_s[2..-1] + field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + if field + lo = field.from + hi = field.to + width = hi - lo + 1 + width = 1 if width < 1 + shifted = @builder.lsr(enc, @builder.const(lo, 32)) + val = @builder.extract_low(shifted, width) + if ADLToLiraUtils.convert_type(lhs.type) != width + if lhs.type.to_s.start_with?('s') + val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) + else + val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) end - @temp_map[lhs] = val - else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) - @temp_map[lhs] = rhs_val if rhs_val end + @vars[lhs] = val else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @temp_map) - @temp_map[lhs] = rhs_val if rhs_val + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + @vars[lhs] = rhs_val if rhs_val end + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + @vars[lhs] = rhs_val if rhs_val + end - when :cast, :zext - process_cast_zext(name, oprnds) + when :cast, :zext + process_cast_zext(name, oprnds) - when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr - out = process_binary_op(name, oprnds) - @temp_map[oprnds[0]] = out if out + when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr + out = process_binary_op(name, oprnds) + @vars[oprnds[0]] = out if out - when :lt, :gt, :le, :ge, :eq, :ne - out = process_cmp_op(name, oprnds) - @temp_map[oprnds[0]] = out if out + when :lt, :gt, :le, :ge, :eq, :ne + out = process_cmp_op(name, oprnds) + @vars[oprnds[0]] = out if out - else + else # Ignore other statements in decode snippet - end end - - val = @temp_map[var] - @builder.output(val || @builder.const(0, 32), 0) - snippet = @builder.build - @arch_builder.add_snippet(snippet) - decode_snippet_names << snippet_name - end - decode_snippet_names - end - - def generate_encode_snippet(adl_instr, operand_vars) - snippet_name = "encode_#{adl_instr.name}" - @builder = Lira::SnippetBuilder.new(snippet_name) - - operand_values = operand_vars.each_with_index.map do |var, idx| - width = ADLToLiraUtils.convert_type(var.type) - width = 1 if width < 1 - @builder.input(idx, width) end - base = @builder.const(0, 32) - adl_instr.fields.each do |field| - lo = field.from - hi = field.to - width = hi - lo + 1 - width = 1 if width < 1 - field_var_name = field.value.name.to_s - value_num = field.value.value - if value_num - const_val = @builder.const(value_num, width) - const_val = ADLToLiraUtils.ensure_width(const_val, 32, @builder) - shifted = @builder.lsl(const_val, @builder.const(lo, 32)) - base = @builder.orr(base, shifted) - elsif field_var_name =~ /^f_(.+)$/ - operand_name = $1 - idx = operand_vars.index { |v| v.name.to_s == operand_name } - if idx - op_val = operand_values[idx] - op_val = ADLToLiraUtils.ensure_width(op_val, 32, @builder) - shifted = @builder.lsl(op_val, @builder.const(lo, 32)) - base = @builder.orr(base, shifted) - end - end + operand_vars.each_with_index do |var, idx| + val = @vars[var] + @builder.output(val, idx) end - @builder.output(base, 0) snippet = @builder.build - @arch_builder.add_snippet(snippet) - snippet_name + seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + + if @decode_cache.key?(seq_str) + decode_snippet_names << @decode_cache[seq_str] + else + unique_name = "decode_#{@decode_snip_id}" + snippet.name = unique_name + @arch_builder.add_snippet(snippet) + @decode_snip_id += 1 + @decode_cache[seq_str] = unique_name + decode_snippet_names << unique_name + end + decode_snippet_names end - def collect_operand_vars(adl_instr) + # NOTE: Temporary disabled + # def generate_encode_snippet(instr, operand_vars) + # @builder = Lira::SnippetBuilder.new("temp_encode") + # + # operand_values = operand_vars.each_with_index.map do |var, idx| + # width = ADLToLiraUtils.convert_type(var.type) + # width = 1 if width < 1 + # @builder.input(idx, width) + # end + # + # base = @builder.const(0, 32) + # instr.fields.each do |field| + # lo = field.from + # hi = field.to + # width = hi - lo + 1 + # width = 1 if width < 1 + # field_var_name = field.value.name.to_s + # value_num = field.value.value + # if value_num + # const_val = @builder.const(value_num, width) + # const_val = ADLToLiraUtils.ensure_width(const_val, 32, @builder) + # shifted = @builder.lsl(const_val, @builder.const(lo, 32)) + # base = @builder.orr(base, shifted) + # elsif field_var_name =~ /^f_(.+)$/ + # operand_name = $1 + # idx = operand_vars.index { |v| v.name.to_s == operand_name } + # if idx + # op_val = operand_values[idx] + # op_val = ADLToLiraUtils.ensure_width(op_val, 32, @builder) + # shifted = @builder.lsl(op_val, @builder.const(lo, 32)) + # base = @builder.orr(base, shifted) + # end + # end + # end + # + # @builder.output(base, 0) + # snippet = @builder.build + # seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + # if @encode_cache.key?(seq_str) + # return @encode_cache[seq_str] + # else + # unique_name = "encode_#{@encode_snip_id}" + # snippet.name = unique_name + # @arch_builder.add_snippet(snippet) + # @encode_snip_id += 1 + # @encode_cache[seq_str] = unique_name + # unique_name + # end + # end + + def collect_operand_vars(instr) operand_vars = [] - adl_instr.map.tree.each do |stmt| + instr.map.tree.each do |stmt| if stmt.name == :new_var var = stmt.oprnds[0] attrs = stmt.attrs @@ -402,27 +428,27 @@ def collect_operand_vars(adl_instr) operand_vars end - def collect_operand_names(adl_instr) - collect_operand_vars(adl_instr).map { |v| v.name.to_s } + def collect_operand_names(instr) + collect_operand_vars(instr).map { |v| v.name.to_s } end - def convert_instruction(adl_instr) - operand_vars = collect_operand_vars(adl_instr) - operand_names = collect_operand_names(adl_instr) + def convert_instruction(instr) + operand_vars = collect_operand_vars(instr) + operand_names = collect_operand_names(instr) @operand_names = operand_names - semantic = generate_semantic(adl_instr) + semantic = generate_semantic(instr) decode_snippets = [] encode_snippet = nil - if adl_instr.map.tree.any? && operand_vars.any? - decode_snippets = generate_decode_snippets(adl_instr, operand_vars) - end - if adl_instr.fields.any? && operand_vars.any? - encode_snippet = generate_encode_snippet(adl_instr, operand_vars) + if instr.map.tree.any? && operand_vars.any? + decode_snippets = generate_decode_snippets(instr, operand_vars) end + # if instr.fields.any? && operand_vars.any? + # encode_snippet = generate_encode_snippet(instr, operand_vars) + # end const_part = 0 - adl_instr.fields.each do |field| + instr.fields.each do |field| value_num = field.value.value const_part |= (value_num << field.from) if value_num end @@ -430,7 +456,7 @@ def convert_instruction(adl_instr) operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } encoding = Lira::InstructionEncoding.new(32, const_part, decode_snippets, encode_snippet || '', '', '') - Lira::Instruction.new(adl_instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) + Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) end def build_arch @@ -461,13 +487,13 @@ def build_arch @arch_builder.add_env_func(Lira::EnvironmentFunction.new("pc_write", [], [32], [])) end - SimInfra.class_variable_get(:@@instructions).each do |adl_instr| - next if adl_instr.name == :fence || adl_instr.name == :ebreak + SimInfra.class_variable_get(:@@instructions).each do |instr| + next if instr.name == :fence || instr.name == :ebreak begin - lira_instr = convert_instruction(adl_instr) + lira_instr = convert_instruction(instr) @arch_builder.add_instruction(lira_instr) rescue => e - warn "Skipping #{adl_instr.name}: #{e}" + warn "Skipping #{instr.name}: #{e}" end end From 86c9cff97db0ed1193f88ffcf0c0824eb1f9e2b3 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 9 Jun 2026 18:26:23 +0300 Subject: [PATCH 28/75] [ser] Serialization updated --- CMakeLists.txt | 6 +- lib/Utility/lira_utils.rb | 48 +++++++++-- lib/lira/arch.rb | 8 +- lib/lira_gen.rb | 169 +++++++++++++++++++++++++------------- 4 files changed, 165 insertions(+), 66 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8d4133..1fe096e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,8 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) PROPERTY VALUE "${CMAKE_BINARY_DIR}/install") endif() -find_package(Ruby 3.4.8 EXACT REQUIRED) -find_package(Python3 3.12 EXACT REQUIRED COMPONENTS Interpreter) +find_package(Ruby 4.0.1 EXACT REQUIRED) +find_package(Python3 3.10 EXACT REQUIRED COMPONENTS Interpreter) message("Python found: ${Python3_EXECUTABLE}") include(ExternalProject) @@ -30,5 +30,5 @@ endif() add_subdirectory(lib) add_subdirectory(sim_lib) -add_subdirectory(sim_gen) +add_subdirectory(sim_gen_lira) add_subdirectory(test) diff --git a/lib/Utility/lira_utils.rb b/lib/Utility/lira_utils.rb index 1209123..3cdcc73 100644 --- a/lib/Utility/lira_utils.rb +++ b/lib/Utility/lira_utils.rb @@ -1,3 +1,4 @@ +# lira_utils.rb module ADLToLiraUtils OP_MAP = { add: :Add, @@ -29,6 +30,8 @@ module ADLToLiraUtils ne: :Ne }.freeze + SPECIAL_REGS = %w[pc].freeze + def self.convert_type(adl_type) return 32 if adl_type.nil? case adl_type.to_s @@ -38,9 +41,10 @@ def self.convert_type(adl_type) end end - def self.resolve_operand(op, builder, temp_map) + def self.resolve_operand(op, builder, vars, operand_names, arch_builder = nil) return nil if op.nil? - return temp_map[op] if temp_map.key?(op) + return vars[op] if vars.key?(op) + if op.is_a?(Integer) return builder.const(op, 32) end @@ -50,9 +54,43 @@ def self.resolve_operand(op, builder, temp_map) if op.is_a?(SimInfra::Var) width = convert_type(op.type) width = 1 if width < 1 - val = builder.seq.new_temp(width) - temp_map[op] = val - return val + + idx = operand_names.index(op.name.to_s) + if idx + input_val = builder.input(idx, width) + vars[op] = input_val + + if op.regset + rf_name = op.regset.to_s + rf = arch_builder.register_files.find { |rf| rf.name == rf_name } + if rf.nil? + warn "Register file '#{rf_name}' not found, skipping statement" + return nil + end + read_val = builder.seq.new_temp(width) + builder.read(rf, input_val) + vars[op] = read_val + return read_val + else + return input_val + end + else + if SPECIAL_REGS.include?(op.name.to_s) + ef = find_env_func(arch_builder, "getPC", [], [32]) + if ef + val = builder.env(ef, [])[0] + vars[op] = val + return val + else + warn "Environment function 'getPC' not registered" + return nil + end + else + val = builder.seq.new_temp(width) + vars[op] = val + return val + end + end end raise "Cannot resolve operand: #{op.inspect}" end diff --git a/lib/lira/arch.rb b/lib/lira/arch.rb index aa22577..8775d25 100644 --- a/lib/lira/arch.rb +++ b/lib/lira/arch.rb @@ -277,12 +277,13 @@ def ==(other) end class InstructionEncoding - attr_accessor :encoded_size, :const_encoding_part, :decode, :encode, + attr_accessor :encoded_size, :const_encoding_part, :const_mask, :decode, :encode, :constraint_decode, :constraint_encode - def initialize(encoded_size, const_encoding_part, decode, encode, constraint_decode, constraint_encode) + def initialize(encoded_size, const_encoding_part, const_mask, decode, encode, constraint_decode, constraint_encode) @encoded_size = encoded_size @const_encoding_part = const_encoding_part + @const_mask = const_mask @decode = decode @encode = encode @constraint_decode = constraint_decode @@ -293,6 +294,7 @@ def to_h { encoded_size: encoded_size, const_encoding_part: const_encoding_part, + const_mask: const_mask, decode: decode, encode: encode, constraint_decode: constraint_decode, @@ -303,6 +305,7 @@ def to_h def self.from_h(hash) new(hash[:encoded_size] || hash['encoded_size'], hash[:const_encoding_part] || hash['const_encoding_part'], + hash[:const_mask] || hash['const_mask'], hash[:decode] || hash['decode'], hash[:encode] || hash['encode'], hash[:constraint_decode] || hash['constraint_decode'], @@ -312,6 +315,7 @@ def self.from_h(hash) def ==(other) other.is_a?(InstructionEncoding) && encoded_size == other.encoded_size && + const_mask == other.const_mask && const_encoding_part == other.const_encoding_part && decode == other.decode && encode == other.encode && diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 58cc935..5427714 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -30,8 +30,8 @@ def initialize(arch_name, arch_attributes = []) def process_binary_op(name, oprnds) op_class = Lira.const_get(ADLToLiraUtils::OP_MAP[name]) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? target_width = [a.width, b.width].max a = ADLToLiraUtils.ensure_width(a, target_width, @builder) @@ -47,8 +47,8 @@ def process_cmp_op(name, oprnds) unsigned = op1_type.start_with?('u') op_map = unsigned ? ADLToLiraUtils::CMP_OP_MAP_U : ADLToLiraUtils::CMP_OP_MAP_S op_class = Lira.const_get(op_map[name]) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? target_width = [a.width, b.width].max a = ADLToLiraUtils.ensure_width(a, target_width, @builder) @@ -65,31 +65,45 @@ def process_read_reg(oprnds) reg_var = oprnds[1] idx = @operand_names.index(reg_var.name.to_s) if idx - input_val = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) - @vars[oprnds[0]] = input_val - input_val - else + reg_num = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) rf_name = reg_var.regset.to_s rf = find_register_file(rf_name) if rf.nil? warn "Register file '#{rf_name}' not found, skipping statement" return nil end - out = @builder.seq.new_temp(32) - reg = reg_var.name.to_s - @builder.read(rf, reg) + out = @builder.read(rf, reg_num) @vars[oprnds[0]] = out out + else + # Special Registers (PC) + val = ADLToLiraUtils.resolve_operand(reg_var, @builder, @vars, @operand_names, @arch_builder) + @vars[oprnds[0]] = val if val + val end end def process_write_reg(oprnds) reg_var = oprnds[0] - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if val.nil? idx = @operand_names.index(reg_var.name.to_s) if idx - @builder.output(val, idx) + reg_num = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) + rf_name = reg_var.regset.to_s + rf = find_register_file(rf_name) + if rf.nil? + warn "Register file '#{rf_name}' not found, skipping statement" + return nil + end + @builder.write(rf, reg_num, val) + elsif ADLToLiraUtils::SPECIAL_REGS.include?(reg_var.name.to_s) + ef = ADLToLiraUtils.find_env_func(@arch_builder, "setPC", [32], []) + if ef.nil? + warn "Environment function 'setPC' not registered, skipping statement" + return nil + end + @builder.env(ef, [val]) else rf_name = reg_var.regset.to_s rf = find_register_file(rf_name) @@ -97,16 +111,14 @@ def process_write_reg(oprnds) warn "Register file '#{rf_name}' not found, skipping statement" return nil end - reg = reg_var.name.to_s - @builder.write(rf, reg, val) + @builder.write(rf, reg_var.name.to_s, val) end nil end def process_read_mem(oprnds) out_type = ADLToLiraUtils.convert_type(oprnds[0].type) - out = @builder.seq.new_temp(out_type) - addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if addr.nil? addr_width = addr.width ef = ADLToLiraUtils.find_env_func(@arch_builder, "readMem", [addr_width], [out_type]) @@ -114,14 +126,15 @@ def process_read_mem(oprnds) warn "Environment function 'readMem' with inputs [#{addr_width}] and outputs [#{out_type}] not registered, skipping statement" return nil end - @builder.env(ef, [addr]) + outs = @builder.env(ef, [addr]) + out = outs[0] @vars[oprnds[0]] = out out end def process_write_mem(oprnds) - addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if addr.nil? || val.nil? addr_width = addr.width ef = ADLToLiraUtils.find_env_func(@arch_builder, "writeMem", [addr_width, val.width], []) @@ -134,14 +147,13 @@ def process_write_mem(oprnds) end def process_extract(oprnds) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if val.nil? hi = oprnds[2].value lo = oprnds[3].value width = hi - lo + 1 width = 1 if width < 1 - out = @builder.seq.new_temp(width) - @builder.extract(val, @builder.const(lo, 32), width) + out = @builder.extract(val, @builder.const(lo, 32), width) @vars[oprnds[0]] = out out end @@ -150,16 +162,15 @@ def process_cast_zext(name, oprnds) dest_type = oprnds[0].type dest_width = ADLToLiraUtils.convert_type(dest_type) dest_width = 1 if dest_width < 1 - src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) + src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if src.nil? if src.width == dest_width out = src else - out = @builder.seq.new_temp(dest_width) if name == :zext || dest_type.to_s.start_with?('u') - @builder.extend_zero(src, dest_width) + out = @builder.extend_zero(src, dest_width) else - @builder.extend_sign(src, dest_width) + out = @builder.extend_sign(src, dest_width) end end @vars[oprnds[0]] = out @@ -167,8 +178,8 @@ def process_cast_zext(name, oprnds) end def process_rem(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? unsigned = oprnds[1].type.to_s.start_with?('u') out = unsigned ? @builder.rem_u(a, b) : @builder.rem_s(a, b) @@ -177,8 +188,8 @@ def process_rem(oprnds) end def process_div(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? unsigned = oprnds[1].type.to_s.start_with?('u') default = @builder.const(0, 32) @@ -201,7 +212,7 @@ def stmt_to_lira(stmt) when :let lhs, rhs = oprnds - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, @operand_names, @arch_builder) @vars[lhs] = rhs_val if rhs_val when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr @@ -213,9 +224,9 @@ def stmt_to_lira(stmt) @vars[oprnds[0]] = out if out when :select - cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars) - t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars) - f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @vars) + cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) + f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @vars, @operand_names, @arch_builder) return if cond.nil? || t.nil? || f.nil? cond = ADLToLiraUtils.ensure_width(cond, 1, @builder) out = @builder.select(cond, t, f) @@ -240,11 +251,11 @@ def stmt_to_lira(stmt) process_write_mem(oprnds) when :branch - target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars) + target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) return if target.nil? - ef = ADLToLiraUtils.find_env_func(@arch_builder, "pc_write", [32], []) + ef = ADLToLiraUtils.find_env_func(@arch_builder, "setPC", [32], []) if ef.nil? - warn "Environment function 'pc_write' not registered, skipping statement" + warn "Environment function 'setPC' not registered, skipping statement" return end @builder.env(ef, [target]) @@ -273,9 +284,10 @@ def generate_semantic(instr) @builder = Lira::InstructionBuilder.new( instr.name.to_s, [], [], - Lira::InstructionEncoding.new(32, 0, [], '', '', '') + Lira::InstructionEncoding.new(32, 0, 0, [], '', '', '') ) @vars = {} + @operand_names = collect_operand_names(instr) instr.code.tree.each do |stmt| stmt_to_lira(stmt) end @@ -306,11 +318,10 @@ def generate_decode_snippets(instr, operand_vars) field_name = rhs.name.to_s[2..-1] field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } if field - lo = field.from - hi = field.to - width = hi - lo + 1 - width = 1 if width < 1 - shifted = @builder.lsr(enc, @builder.const(lo, 32)) + low_bit = field.to + high_bit = field.from + width = high_bit - low_bit + 1 + shifted = @builder.lsr(enc, @builder.const(low_bit, 32)) val = @builder.extract_low(shifted, width) if ADLToLiraUtils.convert_type(lhs.type) != width if lhs.type.to_s.start_with?('s') @@ -321,16 +332,55 @@ def generate_decode_snippets(instr, operand_vars) end @vars[lhs] = val else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) @vars[lhs] = rhs_val if rhs_val end else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars) + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) @vars[lhs] = rhs_val if rhs_val end when :cast, :zext - process_cast_zext(name, oprnds) + lhs, rhs = oprnds + src = @vars[rhs] + if src + dest_type = lhs.type + dest_width = ADLToLiraUtils.convert_type(dest_type) + dest_width = 1 if dest_width < 1 + if src.width == dest_width + val = src + else + if name == :zext || dest_type.to_s.start_with?('u') + val = @builder.extend_zero(src, dest_width) + else + val = @builder.extend_sign(src, dest_width) + end + end + @vars[lhs] = val + elsif rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') + field_name = rhs.name.to_s[2..-1] + field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + if field + low_bit = field.to + high_bit = field.from + width = high_bit - low_bit + 1 + shifted = @builder.lsr(enc, @builder.const(low_bit, 32)) + val = @builder.extract_low(shifted, width) + if ADLToLiraUtils.convert_type(lhs.type) != width + if lhs.type.to_s.start_with?('s') + val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) + else + val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) + end + end + @vars[lhs] = val + else + warn "Field #{field_name} not found" + end + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) + @vars[lhs] = rhs_val if rhs_val + end when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr out = process_binary_op(name, oprnds) @@ -341,13 +391,13 @@ def generate_decode_snippets(instr, operand_vars) @vars[oprnds[0]] = out if out else - # Ignore other statements in decode snippet + # Ignore other statements in decode snippet end end operand_vars.each_with_index do |var, idx| val = @vars[var] - @builder.output(val, idx) + @builder.output(val || @builder.const(0, 32), idx) end snippet = @builder.build @@ -366,6 +416,7 @@ def generate_decode_snippets(instr, operand_vars) decode_snippet_names end + # NOTE: Temporary disabled # def generate_encode_snippet(instr, operand_vars) # @builder = Lira::SnippetBuilder.new("temp_encode") @@ -448,14 +499,21 @@ def convert_instruction(instr) # end const_part = 0 + const_mask = 0 instr.fields.each do |field| value_num = field.value.value - const_part |= (value_num << field.from) if value_num + low_bit = field.to + high_bit = field.from + width = high_bit - low_bit + 1 + if value_num + const_part |= (value_num << low_bit) + const_mask |= (((1 << width) - 1) << low_bit) + end end operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } - encoding = Lira::InstructionEncoding.new(32, const_part, decode_snippets, encode_snippet || '', '', '') + encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, encode_snippet || '', '', '') Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) end @@ -480,15 +538,14 @@ def build_arch @arch_builder.add_env_func(lira_ef) end - unless @arch_builder.environment_functions.any? { |ef| ef.name == "pc_read" } - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("pc_read", [], [], [32])) + unless @arch_builder.environment_functions.any? { |ef| ef.name == "getPC" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("getPC", [], [], [32])) end - unless @arch_builder.environment_functions.any? { |ef| ef.name == "pc_write" } - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("pc_write", [], [32], [])) + unless @arch_builder.environment_functions.any? { |ef| ef.name == "setPC" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("setPC", [], [32], [])) end SimInfra.class_variable_get(:@@instructions).each do |instr| - next if instr.name == :fence || instr.name == :ebreak begin lira_instr = convert_instruction(instr) @arch_builder.add_instruction(lira_instr) From 02e3a46c2c6ff65890d127bb10d7190235704338 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 9 Jun 2026 18:28:33 +0300 Subject: [PATCH 29/75] [sim-gen] Introduced LIRA-Driven Sim Gen --- sim_gen_lira/CMakeLists.txt | 49 +++ sim_gen_lira/CPUState/cpu_state.rb | 311 ++++++++++++++++++ sim_gen_lira/Decoders/decoder.rb | 72 ++++ sim_gen_lira/ExecEngines/base_exec_engine.rb | 59 ++++ sim_gen_lira/ExecEngines/naive_interpreter.rb | 116 +++++++ sim_gen_lira/Hart/hart.rb | 113 +++++++ sim_gen_lira/ISA/isa.rb | 155 +++++++++ sim_gen_lira/Utility/sim_utility.rb | 24 ++ sim_gen_lira/cpp_gen.rb | 262 +++++++++++++++ sim_gen_lira/sim_gen.rb | 70 ++++ 10 files changed, 1231 insertions(+) create mode 100644 sim_gen_lira/CMakeLists.txt create mode 100644 sim_gen_lira/CPUState/cpu_state.rb create mode 100644 sim_gen_lira/Decoders/decoder.rb create mode 100644 sim_gen_lira/ExecEngines/base_exec_engine.rb create mode 100644 sim_gen_lira/ExecEngines/naive_interpreter.rb create mode 100644 sim_gen_lira/Hart/hart.rb create mode 100644 sim_gen_lira/ISA/isa.rb create mode 100644 sim_gen_lira/Utility/sim_utility.rb create mode 100644 sim_gen_lira/cpp_gen.rb create mode 100644 sim_gen_lira/sim_gen.rb diff --git a/sim_gen_lira/CMakeLists.txt b/sim_gen_lira/CMakeLists.txt new file mode 100644 index 0000000..58d0884 --- /dev/null +++ b/sim_gen_lira/CMakeLists.txt @@ -0,0 +1,49 @@ +project(protea_simgen) + +set(PROTEA_SIMGEN_OUTPUT_HEADERS + cpu_state.hh + base_exec_engine.hh + naive_interpreter.hh + ${CMAKE_SOURCE_DIR}/prot_std/std_ops.h + decoder.hh + isa.hh + hart.hh +) + +set(PROTEA_SIMGEN_OUTPUT_SOURCES + base_exec_engine.cc + naive_interpreter.cc + cpu_state.cc + decoder.cc + hart.cc +) + +set(PROTEA_SIMGEN_OUTPUT_FILES + ${PROTEA_SIMGEN_OUTPUT_HEADERS} + ${PROTEA_SIMGEN_OUTPUT_SOURCES} +) + +set(IR_YAML_FILE ${CMAKE_SOURCE_DIR}/lira.yaml) + + +add_custom_command(DEPENDS + OUTPUT ${PROTEA_SIMGEN_OUTPUT_FILES} + COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${IR_YAML_FILE} + DEPENDS protea_irgen + COMMENT "Running ${PROJECT_NAME}" +) +add_custom_target(${PROJECT_NAME} ALL DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) +add_dependencies(${PROJECT_NAME} protea_irgen) + +add_executable(sim ${PROTEA_SIMGEN_OUTPUT_SOURCES} + ${protea_simlib_SOURCE_DIR}/elf_loader.cc + ${protea_simlib_SOURCE_DIR}/base_jit.cc + ${protea_simlib_SOURCE_DIR}/sim.cc + ${protea_simlib_SOURCE_DIR}/jit_factory.cc + ${protea_simlib_SOURCE_DIR}/memory.cc + ${protea_simlib_SOURCE_DIR}/Target/${TARGET_NAME}/cpu_state_ext.cc) + +target_include_directories(sim PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${protea_simlib_SOURCE_DIR}) +target_link_libraries(sim elfio CLI11 fmt) +target_compile_features(sim PRIVATE cxx_std_23) +install(TARGETS sim) diff --git a/sim_gen_lira/CPUState/cpu_state.rb b/sim_gen_lira/CPUState/cpu_state.rb new file mode 100644 index 0000000..922d7e5 --- /dev/null +++ b/sim_gen_lira/CPUState/cpu_state.rb @@ -0,0 +1,311 @@ +# frozen_string_literal: true + +require 'lib/Utility/gen_emitter' +require 'Utility/helper_cpp' + +# SimGen - simulation code generator +module SimGen + # SimGen::CPUState - methods for CPUState header generation + module CPUState + # Helper methods for CPUState generation + module Helper + module_function + + def increase_icount_func + emitter = Utility::GenEmitter.new + emitter.emit_line('// Function to increase instruction count') + emitter.emit_line('void increaseICount() {') + emitter.increase_indent + emitter.emit_line('++m_icount;') + emitter.decrease_indent + emitter.emit_line('}') + emitter.increase_indent_all(2) + emitter + end + + def find_pc_reg(regfiles) + regfiles.each do |regfile| + regfile[:regs].each do |reg| + return reg if reg[:attrs].include? :pc + end + end + raise 'PC register not found in the register files' + end + + def generate_pc_decl(regfiles) + emitter = Utility::GenEmitter.new + pc_reg = find_pc_reg(regfiles) + emitter.emit_line('// Program Counter') + emitter.emit_line("#{Utility::HelperCpp.gen_type(pc_reg[:size])} m_pc;") + emitter.emit_blank_line + emitter.increase_indent_all(2) + emitter + end + + def generate_pc_functions(regfiles) + emitter = Utility::GenEmitter.new + pc_reg = find_pc_reg(regfiles) + emitter.emit_line('// Set PC function') + emitter.emit_line("void setPC(const #{Utility::HelperCpp.gen_type(pc_reg[:size])} value) {") + emitter.increase_indent + emitter.emit_line('m_pc = value;') + emitter.decrease_indent + emitter.emit_line('}') + emitter.emit_blank_line + emitter.emit_line('// Read PC function') + emitter.emit_line("#{Utility::HelperCpp.gen_type(pc_reg[:size])} getPC() const {") + emitter.increase_indent + emitter.emit_line('return m_pc;') + emitter.decrease_indent + emitter.emit_line('}') + emitter.emit_blank_line + emitter.increase_indent_all(2) + emitter + end + + def generate_cpu_regsets(regfiles) + emitter = Utility::GenEmitter.new + regfiles.each do |regfile| + regfile_size = regfile[:regs].size - regfile[:regs].count { |reg| reg[:attrs].include? :pc } + emitter.emit_line("// Register file: #{regfile[:name]}") + regsize = regfile[:regs][0][:size] + array_str = "std::array<#{Utility::HelperCpp.gen_type(regsize)}, #{regfile_size}> m_#{regfile[:name]}{};" + emitter.emit_line(array_str) + emitter.emit_blank_line + end + emitter.increase_indent_all(2) + emitter + end + + def generate_if_zero_reg_check(emitter, regfile) + regfile[:regs].each_with_index do |reg, reg_index| + if reg[:attrs].include? :zero + emitter.emit_line("if (reg == #{reg_index}) return; // #{reg[:name]} is zero register") + end + end + end + + def generate_set_reg_functions(regfiles) + emitter = Utility::GenEmitter.new + regfiles.each do |regfile| + emitter.emit_line("// Set register function for #{regfile[:name]}") + emitter.emit_line('template') + emitter.emit_line("void set#{regfile[:name]}(const std::size_t reg, const T value) {") + emitter.increase_indent + generate_if_zero_reg_check(emitter, regfile) + emitter.emit_line("m_#{regfile[:name]}[reg] = value;") + emitter.decrease_indent + emitter.emit_line('}') + emitter.emit_blank_line + end + emitter.increase_indent_all(2) + emitter + end + + def generate_read_reg_functions(regfiles) + emitter = Utility::GenEmitter.new + regfiles.each do |regfile| + emitter.emit_line("// Read register function for #{regfile[:name]}") + emitter.emit_line('template') + emitter.emit_line("T get#{regfile[:name]}(const std::size_t reg) const {") + emitter.increase_indent + emitter.emit_line("return static_cast(m_#{regfile[:name]}[reg]);") + emitter.decrease_indent + emitter.emit_line('}') + emitter.emit_blank_line + end + emitter.increase_indent_all(2) + emitter + end + + def generate_do_exit_func + emitter = Utility::GenEmitter.new + emitter.emit_line('// Function to stop the CPU execution') + emitter.emit_line('void doExit(isa::Word code) {') + emitter.increase_indent + emitter.emit_line('m_finished = true;') + emitter.emit_line('m_code = code;') + emitter.emit_line("fmt::println(\"Exiting with code {}...\", code);") + emitter.decrease_indent + emitter.emit_line('}') + emitter.increase_indent_all(2) + emitter + end + + def gen_input_args(args) + args.map do |arg| + case arg + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + when 64 then "uint64_t" + else Utility::HelperCpp.gen_type(arg) + end + end.join(', ') + end + + def generate_interface_func(interface_functions) + emitter = Utility::GenEmitter.new + emitter.emit_line('// Interface functions') + interface_functions.each do |ifunc| + # ะ”ะปั ะฒะพะทะฒั€ะฐั‰ะฐะตะผั‹ั… ั‚ะธะฟะพะฒ ั‚ะพะถะต ัะพะฟะพัั‚ะฐะฒะปัะตะผ + ret_types = ifunc[:return_types].map do |t| + case t + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + when 64 then "uint64_t" + else Utility::HelperCpp.gen_type(t) + end + end + + arg_types = ifunc[:argument_types].map do |t| + case t + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + when 64 then "uint64_t" + else Utility::HelperCpp.gen_type(t) + end + end + + if ret_types.empty? + emitter.emit_line("void #{ifunc[:name]}(#{arg_types.join(', ')});") + elsif ret_types.size == 1 + emitter.emit_line("#{ret_types[0]} #{ifunc[:name]}(#{arg_types.join(', ')});") + else + emitter.emit_line("std::tuple<#{ret_types.join(', ')}> #{ifunc[:name]}(#{arg_types.join(', ')});") + end + end + emitter.emit_blank_line + emitter.increase_indent_all(2) + emitter + end + end + end +end + +# SimGen - simulation code generator +module SimGen + # SimGen::CPUState - methods for CPUState header generation + module CPUState + module Header + module_function + + def generate_cpu_state(input_ir) + pc_decl = Helper.generate_pc_decl(input_ir[:regfiles]) + pc_functions = Helper.generate_pc_functions(input_ir[:regfiles]) + regsets_decl = Helper.generate_cpu_regsets(input_ir[:regfiles]) + setreg_funcs = Helper.generate_set_reg_functions(input_ir[:regfiles]) + readreg_funcs = Helper.generate_read_reg_functions(input_ir[:regfiles]) + do_exit_func = Helper.generate_do_exit_func + increase_icount_func = Helper.increase_icount_func + interface_func = Helper.generate_interface_func(input_ir[:interface_functions]) + + base_type = Utility::HelperCpp.gen_type input_ir[:regfiles][0][:regs][0][:size] +"#ifndef GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED +#define GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED + +#include \"memory.hh\" + +#include +#include +#include +#include +#include + +namespace prot::memory { +class Memory; +} // prot::memory + +namespace prot::state { +using namespace prot::memory; + +class CPU final { +public: +#{regsets_decl} +#{pc_decl} + // Instruction count + std::size_t m_icount{0}; + + // Pointer to memory + Memory *m_memory{nullptr}; + + // Finished flag + bool m_finished{false}; + + // Exit code + isa::Word m_code{0}; + + explicit CPU(Memory *mem) : m_memory(mem) {} + +#{setreg_funcs} +#{readreg_funcs} +#{pc_functions} +#{interface_func} +#{do_exit_func} + +#{increase_icount_func} +}; + +} // prot::state + +#endif // GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED +" + end + end + + module TranslationUnit + module_function + + def generate_cpu_state(input_ir) + interface_functions = input_ir[:interface_functions] + implementations = [] + + interface_functions.each do |ifunc| + name = ifunc[:name] + + if name =~ /^readMem(\d+)$/ + width = $1.to_i + ret_type = case width + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + else "uint#{width}_t" + end + implementations << <<~CPP + #{ret_type} CPU::#{name}(uint32_t addr) { + return m_memory->read<#{ret_type}>(addr); + } + CPP + elsif name =~ /^writeMem(\d+)$/ + width = $1.to_i + val_type = case width + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + else "uint#{width}_t" + end + implementations << <<~CPP + void CPU::#{name}(uint32_t addr, #{val_type} value) { + m_memory->write<#{val_type}>(addr, value); + } + CPP + end + end + + <<~CPP + #include "cpu_state.hh" + #include "memory.hh" + #include + + namespace prot::state { + + #{implementations.join("\n")} + + } // namespace prot::state + CPP + end + end + end +end diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb new file mode 100644 index 0000000..3625d9d --- /dev/null +++ b/sim_gen_lira/Decoders/decoder.rb @@ -0,0 +1,72 @@ +require_relative '../cpp_gen' + +module SimGen + module Decoder + module Header + module_function + + def generate_decoder(ir_hash) + <<~CPP + #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_DECODER_HH_INCLUDED + #define GENERATED_#{ir_hash[:isa_name].upcase}_DECODER_HH_INCLUDED + + #include "isa.hh" + #include + + using namespace prot::isa; + + namespace prot::decoder { + std::optional decode(const uint32_t raw_insn); + } + + #endif + CPP + end + end + + module TranslationUnit + module_function + + def generate_decoder(ir_hash) + instructions = ir_hash[:instructions] + snippets = ir_hash[:snippets].to_h { |s| [s[:name], s[:seq]] } + + body = [] + instructions.each do |insn| + next if insn[:encoding][:decode_snippets].empty? + mask = insn[:encoding][:const_mask] + const = insn[:encoding][:const_part] + snippet_name = insn[:encoding][:decode_snippets].first + seq = snippets[snippet_name] + next unless seq + + translator = LiraCppGen::Translator.new(seq, :decode, 2) + snippet_code = translator.translate + + body << <<~CPP + if ((raw_insn & #{mask}) == #{const}) { + #{snippet_code} + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } + CPP + end + + decoder_impl = body.join("\n") + <<~CPP + #include "decoder.hh" + #include "std_ops.h" + #include + + namespace prot::decoder { + std::optional decode(isa::Word raw_insn) { + Instruction insn{}; + #{decoder_impl} + return std::nullopt; + } + } + CPP + end + end + end +end diff --git a/sim_gen_lira/ExecEngines/base_exec_engine.rb b/sim_gen_lira/ExecEngines/base_exec_engine.rb new file mode 100644 index 0000000..dc27c27 --- /dev/null +++ b/sim_gen_lira/ExecEngines/base_exec_engine.rb @@ -0,0 +1,59 @@ +require "sim_gen/Utility/sim_utility" + +module SimGen + module BaseExecEngine + module Header + module_function + + def generate_base_exec_engine(input_ir) +"#ifndef GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED +#define GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED + +#include \"cpu_state.hh\" +#include \"isa.hh\" +#include \"memory.hh\" + +namespace prot::engine { +using namespace prot::state; +using namespace prot::isa; + +struct ExecEngine { + virtual ~ExecEngine() = default; + + virtual void execute(CPU &cpu, const Instruction &insn) = 0; + virtual void step(CPU &cpu); +}; +} // namespace prot::engine + +#endif // GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED +" + end + end + + module TranslationUnit + module_function + + def generate_base_exec_engine(input_ir) + max_xlen = SimGen::Helper::find_max_regsize(input_ir[:regfiles]) + +"#include \"base_exec_engine.hh\" +#include \"memory.hh\" +#include \"decoder.hh\" + +namespace prot::engine { +using namespace prot::state; +using namespace prot::isa; + +void ExecEngine::step(CPU &cpu) { + const auto bytes = cpu.m_memory->read(cpu.getPC()); + auto instr_opt = decoder::decode(bytes); + if (instr_opt) { + execute(cpu, *instr_opt); + cpu.increaseICount(); + } +} +} // namespace prot::engine +" end + end + end +end diff --git a/sim_gen_lira/ExecEngines/naive_interpreter.rb b/sim_gen_lira/ExecEngines/naive_interpreter.rb new file mode 100644 index 0000000..60db4c4 --- /dev/null +++ b/sim_gen_lira/ExecEngines/naive_interpreter.rb @@ -0,0 +1,116 @@ +require_relative '../cpp_gen' + +module SimGen + module NaiveInterpreter + module Header + module_function + + def generate_naive_interpreter(ir_hash) + <<~CPP + #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED + #define GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED + + #include "base_exec_engine.hh" + + namespace prot::engine { + class Interpreter : public ExecEngine { + public: + void execute(CPU &cpu, const Instruction &insn) override; + }; + } + + #endif + CPP + end + end + + module TranslationUnit + module_function + + def generate_naive_interpreter(ir_hash) + exec_functions = [] + branch_insns = [] + + ir_hash[:instructions].each do |insn| + name = insn[:name].to_s.upcase + seq = insn[:semantic_seq] + next unless seq && seq.stmts.any? + + translator = LiraCppGen::Translator.new(seq, :execute, 2) + body = translator.translate + exec_functions << <<~CPP + void do#{name}(CPU &cpu, const Instruction &insn) { + #{body} + } + CPP + + if seq.stmts.any? { |s| s.kind == 'env' && s.specifier == 'setPC' } + branch_insns << "case Opcode::k#{name}: return true;" + end + end + + is_branch = <<~CPP + bool isBranchInstruction(const Instruction &insn) { + switch (insn.m_opc) { + #{branch_insns.join("\n")} + default: return false; + } + } + CPP + + handlers_init = ir_hash[:instructions].map do |insn| + "m_handlers[toUnderlying(Opcode::k#{insn[:name].to_s.upcase})] = &do#{insn[:name].to_s.upcase};" + end.join("\n ") + + <<~CPP + #include "naive_interpreter.hh" + #include "std_ops.h" + #include + #include + + namespace prot::engine { + using namespace prot::state; + using namespace prot::isa; + + namespace { + #{is_branch} + #{exec_functions.join("\n\n")} + + template + constexpr auto toUnderlying(T val) requires std::is_enum_v { + return static_cast>(val); + } + + class ExecHandlersMap { + public: + using ExecHandler = void (*)(CPU &cpu, const Instruction &insn); + private: + std::array m_handlers{}; + public: + constexpr ExecHandlersMap() { + #{handlers_init} + } + ExecHandler get(Opcode opcode) const { + auto idx = toUnderlying(opcode); + if (idx >= m_handlers.size()) return nullptr; + auto h = m_handlers[idx]; + return h; + } + }; + constexpr ExecHandlersMap kExecHandlers{}; + } + + void Interpreter::execute(CPU &cpu, const Instruction &insn) { + auto handler = kExecHandlers.get(insn.m_opc); + if (!handler) return; + auto oldPC = cpu.getPC(); + handler(cpu, insn); + if (!isBranchInstruction(insn)) + cpu.setPC(oldPC + getILen(insn.m_opc)); + } + } + CPP + end + end + end +end diff --git a/sim_gen_lira/Hart/hart.rb b/sim_gen_lira/Hart/hart.rb new file mode 100644 index 0000000..a917f03 --- /dev/null +++ b/sim_gen_lira/Hart/hart.rb @@ -0,0 +1,113 @@ +module SimGen + module Hart + module Header + module_function + + def get_addr_type(instructions) + instructions.each do |insn| + seq = insn[:semantic_seq] + next unless seq && seq.stmts + seq.stmts.each do |stmt| + if stmt.kind == 'env' && (stmt.specifier == 'writeMem' || stmt.specifier == 'readMem') + return 32 + end + end + end + 32 + end + + def generate_hart(ir_hash) + type = get_addr_type(ir_hash[:instructions]) + type_str = Utility::HelperCpp.gen_type(type) + + <<~CPP + #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_HART_HH_INCLUDED + #define GENERATED_#{ir_hash[:isa_name].upcase}_HART_HH_INCLUDED + + #include + + #include "cpu_state.hh" + #include "elf_loader.hh" + #include "base_exec_engine.hh" + #include "memory.hh" + + namespace prot::hart { + using namespace prot::state; + using namespace prot::isa; + using namespace prot::elf_loader; + using namespace prot::engine; + using namespace prot::memory; + + class Hart { + public: + Hart(std::unique_ptr mem, std::unique_ptr engine); + + void setSP(#{type_str} addr); + CPU* getCPU() { return m_cpu.get(); } + + void load(const ElfLoader &loader); + + void setPC(#{type_str} addr); + + void run() { + while (!m_cpu->m_finished) { + m_engine->step(*m_cpu); + } + } + + auto getIcount() const { return m_cpu->m_icount; } + auto getExitCode() const { return m_cpu->m_code; } + + private: + std::unique_ptr m_mem; + std::unique_ptr m_cpu; + std::unique_ptr m_engine; + }; + } + + #endif + CPP + end + end + + module TranslationUnit + module_function + + def get_addr_type(instructions) + instructions.each do |insn| + seq = insn[:semantic_seq] + next unless seq && seq.stmts + seq.stmts.each do |stmt| + if stmt.kind == 'env' && (stmt.specifier == 'writeMem' || stmt.specifier == 'readMem') + return 32 + end + end + end + 32 + end + + def generate_hart(ir_hash) + type = get_addr_type(ir_hash[:instructions]) + type_str = Utility::HelperCpp.gen_type(type) + + <<~CPP + #include "hart.hh" + + namespace prot::hart { + Hart::Hart(std::unique_ptr mem, std::unique_ptr engine) + : m_mem(std::move(mem)), m_cpu(std::make_unique(m_mem.get())), + m_engine(std::move(engine)) {} + + void Hart::load(const ElfLoader &loader) { + loader.loadMemory(*m_mem); + setPC(loader.getEntryPoint()); + } + + void Hart::setSP(#{type_str} addr) { m_cpu->setXRegs(2, addr); } + void Hart::setPC(#{type_str} addr) { m_cpu->setPC(addr); } + } + CPP + end + end + end +end diff --git a/sim_gen_lira/ISA/isa.rb b/sim_gen_lira/ISA/isa.rb new file mode 100644 index 0000000..6827f12 --- /dev/null +++ b/sim_gen_lira/ISA/isa.rb @@ -0,0 +1,155 @@ +module SimGen + module ISA + module Helper + module_function + + def find_max_regsize(regfiles) + max = 0 + regfiles.each do |rf| + rf[:regs].each do |reg| + max = reg[:size] if reg[:size] > max + end + end + max + end + + def find_max_operands(instructions) + max_operands = 0 + max_size = 0 + instructions.each do |insn| + size = insn[:operand_sizes].size + max_operands = size if size > max_operands + insn[:operand_sizes].each do |s| + max_size = s if s > max_size + end + end + [max_operands, max_size] + end + + def generate_fields_struct(max_operands, max_size) + emitter = Utility::GenEmitter.new + (0...max_operands).each do |i| + emitter.emit_line("uint#{max_size}_t operand#{i};") + end + emitter.increase_indent_all(2) + emitter + end + + def generate_instruction_struct(instructions) + max_operands, max_size = find_max_operands(instructions) + fields_struct = generate_fields_struct(max_operands, max_size) + <<~CPP + struct Instruction { + Opcode m_opc; + #{fields_struct.to_s} + }; + CPP + end + + def is_terminator_instruction(insn) + seq = insn[:semantic_seq] + return false unless seq && seq.stmts + seq.stmts.any? do |stmt| + stmt.kind == 'env' && (stmt.specifier == 'setPC' || stmt.specifier == 'sysCall') + end + end + + def generate_is_terminator_function(instructions) + emitter = Utility::GenEmitter.new + emitter.emit_line("inline constexpr bool isTerminator(Opcode opc) {") + emitter.increase_indent + emitter.emit_line("switch (opc) {") + emitter.increase_indent + instructions.each do |insn| + if is_terminator_instruction(insn) + emitter.emit_line("case Opcode::k#{insn[:name].to_s.upcase}: return true;") + end + end + emitter.emit_line("default: return false;") + emitter.decrease_indent + emitter.emit_line("}") + emitter.decrease_indent + emitter.emit_line("}") + emitter + end + + # ะŸะพะปัƒั‡ะฐะตั‚ ั‚ะธะฟ ะฐะดั€ะตัะฐ ะธะท ะธะฝัั‚ั€ัƒะบั†ะธะน (ะฟะพ ะฟะตั€ะฒะพะผัƒ ะพะฟะตั€ะฐะฝะดัƒ readMem/writeMem) + def get_addr_type_from_instructions(instructions) + instructions.each do |insn| + seq = insn[:semantic_seq] + next unless seq && seq.stmts + seq.stmts.each do |stmt| + if stmt.kind == 'env' && (stmt.specifier == 'readMem' || stmt.specifier == 'writeMem') + # ะŸะตั€ะฒั‹ะน ะฒั…ะพะด โ€” ะฐะดั€ะตั, ะตะณะพ ั‚ะธะฟ + addr_input = stmt.inputs[0] + # ะฃะทะฝะฐั‚ัŒ ัˆะธั€ะธะฝัƒ ะฟะพ ะฟะตั€ะตะผะตะฝะฝะพะน (ะผะพะถะฝะพ ะธะท @var_widths, ะฝะพ ะทะดะตััŒ ะฝะตั‚ ะบะพะฝั‚ะตะบัั‚ะฐ) + # ะ—ะฐะณะปัƒัˆะบะฐ: ะฒะตั€ะฝั‘ะผ 32, ั‚ะฐะบ ะบะฐะบ ะฒ RISC-V ะฐะดั€ะตั 32-ะฑะธั‚ะฝั‹ะน + return 32 + end + end + end + 32 # fallback + end + end + + module Header + module_function + + def generate_isa_header(ir_hash) + isa_name = ir_hash[:isa_name] + regfiles = ir_hash[:regfiles] + instructions = ir_hash[:instructions] + + max_xlen = Helper.find_max_regsize(regfiles) + addr_width = Helper.get_addr_type_from_instructions(instructions) + addr_type = case addr_width + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + when 64 then "uint64_t" + else "uint32_t" + end + + opcode_enum = instructions.map { |insn| " k#{insn[:name].to_s.upcase}," }.join("\n") + instruction_struct = Helper.generate_instruction_struct(instructions) + is_terminator_function = Helper.generate_is_terminator_function(instructions) + + get_ilen_lines = instructions.map do |insn| + enc_size = insn[:encoding][:encoded_size] || 32 # ะทะฐั‰ะธั‚ะฐ ะพั‚ nil + len = enc_size / 8 + "case Opcode::k#{insn[:name].to_s.upcase}: return #{len};" + end.join("\n ") + + <<~CPP + #ifndef GENERATED_#{isa_name.upcase}_ISA_HH_INCLUDED + #define GENERATED_#{isa_name.upcase}_ISA_HH_INCLUDED + + #include + + namespace prot::isa { + using Addr = #{addr_type}; + using Word = uint#{max_xlen}_t; + + enum class Opcode : uint32_t { + #{opcode_enum} + }; + + #{instruction_struct} + + #{is_terminator_function.to_s} + + inline constexpr std::size_t getILen(Opcode opc) { + switch (opc) { + #{get_ilen_lines} + default: return 4; + } + } + + } // namespace prot::isa + + #endif // GENERATED_#{isa_name.upcase}_ISA_HH_INCLUDED + CPP + end + end + end +end diff --git a/sim_gen_lira/Utility/sim_utility.rb b/sim_gen_lira/Utility/sim_utility.rb new file mode 100644 index 0000000..39e7276 --- /dev/null +++ b/sim_gen_lira/Utility/sim_utility.rb @@ -0,0 +1,24 @@ +module SimGen + module Helper + module_function + + def find_max_regsize(regfiles) + max_xlen = 0 + regfiles.each do |regfile| + regfile[:regs].each do |reg| + max_xlen = [max_xlen, reg[:size]].max + end + end + max_xlen + end + + def find_max_insn_len(instructions) + max_len = 0 + instructions.each do |insn| + len_insn = insn[:fields].map { |f| f[:from] - f[:to] + 1 }.sum + max_len = [max_len, len_insn].max + end + max_len + end + end +end diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb new file mode 100644 index 0000000..70a7a35 --- /dev/null +++ b/sim_gen_lira/cpp_gen.rb @@ -0,0 +1,262 @@ +require_relative '../lib/lira/ir' + +module LiraCppGen + class Translator + def initialize(seq, context = :execute, indent = 0) + @seq = seq + @context = context + @indent = indent + @output = [] + @var_widths = {} + end + + def translate + @seq.stmts.each { |stmt| translate_stmt(stmt) } + @output.join("\n") + end + + private + + def resolve_var(name, stmt = nil) + return name if @var_widths.key?(name) + if name =~ /^_t\d+$/ + width = 32 + if stmt && stmt.respond_to?(:outputs_types) && stmt.outputs_types.any? + width = stmt.outputs_types[0] + end + emit("#{type_name(width)} #{name} = 0;") + @var_widths[name] = width + return name + end + raise "Unknown variable #{name} in #{stmt&.inspect}" + end + + def translate_stmt(stmt) + case stmt.kind + when 'op' then translate_op(stmt) + when 'const' then translate_const(stmt) + when 'dyn_const' then translate_dyn_const(stmt) + when 'read' then translate_read(stmt) + when 'write' then translate_write(stmt) + when 'env' then translate_env(stmt) + when 'cond_env' then translate_cond_env(stmt) + when 'input' then translate_input(stmt) + when 'output' then translate_output(stmt) + else raise "Unknown statement kind: #{stmt.kind}" + end + end + + def translate_op(stmt) + op_full = stmt.specifier + out = stmt.outputs[0] + out_width = stmt.outputs_types[0] + inputs = stmt.inputs.map { |i| resolve_var(i, stmt) } + + unless @var_widths.key?(out) + emit("#{type_name(out_width)} #{out};") + @var_widths[out] = out_width + end + + base_op = op_full.sub(/_\d+$/, '') + + if ['div_u', 'div_s', 'divs', 'divu'].include?(base_op) + func = base_op == 'divs' ? 'div_s' : (base_op == 'divu' ? 'div_u' : base_op) + func = "#{func}_#{out_width}" + emit("#{out} = #{func}(#{inputs[0]}, #{inputs[1]}, #{inputs[2]});") + return + end + + case base_op + when 'select' + emit("#{out} = #{inputs[0]} ? #{inputs[1]} : #{inputs[2]};") + when 'extract_low' + emit("#{out} = extract_low_#{out_width}(#{inputs[0]});") + when 'extend_sign', 'extend_zero' + in_width = @var_widths[inputs[0]] || 1 + func = "#{base_op}_#{in_width}_#{out_width}" + emit("#{out} = #{func}(#{inputs[0]});") + else + if out_width == 1 && ['eq','ne','slt','sle','sgt','sge','ult','ule','ugt','uge'].include?(base_op) + a, b = inputs + func = "#{base_op}_32" + emit("#{out} = #{func}(#{a}, #{b});") + return + end + + func_name = base_op + if base_op == 'rem' + func_name = 'rem_s' + elsif base_op == 'rems' + func_name = 'rem_s' + elsif base_op == 'remu' + func_name = 'rem_u' + end + func = "#{func_name}_#{out_width}" + if inputs.size == 1 + emit("#{out} = #{func}(#{inputs[0]});") + elsif inputs.size == 2 + emit("#{out} = #{func}(#{inputs[0]}, #{inputs[1]});") + else + raise "Unsupported arity for #{base_op} (#{inputs.size} args)" + end + end + end + + def translate_const(stmt) + value = stmt.specifier + out = stmt.outputs[0] + width = stmt.outputs_types[0] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out} = #{value};") + @var_widths[out] = width + end + end + + def translate_dyn_const(stmt) + name = stmt.specifier + out = stmt.outputs[0] + width = stmt.outputs_types[0] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out} = #{name};") + @var_widths[out] = width + end + end + + def translate_read(stmt) + rf = stmt.specifier + idx = resolve_var(stmt.inputs[0], stmt) + out = stmt.outputs[0] + width = stmt.outputs_types[0] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out};") + @var_widths[out] = width + end + if @context == :execute + emit("#{out} = cpu.get#{rf}<#{type_name(width)}>(#{idx});") + else + emit("#{out} = 0; // read in decode") + end + end + + def translate_write(stmt) + rf = stmt.specifier + idx = resolve_var(stmt.inputs[0], stmt) + val = resolve_var(stmt.inputs[1], stmt) + if @context == :execute + emit("cpu.set#{rf}(#{idx}, #{val});") + end + end + + + def translate_env(stmt) + func = stmt.specifier + inputs = stmt.inputs.map { |i| resolve_var(i, stmt) } + outputs = stmt.outputs + out_types = stmt.outputs_types + + if func == 'readMem' && out_types.size == 1 + func = "readMem#{out_types[0]}" + elsif func == 'writeMem' && inputs.size == 2 + val_name = stmt.inputs[1] + width = @var_widths[val_name] || 32 + func = "writeMem#{width}" + end + + if @context == :execute + if outputs.empty? + emit("cpu.#{func}(#{inputs.join(', ')});") + else + if outputs.size == 1 + out = outputs[0] + width = out_types[0] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out};") + @var_widths[out] = width + end + emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") + else + outputs.each_with_index do |out, i| + width = out_types[i] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out};") + @var_widths[out] = width + end + end + emit("std::tie(#{outputs.join(', ')}) = cpu.#{func}(#{inputs.join(', ')});") + end + end + end + end + + def translate_cond_env(stmt) + cond = resolve_var(stmt.inputs[0], stmt) + inputs = stmt.inputs[1...-stmt.outputs.size].map { |i| resolve_var(i, stmt) } + on_false = stmt.inputs[-stmt.outputs.size..-1].map { |i| resolve_var(i, stmt) } + func = stmt.specifier + outputs = stmt.outputs + emit("if (#{cond}) {") + indent do + outputs.each_with_index do |out, i| + width = stmt.outputs_types[i] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out};") + @var_widths[out] = width + end + emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") + end + end + emit("} else {") + indent do + outputs.each_with_index do |out, i| + emit("#{out} = #{on_false[i]};") + end + end + emit("}") + end + + def translate_input(stmt) + idx = stmt.specifier.to_i + out = stmt.outputs[0] + width = stmt.outputs_types[0] + unless @var_widths.key?(out) + emit("#{type_name(width)} #{out};") + @var_widths[out] = width + end + if @context == :decode + emit("#{out} = raw_insn;") + else + emit("#{out} = insn.operand#{idx};") + end + end + + def translate_output(stmt) + val = resolve_var(stmt.inputs[0], stmt) + idx = stmt.specifier.to_i + emit("insn.operand#{idx} = #{val};") + end + + def type_name(width) + sizes = [1, 8, 16, 32, 64, 128] + rounded = sizes.find { |s| s >= width } || 128 + case rounded + when 1 then "bool" + when 8 then "uint8_t" + when 16 then "uint16_t" + when 32 then "uint32_t" + when 64 then "uint64_t" + when 128 then "unsigned __int128" + else "uint#{rounded}_t" + end + end + + def emit(line) + @output << (" " * @indent + line) + end + + def indent + @indent += 2 + yield + @indent -= 2 + end + end +end diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb new file mode 100644 index 0000000..6b97a88 --- /dev/null +++ b/sim_gen_lira/sim_gen.rb @@ -0,0 +1,70 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +$LOAD_PATH.unshift File.dirname(__FILE__) + +require_relative 'cpp_gen' +require_relative 'CPUState/cpu_state' +require_relative 'Decoders/decoder' +require_relative 'ISA/isa' +require_relative 'ExecEngines/naive_interpreter' +require_relative 'ExecEngines/base_exec_engine' +require_relative 'Hart/hart' +require_relative '../lib/lira/arch_ser_yaml' + +arch = Lira::ArchSerYaml.read_arch(ARGV[0]) + +ir_hash = { + isa_name: arch.name, + regfiles: arch.register_files.map do |rf| + { + name: rf.name, + regs: rf.regs.map.with_index do |r, idx| + { + name: r.name, + size: rf.reg_size.lanes_base, + attrs: r.attributes.map(&:to_sym) + } + end + } + end, + interface_functions: arch.environment_functions + .reject { |ef| ['setPC', 'getPC'].include?(ef.name) } + .map do |ef| + name = ef.name + if name == 'readMem' && ef.outputs.size == 1 + name = "readMem#{ef.outputs[0]}" + elsif name == 'writeMem' && ef.inputs.size == 2 + name = "writeMem#{ef.inputs[1]}" + end + { name: name, argument_types: ef.inputs, return_types: ef.outputs } + end, + instructions: arch.instructions.map do |insn| + { + name: insn.name, + operand_sizes: insn.operand_sizes, + operand_names: insn.operand_names, + encoding: { + const_part: insn.encoding.const_encoding_part, + encoded_size: insn.encoding.encoded_size, + const_mask: insn.encoding.const_mask, + decode_snippets: insn.encoding.decode + }, + semantic_seq: insn.semantic + } + end, + snippets: arch.snippets.map { |s| { name: s.name, seq: s.seq } } +} + +File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(ir_hash)) +File.write('cpu_state.cc', SimGen::CPUState::TranslationUnit.generate_cpu_state(ir_hash)) + +File.write('base_exec_engine.hh', SimGen::BaseExecEngine::Header.generate_base_exec_engine(ir_hash)) +File.write('base_exec_engine.cc', SimGen::BaseExecEngine::TranslationUnit.generate_base_exec_engine(ir_hash)) +File.write('naive_interpreter.hh', SimGen::NaiveInterpreter::Header.generate_naive_interpreter(ir_hash)) +File.write('naive_interpreter.cc', SimGen::NaiveInterpreter::TranslationUnit.generate_naive_interpreter(ir_hash)) +File.write('decoder.hh', SimGen::Decoder::Header.generate_decoder(ir_hash)) +File.write('decoder.cc', SimGen::Decoder::TranslationUnit.generate_decoder(ir_hash)) +File.write('isa.hh', SimGen::ISA::Header.generate_isa_header(ir_hash)) +File.write('hart.hh', SimGen::Hart::Header.generate_hart(ir_hash)) +File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(ir_hash)) From 4963becb836f04f3002e37fbc43d2b1274f5fa59 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 9 Jun 2026 18:29:14 +0300 Subject: [PATCH 30/75] [sim-lib] Temporary Stack access update --- sim_lib/sim.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sim_lib/sim.cc b/sim_lib/sim.cc index 95628d0..a84a16a 100644 --- a/sim_lib/sim.cc +++ b/sim_lib/sim.cc @@ -46,7 +46,9 @@ int main(int argc, const char *argv[]) try { prot::hart::Hart hart{prot::memory::makePlain(4ULL << 30U), std::move(engine)}; hart.load(loader); - hart.m_cpu->setXRegs(2, kDefaultStack); + // hart.m_cpu->setXRegs(2, kDefaultStack); + hart.getCPU()->setXRegs(2, kDefaultStack); + return hart; }(); From 4e8a4e391ad2785bf3661c16694dee7cfea75883 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 9 Jun 2026 18:31:35 +0300 Subject: [PATCH 31/75] [IR] Added LIRA IR temporary --- lira.yaml | 1338 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1338 insertions(+) create mode 100644 lira.yaml diff --git a/lira.yaml b/lira.yaml new file mode 100644 index 0000000..f8186c3 --- /dev/null +++ b/lira.yaml @@ -0,0 +1,1338 @@ +--- +:name: TargetArch +:attributes: [] +:register_files: +- :name: XRegs + :attributes: [] + :reg_size: + :lanes_base: 32 + :lanes_mult: {} + :regs: + - :name: x0 + :attributes: + - zero + - :name: x1 + :attributes: [] + - :name: x2 + :attributes: [] + - :name: x3 + :attributes: [] + - :name: x4 + :attributes: [] + - :name: x5 + :attributes: [] + - :name: x6 + :attributes: [] + - :name: x7 + :attributes: [] + - :name: x8 + :attributes: [] + - :name: x9 + :attributes: [] + - :name: x10 + :attributes: [] + - :name: x11 + :attributes: [] + - :name: x12 + :attributes: [] + - :name: x13 + :attributes: [] + - :name: x14 + :attributes: [] + - :name: x15 + :attributes: [] + - :name: x16 + :attributes: [] + - :name: x17 + :attributes: [] + - :name: x18 + :attributes: [] + - :name: x19 + :attributes: [] + - :name: x20 + :attributes: [] + - :name: x21 + :attributes: [] + - :name: x22 + :attributes: [] + - :name: x23 + :attributes: [] + - :name: x24 + :attributes: [] + - :name: x25 + :attributes: [] + - :name: x26 + :attributes: [] + - :name: x27 + :attributes: [] + - :name: x28 + :attributes: [] + - :name: x29 + :attributes: [] + - :name: x30 + :attributes: [] + - :name: x31 + :attributes: [] + - :name: pc + :attributes: + - pc +:system_registers: [] +:environment_functions: +- :name: sysCall + :attributes: [] + :inputs: [] + :outputs: [] +- :name: writeMem + :attributes: [] + :inputs: + - 32 + - 8 + :outputs: [] +- :name: writeMem + :attributes: [] + :inputs: + - 32 + - 16 + :outputs: [] +- :name: writeMem + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: [] +- :name: readMem + :attributes: [] + :inputs: + - 32 + :outputs: + - 8 +- :name: readMem + :attributes: [] + :inputs: + - 32 + :outputs: + - 16 +- :name: readMem + :attributes: [] + :inputs: + - 32 + :outputs: + - 32 +- :name: getPC + :attributes: [] + :inputs: [] + :outputs: + - 32 +- :name: setPC + :attributes: [] + :inputs: + - 32 + :outputs: [] +:tables_int: [] +:operations: [] +:snippets: +- :name: decode_0 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 7; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 5 _t5 = op extract_low_32_to_5 _t4; + 1 32 _t6 = op extend_zero_5_to_32 _t5; + 1 32 _t8 = const 12; + 1 32 _t9 = op lsr_32 _t1 _t8; + 1 20 _t10 = op extract_low_32_to_20 _t9; + 1 32 _t12 = const 12; + 1 32 _t13 = op extend_zero_20_to_32 _t10; + 1 32 _t14 = op lsl_32 _t13 _t12; + 1 = output 0 _t6; + 1 = output 1 _t14; +- :name: decode_1 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 20; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 5 _t5 = op extract_low_32_to_5 _t4; + 1 32 _t6 = op extend_zero_5_to_32 _t5; + 1 32 _t8 = const 15; + 1 32 _t9 = op lsr_32 _t1 _t8; + 1 5 _t10 = op extract_low_32_to_5 _t9; + 1 32 _t11 = op extend_zero_5_to_32 _t10; + 1 32 _t13 = const 7; + 1 32 _t14 = op lsr_32 _t1 _t13; + 1 5 _t15 = op extract_low_32_to_5 _t14; + 1 32 _t16 = op extend_zero_5_to_32 _t15; + 1 = output 0 _t6; + 1 = output 1 _t11; + 1 = output 2 _t16; +- :name: decode_2 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 20; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 12 _t5 = op extract_low_32_to_12 _t4; + 1 32 _t6 = op extend_sign_12_to_32 _t5; + 1 32 _t9 = const 15; + 1 32 _t10 = op lsr_32 _t1 _t9; + 1 5 _t11 = op extract_low_32_to_5 _t10; + 1 32 _t12 = op extend_zero_5_to_32 _t11; + 1 32 _t14 = const 7; + 1 32 _t15 = op lsr_32 _t1 _t14; + 1 5 _t16 = op extract_low_32_to_5 _t15; + 1 32 _t17 = op extend_zero_5_to_32 _t16; + 1 = output 0 _t6; + 1 = output 1 _t12; + 1 = output 2 _t17; +- :name: decode_3 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 20; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 5 _t5 = op extract_low_32_to_5 _t4; + 1 32 _t6 = op extend_sign_5_to_32 _t5; + 1 32 _t8 = const 15; + 1 32 _t9 = op lsr_32 _t1 _t8; + 1 5 _t10 = op extract_low_32_to_5 _t9; + 1 32 _t11 = op extend_zero_5_to_32 _t10; + 1 32 _t13 = const 7; + 1 32 _t14 = op lsr_32 _t1 _t13; + 1 5 _t15 = op extract_low_32_to_5 _t14; + 1 32 _t16 = op extend_zero_5_to_32 _t15; + 1 = output 0 _t6; + 1 = output 1 _t11; + 1 = output 2 _t16; +- :name: decode_4 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 25; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 7 _t5 = op extract_low_32_to_7 _t4; + 1 12 _t6 = op extend_zero_7_to_12 _t5; + 1 32 _t8 = const 5; + 1 32 _t9 = op extend_zero_12_to_32 _t6; + 1 32 _t10 = op lsl_32 _t9 _t8; + 1 32 _t12 = const 7; + 1 32 _t13 = op lsr_32 _t1 _t12; + 1 5 _t14 = op extract_low_32_to_5 _t13; + 1 12 _t15 = op extend_zero_5_to_12 _t14; + 1 32 _t17 = op extend_zero_12_to_32 _t15; + 1 32 _t18 = op orr_32 _t10 _t17; + 1 32 _t22 = const 15; + 1 32 _t23 = op lsr_32 _t1 _t22; + 1 5 _t24 = op extract_low_32_to_5 _t23; + 1 32 _t25 = op extend_zero_5_to_32 _t24; + 1 32 _t27 = const 20; + 1 32 _t28 = op lsr_32 _t1 _t27; + 1 5 _t29 = op extract_low_32_to_5 _t28; + 1 32 _t30 = op extend_zero_5_to_32 _t29; + 1 = output 0 _t18; + 1 = output 1 _t25; + 1 = output 2 _t30; +:instructions: +- :name: lui + :attributes: [] + :operand_sizes: + - 32 + - 32 + :operand_names: + - rd + - imm + :encoding: + :encoded_size: 32 + :const_encoding_part: 55 + :const_mask: 127 + :decode: + - decode_0 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t1 = input 1; + 1 32 _t2 = input 0; + 1 = write XRegs _t2 _t1; +- :name: auipc + :attributes: [] + :operand_sizes: + - 32 + - 32 + :operand_names: + - rd + - imm + :encoding: + :encoded_size: 32 + :const_encoding_part: 23 + :const_mask: 127 + :decode: + - decode_0 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t2 = input 1; + 1 32 _t3 = env getPC; + 1 32 _t4 = op add_32 _t2 _t3; + 1 32 _t5 = input 0; + 1 = write XRegs _t5 _t4; +- :name: add + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 51 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op add_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: sub + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 1073741875 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op sub_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: sll + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 4147 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op lsl_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: slt + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 8243 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op slt_32 _t4 _t8; + 1 32 _t12 = op extend_sign_1_to_32 _t10; + 1 32 _t13 = input 2; + 1 = write XRegs _t13 _t12; +- :name: sltu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 12339 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op ult_32 _t4 _t8; + 1 32 _t12 = op extend_sign_1_to_32 _t10; + 1 32 _t13 = input 2; + 1 = write XRegs _t13 _t12; +- :name: xor + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 16435 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 32 _t7 = read XRegs _t6; + 1 32 _t8 = op xor_32 _t4 _t7; + 1 32 _t9 = input 2; + 1 = write XRegs _t9 _t8; +- :name: srl + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 20531 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op lsr_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: sra + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 1073762355 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op lsr_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: or + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 24627 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 32 _t7 = read XRegs _t6; + 1 32 _t8 = op orr_32 _t4 _t7; + 1 32 _t9 = input 2; + 1 = write XRegs _t9 _t8; +- :name: and + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 28723 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 32 _t7 = read XRegs _t6; + 1 32 _t8 = op and_32 _t4 _t7; + 1 32 _t9 = input 2; + 1 = write XRegs _t9 _t8; +- :name: addi + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 19 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: slti + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 8211 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 1 _t8 = op slt_32 _t4 _t6; + 1 32 _t10 = op extend_sign_1_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: sltiu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 12307 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 1 _t8 = op ult_32 _t4 _t6; + 1 32 _t10 = op extend_sign_1_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: xori + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 16403 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op xor_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: ori + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 24595 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op orr_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: andi + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 28691 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op and_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: slli + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33558547 + :const_mask: 4261441663 + :decode: + - decode_3 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op lsl_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: srli + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33574931 + :const_mask: 4261441663 + :decode: + - decode_3 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op lsr_32 _t4 _t5; + 1 32 _t7 = input 2; + 1 = write XRegs _t7 _t6; +- :name: srai + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 1107316755 + :const_mask: 4261441663 + :decode: + - decode_3 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 0; + 1 32 _t7 = op lsr_32 _t4 _t6; + 1 32 _t8 = input 2; + 1 = write XRegs _t8 _t7; +- :name: jalr + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 103 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t2 = env getPC; + 1 32 _t3 = const 4; + 1 32 _t4 = op add_32 _t2 _t3; + 1 32 _t8 = input 1; + 1 32 _t9 = read XRegs _t8; + 1 32 _t10 = input 0; + 1 32 _t11 = op add_32 _t9 _t10; + 1 32 _t13 = const -2; + 1 32 _t14 = op and_32 _t11 _t13; + 1 = env setPC _t14; + 1 32 _t15 = input 2; + 1 = write XRegs _t15 _t4; +- :name: sb + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 35 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 32 _t9 = input 2; + 1 32 _t10 = read XRegs _t9; + 1 32 _t11 = const 0; + 1 32 _t12 = op lsr_32 _t10 _t11; + 1 8 _t13 = op extract_low_32_to_8 _t12; + 1 = env writeMem _t6 _t13; +- :name: sh + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 4131 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 32 _t9 = input 2; + 1 32 _t10 = read XRegs _t9; + 1 32 _t11 = const 0; + 1 32 _t12 = op lsr_32 _t10 _t11; + 1 16 _t13 = op extract_low_32_to_16 _t12; + 1 = env writeMem _t6 _t13; +- :name: sw + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 8227 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 32 _t8 = input 2; + 1 32 _t9 = read XRegs _t8; + 1 = env writeMem _t6 _t9; +- :name: lb + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 3 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 8 _t8 = env readMem _t6; + 1 32 _t10 = op extend_sign_8_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: lh + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 4099 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 16 _t8 = env readMem _t6; + 1 32 _t10 = op extend_sign_16_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: lw + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 8195 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 32 _t8 = env readMem _t6; + 1 32 _t9 = input 2; + 1 = write XRegs _t9 _t8; +- :name: lbu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 16387 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 8 _t8 = env readMem _t6; + 1 32 _t10 = op extend_zero_8_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: lhu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 20483 + :const_mask: 28799 + :decode: + - decode_2 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t5 = input 0; + 1 32 _t6 = op add_32 _t4 _t5; + 1 16 _t8 = env readMem _t6; + 1 32 _t10 = op extend_zero_16_to_32 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: ecall + :attributes: [] + :operand_sizes: [] + :operand_names: [] + :encoding: + :encoded_size: 32 + :const_encoding_part: 115 + :const_mask: 4294967295 + :decode: [] + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: '1 = env sysCall; + + ' +- :name: ebreak + :attributes: [] + :operand_sizes: [] + :operand_names: [] + :encoding: + :encoded_size: 32 + :const_encoding_part: 1048691 + :const_mask: 4294967295 + :decode: [] + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: '' +- :name: fence + :attributes: [] + :operand_sizes: [] + :operand_names: [] + :encoding: + :encoded_size: 32 + :const_encoding_part: 15 + :const_mask: 4027580415 + :decode: [] + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: '' +- :name: mul + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33554483 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op mul_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: mulh + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33558579 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 64 _t5 = op extend_sign_32_to_64 _t4; + 1 32 _t8 = input 0; + 1 32 _t9 = read XRegs _t8; + 1 64 _t10 = op extend_sign_32_to_64 _t9; + 1 64 _t12 = op mul_64 _t5 _t10; + 1 32 _t14 = const 32; + 1 64 _t15 = op extend_zero_32_to_64 _t14; + 1 64 _t16 = op lsr_64 _t12 _t15; + 1 32 _t17 = input 2; + 1 = write XRegs _t17 _t16; +- :name: mulhsu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33562675 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 64 _t5 = op extend_sign_32_to_64 _t4; + 1 32 _t8 = input 0; + 1 32 _t9 = read XRegs _t8; + 1 64 _t10 = op extend_zero_32_to_64 _t9; + 1 64 _t13 = op mul_64 _t5 _t10; + 1 32 _t15 = const 32; + 1 64 _t16 = op extend_zero_32_to_64 _t15; + 1 64 _t17 = op lsr_64 _t13 _t16; + 1 32 _t18 = input 2; + 1 = write XRegs _t18 _t17; +- :name: mulhu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33566771 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 64 _t5 = op extend_zero_32_to_64 _t4; + 1 32 _t8 = input 0; + 1 32 _t9 = read XRegs _t8; + 1 64 _t10 = op extend_zero_32_to_64 _t9; + 1 64 _t12 = op mul_64 _t5 _t10; + 1 32 _t14 = const 32; + 1 64 _t15 = op extend_zero_32_to_64 _t14; + 1 64 _t16 = op lsr_64 _t12 _t15; + 1 32 _t17 = input 2; + 1 = write XRegs _t17 _t16; +- :name: div + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33570867 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 0; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = const 0; + 1 1 _t5 = op ne_32 _t4 _t6; + 1 32 _t9 = input 1; + 1 32 _t10 = read XRegs _t9; + 1 32 _t13 = input 0; + 1 32 _t14 = read XRegs _t13; + 1 32 _t16 = const 0; + 1 1 _t15 = op ne_32 _t14 _t16; + 1 32 _t19 = input 0; + 1 32 _t20 = read XRegs _t19; + 1 32 _t22 = const 1; + 1 32 _t23 = op select_32 _t15 _t20 _t22; + 1 32 _t25 = const 0; + 1 32 _t26 = op divs_32 _t10 _t23 _t25; + 1 32 _t28 = const 4294967295; + 1 32 _t29 = op select_32 _t5 _t26 _t28; + 1 32 _t30 = input 2; + 1 = write XRegs _t30 _t29; +- :name: divu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33574963 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 0; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = const 0; + 1 1 _t5 = op ne_32 _t4 _t6; + 1 32 _t9 = input 1; + 1 32 _t10 = read XRegs _t9; + 1 32 _t13 = input 0; + 1 32 _t14 = read XRegs _t13; + 1 32 _t16 = const 0; + 1 1 _t15 = op ne_32 _t14 _t16; + 1 32 _t19 = input 0; + 1 32 _t20 = read XRegs _t19; + 1 32 _t22 = const 1; + 1 32 _t23 = op select_32 _t15 _t20 _t22; + 1 32 _t25 = const 0; + 1 32 _t26 = op divu_32 _t10 _t23 _t25; + 1 32 _t28 = const 4294967295; + 1 32 _t29 = op select_32 _t5 _t26 _t28; + 1 32 _t30 = input 2; + 1 = write XRegs _t30 _t29; +- :name: rem + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33579059 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op rems_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; +- :name: remu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - rs2 + - rs1 + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 33583155 + :const_mask: 4261441663 + :decode: + - decode_1 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 0; + 1 32 _t8 = read XRegs _t7; + 1 32 _t10 = op remu_32 _t4 _t8; + 1 32 _t11 = input 2; + 1 = write XRegs _t11 _t10; From 81efae2f3466182a72db176fa08e6bdf2010be9d Mon Sep 17 00:00:00 2001 From: uslstenn Date: Thu, 11 Jun 2026 14:32:06 +0300 Subject: [PATCH 32/75] [simgen] Debug PC print --- sim_gen_lira/ExecEngines/base_exec_engine.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sim_gen_lira/ExecEngines/base_exec_engine.rb b/sim_gen_lira/ExecEngines/base_exec_engine.rb index dc27c27..a3892e7 100644 --- a/sim_gen_lira/ExecEngines/base_exec_engine.rb +++ b/sim_gen_lira/ExecEngines/base_exec_engine.rb @@ -40,6 +40,8 @@ def generate_base_exec_engine(input_ir) #include \"memory.hh\" #include \"decoder.hh\" +#include + namespace prot::engine { using namespace prot::state; using namespace prot::isa; @@ -49,6 +51,7 @@ def generate_base_exec_engine(input_ir) auto instr_opt = decoder::decode(bytes); if (instr_opt) { execute(cpu, *instr_opt); + std::cout << \"pc = \" << std::hex << cpu.getPC() << std::dec << std::endl; cpu.increaseICount(); } } From 172c0ae379e9f938a9de74680763f8aef0fc5d00 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Thu, 11 Jun 2026 14:32:35 +0300 Subject: [PATCH 33/75] [simgen] Instructions w/ empty body supported --- sim_gen_lira/Decoders/decoder.rb | 40 ++++++++++++------- sim_gen_lira/ExecEngines/naive_interpreter.rb | 14 +++++-- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index 3625d9d..9cad671 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -1,3 +1,4 @@ +# Decoders/decoder.rb require_relative '../cpp_gen' module SimGen @@ -33,23 +34,34 @@ def generate_decoder(ir_hash) body = [] instructions.each do |insn| - next if insn[:encoding][:decode_snippets].empty? mask = insn[:encoding][:const_mask] - const = insn[:encoding][:const_part] - snippet_name = insn[:encoding][:decode_snippets].first - seq = snippets[snippet_name] - next unless seq + const_part = insn[:encoding][:const_part] + decode_snippets = insn[:encoding][:decode_snippets] - translator = LiraCppGen::Translator.new(seq, :decode, 2) - snippet_code = translator.translate + if decode_snippets.nil? || decode_snippets.empty? + # ะ˜ะฝัั‚ั€ัƒะบั†ะธั ะฑะตะท ะฟะพะปะตะน (ะฝะฐะฟั€ะธะผะตั€, fence, ecall, ebreak) + body << <<~CPP + if ((raw_insn & #{mask}) == #{const_part}) { + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } + CPP + else + snippet_name = decode_snippets.first + seq = snippets[snippet_name] + next unless seq - body << <<~CPP - if ((raw_insn & #{mask}) == #{const}) { - #{snippet_code} - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; - return insn; - } - CPP + translator = LiraCppGen::Translator.new(seq, :decode, 2) + snippet_code = translator.translate + + body << <<~CPP + if ((raw_insn & #{mask}) == #{const_part}) { + #{snippet_code} + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } + CPP + end end decoder_impl = body.join("\n") diff --git a/sim_gen_lira/ExecEngines/naive_interpreter.rb b/sim_gen_lira/ExecEngines/naive_interpreter.rb index 60db4c4..7fb061a 100644 --- a/sim_gen_lira/ExecEngines/naive_interpreter.rb +++ b/sim_gen_lira/ExecEngines/naive_interpreter.rb @@ -1,3 +1,4 @@ +# ExecEngines/naive_interpreter.rb require_relative '../cpp_gen' module SimGen @@ -34,17 +35,22 @@ def generate_naive_interpreter(ir_hash) ir_hash[:instructions].each do |insn| name = insn[:name].to_s.upcase seq = insn[:semantic_seq] - next unless seq && seq.stmts.any? - translator = LiraCppGen::Translator.new(seq, :execute, 2) - body = translator.translate + # ะ“ะตะฝะตั€ะธั€ัƒะตะผ ั„ัƒะฝะบั†ะธัŽ ะดะฐะถะต ะดะปั ะฟัƒัั‚ะพะน ัะตะผะฐะฝั‚ะธะบะธ + if seq && seq.stmts.any? + translator = LiraCppGen::Translator.new(seq, :execute, 2) + body = translator.translate + else + body = " // no semantic" + end + exec_functions << <<~CPP void do#{name}(CPU &cpu, const Instruction &insn) { #{body} } CPP - if seq.stmts.any? { |s| s.kind == 'env' && s.specifier == 'setPC' } + if seq && seq.stmts.any? && seq.stmts.any? { |s| s.kind == 'env' && s.specifier == 'setPC' } branch_insns << "case Opcode::k#{name}: return true;" end end From 1591c0a6674b2804dcef528d6d0ca8982bae51f8 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Thu, 11 Jun 2026 14:35:03 +0300 Subject: [PATCH 34/75] [ser] Sign extension fix --- lib/lira_gen.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 5427714..fa0b2c2 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -1,3 +1,4 @@ +# lira_gen.rb #!/usr/bin/env ruby require_relative 'ADL/base' @@ -164,6 +165,11 @@ def process_cast_zext(name, oprnds) dest_width = 1 if dest_width < 1 src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if src.nil? + # Truncate if src is wider than the expected source type + src_expected_width = ADLToLiraUtils.convert_type(oprnds[1].type) + if src.width > src_expected_width + src = @builder.extract_low(src, src_expected_width) + end if src.width == dest_width out = src else @@ -347,6 +353,11 @@ def generate_decode_snippets(instr, operand_vars) dest_type = lhs.type dest_width = ADLToLiraUtils.convert_type(dest_type) dest_width = 1 if dest_width < 1 + # Truncate if src is wider than the expected source type + src_expected_width = ADLToLiraUtils.convert_type(rhs.type) + if src.width > src_expected_width + src = @builder.extract_low(src, src_expected_width) + end if src.width == dest_width val = src else From 6f003595df8d340815d05a690437cdf2409e3b86 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Thu, 11 Jun 2026 19:53:15 +0300 Subject: [PATCH 35/75] [sim-gen] PC debug print removed --- sim_gen_lira/ExecEngines/base_exec_engine.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/sim_gen_lira/ExecEngines/base_exec_engine.rb b/sim_gen_lira/ExecEngines/base_exec_engine.rb index a3892e7..dc27c27 100644 --- a/sim_gen_lira/ExecEngines/base_exec_engine.rb +++ b/sim_gen_lira/ExecEngines/base_exec_engine.rb @@ -40,8 +40,6 @@ def generate_base_exec_engine(input_ir) #include \"memory.hh\" #include \"decoder.hh\" -#include - namespace prot::engine { using namespace prot::state; using namespace prot::isa; @@ -51,7 +49,6 @@ def generate_base_exec_engine(input_ir) auto instr_opt = decoder::decode(bytes); if (instr_opt) { execute(cpu, *instr_opt); - std::cout << \"pc = \" << std::hex << cpu.getPC() << std::dec << std::endl; cpu.increaseICount(); } } From 619666626903679cc4fbd684b2d2ff859c76f24e Mon Sep 17 00:00:00 2001 From: uslstenn Date: Thu, 11 Jun 2026 19:53:57 +0300 Subject: [PATCH 36/75] [RV32I] Shift (I type) instructions enc upd --- lib/Target/RISC-V/32I.rb | 10 +++++----- lib/Target/RISC-V/encoding.rb | 11 +++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/Target/RISC-V/32I.rb b/lib/Target/RISC-V/32I.rb index 8782a77..e0de18c 100644 --- a/lib/Target/RISC-V/32I.rb +++ b/lib/Target/RISC-V/32I.rb @@ -155,19 +155,19 @@ module RV32I } Instruction(:slli) { - encoding *format_i_shift(0b0010011, 0b001, 0b00000) + encoding *format_i_shift(0b0010011, 0b001, 0b0000000) asm { "slli {rd}, {rs1}, {imm}" } code { rd[]= rs1 << imm } } Instruction(:srli) { - encoding *format_i_shift(0b0010011, 0b101, 0b00000) + encoding *format_i_shift(0b0010011, 0b101, 0b0000000) asm { "srli {rd}, {rs1}, {imm}" } code { rd[]= rs1 >> imm } } Instruction(:srai) { - encoding *format_i_shift(0b0010011, 0b101, 0b01000) + encoding *format_i_shift(0b0010011, 0b101, 0b0100000) asm { "srai {rd}, {rs1}, {imm}" } code { rd[]= rs1.s >> imm } } @@ -217,7 +217,7 @@ module RV32I Instruction(:jalr) { encoding *format_i(0b1100111, 0b000) asm { "jalr {rd}, {rs1}, {imm}" } - code { + code { let :t, :b32, pc + 4 branch((rs1 + imm) & (~1)) rd[]= t @@ -259,7 +259,7 @@ module RV32I asm { "lw {rd}, {imm}({rs1})" } code { rd[]= mem[rs1 + imm, :b32] } } - + Instruction(:lbu) { encoding *format_i(0b0000011, 0b100) asm { "lbu {rd}, {imm}({rs1})" } diff --git a/lib/Target/RISC-V/encoding.rb b/lib/Target/RISC-V/encoding.rb index 5ff0310..3214a0b 100644 --- a/lib/Target/RISC-V/encoding.rb +++ b/lib/Target/RISC-V/encoding.rb @@ -60,15 +60,14 @@ def format_i(opcode, funct3) ], i_imm(:imm), xreg(:rs1), xreg(:rd) end - def format_i_shift(opcode, func3, sopcode) - return :srai, [ + def format_i_shift(opcode, func3, funct7) + return :I, [ field(:f_opcode, 6, 0, opcode), - field(:func3, 14, 12, func3), - field(:f_imm4_0, 24, 20), field(:f_rd, 11, 7), + field(:f_funct3, 14, 12, func3), field(:f_rs1, 19, 15), - field(:f_temp, 26, 25, 0b01), - field(:f_sopcode, 31, 27, sopcode), + field(:f_imm11_5, 31, 25, funct7), + field(:f_imm4_0, 24, 20), ], is_imm(:imm), xreg(:rs1), xreg(:rd) end From b2542cedb4c516a60d033c2b35759bc00ce1cc2b Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 00:30:39 +0300 Subject: [PATCH 37/75] [simlib] Stack Pointer set updated --- sim_lib/sim.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sim_lib/sim.cc b/sim_lib/sim.cc index a84a16a..863bd01 100644 --- a/sim_lib/sim.cc +++ b/sim_lib/sim.cc @@ -46,9 +46,7 @@ int main(int argc, const char *argv[]) try { prot::hart::Hart hart{prot::memory::makePlain(4ULL << 30U), std::move(engine)}; hart.load(loader); - // hart.m_cpu->setXRegs(2, kDefaultStack); - hart.getCPU()->setXRegs(2, kDefaultStack); - + hart.setSP(kDefaultStack); return hart; }(); From 758483e40df1c3c8cf9fef6f438b2c7920622417 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 00:31:53 +0300 Subject: [PATCH 38/75] [ser] LIRA IR serialization shift fix * Arithmetic shift serialization fix --- lib/lira_gen.rb | 6 +- lira.yaml | 351 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 335 insertions(+), 22 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index fa0b2c2..9c16a71 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -30,6 +30,10 @@ def initialize(arch_name, arch_attributes = []) end def process_binary_op(name, oprnds) + # Convert logical shift to arithmetic shift if the left operand is signed + if name == :shr && oprnds[1].type.to_s.start_with?('s') + name = :ashr + end op_class = Lira.const_get(ADLToLiraUtils::OP_MAP[name]) a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) @@ -516,7 +520,7 @@ def convert_instruction(instr) low_bit = field.to high_bit = field.from width = high_bit - low_bit + 1 - if value_num + if !value_num.nil? const_part |= (value_num << low_bit) const_mask |= (((1 << width) - 1) << low_bit) end diff --git a/lira.yaml b/lira.yaml index f8186c3..3ae6b3c 100644 --- a/lira.yaml +++ b/lira.yaml @@ -201,6 +201,95 @@ 1 = output 1 _t11; 1 = output 2 _t16; - :name: decode_4 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 31; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 1 _t5 = op extract_low_32_to_1 _t4; + 1 13 _t6 = op extend_zero_1_to_13 _t5; + 1 32 _t8 = const 12; + 1 32 _t9 = op extend_zero_13_to_32 _t6; + 1 32 _t10 = op lsl_32 _t9 _t8; + 1 32 _t12 = const 7; + 1 32 _t13 = op lsr_32 _t1 _t12; + 1 1 _t14 = op extract_low_32_to_1 _t13; + 1 13 _t15 = op extend_zero_1_to_13 _t14; + 1 32 _t17 = const 11; + 1 32 _t18 = op extend_zero_13_to_32 _t15; + 1 32 _t19 = op lsl_32 _t18 _t17; + 1 32 _t21 = op orr_32 _t10 _t19; + 1 32 _t23 = const 25; + 1 32 _t24 = op lsr_32 _t1 _t23; + 1 6 _t25 = op extract_low_32_to_6 _t24; + 1 13 _t26 = op extend_zero_6_to_13 _t25; + 1 32 _t28 = const 5; + 1 32 _t29 = op extend_zero_13_to_32 _t26; + 1 32 _t30 = op lsl_32 _t29 _t28; + 1 32 _t32 = op orr_32 _t21 _t30; + 1 32 _t34 = const 8; + 1 32 _t35 = op lsr_32 _t1 _t34; + 1 4 _t36 = op extract_low_32_to_4 _t35; + 1 13 _t37 = op extend_zero_4_to_13 _t36; + 1 32 _t39 = const 1; + 1 32 _t40 = op extend_zero_13_to_32 _t37; + 1 32 _t41 = op lsl_32 _t40 _t39; + 1 32 _t43 = op orr_32 _t32 _t41; + 1 13 _t45 = op extract_low_32_to_13 _t43; + 1 32 _t46 = op extend_sign_13_to_32 _t45; + 1 32 _t49 = const 15; + 1 32 _t50 = op lsr_32 _t1 _t49; + 1 5 _t51 = op extract_low_32_to_5 _t50; + 1 32 _t52 = op extend_zero_5_to_32 _t51; + 1 32 _t54 = const 20; + 1 32 _t55 = op lsr_32 _t1 _t54; + 1 5 _t56 = op extract_low_32_to_5 _t55; + 1 32 _t57 = op extend_zero_5_to_32 _t56; + 1 = output 0 _t46; + 1 = output 1 _t52; + 1 = output 2 _t57; +- :name: decode_5 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 31; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 1 _t5 = op extract_low_32_to_1 _t4; + 1 21 _t6 = op extend_zero_1_to_21 _t5; + 1 32 _t8 = const 20; + 1 32 _t9 = op extend_zero_21_to_32 _t6; + 1 32 _t10 = op lsl_32 _t9 _t8; + 1 32 _t12 = const 12; + 1 32 _t13 = op lsr_32 _t1 _t12; + 1 8 _t14 = op extract_low_32_to_8 _t13; + 1 21 _t15 = op extend_zero_8_to_21 _t14; + 1 32 _t17 = const 12; + 1 32 _t18 = op extend_zero_21_to_32 _t15; + 1 32 _t19 = op lsl_32 _t18 _t17; + 1 32 _t21 = op orr_32 _t10 _t19; + 1 32 _t23 = const 20; + 1 32 _t24 = op lsr_32 _t1 _t23; + 1 1 _t25 = op extract_low_32_to_1 _t24; + 1 21 _t26 = op extend_zero_1_to_21 _t25; + 1 32 _t28 = const 11; + 1 32 _t29 = op extend_zero_21_to_32 _t26; + 1 32 _t30 = op lsl_32 _t29 _t28; + 1 32 _t32 = op orr_32 _t21 _t30; + 1 32 _t34 = const 21; + 1 32 _t35 = op lsr_32 _t1 _t34; + 1 10 _t36 = op extract_low_32_to_10 _t35; + 1 21 _t37 = op extend_zero_10_to_21 _t36; + 1 32 _t39 = const 1; + 1 32 _t40 = op extend_zero_21_to_32 _t37; + 1 32 _t41 = op lsl_32 _t40 _t39; + 1 32 _t43 = op orr_32 _t32 _t41; + 1 21 _t45 = op extract_low_32_to_21 _t43; + 1 32 _t46 = op extend_sign_21_to_32 _t45; + 1 32 _t49 = const 7; + 1 32 _t50 = op lsr_32 _t1 _t49; + 1 5 _t51 = op extract_low_32_to_5 _t50; + 1 32 _t52 = op extend_zero_5_to_32 _t51; + 1 = output 0 _t46; + 1 = output 1 _t52; +- :name: decode_6 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 25; @@ -216,17 +305,19 @@ 1 12 _t15 = op extend_zero_5_to_12 _t14; 1 32 _t17 = op extend_zero_12_to_32 _t15; 1 32 _t18 = op orr_32 _t10 _t17; - 1 32 _t22 = const 15; - 1 32 _t23 = op lsr_32 _t1 _t22; - 1 5 _t24 = op extract_low_32_to_5 _t23; - 1 32 _t25 = op extend_zero_5_to_32 _t24; - 1 32 _t27 = const 20; - 1 32 _t28 = op lsr_32 _t1 _t27; - 1 5 _t29 = op extract_low_32_to_5 _t28; - 1 32 _t30 = op extend_zero_5_to_32 _t29; - 1 = output 0 _t18; - 1 = output 1 _t25; - 1 = output 2 _t30; + 1 12 _t20 = op extract_low_32_to_12 _t18; + 1 32 _t21 = op extend_sign_12_to_32 _t20; + 1 32 _t24 = const 15; + 1 32 _t25 = op lsr_32 _t1 _t24; + 1 5 _t26 = op extract_low_32_to_5 _t25; + 1 32 _t27 = op extend_zero_5_to_32 _t26; + 1 32 _t29 = const 20; + 1 32 _t30 = op lsr_32 _t1 _t29; + 1 5 _t31 = op extract_low_32_to_5 _t30; + 1 32 _t32 = op extend_zero_5_to_32 _t31; + 1 = output 0 _t21; + 1 = output 1 _t27; + 1 = output 2 _t32; :instructions: - :name: lui :attributes: [] @@ -487,7 +578,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t7 = input 0; 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op lsr_32 _t4 _t8; + 1 32 _t10 = op asr_32 _t4 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; - :name: or @@ -714,7 +805,7 @@ - rd :encoding: :encoded_size: 32 - :const_encoding_part: 33558547 + :const_encoding_part: 4115 :const_mask: 4261441663 :decode: - decode_3 @@ -740,7 +831,7 @@ - rd :encoding: :encoded_size: 32 - :const_encoding_part: 33574931 + :const_encoding_part: 20499 :const_mask: 4261441663 :decode: - decode_3 @@ -766,7 +857,7 @@ - rd :encoding: :encoded_size: 32 - :const_encoding_part: 1107316755 + :const_encoding_part: 1073762323 :const_mask: 4261441663 :decode: - decode_3 @@ -777,9 +868,227 @@ 1 32 _t3 = input 1; 1 32 _t4 = read XRegs _t3; 1 32 _t6 = input 0; - 1 32 _t7 = op lsr_32 _t4 _t6; + 1 32 _t7 = op asr_32 _t4 _t6; 1 32 _t8 = input 2; 1 = write XRegs _t8 _t7; +- :name: beq + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 99 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 2; + 1 32 _t7 = read XRegs _t6; + 1 1 _t8 = op eq_32 _t4 _t7; + 1 32 _t10 = env getPC; + 1 32 _t11 = input 0; + 1 32 _t12 = op add_32 _t10 _t11; + 1 32 _t14 = const 4; + 1 32 _t15 = op add_32 _t10 _t14; + 1 32 _t17 = op select_32 _t8 _t12 _t15; + 1 = env setPC _t17; +- :name: bne + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 4195 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t6 = input 2; + 1 32 _t7 = read XRegs _t6; + 1 1 _t8 = op ne_32 _t4 _t7; + 1 32 _t10 = env getPC; + 1 32 _t11 = input 0; + 1 32 _t12 = op add_32 _t10 _t11; + 1 32 _t14 = const 4; + 1 32 _t15 = op add_32 _t10 _t14; + 1 32 _t17 = op select_32 _t8 _t12 _t15; + 1 = env setPC _t17; +- :name: blt + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 16483 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 2; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op slt_32 _t4 _t8; + 1 32 _t12 = env getPC; + 1 32 _t13 = input 0; + 1 32 _t14 = op add_32 _t12 _t13; + 1 32 _t16 = const 4; + 1 32 _t17 = op add_32 _t12 _t16; + 1 32 _t19 = op select_32 _t10 _t14 _t17; + 1 = env setPC _t19; +- :name: bge + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 20579 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 2; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op sge_32 _t4 _t8; + 1 32 _t12 = env getPC; + 1 32 _t13 = input 0; + 1 32 _t14 = op add_32 _t12 _t13; + 1 32 _t16 = const 4; + 1 32 _t17 = op add_32 _t12 _t16; + 1 32 _t19 = op select_32 _t10 _t14 _t17; + 1 = env setPC _t19; +- :name: bltu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 24675 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 2; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op ult_32 _t4 _t8; + 1 32 _t12 = env getPC; + 1 32 _t13 = input 0; + 1 32 _t14 = op add_32 _t12 _t13; + 1 32 _t16 = const 4; + 1 32 _t17 = op add_32 _t12 _t16; + 1 32 _t19 = op select_32 _t10 _t14 _t17; + 1 = env setPC _t19; +- :name: bgeu + :attributes: [] + :operand_sizes: + - 32 + - 32 + - 32 + :operand_names: + - imm + - rs1 + - rs2 + :encoding: + :encoded_size: 32 + :const_encoding_part: 28771 + :const_mask: 28799 + :decode: + - decode_4 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t3 = input 1; + 1 32 _t4 = read XRegs _t3; + 1 32 _t7 = input 2; + 1 32 _t8 = read XRegs _t7; + 1 1 _t10 = op uge_32 _t4 _t8; + 1 32 _t12 = env getPC; + 1 32 _t13 = input 0; + 1 32 _t14 = op add_32 _t12 _t13; + 1 32 _t16 = const 4; + 1 32 _t17 = op add_32 _t12 _t16; + 1 32 _t19 = op select_32 _t10 _t14 _t17; + 1 = env setPC _t19; +- :name: jal + :attributes: [] + :operand_sizes: + - 32 + - 32 + :operand_names: + - imm + - rd + :encoding: + :encoded_size: 32 + :const_encoding_part: 111 + :const_mask: 127 + :decode: + - decode_5 + :encode: '' + :constraint_decode: '' + :constraint_encode: '' + :semantic: | + 1 32 _t2 = env getPC; + 1 32 _t3 = const 4; + 1 32 _t4 = op add_32 _t2 _t3; + 1 32 _t5 = input 1; + 1 = write XRegs _t5 _t4; + 1 32 _t7 = input 0; + 1 32 _t8 = op add_32 _t2 _t7; + 1 = env setPC _t8; - :name: jalr :attributes: [] :operand_sizes: @@ -827,7 +1136,7 @@ :const_encoding_part: 35 :const_mask: 28799 :decode: - - decode_4 + - decode_6 :encode: '' :constraint_decode: '' :constraint_encode: '' @@ -857,7 +1166,7 @@ :const_encoding_part: 4131 :const_mask: 28799 :decode: - - decode_4 + - decode_6 :encode: '' :constraint_decode: '' :constraint_encode: '' @@ -887,7 +1196,7 @@ :const_encoding_part: 8227 :const_mask: 28799 :decode: - - decode_4 + - decode_6 :encode: '' :constraint_decode: '' :constraint_encode: '' @@ -1135,7 +1444,7 @@ 1 64 _t12 = op mul_64 _t5 _t10; 1 32 _t14 = const 32; 1 64 _t15 = op extend_zero_32_to_64 _t14; - 1 64 _t16 = op lsr_64 _t12 _t15; + 1 64 _t16 = op asr_64 _t12 _t15; 1 32 _t17 = input 2; 1 = write XRegs _t17 _t16; - :name: mulhsu @@ -1167,7 +1476,7 @@ 1 64 _t13 = op mul_64 _t5 _t10; 1 32 _t15 = const 32; 1 64 _t16 = op extend_zero_32_to_64 _t15; - 1 64 _t17 = op lsr_64 _t13 _t16; + 1 64 _t17 = op asr_64 _t13 _t16; 1 32 _t18 = input 2; 1 = write XRegs _t18 _t17; - :name: mulhu From 8eafc97735205040f7be27af83d3d48acdf9c799 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 00:33:38 +0300 Subject: [PATCH 39/75] [simgen] Removed redundant getter --- sim_gen_lira/Hart/hart.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/sim_gen_lira/Hart/hart.rb b/sim_gen_lira/Hart/hart.rb index a917f03..dd1e13b 100644 --- a/sim_gen_lira/Hart/hart.rb +++ b/sim_gen_lira/Hart/hart.rb @@ -43,7 +43,6 @@ class Hart { Hart(std::unique_ptr mem, std::unique_ptr engine); void setSP(#{type_str} addr); - CPU* getCPU() { return m_cpu.get(); } void load(const ElfLoader &loader); From f4c1c11653749b39890d05166a4b7939a73d4d6f Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 00:35:52 +0300 Subject: [PATCH 40/75] [simgen] Base Ops codegen was synced w/ LIRA Ops * Simple Interpreter basic operations code generation was synchronized w/ LIRA basic operations --- lib/lira/ir_ops.rb | 318 +++++++++++++++++- sim_gen_lira/CMakeLists.txt | 2 +- sim_gen_lira/Decoders/decoder.rb | 2 +- sim_gen_lira/ExecEngines/naive_interpreter.rb | 3 +- sim_gen_lira/base_ops_gen.rb | 100 ++++++ sim_gen_lira/sim_gen.rb | 4 +- 6 files changed, 422 insertions(+), 7 deletions(-) create mode 100644 sim_gen_lira/base_ops_gen.rb diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 3ae4ef6..1df6eb4 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -9,6 +9,21 @@ def base_name self.class.name.split('::').last.downcase end + def type_name(width, signed = false) + sizes = [1, 8, 16, 32, 64, 128] + prefix = signed ? "" : "u" + rounded = sizes.find { |s| s >= width } || 128 + case rounded + when 1 then "bool" + when 8 then "#{prefix}int8_t" + when 16 then "#{prefix}int16_t" + when 32 then "#{prefix}int32_t" + when 64 then "#{prefix}int64_t" + when 128 then "#{prefix}int128_t" + else "#{prefix}int#{rounded}_t" + end + end + def generate_name if outputs.size == 1 "#{base_name}_#{outputs.first}" @@ -16,8 +31,76 @@ def generate_name "#{base_name}_#{outputs.join('_')}" end end + + def cpp_func_name + generate_name + end + + def cpp_return_type + type_name(outputs[0]) + end + + def cpp_params + inputs.map.with_index { |w, i| "#{type_name(w)} #{('a'.ord + i).chr}" }.join(", ") + end + + def cpp_body + case semantic_base + when 'not' then 'return ~a;' + when 'neg' then 'return -a;' + when 'add' then 'return a + b;' + when 'sub' then 'return a - b;' + when 'mul' then 'return a * b;' + when 'and' then 'return a & b;' + when 'orr' then 'return a | b;' + when 'xor' then 'return a ^ b;' + when 'eq' then 'return (a == b) ? 1 : 0;' + when 'ne' then 'return (a != b) ? 1 : 0;' + when 'slt' then "return ((#{type_name(inputs[0], true)})a < (#{type_name(inputs[0], true)})b) ? 1 : 0;" + when 'sle' then "return ((#{type_name(inputs[0], true)})a <= (#{type_name(inputs[0], true)})b) ? 1 : 0;" + when 'sgt' then "return ((#{type_name(inputs[0], true)})a > (#{type_name(inputs[0], true)})b) ? 1 : 0;" + when 'sge' then "return ((#{type_name(inputs[0], true)})a >= (#{type_name(inputs[0], true)})b) ? 1 : 0;" + when 'ult' then "return (a < b) ? 1 : 0;" + when 'ule' then "return (a <= b) ? 1 : 0;" + when 'ugt' then "return (a > b) ? 1 : 0;" + when 'uge' then "return (a >= b) ? 1 : 0;" + when 'lsl' then "b &= #{inputs[0] - 1}; return a << b;" + when 'lsr' then "b &= #{inputs[0] - 1}; return a >> b;" + when 'asr' then "b &= #{inputs[0] - 1}; return (#{type_name(inputs[0])})((#{type_name(inputs[0], true)})a >> b);" + when 'div_u' then 'return (b == 0) ? c : a / b;' + when 'div_s' then "return (b == 0) ? c : (#{type_name(inputs[0])})((#{type_name(inputs[0], true)})a / (#{type_name(inputs[0], true)})b);" + when 'select' then 'return cond ? a : b;' + when 'rem_u' then + <<~CPP + if (b == 0) return a; + return a % b; + CPP + when 'rem_s' then + <<~CPP + if (b == 0) return a; + #{type_name(inputs[0], true)} res = (#{type_name(inputs[0], true)})a % (#{type_name(inputs[0], true)})b; + return (#{type_name(inputs[0])})res; + CPP + else + raise "No cpp_body defined for operation #{semantic_base}" + end + end + + def to_cpp + body_indented = cpp_body.lines.map { |l| " #{l.chomp}" }.join("\n") + <<~CPP + static inline #{cpp_return_type} #{cpp_func_name}(#{cpp_params}) { + #{body_indented} + } + CPP + end + + def self.standard_sizes + [8, 16, 32, 64, 128] + end end + class UnaryOp < Operation include StdOperation @@ -68,6 +151,14 @@ def initialize(bits, out_bits = 1, name: nil, semantic_base: nil) check_signature end + def generate_name + "#{base_name}_#{inputs[0]}" + end + + def cpp_return_type + type_name(1) + end + def check_signature raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 @@ -113,6 +204,18 @@ def check_signature raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 raise TypeCheckError, "input >= output" unless inputs[0] < outputs[0] end + + def generate_name + "#{semantic_base}_#{inputs[0]}_to_#{outputs[0]}" + end + + def cpp_return_type + type_name(outputs[0]) + end + + def cpp_params + "#{type_name(outputs[0])} a" + end end class ExtractLowOp < Operation @@ -130,6 +233,18 @@ def check_signature raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 raise TypeCheckError, "output > input" unless outputs[0] <= inputs[0] end + + def generate_name + "extract_low_#{inputs[0]}_to_#{outputs[0]}" + end + + def cpp_return_type + type_name(outputs[0]) + end + + def cpp_params + "#{type_name(outputs[0])} a" + end end class Not < UnaryOp; def initialize(bits); super(bits, semantic_base: 'not'); end; end @@ -153,32 +268,165 @@ class Ult < CmpOp; def initialize(bits); super(bits, semantic_base: 'ult'); end; class Ule < CmpOp; def initialize(bits); super(bits, semantic_base: 'ule'); end; end class Ugt < CmpOp; def initialize(bits); super(bits, semantic_base: 'ugt'); end; end class Uge < CmpOp; def initialize(bits); super(bits, semantic_base: 'uge'); end; end - class ExtendSign < ExtendOp; def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end; end - class ExtendZero < ExtendOp; def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end; end - class ExtractLow < ExtractLowOp; def initialize(in_bits, out_bits); super(in_bits, out_bits); end; end + + class ExtendSign < ExtendOp + def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end + def cpp_body + <<~ะกPP + #{type_name(outputs[0])} val = a & ((1U << #{inputs[0]}) - 1); + #{type_name(outputs[0])} sign = (val >> (#{inputs[0]} - 1)) & 1; + if (sign) + return val | (~((1U << #{inputs[0]}) - 1)); + else + return val; + ะกPP + end + end + + class ExtendZero < ExtendOp + def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end + def cpp_body + "return a & ((1U << #{inputs[0]}) - 1);" + end + end + + class ExtractLow < ExtractLowOp + def initialize(in_bits, out_bits); super(in_bits, out_bits); end + def cpp_body + "return a & ((1U << #{outputs[0]}) - 1);" + end + end class Popcnt < UnaryOp def initialize(bits); super(bits, semantic_base: 'popcnt'); end + def cpp_body + case inputs[0] + when 8 + <<~ะกPP + unsigned cnt = 0; + while (a) { cnt += a & 1; a >>= 1; } + return cnt; + ะกPP + when 16 + "return popcnt_8(a & 0xFF) + popcnt_8((a >> 8) & 0xFF);" + when 32 + "return popcnt_16(a & 0xFFFF) + popcnt_16((a >> 16) & 0xFFFF);" + when 64 + "return popcnt_32(a & 0xFFFFFFFF) + popcnt_32((a >> 32) & 0xFFFFFFFF);" + when 128 + "return popcnt_64((uint64_t)a) + popcnt_64((uint64_t)(a >> 64));" + else + raise "Unsupported popcnt size" + end + end end class Ctz < UnaryOp def initialize(bits); super(bits, semantic_base: 'ctz'); end + def cpp_body + bits = inputs[0] + if bits == 128 + <<~ะกPP + if (a == 0) return 128; + uint64_t lo = (uint64_t)a; + if (lo) return ctz_64(lo); + else return 64 + ctz_64((uint64_t)(a >> 64)); + ะกPP + else + <<~ะกPP + if (a == 0) return #{bits}; + unsigned n = 0; + while ((a & 1) == 0) { a >>= 1; n++; } + return n; + ะกPP + end + end end class Clz < UnaryOp def initialize(bits); super(bits, semantic_base: 'clz'); end + def cpp_body + bits = inputs[0] + if bits == 128 + <<~ะกPP + if (a == 0) return 128; + uint64_t hi = (uint64_t)(a >> 64); + if (hi) return clz_64(hi); + else return 64 + clz_64((uint64_t)a); + ะกPP + else + mask = case bits + when 8 then "0x80" + when 16 then "0x8000" + when 32 then "0x80000000" + when 64 then "0x8000000000000000ULL" + end + <<~ะกPP + if (a == 0) return #{bits}; + unsigned n = 0; + while ((a & #{mask}) == 0) { a <<= 1; n++; } + return n; + ะกPP + end + end end class Reverse < UnaryOp def initialize(bits); super(bits, semantic_base: 'reverse'); end + def cpp_body + case inputs[0] + when 8 + <<~ะกPP + a = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4); + a = ((a & 0xCC) >> 2) | ((a & 0x33) << 2); + a = ((a & 0xAA) >> 1) | ((a & 0x55) << 1); + return a; + ะกPP + when 16 + <<~ะกPP + a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8); + a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4); + a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2); + a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1); + return a; + ะกPP + when 32 + <<~ะกPP + a = ((a & 0xFFFF0000) >> 16) | ((a & 0x0000FFFF) << 16); + a = ((a & 0xFF00FF00) >> 8) | ((a & 0x00FF00FF) << 8); + a = ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); + a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); + a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); + return a; + ะกPP + when 64 + <<~ะกPP + a = ((a & 0xFFFFFFFF00000000ULL) >> 32) | ((a & 0x00000000FFFFFFFFULL) << 32); + a = ((a & 0xFFFF0000FFFF0000ULL) >> 16) | ((a & 0x0000FFFF0000FFFFULL) << 16); + a = ((a & 0xFF00FF00FF00FF00ULL) >> 8) | ((a & 0x00FF00FF00FF00FFULL) << 8); + a = ((a & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((a & 0x0F0F0F0F0F0F0F0FULL) << 4); + a = ((a & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((a & 0x3333333333333333ULL) << 2); + a = ((a & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((a & 0x5555555555555555ULL) << 1); + return a; + ะกPP + when 128 + <<~ะกPP + uint64_t lo = (uint64_t)a; + uint64_t hi = (uint64_t)(a >> 64); + return ((uint128_t)reverse_64(lo) << 64) | reverse_64(hi); + ะกPP + end + end end class RemU < BinaryOp def initialize(bits); super(bits, semantic_base: 'rem_u'); end + def base_name; 'rem_u'; end end class RemS < BinaryOp def initialize(bits); super(bits, semantic_base: 'rem_s'); end + def base_name; 'rem_s'; end end class Ror < BinaryOp @@ -199,10 +447,12 @@ def initialize(bits); super(bits, out_bits: 1, semantic_base: 'sub_overflow'); e class DivU < TernaryOp def initialize(bits); super(bits, semantic_base: 'div_u'); end + def base_name; 'div_u'; end end class DivS < TernaryOp def initialize(bits); super(bits, semantic_base: 'div_s'); end + def base_name; 'div_s'; end end class Select < Operation @@ -217,5 +467,67 @@ def initialize(bits) def check_signature raise TypeCheckError, "true/false branches mismatch" unless inputs[1] == inputs[2] && inputs[1] == outputs[0] end + + def cpp_params + "uint8_t cond, #{type_name(inputs[1])} a, #{type_name(inputs[1])} b" + end + end +end + +module Lira + class Not; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Neg; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Popcnt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Clz; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Ctz; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Reverse; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Add; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Sub; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Mul; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class And; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Orr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Xor; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Lsl; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Lsr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Asr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Eq; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Ne; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Slt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Sle; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Sgt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Sge; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Ult; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Ule; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Ugt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Uge; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class DivU; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class DivS; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + class Select; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end + + class ExtendSign + def self.instances_to_generate + inside = [ + [1, 13], [6, 13], [4, 13], + [1, 21], [8, 21], [10, 21], + [7, 12], [5, 12] + ] + to32 = (2..31).map { |n| [n, 32] } + inside + to32 + end + end + + class ExtendZero + def self.instances_to_generate + ExtendSign.instances_to_generate + end end + + class ExtractLow + def self.instances_to_generate + (2..31).map { |n| [32, n] } + end + end + + class RemU; def self.instances_to_generate; [[32], [64]]; end; end + class RemS; def self.instances_to_generate; [[32], [64]]; end; end end diff --git a/sim_gen_lira/CMakeLists.txt b/sim_gen_lira/CMakeLists.txt index 58d0884..28d5685 100644 --- a/sim_gen_lira/CMakeLists.txt +++ b/sim_gen_lira/CMakeLists.txt @@ -4,10 +4,10 @@ set(PROTEA_SIMGEN_OUTPUT_HEADERS cpu_state.hh base_exec_engine.hh naive_interpreter.hh - ${CMAKE_SOURCE_DIR}/prot_std/std_ops.h decoder.hh isa.hh hart.hh + base_ops.h ) set(PROTEA_SIMGEN_OUTPUT_SOURCES diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index 9cad671..0c8df9b 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -67,7 +67,7 @@ def generate_decoder(ir_hash) decoder_impl = body.join("\n") <<~CPP #include "decoder.hh" - #include "std_ops.h" + #include "base_ops.h" #include namespace prot::decoder { diff --git a/sim_gen_lira/ExecEngines/naive_interpreter.rb b/sim_gen_lira/ExecEngines/naive_interpreter.rb index 7fb061a..3681ac7 100644 --- a/sim_gen_lira/ExecEngines/naive_interpreter.rb +++ b/sim_gen_lira/ExecEngines/naive_interpreter.rb @@ -70,7 +70,8 @@ def generate_naive_interpreter(ir_hash) <<~CPP #include "naive_interpreter.hh" - #include "std_ops.h" + #include "base_ops.h" + #include #include diff --git a/sim_gen_lira/base_ops_gen.rb b/sim_gen_lira/base_ops_gen.rb new file mode 100644 index 0000000..228aaa7 --- /dev/null +++ b/sim_gen_lira/base_ops_gen.rb @@ -0,0 +1,100 @@ +require 'stringio' +require_relative '../lib/lira/ir_ops' + +module SimGen + def self.generate_base_ops + out = StringIO.new + generate_file(out) + out.string + end + + class << self + private + + HEADER = <<~'CPP'.freeze +#ifndef LIRA_STD_OPS_H +#define LIRA_STD_OPS_H + +#include + +#ifdef __SIZEOF_INT128__ +typedef unsigned __int128 uint128_t; +typedef __int128 int128_t; +#else +#error "128-bit integers not supported" +#endif +CPP + + FOOTER = "\n#endif\n" + + OP_CLASSES = [ + Lira::Not, + Lira::Neg, + Lira::Popcnt, + Lira::Clz, + Lira::Ctz, + Lira::Reverse, + Lira::Add, + Lira::Sub, + Lira::Mul, + Lira::And, + Lira::Orr, + Lira::Xor, + Lira::Lsl, + Lira::Lsr, + Lira::Asr, + Lira::Eq, + Lira::Ne, + Lira::Slt, + Lira::Sle, + Lira::Sgt, + Lira::Sge, + Lira::Ult, + Lira::Ule, + Lira::Ugt, + Lira::Uge, + Lira::DivU, + Lira::DivS, + Lira::RemU, + Lira::RemS, + Lira::Select, + Lira::ExtendSign, + Lira::ExtendZero, + Lira::ExtractLow, + ].freeze + + def generate_file(out) + out.puts HEADER + + OP_CLASSES.each do |op_class| + op_class.instances_to_generate.each do |args| + instance = op_class.new(*args) + out.puts instance.to_cpp + end + out.puts + end + + generate_special_extensions(out) + + out.puts FOOTER + end + + def generate_special_extensions(out) + out.puts Lira::ExtractLow.new(64, 32).to_cpp + out.puts Lira::ExtendSign.new(32, 64).to_cpp + out.puts Lira::ExtendZero.new(32, 64).to_cpp + + out.puts "static inline uint8_t extract_low_32_to_1(uint32_t a) { return a & 1; }" + out.puts "static inline uint32_t extend_sign_1_to_32(uint8_t a) {" + out.puts " return (uint32_t)(int32_t)(int8_t)a;" + out.puts "}" + out.puts "static inline uint32_t extend_zero_1_to_32(uint8_t a) { return a; }" + end + end +end + +if __FILE__ == $0 + output_file = ARGV[0] || "std_ops.h" + File.write(output_file, SimGen.generate_base_ops) + puts "Generated #{output_file}" +end diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index 6b97a88..6e7ef5d 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -4,6 +4,8 @@ $LOAD_PATH.unshift File.dirname(__FILE__) require_relative 'cpp_gen' +require_relative 'base_ops_gen' + require_relative 'CPUState/cpu_state' require_relative 'Decoders/decoder' require_relative 'ISA/isa' @@ -58,7 +60,6 @@ File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(ir_hash)) File.write('cpu_state.cc', SimGen::CPUState::TranslationUnit.generate_cpu_state(ir_hash)) - File.write('base_exec_engine.hh', SimGen::BaseExecEngine::Header.generate_base_exec_engine(ir_hash)) File.write('base_exec_engine.cc', SimGen::BaseExecEngine::TranslationUnit.generate_base_exec_engine(ir_hash)) File.write('naive_interpreter.hh', SimGen::NaiveInterpreter::Header.generate_naive_interpreter(ir_hash)) @@ -68,3 +69,4 @@ File.write('isa.hh', SimGen::ISA::Header.generate_isa_header(ir_hash)) File.write('hart.hh', SimGen::Hart::Header.generate_hart(ir_hash)) File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(ir_hash)) +File.write('base_ops.h', SimGen.generate_base_ops) From 1c005cf367831d7e0a69899b1461956bd835ca56 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 14:40:38 +0300 Subject: [PATCH 41/75] [ser] Binary Ops serialization refactoring * Binary Operations serialization refactoring * IR Operations was mapped onto DSL base ops --- lib/Utility/lira_utils.rb | 98 ++++++++++++++++++++++++------- lib/lira_gen.rb | 119 ++++++++++++-------------------------- 2 files changed, 113 insertions(+), 104 deletions(-) diff --git a/lib/Utility/lira_utils.rb b/lib/Utility/lira_utils.rb index 3cdcc73..a1e551a 100644 --- a/lib/Utility/lira_utils.rb +++ b/lib/Utility/lira_utils.rb @@ -1,33 +1,37 @@ -# lira_utils.rb +# lira/lira_utils.rb + +require_relative '../lira/ir_ops' + module ADLToLiraUtils + OP_MAP = { - add: :Add, - sub: :Sub, - mul: :Mul, - and: :And, - or: :Orr, - xor: :Xor, - shl: :Lsl, - shr: :Lsr, - ashr: :Asr + add: Lira::Add, + sub: Lira::Sub, + mul: Lira::Mul, + and: Lira::And, + or: Lira::Orr, + xor: Lira::Xor, + shl: Lira::Lsl, + shr: Lira::Lsr, + ashr: Lira::Asr }.freeze CMP_OP_MAP_S = { - lt: :Slt, - gt: :Sgt, - le: :Sle, - ge: :Sge, - eq: :Eq, - ne: :Ne + eq: Lira::Eq, + ne: Lira::Ne, + lt: Lira::Slt, + gt: Lira::Sgt, + le: Lira::Sle, + ge: Lira::Sge }.freeze CMP_OP_MAP_U = { - lt: :Ult, - gt: :Ugt, - le: :Ule, - ge: :Uge, - eq: :Eq, - ne: :Ne + eq: Lira::Eq, + ne: Lira::Ne, + lt: Lira::Ult, + gt: Lira::Ugt, + le: Lira::Ule, + ge: Lira::Uge }.freeze SPECIAL_REGS = %w[pc].freeze @@ -109,4 +113,54 @@ def self.find_env_func(arch_builder, name, input_types, output_types) ef.name == name && ef.inputs == input_types && ef.outputs == output_types end end + + def self.binary_op(builder, op_name, lhs_type, a, b) + if op_name == :shr && lhs_type.to_s.start_with?('s') + op_name = :ashr + end + op_class = OP_MAP[op_name] + target_width = [a.width, b.width].max + a = ensure_width(a, target_width, builder) + b = ensure_width(b, target_width, builder) + out = builder.seq.new_temp(target_width) + builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + out + end + + def self.cmp_op(builder, op_name, a, b, unsigned) + op_map = unsigned ? CMP_OP_MAP_U : CMP_OP_MAP_S + op_class = op_map[op_name] + target_width = [a.width, b.width].max + a = ensure_width(a, target_width, builder) + b = ensure_width(b, target_width, builder) + out = builder.seq.new_temp(1) + builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + out + end + + def self.rem_op(builder, a, b, unsigned) + unsigned ? builder.rem_u(a, b) : builder.rem_s(a, b) + end + + def self.div_op(builder, a, b, unsigned, default = nil) + default ||= builder.const(0, a.width) + unsigned ? builder.div_u(a, b, default) : builder.div_s(a, b, default) + end + + def self.extract_field(builder, enc, field, dest_type) + low_bit = field.to + high_bit = field.from + width = high_bit - low_bit + 1 + shifted = builder.lsr(enc, builder.const(low_bit, 32)) + val = builder.extract_low(shifted, width) + dest_width = convert_type(dest_type) + if width != dest_width + if dest_type.to_s.start_with?('s') + val = builder.extend_sign(val, dest_width) + else + val = builder.extend_zero(val, dest_width) + end + end + val + end end diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 9c16a71..504e78a 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -1,4 +1,4 @@ -# lira_gen.rb +# lira/lira_gen.rb #!/usr/bin/env ruby require_relative 'ADL/base' @@ -30,35 +30,41 @@ def initialize(arch_name, arch_attributes = []) end def process_binary_op(name, oprnds) - # Convert logical shift to arithmetic shift if the left operand is signed - if name == :shr && oprnds[1].type.to_s.start_with?('s') - name = :ashr - end - op_class = Lira.const_get(ADLToLiraUtils::OP_MAP[name]) a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? - target_width = [a.width, b.width].max - a = ADLToLiraUtils.ensure_width(a, target_width, @builder) - b = ADLToLiraUtils.ensure_width(b, target_width, @builder) - out = @builder.seq.new_temp(target_width) - @builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + out = ADLToLiraUtils.binary_op(@builder, name, oprnds[1].type, a, b) + @vars[oprnds[0]] = out out end def process_cmp_op(name, oprnds) - out = @builder.seq.new_temp(1) - op1_type = oprnds[1]&.type.to_s - unsigned = op1_type.start_with?('u') - op_map = unsigned ? ADLToLiraUtils::CMP_OP_MAP_U : ADLToLiraUtils::CMP_OP_MAP_S - op_class = Lira.const_get(op_map[name]) a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) return nil if a.nil? || b.nil? - target_width = [a.width, b.width].max - a = ADLToLiraUtils.ensure_width(a, target_width, @builder) - b = ADLToLiraUtils.ensure_width(b, target_width, @builder) - @builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) + unsigned = oprnds[1].type.to_s.start_with?('u') + out = ADLToLiraUtils.cmp_op(@builder, name, a, b, unsigned) + @vars[oprnds[0]] = out + out + end + + def process_rem(oprnds) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) + return nil if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + out = ADLToLiraUtils.rem_op(@builder, a, b, unsigned) + @vars[oprnds[0]] = out + out + end + + def process_div(oprnds) + a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) + b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) + return nil if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + out = ADLToLiraUtils.div_op(@builder, a, b, unsigned) + @vars[oprnds[0]] = out out end @@ -110,13 +116,7 @@ def process_write_reg(oprnds) end @builder.env(ef, [val]) else - rf_name = reg_var.regset.to_s - rf = find_register_file(rf_name) - if rf.nil? - warn "Register file '#{rf_name}' not found, skipping statement" - return nil - end - @builder.write(rf, reg_var.name.to_s, val) + warn "Register file '#{rf_name}' not found, skipping statement" end nil end @@ -187,27 +187,6 @@ def process_cast_zext(name, oprnds) out end - def process_rem(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - unsigned = oprnds[1].type.to_s.start_with?('u') - out = unsigned ? @builder.rem_u(a, b) : @builder.rem_s(a, b) - @vars[oprnds[0]] = out - out - end - - def process_div(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - unsigned = oprnds[1].type.to_s.start_with?('u') - default = @builder.const(0, 32) - out = unsigned ? @builder.div_u(a, b, default) : @builder.div_s(a, b, default) - @vars[oprnds[0]] = out - out - end - def stmt_to_lira(stmt) name = stmt.name oprnds = stmt.oprnds @@ -328,22 +307,10 @@ def generate_decode_snippets(instr, operand_vars) field_name = rhs.name.to_s[2..-1] field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } if field - low_bit = field.to - high_bit = field.from - width = high_bit - low_bit + 1 - shifted = @builder.lsr(enc, @builder.const(low_bit, 32)) - val = @builder.extract_low(shifted, width) - if ADLToLiraUtils.convert_type(lhs.type) != width - if lhs.type.to_s.start_with?('s') - val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) - else - val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) - end - end + val = ADLToLiraUtils.extract_field(@builder, enc, field, lhs.type) @vars[lhs] = val else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) - @vars[lhs] = rhs_val if rhs_val + warn "Field #{field_name} not found" end else rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) @@ -357,7 +324,6 @@ def generate_decode_snippets(instr, operand_vars) dest_type = lhs.type dest_width = ADLToLiraUtils.convert_type(dest_type) dest_width = 1 if dest_width < 1 - # Truncate if src is wider than the expected source type src_expected_width = ADLToLiraUtils.convert_type(rhs.type) if src.width > src_expected_width src = @builder.extract_low(src, src_expected_width) @@ -376,18 +342,7 @@ def generate_decode_snippets(instr, operand_vars) field_name = rhs.name.to_s[2..-1] field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } if field - low_bit = field.to - high_bit = field.from - width = high_bit - low_bit + 1 - shifted = @builder.lsr(enc, @builder.const(low_bit, 32)) - val = @builder.extract_low(shifted, width) - if ADLToLiraUtils.convert_type(lhs.type) != width - if lhs.type.to_s.start_with?('s') - val = @builder.extend_sign(val, ADLToLiraUtils.convert_type(lhs.type)) - else - val = @builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) - end - end + val = ADLToLiraUtils.extract_field(@builder, enc, field, lhs.type) @vars[lhs] = val else warn "Field #{field_name} not found" @@ -528,7 +483,7 @@ def convert_instruction(instr) operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } - encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, encode_snippet || '', '', '') + encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, '', '', '') Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) end @@ -553,12 +508,12 @@ def build_arch @arch_builder.add_env_func(lira_ef) end - unless @arch_builder.environment_functions.any? { |ef| ef.name == "getPC" } - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("getPC", [], [], [32])) - end - unless @arch_builder.environment_functions.any? { |ef| ef.name == "setPC" } - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("setPC", [], [32], [])) - end + # unless @arch_builder.environment_functions.any? { |ef| ef.name == "getPC" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("getPC", [], [], [32])) + # end + # unless @arch_builder.environment_functions.any? { |ef| ef.name == "setPC" } + @arch_builder.add_env_func(Lira::EnvironmentFunction.new("setPC", [], [32], [])) + # end SimInfra.class_variable_get(:@@instructions).each do |instr| begin From 1b68dbccf387f76d9c642651e7e5b97a0a77bee1 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Sat, 13 Jun 2026 14:41:19 +0300 Subject: [PATCH 42/75] [IR] LIRA IR updated --- lira.yaml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lira.yaml b/lira.yaml index 3ae6b3c..7a67467 100644 --- a/lira.yaml +++ b/lira.yaml @@ -1533,22 +1533,22 @@ :semantic: | 1 32 _t3 = input 0; 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = const 0; - 1 1 _t5 = op ne_32 _t4 _t6; + 1 32 _t5 = const 0; + 1 1 _t6 = op ne_32 _t4 _t5; 1 32 _t9 = input 1; 1 32 _t10 = read XRegs _t9; 1 32 _t13 = input 0; 1 32 _t14 = read XRegs _t13; - 1 32 _t16 = const 0; - 1 1 _t15 = op ne_32 _t14 _t16; + 1 32 _t15 = const 0; + 1 1 _t16 = op ne_32 _t14 _t15; 1 32 _t19 = input 0; 1 32 _t20 = read XRegs _t19; 1 32 _t22 = const 1; - 1 32 _t23 = op select_32 _t15 _t20 _t22; + 1 32 _t23 = op select_32 _t16 _t20 _t22; 1 32 _t25 = const 0; - 1 32 _t26 = op divs_32 _t10 _t23 _t25; + 1 32 _t26 = op div_s_32 _t10 _t23 _t25; 1 32 _t28 = const 4294967295; - 1 32 _t29 = op select_32 _t5 _t26 _t28; + 1 32 _t29 = op select_32 _t6 _t26 _t28; 1 32 _t30 = input 2; 1 = write XRegs _t30 _t29; - :name: divu @@ -1573,22 +1573,22 @@ :semantic: | 1 32 _t3 = input 0; 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = const 0; - 1 1 _t5 = op ne_32 _t4 _t6; + 1 32 _t5 = const 0; + 1 1 _t6 = op ne_32 _t4 _t5; 1 32 _t9 = input 1; 1 32 _t10 = read XRegs _t9; 1 32 _t13 = input 0; 1 32 _t14 = read XRegs _t13; - 1 32 _t16 = const 0; - 1 1 _t15 = op ne_32 _t14 _t16; + 1 32 _t15 = const 0; + 1 1 _t16 = op ne_32 _t14 _t15; 1 32 _t19 = input 0; 1 32 _t20 = read XRegs _t19; 1 32 _t22 = const 1; - 1 32 _t23 = op select_32 _t15 _t20 _t22; + 1 32 _t23 = op select_32 _t16 _t20 _t22; 1 32 _t25 = const 0; - 1 32 _t26 = op divu_32 _t10 _t23 _t25; + 1 32 _t26 = op div_u_32 _t10 _t23 _t25; 1 32 _t28 = const 4294967295; - 1 32 _t29 = op select_32 _t5 _t26 _t28; + 1 32 _t29 = op select_32 _t6 _t26 _t28; 1 32 _t30 = input 2; 1 = write XRegs _t30 _t29; - :name: rem @@ -1615,7 +1615,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t7 = input 0; 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op rems_32 _t4 _t8; + 1 32 _t10 = op rem_s_32 _t4 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; - :name: remu @@ -1642,6 +1642,6 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t7 = input 0; 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op remu_32 _t4 _t8; + 1 32 _t10 = op rem_u_32 _t4 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; From 74a65dd22c731194f1abfd2af4eb6cb582893345 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 16:50:03 +0300 Subject: [PATCH 43/75] [ADL, ser] Memory Interface names weere committed on ADL side * :writeMem, :readMem statements were preserved for native simulator gen (backward compatibility) * Memory Interfaces (function names) were set as statement attributes --- lib/ADL/base.rb | 4 ++-- lib/ADL/scope.rb | 24 +++++++++++++++++++----- lib/lira_gen.rb | 20 ++++++++------------ sim_gen_lira/sim_gen.rb | 8 +------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/lib/ADL/base.rb b/lib/ADL/base.rb index baa65aa..f33fb2b 100644 --- a/lib/ADL/base.rb +++ b/lib/ADL/base.rb @@ -30,7 +30,7 @@ def self.serialize(msg= nil) yaml_data = YAML.dump( { regfiles: @@regfiles.map(&:to_h), - interface_functions: @@interface_functions.map { |f| f.reject { |k| k == :kind } }, + interface_functions: @@interface_functions.map(&:to_h), instructions: @@instructions.map(&:to_h), } ) @@ -41,7 +41,7 @@ def self.state YAML.dump( { regfiles: @@regfiles.map(&:to_h), - interface_functions: @@interface_functions.map { |f| f.reject { |k| k == :kind } }, + interface_functions: @@interface_functions.map(&:to_h), instructions: @@instructions.map(&:to_h), } ) diff --git a/lib/ADL/scope.rb b/lib/ADL/scope.rb index bfa1a99..0ebd1d6 100644 --- a/lib/ADL/scope.rb +++ b/lib/ADL/scope.rb @@ -107,17 +107,31 @@ def get_reg(expr, regset, type) = rlet("_reg_#{next_counter}".to_sym, regset, ty def write(rfile, reg, expr) = stmt(:write, [rfile, reg, expr]) + def memory_interface_name(base_name, types) + suffix = nil + if base_name == :readMem + type = types.first + suffix = type.to_s.match(/\d+/)[0] if type && type.to_s =~ /b\d+|r\d+/ + elsif base_name == :writeMem + type = types[1] if types.size > 1 + suffix = type.to_s.match(/\d+/)[0] if type && type.to_s =~ /b\d+|r\d+/ + end + suffix ? "#{base_name}#{suffix}".to_sym : base_name + end + def writeMem(addr, expr) - arg_types = [addr.type, expr.type].map { |t| t.is_a?(Symbol) ? t : t.type } - SimInfra.register_memory_interface(:writeMem, [], arg_types) - stmt(:writeMem, [addr, expr]) + arg_types = [addr.type, expr.type] + iface_name = memory_interface_name(:writeMem, arg_types) + SimInfra.register_memory_interface(iface_name, [], arg_types) + stmt(:writeMem, [addr, expr], iface_name) end def readMem(addr, type) arg_types = [addr.type] - SimInfra.register_memory_interface(:readMem, [type], arg_types) + iface_name = memory_interface_name(:readMem, [type]) + iface = SimInfra.register_memory_interface(iface_name, [type], arg_types) v = tmpvar(type) - stmt(:readMem, [v, addr]) + stmt(:readMem, [v, addr], iface_name) end def read(rfile, reg) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 504e78a..7202c9c 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -121,14 +121,14 @@ def process_write_reg(oprnds) nil end - def process_read_mem(oprnds) + def process_read_mem(name, oprnds) out_type = ADLToLiraUtils.convert_type(oprnds[0].type) addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if addr.nil? addr_width = addr.width - ef = ADLToLiraUtils.find_env_func(@arch_builder, "readMem", [addr_width], [out_type]) + ef = ADLToLiraUtils.find_env_func(@arch_builder, name.to_s, [addr_width], [out_type]) if ef.nil? - warn "Environment function 'readMem' with inputs [#{addr_width}] and outputs [#{out_type}] not registered, skipping statement" + warn "Environment function #{name} wasn't registered, skipping statement" return nil end outs = @builder.env(ef, [addr]) @@ -137,14 +137,14 @@ def process_read_mem(oprnds) out end - def process_write_mem(oprnds) + def process_write_mem(name, oprnds) addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) return nil if addr.nil? || val.nil? addr_width = addr.width - ef = ADLToLiraUtils.find_env_func(@arch_builder, "writeMem", [addr_width, val.width], []) + ef = ADLToLiraUtils.find_env_func(@arch_builder, name.to_s, [addr_width, val.width], []) if ef.nil? - warn "Environment function 'writeMem' with inputs [#{addr_width}, #{val.width}] not registered, skipping statement" + warn "Environment function #{name} wasn't registered, skipping statement" return nil end @builder.env(ef, [addr, val]) @@ -234,10 +234,10 @@ def stmt_to_lira(stmt) process_write_reg(oprnds) when :readMem - process_read_mem(oprnds) + process_read_mem(stmt.attrs, oprnds) when :writeMem - process_write_mem(oprnds) + process_write_mem(stmt.attrs, oprnds) when :branch target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) @@ -508,12 +508,8 @@ def build_arch @arch_builder.add_env_func(lira_ef) end - # unless @arch_builder.environment_functions.any? { |ef| ef.name == "getPC" } @arch_builder.add_env_func(Lira::EnvironmentFunction.new("getPC", [], [], [32])) - # end - # unless @arch_builder.environment_functions.any? { |ef| ef.name == "setPC" } @arch_builder.add_env_func(Lira::EnvironmentFunction.new("setPC", [], [32], [])) - # end SimInfra.class_variable_get(:@@instructions).each do |instr| begin diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index 6e7ef5d..e2bbe49 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -33,13 +33,7 @@ interface_functions: arch.environment_functions .reject { |ef| ['setPC', 'getPC'].include?(ef.name) } .map do |ef| - name = ef.name - if name == 'readMem' && ef.outputs.size == 1 - name = "readMem#{ef.outputs[0]}" - elsif name == 'writeMem' && ef.inputs.size == 2 - name = "writeMem#{ef.inputs[1]}" - end - { name: name, argument_types: ef.inputs, return_types: ef.outputs } + { name: ef.name, argument_types: ef.inputs, return_types: ef.outputs } end, instructions: arch.instructions.map do |insn| { From 0d2add418cfa1d79198a2d8b9313ca4e9bb225ac Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 16:57:28 +0300 Subject: [PATCH 44/75] [simgen] CPU State codegen was unified * TODO: * move cpu_state.rb into common part of the sim gen scripting * Memory Access implementations were temporarily placed into arch specific sim library cpu_state_ext.cc --- lib/Utility/helper_cpp.rb | 8 ++- sim_gen/CPUState/cpu_state.rb | 2 +- sim_gen_lira/CPUState/cpu_state.rb | 89 +++------------------------ sim_lib/Target/RISCV/cpu_state_ext.cc | 23 +++++++ 4 files changed, 38 insertions(+), 84 deletions(-) diff --git a/lib/Utility/helper_cpp.rb b/lib/Utility/helper_cpp.rb index 10541c5..6b1d445 100644 --- a/lib/Utility/helper_cpp.rb +++ b/lib/Utility/helper_cpp.rb @@ -7,10 +7,12 @@ module Utility module HelperCpp module_function - def gen_type(type) + def gen_type(type, signed = false) actual_type = Utility.get_type(type) - cpp_bitsize = actual_type.bitsize % 32 == 0 ? actual_type.bitsize : (actual_type.bitsize / 32 + 1) * 32 - "#{actual_type.typeof == :s ? 'int' : 'uint'}#{cpp_bitsize}_t" + width = actual_type.bitsize + prefix = signed || actual_type.typeof == :s ? "" : "u" + rounded = [1, 8, 16, 32, 64, 128].find { |s| s >= width } || 128 + rounded == 1 ? "bool" : "#{prefix}int#{rounded}_t" end def gen_small_type(type) diff --git a/sim_gen/CPUState/cpu_state.rb b/sim_gen/CPUState/cpu_state.rb index f7d97c1..820620f 100644 --- a/sim_gen/CPUState/cpu_state.rb +++ b/sim_gen/CPUState/cpu_state.rb @@ -164,7 +164,7 @@ module SimGen module CPUState module Header module_function - + def generate_cpu_state(input_ir) pc_decl = Helper.generate_pc_decl(input_ir[:regfiles]) pc_functions = Helper.generate_pc_functions(input_ir[:regfiles]) diff --git a/sim_gen_lira/CPUState/cpu_state.rb b/sim_gen_lira/CPUState/cpu_state.rb index 922d7e5..820620f 100644 --- a/sim_gen_lira/CPUState/cpu_state.rb +++ b/sim_gen_lira/CPUState/cpu_state.rb @@ -133,48 +133,21 @@ def generate_do_exit_func end def gen_input_args(args) - args.map do |arg| - case arg - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - when 64 then "uint64_t" - else Utility::HelperCpp.gen_type(arg) - end - end.join(', ') + args.map { |arg| Utility::HelperCpp.gen_type(arg) }.join(', ') end def generate_interface_func(interface_functions) emitter = Utility::GenEmitter.new + emitter.emit_line('// Interface functions') interface_functions.each do |ifunc| - # ะ”ะปั ะฒะพะทะฒั€ะฐั‰ะฐะตะผั‹ั… ั‚ะธะฟะพะฒ ั‚ะพะถะต ัะพะฟะพัั‚ะฐะฒะปัะตะผ - ret_types = ifunc[:return_types].map do |t| - case t - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - when 64 then "uint64_t" - else Utility::HelperCpp.gen_type(t) - end - end - arg_types = ifunc[:argument_types].map do |t| - case t - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - when 64 then "uint64_t" - else Utility::HelperCpp.gen_type(t) - end - end - - if ret_types.empty? - emitter.emit_line("void #{ifunc[:name]}(#{arg_types.join(', ')});") - elsif ret_types.size == 1 - emitter.emit_line("#{ret_types[0]} #{ifunc[:name]}(#{arg_types.join(', ')});") + if ifunc[:return_types].size == 0 + emitter.emit_line("void #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") + elsif ifunc[:return_types].size == 1 + emitter.emit_line("#{gen_input_args(ifunc[:return_types])} #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") else - emitter.emit_line("std::tuple<#{ret_types.join(', ')}> #{ifunc[:name]}(#{arg_types.join(', ')});") + emitter.emit_line("std::tuple<#{gen_input_args(ifunc[:return_types])}> #{ifunc[:name]}(#{gen_input_args(ifunc[:argument_types])});") end end emitter.emit_blank_line @@ -259,52 +232,8 @@ module TranslationUnit module_function def generate_cpu_state(input_ir) - interface_functions = input_ir[:interface_functions] - implementations = [] - - interface_functions.each do |ifunc| - name = ifunc[:name] - - if name =~ /^readMem(\d+)$/ - width = $1.to_i - ret_type = case width - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - else "uint#{width}_t" - end - implementations << <<~CPP - #{ret_type} CPU::#{name}(uint32_t addr) { - return m_memory->read<#{ret_type}>(addr); - } - CPP - elsif name =~ /^writeMem(\d+)$/ - width = $1.to_i - val_type = case width - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - else "uint#{width}_t" - end - implementations << <<~CPP - void CPU::#{name}(uint32_t addr, #{val_type} value) { - m_memory->write<#{val_type}>(addr, value); - } - CPP - end - end - - <<~CPP - #include "cpu_state.hh" - #include "memory.hh" - #include - - namespace prot::state { - - #{implementations.join("\n")} - - } // namespace prot::state - CPP + # Currently, no implementation is needed for the CPUState translation unit. + '' end end end diff --git a/sim_lib/Target/RISCV/cpu_state_ext.cc b/sim_lib/Target/RISCV/cpu_state_ext.cc index 4389d9e..1140fc3 100644 --- a/sim_lib/Target/RISCV/cpu_state_ext.cc +++ b/sim_lib/Target/RISCV/cpu_state_ext.cc @@ -1,4 +1,5 @@ #include "cpu_state.hh" +#include namespace prot::state { @@ -13,4 +14,26 @@ void CPU::sysCall() { } } +void CPU::writeMem8(uint32_t addr, uint8_t value) { + m_memory->write(addr, value); +} + +void CPU::writeMem16(uint32_t addr, uint16_t value) { + m_memory->write(addr, value); +} + +void CPU::writeMem32(uint32_t addr, uint32_t value) { + m_memory->write(addr, value); +} + +uint8_t CPU::readMem8(uint32_t addr) { return m_memory->read(addr); } + +uint16_t CPU::readMem16(uint32_t addr) { + return m_memory->read(addr); +} + +uint32_t CPU::readMem32(uint32_t addr) { + return m_memory->read(addr); +} + } // namespace prot::state From d79e58a6a6fd816a6fcfa9e2ff14c48c6fae1843 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 17:38:36 +0300 Subject: [PATCH 45/75] [simgen] CPP types gen refactored --- lib/lira/ir_ops.rb | 58 ++++++++++++++++------------------------- sim_gen_lira/cpp_gen.rb | 35 ++++++++----------------- 2 files changed, 33 insertions(+), 60 deletions(-) diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 1df6eb4..e2ef561 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -1,5 +1,6 @@ # lira/ir_ops.rb require_relative 'arch' +require_relative '../Utility/helper_cpp' module Lira class TypeCheckError < StandardError; end @@ -9,21 +10,6 @@ def base_name self.class.name.split('::').last.downcase end - def type_name(width, signed = false) - sizes = [1, 8, 16, 32, 64, 128] - prefix = signed ? "" : "u" - rounded = sizes.find { |s| s >= width } || 128 - case rounded - when 1 then "bool" - when 8 then "#{prefix}int8_t" - when 16 then "#{prefix}int16_t" - when 32 then "#{prefix}int32_t" - when 64 then "#{prefix}int64_t" - when 128 then "#{prefix}int128_t" - else "#{prefix}int#{rounded}_t" - end - end - def generate_name if outputs.size == 1 "#{base_name}_#{outputs.first}" @@ -37,11 +23,11 @@ def cpp_func_name end def cpp_return_type - type_name(outputs[0]) + Utility::HelperCpp.gen_type(outputs[0]) end def cpp_params - inputs.map.with_index { |w, i| "#{type_name(w)} #{('a'.ord + i).chr}" }.join(", ") + inputs.map.with_index { |w, i| "#{Utility::HelperCpp.gen_type(w)} #{('a'.ord + i).chr}" }.join(", ") end def cpp_body @@ -56,19 +42,19 @@ def cpp_body when 'xor' then 'return a ^ b;' when 'eq' then 'return (a == b) ? 1 : 0;' when 'ne' then 'return (a != b) ? 1 : 0;' - when 'slt' then "return ((#{type_name(inputs[0], true)})a < (#{type_name(inputs[0], true)})b) ? 1 : 0;" - when 'sle' then "return ((#{type_name(inputs[0], true)})a <= (#{type_name(inputs[0], true)})b) ? 1 : 0;" - when 'sgt' then "return ((#{type_name(inputs[0], true)})a > (#{type_name(inputs[0], true)})b) ? 1 : 0;" - when 'sge' then "return ((#{type_name(inputs[0], true)})a >= (#{type_name(inputs[0], true)})b) ? 1 : 0;" + when 'slt' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a < (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" + when 'sle' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a <= (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" + when 'sgt' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a > (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" + when 'sge' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a >= (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" when 'ult' then "return (a < b) ? 1 : 0;" when 'ule' then "return (a <= b) ? 1 : 0;" when 'ugt' then "return (a > b) ? 1 : 0;" when 'uge' then "return (a >= b) ? 1 : 0;" when 'lsl' then "b &= #{inputs[0] - 1}; return a << b;" when 'lsr' then "b &= #{inputs[0] - 1}; return a >> b;" - when 'asr' then "b &= #{inputs[0] - 1}; return (#{type_name(inputs[0])})((#{type_name(inputs[0], true)})a >> b);" + when 'asr' then "b &= #{inputs[0] - 1}; return (#{Utility::HelperCpp.gen_type(inputs[0])})((#{Utility::HelperCpp.gen_type(inputs[0], true)})a >> b);" when 'div_u' then 'return (b == 0) ? c : a / b;' - when 'div_s' then "return (b == 0) ? c : (#{type_name(inputs[0])})((#{type_name(inputs[0], true)})a / (#{type_name(inputs[0], true)})b);" + when 'div_s' then "return (b == 0) ? c : (#{Utility::HelperCpp.gen_type(inputs[0])})((#{Utility::HelperCpp.gen_type(inputs[0], true)})a / (#{Utility::HelperCpp.gen_type(inputs[0], true)})b);" when 'select' then 'return cond ? a : b;' when 'rem_u' then <<~CPP @@ -78,8 +64,8 @@ def cpp_body when 'rem_s' then <<~CPP if (b == 0) return a; - #{type_name(inputs[0], true)} res = (#{type_name(inputs[0], true)})a % (#{type_name(inputs[0], true)})b; - return (#{type_name(inputs[0])})res; + #{Utility::HelperCpp.gen_type(inputs[0], true)} res = (#{Utility::HelperCpp.gen_type(inputs[0], true)})a % (#{Utility::HelperCpp.gen_type(inputs[0], true)})b; + return (#{Utility::HelperCpp.gen_type(inputs[0])})res; CPP else raise "No cpp_body defined for operation #{semantic_base}" @@ -156,7 +142,7 @@ def generate_name end def cpp_return_type - type_name(1) + Utility::HelperCpp.gen_type(1) end def check_signature @@ -210,11 +196,11 @@ def generate_name end def cpp_return_type - type_name(outputs[0]) + Utility::HelperCpp.gen_type(outputs[0]) end def cpp_params - "#{type_name(outputs[0])} a" + "#{Utility::HelperCpp.gen_type(outputs[0])} a" end end @@ -239,11 +225,11 @@ def generate_name end def cpp_return_type - type_name(outputs[0]) + Utility::HelperCpp.gen_type(outputs[0]) end def cpp_params - "#{type_name(outputs[0])} a" + "#{Utility::HelperCpp.gen_type(outputs[0])} a" end end @@ -273,10 +259,10 @@ class ExtendSign < ExtendOp def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end def cpp_body <<~ะกPP - #{type_name(outputs[0])} val = a & ((1U << #{inputs[0]}) - 1); - #{type_name(outputs[0])} sign = (val >> (#{inputs[0]} - 1)) & 1; + #{Utility::HelperCpp.gen_type(outputs[0])} val = a & (((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1); + #{Utility::HelperCpp.gen_type(outputs[0])} sign = (val >> (#{inputs[0]} - 1)) & 1; if (sign) - return val | (~((1U << #{inputs[0]}) - 1)); + return val | (~(((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1)); else return val; ะกPP @@ -286,14 +272,14 @@ def cpp_body class ExtendZero < ExtendOp def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end def cpp_body - "return a & ((1U << #{inputs[0]}) - 1);" + "return a & (((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1);" end end class ExtractLow < ExtractLowOp def initialize(in_bits, out_bits); super(in_bits, out_bits); end def cpp_body - "return a & ((1U << #{outputs[0]}) - 1);" + "return a & (((#{Utility::HelperCpp.gen_type(inputs[0])})1 << #{outputs[0]}) - 1);" end end @@ -469,7 +455,7 @@ def check_signature end def cpp_params - "uint8_t cond, #{type_name(inputs[1])} a, #{type_name(inputs[1])} b" + "uint8_t cond, #{Utility::HelperCpp.gen_type(inputs[1])} a, #{Utility::HelperCpp.gen_type(inputs[1])} b" end end end diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index 70a7a35..ebe933f 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -1,4 +1,5 @@ require_relative '../lib/lira/ir' +require_relative '../lib/Utility/helper_cpp' module LiraCppGen class Translator @@ -24,7 +25,7 @@ def resolve_var(name, stmt = nil) if stmt && stmt.respond_to?(:outputs_types) && stmt.outputs_types.any? width = stmt.outputs_types[0] end - emit("#{type_name(width)} #{name} = 0;") + emit("#{Utility::HelperCpp.gen_type(width)} #{name} = 0;") @var_widths[name] = width return name end @@ -53,7 +54,7 @@ def translate_op(stmt) inputs = stmt.inputs.map { |i| resolve_var(i, stmt) } unless @var_widths.key?(out) - emit("#{type_name(out_width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(out_width)} #{out};") @var_widths[out] = out_width end @@ -107,7 +108,7 @@ def translate_const(stmt) out = stmt.outputs[0] width = stmt.outputs_types[0] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out} = #{value};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{value};") @var_widths[out] = width end end @@ -117,7 +118,7 @@ def translate_dyn_const(stmt) out = stmt.outputs[0] width = stmt.outputs_types[0] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out} = #{name};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{name};") @var_widths[out] = width end end @@ -128,11 +129,11 @@ def translate_read(stmt) out = stmt.outputs[0] width = stmt.outputs_types[0] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out};") @var_widths[out] = width end if @context == :execute - emit("#{out} = cpu.get#{rf}<#{type_name(width)}>(#{idx});") + emit("#{out} = cpu.get#{rf}<#{Utility::HelperCpp.gen_type(width)}>(#{idx});") else emit("#{out} = 0; // read in decode") end @@ -170,7 +171,7 @@ def translate_env(stmt) out = outputs[0] width = out_types[0] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out};") @var_widths[out] = width end emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") @@ -178,7 +179,7 @@ def translate_env(stmt) outputs.each_with_index do |out, i| width = out_types[i] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out};") @var_widths[out] = width end end @@ -199,7 +200,7 @@ def translate_cond_env(stmt) outputs.each_with_index do |out, i| width = stmt.outputs_types[i] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out};") @var_widths[out] = width end emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") @@ -219,7 +220,7 @@ def translate_input(stmt) out = stmt.outputs[0] width = stmt.outputs_types[0] unless @var_widths.key?(out) - emit("#{type_name(width)} #{out};") + emit("#{Utility::HelperCpp.gen_type(width)} #{out};") @var_widths[out] = width end if @context == :decode @@ -235,20 +236,6 @@ def translate_output(stmt) emit("insn.operand#{idx} = #{val};") end - def type_name(width) - sizes = [1, 8, 16, 32, 64, 128] - rounded = sizes.find { |s| s >= width } || 128 - case rounded - when 1 then "bool" - when 8 then "uint8_t" - when 16 then "uint16_t" - when 32 then "uint32_t" - when 64 then "uint64_t" - when 128 then "unsigned __int128" - else "uint#{rounded}_t" - end - end - def emit(line) @output << (" " * @indent + line) end From b6826e83ffadcba08ef89954874662674e4d7287 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 17:39:39 +0300 Subject: [PATCH 46/75] [simgen] Lira Exec Engine & Interpreted codegen refactored --- sim_gen_lira/ExecEngines/base_exec_engine.rb | 16 +- sim_gen_lira/ExecEngines/naive_interpreter.rb | 155 +++++++++--------- 2 files changed, 88 insertions(+), 83 deletions(-) diff --git a/sim_gen_lira/ExecEngines/base_exec_engine.rb b/sim_gen_lira/ExecEngines/base_exec_engine.rb index dc27c27..97212ab 100644 --- a/sim_gen_lira/ExecEngines/base_exec_engine.rb +++ b/sim_gen_lira/ExecEngines/base_exec_engine.rb @@ -6,7 +6,8 @@ module Header module_function def generate_base_exec_engine(input_ir) -"#ifndef GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED +<<~CPP +#ifndef GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED #define GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED #include \"cpu_state.hh\" @@ -26,7 +27,7 @@ def generate_base_exec_engine(input_ir) } // namespace prot::engine #endif // GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED -" +CPP end end @@ -35,10 +36,10 @@ module TranslationUnit def generate_base_exec_engine(input_ir) max_xlen = SimGen::Helper::find_max_regsize(input_ir[:regfiles]) - -"#include \"base_exec_engine.hh\" -#include \"memory.hh\" -#include \"decoder.hh\" +<<~CPP +#include "base_exec_engine.hh" +#include "memory.hh" +#include "decoder.hh" namespace prot::engine { using namespace prot::state; @@ -53,7 +54,8 @@ def generate_base_exec_engine(input_ir) } } } // namespace prot::engine -" end +CPP + end end end end diff --git a/sim_gen_lira/ExecEngines/naive_interpreter.rb b/sim_gen_lira/ExecEngines/naive_interpreter.rb index 3681ac7..aa55dd4 100644 --- a/sim_gen_lira/ExecEngines/naive_interpreter.rb +++ b/sim_gen_lira/ExecEngines/naive_interpreter.rb @@ -1,4 +1,3 @@ -# ExecEngines/naive_interpreter.rb require_relative '../cpp_gen' module SimGen @@ -7,21 +6,21 @@ module Header module_function def generate_naive_interpreter(ir_hash) - <<~CPP - #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED - #define GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED +<<~CPP + #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED + #define GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED - #include "base_exec_engine.hh" + #include "base_exec_engine.hh" - namespace prot::engine { - class Interpreter : public ExecEngine { - public: - void execute(CPU &cpu, const Instruction &insn) override; - }; - } + namespace prot::engine { + class Interpreter : public ExecEngine { + public: + void execute(CPU &cpu, const Instruction &insn) override; + }; + } - #endif - CPP + #endif +CPP end end @@ -36,7 +35,6 @@ def generate_naive_interpreter(ir_hash) name = insn[:name].to_s.upcase seq = insn[:semantic_seq] - # ะ“ะตะฝะตั€ะธั€ัƒะตะผ ั„ัƒะฝะบั†ะธัŽ ะดะฐะถะต ะดะปั ะฟัƒัั‚ะพะน ัะตะผะฐะฝั‚ะธะบะธ if seq && seq.stmts.any? translator = LiraCppGen::Translator.new(seq, :execute, 2) body = translator.translate @@ -44,79 +42,84 @@ def generate_naive_interpreter(ir_hash) body = " // no semantic" end - exec_functions << <<~CPP - void do#{name}(CPU &cpu, const Instruction &insn) { - #{body} - } - CPP + exec_functions << +<<~CPP + void do#{name}(CPU &cpu, const Instruction &insn) { + #{body} + } +CPP if seq && seq.stmts.any? && seq.stmts.any? { |s| s.kind == 'env' && s.specifier == 'setPC' } branch_insns << "case Opcode::k#{name}: return true;" end end - is_branch = <<~CPP - bool isBranchInstruction(const Instruction &insn) { - switch (insn.m_opc) { - #{branch_insns.join("\n")} - default: return false; - } - } - CPP + is_branch = +<<~CPP +bool isBranchInstruction(const Instruction &insn) { + switch (insn.m_opc) { + #{branch_insns.join("\n")} + default: return false; + } +} +CPP handlers_init = ir_hash[:instructions].map do |insn| "m_handlers[toUnderlying(Opcode::k#{insn[:name].to_s.upcase})] = &do#{insn[:name].to_s.upcase};" end.join("\n ") - <<~CPP - #include "naive_interpreter.hh" - #include "base_ops.h" - - #include - #include - - namespace prot::engine { - using namespace prot::state; - using namespace prot::isa; - - namespace { - #{is_branch} - #{exec_functions.join("\n\n")} - - template - constexpr auto toUnderlying(T val) requires std::is_enum_v { - return static_cast>(val); - } - - class ExecHandlersMap { - public: - using ExecHandler = void (*)(CPU &cpu, const Instruction &insn); - private: - std::array m_handlers{}; - public: - constexpr ExecHandlersMap() { - #{handlers_init} - } - ExecHandler get(Opcode opcode) const { - auto idx = toUnderlying(opcode); - if (idx >= m_handlers.size()) return nullptr; - auto h = m_handlers[idx]; - return h; - } - }; - constexpr ExecHandlersMap kExecHandlers{}; - } - - void Interpreter::execute(CPU &cpu, const Instruction &insn) { - auto handler = kExecHandlers.get(insn.m_opc); - if (!handler) return; - auto oldPC = cpu.getPC(); - handler(cpu, insn); - if (!isBranchInstruction(insn)) - cpu.setPC(oldPC + getILen(insn.m_opc)); - } - } - CPP +<<~CPP +#include "naive_interpreter.hh" +#include "base_ops.h" + +#include +#include + +namespace prot::engine { +using namespace prot::state; +using namespace prot::isa; + +namespace { +#{is_branch} +#{exec_functions.join("\n\n")} + +template +constexpr auto toUnderlying(T val) + requires std::is_enum_v +{ + return static_cast>(val); +} + +class ExecHandlersMap { +public: + using ExecHandler = void (*)(CPU &cpu, const Instruction &insn); +private: + std::array m_handlers{}; +public: + constexpr ExecHandlersMap() { + #{handlers_init} + } + + [[nodiscard]] ExecHandler get(Opcode opcode) const { + assert(toUnderlying(opcode) < m_handlers.size()); + auto toRet = m_handlers[toUnderlying(opcode)]; + assert(toRet != nullptr); + return toRet; + } +}; +constexpr ExecHandlersMap kExecHandlers{}; +} // namespace + +void Interpreter::execute(CPU &cpu, const Instruction &insn) { + const auto handler = kExecHandlers.get(insn.m_opc); + if (!handler) return; + auto oldPC = cpu.getPC(); + handler(cpu, insn); + if (!isBranchInstruction(insn)) + cpu.setPC(oldPC + getILen(insn.m_opc)); +} +} +CPP end end end From f1e271b0b0bd9f9e052a46759d1aaec549a9c43e Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 23:53:54 +0300 Subject: [PATCH 47/75] [infra] Sim gen targets were configured * Sim Lira/Native targets were set up * TODO: Sepearate directories serialization & codegen as follows: -- Protea/ -- simgen/ -- generic/ -- native/ -- lira/ -- ir/ -- native/ -- lira/ --- CMakeLists.txt | 1 + lib/CMakeLists.txt | 33 ++++++++++++++++++++--- sim_gen/CMakeLists.txt | 52 +++++++++++++++++++++++-------------- sim_gen_lira/CMakeLists.txt | 48 ++++++++++++++++++++++------------ 4 files changed, 94 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fe096e..826e46f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,5 +30,6 @@ endif() add_subdirectory(lib) add_subdirectory(sim_lib) +add_subdirectory(sim_gen) add_subdirectory(sim_gen_lira) add_subdirectory(test) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4d58ff4..2168e43 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,10 +1,35 @@ project(protea_irgen) +set(NATIVE_IR_FILE ${CMAKE_CURRENT_BINARY_DIR}/IR.yaml) + add_custom_command( - OUTPUT ${PROJECT_BINARY_DIR}/IR.yaml + OUTPUT ${NATIVE_IR_FILE} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb - COMMENT "Running ${PROJECT_NAME}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating native IR (IR.yaml)" +) + +add_custom_target(native_gen DEPENDS ${NATIVE_IR_FILE}) + +set(LIRA_IR_FILE ${CMAKE_CURRENT_BINARY_DIR}/lira.yaml) + +add_custom_command( + OUTPUT ${LIRA_IR_FILE} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lira_gen.rb + COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/lira_gen.rb + --target ${CMAKE_SOURCE_DIR}/lib/Target/RISC-V/ + --output ${LIRA_IR_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating LIRA IR (lira.yaml)" ) -add_custom_target(${PROJECT_NAME} DEPENDS ${PROJECT_BINARY_DIR}/IR.yaml) -install(FILES ${PROJECT_BINARY_DIR}/IR.yaml DESTINATION share/) + +add_custom_target(lira_gen DEPENDS ${LIRA_IR_FILE}) + +add_custom_target(protea_irgen DEPENDS native_gen) + +set(NATIVE_IR_FILE ${NATIVE_IR_FILE} PARENT_SCOPE) +set(LIRA_IR_FILE ${LIRA_IR_FILE} PARENT_SCOPE) + +install(FILES ${NATIVE_IR_FILE} DESTINATION share/) +install(FILES ${LIRA_IR_FILE} DESTINATION share/) diff --git a/sim_gen/CMakeLists.txt b/sim_gen/CMakeLists.txt index 8d0c5e8..a601fad 100644 --- a/sim_gen/CMakeLists.txt +++ b/sim_gen/CMakeLists.txt @@ -1,4 +1,12 @@ -project(protea_simgen) +# sim_gen/CMakeLists.txt + +project(protea_native_sim_gen) + +if(NOT NATIVE_IR_FILE) + set(NATIVE_IR_FILE ${protea_irgen_BINARY_DIR}/IR.yaml) +endif() + +set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(PROTEA_SIMGEN_OUTPUT_HEADERS cpu_state.hh @@ -21,27 +29,33 @@ set(PROTEA_SIMGEN_OUTPUT_FILES ${PROTEA_SIMGEN_OUTPUT_SOURCES} ) -set(IR_YAML_FILE ${protea_irgen_BINARY_DIR}/IR.yaml) - - -add_custom_command(DEPENDS +add_custom_command( OUTPUT ${PROTEA_SIMGEN_OUTPUT_FILES} - COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${IR_YAML_FILE} - DEPENDS protea_irgen - COMMENT "Running ${PROJECT_NAME}" + DEPENDS ${NATIVE_IR_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb + COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR} + COMMAND cd ${OUTPUT_DIR} && ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${NATIVE_IR_FILE} + COMMENT "Generating native simulator sources from ${NATIVE_IR_FILE}" ) -add_custom_target(${PROJECT_NAME} ALL DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) -add_dependencies(${PROJECT_NAME} protea_irgen) -add_executable(sim ${PROTEA_SIMGEN_OUTPUT_SOURCES} - ${protea_simlib_SOURCE_DIR}/elf_loader.cc - ${protea_simlib_SOURCE_DIR}/base_jit.cc - ${protea_simlib_SOURCE_DIR}/sim.cc +add_custom_target(native_sim_gen DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) +add_dependencies(native_sim_gen native_gen) + +add_executable(sim_native ${PROTEA_SIMGEN_OUTPUT_SOURCES} + ${protea_simlib_SOURCE_DIR}/elf_loader.cc + ${protea_simlib_SOURCE_DIR}/base_jit.cc + ${protea_simlib_SOURCE_DIR}/sim.cc ${protea_simlib_SOURCE_DIR}/jit_factory.cc ${protea_simlib_SOURCE_DIR}/memory.cc ${protea_simlib_SOURCE_DIR}/Target/${TARGET_NAME}/cpu_state_ext.cc) - -target_include_directories(sim PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${protea_simlib_SOURCE_DIR}) -target_link_libraries(sim elfio CLI11 fmt) -target_compile_features(sim PRIVATE cxx_std_23) -install(TARGETS sim) + +target_include_directories(sim_native PRIVATE + ${OUTPUT_DIR} + ${protea_simlib_SOURCE_DIR} +) + +target_link_libraries(sim_native PRIVATE elfio CLI11 fmt) +target_compile_features(sim_native PRIVATE cxx_std_23) +add_dependencies(sim_native native_sim_gen) +add_dependencies(sim_native native_gen) + +install(TARGETS sim_native) diff --git a/sim_gen_lira/CMakeLists.txt b/sim_gen_lira/CMakeLists.txt index 28d5685..f887601 100644 --- a/sim_gen_lira/CMakeLists.txt +++ b/sim_gen_lira/CMakeLists.txt @@ -1,4 +1,12 @@ -project(protea_simgen) +# sim_gen_lira/CMakeLists.txt + +project(protea_lira_sim_gen) + +if(NOT LIRA_IR_FILE) + set(LIRA_IR_FILE ${protea_irgen_BINARY_DIR}/lira.yaml) +endif() + +set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(PROTEA_SIMGEN_OUTPUT_HEADERS cpu_state.hh @@ -7,13 +15,12 @@ set(PROTEA_SIMGEN_OUTPUT_HEADERS decoder.hh isa.hh hart.hh - base_ops.h ) set(PROTEA_SIMGEN_OUTPUT_SOURCES base_exec_engine.cc - naive_interpreter.cc cpu_state.cc + naive_interpreter.cc decoder.cc hart.cc ) @@ -23,27 +30,34 @@ set(PROTEA_SIMGEN_OUTPUT_FILES ${PROTEA_SIMGEN_OUTPUT_SOURCES} ) -set(IR_YAML_FILE ${CMAKE_SOURCE_DIR}/lira.yaml) - -add_custom_command(DEPENDS +add_custom_command( OUTPUT ${PROTEA_SIMGEN_OUTPUT_FILES} - COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${IR_YAML_FILE} - DEPENDS protea_irgen - COMMENT "Running ${PROJECT_NAME}" + DEPENDS ${LIRA_IR_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb + COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR} + COMMAND cd ${OUTPUT_DIR} && ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/sim_gen.rb ${LIRA_IR_FILE} + COMMENT "Generating LIRA simulator sources from ${LIRA_IR_FILE}" ) -add_custom_target(${PROJECT_NAME} ALL DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) -add_dependencies(${PROJECT_NAME} protea_irgen) -add_executable(sim ${PROTEA_SIMGEN_OUTPUT_SOURCES} +add_custom_target(lira_sim_gen DEPENDS ${PROTEA_SIMGEN_OUTPUT_FILES}) +add_dependencies(lira_sim_gen lira_gen) + +add_executable(sim_lira ${PROTEA_SIMGEN_OUTPUT_SOURCES} ${protea_simlib_SOURCE_DIR}/elf_loader.cc ${protea_simlib_SOURCE_DIR}/base_jit.cc ${protea_simlib_SOURCE_DIR}/sim.cc ${protea_simlib_SOURCE_DIR}/jit_factory.cc ${protea_simlib_SOURCE_DIR}/memory.cc - ${protea_simlib_SOURCE_DIR}/Target/${TARGET_NAME}/cpu_state_ext.cc) + ${protea_simlib_SOURCE_DIR}/Target/${TARGET_NAME}/cpu_state_ext.cc +) + +target_include_directories(sim_lira PRIVATE + ${OUTPUT_DIR} + ${protea_simlib_SOURCE_DIR} +) + +target_link_libraries(sim_lira PRIVATE elfio CLI11 fmt) +target_compile_features(sim_lira PRIVATE cxx_std_23) +add_dependencies(sim_lira lira_sim_gen lira_gen) -target_include_directories(sim PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${protea_simlib_SOURCE_DIR}) -target_link_libraries(sim elfio CLI11 fmt) -target_compile_features(sim PRIVATE cxx_std_23) -install(TARGETS sim) +install(TARGETS sim_lira) From 8429a78ce3681d924cdf8c12606ece04cb56a044 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Mon, 15 Jun 2026 23:54:54 +0300 Subject: [PATCH 48/75] LIRA IR updated --- lira.yaml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lira.yaml b/lira.yaml index 7a67467..80dc5c5 100644 --- a/lira.yaml +++ b/lira.yaml @@ -82,37 +82,37 @@ :attributes: [] :inputs: [] :outputs: [] -- :name: writeMem +- :name: writeMem8 :attributes: [] :inputs: - 32 - 8 :outputs: [] -- :name: writeMem +- :name: writeMem16 :attributes: [] :inputs: - 32 - 16 :outputs: [] -- :name: writeMem +- :name: writeMem32 :attributes: [] :inputs: - 32 - 32 :outputs: [] -- :name: readMem +- :name: readMem8 :attributes: [] :inputs: - 32 :outputs: - 8 -- :name: readMem +- :name: readMem16 :attributes: [] :inputs: - 32 :outputs: - 16 -- :name: readMem +- :name: readMem32 :attributes: [] :inputs: - 32 @@ -1150,7 +1150,7 @@ 1 32 _t11 = const 0; 1 32 _t12 = op lsr_32 _t10 _t11; 1 8 _t13 = op extract_low_32_to_8 _t12; - 1 = env writeMem _t6 _t13; + 1 = env writeMem8 _t6 _t13; - :name: sh :attributes: [] :operand_sizes: @@ -1180,7 +1180,7 @@ 1 32 _t11 = const 0; 1 32 _t12 = op lsr_32 _t10 _t11; 1 16 _t13 = op extract_low_32_to_16 _t12; - 1 = env writeMem _t6 _t13; + 1 = env writeMem16 _t6 _t13; - :name: sw :attributes: [] :operand_sizes: @@ -1207,7 +1207,7 @@ 1 32 _t6 = op add_32 _t4 _t5; 1 32 _t8 = input 2; 1 32 _t9 = read XRegs _t8; - 1 = env writeMem _t6 _t9; + 1 = env writeMem32 _t6 _t9; - :name: lb :attributes: [] :operand_sizes: @@ -1232,7 +1232,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t5 = input 0; 1 32 _t6 = op add_32 _t4 _t5; - 1 8 _t8 = env readMem _t6; + 1 8 _t8 = env readMem8 _t6; 1 32 _t10 = op extend_sign_8_to_32 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; @@ -1260,7 +1260,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t5 = input 0; 1 32 _t6 = op add_32 _t4 _t5; - 1 16 _t8 = env readMem _t6; + 1 16 _t8 = env readMem16 _t6; 1 32 _t10 = op extend_sign_16_to_32 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; @@ -1288,7 +1288,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t5 = input 0; 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t8 = env readMem _t6; + 1 32 _t8 = env readMem32 _t6; 1 32 _t9 = input 2; 1 = write XRegs _t9 _t8; - :name: lbu @@ -1315,7 +1315,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t5 = input 0; 1 32 _t6 = op add_32 _t4 _t5; - 1 8 _t8 = env readMem _t6; + 1 8 _t8 = env readMem8 _t6; 1 32 _t10 = op extend_zero_8_to_32 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; @@ -1343,7 +1343,7 @@ 1 32 _t4 = read XRegs _t3; 1 32 _t5 = input 0; 1 32 _t6 = op add_32 _t4 _t5; - 1 16 _t8 = env readMem _t6; + 1 16 _t8 = env readMem16 _t6; 1 32 _t10 = op extend_zero_16_to_32 _t8; 1 32 _t11 = input 2; 1 = write XRegs _t11 _t10; From f075f0209f23ef3cc94977c932b5d1b416101d83 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 02:26:53 +0300 Subject: [PATCH 49/75] [ser] Major LIRA serizalier refactoring * Refactoring from procedural to OOP code generation pattern --- lib/Utility/lira_utils.rb | 157 +++------ lib/lira/ir_builder.rb | 6 + lib/lira_gen.rb | 658 +++++++++++++++++++++----------------- 3 files changed, 413 insertions(+), 408 deletions(-) diff --git a/lib/Utility/lira_utils.rb b/lib/Utility/lira_utils.rb index a1e551a..ce53b1a 100644 --- a/lib/Utility/lira_utils.rb +++ b/lib/Utility/lira_utils.rb @@ -4,36 +4,6 @@ module ADLToLiraUtils - OP_MAP = { - add: Lira::Add, - sub: Lira::Sub, - mul: Lira::Mul, - and: Lira::And, - or: Lira::Orr, - xor: Lira::Xor, - shl: Lira::Lsl, - shr: Lira::Lsr, - ashr: Lira::Asr - }.freeze - - CMP_OP_MAP_S = { - eq: Lira::Eq, - ne: Lira::Ne, - lt: Lira::Slt, - gt: Lira::Sgt, - le: Lira::Sle, - ge: Lira::Sge - }.freeze - - CMP_OP_MAP_U = { - eq: Lira::Eq, - ne: Lira::Ne, - lt: Lira::Ult, - gt: Lira::Ugt, - le: Lira::Ule, - ge: Lira::Uge - }.freeze - SPECIAL_REGS = %w[pc].freeze def self.convert_type(adl_type) @@ -49,63 +19,59 @@ def self.resolve_operand(op, builder, vars, operand_names, arch_builder = nil) return nil if op.nil? return vars[op] if vars.key?(op) - if op.is_a?(Integer) - return builder.const(op, 32) + case op + when Integer + builder.const(op, 32) + when SimInfra::Constant + builder.const(op.value, 32) + when SimInfra::Var + resolve_var(op, builder, vars, operand_names, arch_builder) + else + raise "Cannot resolve operand: #{op.inspect}" + end + end + + def self.resolve_var(var, builder, vars, operand_names, arch_builder) + width = convert_type(var.type) + width = 1 if width < 1 + + if (idx = operand_names.index(var.name.to_s)) + return resolve_operand_var(var, idx, width, builder, vars, arch_builder) end - if op.is_a?(SimInfra::Constant) - return builder.const(op.value, 32) + if SPECIAL_REGS.include?(var.name.to_s) + return resolve_special_reg(var, builder, vars, arch_builder) end - if op.is_a?(SimInfra::Var) - width = convert_type(op.type) - width = 1 if width < 1 + val = builder.seq.new_temp(width) + vars[var] = val + val + end - idx = operand_names.index(op.name.to_s) - if idx - input_val = builder.input(idx, width) - vars[op] = input_val + def self.resolve_operand_var(var, idx, width, builder, vars, arch_builder) + input_val = builder.input(idx, width) + vars[var] = input_val + return input_val unless var.regset - if op.regset - rf_name = op.regset.to_s - rf = arch_builder.register_files.find { |rf| rf.name == rf_name } - if rf.nil? - warn "Register file '#{rf_name}' not found, skipping statement" - return nil - end - read_val = builder.seq.new_temp(width) - builder.read(rf, input_val) - vars[op] = read_val - return read_val - else - return input_val - end - else - if SPECIAL_REGS.include?(op.name.to_s) - ef = find_env_func(arch_builder, "getPC", [], [32]) - if ef - val = builder.env(ef, [])[0] - vars[op] = val - return val - else - warn "Environment function 'getPC' not registered" - return nil - end - else - val = builder.seq.new_temp(width) - vars[op] = val - return val - end - end + rf_name = var.regset.to_s + rf = arch_builder.register_files.find { |rf| rf.name == rf_name } + unless rf + warn "Register file '#{rf_name}' not found, skipping statement" + return nil end - raise "Cannot resolve operand: #{op.inspect}" + read_val = builder.seq.new_temp(width) + builder.read(rf, input_val) + vars[var] = read_val + read_val end - def self.ensure_width(val, width, builder) - return val if val.width == width - if val.width < width - builder.extend_zero(val, width) - else - builder.extract_low(val, width) + def self.resolve_special_reg(var, builder, vars, arch_builder) + ef = find_env_func(arch_builder, "getPC", [], [32]) + unless ef + warn "Environment function 'getPC' not registered" + return nil end + val = builder.env(ef, [])[0] + vars[var] = val + val end def self.find_env_func(arch_builder, name, input_types, output_types) @@ -114,39 +80,6 @@ def self.find_env_func(arch_builder, name, input_types, output_types) end end - def self.binary_op(builder, op_name, lhs_type, a, b) - if op_name == :shr && lhs_type.to_s.start_with?('s') - op_name = :ashr - end - op_class = OP_MAP[op_name] - target_width = [a.width, b.width].max - a = ensure_width(a, target_width, builder) - b = ensure_width(b, target_width, builder) - out = builder.seq.new_temp(target_width) - builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) - out - end - - def self.cmp_op(builder, op_name, a, b, unsigned) - op_map = unsigned ? CMP_OP_MAP_U : CMP_OP_MAP_S - op_class = op_map[op_name] - target_width = [a.width, b.width].max - a = ensure_width(a, target_width, builder) - b = ensure_width(b, target_width, builder) - out = builder.seq.new_temp(1) - builder.seq.add_op(op_class.new(target_width), [a.name, b.name], [out.name]) - out - end - - def self.rem_op(builder, a, b, unsigned) - unsigned ? builder.rem_u(a, b) : builder.rem_s(a, b) - end - - def self.div_op(builder, a, b, unsigned, default = nil) - default ||= builder.const(0, a.width) - unsigned ? builder.div_u(a, b, default) : builder.div_s(a, b, default) - end - def self.extract_field(builder, enc, field, dest_type) low_bit = field.to high_bit = field.from diff --git a/lib/lira/ir_builder.rb b/lib/lira/ir_builder.rb index e61a777..e176a97 100644 --- a/lib/lira/ir_builder.rb +++ b/lib/lira/ir_builder.rb @@ -270,6 +270,11 @@ def extract(value, start, out_width) extract_low(shifted, out_width) end + def ensure_width(val, width) + return val if val.width == width + val.width < width ? extend_zero(val, width) : extract_low(val, width) + end + # Register & memory def read(rf, rsi, shape = Shape.new(1, nil)) width = rf.reg_size.lanes_base @@ -409,6 +414,7 @@ def select(cond, true_val, false_val) = @seq.select(cond, true_val, false_val) def concat(low, high) = @seq.concat(low, high) def extract_low(a, out_width) = @seq.extract_low(a, out_width) def extract(value, start, out_width) = @seq.extract(value, start, out_width) + def ensure_width(val, width) = @seq.ensure_width(val, width) def read(rf, rsi, shape = Shape.new(1, nil)) = @seq.read(rf, rsi, shape) def write(rf, rsi, value, shape = Shape.new(1, nil)) = @seq.write(rf, rsi, value, shape) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 7202c9c..9e4fa6e 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -12,262 +12,398 @@ require_relative 'Utility/lira_utils' class LiraSerializer - def initialize(arch_name, arch_attributes = []) - @arch_name = arch_name - @arch_attributes = arch_attributes - @arch_builder = nil - @builder = nil - @vars = nil - @operand_names = nil - @operand_vars = nil + OP_MAP = { + add: Lira::Add, + sub: Lira::Sub, + mul: Lira::Mul, + and: Lira::And, + or: Lira::Orr, + xor: Lira::Xor, + shl: Lira::Lsl, + shr: Lira::Lsr, + ashr: Lira::Asr + }.freeze + + CMP_OP_MAP_S = { + eq: Lira::Eq, + ne: Lira::Ne, + lt: Lira::Slt, + gt: Lira::Sgt, + le: Lira::Sle, + ge: Lira::Sge + }.freeze + + CMP_OP_MAP_U = { + eq: Lira::Eq, + ne: Lira::Ne, + lt: Lira::Ult, + gt: Lira::Ugt, + le: Lira::Ule, + ge: Lira::Uge + }.freeze + + class StmtHandler + def initialize(serializer) + @ser = serializer + end - @decode_cache = {} - @decode_snip_id = 0 + def handle(stmt) + raise NotImplementedError + end + + private - # NOTE: Temporary disabled - # @encode_cache = {} - # @encode_snip_id = 0 + attr_reader :ser + + def resolved(op) = ser.resolved(op) + def builder = ser.builder + def vars = ser.vars + def operand_names = ser.operand_names + def arch_builder = ser.arch_builder + def current_instr = ser.current_instr + def store(var, val) = ser.store_result(var, val) end - def process_binary_op(name, oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - out = ADLToLiraUtils.binary_op(@builder, name, oprnds[1].type, a, b) - @vars[oprnds[0]] = out - out + class NewVarHandler < StmtHandler + def handle(stmt) + var = stmt.oprnds[0] + width = ADLToLiraUtils.convert_type(var.type) + width = 1 if width < 1 + vars[var] = builder.seq.new_temp(width) + end end - def process_cmp_op(name, oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - unsigned = oprnds[1].type.to_s.start_with?('u') - out = ADLToLiraUtils.cmp_op(@builder, name, a, b, unsigned) - @vars[oprnds[0]] = out - out + class LetHandler < StmtHandler + def handle(stmt) + rhs_val = resolved(stmt.oprnds[1]) + vars[stmt.oprnds[0]] = rhs_val if rhs_val + end end - def process_rem(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - unsigned = oprnds[1].type.to_s.start_with?('u') - out = ADLToLiraUtils.rem_op(@builder, a, b, unsigned) - @vars[oprnds[0]] = out - out + class DecodeLetHandler < StmtHandler + def handle(stmt) + lhs, rhs = stmt.oprnds + if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') + field_name = rhs.name.to_s[2..] + field = current_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + if field + vars[lhs] = ADLToLiraUtils.extract_field(builder, ser.raw_enc, field, lhs.type) + else + warn "Field #{field_name} not found" + end + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, builder, vars, [], arch_builder) + vars[lhs] = rhs_val if rhs_val + end + end end - def process_div(oprnds) - a = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - b = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - return nil if a.nil? || b.nil? - unsigned = oprnds[1].type.to_s.start_with?('u') - out = ADLToLiraUtils.div_op(@builder, a, b, unsigned) - @vars[oprnds[0]] = out - out + class AluOpHandler < StmtHandler + def handle(stmt) + name, oprnds = stmt.name, stmt.oprnds + a, b = resolved(oprnds[1]), resolved(oprnds[2]) + return if a.nil? || b.nil? + lhs_signed = oprnds[1].type.to_s.start_with?('s') + store(oprnds[0], ser.op_alu(name, lhs_signed, a, b)) + end end - def find_register_file(name) - @arch_builder.register_files.find { |rf| rf.name == name } + class CmpOpHandler < StmtHandler + def handle(stmt) + name, oprnds = stmt.name, stmt.oprnds + a, b = resolved(oprnds[1]), resolved(oprnds[2]) + return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + store(oprnds[0], ser.op_cmp(name, unsigned, a, b)) + end + end + + class SelectHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + cond, t, f = resolved(oprnds[1]), resolved(oprnds[2]), resolved(oprnds[3]) + return if cond.nil? || t.nil? || f.nil? + cond = builder.ensure_width(cond, 1) + store(oprnds[0], builder.select(cond, t, f)) + end + end + + class CastHandler < StmtHandler + def handle(stmt) + name, oprnds = stmt.name, stmt.oprnds + src = resolved(oprnds[1]) + return if src.nil? + store(oprnds[0], ser.widen_or_truncate(name, oprnds[0].type, src, oprnds[1].type)) + end end - def process_read_reg(oprnds) - reg_var = oprnds[1] - idx = @operand_names.index(reg_var.name.to_s) - if idx - reg_num = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) - rf_name = reg_var.regset.to_s - rf = find_register_file(rf_name) - if rf.nil? - warn "Register file '#{rf_name}' not found, skipping statement" - return nil + class DecodeCastHandler < StmtHandler + def handle(stmt) + name, oprnds = stmt.name, stmt.oprnds + lhs, rhs = oprnds + src = vars[rhs] + if src + vars[lhs] = ser.widen_or_truncate(name, lhs.type, src, rhs.type) + elsif rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') + field_name = rhs.name.to_s[2..] + field = current_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + if field + vars[lhs] = ADLToLiraUtils.extract_field(builder, ser.raw_enc, field, lhs.type) + else + warn "Field #{field_name} not found" + end + else + rhs_val = ADLToLiraUtils.resolve_operand(rhs, builder, vars, [], arch_builder) + vars[lhs] = rhs_val if rhs_val end - out = @builder.read(rf, reg_num) - @vars[oprnds[0]] = out - out - else - # Special Registers (PC) - val = ADLToLiraUtils.resolve_operand(reg_var, @builder, @vars, @operand_names, @arch_builder) - @vars[oprnds[0]] = val if val - val - end - end - - def process_write_reg(oprnds) - reg_var = oprnds[0] - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - return nil if val.nil? - idx = @operand_names.index(reg_var.name.to_s) - if idx - reg_num = @builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) - rf_name = reg_var.regset.to_s - rf = find_register_file(rf_name) - if rf.nil? - warn "Register file '#{rf_name}' not found, skipping statement" - return nil + end + end + + class ExtractHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + val = resolved(oprnds[1]) + return if val.nil? + hi, lo = oprnds[2].value, oprnds[3].value + width = hi - lo + 1 + width = 1 if width < 1 + store(oprnds[0], builder.extract(val, builder.const(lo, 32), width)) + end + end + + class ReadRegHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + reg_var = oprnds[1] + idx = operand_names.index(reg_var.name.to_s) + if idx + reg_num = builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) + rf_name = reg_var.regset.to_s + rf = arch_builder.register_files.find { |r| r.name == rf_name } + unless rf + warn "Register file '#{rf_name}' not found, skipping statement" + return + end + store(oprnds[0], builder.read(rf, reg_num)) + else + val = resolved(reg_var) + store(oprnds[0], val) if val end - @builder.write(rf, reg_num, val) - elsif ADLToLiraUtils::SPECIAL_REGS.include?(reg_var.name.to_s) - ef = ADLToLiraUtils.find_env_func(@arch_builder, "setPC", [32], []) - if ef.nil? - warn "Environment function 'setPC' not registered, skipping statement" - return nil + end + end + + class WriteRegHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + reg_var, val = oprnds[0], resolved(oprnds[1]) + return if val.nil? + idx = operand_names.index(reg_var.name.to_s) + if idx + reg_num = builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) + rf_name = reg_var.regset.to_s + rf = arch_builder.register_files.find { |r| r.name == rf_name } + unless rf + warn "Register file '#{rf_name}' not found, skipping statement" + return + end + builder.write(rf, reg_num, val) + elsif ADLToLiraUtils::SPECIAL_REGS.include?(reg_var.name.to_s) + ef = ADLToLiraUtils.find_env_func(arch_builder, 'setPC', [32], []) + unless ef + warn "Environment function 'setPC' not registered, skipping statement" + return + end + builder.env(ef, [val]) + else + warn "Register file '#{reg_var.regset}' not found, skipping statement" end - @builder.env(ef, [val]) - else - warn "Register file '#{rf_name}' not found, skipping statement" end - nil end - def process_read_mem(name, oprnds) - out_type = ADLToLiraUtils.convert_type(oprnds[0].type) - addr = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - return nil if addr.nil? - addr_width = addr.width - ef = ADLToLiraUtils.find_env_func(@arch_builder, name.to_s, [addr_width], [out_type]) - if ef.nil? - warn "Environment function #{name} wasn't registered, skipping statement" - return nil + class ReadMemHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + out_type = ADLToLiraUtils.convert_type(oprnds[0].type) + addr = resolved(oprnds[1]) + return if addr.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, stmt.attrs.to_s, [addr.width], [out_type]) + unless ef + warn "Environment function #{stmt.attrs} wasn't registered, skipping statement" + return + end + store(oprnds[0], builder.env(ef, [addr])[0]) end - outs = @builder.env(ef, [addr]) - out = outs[0] - @vars[oprnds[0]] = out - out end - def process_write_mem(name, oprnds) - addr = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - return nil if addr.nil? || val.nil? - addr_width = addr.width - ef = ADLToLiraUtils.find_env_func(@arch_builder, name.to_s, [addr_width, val.width], []) - if ef.nil? - warn "Environment function #{name} wasn't registered, skipping statement" - return nil - end - @builder.env(ef, [addr, val]) - nil - end - - def process_extract(oprnds) - val = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - return nil if val.nil? - hi = oprnds[2].value - lo = oprnds[3].value - width = hi - lo + 1 - width = 1 if width < 1 - out = @builder.extract(val, @builder.const(lo, 32), width) - @vars[oprnds[0]] = out - out + class WriteMemHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + addr, val = resolved(oprnds[0]), resolved(oprnds[1]) + return if addr.nil? || val.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, stmt.attrs.to_s, [addr.width, val.width], []) + unless ef + warn "Environment function #{stmt.attrs} wasn't registered, skipping statement" + return + end + builder.env(ef, [addr, val]) + end end - def process_cast_zext(name, oprnds) - dest_type = oprnds[0].type - dest_width = ADLToLiraUtils.convert_type(dest_type) - dest_width = 1 if dest_width < 1 - src = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - return nil if src.nil? - # Truncate if src is wider than the expected source type - src_expected_width = ADLToLiraUtils.convert_type(oprnds[1].type) - if src.width > src_expected_width - src = @builder.extract_low(src, src_expected_width) - end - if src.width == dest_width - out = src - else - if name == :zext || dest_type.to_s.start_with?('u') - out = @builder.extend_zero(src, dest_width) - else - out = @builder.extend_sign(src, dest_width) + class BranchHandler < StmtHandler + def handle(stmt) + target = resolved(stmt.oprnds[0]) + return if target.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, 'setPC', [32], []) + unless ef + warn "Environment function 'setPC' not registered, skipping statement" + return end + builder.env(ef, [target]) end - @vars[oprnds[0]] = out - out end - def stmt_to_lira(stmt) - name = stmt.name - oprnds = stmt.oprnds + class SysCallHandler < StmtHandler + def handle(stmt) + ef = ADLToLiraUtils.find_env_func(arch_builder, 'sysCall', [], []) + unless ef + warn "Environment function 'sysCall' not registered, skipping statement" + return + end + builder.env(ef, []) + end + end - case name - when :new_var - var = oprnds[0] - width = ADLToLiraUtils.convert_type(var.type) - width = 1 if width < 1 - val = @builder.seq.new_temp(width) - @vars[var] = val + class RemHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + a, b = resolved(oprnds[1]), resolved(oprnds[2]) + return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + store(oprnds[0], unsigned ? builder.rem_u(a, b) : builder.rem_s(a, b)) + end + end - when :let - lhs, rhs = oprnds - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, @operand_names, @arch_builder) - @vars[lhs] = rhs_val if rhs_val + class DivHandler < StmtHandler + def handle(stmt) + oprnds = stmt.oprnds + a, b = resolved(oprnds[1]), resolved(oprnds[2]) + return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') + default_val = builder.const(0, a.width) + store(oprnds[0], unsigned ? builder.div_u(a, b, default_val) : builder.div_s(a, b, default_val)) + end + end - when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr - out = process_binary_op(name, oprnds) - @vars[oprnds[0]] = out if out + HANDLER_MAP = { + new_var: NewVarHandler, + let: LetHandler, + add: AluOpHandler, + sub: AluOpHandler, + mul: AluOpHandler, + and: AluOpHandler, + or: AluOpHandler, + xor: AluOpHandler, + shl: AluOpHandler, + shr: AluOpHandler, + ashr: AluOpHandler, - when :lt, :gt, :le, :ge, :eq, :ne - out = process_cmp_op(name, oprnds) - @vars[oprnds[0]] = out if out + lt: CmpOpHandler, + gt: CmpOpHandler, + le: CmpOpHandler, + ge: CmpOpHandler, + eq: CmpOpHandler, + ne: CmpOpHandler, - when :select - cond = ADLToLiraUtils.resolve_operand(oprnds[1], @builder, @vars, @operand_names, @arch_builder) - t = ADLToLiraUtils.resolve_operand(oprnds[2], @builder, @vars, @operand_names, @arch_builder) - f = ADLToLiraUtils.resolve_operand(oprnds[3], @builder, @vars, @operand_names, @arch_builder) - return if cond.nil? || t.nil? || f.nil? - cond = ADLToLiraUtils.ensure_width(cond, 1, @builder) - out = @builder.select(cond, t, f) - @vars[oprnds[0]] = out + select: SelectHandler, - when :extract - process_extract(oprnds) + cast: CastHandler, zext: CastHandler, - when :cast, :zext - process_cast_zext(name, oprnds) + extract: ExtractHandler, - when :readReg - process_read_reg(oprnds) + readReg: ReadRegHandler, + writeReg: WriteRegHandler, - when :writeReg - process_write_reg(oprnds) + readMem: ReadMemHandler, + writeMem: WriteMemHandler, - when :readMem - process_read_mem(stmt.attrs, oprnds) + branch: BranchHandler, + sysCall: SysCallHandler, - when :writeMem - process_write_mem(stmt.attrs, oprnds) + rem: RemHandler, + div: DivHandler, + }.freeze - when :branch - target = ADLToLiraUtils.resolve_operand(oprnds[0], @builder, @vars, @operand_names, @arch_builder) - return if target.nil? - ef = ADLToLiraUtils.find_env_func(@arch_builder, "setPC", [32], []) - if ef.nil? - warn "Environment function 'setPC' not registered, skipping statement" - return - end - @builder.env(ef, [target]) + DECODE_HANDLER_MAP = HANDLER_MAP.merge( + let: DecodeLetHandler, + cast: DecodeCastHandler, + zext: DecodeCastHandler, + ).freeze - when :sysCall - ef = ADLToLiraUtils.find_env_func(@arch_builder, "sysCall", [], []) - if ef.nil? - warn "Environment function 'sysCall' not registered, skipping statement" - return - end - @builder.env(ef, []) + attr_reader :builder, :vars, :operand_names, :arch_builder + attr_accessor :current_instr, :raw_enc + + def initialize(arch_name, arch_attributes = []) + @arch_name = arch_name + @arch_attributes = arch_attributes + @arch_builder = nil + @builder = nil + @vars = nil + @operand_names = nil + @current_instr = nil + + @decode_cache = {} + @decode_snip_id = 0 + end + + def resolved(op) + ADLToLiraUtils.resolve_operand(op, @builder, @vars, @operand_names, @arch_builder) + end - when :rem - process_rem(oprnds) + def store_result(var, val) + @vars[var] = val if val + val + end - when :div - process_div(oprnds) + def op_alu(adl_name, lhs_signed, a, b) + op_name = adl_name == :shr && lhs_signed ? :ashr : adl_name + op_class = OP_MAP[op_name] or raise "Unknown ALU op: #{adl_name}" + w = [a.width, b.width].max + a = @builder.ensure_width(a, w) + b = @builder.ensure_width(b, w) + out = @builder.seq.new_temp(w) + @builder.seq.add_op(op_class.new(w), [a.name, b.name], [out.name]) + out + end + def op_cmp(adl_name, unsigned, a, b) + op_map = unsigned ? CMP_OP_MAP_U : CMP_OP_MAP_S + op_class = op_map[adl_name] or raise "Unknown cmp op: #{adl_name}" + w = [a.width, b.width].max + a = @builder.ensure_width(a, w) + b = @builder.ensure_width(b, w) + out = @builder.seq.new_temp(1) + @builder.seq.add_op(op_class.new(w), [a.name, b.name], [out.name]) + out + end + + def widen_or_truncate(name, dest_type, src, src_type) + dest_width = ADLToLiraUtils.convert_type(dest_type) + dest_width = 1 if dest_width < 1 + src_expected_width = ADLToLiraUtils.convert_type(src_type) + src = @builder.extract_low(src, src_expected_width) if src.width > src_expected_width + return src if src.width == dest_width + if name == :zext || dest_type.to_s.start_with?('u') + @builder.extend_zero(src, dest_width) else - raise "Unhandled statement: #{name}" + @builder.extend_sign(src, dest_width) end end + def stmt_to_lira(stmt) + handler_class = HANDLER_MAP[stmt.name] or raise "Unhandled statement: #{stmt.name}" + handler_class.new(self).handle(stmt) + end + def generate_semantic(instr) return Lira::StatementSeq.new([]) if instr.code.tree.empty? @@ -277,92 +413,21 @@ def generate_semantic(instr) ) @vars = {} @operand_names = collect_operand_names(instr) - instr.code.tree.each do |stmt| - stmt_to_lira(stmt) - end + instr.code.tree.each { |stmt| stmt_to_lira(stmt) } @builder.seq.build end def generate_decode_snippets(instr, operand_vars) decode_snippet_names = [] - @builder = Lira::SnippetBuilder.new("temp_decode") + @builder = Lira::SnippetBuilder.new('temp_decode') @vars = {} - enc = @builder.input(0, 32) + @current_instr = instr + @raw_enc = @builder.input(0, 32) instr.map.tree.each do |stmt| - name = stmt.name - oprnds = stmt.oprnds - - case name - when :new_var - v = oprnds[0] - width = ADLToLiraUtils.convert_type(v.type) - width = 1 if width < 1 - val = @builder.seq.new_temp(width) - @vars[v] = val - - when :let - lhs, rhs = oprnds - if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') - field_name = rhs.name.to_s[2..-1] - field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } - if field - val = ADLToLiraUtils.extract_field(@builder, enc, field, lhs.type) - @vars[lhs] = val - else - warn "Field #{field_name} not found" - end - else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) - @vars[lhs] = rhs_val if rhs_val - end - - when :cast, :zext - lhs, rhs = oprnds - src = @vars[rhs] - if src - dest_type = lhs.type - dest_width = ADLToLiraUtils.convert_type(dest_type) - dest_width = 1 if dest_width < 1 - src_expected_width = ADLToLiraUtils.convert_type(rhs.type) - if src.width > src_expected_width - src = @builder.extract_low(src, src_expected_width) - end - if src.width == dest_width - val = src - else - if name == :zext || dest_type.to_s.start_with?('u') - val = @builder.extend_zero(src, dest_width) - else - val = @builder.extend_sign(src, dest_width) - end - end - @vars[lhs] = val - elsif rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') - field_name = rhs.name.to_s[2..-1] - field = instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } - if field - val = ADLToLiraUtils.extract_field(@builder, enc, field, lhs.type) - @vars[lhs] = val - else - warn "Field #{field_name} not found" - end - else - rhs_val = ADLToLiraUtils.resolve_operand(rhs, @builder, @vars, [], @arch_builder) - @vars[lhs] = rhs_val if rhs_val - end - - when :add, :sub, :mul, :and, :or, :xor, :shl, :shr, :ashr - out = process_binary_op(name, oprnds) - @vars[oprnds[0]] = out if out - - when :lt, :gt, :le, :ge, :eq, :ne - out = process_cmp_op(name, oprnds) - @vars[oprnds[0]] = out if out - - else - # Ignore other statements in decode snippet - end + handler_class = DECODE_HANDLER_MAP[stmt.name] + next unless handler_class + handler_class.new(self).handle(stmt) end operand_vars.each_with_index do |var, idx| @@ -384,10 +449,11 @@ def generate_decode_snippets(instr, operand_vars) decode_snippet_names << unique_name end decode_snippet_names + ensure + @current_instr = nil end - - # NOTE: Temporary disabled + # NOTE: It was temporary disabled # def generate_encode_snippet(instr, operand_vars) # @builder = Lira::SnippetBuilder.new("temp_encode") # @@ -457,10 +523,10 @@ def convert_instruction(instr) operand_vars = collect_operand_vars(instr) operand_names = collect_operand_names(instr) @operand_names = operand_names + @current_instr = instr semantic = generate_semantic(instr) decode_snippets = [] - encode_snippet = nil if instr.map.tree.any? && operand_vars.any? decode_snippets = generate_decode_snippets(instr, operand_vars) end @@ -475,16 +541,17 @@ def convert_instruction(instr) low_bit = field.to high_bit = field.from width = high_bit - low_bit + 1 - if !value_num.nil? + unless value_num.nil? const_part |= (value_num << low_bit) const_mask |= (((1 << width) - 1) << low_bit) end end operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } - encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, '', '', '') Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) + ensure + @current_instr = nil end def build_arch @@ -492,8 +559,7 @@ def build_arch SimInfra.class_variable_get(:@@regfiles).each do |rf| regs = rf.regs.map do |reg| - attrs = reg.attrs.map(&:to_s) - Lira::Register.new(reg.name.to_s, attrs) + Lira::Register.new(reg.name.to_s, reg.attrs.map(&:to_s)) end lira_rf = Lira::RegisterFile.new(rf.name.to_s, [], Lira::Shape.new(32, nil), regs) @arch_builder.add_register_file(lira_rf) @@ -508,8 +574,8 @@ def build_arch @arch_builder.add_env_func(lira_ef) end - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("getPC", [], [], [32])) - @arch_builder.add_env_func(Lira::EnvironmentFunction.new("setPC", [], [32], [])) + @arch_builder.add_env_func(Lira::EnvironmentFunction.new('getPC', [], [], [32])) + @arch_builder.add_env_func(Lira::EnvironmentFunction.new('setPC', [], [32], [])) SimInfra.class_variable_get(:@@instructions).each do |instr| begin @@ -541,7 +607,7 @@ def load_target(path) end end -def extract_arch_name(loaded_modules) +def extract_arch_name(_loaded_modules) target_name = nil ObjectSpace.each_object(Module) do |mod| if mod.is_a?(Module) && mod.name && mod.name !~ /^SimInfra/ && mod.constants.include?(:XRegs) @@ -549,7 +615,7 @@ def extract_arch_name(loaded_modules) break end end - target_name ||= "TargetArch" + target_name ||= 'TargetArch' [target_name, []] end From e65c78ad847dc72995028058237577691ada25c3 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 02:28:20 +0300 Subject: [PATCH 50/75] [simgen] Cpp Codegen major refactoring * Refactoring from procedural to OOP code generation pattern * Base ops implementations (C) were moved from LIRA library into cpp_ops module --- lib/lira/ir_ops.rb | 354 ++++++++------------------ sim_gen_lira/base_ops_gen.rb | 2 +- sim_gen_lira/cpp_gen.rb | 472 +++++++++++++++++++++-------------- sim_gen_lira/cpp_ops.rb | 282 +++++++++++++++++++++ 4 files changed, 669 insertions(+), 441 deletions(-) create mode 100644 sim_gen_lira/cpp_ops.rb diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index e2ef561..2505f56 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -1,6 +1,5 @@ # lira/ir_ops.rb require_relative 'arch' -require_relative '../Utility/helper_cpp' module Lira class TypeCheckError < StandardError; end @@ -18,75 +17,11 @@ def generate_name end end - def cpp_func_name - generate_name - end - - def cpp_return_type - Utility::HelperCpp.gen_type(outputs[0]) - end - - def cpp_params - inputs.map.with_index { |w, i| "#{Utility::HelperCpp.gen_type(w)} #{('a'.ord + i).chr}" }.join(", ") - end - - def cpp_body - case semantic_base - when 'not' then 'return ~a;' - when 'neg' then 'return -a;' - when 'add' then 'return a + b;' - when 'sub' then 'return a - b;' - when 'mul' then 'return a * b;' - when 'and' then 'return a & b;' - when 'orr' then 'return a | b;' - when 'xor' then 'return a ^ b;' - when 'eq' then 'return (a == b) ? 1 : 0;' - when 'ne' then 'return (a != b) ? 1 : 0;' - when 'slt' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a < (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" - when 'sle' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a <= (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" - when 'sgt' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a > (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" - when 'sge' then "return ((#{Utility::HelperCpp.gen_type(inputs[0], true)})a >= (#{Utility::HelperCpp.gen_type(inputs[0], true)})b) ? 1 : 0;" - when 'ult' then "return (a < b) ? 1 : 0;" - when 'ule' then "return (a <= b) ? 1 : 0;" - when 'ugt' then "return (a > b) ? 1 : 0;" - when 'uge' then "return (a >= b) ? 1 : 0;" - when 'lsl' then "b &= #{inputs[0] - 1}; return a << b;" - when 'lsr' then "b &= #{inputs[0] - 1}; return a >> b;" - when 'asr' then "b &= #{inputs[0] - 1}; return (#{Utility::HelperCpp.gen_type(inputs[0])})((#{Utility::HelperCpp.gen_type(inputs[0], true)})a >> b);" - when 'div_u' then 'return (b == 0) ? c : a / b;' - when 'div_s' then "return (b == 0) ? c : (#{Utility::HelperCpp.gen_type(inputs[0])})((#{Utility::HelperCpp.gen_type(inputs[0], true)})a / (#{Utility::HelperCpp.gen_type(inputs[0], true)})b);" - when 'select' then 'return cond ? a : b;' - when 'rem_u' then - <<~CPP - if (b == 0) return a; - return a % b; - CPP - when 'rem_s' then - <<~CPP - if (b == 0) return a; - #{Utility::HelperCpp.gen_type(inputs[0], true)} res = (#{Utility::HelperCpp.gen_type(inputs[0], true)})a % (#{Utility::HelperCpp.gen_type(inputs[0], true)})b; - return (#{Utility::HelperCpp.gen_type(inputs[0])})res; - CPP - else - raise "No cpp_body defined for operation #{semantic_base}" - end - end - - def to_cpp - body_indented = cpp_body.lines.map { |l| " #{l.chomp}" }.join("\n") - <<~CPP - static inline #{cpp_return_type} #{cpp_func_name}(#{cpp_params}) { - #{body_indented} - } - CPP - end - def self.standard_sizes [8, 16, 32, 64, 128] end end - class UnaryOp < Operation include StdOperation @@ -99,9 +34,9 @@ def initialize(out_bits, name: nil, semantic_base: nil) end def check_signature - raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 - raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 - raise TypeCheckError, "input != output" unless inputs[0] == outputs[0] + raise TypeCheckError, 'input width must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'output width must be positive' unless outputs[0] > 0 + raise TypeCheckError, 'input != output' unless inputs[0] == outputs[0] end end @@ -117,9 +52,9 @@ def initialize(bits, name: nil, semantic_base: nil) end def check_signature - raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 - raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 - raise TypeCheckError, "output must be positive" unless outputs[0] > 0 + raise TypeCheckError, 'input[0] must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'input[1] must be positive' unless inputs[1] > 0 + raise TypeCheckError, 'output must be positive' unless outputs[0] > 0 unless inputs[0] == inputs[1] && inputs[0] == outputs[0] raise TypeCheckError, "mismatched widths: #{inputs} -> #{outputs[0]}" end @@ -141,15 +76,11 @@ def generate_name "#{base_name}_#{inputs[0]}" end - def cpp_return_type - Utility::HelperCpp.gen_type(1) - end - def check_signature - raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 - raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 - raise TypeCheckError, "output must be positive" unless outputs[0] > 0 - raise TypeCheckError, "input widths differ" unless inputs[0] == inputs[1] + raise TypeCheckError, 'input[0] must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'input[1] must be positive' unless inputs[1] > 0 + raise TypeCheckError, 'output must be positive' unless outputs[0] > 0 + raise TypeCheckError, 'input widths differ' unless inputs[0] == inputs[1] end end @@ -165,10 +96,10 @@ def initialize(bits, name: nil, semantic_base: nil) end def check_signature - raise TypeCheckError, "input[0] must be positive" unless inputs[0] > 0 - raise TypeCheckError, "input[1] must be positive" unless inputs[1] > 0 - raise TypeCheckError, "input[2] must be positive" unless inputs[2] > 0 - raise TypeCheckError, "output must be positive" unless outputs[0] > 0 + raise TypeCheckError, 'input[0] must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'input[1] must be positive' unless inputs[1] > 0 + raise TypeCheckError, 'input[2] must be positive' unless inputs[2] > 0 + raise TypeCheckError, 'output must be positive' unless outputs[0] > 0 unless inputs[0] == inputs[1] && inputs[0] == inputs[2] && inputs[0] == outputs[0] raise TypeCheckError, "mismatched widths: #{inputs} -> #{outputs[0]}" end @@ -186,22 +117,14 @@ def initialize(in_bits, out_bits, kind, name: nil) end def check_signature - raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 - raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 - raise TypeCheckError, "input >= output" unless inputs[0] < outputs[0] + raise TypeCheckError, 'input width must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'output width must be positive' unless outputs[0] > 0 + raise TypeCheckError, 'input >= output' unless inputs[0] < outputs[0] end def generate_name "#{semantic_base}_#{inputs[0]}_to_#{outputs[0]}" end - - def cpp_return_type - Utility::HelperCpp.gen_type(outputs[0]) - end - - def cpp_params - "#{Utility::HelperCpp.gen_type(outputs[0])} a" - end end class ExtractLowOp < Operation @@ -215,194 +138,126 @@ def initialize(in_bits, out_bits, name: nil) end def check_signature - raise TypeCheckError, "input width must be positive" unless inputs[0] > 0 - raise TypeCheckError, "output width must be positive" unless outputs[0] > 0 - raise TypeCheckError, "output > input" unless outputs[0] <= inputs[0] + raise TypeCheckError, 'input width must be positive' unless inputs[0] > 0 + raise TypeCheckError, 'output width must be positive' unless outputs[0] > 0 + raise TypeCheckError, 'output > input' unless outputs[0] <= inputs[0] end def generate_name "extract_low_#{inputs[0]}_to_#{outputs[0]}" end + end - def cpp_return_type - Utility::HelperCpp.gen_type(outputs[0]) - end + class Not < UnaryOp + def initialize(bits); super(bits, semantic_base: 'not'); end + end - def cpp_params - "#{Utility::HelperCpp.gen_type(outputs[0])} a" - end + class Neg < UnaryOp + def initialize(bits); super(bits, semantic_base: 'neg'); end + end + + class Add < BinaryOp + def initialize(bits); super(bits, semantic_base: 'add'); end + end + + class Sub < BinaryOp + def initialize(bits); super(bits, semantic_base: 'sub'); end + end + + class Mul < BinaryOp + def initialize(bits); super(bits, semantic_base: 'mul'); end + end + + class And < BinaryOp + def initialize(bits); super(bits, semantic_base: 'and'); end + end + + class Orr < BinaryOp + def initialize(bits); super(bits, semantic_base: 'orr'); end + end + + class Xor < BinaryOp + def initialize(bits); super(bits, semantic_base: 'xor'); end + end + + class Lsl < BinaryOp + def initialize(bits); super(bits, semantic_base: 'lsl'); end + end + + class Lsr < BinaryOp + def initialize(bits); super(bits, semantic_base: 'lsr'); end end - class Not < UnaryOp; def initialize(bits); super(bits, semantic_base: 'not'); end; end - class Neg < UnaryOp; def initialize(bits); super(bits, semantic_base: 'neg'); end; end - class Add < BinaryOp; def initialize(bits); super(bits, semantic_base: 'add'); end; end - class Sub < BinaryOp; def initialize(bits); super(bits, semantic_base: 'sub'); end; end - class Mul < BinaryOp; def initialize(bits); super(bits, semantic_base: 'mul'); end; end - class And < BinaryOp; def initialize(bits); super(bits, semantic_base: 'and'); end; end - class Orr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'orr'); end; end - class Xor < BinaryOp; def initialize(bits); super(bits, semantic_base: 'xor'); end; end - class Lsl < BinaryOp; def initialize(bits); super(bits, semantic_base: 'lsl'); end; end - class Lsr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'lsr'); end; end - class Asr < BinaryOp; def initialize(bits); super(bits, semantic_base: 'asr'); end; end - class Eq < CmpOp; def initialize(bits); super(bits, semantic_base: 'eq'); end; end - class Ne < CmpOp; def initialize(bits); super(bits, semantic_base: 'ne'); end; end - class Slt < CmpOp; def initialize(bits); super(bits, semantic_base: 'slt'); end; end - class Sle < CmpOp; def initialize(bits); super(bits, semantic_base: 'sle'); end; end - class Sgt < CmpOp; def initialize(bits); super(bits, semantic_base: 'sgt'); end; end - class Sge < CmpOp; def initialize(bits); super(bits, semantic_base: 'sge'); end; end - class Ult < CmpOp; def initialize(bits); super(bits, semantic_base: 'ult'); end; end - class Ule < CmpOp; def initialize(bits); super(bits, semantic_base: 'ule'); end; end - class Ugt < CmpOp; def initialize(bits); super(bits, semantic_base: 'ugt'); end; end - class Uge < CmpOp; def initialize(bits); super(bits, semantic_base: 'uge'); end; end + class Asr < BinaryOp + def initialize(bits); super(bits, semantic_base: 'asr'); end + end + + class Eq < CmpOp + def initialize(bits); super(bits, semantic_base: 'eq'); end + end + + class Ne < CmpOp + def initialize(bits); super(bits, semantic_base: 'ne'); end + end + + class Slt < CmpOp + def initialize(bits); super(bits, semantic_base: 'slt'); end + end + + class Sle < CmpOp + def initialize(bits); super(bits, semantic_base: 'sle'); end + end + + class Sgt < CmpOp + def initialize(bits); super(bits, semantic_base: 'sgt'); end + end + + class Sge < CmpOp + def initialize(bits); super(bits, semantic_base: 'sge'); end + end + + class Ult < CmpOp + def initialize(bits); super(bits, semantic_base: 'ult'); end + end + + class Ule < CmpOp + def initialize(bits); super(bits, semantic_base: 'ule'); end + end + + class Ugt < CmpOp + def initialize(bits); super(bits, semantic_base: 'ugt'); end + end + + class Uge < CmpOp + def initialize(bits); super(bits, semantic_base: 'uge'); end + end class ExtendSign < ExtendOp def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end - def cpp_body - <<~ะกPP - #{Utility::HelperCpp.gen_type(outputs[0])} val = a & (((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1); - #{Utility::HelperCpp.gen_type(outputs[0])} sign = (val >> (#{inputs[0]} - 1)) & 1; - if (sign) - return val | (~(((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1)); - else - return val; - ะกPP - end end class ExtendZero < ExtendOp def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end - def cpp_body - "return a & (((#{Utility::HelperCpp.gen_type(outputs[0])})1 << #{inputs[0]}) - 1);" - end end class ExtractLow < ExtractLowOp def initialize(in_bits, out_bits); super(in_bits, out_bits); end - def cpp_body - "return a & (((#{Utility::HelperCpp.gen_type(inputs[0])})1 << #{outputs[0]}) - 1);" - end end class Popcnt < UnaryOp def initialize(bits); super(bits, semantic_base: 'popcnt'); end - def cpp_body - case inputs[0] - when 8 - <<~ะกPP - unsigned cnt = 0; - while (a) { cnt += a & 1; a >>= 1; } - return cnt; - ะกPP - when 16 - "return popcnt_8(a & 0xFF) + popcnt_8((a >> 8) & 0xFF);" - when 32 - "return popcnt_16(a & 0xFFFF) + popcnt_16((a >> 16) & 0xFFFF);" - when 64 - "return popcnt_32(a & 0xFFFFFFFF) + popcnt_32((a >> 32) & 0xFFFFFFFF);" - when 128 - "return popcnt_64((uint64_t)a) + popcnt_64((uint64_t)(a >> 64));" - else - raise "Unsupported popcnt size" - end - end end class Ctz < UnaryOp def initialize(bits); super(bits, semantic_base: 'ctz'); end - def cpp_body - bits = inputs[0] - if bits == 128 - <<~ะกPP - if (a == 0) return 128; - uint64_t lo = (uint64_t)a; - if (lo) return ctz_64(lo); - else return 64 + ctz_64((uint64_t)(a >> 64)); - ะกPP - else - <<~ะกPP - if (a == 0) return #{bits}; - unsigned n = 0; - while ((a & 1) == 0) { a >>= 1; n++; } - return n; - ะกPP - end - end end class Clz < UnaryOp def initialize(bits); super(bits, semantic_base: 'clz'); end - def cpp_body - bits = inputs[0] - if bits == 128 - <<~ะกPP - if (a == 0) return 128; - uint64_t hi = (uint64_t)(a >> 64); - if (hi) return clz_64(hi); - else return 64 + clz_64((uint64_t)a); - ะกPP - else - mask = case bits - when 8 then "0x80" - when 16 then "0x8000" - when 32 then "0x80000000" - when 64 then "0x8000000000000000ULL" - end - <<~ะกPP - if (a == 0) return #{bits}; - unsigned n = 0; - while ((a & #{mask}) == 0) { a <<= 1; n++; } - return n; - ะกPP - end - end end class Reverse < UnaryOp def initialize(bits); super(bits, semantic_base: 'reverse'); end - def cpp_body - case inputs[0] - when 8 - <<~ะกPP - a = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4); - a = ((a & 0xCC) >> 2) | ((a & 0x33) << 2); - a = ((a & 0xAA) >> 1) | ((a & 0x55) << 1); - return a; - ะกPP - when 16 - <<~ะกPP - a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8); - a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4); - a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2); - a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1); - return a; - ะกPP - when 32 - <<~ะกPP - a = ((a & 0xFFFF0000) >> 16) | ((a & 0x0000FFFF) << 16); - a = ((a & 0xFF00FF00) >> 8) | ((a & 0x00FF00FF) << 8); - a = ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); - a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); - a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); - return a; - ะกPP - when 64 - <<~ะกPP - a = ((a & 0xFFFFFFFF00000000ULL) >> 32) | ((a & 0x00000000FFFFFFFFULL) << 32); - a = ((a & 0xFFFF0000FFFF0000ULL) >> 16) | ((a & 0x0000FFFF0000FFFFULL) << 16); - a = ((a & 0xFF00FF00FF00FF00ULL) >> 8) | ((a & 0x00FF00FF00FF00FFULL) << 8); - a = ((a & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((a & 0x0F0F0F0F0F0F0F0FULL) << 4); - a = ((a & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((a & 0x3333333333333333ULL) << 2); - a = ((a & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((a & 0x5555555555555555ULL) << 1); - return a; - ะกPP - when 128 - <<~ะกPP - uint64_t lo = (uint64_t)a; - uint64_t hi = (uint64_t)(a >> 64); - return ((uint128_t)reverse_64(lo) << 64) | reverse_64(hi); - ะกPP - end - end end class RemU < BinaryOp @@ -443,6 +298,7 @@ def base_name; 'div_s'; end class Select < Operation include StdOperation + def initialize(bits) name = "select_#{bits}" super(name, [], [1, bits, bits], [bits], @@ -451,11 +307,7 @@ def initialize(bits) end def check_signature - raise TypeCheckError, "true/false branches mismatch" unless inputs[1] == inputs[2] && inputs[1] == outputs[0] - end - - def cpp_params - "uint8_t cond, #{Utility::HelperCpp.gen_type(inputs[1])} a, #{Utility::HelperCpp.gen_type(inputs[1])} b" + raise TypeCheckError, 'true/false branches mismatch' unless inputs[1] == inputs[2] && inputs[1] == outputs[0] end end end diff --git a/sim_gen_lira/base_ops_gen.rb b/sim_gen_lira/base_ops_gen.rb index 228aaa7..f100a17 100644 --- a/sim_gen_lira/base_ops_gen.rb +++ b/sim_gen_lira/base_ops_gen.rb @@ -1,5 +1,5 @@ require 'stringio' -require_relative '../lib/lira/ir_ops' +require_relative 'cpp_ops' module SimGen def self.generate_base_ops diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index ebe933f..e835d44 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -1,243 +1,329 @@ +# frozen_string_literal: true + require_relative '../lib/lira/ir' +require_relative 'cpp_ops' require_relative '../lib/Utility/helper_cpp' module LiraCppGen - class Translator - def initialize(seq, context = :execute, indent = 0) - @seq = seq - @context = context - @indent = indent - @output = [] - @var_widths = {} - end + module OpRegistry + BASE_TO_CLASS = { + 'not' => Lira::Not, + 'neg' => Lira::Neg, + 'popcnt' => Lira::Popcnt, + 'clz' => Lira::Clz, + 'ctz' => Lira::Ctz, + 'reverse' => Lira::Reverse, + 'add' => Lira::Add, + 'sub' => Lira::Sub, + 'mul' => Lira::Mul, + 'and' => Lira::And, + 'orr' => Lira::Orr, + 'xor' => Lira::Xor, + 'lsl' => Lira::Lsl, + 'lsr' => Lira::Lsr, + 'asr' => Lira::Asr, + 'eq' => Lira::Eq, + 'ne' => Lira::Ne, + 'slt' => Lira::Slt, + 'sle' => Lira::Sle, + 'sgt' => Lira::Sgt, + 'sge' => Lira::Sge, + 'ult' => Lira::Ult, + 'ule' => Lira::Ule, + 'ugt' => Lira::Ugt, + 'uge' => Lira::Uge, + 'div_s' => Lira::DivS, + 'div_u' => Lira::DivU, + 'rem_s' => Lira::RemS, + 'rem_u' => Lira::RemU, + 'ror' => Lira::Ror, + 'rol' => Lira::Rol, + 'add_overflow' => Lira::AddOverflow, + 'sub_overflow' => Lira::SubOverflow, + 'select' => Lira::Select, + }.freeze - def translate - @seq.stmts.each { |stmt| translate_stmt(stmt) } - @output.join("\n") + SPECIAL = [ + [/^extend_sign_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtendSign.new(m[1].to_i, m[2].to_i) }], + [/^extend_zero_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtendZero.new(m[1].to_i, m[2].to_i) }], + [/^extract_low_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtractLow.new(m[1].to_i, m[2].to_i) }] + ].freeze + + def self.lookup(specifier) + SPECIAL.each do |pattern, factory| + m = specifier.match(pattern) + return factory.call(m) if m + end + parse_standard(specifier) or raise "Unknown operation: #{specifier}" end - private + def self.parse_standard(specifier) + parts = specifier.split('_') + return nil unless parts.last.match?(/^\d+$/) - def resolve_var(name, stmt = nil) - return name if @var_widths.key?(name) - if name =~ /^_t\d+$/ - width = 32 - if stmt && stmt.respond_to?(:outputs_types) && stmt.outputs_types.any? - width = stmt.outputs_types[0] - end - emit("#{Utility::HelperCpp.gen_type(width)} #{name} = 0;") - @var_widths[name] = width - return name + width = parts.pop.to_i + (1..parts.size).reverse_each do |len| + base = parts[0...len].join('_') + klass = BASE_TO_CLASS[base] + return klass.new(width) if klass end - raise "Unknown variable #{name} in #{stmt&.inspect}" + nil end + end - def translate_stmt(stmt) - case stmt.kind - when 'op' then translate_op(stmt) - when 'const' then translate_const(stmt) - when 'dyn_const' then translate_dyn_const(stmt) - when 'read' then translate_read(stmt) - when 'write' then translate_write(stmt) - when 'env' then translate_env(stmt) - when 'cond_env' then translate_cond_env(stmt) - when 'input' then translate_input(stmt) - when 'output' then translate_output(stmt) - else raise "Unknown statement kind: #{stmt.kind}" - end + class StmtEmitter + def initialize(translator) + @t = translator end - def translate_op(stmt) - op_full = stmt.specifier - out = stmt.outputs[0] - out_width = stmt.outputs_types[0] - inputs = stmt.inputs.map { |i| resolve_var(i, stmt) } + def stmt + @t.current_stmt + end - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(out_width)} #{out};") - @var_widths[out] = out_width - end + def emit(line) + @t.emit(line) + end - base_op = op_full.sub(/_\d+$/, '') + def indent(&block) + @t.indent(&block) + end - if ['div_u', 'div_s', 'divs', 'divu'].include?(base_op) - func = base_op == 'divs' ? 'div_s' : (base_op == 'divu' ? 'div_u' : base_op) - func = "#{func}_#{out_width}" - emit("#{out} = #{func}(#{inputs[0]}, #{inputs[1]}, #{inputs[2]});") - return - end + def context + @t.context + end + + def resolve_var(name) + @t.resolve_var(name, stmt) + end + + def declare(name, width) + @t.declare_var(name, width) + end + + def var_width(name) + @t.var_width(name) + end - case base_op - when 'select' + def emit_code + raise NotImplementedError + end + end + + class OpEmitter < StmtEmitter + def emit_code + s = stmt + out = s.outputs[0] + declare(out, s.outputs_types[0]) + inputs = s.inputs.map { |i| resolve_var(i) } + op = OpRegistry.lookup(s.specifier) + + if op.semantic_base == 'select' emit("#{out} = #{inputs[0]} ? #{inputs[1]} : #{inputs[2]};") - when 'extract_low' - emit("#{out} = extract_low_#{out_width}(#{inputs[0]});") - when 'extend_sign', 'extend_zero' - in_width = @var_widths[inputs[0]] || 1 - func = "#{base_op}_#{in_width}_#{out_width}" - emit("#{out} = #{func}(#{inputs[0]});") else - if out_width == 1 && ['eq','ne','slt','sle','sgt','sge','ult','ule','ugt','uge'].include?(base_op) - a, b = inputs - func = "#{base_op}_32" - emit("#{out} = #{func}(#{a}, #{b});") - return - end - - func_name = base_op - if base_op == 'rem' - func_name = 'rem_s' - elsif base_op == 'rems' - func_name = 'rem_s' - elsif base_op == 'remu' - func_name = 'rem_u' - end - func = "#{func_name}_#{out_width}" - if inputs.size == 1 - emit("#{out} = #{func}(#{inputs[0]});") - elsif inputs.size == 2 - emit("#{out} = #{func}(#{inputs[0]}, #{inputs[1]});") - else - raise "Unsupported arity for #{base_op} (#{inputs.size} args)" - end + emit("#{out} = #{op.cpp_func_name}(#{inputs.join(', ')});") end end + end - def translate_const(stmt) - value = stmt.specifier - out = stmt.outputs[0] - width = stmt.outputs_types[0] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{value};") - @var_widths[out] = width - end + class ConstEmitter < StmtEmitter + def emit_code + s = stmt + out = s.outputs[0] + width = s.outputs_types[0] + return if @t.var_declared?(out) + + emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{s.specifier};") + @t.register_var(out, width) end + end - def translate_dyn_const(stmt) - name = stmt.specifier - out = stmt.outputs[0] - width = stmt.outputs_types[0] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{name};") - @var_widths[out] = width - end + class DynConstEmitter < StmtEmitter + def emit_code + s = stmt + out = s.outputs[0] + width = s.outputs_types[0] + return if @t.var_declared?(out) + + emit("#{Utility::HelperCpp.gen_type(width)} #{out} = #{s.specifier};") + @t.register_var(out, width) end + end - def translate_read(stmt) - rf = stmt.specifier - idx = resolve_var(stmt.inputs[0], stmt) - out = stmt.outputs[0] - width = stmt.outputs_types[0] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out};") - @var_widths[out] = width - end - if @context == :execute + class ReadEmitter < StmtEmitter + def emit_code + s = stmt + rf = s.specifier + idx = resolve_var(s.inputs[0]) + out = s.outputs[0] + width = s.outputs_types[0] + declare(out, width) + if context == :execute emit("#{out} = cpu.get#{rf}<#{Utility::HelperCpp.gen_type(width)}>(#{idx});") else emit("#{out} = 0; // read in decode") end end + end - def translate_write(stmt) - rf = stmt.specifier - idx = resolve_var(stmt.inputs[0], stmt) - val = resolve_var(stmt.inputs[1], stmt) - if @context == :execute - emit("cpu.set#{rf}(#{idx}, #{val});") - end + class WriteEmitter < StmtEmitter + def emit_code + s = stmt + rf = s.specifier + idx = resolve_var(s.inputs[0]) + val = resolve_var(s.inputs[1]) + emit("cpu.set#{rf}(#{idx}, #{val});") if context == :execute end + end + class EnvEmitter < StmtEmitter + def emit_code + s = stmt + func = s.specifier + inputs = s.inputs.map { |i| resolve_var(i) } + outputs = s.outputs + out_types = s.outputs_types - def translate_env(stmt) - func = stmt.specifier - inputs = stmt.inputs.map { |i| resolve_var(i, stmt) } - outputs = stmt.outputs - out_types = stmt.outputs_types + func = resolve_env_func(func, out_types, inputs) - if func == 'readMem' && out_types.size == 1 - func = "readMem#{out_types[0]}" - elsif func == 'writeMem' && inputs.size == 2 - val_name = stmt.inputs[1] - width = @var_widths[val_name] || 32 - func = "writeMem#{width}" + return unless context == :execute + + if outputs.empty? + emit("cpu.#{func}(#{inputs.join(', ')});") + elsif outputs.size == 1 + out = outputs[0] + declare(out, out_types[0]) + emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") + else + outputs.each_with_index { |out, i| declare(out, out_types[i]) } + emit("std::tie(#{outputs.join(', ')}) = cpu.#{func}(#{inputs.join(', ')});") end + end + + private - if @context == :execute - if outputs.empty? - emit("cpu.#{func}(#{inputs.join(', ')});") - else - if outputs.size == 1 - out = outputs[0] - width = out_types[0] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out};") - @var_widths[out] = width - end - emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") - else - outputs.each_with_index do |out, i| - width = out_types[i] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out};") - @var_widths[out] = width - end - end - emit("std::tie(#{outputs.join(', ')}) = cpu.#{func}(#{inputs.join(', ')});") - end - end + def resolve_env_func(func, out_types, inputs) + if func == 'readMem' && out_types.size == 1 + "readMem#{out_types[0]}" + elsif func == 'writeMem' && inputs.size >= 2 + width = var_width(stmt.inputs[1]) || 32 + "writeMem#{width}" + else + func end end + end + + class CondEnvEmitter < StmtEmitter + def emit_code + s = stmt + cond = resolve_var(s.inputs[0]) + inputs = s.inputs[1...-s.outputs.size].map { |i| resolve_var(i) } + on_false = s.inputs[-s.outputs.size..].map { |i| resolve_var(i) } + func = s.specifier - def translate_cond_env(stmt) - cond = resolve_var(stmt.inputs[0], stmt) - inputs = stmt.inputs[1...-stmt.outputs.size].map { |i| resolve_var(i, stmt) } - on_false = stmt.inputs[-stmt.outputs.size..-1].map { |i| resolve_var(i, stmt) } - func = stmt.specifier - outputs = stmt.outputs emit("if (#{cond}) {") - indent do - outputs.each_with_index do |out, i| - width = stmt.outputs_types[i] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out};") - @var_widths[out] = width - end - emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") - end - end - emit("} else {") - indent do - outputs.each_with_index do |out, i| - emit("#{out} = #{on_false[i]};") - end - end - emit("}") + indent { emit_cond_true(s, func, inputs) } + emit('} else {') + indent { emit_cond_false(s, on_false) } + emit('}') end - def translate_input(stmt) - idx = stmt.specifier.to_i - out = stmt.outputs[0] - width = stmt.outputs_types[0] - unless @var_widths.key?(out) - emit("#{Utility::HelperCpp.gen_type(width)} #{out};") - @var_widths[out] = width - end - if @context == :decode - emit("#{out} = raw_insn;") - else - emit("#{out} = insn.operand#{idx};") + private + + def emit_cond_true(st, func, inputs) + st.outputs.each_with_index do |out, i| + declare(out, st.outputs_types[i]) + emit("#{out} = cpu.#{func}(#{inputs.join(', ')});") end end - def translate_output(stmt) - val = resolve_var(stmt.inputs[0], stmt) - idx = stmt.specifier.to_i + def emit_cond_false(st, on_false) + st.outputs.each_with_index { |out, i| emit("#{out} = #{on_false[i]};") } + end + end + + class InputEmitter < StmtEmitter + def emit_code + s = stmt + idx = s.specifier.to_i + out = s.outputs[0] + width = s.outputs_types[0] + declare(out, width) + emit(context == :decode ? "#{out} = raw_insn;" : "#{out} = insn.operand#{idx};") + end + end + + class OutputEmitter < StmtEmitter + def emit_code + s = stmt + val = resolve_var(s.inputs[0]) + idx = s.specifier.to_i emit("insn.operand#{idx} = #{val};") end + end + + EMITTER_MAP = { + 'op' => OpEmitter, + 'const' => ConstEmitter, + 'dyn_const' => DynConstEmitter, + 'read' => ReadEmitter, + 'write' => WriteEmitter, + 'env' => EnvEmitter, + 'cond_env' => CondEnvEmitter, + 'input' => InputEmitter, + 'output' => OutputEmitter + }.freeze + + class Translator + attr_reader :context, :current_stmt + + def initialize(seq, context = :execute, indent = 0) + @seq = seq + @context = context + @indent = indent + @output = [] + @var_widths = {} + end + + def translate + @seq.stmts.each { |stmt| translate_stmt(stmt) } + @output.join("\n") + end + + def declare_var(name, width) + return if var_declared?(name) + + emit("#{Utility::HelperCpp.gen_type(width)} #{name};") + register_var(name, width) + end + + def var_declared?(name) + @var_widths.key?(name) + end + + def var_width(name) + @var_widths[name] + end + + def register_var(name, width) + @var_widths[name] = width + end + + def resolve_var(name, stmt) + return name if var_declared?(name) + + if name =~ /^_t\d+$/ + width = 32 + width = stmt.outputs_types[0] if stmt.respond_to?(:outputs_types) && stmt.outputs_types.any? + emit("#{Utility::HelperCpp.gen_type(width)} #{name} = 0;") + register_var(name, width) + return name + end + raise "Unknown variable #{name} in #{stmt&.inspect}" + end def emit(line) - @output << (" " * @indent + line) + @output << (' ' * @indent + line) end def indent @@ -245,5 +331,13 @@ def indent yield @indent -= 2 end + + private + + def translate_stmt(stmt) + emitter_class = EMITTER_MAP[stmt.kind] or raise "Unknown statement kind: #{stmt.kind}" + @current_stmt = stmt + emitter_class.new(self).emit_code + end end end diff --git a/sim_gen_lira/cpp_ops.rb b/sim_gen_lira/cpp_ops.rb new file mode 100644 index 0000000..0a4b17d --- /dev/null +++ b/sim_gen_lira/cpp_ops.rb @@ -0,0 +1,282 @@ +require_relative '../lib/lira/ir_ops' +require_relative '../lib/Utility/helper_cpp' + +module Lira + module CppCodegen + def cpp_func_name + generate_name + end + + def cpp_return_type + Utility::HelperCpp.gen_type(outputs[0]) + end + + def cpp_params + inputs.map.with_index { |w, i| + "#{Utility::HelperCpp.gen_type(w)} #{('a'.ord + i).chr}" + }.join(', ') + end + + def cpp_body + case semantic_base + when 'not' then 'return ~a;' + when 'neg' then 'return -a;' + when 'add' then 'return a + b;' + when 'sub' then 'return a - b;' + when 'mul' then 'return a * b;' + when 'and' then 'return a & b;' + when 'orr' then 'return a | b;' + when 'xor' then 'return a ^ b;' + when 'eq' then 'return (a == b) ? 1 : 0;' + when 'ne' then 'return (a != b) ? 1 : 0;' + when 'slt' then signed_cmp('<') + when 'sle' then signed_cmp('<=') + when 'sgt' then signed_cmp('>') + when 'sge' then signed_cmp('>=') + when 'ult' then 'return (a < b) ? 1 : 0;' + when 'ule' then 'return (a <= b) ? 1 : 0;' + when 'ugt' then 'return (a > b) ? 1 : 0;' + when 'uge' then 'return (a >= b) ? 1 : 0;' + when 'lsl' then "b &= #{inputs[0] - 1}; return a << b;" + when 'lsr' then "b &= #{inputs[0] - 1}; return a >> b;" + when 'asr' then asr_body + when 'div_u' then 'return (b == 0) ? c : a / b;' + when 'div_s' then div_s_body + when 'select' then 'return cond ? a : b;' + when 'rem_u' then rem_u_body + when 'rem_s' then rem_s_body + else raise "No cpp_body defined for operation #{semantic_base}" + end + end + + def to_cpp + body_indented = cpp_body.lines.map { |l| " #{l.chomp}" }.join("\n") + <<~CPP + static inline #{cpp_return_type} #{cpp_func_name}(#{cpp_params}) { + #{body_indented} + } + CPP + end + + private + + def signed_cmp(op) + t = Utility::HelperCpp.gen_type(inputs[0], true) + "return ((#{t})a #{op} (#{t})b) ? 1 : 0;" + end + + def asr_body + t = Utility::HelperCpp.gen_type(inputs[0]) + ts = Utility::HelperCpp.gen_type(inputs[0], true) + "b &= #{inputs[0] - 1}; return (#{t})((#{ts})a >> b);" + end + + def div_s_body + t = Utility::HelperCpp.gen_type(inputs[0]) + ts = Utility::HelperCpp.gen_type(inputs[0], true) + "return (b == 0) ? c : (#{t})((#{ts})a / (#{ts})b);" + end + + def rem_u_body + <<~CPP + if (b == 0) return a; + return a % b; + CPP + end + + def rem_s_body + t = Utility::HelperCpp.gen_type(inputs[0]) + ts = Utility::HelperCpp.gen_type(inputs[0], true) + <<~CPP + if (b == 0) return a; + #{ts} res = (#{ts})a % (#{ts})b; + return (#{t})res; + CPP + end + end + + class UnaryOp; include CppCodegen; end + class BinaryOp; include CppCodegen; end + class CmpOp; include CppCodegen; end + class TernaryOp; include CppCodegen; end + class ExtendOp; include CppCodegen; end + class ExtractLowOp; include CppCodegen; end + class Select; include CppCodegen; end + + class CmpOp + def cpp_return_type + Utility::HelperCpp.gen_type(1) + end + end + + class ExtendOp + def cpp_return_type + Utility::HelperCpp.gen_type(outputs[0]) + end + + def cpp_params + "#{Utility::HelperCpp.gen_type(outputs[0])} a" + end + end + + class ExtractLowOp + def cpp_return_type + Utility::HelperCpp.gen_type(outputs[0]) + end + + def cpp_params + "#{Utility::HelperCpp.gen_type(outputs[0])} a" + end + end + + class Select + def cpp_params + "uint8_t cond, #{Utility::HelperCpp.gen_type(inputs[1])} a, #{Utility::HelperCpp.gen_type(inputs[1])} b" + end + end + + class ExtendSign + def cpp_body + t = Utility::HelperCpp.gen_type(outputs[0]) + <<~CPP + #{t} val = a & (((#{t})1 << #{inputs[0]}) - 1); + #{t} sign = (val >> (#{inputs[0]} - 1)) & 1; + if (sign) + return val | (~(((#{t})1 << #{inputs[0]}) - 1)); + else + return val; + CPP + end + end + + class ExtendZero + def cpp_body + t = Utility::HelperCpp.gen_type(outputs[0]) + "return a & (((#{t})1 << #{inputs[0]}) - 1);" + end + end + + class ExtractLow + def cpp_body + t = Utility::HelperCpp.gen_type(inputs[0]) + "return a & (((#{t})1 << #{outputs[0]}) - 1);" + end + end + + class Popcnt + def cpp_body + case inputs[0] + when 8 + <<~CPP + unsigned cnt = 0; + while (a) { cnt += a & 1; a >>= 1; } + return cnt; + CPP + when 16 + 'return popcnt_8(a & 0xFF) + popcnt_8((a >> 8) & 0xFF);' + when 32 + 'return popcnt_16(a & 0xFFFF) + popcnt_16((a >> 16) & 0xFFFF);' + when 64 + 'return popcnt_32(a & 0xFFFFFFFF) + popcnt_32((a >> 32) & 0xFFFFFFFF);' + when 128 + 'return popcnt_64((uint64_t)a) + popcnt_64((uint64_t)(a >> 64));' + else raise 'Unsupported popcnt size' + end + end + end + + class Ctz + def cpp_body + bits = inputs[0] + if bits == 128 + <<~CPP + if (a == 0) return 128; + uint64_t lo = (uint64_t)a; + if (lo) return ctz_64(lo); + else return 64 + ctz_64((uint64_t)(a >> 64)); + CPP + else + <<~CPP + if (a == 0) return #{bits}; + unsigned n = 0; + while ((a & 1) == 0) { a >>= 1; n++; } + return n; + CPP + end + end + end + + class Clz + def cpp_body + bits = inputs[0] + if bits == 128 + <<~CPP + if (a == 0) return 128; + uint64_t hi = (uint64_t)(a >> 64); + if (hi) return clz_64(hi); + else return 64 + clz_64((uint64_t)a); + CPP + else + mask = case bits + when 8 then '0x80' + when 16 then '0x8000' + when 32 then '0x80000000' + when 64 then '0x8000000000000000ULL' + end + <<~CPP + if (a == 0) return #{bits}; + unsigned n = 0; + while ((a & #{mask}) == 0) { a <<= 1; n++; } + return n; + CPP + end + end + end + + class Reverse + def cpp_body + case inputs[0] + when 8 + <<~CPP + a = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4); + a = ((a & 0xCC) >> 2) | ((a & 0x33) << 2); + a = ((a & 0xAA) >> 1) | ((a & 0x55) << 1); + return a; + CPP + when 16 + <<~CPP + a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8); + a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4); + a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2); + a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1); + return a; + CPP + when 32 + <<~CPP + a = ((a & 0xFFFF0000) >> 16) | ((a & 0x0000FFFF) << 16); + a = ((a & 0xFF00FF00) >> 8) | ((a & 0x00FF00FF) << 8); + a = ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); + a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); + a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); + return a; + CPP + when 64 + <<~CPP + a = ((a & 0xFFFFFFFF00000000ULL) >> 32) | ((a & 0x00000000FFFFFFFFULL) << 32); + a = ((a & 0xFFFF0000FFFF0000ULL) >> 16) | ((a & 0x0000FFFF0000FFFFULL) << 16); + a = ((a & 0xFF00FF00FF00FF00ULL) >> 8) | ((a & 0x00FF00FF00FF00FFULL) << 8); + a = ((a & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((a & 0x0F0F0F0F0F0F0F0FULL) << 4); + a = ((a & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((a & 0x3333333333333333ULL) << 2); + a = ((a & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((a & 0x5555555555555555ULL) << 1); + return a; + CPP + when 128 + <<~CPP + uint64_t lo = (uint64_t)a; + uint64_t hi = (uint64_t)(a >> 64); + return ((uint128_t)reverse_64(lo) << 64) | reverse_64(hi); + CPP + end + end + end +end From b4d18bddcf4e27bdbd9a113319ee1fa25bb31a86 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 03:44:12 +0300 Subject: [PATCH 51/75] [lib, sim_gen] Operations register & look up was supported * Now base operations are committing into operations list on demand * Header base_ops.h contains only base operations that really used in decode & instructions semantic --- lib/lira/ir_ops.rb | 110 +++++++++++++++++------------------ lib/lira_gen.rb | 15 ++++- sim_gen_lira/base_ops_gen.rb | 68 +++------------------- sim_gen_lira/cpp_gen.rb | 64 +------------------- sim_gen_lira/cpp_ops.rb | 5 +- sim_gen_lira/sim_gen.rb | 2 +- 6 files changed, 81 insertions(+), 183 deletions(-) diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 2505f56..f9d99fa 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -16,10 +16,6 @@ def generate_name "#{base_name}_#{outputs.join('_')}" end end - - def self.standard_sizes - [8, 16, 32, 64, 128] - end end class UnaryOp < Operation @@ -310,62 +306,62 @@ def check_signature raise TypeCheckError, 'true/false branches mismatch' unless inputs[1] == inputs[2] && inputs[1] == outputs[0] end end -end -module Lira - class Not; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Neg; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Popcnt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Clz; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Ctz; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Reverse; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Add; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Sub; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Mul; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class And; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Orr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Xor; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Lsl; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Lsr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Asr; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Eq; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Ne; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Slt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Sle; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Sgt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Sge; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Ult; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Ule; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Ugt; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Uge; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class DivU; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class DivS; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - class Select; def self.instances_to_generate; StdOperation.standard_sizes.map { |b| [b] }; end; end - - class ExtendSign - def self.instances_to_generate - inside = [ - [1, 13], [6, 13], [4, 13], - [1, 21], [8, 21], [10, 21], - [7, 12], [5, 12] - ] - to32 = (2..31).map { |n| [n, 32] } - inside + to32 + BASE_OP_CLASSES = { + 'not' => Not, + 'neg' => Neg, + 'popcnt' => Popcnt, + 'clz' => Clz, + 'ctz' => Ctz, + 'reverse' => Reverse, + 'add' => Add, + 'sub' => Sub, + 'mul' => Mul, + 'and' => And, + 'orr' => Orr, + 'xor' => Xor, + 'lsl' => Lsl, + 'lsr' => Lsr, + 'asr' => Asr, + 'eq' => Eq, + 'ne' => Ne, + 'slt' => Slt, + 'sle' => Sle, + 'sgt' => Sgt, + 'sge' => Sge, + 'ult' => Ult, + 'ule' => Ule, + 'ugt' => Ugt, + 'uge' => Uge, + 'div_s' => DivS, + 'div_u' => DivU, + 'rem_s' => RemS, + 'rem_u' => RemU, + 'ror' => Ror, + 'rol' => Rol, + 'add_overflow' => AddOverflow, + 'sub_overflow' => SubOverflow, + 'select' => Select, + }.freeze + + def self.lookup_operation(name) + if (m = name.match(/^extend_sign_(\d+)_to_(\d+)$/)) + return ExtendSign.new(m[1].to_i, m[2].to_i) end - end - - class ExtendZero - def self.instances_to_generate - ExtendSign.instances_to_generate + if (m = name.match(/^extend_zero_(\d+)_to_(\d+)$/)) + return ExtendZero.new(m[1].to_i, m[2].to_i) end - end - - class ExtractLow - def self.instances_to_generate - (2..31).map { |n| [32, n] } + if (m = name.match(/^extract_low_(\d+)_to_(\d+)$/)) + return ExtractLow.new(m[1].to_i, m[2].to_i) end + parts = name.split('_') + return nil unless parts.last.match?(/^\d+$/) + width = parts.pop.to_i + (1..parts.size).reverse_each do |len| + base = parts[0...len].join('_') + klass = BASE_OP_CLASSES[base] + return klass.new(width) if klass + end + nil end - - class RemU; def self.instances_to_generate; [[32], [64]]; end; end - class RemS; def self.instances_to_generate; [[32], [64]]; end; end end diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 9e4fa6e..7a0d98d 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -353,6 +353,7 @@ def initialize(arch_name, arch_attributes = []) @decode_cache = {} @decode_snip_id = 0 + @ops_used = Set.new end def resolved(op) @@ -399,6 +400,10 @@ def widen_or_truncate(name, dest_type, src, src_type) end end + def collect_ops(seq) + seq.stmts.each { |s| @ops_used << s.specifier if s.kind == 'op' } + end + def stmt_to_lira(stmt) handler_class = HANDLER_MAP[stmt.name] or raise "Unhandled statement: #{stmt.name}" handler_class.new(self).handle(stmt) @@ -414,7 +419,9 @@ def generate_semantic(instr) @vars = {} @operand_names = collect_operand_names(instr) instr.code.tree.each { |stmt| stmt_to_lira(stmt) } - @builder.seq.build + seq = @builder.seq.build + collect_ops(seq) + seq end def generate_decode_snippets(instr, operand_vars) @@ -436,6 +443,7 @@ def generate_decode_snippets(instr, operand_vars) end snippet = @builder.build + collect_ops(snippet.seq) seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) if @decode_cache.key?(seq_str) @@ -586,6 +594,11 @@ def build_arch end end + @ops_used.each do |op_name| + op = Lira.lookup_operation(op_name) + @arch_builder.add_operation(op) if op + end + @arch_builder.build end end diff --git a/sim_gen_lira/base_ops_gen.rb b/sim_gen_lira/base_ops_gen.rb index f100a17..0b49af5 100644 --- a/sim_gen_lira/base_ops_gen.rb +++ b/sim_gen_lira/base_ops_gen.rb @@ -2,9 +2,9 @@ require_relative 'cpp_ops' module SimGen - def self.generate_base_ops + def self.generate_base_ops(operations = []) out = StringIO.new - generate_file(out) + generate_file(out, operations) out.string end @@ -27,74 +27,22 @@ class << self FOOTER = "\n#endif\n" - OP_CLASSES = [ - Lira::Not, - Lira::Neg, - Lira::Popcnt, - Lira::Clz, - Lira::Ctz, - Lira::Reverse, - Lira::Add, - Lira::Sub, - Lira::Mul, - Lira::And, - Lira::Orr, - Lira::Xor, - Lira::Lsl, - Lira::Lsr, - Lira::Asr, - Lira::Eq, - Lira::Ne, - Lira::Slt, - Lira::Sle, - Lira::Sgt, - Lira::Sge, - Lira::Ult, - Lira::Ule, - Lira::Ugt, - Lira::Uge, - Lira::DivU, - Lira::DivS, - Lira::RemU, - Lira::RemS, - Lira::Select, - Lira::ExtendSign, - Lira::ExtendZero, - Lira::ExtractLow, - ].freeze - - def generate_file(out) + def generate_file(out, operations) out.puts HEADER - OP_CLASSES.each do |op_class| - op_class.instances_to_generate.each do |args| - instance = op_class.new(*args) - out.puts instance.to_cpp - end - out.puts + operations.each do |op| + instance = Lira.lookup_operation(op.name) || op + out.puts instance.to_cpp end - - generate_special_extensions(out) + out.puts out.puts FOOTER end - - def generate_special_extensions(out) - out.puts Lira::ExtractLow.new(64, 32).to_cpp - out.puts Lira::ExtendSign.new(32, 64).to_cpp - out.puts Lira::ExtendZero.new(32, 64).to_cpp - - out.puts "static inline uint8_t extract_low_32_to_1(uint32_t a) { return a & 1; }" - out.puts "static inline uint32_t extend_sign_1_to_32(uint8_t a) {" - out.puts " return (uint32_t)(int32_t)(int8_t)a;" - out.puts "}" - out.puts "static inline uint32_t extend_zero_1_to_32(uint8_t a) { return a; }" - end end end if __FILE__ == $0 - output_file = ARGV[0] || "std_ops.h" + output_file = ARGV[0] || 'std_ops.h' File.write(output_file, SimGen.generate_base_ops) puts "Generated #{output_file}" end diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index e835d44..d584155 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -6,68 +6,8 @@ module LiraCppGen module OpRegistry - BASE_TO_CLASS = { - 'not' => Lira::Not, - 'neg' => Lira::Neg, - 'popcnt' => Lira::Popcnt, - 'clz' => Lira::Clz, - 'ctz' => Lira::Ctz, - 'reverse' => Lira::Reverse, - 'add' => Lira::Add, - 'sub' => Lira::Sub, - 'mul' => Lira::Mul, - 'and' => Lira::And, - 'orr' => Lira::Orr, - 'xor' => Lira::Xor, - 'lsl' => Lira::Lsl, - 'lsr' => Lira::Lsr, - 'asr' => Lira::Asr, - 'eq' => Lira::Eq, - 'ne' => Lira::Ne, - 'slt' => Lira::Slt, - 'sle' => Lira::Sle, - 'sgt' => Lira::Sgt, - 'sge' => Lira::Sge, - 'ult' => Lira::Ult, - 'ule' => Lira::Ule, - 'ugt' => Lira::Ugt, - 'uge' => Lira::Uge, - 'div_s' => Lira::DivS, - 'div_u' => Lira::DivU, - 'rem_s' => Lira::RemS, - 'rem_u' => Lira::RemU, - 'ror' => Lira::Ror, - 'rol' => Lira::Rol, - 'add_overflow' => Lira::AddOverflow, - 'sub_overflow' => Lira::SubOverflow, - 'select' => Lira::Select, - }.freeze - - SPECIAL = [ - [/^extend_sign_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtendSign.new(m[1].to_i, m[2].to_i) }], - [/^extend_zero_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtendZero.new(m[1].to_i, m[2].to_i) }], - [/^extract_low_(\d+)_to_(\d+)$/, ->(m) { Lira::ExtractLow.new(m[1].to_i, m[2].to_i) }] - ].freeze - - def self.lookup(specifier) - SPECIAL.each do |pattern, factory| - m = specifier.match(pattern) - return factory.call(m) if m - end - parse_standard(specifier) or raise "Unknown operation: #{specifier}" - end - - def self.parse_standard(specifier) - parts = specifier.split('_') - return nil unless parts.last.match?(/^\d+$/) - - width = parts.pop.to_i - (1..parts.size).reverse_each do |len| - base = parts[0...len].join('_') - klass = BASE_TO_CLASS[base] - return klass.new(width) if klass - end - nil + def self.lookup(name) + Lira.lookup_operation(name) or raise "Unknown operation: #{name}" end end diff --git a/sim_gen_lira/cpp_ops.rb b/sim_gen_lira/cpp_ops.rb index 0a4b17d..348e3fe 100644 --- a/sim_gen_lira/cpp_ops.rb +++ b/sim_gen_lira/cpp_ops.rb @@ -115,7 +115,7 @@ def cpp_return_type end def cpp_params - "#{Utility::HelperCpp.gen_type(outputs[0])} a" + "#{Utility::HelperCpp.gen_type(inputs[0])} a" end end @@ -125,7 +125,7 @@ def cpp_return_type end def cpp_params - "#{Utility::HelperCpp.gen_type(outputs[0])} a" + "#{Utility::HelperCpp.gen_type(inputs[0])} a" end end @@ -137,6 +137,7 @@ def cpp_params class ExtendSign def cpp_body + return 'return a;' if inputs[0] == 1 t = Utility::HelperCpp.gen_type(outputs[0]) <<~CPP #{t} val = a & (((#{t})1 << #{inputs[0]}) - 1); diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index e2bbe49..873c7ab 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -63,4 +63,4 @@ File.write('isa.hh', SimGen::ISA::Header.generate_isa_header(ir_hash)) File.write('hart.hh', SimGen::Hart::Header.generate_hart(ir_hash)) File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(ir_hash)) -File.write('base_ops.h', SimGen.generate_base_ops) +File.write('base_ops.h', SimGen.generate_base_ops(arch.operations)) From 7026ed88f6bd3089c510be25d858eb336949ecdc Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 03:44:57 +0300 Subject: [PATCH 52/75] [lira] Operations added --- lira.yaml | 618 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 617 insertions(+), 1 deletion(-) diff --git a/lira.yaml b/lira.yaml index 80dc5c5..d21e207 100644 --- a/lira.yaml +++ b/lira.yaml @@ -129,7 +129,623 @@ - 32 :outputs: [] :tables_int: [] -:operations: [] +:operations: +- :name: lsr_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: lsr + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_5 + :attributes: [] + :inputs: + - 32 + :outputs: + - 5 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_5_to_32 + :attributes: [] + :inputs: + - 5 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_20 + :attributes: [] + :inputs: + - 32 + :outputs: + - 20 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_20_to_32 + :attributes: [] + :inputs: + - 20 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: lsl_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: lsl + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: add_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: add + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: sub_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: sub + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: slt_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: slt + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_1_to_32 + :attributes: [] + :inputs: + - 1 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: ult_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: ult + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: xor_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: xor + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: asr_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: asr + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: orr_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: orr + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: and_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: and + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_12 + :attributes: [] + :inputs: + - 32 + :outputs: + - 12 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_12_to_32 + :attributes: [] + :inputs: + - 12 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_5_to_32 + :attributes: [] + :inputs: + - 5 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: eq_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: eq + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: select_32 + :attributes: [] + :inputs: + - 1 + - 32 + - 32 + :outputs: + - 32 + :semantic_base: select + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_1 + :attributes: [] + :inputs: + - 32 + :outputs: + - 1 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_1_to_13 + :attributes: [] + :inputs: + - 1 + :outputs: + - 13 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_13_to_32 + :attributes: [] + :inputs: + - 13 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_6 + :attributes: [] + :inputs: + - 32 + :outputs: + - 6 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_6_to_13 + :attributes: [] + :inputs: + - 6 + :outputs: + - 13 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_4 + :attributes: [] + :inputs: + - 32 + :outputs: + - 4 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_4_to_13 + :attributes: [] + :inputs: + - 4 + :outputs: + - 13 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_13 + :attributes: [] + :inputs: + - 32 + :outputs: + - 13 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_13_to_32 + :attributes: [] + :inputs: + - 13 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: ne_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: ne + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: sge_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: sge + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: uge_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 1 + :semantic_base: uge + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_1_to_21 + :attributes: [] + :inputs: + - 1 + :outputs: + - 21 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_21_to_32 + :attributes: [] + :inputs: + - 21 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_8 + :attributes: [] + :inputs: + - 32 + :outputs: + - 8 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_8_to_21 + :attributes: [] + :inputs: + - 8 + :outputs: + - 21 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_10 + :attributes: [] + :inputs: + - 32 + :outputs: + - 10 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_10_to_21 + :attributes: [] + :inputs: + - 10 + :outputs: + - 21 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_21 + :attributes: [] + :inputs: + - 32 + :outputs: + - 21 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_21_to_32 + :attributes: [] + :inputs: + - 21 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_7 + :attributes: [] + :inputs: + - 32 + :outputs: + - 7 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_7_to_12 + :attributes: [] + :inputs: + - 7 + :outputs: + - 12 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_12_to_32 + :attributes: [] + :inputs: + - 12 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_5_to_12 + :attributes: [] + :inputs: + - 5 + :outputs: + - 12 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extract_low_32_to_16 + :attributes: [] + :inputs: + - 32 + :outputs: + - 16 + :semantic_base: extract_low + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_8_to_32 + :attributes: [] + :inputs: + - 8 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_16_to_32 + :attributes: [] + :inputs: + - 16 + :outputs: + - 32 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_8_to_32 + :attributes: [] + :inputs: + - 8 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_16_to_32 + :attributes: [] + :inputs: + - 16 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: mul_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: mul + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_32_to_64 + :attributes: [] + :inputs: + - 32 + :outputs: + - 64 + :semantic_base: extend_sign + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: mul_64 + :attributes: [] + :inputs: + - 64 + - 64 + :outputs: + - 64 + :semantic_base: mul + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_zero_32_to_64 + :attributes: [] + :inputs: + - 32 + :outputs: + - 64 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: asr_64 + :attributes: [] + :inputs: + - 64 + - 64 + :outputs: + - 64 + :semantic_base: asr + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: lsr_64 + :attributes: [] + :inputs: + - 64 + - 64 + :outputs: + - 64 + :semantic_base: lsr + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: div_s_32 + :attributes: [] + :inputs: + - 32 + - 32 + - 32 + :outputs: + - 32 + :semantic_base: div_s + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: div_u_32 + :attributes: [] + :inputs: + - 32 + - 32 + - 32 + :outputs: + - 32 + :semantic_base: div_u + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: rem_s_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: rem_s + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: rem_u_32 + :attributes: [] + :inputs: + - 32 + - 32 + :outputs: + - 32 + :semantic_base: rem_u + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} :snippets: - :name: decode_0 :seq: | From d2e81cde50768eb3d77134098f88389c2b4e6790 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 12:19:16 +0300 Subject: [PATCH 53/75] [ser] Encode & Decode constraints were supported --- lib/lira_gen.rb | 135 +++++++++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 7a0d98d..920bb97 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -353,6 +353,10 @@ def initialize(arch_name, arch_attributes = []) @decode_cache = {} @decode_snip_id = 0 + @encode_cache = {} + @encode_snip_id = 0 + @constraint_cache = {} + @constraint_snip_id = 0 @ops_used = Set.new end @@ -461,55 +465,78 @@ def generate_decode_snippets(instr, operand_vars) @current_instr = nil end - # NOTE: It was temporary disabled - # def generate_encode_snippet(instr, operand_vars) - # @builder = Lira::SnippetBuilder.new("temp_encode") - # - # operand_values = operand_vars.each_with_index.map do |var, idx| - # width = ADLToLiraUtils.convert_type(var.type) - # width = 1 if width < 1 - # @builder.input(idx, width) - # end - # - # base = @builder.const(0, 32) - # instr.fields.each do |field| - # lo = field.from - # hi = field.to - # width = hi - lo + 1 - # width = 1 if width < 1 - # field_var_name = field.value.name.to_s - # value_num = field.value.value - # if value_num - # const_val = @builder.const(value_num, width) - # const_val = ADLToLiraUtils.ensure_width(const_val, 32, @builder) - # shifted = @builder.lsl(const_val, @builder.const(lo, 32)) - # base = @builder.orr(base, shifted) - # elsif field_var_name =~ /^f_(.+)$/ - # operand_name = $1 - # idx = operand_vars.index { |v| v.name.to_s == operand_name } - # if idx - # op_val = operand_values[idx] - # op_val = ADLToLiraUtils.ensure_width(op_val, 32, @builder) - # shifted = @builder.lsl(op_val, @builder.const(lo, 32)) - # base = @builder.orr(base, shifted) - # end - # end - # end - # - # @builder.output(base, 0) - # snippet = @builder.build - # seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) - # if @encode_cache.key?(seq_str) - # return @encode_cache[seq_str] - # else - # unique_name = "encode_#{@encode_snip_id}" - # snippet.name = unique_name - # @arch_builder.add_snippet(snippet) - # @encode_snip_id += 1 - # @encode_cache[seq_str] = unique_name - # unique_name - # end - # end + def generate_encode_snippet(instr, operand_vars) + @builder = Lira::SnippetBuilder.new('temp_encode') + + operand_values = operand_vars.each_with_index.map do |var, idx| + width = ADLToLiraUtils.convert_type(var.type) + width = 1 if width < 1 + @builder.input(idx, width) + end + + base = @builder.const(0, 32) + instr.fields.each do |field| + lo = field.from + hi = field.to + width = hi - lo + 1 + width = 1 if width < 1 + field_var_name = field.value.name.to_s + value_num = field.value.value + if value_num + const_val = @builder.const(value_num, width) + const_val = @builder.ensure_width(const_val, 32) + shifted = @builder.lsl(const_val, @builder.const(lo, 32)) + base = @builder.orr(base, shifted) + elsif field_var_name =~ /^f_(.+)$/ + operand_name = $1 + idx = operand_vars.index { |v| v.name.to_s == operand_name } + if idx + op_val = operand_values[idx] + op_val = @builder.ensure_width(op_val, 32) + shifted = @builder.lsl(op_val, @builder.const(lo, 32)) + base = @builder.orr(base, shifted) + end + end + end + + @builder.output(base, 0) + snippet = @builder.build + collect_ops(snippet.seq) + seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + + if @encode_cache.key?(seq_str) + @encode_cache[seq_str] + else + unique_name = "encode_#{@encode_snip_id}" + snippet.name = unique_name + @arch_builder.add_snippet(snippet) + @encode_snip_id += 1 + @encode_cache[seq_str] = unique_name + unique_name + end + end + + def generate_constraint_snippet(const_part, const_mask) + @builder = Lira::SnippetBuilder.new('temp_constraint') + raw = @builder.input(0, 32) + masked = @builder.and_(raw, @builder.const(const_mask, 32)) + result = op_cmp(:eq, false, masked, @builder.const(const_part, 32)) + @builder.output(result, 0) + snippet = @builder.build + collect_ops(snippet.seq) + seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + + if @constraint_cache.key?(seq_str) + @constraint_cache[seq_str] + else + unique_name = "constraint_#{@constraint_snip_id}" + snippet.name = unique_name + @arch_builder.add_snippet(snippet) + @constraint_snip_id += 1 + @constraint_cache[seq_str] = unique_name + unique_name + end + end def collect_operand_vars(instr) operand_vars = [] @@ -535,12 +562,13 @@ def convert_instruction(instr) semantic = generate_semantic(instr) decode_snippets = [] + encode_snippet = '' if instr.map.tree.any? && operand_vars.any? decode_snippets = generate_decode_snippets(instr, operand_vars) end - # if instr.fields.any? && operand_vars.any? - # encode_snippet = generate_encode_snippet(instr, operand_vars) - # end + if instr.fields.any? && operand_vars.any? + encode_snippet = generate_encode_snippet(instr, operand_vars) + end const_part = 0 const_mask = 0 @@ -556,7 +584,8 @@ def convert_instruction(instr) end operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } - encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, '', '', '') + constraint_decode = generate_constraint_snippet(const_part, const_mask) + encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, encode_snippet, constraint_decode, '') Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) ensure @current_instr = nil From ce1a2cd6ef18040124789ab2beff89b2acd783b2 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 12:20:08 +0300 Subject: [PATCH 54/75] [simgen] Decode constraints were supported in decoder gen --- sim_gen_lira/Decoders/decoder.rb | 31 +++++++++++++++++++++---------- sim_gen_lira/sim_gen.rb | 3 ++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index 0c8df9b..e71accb 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -34,16 +34,24 @@ def generate_decoder(ir_hash) body = [] instructions.each do |insn| - mask = insn[:encoding][:const_mask] - const_part = insn[:encoding][:const_part] decode_snippets = insn[:encoding][:decode_snippets] + constraint_name = insn[:encoding][:constraint_decode] + + next unless constraint_name + constraint_seq = snippets[constraint_name] + next unless constraint_seq + + constraint_t = LiraCppGen::Translator.new(constraint_seq, :decode, 2) + constraint_code = constraint_t.translate if decode_snippets.nil? || decode_snippets.empty? - # ะ˜ะฝัั‚ั€ัƒะบั†ะธั ะฑะตะท ะฟะพะปะตะน (ะฝะฐะฟั€ะธะผะตั€, fence, ecall, ebreak) body << <<~CPP - if ((raw_insn & #{mask}) == #{const_part}) { - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; - return insn; + { + #{constraint_code} + if (insn.operand0) { + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } } CPP else @@ -55,10 +63,13 @@ def generate_decoder(ir_hash) snippet_code = translator.translate body << <<~CPP - if ((raw_insn & #{mask}) == #{const_part}) { - #{snippet_code} - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; - return insn; + { + #{constraint_code} + if (insn.operand0) { + #{snippet_code} + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } } CPP end diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index 873c7ab..5ac9029 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -44,7 +44,8 @@ const_part: insn.encoding.const_encoding_part, encoded_size: insn.encoding.encoded_size, const_mask: insn.encoding.const_mask, - decode_snippets: insn.encoding.decode + decode_snippets: insn.encoding.decode, + constraint_decode: insn.encoding.constraint_decode }, semantic_seq: insn.semantic } From 220c5883708d969aa092e6327f98c48fd95c6eee Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 14:46:22 +0300 Subject: [PATCH 55/75] [ADL] Introduced Operands List & Mapping * In addition to the previous map section, we propose ordered operand list with specific map sections per-operand --- lib/ADL/builder.rb | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index e15ec5d..2396ad2 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -40,11 +40,14 @@ def self.interface_functions end class InstructionInfo - attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :feature + attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :feature, + :operand_map, :operand_list def initialize(name, feature) @name = name; @map_code_blocks = {} @feature = feature + @operand_map = {} + @operand_list = [] end def to_h @@ -55,6 +58,8 @@ def to_h asm_str: @asm_str, code: @code.to_h, map: @map.to_h, + operand_map: @operand_map.transform_values(&:to_h), + operand_list: @operand_list, feature: @feature, } end @@ -68,6 +73,10 @@ def self.from_h(h) info.code.instance_variable_set(:@tree, h[:code][:tree].map { |s| IrStmt.from_h(s) }) info.map = Scope.new(nil) info.map.instance_variable_set(:@tree, h[:map][:tree].map { |s| IrStmt.from_h(s) }) + if h[:operand_map] + info.operand_map = h[:operand_map].transform_values { |v| Scope.from_h(v) } + info.operand_list = h[:operand_list] || info.operand_map.keys + end info end end @@ -214,17 +223,20 @@ def RegFiles() module SimInfra class InstructionInfoBuilder def code(&block) - if !@info.map_code_blocks.empty? - @info.fields.each { |f| - @info.map.method(f.value.name, f.value.type) - } - end - @info.map_code_blocks.each do |k, v| - @info.map.instance_eval v[1] + # Build legacy map from operand scopes for backward compat + @info.map = Scope.new(nil) + @info.fields.each { |f| @info.map.method(f.value.name, f.value.type) } + @info.operand_map.each_value do |scope| + scope.tree.each { |stmt| @info.map.tree << stmt } end - @info.map_code_blocks.each do |k, v| - @info.code.method(k, v[0], @info.map.vars[k].regset) + + # Link code scope methods to operand vars + @info.operand_map.each do |name, scope| + var = scope.vars[name] + @info.code.method(name, var.type, var.regset) if var end + + # Register files for regfile in @@regfiles for reg in regfile.regs @info.code.method(reg.name, ('r' + reg.size.to_s).to_sym) @@ -234,11 +246,14 @@ def code(&block) end def map(blocks) - if (!blocks.nil? && !blocks.empty?) - for blck in blocks - @info.map_code_blocks[blck[0]] = [blck[1], blck[2]] - end + return if blocks.nil? || blocks.empty? + blocks.each do |name, type, code_str| + scope = Scope.new(nil) + @info.fields.each { |f| scope.method(f.value.name, f.value.type) } + scope.instance_eval(code_str) + @info.operand_map[name] = scope end + @info.operand_list = blocks.map(&:first) end def asm(&block) From 28a8c66cca813909a57897aeee93629fa1fe1fa2 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 14:47:48 +0300 Subject: [PATCH 56/75] [ser] Operand List & Map sections serialization supported --- lib/lira_gen.rb | 67 +++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 920bb97..6ef7563 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -430,36 +430,43 @@ def generate_semantic(instr) def generate_decode_snippets(instr, operand_vars) decode_snippet_names = [] - @builder = Lira::SnippetBuilder.new('temp_decode') - @vars = {} @current_instr = instr - @raw_enc = @builder.input(0, 32) + return [] if instr.operand_map.nil? || instr.operand_map.empty? - instr.map.tree.each do |stmt| - handler_class = DECODE_HANDLER_MAP[stmt.name] - next unless handler_class - handler_class.new(self).handle(stmt) - end + instr.operand_list.each do |op_name| + op_scope = instr.operand_map[op_name] + next unless op_scope - operand_vars.each_with_index do |var, idx| - val = @vars[var] - @builder.output(val || @builder.const(0, 32), idx) - end + @builder = Lira::SnippetBuilder.new('temp_operand') + @vars = {} + @raw_enc = @builder.input(0, 32) - snippet = @builder.build - collect_ops(snippet.seq) - seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + op_scope.tree.each do |stmt| + handler_class = DECODE_HANDLER_MAP[stmt.name] + next unless handler_class + handler_class.new(self).handle(stmt) + end - if @decode_cache.key?(seq_str) - decode_snippet_names << @decode_cache[seq_str] - else - unique_name = "decode_#{@decode_snip_id}" - snippet.name = unique_name - @arch_builder.add_snippet(snippet) - @decode_snip_id += 1 - @decode_cache[seq_str] = unique_name - decode_snippet_names << unique_name + val = @vars[op_scope.vars[op_name]] + @builder.output(val || @builder.const(0, 32), 0) + + snippet = @builder.build + collect_ops(snippet.seq) + seq_str = Lira::IrSerTxt.serialize_statement_seq(snippet.seq) + + snip_name = if @decode_cache.key?(seq_str) + @decode_cache[seq_str] + else + unique_name = "decode_#{@decode_snip_id}" + snippet.name = unique_name + @arch_builder.add_snippet(snippet) + @decode_snip_id += 1 + @decode_cache[seq_str] = unique_name + unique_name + end + decode_snippet_names << snip_name end + decode_snippet_names ensure @current_instr = nil @@ -539,15 +546,9 @@ def generate_constraint_snippet(const_part, const_mask) end def collect_operand_vars(instr) - operand_vars = [] - instr.map.tree.each do |stmt| - if stmt.name == :new_var - var = stmt.oprnds[0] - attrs = stmt.attrs - operand_vars << var if attrs && attrs.include?(:op) - end - end - operand_vars + return [] if instr.operand_map.nil? || instr.operand_map.empty? + + instr.operand_list.map { |name| instr.operand_map[name].vars[name] }.compact end def collect_operand_names(instr) From 7b3bff666870253eaab58a223e98baf0594579ff Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 14:52:44 +0300 Subject: [PATCH 57/75] [simgen] Decode & Constraint snipptets refactoring * Introduced per-operand Decode Snippets instead of the previous one * Introduced separarte snippets codegen module --- sim_gen_lira/Decoders/decoder.rb | 49 +++++++++----------------------- sim_gen_lira/cpp_gen.rb | 8 ++++-- sim_gen_lira/sim_gen.rb | 2 ++ sim_gen_lira/snippets_gen.rb | 35 +++++++++++++++++++++++ 4 files changed, 57 insertions(+), 37 deletions(-) create mode 100644 sim_gen_lira/snippets_gen.rb diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index e71accb..3980cd6 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -34,51 +34,30 @@ def generate_decoder(ir_hash) body = [] instructions.each do |insn| - decode_snippets = insn[:encoding][:decode_snippets] constraint_name = insn[:encoding][:constraint_decode] + decode_names = insn[:encoding][:decode_snippets] - next unless constraint_name + next unless constraint_name && decode_names constraint_seq = snippets[constraint_name] next unless constraint_seq - constraint_t = LiraCppGen::Translator.new(constraint_seq, :decode, 2) - constraint_code = constraint_t.translate - - if decode_snippets.nil? || decode_snippets.empty? - body << <<~CPP - { - #{constraint_code} - if (insn.operand0) { - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; - return insn; - } - } - CPP - else - snippet_name = decode_snippets.first - seq = snippets[snippet_name] - next unless seq - - translator = LiraCppGen::Translator.new(seq, :decode, 2) - snippet_code = translator.translate - - body << <<~CPP - { - #{constraint_code} - if (insn.operand0) { - #{snippet_code} - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; - return insn; - } - } - CPP - end + operand_calls = decode_names.each_with_index.map { |name, idx| + "insn.operand#{idx} = #{name}(raw_insn);" + }.join("\n ") + + body << <<~CPP + if (#{constraint_name}(raw_insn)) { + #{operand_calls} + insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + return insn; + } + CPP end decoder_impl = body.join("\n") <<~CPP #include "decoder.hh" - #include "base_ops.h" + #include "snippets.h" #include namespace prot::decoder { diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index d584155..5e6183c 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -189,7 +189,7 @@ def emit_code out = s.outputs[0] width = s.outputs_types[0] declare(out, width) - emit(context == :decode ? "#{out} = raw_insn;" : "#{out} = insn.operand#{idx};") + emit(context == :decode || context == :snippet ? "#{out} = raw_insn;" : "#{out} = insn.operand#{idx};") end end @@ -198,7 +198,11 @@ def emit_code s = stmt val = resolve_var(s.inputs[0]) idx = s.specifier.to_i - emit("insn.operand#{idx} = #{val};") + if context == :snippet + emit("return #{val};") + else + emit("insn.operand#{idx} = #{val};") + end end end diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index 5ac9029..fd44b26 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -5,6 +5,7 @@ require_relative 'cpp_gen' require_relative 'base_ops_gen' +require_relative 'snippets_gen' require_relative 'CPUState/cpu_state' require_relative 'Decoders/decoder' @@ -65,3 +66,4 @@ File.write('hart.hh', SimGen::Hart::Header.generate_hart(ir_hash)) File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(ir_hash)) File.write('base_ops.h', SimGen.generate_base_ops(arch.operations)) +File.write('snippets.h', SimGen::Snippets.generate_snippets_header(ir_hash[:snippets])) diff --git a/sim_gen_lira/snippets_gen.rb b/sim_gen_lira/snippets_gen.rb new file mode 100644 index 0000000..2c559f8 --- /dev/null +++ b/sim_gen_lira/snippets_gen.rb @@ -0,0 +1,35 @@ +require_relative 'cpp_gen' + +module SimGen + module Snippets + module_function + + def generate_snippets_header(snippets) + funcs = snippets + .select { |s| s[:name].start_with?('decode_') || s[:name].start_with?('constraint_') } + .map { |snip| generate_function(snip[:name], snip[:seq]) } + + <<~CPP + #ifndef GENERATED_SNIPPETS_H + #define GENERATED_SNIPPETS_H + + #include + #include "base_ops.h" + + #{funcs.join("\n\n")} + + #endif + CPP + end + + def generate_function(name, seq) + translator = LiraCppGen::Translator.new(seq, :snippet, 2) + body = translator.translate + <<~CPP + static inline uint32_t #{name}(uint32_t raw_insn) { + #{body} + } + CPP + end + end +end From bf7366811554d97481abb84ba31d962703409c29 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 14:53:22 +0300 Subject: [PATCH 58/75] LIRA IR updated --- lira.yaml | 2142 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 1894 insertions(+), 248 deletions(-) diff --git a/lira.yaml b/lira.yaml index d21e207..dd54634 100644 --- a/lira.yaml +++ b/lira.yaml @@ -192,101 +192,122 @@ :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: add_32 +- :name: extend_zero_1_to_32 + :attributes: [] + :inputs: + - 1 + :outputs: + - 32 + :semantic_base: extend_zero + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: orr_32 :attributes: [] :inputs: - 32 - 32 :outputs: - 32 - :semantic_base: add + :semantic_base: orr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: sub_32 +- :name: and_32 :attributes: [] :inputs: - 32 - 32 :outputs: - 32 - :semantic_base: sub + :semantic_base: and :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: slt_32 +- :name: eq_32 :attributes: [] :inputs: - 32 - 32 :outputs: - 1 - :semantic_base: slt + :semantic_base: eq :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: extend_sign_1_to_32 +- :name: add_32 :attributes: [] :inputs: - - 1 + - 32 + - 32 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: add :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: ult_32 +- :name: sub_32 :attributes: [] :inputs: - 32 - 32 :outputs: - - 1 - :semantic_base: ult + - 32 + :semantic_base: sub :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: xor_32 +- :name: slt_32 :attributes: [] :inputs: - 32 - 32 :outputs: + - 1 + :semantic_base: slt + :semantic_func: {} + :semantic_func_128: {} + :semantic_table: {} +- :name: extend_sign_1_to_32 + :attributes: [] + :inputs: + - 1 + :outputs: - 32 - :semantic_base: xor + :semantic_base: extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: asr_32 +- :name: ult_32 :attributes: [] :inputs: - 32 - 32 :outputs: - - 32 - :semantic_base: asr + - 1 + :semantic_base: ult :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: orr_32 +- :name: xor_32 :attributes: [] :inputs: - 32 - 32 :outputs: - 32 - :semantic_base: orr + :semantic_base: xor :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: and_32 +- :name: asr_32 :attributes: [] :inputs: - 32 - 32 :outputs: - 32 - :semantic_base: and + :semantic_base: asr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -320,17 +341,6 @@ :semantic_func: {} :semantic_func_128: {} :semantic_table: {} -- :name: eq_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: eq - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} - :name: select_32 :attributes: [] :inputs: @@ -754,69 +764,802 @@ 1 32 _t4 = op lsr_32 _t1 _t3; 1 5 _t5 = op extract_low_32_to_5 _t4; 1 32 _t6 = op extend_zero_5_to_32 _t5; - 1 32 _t8 = const 12; - 1 32 _t9 = op lsr_32 _t1 _t8; - 1 20 _t10 = op extract_low_32_to_20 _t9; - 1 32 _t12 = const 12; - 1 32 _t13 = op extend_zero_20_to_32 _t10; - 1 32 _t14 = op lsl_32 _t13 _t12; 1 = output 0 _t6; - 1 = output 1 _t14; - :name: decode_1 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 12; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 20 _t5 = op extract_low_32_to_20 _t4; + 1 32 _t7 = const 12; + 1 32 _t8 = op extend_zero_20_to_32 _t5; + 1 32 _t9 = op lsl_32 _t8 _t7; + 1 = output 0 _t9; +- :name: encode_0 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = const 0; + 1 1 _t4 = const 55; + 1 32 _t5 = op extend_zero_1_to_32 _t4; + 1 32 _t6 = const 6; + 1 32 _t7 = op lsl_32 _t5 _t6; + 1 32 _t8 = op orr_32 _t3 _t7; + 1 32 _t9 = const 11; + 1 32 _t10 = op lsl_32 _t1 _t9; + 1 32 _t11 = op orr_32 _t8 _t10; + 1 32 _t12 = const 31; + 1 32 _t13 = op lsl_32 _t2 _t12; + 1 32 _t14 = op orr_32 _t11 _t13; + 1 = output 0 _t14; +- :name: constraint_0 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 127; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 55; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_1 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = const 0; + 1 1 _t4 = const 23; + 1 32 _t5 = op extend_zero_1_to_32 _t4; + 1 32 _t6 = const 6; + 1 32 _t7 = op lsl_32 _t5 _t6; + 1 32 _t8 = op orr_32 _t3 _t7; + 1 32 _t9 = const 11; + 1 32 _t10 = op lsl_32 _t1 _t9; + 1 32 _t11 = op orr_32 _t8 _t10; + 1 32 _t12 = const 31; + 1 32 _t13 = op lsl_32 _t2 _t12; + 1 32 _t14 = op orr_32 _t11 _t13; + 1 = output 0 _t14; +- :name: constraint_1 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 127; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 23; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_2 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 20; 1 32 _t4 = op lsr_32 _t1 _t3; 1 5 _t5 = op extract_low_32_to_5 _t4; 1 32 _t6 = op extend_zero_5_to_32 _t5; - 1 32 _t8 = const 15; - 1 32 _t9 = op lsr_32 _t1 _t8; - 1 5 _t10 = op extract_low_32_to_5 _t9; - 1 32 _t11 = op extend_zero_5_to_32 _t10; - 1 32 _t13 = const 7; - 1 32 _t14 = op lsr_32 _t1 _t13; - 1 5 _t15 = op extract_low_32_to_5 _t14; - 1 32 _t16 = op extend_zero_5_to_32 _t15; 1 = output 0 _t6; - 1 = output 1 _t11; - 1 = output 2 _t16; -- :name: decode_2 +- :name: decode_3 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 15; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 5 _t5 = op extract_low_32_to_5 _t4; + 1 32 _t6 = op extend_zero_5_to_32 _t5; + 1 = output 0 _t6; +- :name: encode_2 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_2 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 51; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_3 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 32; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_3 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 1073741875; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_4 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 1; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_4 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 4147; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_5 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 2; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_5 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 8243; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_6 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 3; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_6 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 12339; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_7 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 4; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_7 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 16435; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_8 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_8 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 20531; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_9 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 32; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_9 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 1073762355; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_10 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 6; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_10 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 24627; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_11 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 7; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 0; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_11 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 28723; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_4 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 20; 1 32 _t4 = op lsr_32 _t1 _t3; 1 12 _t5 = op extract_low_32_to_12 _t4; 1 32 _t6 = op extend_sign_12_to_32 _t5; - 1 32 _t9 = const 15; - 1 32 _t10 = op lsr_32 _t1 _t9; - 1 5 _t11 = op extract_low_32_to_5 _t10; - 1 32 _t12 = op extend_zero_5_to_32 _t11; - 1 32 _t14 = const 7; - 1 32 _t15 = op lsr_32 _t1 _t14; - 1 5 _t16 = op extract_low_32_to_5 _t15; - 1 32 _t17 = op extend_zero_5_to_32 _t16; 1 = output 0 _t6; - 1 = output 1 _t12; - 1 = output 2 _t17; -- :name: decode_3 +- :name: encode_12 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_12 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 19; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_13 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 2; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_13 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 8211; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_14 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 3; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_14 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 12307; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_15 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 4; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_15 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 16403; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_16 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 6; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_16 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 24595; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_17 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 7; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_17 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 28691; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_5 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 20; 1 32 _t4 = op lsr_32 _t1 _t3; 1 5 _t5 = op extract_low_32_to_5 _t4; 1 32 _t6 = op extend_sign_5_to_32 _t5; - 1 32 _t8 = const 15; - 1 32 _t9 = op lsr_32 _t1 _t8; - 1 5 _t10 = op extract_low_32_to_5 _t9; - 1 32 _t11 = op extend_zero_5_to_32 _t10; - 1 32 _t13 = const 7; - 1 32 _t14 = op lsr_32 _t1 _t13; - 1 5 _t15 = op extract_low_32_to_5 _t14; - 1 32 _t16 = op extend_zero_5_to_32 _t15; 1 = output 0 _t6; - 1 = output 1 _t11; - 1 = output 2 _t16; -- :name: decode_4 +- :name: encode_18 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 1; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 1 _t21 = const 0; + 1 32 _t22 = op extend_zero_1_to_32 _t21; + 1 32 _t23 = const 31; + 1 32 _t24 = op lsl_32 _t22 _t23; + 1 32 _t25 = op orr_32 _t20 _t24; + 1 = output 0 _t25; +- :name: constraint_18 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 4115; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_19 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 1 _t21 = const 0; + 1 32 _t22 = op extend_zero_1_to_32 _t21; + 1 32 _t23 = const 31; + 1 32 _t24 = op lsl_32 _t22 _t23; + 1 32 _t25 = op orr_32 _t20 _t24; + 1 = output 0 _t25; +- :name: constraint_19 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 20499; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_20 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 19; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 1 _t21 = const 32; + 1 32 _t22 = op extend_zero_1_to_32 _t21; + 1 32 _t23 = const 31; + 1 32 _t24 = op lsl_32 _t22 _t23; + 1 32 _t25 = op orr_32 _t20 _t24; + 1 = output 0 _t25; +- :name: constraint_20 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 1073762323; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_6 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 31; @@ -852,18 +1595,194 @@ 1 32 _t43 = op orr_32 _t32 _t41; 1 13 _t45 = op extract_low_32_to_13 _t43; 1 32 _t46 = op extend_sign_13_to_32 _t45; - 1 32 _t49 = const 15; - 1 32 _t50 = op lsr_32 _t1 _t49; - 1 5 _t51 = op extract_low_32_to_5 _t50; - 1 32 _t52 = op extend_zero_5_to_32 _t51; - 1 32 _t54 = const 20; - 1 32 _t55 = op lsr_32 _t1 _t54; - 1 5 _t56 = op extract_low_32_to_5 _t55; - 1 32 _t57 = op extend_zero_5_to_32 _t56; 1 = output 0 _t46; - 1 = output 1 _t52; - 1 = output 2 _t57; -- :name: decode_5 +- :name: encode_21 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 0; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_21 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 99; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_22 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 1; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_22 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 4195; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_23 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 4; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_23 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 16483; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_24 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 5; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_24 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 20579; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_25 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 6; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_25 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 24675; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_26 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 99; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 7; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_26 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 28771; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_7 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 31; @@ -899,41 +1818,681 @@ 1 32 _t43 = op orr_32 _t32 _t41; 1 21 _t45 = op extract_low_32_to_21 _t43; 1 32 _t46 = op extend_sign_21_to_32 _t45; - 1 32 _t49 = const 7; - 1 32 _t50 = op lsr_32 _t1 _t49; - 1 5 _t51 = op extract_low_32_to_5 _t50; - 1 32 _t52 = op extend_zero_5_to_32 _t51; 1 = output 0 _t46; - 1 = output 1 _t52; -- :name: decode_6 +- :name: encode_27 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = const 0; + 1 1 _t4 = const 111; + 1 32 _t5 = op extend_zero_1_to_32 _t4; + 1 32 _t6 = const 6; + 1 32 _t7 = op lsl_32 _t5 _t6; + 1 32 _t8 = op orr_32 _t3 _t7; + 1 32 _t9 = const 11; + 1 32 _t10 = op lsl_32 _t2 _t9; + 1 32 _t11 = op orr_32 _t8 _t10; + 1 = output 0 _t11; +- :name: constraint_27 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 127; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 111; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_28 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 103; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_28 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 103; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: decode_8 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t3 = const 25; + 1 32 _t4 = op lsr_32 _t1 _t3; + 1 7 _t5 = op extract_low_32_to_7 _t4; + 1 12 _t6 = op extend_zero_7_to_12 _t5; + 1 32 _t8 = const 5; + 1 32 _t9 = op extend_zero_12_to_32 _t6; + 1 32 _t10 = op lsl_32 _t9 _t8; + 1 32 _t12 = const 7; + 1 32 _t13 = op lsr_32 _t1 _t12; + 1 5 _t14 = op extract_low_32_to_5 _t13; + 1 12 _t15 = op extend_zero_5_to_12 _t14; + 1 32 _t17 = op extend_zero_12_to_32 _t15; + 1 32 _t18 = op orr_32 _t10 _t17; + 1 12 _t20 = op extract_low_32_to_12 _t18; + 1 32 _t21 = op extend_sign_12_to_32 _t20; + 1 = output 0 _t21; +- :name: encode_29 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 35; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 0; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_29 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 35; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_30 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 35; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 1; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_30 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 4131; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_31 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 35; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 1 _t10 = const 2; + 1 32 _t11 = op extend_zero_1_to_32 _t10; + 1 32 _t12 = const 14; + 1 32 _t13 = op lsl_32 _t11 _t12; + 1 32 _t14 = op orr_32 _t9 _t13; + 1 32 _t15 = const 19; + 1 32 _t16 = op lsl_32 _t2 _t15; + 1 32 _t17 = op orr_32 _t14 _t16; + 1 32 _t18 = const 24; + 1 32 _t19 = op lsl_32 _t3 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 = output 0 _t20; +- :name: constraint_31 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 8227; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_32 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 3; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_32 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 3; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_33 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 3; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 1; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_33 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 4099; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_34 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 3; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 2; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_34 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 8195; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_35 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 3; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 4; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_35 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 16387; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_36 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 3; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 31; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 = output 0 _t23; +- :name: constraint_36 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 28799; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 20483; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: constraint_37 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4294967295; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 115; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: constraint_38 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4294967295; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 1048691; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: constraint_39 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4027580415; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 15; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_37 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 0; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_40 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33554483; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_38 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 1; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_41 :seq: | 1 32 _t1 = input 0; - 1 32 _t3 = const 25; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 7 _t5 = op extract_low_32_to_7 _t4; - 1 12 _t6 = op extend_zero_7_to_12 _t5; - 1 32 _t8 = const 5; - 1 32 _t9 = op extend_zero_12_to_32 _t6; - 1 32 _t10 = op lsl_32 _t9 _t8; - 1 32 _t12 = const 7; - 1 32 _t13 = op lsr_32 _t1 _t12; - 1 5 _t14 = op extract_low_32_to_5 _t13; - 1 12 _t15 = op extend_zero_5_to_12 _t14; - 1 32 _t17 = op extend_zero_12_to_32 _t15; - 1 32 _t18 = op orr_32 _t10 _t17; - 1 12 _t20 = op extract_low_32_to_12 _t18; - 1 32 _t21 = op extend_sign_12_to_32 _t20; - 1 32 _t24 = const 15; - 1 32 _t25 = op lsr_32 _t1 _t24; - 1 5 _t26 = op extract_low_32_to_5 _t25; - 1 32 _t27 = op extend_zero_5_to_32 _t26; - 1 32 _t29 = const 20; - 1 32 _t30 = op lsr_32 _t1 _t29; - 1 5 _t31 = op extract_low_32_to_5 _t30; - 1 32 _t32 = op extend_zero_5_to_32 _t31; - 1 = output 0 _t21; - 1 = output 1 _t27; - 1 = output 2 _t32; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33558579; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_39 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 2; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_42 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33562675; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_40 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 3; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_43 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33566771; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_41 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 4; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_44 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33570867; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_42 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 5; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_45 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33574963; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_43 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 6; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_46 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33579059; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; +- :name: encode_44 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = input 1; + 1 32 _t3 = input 2; + 1 32 _t4 = const 0; + 1 1 _t5 = const 51; + 1 32 _t6 = op extend_zero_1_to_32 _t5; + 1 32 _t7 = const 6; + 1 32 _t8 = op lsl_32 _t6 _t7; + 1 32 _t9 = op orr_32 _t4 _t8; + 1 32 _t10 = const 11; + 1 32 _t11 = op lsl_32 _t3 _t10; + 1 32 _t12 = op orr_32 _t9 _t11; + 1 1 _t13 = const 7; + 1 32 _t14 = op extend_zero_1_to_32 _t13; + 1 32 _t15 = const 14; + 1 32 _t16 = op lsl_32 _t14 _t15; + 1 32 _t17 = op orr_32 _t12 _t16; + 1 32 _t18 = const 19; + 1 32 _t19 = op lsl_32 _t2 _t18; + 1 32 _t20 = op orr_32 _t17 _t19; + 1 32 _t21 = const 24; + 1 32 _t22 = op lsl_32 _t1 _t21; + 1 32 _t23 = op orr_32 _t20 _t22; + 1 1 _t24 = const 1; + 1 32 _t25 = op extend_zero_1_to_32 _t24; + 1 32 _t26 = const 31; + 1 32 _t27 = op lsl_32 _t25 _t26; + 1 32 _t28 = op orr_32 _t23 _t27; + 1 = output 0 _t28; +- :name: constraint_47 + :seq: | + 1 32 _t1 = input 0; + 1 32 _t2 = const 4261441663; + 1 32 _t3 = op and_32 _t1 _t2; + 1 32 _t4 = const 33583155; + 1 1 _t5 = op eq_32 _t3 _t4; + 1 = output 0 _t5; :instructions: - :name: lui :attributes: [] @@ -949,8 +2508,9 @@ :const_mask: 127 :decode: - decode_0 - :encode: '' - :constraint_decode: '' + - decode_1 + :encode: encode_0 + :constraint_decode: constraint_0 :constraint_encode: '' :semantic: | 1 32 _t1 = input 1; @@ -970,8 +2530,9 @@ :const_mask: 127 :decode: - decode_0 - :encode: '' - :constraint_decode: '' + - decode_1 + :encode: encode_1 + :constraint_decode: constraint_1 :constraint_encode: '' :semantic: | 1 32 _t2 = input 1; @@ -994,9 +2555,11 @@ :const_encoding_part: 51 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_2 + :constraint_decode: constraint_2 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1021,9 +2584,11 @@ :const_encoding_part: 1073741875 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_3 + :constraint_decode: constraint_3 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1048,9 +2613,11 @@ :const_encoding_part: 4147 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_4 + :constraint_decode: constraint_4 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1075,9 +2642,11 @@ :const_encoding_part: 8243 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_5 + :constraint_decode: constraint_5 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1103,9 +2672,11 @@ :const_encoding_part: 12339 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_6 + :constraint_decode: constraint_6 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1131,9 +2702,11 @@ :const_encoding_part: 16435 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_7 + :constraint_decode: constraint_7 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1158,9 +2731,11 @@ :const_encoding_part: 20531 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_8 + :constraint_decode: constraint_8 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1185,9 +2760,11 @@ :const_encoding_part: 1073762355 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_9 + :constraint_decode: constraint_9 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1212,9 +2789,11 @@ :const_encoding_part: 24627 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_10 + :constraint_decode: constraint_10 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1239,9 +2818,11 @@ :const_encoding_part: 28723 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_11 + :constraint_decode: constraint_11 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1266,9 +2847,11 @@ :const_encoding_part: 19 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_12 + :constraint_decode: constraint_12 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1292,9 +2875,11 @@ :const_encoding_part: 8211 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_13 + :constraint_decode: constraint_13 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1319,9 +2904,11 @@ :const_encoding_part: 12307 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_14 + :constraint_decode: constraint_14 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1346,9 +2933,11 @@ :const_encoding_part: 16403 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_15 + :constraint_decode: constraint_15 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1372,9 +2961,11 @@ :const_encoding_part: 24595 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_16 + :constraint_decode: constraint_16 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1398,9 +2989,11 @@ :const_encoding_part: 28691 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_17 + :constraint_decode: constraint_17 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1424,9 +3017,11 @@ :const_encoding_part: 4115 :const_mask: 4261441663 :decode: + - decode_5 - decode_3 - :encode: '' - :constraint_decode: '' + - decode_0 + :encode: encode_18 + :constraint_decode: constraint_18 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1450,9 +3045,11 @@ :const_encoding_part: 20499 :const_mask: 4261441663 :decode: + - decode_5 - decode_3 - :encode: '' - :constraint_decode: '' + - decode_0 + :encode: encode_19 + :constraint_decode: constraint_19 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1476,9 +3073,11 @@ :const_encoding_part: 1073762323 :const_mask: 4261441663 :decode: + - decode_5 - decode_3 - :encode: '' - :constraint_decode: '' + - decode_0 + :encode: encode_20 + :constraint_decode: constraint_20 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1502,9 +3101,11 @@ :const_encoding_part: 99 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_21 + :constraint_decode: constraint_21 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1534,9 +3135,11 @@ :const_encoding_part: 4195 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_22 + :constraint_decode: constraint_22 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1566,9 +3169,11 @@ :const_encoding_part: 16483 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_23 + :constraint_decode: constraint_23 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1598,9 +3203,11 @@ :const_encoding_part: 20579 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_24 + :constraint_decode: constraint_24 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1630,9 +3237,11 @@ :const_encoding_part: 24675 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_25 + :constraint_decode: constraint_25 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1662,9 +3271,11 @@ :const_encoding_part: 28771 :const_mask: 28799 :decode: - - decode_4 - :encode: '' - :constraint_decode: '' + - decode_6 + - decode_3 + - decode_2 + :encode: encode_26 + :constraint_decode: constraint_26 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1692,9 +3303,10 @@ :const_encoding_part: 111 :const_mask: 127 :decode: - - decode_5 - :encode: '' - :constraint_decode: '' + - decode_7 + - decode_0 + :encode: encode_27 + :constraint_decode: constraint_27 :constraint_encode: '' :semantic: | 1 32 _t2 = env getPC; @@ -1720,9 +3332,11 @@ :const_encoding_part: 103 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_28 + :constraint_decode: constraint_28 :constraint_encode: '' :semantic: | 1 32 _t2 = env getPC; @@ -1752,9 +3366,11 @@ :const_encoding_part: 35 :const_mask: 28799 :decode: - - decode_6 - :encode: '' - :constraint_decode: '' + - decode_8 + - decode_3 + - decode_2 + :encode: encode_29 + :constraint_decode: constraint_29 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1782,9 +3398,11 @@ :const_encoding_part: 4131 :const_mask: 28799 :decode: - - decode_6 - :encode: '' - :constraint_decode: '' + - decode_8 + - decode_3 + - decode_2 + :encode: encode_30 + :constraint_decode: constraint_30 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1812,9 +3430,11 @@ :const_encoding_part: 8227 :const_mask: 28799 :decode: - - decode_6 - :encode: '' - :constraint_decode: '' + - decode_8 + - decode_3 + - decode_2 + :encode: encode_31 + :constraint_decode: constraint_31 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1839,9 +3459,11 @@ :const_encoding_part: 3 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_32 + :constraint_decode: constraint_32 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1867,9 +3489,11 @@ :const_encoding_part: 4099 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_33 + :constraint_decode: constraint_33 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1895,9 +3519,11 @@ :const_encoding_part: 8195 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_34 + :constraint_decode: constraint_34 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1922,9 +3548,11 @@ :const_encoding_part: 16387 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_35 + :constraint_decode: constraint_35 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1950,9 +3578,11 @@ :const_encoding_part: 20483 :const_mask: 28799 :decode: - - decode_2 - :encode: '' - :constraint_decode: '' + - decode_4 + - decode_3 + - decode_0 + :encode: encode_36 + :constraint_decode: constraint_36 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -1973,7 +3603,7 @@ :const_mask: 4294967295 :decode: [] :encode: '' - :constraint_decode: '' + :constraint_decode: constraint_37 :constraint_encode: '' :semantic: '1 = env sysCall; @@ -1988,7 +3618,7 @@ :const_mask: 4294967295 :decode: [] :encode: '' - :constraint_decode: '' + :constraint_decode: constraint_38 :constraint_encode: '' :semantic: '' - :name: fence @@ -2001,7 +3631,7 @@ :const_mask: 4027580415 :decode: [] :encode: '' - :constraint_decode: '' + :constraint_decode: constraint_39 :constraint_encode: '' :semantic: '' - :name: mul @@ -2019,9 +3649,11 @@ :const_encoding_part: 33554483 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_37 + :constraint_decode: constraint_40 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -2046,9 +3678,11 @@ :const_encoding_part: 33558579 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_38 + :constraint_decode: constraint_41 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -2078,9 +3712,11 @@ :const_encoding_part: 33562675 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_39 + :constraint_decode: constraint_42 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -2110,9 +3746,11 @@ :const_encoding_part: 33566771 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_40 + :constraint_decode: constraint_43 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -2142,9 +3780,11 @@ :const_encoding_part: 33570867 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_41 + :constraint_decode: constraint_44 :constraint_encode: '' :semantic: | 1 32 _t3 = input 0; @@ -2182,9 +3822,11 @@ :const_encoding_part: 33574963 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_42 + :constraint_decode: constraint_45 :constraint_encode: '' :semantic: | 1 32 _t3 = input 0; @@ -2222,9 +3864,11 @@ :const_encoding_part: 33579059 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_43 + :constraint_decode: constraint_46 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; @@ -2249,9 +3893,11 @@ :const_encoding_part: 33583155 :const_mask: 4261441663 :decode: - - decode_1 - :encode: '' - :constraint_decode: '' + - decode_2 + - decode_3 + - decode_0 + :encode: encode_44 + :constraint_decode: constraint_47 :constraint_encode: '' :semantic: | 1 32 _t3 = input 1; From 4c5d2c175d2f2ae244aaf01569c218f83f64f458 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 15:24:26 +0300 Subject: [PATCH 59/75] [ser, simgen] Base Ops caching added into lookup instead of deserialization --- lib/lira/ir_builder.rb | 6 ++++ lib/lira/ir_ops.rb | 58 ------------------------------------ lib/lira_gen.rb | 17 ++++++----- sim_gen_lira/base_ops_gen.rb | 7 +---- sim_gen_lira/cpp_gen.rb | 8 ++++- sim_gen_lira/cpp_ops.rb | 31 +++++++++++++++++-- sim_gen_lira/sim_gen.rb | 3 ++ 7 files changed, 55 insertions(+), 75 deletions(-) diff --git a/lib/lira/ir_builder.rb b/lib/lira/ir_builder.rb index e176a97..07a2b65 100644 --- a/lib/lira/ir_builder.rb +++ b/lib/lira/ir_builder.rb @@ -372,6 +372,10 @@ def +(other) self end + def operations_map + @op_cache.each_value.to_h { |op| [op.name, op] } + end + private def check_width_match(a, b) @@ -426,6 +430,8 @@ def input(idx, width = 32) = @seq.input(idx, width) def output(value, idx) = @seq.output(value, idx) def op(operation, inputs) = @seq.op(operation, inputs) def op_multi(operation, inputs) = @seq.op_multi(operation, inputs) + def operations_map = @seq.operations_map + def get_or_create_op(op_class, *args) = @seq.get_or_create_op(op_class, *args) end class SnippetBuilder < BaseBuilder diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index f9d99fa..7024ce3 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -306,62 +306,4 @@ def check_signature raise TypeCheckError, 'true/false branches mismatch' unless inputs[1] == inputs[2] && inputs[1] == outputs[0] end end - - BASE_OP_CLASSES = { - 'not' => Not, - 'neg' => Neg, - 'popcnt' => Popcnt, - 'clz' => Clz, - 'ctz' => Ctz, - 'reverse' => Reverse, - 'add' => Add, - 'sub' => Sub, - 'mul' => Mul, - 'and' => And, - 'orr' => Orr, - 'xor' => Xor, - 'lsl' => Lsl, - 'lsr' => Lsr, - 'asr' => Asr, - 'eq' => Eq, - 'ne' => Ne, - 'slt' => Slt, - 'sle' => Sle, - 'sgt' => Sgt, - 'sge' => Sge, - 'ult' => Ult, - 'ule' => Ule, - 'ugt' => Ugt, - 'uge' => Uge, - 'div_s' => DivS, - 'div_u' => DivU, - 'rem_s' => RemS, - 'rem_u' => RemU, - 'ror' => Ror, - 'rol' => Rol, - 'add_overflow' => AddOverflow, - 'sub_overflow' => SubOverflow, - 'select' => Select, - }.freeze - - def self.lookup_operation(name) - if (m = name.match(/^extend_sign_(\d+)_to_(\d+)$/)) - return ExtendSign.new(m[1].to_i, m[2].to_i) - end - if (m = name.match(/^extend_zero_(\d+)_to_(\d+)$/)) - return ExtendZero.new(m[1].to_i, m[2].to_i) - end - if (m = name.match(/^extract_low_(\d+)_to_(\d+)$/)) - return ExtractLow.new(m[1].to_i, m[2].to_i) - end - parts = name.split('_') - return nil unless parts.last.match?(/^\d+$/) - width = parts.pop.to_i - (1..parts.size).reverse_each do |len| - base = parts[0...len].join('_') - klass = BASE_OP_CLASSES[base] - return klass.new(width) if klass - end - nil - end end diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 6ef7563..6498ccf 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -357,7 +357,7 @@ def initialize(arch_name, arch_attributes = []) @encode_snip_id = 0 @constraint_cache = {} @constraint_snip_id = 0 - @ops_used = Set.new + @ops_used = {} end def resolved(op) @@ -375,8 +375,9 @@ def op_alu(adl_name, lhs_signed, a, b) w = [a.width, b.width].max a = @builder.ensure_width(a, w) b = @builder.ensure_width(b, w) + op = @builder.get_or_create_op(op_class, w) out = @builder.seq.new_temp(w) - @builder.seq.add_op(op_class.new(w), [a.name, b.name], [out.name]) + @builder.seq.add_op(op, [a.name, b.name], [out.name]) out end @@ -386,8 +387,9 @@ def op_cmp(adl_name, unsigned, a, b) w = [a.width, b.width].max a = @builder.ensure_width(a, w) b = @builder.ensure_width(b, w) + op = @builder.get_or_create_op(op_class, w) out = @builder.seq.new_temp(1) - @builder.seq.add_op(op_class.new(w), [a.name, b.name], [out.name]) + @builder.seq.add_op(op, [a.name, b.name], [out.name]) out end @@ -404,8 +406,8 @@ def widen_or_truncate(name, dest_type, src, src_type) end end - def collect_ops(seq) - seq.stmts.each { |s| @ops_used << s.specifier if s.kind == 'op' } + def collect_ops(_seq) + @builder.operations_map.each { |name, op| @ops_used[name] = op } end def stmt_to_lira(stmt) @@ -624,9 +626,8 @@ def build_arch end end - @ops_used.each do |op_name| - op = Lira.lookup_operation(op_name) - @arch_builder.add_operation(op) if op + @ops_used.each_value do |op| + @arch_builder.add_operation(op) end @arch_builder.build diff --git a/sim_gen_lira/base_ops_gen.rb b/sim_gen_lira/base_ops_gen.rb index 0b49af5..df976ea 100644 --- a/sim_gen_lira/base_ops_gen.rb +++ b/sim_gen_lira/base_ops_gen.rb @@ -29,13 +29,8 @@ class << self def generate_file(out, operations) out.puts HEADER - - operations.each do |op| - instance = Lira.lookup_operation(op.name) || op - out.puts instance.to_cpp - end + operations.each { |op| out.puts op.to_cpp } out.puts - out.puts FOOTER end end diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index 5e6183c..0826755 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -6,8 +6,14 @@ module LiraCppGen module OpRegistry + @ops = {} + + def self.ops=(map) + @ops = map + end + def self.lookup(name) - Lira.lookup_operation(name) or raise "Unknown operation: #{name}" + @ops[name] or raise "Unknown operation: #{name}" end end diff --git a/sim_gen_lira/cpp_ops.rb b/sim_gen_lira/cpp_ops.rb index 348e3fe..0be1624 100644 --- a/sim_gen_lira/cpp_ops.rb +++ b/sim_gen_lira/cpp_ops.rb @@ -4,7 +4,7 @@ module Lira module CppCodegen def cpp_func_name - generate_name + name end def cpp_return_type @@ -42,9 +42,12 @@ def cpp_body when 'asr' then asr_body when 'div_u' then 'return (b == 0) ? c : a / b;' when 'div_s' then div_s_body - when 'select' then 'return cond ? a : b;' + when 'select' then 'return a ? b : c;' when 'rem_u' then rem_u_body when 'rem_s' then rem_s_body + when 'extend_sign' then extend_sign_body + when 'extend_zero' then extend_zero_body + when 'extract_low' then extract_low_body else raise "No cpp_body defined for operation #{semantic_base}" end end @@ -93,8 +96,32 @@ def rem_s_body return (#{t})res; CPP end + + def extend_sign_body + return 'return a;' if inputs[0] == 1 + t = Utility::HelperCpp.gen_type(outputs[0]) + <<~CPP + #{t} val = a & (((#{t})1 << #{inputs[0]}) - 1); + #{t} sign = (val >> (#{inputs[0]} - 1)) & 1; + if (sign) + return val | (~(((#{t})1 << #{inputs[0]}) - 1)); + else + return val; + CPP + end + + def extend_zero_body + t = Utility::HelperCpp.gen_type(outputs[0]) + "return a & (((#{t})1 << #{inputs[0]}) - 1);" + end + + def extract_low_body + t = Utility::HelperCpp.gen_type(inputs[0]) + "return a & (((#{t})1 << #{outputs[0]}) - 1);" + end end + class Operation; include CppCodegen; end class UnaryOp; include CppCodegen; end class BinaryOp; include CppCodegen; end class CmpOp; include CppCodegen; end diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index fd44b26..0053c1e 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -17,6 +17,9 @@ arch = Lira::ArchSerYaml.read_arch(ARGV[0]) +ops_map = arch.operations.to_h { |op| [op.name, op] } +LiraCppGen::OpRegistry.ops = ops_map + ir_hash = { isa_name: arch.name, regfiles: arch.register_files.map do |rf| From b52fa03196be1ffc49d1da855ea004f6e1c6b569 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 15:57:59 +0300 Subject: [PATCH 60/75] Introduced base operations enum instead of strings --- lib/lira/ir_ops.rb | 123 ++++++++++++++++++++++++++-------------- sim_gen_lira/cpp_gen.rb | 2 +- sim_gen_lira/cpp_ops.rb | 58 +++++++++---------- 3 files changed, 111 insertions(+), 72 deletions(-) diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 7024ce3..2c5fff5 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -4,9 +4,48 @@ module Lira class TypeCheckError < StandardError; end + module BaseOp + NOT = :not; + NEG = :neg + ADD = :add; + SUB = :sub; + MUL = :mul + AND = :and; + ORR = :orr; + XOR = :xor + LSL = :lsl; + LSR = :lsr; + ASR = :asr + EQ = :eq; + NE = :ne + SLT = :slt; + SLE = :sle; + SGT = :sgt; + SGE = :sge + ULT = :ult; + ULE = :ule; + UGT = :ugt; + UGE = :uge + DIV_U = :div_u; + DIV_S = :div_s + REM_U = :rem_u; + REM_S = :rem_s + ROR = :ror; + ROL = :rol + ADD_OVERFLOW = :add_overflow; + SUB_OVERFLOW = :sub_overflow + SELECT = :select + EXTEND_SIGN = :extend_sign; EXTEND_ZERO = :extend_zero + EXTRACT_LOW = :extract_low + POPCNT = :popcnt; + CTZ = :ctz; + CLZ = :clz + REVERSE = :reverse + end + module StdOperation def base_name - self.class.name.split('::').last.downcase + self.class.name.split('::').last.downcase.to_sym end def generate_name @@ -129,7 +168,7 @@ class ExtractLowOp < Operation def initialize(in_bits, out_bits, name: nil) name ||= "extract_low_#{in_bits}_to_#{out_bits}" super(name, [], [in_bits], [out_bits], - semantic_base: 'extract_low', semantic_func: nil, semantic_table: nil) + semantic_base: BaseOp::EXTRACT_LOW, semantic_func: nil, semantic_table: nil) check_signature end @@ -145,95 +184,95 @@ def generate_name end class Not < UnaryOp - def initialize(bits); super(bits, semantic_base: 'not'); end + def initialize(bits); super(bits, semantic_base: BaseOp::NOT); end end class Neg < UnaryOp - def initialize(bits); super(bits, semantic_base: 'neg'); end + def initialize(bits); super(bits, semantic_base: BaseOp::NEG); end end class Add < BinaryOp - def initialize(bits); super(bits, semantic_base: 'add'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ADD); end end class Sub < BinaryOp - def initialize(bits); super(bits, semantic_base: 'sub'); end + def initialize(bits); super(bits, semantic_base: BaseOp::SUB); end end class Mul < BinaryOp - def initialize(bits); super(bits, semantic_base: 'mul'); end + def initialize(bits); super(bits, semantic_base: BaseOp::MUL); end end class And < BinaryOp - def initialize(bits); super(bits, semantic_base: 'and'); end + def initialize(bits); super(bits, semantic_base: BaseOp::AND); end end class Orr < BinaryOp - def initialize(bits); super(bits, semantic_base: 'orr'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ORR); end end class Xor < BinaryOp - def initialize(bits); super(bits, semantic_base: 'xor'); end + def initialize(bits); super(bits, semantic_base: BaseOp::XOR); end end class Lsl < BinaryOp - def initialize(bits); super(bits, semantic_base: 'lsl'); end + def initialize(bits); super(bits, semantic_base: BaseOp::LSL); end end class Lsr < BinaryOp - def initialize(bits); super(bits, semantic_base: 'lsr'); end + def initialize(bits); super(bits, semantic_base: BaseOp::LSR); end end class Asr < BinaryOp - def initialize(bits); super(bits, semantic_base: 'asr'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ASR); end end class Eq < CmpOp - def initialize(bits); super(bits, semantic_base: 'eq'); end + def initialize(bits); super(bits, semantic_base: BaseOp::EQ); end end class Ne < CmpOp - def initialize(bits); super(bits, semantic_base: 'ne'); end + def initialize(bits); super(bits, semantic_base: BaseOp::NE); end end class Slt < CmpOp - def initialize(bits); super(bits, semantic_base: 'slt'); end + def initialize(bits); super(bits, semantic_base: BaseOp::SLT); end end class Sle < CmpOp - def initialize(bits); super(bits, semantic_base: 'sle'); end + def initialize(bits); super(bits, semantic_base: BaseOp::SLE); end end class Sgt < CmpOp - def initialize(bits); super(bits, semantic_base: 'sgt'); end + def initialize(bits); super(bits, semantic_base: BaseOp::SGT); end end class Sge < CmpOp - def initialize(bits); super(bits, semantic_base: 'sge'); end + def initialize(bits); super(bits, semantic_base: BaseOp::SGE); end end class Ult < CmpOp - def initialize(bits); super(bits, semantic_base: 'ult'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ULT); end end class Ule < CmpOp - def initialize(bits); super(bits, semantic_base: 'ule'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ULE); end end class Ugt < CmpOp - def initialize(bits); super(bits, semantic_base: 'ugt'); end + def initialize(bits); super(bits, semantic_base: BaseOp::UGT); end end class Uge < CmpOp - def initialize(bits); super(bits, semantic_base: 'uge'); end + def initialize(bits); super(bits, semantic_base: BaseOp::UGE); end end class ExtendSign < ExtendOp - def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_sign'); end + def initialize(in_bits, out_bits); super(in_bits, out_bits, BaseOp::EXTEND_SIGN); end end class ExtendZero < ExtendOp - def initialize(in_bits, out_bits); super(in_bits, out_bits, 'extend_zero'); end + def initialize(in_bits, out_bits); super(in_bits, out_bits, BaseOp::EXTEND_ZERO); end end class ExtractLow < ExtractLowOp @@ -241,55 +280,55 @@ def initialize(in_bits, out_bits); super(in_bits, out_bits); end end class Popcnt < UnaryOp - def initialize(bits); super(bits, semantic_base: 'popcnt'); end + def initialize(bits); super(bits, semantic_base: BaseOp::POPCNT); end end class Ctz < UnaryOp - def initialize(bits); super(bits, semantic_base: 'ctz'); end + def initialize(bits); super(bits, semantic_base: BaseOp::CTZ); end end class Clz < UnaryOp - def initialize(bits); super(bits, semantic_base: 'clz'); end + def initialize(bits); super(bits, semantic_base: BaseOp::CLZ); end end class Reverse < UnaryOp - def initialize(bits); super(bits, semantic_base: 'reverse'); end + def initialize(bits); super(bits, semantic_base: BaseOp::REVERSE); end end class RemU < BinaryOp - def initialize(bits); super(bits, semantic_base: 'rem_u'); end - def base_name; 'rem_u'; end + def initialize(bits); super(bits, semantic_base: BaseOp::REM_U); end + def base_name; BaseOp::REM_U; end end class RemS < BinaryOp - def initialize(bits); super(bits, semantic_base: 'rem_s'); end - def base_name; 'rem_s'; end + def initialize(bits); super(bits, semantic_base: BaseOp::REM_S); end + def base_name; BaseOp::REM_S; end end class Ror < BinaryOp - def initialize(bits); super(bits, semantic_base: 'ror'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ROR); end end class Rol < BinaryOp - def initialize(bits); super(bits, semantic_base: 'rol'); end + def initialize(bits); super(bits, semantic_base: BaseOp::ROL); end end class AddOverflow < CmpOp - def initialize(bits); super(bits, out_bits: 1, semantic_base: 'add_overflow'); end + def initialize(bits); super(bits, out_bits: 1, semantic_base: BaseOp::ADD_OVERFLOW); end end class SubOverflow < CmpOp - def initialize(bits); super(bits, out_bits: 1, semantic_base: 'sub_overflow'); end + def initialize(bits); super(bits, out_bits: 1, semantic_base: BaseOp::SUB_OVERFLOW); end end class DivU < TernaryOp - def initialize(bits); super(bits, semantic_base: 'div_u'); end - def base_name; 'div_u'; end + def initialize(bits); super(bits, semantic_base: BaseOp::DIV_U); end + def base_name; BaseOp::DIV_U; end end class DivS < TernaryOp - def initialize(bits); super(bits, semantic_base: 'div_s'); end - def base_name; 'div_s'; end + def initialize(bits); super(bits, semantic_base: BaseOp::DIV_S); end + def base_name; BaseOp::DIV_S; end end class Select < Operation @@ -298,7 +337,7 @@ class Select < Operation def initialize(bits) name = "select_#{bits}" super(name, [], [1, bits, bits], [bits], - semantic_base: 'select', semantic_func: nil, semantic_table: nil) + semantic_base: BaseOp::SELECT, semantic_func: nil, semantic_table: nil) check_signature end diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index 0826755..0132503 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -63,7 +63,7 @@ def emit_code inputs = s.inputs.map { |i| resolve_var(i) } op = OpRegistry.lookup(s.specifier) - if op.semantic_base == 'select' + if op.semantic_base == Lira::BaseOp::SELECT emit("#{out} = #{inputs[0]} ? #{inputs[1]} : #{inputs[2]};") else emit("#{out} = #{op.cpp_func_name}(#{inputs.join(', ')});") diff --git a/sim_gen_lira/cpp_ops.rb b/sim_gen_lira/cpp_ops.rb index 0be1624..08f5cd3 100644 --- a/sim_gen_lira/cpp_ops.rb +++ b/sim_gen_lira/cpp_ops.rb @@ -19,35 +19,35 @@ def cpp_params def cpp_body case semantic_base - when 'not' then 'return ~a;' - when 'neg' then 'return -a;' - when 'add' then 'return a + b;' - when 'sub' then 'return a - b;' - when 'mul' then 'return a * b;' - when 'and' then 'return a & b;' - when 'orr' then 'return a | b;' - when 'xor' then 'return a ^ b;' - when 'eq' then 'return (a == b) ? 1 : 0;' - when 'ne' then 'return (a != b) ? 1 : 0;' - when 'slt' then signed_cmp('<') - when 'sle' then signed_cmp('<=') - when 'sgt' then signed_cmp('>') - when 'sge' then signed_cmp('>=') - when 'ult' then 'return (a < b) ? 1 : 0;' - when 'ule' then 'return (a <= b) ? 1 : 0;' - when 'ugt' then 'return (a > b) ? 1 : 0;' - when 'uge' then 'return (a >= b) ? 1 : 0;' - when 'lsl' then "b &= #{inputs[0] - 1}; return a << b;" - when 'lsr' then "b &= #{inputs[0] - 1}; return a >> b;" - when 'asr' then asr_body - when 'div_u' then 'return (b == 0) ? c : a / b;' - when 'div_s' then div_s_body - when 'select' then 'return a ? b : c;' - when 'rem_u' then rem_u_body - when 'rem_s' then rem_s_body - when 'extend_sign' then extend_sign_body - when 'extend_zero' then extend_zero_body - when 'extract_low' then extract_low_body + when BaseOp::NOT then 'return ~a;' + when BaseOp::NEG then 'return -a;' + when BaseOp::ADD then 'return a + b;' + when BaseOp::SUB then 'return a - b;' + when BaseOp::MUL then 'return a * b;' + when BaseOp::AND then 'return a & b;' + when BaseOp::ORR then 'return a | b;' + when BaseOp::XOR then 'return a ^ b;' + when BaseOp::EQ then 'return (a == b) ? 1 : 0;' + when BaseOp::NE then 'return (a != b) ? 1 : 0;' + when BaseOp::SLT then signed_cmp('<') + when BaseOp::SLE then signed_cmp('<=') + when BaseOp::SGT then signed_cmp('>') + when BaseOp::SGE then signed_cmp('>=') + when BaseOp::ULT then 'return (a < b) ? 1 : 0;' + when BaseOp::ULE then 'return (a <= b) ? 1 : 0;' + when BaseOp::UGT then 'return (a > b) ? 1 : 0;' + when BaseOp::UGE then 'return (a >= b) ? 1 : 0;' + when BaseOp::LSL then "b &= #{inputs[0] - 1}; return a << b;" + when BaseOp::LSR then "b &= #{inputs[0] - 1}; return a >> b;" + when BaseOp::ASR then asr_body + when BaseOp::DIV_U then 'return (b == 0) ? c : a / b;' + when BaseOp::DIV_S then div_s_body + when BaseOp::SELECT then 'return a ? b : c;' + when BaseOp::REM_U then rem_u_body + when BaseOp::REM_S then rem_s_body + when BaseOp::EXTEND_SIGN then extend_sign_body + when BaseOp::EXTEND_ZERO then extend_zero_body + when BaseOp::EXTRACT_LOW then extract_low_body else raise "No cpp_body defined for operation #{semantic_base}" end end From 645f19b5c714bb2f2b0bfd99390d0d2aff6fa0cd Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 16:08:15 +0300 Subject: [PATCH 61/75] Refactored --- lib/lira/arch_ser_txt.rb | 2 -- lib/lira/ir_ops.rb | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/lira/arch_ser_txt.rb b/lib/lira/arch_ser_txt.rb index 302302d..0792481 100644 --- a/lib/lira/arch_ser_txt.rb +++ b/lib/lira/arch_ser_txt.rb @@ -36,7 +36,6 @@ def from_serializable(klass, data, item_class = nil) end if klass.respond_to?(:from_h) - # ะ ะตะบัƒั€ัะธะฒะฝะพ ะฟั€ะตะพะฑั€ะฐะทัƒะตะผ ะฒัะต ะทะฝะฐั‡ะตะฝะธั ั…ะตัˆะฐ transformed = data.transform_values { |v| from_serializable(Object, v) } klass.from_h(transformed) else @@ -44,7 +43,6 @@ def from_serializable(klass, data, item_class = nil) end end - # ะ’ัะฟะพะผะพะณะฐั‚ะตะปัŒะฝั‹ะต ะผะตั‚ะพะดั‹ ะดะปั ั€ะฐะฑะพั‚ั‹ ั JSON def write_json(data, path) File.write(path, JSON.pretty_generate(data)) end diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 2c5fff5..85980f1 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -35,7 +35,8 @@ module BaseOp ADD_OVERFLOW = :add_overflow; SUB_OVERFLOW = :sub_overflow SELECT = :select - EXTEND_SIGN = :extend_sign; EXTEND_ZERO = :extend_zero + EXTEND_SIGN = :extend_sign; + EXTEND_ZERO = :extend_zero EXTRACT_LOW = :extract_low POPCNT = :popcnt; CTZ = :ctz; From 5e1ba9531ee2e059461387d331ea0d3a9f7cee6b Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 16:44:55 +0300 Subject: [PATCH 62/75] Aliases support --- sim_gen/sim_gen.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim_gen/sim_gen.rb b/sim_gen/sim_gen.rb index 572cf54..f3cc91c 100755 --- a/sim_gen/sim_gen.rb +++ b/sim_gen/sim_gen.rb @@ -11,7 +11,7 @@ require 'yaml' -yaml_data = YAML.load_file(ARGV[0]) +yaml_data = YAML.safe_load_file(ARGV[0], permitted_classes: [Symbol], aliases: true) yaml_data[:isa_name] = "RISCV" File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(yaml_data)) From 740ad7d242e709272796431208068496e6a99a59 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 16:45:12 +0300 Subject: [PATCH 63/75] [simgen] Redundant arch hash was removed --- sim_gen_lira/CPUState/cpu_state.rb | 82 ++++++++++--------- sim_gen_lira/Decoders/decoder.rb | 19 ++--- sim_gen_lira/ExecEngines/base_exec_engine.rb | 11 ++- sim_gen_lira/ExecEngines/naive_interpreter.rb | 20 ++--- sim_gen_lira/Hart/hart.rb | 16 ++-- sim_gen_lira/ISA/isa.rb | 32 ++++---- sim_gen_lira/sim_gen.rb | 65 +++------------ sim_gen_lira/snippets_gen.rb | 4 +- 8 files changed, 105 insertions(+), 144 deletions(-) diff --git a/sim_gen_lira/CPUState/cpu_state.rb b/sim_gen_lira/CPUState/cpu_state.rb index 820620f..0950373 100644 --- a/sim_gen_lira/CPUState/cpu_state.rb +++ b/sim_gen_lira/CPUState/cpu_state.rb @@ -24,9 +24,9 @@ def increase_icount_func end def find_pc_reg(regfiles) - regfiles.each do |regfile| - regfile[:regs].each do |reg| - return reg if reg[:attrs].include? :pc + regfiles.each do |rf| + rf.regs.each do |reg| + return [reg, rf] if reg.attributes.any? { |a| a.to_s == 'pc' } end end raise 'PC register not found in the register files' @@ -34,9 +34,9 @@ def find_pc_reg(regfiles) def generate_pc_decl(regfiles) emitter = Utility::GenEmitter.new - pc_reg = find_pc_reg(regfiles) + pc_reg, = find_pc_reg(regfiles) emitter.emit_line('// Program Counter') - emitter.emit_line("#{Utility::HelperCpp.gen_type(pc_reg[:size])} m_pc;") + emitter.emit_line("#{Utility::HelperCpp.gen_type(regfiles[0].reg_size.lanes_base)} m_pc;") emitter.emit_blank_line emitter.increase_indent_all(2) emitter @@ -44,16 +44,17 @@ def generate_pc_decl(regfiles) def generate_pc_functions(regfiles) emitter = Utility::GenEmitter.new - pc_reg = find_pc_reg(regfiles) + pc_reg, = find_pc_reg(regfiles) + pc_type = Utility::HelperCpp.gen_type(regfiles[0].reg_size.lanes_base) emitter.emit_line('// Set PC function') - emitter.emit_line("void setPC(const #{Utility::HelperCpp.gen_type(pc_reg[:size])} value) {") + emitter.emit_line("void setPC(const #{pc_type} value) {") emitter.increase_indent emitter.emit_line('m_pc = value;') emitter.decrease_indent emitter.emit_line('}') emitter.emit_blank_line emitter.emit_line('// Read PC function') - emitter.emit_line("#{Utility::HelperCpp.gen_type(pc_reg[:size])} getPC() const {") + emitter.emit_line("#{pc_type} getPC() const {") emitter.increase_indent emitter.emit_line('return m_pc;') emitter.decrease_indent @@ -65,11 +66,12 @@ def generate_pc_functions(regfiles) def generate_cpu_regsets(regfiles) emitter = Utility::GenEmitter.new - regfiles.each do |regfile| - regfile_size = regfile[:regs].size - regfile[:regs].count { |reg| reg[:attrs].include? :pc } - emitter.emit_line("// Register file: #{regfile[:name]}") - regsize = regfile[:regs][0][:size] - array_str = "std::array<#{Utility::HelperCpp.gen_type(regsize)}, #{regfile_size}> m_#{regfile[:name]}{};" + regfiles.each do |rf| + pc_count = rf.regs.count { |r| r.attributes.any? { |a| a.to_s == 'pc' } } + rf_size = rf.regs.size - pc_count + emitter.emit_line("// Register file: #{rf.name}") + regsize = rf.reg_size.lanes_base + array_str = "std::array<#{Utility::HelperCpp.gen_type(regsize)}, #{rf_size}> m_#{rf.name}{};" emitter.emit_line(array_str) emitter.emit_blank_line end @@ -77,23 +79,23 @@ def generate_cpu_regsets(regfiles) emitter end - def generate_if_zero_reg_check(emitter, regfile) - regfile[:regs].each_with_index do |reg, reg_index| - if reg[:attrs].include? :zero - emitter.emit_line("if (reg == #{reg_index}) return; // #{reg[:name]} is zero register") + def generate_if_zero_reg_check(emitter, rf) + rf.regs.each_with_index do |reg, reg_index| + if reg.attributes.any? { |a| a.to_s == 'zero' } + emitter.emit_line("if (reg == #{reg_index}) return; // #{reg.name} is zero register") end end end def generate_set_reg_functions(regfiles) emitter = Utility::GenEmitter.new - regfiles.each do |regfile| - emitter.emit_line("// Set register function for #{regfile[:name]}") + regfiles.each do |rf| + emitter.emit_line("// Set register function for #{rf.name}") emitter.emit_line('template') - emitter.emit_line("void set#{regfile[:name]}(const std::size_t reg, const T value) {") + emitter.emit_line("void set#{rf.name}(const std::size_t reg, const T value) {") emitter.increase_indent - generate_if_zero_reg_check(emitter, regfile) - emitter.emit_line("m_#{regfile[:name]}[reg] = value;") + generate_if_zero_reg_check(emitter, rf) + emitter.emit_line("m_#{rf.name}[reg] = value;") emitter.decrease_indent emitter.emit_line('}') emitter.emit_blank_line @@ -104,12 +106,12 @@ def generate_set_reg_functions(regfiles) def generate_read_reg_functions(regfiles) emitter = Utility::GenEmitter.new - regfiles.each do |regfile| - emitter.emit_line("// Read register function for #{regfile[:name]}") + regfiles.each do |rf| + emitter.emit_line("// Read register function for #{rf.name}") emitter.emit_line('template') - emitter.emit_line("T get#{regfile[:name]}(const std::size_t reg) const {") + emitter.emit_line("T get#{rf.name}(const std::size_t reg) const {") emitter.increase_indent - emitter.emit_line("return static_cast(m_#{regfile[:name]}[reg]);") + emitter.emit_line("return static_cast(m_#{rf.name}[reg]);") emitter.decrease_indent emitter.emit_line('}') emitter.emit_blank_line @@ -165,19 +167,23 @@ module CPUState module Header module_function - def generate_cpu_state(input_ir) - pc_decl = Helper.generate_pc_decl(input_ir[:regfiles]) - pc_functions = Helper.generate_pc_functions(input_ir[:regfiles]) - regsets_decl = Helper.generate_cpu_regsets(input_ir[:regfiles]) - setreg_funcs = Helper.generate_set_reg_functions(input_ir[:regfiles]) - readreg_funcs = Helper.generate_read_reg_functions(input_ir[:regfiles]) + def generate_cpu_state(arch) + regfiles = arch.register_files + pc_decl = Helper.generate_pc_decl(regfiles) + pc_functions = Helper.generate_pc_functions(regfiles) + regsets_decl = Helper.generate_cpu_regsets(regfiles) + setreg_funcs = Helper.generate_set_reg_functions(regfiles) + readreg_funcs = Helper.generate_read_reg_functions(regfiles) do_exit_func = Helper.generate_do_exit_func increase_icount_func = Helper.increase_icount_func - interface_func = Helper.generate_interface_func(input_ir[:interface_functions]) + iface = arch.environment_functions.reject { |ef| %w[setPC getPC].include?(ef.name) } + iface_hashes = iface.map { |ef| { name: ef.name, argument_types: ef.inputs, return_types: ef.outputs } } + interface_func = Helper.generate_interface_func(iface_hashes) - base_type = Utility::HelperCpp.gen_type input_ir[:regfiles][0][:regs][0][:size] -"#ifndef GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED -#define GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED + base_type = Utility::HelperCpp.gen_type regfiles[0].reg_size.lanes_base + isa_name = arch.name +"#ifndef GENERATED_#{isa_name.upcase}_CPUSTATE_HH_INCLUDED +#define GENERATED_#{isa_name.upcase}_CPUSTATE_HH_INCLUDED #include \"memory.hh\" @@ -223,7 +229,7 @@ class CPU final { } // prot::state -#endif // GENERATED_#{input_ir[:isa_name].upcase}_CPUSTATE_HH_INCLUDED +#endif // GENERATED_#{isa_name.upcase}_CPUSTATE_HH_INCLUDED " end end @@ -231,7 +237,7 @@ class CPU final { module TranslationUnit module_function - def generate_cpu_state(input_ir) + def generate_cpu_state(arch) # Currently, no implementation is needed for the CPUState translation unit. '' end diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index 3980cd6..5fbb561 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -6,10 +6,10 @@ module Decoder module Header module_function - def generate_decoder(ir_hash) + def generate_decoder(arch) <<~CPP - #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_DECODER_HH_INCLUDED - #define GENERATED_#{ir_hash[:isa_name].upcase}_DECODER_HH_INCLUDED + #ifndef GENERATED_#{arch.name.upcase}_DECODER_HH_INCLUDED + #define GENERATED_#{arch.name.upcase}_DECODER_HH_INCLUDED #include "isa.hh" #include @@ -28,14 +28,13 @@ def generate_decoder(ir_hash) module TranslationUnit module_function - def generate_decoder(ir_hash) - instructions = ir_hash[:instructions] - snippets = ir_hash[:snippets].to_h { |s| [s[:name], s[:seq]] } + def generate_decoder(arch) + snippets = arch.snippets.to_h { |s| [s.name, s.seq] } body = [] - instructions.each do |insn| - constraint_name = insn[:encoding][:constraint_decode] - decode_names = insn[:encoding][:decode_snippets] + arch.instructions.each do |insn| + constraint_name = insn.encoding.constraint_decode + decode_names = insn.encoding.decode next unless constraint_name && decode_names constraint_seq = snippets[constraint_name] @@ -48,7 +47,7 @@ def generate_decoder(ir_hash) body << <<~CPP if (#{constraint_name}(raw_insn)) { #{operand_calls} - insn.m_opc = Opcode::k#{insn[:name].to_s.upcase}; + insn.m_opc = Opcode::k#{insn.name.to_s.upcase}; return insn; } CPP diff --git a/sim_gen_lira/ExecEngines/base_exec_engine.rb b/sim_gen_lira/ExecEngines/base_exec_engine.rb index 97212ab..9f42c45 100644 --- a/sim_gen_lira/ExecEngines/base_exec_engine.rb +++ b/sim_gen_lira/ExecEngines/base_exec_engine.rb @@ -5,10 +5,10 @@ module BaseExecEngine module Header module_function - def generate_base_exec_engine(input_ir) + def generate_base_exec_engine(arch) <<~CPP -#ifndef GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED -#define GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED +#ifndef GENERATED_#{arch.name.upcase}_EXEC_ENGINE_HH_INCLUDED +#define GENERATED_#{arch.name.upcase}_EXEC_ENGINE_HH_INCLUDED #include \"cpu_state.hh\" #include \"isa.hh\" @@ -26,7 +26,7 @@ def generate_base_exec_engine(input_ir) }; } // namespace prot::engine -#endif // GENERATED_#{input_ir[:isa_name].upcase}_EXEC_ENGINE_HH_INCLUDED +#endif // GENERATED_#{arch.name.upcase}_EXEC_ENGINE_HH_INCLUDED CPP end end @@ -34,8 +34,7 @@ def generate_base_exec_engine(input_ir) module TranslationUnit module_function - def generate_base_exec_engine(input_ir) - max_xlen = SimGen::Helper::find_max_regsize(input_ir[:regfiles]) + def generate_base_exec_engine(arch) <<~CPP #include "base_exec_engine.hh" #include "memory.hh" diff --git a/sim_gen_lira/ExecEngines/naive_interpreter.rb b/sim_gen_lira/ExecEngines/naive_interpreter.rb index aa55dd4..cde6264 100644 --- a/sim_gen_lira/ExecEngines/naive_interpreter.rb +++ b/sim_gen_lira/ExecEngines/naive_interpreter.rb @@ -5,10 +5,10 @@ module NaiveInterpreter module Header module_function - def generate_naive_interpreter(ir_hash) + def generate_naive_interpreter(arch) <<~CPP - #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED - #define GENERATED_#{ir_hash[:isa_name].upcase}_INTERPRETER_HH_INCLUDED + #ifndef GENERATED_#{arch.name.upcase}_INTERPRETER_HH_INCLUDED + #define GENERATED_#{arch.name.upcase}_INTERPRETER_HH_INCLUDED #include "base_exec_engine.hh" @@ -27,13 +27,13 @@ class Interpreter : public ExecEngine { module TranslationUnit module_function - def generate_naive_interpreter(ir_hash) + def generate_naive_interpreter(arch) exec_functions = [] branch_insns = [] - ir_hash[:instructions].each do |insn| - name = insn[:name].to_s.upcase - seq = insn[:semantic_seq] + arch.instructions.each do |insn| + name = insn.name.to_s.upcase + seq = insn.semantic if seq && seq.stmts.any? translator = LiraCppGen::Translator.new(seq, :execute, 2) @@ -64,8 +64,8 @@ def generate_naive_interpreter(ir_hash) } CPP - handlers_init = ir_hash[:instructions].map do |insn| - "m_handlers[toUnderlying(Opcode::k#{insn[:name].to_s.upcase})] = &do#{insn[:name].to_s.upcase};" + handlers_init = arch.instructions.map do |insn| + "m_handlers[toUnderlying(Opcode::k#{insn.name.to_s.upcase})] = &do#{insn.name.to_s.upcase};" end.join("\n ") <<~CPP @@ -94,7 +94,7 @@ class ExecHandlersMap { public: using ExecHandler = void (*)(CPU &cpu, const Instruction &insn); private: - std::array m_handlers{}; + std::array m_handlers{}; public: constexpr ExecHandlersMap() { #{handlers_init} diff --git a/sim_gen_lira/Hart/hart.rb b/sim_gen_lira/Hart/hart.rb index dd1e13b..81e62ef 100644 --- a/sim_gen_lira/Hart/hart.rb +++ b/sim_gen_lira/Hart/hart.rb @@ -5,7 +5,7 @@ module Header def get_addr_type(instructions) instructions.each do |insn| - seq = insn[:semantic_seq] + seq = insn.semantic next unless seq && seq.stmts seq.stmts.each do |stmt| if stmt.kind == 'env' && (stmt.specifier == 'writeMem' || stmt.specifier == 'readMem') @@ -16,13 +16,13 @@ def get_addr_type(instructions) 32 end - def generate_hart(ir_hash) - type = get_addr_type(ir_hash[:instructions]) + def generate_hart(arch) + type = get_addr_type(arch.instructions) type_str = Utility::HelperCpp.gen_type(type) <<~CPP - #ifndef GENERATED_#{ir_hash[:isa_name].upcase}_HART_HH_INCLUDED - #define GENERATED_#{ir_hash[:isa_name].upcase}_HART_HH_INCLUDED + #ifndef GENERATED_#{arch.name.upcase}_HART_HH_INCLUDED + #define GENERATED_#{arch.name.upcase}_HART_HH_INCLUDED #include @@ -74,7 +74,7 @@ module TranslationUnit def get_addr_type(instructions) instructions.each do |insn| - seq = insn[:semantic_seq] + seq = insn.semantic next unless seq && seq.stmts seq.stmts.each do |stmt| if stmt.kind == 'env' && (stmt.specifier == 'writeMem' || stmt.specifier == 'readMem') @@ -85,8 +85,8 @@ def get_addr_type(instructions) 32 end - def generate_hart(ir_hash) - type = get_addr_type(ir_hash[:instructions]) + def generate_hart(arch) + type = get_addr_type(arch.instructions) type_str = Utility::HelperCpp.gen_type(type) <<~CPP diff --git a/sim_gen_lira/ISA/isa.rb b/sim_gen_lira/ISA/isa.rb index 6827f12..80abc4c 100644 --- a/sim_gen_lira/ISA/isa.rb +++ b/sim_gen_lira/ISA/isa.rb @@ -6,8 +6,8 @@ module Helper def find_max_regsize(regfiles) max = 0 regfiles.each do |rf| - rf[:regs].each do |reg| - max = reg[:size] if reg[:size] > max + rf.regs.each do |reg| + max = rf.reg_size.lanes_base if rf.reg_size.lanes_base > max end end max @@ -17,9 +17,9 @@ def find_max_operands(instructions) max_operands = 0 max_size = 0 instructions.each do |insn| - size = insn[:operand_sizes].size + size = insn.operand_sizes.size max_operands = size if size > max_operands - insn[:operand_sizes].each do |s| + insn.operand_sizes.each do |s| max_size = s if s > max_size end end @@ -47,7 +47,7 @@ def generate_instruction_struct(instructions) end def is_terminator_instruction(insn) - seq = insn[:semantic_seq] + seq = insn.semantic return false unless seq && seq.stmts seq.stmts.any? do |stmt| stmt.kind == 'env' && (stmt.specifier == 'setPC' || stmt.specifier == 'sysCall') @@ -62,7 +62,7 @@ def generate_is_terminator_function(instructions) emitter.increase_indent instructions.each do |insn| if is_terminator_instruction(insn) - emitter.emit_line("case Opcode::k#{insn[:name].to_s.upcase}: return true;") + emitter.emit_line("case Opcode::k#{insn.name.to_s.upcase}: return true;") end end emitter.emit_line("default: return false;") @@ -73,17 +73,13 @@ def generate_is_terminator_function(instructions) emitter end - # ะŸะพะปัƒั‡ะฐะตั‚ ั‚ะธะฟ ะฐะดั€ะตัะฐ ะธะท ะธะฝัั‚ั€ัƒะบั†ะธะน (ะฟะพ ะฟะตั€ะฒะพะผัƒ ะพะฟะตั€ะฐะฝะดัƒ readMem/writeMem) def get_addr_type_from_instructions(instructions) instructions.each do |insn| - seq = insn[:semantic_seq] + seq = insn.semantic next unless seq && seq.stmts seq.stmts.each do |stmt| if stmt.kind == 'env' && (stmt.specifier == 'readMem' || stmt.specifier == 'writeMem') - # ะŸะตั€ะฒั‹ะน ะฒั…ะพะด โ€” ะฐะดั€ะตั, ะตะณะพ ั‚ะธะฟ addr_input = stmt.inputs[0] - # ะฃะทะฝะฐั‚ัŒ ัˆะธั€ะธะฝัƒ ะฟะพ ะฟะตั€ะตะผะตะฝะฝะพะน (ะผะพะถะฝะพ ะธะท @var_widths, ะฝะพ ะทะดะตััŒ ะฝะตั‚ ะบะพะฝั‚ะตะบัั‚ะฐ) - # ะ—ะฐะณะปัƒัˆะบะฐ: ะฒะตั€ะฝั‘ะผ 32, ั‚ะฐะบ ะบะฐะบ ะฒ RISC-V ะฐะดั€ะตั 32-ะฑะธั‚ะฝั‹ะน return 32 end end @@ -95,10 +91,10 @@ def get_addr_type_from_instructions(instructions) module Header module_function - def generate_isa_header(ir_hash) - isa_name = ir_hash[:isa_name] - regfiles = ir_hash[:regfiles] - instructions = ir_hash[:instructions] + def generate_isa_header(arch) + isa_name = arch.name + regfiles = arch.register_files + instructions = arch.instructions max_xlen = Helper.find_max_regsize(regfiles) addr_width = Helper.get_addr_type_from_instructions(instructions) @@ -110,14 +106,14 @@ def generate_isa_header(ir_hash) else "uint32_t" end - opcode_enum = instructions.map { |insn| " k#{insn[:name].to_s.upcase}," }.join("\n") + opcode_enum = instructions.map { |insn| " k#{insn.name.to_s.upcase}," }.join("\n") instruction_struct = Helper.generate_instruction_struct(instructions) is_terminator_function = Helper.generate_is_terminator_function(instructions) get_ilen_lines = instructions.map do |insn| - enc_size = insn[:encoding][:encoded_size] || 32 # ะทะฐั‰ะธั‚ะฐ ะพั‚ nil + enc_size = insn.encoding.encoded_size || 32 len = enc_size / 8 - "case Opcode::k#{insn[:name].to_s.upcase}: return #{len};" + "case Opcode::k#{insn.name.to_s.upcase}: return #{len};" end.join("\n ") <<~CPP diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index 0053c1e..e51bb66 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -16,57 +16,18 @@ require_relative '../lib/lira/arch_ser_yaml' arch = Lira::ArchSerYaml.read_arch(ARGV[0]) +LiraCppGen::OpRegistry.ops = arch.operations.to_h { |op| [op.name, op] } -ops_map = arch.operations.to_h { |op| [op.name, op] } -LiraCppGen::OpRegistry.ops = ops_map - -ir_hash = { - isa_name: arch.name, - regfiles: arch.register_files.map do |rf| - { - name: rf.name, - regs: rf.regs.map.with_index do |r, idx| - { - name: r.name, - size: rf.reg_size.lanes_base, - attrs: r.attributes.map(&:to_sym) - } - end - } - end, - interface_functions: arch.environment_functions - .reject { |ef| ['setPC', 'getPC'].include?(ef.name) } - .map do |ef| - { name: ef.name, argument_types: ef.inputs, return_types: ef.outputs } - end, - instructions: arch.instructions.map do |insn| - { - name: insn.name, - operand_sizes: insn.operand_sizes, - operand_names: insn.operand_names, - encoding: { - const_part: insn.encoding.const_encoding_part, - encoded_size: insn.encoding.encoded_size, - const_mask: insn.encoding.const_mask, - decode_snippets: insn.encoding.decode, - constraint_decode: insn.encoding.constraint_decode - }, - semantic_seq: insn.semantic - } - end, - snippets: arch.snippets.map { |s| { name: s.name, seq: s.seq } } -} - -File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(ir_hash)) -File.write('cpu_state.cc', SimGen::CPUState::TranslationUnit.generate_cpu_state(ir_hash)) -File.write('base_exec_engine.hh', SimGen::BaseExecEngine::Header.generate_base_exec_engine(ir_hash)) -File.write('base_exec_engine.cc', SimGen::BaseExecEngine::TranslationUnit.generate_base_exec_engine(ir_hash)) -File.write('naive_interpreter.hh', SimGen::NaiveInterpreter::Header.generate_naive_interpreter(ir_hash)) -File.write('naive_interpreter.cc', SimGen::NaiveInterpreter::TranslationUnit.generate_naive_interpreter(ir_hash)) -File.write('decoder.hh', SimGen::Decoder::Header.generate_decoder(ir_hash)) -File.write('decoder.cc', SimGen::Decoder::TranslationUnit.generate_decoder(ir_hash)) -File.write('isa.hh', SimGen::ISA::Header.generate_isa_header(ir_hash)) -File.write('hart.hh', SimGen::Hart::Header.generate_hart(ir_hash)) -File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(ir_hash)) +File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(arch)) +File.write('cpu_state.cc', SimGen::CPUState::TranslationUnit.generate_cpu_state(arch)) +File.write('base_exec_engine.hh', SimGen::BaseExecEngine::Header.generate_base_exec_engine(arch)) +File.write('base_exec_engine.cc', SimGen::BaseExecEngine::TranslationUnit.generate_base_exec_engine(arch)) +File.write('naive_interpreter.hh', SimGen::NaiveInterpreter::Header.generate_naive_interpreter(arch)) +File.write('naive_interpreter.cc', SimGen::NaiveInterpreter::TranslationUnit.generate_naive_interpreter(arch)) +File.write('decoder.hh', SimGen::Decoder::Header.generate_decoder(arch)) +File.write('decoder.cc', SimGen::Decoder::TranslationUnit.generate_decoder(arch)) +File.write('isa.hh', SimGen::ISA::Header.generate_isa_header(arch)) +File.write('hart.hh', SimGen::Hart::Header.generate_hart(arch)) +File.write('hart.cc', SimGen::Hart::TranslationUnit.generate_hart(arch)) File.write('base_ops.h', SimGen.generate_base_ops(arch.operations)) -File.write('snippets.h', SimGen::Snippets.generate_snippets_header(ir_hash[:snippets])) +File.write('snippets.h', SimGen::Snippets.generate_snippets_header(arch.snippets)) diff --git a/sim_gen_lira/snippets_gen.rb b/sim_gen_lira/snippets_gen.rb index 2c559f8..ff9b721 100644 --- a/sim_gen_lira/snippets_gen.rb +++ b/sim_gen_lira/snippets_gen.rb @@ -6,8 +6,8 @@ module Snippets def generate_snippets_header(snippets) funcs = snippets - .select { |s| s[:name].start_with?('decode_') || s[:name].start_with?('constraint_') } - .map { |snip| generate_function(snip[:name], snip[:seq]) } + .select { |s| s.name.start_with?('decode_') || s.name.start_with?('constraint_') } + .map { |snip| generate_function(snip.name, snip.seq) } <<~CPP #ifndef GENERATED_SNIPPETS_H From dda6c2626e5f62f2634a15690d405fb426db3e52 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 17:23:32 +0300 Subject: [PATCH 64/75] [infra, simgen] cpu_state.cc removed from the build --- sim_gen_lira/CMakeLists.txt | 1 - sim_gen_lira/sim_gen.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/sim_gen_lira/CMakeLists.txt b/sim_gen_lira/CMakeLists.txt index f887601..f449c5c 100644 --- a/sim_gen_lira/CMakeLists.txt +++ b/sim_gen_lira/CMakeLists.txt @@ -19,7 +19,6 @@ set(PROTEA_SIMGEN_OUTPUT_HEADERS set(PROTEA_SIMGEN_OUTPUT_SOURCES base_exec_engine.cc - cpu_state.cc naive_interpreter.cc decoder.cc hart.cc diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index e51bb66..e1fe51c 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -19,7 +19,6 @@ LiraCppGen::OpRegistry.ops = arch.operations.to_h { |op| [op.name, op] } File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(arch)) -File.write('cpu_state.cc', SimGen::CPUState::TranslationUnit.generate_cpu_state(arch)) File.write('base_exec_engine.hh', SimGen::BaseExecEngine::Header.generate_base_exec_engine(arch)) File.write('base_exec_engine.cc', SimGen::BaseExecEngine::TranslationUnit.generate_base_exec_engine(arch)) File.write('naive_interpreter.hh', SimGen::NaiveInterpreter::Header.generate_naive_interpreter(arch)) From 3a341859197953853a4f4e4eccb5b93790b87f54 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 17:24:17 +0300 Subject: [PATCH 65/75] [simgen] Read Reg statement in decoder is prohibited --- sim_gen_lira/cpp_gen.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim_gen_lira/cpp_gen.rb b/sim_gen_lira/cpp_gen.rb index 0132503..60f0f05 100644 --- a/sim_gen_lira/cpp_gen.rb +++ b/sim_gen_lira/cpp_gen.rb @@ -106,7 +106,7 @@ def emit_code if context == :execute emit("#{out} = cpu.get#{rf}<#{Utility::HelperCpp.gen_type(width)}>(#{idx});") else - emit("#{out} = 0; // read in decode") + raise "Unexpected read statement in decode section" end end end From 5f9a56e285f254675d50f86e554c10b1e0b08646 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 17:25:46 +0300 Subject: [PATCH 66/75] [ADL, simgen] Single :map section is deprecated --- lib/ADL/builder.rb | 10 ---------- lib/lira_gen.rb | 2 +- sim_gen/Decoders/decoder.rb | 12 ++++-------- sim_gen/ExecEngines/naive_interpreter.rb | 8 ++------ sim_gen/ISA/isa.rb | 22 ++++++++++++++-------- 5 files changed, 21 insertions(+), 33 deletions(-) diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index 2396ad2..a03bcc7 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -57,7 +57,6 @@ def to_h frmt: @frmt, asm_str: @asm_str, code: @code.to_h, - map: @map.to_h, operand_map: @operand_map.transform_values(&:to_h), operand_list: @operand_list, feature: @feature, @@ -71,8 +70,6 @@ def self.from_h(h) info.asm_str = h[:asm_str] info.code = Scope.new(nil) info.code.instance_variable_set(:@tree, h[:code][:tree].map { |s| IrStmt.from_h(s) }) - info.map = Scope.new(nil) - info.map.instance_variable_set(:@tree, h[:map][:tree].map { |s| IrStmt.from_h(s) }) if h[:operand_map] info.operand_map = h[:operand_map].transform_values { |v| Scope.from_h(v) } info.operand_list = h[:operand_list] || info.operand_map.keys @@ -223,13 +220,6 @@ def RegFiles() module SimInfra class InstructionInfoBuilder def code(&block) - # Build legacy map from operand scopes for backward compat - @info.map = Scope.new(nil) - @info.fields.each { |f| @info.map.method(f.value.name, f.value.type) } - @info.operand_map.each_value do |scope| - scope.tree.each { |stmt| @info.map.tree << stmt } - end - # Link code scope methods to operand vars @info.operand_map.each do |name, scope| var = scope.vars[name] diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 6498ccf..97e48d7 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -566,7 +566,7 @@ def convert_instruction(instr) decode_snippets = [] encode_snippet = '' - if instr.map.tree.any? && operand_vars.any? + if !instr.operand_map.empty? && operand_vars.any? decode_snippets = generate_decode_snippets(instr, operand_vars) end if instr.fields.any? && operand_vars.any? diff --git a/sim_gen/Decoders/decoder.rb b/sim_gen/Decoders/decoder.rb index c9475d0..e8c28f9 100644 --- a/sim_gen/Decoders/decoder.rb +++ b/sim_gen/Decoders/decoder.rb @@ -157,12 +157,8 @@ def make_child_tree(node_value, separ_mask, instructions, subtree) def map_operands(insn) operands = {} - cnt = 0 - for node in insn[:map][:tree] - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands[node[:oprnds][0][:name]] = "insn.operand#{cnt}" - cnt += 1 - end + (insn[:operand_list] || []).each_with_index do |name, idx| + operands[name] = "insn.operand#{idx}" end operands end @@ -189,8 +185,8 @@ def generate_mapping_body(insn) emitter = Utility::GenEmitter.new operand_map = map_operands(insn) gen = CodeGen::CppGenerator.new(emitter, operand_map) - for node in insn[:map][:tree] - gen.generate_statement(node) + (insn[:operand_map] || {}).each_value do |scope| + (scope[:tree] || []).each { |node| gen.generate_statement(node) } end emitter end diff --git a/sim_gen/ExecEngines/naive_interpreter.rb b/sim_gen/ExecEngines/naive_interpreter.rb index ae00151..7aff60a 100644 --- a/sim_gen/ExecEngines/naive_interpreter.rb +++ b/sim_gen/ExecEngines/naive_interpreter.rb @@ -33,12 +33,8 @@ module TranslationUnit def map_operands(insn) operands = {} - cnt = 0 - insn[:map][:tree].each do |node| - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands[node[:oprnds][0][:name]] = "insn.operand#{cnt}" - cnt += 1 - end + (insn[:operand_list] || []).each_with_index do |name, idx| + operands[name] = "insn.operand#{idx}" end operands[:pc] = 'cpu.getPC()' operands diff --git a/sim_gen/ISA/isa.rb b/sim_gen/ISA/isa.rb index 4f4b830..e50683f 100644 --- a/sim_gen/ISA/isa.rb +++ b/sim_gen/ISA/isa.rb @@ -18,14 +18,20 @@ def find_max_operands(instructions) max_operands = 0 max_size = 0 instructions.each do |insn| - operands_count = 0 - insn[:map][:tree].each do |node| - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands_count += 1 - max_size = Utility.get_type(node[:oprnds][0][:type]).bitsize if Utility.get_type(node[:oprnds][0][:type]).bitsize > max_size - end - end - max_operands = operands_count if operands_count > max_operands + op_list = insn[:operand_list] || [] + max_operands = op_list.size if op_list.size > max_operands + op_map = insn[:operand_map] || {} + op_list.each do |name| + scope = op_map[name] + next unless scope + new_var_node = (scope[:tree] || []).find { |n| + n[:name] == :new_var && n[:attrs]&.include?(:op) + } + next unless new_var_node + type = new_var_node[:oprnds][0][:type] + bitsize = Utility.get_type(type).bitsize + max_size = bitsize if bitsize > max_size + end end [max_operands, max_size] end From c7001d47efb45e0383c0dace7e830db5e8add83f Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 22:37:47 +0300 Subject: [PATCH 67/75] [ser] Added Field resolve function --- lib/lira_gen.rb | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 97e48d7..6e0be5a 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -84,13 +84,11 @@ class DecodeLetHandler < StmtHandler def handle(stmt) lhs, rhs = stmt.oprnds if rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') - field_name = rhs.name.to_s[2..] - field = current_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } - if field - vars[lhs] = ADLToLiraUtils.extract_field(builder, ser.raw_enc, field, lhs.type) - else - warn "Field #{field_name} not found" + val = ser.resolve_field(rhs) + if val && val.width != ADLToLiraUtils.convert_type(lhs.type) + val = builder.extend_zero(val, ADLToLiraUtils.convert_type(lhs.type)) end + vars[lhs] = val if val else rhs_val = ADLToLiraUtils.resolve_operand(rhs, builder, vars, [], arch_builder) vars[lhs] = rhs_val if rhs_val @@ -145,13 +143,8 @@ def handle(stmt) if src vars[lhs] = ser.widen_or_truncate(name, lhs.type, src, rhs.type) elsif rhs.is_a?(SimInfra::Var) && rhs.name.to_s.start_with?('f_') - field_name = rhs.name.to_s[2..] - field = current_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } - if field - vars[lhs] = ADLToLiraUtils.extract_field(builder, ser.raw_enc, field, lhs.type) - else - warn "Field #{field_name} not found" - end + val = ser.resolve_field(rhs, lhs.type) + vars[lhs] = val if val else rhs_val = ADLToLiraUtils.resolve_operand(rhs, builder, vars, [], arch_builder) vars[lhs] = rhs_val if rhs_val @@ -406,6 +399,16 @@ def widen_or_truncate(name, dest_type, src, src_type) end end + def resolve_field(field_var, dest_type = :b32) + field_name = field_var.name.to_s[2..] + field = @current_instr.fields.find { |f| f.value.name.to_s == "f_#{field_name}" } + unless field + warn "Field #{field_name} not found" + return nil + end + ADLToLiraUtils.extract_field(@builder, @raw_enc, field, dest_type) + end + def collect_ops(_seq) @builder.operations_map.each { |name, op| @ops_used[name] = op } end From 41e86df9ceab1869ac0da373e4c5b86240c2789d Mon Sep 17 00:00:00 2001 From: uslstenn Date: Tue, 16 Jun 2026 23:33:21 +0300 Subject: [PATCH 68/75] [simgen] Introduced decode tree --- sim_gen_lira/Decoders/decoder.rb | 159 ++++++++++++++++++++++++++----- 1 file changed, 134 insertions(+), 25 deletions(-) diff --git a/sim_gen_lira/Decoders/decoder.rb b/sim_gen_lira/Decoders/decoder.rb index 5fbb561..b336966 100644 --- a/sim_gen_lira/Decoders/decoder.rb +++ b/sim_gen_lira/Decoders/decoder.rb @@ -30,30 +30,8 @@ module TranslationUnit def generate_decoder(arch) snippets = arch.snippets.to_h { |s| [s.name, s.seq] } - - body = [] - arch.instructions.each do |insn| - constraint_name = insn.encoding.constraint_decode - decode_names = insn.encoding.decode - - next unless constraint_name && decode_names - constraint_seq = snippets[constraint_name] - next unless constraint_seq - - operand_calls = decode_names.each_with_index.map { |name, idx| - "insn.operand#{idx} = #{name}(raw_insn);" - }.join("\n ") - - body << <<~CPP - if (#{constraint_name}(raw_insn)) { - #{operand_calls} - insn.m_opc = Opcode::k#{insn.name.to_s.upcase}; - return insn; - } - CPP - end - - decoder_impl = body.join("\n") + tree = build_decode_tree(arch.instructions) + body = emit_tree(tree, 0, snippets, arch.instructions) <<~CPP #include "decoder.hh" #include "snippets.h" @@ -62,12 +40,143 @@ def generate_decoder(arch) namespace prot::decoder { std::optional decode(isa::Word raw_insn) { Instruction insn{}; - #{decoder_impl} + #{body} return std::nullopt; } } CPP end + + private + + module_function + + def build_decode_tree(instructions) + # Find the best discriminating bit range + mask_union = instructions.map(&:encoding).map(&:const_mask).reduce(0, :|) + mask_inter = instructions.map(&:encoding).map(&:const_mask).reduce(mask_union, :&) + + # Prefer bits in the intersection (checked by all), then union + work_mask = mask_inter != 0 ? mask_inter : mask_union + + build_tree_node(instructions, work_mask, 0, 31) + end + + def build_tree_node(instructions, work_mask, min_bit, max_bit) + return nil if instructions.empty? + return { leaf: instructions[0] } if instructions.size == 1 + + # Find best discriminating bit range in work_mask + lsb, msb = find_best_range(instructions, work_mask, min_bit, max_bit) + return fallback_linear(instructions) unless lsb + + width = msb - lsb + 1 + mask = ((1 << width) - 1) << lsb + + # Group instructions by their value in this bit range + groups = instructions.group_by { |insn| (insn.encoding.const_encoding_part & mask) >> lsb } + + node = { range: [lsb, msb], children: {} } + groups.each do |val, group| + next_mask = work_mask & ~mask + if group.size == 1 + node[:children][val] = { leaf: group[0] } + else + child = build_tree_node(group, next_mask, min_bit, max_bit) + node[:children][val] = child || { leaf: group[0] } + end + end + node + end + + def find_best_range(instructions, work_mask, min_bit, max_bit) + lead_bits = {} + (min_bit..max_bit).each do |bit| + next if (work_mask & (1 << bit)) == 0 + count_0 = 0 + count_1 = 0 + all_have = true + instructions.each do |insn| + if (insn.encoding.const_mask & (1 << bit)) == 0 + all_have = false + break + end + if (insn.encoding.const_encoding_part & (1 << bit)) != 0 + count_1 += 1 + else + count_0 += 1 + end + end + lead_bits[bit] = [count_0, count_1] if all_have && count_0 > 0 && count_1 > 0 + end + + bits = lead_bits.keys.sort + return nil if bits.empty? + + best_range = [bits[0], bits[0]] + best_score = 0 + (0...bits.size).each do |i| + score = 0 + (i...bits.size).each do |j| + break if bits[j] != bits[i] + (j - i) + score += lead_bits[bits[j]].min + if score > best_score + best_score = score + best_range = [bits[i], bits[j]] + end + end + end + best_range + end + + def fallback_linear(instructions) + { linear: instructions } + end + + def emit_tree(node, indent, snippets, all_instructions) + if node[:leaf] + insn = node[:leaf] + emit_insn_block(insn, indent, snippets) + elsif node[:linear] + node[:linear].map { |insn| emit_insn_block(insn, indent, snippets) }.join("\n") + else + lsb, msb = node[:range] + width = msb - lsb + 1 + mask = ((1 << width) - 1) + shift = lsb + + lines = [] + ind = ' ' * indent + lines << "#{ind}switch ((raw_insn >> #{shift}) & #{mask}) {" + node[:children].sort.each do |val, child| + lines << "#{ind} case #{val}: {" + lines << emit_tree(child, indent + 2, snippets, all_instructions) + lines << "#{ind} }" + end + lines << "#{ind} default: break;" + lines << "#{ind}}" + lines.join("\n") + end + end + + def emit_insn_block(insn, indent, snippets) + constraint_name = insn.encoding.constraint_decode + decode_names = insn.encoding.decode + return '' unless constraint_name && decode_names + + ind = ' ' * indent + operand_calls = decode_names.each_with_index.map { |name, idx| + "insn.operand#{idx} = #{name}(raw_insn);" + }.join("\n#{ind} ") + + <<~CPP + #{ind}if (#{constraint_name}(raw_insn)) { + #{ind} #{operand_calls} + #{ind} insn.m_opc = Opcode::k#{insn.name.to_s.upcase}; + #{ind} return insn; + #{ind}} + CPP + end end end end From 250f1ad48cd64c0ee6eb479a5fc8cb8bcacba62d Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 17 Jun 2026 12:20:44 +0300 Subject: [PATCH 69/75] [ADL, Target] Introduced Operand & OperandBuilder * Removed string-driven programming in operand definition * Operands was applied in "RISC-V/encoding.rb" description --- lib/ADL/base.rb | 2 +- lib/ADL/builder.rb | 87 +++++++++++++++++++++++++++++++++-- lib/Target/RISC-V/encoding.rb | 51 +++++++++++--------- 3 files changed, 113 insertions(+), 27 deletions(-) diff --git a/lib/ADL/base.rb b/lib/ADL/base.rb index f33fb2b..4f0a607 100644 --- a/lib/ADL/base.rb +++ b/lib/ADL/base.rb @@ -48,7 +48,7 @@ def self.state end # reset state - def siminfra_reset_module_state; @@instructions = []; end + def siminfra_reset_module_state; @@instructions = []; @@operands = []; end # mixin for global counter, function returns 0,1,2,.... module GlobalCounter diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index a03bcc7..b7fe22d 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -34,6 +34,7 @@ def assert(condition, msg = nil); raise msg if !condition; end @@instructions = [] @@interface_functions = [] + @@operands = [] def self.interface_functions @@interface_functions @@ -78,6 +79,29 @@ def self.from_h(h) end end + class OperandInfo + attr_accessor :name, :type, :map_proc, :asm_str, :sem_proc + + def initialize(name, type = nil) + @name = name + @type = type + @map_proc = nil + @asm_str = nil + @sem_proc = nil + end + + def for(op_name) + template = self + info = OperandInfo.new(op_name, @type) + info.asm_str = @asm_str + info.sem_proc = @sem_proc + info.map_proc = proc { instance_exec(op_name, &template.map_proc) } + info + end + + alias_method :[], :for + end + class InstructionInfoBuilder include SimInfra @@ -129,6 +153,42 @@ def Instruction(name, &block) nil # only for debugging in IRB end + class OperandBuilder + include SimInfra + + def initialize(name, type = nil) + @info = OperandInfo.new(name, type) + end + + def map(type = nil, &block) + @info.type = type if type + @info.map_proc = block if block + end + + def asm(&block) + @info.asm_str = instance_eval(&block) if block + end + + def code(&block) + @info.map_proc = block if block + end + + def sem(&block) + @info.sem_proc = block if block + end + + attr_reader :info + end + + def Operand(name, type = nil, &block) + bldr = OperandBuilder.new(name, type) + bldr.instance_eval(&block) if block + @@operands << bldr.info + bldr.info + end + + module_function :Operand + class InterfaceBuilder include SimInfra @@ -237,13 +297,30 @@ def code(&block) def map(blocks) return if blocks.nil? || blocks.empty? - blocks.each do |name, type, code_str| - scope = Scope.new(nil) - @info.fields.each { |f| scope.method(f.value.name, f.value.type) } - scope.instance_eval(code_str) + + blocks.each do |block| + scope = build_scope(block) + name = operand_name(block) @info.operand_map[name] = scope end - @info.operand_list = blocks.map(&:first) + @info.operand_list = blocks.map { |b| operand_name(b) } + end + + private + + def operand_name(block) + block.is_a?(OperandInfo) ? block.name : block[0] + end + + def build_scope(block) + scope = Scope.new(nil) + @info.fields.each { |f| scope.method(f.value.name, f.value.type) } + if block.is_a?(OperandInfo) + scope.instance_eval(&block.map_proc) + else + scope.instance_eval(block[2]) + end + scope end def asm(&block) diff --git a/lib/Target/RISC-V/encoding.rb b/lib/Target/RISC-V/encoding.rb index 3214a0b..ba77af3 100644 --- a/lib/Target/RISC-V/encoding.rb +++ b/lib/Target/RISC-V/encoding.rb @@ -1,32 +1,41 @@ require_relative "../../ADL/base" +require_relative "../../ADL/builder" module SimInfra - def u_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_#{imm}.s << 12" + XReg = Operand(:XReg, :r32) do + map { |name| let name, :XRegs, [:op], :r32, send("f_#{name}") } end - def i_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_#{imm}.s32" + IImm = Operand(:IImm, :s32) do + map { |name| let name, [:op], :s32, send("f_#{name}").s32 } end - def is_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_imm4_0" + UImm = Operand(:UImm, :s32) do + map { |name| let name, [:op], :s32, (send("f_#{name}").s << 12) } end - def j_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm20.b21 << 20 | f_imm19_12.b21 << 12 | f_imm11.b21 << 11 | f_imm10_1.b21 << 1).s32" + IsImm = Operand(:IsImm, :s32) do + map { |name| let name, [:op], :s32, f_imm4_0 } end - def b_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm12.b13 << 12 | f_imm11.b13 << 11 | f_imm10_5.b13 << 5 | f_imm4_1.b13 << 1).s32" + JImm = Operand(:JImm, :s32) do + map { |name| + let name, [:op], :s32, + (f_imm20.b21 << 20 | f_imm19_12.b21 << 12 | f_imm11.b21 << 11 | f_imm10_1.b21 << 1).s32 + } end - def s_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm11_5.b12 << 5 | f_imm4_0.b12).s32" + BImm = Operand(:BImm, :s32) do + map { |name| + let name, [:op], :s32, + (f_imm12.b13 << 12 | f_imm11.b13 << 11 | f_imm10_5.b13 << 5 | f_imm4_1.b13 << 1).s32 + } end - def xreg(name) - return name, :r32, "let :#{name}, :XRegs, [:op], :r32, f_#{name}" + SImm = Operand(:SImm, :s32) do + map { |name| + let name, [:op], :s32, (f_imm11_5.b12 << 5 | f_imm4_0.b12).s32 + } end end @@ -36,7 +45,7 @@ def format_u(opcode) field(:f_opcode, 6, 0, opcode), field(:f_rd, 11, 7), field(:f_imm, 31, 12), - ], xreg(:rd), u_imm(:imm) + ], XReg[:rd], UImm[:imm] end def format_r(opcode, funct3, funct7) @@ -47,7 +56,7 @@ def format_r(opcode, funct3, funct7) field(:f_rs1, 19, 15), field(:f_rs2, 24, 20), field(:f_funct7, 31, 25, funct7), - ], xreg(:rs2), xreg(:rs1), xreg(:rd) + ], XReg[:rs2], XReg[:rs1], XReg[:rd] end def format_i(opcode, funct3) @@ -57,7 +66,7 @@ def format_i(opcode, funct3) field(:f_funct3, 14, 12, funct3), field(:f_rs1, 19, 15), field(:f_imm, 31, 20), - ], i_imm(:imm), xreg(:rs1), xreg(:rd) + ], IImm[:imm], XReg[:rs1], XReg[:rd] end def format_i_shift(opcode, func3, funct7) @@ -68,7 +77,7 @@ def format_i_shift(opcode, func3, funct7) field(:f_rs1, 19, 15), field(:f_imm11_5, 31, 25, funct7), field(:f_imm4_0, 24, 20), - ], is_imm(:imm), xreg(:rs1), xreg(:rd) + ], IsImm[:imm], XReg[:rs1], XReg[:rd] end def format_b(opcode, funct3) @@ -81,7 +90,7 @@ def format_b(opcode, funct3) field(:f_imm10_5, 30, 25), field(:f_imm11, 7, 7), field(:f_imm12, 31, 31), - ], b_imm(:imm), xreg(:rs1), xreg(:rs2) + ], BImm[:imm], XReg[:rs1], XReg[:rs2] end def format_j(opcode) @@ -92,7 +101,7 @@ def format_j(opcode) field(:f_imm19_12, 19, 12), field(:f_imm11, 20, 20), field(:f_imm10_1, 30, 21), - ], j_imm(:imm), xreg(:rd) + ], JImm[:imm], XReg[:rd] end def format_s(opcode, func3) @@ -103,6 +112,6 @@ def format_s(opcode, func3) field(:f_rs1, 19, 15), field(:f_rs2, 24, 20), field(:f_imm11_5, 31, 25), - ], s_imm(:imm), xreg(:rs1), xreg(:rs2) + ], SImm[:imm], XReg[:rs1], XReg[:rs2] end end From 0dd78024505fd652dd7f6ffbb2c08191edbb5d0a Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 17 Jun 2026 12:21:08 +0300 Subject: [PATCH 70/75] [infra] Build upd --- lib/CMakeLists.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2168e43..91e289d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -5,6 +5,11 @@ set(NATIVE_IR_FILE ${CMAKE_CURRENT_BINARY_DIR}/IR.yaml) add_custom_command( OUTPUT ${NATIVE_IR_FILE} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/base.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/builder.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/encoding.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/32I.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/32M.rb COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/ir_gen.rb WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating native IR (IR.yaml)" @@ -17,6 +22,22 @@ set(LIRA_IR_FILE ${CMAKE_CURRENT_BINARY_DIR}/lira.yaml) add_custom_command( OUTPUT ${LIRA_IR_FILE} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lira_gen.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/base.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/builder.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/scope.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/var.rb + ${CMAKE_CURRENT_SOURCE_DIR}/ADL/value.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/encoding.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/32I.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Target/RISC-V/32M.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/arch.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/ir.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/ir_builder.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/ir_ops.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/arch_ser_yaml.rb + ${CMAKE_CURRENT_SOURCE_DIR}/lira/ir_ser_txt.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Utility/lira_utils.rb + ${CMAKE_CURRENT_SOURCE_DIR}/Utility/type.rb COMMAND ${BUNDLE_PATH} exec ruby ${CMAKE_CURRENT_SOURCE_DIR}/lira_gen.rb --target ${CMAKE_SOURCE_DIR}/lib/Target/RISC-V/ --output ${LIRA_IR_FILE} From aaf03f553f489190cd49e207e62254f9f0d04fbf Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 17 Jun 2026 12:21:22 +0300 Subject: [PATCH 71/75] LIRA IR updated --- lira.yaml | 168 ++++++++++++++++++++++++------------------------------ 1 file changed, 75 insertions(+), 93 deletions(-) diff --git a/lira.yaml b/lira.yaml index dd54634..0652f67 100644 --- a/lira.yaml +++ b/lira.yaml @@ -137,7 +137,7 @@ - 32 :outputs: - 32 - :semantic_base: lsr + :semantic_base: :lsr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -147,7 +147,7 @@ - 32 :outputs: - 5 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -157,7 +157,7 @@ - 5 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -167,7 +167,7 @@ - 32 :outputs: - 20 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -177,7 +177,7 @@ - 20 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -188,7 +188,7 @@ - 32 :outputs: - 32 - :semantic_base: lsl + :semantic_base: :lsl :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -198,7 +198,7 @@ - 1 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -209,7 +209,7 @@ - 32 :outputs: - 32 - :semantic_base: orr + :semantic_base: :orr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -220,7 +220,7 @@ - 32 :outputs: - 32 - :semantic_base: and + :semantic_base: :and :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -231,7 +231,7 @@ - 32 :outputs: - 1 - :semantic_base: eq + :semantic_base: :eq :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -242,7 +242,7 @@ - 32 :outputs: - 32 - :semantic_base: add + :semantic_base: :add :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -253,7 +253,7 @@ - 32 :outputs: - 32 - :semantic_base: sub + :semantic_base: :sub :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -264,7 +264,7 @@ - 32 :outputs: - 1 - :semantic_base: slt + :semantic_base: :slt :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -274,7 +274,7 @@ - 1 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -285,7 +285,7 @@ - 32 :outputs: - 1 - :semantic_base: ult + :semantic_base: :ult :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -296,7 +296,7 @@ - 32 :outputs: - 32 - :semantic_base: xor + :semantic_base: :xor :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -307,7 +307,7 @@ - 32 :outputs: - 32 - :semantic_base: asr + :semantic_base: :asr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -317,7 +317,7 @@ - 32 :outputs: - 12 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -327,17 +327,7 @@ - 12 :outputs: - 32 - :semantic_base: extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_5_to_32 - :attributes: [] - :inputs: - - 5 - :outputs: - - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -349,7 +339,7 @@ - 32 :outputs: - 32 - :semantic_base: select + :semantic_base: :select :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -359,7 +349,7 @@ - 32 :outputs: - 1 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -369,7 +359,7 @@ - 1 :outputs: - 13 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -379,7 +369,7 @@ - 13 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -389,7 +379,7 @@ - 32 :outputs: - 6 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -399,7 +389,7 @@ - 6 :outputs: - 13 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -409,7 +399,7 @@ - 32 :outputs: - 4 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -419,7 +409,7 @@ - 4 :outputs: - 13 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -429,7 +419,7 @@ - 32 :outputs: - 13 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -439,7 +429,7 @@ - 13 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -450,7 +440,7 @@ - 32 :outputs: - 1 - :semantic_base: ne + :semantic_base: :ne :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -461,7 +451,7 @@ - 32 :outputs: - 1 - :semantic_base: sge + :semantic_base: :sge :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -472,7 +462,7 @@ - 32 :outputs: - 1 - :semantic_base: uge + :semantic_base: :uge :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -482,7 +472,7 @@ - 1 :outputs: - 21 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -492,7 +482,7 @@ - 21 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -502,7 +492,7 @@ - 32 :outputs: - 8 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -512,7 +502,7 @@ - 8 :outputs: - 21 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -522,7 +512,7 @@ - 32 :outputs: - 10 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -532,7 +522,7 @@ - 10 :outputs: - 21 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -542,7 +532,7 @@ - 32 :outputs: - 21 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -552,7 +542,7 @@ - 21 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -562,7 +552,7 @@ - 32 :outputs: - 7 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -572,7 +562,7 @@ - 7 :outputs: - 12 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -582,7 +572,7 @@ - 12 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -592,7 +582,7 @@ - 5 :outputs: - 12 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -602,7 +592,7 @@ - 32 :outputs: - 16 - :semantic_base: extract_low + :semantic_base: :extract_low :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -612,7 +602,7 @@ - 8 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -622,7 +612,7 @@ - 16 :outputs: - 32 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -632,7 +622,7 @@ - 8 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -642,7 +632,7 @@ - 16 :outputs: - 32 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -653,7 +643,7 @@ - 32 :outputs: - 32 - :semantic_base: mul + :semantic_base: :mul :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -663,7 +653,7 @@ - 32 :outputs: - 64 - :semantic_base: extend_sign + :semantic_base: :extend_sign :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -674,7 +664,7 @@ - 64 :outputs: - 64 - :semantic_base: mul + :semantic_base: :mul :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -684,7 +674,7 @@ - 32 :outputs: - 64 - :semantic_base: extend_zero + :semantic_base: :extend_zero :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -695,7 +685,7 @@ - 64 :outputs: - 64 - :semantic_base: asr + :semantic_base: :asr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -706,7 +696,7 @@ - 64 :outputs: - 64 - :semantic_base: lsr + :semantic_base: :lsr :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -718,7 +708,7 @@ - 32 :outputs: - 32 - :semantic_base: div_s + :semantic_base: :div_s :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -730,7 +720,7 @@ - 32 :outputs: - 32 - :semantic_base: div_u + :semantic_base: :div_u :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -741,7 +731,7 @@ - 32 :outputs: - 32 - :semantic_base: rem_s + :semantic_base: :rem_s :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -752,7 +742,7 @@ - 32 :outputs: - 32 - :semantic_base: rem_u + :semantic_base: :rem_u :semantic_func: {} :semantic_func_128: {} :semantic_table: {} @@ -1443,14 +1433,6 @@ 1 32 _t4 = const 28691; 1 1 _t5 = op eq_32 _t3 _t4; 1 = output 0 _t5; -- :name: decode_5 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 20; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 5 _t5 = op extract_low_32_to_5 _t4; - 1 32 _t6 = op extend_sign_5_to_32 _t5; - 1 = output 0 _t6; - :name: encode_18 :seq: | 1 32 _t1 = input 0; @@ -1559,7 +1541,7 @@ 1 32 _t4 = const 1073762323; 1 1 _t5 = op eq_32 _t3 _t4; 1 = output 0 _t5; -- :name: decode_6 +- :name: decode_5 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 31; @@ -1782,7 +1764,7 @@ 1 32 _t4 = const 28771; 1 1 _t5 = op eq_32 _t3 _t4; 1 = output 0 _t5; -- :name: decode_7 +- :name: decode_6 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 31; @@ -1875,7 +1857,7 @@ 1 32 _t4 = const 103; 1 1 _t5 = op eq_32 _t3 _t4; 1 = output 0 _t5; -- :name: decode_8 +- :name: decode_7 :seq: | 1 32 _t1 = input 0; 1 32 _t3 = const 25; @@ -3017,7 +2999,7 @@ :const_encoding_part: 4115 :const_mask: 4261441663 :decode: - - decode_5 + - decode_2 - decode_3 - decode_0 :encode: encode_18 @@ -3045,7 +3027,7 @@ :const_encoding_part: 20499 :const_mask: 4261441663 :decode: - - decode_5 + - decode_2 - decode_3 - decode_0 :encode: encode_19 @@ -3073,7 +3055,7 @@ :const_encoding_part: 1073762323 :const_mask: 4261441663 :decode: - - decode_5 + - decode_2 - decode_3 - decode_0 :encode: encode_20 @@ -3101,7 +3083,7 @@ :const_encoding_part: 99 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_21 @@ -3135,7 +3117,7 @@ :const_encoding_part: 4195 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_22 @@ -3169,7 +3151,7 @@ :const_encoding_part: 16483 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_23 @@ -3203,7 +3185,7 @@ :const_encoding_part: 20579 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_24 @@ -3237,7 +3219,7 @@ :const_encoding_part: 24675 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_25 @@ -3271,7 +3253,7 @@ :const_encoding_part: 28771 :const_mask: 28799 :decode: - - decode_6 + - decode_5 - decode_3 - decode_2 :encode: encode_26 @@ -3303,7 +3285,7 @@ :const_encoding_part: 111 :const_mask: 127 :decode: - - decode_7 + - decode_6 - decode_0 :encode: encode_27 :constraint_decode: constraint_27 @@ -3366,7 +3348,7 @@ :const_encoding_part: 35 :const_mask: 28799 :decode: - - decode_8 + - decode_7 - decode_3 - decode_2 :encode: encode_29 @@ -3398,7 +3380,7 @@ :const_encoding_part: 4131 :const_mask: 28799 :decode: - - decode_8 + - decode_7 - decode_3 - decode_2 :encode: encode_30 @@ -3430,7 +3412,7 @@ :const_encoding_part: 8227 :const_mask: 28799 :decode: - - decode_8 + - decode_7 - decode_3 - decode_2 :encode: encode_31 From 88e8d71f510a8005dfcd1c7aa12b0eb5af0778c1 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 24 Jun 2026 16:36:10 +0300 Subject: [PATCH 72/75] [lira] LIRA Library updated --- lib/lira/arch_ser.rb | 7 - lib/lira/arch_ser_txt.rb | 153 ----------- lib/lira/arch_ser_yaml.rb | 8 +- lib/lira/ir_builder.rb | 559 ++++++++++++++++++++++++-------------- lib/lira/ir_ops.rb | 186 +++++-------- lib/lira_gen.rb | 31 +-- 6 files changed, 437 insertions(+), 507 deletions(-) delete mode 100644 lib/lira/arch_ser.rb delete mode 100644 lib/lira/arch_ser_txt.rb diff --git a/lib/lira/arch_ser.rb b/lib/lira/arch_ser.rb deleted file mode 100644 index 5055630..0000000 --- a/lib/lira/arch_ser.rb +++ /dev/null @@ -1,7 +0,0 @@ -# lira/arch_ser.rb -module Lira - module SerializationFormat - TXT = :txt - YAML = :yaml - end -end diff --git a/lib/lira/arch_ser_txt.rb b/lib/lira/arch_ser_txt.rb deleted file mode 100644 index 0792481..0000000 --- a/lib/lira/arch_ser_txt.rb +++ /dev/null @@ -1,153 +0,0 @@ -# lira/arch_ser_txt.rb -require 'json' -require 'pathname' -require 'fileutils' -require_relative 'ir' -require_relative 'arch' - -module Lira - module ArchSerTxt - module_function - - def to_serializable(obj) - case obj - when StatementSeq - IrSerTxt.serialize_statement_seq(obj) - when Array - obj.map { |item| to_serializable(item) } - when Hash - obj.transform_values { |v| to_serializable(v) } - else - if obj.respond_to?(:to_h) - obj.to_h.transform_values { |v| to_serializable(v) } - else - obj - end - end - end - - def from_serializable(klass, data, item_class = nil) - if klass == Array - if item_class - return data.map { |elem| from_serializable(item_class, elem) } - else - return data.map { |elem| from_serializable(Object, elem) } - end - end - - if klass.respond_to?(:from_h) - transformed = data.transform_values { |v| from_serializable(Object, v) } - klass.from_h(transformed) - else - data - end - end - - def write_json(data, path) - File.write(path, JSON.pretty_generate(data)) - end - - def write_component_list(list, path) - write_json(list.map { |obj| to_serializable(obj) }, path) - end - - def write_arch(arch, folder_path) - folder_path = Pathname.new(folder_path) - FileUtils.rm_rf(folder_path) if folder_path.exist? - FileUtils.mkdir_p(folder_path) - - write_json({ 'name' => arch.name, 'attributes' => arch.attributes }, folder_path / 'arch.json') - - write_component_list(arch.register_files, folder_path / 'register_files.json') - write_component_list(arch.system_registers, folder_path / 'system_registers.json') - write_component_list(arch.environment_functions, folder_path / 'environment_functions.json') - write_component_list(arch.tables_int, folder_path / 'tables_int.json') - - index = { - 'operations' => arch.operations.map(&:name), - 'snippets' => arch.snippets.map(&:name), - 'instructions' => arch.instructions.map(&:name) - } - write_json(index, folder_path / 'index.json') - - ops_dir = folder_path / 'operations' - FileUtils.mkdir_p(ops_dir) - arch.operations.each do |op| - write_json(to_serializable(op), ops_dir / "#{op.name}.json") - end - - snippets_dir = folder_path / 'snippets' - FileUtils.mkdir_p(snippets_dir) - arch.snippets.each do |snip| - File.write(snippets_dir / "#{snip.name}.lira", IrSerTxt.serialize_statement_seq(snip.seq)) - end - - instr_dir = folder_path / 'instructions' - FileUtils.mkdir_p(instr_dir) - arch.instructions.each do |instr| - instr_dict = to_serializable(instr) - instr_dict.delete('semantic') - write_json(instr_dict, instr_dir / "#{instr.name}.json") - File.write(instr_dir / "#{instr.name}.lira", IrSerTxt.serialize_statement_seq(instr.semantic)) - end - end - - def load_json(path) - JSON.parse(File.read(path)) - end - - def load_lira(path) - IrSerTxt.deserialize_statement_seq(File.read(path)) - end - - def load_operation(folder, name) - data = load_json(folder / 'operations' / "#{name}.json") - from_serializable(Operation, data) - end - - def load_snippet(folder, name) - seq = load_lira(folder / 'snippets' / "#{name}.lira") - Snippet.new(name, seq) - end - - def load_instruction(folder, name) - data = load_json(folder / 'instructions' / "#{name}.json") - semantic = load_lira(folder / 'instructions' / "#{name}.lira") - from_serializable(Instruction, data.merge('semantic' => semantic.to_h)) - end - - def read_arch(folder_path) - folder_path = Pathname.new(folder_path) - - arch_info = load_json(folder_path / 'arch.json') - name = arch_info['name'] - attributes = arch_info['attributes'] - - register_files = from_serializable(Array, load_json(folder_path / 'register_files.json'), RegisterFile) - system_registers = from_serializable(Array, load_json(folder_path / 'system_registers.json'), SystemRegister) - environment_functions = from_serializable(Array, load_json(folder_path / 'environment_functions.json'), EnvironmentFunction) - tables_int = from_serializable(Array, load_json(folder_path / 'tables_int.json'), TableInt) - - index = load_json(folder_path / 'index.json') - op_names = index['operations'] - snippet_names = index['snippets'] - instr_names = index['instructions'] - - operations = op_names.map { |n| load_operation(folder_path, n) } - snippets = snippet_names.map { |n| load_snippet(folder_path, n) } - instructions = instr_names.map { |n| load_instruction(folder_path, n) } - - Arch.new( - name, - attributes, - register_files: register_files, - system_registers: system_registers, - environment_functions: environment_functions, - tables_int: tables_int, - operations: operations, - snippets: snippets, - instructions: instructions - ) - end - end -end diff --git a/lib/lira/arch_ser_yaml.rb b/lib/lira/arch_ser_yaml.rb index 7b35841..ba68c65 100644 --- a/lib/lira/arch_ser_yaml.rb +++ b/lib/lira/arch_ser_yaml.rb @@ -9,15 +9,17 @@ module ArchSerYaml def to_serializable(obj) case obj + when nil + nil when StatementSeq IrSerTxt.serialize_statement_seq(obj) when Array obj.map { |item| to_serializable(item) } when Hash - obj.transform_values { |v| to_serializable(v) } + obj.transform_keys(&:to_s).transform_values { |v| to_serializable(v) } else if obj.respond_to?(:to_h) - obj.to_h.transform_values { |v| to_serializable(v) } + obj.to_h.transform_keys(&:to_s).transform_values { |v| to_serializable(v) } else obj end @@ -38,7 +40,7 @@ def from_serializable(klass, data, item_class = nil) end if klass.respond_to?(:from_h) - transformed = data.transform_values { |v| from_serializable(Object, v) } + transformed = data.transform_keys(&:to_sym).transform_values { |v| from_serializable(Object, v) } klass.from_h(transformed) else data diff --git a/lib/lira/ir_builder.rb b/lib/lira/ir_builder.rb index 07a2b65..6e8850d 100644 --- a/lib/lira/ir_builder.rb +++ b/lib/lira/ir_builder.rb @@ -10,6 +10,7 @@ class Value def initialize(name, width = 32) @name = name @width = width + @shape = Shape.new(1, nil) end def to_s @@ -26,12 +27,11 @@ def ==(other) end class SeqBuilder - attr_reader :stmts, :temp_counter, :op_cache + attr_reader :stmts, :temp_counter def initialize @stmts = [] @temp_counter = 0 - @op_cache = {} end def new_temp(width = 32) @@ -39,253 +39,219 @@ def new_temp(width = 32) Value.new("_t#{@temp_counter}", width) end - def get_or_create_op(op_class, *args) - key = [op_class, args] - @op_cache[key] ||= op_class.new(*args) + def emit_op(op, inputs, out_bits) + out = new_temp(out_bits) + add_op(op, inputs, [out.name]) + out + end + + def check_width_match(a, b) + raise "width mismatch: #{a.width} != #{b.width}" if a.width != b.width end + # ------------------------------------------------------------------ + # NOTE: Building ruby/lira/ir_ops.rb objects + # ------------------------------------------------------------------ def add(a, b) check_width_match(a, b) - op = get_or_create_op(Add, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Add.new(a.width), [a.name, b.name], a.width) end def sub(a, b) check_width_match(a, b) - op = get_or_create_op(Sub, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Sub.new(a.width), [a.name, b.name], a.width) end def mul(a, b) check_width_match(a, b) - op = get_or_create_op(Mul, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Mul.new(a.width), [a.name, b.name], a.width) end def and_(a, b) check_width_match(a, b) - op = get_or_create_op(And, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(And.new(a.width), [a.name, b.name], a.width) end def orr(a, b) check_width_match(a, b) - op = get_or_create_op(Orr, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Orr.new(a.width), [a.name, b.name], a.width) end def xor(a, b) check_width_match(a, b) - op = get_or_create_op(Xor, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Xor.new(a.width), [a.name, b.name], a.width) end def lsl(a, b) check_width_match(a, b) - op = get_or_create_op(Lsl, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Lsl.new(a.width), [a.name, b.name], a.width) end def lsr(a, b) check_width_match(a, b) - op = get_or_create_op(Lsr, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Lsr.new(a.width), [a.name, b.name], a.width) end def asr(a, b) check_width_match(a, b) - op = get_or_create_op(Asr, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Asr.new(a.width), [a.name, b.name], a.width) end def slt(a, b) check_width_match(a, b) - op = get_or_create_op(Slt, a.width) - out = new_temp(1) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Slt.new(a.width), [a.name, b.name], 1) end - def extend_sign(a, to_width) - raise "extend_sign: input width #{a.width} >= output width #{to_width}" if a.width >= to_width - op = get_or_create_op(ExtendSign, a.width, to_width) - out = new_temp(to_width) - add_op(op, [a.name], [out.name]) - out + def sle(a, b) + check_width_match(a, b) + emit_op(Sle.new(a.width), [a.name, b.name], 1) end - def extend_zero(a, to_width) - raise "extend_zero: input width #{a.width} >= output width #{to_width}" if a.width >= to_width - op = get_or_create_op(ExtendZero, a.width, to_width) - out = new_temp(to_width) - add_op(op, [a.name], [out.name]) - out + def sgt(a, b) + check_width_match(a, b) + emit_op(Sgt.new(a.width), [a.name, b.name], 1) end - def popcnt(a) - op = get_or_create_op(Popcnt, a.width) - out = new_temp(a.width) - add_op(op, [a.name], [out.name]) - out + def sge(a, b) + check_width_match(a, b) + emit_op(Sge.new(a.width), [a.name, b.name], 1) end - def ctz(a) - op = get_or_create_op(Ctz, a.width) - out = new_temp(a.width) - add_op(op, [a.name], [out.name]) - out + def ult(a, b) + check_width_match(a, b) + emit_op(Ult.new(a.width), [a.name, b.name], 1) end - def clz(a) - op = get_or_create_op(Clz, a.width) - out = new_temp(a.width) - add_op(op, [a.name], [out.name]) - out + def ule(a, b) + check_width_match(a, b) + emit_op(Ule.new(a.width), [a.name, b.name], 1) end - def reverse(a) - op = get_or_create_op(Reverse, a.width) - out = new_temp(a.width) - add_op(op, [a.name], [out.name]) - out + def ugt(a, b) + check_width_match(a, b) + emit_op(Ugt.new(a.width), [a.name, b.name], 1) + end + + def uge(a, b) + check_width_match(a, b) + emit_op(Uge.new(a.width), [a.name, b.name], 1) + end + + def eq(a, b) + check_width_match(a, b) + emit_op(Eq.new(a.width), [a.name, b.name], 1) + end + + def ne(a, b) + check_width_match(a, b) + emit_op(Ne.new(a.width), [a.name, b.name], 1) end def rem_u(a, b) check_width_match(a, b) - op = get_or_create_op(RemU, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(RemU.new(a.width), [a.name, b.name], a.width) end def rem_s(a, b) check_width_match(a, b) - op = get_or_create_op(RemS, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(RemS.new(a.width), [a.name, b.name], a.width) end def ror(a, b) check_width_match(a, b) - op = get_or_create_op(Ror, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Ror.new(a.width), [a.name, b.name], a.width) end def rol(a, b) check_width_match(a, b) - op = get_or_create_op(Rol, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(Rol.new(a.width), [a.name, b.name], a.width) end def add_overflow(a, b) check_width_match(a, b) - op = get_or_create_op(AddOverflow, a.width) - out = new_temp(1) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(AddOverflow.new(a.width), [a.name, b.name], 1) end def sub_overflow(a, b) check_width_match(a, b) - op = get_or_create_op(SubOverflow, a.width) - out = new_temp(1) - add_op(op, [a.name, b.name], [out.name]) - out + emit_op(SubOverflow.new(a.width), [a.name, b.name], 1) end - def div_u(a, b, default) - check_width_match(a, b) - raise "div_u: default width mismatch" if a.width != default.width - op = get_or_create_op(DivU, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name, default.name], [out.name]) - out + def not_(a) + emit_op(Not.new(a.width), [a.name], a.width) end - def div_s(a, b, default) - check_width_match(a, b) - raise "div_s: default width mismatch" if a.width != default.width - op = get_or_create_op(DivS, a.width) - out = new_temp(a.width) - add_op(op, [a.name, b.name, default.name], [out.name]) - out + def neg(a) + emit_op(Neg.new(a.width), [a.name], a.width) end - def select(cond, true_val, false_val) - raise "select: condition must be 1-bit" unless cond.width == 1 - raise "select: true/false widths mismatch" unless true_val.width == false_val.width - op = get_or_create_op(Select, true_val.width) - out = new_temp(true_val.width) - add_op(op, [cond.name, true_val.name, false_val.name], [out.name]) - out + def popcnt(a) + emit_op(Popcnt.new(a.width), [a.name], a.width) end - def concat(low, high) - low_width = low.width - high_width = high.width - total_width = low_width + high_width + def ctz(a) + emit_op(Ctz.new(a.width), [a.name], a.width) + end - high_ext = extend_zero(high, total_width) - shift_width = (low_width.bit_length + 1) rescue 1 - shift_amount = const(low_width, shift_width) - high_shifted = lsl(high_ext, shift_amount) - low_ext = extend_zero(low, total_width) - orr(low_ext, high_shifted) + def clz(a) + emit_op(Clz.new(a.width), [a.name], a.width) + end + + def reverse(a) + emit_op(Reverse.new(a.width), [a.name], a.width) + end + + def extend_sign(a, to_width) + raise "extend_sign: input width #{a.width} >= output width #{to_width}" if a.width >= to_width + emit_op(ExtendSign.new(a.width, to_width), [a.name], to_width) + end + + def extend_zero(a, to_width) + raise "extend_zero: input width #{a.width} >= output width #{to_width}" if a.width >= to_width + emit_op(ExtendZero.new(a.width, to_width), [a.name], to_width) end def extract_low(a, out_width) raise "extract_low: output width #{out_width} > input width #{a.width}" if out_width > a.width - op = get_or_create_op(ExtractLow, a.width, out_width) - out = new_temp(out_width) - add_op(op, [a.name], [out.name]) - out + emit_op(ExtractLow.new(a.width, out_width), [a.name], out_width) + end + + def div_u(a, b, default) + check_width_match(a, b) + raise "div_u: default width mismatch" if a.width != default.width + emit_op(DivU.new(a.width), [a.name, b.name, default.name], a.width) end - def extract(value, start, out_width) - start = extend_zero(start, value.width) if start.width != value.width - shifted = lsr(value, start) - extract_low(shifted, out_width) + def div_s(a, b, default) + check_width_match(a, b) + raise "div_s: default width mismatch" if a.width != default.width + emit_op(DivS.new(a.width), [a.name, b.name, default.name], a.width) end - def ensure_width(val, width) - return val if val.width == width - val.width < width ? extend_zero(val, width) : extract_low(val, width) + def select(cond, true_val, false_val) + raise "select: condition must be 1-bit" unless cond.width == 1 + raise "select: true/false widths mismatch" unless true_val.width == false_val.width + emit_op( + Select.new(true_val.width), + [cond.name, true_val.name, false_val.name], + true_val.width + ) end - # Register & memory + + # ------------------------------------------------------------------ + # NOTE: Building ruby/lira/ir_std.rb objects + # ------------------------------------------------------------------ def read(rf, rsi, shape = Shape.new(1, nil)) width = rf.reg_size.lanes_base out = new_temp(width) - stmt = Statement.new(shape, [out.name], [width], 'read', rf.name, [rsi.to_s]) + stmt = Statement.new(shape, [out.name], [width], 'read', rf.name, [rsi.name]) @stmts << stmt out end def write(rf, rsi, value, shape = Shape.new(1, nil)) - stmt = Statement.new(shape, [], [], 'write', rf.name, [rsi.to_s, value.to_s]) + stmt = Statement.new(shape, [], [], 'write', rf.name, [rsi.name, value.name]) @stmts << stmt end @@ -311,7 +277,7 @@ def env(env_func, inputs) env_func.outputs, 'env', env_func.name, - inputs.map(&:to_s) + inputs.map(&:name) ) @stmts << stmt outputs @@ -319,7 +285,7 @@ def env(env_func, inputs) def cond_env(env_func, cond, inputs, on_false) outputs = env_func.outputs.map { |w| new_temp(w) } - all_inputs = [cond.to_s] + inputs.map(&:to_s) + on_false.map(&:to_s) + all_inputs = [cond.name] + inputs.map(&:name) + on_false.map(&:name) stmt = Statement.new( Shape.new(1, nil), outputs.map(&:name), @@ -340,7 +306,7 @@ def input(idx, width = 32) end def output(value, idx) - stmt = Statement.new(Shape.new(1, nil), [], [], 'output', idx.to_s, [value.to_s]) + stmt = Statement.new(Shape.new(1, nil), [], [], 'output', idx.to_s, [value.name]) @stmts << stmt end @@ -351,14 +317,12 @@ def add_op(operation, inputs, outputs, shape = Shape.new(1, nil)) def op(operation, inputs) raise "Operation #{operation.name} has #{operation.outputs.size} outputs, use op_multi" if operation.outputs.size != 1 - out = new_temp(operation.outputs.first) - add_op(operation, inputs.map(&:to_s), [out.name]) - out + emit_op(operation, inputs.map(&:name), operation.outputs.first) end def op_multi(operation, inputs) outputs = operation.outputs.map { |w| new_temp(w) } - add_op(operation, inputs.map(&:to_s), outputs.map(&:name)) + add_op(operation, inputs.map(&:name), outputs.map(&:name)) outputs end @@ -371,67 +335,256 @@ def +(other) @temp_counter = [@temp_counter, other.temp_counter].max self end + end + + class BaseBuilder + attr_reader :seq + + def initialize + @seq = SeqBuilder.new + @op_cache = {} + end + + def cache_op(op_class, *args) + op = op_class.new(*args) + @op_cache[op.name] ||= op + end def operations_map @op_cache.each_value.to_h { |op| [op.name, op] } end - private + # ------------------------------------------------------------------ + # NOTE: Building ruby/lira/ir_ops.rb objects + # ------------------------------------------------------------------ + def add(a, b) + cache_op(Add, a.width) + @seq.add(a, b) + end - def check_width_match(a, b) - raise "width mismatch: #{a.width} vs #{b.width}" if a.width != b.width + def sub(a, b) + cache_op(Sub, a.width) + @seq.sub(a, b) end - end - class BaseBuilder - attr_reader :seq + def mul(a, b) + cache_op(Mul, a.width) + @seq.mul(a, b) + end - def initialize - @seq = SeqBuilder.new + def and_(a, b) + cache_op(And, a.width) + @seq.and_(a, b) + end + + def orr(a, b) + cache_op(Orr, a.width) + @seq.orr(a, b) + end + + def xor(a, b) + cache_op(Xor, a.width) + @seq.xor(a, b) + end + + def lsl(a, b) + cache_op(Lsl, a.width) + @seq.lsl(a, b) + end + + def lsr(a, b) + cache_op(Lsr, a.width) + @seq.lsr(a, b) + end + + def asr(a, b) + cache_op(Asr, a.width) + @seq.asr(a, b) + end + + def slt(a, b) + cache_op(Slt, a.width) + @seq.slt(a, b) + end + + def sle(a, b) + cache_op(Sle, a.width) + @seq.sle(a, b) + end + + def sgt(a, b) + cache_op(Sgt, a.width) + @seq.sgt(a, b) + end + + def sge(a, b) + cache_op(Sge, a.width) + @seq.sge(a, b) + end + + def ult(a, b) + cache_op(Ult, a.width) + @seq.ult(a, b) + end + + def ule(a, b) + cache_op(Ule, a.width) + @seq.ule(a, b) + end + + def ugt(a, b) + cache_op(Ugt, a.width) + @seq.ugt(a, b) + end + + def uge(a, b) + cache_op(Uge, a.width) + @seq.uge(a, b) + end + + def eq(a, b) + cache_op(Eq, a.width) + @seq.eq(a, b) + end + + def ne(a, b) + cache_op(Ne, a.width) + @seq.ne(a, b) + end + + def rem_u(a, b) + cache_op(RemU, a.width) + @seq.rem_u(a, b) + end + + def rem_s(a, b) + cache_op(RemS, a.width) + @seq.rem_s(a, b) + end + + def ror(a, b) + cache_op(Ror, a.width) + @seq.ror(a, b) + end + + def rol(a, b) + cache_op(Rol, a.width) + @seq.rol(a, b) + end + + def add_overflow(a, b) + cache_op(AddOverflow, a.width) + @seq.add_overflow(a, b) + end + + def sub_overflow(a, b) + cache_op(SubOverflow, a.width) + @seq.sub_overflow(a, b) + end + + def not_(a) + cache_op(Not, a.width) + @seq.not_(a) + end + + def neg(a) + cache_op(Neg, a.width) + @seq.neg(a) + end + + def popcnt(a) + cache_op(Popcnt, a.width) + @seq.popcnt(a) + end + + def ctz(a) + cache_op(Ctz, a.width) + @seq.ctz(a) + end + + def clz(a) + cache_op(Clz, a.width) + @seq.clz(a) + end + + def reverse(a) + cache_op(Reverse, a.width) + @seq.reverse(a) + end + + def extend_sign(a, to_width) + cache_op(ExtendSign, a.width, to_width) + @seq.extend_sign(a, to_width) + end + + def extend_zero(a, to_width) + cache_op(ExtendZero, a.width, to_width) + @seq.extend_zero(a, to_width) + end + + def extract_low(a, out_width) + cache_op(ExtractLow, a.width, out_width) + @seq.extract_low(a, out_width) + end + + def div_u(a, b, default) + cache_op(DivU, a.width) + @seq.div_u(a, b, default) + end + + def div_s(a, b, default) + cache_op(DivS, a.width) + @seq.div_s(a, b, default) + end + + def select(cond, true_val, false_val) + cache_op(Select, true_val.width) + @seq.select(cond, true_val, false_val) end - def add(a, b) = @seq.add(a, b) - def sub(a, b) = @seq.sub(a, b) - def mul(a, b) = @seq.mul(a, b) - def and_(a, b) = @seq.and_(a, b) - def orr(a, b) = @seq.orr(a, b) - def xor(a, b) = @seq.xor(a, b) - def lsl(a, b) = @seq.lsl(a, b) - def lsr(a, b) = @seq.lsr(a, b) - def asr(a, b) = @seq.asr(a, b) - def slt(a, b) = @seq.slt(a, b) - def extend_sign(a, to_width) = @seq.extend_sign(a, to_width) - def extend_zero(a, to_width) = @seq.extend_zero(a, to_width) - def popcnt(a) = @seq.popcnt(a) - def ctz(a) = @seq.ctz(a) - def clz(a) = @seq.clz(a) - def reverse(a) = @seq.reverse(a) - def rem_u(a, b) = @seq.rem_u(a, b) - def rem_s(a, b) = @seq.rem_s(a, b) - def ror(a, b) = @seq.ror(a, b) - def rol(a, b) = @seq.rol(a, b) - def add_overflow(a, b) = @seq.add_overflow(a, b) - def sub_overflow(a, b) = @seq.sub_overflow(a, b) - def div_u(a, b, default) = @seq.div_u(a, b, default) - def div_s(a, b, default) = @seq.div_s(a, b, default) - def select(cond, true_val, false_val) = @seq.select(cond, true_val, false_val) - def concat(low, high) = @seq.concat(low, high) - def extract_low(a, out_width) = @seq.extract_low(a, out_width) - def extract(value, start, out_width) = @seq.extract(value, start, out_width) - def ensure_width(val, width) = @seq.ensure_width(val, width) - - def read(rf, rsi, shape = Shape.new(1, nil)) = @seq.read(rf, rsi, shape) - def write(rf, rsi, value, shape = Shape.new(1, nil)) = @seq.write(rf, rsi, value, shape) - def const(value, width = 32) = @seq.const(value, width) - def dyn_const(name, width = 32) = @seq.dyn_const(name, width) - def env(env_func, inputs) = @seq.env(env_func, inputs) - def cond_env(env_func, cond, inputs, on_false) = @seq.cond_env(env_func, cond, inputs, on_false) - def input(idx, width = 32) = @seq.input(idx, width) - def output(value, idx) = @seq.output(value, idx) - def op(operation, inputs) = @seq.op(operation, inputs) - def op_multi(operation, inputs) = @seq.op_multi(operation, inputs) - def operations_map = @seq.operations_map - def get_or_create_op(op_class, *args) = @seq.get_or_create_op(op_class, *args) + # ------------------------------------------------------------------ + # NOTE: Building ruby/lira/ir_std.rb objects + # ------------------------------------------------------------------ + def read(rf, rsi, shape = Shape.new(1, nil)) + @seq.read(rf, rsi, shape) + end + + def write(rf, rsi, value, shape = Shape.new(1, nil)) + @seq.write(rf, rsi, value, shape) + end + + def const(value, width = 32) + @seq.const(value, width) + end + + def dyn_const(name, width = 32) + @seq.dyn_const(name, width) + end + + def env(env_func, inputs) + @seq.env(env_func, inputs) + end + + def cond_env(env_func, cond, inputs, on_false) + @seq.cond_env(env_func, cond, inputs, on_false) + end + + def input(idx, width = 32) + @seq.input(idx, width) + end + + def output(value, idx) + @seq.output(value, idx) + end + + def op(operation, inputs) + @op_cache[operation.name] ||= operation + @seq.op(operation, inputs) + end + + def op_multi(operation, inputs) + @seq.op_multi(operation, inputs) + end end class SnippetBuilder < BaseBuilder diff --git a/lib/lira/ir_ops.rb b/lib/lira/ir_ops.rb index 85980f1..1afc94e 100644 --- a/lib/lira/ir_ops.rb +++ b/lib/lira/ir_ops.rb @@ -5,65 +5,48 @@ module Lira class TypeCheckError < StandardError; end module BaseOp - NOT = :not; + NOT = :not NEG = :neg - ADD = :add; - SUB = :sub; + ADD = :add + SUB = :sub MUL = :mul - AND = :and; - ORR = :orr; + AND = :and + ORR = :orr XOR = :xor - LSL = :lsl; - LSR = :lsr; + LSL = :lsl + LSR = :lsr ASR = :asr - EQ = :eq; + EQ = :eq NE = :ne - SLT = :slt; - SLE = :sle; - SGT = :sgt; + SLT = :slt + SLE = :sle + SGT = :sgt SGE = :sge - ULT = :ult; - ULE = :ule; - UGT = :ugt; + ULT = :ult + ULE = :ule + UGT = :ugt UGE = :uge - DIV_U = :div_u; + DIV_U = :div_u DIV_S = :div_s - REM_U = :rem_u; + REM_U = :rem_u REM_S = :rem_s - ROR = :ror; + ROR = :ror ROL = :rol - ADD_OVERFLOW = :add_overflow; + ADD_OVERFLOW = :add_overflow SUB_OVERFLOW = :sub_overflow SELECT = :select - EXTEND_SIGN = :extend_sign; + EXTEND_SIGN = :extend_sign EXTEND_ZERO = :extend_zero EXTRACT_LOW = :extract_low - POPCNT = :popcnt; - CTZ = :ctz; + POPCNT = :popcnt + CTZ = :ctz CLZ = :clz REVERSE = :reverse end - module StdOperation - def base_name - self.class.name.split('::').last.downcase.to_sym - end - - def generate_name - if outputs.size == 1 - "#{base_name}_#{outputs.first}" - else - "#{base_name}_#{outputs.join('_')}" - end - end - end - class UnaryOp < Operation - include StdOperation - - def initialize(out_bits, name: nil, semantic_base: nil) - name ||= "#{base_name}_#{out_bits}" - semantic_base ||= base_name + def initialize(out_bits, semantic_base, name: nil) + name ||= "#{semantic_base}_#{out_bits}" super(name, [], [out_bits], [out_bits], semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature @@ -77,11 +60,8 @@ def check_signature end class BinaryOp < Operation - include StdOperation - - def initialize(bits, name: nil, semantic_base: nil) - name ||= "#{base_name}_#{bits}" - semantic_base ||= base_name + def initialize(bits, semantic_base, name: nil) + name ||= "#{semantic_base}_#{bits}" super(name, [], [bits, bits], [bits], semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature @@ -98,20 +78,13 @@ def check_signature end class CmpOp < Operation - include StdOperation - - def initialize(bits, out_bits = 1, name: nil, semantic_base: nil) - name ||= "#{base_name}_#{bits}" - semantic_base ||= base_name + def initialize(bits, semantic_base, out_bits = 1, name: nil) + name ||= "#{semantic_base}_#{bits}" super(name, [], [bits, bits], [out_bits], semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature end - def generate_name - "#{base_name}_#{inputs[0]}" - end - def check_signature raise TypeCheckError, 'input[0] must be positive' unless inputs[0] > 0 raise TypeCheckError, 'input[1] must be positive' unless inputs[1] > 0 @@ -121,11 +94,8 @@ def check_signature end class TernaryOp < Operation - include StdOperation - - def initialize(bits, name: nil, semantic_base: nil) - name ||= "#{base_name}_#{bits}" - semantic_base ||= base_name + def initialize(bits, semantic_base, name: nil) + name ||= "#{semantic_base}_#{bits}" super(name, [], [bits, bits, bits], [bits], semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature @@ -143,12 +113,10 @@ def check_signature end class ExtendOp < Operation - include StdOperation - - def initialize(in_bits, out_bits, kind, name: nil) - name ||= "#{kind}_#{in_bits}_to_#{out_bits}" + def initialize(in_bits, out_bits, semantic_base, name: nil) + name ||= "#{semantic_base}_#{in_bits}_to_#{out_bits}" super(name, [], [in_bits], [out_bits], - semantic_base: kind, semantic_func: nil, semantic_table: nil) + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature end @@ -157,19 +125,13 @@ def check_signature raise TypeCheckError, 'output width must be positive' unless outputs[0] > 0 raise TypeCheckError, 'input >= output' unless inputs[0] < outputs[0] end - - def generate_name - "#{semantic_base}_#{inputs[0]}_to_#{outputs[0]}" - end end class ExtractLowOp < Operation - include StdOperation - - def initialize(in_bits, out_bits, name: nil) - name ||= "extract_low_#{in_bits}_to_#{out_bits}" + def initialize(in_bits, out_bits, semantic_base, name: nil) + name ||= "#{semantic_base}_#{in_bits}_to_#{out_bits}" super(name, [], [in_bits], [out_bits], - semantic_base: BaseOp::EXTRACT_LOW, semantic_func: nil, semantic_table: nil) + semantic_base: semantic_base, semantic_func: nil, semantic_table: nil) check_signature end @@ -178,94 +140,90 @@ def check_signature raise TypeCheckError, 'output width must be positive' unless outputs[0] > 0 raise TypeCheckError, 'output > input' unless outputs[0] <= inputs[0] end - - def generate_name - "extract_low_#{inputs[0]}_to_#{outputs[0]}" - end end class Not < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::NOT); end + def initialize(bits); super(bits, BaseOp::NOT); end end class Neg < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::NEG); end + def initialize(bits); super(bits, BaseOp::NEG); end end class Add < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::ADD); end + def initialize(bits); super(bits, BaseOp::ADD); end end class Sub < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::SUB); end + def initialize(bits); super(bits, BaseOp::SUB); end end class Mul < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::MUL); end + def initialize(bits); super(bits, BaseOp::MUL); end end class And < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::AND); end + def initialize(bits); super(bits, BaseOp::AND); end end class Orr < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::ORR); end + def initialize(bits); super(bits, BaseOp::ORR); end end class Xor < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::XOR); end + def initialize(bits); super(bits, BaseOp::XOR); end end class Lsl < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::LSL); end + def initialize(bits); super(bits, BaseOp::LSL); end end class Lsr < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::LSR); end + def initialize(bits); super(bits, BaseOp::LSR); end end class Asr < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::ASR); end + def initialize(bits); super(bits, BaseOp::ASR); end end class Eq < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::EQ); end + def initialize(bits); super(bits, BaseOp::EQ); end end class Ne < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::NE); end + def initialize(bits); super(bits, BaseOp::NE); end end class Slt < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::SLT); end + def initialize(bits); super(bits, BaseOp::SLT); end end class Sle < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::SLE); end + def initialize(bits); super(bits, BaseOp::SLE); end end class Sgt < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::SGT); end + def initialize(bits); super(bits, BaseOp::SGT); end end class Sge < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::SGE); end + def initialize(bits); super(bits, BaseOp::SGE); end end class Ult < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::ULT); end + def initialize(bits); super(bits, BaseOp::ULT); end end class Ule < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::ULE); end + def initialize(bits); super(bits, BaseOp::ULE); end end class Ugt < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::UGT); end + def initialize(bits); super(bits, BaseOp::UGT); end end class Uge < CmpOp - def initialize(bits); super(bits, semantic_base: BaseOp::UGE); end + def initialize(bits); super(bits, BaseOp::UGE); end end class ExtendSign < ExtendOp @@ -277,64 +235,58 @@ def initialize(in_bits, out_bits); super(in_bits, out_bits, BaseOp::EXTEND_ZERO) end class ExtractLow < ExtractLowOp - def initialize(in_bits, out_bits); super(in_bits, out_bits); end + def initialize(in_bits, out_bits); super(in_bits, out_bits, BaseOp::EXTRACT_LOW); end end class Popcnt < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::POPCNT); end + def initialize(bits); super(bits, BaseOp::POPCNT); end end class Ctz < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::CTZ); end + def initialize(bits); super(bits, BaseOp::CTZ); end end class Clz < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::CLZ); end + def initialize(bits); super(bits, BaseOp::CLZ); end end class Reverse < UnaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::REVERSE); end + def initialize(bits); super(bits, BaseOp::REVERSE); end end class RemU < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::REM_U); end - def base_name; BaseOp::REM_U; end + def initialize(bits); super(bits, BaseOp::REM_U); end end class RemS < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::REM_S); end - def base_name; BaseOp::REM_S; end + def initialize(bits); super(bits, BaseOp::REM_S); end end class Ror < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::ROR); end + def initialize(bits); super(bits, BaseOp::ROR); end end class Rol < BinaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::ROL); end + def initialize(bits); super(bits, BaseOp::ROL); end end class AddOverflow < CmpOp - def initialize(bits); super(bits, out_bits: 1, semantic_base: BaseOp::ADD_OVERFLOW); end + def initialize(bits); super(bits, BaseOp::ADD_OVERFLOW, out_bits: 1); end end class SubOverflow < CmpOp - def initialize(bits); super(bits, out_bits: 1, semantic_base: BaseOp::SUB_OVERFLOW); end + def initialize(bits); super(bits, BaseOp::SUB_OVERFLOW, out_bits: 1); end end class DivU < TernaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::DIV_U); end - def base_name; BaseOp::DIV_U; end + def initialize(bits); super(bits, BaseOp::DIV_U); end end class DivS < TernaryOp - def initialize(bits); super(bits, semantic_base: BaseOp::DIV_S); end - def base_name; BaseOp::DIV_S; end + def initialize(bits); super(bits, BaseOp::DIV_S); end end class Select < Operation - include StdOperation - def initialize(bits) name = "select_#{bits}" super(name, [], [1, bits, bits], [bits], diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 6e0be5a..4a49e37 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -121,7 +121,6 @@ def handle(stmt) oprnds = stmt.oprnds cond, t, f = resolved(oprnds[1]), resolved(oprnds[2]), resolved(oprnds[3]) return if cond.nil? || t.nil? || f.nil? - cond = builder.ensure_width(cond, 1) store(oprnds[0], builder.select(cond, t, f)) end end @@ -160,7 +159,7 @@ def handle(stmt) hi, lo = oprnds[2].value, oprnds[3].value width = hi - lo + 1 width = 1 if width < 1 - store(oprnds[0], builder.extract(val, builder.const(lo, 32), width)) + store(oprnds[0], builder.extract_low(val, width)) end end @@ -365,25 +364,13 @@ def store_result(var, val) def op_alu(adl_name, lhs_signed, a, b) op_name = adl_name == :shr && lhs_signed ? :ashr : adl_name op_class = OP_MAP[op_name] or raise "Unknown ALU op: #{adl_name}" - w = [a.width, b.width].max - a = @builder.ensure_width(a, w) - b = @builder.ensure_width(b, w) - op = @builder.get_or_create_op(op_class, w) - out = @builder.seq.new_temp(w) - @builder.seq.add_op(op, [a.name, b.name], [out.name]) - out + @builder.op(op_class.new(a.width), [a, b]) end def op_cmp(adl_name, unsigned, a, b) op_map = unsigned ? CMP_OP_MAP_U : CMP_OP_MAP_S op_class = op_map[adl_name] or raise "Unknown cmp op: #{adl_name}" - w = [a.width, b.width].max - a = @builder.ensure_width(a, w) - b = @builder.ensure_width(b, w) - op = @builder.get_or_create_op(op_class, w) - out = @builder.seq.new_temp(1) - @builder.seq.add_op(op, [a.name, b.name], [out.name]) - out + @builder.op(op_class.new(a.width), [a, b]) end def widen_or_truncate(name, dest_type, src, src_type) @@ -496,7 +483,7 @@ def generate_encode_snippet(instr, operand_vars) value_num = field.value.value if value_num const_val = @builder.const(value_num, width) - const_val = @builder.ensure_width(const_val, 32) + const_val = @builder.extend_zero(const_val, 32) if const_val.width < 32 shifted = @builder.lsl(const_val, @builder.const(lo, 32)) base = @builder.orr(base, shifted) elsif field_var_name =~ /^f_(.+)$/ @@ -504,7 +491,7 @@ def generate_encode_snippet(instr, operand_vars) idx = operand_vars.index { |v| v.name.to_s == operand_name } if idx op_val = operand_values[idx] - op_val = @builder.ensure_width(op_val, 32) + op_val = @builder.extend_zero(op_val, 32) if op_val.width < 32 shifted = @builder.lsl(op_val, @builder.const(lo, 32)) base = @builder.orr(base, shifted) end @@ -656,12 +643,8 @@ def load_target(path) def extract_arch_name(_loaded_modules) target_name = nil - ObjectSpace.each_object(Module) do |mod| - if mod.is_a?(Module) && mod.name && mod.name !~ /^SimInfra/ && mod.constants.include?(:XRegs) - target_name = mod.name.to_s - break - end - end + instructions = SimInfra.class_variable_get(:@@instructions) + target_name = instructions.first.feature.to_s unless instructions.empty? target_name ||= 'TargetArch' [target_name, []] end From cd97bb7311dfc5464aca77bbecef00e2fd8734a6 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 24 Jun 2026 16:36:37 +0300 Subject: [PATCH 73/75] [IR] LIRA IR removed --- lira.yaml | 3891 ----------------------------------------------------- 1 file changed, 3891 deletions(-) delete mode 100644 lira.yaml diff --git a/lira.yaml b/lira.yaml deleted file mode 100644 index 0652f67..0000000 --- a/lira.yaml +++ /dev/null @@ -1,3891 +0,0 @@ ---- -:name: TargetArch -:attributes: [] -:register_files: -- :name: XRegs - :attributes: [] - :reg_size: - :lanes_base: 32 - :lanes_mult: {} - :regs: - - :name: x0 - :attributes: - - zero - - :name: x1 - :attributes: [] - - :name: x2 - :attributes: [] - - :name: x3 - :attributes: [] - - :name: x4 - :attributes: [] - - :name: x5 - :attributes: [] - - :name: x6 - :attributes: [] - - :name: x7 - :attributes: [] - - :name: x8 - :attributes: [] - - :name: x9 - :attributes: [] - - :name: x10 - :attributes: [] - - :name: x11 - :attributes: [] - - :name: x12 - :attributes: [] - - :name: x13 - :attributes: [] - - :name: x14 - :attributes: [] - - :name: x15 - :attributes: [] - - :name: x16 - :attributes: [] - - :name: x17 - :attributes: [] - - :name: x18 - :attributes: [] - - :name: x19 - :attributes: [] - - :name: x20 - :attributes: [] - - :name: x21 - :attributes: [] - - :name: x22 - :attributes: [] - - :name: x23 - :attributes: [] - - :name: x24 - :attributes: [] - - :name: x25 - :attributes: [] - - :name: x26 - :attributes: [] - - :name: x27 - :attributes: [] - - :name: x28 - :attributes: [] - - :name: x29 - :attributes: [] - - :name: x30 - :attributes: [] - - :name: x31 - :attributes: [] - - :name: pc - :attributes: - - pc -:system_registers: [] -:environment_functions: -- :name: sysCall - :attributes: [] - :inputs: [] - :outputs: [] -- :name: writeMem8 - :attributes: [] - :inputs: - - 32 - - 8 - :outputs: [] -- :name: writeMem16 - :attributes: [] - :inputs: - - 32 - - 16 - :outputs: [] -- :name: writeMem32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: [] -- :name: readMem8 - :attributes: [] - :inputs: - - 32 - :outputs: - - 8 -- :name: readMem16 - :attributes: [] - :inputs: - - 32 - :outputs: - - 16 -- :name: readMem32 - :attributes: [] - :inputs: - - 32 - :outputs: - - 32 -- :name: getPC - :attributes: [] - :inputs: [] - :outputs: - - 32 -- :name: setPC - :attributes: [] - :inputs: - - 32 - :outputs: [] -:tables_int: [] -:operations: -- :name: lsr_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :lsr - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_5 - :attributes: [] - :inputs: - - 32 - :outputs: - - 5 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_5_to_32 - :attributes: [] - :inputs: - - 5 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_20 - :attributes: [] - :inputs: - - 32 - :outputs: - - 20 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_20_to_32 - :attributes: [] - :inputs: - - 20 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: lsl_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :lsl - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_1_to_32 - :attributes: [] - :inputs: - - 1 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: orr_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :orr - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: and_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :and - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: eq_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :eq - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: add_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :add - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: sub_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :sub - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: slt_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :slt - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_1_to_32 - :attributes: [] - :inputs: - - 1 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: ult_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :ult - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: xor_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :xor - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: asr_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :asr - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_12 - :attributes: [] - :inputs: - - 32 - :outputs: - - 12 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_12_to_32 - :attributes: [] - :inputs: - - 12 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: select_32 - :attributes: [] - :inputs: - - 1 - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :select - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_1 - :attributes: [] - :inputs: - - 32 - :outputs: - - 1 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_1_to_13 - :attributes: [] - :inputs: - - 1 - :outputs: - - 13 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_13_to_32 - :attributes: [] - :inputs: - - 13 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_6 - :attributes: [] - :inputs: - - 32 - :outputs: - - 6 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_6_to_13 - :attributes: [] - :inputs: - - 6 - :outputs: - - 13 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_4 - :attributes: [] - :inputs: - - 32 - :outputs: - - 4 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_4_to_13 - :attributes: [] - :inputs: - - 4 - :outputs: - - 13 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_13 - :attributes: [] - :inputs: - - 32 - :outputs: - - 13 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_13_to_32 - :attributes: [] - :inputs: - - 13 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: ne_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :ne - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: sge_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :sge - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: uge_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 1 - :semantic_base: :uge - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_1_to_21 - :attributes: [] - :inputs: - - 1 - :outputs: - - 21 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_21_to_32 - :attributes: [] - :inputs: - - 21 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_8 - :attributes: [] - :inputs: - - 32 - :outputs: - - 8 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_8_to_21 - :attributes: [] - :inputs: - - 8 - :outputs: - - 21 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_10 - :attributes: [] - :inputs: - - 32 - :outputs: - - 10 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_10_to_21 - :attributes: [] - :inputs: - - 10 - :outputs: - - 21 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_21 - :attributes: [] - :inputs: - - 32 - :outputs: - - 21 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_21_to_32 - :attributes: [] - :inputs: - - 21 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_7 - :attributes: [] - :inputs: - - 32 - :outputs: - - 7 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_7_to_12 - :attributes: [] - :inputs: - - 7 - :outputs: - - 12 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_12_to_32 - :attributes: [] - :inputs: - - 12 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_5_to_12 - :attributes: [] - :inputs: - - 5 - :outputs: - - 12 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extract_low_32_to_16 - :attributes: [] - :inputs: - - 32 - :outputs: - - 16 - :semantic_base: :extract_low - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_8_to_32 - :attributes: [] - :inputs: - - 8 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_16_to_32 - :attributes: [] - :inputs: - - 16 - :outputs: - - 32 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_8_to_32 - :attributes: [] - :inputs: - - 8 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_16_to_32 - :attributes: [] - :inputs: - - 16 - :outputs: - - 32 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: mul_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :mul - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_sign_32_to_64 - :attributes: [] - :inputs: - - 32 - :outputs: - - 64 - :semantic_base: :extend_sign - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: mul_64 - :attributes: [] - :inputs: - - 64 - - 64 - :outputs: - - 64 - :semantic_base: :mul - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: extend_zero_32_to_64 - :attributes: [] - :inputs: - - 32 - :outputs: - - 64 - :semantic_base: :extend_zero - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: asr_64 - :attributes: [] - :inputs: - - 64 - - 64 - :outputs: - - 64 - :semantic_base: :asr - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: lsr_64 - :attributes: [] - :inputs: - - 64 - - 64 - :outputs: - - 64 - :semantic_base: :lsr - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: div_s_32 - :attributes: [] - :inputs: - - 32 - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :div_s - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: div_u_32 - :attributes: [] - :inputs: - - 32 - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :div_u - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: rem_s_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :rem_s - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -- :name: rem_u_32 - :attributes: [] - :inputs: - - 32 - - 32 - :outputs: - - 32 - :semantic_base: :rem_u - :semantic_func: {} - :semantic_func_128: {} - :semantic_table: {} -:snippets: -- :name: decode_0 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 7; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 5 _t5 = op extract_low_32_to_5 _t4; - 1 32 _t6 = op extend_zero_5_to_32 _t5; - 1 = output 0 _t6; -- :name: decode_1 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 12; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 20 _t5 = op extract_low_32_to_20 _t4; - 1 32 _t7 = const 12; - 1 32 _t8 = op extend_zero_20_to_32 _t5; - 1 32 _t9 = op lsl_32 _t8 _t7; - 1 = output 0 _t9; -- :name: encode_0 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = const 0; - 1 1 _t4 = const 55; - 1 32 _t5 = op extend_zero_1_to_32 _t4; - 1 32 _t6 = const 6; - 1 32 _t7 = op lsl_32 _t5 _t6; - 1 32 _t8 = op orr_32 _t3 _t7; - 1 32 _t9 = const 11; - 1 32 _t10 = op lsl_32 _t1 _t9; - 1 32 _t11 = op orr_32 _t8 _t10; - 1 32 _t12 = const 31; - 1 32 _t13 = op lsl_32 _t2 _t12; - 1 32 _t14 = op orr_32 _t11 _t13; - 1 = output 0 _t14; -- :name: constraint_0 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 127; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 55; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_1 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = const 0; - 1 1 _t4 = const 23; - 1 32 _t5 = op extend_zero_1_to_32 _t4; - 1 32 _t6 = const 6; - 1 32 _t7 = op lsl_32 _t5 _t6; - 1 32 _t8 = op orr_32 _t3 _t7; - 1 32 _t9 = const 11; - 1 32 _t10 = op lsl_32 _t1 _t9; - 1 32 _t11 = op orr_32 _t8 _t10; - 1 32 _t12 = const 31; - 1 32 _t13 = op lsl_32 _t2 _t12; - 1 32 _t14 = op orr_32 _t11 _t13; - 1 = output 0 _t14; -- :name: constraint_1 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 127; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 23; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: decode_2 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 20; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 5 _t5 = op extract_low_32_to_5 _t4; - 1 32 _t6 = op extend_zero_5_to_32 _t5; - 1 = output 0 _t6; -- :name: decode_3 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 15; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 5 _t5 = op extract_low_32_to_5 _t4; - 1 32 _t6 = op extend_zero_5_to_32 _t5; - 1 = output 0 _t6; -- :name: encode_2 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_2 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 51; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_3 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 32; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_3 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 1073741875; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_4 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 1; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_4 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 4147; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_5 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 2; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_5 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 8243; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_6 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 3; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_6 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 12339; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_7 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 4; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_7 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 16435; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_8 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_8 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 20531; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_9 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 32; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_9 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 1073762355; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_10 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 6; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_10 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 24627; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_11 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 7; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 0; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_11 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 28723; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: decode_4 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 20; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 12 _t5 = op extract_low_32_to_12 _t4; - 1 32 _t6 = op extend_sign_12_to_32 _t5; - 1 = output 0 _t6; -- :name: encode_12 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_12 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 19; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_13 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 2; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_13 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 8211; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_14 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 3; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_14 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 12307; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_15 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 4; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_15 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 16403; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_16 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 6; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_16 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 24595; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_17 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 7; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_17 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 28691; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_18 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 1; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 1 _t21 = const 0; - 1 32 _t22 = op extend_zero_1_to_32 _t21; - 1 32 _t23 = const 31; - 1 32 _t24 = op lsl_32 _t22 _t23; - 1 32 _t25 = op orr_32 _t20 _t24; - 1 = output 0 _t25; -- :name: constraint_18 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 4115; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_19 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 1 _t21 = const 0; - 1 32 _t22 = op extend_zero_1_to_32 _t21; - 1 32 _t23 = const 31; - 1 32 _t24 = op lsl_32 _t22 _t23; - 1 32 _t25 = op orr_32 _t20 _t24; - 1 = output 0 _t25; -- :name: constraint_19 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 20499; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_20 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 19; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 1 _t21 = const 32; - 1 32 _t22 = op extend_zero_1_to_32 _t21; - 1 32 _t23 = const 31; - 1 32 _t24 = op lsl_32 _t22 _t23; - 1 32 _t25 = op orr_32 _t20 _t24; - 1 = output 0 _t25; -- :name: constraint_20 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 1073762323; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: decode_5 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 31; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 1 _t5 = op extract_low_32_to_1 _t4; - 1 13 _t6 = op extend_zero_1_to_13 _t5; - 1 32 _t8 = const 12; - 1 32 _t9 = op extend_zero_13_to_32 _t6; - 1 32 _t10 = op lsl_32 _t9 _t8; - 1 32 _t12 = const 7; - 1 32 _t13 = op lsr_32 _t1 _t12; - 1 1 _t14 = op extract_low_32_to_1 _t13; - 1 13 _t15 = op extend_zero_1_to_13 _t14; - 1 32 _t17 = const 11; - 1 32 _t18 = op extend_zero_13_to_32 _t15; - 1 32 _t19 = op lsl_32 _t18 _t17; - 1 32 _t21 = op orr_32 _t10 _t19; - 1 32 _t23 = const 25; - 1 32 _t24 = op lsr_32 _t1 _t23; - 1 6 _t25 = op extract_low_32_to_6 _t24; - 1 13 _t26 = op extend_zero_6_to_13 _t25; - 1 32 _t28 = const 5; - 1 32 _t29 = op extend_zero_13_to_32 _t26; - 1 32 _t30 = op lsl_32 _t29 _t28; - 1 32 _t32 = op orr_32 _t21 _t30; - 1 32 _t34 = const 8; - 1 32 _t35 = op lsr_32 _t1 _t34; - 1 4 _t36 = op extract_low_32_to_4 _t35; - 1 13 _t37 = op extend_zero_4_to_13 _t36; - 1 32 _t39 = const 1; - 1 32 _t40 = op extend_zero_13_to_32 _t37; - 1 32 _t41 = op lsl_32 _t40 _t39; - 1 32 _t43 = op orr_32 _t32 _t41; - 1 13 _t45 = op extract_low_32_to_13 _t43; - 1 32 _t46 = op extend_sign_13_to_32 _t45; - 1 = output 0 _t46; -- :name: encode_21 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 0; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_21 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 99; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_22 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 1; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_22 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 4195; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_23 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 4; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_23 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 16483; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_24 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 5; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_24 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 20579; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_25 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 6; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_25 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 24675; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_26 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 99; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 7; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_26 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 28771; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: decode_6 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 31; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 1 _t5 = op extract_low_32_to_1 _t4; - 1 21 _t6 = op extend_zero_1_to_21 _t5; - 1 32 _t8 = const 20; - 1 32 _t9 = op extend_zero_21_to_32 _t6; - 1 32 _t10 = op lsl_32 _t9 _t8; - 1 32 _t12 = const 12; - 1 32 _t13 = op lsr_32 _t1 _t12; - 1 8 _t14 = op extract_low_32_to_8 _t13; - 1 21 _t15 = op extend_zero_8_to_21 _t14; - 1 32 _t17 = const 12; - 1 32 _t18 = op extend_zero_21_to_32 _t15; - 1 32 _t19 = op lsl_32 _t18 _t17; - 1 32 _t21 = op orr_32 _t10 _t19; - 1 32 _t23 = const 20; - 1 32 _t24 = op lsr_32 _t1 _t23; - 1 1 _t25 = op extract_low_32_to_1 _t24; - 1 21 _t26 = op extend_zero_1_to_21 _t25; - 1 32 _t28 = const 11; - 1 32 _t29 = op extend_zero_21_to_32 _t26; - 1 32 _t30 = op lsl_32 _t29 _t28; - 1 32 _t32 = op orr_32 _t21 _t30; - 1 32 _t34 = const 21; - 1 32 _t35 = op lsr_32 _t1 _t34; - 1 10 _t36 = op extract_low_32_to_10 _t35; - 1 21 _t37 = op extend_zero_10_to_21 _t36; - 1 32 _t39 = const 1; - 1 32 _t40 = op extend_zero_21_to_32 _t37; - 1 32 _t41 = op lsl_32 _t40 _t39; - 1 32 _t43 = op orr_32 _t32 _t41; - 1 21 _t45 = op extract_low_32_to_21 _t43; - 1 32 _t46 = op extend_sign_21_to_32 _t45; - 1 = output 0 _t46; -- :name: encode_27 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = const 0; - 1 1 _t4 = const 111; - 1 32 _t5 = op extend_zero_1_to_32 _t4; - 1 32 _t6 = const 6; - 1 32 _t7 = op lsl_32 _t5 _t6; - 1 32 _t8 = op orr_32 _t3 _t7; - 1 32 _t9 = const 11; - 1 32 _t10 = op lsl_32 _t2 _t9; - 1 32 _t11 = op orr_32 _t8 _t10; - 1 = output 0 _t11; -- :name: constraint_27 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 127; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 111; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_28 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 103; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_28 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 103; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: decode_7 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t3 = const 25; - 1 32 _t4 = op lsr_32 _t1 _t3; - 1 7 _t5 = op extract_low_32_to_7 _t4; - 1 12 _t6 = op extend_zero_7_to_12 _t5; - 1 32 _t8 = const 5; - 1 32 _t9 = op extend_zero_12_to_32 _t6; - 1 32 _t10 = op lsl_32 _t9 _t8; - 1 32 _t12 = const 7; - 1 32 _t13 = op lsr_32 _t1 _t12; - 1 5 _t14 = op extract_low_32_to_5 _t13; - 1 12 _t15 = op extend_zero_5_to_12 _t14; - 1 32 _t17 = op extend_zero_12_to_32 _t15; - 1 32 _t18 = op orr_32 _t10 _t17; - 1 12 _t20 = op extract_low_32_to_12 _t18; - 1 32 _t21 = op extend_sign_12_to_32 _t20; - 1 = output 0 _t21; -- :name: encode_29 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 35; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 0; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_29 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 35; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_30 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 35; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 1; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_30 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 4131; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_31 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 35; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 1 _t10 = const 2; - 1 32 _t11 = op extend_zero_1_to_32 _t10; - 1 32 _t12 = const 14; - 1 32 _t13 = op lsl_32 _t11 _t12; - 1 32 _t14 = op orr_32 _t9 _t13; - 1 32 _t15 = const 19; - 1 32 _t16 = op lsl_32 _t2 _t15; - 1 32 _t17 = op orr_32 _t14 _t16; - 1 32 _t18 = const 24; - 1 32 _t19 = op lsl_32 _t3 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 = output 0 _t20; -- :name: constraint_31 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 8227; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_32 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 3; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_32 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 3; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_33 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 3; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 1; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_33 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 4099; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_34 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 3; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 2; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_34 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 8195; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_35 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 3; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 4; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_35 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 16387; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_36 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 3; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 31; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 = output 0 _t23; -- :name: constraint_36 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 28799; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 20483; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: constraint_37 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4294967295; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 115; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: constraint_38 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4294967295; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 1048691; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: constraint_39 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4027580415; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 15; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_37 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 0; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_40 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33554483; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_38 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 1; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_41 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33558579; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_39 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 2; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_42 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33562675; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_40 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 3; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_43 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33566771; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_41 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 4; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_44 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33570867; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_42 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 5; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_45 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33574963; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_43 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 6; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_46 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33579059; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -- :name: encode_44 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = input 1; - 1 32 _t3 = input 2; - 1 32 _t4 = const 0; - 1 1 _t5 = const 51; - 1 32 _t6 = op extend_zero_1_to_32 _t5; - 1 32 _t7 = const 6; - 1 32 _t8 = op lsl_32 _t6 _t7; - 1 32 _t9 = op orr_32 _t4 _t8; - 1 32 _t10 = const 11; - 1 32 _t11 = op lsl_32 _t3 _t10; - 1 32 _t12 = op orr_32 _t9 _t11; - 1 1 _t13 = const 7; - 1 32 _t14 = op extend_zero_1_to_32 _t13; - 1 32 _t15 = const 14; - 1 32 _t16 = op lsl_32 _t14 _t15; - 1 32 _t17 = op orr_32 _t12 _t16; - 1 32 _t18 = const 19; - 1 32 _t19 = op lsl_32 _t2 _t18; - 1 32 _t20 = op orr_32 _t17 _t19; - 1 32 _t21 = const 24; - 1 32 _t22 = op lsl_32 _t1 _t21; - 1 32 _t23 = op orr_32 _t20 _t22; - 1 1 _t24 = const 1; - 1 32 _t25 = op extend_zero_1_to_32 _t24; - 1 32 _t26 = const 31; - 1 32 _t27 = op lsl_32 _t25 _t26; - 1 32 _t28 = op orr_32 _t23 _t27; - 1 = output 0 _t28; -- :name: constraint_47 - :seq: | - 1 32 _t1 = input 0; - 1 32 _t2 = const 4261441663; - 1 32 _t3 = op and_32 _t1 _t2; - 1 32 _t4 = const 33583155; - 1 1 _t5 = op eq_32 _t3 _t4; - 1 = output 0 _t5; -:instructions: -- :name: lui - :attributes: [] - :operand_sizes: - - 32 - - 32 - :operand_names: - - rd - - imm - :encoding: - :encoded_size: 32 - :const_encoding_part: 55 - :const_mask: 127 - :decode: - - decode_0 - - decode_1 - :encode: encode_0 - :constraint_decode: constraint_0 - :constraint_encode: '' - :semantic: | - 1 32 _t1 = input 1; - 1 32 _t2 = input 0; - 1 = write XRegs _t2 _t1; -- :name: auipc - :attributes: [] - :operand_sizes: - - 32 - - 32 - :operand_names: - - rd - - imm - :encoding: - :encoded_size: 32 - :const_encoding_part: 23 - :const_mask: 127 - :decode: - - decode_0 - - decode_1 - :encode: encode_1 - :constraint_decode: constraint_1 - :constraint_encode: '' - :semantic: | - 1 32 _t2 = input 1; - 1 32 _t3 = env getPC; - 1 32 _t4 = op add_32 _t2 _t3; - 1 32 _t5 = input 0; - 1 = write XRegs _t5 _t4; -- :name: add - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 51 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_2 - :constraint_decode: constraint_2 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op add_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: sub - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 1073741875 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_3 - :constraint_decode: constraint_3 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op sub_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: sll - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 4147 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_4 - :constraint_decode: constraint_4 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op lsl_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: slt - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 8243 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_5 - :constraint_decode: constraint_5 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op slt_32 _t4 _t8; - 1 32 _t12 = op extend_sign_1_to_32 _t10; - 1 32 _t13 = input 2; - 1 = write XRegs _t13 _t12; -- :name: sltu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 12339 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_6 - :constraint_decode: constraint_6 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op ult_32 _t4 _t8; - 1 32 _t12 = op extend_sign_1_to_32 _t10; - 1 32 _t13 = input 2; - 1 = write XRegs _t13 _t12; -- :name: xor - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 16435 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_7 - :constraint_decode: constraint_7 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 32 _t7 = read XRegs _t6; - 1 32 _t8 = op xor_32 _t4 _t7; - 1 32 _t9 = input 2; - 1 = write XRegs _t9 _t8; -- :name: srl - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 20531 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_8 - :constraint_decode: constraint_8 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op lsr_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: sra - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 1073762355 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_9 - :constraint_decode: constraint_9 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op asr_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: or - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 24627 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_10 - :constraint_decode: constraint_10 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 32 _t7 = read XRegs _t6; - 1 32 _t8 = op orr_32 _t4 _t7; - 1 32 _t9 = input 2; - 1 = write XRegs _t9 _t8; -- :name: and - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 28723 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_11 - :constraint_decode: constraint_11 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 32 _t7 = read XRegs _t6; - 1 32 _t8 = op and_32 _t4 _t7; - 1 32 _t9 = input 2; - 1 = write XRegs _t9 _t8; -- :name: addi - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 19 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_12 - :constraint_decode: constraint_12 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: slti - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 8211 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_13 - :constraint_decode: constraint_13 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 1 _t8 = op slt_32 _t4 _t6; - 1 32 _t10 = op extend_sign_1_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: sltiu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 12307 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_14 - :constraint_decode: constraint_14 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 1 _t8 = op ult_32 _t4 _t6; - 1 32 _t10 = op extend_sign_1_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: xori - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 16403 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_15 - :constraint_decode: constraint_15 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op xor_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: ori - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 24595 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_16 - :constraint_decode: constraint_16 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op orr_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: andi - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 28691 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_17 - :constraint_decode: constraint_17 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op and_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: slli - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 4115 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_18 - :constraint_decode: constraint_18 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op lsl_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: srli - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 20499 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_19 - :constraint_decode: constraint_19 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op lsr_32 _t4 _t5; - 1 32 _t7 = input 2; - 1 = write XRegs _t7 _t6; -- :name: srai - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 1073762323 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_20 - :constraint_decode: constraint_20 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 0; - 1 32 _t7 = op asr_32 _t4 _t6; - 1 32 _t8 = input 2; - 1 = write XRegs _t8 _t7; -- :name: beq - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 99 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_21 - :constraint_decode: constraint_21 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 2; - 1 32 _t7 = read XRegs _t6; - 1 1 _t8 = op eq_32 _t4 _t7; - 1 32 _t10 = env getPC; - 1 32 _t11 = input 0; - 1 32 _t12 = op add_32 _t10 _t11; - 1 32 _t14 = const 4; - 1 32 _t15 = op add_32 _t10 _t14; - 1 32 _t17 = op select_32 _t8 _t12 _t15; - 1 = env setPC _t17; -- :name: bne - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 4195 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_22 - :constraint_decode: constraint_22 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t6 = input 2; - 1 32 _t7 = read XRegs _t6; - 1 1 _t8 = op ne_32 _t4 _t7; - 1 32 _t10 = env getPC; - 1 32 _t11 = input 0; - 1 32 _t12 = op add_32 _t10 _t11; - 1 32 _t14 = const 4; - 1 32 _t15 = op add_32 _t10 _t14; - 1 32 _t17 = op select_32 _t8 _t12 _t15; - 1 = env setPC _t17; -- :name: blt - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 16483 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_23 - :constraint_decode: constraint_23 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 2; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op slt_32 _t4 _t8; - 1 32 _t12 = env getPC; - 1 32 _t13 = input 0; - 1 32 _t14 = op add_32 _t12 _t13; - 1 32 _t16 = const 4; - 1 32 _t17 = op add_32 _t12 _t16; - 1 32 _t19 = op select_32 _t10 _t14 _t17; - 1 = env setPC _t19; -- :name: bge - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 20579 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_24 - :constraint_decode: constraint_24 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 2; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op sge_32 _t4 _t8; - 1 32 _t12 = env getPC; - 1 32 _t13 = input 0; - 1 32 _t14 = op add_32 _t12 _t13; - 1 32 _t16 = const 4; - 1 32 _t17 = op add_32 _t12 _t16; - 1 32 _t19 = op select_32 _t10 _t14 _t17; - 1 = env setPC _t19; -- :name: bltu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 24675 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_25 - :constraint_decode: constraint_25 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 2; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op ult_32 _t4 _t8; - 1 32 _t12 = env getPC; - 1 32 _t13 = input 0; - 1 32 _t14 = op add_32 _t12 _t13; - 1 32 _t16 = const 4; - 1 32 _t17 = op add_32 _t12 _t16; - 1 32 _t19 = op select_32 _t10 _t14 _t17; - 1 = env setPC _t19; -- :name: bgeu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 28771 - :const_mask: 28799 - :decode: - - decode_5 - - decode_3 - - decode_2 - :encode: encode_26 - :constraint_decode: constraint_26 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 2; - 1 32 _t8 = read XRegs _t7; - 1 1 _t10 = op uge_32 _t4 _t8; - 1 32 _t12 = env getPC; - 1 32 _t13 = input 0; - 1 32 _t14 = op add_32 _t12 _t13; - 1 32 _t16 = const 4; - 1 32 _t17 = op add_32 _t12 _t16; - 1 32 _t19 = op select_32 _t10 _t14 _t17; - 1 = env setPC _t19; -- :name: jal - :attributes: [] - :operand_sizes: - - 32 - - 32 - :operand_names: - - imm - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 111 - :const_mask: 127 - :decode: - - decode_6 - - decode_0 - :encode: encode_27 - :constraint_decode: constraint_27 - :constraint_encode: '' - :semantic: | - 1 32 _t2 = env getPC; - 1 32 _t3 = const 4; - 1 32 _t4 = op add_32 _t2 _t3; - 1 32 _t5 = input 1; - 1 = write XRegs _t5 _t4; - 1 32 _t7 = input 0; - 1 32 _t8 = op add_32 _t2 _t7; - 1 = env setPC _t8; -- :name: jalr - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 103 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_28 - :constraint_decode: constraint_28 - :constraint_encode: '' - :semantic: | - 1 32 _t2 = env getPC; - 1 32 _t3 = const 4; - 1 32 _t4 = op add_32 _t2 _t3; - 1 32 _t8 = input 1; - 1 32 _t9 = read XRegs _t8; - 1 32 _t10 = input 0; - 1 32 _t11 = op add_32 _t9 _t10; - 1 32 _t13 = const -2; - 1 32 _t14 = op and_32 _t11 _t13; - 1 = env setPC _t14; - 1 32 _t15 = input 2; - 1 = write XRegs _t15 _t4; -- :name: sb - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 35 - :const_mask: 28799 - :decode: - - decode_7 - - decode_3 - - decode_2 - :encode: encode_29 - :constraint_decode: constraint_29 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t9 = input 2; - 1 32 _t10 = read XRegs _t9; - 1 32 _t11 = const 0; - 1 32 _t12 = op lsr_32 _t10 _t11; - 1 8 _t13 = op extract_low_32_to_8 _t12; - 1 = env writeMem8 _t6 _t13; -- :name: sh - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 4131 - :const_mask: 28799 - :decode: - - decode_7 - - decode_3 - - decode_2 - :encode: encode_30 - :constraint_decode: constraint_30 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t9 = input 2; - 1 32 _t10 = read XRegs _t9; - 1 32 _t11 = const 0; - 1 32 _t12 = op lsr_32 _t10 _t11; - 1 16 _t13 = op extract_low_32_to_16 _t12; - 1 = env writeMem16 _t6 _t13; -- :name: sw - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rs2 - :encoding: - :encoded_size: 32 - :const_encoding_part: 8227 - :const_mask: 28799 - :decode: - - decode_7 - - decode_3 - - decode_2 - :encode: encode_31 - :constraint_decode: constraint_31 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t8 = input 2; - 1 32 _t9 = read XRegs _t8; - 1 = env writeMem32 _t6 _t9; -- :name: lb - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 3 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_32 - :constraint_decode: constraint_32 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 8 _t8 = env readMem8 _t6; - 1 32 _t10 = op extend_sign_8_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: lh - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 4099 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_33 - :constraint_decode: constraint_33 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 16 _t8 = env readMem16 _t6; - 1 32 _t10 = op extend_sign_16_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: lw - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 8195 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_34 - :constraint_decode: constraint_34 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 32 _t8 = env readMem32 _t6; - 1 32 _t9 = input 2; - 1 = write XRegs _t9 _t8; -- :name: lbu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 16387 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_35 - :constraint_decode: constraint_35 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 8 _t8 = env readMem8 _t6; - 1 32 _t10 = op extend_zero_8_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: lhu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - imm - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 20483 - :const_mask: 28799 - :decode: - - decode_4 - - decode_3 - - decode_0 - :encode: encode_36 - :constraint_decode: constraint_36 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = input 0; - 1 32 _t6 = op add_32 _t4 _t5; - 1 16 _t8 = env readMem16 _t6; - 1 32 _t10 = op extend_zero_16_to_32 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: ecall - :attributes: [] - :operand_sizes: [] - :operand_names: [] - :encoding: - :encoded_size: 32 - :const_encoding_part: 115 - :const_mask: 4294967295 - :decode: [] - :encode: '' - :constraint_decode: constraint_37 - :constraint_encode: '' - :semantic: '1 = env sysCall; - - ' -- :name: ebreak - :attributes: [] - :operand_sizes: [] - :operand_names: [] - :encoding: - :encoded_size: 32 - :const_encoding_part: 1048691 - :const_mask: 4294967295 - :decode: [] - :encode: '' - :constraint_decode: constraint_38 - :constraint_encode: '' - :semantic: '' -- :name: fence - :attributes: [] - :operand_sizes: [] - :operand_names: [] - :encoding: - :encoded_size: 32 - :const_encoding_part: 15 - :const_mask: 4027580415 - :decode: [] - :encode: '' - :constraint_decode: constraint_39 - :constraint_encode: '' - :semantic: '' -- :name: mul - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33554483 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_37 - :constraint_decode: constraint_40 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op mul_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: mulh - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33558579 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_38 - :constraint_decode: constraint_41 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 64 _t5 = op extend_sign_32_to_64 _t4; - 1 32 _t8 = input 0; - 1 32 _t9 = read XRegs _t8; - 1 64 _t10 = op extend_sign_32_to_64 _t9; - 1 64 _t12 = op mul_64 _t5 _t10; - 1 32 _t14 = const 32; - 1 64 _t15 = op extend_zero_32_to_64 _t14; - 1 64 _t16 = op asr_64 _t12 _t15; - 1 32 _t17 = input 2; - 1 = write XRegs _t17 _t16; -- :name: mulhsu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33562675 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_39 - :constraint_decode: constraint_42 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 64 _t5 = op extend_sign_32_to_64 _t4; - 1 32 _t8 = input 0; - 1 32 _t9 = read XRegs _t8; - 1 64 _t10 = op extend_zero_32_to_64 _t9; - 1 64 _t13 = op mul_64 _t5 _t10; - 1 32 _t15 = const 32; - 1 64 _t16 = op extend_zero_32_to_64 _t15; - 1 64 _t17 = op asr_64 _t13 _t16; - 1 32 _t18 = input 2; - 1 = write XRegs _t18 _t17; -- :name: mulhu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33566771 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_40 - :constraint_decode: constraint_43 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 64 _t5 = op extend_zero_32_to_64 _t4; - 1 32 _t8 = input 0; - 1 32 _t9 = read XRegs _t8; - 1 64 _t10 = op extend_zero_32_to_64 _t9; - 1 64 _t12 = op mul_64 _t5 _t10; - 1 32 _t14 = const 32; - 1 64 _t15 = op extend_zero_32_to_64 _t14; - 1 64 _t16 = op lsr_64 _t12 _t15; - 1 32 _t17 = input 2; - 1 = write XRegs _t17 _t16; -- :name: div - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33570867 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_41 - :constraint_decode: constraint_44 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 0; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = const 0; - 1 1 _t6 = op ne_32 _t4 _t5; - 1 32 _t9 = input 1; - 1 32 _t10 = read XRegs _t9; - 1 32 _t13 = input 0; - 1 32 _t14 = read XRegs _t13; - 1 32 _t15 = const 0; - 1 1 _t16 = op ne_32 _t14 _t15; - 1 32 _t19 = input 0; - 1 32 _t20 = read XRegs _t19; - 1 32 _t22 = const 1; - 1 32 _t23 = op select_32 _t16 _t20 _t22; - 1 32 _t25 = const 0; - 1 32 _t26 = op div_s_32 _t10 _t23 _t25; - 1 32 _t28 = const 4294967295; - 1 32 _t29 = op select_32 _t6 _t26 _t28; - 1 32 _t30 = input 2; - 1 = write XRegs _t30 _t29; -- :name: divu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33574963 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_42 - :constraint_decode: constraint_45 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 0; - 1 32 _t4 = read XRegs _t3; - 1 32 _t5 = const 0; - 1 1 _t6 = op ne_32 _t4 _t5; - 1 32 _t9 = input 1; - 1 32 _t10 = read XRegs _t9; - 1 32 _t13 = input 0; - 1 32 _t14 = read XRegs _t13; - 1 32 _t15 = const 0; - 1 1 _t16 = op ne_32 _t14 _t15; - 1 32 _t19 = input 0; - 1 32 _t20 = read XRegs _t19; - 1 32 _t22 = const 1; - 1 32 _t23 = op select_32 _t16 _t20 _t22; - 1 32 _t25 = const 0; - 1 32 _t26 = op div_u_32 _t10 _t23 _t25; - 1 32 _t28 = const 4294967295; - 1 32 _t29 = op select_32 _t6 _t26 _t28; - 1 32 _t30 = input 2; - 1 = write XRegs _t30 _t29; -- :name: rem - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33579059 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_43 - :constraint_decode: constraint_46 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op rem_s_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; -- :name: remu - :attributes: [] - :operand_sizes: - - 32 - - 32 - - 32 - :operand_names: - - rs2 - - rs1 - - rd - :encoding: - :encoded_size: 32 - :const_encoding_part: 33583155 - :const_mask: 4261441663 - :decode: - - decode_2 - - decode_3 - - decode_0 - :encode: encode_44 - :constraint_decode: constraint_47 - :constraint_encode: '' - :semantic: | - 1 32 _t3 = input 1; - 1 32 _t4 = read XRegs _t3; - 1 32 _t7 = input 0; - 1 32 _t8 = read XRegs _t7; - 1 32 _t10 = op rem_u_32 _t4 _t8; - 1 32 _t11 = input 2; - 1 = write XRegs _t11 _t10; From 6562235c887de117a1cfd0d3040a862b919c26f9 Mon Sep 17 00:00:00 2001 From: uslstenn Date: Wed, 24 Jun 2026 16:37:15 +0300 Subject: [PATCH 74/75] [simgen] Simgen sync w/ LIRA lib update --- sim_gen_lira/Target/RV32I/cpp_ops.rb | 55 ++++++++++++++++++++++++++++ sim_gen_lira/cpp_ops.rb | 6 +-- sim_gen_lira/sim_gen.rb | 7 +++- 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 sim_gen_lira/Target/RV32I/cpp_ops.rb diff --git a/sim_gen_lira/Target/RV32I/cpp_ops.rb b/sim_gen_lira/Target/RV32I/cpp_ops.rb new file mode 100644 index 0000000..ee585b7 --- /dev/null +++ b/sim_gen_lira/Target/RV32I/cpp_ops.rb @@ -0,0 +1,55 @@ +# sim_gen_lira/Target/RISC-V/cpp_ops.rb +# RISC-V ISA-specific C++ codegen overrides. +# Shift operations mask the shift amount to log2(XLEN) bits (RISC-V spec ยง2.4). + +require_relative '../../cpp_ops' + +module Lira + module CppCodegen + private + + def cpp_type_bits + [1, 8, 16, 32, 64, 128].find { |s| s >= inputs[0] } || 128 + end + end + + class Lsl + def cpp_body + mask = cpp_type_bits - 1 + "b &= #{mask}; return a << b;" + end + end + + class Lsr + def cpp_body + mask = cpp_type_bits - 1 + "b &= #{mask}; return a >> b;" + end + end + + class Asr + def cpp_body + t = Utility::HelperCpp.gen_type(inputs[0]) + ts = Utility::HelperCpp.gen_type(inputs[0], true) + mask = cpp_type_bits - 1 + "b &= #{mask}; return (#{t})((#{ts})a >> b);" + end + end + + class Operation + alias_method :cpp_body_base, :cpp_body + + def cpp_body + case semantic_base + when BaseOp::LSL then "b &= #{cpp_type_bits - 1}; return a << b;" + when BaseOp::LSR then "b &= #{cpp_type_bits - 1}; return a >> b;" + when BaseOp::ASR + t = Utility::HelperCpp.gen_type(inputs[0]) + ts = Utility::HelperCpp.gen_type(inputs[0], true) + "b &= #{cpp_type_bits - 1}; return (#{t})((#{ts})a >> b);" + else + cpp_body_base + end + end + end +end diff --git a/sim_gen_lira/cpp_ops.rb b/sim_gen_lira/cpp_ops.rb index 08f5cd3..00654af 100644 --- a/sim_gen_lira/cpp_ops.rb +++ b/sim_gen_lira/cpp_ops.rb @@ -37,8 +37,8 @@ def cpp_body when BaseOp::ULE then 'return (a <= b) ? 1 : 0;' when BaseOp::UGT then 'return (a > b) ? 1 : 0;' when BaseOp::UGE then 'return (a >= b) ? 1 : 0;' - when BaseOp::LSL then "b &= #{inputs[0] - 1}; return a << b;" - when BaseOp::LSR then "b &= #{inputs[0] - 1}; return a >> b;" + when BaseOp::LSL then "return a << b;" + when BaseOp::LSR then "return a >> b;" when BaseOp::ASR then asr_body when BaseOp::DIV_U then 'return (b == 0) ? c : a / b;' when BaseOp::DIV_S then div_s_body @@ -71,7 +71,7 @@ def signed_cmp(op) def asr_body t = Utility::HelperCpp.gen_type(inputs[0]) ts = Utility::HelperCpp.gen_type(inputs[0], true) - "b &= #{inputs[0] - 1}; return (#{t})((#{ts})a >> b);" + "return (#{t})((#{ts})a >> b);" end def div_s_body diff --git a/sim_gen_lira/sim_gen.rb b/sim_gen_lira/sim_gen.rb index e1fe51c..c25f578 100644 --- a/sim_gen_lira/sim_gen.rb +++ b/sim_gen_lira/sim_gen.rb @@ -3,6 +3,11 @@ $LOAD_PATH.unshift File.dirname(__FILE__) +require_relative '../lib/lira/arch_ser_yaml' + +arch = Lira::ArchSerYaml.read_arch(ARGV[0]) +require "Target/#{arch.name}/cpp_ops" + require_relative 'cpp_gen' require_relative 'base_ops_gen' require_relative 'snippets_gen' @@ -13,9 +18,7 @@ require_relative 'ExecEngines/naive_interpreter' require_relative 'ExecEngines/base_exec_engine' require_relative 'Hart/hart' -require_relative '../lib/lira/arch_ser_yaml' -arch = Lira::ArchSerYaml.read_arch(ARGV[0]) LiraCppGen::OpRegistry.ops = arch.operations.to_h { |op| [op.name, op] } File.write('cpu_state.hh', SimGen::CPUState::Header.generate_cpu_state(arch)) From 5622f6365c682025216d0310e340af88aba48d91 Mon Sep 17 00:00:00 2001 From: milkicow Date: Thu, 25 Jun 2026 19:30:41 +0300 Subject: [PATCH 75/75] [ser] Fix LIRA encode generation - Fix bug with field hi & lo bits - Fix processing for split imm e.g. imm11_5 --- lib/lira_gen.rb | 111 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/lib/lira_gen.rb b/lib/lira_gen.rb index 4a49e37..88a2fce 100644 --- a/lib/lira_gen.rb +++ b/lib/lira_gen.rb @@ -1,5 +1,5 @@ # lira/lira_gen.rb -#!/usr/bin/env ruby +# !/usr/bin/env ruby require_relative 'ADL/base' require_relative 'ADL/builder' @@ -98,9 +98,12 @@ def handle(stmt) class AluOpHandler < StmtHandler def handle(stmt) - name, oprnds = stmt.name, stmt.oprnds - a, b = resolved(oprnds[1]), resolved(oprnds[2]) + name = stmt.name + oprnds = stmt.oprnds + a = resolved(oprnds[1]) + b = resolved(oprnds[2]) return if a.nil? || b.nil? + lhs_signed = oprnds[1].type.to_s.start_with?('s') store(oprnds[0], ser.op_alu(name, lhs_signed, a, b)) end @@ -108,9 +111,12 @@ def handle(stmt) class CmpOpHandler < StmtHandler def handle(stmt) - name, oprnds = stmt.name, stmt.oprnds - a, b = resolved(oprnds[1]), resolved(oprnds[2]) + name = stmt.name + oprnds = stmt.oprnds + a = resolved(oprnds[1]) + b = resolved(oprnds[2]) return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') store(oprnds[0], ser.op_cmp(name, unsigned, a, b)) end @@ -119,24 +125,30 @@ def handle(stmt) class SelectHandler < StmtHandler def handle(stmt) oprnds = stmt.oprnds - cond, t, f = resolved(oprnds[1]), resolved(oprnds[2]), resolved(oprnds[3]) + cond = resolved(oprnds[1]) + t = resolved(oprnds[2]) + f = resolved(oprnds[3]) return if cond.nil? || t.nil? || f.nil? + store(oprnds[0], builder.select(cond, t, f)) end end class CastHandler < StmtHandler def handle(stmt) - name, oprnds = stmt.name, stmt.oprnds + name = stmt.name + oprnds = stmt.oprnds src = resolved(oprnds[1]) return if src.nil? + store(oprnds[0], ser.widen_or_truncate(name, oprnds[0].type, src, oprnds[1].type)) end end class DecodeCastHandler < StmtHandler def handle(stmt) - name, oprnds = stmt.name, stmt.oprnds + name = stmt.name + oprnds = stmt.oprnds lhs, rhs = oprnds src = vars[rhs] if src @@ -156,7 +168,9 @@ def handle(stmt) oprnds = stmt.oprnds val = resolved(oprnds[1]) return if val.nil? - hi, lo = oprnds[2].value, oprnds[3].value + + hi = oprnds[2].value + lo = oprnds[3].value width = hi - lo + 1 width = 1 if width < 1 store(oprnds[0], builder.extract_low(val, width)) @@ -187,8 +201,10 @@ def handle(stmt) class WriteRegHandler < StmtHandler def handle(stmt) oprnds = stmt.oprnds - reg_var, val = oprnds[0], resolved(oprnds[1]) + reg_var = oprnds[0] + val = resolved(oprnds[1]) return if val.nil? + idx = operand_names.index(reg_var.name.to_s) if idx reg_num = builder.input(idx, ADLToLiraUtils.convert_type(reg_var.type)) @@ -218,6 +234,7 @@ def handle(stmt) out_type = ADLToLiraUtils.convert_type(oprnds[0].type) addr = resolved(oprnds[1]) return if addr.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, stmt.attrs.to_s, [addr.width], [out_type]) unless ef warn "Environment function #{stmt.attrs} wasn't registered, skipping statement" @@ -230,8 +247,10 @@ def handle(stmt) class WriteMemHandler < StmtHandler def handle(stmt) oprnds = stmt.oprnds - addr, val = resolved(oprnds[0]), resolved(oprnds[1]) + addr = resolved(oprnds[0]) + val = resolved(oprnds[1]) return if addr.nil? || val.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, stmt.attrs.to_s, [addr.width, val.width], []) unless ef warn "Environment function #{stmt.attrs} wasn't registered, skipping statement" @@ -245,6 +264,7 @@ class BranchHandler < StmtHandler def handle(stmt) target = resolved(stmt.oprnds[0]) return if target.nil? + ef = ADLToLiraUtils.find_env_func(arch_builder, 'setPC', [32], []) unless ef warn "Environment function 'setPC' not registered, skipping statement" @@ -268,8 +288,10 @@ def handle(stmt) class RemHandler < StmtHandler def handle(stmt) oprnds = stmt.oprnds - a, b = resolved(oprnds[1]), resolved(oprnds[2]) + a = resolved(oprnds[1]) + b = resolved(oprnds[2]) return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') store(oprnds[0], unsigned ? builder.rem_u(a, b) : builder.rem_s(a, b)) end @@ -278,8 +300,10 @@ def handle(stmt) class DivHandler < StmtHandler def handle(stmt) oprnds = stmt.oprnds - a, b = resolved(oprnds[1]), resolved(oprnds[2]) + a = resolved(oprnds[1]) + b = resolved(oprnds[2]) return if a.nil? || b.nil? + unsigned = oprnds[1].type.to_s.start_with?('u') default_val = builder.const(0, a.width) store(oprnds[0], unsigned ? builder.div_u(a, b, default_val) : builder.div_s(a, b, default_val)) @@ -322,13 +346,13 @@ def handle(stmt) sysCall: SysCallHandler, rem: RemHandler, - div: DivHandler, + div: DivHandler }.freeze DECODE_HANDLER_MAP = HANDLER_MAP.merge( let: DecodeLetHandler, cast: DecodeCastHandler, - zext: DecodeCastHandler, + zext: DecodeCastHandler ).freeze attr_reader :builder, :vars, :operand_names, :arch_builder @@ -379,6 +403,7 @@ def widen_or_truncate(name, dest_type, src, src_type) src_expected_width = ADLToLiraUtils.convert_type(src_type) src = @builder.extract_low(src, src_expected_width) if src.width > src_expected_width return src if src.width == dest_width + if name == :zext || dest_type.to_s.start_with?('u') @builder.extend_zero(src, dest_width) else @@ -436,6 +461,7 @@ def generate_decode_snippets(instr, operand_vars) op_scope.tree.each do |stmt| handler_class = DECODE_HANDLER_MAP[stmt.name] next unless handler_class + handler_class.new(self).handle(stmt) end @@ -475,8 +501,8 @@ def generate_encode_snippet(instr, operand_vars) base = @builder.const(0, 32) instr.fields.each do |field| - lo = field.from - hi = field.to + hi = field.from + lo = field.to width = hi - lo + 1 width = 1 if width < 1 field_var_name = field.value.name.to_s @@ -487,11 +513,33 @@ def generate_encode_snippet(instr, operand_vars) shifted = @builder.lsl(const_val, @builder.const(lo, 32)) base = @builder.orr(base, shifted) elsif field_var_name =~ /^f_(.+)$/ - operand_name = $1 + rest = $1 + op_high = op_low = nil + operand_name = rest + + # Split immediate fields encode a sub-range of the single `imm` + # operand: `f_imm11_5` -> imm[11:5], `f_imm12` -> imm[12]. + if rest =~ /^imm(\d+)_(\d+)$/ + op_high = ::Regexp.last_match(1).to_i + op_low = ::Regexp.last_match(2).to_i + operand_name = 'imm' + elsif rest =~ /^imm(\d+)$/ + op_high = op_low = ::Regexp.last_match(1).to_i + operand_name = 'imm' + end + idx = operand_vars.index { |v| v.name.to_s == operand_name } if idx op_val = operand_values[idx] op_val = @builder.extend_zero(op_val, 32) if op_val.width < 32 + + # Extract imm[op_high:op_low] before placing it at the field offset. + if op_low + op_val = @builder.lsr(op_val, @builder.const(op_low, 32)) if op_low != 0 + mask = (1 << (op_high - op_low + 1)) - 1 + op_val = @builder.and_(op_val, @builder.const(mask, 32)) + end + shifted = @builder.lsl(op_val, @builder.const(lo, 32)) base = @builder.orr(base, shifted) end @@ -556,12 +604,8 @@ def convert_instruction(instr) decode_snippets = [] encode_snippet = '' - if !instr.operand_map.empty? && operand_vars.any? - decode_snippets = generate_decode_snippets(instr, operand_vars) - end - if instr.fields.any? && operand_vars.any? - encode_snippet = generate_encode_snippet(instr, operand_vars) - end + decode_snippets = generate_decode_snippets(instr, operand_vars) if !instr.operand_map.empty? && operand_vars.any? + encode_snippet = generate_encode_snippet(instr, operand_vars) if instr.fields.any? && operand_vars.any? const_part = 0 const_mask = 0 @@ -578,7 +622,8 @@ def convert_instruction(instr) operand_sizes = operand_vars.map { |v| ADLToLiraUtils.convert_type(v.type) } constraint_decode = generate_constraint_snippet(const_part, const_mask) - encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, encode_snippet, constraint_decode, '') + encoding = Lira::InstructionEncoding.new(32, const_part, const_mask, decode_snippets, encode_snippet, + constraint_decode, '') Lira::Instruction.new(instr.name.to_s, [], operand_sizes, operand_names, encoding, semantic) ensure @current_instr = nil @@ -608,12 +653,10 @@ def build_arch @arch_builder.add_env_func(Lira::EnvironmentFunction.new('setPC', [], [32], [])) SimInfra.class_variable_get(:@@instructions).each do |instr| - begin - lira_instr = convert_instruction(instr) - @arch_builder.add_instruction(lira_instr) - rescue => e - warn "Skipping #{instr.name}: #{e}" - end + lira_instr = convert_instruction(instr) + @arch_builder.add_instruction(lira_instr) + rescue StandardError => e + warn "Skipping #{instr.name}: #{e}" end @ops_used.each_value do |op| @@ -651,7 +694,7 @@ def extract_arch_name(_loaded_modules) def main options = { - output: 'lira.yaml', + output: 'lira.yaml' } OptionParser.new do |opts| @@ -677,6 +720,4 @@ def main puts "Serialized architecture to #{options[:output]}" end -if __FILE__ == $0 - main -end +main if __FILE__ == $0