diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..644b6f7c59513114c9b34ae9ab96075ad3f2f74a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1746 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy 0.5.2", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.0", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.3.2", + "async-lock 3.3.0", + "blocking", + "futures-lite 2.3.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.0", + "rustix 0.38.34", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blocking" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +dependencies = [ + "async-channel 2.3.1", + "async-lock 3.3.0", + "async-task", + "futures-io", + "futures-lite 2.3.0", + "piper", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cactus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbc26382d871df4b7442e3df10a9402bf3cf5e55cbd66f12be38861425f0564" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfgrammar" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163348850b1cd34fa99ef1592b5d598ea7e6752f18aff2125b67537e887edb36" +dependencies = [ + "indexmap", + "lazy_static", + "num-traits", + "regex", + "serde", + "vob", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hercules_cg" +version = "0.1.0" +dependencies = [ + "bitvec", + "hercules_ir", +] + +[[package]] +name = "hercules_driver" +version = "0.1.0" +dependencies = [ + "clap", + "hercules_ir", + "hercules_opt", + "ron", +] + +[[package]] +name = "hercules_hbin_dump" +version = "0.1.0" +dependencies = [ + "clap", + "hercules_ir", + "postcard", + "serde", +] + +[[package]] +name = "hercules_ir" +version = "0.1.0" +dependencies = [ + "bitvec", + "nom", + "ordered-float", + "rand", + "serde", +] + +[[package]] +name = "hercules_matmul" +version = "0.1.0" +dependencies = [ + "async-std", + "clap", + "hercules_rt", + "rand", +] + +[[package]] +name = "hercules_opt" +version = "0.1.0" +dependencies = [ + "bitvec", + "hercules_cg", + "hercules_ir", + "ordered-float", + "postcard", + "serde", + "take_mut", +] + +[[package]] +name = "hercules_rt" +version = "0.1.0" +dependencies = [ + "hercules_rt_proc", + "libc", + "postcard", + "serde", +] + +[[package]] +name = "hercules_rt_proc" +version = "0.1.0" +dependencies = [ + "anyhow", + "hercules_ir", + "postcard", + "serde", +] + +[[package]] +name = "hercules_task_parallel" +version = "0.1.0" +dependencies = [ + "async-std", + "clap", + "hercules_rt", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "juno_frontend" +version = "0.1.0" +dependencies = [ + "cfgrammar", + "clap", + "hercules_ir", + "hercules_opt", + "lrlex", + "lrpar", + "num-rational", + "num-traits", + "ordered-float", + "phf", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "value-bag", +] + +[[package]] +name = "lrlex" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ff18e1bd3ed77d7bc2800a0f8b0e922a3c7ba525505be8bab9cf45dfc4984b" +dependencies = [ + "cfgrammar", + "getopts", + "lazy_static", + "lrpar", + "num-traits", + "quote", + "regex", + "regex-syntax", + "serde", + "vergen", +] + +[[package]] +name = "lrpar" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efea5a41b9988b5ae41ea9b2375a52cfa0e483f0210357209caa8d361a24a368" +dependencies = [ + "bincode", + "cactus", + "cfgrammar", + "filetime", + "indexmap", + "lazy_static", + "lrtable", + "num-traits", + "packedvec", + "regex", + "serde", + "static_assertions", + "vergen", + "vob", +] + +[[package]] +name = "lrtable" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff5668c3bfd279ed24d5b0d24568c48dc993f9beabd51f74d1865a78c1d206ab" +dependencies = [ + "cfgrammar", + "fnv", + "num-traits", + "serde", + "sparsevec", + "vob", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ordered-float" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "packedvec" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde3c690ec20e4a2b4fb46f0289a451181eb50011a1e2acc8d85e2fde9062a45" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" +dependencies = [ + "atomic-waker", + "fastrand 2.1.0", + "futures-io", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 0.38.34", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "heapless", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64", + "bitflags 2.5.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sparsevec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35df5d2e580b29f3f7ec5b4ed49b0ab3acf7f3624122b3e823cafb9630f293b8" +dependencies = [ + "num-traits", + "packedvec", + "serde", + "vob", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + +[[package]] +name = "vergen" +version = "8.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525" +dependencies = [ + "anyhow", + "rustversion", + "time", +] + +[[package]] +name = "vob" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c058f4c41e71a043c67744cb76dcc1ae63ece328c1732a72489ccccc2dec23e6" +dependencies = [ + "num-traits", + "rustc_version", + "serde", +] + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/Cargo.toml b/Cargo.toml index ba6ffb28f3a8dacd63344252d110323885ba12e2..936803f2646b209c4b0ac5269070318787932610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,7 @@ members = [ "hercules_rt_proc", "hercules_tools/hercules_driver", - "hercules_tools/hercules_dot", - "hercules_tools/hercules_cpu_beta", + "hercules_tools/hercules_hbin_dump", "juno_frontend", diff --git a/DESIGN.md b/DESIGN.md deleted file mode 100644 index 841a05f91c372fbb5e61425be143edd3bd849c1e..0000000000000000000000000000000000000000 --- a/DESIGN.md +++ /dev/null @@ -1,68 +0,0 @@ -# Hercules' Design - -Hercules' is a compiler targeting heterogenous devices. The key goals of Hercules are listed below: - -- Generate optimized, memory efficient, and parallel code for devices containing CPUs, GPUs, and other processing elements. -- Explore language design for programming heterogenous systems in a performant, expressive, and safe manner. -- Expose detailed configuration of code generation and scheduling through a novel scheduling language. -- Design an intermediate representation that allows for fine-grained control of what code is executed on what device in a system. -- Develop a runtime system capable of dynamically scheduling generated code fragments on a heterogenous machine. - -The following sections contain information on how Hercules is designed to meet these goals. - -## Front-end Language Design - -The front-end language Juno is a relatively standard imperative programming language based on Rust syntax, though using Mutual Value Semantics and making certain restrictions useful for compiling of to heterogeneous systems. -More information about Juno can be found in [juno_frontend/README.md](juno_frontend/README.md). - -## Scheduling Language Design - -TODO: @aaronjc4 - -## Compiler Design - -The Hercules' compiler is split into the following components: - -### Hercules IR - -The IR of the Hercules compiler is similar to the sea of nodes IR presented in "A Simple Graph-Based Intermediate Representation", with a few differences. - -- There are dynamic constants, which are constants provided dynamically to the conductor (this is the runtime system, [see the section describing the conductor](#the-conductor)) - these can be used to specify array type sizes, unlike normal runtime values. -- There is no single global store. The closest analog are individual values with an array type, which support dynamically indexed read and write operations. -- There is no I/O, or other side effects. -- There is no recursion. -- The implementation of Hercules IR does not follow the original object oriented design of sea-of-nodes. - -A key design consideration of Hercules IR is the absence of a concept of memory. A downside of this approach is that any language targetting Hecules IR must also be very restrictive regarding memory - in practice, this means tightly controlling or eliminating first-class references. The upside is that the compiler has complete freedom to layout data however it likes in memory when performing code generation. This includes deciding which data resides in which address spaces, which is a necessary ability for a compiler striving to have fine-grained control over what operations are computed on what devices. - -In addition to not having a generalized memory, Hercules IR has no functionality for calling functions with side-effects, or doing IO. In other words, Hercules is a pure IR (it's not functional, as functions aren't first class values). This may be changed in the future - we could support effectful programs by giving call operators a control input and output edge. However, at least for now, we'd like to work with the simplest IR possible, so the IR is pure. - -The key idea behind the sea of nodes IR is that control flow and data flow are represented in the same graph. The entire program thus can be represented by one large flow graph. This has several nice properties, the primary of which being that instructions are unordered except by true dependencies. This alleviates most code motion concerns, and also makes peephole optimizations more practical. Additionally, loop invariant code is neither "inside" nor "outside" a loop in the sea of nodes. Thus, any optimizations benefitting from a particular assumption about the position of loop invariant code works without needing to do code motion. Deciding whether code lives inside a loop or not becomes a scheduling concern. - -We chose to use a sea of nodes based IR because we believe it will be easier to partition than a CFG + basic block style IR. A CFG + basic block IR is inherently two-level - there is the control flow level in the CFG, and the data flow in the basic blocks. Partitioning a function across these two levels is a challenging task. As shown by previous work (HPVM), introducing more graph levels into the IR makes partitioning harder, not easier. We want Hercules to have fine-grained control over which code executes where. This requires Hercules' compiler IR to have as few graph levels as reasonable. - -See [IR.md](IR.md) for a more specific description of Hercules IR. - -### Optimizations - -Hercules relies on other compiler infrastructures, such as LLVM, to do code generation for specific devices. Thus, Hercules itself doesn't perform particularly sophisticated optimizations. In general, the optimizations Hercules do are done to make partitioning easier. This includes things like GVN and peephole optimizations, which in general, make the IR "simpler". - -TODO: @rarbore2 - -### Partitioning - -Partitioning is responsible for deciding which operations in the IR graph are executed on which devices. Additionally, operations are broken up into shards - every node in a shard executes on the same device, and the runtime system schedules execution at the shard level. Partitioning is conceptually very similar to instruction selection. Each shard can be thought of as a single instruction, and the device the shard is executed on can be thought of as the particular instruction being selected. In instruction selection, there is not only the choice of which instructions to use, but also how to partition the potentially many operations in the IR into a smaller number of target instructions. Similarly, the Hercules IR partitioning process must decide which operations are grouped together into the same shard, and for each shard, which device it should execute on. The set of operations each potential target device is capable of executing is crucial information when forming the shard boundaries, so this cannot be performed optimally as a sequential two step process. - -TODO: @rarbore2 - -### Code Generation - -Hercules uses LLVM for generating CPU and GPU code. Memory is "introduced" into the program representation at this stage. Operations in a function are separated into basic blocks. The data layout of values is decided on, and memory is allocated on the stack or is designated as separately allocated and passed into functions as necessary. Code is generated corresponding to possibly several estimates of dynamic constants. - -TODO: @rarbore2 - -## The Conductor - -The conductor is responsible for dynamically executing code generated by Hercules. It exposes a Rust API for executing Hercules code. It takes care of memory allocation, synchronization, and scheduling. It is what is called the "runtime" in other systems - we chose a different name as there are events that happen distinctly as "conductor time" (such as providing dynamic constants), rather than at "runtime" (where the generated code is actually executed). - -TODO: @rarbore2 diff --git a/README.md b/README.md index 32a3a13692e69077341ab88f56ddf0257ddc472a..cd6795b70c998d587e332d3f6239b152d3af24be 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Hercules -See [DESIGN.md](DESIGN.md) for a discussion of Hercules' design. +See `reports/` for discussions of Hercules' design. diff --git a/hercules_cg/src/common.rs b/hercules_cg/src/common.rs index f3d5a89d05e9fda42ed09ecc43b092b819f7a9a6..e3e1a3c4e6ebc7f2e11fba5270f82ec25e840d6a 100644 --- a/hercules_cg/src/common.rs +++ b/hercules_cg/src/common.rs @@ -1,6 +1,7 @@ extern crate hercules_ir; use std::collections::HashMap; +use std::iter::repeat; use self::hercules_ir::*; @@ -258,6 +259,27 @@ impl<'a> FunctionContext<'a> { res.sort(); res } + + /* + * Determine the array numbers for all the array constants. These are needed + * to know which pointer passed to the runtime corresponds to which array + * constant. Return a map from constant ID to array number - non-array + * constants don't have an array number. + */ + pub(crate) fn array_constant_inputs(&self) -> Vec<Option<u32>> { + self.constants + .iter() + .scan(0, |num, cons| { + if cons.try_array_type(self.types).is_some() { + let res = Some(*num); + *num += 1; + Some(res) + } else { + Some(None) + } + }) + .collect() + } } /* @@ -327,14 +349,12 @@ impl<'a> PartitionContext<'a> { // Assemble the manifest. let mut manifest = PartitionManifest::default(); - manifest.top_node = top_node.idx() as u32; + manifest.top_node = top_node; // The first inputs are the data inputs, from other partitions. - manifest.inputs.extend( - data_inputs - .iter() - .map(|x| PartitionInput::DataInput(x.idx() as u32)), - ); + manifest + .inputs + .extend(data_inputs.iter().map(|x| PartitionInput::DataInput(*x))); // The next inputs are the function parameters, all in order. manifest.inputs.extend( @@ -342,7 +362,9 @@ impl<'a> PartitionContext<'a> { .map(|x| PartitionInput::FunctionArgument(x as u32)), ); - // The next inputs are the array constants, all in order. + // The next inputs are the array constants, all in order. TODO: only + // include constant inputs for constants actually used by this function, + // not all the constants in the module. manifest.inputs.extend( (0..(function .constants @@ -359,11 +381,9 @@ impl<'a> PartitionContext<'a> { ); // The outputs are the data outputs of this partition. - manifest.outputs.extend( - data_outputs - .iter() - .map(|x| PartitionOutput::DataOutput(x.idx() as u32)), - ); + manifest + .outputs + .extend(data_outputs.iter().map(|x| PartitionOutput::DataOutput(*x))); // If there are multiple control returns, also output the node being // returned from. @@ -374,7 +394,7 @@ impl<'a> PartitionContext<'a> { // Store the successor partitions. manifest.successor_partitions = control_successors .into_iter() - .map(|(part_id, control_id)| (control_id.idx() as u32, part_id.idx() as u32)) + .map(|(part_id, control_id)| (control_id, part_id)) .collect(); PartitionContext { @@ -423,13 +443,13 @@ pub(crate) fn generate_type_string(ty: &Type, llvm_types: &Vec<String>) -> Strin "{}".to_string() } } + Type::Summation(_) => todo!(), Type::Array(_, _) => { // Array types becomes pointers. The element type and dynamic // constant bounds characterize the access code we generate later, // not the type itself. "ptr".to_string() } - Type::Summation(_) => todo!(), } } @@ -524,3 +544,194 @@ pub(crate) fn generate_dynamic_constant_strings(module: &Module) -> Vec<String> llvm_dynamic_constants } + +/* + * Calculate in-memory size and alignment of a type. The size is optional, since + * array types with dynamic constant dimensions may not have a compile time + * known size. + */ +pub fn type_size_and_alignment(module: &Module, ty: TypeID) -> (Option<usize>, usize) { + match module.types[ty.idx()] { + Type::Control(_) => { + panic!("PANIC: Can't calculate in-memory size and alignment of control type.") + } + Type::Boolean => (Some(1), 1), + Type::Integer8 => (Some(1), 1), + Type::Integer16 => (Some(2), 2), + Type::Integer32 => (Some(4), 4), + Type::Integer64 => (Some(8), 8), + Type::UnsignedInteger8 => (Some(1), 1), + Type::UnsignedInteger16 => (Some(2), 2), + Type::UnsignedInteger32 => (Some(4), 4), + Type::UnsignedInteger64 => (Some(8), 8), + Type::Float32 => (Some(4), 4), + Type::Float64 => (Some(8), 8), + Type::Product(ref fields) => { + let (size, align) = fields + .iter() + .map(|ty| type_size_and_alignment(module, *ty)) + .fold( + (Some(0), 1), + |(acc_size, acc_align), (field_size, field_align)| { + // Alignment of product is maximum alignment of fields. + let new_align = std::cmp::max(acc_align, field_align); + if let (Some(acc_size), Some(field_size)) = (acc_size, field_size) { + // Pre-padding is so that the new field has proper + // alignment within the product. + let mut pre_padding = field_align - acc_size % field_align; + if pre_padding == field_align { + pre_padding = 0; + } + (Some(acc_size + pre_padding + field_size), new_align) + } else { + (None, new_align) + } + }, + ); + + if let Some(size) = size { + // Post-padding is so that the overall in-memory size has the + // right alignment in an array, and is only done at the end. + let mut post_padding = align - size % align; + if post_padding == align { + post_padding = 0; + } + (Some(size + post_padding), align) + } else { + (None, align) + } + } + Type::Summation(_) => todo!(), + Type::Array(elem, ref dims) => { + let (maybe_elem_size, elem_align) = type_size_and_alignment(module, elem); + + // We can only calculate the number of elements at compile time if + // every dynamic constant dimension is a compile-time constant. + let maybe_num_elems = dims.iter().fold(Some(1), |acc, dim| { + Some(acc? * module.dynamic_constants[dim.idx()].try_constant()?) + }); + + // Even if the number of elements is compile-time known, the element + // type may have unknown compile-time size. + if let (Some(elem_size), Some(num_elems)) = (maybe_elem_size, maybe_num_elems) { + (Some(elem_size * num_elems), elem_align) + } else { + (None, elem_align) + } + } + } +} + +/* + * Calculate in-memory bytes representing constant. Return the in-memory bytes + * and the alignment of the constant, if it's non-zero. If it's zero, optionally + * return the size of the constant, and its alignment. TODO: decide on how to + * represent memory layouts at the compiler level. + */ +pub fn embed_constant(module: &Module, cons: ConstantID) -> ConstantBytes { + let unchecked = match module.constants[cons.idx()] { + // Handle zero constant scalars below. + Constant::Boolean(v) => ConstantBytes::NonZero(vec![v as u8], 1), + Constant::Integer8(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 1), + Constant::Integer16(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 2), + Constant::Integer32(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 4), + Constant::Integer64(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 8), + Constant::UnsignedInteger8(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 1), + Constant::UnsignedInteger16(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 2), + Constant::UnsignedInteger32(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 4), + Constant::UnsignedInteger64(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 8), + Constant::Float32(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 4), + Constant::Float64(v) => ConstantBytes::NonZero(v.to_ne_bytes().to_vec(), 8), + Constant::Product(ty, ref fields) => { + let field_bytes: Vec<ConstantBytes> = fields + .iter() + .map(|field| embed_constant(module, *field)) + .collect(); + + if field_bytes.iter().all(|cb| { + if let ConstantBytes::Zero(_, _) = cb { + true + } else { + false + } + }) { + // If all of the fields are zero constants, then this is a zero + // constant. + let (size, align) = type_size_and_alignment(module, ty); + ConstantBytes::Zero(size, align) + } else { + // We only construct the in-memory bytes if there is a non-zero + // bytes somewhere. + let (mut bytes, align) = field_bytes.into_iter().fold( + (vec![], 0), + |(mut acc_bytes, acc_align), field| { + // Alignment of product is maximum alignment of fields. + let new_align = std::cmp::max(acc_align, field.align()); + + // Pre-padding is so that the new field has proper + // alignment within the product. + while acc_bytes.len() % field.align() != 0 { + acc_bytes.push(0); + } + match field { + ConstantBytes::NonZero(bytes, _) => acc_bytes.extend(&bytes), + ConstantBytes::Zero(size, _) => acc_bytes.extend(repeat(0).take(size.expect("PANIC: Attempted to embed a zero constant with unknown size into a non-zero constant product. Non-zero constants must have compile-time known size. This is probably because an array field is a zero constant with non-constant dynamic constant dimensions."))), + } + (acc_bytes, new_align) + }, + ); + + // Post-padding is so that the overall in-memory vector has the + // right size, and is only done at the end. + while bytes.len() % align != 0 { + bytes.push(0); + } + ConstantBytes::NonZero(bytes, align) + } + } + Constant::Summation(_, _, _) => todo!(), + Constant::Array(ty, ref elements) => { + let element_bytes: Vec<ConstantBytes> = elements + .iter() + .map(|element| embed_constant(module, *element)) + .collect(); + + let (size, align) = type_size_and_alignment(module, ty); + if element_bytes.iter().all(|cb| { + if let ConstantBytes::Zero(_, _) = cb { + true + } else { + false + } + }) { + // If all of the fields are zero constants, then this is a zero + // constant. + ConstantBytes::Zero(size, align) + } else { + let array_bytes: Vec<u8> = element_bytes + .into_iter() + .map(|cb| match cb { + ConstantBytes::NonZero(bytes, _) => bytes, + ConstantBytes::Zero(size, _) => vec![0; size.expect("PANIC: Attempted to embed a zero constant with unknown size into a non-zero constant array. Non-zero constants must have compile-time known size. This is probably because an array element is a zero constant with non-constant dynamic constant dimensions.")], + }) + .flatten() + .collect(); + assert_eq!(array_bytes.len(), size.expect("PANIC: Size of a non-zero constant array is unknown at compile time. All non-zero constants must have compile time known size."), "PANIC: Size of array type calculated by type_size_and_alignment differs from calculated in-memory byte representation's size."); + ConstantBytes::NonZero(array_bytes, align) + } + } + Constant::Zero(ty) => { + let (size, align) = type_size_and_alignment(module, ty); + ConstantBytes::Zero(size, align) + } + }; + + // Catch all code for making zero constant scalars actually + // ConstantBytes::Zero variants. + if let ConstantBytes::NonZero(bytes, align) = &unchecked { + if module.constants[cons.idx()].is_strictly_scalar() && bytes.iter().all(|x| *x == 0) { + return ConstantBytes::Zero(Some(bytes.len()), *align); + } + } + unchecked +} diff --git a/hercules_cg/src/cpu_beta.rs b/hercules_cg/src/cpu_beta.rs deleted file mode 100644 index 1a5631437adf46ea9c7db578157d6aedbdf1d9de..0000000000000000000000000000000000000000 --- a/hercules_cg/src/cpu_beta.rs +++ /dev/null @@ -1,812 +0,0 @@ -extern crate bitvec; -extern crate hercules_ir; - -use std::collections::HashMap; -use std::collections::VecDeque; - -use std::fmt::Write; -use std::iter::zip; - -use self::bitvec::prelude::*; - -use self::hercules_ir::def_use::*; -use self::hercules_ir::ir::*; - -/* - * This CPU backend is a rewrite of the original CPU alpha backend. It accounts - * for many changes in the IR designed to make lowering, optimization, and code - * generation easier. - */ - -#[derive(Debug)] -struct LLVMBlock { - header: String, - phis: String, - data: String, - terminator: String, -} - -/* - * Top level function to generate code for a module. Emits LLVM IR text. - */ -pub fn cpu_beta_codegen<W: Write>( - module: &hercules_ir::ir::Module, - typing: &hercules_ir::typecheck::ModuleTyping, - reverse_postorders: &Vec<Vec<NodeID>>, - def_uses: &Vec<ImmutableDefUseMap>, - bbs: &Vec<Vec<NodeID>>, - antideps: &Vec<Vec<(NodeID, NodeID)>>, - fork_join_maps: &Vec<HashMap<NodeID, NodeID>>, - fork_join_nests: &Vec<HashMap<NodeID, Vec<NodeID>>>, - w: &mut W, -) -> std::fmt::Result { - let hercules_ir::ir::Module { - functions, - types, - constants, - dynamic_constants, - } = module; - - // Step 1: render types into LLVM IR. This requires translating from our - // interning structures to LLVM types. We can't just blow through the types - // vector, since a type may reference a type ID ahead of it in the vector. - // Instead, iterate types in a bottom up order with respect to the type - // intern DAGs. - let mut llvm_types = vec!["".to_string(); types.len()]; - for id in module.types_bottom_up() { - match &types[id.idx()] { - Type::Control(_) => { - // Later, we create virtual registers corresponding to fork - // nodes of type i64, so we need the "type" of the fork node - // to be i64. - llvm_types[id.idx()] = "i64".to_string(); - } - Type::Boolean => { - llvm_types[id.idx()] = "i1".to_string(); - } - Type::Integer8 | Type::UnsignedInteger8 => { - llvm_types[id.idx()] = "i8".to_string(); - } - Type::Integer16 | Type::UnsignedInteger16 => { - llvm_types[id.idx()] = "i16".to_string(); - } - Type::Integer32 | Type::UnsignedInteger32 => { - llvm_types[id.idx()] = "i32".to_string(); - } - Type::Integer64 | Type::UnsignedInteger64 => { - llvm_types[id.idx()] = "i64".to_string(); - } - Type::Float32 => { - llvm_types[id.idx()] = "float".to_string(); - } - Type::Float64 => { - llvm_types[id.idx()] = "double".to_string(); - } - // Because we traverse in bottom-up order, we can assume that the - // LLVM types for children types are already computed. - Type::Product(fields) => { - let mut iter = fields.iter(); - if let Some(first) = iter.next() { - llvm_types[id.idx()] = - iter.fold("{".to_string() + &llvm_types[first.idx()], |s, f| { - s + ", " + &llvm_types[f.idx()] - }) + "}"; - } else { - llvm_types[id.idx()] = "{}".to_string(); - } - } - Type::Array(_, _) => { - // Array types becomes pointers. The element type and dynamic - // constant bounds characterize the access code we generate - // later, not the type itself. - llvm_types[id.idx()] = "ptr".to_string(); - } - Type::Summation(_) => todo!(), - } - } - - // Step 2: render constants into LLVM IR. This is done in a very similar - // manner as types. - let mut llvm_constants = vec!["".to_string(); constants.len()]; - fn render_zero_constant(cons_id: ConstantID, ty_id: TypeID, types: &Vec<Type>) -> String { - match &types[ty_id.idx()] { - Type::Control(_) => panic!(), - Type::Boolean => "false".to_string(), - Type::Integer8 - | Type::Integer16 - | Type::Integer32 - | Type::Integer64 - | Type::UnsignedInteger8 - | Type::UnsignedInteger16 - | Type::UnsignedInteger32 - | Type::UnsignedInteger64 => "0".to_string(), - Type::Float32 | Type::Float64 => "0.0".to_string(), - Type::Product(fields) => { - let mut iter = fields.iter(); - if let Some(first) = iter.next() { - iter.fold( - "{".to_string() + &render_zero_constant(cons_id, *first, types), - |s, f| s + ", " + &render_zero_constant(cons_id, *f, types), - ) + "}" - } else { - "{}".to_string() - } - } - Type::Summation(_) => todo!(), - Type::Array(_, _) => format!("%arr.{}", cons_id.idx()), - } - } - - for id in module.constants_bottom_up() { - match &constants[id.idx()] { - Constant::Boolean(val) => { - llvm_constants[id.idx()] = if *val { - "true".to_string() - } else { - "false".to_string() - }; - } - Constant::Integer8(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::Integer16(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::Integer32(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::Integer64(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::UnsignedInteger8(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::UnsignedInteger16(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::UnsignedInteger32(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::UnsignedInteger64(val) => llvm_constants[id.idx()] = format!("{}", val), - Constant::Float32(val) => { - llvm_constants[id.idx()] = if val.fract() == 0.0 { - format!("{}.0", val) - } else { - format!("{}", val) - } - } - Constant::Float64(val) => { - llvm_constants[id.idx()] = if val.fract() == 0.0 { - format!("{}.0", val) - } else { - format!("{}", val) - } - } - Constant::Product(_, fields) => { - let mut iter = fields.iter(); - if let Some(first) = iter.next() { - llvm_constants[id.idx()] = - iter.fold("{".to_string() + &llvm_constants[first.idx()], |s, f| { - s + ", " + &llvm_constants[f.idx()] - }) + "}"; - } else { - llvm_constants[id.idx()] = "{}".to_string(); - } - } - Constant::Array(_, _) => llvm_constants[id.idx()] = format!("%arr.{}", id.idx()), - Constant::Summation(_, _, _) => todo!(), - Constant::Zero(ty_id) => { - llvm_constants[id.idx()] = render_zero_constant(id, *ty_id, types) - } - } - } - - // Step 3: render dynamic constants into LLVM IR. - let mut llvm_dynamic_constants = vec!["".to_string(); dynamic_constants.len()]; - for id in (0..dynamic_constants.len()).map(DynamicConstantID::new) { - match &dynamic_constants[id.idx()] { - DynamicConstant::Constant(val) => llvm_dynamic_constants[id.idx()] = format!("{}", val), - DynamicConstant::Parameter(num) => { - llvm_dynamic_constants[id.idx()] = format!("%dc{}", num) - } - } - } - - // Step 4: generate dummy uninitialized global - this is needed so that - // there'll be a non-empty .bss section in the ELF object file. - write!(w, "@dummy = dso_local global i32 0, align 4\n")?; - - // Step 5: do codegen for each function. - for function_idx in 0..functions.len() { - let function = &functions[function_idx]; - let typing = &typing[function_idx]; - let reverse_postorder = &reverse_postorders[function_idx]; - let def_use = &def_uses[function_idx]; - let bb = &bbs[function_idx]; - let antideps = &antideps[function_idx]; - let fork_join_map = &fork_join_maps[function_idx]; - let fork_join_nest = &fork_join_nests[function_idx]; - - // Step 5.1: emit function signature. - let llvm_ret_type = &llvm_types[function.return_type.idx()]; - let mut llvm_params = function - .param_types - .iter() - .enumerate() - .map(|(idx, id)| format!("{} %p{}", &llvm_types[id.idx()], idx)) - .chain((0..function.num_dynamic_constants).map(|idx| format!("i64 %dc{}", idx))) - .chain( - (0..constants.len()) - .filter(|idx| module.is_array_constant(ConstantID::new(*idx))) - .map(|idx| format!("ptr %arr.{}", idx)), - ); - write!(w, "define {} @{}(", llvm_ret_type, function.name)?; - if let Some(first) = llvm_params.next() { - write!(w, "{}", first)?; - for p in llvm_params { - write!(w, ", {}", p)?; - } - } - write!(w, ") {{\n")?; - - // Step 5.2: emit basic blocks. A node represents a basic block if its - // entry in the basic blocks vector points to itself. Each basic block - // is created as four strings: the block header, the block's phis, the - // block's data computations, and the block's terminator instruction. - let mut llvm_bbs = HashMap::new(); - for id in (0..function.nodes.len()).map(NodeID::new) { - if bb[id.idx()] == id { - llvm_bbs.insert( - id, - LLVMBlock { - header: format!("bb_{}:\n", id.idx()), - phis: "".to_string(), - data: "".to_string(), - terminator: "".to_string(), - }, - ); - } - } - - // Step 5.3: emit nodes. Nodes are emitted into basic blocks separately - // as nodes are not necessarily emitted in order. Assemble worklist of - // nodes, starting as reverse post order of nodes. For non-phi and non- - // reduce nodes, only emit once all data uses are emitted. In addition, - // consider additional anti-dependence edges from read to write nodes. - let mut visited = bitvec![u8, Lsb0; 0; function.nodes.len()]; - let mut worklist = VecDeque::from(reverse_postorder.clone()); - while let Some(id) = worklist.pop_front() { - if !(function.nodes[id.idx()].is_phi() || function.nodes[id.idx()].is_reduce()) - && !get_uses(&function.nodes[id.idx()]) - .as_ref() - .into_iter() - .chain( - antideps.iter().filter_map( - |(read, write)| if id == *write { Some(read) } else { None }, - ), - ) - .all(|x| function.nodes[x.idx()].is_control() || visited[x.idx()]) - { - // Skip emitting node if it's not a phi or reducee node and if - // its data uses are not emitted yet. - worklist.push_back(id); - } else { - // Once all of the data dependencies for this node are emitted, - // this node can be emitted. - emit_llvm_for_node( - id, - function, - typing, - types, - dynamic_constants, - bb, - def_use, - fork_join_map, - fork_join_nest, - &mut llvm_bbs, - &llvm_types, - &llvm_constants, - &llvm_dynamic_constants, - )?; - visited.set(id.idx(), true); - } - } - - // Step 5.4: put basic blocks in order. - for node in reverse_postorder { - if bb[node.idx()] == *node { - write!( - w, - "{}{}{}{}", - llvm_bbs[node].header, - llvm_bbs[node].phis, - llvm_bbs[node].data, - llvm_bbs[node].terminator - )?; - } - } - - // Step 5.5: close function. - write!(w, "}}\n")?; - } - - Ok(()) -} - -/* - * Emit LLVM implementing a single node. - */ -fn emit_llvm_for_node( - id: NodeID, - function: &Function, - typing: &Vec<TypeID>, - types: &Vec<Type>, - dynamic_constants: &Vec<DynamicConstant>, - bb: &Vec<NodeID>, - def_use: &ImmutableDefUseMap, - fork_join_map: &HashMap<NodeID, NodeID>, - fork_join_nest: &HashMap<NodeID, Vec<NodeID>>, - llvm_bbs: &mut HashMap<NodeID, LLVMBlock>, - llvm_types: &Vec<String>, - llvm_constants: &Vec<String>, - llvm_dynamic_constants: &Vec<String>, -) -> std::fmt::Result { - // Helper to get the virtual register corresponding to a node. Overload to - // also emit constants, dynamic constants, parameters, and thread IDs. - // Override writes to use previous non-store pointer, since emitting a store - // doesn't create a new pointer virtual register we should use. If the user - // (current node being emitted) is outside the fork-join nest of a reduce - // node, use the reduct input to the reduce node instead - this is needed to - // not get a value from the loop one iteration too early. - let virtual_register = |mut vid: NodeID| { - while let Node::Reduce { - control, - init: _, - reduct, - } = &function.nodes[vid.idx()] - { - // Figure out the fork corresponding to the associated join. - let fork_id = if let Node::Join { control } = function.nodes[control.idx()] { - if let Type::Control(factors) = &types[typing[control.idx()].idx()] { - *factors.last().unwrap() - } else { - panic!() - } - } else { - panic!() - }; - - if !fork_join_nest[&bb[id.idx()]].contains(&fork_id) { - vid = *reduct; - } else { - break; - } - } - - while let Node::Write { - collect, - indices: _, - data: _, - } = &function.nodes[vid.idx()] - { - vid = *collect; - } - - match function.nodes[vid.idx()] { - Node::Constant { id } => llvm_constants[id.idx()].clone(), - Node::DynamicConstant { id } => llvm_dynamic_constants[id.idx()].clone(), - Node::Parameter { index } => format!("%p{}", index), - Node::ThreadID { control } => format!("%v{}", control.idx()), - _ => format!("%v{}", vid.idx()), - } - }; - let type_of = |id: NodeID| format!("{}", llvm_types[typing[id.idx()].idx()]); - let normal_value = |id: NodeID| format!("{} {}", type_of(id), virtual_register(id)); - - // Helper to emit code to index into an aggregate, and return a pointer to - // the indexed element. This only works when the first aggregate is an - // array. - let mut generate_index_code = |collect: NodeID, indices: &[Index]| { - let extents = types[typing[collect.idx()].idx()].try_extents().unwrap(); - let position = indices[0].try_position().unwrap(); - for (idx, (extent, index_id)) in zip(extents, position).enumerate() { - if idx == 0 { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %index.{}.acc.add.{} = add {}, {}\n", - id.idx(), - idx, - normal_value(*index_id), - 0, - ); - } else { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %index.{}.acc.mul.{} = mul i64 {}, %index.{}.acc.add.{}\n", - id.idx(), - idx, - llvm_dynamic_constants[extent.idx()], - id.idx(), - idx - 1, - ); - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %index.{}.acc.add.{} = add {}, %index.{}.acc.mul.{}\n", - id.idx(), - idx, - normal_value(*index_id), - id.idx(), - idx, - ); - } - } - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %index.{}.ptr = getelementptr {}, {}, i64 %index.{}.acc.add.{}", - id.idx(), - llvm_types[types[typing[collect.idx()].idx()] - .try_element_type() - .unwrap() - .idx()], - normal_value(collect), - id.idx(), - extents.len() - 1 - ); - for index in &indices[1..] { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += - &format!(", i32 {}", index.try_field().unwrap()); - } - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += "\n"; - }; - - // Emit code depending on the type of the node. - match function.nodes[id.idx()] { - Node::Start | Node::Region { preds: _ } => { - let successor = def_use - .get_users(id) - .iter() - .filter(|id| function.nodes[id.idx()].is_strictly_control()) - .next() - .unwrap(); - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = - format!(" br label %bb_{}\n", successor.idx()); - } - Node::If { control: _, cond } => { - let successors = def_use.get_users(id); - let rev = if let Node::Read { - collect: _, - indices, - } = &function.nodes[successors[0].idx()] - { - indices[0] != Index::Control(0) - } else { - panic!() - }; - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = format!( - " br {}, label %bb_{}, label %bb_{}\n", - normal_value(cond), - successors[(!rev) as usize].idx(), - successors[rev as usize].idx() - ); - } - Node::Fork { control, factor: _ } => { - // Calculate the join and successor. - let join = fork_join_map[&id]; - let successor = def_use - .get_users(id) - .iter() - .filter(|id| function.nodes[id.idx()].is_strictly_control()) - .next() - .unwrap(); - - // Need to create phi node for the loop index. - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().phis += &format!( - " {} = phi i64 [ 0, %bb_{} ], [ %fork.{}.inc, %bb_{} ]\n", - virtual_register(id), - control.idx(), - id.idx(), - join.idx(), - ); - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %fork.{}.inc = add i64 1, {}\n", - id.idx(), - virtual_register(id), - ); - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = - format!(" br label %bb_{}\n", successor.idx()); - } - Node::Join { control } => { - // Get the fork, its factor, and the successor to this join. - let fork_id = if let Type::Control(factors) = &types[typing[control.idx()].idx()] { - *factors.last().unwrap() - } else { - panic!() - }; - let factor = if let Node::Fork { control: _, factor } = &function.nodes[fork_id.idx()] { - *factor - } else { - panic!() - }; - let successor = def_use - .get_users(id) - .iter() - .filter(|id| function.nodes[id.idx()].is_strictly_control()) - .next() - .unwrap(); - - // Form the bottom of the loop. We need to branch between the - // successor and the fork. - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " %join.{}.cond = icmp ult i64 %fork.{}.inc, {}\n", - id.idx(), - fork_id.idx(), - llvm_dynamic_constants[factor.idx()], - ); - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = format!( - " br i1 %join.{}.cond, label %bb_{}, label %bb_{}\n", - id.idx(), - fork_id.idx(), - successor.idx(), - ); - } - Node::Phi { - control: _, - ref data, - } => { - let pred_ids = get_uses(&function.nodes[bb[id.idx()].idx()]); - let mut iter = zip(data.iter(), pred_ids.as_ref().iter()); - let (first_data, first_control) = iter.next().unwrap(); - let mut phi = format!( - " {} = phi {} [ {}, %bb_{} ]", - virtual_register(id), - type_of(id), - virtual_register(*first_data), - bb[first_control.idx()].idx() - ); - for (data, control) in iter { - phi += &format!( - ", [ {}, %bb_{} ]", - virtual_register(*data), - bb[control.idx()].idx() - ); - } - phi += "\n"; - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().phis += φ - } - // No code needs to get emitted for thread ID nodes - the loop index is - // emitted in the fork. - Node::ThreadID { control: _ } => {} - Node::Reduce { - control, - init, - reduct, - } => { - // Figure out the fork corresponding to the associated join. - let fork_id = if let Node::Join { control } = function.nodes[control.idx()] { - if let Type::Control(factors) = &types[typing[control.idx()].idx()] { - *factors.last().unwrap() - } else { - panic!() - } - } else { - panic!() - }; - - // Figure out the fork's predecessor. - let pred = if let Node::Fork { control, factor: _ } = function.nodes[fork_id.idx()] { - control - } else { - panic!() - }; - - // Create the phi node for the reduction. - llvm_bbs.get_mut(&bb[fork_id.idx()]).unwrap().phis += &format!( - " {} = phi {} [ {}, %bb_{} ], [ {}, %bb_{} ]\n", - virtual_register(id), - type_of(id), - virtual_register(init), - pred.idx(), - virtual_register(reduct), - control.idx(), - ); - } - Node::Return { control: _, data } => { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = - format!(" ret {}\n", normal_value(data)); - } - // No code needs to get emitted for parameters, constants, or dynamic - // constants - these are just specific virtual registers or constant - // values. - Node::Parameter { index: _ } => {} - Node::Constant { id: _ } => {} - Node::DynamicConstant { id: _ } => {} - Node::Unary { input, op } => match op { - UnaryOperator::Not => todo!(), - UnaryOperator::Neg => { - if types[typing[input.idx()].idx()].is_float() { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = fneg {}\n", - virtual_register(id), - normal_value(input) - ); - } else { - todo!() - } - } - UnaryOperator::Cast(_) => todo!(), - }, - Node::Binary { left, right, op } => { - let opcode = match op { - BinaryOperator::Add => { - if types[typing[left.idx()].idx()].is_float() { - "fadd" - } else { - "add" - } - } - BinaryOperator::Sub => { - if types[typing[left.idx()].idx()].is_float() { - "fsub" - } else { - "sub" - } - } - BinaryOperator::Mul => { - if types[typing[left.idx()].idx()].is_float() { - "fmul" - } else { - "mul" - } - } - BinaryOperator::Div => { - if types[typing[left.idx()].idx()].is_float() { - "fdiv" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "udiv" - } else { - "sdiv" - } - } - BinaryOperator::Rem => { - if types[typing[left.idx()].idx()].is_float() { - "frem" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "urem" - } else { - "srem" - } - } - BinaryOperator::LT => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp olt" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "icmp ult" - } else { - "icmp slt" - } - } - BinaryOperator::LTE => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp ole" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "icmp ule" - } else { - "icmp sle" - } - } - BinaryOperator::GT => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp ogt" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "icmp ugt" - } else { - "icmp sgt" - } - } - BinaryOperator::GTE => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp oge" - } else if types[typing[left.idx()].idx()].is_unsigned() { - "icmp uge" - } else { - "icmp sge" - } - } - BinaryOperator::EQ => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp oeq" - } else { - "icmp eq" - } - } - BinaryOperator::NE => { - if types[typing[left.idx()].idx()].is_float() { - "fcmp one" - } else { - "icmp ne" - } - } - BinaryOperator::Or => "or", - BinaryOperator::And => "and", - BinaryOperator::Xor => "xor", - BinaryOperator::LSh => "lsh", - BinaryOperator::RSh => { - if types[typing[left.idx()].idx()].is_unsigned() { - "lshr" - } else { - "ashr" - } - } - }; - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = {} {}, {}\n", - virtual_register(id), - opcode, - normal_value(left), - virtual_register(right), - ); - } - Node::Ternary { - first, - second, - third, - op, - } => { - let opcode = match op { - TernaryOperator::Select => "select", - }; - - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = {} {}, {}, {}\n", - virtual_register(id), - opcode, - normal_value(first), - normal_value(second), - normal_value(third), - ); - } - Node::Read { - collect, - ref indices, - } => { - // Read nodes may be projection successors of if or match nodes. - if function.nodes[collect.idx()].is_strictly_control() { - let successor = def_use.get_users(id)[0]; - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().terminator = - format!(" br label %bb_{}\n", successor.idx()); - } else { - generate_index_code(collect, indices); - if types[typing[collect.idx()].idx()].is_array() { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = load {}, ptr %index.{}.ptr\n", - virtual_register(id), - llvm_types[typing[id.idx()].idx()], - id.idx() - ); - } else { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = extractvalue {}", - virtual_register(id), - normal_value(collect) - ); - for index in indices.iter() { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += - &format!(", {}", index.try_field().unwrap()); - } - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += "\n"; - } - } - } - Node::Write { - collect, - ref indices, - data, - } => { - generate_index_code(collect, indices); - if types[typing[collect.idx()].idx()].is_array() { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " store {}, ptr %index.{}.ptr\n", - normal_value(data), - id.idx() - ); - } else { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += &format!( - " {} = insertvalue {}, {}", - virtual_register(id), - normal_value(collect), - normal_value(data) - ); - for index in indices.iter() { - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += - &format!(", {}", index.try_field().unwrap()); - } - llvm_bbs.get_mut(&bb[id.idx()]).unwrap().data += "\n"; - } - } - _ => todo!(), - } - - Ok(()) -} diff --git a/hercules_cg/src/top.rs b/hercules_cg/src/top.rs index 626c425772d9d1ec7e37e5ce00471b476c940dd5..4e029ccfd2de5180969b68235281660d5b7ac664 100644 --- a/hercules_cg/src/top.rs +++ b/hercules_cg/src/top.rs @@ -65,8 +65,57 @@ pub fn codegen<W: Write>( Ok(ModuleManifest { functions: manifests, types: module.types.clone(), - // TODO: populate array constants. - array_constants: vec![], + type_sizes_aligns: (0..module.types.len()) + .map(|idx| { + if module.types[idx].is_control() { + (None, 0) + } else { + type_size_and_alignment(module, TypeID::new(idx)) + } + }) + .collect(), + dynamic_constants: module.dynamic_constants.clone(), + // Get the types of all of the constants. This requires collecting over + // all of the functions, since the calculated types of constants may be + // distributed over many functions. This may contain duplicate mappings, + // but this should be fine for our purposes, since the mappings + // shouldn't conflict. + constant_types: module + .functions + .iter() + .enumerate() + .map(|(func_idx, function)| { + function + .nodes + .iter() + .enumerate() + .filter_map(move |(idx, node)| { + Some((node.try_constant()?, typing[func_idx][idx])) + }) + }) + .flatten() + .collect(), + array_constants: (0..module.constants.len()) + .map(ConstantID::new) + .filter_map(|cons_id| { + if module.constants[cons_id.idx()] + .try_array_type(&module.types) + .is_some() + { + Some(embed_constant(module, cons_id)) + } else { + None + } + }) + .collect(), + array_cons_ids: (0..module.constants.len()) + .map(ConstantID::new) + .filter(|id| { + module.constants[id.idx()] + .try_array_type(&module.types) + .is_some() + }) + .collect(), }) } @@ -112,11 +161,11 @@ impl<'a> FunctionContext<'a> { .function .nodes .iter() - .filter_map(|node| node.try_return().map(|(_, data)| data.idx() as u32)) - .collect::<Vec<u32>>(); + .filter_map(|node| node.try_return().map(|(_, data)| data)) + .collect(); // Get the partition ID of the start node. - let top_partition = self.plan.partitions[0].idx() as u32; + let top_partition = self.plan.partitions[0]; // Generate code for each individual partition. This generates a single // LLVM function per partition. These functions will be called in async diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index 3a315aedcad165d83a3237a86b1c26afd7a31fdc..6f44bff7e620da5f04c7f8073ac70610001a670e 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -113,9 +113,12 @@ pub enum Constant { * allocation - by providing dynamic constants to the conductor API, the * conductor can allocate memory as necessary. */ -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum DynamicConstant { + // The usize here is a constant value. Constant(usize), + // The usize here is an index (which dynamic constant parameter of a + // function is this). Parameter(usize), } @@ -713,6 +716,23 @@ impl Constant { } } + pub fn is_strictly_scalar(&self) -> bool { + match self { + Constant::Boolean(_) => true, + Constant::Integer8(_) => true, + Constant::Integer16(_) => true, + Constant::Integer32(_) => true, + Constant::Integer64(_) => true, + Constant::UnsignedInteger8(_) => true, + Constant::UnsignedInteger16(_) => true, + Constant::UnsignedInteger32(_) => true, + Constant::UnsignedInteger64(_) => true, + Constant::Float32(_) => true, + Constant::Float64(_) => true, + _ => false, + } + } + /* * Useful for GVN. */ @@ -758,6 +778,14 @@ impl DynamicConstant { false } } + + pub fn try_constant(&self) -> Option<usize> { + if let DynamicConstant::Constant(v) = self { + Some(*v) + } else { + None + } + } } /* @@ -1189,6 +1217,7 @@ macro_rules! define_id_type { ($x: ident) => { #[derive( Debug, + Default, Clone, Copy, PartialEq, @@ -1389,7 +1418,21 @@ impl IRDisplay for Node { } write!(f, ")") } - Node::Ternary { .. } => todo!(), + Node::Ternary { + first, + second, + third, + op, + } => { + write!( + f, + "{}(var_{}, var_{}, var_{})", + op.lower_case_name(), + first.0, + second.0, + third.0 + ) + } } } } diff --git a/hercules_ir/src/manifest.rs b/hercules_ir/src/manifest.rs index 74dc2ce49ad46afc48784865b24844add758bea8..8b2914c89e235cc3122c967589124b581c3a41e9 100644 --- a/hercules_ir/src/manifest.rs +++ b/hercules_ir/src/manifest.rs @@ -17,12 +17,33 @@ pub struct ModuleManifest { pub functions: Vec<FunctionManifest>, // All of the types used in the module. pub types: Vec<Type>, + // All of the sizes and alignments for types in the module. + pub type_sizes_aligns: Vec<(Option<usize>, usize)>, + // All of the dynamic constants used in the module. + pub dynamic_constants: Vec<DynamicConstant>, + // Store the types of constants. + pub constant_types: Vec<(ConstantID, TypeID)>, // The only constants that aren't baked into the generated code are array // constants. These are explicitly stored in and loaded from the manifest. - // Arrays are composed of the underlying array bytes. We don't need to store - // the dimensions of arrays at this point, since the runtime doesn't - // manipulate or otherwise need the dimensions of constant arrays. - pub array_constants: Vec<Vec<u8>>, + // We only store the array bytes if the array is non-zero. If the array is + // all zeros, we optionally store the size of the array. We may not be able + // to store the array size at compile time if it's all zeros, as its size + // may be a dynamic constant with compile-time unknown size. + pub array_constants: Vec<ConstantBytes>, + // Store map from array number, in array_constants, to constant ID. + pub array_cons_ids: Vec<ConstantID>, +} + +/* + * embed_constant calculates the byte representation of a constant. For zero + * constants, we avoid storing the actual zero bytes, and optionally store the + * size - zero constant arrays may have dynamic constant dimensions unknown at + * compile time. + */ +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ConstantBytes { + NonZero(Vec<u8>, usize), + Zero(Option<usize>, usize), } #[derive(Debug, Serialize, Deserialize, Hash)] @@ -47,29 +68,26 @@ pub struct FunctionManifest { // their dynamic constant parameters. pub dynamic_constant_rules: Vec<DynamicConstantRule>, // The partition containing the start node might not be partition 0. - pub top_partition: u32, + pub top_partition: PartitionID, // Keep track of which node values are returned from the overall function. - // Integer is the node ID. - pub returned_values: Vec<u32>, + pub returned_values: Vec<NodeID>, } /* - * Rules for validity of provided dynamic constants. Integers refer to dynamic - * constant parameters of a function. + * Rules for validity of provided dynamic constants */ #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] pub enum DynamicConstantRule { // Generated from subtraction. - LessThan(u32, u32), + LessThan(DynamicConstantID, DynamicConstantID), // Generated from division. - Divides(u32, u32), + Divides(DynamicConstantID, DynamicConstantID), } #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] pub enum PartitionInput { - // Data input from another partition within this function. Integer is the - // node ID used from the other partition. - DataInput(u32), + // Data input from another partition within this function. + DataInput(NodeID), // An argument from the function parameters. Integer is the parameter index. FunctionArgument(u32), // An array constant used in this function. Integer is the array constant @@ -83,31 +101,39 @@ pub enum PartitionInput { #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] pub enum PartitionOutput { // Data output used by another partition within this function, or to be - // returned from this function. Integer is the node ID used in the other - // partition or by a return node. - DataOutput(u32), + // returned from this function. + DataOutput(NodeID), // Value indicating control flow that the runtime should take. ControlIndicator, } #[derive(Debug, Serialize, Deserialize, Default, Hash)] pub struct PartitionManifest { - // Top node for this partition, as an integer. - pub top_node: u32, + // Top node for this partition. + pub top_node: NodeID, pub inputs: Vec<PartitionInput>, pub outputs: Vec<PartitionOutput>, // Store the partitions that come after this partition. The first element of // the pair is the control returning node in the current partition that // corresponds to a particular successor, and the second element of the pair - // is the partition index of the corresponding successor partition. - pub successor_partitions: Vec<(u32, u32)>, + // is the partition ID of the corresponding successor partition. + pub successor_partitions: Vec<(NodeID, PartitionID)>, +} + +impl ConstantBytes { + pub fn align(&self) -> usize { + match self { + ConstantBytes::NonZero(_, align) => *align, + ConstantBytes::Zero(_, align) => *align, + } + } } /* * Get the data inputs of partitions in a function. */ -pub fn function_partition_inputs(manifest: &FunctionManifest) -> Vec<u32> { +pub fn function_partition_inputs(manifest: &FunctionManifest) -> Vec<NodeID> { let mut all_data_inputs = manifest .partitions .iter() @@ -121,7 +147,7 @@ pub fn function_partition_inputs(manifest: &FunctionManifest) -> Vec<u32> { }) }) .flatten() - .collect::<Vec<u32>>(); + .collect::<Vec<NodeID>>(); all_data_inputs.sort(); all_data_inputs.dedup(); all_data_inputs @@ -130,7 +156,7 @@ pub fn function_partition_inputs(manifest: &FunctionManifest) -> Vec<u32> { /* * Get the data outputs of partitions in a function. */ -pub fn function_partition_outputs(manifest: &FunctionManifest) -> Vec<u32> { +pub fn function_partition_outputs(manifest: &FunctionManifest) -> Vec<NodeID> { let mut all_data_outputs = manifest .partitions .iter() @@ -144,7 +170,7 @@ pub fn function_partition_outputs(manifest: &FunctionManifest) -> Vec<u32> { }) }) .flatten() - .collect::<Vec<u32>>(); + .collect::<Vec<NodeID>>(); all_data_outputs.sort(); all_data_outputs.dedup(); all_data_outputs @@ -160,13 +186,19 @@ pub fn verify_manifest(manifest: &ModuleManifest) -> Result<(), String> { .map(|manifest| { // First, check that all partitiion data inputs get used, and that // all partition data outputs are produced. - let all_data_inputs = function_partition_inputs(manifest); + let mut all_data_inputs = function_partition_inputs(manifest); let all_data_outputs = function_partition_outputs(manifest); // Data outputs include values returned from the overall function. // These are obviously not used by another partition, but that's - // fine. Remove them here explicitly. - let all_data_outputs = all_data_outputs.into_iter().filter(|idx| !manifest.returned_values.contains(idx)).collect::<Vec<u32>>(); + // fine. We add these artificially as "inputs" to a partition so + // that this check still passes. We don't just remove the returned + // value from the data outputs because it might also be the + // legitimate output of another partition, and doing that would + // cause a false negative. + all_data_inputs.extend(&manifest.returned_values); + all_data_inputs.sort(); + all_data_inputs.dedup(); if all_data_inputs != all_data_outputs { return Err(format!("PANIC: Partitions in manifest contain inconsistent data inputs and data outputs of partitions.\nHere are the data input IDs:\n{:?}\nHere are the data output IDs:\n{:?}\n", all_data_inputs, all_data_outputs)); } @@ -174,8 +206,10 @@ pub fn verify_manifest(manifest: &ModuleManifest) -> Result<(), String> { // Next, check that partitions contain multiple successors if and // only if a control indicator is present in their outputs. // TODO: this will fail to verify a partition with a return node and - // a single successor partition, which technically is allowed. Deal - // with this later. + // a single successor partition, which technically is allowed. In + // this scenario, a control indicator is required (to tell if we + // should return or advance the control token), but there is only + // one successor partition. Deal with this later. manifest.partitions.iter().map(|manifest| { let multiple_successors = manifest.successor_partitions.len() > 1; let control_indicator = manifest.outputs.contains(&PartitionOutput::ControlIndicator); diff --git a/hercules_rt_proc/src/lib.rs b/hercules_rt_proc/src/lib.rs index b335a0135daac4b0e6c329c6ce1d30ec078b8484..1e600cb7f32636377d98d797e023dee6731971a5 100644 --- a/hercules_rt_proc/src/lib.rs +++ b/hercules_rt_proc/src/lib.rs @@ -48,7 +48,39 @@ fn generate_type_string(ty: &Type, rust_types: &Vec<String>) -> String { + ")" } Type::Summation(_) => todo!(), - Type::Array(elem, _) => format!("::std::boxed::Box<[{}]>", &rust_types[elem.idx()]), + Type::Array(elem, _) => format!("*mut {}", &rust_types[elem.idx()]), + } +} + +/* + * Emit a dynamic constant, which isn't necessarily just a dynamic constant + * parameter. + */ +fn emit_dynamic_constant(dc: DynamicConstantID, manifest: &ModuleManifest) -> String { + match manifest.dynamic_constants[dc.idx()] { + DynamicConstant::Constant(val) => format!("{}", val), + DynamicConstant::Parameter(idx) => format!("dyn_cons_{}", idx), + } +} + +/* + * Emit dynamic constant math to calculate the runtime size of a type, in number + * of bytes. + */ +fn emit_type_size_expression(ty: TypeID, manifest: &ModuleManifest) -> String { + match manifest.types[ty.idx()] { + Type::Array(elem, ref dcs) => { + dcs.iter().fold( + "(".to_string() + &emit_type_size_expression(elem, manifest), + |acc, dc| acc + " * " + &emit_dynamic_constant(*dc, manifest), + ) + ")" + } + _ => format!( + "{}", + manifest.type_sizes_aligns[ty.idx()] + .0 + .expect("PANIC: Size of non-array type is unknown at compile-time.") + ), } } @@ -118,11 +150,22 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro .unwrap(), ); let input_types = partition.inputs.iter().map(|input| match input { - PartitionInput::DataInput(node_idx) => function.typing[*node_idx as usize], + PartitionInput::DataInput(node_id) => function.typing[node_id.idx()], PartitionInput::FunctionArgument(param_idx) => { function.param_types[*param_idx as usize] } - PartitionInput::ArrayConstant(_) => todo!(), + PartitionInput::ArrayConstant(num) => { + // We store the types of constants in the manifest - use + // this info to get the type of this array constant. + let arr_cons_id = manifest.array_cons_ids[*num as usize]; + manifest + .constant_types + .iter() + .filter(|(cons_id, _)| arr_cons_id == *cons_id) + .next() + .expect("PANIC: Couldn't find type of array constant in manifest.") + .1 + } PartitionInput::DynamicConstant(_) => u64_ty_id, }); let output_type = Type::Product( @@ -130,9 +173,7 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro .outputs .iter() .map(|input| match input { - PartitionOutput::DataOutput(node_idx) => { - function.typing[*node_idx as usize] - } + PartitionOutput::DataOutput(node_id) => function.typing[node_id.idx()], PartitionOutput::ControlIndicator => u64_ty_id, }) .collect(), @@ -166,8 +207,32 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro write!( rust_code, "let mut node_{}: Option<{}> = None;", - node, - &rust_types[function.typing[node as usize].idx()] + node.idx(), + &rust_types[function.typing[node.idx()].idx()] + )?; + } + + // Declare all of the array constant memories. We declare them as Vecs + // to allocate the memories. We emit multiplications of the dynamic + // constant dimensions to allocate the whole memory as one contiguous + // range. TODO: emit only the array constants actually used in this + // function. + for (arr_cons_num, arr_cons_id) in manifest.array_cons_ids.iter().enumerate() { + let arr_ty_id = manifest + .constant_types + .iter() + .filter(|(cons_id, _)| arr_cons_id == cons_id) + .next() + .expect("PANIC: Couldn't find type of array constant in manifest.") + .1; + write!( + rust_code, + "let mut arr_cons_{}_vec = vec![0u8; {} as usize];let mut arr_cons_{} = arr_cons_{}_vec.as_mut_ptr();arr_cons_{}_vec.leak();", + arr_cons_num, + emit_type_size_expression(arr_ty_id, manifest), + arr_cons_num, + arr_cons_num, + arr_cons_num, )?; } @@ -177,7 +242,7 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro write!( rust_code, "let mut control_token: u32 = {};loop {{", - function.top_partition + function.top_partition.idx() )?; // Match on the control token position to determine which partition to @@ -194,12 +259,12 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro "let input_{} = {};", input_idx, match input { - PartitionInput::DataInput(idx) => format!( + PartitionInput::DataInput(id) => format!( "node_{}.expect(\"PANIC: Encountered use before def in runtime.\")", - idx + id.idx() ), PartitionInput::FunctionArgument(idx) => format!("param_{}", idx), - PartitionInput::ArrayConstant(_) => todo!(), + PartitionInput::ArrayConstant(num) => format!("arr_cons_{} as _", num), PartitionInput::DynamicConstant(idx) => format!("dyn_cons_{}", idx), } )?; @@ -218,7 +283,9 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro rust_code, "{} = Some(output.{});", match output { - PartitionOutput::DataOutput(idx) => format!("node_{}", idx), + PartitionOutput::DataOutput(id) => format!("node_{}", id.idx()), + // TODO: handle partitions with control indicator + // outputs. PartitionOutput::ControlIndicator => "todo!()".to_string(), }, output_idx @@ -230,7 +297,7 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro // token to that successor's index. If there are multiple control // successors, set the control token to the control indicator output // of the partition function. - // TODO: handle functions with multiple returned values. + // TODO: handle partitions with multiple return nodes. // TODO: handle partitions with a return node and a single successor // partition. if partition.successor_partitions.len() == 0 { @@ -238,13 +305,13 @@ fn codegen(manifest: &ModuleManifest, elf: &[u8]) -> Result<String, anyhow::Erro write!( rust_code, "return node_{}.expect(\"PANIC: Encountered use before def in runtime.\");", - function.returned_values[0] + function.returned_values[0].idx() )?; } else if partition.successor_partitions.len() == 1 { write!( rust_code, "control_token = {};", - partition.successor_partitions[0].1 + partition.successor_partitions[0].1.idx() )?; } else { todo!(); diff --git a/hercules_samples/matmul/Cargo.toml b/hercules_samples/matmul/Cargo.toml index 945032691547814c74da7ac63e7d4a9f61a54196..723e9b523c693657a48a5a0213deab99ab875852 100644 --- a/hercules_samples/matmul/Cargo.toml +++ b/hercules_samples/matmul/Cargo.toml @@ -2,8 +2,10 @@ name = "hercules_matmul" version = "0.1.0" authors = ["Russel Arbore <rarbore2@illinois.edu>"] +edition = "2021" [dependencies] clap = { version = "*", features = ["derive"] } hercules_rt = { path = "../../hercules_rt" } rand = "*" +async-std = "*" diff --git a/hercules_samples/matmul/src/main.rs b/hercules_samples/matmul/src/main.rs index f281b97ec103d1e2a864983388795ff108bb1f15..732aece4410232a3b4ba0785a969b89a7a6b1aa5 100644 --- a/hercules_samples/matmul/src/main.rs +++ b/hercules_samples/matmul/src/main.rs @@ -1,12 +1,26 @@ +extern crate async_std; extern crate clap; extern crate hercules_rt; +// To compile currently, run from the Hercules project root directory: +// cargo run --bin hercules_driver hercules_samples/matmul/matmul.hir "Codegen(\"matmul.hbin\")" +// Then, you can execute this example with: +// cargo run --bin hercules_matmul hercules_rt::use_hbin!("matmul.hbin"); fn main() { - //let a = [[1.0f32, 2.0f32], [3.0f32, 4.0f32]]; - //let b = [[5.0f32, 6.0f32], [7.0f32, 8.0f32]]; - //let mut c = [[0.0f32, 0.0f32], [0.0f32, 0.0f32]]; - //matmul(&a, &b, &mut c, 2, 2, 2); - //println!("{} {}\n{} {}", c[0][0], c[0][1], c[1][0], c[1][1]); + async_std::task::block_on(async { + let mut a = vec![1.0, 2.0, 3.0, 4.0]; + let mut b = vec![5.0, 6.0, 7.0, 8.0]; + let c = matmul(a.as_mut_ptr(), b.as_mut_ptr(), 2, 2, 2).await; + unsafe { + println!( + "[[{}, {}], [{}, {}]]", + *c, + *c.offset(1), + *c.offset(2), + *c.offset(3) + ); + } + }); } diff --git a/hercules_samples/task_parallel/Cargo.toml b/hercules_samples/task_parallel/Cargo.toml index 03c402c6626426c892aba0b9c32c8ab73a19fc53..76b678cc3b4ac042f0f48bb247c7ed58f4dc5efa 100644 --- a/hercules_samples/task_parallel/Cargo.toml +++ b/hercules_samples/task_parallel/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" [dependencies] clap = { version = "*", features = ["derive"] } hercules_rt = { path = "../../hercules_rt" } -rand = "*" async-std = "*" diff --git a/hercules_tools/hercules_cpu_beta/Cargo.toml b/hercules_tools/hercules_cpu_beta/Cargo.toml deleted file mode 100644 index 38b30e82776f5a1bef03c3a887a9d59deba72431..0000000000000000000000000000000000000000 --- a/hercules_tools/hercules_cpu_beta/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "hercules_cpu_beta" -version = "0.1.0" -authors = ["Russel Arbore <rarbore2@illinois.edu>"] - -[dependencies] -clap = { version = "*", features = ["derive"] } -hercules_ir = { path = "../../hercules_ir" } -hercules_opt = { path = "../../hercules_opt" } -hercules_cg = { path = "../../hercules_cg" } -rand = "*" diff --git a/hercules_tools/hercules_cpu_beta/src/main.rs b/hercules_tools/hercules_cpu_beta/src/main.rs deleted file mode 100644 index 2edd426a30ccba4caaf606fd8e08f9d545321ee4..0000000000000000000000000000000000000000 --- a/hercules_tools/hercules_cpu_beta/src/main.rs +++ /dev/null @@ -1,75 +0,0 @@ -extern crate clap; - -use std::fs::File; -use std::io::prelude::*; - -use clap::Parser; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - hir_file: String, - - #[arg(short, long, default_value_t = String::new())] - output: String, -} - -fn main() { - let args = Args::parse(); - if !args.hir_file.ends_with(".hir") { - eprintln!("WARNING: Running hercules_cpu_beta on a file without a .hir extension - interpreting as a textual Hercules IR file."); - } - - let mut file = File::open(args.hir_file).expect("PANIC: Unable to open input file."); - let mut contents = String::new(); - file.read_to_string(&mut contents) - .expect("PANIC: Unable to read input file contents."); - let module = - hercules_ir::parse::parse(&contents).expect("PANIC: Failed to parse Hercules IR file."); - - let mut pm = hercules_opt::pass::PassManager::new(module); - pm.add_pass(hercules_opt::pass::Pass::Verify); - pm.add_pass(hercules_opt::pass::Pass::CCP); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::GVN); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::Forkify); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::Predication); - pm.add_pass(hercules_opt::pass::Pass::DCE); - - pm.run_passes(); - pm.make_typing(); - pm.make_reverse_postorders(); - pm.make_def_uses(); - pm.make_bbs(); - pm.make_antideps(); - pm.make_fork_join_maps(); - pm.make_fork_join_nests(); - - let typing = pm.typing.as_ref().unwrap().clone(); - let reverse_postorders = pm.reverse_postorders.as_ref().unwrap().clone(); - let def_uses = pm.def_uses.as_ref().unwrap().clone(); - let bbs = pm.bbs.as_ref().unwrap().clone(); - let antideps = pm.antideps.as_ref().unwrap().clone(); - let fork_join_maps = pm.fork_join_maps.as_ref().unwrap().clone(); - let fork_join_nests = pm.fork_join_nests.as_ref().unwrap().clone(); - - let module = pm.get_module(); - - let mut file = File::create("test.ll").unwrap(); - let mut contents = String::new(); - hercules_cg::cpu_beta::cpu_beta_codegen( - &module, - &typing, - &reverse_postorders, - &def_uses, - &bbs, - &antideps, - &fork_join_maps, - &fork_join_nests, - &mut contents, - ) - .unwrap(); - file.write_all(contents.as_bytes()).unwrap(); -} diff --git a/hercules_tools/hercules_dot/Cargo.toml b/hercules_tools/hercules_dot/Cargo.toml deleted file mode 100644 index f2b42c0ea2bf18fdca6dc00b33af17302c19f145..0000000000000000000000000000000000000000 --- a/hercules_tools/hercules_dot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "hercules_dot" -version = "0.1.0" -authors = ["Russel Arbore <rarbore2@illinois.edu>"] - -[dependencies] -clap = { version = "*", features = ["derive"] } -hercules_ir = { path = "../../hercules_ir" } -hercules_opt = { path = "../../hercules_opt" } -rand = "*" diff --git a/hercules_tools/hercules_dot/src/main.rs b/hercules_tools/hercules_dot/src/main.rs deleted file mode 100644 index 013ba87b7b11233b1f67fe9c0b63b91dfd5bfc44..0000000000000000000000000000000000000000 --- a/hercules_tools/hercules_dot/src/main.rs +++ /dev/null @@ -1,74 +0,0 @@ -extern crate clap; -extern crate rand; - -use std::fs::File; -use std::io::prelude::*; - -use clap::Parser; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - hir_file: String, - - #[arg(short, long, default_value_t = String::new())] - output: String, -} - -fn main() { - let args = Args::parse(); - if !args.hir_file.ends_with(".hir") { - eprintln!("WARNING: Running hercules_dot on a file without a .hir extension - interpreting as a textual Hercules IR file."); - } - - let mut file = File::open(args.hir_file).expect("PANIC: Unable to open input file."); - let mut contents = String::new(); - file.read_to_string(&mut contents) - .expect("PANIC: Unable to read input file contents."); - let module = - hercules_ir::parse::parse(&contents).expect("PANIC: Failed to parse Hercules IR file."); - - let mut pm = hercules_opt::pass::PassManager::new(module); - pm.add_pass(hercules_opt::pass::Pass::Verify); - pm.add_pass(hercules_opt::pass::Pass::CCP); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::GVN); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::Forkify); - pm.add_pass(hercules_opt::pass::Pass::DCE); - pm.add_pass(hercules_opt::pass::Pass::Predication); - pm.add_pass(hercules_opt::pass::Pass::DCE); - - if args.output.is_empty() { - pm.add_pass(hercules_opt::pass::Pass::Xdot(true)); - pm.run_passes(); - } else { - let mut file = File::create(args.output).expect("PANIC: Unable to open output file."); - let mut contents = String::new(); - - pm.run_passes(); - pm.make_reverse_postorders(); - pm.make_doms(); - pm.make_fork_join_maps(); - pm.make_plans(); - - let reverse_postorders = pm.reverse_postorders.as_ref().unwrap().clone(); - let doms = pm.doms.as_ref().unwrap().clone(); - let fork_join_maps = pm.fork_join_maps.as_ref().unwrap().clone(); - let plans = pm.plans.as_ref().unwrap().clone(); - - let module = pm.get_module(); - - hercules_ir::dot::write_dot( - &module, - &reverse_postorders, - Some(&doms), - Some(&fork_join_maps), - Some(&plans), - &mut contents, - ) - .expect("PANIC: Unable to generate output file contents."); - file.write_all(contents.as_bytes()) - .expect("PANIC: Unable to write output file contents."); - } -} diff --git a/hercules_tools/hercules_hbin_dump/Cargo.toml b/hercules_tools/hercules_hbin_dump/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..44504cb58c8f008d88632dd26cbd3ff1745b6109 --- /dev/null +++ b/hercules_tools/hercules_hbin_dump/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "hercules_hbin_dump" +version = "0.1.0" +authors = ["Russel Arbore <rarbore2@illinois.edu>"] +edition = "2021" + +[dependencies] +clap = { version = "*", features = ["derive"] } +postcard = { version = "*", features = ["alloc"] } +serde = { version = "*", features = ["derive"] } +hercules_ir = { path = "../../hercules_ir" } \ No newline at end of file diff --git a/hercules_tools/hercules_hbin_dump/src/main.rs b/hercules_tools/hercules_hbin_dump/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..0b258ab4e534b189f86b53d03dc60a040de87be0 --- /dev/null +++ b/hercules_tools/hercules_hbin_dump/src/main.rs @@ -0,0 +1,28 @@ +extern crate clap; +extern crate hercules_ir; +extern crate postcard; + +use std::fs::File; +use std::io::prelude::*; + +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + hbin_file: String, +} + +fn main() { + let args = Args::parse(); + if !args.hbin_file.ends_with(".hbin") { + eprintln!("WARNING: Running hercules_hbin_dump on a file without a .hbin extension - interpreting as a Hercules binary file."); + } + + let mut f = File::open(args.hbin_file).unwrap(); + let mut buffer = vec![]; + f.read_to_end(&mut buffer).unwrap(); + let (manifest, _): (hercules_ir::ModuleManifest, Vec<u8>) = + postcard::from_bytes(&buffer).unwrap(); + println!("{:#?}", manifest); +}