diff --git a/.forgejo/workflows/deps.yml b/.forgejo/workflows/deps.yml deleted file mode 100644 index b29723c..0000000 --- a/.forgejo/workflows/deps.yml +++ /dev/null @@ -1,77 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -# See Notices.txt for copyright information -on: - workflow_call: - outputs: - cache-primary-key: - value: ${{ jobs.deps.outputs.cache-primary-key }} - -jobs: - deps: - runs-on: debian-12 - outputs: - cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }} - steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 - with: - fetch-depth: 0 - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - id: restore-deps - with: - path: deps - key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }} - lookup-only: true - - name: Install Apt packages - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - apt-get update -qq - apt-get install -qq \ - bison \ - build-essential \ - ccache \ - clang \ - cvc5 \ - flex \ - gawk \ - g++ \ - git \ - libboost-filesystem-dev \ - libboost-python-dev \ - libboost-system-dev \ - libffi-dev \ - libreadline-dev \ - lld \ - pkg-config \ - python3 \ - python3-click \ - tcl-dev \ - zlib1g-dev - - name: Install Firtool - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - mkdir -p deps - wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz - sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz' - tar -C deps -xvaf deps/firrtl.tar.gz - rm -rf deps/firtool - mv deps/firtool-1.86.0 deps/firtool - - name: Get SymbiYosys - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby - - name: Build Z3 - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3 - (cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local) - make -C deps/z3/build -j"$(nproc)" - - name: Build Yosys - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys - make -C deps/yosys -j"$(nproc)" - - uses: https://git.libre-chip.org/mirrors/cache/save@v3 - if: steps.restore-deps.outputs.cache-hit != 'true' - with: - path: deps - key: ${{ steps.restore-deps.outputs.cache-primary-key }} diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index b2d03ba..088ca7c 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -1,62 +1,19 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -# See Notices.txt for copyright information on: [push, pull_request] jobs: - deps: - uses: ./.forgejo/workflows/deps.yml test: runs-on: debian-12 - needs: deps steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 + - uses: https://code.forgejo.org/actions/checkout@v3 with: fetch-depth: 0 - run: | - scripts/check-copyright.sh - - run: | - apt-get update -qq - apt-get install -qq \ - bison \ - build-essential \ - ccache \ - clang \ - cvc5 \ - flex \ - gawk \ - git \ - libboost-filesystem-dev \ - libboost-python-dev \ - libboost-system-dev \ - libffi-dev \ - libreadline-dev \ - lld \ - pkg-config \ - python3 \ - python3-click \ - tcl-dev \ - z3 \ - zlib1g-dev - - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.82.0 + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.80.1 source "$HOME/.cargo/env" echo "$PATH" >> "$GITHUB_PATH" - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - with: - path: deps - key: ${{ needs.deps.outputs.cache-primary-key }} - fail-on-cache-miss: true - - run: | - make -C deps/z3/build install - make -C deps/sby install - make -C deps/yosys install - export PATH="$(realpath deps/firtool/bin):$PATH" - echo "$PATH" >> "$GITHUB_PATH" - - uses: https://git.libre-chip.org/mirrors/rust-cache@v2 + - uses: https://github.com/Swatinem/rust-cache@v2 with: save-if: ${{ github.ref == 'refs/heads/master' }} - run: cargo test - - run: cargo build --tests --features=unstable-doc - - run: cargo test --doc --features=unstable-doc + - run: cargo test --features=unstable-doc - run: cargo doc --features=unstable-doc - - run: FAYALITE_TEST_HASHER=always_zero cargo test --test=module --features=unstable-doc,unstable-test-hasher diff --git a/.gitignore b/.gitignore index 0655406..ccb5166 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -# See Notices.txt for copyright information /target -.vscode +.vscode \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e0c32e9..1c17ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -44,7 +56,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -54,21 +66,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "autocfg" version = "1.1.0" @@ -109,20 +109,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "serde", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -132,15 +118,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cc" -version = "1.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -193,12 +170,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "cpufeatures" version = "0.2.12" @@ -218,27 +189,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "derive_destructure2" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b697ac90ff296f0fc031ee5a61c7ac31fb9fff50e3fb32873b09223613fc0c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.10.7" @@ -268,7 +218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -289,39 +239,32 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fayalite" -version = "0.3.0" +version = "0.2.0" dependencies = [ "bitvec", - "blake3", "clap", - "ctor", "eyre", "fayalite-proc-macros", "fayalite-visit-gen", "hashbrown", - "jobslot", "num-bigint", "num-traits", - "os_pipe", - "petgraph", "serde", "serde_json", - "tempfile", "trybuild", - "vec_map", "which", ] [[package]] name = "fayalite-proc-macros" -version = "0.3.0" +version = "0.2.0" dependencies = [ "fayalite-proc-macros-impl", ] [[package]] name = "fayalite-proc-macros-impl" -version = "0.3.0" +version = "0.2.0" dependencies = [ "base16ct", "num-bigint", @@ -335,7 +278,7 @@ dependencies = [ [[package]] name = "fayalite-visit-gen" -version = "0.3.0" +version = "0.2.0" dependencies = [ "indexmap", "prettyplease", @@ -347,18 +290,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "funty" version = "2.0.0" @@ -375,17 +306,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "glob" version = "0.3.1" @@ -394,13 +314,12 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ + "ahash", "allocator-api2", - "equivalent", - "foldhash", ] [[package]] @@ -415,7 +334,7 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -426,9 +345,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -447,20 +366,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "jobslot" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d" -dependencies = [ - "cfg-if", - "derive_destructure2", - "getrandom", - "libc", - "scopeguard", - "windows-sys 0.59.0", -] - [[package]] name = "libc" version = "0.2.153" @@ -475,10 +380,11 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ + "autocfg", "num-integer", "num-traits", ] @@ -507,28 +413,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "petgraph" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06" -dependencies = [ - "fixedbitset", - "hashbrown", - "indexmap", - "serde", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -541,9 +425,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -573,7 +457,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -582,12 +466,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" version = "1.0.202" @@ -631,12 +509,6 @@ dependencies = [ "digest", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "strsim" version = "0.11.1" @@ -645,9 +517,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.93" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -669,7 +541,7 @@ dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -734,24 +606,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "which" version = "6.0.1" @@ -804,25 +664,15 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", - "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -831,51 +681,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winsafe" @@ -891,3 +735,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index d681425..1608a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,40 +5,31 @@ resolver = "2" members = ["crates/*"] [workspace.package] -version = "0.3.0" +version = "0.2.0" license = "LGPL-3.0-or-later" edition = "2021" repository = "https://git.libre-chip.org/libre-chip/fayalite" keywords = ["hdl", "hardware", "semiconductors", "firrtl", "fpga"] categories = ["simulation", "development-tools", "compilers"] -rust-version = "1.82.0" +rust-version = "1.80.1" [workspace.dependencies] -fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" } -fayalite-proc-macros-impl = { version = "=0.3.0", path = "crates/fayalite-proc-macros-impl" } -fayalite-visit-gen = { version = "=0.3.0", path = "crates/fayalite-visit-gen" } +fayalite-proc-macros = { version = "=0.2.0", path = "crates/fayalite-proc-macros" } +fayalite-proc-macros-impl = { version = "=0.2.0", path = "crates/fayalite-proc-macros-impl" } +fayalite-visit-gen = { version = "=0.2.0", path = "crates/fayalite-visit-gen" } base16ct = "0.2.0" bitvec = { version = "1.0.1", features = ["serde"] } -blake3 = { version = "1.5.4", features = ["serde"] } -clap = { version = "4.5.9", features = ["derive", "env", "string"] } -ctor = "0.2.8" -eyre = "0.6.12" -hashbrown = "0.15.2" -indexmap = { version = "2.5.0", features = ["serde"] } -jobslot = "0.2.19" -num-bigint = "0.4.6" +hashbrown = "0.14.3" +indexmap = { version = "2.2.6", features = ["serde"] } +num-bigint = "0.4.4" num-traits = "0.2.16" -os_pipe = "1.2.1" -petgraph = "0.8.1" prettyplease = "0.2.20" proc-macro2 = "1.0.83" quote = "1.0.36" serde = { version = "1.0.202", features = ["derive"] } serde_json = { version = "1.0.117", features = ["preserve_order"] } sha2 = "0.10.8" -syn = { version = "2.0.93", features = ["full", "fold", "visit", "extra-traits"] } +syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"] } tempfile = "3.10.1" thiserror = "1.0.61" trybuild = "1.0" -vec_map = "0.8.2" -which = "6.0.1" diff --git a/README.md b/README.md index 438550e..6e14e9f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ - # Fayalite Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/). diff --git a/crates/fayalite-proc-macros-impl/Cargo.toml b/crates/fayalite-proc-macros-impl/Cargo.toml index d56f03d..31c4465 100644 --- a/crates/fayalite-proc-macros-impl/Cargo.toml +++ b/crates/fayalite-proc-macros-impl/Cargo.toml @@ -13,11 +13,11 @@ rust-version.workspace = true version.workspace = true [dependencies] -base16ct.workspace = true -num-bigint.workspace = true -prettyplease.workspace = true -proc-macro2.workspace = true -quote.workspace = true -sha2.workspace = true -syn.workspace = true -tempfile.workspace = true +base16ct = { workspace = true } +num-bigint = { workspace = true } +prettyplease = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +sha2 = { workspace = true } +syn = { workspace = true } +tempfile = { workspace = true } diff --git a/crates/fayalite-proc-macros-impl/src/fold.rs b/crates/fayalite-proc-macros-impl/src/fold.rs index 22e7b82..49cc8c1 100644 --- a/crates/fayalite-proc-macros-impl/src/fold.rs +++ b/crates/fayalite-proc-macros-impl/src/fold.rs @@ -220,7 +220,6 @@ forward_fold!(syn::ExprArray => fold_expr_array); forward_fold!(syn::ExprCall => fold_expr_call); forward_fold!(syn::ExprIf => fold_expr_if); forward_fold!(syn::ExprMatch => fold_expr_match); -forward_fold!(syn::ExprMethodCall => fold_expr_method_call); forward_fold!(syn::ExprPath => fold_expr_path); forward_fold!(syn::ExprRepeat => fold_expr_repeat); forward_fold!(syn::ExprStruct => fold_expr_struct); diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index 7441cb3..f29f43a 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use crate::{ hdl_type_common::{ common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField, @@ -21,18 +19,16 @@ use syn::{ #[derive(Clone, Debug)] pub(crate) struct ParsedBundle { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) vis: Visibility, pub(crate) struct_token: Token![struct], pub(crate) ident: Ident, pub(crate) generics: MaybeParsed, pub(crate) fields: MaybeParsed, - pub(crate) field_flips: Vec>>, + pub(crate) field_flips: Vec>>, pub(crate) mask_type_ident: Ident, pub(crate) mask_type_match_variant_ident: Ident, - pub(crate) mask_type_sim_value_ident: Ident, pub(crate) match_variant_ident: Ident, - pub(crate) sim_value_ident: Ident, pub(crate) builder_ident: Ident, pub(crate) mask_type_builder_ident: Ident, } @@ -42,7 +38,7 @@ impl ParsedBundle { errors: &mut Errors, field: &mut Field, index: usize, - ) -> Option> { + ) -> Option> { let Field { attrs, vis: _, @@ -60,7 +56,8 @@ impl ParsedBundle { } *mutability = FieldMutability::None; colon_token.get_or_insert(Token![:](ident.span())); - errors.unwrap_or_default(HdlAttr::parse_and_take_attr(attrs)) + let options = errors.unwrap_or_default(HdlAttr::parse_and_take_attr(attrs)); + options } fn parse(item: ItemStruct) -> syn::Result { let ItemStruct { @@ -74,9 +71,7 @@ impl ParsedBundle { } = item; let mut errors = Errors::new(); let mut options = errors - .unwrap_or_default(HdlAttr::::parse_and_take_attr( - &mut attrs, - )) + .unwrap_or_default(HdlAttr::::parse_and_take_attr(&mut attrs)) .unwrap_or_default(); errors.ok(options.body.validate()); let ItemOptions { @@ -85,7 +80,6 @@ impl ParsedBundle { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq: _, } = options.body; let mut fields = match fields { syn::Fields::Named(fields) => fields, @@ -127,9 +121,7 @@ impl ParsedBundle { field_flips, mask_type_ident: format_ident!("__{}__MaskType", ident), mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident), - mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident), match_variant_ident: format_ident!("__{}__MatchVariant", ident), - sim_value_ident: format_ident!("__{}__SimValue", ident), mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident), builder_ident: format_ident!("__{}__Builder", ident), ident, @@ -345,7 +337,7 @@ impl ToTokens for Builder { })); quote_spanned! {self.ident.span()=> #[automatically_derived] - #[allow(non_camel_case_types, non_snake_case, dead_code)] + #[allow(non_camel_case_types, dead_code)] impl #impl_generics #unfilled_ty #where_clause { @@ -431,24 +423,20 @@ impl ToTokens for ParsedBundle { field_flips, mask_type_ident, mask_type_match_variant_ident, - mask_type_sim_value_ident, match_variant_ident, - sim_value_ident, builder_ident, mask_type_builder_ident, } = self; - let span = ident.span(); let ItemOptions { outline_generated: _, target, custom_bounds: _, no_static, no_runtime_generics, - cmp_eq, } = &options.body; let target = get_target(target, ident); let mut item_attrs = attrs.clone(); - item_attrs.push(common_derives(span)); + item_attrs.push(common_derives(ident.span())); ItemStruct { attrs: item_attrs, vis: vis.clone(), @@ -470,19 +458,19 @@ impl ToTokens for ParsedBundle { .map(|ParsedField { ident, ty, .. }| { let ident = ident.as_ref().unwrap(); let expr = ty.make_hdl_type_expr(context); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: #expr, } }) .collect(); - parse_quote_spanned! {span=> + parse_quote_spanned! {ident.span()=> #target { #(#fields)* } } }) } - let mut wrapped_in_const = WrappedInConst::new(tokens, span); + let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); let tokens = wrapped_in_const.inner(); let builder = Builder { vis: vis.clone(), @@ -496,8 +484,9 @@ impl ToTokens for ParsedBundle { let unfilled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Unfilled); let filled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Filled); let mut mask_type_fields = FieldsNamed::from(fields.clone()); - for Field { ty, .. } in &mut mask_type_fields.named { - *ty = parse_quote_spanned! {span=> + for Field { ident, ty, .. } in &mut mask_type_fields.named { + let ident = ident.as_ref().unwrap(); + *ty = parse_quote_spanned! {ident.span()=> <#ty as ::fayalite::ty::Type>::MaskType }; } @@ -516,8 +505,8 @@ impl ToTokens for ParsedBundle { mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Filled); ItemStruct { attrs: vec![ - common_derives(span), - parse_quote_spanned! {span=> + common_derives(ident.span()), + parse_quote_spanned! {ident.span()=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -529,16 +518,17 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); - let mut mask_type_match_variant_fields = mask_type_fields.clone(); - for Field { ty, .. } in &mut mask_type_match_variant_fields.named { - *ty = parse_quote_spanned! {span=> + let mut mask_type_match_variant_fields = mask_type_fields; + for Field { ident, ty, .. } in &mut mask_type_match_variant_fields.named { + let ident = ident.as_ref().unwrap(); + *ty = parse_quote_spanned! {ident.span()=> ::fayalite::expr::Expr<#ty> }; } ItemStruct { attrs: vec![ - common_derives(span), - parse_quote_spanned! {span=> + common_derives(ident.span()), + parse_quote_spanned! {ident.span()=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -551,15 +541,16 @@ impl ToTokens for ParsedBundle { } .to_tokens(tokens); let mut match_variant_fields = FieldsNamed::from(fields.clone()); - for Field { ty, .. } in &mut match_variant_fields.named { - *ty = parse_quote_spanned! {span=> + for Field { ident, ty, .. } in &mut match_variant_fields.named { + let ident = ident.as_ref().unwrap(); + *ty = parse_quote_spanned! {ident.span()=> ::fayalite::expr::Expr<#ty> }; } ItemStruct { attrs: vec![ - common_derives(span), - parse_quote_spanned! {span=> + common_derives(ident.span()), + parse_quote_spanned! {ident.span()=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -571,72 +562,17 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); - let mut mask_type_sim_value_fields = mask_type_fields; - for Field { ty, .. } in &mut mask_type_sim_value_fields.named { - *ty = parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }; - } - ItemStruct { - attrs: vec![ - parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }, - parse_quote_spanned! {span=> - #[allow(non_camel_case_types, dead_code)] - }, - ], - vis: vis.clone(), - struct_token: *struct_token, - ident: mask_type_sim_value_ident.clone(), - generics: generics.into(), - fields: Fields::Named(mask_type_sim_value_fields), - semi_token: None, - } - .to_tokens(tokens); - let mut sim_value_fields = FieldsNamed::from(fields.clone()); - for Field { ty, .. } in &mut sim_value_fields.named { - *ty = parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }; - } - ItemStruct { - attrs: vec![ - parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }, - parse_quote_spanned! {span=> - #[allow(non_camel_case_types, dead_code)] - }, - ], - vis: vis.clone(), - struct_token: *struct_token, - ident: sim_value_ident.clone(), - generics: generics.into(), - fields: Fields::Named(sim_value_fields), - semi_token: None, - } - .to_tokens(tokens); - let this_token = Ident::new("__this", span); - let fields_token = Ident::new("__fields", span); - let self_token = Token![self](span); let match_variant_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); - quote_spanned! {span=> - #ident: ::fayalite::expr::Expr::field(#this_token, #ident_str), + quote_spanned! {ident.span()=> + #ident: ::fayalite::expr::Expr::field(__this, #ident_str), } })); let mask_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - #ident: ::fayalite::ty::Type::mask_type(&#self_token.#ident), + quote_spanned! {ident.span()=> + #ident: ::fayalite::ty::Type::mask_type(&self.#ident), } })); let from_canonical_body_fields = @@ -644,16 +580,16 @@ impl ToTokens for ParsedBundle { |((index, field), flip)| { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); - let not_flipped = flip.is_none().then(|| Token![!](span)); - quote_spanned! {span=> + let flipped = flip.is_some(); + quote_spanned! {ident.span()=> #ident: { let ::fayalite::bundle::BundleField { name: __name, flipped: __flipped, ty: __ty, - } = #fields_token[#index]; + } = __fields[#index]; ::fayalite::__std::assert_eq!(&*__name, #ident_str); - ::fayalite::__std::assert!(#not_flipped __flipped); + ::fayalite::__std::assert_eq!(__flipped, #flipped); ::fayalite::ty::Type::from_canonical(__ty) }, } @@ -664,49 +600,23 @@ impl ToTokens for ParsedBundle { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); let flipped = flip.is_some(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::bundle::BundleField { name: ::fayalite::intern::Intern::intern(#ident_str), flipped: #flipped, - ty: ::fayalite::ty::Type::canonical(&#self_token.#ident), + ty: ::fayalite::ty::Type::canonical(&self.#ident), }, } }, )); - let sim_value_from_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - #ident: v.field_from_bits(), - } - })); - let sim_value_clone_from_bits_fields = - Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - v.field_clone_from_bits(&mut value.#ident); - } - })); - let sim_value_to_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - v.field_to_bits(&value.#ident); - } - })); - let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - #ident: ::fayalite::sim::value::SimValue::ty(&self.#ident), - } - })); let fields_len = fields.named().into_iter().len(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #[automatically_derived] impl #impl_generics ::fayalite::ty::Type for #mask_type_ident #type_generics #where_clause { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; - type SimValue = #mask_type_sim_value_ident #type_generics; type MatchVariant = #mask_type_match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -716,7 +626,7 @@ impl ToTokens for ParsedBundle { ::MatchVariantAndInactiveScope, >; fn match_variants( - #this_token: ::fayalite::expr::Expr, + __this: ::fayalite::expr::Expr, __source_location: ::fayalite::source_location::SourceLocation, ) -> ::MatchVariantsIter { let __retval = #mask_type_match_variant_ident { @@ -724,19 +634,19 @@ impl ToTokens for ParsedBundle { }; ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval)) } - fn mask_type(&#self_token) -> ::MaskType { - *#self_token + fn mask_type(&self) -> ::MaskType { + *self } - fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(#self_token))) + fn canonical(&self) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self))) } #[track_caller] fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self { let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else { ::fayalite::__std::panic!("expected bundle"); }; - let #fields_token = ::fayalite::bundle::BundleType::fields(&__bundle); - ::fayalite::__std::assert_eq!(#fields_token.len(), #fields_len, "bundle has wrong number of fields"); + let __fields = ::fayalite::bundle::BundleType::fields(&__bundle); + ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields"); Self { #(#from_canonical_body_fields)* } @@ -744,34 +654,6 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_bits( - &self, - bits: &::fayalite::bitvec::slice::BitSlice, - ) -> ::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); - #mask_type_sim_value_ident { - #(#sim_value_from_bits_fields)* - } - } - fn sim_value_clone_from_bits( - &self, - value: &mut ::SimValue, - bits: &::fayalite::bitvec::slice::BitSlice, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); - #(#sim_value_clone_from_bits_fields)* - } - fn sim_value_to_bits( - &self, - value: &::SimValue, - bits: &mut ::fayalite::bitvec::slice::BitSlice, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); - #(#sim_value_to_bits_fields)* - } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics @@ -779,7 +661,7 @@ impl ToTokens for ParsedBundle { { type Builder = #unfilled_mask_type_builder_ty; type FilledBuilder = #filled_mask_type_builder_ty; - fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { + fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..]) } } @@ -794,57 +676,12 @@ impl ToTokens for ParsedBundle { impl #impl_generics ::fayalite::ty::TypeWithDeref for #mask_type_ident #type_generics #where_clause { - fn expr_deref(#this_token: &::fayalite::expr::Expr) -> &::MatchVariant { - let #this_token = *#this_token; + fn expr_deref(__this: &::fayalite::expr::Expr) -> &::MatchVariant { + let __this = *__this; let __retval = #mask_type_match_variant_ident { #(#match_variant_body_fields)* }; - ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics - #where_clause - { - type Type = #mask_type_ident #type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #mask_type_ident { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #mask_type_ident { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#mask_type_ident #type_generics> - for #mask_type_sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #mask_type_ident #type_generics, - ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #mask_type_ident #type_generics, - ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) + ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) } } #[automatically_derived] @@ -853,7 +690,6 @@ impl ToTokens for ParsedBundle { { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; - type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -863,7 +699,7 @@ impl ToTokens for ParsedBundle { ::MatchVariantAndInactiveScope, >; fn match_variants( - #this_token: ::fayalite::expr::Expr, + __this: ::fayalite::expr::Expr, __source_location: ::fayalite::source_location::SourceLocation, ) -> ::MatchVariantsIter { let __retval = #match_variant_ident { @@ -871,21 +707,21 @@ impl ToTokens for ParsedBundle { }; ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval)) } - fn mask_type(&#self_token) -> ::MaskType { + fn mask_type(&self) -> ::MaskType { #mask_type_ident { #(#mask_type_body_fields)* } } - fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(#self_token))) + fn canonical(&self) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self))) } #[track_caller] fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self { let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else { ::fayalite::__std::panic!("expected bundle"); }; - let #fields_token = ::fayalite::bundle::BundleType::fields(&__bundle); - ::fayalite::__std::assert_eq!(#fields_token.len(), #fields_len, "bundle has wrong number of fields"); + let __fields = ::fayalite::bundle::BundleType::fields(&__bundle); + ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields"); Self { #(#from_canonical_body_fields)* } @@ -893,34 +729,6 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_bits( - &self, - bits: &::fayalite::bitvec::slice::BitSlice, - ) -> ::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); - #sim_value_ident { - #(#sim_value_from_bits_fields)* - } - } - fn sim_value_clone_from_bits( - &self, - value: &mut ::SimValue, - bits: &::fayalite::bitvec::slice::BitSlice, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); - #(#sim_value_clone_from_bits_fields)* - } - fn sim_value_to_bits( - &self, - value: &::SimValue, - bits: &mut ::fayalite::bitvec::slice::BitSlice, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); - #(#sim_value_to_bits_fields)* - } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics @@ -928,7 +736,7 @@ impl ToTokens for ParsedBundle { { type Builder = #unfilled_builder_ty; type FilledBuilder = #filled_builder_ty; - fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { + fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..]) } } @@ -943,152 +751,16 @@ impl ToTokens for ParsedBundle { impl #impl_generics ::fayalite::ty::TypeWithDeref for #target #type_generics #where_clause { - fn expr_deref(#this_token: &::fayalite::expr::Expr) -> &::MatchVariant { - let #this_token = *#this_token; + fn expr_deref(__this: &::fayalite::expr::Expr) -> &::MatchVariant { + let __this = *__this; let __retval = #match_variant_ident { #(#match_variant_body_fields)* }; - ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics - #where_clause - { - type Type = #target #type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #target { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #target { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> - for #sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) + ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) } } } .to_tokens(tokens); - if let Some((cmp_eq,)) = cmp_eq { - let mut expr_where_clause = - Generics::from(generics) - .where_clause - .unwrap_or_else(|| syn::WhereClause { - where_token: Token![where](span), - predicates: Punctuated::new(), - }); - let mut sim_value_where_clause = expr_where_clause.clone(); - let mut fields_sim_value_eq = vec![]; - let mut fields_cmp_eq = vec![]; - let mut fields_cmp_ne = vec![]; - for field in fields.named() { - let field_ident = field.ident(); - let field_ty = field.ty(); - expr_where_clause - .predicates - .push(parse_quote_spanned! {cmp_eq.span=> - #field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty> - }); - sim_value_where_clause - .predicates - .push(parse_quote_spanned! {cmp_eq.span=> - #field_ty: ::fayalite::sim::value::SimValuePartialEq<#field_ty> - }); - fields_sim_value_eq.push(quote_spanned! {span=> - ::fayalite::sim::value::SimValuePartialEq::sim_value_eq(&__lhs.#field_ident, &__rhs.#field_ident) - }); - fields_cmp_eq.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident) - }); - fields_cmp_ne.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident) - }); - } - let sim_value_eq_body; - let cmp_eq_body; - let cmp_ne_body; - if fields_len == 0 { - sim_value_eq_body = quote_spanned! {span=> - true - }; - cmp_eq_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&true) - }; - cmp_ne_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&false) - }; - } else { - sim_value_eq_body = quote_spanned! {span=> - #(#fields_sim_value_eq)&&* - }; - cmp_eq_body = quote_spanned! {span=> - #(#fields_cmp_eq)&* - }; - cmp_ne_body = quote_spanned! {span=> - #(#fields_cmp_ne)|* - }; - }; - quote_spanned! {span=> - #[automatically_derived] - impl #impl_generics ::fayalite::expr::ops::ExprPartialEq for #target #type_generics - #expr_where_clause - { - fn cmp_eq( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_eq_body - } - fn cmp_ne( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_ne_body - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::SimValuePartialEq for #target #type_generics - #sim_value_where_clause - { - fn sim_value_eq( - __lhs: &::fayalite::sim::value::SimValue, - __rhs: &::fayalite::sim::value::SimValue, - ) -> bool { - #sim_value_eq_body - } - } - } - .to_tokens(tokens); - } if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { let static_generics = generics.clone().for_static_type(); let (static_impl_generics, static_type_generics, static_where_clause) = @@ -1096,7 +768,7 @@ impl ToTokens for ParsedBundle { let static_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ty = field.ty(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: <#ty as ::fayalite::ty::StaticType>::TYPE, } })); @@ -1104,34 +776,28 @@ impl ToTokens for ParsedBundle { Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ty = field.ty(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: <#ty as ::fayalite::ty::StaticType>::MASK_TYPE, } })); - let type_properties = format_ident!("__type_properties", span = span); + let type_properties = format_ident!("__type_properties", span = ident.span()); let type_properties_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| { + let ident: &Ident = field.ident().as_ref().unwrap(); let flipped = field_flip.is_some(); let ty = field.ty(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES); } })); let type_properties_mask_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| { + let ident: &Ident = field.ident().as_ref().unwrap(); let flipped = field_flip.is_some(); let ty = field.ty(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::MASK_TYPE_PROPERTIES); } })); - quote_spanned! {span=> - #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default for #mask_type_ident #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } + quote_spanned! {ident.span()=> #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics #static_where_clause @@ -1154,15 +820,6 @@ impl ToTokens for ParsedBundle { }; } #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default - for #target #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } - #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics #static_where_clause { diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index e072135..1e0b66b 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -1,11 +1,9 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use crate::{ hdl_type_common::{ common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, SplitForImpl, TypesParser, WrappedInConst, }, - kw, Errors, HdlAttr, PairsIterExt, + Errors, HdlAttr, PairsIterExt, }; use proc_macro2::TokenStream; use quote::{format_ident, quote_spanned, ToTokens}; @@ -31,7 +29,7 @@ crate::options! { pub(crate) struct ParsedVariantField { pub(crate) paren_token: Paren, pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) ty: MaybeParsed, pub(crate) comma_token: Option, } @@ -39,7 +37,7 @@ pub(crate) struct ParsedVariantField { #[derive(Clone, Debug)] pub(crate) struct ParsedVariant { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) ident: Ident, pub(crate) field: Option, } @@ -121,7 +119,7 @@ impl ParsedVariant { #[derive(Clone, Debug)] pub(crate) struct ParsedEnum { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) vis: Visibility, pub(crate) enum_token: Token![enum], pub(crate) ident: Ident, @@ -129,9 +127,6 @@ pub(crate) struct ParsedEnum { pub(crate) brace_token: Brace, pub(crate) variants: Punctuated, pub(crate) match_variant_ident: Ident, - pub(crate) sim_value_ident: Ident, - pub(crate) sim_builder_ident: Ident, - pub(crate) sim_builder_ty_field_ident: Ident, } impl ParsedEnum { @@ -147,9 +142,7 @@ impl ParsedEnum { } = item; let mut errors = Errors::new(); let mut options = errors - .unwrap_or_default(HdlAttr::::parse_and_take_attr( - &mut attrs, - )) + .unwrap_or_default(HdlAttr::::parse_and_take_attr(&mut attrs)) .unwrap_or_default(); errors.ok(options.body.validate()); let ItemOptions { @@ -158,11 +151,7 @@ impl ParsedEnum { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq, } = options.body; - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums"); - } attrs.retain(|attr| { if attr.path().is_ident("repr") { errors.error(attr, "#[repr] is not supported on #[hdl] enums"); @@ -193,9 +182,6 @@ impl ParsedEnum { brace_token, variants, match_variant_ident: format_ident!("__{}__MatchVariant", ident), - sim_value_ident: format_ident!("__{}__SimValue", ident), - sim_builder_ident: format_ident!("__{}__SimBuilder", ident), - sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()), ident, }) } @@ -213,23 +199,18 @@ impl ToTokens for ParsedEnum { brace_token, variants, match_variant_ident, - sim_value_ident, - sim_builder_ident, - sim_builder_ty_field_ident, } = self; - let span = ident.span(); let ItemOptions { outline_generated: _, target, custom_bounds: _, no_static, no_runtime_generics, - cmp_eq: _, // TODO: implement cmp_eq for enums } = &options.body; let target = get_target(target, ident); let mut struct_attrs = attrs.clone(); - struct_attrs.push(common_derives(span)); - struct_attrs.push(parse_quote_spanned! {span=> + struct_attrs.push(common_derives(ident.span())); + struct_attrs.push(parse_quote_spanned! {ident.span()=> #[allow(non_snake_case)] }); let struct_fields = Punctuated::from_iter(variants.pairs().map_pair_value_ref( @@ -253,8 +234,8 @@ impl ToTokens for ParsedEnum { colon_token = Token![:](paren_token.span.open()); ty.clone().into() } else { - colon_token = Token![:](span); - parse_quote_spanned! {span=> + colon_token = Token![:](ident.span()); + parse_quote_spanned! {ident.span()=> () } }; @@ -297,30 +278,30 @@ impl ToTokens for ParsedEnum { }) = field { let expr = ty.make_hdl_type_expr(context); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: #expr, } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: (), } } }) .collect(); - parse_quote_spanned! {span=> + parse_quote_spanned! {ident.span()=> #target { #(#fields)* } } }) } - let mut wrapped_in_const = WrappedInConst::new(tokens, span); + let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); let tokens = wrapped_in_const.inner(); { - let mut wrapped_in_const = WrappedInConst::new(tokens, span); + let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); let tokens = wrapped_in_const.inner(); let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {span=> + enum_attrs.push(parse_quote_spanned! {ident.span()=> #[allow(dead_code)] }); ItemEnum { @@ -369,7 +350,7 @@ impl ToTokens for ParsedEnum { .to_tokens(tokens); } let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {span=> + enum_attrs.push(parse_quote_spanned! {ident.span()=> #[allow(dead_code, non_camel_case_types)] }); ItemEnum { @@ -404,7 +385,7 @@ impl ToTokens for ParsedEnum { mutability: FieldMutability::None, ident: None, colon_token: None, - ty: parse_quote_spanned! {span=> + ty: parse_quote_spanned! {ident.span()=> ::fayalite::expr::Expr<#ty> }, }, @@ -418,149 +399,21 @@ impl ToTokens for ParsedEnum { )), } .to_tokens(tokens); - let mut struct_attrs = attrs.clone(); - struct_attrs.push(parse_quote_spanned! {span=> - #[allow(dead_code, non_camel_case_types)] - }); - ItemStruct { - attrs: struct_attrs, - vis: vis.clone(), - struct_token: Token![struct](enum_token.span), - ident: sim_builder_ident.clone(), - generics: generics.into(), - fields: FieldsNamed { - brace_token: *brace_token, - named: Punctuated::from_iter([Field { - attrs: vec![], - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: Some(sim_builder_ty_field_ident.clone()), - colon_token: Some(Token![:](span)), - ty: parse_quote_spanned! {span=> - #target #type_generics - }, - }]), - } - .into(), - semi_token: None, - } - .to_tokens(tokens); - let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }); - enum_attrs.push(parse_quote_spanned! {span=> - #[allow(dead_code, non_camel_case_types)] - }); - let sim_value_has_unknown_variant = !variants.len().is_power_of_two(); - let sim_value_unknown_variant_name = sim_value_has_unknown_variant.then(|| { - let mut name = String::new(); - let unknown = "Unknown"; - loop { - let orig_len = name.len(); - name.push_str(unknown); - if variants.iter().all(|v| v.ident != name) { - break Ident::new(&name, span); - } - name.truncate(orig_len); - name.push('_'); - } - }); - let sim_value_unknown_variant = - sim_value_unknown_variant_name - .as_ref() - .map(|unknown_variant_name| { - Pair::End(parse_quote_spanned! {span=> - #unknown_variant_name(::fayalite::enum_::UnknownVariantSimValue) - }) - }); - ItemEnum { - attrs: enum_attrs, - vis: vis.clone(), - enum_token: *enum_token, - ident: sim_value_ident.clone(), - generics: generics.into(), - brace_token: *brace_token, - variants: Punctuated::from_iter( - variants - .pairs() - .map_pair_value_ref( - |ParsedVariant { - attrs, - options: _, - ident, - field, - }| Variant { - attrs: attrs.clone(), - ident: ident.clone(), - fields: match field { - Some(ParsedVariantField { - paren_token, - attrs, - options: _, - ty, - comma_token, - }) => Fields::Unnamed(FieldsUnnamed { - paren_token: *paren_token, - unnamed: Punctuated::from_iter([ - Pair::new( - Field { - attrs: attrs.clone(), - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: None, - colon_token: None, - ty: parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }, - }, - Some(comma_token.unwrap_or(Token![,](ident.span()))), - ), - Pair::new( - Field { - attrs: vec![], - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: None, - colon_token: None, - ty: parse_quote_spanned! {span=> - ::fayalite::enum_::EnumPaddingSimValue - }, - }, - None, - ), - ]), - }), - None => Fields::Unnamed(parse_quote_spanned! {span=> - (::fayalite::enum_::EnumPaddingSimValue) - }), - }, - discriminant: None, - }, - ) - .chain(sim_value_unknown_variant), - ), - } - .to_tokens(tokens); - let self_token = Token![self](span); for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() { if let Some(ParsedVariantField { ty, .. }) = field { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { #[allow(non_snake_case, dead_code)] #vis fn #ident<__V: ::fayalite::expr::ToExpr>( - #self_token, + self, v: __V, ) -> ::fayalite::expr::Expr { ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::EnumLiteral::new_by_index( - #self_token, + self, #index, ::fayalite::__std::option::Option::Some( ::fayalite::expr::Expr::canonical( @@ -571,101 +424,68 @@ impl ToTokens for ParsedEnum { ) } } - #[automatically_derived] - impl #impl_generics #sim_builder_ident #type_generics - #where_clause - { - #[allow(non_snake_case, dead_code)] - #vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>( - #self_token, - v: __V, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type( - v, - #self_token.#sim_builder_ty_field_ident.#ident, - ); - ::fayalite::sim::value::SimValue::from_value( - #self_token.#sim_builder_ty_field_ident, - #sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()), - ) - } - } } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { #[allow(non_snake_case, dead_code)] - #vis fn #ident(#self_token) -> ::fayalite::expr::Expr { + #vis fn #ident(self) -> ::fayalite::expr::Expr { ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::EnumLiteral::new_by_index( - #self_token, + self, #index, ::fayalite::__std::option::Option::None, ), ) } } - #[automatically_derived] - impl #impl_generics #sim_builder_ident #type_generics - #where_clause - { - #[allow(non_snake_case, dead_code)] - #vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value( - #self_token.#sim_builder_ty_field_ident, - #sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()), - ) - } - } } } .to_tokens(tokens); } - let variants_token = Ident::new("variants", span); let from_canonical_body_fields = Vec::from_iter(variants.iter().enumerate().map( |(index, ParsedVariant { ident, field, .. })| { let ident_str = ident.to_string(); let val = if field.is_some() { let missing_value_msg = format!("expected variant {ident} to have a field"); - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::ty::Type::from_canonical(ty.expect(#missing_value_msg)) } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::__std::assert!(ty.is_none()); } }; - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: { let ::fayalite::enum_::EnumVariant { name, ty, - } = #variants_token[#index]; + } = variants[#index]; ::fayalite::__std::assert_eq!(&*name, #ident_str); #val }, } }, )); - let variant_access_token = Ident::new("variant_access", span); let match_active_scope_match_arms = Vec::from_iter(variants.iter().enumerate().map( |(index, ParsedVariant { ident, field, .. })| { if field.is_some() { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #index => #match_variant_ident::#ident( ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::VariantAccess::new_by_index( - #variant_access_token.base(), - #variant_access_token.variant_index(), + variant_access.base(), + variant_access.variant_index(), ), ), ), } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #index => #match_variant_ident::#ident, } } @@ -683,16 +503,16 @@ impl ToTokens for ParsedEnum { match field { Some(ParsedVariantField { options, .. }) => { let FieldOptions {} = options.body; - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::enum_::EnumVariant { name: ::fayalite::intern::Intern::intern(#ident_str), ty: ::fayalite::__std::option::Option::Some( - ::fayalite::ty::Type::canonical(&#self_token.#ident), + ::fayalite::ty::Type::canonical(&self.#ident), ), }, } } - None => quote_spanned! {span=> + None => quote_spanned! {ident.span()=> ::fayalite::enum_::EnumVariant { name: ::fayalite::intern::Intern::intern(#ident_str), ty: ::fayalite::__std::option::Option::None, @@ -701,151 +521,14 @@ impl ToTokens for ParsedEnum { } }, )); - let sim_value_from_bits_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = - &sim_value_unknown_variant_name - { - quote_spanned! {span=> - _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_bits()), - } - } else { - quote_spanned! {span=> - _ => ::fayalite::__std::unreachable!(), - } - }; - let sim_value_from_bits_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #index => { - let (field, padding) = v.variant_with_field_from_bits(); - #sim_value_ident::#ident(field, padding) - } - } - } else { - quote_spanned! {span=> - #index => #sim_value_ident::#ident( - v.variant_no_field_from_bits(), - ), - } - } - }, - ) - .chain([sim_value_from_bits_unknown_match_arm]), - ); - let sim_value_clone_from_bits_unknown_match_arm = - if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { - quote_spanned! {span=> - _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { - v.unknown_variant_clone_from_bits(value); - } else { - *value = #sim_value_ident::#sim_value_unknown_variant_name( - v.unknown_variant_from_bits(), - ); - }, - } - } else { - quote_spanned! {span=> - _ => ::fayalite::__std::unreachable!(), - } - }; - let sim_value_clone_from_bits_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #index => if let #sim_value_ident::#ident(field, padding) = value { - v.variant_with_field_clone_from_bits(field, padding); - } else { - let (field, padding) = v.variant_with_field_from_bits(); - *value = #sim_value_ident::#ident(field, padding); - }, - } - } else { - quote_spanned! {span=> - #index => if let #sim_value_ident::#ident(padding) = value { - v.variant_no_field_clone_from_bits(padding); - } else { - *value = #sim_value_ident::#ident( - v.variant_no_field_from_bits(), - ); - }, - } - } - }, - ) - .chain([sim_value_clone_from_bits_unknown_match_arm]), - ); - let sim_value_to_bits_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #sim_value_ident::#ident(field, padding) => { - v.variant_with_field_to_bits(#index, field, padding); - } - } - } else { - quote_spanned! {span=> - #sim_value_ident::#ident(padding) => { - v.variant_no_field_to_bits(#index, padding); - } - } - } - }, - ) - .chain(sim_value_unknown_variant_name.as_ref().map( - |sim_value_unknown_variant_name| { - quote_spanned! {span=> - #sim_value_ident::#sim_value_unknown_variant_name(value) => { - v.unknown_variant_to_bits(value); - } - } - }, - )), - ); let variants_len = variants.len(); - quote_spanned! {span=> + quote_spanned! {ident.span()=> #[automatically_derived] impl #impl_generics ::fayalite::ty::Type for #target #type_generics #where_clause { type BaseType = ::fayalite::enum_::Enum; type MaskType = ::fayalite::int::Bool; - type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = ::fayalite::module::Scope; type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope; @@ -857,11 +540,11 @@ impl ToTokens for ParsedEnum { ) -> ::MatchVariantsIter { ::fayalite::module::enum_match_variants_helper(this, source_location) } - fn mask_type(&#self_token) -> ::MaskType { + fn mask_type(&self) -> ::MaskType { ::fayalite::int::Bool } - fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token))) + fn canonical(&self) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(self))) } #[track_caller] #[allow(non_snake_case)] @@ -869,8 +552,8 @@ impl ToTokens for ParsedEnum { let ::fayalite::ty::CanonicalType::Enum(enum_) = canonical_type else { ::fayalite::__std::panic!("expected enum"); }; - let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_); - ::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants"); + let variants = ::fayalite::enum_::EnumType::variants(&enum_); + ::fayalite::__std::assert_eq!(variants.len(), #variants_len, "enum has wrong number of variants"); Self { #(#from_canonical_body_fields)* } @@ -878,86 +561,29 @@ impl ToTokens for ParsedEnum { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_bits( - &self, - bits: &::fayalite::bitvec::slice::BitSlice, - ) -> ::SimValue { - let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); - match v.discriminant() { - #(#sim_value_from_bits_match_arms)* - } - } - fn sim_value_clone_from_bits( - &self, - value: &mut ::SimValue, - bits: &::fayalite::bitvec::slice::BitSlice, - ) { - let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); - match v.discriminant() { - #(#sim_value_clone_from_bits_match_arms)* - } - } - fn sim_value_to_bits( - &self, - value: &::SimValue, - bits: &mut ::fayalite::bitvec::slice::BitSlice, - ) { - let v = ::fayalite::enum_::EnumSimValueToBits::new(*self, bits); - match value { - #(#sim_value_to_bits_match_arms)* - } - } } #[automatically_derived] impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics #where_clause { - type SimBuilder = #sim_builder_ident #type_generics; fn match_activate_scope( v: ::MatchVariantAndInactiveScope, ) -> (::MatchVariant, ::MatchActiveScope) { - let (#variant_access_token, scope) = v.activate(); + let (variant_access, scope) = v.activate(); ( - match #variant_access_token.variant_index() { + match variant_access.variant_index() { #(#match_active_scope_match_arms)* #variants_len.. => ::fayalite::__std::panic!("invalid variant index"), }, scope, ) } - fn variants(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> { + fn variants(&self) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> { ::fayalite::intern::Intern::intern(&[ #(#variants_body_variants)* ][..]) } } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> - for #sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics> - for #sim_builder_ident #type_generics - #where_clause - { - fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self { - Self { #sim_builder_ty_field_ident } - } - } } .to_tokens(tokens); if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { @@ -966,44 +592,35 @@ impl ToTokens for ParsedEnum { static_generics.split_for_impl(); let static_type_body_variants = Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| { - if field.is_some() { - quote_spanned! {span=> + if let Some(_) = field { + quote_spanned! {ident.span()=> #ident: ::fayalite::ty::StaticType::TYPE, } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> #ident: (), } } })); - let type_properties = format_ident!("__type_properties", span = span); + let type_properties = format_ident!("__type_properties", span = ident.span()); let type_properties_variants = - Vec::from_iter(variants.iter().map(|ParsedVariant { field, .. }| { + Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| { let variant = if let Some(ParsedVariantField { ty, .. }) = field { - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::__std::option::Option::Some( <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES, ) } } else { - quote_spanned! {span=> + quote_spanned! {ident.span()=> ::fayalite::__std::option::Option::None } }; - quote_spanned! {span=> + quote_spanned! {ident.span()=> let #type_properties = #type_properties.variant(#variant); } })); - quote_spanned! {span=> - #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default - for #target #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } + quote_spanned! {ident.span()=> #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics @@ -1022,34 +639,6 @@ impl ToTokens for ParsedEnum { const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; } - #[automatically_derived] - impl #static_impl_generics ::fayalite::sim::value::ToSimValue - for #sim_value_ident #static_type_generics - #static_where_clause - { - type Type = #target #static_type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - ::fayalite::sim::value::SimValue::from_value( - ::fayalite::ty::StaticType::TYPE, - ::fayalite::__std::clone::Clone::clone(self), - ) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - ::fayalite::sim::value::SimValue::from_value( - ::fayalite::ty::StaticType::TYPE, - self, - ) - } - } } .to_tokens(tokens); } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs deleted file mode 100644 index 97501e7..0000000 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -use crate::{ - hdl_type_common::{ - get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, - TypesParser, - }, - kw, Errors, HdlAttr, -}; -use proc_macro2::TokenStream; -use quote::ToTokens; -use syn::{parse_quote_spanned, Attribute, Generics, Ident, ItemType, Token, Type, Visibility}; - -#[derive(Clone, Debug)] -pub(crate) struct ParsedTypeAlias { - pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, - pub(crate) vis: Visibility, - pub(crate) type_token: Token![type], - pub(crate) ident: Ident, - pub(crate) generics: MaybeParsed, - pub(crate) eq_token: Token![=], - pub(crate) ty: MaybeParsed, - pub(crate) semi_token: Token![;], -} - -impl ParsedTypeAlias { - fn parse(item: ItemType) -> syn::Result { - let ItemType { - mut attrs, - vis, - type_token, - ident, - mut generics, - eq_token, - ty, - semi_token, - } = item; - let mut errors = Errors::new(); - let mut options = errors - .unwrap_or_default(HdlAttr::::parse_and_take_attr( - &mut attrs, - )) - .unwrap_or_default(); - errors.ok(options.body.validate()); - let ItemOptions { - outline_generated: _, - target: _, - custom_bounds, - no_static, - no_runtime_generics: _, - cmp_eq, - } = options.body; - if let Some((no_static,)) = no_static { - errors.error(no_static, "no_static is not valid on type aliases"); - } - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "cmp_eq is not valid on type aliases"); - } - let generics = if custom_bounds.is_some() { - MaybeParsed::Unrecognized(generics) - } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) { - MaybeParsed::Parsed(generics) - } else { - MaybeParsed::Unrecognized(generics) - }; - let ty = TypesParser::maybe_run(generics.as_ref(), *ty, &mut errors); - errors.finish()?; - Ok(Self { - attrs, - options, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - }) - } -} - -impl ToTokens for ParsedTypeAlias { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - attrs, - options, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } = self; - let ItemOptions { - outline_generated: _, - target, - custom_bounds: _, - no_static: _, - no_runtime_generics, - cmp_eq: _, - } = &options.body; - let target = get_target(target, ident); - let mut type_attrs = attrs.clone(); - type_attrs.push(parse_quote_spanned! {ident.span()=> - #[allow(type_alias_bounds)] - }); - ItemType { - attrs: type_attrs, - vis: vis.clone(), - type_token: *type_token, - ident: ident.clone(), - generics: generics.into(), - eq_token: *eq_token, - ty: Box::new(ty.clone().into()), - semi_token: *semi_token, - } - .to_tokens(tokens); - if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) = - (generics, ty, no_runtime_generics) - { - generics.make_runtime_generics(tokens, vis, ident, &target, |context| { - ty.make_hdl_type_expr(context) - }) - } - } -} - -pub(crate) fn hdl_type_alias_impl(item: ItemType) -> syn::Result { - let item = ParsedTypeAlias::parse(item)?; - let outline_generated = item.options.body.outline_generated; - let mut contents = item.to_token_stream(); - if outline_generated.is_some() { - contents = crate::outline_generated(contents, "hdl-type-alias-"); - } - Ok(contents) -} diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs index 2da0915..88da9a7 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use crate::{fold::impl_fold, kw, Errors, HdlAttr, PairsIterExt}; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote_spanned, ToTokens}; @@ -26,7 +24,6 @@ crate::options! { CustomBounds(custom_bounds), NoStatic(no_static), NoRuntimeGenerics(no_runtime_generics), - CmpEq(cmp_eq), } } @@ -67,7 +64,6 @@ impl Drop for WrappedInConst<'_> { fn drop(&mut self) { let inner = &self.inner; quote_spanned! {self.span=> - #[allow(clippy::type_complexity)] const _: () = { #inner }; @@ -1274,130 +1270,6 @@ make_parsed_type_or_const! { } } -#[derive(Debug, Clone)] -pub(crate) struct ParsedTypePhantomData { - pub(crate) phantom_data: known_items::PhantomData, - pub(crate) lt_token: Token![<], - pub(crate) ty: Box, - pub(crate) gt_token: Token![>], -} - -impl_fold! { - struct ParsedTypePhantomData<> { - phantom_data: known_items::PhantomData, - lt_token: Token![<], - ty: Box, - gt_token: Token![>], - } -} - -impl ParsedTypePhantomData { - pub(crate) fn try_from_named( - named: ParsedTypeNamed, - parser: &mut TypesParser<'_>, - ) -> Result, ParseFailed> { - let ParsedTypeNamed { path, args } = named; - let parsed_path = known_items::PhantomData::parse_path(path); - let phantom_data = match parsed_path { - Ok(phantom_data) => phantom_data, - Err(path) => return Ok(Err(ParsedTypeNamed { path, args })), - }; - let Some(ParsedGenericArguments { - colon2_token: _, - lt_token, - args, - gt_token, - }) = args - else { - parser - .errors() - .error(phantom_data, "PhantomData requires generic arguments"); - return Err(ParseFailed); - }; - let args_len = args.len(); - if args_len != 1 { - parser.errors().error( - phantom_data, - format_args!( - "wrong number of generic arguments supplied: got {args_len}, expected 1" - ), - ); - return Err(ParseFailed); - } - let ty = args.into_iter().next().unwrap(); - let ParsedGenericArgument::Type(ty) = ty else { - parser.errors().error(ty, "expected a type"); - return Err(ParseFailed); - }; - Ok(Ok(Self { - phantom_data, - lt_token, - ty: Box::new(ty), - gt_token, - })) - } -} - -impl From for Type { - fn from(value: ParsedTypePhantomData) -> Type { - let ParsedTypePhantomData { - phantom_data, - lt_token, - ty, - gt_token, - } = value; - let path = phantom_data.path; - let mut args = Punctuated::new(); - args.push(GenericArgument::Type(ty.into())); - let args = AngleBracketedGenericArguments { - colon2_token: Some(Token![::](lt_token.span)), - lt_token, - args, - gt_token, - }; - let mut segments = path.segments; - segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(args); - Type::Path(TypePath { - qself: None, - path: Path { - leading_colon: path.leading_colon, - segments, - }, - }) - } -} - -impl MakeHdlTypeExpr for ParsedTypePhantomData { - fn make_hdl_type_expr(&self, _context: &MakeHdlTypeExprContext) -> Expr { - let ParsedTypePhantomData { - phantom_data, - lt_token: _, - ty: _, - gt_token: _, - } = self; - Expr::Path(ExprPath { - attrs: vec![], - qself: None, - path: phantom_data.path.clone(), - }) - } -} - -impl ToTokens for ParsedTypePhantomData { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - phantom_data, - lt_token, - ty, - gt_token, - } = self; - phantom_data.to_tokens(tokens); - lt_token.to_tokens(tokens); - ty.to_tokens(tokens); - gt_token.to_tokens(tokens); - } -} - #[derive(Debug, Clone)] pub(crate) enum ParsedType { Delimited(ParsedTypeDelimited), @@ -1405,7 +1277,6 @@ pub(crate) enum ParsedType { NamedParam(ParsedTypeNamedParam), Tuple(ParsedTypeTuple), ConstUsize(ParsedTypeConstUsize), - PhantomData(ParsedTypePhantomData), Array(ParsedTypeArray), UInt(ParsedTypeUInt), SInt(ParsedTypeSInt), @@ -1420,7 +1291,6 @@ impl_fold! { NamedParam(ParsedTypeNamedParam), Tuple(ParsedTypeTuple), ConstUsize(ParsedTypeConstUsize), - PhantomData(ParsedTypePhantomData), Array(ParsedTypeArray), UInt(ParsedTypeUInt), SInt(ParsedTypeSInt), @@ -1437,7 +1307,6 @@ impl From for Type { ParsedType::NamedParam(v) => v.into(), ParsedType::Tuple(v) => v.into(), ParsedType::ConstUsize(v) => v.into(), - ParsedType::PhantomData(v) => v.into(), ParsedType::Array(v) => v.into(), ParsedType::UInt(v) => v.into(), ParsedType::SInt(v) => v.into(), @@ -1488,7 +1357,6 @@ impl ToTokens for ParsedType { ParsedType::Named(ty) => ty.to_tokens(tokens), ParsedType::Tuple(ty) => ty.to_tokens(tokens), ParsedType::ConstUsize(ty) => ty.to_tokens(tokens), - ParsedType::PhantomData(ty) => ty.to_tokens(tokens), ParsedType::Array(ty) => ty.to_tokens(tokens), ParsedType::UInt(ty) => ty.to_tokens(tokens), ParsedType::SInt(ty) => ty.to_tokens(tokens), @@ -1540,7 +1408,7 @@ impl ParseTypes for ParsedType { let mut args = None; let segments = Punctuated::from_iter(segments.pairs_mut().map_pair_value_mut(|segment| { let PathSegment { ident, arguments } = segment; - if args.is_some() { + if let Some(_) = args { parser .errors() .error(&ident, "associated types/consts are not yet implemented"); @@ -1596,10 +1464,6 @@ impl ParseTypes for ParsedType { Ok(v) => return Ok(Self::ConstUsize(v)), Err(named) => named, }; - let named = match ParsedTypePhantomData::try_from_named(named, parser)? { - Ok(v) => return Ok(Self::PhantomData(v)), - Err(named) => named, - }; let named = match ParsedTypeUInt::try_from_named(named, parser)? { Ok(v) => return Ok(Self::UInt(v)), Err(named) => named, @@ -1728,7 +1592,7 @@ impl ParseTypes for ParsedConstGenericType { let mut args = None; let segments = Punctuated::from_iter(segments.pairs_mut().map_pair_value_mut(|segment| { let PathSegment { ident, arguments } = segment; - if args.is_some() { + if let Some(_) = args { parser .errors() .error(&ident, "associated types/consts are not yet implemented"); @@ -1881,7 +1745,7 @@ impl, I, P: Clone> ParseTypes> for Punctuated< pub(crate) enum UnparsedGenericParam { Type { attrs: Vec, - options: HdlAttr, + options: HdlAttr, ident: Ident, colon_token: Token![:], bounds: ParsedBounds, @@ -1889,7 +1753,7 @@ pub(crate) enum UnparsedGenericParam { }, Const { attrs: Vec, - options: HdlAttr, + options: HdlAttr, const_token: Token![const], ident: Ident, colon_token: Token![:], @@ -1917,7 +1781,7 @@ pub(crate) mod known_items { #[allow(non_snake_case, dead_code)] pub(crate) fn $known_item(span: Span) -> $known_item { - let segments = $known_item::PATH_SEGMENTS[0].iter() + let segments = $known_item::PATH_SEGMENTS.iter() .copied() .map(|seg| PathSegment::from(Ident::new(seg, span))) .collect(); @@ -1943,21 +1807,20 @@ pub(crate) mod known_items { return Ok(Self { span: ident.span(), path }); } } - for &path_segments in Self::PATH_SEGMENTS.iter() { - if path.segments.len() == path_segments.len() - && path - .segments - .iter() - .zip(path_segments) - .all(|(seg, expected)| { - matches!(seg.arguments, PathArguments::None) - && seg.ident == *expected - }) - { - return Ok(Self { span: path.segments.last().unwrap().ident.span(), path }); - } + if path.segments.len() == Self::PATH_SEGMENTS.len() + && path + .segments + .iter() + .zip(Self::PATH_SEGMENTS) + .all(|(seg, expected)| { + matches!(seg.arguments, PathArguments::None) + && seg.ident == *expected + }) + { + Ok(Self { span: path.segments.last().unwrap().ident.span(), path }) + } else { + Err(path) } - Err(path) } #[allow(dead_code)] pub(crate) fn parse_path_with_arguments(mut path: Path) -> Result<(Self, PathArguments), Path> { @@ -2012,31 +1875,25 @@ pub(crate) mod known_items { } macro_rules! impl_known_item { - ($(#[alias = $(::$alias:ident)+])* [$(::$seg:ident)+] ::$known_item:ident) => { + ($([$(::$head:ident)*])? ::$next:ident $(::$tail:ident)+) => { + impl_known_item!([$($(::$head)*)? ::$next] $(::$tail)+); + }; + ([$(::$seg:ident)+] ::$known_item:ident) => { impl_known_item_body!($known_item); impl $known_item { - pub(crate) const PATH_SEGMENTS: &'static [&'static [&'static str]] = &[ - &[ - $(stringify!($seg),)+ - stringify!($known_item), - ], - $(&[ - $(stringify!($alias),)+ - ],)* + pub(crate) const PATH_SEGMENTS: &'static [&'static str] = &[ + $(stringify!($seg),)+ + stringify!($known_item), ]; } }; - ($(#[alias = $(::$alias:ident)+])* $([$(::$head:ident)*])? ::$next:ident $(::$tail:ident)+) => { - impl_known_item!($(#[alias = $(::$alias)+])* [$($(::$head)*)? ::$next] $(::$tail)+); - }; } impl_known_item!(::fayalite::array::Array); impl_known_item!(::fayalite::array::ArrayType); impl_known_item!(::fayalite::bundle::BundleType); impl_known_item!(::fayalite::enum_::EnumType); - impl_known_item!(::fayalite::int::BoolOrIntType); impl_known_item!(::fayalite::int::DynSize); impl_known_item!(::fayalite::int::IntType); impl_known_item!(::fayalite::int::KnownSize); @@ -2045,22 +1902,12 @@ pub(crate) mod known_items { impl_known_item!(::fayalite::int::Size); impl_known_item!(::fayalite::int::UInt); impl_known_item!(::fayalite::int::UIntType); - impl_known_item!(::fayalite::reset::ResetType); impl_known_item!(::fayalite::ty::CanonicalType); impl_known_item!(::fayalite::ty::StaticType); impl_known_item!(::fayalite::ty::Type); impl_known_item!(::fayalite::ty::Type::MaskType); impl_known_item!(::fayalite::util::ConstUsize); - impl_known_item!( - #[alias = ::std::primitive::usize] - #[alias = ::core::primitive::usize] - ::fayalite::__std::primitive::usize - ); - impl_known_item!( - #[alias = ::std::marker::PhantomData] - #[alias = ::core::marker::PhantomData] - ::fayalite::__std::marker::PhantomData - ); + impl_known_item!(::fayalite::__std::primitive::usize); } macro_rules! impl_bounds { @@ -2070,16 +1917,11 @@ macro_rules! impl_bounds { $( $Variant:ident, )* - $( - #[unknown] - $Unknown:ident, - )? } ) => { #[derive(Clone, Debug)] $vis enum $enum_type { $($Variant(known_items::$Variant),)* - $($Unknown(syn::TypeParamBound),)? } $(impl From for $enum_type { @@ -2092,54 +1934,28 @@ macro_rules! impl_bounds { fn to_tokens(&self, tokens: &mut TokenStream) { match self { $(Self::$Variant(v) => v.to_tokens(tokens),)* - $(Self::$Unknown(v) => v.to_tokens(tokens),)? } } } impl $enum_type { $vis fn parse_path(path: Path) -> Result { - #![allow(unreachable_code)] $(let path = match known_items::$Variant::parse_path(path) { Ok(v) => return Ok(Self::$Variant(v)), Err(path) => path, };)* - $(return Ok(Self::$Unknown(syn::TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - }.into()));)? Err(path) } - $vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> Result { - #![allow(unreachable_code)] - if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound { - if let syn::TraitBound { - paren_token: _, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path: _, - } = trait_bound { - match Self::parse_path(trait_bound.path) { - Ok(retval) => return Ok(retval), - Err(path) => trait_bound.path = path, - } - } - type_param_bound = trait_bound.into(); - } - $(return Ok(Self::$Unknown(type_param_bound));)? - Err(type_param_bound) - } } impl Parse for $enum_type { fn parse(input: ParseStream) -> syn::Result { - Self::parse_type_param_bound(input.parse()?) - .map_err(|type_param_bound| syn::Error::new_spanned( - type_param_bound, + Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| { + syn::Error::new_spanned( + path, format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), - )) + ) + }) } } @@ -2147,7 +1963,6 @@ macro_rules! impl_bounds { #[allow(non_snake_case)] $vis struct $struct_type { $($vis $Variant: Option,)* - $($vis $Unknown: Vec,)? } impl ToTokens for $struct_type { @@ -2159,63 +1974,42 @@ macro_rules! impl_bounds { separator = Some(::default()); v.to_tokens(tokens); })* - $(for v in &self.$Unknown { - separator.to_tokens(tokens); - separator = Some(::default()); - v.to_tokens(tokens); - })* } } const _: () = { #[derive(Clone, Debug)] - #[allow(non_snake_case)] - $vis struct Iter { - $($Variant: Option,)* - $($Unknown: std::vec::IntoIter,)? - } + $vis struct Iter($vis $struct_type); impl IntoIterator for $struct_type { type Item = $enum_type; type IntoIter = Iter; fn into_iter(self) -> Self::IntoIter { - Iter { - $($Variant: self.$Variant,)* - $($Unknown: self.$Unknown.into_iter(),)? - } + Iter(self) } } impl Iterator for Iter { type Item = $enum_type; + fn next(&mut self) -> Option { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { return Some($enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$Unknown.next() { - return Some($enum_type::$Unknown(value)); - } - )? None } #[allow(unused_mut, unused_variables)] fn fold B>(mut self, mut init: B, mut f: F) -> B { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { init = f(init, $enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$Unknown.next() { - init = f(init, $enum_type::$Unknown(value)); - } - )? init } } @@ -2227,9 +2021,6 @@ macro_rules! impl_bounds { $($enum_type::$Variant(v) => { self.$Variant = Some(v); })* - $($enum_type::$Unknown(v) => { - self.$Unknown.push(v); - })? }); } } @@ -2248,7 +2039,6 @@ macro_rules! impl_bounds { $(if let Some(v) = v.$Variant { self.$Variant = Some(v); })* - $(self.$Unknown.extend(v.$Unknown);)* }); } } @@ -2293,46 +2083,35 @@ macro_rules! impl_bounds { impl_bounds! { #[struct = ParsedBounds] pub(crate) enum ParsedBound { - BoolOrIntType, BundleType, EnumType, IntType, KnownSize, - ResetType, Size, StaticType, Type, - #[unknown] - Unknown, } } impl_bounds! { #[struct = ParsedTypeBounds] pub(crate) enum ParsedTypeBound { - BoolOrIntType, BundleType, EnumType, IntType, - ResetType, StaticType, Type, - #[unknown] - Unknown, } } impl From for ParsedBound { fn from(value: ParsedTypeBound) -> Self { match value { - ParsedTypeBound::BoolOrIntType(v) => ParsedBound::BoolOrIntType(v), ParsedTypeBound::BundleType(v) => ParsedBound::BundleType(v), ParsedTypeBound::EnumType(v) => ParsedBound::EnumType(v), ParsedTypeBound::IntType(v) => ParsedBound::IntType(v), - ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v), ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v), ParsedTypeBound::Type(v) => ParsedBound::Type(v), - ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v), } } } @@ -2340,26 +2119,20 @@ impl From for ParsedBound { impl From for ParsedBounds { fn from(value: ParsedTypeBounds) -> Self { let ParsedTypeBounds { - BoolOrIntType, BundleType, EnumType, IntType, - ResetType, StaticType, Type, - Unknown, } = value; Self { - BoolOrIntType, BundleType, EnumType, IntType, KnownSize: None, - ResetType, Size: None, StaticType, Type, - Unknown, } } } @@ -2368,10 +2141,6 @@ impl ParsedTypeBound { fn implied_bounds(self) -> ParsedTypeBounds { let span = self.span(); match self { - Self::BoolOrIntType(v) => ParsedTypeBounds::from_iter([ - ParsedTypeBound::from(v), - ParsedTypeBound::Type(known_items::Type(span)), - ]), Self::BundleType(v) => ParsedTypeBounds::from_iter([ ParsedTypeBound::from(v), ParsedTypeBound::Type(known_items::Type(span)), @@ -2382,12 +2151,6 @@ impl ParsedTypeBound { ]), Self::IntType(v) => ParsedTypeBounds::from_iter([ ParsedTypeBound::from(v), - ParsedTypeBound::BoolOrIntType(known_items::BoolOrIntType(span)), - ParsedTypeBound::Type(known_items::Type(span)), - ]), - Self::ResetType(v) => ParsedTypeBounds::from_iter([ - ParsedTypeBound::from(v), - ParsedTypeBound::StaticType(known_items::StaticType(span)), ParsedTypeBound::Type(known_items::Type(span)), ]), Self::StaticType(v) => ParsedTypeBounds::from_iter([ @@ -2395,7 +2158,6 @@ impl ParsedTypeBound { ParsedTypeBound::Type(known_items::Type(span)), ]), Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]), - Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]), } } } @@ -2421,16 +2183,13 @@ impl From for ParsedBounds { fn from(value: ParsedSizeTypeBounds) -> Self { let ParsedSizeTypeBounds { KnownSize, Size } = value; Self { - BoolOrIntType: None, BundleType: None, EnumType: None, IntType: None, KnownSize, - ResetType: None, Size, StaticType: None, Type: None, - Unknown: vec![], } } } @@ -2458,7 +2217,6 @@ impl ParsedBounds { fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory { let mut type_bounds = None; let mut size_type_bounds = None; - let mut unknown_bounds = vec![]; self.into_iter().for_each(|bound| match bound.categorize() { ParsedBoundCategory::Type(bound) => { type_bounds @@ -2470,37 +2228,15 @@ impl ParsedBounds { .get_or_insert_with(ParsedSizeTypeBounds::default) .extend([bound]); } - ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound), }); - match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) { - (None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds { + match (type_bounds, size_type_bounds) { + (None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds { Type: Some(known_items::Type(span)), ..Default::default() }), - (None, None, false) => { - errors.error( - unknown_bounds.remove(0), - "unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds", - ); - ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..Default::default() - }) - } - (None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds), - (None, Some(bounds), false) => { - // TODO: implement - errors.error( - unknown_bounds.remove(0), - "unknown bounds with `Size` bounds are not implemented", - ); - ParsedBoundsCategory::SizeType(bounds) - } - (Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..bounds - }), - (Some(type_bounds), Some(size_type_bounds), _) => { + (None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds), + (Some(bounds), None) => ParsedBoundsCategory::Type(bounds), + (Some(type_bounds), Some(size_type_bounds)) => { errors.error( size_type_bounds .Size @@ -2517,29 +2253,24 @@ impl ParsedBounds { pub(crate) enum ParsedBoundCategory { Type(ParsedTypeBound), SizeType(ParsedSizeTypeBound), - Unknown(syn::TypeParamBound), } impl ParsedBound { fn categorize(self) -> ParsedBoundCategory { match self { - Self::BoolOrIntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::BoolOrIntType(v)), Self::BundleType(v) => ParsedBoundCategory::Type(ParsedTypeBound::BundleType(v)), Self::EnumType(v) => ParsedBoundCategory::Type(ParsedTypeBound::EnumType(v)), Self::IntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::IntType(v)), Self::KnownSize(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::KnownSize(v)), - Self::ResetType(v) => ParsedBoundCategory::Type(ParsedTypeBound::ResetType(v)), Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)), Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)), Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)), - Self::Unknown(v) => ParsedBoundCategory::Unknown(v), } } fn implied_bounds(self) -> ParsedBounds { match self.categorize() { ParsedBoundCategory::Type(v) => v.implied_bounds().into(), ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(), - ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]), } } } @@ -2547,7 +2278,7 @@ impl ParsedBound { #[derive(Debug, Clone)] pub(crate) struct ParsedTypeParam { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) ident: Ident, pub(crate) colon_token: Token![:], pub(crate) bounds: ParsedTypeBounds, @@ -2581,7 +2312,7 @@ impl ToTokens for ParsedTypeParam { #[derive(Debug, Clone)] pub(crate) struct ParsedSizeTypeParam { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) ident: Ident, pub(crate) colon_token: Token![:], pub(crate) bounds: ParsedSizeTypeBounds, @@ -2625,7 +2356,7 @@ pub(crate) struct ParsedConstParamWhereBounds { #[derive(Debug, Clone)] pub(crate) struct ParsedConstParam { pub(crate) attrs: Vec, - pub(crate) options: HdlAttr, + pub(crate) options: HdlAttr, pub(crate) const_token: Token![const], pub(crate) ident: Ident, pub(crate) colon_token: Token![:], @@ -2682,7 +2413,7 @@ impl ParsedGenericParam { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub(crate) struct ParsedGenerics { pub(crate) lt_token: Option, pub(crate) params: Punctuated, @@ -2842,7 +2573,6 @@ impl ParsedGenerics { } }) .collect(); - let param_token = Ident::new("__param", ident.span()); for (param_count, (generics_accumulation_type, next_param)) in generics_accumulation_types .iter() .zip(&self.params) @@ -2891,7 +2621,7 @@ impl ParsedGenerics { next_generics.split_for_impl(); let next_turbofish = next_type_generics.as_turbofish(); let mut param: Expr = parse_quote_spanned! {ident.span()=> - #param_token + __param }; let mut generics = next_generics.clone(); let mut index_type = param_ident.clone(); @@ -2906,7 +2636,7 @@ impl ParsedGenerics { is_const: false, }); param = parse_quote_spanned! {ident.span()=> - ::fayalite::ty::TypeOrDefault::get(#param_token, || #default_expr) + ::fayalite::ty::TypeOrDefault::get(__param, || #default_expr) }; let context = MakeHdlTypeExprContext { named_param_values: self_members[..param_count] @@ -2971,8 +2701,8 @@ impl ParsedGenerics { { type Output = #next_target #next_type_generics; - fn index(&self, #param_token: #index_type) -> &Self::Output { - ::fayalite::intern::Interned::into_inner( + fn index(&self, __param: #index_type) -> &Self::Output { + ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) } @@ -2992,7 +2722,7 @@ impl ParsedGenerics { .iter() .cloned() .chain([parse_quote_spanned! {ident.span()=> - #param_token + __param }]) .collect(), is_const: false, @@ -3031,8 +2761,8 @@ impl ParsedGenerics { { type Output = #next_target #next_target_args; - fn index(&self, #param_token: #param_ident) -> &Self::Output { - ::fayalite::intern::Interned::into_inner( + fn index(&self, __param: #param_ident) -> &Self::Output { + ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) } @@ -3059,7 +2789,7 @@ impl ParsedGenerics { .iter() .cloned() .chain([parse_quote_spanned! {ident.span()=> - #param_token + __param }]) .collect(), is_const: false, @@ -3101,8 +2831,8 @@ impl ParsedGenerics { { type Output = #next_target #next_target_args; - fn index(&self, #param_token: __Param) -> &Self::Output { - ::fayalite::intern::Interned::into_inner( + fn index(&self, __param: __Param) -> &Self::Output { + ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) } @@ -3133,11 +2863,9 @@ impl ParsedGenerics { let (input_param, punct) = input_param.into_tuple(); let (unparsed_param, late_parsed_param) = match input_param { GenericParam::Lifetime(param) => { - errors.unwrap_or_default( - HdlAttr::::parse_and_take_attr( - &mut param.attrs, - ), - ); + errors.unwrap_or_default(HdlAttr::::parse_and_take_attr( + &mut param.attrs, + )); errors.error(param, "lifetime generics are not supported by #[hdl]"); continue; } @@ -3151,9 +2879,7 @@ impl ParsedGenerics { }) => { let span = ident.span(); let options = errors - .unwrap_or_default( - HdlAttr::::parse_and_take_attr(attrs), - ) + .unwrap_or_default(HdlAttr::::parse_and_take_attr(attrs)) .unwrap_or_default(); let colon_token = colon_token.unwrap_or_else(|| Token![:](span)); if !bounds.is_empty() { @@ -3191,9 +2917,7 @@ impl ParsedGenerics { default, }) => { let options = errors - .unwrap_or_default( - HdlAttr::::parse_and_take_attr(attrs), - ) + .unwrap_or_default(HdlAttr::::parse_and_take_attr(attrs)) .unwrap_or_default(); if let Some(default) = default { let _ = eq_token; @@ -3413,29 +3137,17 @@ impl ParsedGenerics { .Type .get_or_insert_with(|| known_items::Type(bound.span())); match bound { - ParsedTypeBound::BoolOrIntType(_) - | ParsedTypeBound::BundleType(_) + ParsedTypeBound::BundleType(_) | ParsedTypeBound::EnumType(_) - | ParsedTypeBound::IntType(_) - | ParsedTypeBound::ResetType(_) => { - errors.error(bound, "bounds on mask types are not implemented"); + | ParsedTypeBound::IntType(_) => { + errors.error(bound, "bound on mask type not implemented"); } ParsedTypeBound::StaticType(bound) => { if bounds.StaticType.is_none() { - errors.error( - bound, - "StaticType bound on mask type without corresponding \ - StaticType bound on original type is not implemented", - ); + errors.error(bound, "StaticType bound on mask type without corresponding StaticType bound on original type is not implemented"); } - } + }, ParsedTypeBound::Type(_) => {} - ParsedTypeBound::Unknown(_) => { - errors.error( - bound, - "unknown bounds on mask types are not implemented", - ); - } } } bounds.add_implied_bounds(); @@ -3815,7 +3527,7 @@ impl SplitForImpl for Generics { Self::TypeGenerics<'_>, Self::WhereClause<'_>, ) { - Generics::split_for_impl(self) + Generics::split_for_impl(&self) } } @@ -4229,7 +3941,6 @@ impl MakeHdlTypeExpr for ParsedType { Self::NamedParam(v) => v.make_hdl_type_expr(context), Self::Tuple(v) => v.make_hdl_type_expr(context), Self::ConstUsize(v) => v.make_hdl_type_expr(context), - Self::PhantomData(v) => v.make_hdl_type_expr(context), Self::Array(v) => v.make_hdl_type_expr(context), Self::UInt(v) => v.make_hdl_type_expr(context), Self::SInt(v) => v.make_hdl_type_expr(context), @@ -4276,13 +3987,7 @@ impl MakeHdlTypeExpr for ParsedExpr { match self { ParsedExpr::Delimited(expr) => expr.make_hdl_type_expr(context), ParsedExpr::NamedParamConst(expr) => expr.make_hdl_type_expr(context), - ParsedExpr::Other(expr) => { - let span = expr.span(); - let const_usize = known_items::ConstUsize(span); - parse_quote_spanned! {expr.span()=> - #const_usize::<{ #expr }> - } - } + ParsedExpr::Other(expr) => (**expr).clone(), } } } diff --git a/crates/fayalite-proc-macros-impl/src/lib.rs b/crates/fayalite-proc-macros-impl/src/lib.rs index 4f7c4f0..94fb040 100644 --- a/crates/fayalite-proc-macros-impl/src/lib.rs +++ b/crates/fayalite-proc-macros-impl/src/lib.rs @@ -3,43 +3,22 @@ #![cfg_attr(test, recursion_limit = "512")] use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; -use std::{ - collections::{hash_map::Entry, HashMap}, - io::{ErrorKind, Write}, -}; +use std::io::{ErrorKind, Write}; use syn::{ - bracketed, - ext::IdentExt, - parenthesized, + bracketed, parenthesized, parse::{Parse, ParseStream, Parser}, parse_quote, - punctuated::{Pair, Punctuated}, - spanned::Spanned, - token::{Bracket, Paren}, - AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, + punctuated::Pair, + AttrStyle, Attribute, Error, Item, Token, }; mod fold; mod hdl_bundle; mod hdl_enum; -mod hdl_type_alias; mod hdl_type_common; mod module; -mod process_cfg; - -pub(crate) trait CustomToken: - Copy - + Spanned - + ToTokens - + std::fmt::Debug - + Eq - + std::hash::Hash - + Default - + quote::IdentFragment - + Parse -{ - const IDENT_STR: &'static str; -} +//mod value_derive_common; +//mod value_derive_struct; mod kw { pub(crate) use syn::token::Extern as extern_; @@ -59,26 +38,14 @@ mod kw { } crate::fold::no_op_fold!($kw); - - impl crate::CustomToken for $kw { - const IDENT_STR: &'static str = stringify!($kw); - } }; } - custom_keyword!(__evaluated_cfgs); - custom_keyword!(all); - custom_keyword!(any); - custom_keyword!(cfg); - custom_keyword!(cfg_attr); custom_keyword!(clock_domain); - custom_keyword!(cmp_eq); custom_keyword!(connect_inexact); custom_keyword!(custom_bounds); custom_keyword!(flip); custom_keyword!(hdl); - custom_keyword!(hdl_module); - custom_keyword!(incomplete_wire); custom_keyword!(input); custom_keyword!(instance); custom_keyword!(m); @@ -88,12 +55,11 @@ mod kw { custom_keyword!(no_reset); custom_keyword!(no_runtime_generics); custom_keyword!(no_static); - custom_keyword!(not); custom_keyword!(outline_generated); custom_keyword!(output); custom_keyword!(reg_builder); custom_keyword!(reset); - custom_keyword!(sim); + custom_keyword!(reset_default); custom_keyword!(skip); custom_keyword!(target); custom_keyword!(wire); @@ -102,34 +68,34 @@ mod kw { type Pound = Token![#]; // work around https://github.com/rust-lang/rust/issues/50676 #[derive(Clone, Debug)] -pub(crate) struct HdlAttr { +pub(crate) struct HdlAttr { pub(crate) pound_token: Pound, pub(crate) style: AttrStyle, pub(crate) bracket_token: syn::token::Bracket, - pub(crate) kw: KW, + pub(crate) hdl: kw::hdl, pub(crate) paren_token: Option, pub(crate) body: T, } crate::fold::impl_fold! { - struct HdlAttr { + struct HdlAttr { pound_token: Pound, style: AttrStyle, bracket_token: syn::token::Bracket, - kw: KW, + hdl: kw::hdl, paren_token: Option, body: T, } } #[allow(dead_code)] -impl HdlAttr { - pub(crate) fn split_body(self) -> (HdlAttr<(), KW>, T) { +impl HdlAttr { + pub(crate) fn split_body(self) -> (HdlAttr<()>, T) { let Self { pound_token, style, bracket_token, - kw, + hdl, paren_token, body, } = self; @@ -138,19 +104,19 @@ impl HdlAttr { pound_token, style, bracket_token, - kw, + hdl, paren_token, body: (), }, body, ) } - pub(crate) fn replace_body(self, body: T2) -> HdlAttr { + pub(crate) fn replace_body(self, body: T2) -> HdlAttr { let Self { pound_token, style, bracket_token, - kw, + hdl, paren_token, body: _, } = self; @@ -158,20 +124,17 @@ impl HdlAttr { pound_token, style, bracket_token, - kw, + hdl, paren_token, body, } } - pub(crate) fn as_ref(&self) -> HdlAttr<&T, KW> - where - KW: Clone, - { + pub(crate) fn as_ref(&self) -> HdlAttr<&T> { let Self { pound_token, style, bracket_token, - ref kw, + hdl, paren_token, ref body, } = *self; @@ -179,20 +142,17 @@ impl HdlAttr { pound_token, style, bracket_token, - kw: kw.clone(), + hdl, paren_token, body, } } - pub(crate) fn try_map Result>( - self, - f: F, - ) -> Result, E> { + pub(crate) fn try_map Result>(self, f: F) -> Result, E> { let Self { pound_token, style, bracket_token, - kw, + hdl, paren_token, body, } = self; @@ -200,17 +160,17 @@ impl HdlAttr { pound_token, style, bracket_token, - kw, + hdl, paren_token, body: f(body)?, }) } - pub(crate) fn map R>(self, f: F) -> HdlAttr { + pub(crate) fn map R>(self, f: F) -> HdlAttr { let Self { pound_token, style, bracket_token, - kw, + hdl, paren_token, body, } = self; @@ -218,7 +178,7 @@ impl HdlAttr { pound_token, style, bracket_token, - kw, + hdl, paren_token, body: f(body), } @@ -226,32 +186,31 @@ impl HdlAttr { fn to_attr(&self) -> Attribute where T: ToTokens, - KW: ToTokens, { parse_quote! { #self } } } -impl Default for HdlAttr { +impl Default for HdlAttr { fn default() -> Self { T::default().into() } } -impl From for HdlAttr { +impl From for HdlAttr { fn from(body: T) -> Self { HdlAttr { pound_token: Default::default(), style: AttrStyle::Outer, bracket_token: Default::default(), - kw: Default::default(), + hdl: Default::default(), paren_token: Default::default(), body, } } } -impl ToTokens for HdlAttr { +impl ToTokens for HdlAttr { fn to_tokens(&self, tokens: &mut TokenStream) { self.pound_token.to_tokens(tokens); match self.style { @@ -259,7 +218,7 @@ impl ToTokens for HdlAttr { AttrStyle::Outer => {} }; self.bracket_token.surround(tokens, |tokens| { - self.kw.to_tokens(tokens); + self.hdl.to_tokens(tokens); match self.paren_token { Some(paren_token) => { paren_token.surround(tokens, |tokens| self.body.to_tokens(tokens)) @@ -267,7 +226,7 @@ impl ToTokens for HdlAttr { None => { let body = self.body.to_token_stream(); if !body.is_empty() { - syn::token::Paren(self.kw.span()) + syn::token::Paren(self.hdl.span) .surround(tokens, |tokens| tokens.extend([body])); } } @@ -276,24 +235,18 @@ impl ToTokens for HdlAttr { } } -fn is_hdl_attr(attr: &Attribute) -> bool { - attr.path().is_ident(KW::IDENT_STR) +fn is_hdl_attr(attr: &Attribute) -> bool { + attr.path().is_ident("hdl") } -impl HdlAttr { - fn parse_and_take_attr(attrs: &mut Vec) -> syn::Result> - where - KW: ToTokens, - { +impl HdlAttr { + fn parse_and_take_attr(attrs: &mut Vec) -> syn::Result> { let mut retval = None; let mut errors = Errors::new(); attrs.retain(|attr| { - if let Ok(kw) = syn::parse2::(attr.path().to_token_stream()) { + if is_hdl_attr(attr) { if retval.is_some() { - errors.push(Error::new_spanned( - attr, - format_args!("more than one #[{}] attribute", kw.to_token_stream()), - )); + errors.push(Error::new_spanned(attr, "more than one #[hdl] attribute")); } errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v))); false @@ -304,19 +257,13 @@ impl HdlAttr { errors.finish()?; Ok(retval) } - fn parse_and_leave_attr(attrs: &[Attribute]) -> syn::Result> - where - KW: ToTokens, - { + fn parse_and_leave_attr(attrs: &[Attribute]) -> syn::Result> { let mut retval = None; let mut errors = Errors::new(); for attr in attrs { - if let Ok(kw) = syn::parse2::(attr.path().to_token_stream()) { + if is_hdl_attr(attr) { if retval.is_some() { - errors.push(Error::new_spanned( - attr, - format_args!("more than one #[{}] attribute", kw.to_token_stream()), - )); + errors.push(Error::new_spanned(attr, "more than one #[hdl] attribute")); } errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v))); } @@ -337,7 +284,7 @@ impl HdlAttr { ) -> syn::Result { let bracket_content; let bracket_token = bracketed!(bracket_content in input); - let kw = bracket_content.parse()?; + let hdl = bracket_content.parse()?; let paren_content; let body; let paren_token; @@ -358,7 +305,7 @@ impl HdlAttr { pound_token, style, bracket_token, - kw, + hdl, paren_token, body, }) @@ -866,7 +813,6 @@ macro_rules! options { }; } -use crate::hdl_type_alias::hdl_type_alias_impl; pub(crate) use options; pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStream { @@ -906,372 +852,25 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr } } -fn hdl_module_impl(item: ItemFn) -> syn::Result { - let func = module::ModuleFn::parse_from_fn(item)?; - let options = func.config_options(); +pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result { + let options = syn::parse2::(attr)?; + let options = HdlAttr::from(options); + let func = syn::parse2::(quote! { #options #item })?; let mut contents = func.generate(); - if options.outline_generated.is_some() { + if options.body.outline_generated.is_some() { contents = outline_generated(contents, "module-"); } Ok(contents) } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) enum CfgExpr { - Option { - ident: Ident, - value: Option<(Token![=], LitStr)>, - }, - All { - all: kw::all, - paren: Paren, - exprs: Punctuated, - }, - Any { - any: kw::any, - paren: Paren, - exprs: Punctuated, - }, - Not { - not: kw::not, - paren: Paren, - expr: Box, - trailing_comma: Option, - }, -} - -impl Parse for CfgExpr { - fn parse(input: ParseStream) -> syn::Result { - match input.cursor().ident() { - Some((_, cursor)) if cursor.eof() => { - return Ok(CfgExpr::Option { - ident: input.call(Ident::parse_any)?, - value: None, - }); - } - _ => {} - } - if input.peek(Ident::peek_any) && input.peek2(Token![=]) { - return Ok(CfgExpr::Option { - ident: input.call(Ident::parse_any)?, - value: Some((input.parse()?, input.parse()?)), - }); - } - let contents; - if input.peek(kw::all) { - Ok(CfgExpr::All { - all: input.parse()?, - paren: parenthesized!(contents in input), - exprs: contents.call(Punctuated::parse_terminated)?, - }) - } else if input.peek(kw::any) { - Ok(CfgExpr::Any { - any: input.parse()?, - paren: parenthesized!(contents in input), - exprs: contents.call(Punctuated::parse_terminated)?, - }) - } else if input.peek(kw::not) { - Ok(CfgExpr::Not { - not: input.parse()?, - paren: parenthesized!(contents in input), - expr: contents.parse()?, - trailing_comma: contents.parse()?, - }) - } else { - Err(input.error("expected cfg-pattern")) - } - } -} - -impl ToTokens for CfgExpr { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - CfgExpr::Option { ident, value } => { - ident.to_tokens(tokens); - if let Some((eq, value)) = value { - eq.to_tokens(tokens); - value.to_tokens(tokens); - } - } - CfgExpr::All { all, paren, exprs } => { - all.to_tokens(tokens); - paren.surround(tokens, |tokens| exprs.to_tokens(tokens)); - } - CfgExpr::Any { any, paren, exprs } => { - any.to_tokens(tokens); - paren.surround(tokens, |tokens| exprs.to_tokens(tokens)); - } - CfgExpr::Not { - not, - paren, - expr, - trailing_comma, - } => { - not.to_tokens(tokens); - paren.surround(tokens, |tokens| { - expr.to_tokens(tokens); - trailing_comma.to_tokens(tokens); - }); - } - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct Cfg { - cfg: kw::cfg, - paren: Paren, - expr: CfgExpr, - trailing_comma: Option, -} - -impl Cfg { - fn parse_meta(meta: &Meta) -> syn::Result { - syn::parse2(meta.to_token_stream()) - } -} - -impl ToTokens for Cfg { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - cfg, - paren, - expr, - trailing_comma, - } = self; - cfg.to_tokens(tokens); - paren.surround(tokens, |tokens| { - expr.to_tokens(tokens); - trailing_comma.to_tokens(tokens); - }); - } -} - -impl Parse for Cfg { - fn parse(input: ParseStream) -> syn::Result { - let contents; - Ok(Self { - cfg: input.parse()?, - paren: parenthesized!(contents in input), - expr: contents.parse()?, - trailing_comma: contents.parse()?, - }) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct CfgAttr { - cfg_attr: kw::cfg_attr, - paren: Paren, - expr: CfgExpr, - comma: Token![,], - attrs: Punctuated, -} - -impl CfgAttr { - pub(crate) fn to_cfg(&self) -> Cfg { - Cfg { - cfg: kw::cfg(self.cfg_attr.span), - paren: self.paren, - expr: self.expr.clone(), - trailing_comma: None, - } - } - fn parse_meta(meta: &Meta) -> syn::Result { - syn::parse2(meta.to_token_stream()) - } -} - -impl Parse for CfgAttr { - fn parse(input: ParseStream) -> syn::Result { - let contents; - Ok(Self { - cfg_attr: input.parse()?, - paren: parenthesized!(contents in input), - expr: contents.parse()?, - comma: contents.parse()?, - attrs: contents.call(Punctuated::parse_terminated)?, - }) - } -} - -pub(crate) struct CfgAndValue { - cfg: Cfg, - eq_token: Token![=], - value: LitBool, -} - -impl Parse for CfgAndValue { - fn parse(input: ParseStream) -> syn::Result { - Ok(Self { - cfg: input.parse()?, - eq_token: input.parse()?, - value: input.parse()?, - }) - } -} - -pub(crate) struct Cfgs { - pub(crate) bracket: Bracket, - pub(crate) cfgs_map: HashMap, - pub(crate) cfgs_list: Vec, -} - -impl Default for Cfgs { - fn default() -> Self { - Self { - bracket: Default::default(), - cfgs_map: Default::default(), - cfgs_list: Default::default(), - } - } -} - -impl Cfgs { - fn insert_cfg(&mut self, cfg: Cfg, value: T) { - match self.cfgs_map.entry(cfg) { - Entry::Occupied(_) => {} - Entry::Vacant(entry) => { - self.cfgs_list.push(entry.key().clone()); - entry.insert(value); - } - } - } -} - -impl Parse for Cfgs { - fn parse(input: ParseStream) -> syn::Result { - let contents; - let bracket = bracketed!(contents in input); - let mut cfgs_map = HashMap::new(); - let mut cfgs_list = Vec::new(); - for CfgAndValue { - cfg, - eq_token, - value, - } in contents.call(Punctuated::::parse_terminated)? - { - let _ = eq_token; - match cfgs_map.entry(cfg) { - Entry::Occupied(_) => {} - Entry::Vacant(entry) => { - cfgs_list.push(entry.key().clone()); - entry.insert(value.value); - } - } - } - Ok(Self { - bracket, - cfgs_map, - cfgs_list, - }) - } -} - -impl Parse for Cfgs<()> { - fn parse(input: ParseStream) -> syn::Result { - let contents; - let bracket = bracketed!(contents in input); - let mut cfgs_map = HashMap::new(); - let mut cfgs_list = Vec::new(); - for cfg in contents.call(Punctuated::::parse_terminated)? { - match cfgs_map.entry(cfg) { - Entry::Occupied(_) => {} - Entry::Vacant(entry) => { - cfgs_list.push(entry.key().clone()); - entry.insert(()); - } - } - } - Ok(Self { - bracket, - cfgs_map, - cfgs_list, - }) - } -} - -impl ToTokens for Cfgs<()> { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - bracket, - cfgs_map: _, - cfgs_list, - } = self; - bracket.surround(tokens, |tokens| { - for cfg in cfgs_list { - cfg.to_tokens(tokens); - ::default().to_tokens(tokens); - } - }); - } -} - -fn hdl_main( - kw: impl CustomToken, - attr: TokenStream, - item: TokenStream, -) -> syn::Result { - fn parse_evaluated_cfgs_attr( - input: ParseStream, - parse_inner: impl FnOnce(ParseStream) -> syn::Result, - ) -> syn::Result { - let _: Token![#] = input.parse()?; - let bracket_content; - bracketed!(bracket_content in input); - let _: kw::__evaluated_cfgs = bracket_content.parse()?; - let paren_content; - parenthesized!(paren_content in bracket_content); - parse_inner(&paren_content) - } - let (evaluated_cfgs, item): (_, TokenStream) = Parser::parse2( - |input: ParseStream| { - let peek = input.fork(); - if parse_evaluated_cfgs_attr(&peek, |_| Ok(())).is_ok() { - let evaluated_cfgs = parse_evaluated_cfgs_attr(input, Cfgs::::parse)?; - Ok((Some(evaluated_cfgs), input.parse()?)) - } else { - Ok((None, input.parse()?)) - } - }, - item, - )?; - let cfgs = if let Some(cfgs) = evaluated_cfgs { - cfgs - } else { - let cfgs = process_cfg::collect_cfgs(syn::parse2(item.clone())?)?; - if cfgs.cfgs_list.is_empty() { - Cfgs::default() - } else { - return Ok(quote! { - ::fayalite::__cfg_expansion_helper! { - [] - #cfgs - {#[::fayalite::#kw(#attr)]} { #item } - } - }); - } - }; - let item = syn::parse2(quote! { #[#kw(#attr)] #item })?; - let Some(item) = process_cfg::process_cfgs(item, cfgs)? else { - return Ok(TokenStream::new()); - }; +pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result { + let item = syn::parse2::(quote! { #[hdl(#attr)] #item })?; match item { Item::Enum(item) => hdl_enum::hdl_enum(item), Item::Struct(item) => hdl_bundle::hdl_bundle(item), - Item::Fn(item) => hdl_module_impl(item), - Item::Type(item) => hdl_type_alias_impl(item), _ => Err(syn::Error::new( Span::call_site(), - "top-level #[hdl] can only be used on structs, enums, type aliases, or functions", + "top-level #[hdl] can only be used on structs or enums", )), } } - -pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result { - hdl_main(kw::hdl_module::default(), attr, item) -} - -pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result { - hdl_main(kw::hdl::default(), attr, item) -} diff --git a/crates/fayalite-proc-macros-impl/src/module.rs b/crates/fayalite-proc-macros-impl/src/module.rs index 62b7837..0945abb 100644 --- a/crates/fayalite-proc-macros-impl/src/module.rs +++ b/crates/fayalite-proc-macros-impl/src/module.rs @@ -2,7 +2,6 @@ // See Notices.txt for copyright information use crate::{ hdl_type_common::{ParsedGenerics, SplitForImpl}, - kw, module::transform_body::{HdlLet, HdlLetKindIO}, options, Errors, HdlAttr, PairsIterExt, }; @@ -10,6 +9,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::HashSet; use syn::{ + parse::{Parse, ParseStream}, parse_quote, visit::{visit_pat, Visit}, Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct, @@ -59,9 +59,9 @@ impl Visit<'_> for CheckNameConflictsWithModuleBuilderVisitor<'_> { pub(crate) type ModuleIO = HdlLet; -struct ModuleFnModule { +pub(crate) struct ModuleFn { attrs: Vec, - config_options: HdlAttr, + config_options: HdlAttr, module_kind: ModuleKind, vis: Visibility, sig: Signature, @@ -70,26 +70,6 @@ struct ModuleFnModule { the_struct: TokenStream, } -enum ModuleFnImpl { - Module(ModuleFnModule), - Fn { - attrs: Vec, - config_options: HdlAttr, - vis: Visibility, - sig: Signature, - block: Box, - }, -} - -options! { - pub(crate) enum HdlOrHdlModule { - Hdl(hdl), - HdlModule(hdl_module), - } -} - -pub(crate) struct ModuleFn(ModuleFnImpl); - #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub(crate) enum ModuleKind { Extern, @@ -109,25 +89,14 @@ impl Visit<'_> for ContainsSkippedIdent<'_> { } } -impl ModuleFn { - pub(crate) fn config_options(&self) -> ConfigOptions { - let (ModuleFnImpl::Module(ModuleFnModule { - config_options: HdlAttr { body, .. }, - .. - }) - | ModuleFnImpl::Fn { - config_options: HdlAttr { body, .. }, - .. - }) = &self.0; - body.clone() - } - pub(crate) fn parse_from_fn(item: ItemFn) -> syn::Result { +impl Parse for ModuleFn { + fn parse(input: ParseStream) -> syn::Result { let ItemFn { mut attrs, vis, mut sig, block, - } = item; + } = input.parse()?; let Signature { ref constness, ref asyncness, @@ -142,60 +111,43 @@ impl ModuleFn { ref output, } = sig; let mut errors = Errors::new(); - let Some(mut config_options) = - errors.unwrap_or_default( - HdlAttr::::parse_and_take_attr(&mut attrs), - ) - else { - errors.error(sig.ident, "missing #[hdl] or #[hdl_module] attribute"); - errors.finish()?; - unreachable!(); - }; + let config_options = errors + .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs)) + .unwrap_or_default(); let ConfigOptions { outline_generated: _, extern_, } = config_options.body; - let module_kind = match (config_options.kw, extern_) { - (HdlOrHdlModule::Hdl(_), None) => None, - (HdlOrHdlModule::Hdl(_), Some(extern2)) => { - config_options.body.extern_ = None; - errors.error( - extern2.0, - "extern can only be used as #[hdl_module(extern)]", - ); - None - } - (HdlOrHdlModule::HdlModule(_), None) => Some(ModuleKind::Normal), - (HdlOrHdlModule::HdlModule(_), Some(_)) => Some(ModuleKind::Extern), + let module_kind = match extern_ { + Some(_) => ModuleKind::Extern, + None => ModuleKind::Normal, }; - if let HdlOrHdlModule::HdlModule(_) = config_options.kw { - for fn_arg in inputs { - match fn_arg { - FnArg::Receiver(_) => { - errors.push(syn::Error::new_spanned(fn_arg, "self not allowed here")); - } - FnArg::Typed(fn_arg) => { - visit_pat( - &mut CheckNameConflictsWithModuleBuilderVisitor { - errors: &mut errors, - }, - &fn_arg.pat, - ); - } + for fn_arg in inputs { + match fn_arg { + FnArg::Receiver(_) => { + errors.push(syn::Error::new_spanned(fn_arg, "self not allowed here")); + } + FnArg::Typed(fn_arg) => { + visit_pat( + &mut CheckNameConflictsWithModuleBuilderVisitor { + errors: &mut errors, + }, + &fn_arg.pat, + ); } } - if let Some(constness) = constness { - errors.push(syn::Error::new_spanned(constness, "const not allowed here")); - } - if let Some(asyncness) = asyncness { - errors.push(syn::Error::new_spanned(asyncness, "async not allowed here")); - } - if let Some(unsafety) = unsafety { - errors.push(syn::Error::new_spanned(unsafety, "unsafe not allowed here")); - } - if let Some(abi) = abi { - errors.push(syn::Error::new_spanned(abi, "extern not allowed here")); - } + } + if let Some(constness) = constness { + errors.push(syn::Error::new_spanned(constness, "const not allowed here")); + } + if let Some(asyncness) = asyncness { + errors.push(syn::Error::new_spanned(asyncness, "async not allowed here")); + } + if let Some(unsafety) = unsafety { + errors.push(syn::Error::new_spanned(unsafety, "unsafe not allowed here")); + } + if let Some(abi) = abi { + errors.push(syn::Error::new_spanned(abi, "extern not allowed here")); } let mut skipped_idents = HashSet::new(); let struct_generic_params = generics @@ -203,17 +155,14 @@ impl ModuleFn { .pairs_mut() .filter_map_pair_value_mut(|v| match v { GenericParam::Lifetime(LifetimeParam { attrs, .. }) => { - errors.unwrap_or_default( - HdlAttr::::parse_and_take_attr(attrs), - ); + errors + .unwrap_or_default(HdlAttr::::parse_and_take_attr(attrs)); None } GenericParam::Type(TypeParam { attrs, ident, .. }) | GenericParam::Const(ConstParam { attrs, ident, .. }) => { if errors - .unwrap_or_default( - HdlAttr::::parse_and_take_attr(attrs), - ) + .unwrap_or_default(HdlAttr::::parse_and_take_attr(attrs)) .is_some() { skipped_idents.insert(ident.clone()); @@ -227,7 +176,6 @@ impl ModuleFn { let struct_where_clause = generics .where_clause .as_mut() - .filter(|_| matches!(config_options.kw, HdlOrHdlModule::HdlModule(_))) .map(|where_clause| WhereClause { where_token: where_clause.where_token, predicates: where_clause @@ -250,26 +198,22 @@ impl ModuleFn { }) .collect(), }); - let struct_generics = if let HdlOrHdlModule::HdlModule(_) = config_options.kw { - let mut struct_generics = Generics { - lt_token: generics.lt_token, - params: struct_generic_params, - gt_token: generics.gt_token, - where_clause: struct_where_clause, - }; - if let Some(variadic) = variadic { - errors.push(syn::Error::new_spanned(variadic, "... not allowed here")); - } - if !matches!(output, ReturnType::Default) { - errors.push(syn::Error::new_spanned( - output, - "return type not allowed here", - )); - } - errors.ok(ParsedGenerics::parse(&mut struct_generics)) - } else { - Some(ParsedGenerics::default()) + let struct_generics = Generics { + lt_token: generics.lt_token, + params: struct_generic_params, + gt_token: generics.gt_token, + where_clause: struct_where_clause, }; + if let Some(variadic) = variadic { + errors.push(syn::Error::new_spanned(variadic, "... not allowed here")); + } + if !matches!(output, ReturnType::Default) { + errors.push(syn::Error::new_spanned( + output, + "return type not allowed here", + )); + } + let struct_generics = errors.ok(ParsedGenerics::parse(&mut { struct_generics })); let body_results = struct_generics.as_ref().and_then(|struct_generics| { errors.ok(transform_body::transform_body( module_kind, @@ -280,47 +224,6 @@ impl ModuleFn { errors.finish()?; let struct_generics = struct_generics.unwrap(); let (block, io) = body_results.unwrap(); - let config_options = match config_options { - HdlAttr { - pound_token, - style, - bracket_token, - kw: HdlOrHdlModule::Hdl((kw,)), - paren_token, - body, - } => { - debug_assert!(io.is_empty()); - return Ok(Self(ModuleFnImpl::Fn { - attrs, - config_options: HdlAttr { - pound_token, - style, - bracket_token, - kw, - paren_token, - body, - }, - vis, - sig, - block, - })); - } - HdlAttr { - pound_token, - style, - bracket_token, - kw: HdlOrHdlModule::HdlModule((kw,)), - paren_token, - body, - } => HdlAttr { - pound_token, - style, - bracket_token, - kw, - paren_token, - body, - }, - }; let (_struct_impl_generics, _struct_type_generics, struct_where_clause) = struct_generics.split_for_impl(); let struct_where_clause: Option = parse_quote! { #struct_where_clause }; @@ -356,52 +259,31 @@ impl ModuleFn { } }; let the_struct = crate::hdl_bundle::hdl_bundle(the_struct)?; - Ok(Self(ModuleFnImpl::Module(ModuleFnModule { - attrs, - config_options, - module_kind: module_kind.unwrap(), - vis, - sig, - block, - struct_generics, - the_struct, - }))) - } -} - -impl ModuleFn { - pub(crate) fn generate(self) -> TokenStream { - let ModuleFnModule { + Ok(Self { attrs, config_options, module_kind, vis, sig, - mut block, + block, struct_generics, the_struct, - } = match self.0 { - ModuleFnImpl::Module(v) => v, - ModuleFnImpl::Fn { - attrs, - config_options, - vis, - sig, - block, - } => { - let ConfigOptions { - outline_generated: _, - extern_: _, - } = config_options.body; - return ItemFn { - attrs, - vis, - sig, - block, - } - .into_token_stream(); - } - }; + }) + } +} + +impl ModuleFn { + pub(crate) fn generate(self) -> TokenStream { + let Self { + attrs, + config_options, + module_kind, + vis, + sig, + block, + struct_generics, + the_struct, + } = self; let ConfigOptions { outline_generated: _, extern_: _, @@ -439,12 +321,6 @@ impl ModuleFn { body_sig .inputs .insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder }); - block.stmts.insert( - 0, - parse_quote! { - let _ = m; - }, - ); let body_fn = ItemFn { attrs: vec![], vis: Visibility::Inherited, @@ -456,21 +332,12 @@ impl ModuleFn { let fn_name_str = fn_name.to_string(); let (_, body_type_generics, _) = body_fn.sig.generics.split_for_impl(); let body_turbofish_type_generics = body_type_generics.as_turbofish(); - let body_lambda = if param_names.is_empty() { - quote! { - __body #body_turbofish_type_generics - } - } else { - quote! { - |m| __body #body_turbofish_type_generics(m, #(#param_names,)*) - } - }; let block = parse_quote! {{ #body_fn ::fayalite::module::ModuleBuilder::run( #fn_name_str, #module_kind_value, - #body_lambda, + |m| __body #body_turbofish_type_generics(m, #(#param_names,)*), ) }}; let outer_fn = ItemFn { diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs index a0f8eb0..76e1d69 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs @@ -16,7 +16,7 @@ use std::{borrow::Borrow, convert::Infallible}; use syn::{ fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold}, parenthesized, - parse::{Parse, ParseStream}, + parse::{Nothing, Parse, ParseStream}, parse_quote, parse_quote_spanned, spanned::Spanned, token::Paren, @@ -27,13 +27,6 @@ use syn::{ mod expand_aggregate_literals; mod expand_match; -options! { - #[options = ExprOptions] - pub(crate) enum ExprOption { - Sim(sim), - } -} - options! { pub(crate) enum LetFnKind { Input(input), @@ -41,7 +34,6 @@ options! { Instance(instance), RegBuilder(reg_builder), Wire(wire), - IncompleteWire(incomplete_wire), Memory(memory), MemoryArray(memory_array), MemoryWithInit(memory_with_init), @@ -272,6 +264,11 @@ pub(crate) enum RegBuilderReset { paren: Paren, init_expr: Box, }, + ResetDefault { + dot_token: Token![.], + reset_default: kw::reset_default, + paren: Paren, + }, } impl_fold! { @@ -288,6 +285,11 @@ impl_fold! { paren: Paren, init_expr: Box, }, + ResetDefault { + dot_token: Token![.], + reset_default: kw::reset_default, + paren: Paren, + }, } } @@ -309,6 +311,11 @@ impl Parse for RegBuilderReset { paren: parenthesized!(paren_contents in input), init_expr: paren_contents.call(parse_single_fn_arg)?, }), + RegBuilderMethod::ResetDefault(reset_default) => Ok(Self::ResetDefault { + dot_token, + reset_default, + paren: parenthesized!(paren_contents in input), + }), } } } @@ -336,6 +343,15 @@ impl ToTokens for RegBuilderReset { reset.to_tokens(tokens); paren.surround(tokens, |tokens| init_expr.to_tokens(tokens)); } + RegBuilderReset::ResetDefault { + dot_token, + reset_default, + paren, + } => { + dot_token.to_tokens(tokens); + reset_default.to_tokens(tokens); + paren.surround(tokens, |_| {}); + } } } } @@ -384,6 +400,8 @@ make_builder_method_enum! { NoReset(no_reset), #[cond = need_reset] Reset(reset), + #[cond = need_reset] + ResetDefault(reset_default), } } @@ -426,13 +444,17 @@ impl HdlLetKindRegBuilder { let mut clock_domain = None; match RegBuilderMethod::parse_dot_prefixed(&input.fork(), true, true)?.1 { RegBuilderMethod::ClockDomain(_) => clock_domain = Some(input.parse()?), - RegBuilderMethod::NoReset(_) | RegBuilderMethod::Reset(_) => {} + RegBuilderMethod::NoReset(_) + | RegBuilderMethod::Reset(_) + | RegBuilderMethod::ResetDefault(_) => {} } let reset = input.parse()?; if clock_domain.is_none() { match RegBuilderMethod::parse_dot_prefixed(&input.fork(), true, false)?.1 { RegBuilderMethod::ClockDomain(_) => clock_domain = Some(input.parse()?), - RegBuilderMethod::NoReset(_) | RegBuilderMethod::Reset(_) => unreachable!(), + RegBuilderMethod::NoReset(_) + | RegBuilderMethod::Reset(_) + | RegBuilderMethod::ResetDefault(_) => unreachable!(), } } Ok(Self { @@ -511,41 +533,6 @@ impl HdlLetKindToTokens for HdlLetKindWire { } } -options! { - pub(crate) enum LetFnKindIncomplete { - IncompleteWire(incomplete_wire), - } -} - -#[derive(Clone, Debug)] -pub(crate) struct HdlLetKindIncomplete { - pub(crate) kind: LetFnKindIncomplete, - pub(crate) paren: Paren, -} - -impl ParseTypes for HdlLetKindIncomplete { - fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result { - Ok(input.clone()) - } -} - -impl_fold! { - struct HdlLetKindIncomplete<> { - kind: LetFnKindIncomplete, - paren: Paren, - } -} - -impl HdlLetKindToTokens for HdlLetKindIncomplete { - fn ty_to_tokens(&self, _tokens: &mut TokenStream) {} - - fn expr_to_tokens(&self, tokens: &mut TokenStream) { - let Self { kind, paren } = self; - kind.to_tokens(tokens); - paren.surround(tokens, |_| {}); - } -} - options! { pub(crate) enum MemoryFnName { Memory(memory), @@ -710,7 +697,6 @@ impl HdlLetKindMemory { #[derive(Clone, Debug)] pub(crate) enum HdlLetKind { IO(HdlLetKindIO), - Incomplete(HdlLetKindIncomplete), Instance(HdlLetKindInstance), RegBuilder(HdlLetKindRegBuilder), Wire(HdlLetKindWire), @@ -720,7 +706,6 @@ pub(crate) enum HdlLetKind { impl_fold! { enum HdlLetKind { IO(HdlLetKindIO), - Incomplete(HdlLetKindIncomplete), Instance(HdlLetKindInstance), RegBuilder(HdlLetKindRegBuilder), Wire(HdlLetKindWire), @@ -735,9 +720,6 @@ impl, I> ParseTypes> for HdlLetKind { ) -> Result { match input { HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO), - HdlLetKind::Incomplete(input) => { - ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete) - } HdlLetKind::Instance(input) => { ParseTypes::parse_types(input, parser).map(HdlLetKind::Instance) } @@ -889,20 +871,6 @@ impl HdlLetKindParse for HdlLetKind { ty_expr: paren_contents.call(parse_optional_fn_arg)?, })) } - LetFnKind::IncompleteWire(incomplete_wire) => { - if let Some(parsed_ty) = parsed_ty { - return Err(Error::new_spanned( - parsed_ty.1, - "type annotation not allowed for incomplete_wire", - )); - } - check_empty_m_dot(m_dot, kind)?; - let _paren_contents; - Ok(Self::Incomplete(HdlLetKindIncomplete { - kind: LetFnKindIncomplete::IncompleteWire(incomplete_wire), - paren: parenthesized!(_paren_contents in input), - })) - } LetFnKind::Memory(fn_name) => HdlLetKindMemory::rest_of_parse( input, parsed_ty, @@ -935,7 +903,6 @@ impl HdlLetKindToTokens for HdlLetKind { fn ty_to_tokens(&self, tokens: &mut TokenStream) { match self { HdlLetKind::IO(v) => v.ty_to_tokens(tokens), - HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens), HdlLetKind::Instance(v) => v.ty_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens), HdlLetKind::Wire(v) => v.ty_to_tokens(tokens), @@ -946,7 +913,6 @@ impl HdlLetKindToTokens for HdlLetKind { fn expr_to_tokens(&self, tokens: &mut TokenStream) { match self { HdlLetKind::IO(v) => v.expr_to_tokens(tokens), - HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens), HdlLetKind::Instance(v) => v.expr_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens), HdlLetKind::Wire(v) => v.expr_to_tokens(tokens), @@ -959,7 +925,7 @@ with_debug_clone_and_fold! { #[allow(dead_code)] pub(crate) struct HdlLet { pub(crate) attrs: Vec, - pub(crate) hdl_attr: HdlAttr, + pub(crate) hdl_attr: HdlAttr, pub(crate) let_token: Token![let], pub(crate) mut_token: Option, pub(crate) name: Ident, @@ -1116,7 +1082,7 @@ fn parse_quote_let_pat>( } } -pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { +fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { parse_quote_spanned! {ty.span()=> ::fayalite::expr::Expr<#ty> } @@ -1146,7 +1112,7 @@ impl ToTokens for ImplicitName { } struct Visitor<'a> { - module_kind: Option, + module_kind: ModuleKind, errors: Errors, io: Vec, block_depth: usize, @@ -1154,33 +1120,22 @@ struct Visitor<'a> { } impl Visitor<'_> { - fn take_hdl_attr( - &mut self, - attrs: &mut Vec, - ) -> Option> { + fn take_hdl_attr(&mut self, attrs: &mut Vec) -> Option> { self.errors.unwrap_or( HdlAttr::parse_and_take_attr(attrs), Some(syn::parse2::(quote! {}).unwrap().into()), ) } - fn require_normal_module_or_fn(&mut self, spanned: impl ToTokens) { + fn require_normal_module(&mut self, spanned: impl ToTokens) { match self.module_kind { - Some(ModuleKind::Extern) => { + ModuleKind::Extern => { self.errors .error(spanned, "not allowed in #[hdl_module(extern)]"); } - Some(ModuleKind::Normal) | None => {} + ModuleKind::Normal => {} } } - fn require_module(&mut self, spanned: impl ToTokens) { - match self.module_kind { - None => { - self.errors.error(spanned, "not allowed in #[hdl] fn"); - } - Some(_) => {} - } - } - fn process_hdl_if(&mut self, hdl_attr: HdlAttr, expr_if: ExprIf) -> Expr { + fn process_hdl_if(&mut self, hdl_attr: HdlAttr, expr_if: ExprIf) -> Expr { let ExprIf { attrs, if_token, @@ -1188,10 +1143,10 @@ impl Visitor<'_> { then_branch, else_branch, } = expr_if; - let (else_token, else_expr) = else_branch.unzip(); - let else_expr = else_expr.map(|else_expr| match *else_expr { - Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)), - _ => else_expr, + self.require_normal_module(if_token); + let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr { + Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if), + expr => expr, }); if let Expr::Let(ExprLet { attrs: let_attrs, @@ -1213,19 +1168,7 @@ impl Visitor<'_> { }, ); } - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - ExprIf { - attrs, - if_token, - cond: parse_quote_spanned! {if_token.span=> - *::fayalite::sim::value::SimValue::<::fayalite::int::Bool>::value(&::fayalite::sim::value::ToSimValue::into_sim_value(#cond)) - }, - then_branch, - else_branch: else_token.zip(else_expr), - } - .into() - } else if let Some(else_expr) = else_expr { + if let Some(else_expr) = else_expr { parse_quote_spanned! {if_token.span=> #(#attrs)* { @@ -1265,12 +1208,11 @@ impl Visitor<'_> { .to_tokens(expr); }); let mut attrs = hdl_let.attrs.clone(); - self.require_module(kind); match self.module_kind { - Some(ModuleKind::Extern) => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=> + ModuleKind::Extern => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=> #[allow(unused_variables)] }), - Some(ModuleKind::Normal) | None => {} + ModuleKind::Normal => {} } let let_stmt = Local { attrs, @@ -1307,7 +1249,7 @@ impl Visitor<'_> { }, semi_token, } = hdl_let; - self.require_normal_module_or_fn(instance); + self.require_normal_module(instance); let mut expr = instance.to_token_stream(); paren.surround(&mut expr, |expr| { let name_str = ImplicitName { @@ -1334,7 +1276,7 @@ impl Visitor<'_> { fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet) -> Local { let name = &hdl_let.name; let reg_builder = hdl_let.kind.reg_builder; - self.require_normal_module_or_fn(reg_builder); + self.require_normal_module(reg_builder); let mut expr = reg_builder.to_token_stream(); hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| { let name_str = ImplicitName { @@ -1359,7 +1301,7 @@ impl Visitor<'_> { no_reset.to_tokens(&mut expr); paren.surround(&mut expr, |expr| ty_expr.to_tokens(expr)); } - RegBuilderReset::Reset { .. } => { + RegBuilderReset::Reset { .. } | RegBuilderReset::ResetDefault { .. } => { hdl_let.kind.reset.to_tokens(&mut expr); } } @@ -1385,7 +1327,7 @@ impl Visitor<'_> { fn process_hdl_let_wire(&mut self, hdl_let: HdlLet) -> Local { let name = &hdl_let.name; let wire = hdl_let.kind.wire; - self.require_normal_module_or_fn(wire); + self.require_normal_module(wire); let ty_expr = unwrap_or_static_type(hdl_let.kind.ty_expr.as_ref(), wire.span()); let mut expr = wire.to_token_stream(); hdl_let.kind.paren.surround(&mut expr, |expr| { @@ -1415,36 +1357,11 @@ impl Visitor<'_> { semi_token: hdl_let.semi_token, } } - fn process_hdl_let_incomplete(&mut self, hdl_let: HdlLet) -> Local { - let name = &hdl_let.name; - let kind = hdl_let.kind.kind; - self.require_normal_module_or_fn(kind); - let mut expr = kind.to_token_stream(); - hdl_let.kind.paren.surround(&mut expr, |expr| { - ImplicitName { - name, - span: name.span(), - } - .to_tokens(expr); - }); - let mut_token = &hdl_let.mut_token; - Local { - attrs: hdl_let.attrs.clone(), - let_token: hdl_let.let_token, - pat: parse_quote! { #mut_token #name }, - init: Some(LocalInit { - eq_token: hdl_let.eq_token, - expr: parse_quote! { #expr }, - diverge: None, - }), - semi_token: hdl_let.semi_token, - } - } fn process_hdl_let_memory(&mut self, hdl_let: HdlLet) -> Local { let name = &hdl_let.name; let memory_fn = hdl_let.kind.memory_fn; let memory_fn_name = memory_fn.name(); - self.require_normal_module_or_fn(memory_fn_name); + self.require_normal_module(memory_fn_name); let mut expr = memory_fn_name.to_token_stream(); let (paren, arg) = match memory_fn { MemoryFn::Memory { @@ -1509,7 +1426,6 @@ impl Visitor<'_> { } the_match! { IO => process_hdl_let_io, - Incomplete => process_hdl_let_incomplete, Instance => process_hdl_let_instance, RegBuilder => process_hdl_let_reg_builder, Wire => process_hdl_let_wire, @@ -1605,7 +1521,7 @@ impl Visitor<'_> { } } -pub(crate) fn empty_let() -> Local { +fn empty_let() -> Local { Local { attrs: vec![], let_token: Default::default(), @@ -1627,7 +1543,7 @@ impl Fold for Visitor<'_> { } fn fold_attribute(&mut self, attr: Attribute) -> Attribute { - if is_hdl_attr::(&attr) { + if is_hdl_attr(&attr) { self.errors .error(&attr, "#[hdl] attribute not supported here"); } @@ -1687,42 +1603,19 @@ impl Fold for Visitor<'_> { Repeat => process_hdl_repeat, Struct => process_hdl_struct, Tuple => process_hdl_tuple, - MethodCall => process_hdl_method_call, - Call => process_hdl_call, } } } - fn fold_local(&mut self, mut let_stmt: Local) -> Local { + fn fold_local(&mut self, let_stmt: Local) -> Local { match self .errors - .ok(HdlAttr::::parse_and_leave_attr( - &let_stmt.attrs, - )) { + .ok(HdlAttr::::parse_and_leave_attr(&let_stmt.attrs)) + { None => return empty_let(), Some(None) => return fold_local(self, let_stmt), Some(Some(HdlAttr { .. })) => {} }; - let mut pat = &let_stmt.pat; - if let Pat::Type(pat_type) = pat { - pat = &pat_type.pat; - } - let Pat::Ident(syn::PatIdent { - attrs: _, - by_ref: None, - mutability: _, - ident: _, - subpat: None, - }) = pat - else { - let hdl_attr = - HdlAttr::::parse_and_take_attr(&mut let_stmt.attrs) - .ok() - .flatten() - .expect("already checked above"); - let let_stmt = fold_local(self, let_stmt); - return self.process_hdl_let_pat(hdl_attr, let_stmt); - }; let hdl_let = syn::parse2::>>(let_stmt.into_token_stream()); let Some(hdl_let) = self.errors.ok(hdl_let) else { return empty_let(); @@ -1753,7 +1646,7 @@ impl Fold for Visitor<'_> { } pub(crate) fn transform_body( - module_kind: Option, + module_kind: ModuleKind, mut body: Box, parsed_generics: &ParsedGenerics, ) -> syn::Result<(Box, Vec)> { diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs index 61f6c75..00ee706 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs @@ -1,103 +1,45 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information - -use crate::{ - kw, - module::transform_body::{ - expand_match::{parse_enum_path, EnumPath}, - ExprOptions, Visitor, - }, - HdlAttr, -}; +use crate::{module::transform_body::Visitor, HdlAttr}; use quote::{format_ident, quote_spanned}; -use std::mem; use syn::{ - parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::Paren, Expr, ExprArray, - ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprStruct, ExprTuple, - FieldValue, Token, TypePath, + parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, + ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath, }; impl Visitor<'_> { pub(crate) fn process_hdl_array( &mut self, - hdl_attr: HdlAttr, + hdl_attr: HdlAttr, mut expr_array: ExprArray, ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - if sim.is_some() { - for elem in &mut expr_array.elems { - *elem = parse_quote_spanned! {elem.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#elem)) - }; - } - parse_quote_spanned! {span=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_array) - } - } else { - for elem in &mut expr_array.elems { - *elem = parse_quote_spanned! {elem.span()=> - ::fayalite::expr::ToExpr::to_expr(&(#elem)) - }; - } - parse_quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&#expr_array) - } + self.require_normal_module(hdl_attr); + for elem in &mut expr_array.elems { + *elem = parse_quote_spanned! {elem.span()=> + ::fayalite::expr::ToExpr::to_expr(&(#elem)) + }; } + parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)} } pub(crate) fn process_hdl_repeat( &mut self, - hdl_attr: HdlAttr, + hdl_attr: HdlAttr, mut expr_repeat: ExprRepeat, ) -> Expr { + self.require_normal_module(hdl_attr); let repeated_value = &expr_repeat.expr; - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - if sim.is_some() { - *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#repeated_value)) - }; - parse_quote_spanned! {span=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_repeat) - } - } else { - *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> - ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) - }; - parse_quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&#expr_repeat) - } - } + *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> + ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) + }; + parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)} } pub(crate) fn process_hdl_struct( &mut self, - hdl_attr: HdlAttr, - mut expr_struct: ExprStruct, + hdl_attr: HdlAttr, + expr_struct: ExprStruct, ) -> Expr { + self.require_normal_module(&hdl_attr); let name_span = expr_struct.path.segments.last().unwrap().ident.span(); - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - let ty_path = TypePath { - qself: expr_struct.qself.take(), - path: expr_struct.path, - }; - expr_struct.path = parse_quote_spanned! {name_span=> - __SimValue::<#ty_path> - }; - for field in &mut expr_struct.fields { - let expr = &field.expr; - field.expr = parse_quote_spanned! {field.member.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)) - }; - } - return parse_quote_spanned! {name_span=> - { - type __SimValue = ::SimValue; - let value: ::fayalite::sim::value::SimValue<#ty_path> = ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_struct); - value - } - }; - } let builder_ident = format_ident!("__builder", span = name_span); let empty_builder = if expr_struct.qself.is_some() || expr_struct @@ -149,126 +91,12 @@ impl Visitor<'_> { } pub(crate) fn process_hdl_tuple( &mut self, - hdl_attr: HdlAttr, - mut expr_tuple: ExprTuple, + hdl_attr: HdlAttr, + expr_tuple: ExprTuple, ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - for element in &mut expr_tuple.elems { - *element = parse_quote_spanned! {element.span()=> - &(#element) - }; - } - parse_quote_spanned! {expr_tuple.span()=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_tuple) - } - } else { - parse_quote_spanned! {expr_tuple.span()=> - ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) - } + self.require_normal_module(hdl_attr); + parse_quote_spanned! {expr_tuple.span()=> + ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) } } - pub(crate) fn process_hdl_call( - &mut self, - hdl_attr: HdlAttr, - mut expr_call: ExprCall, - ) -> Expr { - let span = hdl_attr.kw.span; - let mut func = &mut *expr_call.func; - let EnumPath { - variant_path: _, - enum_path, - variant_name, - } = loop { - match func { - Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => { - func = &mut **expr; - } - Expr::Path(_) => { - let Expr::Path(ExprPath { attrs, qself, path }) = - mem::replace(func, Expr::PLACEHOLDER) - else { - unreachable!(); - }; - match parse_enum_path(TypePath { qself, path }) { - Ok(path) => break path, - Err(path) => { - self.errors.error(&path, "unsupported enum variant path"); - let TypePath { qself, path } = path; - *func = ExprPath { attrs, qself, path }.into(); - return expr_call.into(); - } - } - } - _ => { - self.errors.error( - &expr_call.func, - "#[hdl] function call -- function must be a possibly-parenthesized path", - ); - return expr_call.into(); - } - } - }; - self.process_hdl_method_call( - hdl_attr, - ExprMethodCall { - attrs: expr_call.attrs, - receiver: parse_quote_spanned! {span=> - <#enum_path as ::fayalite::ty::StaticType>::TYPE - }, - dot_token: Token![.](span), - method: variant_name, - turbofish: None, - paren_token: expr_call.paren_token, - args: expr_call.args, - }, - ) - } - pub(crate) fn process_hdl_method_call( - &mut self, - hdl_attr: HdlAttr, - mut expr_method_call: ExprMethodCall, - ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - // remove any number of groups and up to one paren - let mut receiver = &mut *expr_method_call.receiver; - let mut has_group = false; - let receiver = loop { - match receiver { - Expr::Group(ExprGroup { expr, .. }) => { - has_group = true; - receiver = expr; - } - Expr::Paren(ExprParen { expr, .. }) => break &mut **expr, - receiver @ Expr::Path(_) => break receiver, - _ => { - if !has_group { - self.errors.error( - &expr_method_call.receiver, - "#[hdl] on a method call needs parenthesized receiver", - ); - } - break &mut *expr_method_call.receiver; - } - } - }; - let func = if sim.is_some() { - parse_quote_spanned! {span=> - ::fayalite::enum_::enum_type_to_sim_builder - } - } else { - parse_quote_spanned! {span=> - ::fayalite::enum_::assert_is_enum_type - } - }; - *expr_method_call.receiver = ExprCall { - attrs: vec![], - func, - paren_token: Paren(span), - args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]), - } - .into(); - expr_method_call.into() - } } diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs index 68218c1..ae21a73 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs @@ -2,120 +2,22 @@ // See Notices.txt for copyright information use crate::{ fold::{impl_fold, DoFold}, - kw, - module::transform_body::{ - empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, ExprOptions, Visitor, - }, + module::transform_body::{with_debug_clone_and_fold, Visitor}, Errors, HdlAttr, PairsIterExt, }; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt}; -use std::collections::BTreeSet; use syn::{ - fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold}, + fold::{fold_arm, fold_expr_match, fold_pat, Fold}, + parse::Nothing, parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::{Brace, Paren}, - Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr, - PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment, - Token, TypePath, + Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen, + PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath, }; -macro_rules! visit_trait { - ( - $($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)* - ) => { - trait VisitMatchPat<'a> { - $(fn $fn(&mut self, $value: &'a $Value) { - $fn(self, $value); - })* - } - - $($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)* - }; -} - -visit_trait! { - fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) { - let MatchPatBinding { ident: _ } = v; - } - fn visit_match_pat_wild(_state: _, v: &MatchPatWild) { - let MatchPatWild { underscore_token: _ } = v; - } - fn visit_match_pat_rest(_state: _, v: &MatchPatRest) { - let MatchPatRest { dot2_token: _ } = v; - } - fn visit_match_pat_paren(state: _, v: &MatchPatParen) { - let MatchPatParen { paren_token: _, pat } = v; - state.visit_match_pat(pat); - } - fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen) { - let MatchPatParen { paren_token: _, pat } = v; - state.visit_match_pat_simple(pat); - } - fn visit_match_pat_or(state: _, v: &MatchPatOr) { - let MatchPatOr { leading_vert: _, cases } = v; - for v in cases { - state.visit_match_pat(v); - } - } - fn visit_match_pat_or_simple(state: _, v: &MatchPatOr) { - let MatchPatOr { leading_vert: _, cases } = v; - for v in cases { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) { - let MatchPatStructField { field_name: _, colon_token: _, pat } = v; - state.visit_match_pat_simple(pat); - } - fn visit_match_pat_struct(state: _, v: &MatchPatStruct) { - let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v; - for v in fields { - state.visit_match_pat_struct_field(v); - } - } - fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) { - let MatchPatTuple { paren_token: _, fields } = v; - for v in fields { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) { - let MatchPatEnumVariant { - match_span:_, - sim:_, - variant_path: _, - enum_path: _, - variant_name: _, - field, - } = v; - if let Some((_, v)) = field { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_simple(state: _, v: &MatchPatSimple) { - match v { - MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v), - MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v), - MatchPatSimple::Binding(v) => state.visit_match_pat_binding(v), - MatchPatSimple::Wild(v) => state.visit_match_pat_wild(v), - MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v), - } - } - fn visit_match_pat(state: _, v: &MatchPat) { - match v { - MatchPat::Simple(v) => state.visit_match_pat_simple(v), - MatchPat::Or(v) => state.visit_match_pat_or(v), - MatchPat::Paren(v) => state.visit_match_pat_paren(v), - MatchPat::Struct(v) => state.visit_match_pat_struct(v), - MatchPat::Tuple(v) => state.visit_match_pat_tuple(v), - MatchPat::EnumVariant(v) => state.visit_match_pat_enum_variant(v), - } - } -} - with_debug_clone_and_fold! { struct MatchPatBinding<> { ident: Ident, @@ -150,15 +52,6 @@ with_debug_clone_and_fold! { } } -impl

MatchPatOr

{ - /// returns the first `|` between two patterns - fn first_inner_vert(&self) -> Option { - let mut pairs = self.cases.pairs(); - pairs.next_back(); - pairs.next().and_then(|v| v.into_tuple().1.copied()) - } -} - impl ToTokens for MatchPatOr

{ fn to_tokens(&self, tokens: &mut TokenStream) { let Self { @@ -183,19 +76,6 @@ impl ToTokens for MatchPatWild { } } -with_debug_clone_and_fold! { - struct MatchPatRest<> { - dot2_token: Token![..], - } -} - -impl ToTokens for MatchPatRest { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { dot2_token } = self; - dot2_token.to_tokens(tokens); - } -} - with_debug_clone_and_fold! { struct MatchPatStructField<> { field_name: Ident, @@ -278,29 +158,9 @@ impl ToTokens for MatchPatStruct { } } -with_debug_clone_and_fold! { - struct MatchPatTuple<> { - paren_token: Paren, - fields: Punctuated, - } -} - -impl ToTokens for MatchPatTuple { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - paren_token, - fields, - } = self; - paren_token.surround(tokens, |tokens| { - fields.to_tokens(tokens); - }) - } -} - with_debug_clone_and_fold! { struct MatchPatEnumVariant<> { match_span: Span, - sim: Option<(kw::sim,)>, variant_path: Path, enum_path: Path, variant_name: Ident, @@ -312,7 +172,6 @@ impl ToTokens for MatchPatEnumVariant { fn to_tokens(&self, tokens: &mut TokenStream) { let Self { match_span, - sim, variant_path: _, enum_path, variant_name, @@ -322,28 +181,7 @@ impl ToTokens for MatchPatEnumVariant { __MatchTy::<#enum_path>::#variant_name } .to_tokens(tokens); - if sim.is_some() { - if let Some((paren_token, field)) = field { - paren_token.surround(tokens, |tokens| { - field.to_tokens(tokens); - match field { - MatchPatSimple::Paren(_) - | MatchPatSimple::Or(_) - | MatchPatSimple::Binding(_) - | MatchPatSimple::Wild(_) => quote_spanned! {*match_span=> - , _ - } - .to_tokens(tokens), - MatchPatSimple::Rest(_) => {} - } - }); - } else { - quote_spanned! {*match_span=> - (_) - } - .to_tokens(tokens); - } - } else if let Some((paren_token, field)) = field { + if let Some((paren_token, field)) = field { paren_token.surround(tokens, |tokens| field.to_tokens(tokens)); } } @@ -355,7 +193,6 @@ enum MatchPatSimple { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), - Rest(MatchPatRest), } impl_fold! { @@ -364,7 +201,6 @@ impl_fold! { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), - Rest(MatchPatRest), } } @@ -375,18 +211,17 @@ impl ToTokens for MatchPatSimple { Self::Paren(v) => v.to_tokens(tokens), Self::Binding(v) => v.to_tokens(tokens), Self::Wild(v) => v.to_tokens(tokens), - Self::Rest(v) => v.to_tokens(tokens), } } } -pub(crate) struct EnumPath { - pub(crate) variant_path: Path, - pub(crate) enum_path: Path, - pub(crate) variant_name: Ident, +struct EnumPath { + variant_path: Path, + enum_path: Path, + variant_name: Ident, } -pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result { +fn parse_enum_path(variant_path: TypePath) -> Result { let TypePath { qself: None, path: variant_path, @@ -442,7 +277,6 @@ trait ParseMatchPat: Sized { fn or(v: MatchPatOr) -> Self; fn paren(v: MatchPatParen) -> Self; fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result; - fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result; fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant) -> Result; fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result { @@ -478,7 +312,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -525,7 +358,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -610,7 +442,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -630,34 +461,7 @@ trait ParseMatchPat: Sized { }) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild { underscore_token, }))), - Pat::Tuple(PatTuple { - attrs: _, - paren_token, - elems, - }) => { - let fields = elems - .into_pairs() - .filter_map_pair_value(|field_pat| { - if let Pat::Rest(PatRest { - attrs: _, - dot2_token, - }) = field_pat - { - Some(MatchPatSimple::Rest(MatchPatRest { dot2_token })) - } else { - MatchPatSimple::parse(state, field_pat).ok() - } - }) - .collect(); - Self::tuple( - state, - MatchPatTuple { - paren_token, - fields, - }, - ) - } - Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { + Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { state .errors .error(pat, "not yet implemented in #[hdl] patterns"); @@ -692,14 +496,6 @@ impl ParseMatchPat for MatchPatSimple { Err(()) } - fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { - state.errors.push(syn::Error::new( - v.paren_token.span.open(), - "matching tuples is not yet implemented inside structs/enums in #[hdl] patterns", - )); - Err(()) - } - fn enum_variant( state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -718,7 +514,6 @@ enum MatchPat { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), - Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } @@ -728,7 +523,6 @@ impl_fold! { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), - Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } } @@ -750,10 +544,6 @@ impl ParseMatchPat for MatchPat { Ok(Self::Struct(v)) } - fn tuple(_state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { - Ok(Self::Tuple(v)) - } - fn enum_variant( _state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -769,7 +559,6 @@ impl ToTokens for MatchPat { Self::Or(v) => v.to_tokens(tokens), Self::Paren(v) => v.to_tokens(tokens), Self::Struct(v) => v.to_tokens(tokens), - Self::Tuple(v) => v.to_tokens(tokens), Self::EnumVariant(v) => v.to_tokens(tokens), } } @@ -832,6 +621,10 @@ struct RewriteAsCheckMatch { } impl Fold for RewriteAsCheckMatch { + fn fold_field_pat(&mut self, mut i: FieldPat) -> FieldPat { + i.colon_token = Some(Token![:](i.member.span())); + i + } fn fold_pat(&mut self, pat: Pat) -> Pat { match pat { Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) { @@ -946,177 +739,17 @@ impl Fold for RewriteAsCheckMatch { // don't recurse into expressions i } - fn fold_local(&mut self, mut let_stmt: Local) -> Local { - if let Some(syn::LocalInit { - eq_token, - expr: _, - diverge, - }) = let_stmt.init.take() - { - let_stmt.init = Some(syn::LocalInit { - eq_token, - expr: parse_quote_spanned! {self.span=> - __match_value - }, - diverge: diverge.map(|(else_, _expr)| { - ( - else_, - parse_quote_spanned! {self.span=> - match __infallible {} - }, - ) - }), - }); - } - fold_local(self, let_stmt) - } } struct HdlMatchParseState<'a> { - sim: Option<(kw::sim,)>, match_span: Span, errors: &'a mut Errors, } -struct HdlLetPatVisitState<'a> { - errors: &'a mut Errors, - bindings: BTreeSet<&'a Ident>, -} - -impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> { - fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) { - self.bindings.insert(&v.ident); - } - - fn visit_match_pat_or(&mut self, v: &'a MatchPatOr) { - if let Some(first_inner_vert) = v.first_inner_vert() { - self.errors.error( - first_inner_vert, - "or-patterns are not supported in let statements", - ); - } - visit_match_pat_or(self, v); - } - - fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr) { - if let Some(first_inner_vert) = v.first_inner_vert() { - self.errors.error( - first_inner_vert, - "or-patterns are not supported in let statements", - ); - } - visit_match_pat_or_simple(self, v); - } - - fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) { - self.errors.error(v, "refutable pattern in let statement"); - } -} - impl Visitor<'_> { - pub(crate) fn process_hdl_let_pat( - &mut self, - hdl_attr: HdlAttr, - mut let_stmt: Local, - ) -> Local { - let span = let_stmt.let_token.span(); - let ExprOptions { sim } = hdl_attr.body; - if let Pat::Type(pat) = &mut let_stmt.pat { - *pat.ty = wrap_ty_with_expr((*pat.ty).clone()); - } - let check_let_stmt = RewriteAsCheckMatch { span }.fold_local(let_stmt.clone()); - let Local { - attrs: _, - let_token, - pat, - init, - semi_token, - } = let_stmt; - let Some(syn::LocalInit { - eq_token, - expr, - diverge, - }) = init - else { - self.errors - .error(let_token, "#[hdl] let must be assigned a value"); - return empty_let(); - }; - if let Some((else_, _)) = diverge { - // TODO: implement let-else - self.errors - .error(else_, "#[hdl] let ... else { ... } is not implemented"); - return empty_let(); - } - let Ok(pat) = MatchPat::parse( - &mut HdlMatchParseState { - sim, - match_span: span, - errors: &mut self.errors, - }, - pat, - ) else { - return empty_let(); - }; - let mut state = HdlLetPatVisitState { - errors: &mut self.errors, - bindings: BTreeSet::new(), - }; - state.visit_match_pat(&pat); - let HdlLetPatVisitState { - errors: _, - bindings, - } = state; - let retval = if sim.is_some() { - parse_quote_spanned! {span=> - let (#(#bindings,)*) = { - type __MatchTy = ::SimValue; - let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); - #let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token - (#(#bindings,)*) - }; - } - } else { - parse_quote_spanned! {span=> - let (#(#bindings,)* __scope,) = { - type __MatchTy = ::MatchVariant; - let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); - ::fayalite::expr::check_match_expr( - __match_expr, - |__match_value, __infallible| { - #[allow(unused_variables)] - #check_let_stmt - match __infallible {} - }, - ); - let mut __match_iter = ::fayalite::module::match_(__match_expr); - let ::fayalite::__std::option::Option::Some(__match_variant) = - ::fayalite::__std::iter::Iterator::next(&mut __match_iter) - else { - ::fayalite::__std::unreachable!("#[hdl] let with uninhabited type"); - }; - let ::fayalite::__std::option::Option::None = - ::fayalite::__std::iter::Iterator::next(&mut __match_iter) - else { - ::fayalite::__std::unreachable!("#[hdl] let with refutable pattern"); - }; - let (__match_variant, __scope) = - ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( - __match_variant, - ); - #let_token #pat #eq_token __match_variant #semi_token - (#(#bindings,)* __scope,) - }; - } - }; - match retval { - syn::Stmt::Local(retval) => retval, - _ => unreachable!(), - } - } pub(crate) fn process_hdl_match( &mut self, - hdl_attr: HdlAttr, + _hdl_attr: HdlAttr, expr_match: ExprMatch, ) -> Expr { let span = expr_match.match_token.span(); @@ -1128,9 +761,8 @@ impl Visitor<'_> { brace_token: _, arms, } = expr_match; - let ExprOptions { sim } = hdl_attr.body; + self.require_normal_module(match_token); let mut state = HdlMatchParseState { - sim, match_span: span, errors: &mut self.errors, }; @@ -1138,36 +770,24 @@ impl Visitor<'_> { arms.into_iter() .filter_map(|arm| MatchArm::parse(&mut state, arm).ok()), ); - let expr = if sim.is_some() { - quote_spanned! {span=> - { - type __MatchTy = ::SimValue; - let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); - #match_token ::fayalite::sim::value::SimValue::into_value(__match_expr) { + let expr = quote_spanned! {span=> + { + type __MatchTy = ::MatchVariant; + let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); + ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { + #[allow(unused_variables)] + #check_match + }); + for __match_variant in ::fayalite::module::match_(__match_expr) { + let (__match_variant, __scope) = + ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( + __match_variant, + ); + #match_token __match_variant { #(#arms)* } } } - } else { - quote_spanned! {span=> - { - type __MatchTy = ::MatchVariant; - let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); - ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { - #[allow(unused_variables)] - #check_match - }); - for __match_variant in ::fayalite::module::match_(__match_expr) { - let (__match_variant, __scope) = - ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( - __match_variant, - ); - #match_token __match_variant { - #(#arms)* - } - } - } - } }; syn::parse2(expr).unwrap() } diff --git a/crates/fayalite-proc-macros-impl/src/process_cfg.rs b/crates/fayalite-proc-macros-impl/src/process_cfg.rs deleted file mode 100644 index 5cff08f..0000000 --- a/crates/fayalite-proc-macros-impl/src/process_cfg.rs +++ /dev/null @@ -1,2527 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{Cfg, CfgAttr, Cfgs, Errors}; -use proc_macro2::Ident; -use std::{collections::VecDeque, marker::PhantomData}; -use syn::{ - punctuated::{Pair, Punctuated}, - Token, -}; - -struct State { - cfgs: Cfgs, - errors: Errors, - _phantom: PhantomData

, -} - -impl State

{ - #[must_use] - fn eval_cfg(&mut self, cfg: Cfg) -> bool { - struct MyDispatch<'a> { - cfg: Cfg, - _phantom: PhantomData<&'a ()>, - } - impl<'a> PhaseDispatch for MyDispatch<'a> { - type Args = &'a mut State

; - type Output = bool; - - fn dispatch_collect( - self, - args: Self::Args, - ) -> Self::Output { - args.cfgs.insert_cfg(self.cfg, ()); - true - } - - fn dispatch_process( - self, - args: Self::Args, - ) -> Self::Output { - if let Some(&retval) = args.cfgs.cfgs_map.get(&self.cfg) { - retval - } else { - args.errors.error(self.cfg, "unrecognized cfg -- cfg wasn't evaluated when running `__cfg_expansion_helper!`"); - true - } - } - } - P::dispatch( - MyDispatch { - cfg, - _phantom: PhantomData, - }, - self, - ) - } - #[must_use] - fn eval_cfgs( - &mut self, - mut attrs: Vec, - ) -> Option, P>> { - let mut queue = VecDeque::from(attrs); - attrs = Vec::with_capacity(queue.len()); // cfg_attr is rare, and cfg can't increase length - while let Some(attr) = queue.pop_front() { - if attr.path().is_ident("cfg") { - if let Some(cfg) = self.errors.ok(Cfg::parse_meta(&attr.meta)) { - if !self.eval_cfg(cfg) { - return None; - } - continue; - } - } else if attr.path().is_ident("cfg_attr") { - if let Some(cfg_attr) = self.errors.ok(CfgAttr::parse_meta(&attr.meta)) { - if self.eval_cfg(cfg_attr.to_cfg()) { - // push onto queue since cfg_attr(, cfg_attr(, )) is valid - for meta in cfg_attr.attrs { - queue.push_front(syn::Attribute { - pound_token: attr.pound_token, - style: attr.style, - bracket_token: attr.bracket_token, - meta, - }); - } - } - continue; - } - } - attrs.push(attr); - } - Some(Output::new(attrs)) - } - fn process_qself_and_path( - &mut self, - qself: Option, - path: syn::Path, - ) -> Option<(Output, P>, Output)> { - let qself = if let Some(syn::QSelf { - lt_token, - ty, - position, - as_token, - gt_token, - }) = qself - { - ty.process(self)?.map(|ty| { - Some(syn::QSelf { - lt_token, - ty, - position, - as_token, - gt_token, - }) - }) - } else { - Output::new(None) - }; - let syn::Path { - leading_colon, - segments, - } = path; - // path segments don't get removed - let path = segments.process(self)?.map(|segments| syn::Path { - leading_colon, - segments, - }); - Some((qself, path)) - } -} - -trait PhaseDispatch { - type Args; - type Output; - fn dispatch_collect(self, args: Self::Args) - -> Self::Output; - fn dispatch_process(self, args: Self::Args) - -> Self::Output; -} - -trait Phase: Sized + 'static { - type Output; - type CfgsValue; - fn output_new(v: T) -> Output; - fn output_map U>(v: Output, f: F) -> Output; - fn output_zip(t: Output, u: Output) -> Output<(T, U), Self>; - fn dispatch(d: D, args: D::Args) -> D::Output; -} - -struct CollectCfgsPhase; - -impl Phase for CollectCfgsPhase { - type Output = (); - type CfgsValue = (); - - fn output_new(_v: T) -> Output { - Output(()) - } - - fn output_map U>(_v: Output, _f: F) -> Output { - Output(()) - } - - fn output_zip(_t: Output, _u: Output) -> Output<(T, U), Self> { - Output(()) - } - - fn dispatch(d: D, args: D::Args) -> D::Output { - d.dispatch_collect(args) - } -} - -struct ProcessCfgsPhase; - -impl Phase for ProcessCfgsPhase { - type Output = T; - type CfgsValue = bool; - - fn output_new(v: T) -> Output { - Output(v) - } - - fn output_map U>(v: Output, f: F) -> Output { - Output(f(v.0)) - } - - fn output_zip(t: Output, u: Output) -> Output<(T, U), Self> { - Output((t.0, u.0)) - } - - fn dispatch(d: D, args: D::Args) -> D::Output { - d.dispatch_process(args) - } -} - -struct Output(P::Output); - -trait OutputZip: Sized { - type Output; - fn zip(self) -> Output; - fn call R>(self, f: F) -> Output { - self.zip().map(f) - } -} - -impl OutputZip

for () { - type Output = (); - - fn zip(self) -> Output { - Output::new(()) - } -} - -impl OutputZip

for (Output,) { - type Output = (T,); - - fn zip(self) -> Output { - self.0.map(|v| (v,)) - } -} - -macro_rules! impl_zip { - ($first_arg:ident: $first_T:ident, $($arg:ident: $T:ident),* $(,)?) => { - impl_zip!(@step [], [($first_arg: $first_T) $(($arg: $T))*], (),); - }; - ( - @impl($first_arg:tt,), - $tuple_pat:tt, - ) => {}; - ( - @impl(($first_arg:ident: $first_T:ident), - $(($arg:ident: $T:ident),)*), - $tuple_pat:tt, - ) => { - impl<$first_T, $($T,)* P: Phase> OutputZip

for (Output<$first_T, P>, $(Output<$T, P>),*) { - type Output = ($first_T, $($T),*); - fn zip(self) -> Output<($first_T, $($T),*), P> { - let (tuples, $($arg),*) = self; - $(let tuples = P::output_zip(tuples, $arg);)* - tuples.map(|$tuple_pat| ($first_arg, $($arg),*)) - } - } - }; - ( - @step [$($cur:tt)*], - [], - $tuple_pat:tt, - ) => {}; - ( - @step [$($cur:tt)*], - [($next_arg:ident: $next_T:ident) $($rest:tt)*], - (), - ) => { - impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), $next_arg,); - impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], $next_arg,); - }; - ( - @step [$($cur:tt)*], - [($next_arg:ident: $next_T:ident) $($rest:tt)*], - $tuple_pat:tt, - ) => { - impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), ($tuple_pat, $next_arg),); - impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], ($tuple_pat, $next_arg),); - }; -} - -impl_zip!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, t11: T11); - -impl Copy for Output where P::Output: Copy {} - -impl Clone for Output -where - P::Output: Clone, -{ - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl Output { - fn new(v: T) -> Self { - P::output_new(v) - } - fn map U>(self, f: F) -> Output { - P::output_map(self, f) - } -} - -trait Process: Sized { - #[must_use] - fn process(self, state: &mut State

) -> Option>; -} - -impl Process

for syn::Item { - fn process(self, _state: &mut State

) -> Option> { - // don't recurse into items - Some(Output::new(self)) - } -} - -impl Process

for Vec { - fn process(self, state: &mut State

) -> Option> { - state.eval_cfgs(self) - } -} - -impl, P: Phase> Process

for Box { - fn process(self, state: &mut State

) -> Option> { - Some(T::process(*self, state)?.map(Box::new)) - } -} - -trait ProcessVecElement { - const REMOVE_ELEMENTS: bool; -} - -impl ProcessVecElement for syn::Arm { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessVecElement for syn::Stmt { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessVecElement for syn::ForeignItem { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessVecElement for syn::ImplItem { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessVecElement for syn::Item { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessVecElement for syn::TraitItem { - const REMOVE_ELEMENTS: bool = true; -} - -impl + ProcessVecElement, P: Phase> Process

for Vec { - fn process(self, state: &mut State

) -> Option> { - let mut output = Output::new(Vec::new()); - for value in self { - if let Some(value) = value.process(state) { - output = (output, value).call(|(mut output, value)| { - output.push(value); - output - }); - } else if !T::REMOVE_ELEMENTS { - return None; - } - } - Some(output) - } -} - -trait ProcessOption { - /// if a configured-off value causes this value to be `None` instead of propagating the configuring-off - const REMOVE_VALUE: bool; -} - -impl ProcessOption for syn::Abi { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::Block { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::WhereClause { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::Expr { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::Type { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for Box { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::AngleBracketedGenericArguments { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::ImplRestriction { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for syn::BoundLifetimes { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for (Token![=], syn::Expr) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Token![=], syn::Type) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Token![if], Box) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Token![else], Box) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Token![&], Option) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Token![as], Ident) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Ident, Token![:]) { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Option, syn::Path, Token![for]) { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for syn::BareVariadic { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::Variadic { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::LocalInit { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for syn::Label { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for syn::PatRest { - const REMOVE_VALUE: bool = true; -} - -impl ProcessOption for (Box, Token![:]) { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for (Token![@], Box) { - const REMOVE_VALUE: bool = false; -} - -impl ProcessOption for (syn::token::Brace, Vec) { - const REMOVE_VALUE: bool = false; -} - -impl + ProcessOption, P: Phase> Process

for Option { - fn process(self, state: &mut State

) -> Option> { - if let Some(this) = self { - match this.process(state) { - Some(v) => Some(v.map(Some)), - None => { - if T::REMOVE_VALUE { - Some(Output::new(None)) - } else { - None - } - } - } - } else { - Some(Output::new(None)) - } - } -} - -trait ProcessPunctuatedElement { - const REMOVE_ELEMENTS: bool; -} - -impl + ProcessPunctuatedElement, P: Phase, Punct: Default> Process

- for Punctuated -{ - fn process(self, state: &mut State

) -> Option> { - let mut output = Output::new(Punctuated::::new()); - for pair in self.into_pairs() { - let (value, punct) = pair.into_tuple(); - if let Some(value) = value.process(state) { - output = (output, value).call(|(mut output, value)| { - output.extend([Pair::new(value, punct)]); - output - }); - } else if !T::REMOVE_ELEMENTS { - return None; - } - } - Some(output) - } -} - -impl ProcessPunctuatedElement for syn::PathSegment { - const REMOVE_ELEMENTS: bool = false; -} - -impl ProcessPunctuatedElement for syn::Type { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::Expr { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::Pat { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::CapturedParam { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::GenericArgument { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::GenericParam { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::Lifetime { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::WherePredicate { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::Variant { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::FnArg { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::BareFnArg { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::TypeParamBound { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::FieldValue { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::Field { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::FieldPat { - const REMOVE_ELEMENTS: bool = true; -} - -impl ProcessPunctuatedElement for syn::UseTree { - const REMOVE_ELEMENTS: bool = true; -} - -impl, U: Process

, P: Phase> Process

for (T, U) { - fn process(self, state: &mut State

) -> Option> { - let (t, u) = self; - let t = t.process(state)?; - let u = u.process(state)?; - Some((t, u).zip()) - } -} - -impl, U: Process

, V: Process

, P: Phase> Process

for (T, U, V) { - fn process(self, state: &mut State

) -> Option> { - let (t, u, v) = self; - let t = t.process(state)?; - let u = u.process(state)?; - let v = v.process(state)?; - Some((t, u, v).zip()) - } -} - -macro_rules! process_no_op { - ($ty:ty) => { - impl Process

for $ty { - fn process(self, _state: &mut State

) -> Option> { - Some(Output::new(self)) - } - } - - impl ProcessOption for $ty { - const REMOVE_VALUE: bool = false; - } - }; -} - -process_no_op!(Token![Self]); -process_no_op!(Token![abstract]); -process_no_op!(Token![as]); -process_no_op!(Token![async]); -process_no_op!(Token![auto]); -process_no_op!(Token![await]); -process_no_op!(Token![become]); -process_no_op!(Token![box]); -process_no_op!(Token![break]); -process_no_op!(Token![const]); -process_no_op!(Token![continue]); -process_no_op!(Token![crate]); -process_no_op!(Token![default]); -process_no_op!(Token![do]); -process_no_op!(Token![dyn]); -process_no_op!(Token![else]); -process_no_op!(Token![enum]); -process_no_op!(Token![extern]); -process_no_op!(Token![final]); -process_no_op!(Token![fn]); -process_no_op!(Token![for]); -process_no_op!(Token![if]); -process_no_op!(Token![impl]); -process_no_op!(Token![in]); -process_no_op!(Token![let]); -process_no_op!(Token![loop]); -process_no_op!(Token![macro]); -process_no_op!(Token![match]); -process_no_op!(Token![mod]); -process_no_op!(Token![move]); -process_no_op!(Token![mut]); -process_no_op!(Token![override]); -process_no_op!(Token![priv]); -process_no_op!(Token![pub]); -process_no_op!(Token![raw]); -process_no_op!(Token![ref]); -process_no_op!(Token![return]); -process_no_op!(Token![self]); -process_no_op!(Token![static]); -process_no_op!(Token![struct]); -process_no_op!(Token![super]); -process_no_op!(Token![trait]); -process_no_op!(Token![try]); -process_no_op!(Token![type]); -process_no_op!(Token![typeof]); -process_no_op!(Token![union]); -process_no_op!(Token![unsafe]); -process_no_op!(Token![unsized]); -process_no_op!(Token![use]); -process_no_op!(Token![virtual]); -process_no_op!(Token![where]); -process_no_op!(Token![while]); -process_no_op!(Token![yield]); - -process_no_op!(Token![!]); -process_no_op!(Token![!=]); -process_no_op!(Token![#]); -process_no_op!(Token![$]); -process_no_op!(Token![%]); -process_no_op!(Token![%=]); -process_no_op!(Token![&]); -process_no_op!(Token![&&]); -process_no_op!(Token![&=]); -process_no_op!(Token![*]); -process_no_op!(Token![*=]); -process_no_op!(Token![+]); -process_no_op!(Token![+=]); -process_no_op!(Token![,]); -process_no_op!(Token![-]); -process_no_op!(Token![-=]); -process_no_op!(Token![->]); -process_no_op!(Token![.]); -process_no_op!(Token![..]); -process_no_op!(Token![...]); -process_no_op!(Token![..=]); -process_no_op!(Token![/]); -process_no_op!(Token![/=]); -process_no_op!(Token![:]); -process_no_op!(Token![::]); -process_no_op!(Token![;]); -process_no_op!(Token![<]); -process_no_op!(Token![<-]); -process_no_op!(Token![<<]); -process_no_op!(Token![<<=]); -process_no_op!(Token![<=]); -process_no_op!(Token![=]); -process_no_op!(Token![==]); -process_no_op!(Token![=>]); -process_no_op!(Token![>]); -process_no_op!(Token![>=]); -process_no_op!(Token![>>]); -process_no_op!(Token![>>=]); -process_no_op!(Token![?]); -process_no_op!(Token![@]); -process_no_op!(Token![^]); -process_no_op!(Token![^=]); -process_no_op!(Token![_]); -process_no_op!(Token![|]); -process_no_op!(Token![|=]); -process_no_op!(Token![||]); -process_no_op!(Token![~]); - -process_no_op!(syn::token::Brace); -process_no_op!(syn::token::Bracket); -process_no_op!(syn::token::Paren); -process_no_op!(syn::token::Group); - -process_no_op!(Ident); -process_no_op!(syn::Index); -process_no_op!(syn::Lifetime); -process_no_op!(syn::LitBool); -process_no_op!(syn::LitByte); -process_no_op!(syn::LitByteStr); -process_no_op!(syn::LitChar); -process_no_op!(syn::LitCStr); -process_no_op!(syn::LitFloat); -process_no_op!(syn::LitInt); -process_no_op!(syn::LitStr); -process_no_op!(proc_macro2::TokenStream); -process_no_op!(proc_macro2::Literal); - -macro_rules! process_struct { - ($ty:path { - $($field:ident,)* - }) => { - impl Process

for $ty { - fn process(self, state: &mut State

) -> Option> { - let Self { - $($field,)* - } = self; - $(let $field = $field.process(state)?;)* - Some(($($field,)*).call(|($($field,)*)| Self { - $($field,)* - })) - } - } - }; - ($ty:path { - $($fields_before:ident,)* - #[qself] - $qself:ident, - $path:ident, - $($fields_after:ident,)* - }) => { - impl Process

for $ty { - fn process(self, state: &mut State

) -> Option> { - let Self { - $($fields_before,)* - $qself, - $path, - $($fields_after,)* - } = self; - $(let $fields_before = $fields_before.process(state)?;)* - let ($qself, $path) = state.process_qself_and_path($qself, $path)?; - $(let $fields_after = $fields_after.process(state)?;)* - Some(( - $($fields_before,)* - $qself, - $path, - $($fields_after,)* - ).call(|( - $($fields_before,)* - $qself, - $path, - $($fields_after,)* - )| Self { - $($fields_before,)* - $qself, - $path, - $($fields_after,)* - })) - } - } - }; -} - -process_struct! { - syn::Abi { - extern_token, - name, - } -} - -process_struct! { - syn::AngleBracketedGenericArguments { - colon2_token, - lt_token, - args, - gt_token, - } -} - -process_struct! { - syn::Arm { - attrs, - pat, - guard, - fat_arrow_token, - body, - comma, - } -} - -process_struct! { - syn::AssocConst { - ident, - generics, - eq_token, - value, - } -} - -process_struct! { - syn::AssocType { - ident, - generics, - eq_token, - ty, - } -} - -process_struct! { - syn::BareFnArg { - attrs, - name, - ty, - } -} - -process_struct! { - syn::BareVariadic { - attrs, - name, - dots, - comma, - } -} - -process_struct! { - syn::Block { - brace_token, - stmts, - } -} - -process_struct! { - syn::BoundLifetimes { - for_token, - lt_token, - lifetimes, - gt_token, - } -} - -process_struct! { - syn::ConstParam { - attrs, - const_token, - ident, - colon_token, - ty, - eq_token, - default, - } -} - -process_struct! { - syn::Constraint { - ident, - generics, - colon_token, - bounds, - } -} - -process_struct! { - syn::DataEnum { - enum_token, - brace_token, - variants, - } -} - -process_struct! { - syn::DataStruct { - struct_token, - fields, - semi_token, - } -} - -process_struct! { - syn::DataUnion { - union_token, - fields, - } -} - -process_struct! { - syn::DeriveInput { - attrs, - vis, - ident, - generics, - data, - } -} - -process_struct! { - syn::ExprArray { - attrs, - bracket_token, - elems, - } -} - -process_struct! { - syn::ExprAssign { - attrs, - left, - eq_token, - right, - } -} - -process_struct! { - syn::ExprAsync { - attrs, - async_token, - capture, - block, - } -} - -process_struct! { - syn::ExprAwait { - attrs, - base, - dot_token, - await_token, - } -} - -process_struct! { - syn::ExprBinary { - attrs, - left, - op, - right, - } -} - -process_struct! { - syn::ExprBlock { - attrs, - label, - block, - } -} - -process_struct! { - syn::ExprBreak { - attrs, - break_token, - label, - expr, - } -} - -process_struct! { - syn::ExprCall { - attrs, - func, - paren_token, - args, - } -} - -process_struct! { - syn::ExprCast { - attrs, - expr, - as_token, - ty, - } -} - -process_struct! { - syn::ExprClosure { - attrs, - lifetimes, - constness, - movability, - asyncness, - capture, - or1_token, - inputs, - or2_token, - output, - body, - } -} - -process_struct! { - syn::ExprConst { - attrs, - const_token, - block, - } -} - -process_struct! { - syn::ExprContinue { - attrs, - continue_token, - label, - } -} - -process_struct! { - syn::ExprField { - attrs, - base, - dot_token, - member, - } -} - -process_struct! { - syn::ExprForLoop { - attrs, - label, - for_token, - pat, - in_token, - expr, - body, - } -} - -process_struct! { - syn::ExprGroup { - attrs, - group_token, - expr, - } -} - -process_struct! { - syn::ExprIf { - attrs, - if_token, - cond, - then_branch, - else_branch, - } -} - -process_struct! { - syn::ExprIndex { - attrs, - expr, - bracket_token, - index, - } -} - -process_struct! { - syn::ExprInfer { - attrs, - underscore_token, - } -} - -process_struct! { - syn::ExprLet { - attrs, - let_token, - pat, - eq_token, - expr, - } -} - -process_struct! { - syn::ExprLit { - attrs, - lit, - } -} - -process_struct! { - syn::ExprLoop { - attrs, - label, - loop_token, - body, - } -} - -process_struct! { - syn::ExprMacro { - attrs, - mac, - } -} - -process_struct! { - syn::ExprMatch { - attrs, - match_token, - expr, - brace_token, - arms, - } -} - -process_struct! { - syn::ExprMethodCall { - attrs, - receiver, - dot_token, - method, - turbofish, - paren_token, - args, - } -} - -process_struct! { - syn::ExprParen { - attrs, - paren_token, - expr, - } -} - -process_struct! { - syn::ExprPath { - attrs, - #[qself] - qself, - path, - } -} - -process_struct! { - syn::ExprRange { - attrs, - start, - limits, - end, - } -} - -process_struct! { - syn::ExprRawAddr { - attrs, - and_token, - raw, - mutability, - expr, - } -} - -process_struct! { - syn::ExprReference { - attrs, - and_token, - mutability, - expr, - } -} - -process_struct! { - syn::ExprRepeat { - attrs, - bracket_token, - expr, - semi_token, - len, - } -} - -process_struct! { - syn::ExprReturn { - attrs, - return_token, - expr, - } -} - -process_struct! { - syn::ExprStruct { - attrs, - #[qself] - qself, - path, - brace_token, - fields, - dot2_token, - rest, - } -} - -process_struct! { - syn::ExprTry { - attrs, - expr, - question_token, - } -} - -process_struct! { - syn::ExprTryBlock { - attrs, - try_token, - block, - } -} - -process_struct! { - syn::ExprTuple { - attrs, - paren_token, - elems, - } -} - -process_struct! { - syn::ExprUnary { - attrs, - op, - expr, - } -} - -process_struct! { - syn::ExprUnsafe { - attrs, - unsafe_token, - block, - } -} - -process_struct! { - syn::ExprWhile { - attrs, - label, - while_token, - cond, - body, - } -} - -process_struct! { - syn::ExprYield { - attrs, - yield_token, - expr, - } -} - -process_struct! { - syn::Field { - attrs, - vis, - mutability, - ident, - colon_token, - ty, - } -} - -process_struct! { - syn::FieldPat { - attrs, - member, - colon_token, - pat, - } -} - -process_struct! { - syn::FieldValue { - attrs, - member, - colon_token, - expr, - } -} - -process_struct! { - syn::FieldsNamed { - brace_token, - named, - } -} - -process_struct! { - syn::FieldsUnnamed { - paren_token, - unnamed, - } -} - -process_struct! { - syn::ForeignItemFn { - attrs, - vis, - sig, - semi_token, - } -} - -process_struct! { - syn::ForeignItemMacro { - attrs, - mac, - semi_token, - } -} - -process_struct! { - syn::ForeignItemStatic { - attrs, - vis, - static_token, - mutability, - ident, - colon_token, - ty, - semi_token, - } -} - -process_struct! { - syn::ForeignItemType { - attrs, - vis, - type_token, - ident, - generics, - semi_token, - } -} - -process_struct! { - syn::Generics { - lt_token, - params, - gt_token, - where_clause, - } -} - -process_struct! { - syn::ImplItemConst { - attrs, - vis, - defaultness, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr, - semi_token, - } -} - -process_struct! { - syn::ImplItemFn { - attrs, - vis, - defaultness, - sig, - block, - } -} - -process_struct! { - syn::ImplItemMacro { - attrs, - mac, - semi_token, - } -} - -process_struct! { - syn::ImplItemType { - attrs, - vis, - defaultness, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } -} - -process_struct! { - syn::ItemConst { - attrs, - vis, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr, - semi_token, - } -} - -process_struct! { - syn::ItemEnum { - attrs, - vis, - enum_token, - ident, - generics, - brace_token, - variants, - } -} - -process_struct! { - syn::ItemExternCrate { - attrs, - vis, - extern_token, - crate_token, - ident, - rename, - semi_token, - } -} - -process_struct! { - syn::ItemFn { - attrs, - vis, - sig, - block, - } -} - -process_struct! { - syn::ItemForeignMod { - attrs, - unsafety, - abi, - brace_token, - items, - } -} - -process_struct! { - syn::ItemImpl { - attrs, - defaultness, - unsafety, - impl_token, - generics, - trait_, - self_ty, - brace_token, - items, - } -} - -process_struct! { - syn::ItemMacro { - attrs, - ident, - mac, - semi_token, - } -} - -process_struct! { - syn::ItemMod { - attrs, - vis, - unsafety, - mod_token, - ident, - content, - semi, - } -} - -process_struct! { - syn::ItemStatic { - attrs, - vis, - static_token, - mutability, - ident, - colon_token, - ty, - eq_token, - expr, - semi_token, - } -} - -process_struct! { - syn::ItemStruct { - attrs, - vis, - struct_token, - ident, - generics, - fields, - semi_token, - } -} - -process_struct! { - syn::ItemTrait { - attrs, - vis, - unsafety, - auto_token, - restriction, - trait_token, - ident, - generics, - colon_token, - supertraits, - brace_token, - items, - } -} - -process_struct! { - syn::ItemTraitAlias { - attrs, - vis, - trait_token, - ident, - generics, - eq_token, - bounds, - semi_token, - } -} - -process_struct! { - syn::ItemType { - attrs, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } -} - -process_struct! { - syn::ItemUnion { - attrs, - vis, - union_token, - ident, - generics, - fields, - } -} - -process_struct! { - syn::ItemUse { - attrs, - vis, - use_token, - leading_colon, - tree, - semi_token, - } -} - -process_struct! { - syn::Label { - name, - colon_token, - } -} - -process_struct! { - syn::LifetimeParam { - attrs, - lifetime, - colon_token, - bounds, - } -} - -process_struct! { - syn::Local { - attrs, - let_token, - pat, - init, - semi_token, - } -} - -process_struct! { - syn::LocalInit { - eq_token, - expr, - diverge, - } -} - -process_struct! { - syn::Macro { - path, - bang_token, - delimiter, - tokens, - } -} - -process_struct! { - syn::MetaList { - path, - delimiter, - tokens, - } -} - -process_struct! { - syn::MetaNameValue { - path, - eq_token, - value, - } -} - -process_struct! { - syn::ParenthesizedGenericArguments { - paren_token, - inputs, - output, - } -} - -process_struct! { - syn::PatIdent { - attrs, - by_ref, - mutability, - ident, - subpat, - } -} - -process_struct! { - syn::PatOr { - attrs, - leading_vert, - cases, - } -} - -process_struct! { - syn::PatParen { - attrs, - paren_token, - pat, - } -} - -process_struct! { - syn::PatReference { - attrs, - and_token, - mutability, - pat, - } -} - -process_struct! { - syn::PatRest { - attrs, - dot2_token, - } -} - -process_struct! { - syn::PatSlice { - attrs, - bracket_token, - elems, - } -} - -process_struct! { - syn::PatStruct { - attrs, - #[qself] - qself, - path, - brace_token, - fields, - rest, - } -} - -process_struct! { - syn::PatTuple { - attrs, - paren_token, - elems, - } -} - -process_struct! { - syn::PatTupleStruct { - attrs, - #[qself] - qself, - path, - paren_token, - elems, - } -} - -process_struct! { - syn::PatType { - attrs, - pat, - colon_token, - ty, - } -} - -process_struct! { - syn::PatWild { - attrs, - underscore_token, - } -} - -process_struct! { - syn::Path { - leading_colon, - segments, - } -} - -process_struct! { - syn::PathSegment { - ident, - arguments, - } -} - -process_struct! { - syn::PreciseCapture { - use_token, - lt_token, - params, - gt_token, - } -} - -process_struct! { - syn::PredicateLifetime { - lifetime, - colon_token, - bounds, - } -} - -process_struct! { - syn::PredicateType { - lifetimes, - bounded_ty, - colon_token, - bounds, - } -} - -process_struct! { - syn::Receiver { - attrs, - reference, - mutability, - self_token, - colon_token, - ty, - } -} - -process_struct! { - syn::Signature { - constness, - asyncness, - unsafety, - abi, - fn_token, - ident, - generics, - paren_token, - inputs, - variadic, - output, - } -} - -process_struct! { - syn::StmtMacro { - attrs, - mac, - semi_token, - } -} - -process_struct! { - syn::TraitBound { - paren_token, - modifier, - lifetimes, - path, - } -} - -process_struct! { - syn::TraitItemConst { - attrs, - const_token, - ident, - generics, - colon_token, - ty, - default, - semi_token, - } -} - -process_struct! { - syn::TraitItemFn { - attrs, - sig, - default, - semi_token, - } -} - -process_struct! { - syn::TraitItemMacro { - attrs, - mac, - semi_token, - } -} - -process_struct! { - syn::TraitItemType { - attrs, - type_token, - ident, - generics, - colon_token, - bounds, - default, - semi_token, - } -} - -process_struct! { - syn::TypeArray { - bracket_token, - elem, - semi_token, - len, - } -} - -process_struct! { - syn::TypeBareFn { - lifetimes, - unsafety, - abi, - fn_token, - paren_token, - inputs, - variadic, - output, - } -} - -process_struct! { - syn::TypeGroup { - group_token, - elem, - } -} - -process_struct! { - syn::TypeImplTrait { - impl_token, - bounds, - } -} - -process_struct! { - syn::TypeInfer { - underscore_token, - } -} - -process_struct! { - syn::TypeMacro { - mac, - } -} - -process_struct! { - syn::TypeNever { - bang_token, - } -} - -process_struct! { - syn::TypeParam { - attrs, - ident, - colon_token, - bounds, - eq_token, - default, - } -} - -process_struct! { - syn::TypeParen { - paren_token, - elem, - } -} - -process_struct! { - syn::TypePath { - #[qself] - qself, - path, - } -} - -process_struct! { - syn::TypePtr { - star_token, - const_token, - mutability, - elem, - } -} - -process_struct! { - syn::TypeReference { - and_token, - lifetime, - mutability, - elem, - } -} - -process_struct! { - syn::TypeSlice { - bracket_token, - elem, - } -} - -process_struct! { - syn::TypeTraitObject { - dyn_token, - bounds, - } -} - -process_struct! { - syn::TypeTuple { - paren_token, - elems, - } -} - -process_struct! { - syn::UseGlob { - star_token, - } -} - -process_struct! { - syn::UseGroup { - brace_token, - items, - } -} - -process_struct! { - syn::UseName { - ident, - } -} - -process_struct! { - syn::UsePath { - ident, - colon2_token, - tree, - } -} - -process_struct! { - syn::UseRename { - ident, - as_token, - rename, - } -} - -process_struct! { - syn::Variadic { - attrs, - pat, - dots, - comma, - } -} - -process_struct! { - syn::Variant { - attrs, - ident, - fields, - discriminant, - } -} - -process_struct! { - syn::VisRestricted { - pub_token, - paren_token, - in_token, - path, - } -} - -process_struct! { - syn::WhereClause { - where_token, - predicates, - } -} - -macro_rules! process_enum { - ($path:path { - $($variant:ident$(($($field:ident),* $(,)?))?,)* - }) => { - impl Process

for $path { - fn process(self, state: &mut State

) -> Option> { - match self { - $(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)* - } - } - } - }; - ($path:path { - $($variant:ident$(($($field:ident),* $(,)?))?,)* - #[no_op] - _, - }) => { - impl Process

for $path { - fn process(self, state: &mut State

) -> Option> { - #![allow(unused_variables)] - match self { - $(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)* - _ => Some(Output::new(self)), - } - } - } - }; -} - -process_enum! { - syn::AttrStyle { - Outer, - Inner(f0), - } -} - -process_enum! { - syn::BinOp { - Add(f0), - Sub(f0), - Mul(f0), - Div(f0), - Rem(f0), - And(f0), - Or(f0), - BitXor(f0), - BitAnd(f0), - BitOr(f0), - Shl(f0), - Shr(f0), - Eq(f0), - Lt(f0), - Le(f0), - Ne(f0), - Ge(f0), - Gt(f0), - AddAssign(f0), - SubAssign(f0), - MulAssign(f0), - DivAssign(f0), - RemAssign(f0), - BitXorAssign(f0), - BitAndAssign(f0), - BitOrAssign(f0), - ShlAssign(f0), - ShrAssign(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::CapturedParam { - Lifetime(f0), - Ident(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::Data { - Struct(f0), - Enum(f0), - Union(f0), - } -} - -process_enum! { - syn::Expr { - Array(f0), - Assign(f0), - Async(f0), - Await(f0), - Binary(f0), - Block(f0), - Break(f0), - Call(f0), - Cast(f0), - Closure(f0), - Const(f0), - Continue(f0), - Field(f0), - ForLoop(f0), - Group(f0), - If(f0), - Index(f0), - Infer(f0), - Let(f0), - Lit(f0), - Loop(f0), - Macro(f0), - Match(f0), - MethodCall(f0), - Paren(f0), - Path(f0), - Range(f0), - RawAddr(f0), - Reference(f0), - Repeat(f0), - Return(f0), - Struct(f0), - Try(f0), - TryBlock(f0), - Tuple(f0), - Unary(f0), - Unsafe(f0), - Verbatim(f0), - While(f0), - Yield(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::FieldMutability { - None, - #[no_op] - _, - } -} - -process_enum! { - syn::Fields { - Named(f0), - Unnamed(f0), - Unit, - } -} - -process_enum! { - syn::FnArg { - Receiver(f0), - Typed(f0), - } -} - -process_enum! { - syn::ForeignItem { - Fn(f0), - Static(f0), - Type(f0), - Macro(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::GenericArgument { - Lifetime(f0), - Type(f0), - Const(f0), - AssocType(f0), - AssocConst(f0), - Constraint(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::GenericParam { - Lifetime(f0), - Type(f0), - Const(f0), - } -} - -process_enum! { - syn::ImplItem { - Const(f0), - Fn(f0), - Type(f0), - Macro(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::ImplRestriction { - #[no_op] - _, - } -} - -process_enum! { - syn::Lit { - Str(f0), - ByteStr(f0), - CStr(f0), - Byte(f0), - Char(f0), - Int(f0), - Float(f0), - Bool(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::MacroDelimiter { - Paren(f0), - Brace(f0), - Bracket(f0), - } -} - -process_enum! { - syn::Member { - Named(f0), - Unnamed(f0), - } -} - -process_enum! { - syn::Meta { - Path(f0), - List(f0), - NameValue(f0), - } -} - -process_enum! { - syn::Pat { - Const(f0), - Ident(f0), - Lit(f0), - Macro(f0), - Or(f0), - Paren(f0), - Path(f0), - Range(f0), - Reference(f0), - Rest(f0), - Slice(f0), - Struct(f0), - Tuple(f0), - TupleStruct(f0), - Type(f0), - Verbatim(f0), - Wild(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::PathArguments { - None, - AngleBracketed(f0), - Parenthesized(f0), - } -} - -process_enum! { - syn::PointerMutability { - Const(f0), - Mut(f0), - } -} - -process_enum! { - syn::RangeLimits { - HalfOpen(f0), - Closed(f0), - } -} - -process_enum! { - syn::ReturnType { - Default, - Type(f0, f1), - } -} - -process_enum! { - syn::StaticMutability { - Mut(f0), - None, - #[no_op] - _, - } -} - -process_enum! { - syn::Stmt { - Local(f0), - Item(f0), - Expr(f0, f1), - Macro(f0), - } -} - -process_enum! { - syn::TraitBoundModifier { - None, - Maybe(f0), - } -} - -process_enum! { - syn::TraitItem { - Const(f0), - Fn(f0), - Type(f0), - Macro(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::Type { - Array(f0), - BareFn(f0), - Group(f0), - ImplTrait(f0), - Infer(f0), - Macro(f0), - Never(f0), - Paren(f0), - Path(f0), - Ptr(f0), - Reference(f0), - Slice(f0), - TraitObject(f0), - Tuple(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::TypeParamBound { - Trait(f0), - Lifetime(f0), - PreciseCapture(f0), - Verbatim(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::UnOp { - Deref(f0), - Not(f0), - Neg(f0), - #[no_op] - _, - } -} - -process_enum! { - syn::UseTree { - Path(f0), - Name(f0), - Rename(f0), - Glob(f0), - Group(f0), - } -} - -process_enum! { - syn::Visibility { - Public(f0), - Restricted(f0), - Inherited, - } -} - -process_enum! { - syn::WherePredicate { - Lifetime(f0), - Type(f0), - #[no_op] - _, - } -} - -struct TopItem(syn::Item); - -impl Process

for TopItem { - fn process(self, state: &mut State

) -> Option> { - match self.0 { - syn::Item::Const(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Enum(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::ExternCrate(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Fn(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::ForeignMod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Impl(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Macro(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Mod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Static(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Struct(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Trait(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::TraitAlias(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Type(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Union(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - syn::Item::Use(item) => Some(item.process(state)?.map(Into::into).map(TopItem)), - _ => Some(Output::new(self)), - } - } -} - -pub(crate) fn process_cfgs(item: syn::Item, cfgs: Cfgs) -> syn::Result> { - let mut state = State:: { - cfgs, - errors: Errors::new(), - _phantom: PhantomData, - }; - let retval = TopItem(item).process(&mut state).map(|v| v.0 .0); - state.errors.finish()?; - Ok(retval) -} - -pub(crate) fn collect_cfgs(item: syn::Item) -> syn::Result> { - let mut state = State:: { - cfgs: Cfgs::default(), - errors: Errors::new(), - _phantom: PhantomData, - }; - let (None | Some(Output(()))) = TopItem(item).process(&mut state); - state.errors.finish()?; - Ok(state.cfgs) -} diff --git a/crates/fayalite-proc-macros/Cargo.toml b/crates/fayalite-proc-macros/Cargo.toml index 6941d12..08c630a 100644 --- a/crates/fayalite-proc-macros/Cargo.toml +++ b/crates/fayalite-proc-macros/Cargo.toml @@ -16,4 +16,4 @@ version.workspace = true proc-macro = true [dependencies] -fayalite-proc-macros-impl.workspace = true +fayalite-proc-macros-impl = { workspace = true } diff --git a/crates/fayalite-visit-gen/Cargo.toml b/crates/fayalite-visit-gen/Cargo.toml index 5a98947..6da95d2 100644 --- a/crates/fayalite-visit-gen/Cargo.toml +++ b/crates/fayalite-visit-gen/Cargo.toml @@ -13,11 +13,11 @@ rust-version.workspace = true version.workspace = true [dependencies] -indexmap.workspace = true -prettyplease.workspace = true -proc-macro2.workspace = true -quote.workspace = true -serde.workspace = true -serde_json.workspace = true -syn.workspace = true -thiserror.workspace = true +indexmap = { workspace = true } +prettyplease = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +syn = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/fayalite/Cargo.toml b/crates/fayalite/Cargo.toml index f176698..555f7f5 100644 --- a/crates/fayalite/Cargo.toml +++ b/crates/fayalite/Cargo.toml @@ -14,33 +14,25 @@ rust-version.workspace = true version.workspace = true [dependencies] -bitvec.workspace = true -blake3.workspace = true -clap.workspace = true -ctor.workspace = true -eyre.workspace = true -fayalite-proc-macros.workspace = true -hashbrown.workspace = true -jobslot.workspace = true -num-bigint.workspace = true -num-traits.workspace = true -os_pipe.workspace = true -petgraph.workspace = true -serde_json.workspace = true -serde.workspace = true -tempfile.workspace = true -vec_map.workspace = true -which.workspace = true +bitvec = { workspace = true } +hashbrown = { workspace = true } +num-bigint = { workspace = true } +num-traits = { workspace = true } +fayalite-proc-macros = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +clap = { version = "4.5.9", features = ["derive", "env"] } +eyre = "0.6.12" +which = "6.0.1" [dev-dependencies] -trybuild.workspace = true +trybuild = { workspace = true } [build-dependencies] -fayalite-visit-gen.workspace = true +fayalite-visit-gen = { workspace = true } [features] unstable-doc = [] -unstable-test-hasher = [] [package.metadata.docs.rs] features = ["unstable-doc"] diff --git a/crates/fayalite/build.rs b/crates/fayalite/build.rs index c6680d5..24d8f31 100644 --- a/crates/fayalite/build.rs +++ b/crates/fayalite/build.rs @@ -5,9 +5,6 @@ use std::{env, fs, path::Path}; fn main() { println!("cargo::rustc-check-cfg=cfg(todo)"); - println!("cargo::rustc-check-cfg=cfg(cfg_false_for_tests)"); - println!("cargo::rustc-check-cfg=cfg(cfg_true_for_tests)"); - println!("cargo::rustc-cfg=cfg_true_for_tests"); let path = "visit_types.json"; println!("cargo::rerun-if-changed={path}"); println!("cargo::rerun-if-changed=build.rs"); diff --git a/crates/fayalite/examples/blinky.rs b/crates/fayalite/examples/blinky.rs index 87b77c1..588ca9a 100644 --- a/crates/fayalite/examples/blinky.rs +++ b/crates/fayalite/examples/blinky.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use clap::Parser; use fayalite::{cli, prelude::*}; @@ -17,15 +15,15 @@ fn blinky(clock_frequency: u64) { let max_value = clock_frequency / 2 - 1; let int_ty = UInt::range_inclusive(0..=max_value); #[hdl] - let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty)); + let counter: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty)); #[hdl] let output_reg: Bool = reg_builder().clock_domain(cd).reset(false); #[hdl] - if counter_reg.cmp_eq(max_value) { - connect_any(counter_reg, 0u8); + if counter.cmp_eq(max_value) { + connect_any(counter, 0u8); connect(output_reg, !output_reg); } else { - connect_any(counter_reg, counter_reg + 1_hdl_u1); + connect_any(counter, counter + 1_hdl_u1); } #[hdl] let led: Bool = m.output(); diff --git a/crates/fayalite/src/_docs.rs b/crates/fayalite/src/_docs.rs index 5b1888b..4d254a7 100644 --- a/crates/fayalite/src/_docs.rs +++ b/crates/fayalite/src/_docs.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information #![doc = include_str!("../README.md")] //! diff --git a/crates/fayalite/src/_docs/modules.rs b/crates/fayalite/src/_docs/modules.rs index 99b98e8..c392f2e 100644 --- a/crates/fayalite/src/_docs/modules.rs +++ b/crates/fayalite/src/_docs/modules.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Fayalite Modules //! //! The [`#[hdl_module]`][`crate::hdl_module`] attribute is applied to a Rust diff --git a/crates/fayalite/src/_docs/modules/extern_module.rs b/crates/fayalite/src/_docs/modules/extern_module.rs index c1367d9..bf2034b 100644 --- a/crates/fayalite/src/_docs/modules/extern_module.rs +++ b/crates/fayalite/src/_docs/modules/extern_module.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! These are for when you want to use modules written in //! some other language, such as Verilog. //! diff --git a/crates/fayalite/src/_docs/modules/module_bodies.rs b/crates/fayalite/src/_docs/modules/module_bodies.rs index c12ae21..bd85c61 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Module Function Bodies //! //! The `#[hdl_module]` attribute lets you have statements/expressions with `#[hdl]` annotations diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_array_expressions.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_array_expressions.rs index c0b15ad..c4bbfa4 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_array_expressions.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_array_expressions.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # `#[hdl]` Array Expressions //! //! `#[hdl]` can be used on Array Expressions to construct an [`Array<[T; N]>`][type@Array] expression: diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_if_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_if_statements.rs index 7d09943..46bb568 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_if_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_if_statements.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # `#[hdl] if` Statements //! //! `#[hdl] if` statements behave similarly to Rust `if` statements, except they end up as muxes diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs index 229871b..c4e3e70 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs @@ -1,8 +1,5 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! ## `#[hdl] let` statements -pub mod destructuring; pub mod inputs_outputs; pub mod instances; pub mod memories; diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs deleted file mode 100644 index 1fc4705..0000000 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -//! ### Destructuring Let -//! -//! You can use `#[hdl] let` to destructure types, similarly to Rust `let` statements with non-trivial patterns. -//! -//! `#[hdl] let` statements can only match one level of struct/tuple pattern for now, -//! e.g. you can match with the pattern `MyStruct { a, b }`, but not `MyStruct { a, b: Struct2 { v } }`. -//! -//! ``` -//! # use fayalite::prelude::*; -//! #[hdl] -//! struct MyStruct { -//! a: UInt<8>, -//! b: Bool, -//! } -//! -//! #[hdl_module] -//! fn my_module() { -//! #[hdl] -//! let my_input: MyStruct = m.input(); -//! #[hdl] -//! let my_output: UInt<8> = m.input(); -//! #[hdl] -//! let MyStruct { a, b } = my_input; -//! #[hdl] -//! if b { -//! connect(my_output, a); -//! } else { -//! connect(my_output, 0_hdl_u8); -//! } -//! } -//! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/inputs_outputs.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/inputs_outputs.rs index 14169d9..bfd7521 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/inputs_outputs.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/inputs_outputs.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! ### Inputs/Outputs //! //! Inputs/Outputs create a Rust variable with type [`Expr`] where `T` is the type of the input/output. diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/instances.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/instances.rs index 75def03..2776754 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/instances.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/instances.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! ### Module Instances //! //! module instances are kinda like the hardware equivalent of calling a function, diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/memories.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/memories.rs index ddd60b9..e491eef 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/memories.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/memories.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Memories //! //! Memories are optimized for storing large amounts of data. diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/registers.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/registers.rs index 2876389..28db27f 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/registers.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/registers.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! ### Registers //! //! Registers are memory devices that will change their state only on a clock @@ -9,9 +7,6 @@ //! //! Registers follow [connection semantics], which are unlike assignments in software, so you should read it. //! -//! By convention, register names end in `_reg` -- this helps you tell which values are written -//! immediately or on the next clock edge when connecting to them. -//! //! ``` //! # use fayalite::prelude::*; //! # #[hdl_module] @@ -21,11 +16,11 @@ //! #[hdl] //! let cd: ClockDomain = m.input(); //! #[hdl] -//! let my_reg: UInt<8> = reg_builder().clock_domain(cd).reset(8_hdl_u8); +//! let my_register: UInt<8> = reg_builder().clock_domain(cd).reset(8_hdl_u8); //! #[hdl] //! if v { -//! // my_reg is only changed when both `v` is set and `cd`'s clock edge occurs. -//! connect(my_reg, 0x45_hdl_u8); +//! // my_register is only changed when both `v` is set and `cd`'s clock edge occurs. +//! connect(my_register, 0x45_hdl_u8); //! } //! # } //! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/wires.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/wires.rs index 7d92b41..b22e0fd 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/wires.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/wires.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! ### Wires //! //! Wires are kinda like variables, but unlike registers, diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_literals.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_literals.rs index 91710e7..a6c9b58 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_literals.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_literals.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # `_hdl`-suffixed literals //! //! You can have integer literals with an arbitrary number of bits like so: diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs index 6df70f1..c0d4ea6 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # `#[hdl] match` Statements //! //! `#[hdl] match` statements behave similarly to Rust `match` statements, except they end up as muxes @@ -7,5 +5,5 @@ //! //! `#[hdl] match` statements' bodies must evaluate to type `()` for now. //! -//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now, +//! `#[hdl] match` statements can only match one level of struct/enum pattern for now, //! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`. diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_struct_variant_expressions.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_struct_variant_expressions.rs index 68cd685..9d63895 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_struct_variant_expressions.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_struct_variant_expressions.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # `#[hdl]` Struct/Variant Expressions //! //! Note: Structs are also known as [Bundles] when used in Fayalite, the Bundle name comes from [FIRRTL]. diff --git a/crates/fayalite/src/_docs/modules/normal_module.rs b/crates/fayalite/src/_docs/modules/normal_module.rs index 1267551..f84678e 100644 --- a/crates/fayalite/src/_docs/modules/normal_module.rs +++ b/crates/fayalite/src/_docs/modules/normal_module.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Normal Modules //! //! See also: [Extern Modules][`super::extern_module`] diff --git a/crates/fayalite/src/_docs/semantics.rs b/crates/fayalite/src/_docs/semantics.rs index 2282f25..a499e8e 100644 --- a/crates/fayalite/src/_docs/semantics.rs +++ b/crates/fayalite/src/_docs/semantics.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Fayalite Semantics //! //! Fayalite's semantics are based on [FIRRTL]. Due to their significance, some of the semantics are also documented here. diff --git a/crates/fayalite/src/_docs/semantics/connection_semantics.rs b/crates/fayalite/src/_docs/semantics/connection_semantics.rs index ba2a679..41155bf 100644 --- a/crates/fayalite/src/_docs/semantics/connection_semantics.rs +++ b/crates/fayalite/src/_docs/semantics/connection_semantics.rs @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information //! # Connection Semantics //! //! Fayalite's connection semantics are unlike assignments in software, so be careful! diff --git a/crates/fayalite/src/annotations.rs b/crates/fayalite/src/annotations.rs index 1c517ae..8e645c3 100644 --- a/crates/fayalite/src/annotations.rs +++ b/crates/fayalite/src/annotations.rs @@ -8,11 +8,10 @@ use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, - iter::FusedIterator, ops::Deref, }; -#[derive(Clone, Debug)] +#[derive(Clone)] struct CustomFirrtlAnnotationFieldsImpl { value: serde_json::Map, serialized: Interned, @@ -119,87 +118,11 @@ pub struct CustomFirrtlAnnotation { pub additional_fields: CustomFirrtlAnnotationFields, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] -pub struct DontTouchAnnotation; - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] -pub struct SVAttributeAnnotation { - pub text: Interned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] -pub struct BlackBoxInlineAnnotation { - pub path: Interned, - pub text: Interned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] -pub struct BlackBoxPathAnnotation { - pub path: Interned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] -pub struct DocStringAnnotation { - pub text: Interned, -} - -macro_rules! make_annotation_enum { - ( - $(#[$meta:meta])* - $vis:vis enum $Annotation:ident { - $($Variant:ident($T:ident),)* - } - ) => { - $(#[$meta])* - $vis enum $Annotation { - $($Variant($T),)* - } - - $(impl IntoAnnotations for $T { - type IntoAnnotations = [$Annotation; 1]; - - fn into_annotations(self) -> Self::IntoAnnotations { - [$Annotation::$Variant(self)] - } - } - - impl IntoAnnotations for &'_ $T { - type IntoAnnotations = [$Annotation; 1]; - - fn into_annotations(self) -> Self::IntoAnnotations { - [$Annotation::$Variant(*self)] - } - } - - impl IntoAnnotations for &'_ mut $T { - type IntoAnnotations = [$Annotation; 1]; - - fn into_annotations(self) -> Self::IntoAnnotations { - [$Annotation::$Variant(*self)] - } - } - - impl IntoAnnotations for Box<$T> { - type IntoAnnotations = [$Annotation; 1]; - - fn into_annotations(self) -> Self::IntoAnnotations { - [$Annotation::$Variant(*self)] - } - })* - }; -} - -make_annotation_enum! { - #[derive(Clone, PartialEq, Eq, Hash, Debug)] - #[non_exhaustive] - pub enum Annotation { - DontTouch(DontTouchAnnotation), - SVAttribute(SVAttributeAnnotation), - BlackBoxInline(BlackBoxInlineAnnotation), - BlackBoxPath(BlackBoxPathAnnotation), - DocString(DocStringAnnotation), - CustomFirrtl(CustomFirrtlAnnotation), - } +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[non_exhaustive] +pub enum Annotation { + DontTouch, + CustomFirrtl(CustomFirrtlAnnotation), } #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -264,70 +187,10 @@ impl IntoAnnotations for &'_ mut Annotation { } } -pub struct IterIntoAnnotations> { - outer: T, - inner: Option<<::IntoAnnotations as IntoIterator>::IntoIter>, -} - -impl> Iterator for IterIntoAnnotations { - type Item = Annotation; - - fn next(&mut self) -> Option { - loop { - if let Some(inner) = &mut self.inner { - let Some(retval) = inner.next() else { - self.inner = None; - continue; - }; - return Some(retval); - } else { - self.inner = Some(self.outer.next()?.into_annotations().into_iter()); - } - } - } - - fn size_hint(&self) -> (usize, Option) { - if let (0, Some(0)) = self.outer.size_hint() { - self.inner - .as_ref() - .map(|v| v.size_hint()) - .unwrap_or((0, Some(0))) - } else { - ( - self.inner.as_ref().map(|v| v.size_hint().0).unwrap_or(0), - None, - ) - } - } - - fn fold(self, init: B, f: F) -> B - where - Self: Sized, - F: FnMut(B, Self::Item) -> B, - { - self.inner - .into_iter() - .chain(self.outer.map(|v| v.into_annotations().into_iter())) - .flatten() - .fold(init, f) - } -} - -impl< - T: FusedIterator< - Item: IntoAnnotations>, - >, - > FusedIterator for IterIntoAnnotations -{ -} - -impl> IntoAnnotations for T { - type IntoAnnotations = IterIntoAnnotations; +impl> IntoAnnotations for T { + type IntoAnnotations = Self; fn into_annotations(self) -> Self::IntoAnnotations { - IterIntoAnnotations { - outer: self.into_iter(), - inner: None, - } + self } } diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 6d9b043..d543322 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -2,24 +2,17 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq}, - CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr, - }, - int::{Bool, DynSize, KnownSize, Size, SizeType, DYN_SIZE}, + expr::{ops::ArrayIndex, Expr, ToExpr}, + int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE}, intern::{Intern, Interned, LazyInterned}, module::transform::visit::{Fold, Folder, Visit, Visitor}, - sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, ty::{ - serde_impls::SerdeCanonicalType, CanonicalType, MatchVariantWithoutScope, StaticType, Type, - TypeProperties, TypeWithDeref, + CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, }, util::ConstUsize, }; -use bitvec::slice::BitSlice; -use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use std::{iter::FusedIterator, ops::Index}; +use std::ops::Index; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct ArrayType { @@ -92,18 +85,12 @@ impl ArrayType { } } -impl> ArrayType { +impl ArrayType { pub fn new_static(element: T) -> Self { Self::new(element, Len::SizeType::default()) } } -impl Default for ArrayType { - fn default() -> Self { - Self::TYPE - } -} - impl StaticType for ArrayType { const TYPE: Self = Self { element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()), @@ -152,7 +139,6 @@ impl, Len: Size, State: Visitor + ?Sized> Visit impl Type for ArrayType { type BaseType = Array; type MaskType = ArrayType; - type SimValue = Len::ArraySimValue; type MatchVariant = Len::ArrayMatch; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope>; @@ -162,8 +148,10 @@ impl Type for ArrayType { this: Expr, source_location: SourceLocation, ) -> Self::MatchVariantsIter { + let base = Expr::as_dyn_array(this); + let base_ty = Expr::ty(base); let _ = source_location; - let retval = Vec::from_iter(this); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); std::iter::once(MatchVariantWithoutScope( Len::ArrayMatch::::try_from(retval) .ok() @@ -189,98 +177,17 @@ impl Type for ArrayType { Len::from_usize(array.len()), ) } - fn source_location() -> SourceLocation { SourceLocation::builtin() } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), self.type_properties.bit_width); - let element = self.element(); - let element_bit_width = element.canonical().bit_width(); - TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| { - SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width]) - }))) - .ok() - .expect("used correct length") - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), self.type_properties.bit_width); - let element_ty = self.element(); - let element_bit_width = element_ty.canonical().bit_width(); - let value: &mut [SimValue] = value.as_mut(); - assert_eq!(self.len(), value.len()); - for (i, element_value) in value.iter_mut().enumerate() { - assert_eq!(SimValue::ty(element_value), element_ty); - SimValue::bits_mut(element_value) - .bits_mut() - .copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]); - } - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), self.type_properties.bit_width); - let element_ty = self.element(); - let element_bit_width = element_ty.canonical().bit_width(); - let value: &[SimValue] = value.as_ref(); - assert_eq!(self.len(), value.len()); - for (i, element_value) in value.iter().enumerate() { - assert_eq!(SimValue::ty(element_value), element_ty); - bits[i * element_bit_width..][..element_bit_width] - .copy_from_bitslice(SimValue::bits(element_value).bits()); - } - } -} - -impl Serialize for ArrayType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeCanonicalType::::Array { - element: self.element(), - len: self.len(), - } - .serialize(serializer) - } -} - -impl<'de, T: Type + Deserialize<'de>, Len: Size> Deserialize<'de> for ArrayType { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = |len| -> String { - if let Some(len) = len { - format!("an Array<_, {len}>") - } else { - "an Array<_>".to_string() - } - }; - match SerdeCanonicalType::::deserialize(deserializer)? { - SerdeCanonicalType::Array { element, len } => { - if let Some(len) = Len::try_from_usize(len) { - Ok(Self::new(element, len)) - } else { - Err(Error::invalid_value( - serde::de::Unexpected::Other(&name(Some(len))), - &&*name(Len::KNOWN_VALUE), - )) - } - } - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &&*name(Len::KNOWN_VALUE), - )), - } - } } impl TypeWithDeref for ArrayType { fn expr_deref(this: &Expr) -> &Self::MatchVariant { - let retval = Vec::from_iter(*this); - Interned::into_inner(Intern::intern_sized( + let base = Expr::as_dyn_array(*this); + let base_ty = Expr::ty(base); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); + Interned::<_>::into_inner(Intern::intern_sized( Len::ArrayMatch::::try_from(retval) .ok() .expect("unreachable"), @@ -295,7 +202,7 @@ impl Index for ArrayWithoutGenerics { type Output = ArrayWithoutLen; fn index(&self, element: T) -> &Self::Output { - Interned::into_inner(Intern::intern_sized(ArrayWithoutLen { element })) + Interned::<_>::into_inner(Intern::intern_sized(ArrayWithoutLen { element })) } } @@ -308,146 +215,6 @@ impl Index for ArrayWithoutLen { type Output = ArrayType; fn index(&self, len: L) -> &Self::Output { - Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) - } -} - -impl ExprPartialEq> for ArrayType -where - Lhs: ExprPartialEq, -{ - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_eq(r)) - .collect::>>() - .cast_to_bits() - .all_one_bits() - } - - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_ne(r)) - .collect::>>() - .cast_to_bits() - .any_one_bits() - } -} - -impl SimValuePartialEq> for ArrayType -where - Lhs: SimValuePartialEq, -{ - fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { - AsRef::<[_]>::as_ref(&**this) - .iter() - .zip(AsRef::<[_]>::as_ref(&**other)) - .all(|(l, r)| SimValuePartialEq::sim_value_eq(l, r)) - } -} - -impl ExprIntoIterator for ArrayType { - type Item = T; - type ExprIntoIter = ExprArrayIter; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter { - ExprArrayIter { - base: e, - indexes: 0..Expr::ty(e).len(), - } - } -} - -#[derive(Clone, Debug)] -pub struct ExprArrayIter { - base: Expr>, - indexes: std::ops::Range, -} - -impl ExprArrayIter { - pub fn base(&self) -> Expr> { - self.base - } - pub fn indexes(&self) -> std::ops::Range { - self.indexes.clone() - } -} - -impl Iterator for ExprArrayIter { - type Item = Expr; - - fn next(&mut self) -> Option { - self.indexes.next().map(|i| self.base[i]) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } - - fn count(self) -> usize { - self.indexes.count() - } - - fn last(mut self) -> Option { - self.next_back() - } - - fn nth(&mut self, n: usize) -> Option { - self.indexes.nth(n).map(|i| self.base[i]) - } - - fn fold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.fold(init, |b, i| f(b, self.base[i])) - } -} - -impl DoubleEndedIterator for ExprArrayIter { - fn next_back(&mut self) -> Option { - self.indexes.next_back().map(|i| self.base[i]) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.indexes.nth_back(n).map(|i| self.base[i]) - } - - fn rfold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.rfold(init, |b, i| f(b, self.base[i])) - } -} - -impl ExactSizeIterator for ExprArrayIter { - fn len(&self) -> usize { - self.indexes.len() - } -} - -impl FusedIterator for ExprArrayIter {} - -impl ExprFromIterator> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - ArrayLiteral::new( - A::TYPE, - iter.into_iter().map(|v| Expr::canonical(v)).collect(), - ) - .to_expr() - } -} - -impl<'a, A: StaticType> ExprFromIterator<&'a Expr> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - iter.into_iter().copied().collect() + Interned::<_>::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) } } diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 240c0c6..95c87f9 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -2,25 +2,18 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ArrayLiteral, BundleLiteral, ExprPartialEq}, - CastToBits, Expr, ReduceBits, ToExpr, - }, - int::{Bool, DynSize}, + expr::{ops::BundleLiteral, Expr, ToExpr}, intern::{Intern, Interned}, - sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, source_location::SourceLocation, ty::{ - impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, - StaticType, Type, TypeProperties, TypeWithDeref, + impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type, + TypeProperties, TypeWithDeref, }, - util::HashMap, }; -use bitvec::{slice::BitSlice, vec::BitVec}; -use serde::{Deserialize, Serialize}; +use hashbrown::HashMap; use std::{fmt, marker::PhantomData}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct BundleField { pub name: Interned, pub flipped: bool, @@ -151,16 +144,10 @@ impl BundleTypePropertiesBuilder { } } -impl Default for BundleTypePropertiesBuilder { - fn default() -> Self { - Self::new() - } -} - impl Bundle { #[track_caller] pub fn new(fields: Interned<[BundleField]>) -> Self { - let mut name_indexes = HashMap::with_capacity_and_hasher(fields.len(), Default::default()); + let mut name_indexes = HashMap::with_capacity(fields.len()); let mut field_offsets = Vec::with_capacity(fields.len()); let mut type_props_builder = BundleTypePropertiesBuilder::new(); for (index, &BundleField { name, flipped, ty }) in fields.iter().enumerate() { @@ -217,7 +204,6 @@ impl Bundle { impl Type for Bundle { type BaseType = Bundle; type MaskType = Bundle; - type SimValue = OpaqueSimValue; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Self::new(Interned::from_iter(self.0.fields.into_iter().map( @@ -241,20 +227,6 @@ impl Type for Bundle { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), self.type_properties().bit_width); - OpaqueSimValue::from_bitslice(bits) - } - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), self.type_properties().bit_width); - assert_eq!(value.bit_width(), self.type_properties().bit_width); - value.bits_mut().bits_mut().copy_from_bitslice(bits); - } - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), self.type_properties().bit_width); - assert_eq!(value.bit_width(), self.type_properties().bit_width); - bits.copy_from_bitslice(value.bits().bits()); - } } pub trait BundleType: Type { @@ -263,93 +235,6 @@ pub trait BundleType: Type { fn fields(&self) -> Interned<[BundleField]>; } -pub struct BundleSimValueFromBits<'a> { - fields: std::slice::Iter<'static, BundleField>, - bits: &'a BitSlice, -} - -impl<'a> BundleSimValueFromBits<'a> { - #[track_caller] - pub fn new(bundle_ty: T, bits: &'a BitSlice) -> Self { - let fields = bundle_ty.fields(); - assert_eq!( - bits.len(), - fields - .iter() - .map(|BundleField { ty, .. }| ty.bit_width()) - .sum::() - ); - Self { - fields: Interned::into_inner(fields).iter(), - bits, - } - } - #[track_caller] - fn field_ty_and_bits(&mut self) -> (T, &'a BitSlice) { - let Some(&BundleField { - name: _, - flipped: _, - ty, - }) = self.fields.next() - else { - panic!("tried to read too many fields from BundleSimValueFromBits"); - }; - let (field_bits, rest) = self.bits.split_at(ty.bit_width()); - self.bits = rest; - (T::from_canonical(ty), field_bits) - } - #[track_caller] - pub fn field_from_bits(&mut self) -> SimValue { - let (field_ty, field_bits) = self.field_ty_and_bits::(); - SimValue::from_bitslice(field_ty, field_bits) - } - #[track_caller] - pub fn field_clone_from_bits(&mut self, field_value: &mut SimValue) { - let (field_ty, field_bits) = self.field_ty_and_bits::(); - assert_eq!(field_ty, SimValue::ty(field_value)); - SimValue::bits_mut(field_value) - .bits_mut() - .copy_from_bitslice(field_bits); - } -} - -pub struct BundleSimValueToBits<'a> { - fields: std::slice::Iter<'static, BundleField>, - bits: &'a mut BitSlice, -} - -impl<'a> BundleSimValueToBits<'a> { - #[track_caller] - pub fn new(bundle_ty: T, bits: &'a mut BitSlice) -> Self { - let fields = bundle_ty.fields(); - assert_eq!( - bits.len(), - fields - .iter() - .map(|BundleField { ty, .. }| ty.bit_width()) - .sum::() - ); - Self { - fields: Interned::into_inner(fields).iter(), - bits, - } - } - #[track_caller] - pub fn field_to_bits(&mut self, field_value: &SimValue) { - let Some(&BundleField { - name: _, - flipped: _, - ty, - }) = self.fields.next() - else { - panic!("tried to read too many fields from BundleSimValueFromBits"); - }; - assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); - self.bits[..ty.bit_width()].copy_from_bitslice(SimValue::bits(field_value).bits()); - self.bits = &mut std::mem::take(&mut self.bits)[ty.bit_width()..]; - } -} - #[derive(Default)] pub struct NoBuilder; @@ -432,19 +317,7 @@ macro_rules! impl_tuple_builder_fields { } macro_rules! impl_tuples { - ( - [$({ - #[ - num = $num:tt, - field = $field:ident, - ty = $ty_var:ident: $Ty:ident, - lhs = $lhs_var:ident: $Lhs:ident, - rhs = $rhs_var:ident: $Rhs:ident - ] - $var:ident: $T:ident - })*] - [] - ) => { + ([$({#[num = $num:literal, field = $field:ident] $var:ident: $T:ident})*] []) => { impl_tuple_builder_fields! { {} [$({ @@ -456,7 +329,6 @@ macro_rules! impl_tuples { impl<$($T: Type,)*> Type for ($($T,)*) { type BaseType = Bundle; type MaskType = ($($T::MaskType,)*); - type SimValue = ($(SimValue<$T>,)*); type MatchVariant = ($(Expr<$T>,)*); type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -470,7 +342,6 @@ macro_rules! impl_tuples { std::iter::once(MatchVariantWithoutScope(($(Expr::field(this, stringify!($num)),)*))) } fn mask_type(&self) -> Self::MaskType { - #![allow(clippy::unused_unit)] let ($($var,)*) = self; ($($var.mask_type(),)*) } @@ -479,7 +350,6 @@ macro_rules! impl_tuples { } #[track_caller] fn from_canonical(canonical_type: CanonicalType) -> Self { - #![allow(clippy::unused_unit)] let CanonicalType::Bundle(bundle) = canonical_type else { panic!("expected bundle"); }; @@ -488,31 +358,13 @@ macro_rules! impl_tuples { }; $(let BundleField { name, flipped, ty } = $var; assert_eq!(&*name, stringify!($num)); - assert!(!flipped); + assert_eq!(flipped, false); let $var = $T::from_canonical(ty);)* ($($var,)*) } fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueFromBits::new(*self, bits); - $(let $var = v.field_from_bits();)* - ($($var,)*) - } - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueFromBits::new(*self, bits); - let ($($var,)*) = value; - $(v.field_clone_from_bits($var);)* - } - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueToBits::new(*self, bits); - let ($($var,)*) = value; - $(v.field_to_bits($var);)* - } } impl<$($T: Type,)*> BundleType for ($($T,)*) { type Builder = TupleBuilder<($(Unfilled<$T>,)*)>; @@ -525,7 +377,7 @@ macro_rules! impl_tuples { impl<$($T: Type,)*> TypeWithDeref for ($($T,)*) { fn expr_deref(this: &Expr) -> &Self::MatchVariant { let _ = this; - Interned::into_inner(($(Expr::field(*this, stringify!($num)),)*).intern_sized()) + Interned::<_>::into_inner(($(Expr::field(*this, stringify!($num)),)*).intern_sized()) } } impl<$($T: StaticType,)*> StaticType for ($($T,)*) { @@ -563,106 +415,6 @@ macro_rules! impl_tuples { BundleLiteral::new(ty, field_values[..].intern()).to_expr() } } - impl<$($T: ToSimValueWithType,)*> ToSimValueWithType for ($($T,)*) { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(ToSimValueWithType::::to_sim_value_with_type(self, Bundle::from_canonical(ty))) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue - { - SimValue::into_canonical(ToSimValueWithType::::into_sim_value_with_type(self, Bundle::from_canonical(ty))) - } - } - impl<$($T: ToSimValueWithType,)*> ToSimValueWithType for ($($T,)*) { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue { - let ($($var,)*) = self; - let [$($ty_var,)*] = *ty.fields() else { - panic!("bundle has wrong number of fields"); - }; - $(let $var = $var.to_sim_value_with_type($ty_var.ty);)* - ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: Bundle) -> SimValue { - #![allow(unused_mut)] - #![allow(clippy::unused_unit)] - let ($($var,)*) = self; - let [$($ty_var,)*] = *ty.fields() else { - panic!("bundle has wrong number of fields"); - }; - let mut bits = BitVec::new(); - $(let $var = $var.into_sim_value_with_type($ty_var.ty); - assert_eq!(SimValue::ty(&$var), $ty_var.ty); - bits.extend_from_bitslice(SimValue::bits(&$var).bits()); - )* - bits.into_sim_value_with_type(ty) - } - } - impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { - #[track_caller] - fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { - let ($($var,)*) = self; - let ($($ty_var,)*) = ty; - $(let $var = $var.to_sim_value_with_type($ty_var);)* - SimValue::from_value(ty, ($($var,)*)) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { - let ($($var,)*) = self; - let ($($ty_var,)*) = ty; - $(let $var = $var.into_sim_value_with_type($ty_var);)* - SimValue::from_value(ty, ($($var,)*)) - } - } - impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { - type Type = ($($T::Type,)*); - #[track_caller] - fn to_sim_value(&self) -> SimValue { - let ($($var,)*) = self; - $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) - } - #[track_caller] - fn into_sim_value(self) -> SimValue { - let ($($var,)*) = self; - $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) - } - } - impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { - fn cmp_eq(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .all_one_bits() - } - - fn cmp_ne(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .any_one_bits() - } - } - impl<$($Lhs: SimValuePartialEq<$Rhs>, $Rhs: Type,)*> SimValuePartialEq<($($Rhs,)*)> for ($($Lhs,)*) { - fn sim_value_eq(lhs: &SimValue, rhs: &SimValue<($($Rhs,)*)>) -> bool { - let ($($lhs_var,)*) = &**lhs; - let ($($rhs_var,)*) = &**rhs; - let retval = true; - $(let retval = retval && $lhs_var == $rhs_var;)* - retval - } - } }; ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { impl_tuples!([$($lhs)*] []); @@ -672,146 +424,17 @@ macro_rules! impl_tuples { impl_tuples! { [] [ - {#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0} - {#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1} - {#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2} - {#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3} - {#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4} - {#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5} - {#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6} - {#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7} - {#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8} - {#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9} - {#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10} - {#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11} + {#[num = 0, field = field_0] v0: T0} + {#[num = 1, field = field_1] v1: T1} + {#[num = 2, field = field_2] v2: T2} + {#[num = 3, field = field_3] v3: T3} + {#[num = 4, field = field_4] v4: T4} + {#[num = 5, field = field_5] v5: T5} + {#[num = 6, field = field_6] v6: T6} + {#[num = 7, field = field_7] v7: T7} + {#[num = 8, field = field_8] v8: T8} + {#[num = 9, field = field_9] v9: T9} + {#[num = 10, field = field_10] v10: T10} + {#[num = 11, field = field_11] v11: T11} ] } - -impl Type for PhantomData { - type BaseType = Bundle; - type MaskType = (); - type SimValue = PhantomData; - type MatchVariant = PhantomData; - type MatchActiveScope = (); - type MatchVariantAndInactiveScope = MatchVariantWithoutScope; - type MatchVariantsIter = std::iter::Once; - fn match_variants( - this: Expr, - source_location: SourceLocation, - ) -> Self::MatchVariantsIter { - let _ = this; - let _ = source_location; - std::iter::once(MatchVariantWithoutScope(PhantomData)) - } - fn mask_type(&self) -> Self::MaskType { - () - } - fn canonical(&self) -> CanonicalType { - Bundle::new(self.fields()).canonical() - } - #[track_caller] - fn from_canonical(canonical_type: CanonicalType) -> Self { - let CanonicalType::Bundle(bundle) = canonical_type else { - panic!("expected bundle"); - }; - assert!( - bundle.fields().is_empty(), - "bundle has wrong number of fields" - ); - PhantomData - } - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert!(bits.is_empty()); - *self - } - fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { - assert!(bits.is_empty()); - } - fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { - assert!(bits.is_empty()); - } -} - -pub struct PhantomDataBuilder(PhantomData); - -impl Default for PhantomDataBuilder { - fn default() -> Self { - Self(PhantomData) - } -} - -impl ToExpr for PhantomDataBuilder { - type Type = PhantomData; - - fn to_expr(&self) -> Expr { - PhantomData.to_expr() - } -} - -impl BundleType for PhantomData { - type Builder = PhantomDataBuilder; - type FilledBuilder = PhantomDataBuilder; - fn fields(&self) -> Interned<[BundleField]> { - Interned::default() - } -} - -impl TypeWithDeref for PhantomData { - fn expr_deref(_this: &Expr) -> &Self::MatchVariant { - &PhantomData - } -} - -impl StaticType for PhantomData { - const TYPE: Self = PhantomData; - const MASK_TYPE: Self::MaskType = (); - const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; - const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; -} - -impl ToExpr for PhantomData { - type Type = PhantomData; - - fn to_expr(&self) -> Expr { - BundleLiteral::new(PhantomData, Interned::default()).to_expr() - } -} - -impl ToSimValue for PhantomData { - type Type = PhantomData; - - #[track_caller] - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(*self, *self) - } -} - -impl ToSimValueWithType for PhantomData { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Self) -> SimValue { - SimValue::from_value(ty, *self) - } -} - -impl ToSimValueWithType for PhantomData { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue { - assert!(ty.fields().is_empty()); - ToSimValueWithType::into_sim_value_with_type(BitVec::new(), ty) - } -} - -impl ToSimValueWithType for PhantomData { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - let ty = Bundle::from_canonical(ty); - assert!(ty.fields().is_empty()); - SimValue::into_canonical(ToSimValueWithType::into_sim_value_with_type( - BitVec::new(), - ty, - )) - } -} diff --git a/crates/fayalite/src/cli.rs b/crates/fayalite/src/cli.rs index 1f208a8..f848d36 100644 --- a/crates/fayalite/src/cli.rs +++ b/crates/fayalite/src/cli.rs @@ -1,27 +1,15 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use crate::{ bundle::{Bundle, BundleType}, - firrtl::{self, ExportOptions}, + firrtl, intern::Interned, module::Module, - util::{job_server::AcquiredJob, streaming_read_utf8::streaming_read_utf8}, }; use clap::{ builder::{OsStringValueParser, TypedValueParser}, - Parser, Subcommand, ValueEnum, ValueHint, + Args, Parser, Subcommand, ValueEnum, ValueHint, }; use eyre::{eyre, Report}; -use serde::{Deserialize, Serialize}; -use std::{ - error, - ffi::OsString, - fmt::{self, Write}, - fs, io, mem, - path::{Path, PathBuf}, - process, -}; -use tempfile::TempDir; +use std::{error, ffi::OsString, fmt, io, path::PathBuf, process}; pub type Result = std::result::Result; @@ -49,157 +37,74 @@ impl From for CliError { pub trait RunPhase { type Output; - fn run(&self, arg: Arg) -> Result { - self.run_with_job(arg, &mut AcquiredJob::acquire()) - } - fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result; + fn run(&self, arg: Arg) -> Result; } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct BaseArgs { /// the directory to put the generated main output file and associated files in - #[arg(short, long, value_hint = ValueHint::DirPath, required = true)] - pub output: Option, + #[arg(short, long, value_hint = ValueHint::DirPath)] + pub output: PathBuf, /// the stem of the generated main output file, e.g. to get foo.v, pass --file-stem=foo #[arg(long)] pub file_stem: Option, - #[arg(long, env = "FAYALITE_KEEP_TEMP_DIR")] - pub keep_temp_dir: bool, - #[arg(skip = false)] - pub redirect_output_for_rust_test: bool, } impl BaseArgs { - fn make_firrtl_file_backend(&self) -> Result<(firrtl::FileBackend, Option)> { - let (dir_path, temp_dir) = match &self.output { - Some(output) => (output.clone(), None), - None => { - let temp_dir = TempDir::new()?; - if self.keep_temp_dir { - let temp_dir = temp_dir.into_path(); - println!("created temporary directory: {}", temp_dir.display()); - (temp_dir, None) - } else { - (temp_dir.path().to_path_buf(), Some(temp_dir)) - } - } - }; - Ok(( - firrtl::FileBackend { - dir_path, - top_fir_file_stem: self.file_stem.clone(), - circuit_name: None, - }, - temp_dir, - )) - } - /// handles possibly redirecting the command's output for Rust tests - pub fn run_external_command( - &self, - _acquired_job: &mut AcquiredJob, - mut command: process::Command, - mut captured_output: Option<&mut String>, - ) -> io::Result { - if self.redirect_output_for_rust_test || captured_output.is_some() { - let (reader, writer) = os_pipe::pipe()?; - let mut reader = io::BufReader::new(reader); - command.stderr(writer.try_clone()?); - command.stdout(writer); // must not leave writer around after spawning child - command.stdin(process::Stdio::null()); - let mut child = command.spawn()?; - drop(command); // close writers - Ok(loop { - let status = child.try_wait()?; - streaming_read_utf8(&mut reader, |s| { - if let Some(captured_output) = captured_output.as_deref_mut() { - captured_output.push_str(s); - } - // use print! so output goes to Rust test output capture - print!("{s}"); - io::Result::Ok(()) - })?; - if let Some(status) = status { - break status; - } - }) - } else { - command.status() + pub fn to_firrtl_file_backend(&self) -> firrtl::FileBackend { + firrtl::FileBackend { + dir_path: self.output.clone(), + top_fir_file_stem: self.file_stem.clone(), } } } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct FirrtlArgs { #[command(flatten)] pub base: BaseArgs, - #[command(flatten)] - pub export_options: ExportOptions, } #[derive(Debug)] #[non_exhaustive] pub struct FirrtlOutput { pub file_stem: String, - pub top_module: String, - pub output_dir: PathBuf, - pub temp_dir: Option, } impl FirrtlOutput { - pub fn file_with_ext(&self, ext: &str) -> PathBuf { - let mut retval = self.output_dir.join(&self.file_stem); - retval.set_extension(ext); + pub fn firrtl_file(&self, args: &FirrtlArgs) -> PathBuf { + let mut retval = args.base.output.join(&self.file_stem); + retval.set_extension("fir"); retval } - pub fn firrtl_file(&self) -> PathBuf { - self.file_with_ext("fir") - } } impl FirrtlArgs { - fn run_impl( - &self, - top_module: Module, - _acquired_job: &mut AcquiredJob, - ) -> Result { - let (file_backend, temp_dir) = self.base.make_firrtl_file_backend()?; + fn run_impl(&self, top_module: Module) -> Result { let firrtl::FileBackend { - top_fir_file_stem, - circuit_name, - dir_path, - } = firrtl::export(file_backend, &top_module, self.export_options)?; + top_fir_file_stem, .. + } = firrtl::export(self.base.to_firrtl_file_backend(), &top_module)?; Ok(FirrtlOutput { file_stem: top_fir_file_stem.expect( "export is known to set the file stem from the circuit name if not provided", ), - top_module: circuit_name.expect("export is known to set the circuit name"), - output_dir: dir_path, - temp_dir, }) } } impl RunPhase> for FirrtlArgs { type Output = FirrtlOutput; - fn run_with_job( - &self, - top_module: Module, - acquired_job: &mut AcquiredJob, - ) -> Result { - self.run_impl(top_module.canonical(), acquired_job) + fn run(&self, top_module: Module) -> Result { + self.run_impl(top_module.canonical()) } } impl RunPhase>> for FirrtlArgs { type Output = FirrtlOutput; - fn run_with_job( - &self, - top_module: Interned>, - acquired_job: &mut AcquiredJob, - ) -> Result { - self.run_with_job(*top_module, acquired_job) + fn run(&self, top_module: Interned>) -> Result { + self.run(*top_module) } } @@ -215,22 +120,7 @@ pub enum VerilogDialect { Yosys, } -impl fmt::Display for VerilogDialect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - impl VerilogDialect { - pub fn as_str(self) -> &'static str { - match self { - VerilogDialect::Questa => "questa", - VerilogDialect::Spyglass => "spyglass", - VerilogDialect::Verilator => "verilator", - VerilogDialect::Vivado => "vivado", - VerilogDialect::Yosys => "yosys", - } - } pub fn firtool_extra_args(self) -> &'static [&'static str] { match self { VerilogDialect::Questa => &["--lowering-options=emitWireInPorts"], @@ -248,7 +138,7 @@ impl VerilogDialect { } } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct VerilogArgs { #[command(flatten)] @@ -258,7 +148,7 @@ pub struct VerilogArgs { default_value = "firtool", env = "FIRTOOL", value_hint = ValueHint::CommandName, - value_parser = OsStringValueParser::new().try_map(which) + value_parser = OsStringValueParser::new().try_map(which::which) )] pub firtool: PathBuf, #[arg(long)] @@ -266,94 +156,39 @@ pub struct VerilogArgs { /// adapt the generated Verilog for a particular toolchain #[arg(long)] pub verilog_dialect: Option, - #[arg(long, short = 'g')] - pub debug: bool, } #[derive(Debug)] #[non_exhaustive] pub struct VerilogOutput { pub firrtl: FirrtlOutput, - pub verilog_files: Vec, - pub contents_hash: Option, } impl VerilogOutput { - pub fn main_verilog_file(&self) -> PathBuf { - self.firrtl.file_with_ext("v") - } - fn unadjusted_verilog_file(&self) -> PathBuf { - self.firrtl.file_with_ext("unadjusted.v") + pub fn verilog_file(&self, args: &VerilogArgs) -> PathBuf { + let mut retval = args.firrtl.base.output.join(&self.firrtl.file_stem); + retval.set_extension("v"); + retval } } impl VerilogArgs { - fn process_unadjusted_verilog_file(&self, mut output: VerilogOutput) -> Result { - let input = fs::read_to_string(output.unadjusted_verilog_file())?; - let file_separator_prefix = "\n// ----- 8< ----- FILE \""; - let file_separator_suffix = "\" ----- 8< -----\n\n"; - let mut input = &*input; - output.contents_hash = Some(blake3::hash(input.as_bytes())); - let main_verilog_file = output.main_verilog_file(); - let mut file_name: Option<&Path> = Some(&main_verilog_file); - loop { - let (chunk, next_file_name) = if let Some((chunk, rest)) = - input.split_once(file_separator_prefix) - { - let Some((next_file_name, rest)) = rest.split_once(file_separator_suffix) else { - return Err(CliError(eyre!("parsing firtool's output failed: found {file_separator_prefix:?} but no {file_separator_suffix:?}"))); - }; - input = rest; - (chunk, Some(next_file_name.as_ref())) - } else { - (mem::take(&mut input), None) - }; - let Some(file_name) = mem::replace(&mut file_name, next_file_name) else { - break; - }; - let file_name = output.firrtl.output_dir.join(file_name); - fs::write(&file_name, chunk)?; - if let Some(extension) = file_name.extension() { - if extension == "v" || extension == "sv" { - output.verilog_files.push(file_name); - } - } - } - Ok(output) - } - fn run_impl( - &self, - firrtl_output: FirrtlOutput, - acquired_job: &mut AcquiredJob, - ) -> Result { - let Self { - firrtl, - firtool, - firtool_extra_args, - verilog_dialect, - debug, - } = self; + fn run_impl(&self, firrtl_output: FirrtlOutput) -> Result { let output = VerilogOutput { firrtl: firrtl_output, - verilog_files: vec![], - contents_hash: None, }; - let mut cmd = process::Command::new(firtool); - cmd.arg(output.firrtl.firrtl_file()); + let mut cmd = process::Command::new(&self.firtool); + cmd.arg(output.firrtl.firrtl_file(&self.firrtl)); cmd.arg("-o"); - cmd.arg(output.unadjusted_verilog_file()); - if *debug { - cmd.arg("-g"); - cmd.arg("--preserve-values=all"); - } - if let Some(dialect) = verilog_dialect { + cmd.arg(output.verilog_file(self)); + if let Some(dialect) = self.verilog_dialect { cmd.args(dialect.firtool_extra_args()); } - cmd.args(firtool_extra_args); - cmd.current_dir(&output.firrtl.output_dir); - let status = firrtl.base.run_external_command(acquired_job, cmd, None)?; + cmd.args(&self.firtool_extra_args); + cmd.current_dir(&self.firrtl.base.output); + let status = cmd.status()?; if status.success() { - self.process_unadjusted_verilog_file(output) + Ok(output) } else { Err(CliError(eyre!( "running {} failed: {status}", @@ -368,323 +203,9 @@ where FirrtlArgs: RunPhase, { type Output = VerilogOutput; - fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result { - let firrtl_output = self.firrtl.run_with_job(arg, acquired_job)?; - self.run_impl(firrtl_output, acquired_job) - } -} - -#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash, Default)] -#[non_exhaustive] -pub enum FormalMode { - #[default] - BMC, - Prove, - Live, - Cover, -} - -impl FormalMode { - pub fn as_str(self) -> &'static str { - match self { - FormalMode::BMC => "bmc", - FormalMode::Prove => "prove", - FormalMode::Live => "live", - FormalMode::Cover => "cover", - } - } -} - -impl fmt::Display for FormalMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -#[derive(Clone)] -struct FormalAdjustArgs; - -impl clap::FromArgMatches for FormalAdjustArgs { - fn from_arg_matches(_matches: &clap::ArgMatches) -> Result { - Ok(Self) - } - - fn update_from_arg_matches(&mut self, _matches: &clap::ArgMatches) -> Result<(), clap::Error> { - Ok(()) - } -} - -impl clap::Args for FormalAdjustArgs { - fn augment_args(cmd: clap::Command) -> clap::Command { - cmd.mut_arg("output", |arg| arg.required(false)) - .mut_arg("verilog_dialect", |arg| { - arg.default_value(VerilogDialect::Yosys.to_string()) - .hide(true) - }) - } - - fn augment_args_for_update(cmd: clap::Command) -> clap::Command { - Self::augment_args(cmd) - } -} - -fn which(v: std::ffi::OsString) -> which::Result { - #[cfg(not(miri))] - return which::which(v); - #[cfg(miri)] - return Ok(Path::new("/").join(v)); -} - -#[derive(Parser, Clone)] -#[non_exhaustive] -pub struct FormalArgs { - #[command(flatten)] - pub verilog: VerilogArgs, - #[arg( - long, - default_value = "sby", - env = "SBY", - value_hint = ValueHint::CommandName, - value_parser = OsStringValueParser::new().try_map(which) - )] - pub sby: PathBuf, - #[arg(long)] - pub sby_extra_args: Vec, - #[arg(long, default_value_t)] - pub mode: FormalMode, - #[arg(long, default_value_t = Self::DEFAULT_DEPTH)] - pub depth: u64, - #[arg(long, default_value = "z3")] - pub solver: String, - #[arg(long)] - pub smtbmc_extra_args: Vec, - #[arg(long, default_value_t = true, env = "FAYALITE_CACHE_RESULTS")] - pub cache_results: bool, - #[command(flatten)] - _formal_adjust_args: FormalAdjustArgs, -} - -impl fmt::Debug for FormalArgs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - verilog, - sby, - sby_extra_args, - mode, - depth, - solver, - smtbmc_extra_args, - cache_results, - _formal_adjust_args: _, - } = self; - f.debug_struct("FormalArgs") - .field("verilog", verilog) - .field("sby", sby) - .field("sby_extra_args", sby_extra_args) - .field("mode", mode) - .field("depth", depth) - .field("solver", solver) - .field("smtbmc_extra_args", smtbmc_extra_args) - .field("cache_results", cache_results) - .finish_non_exhaustive() - } -} - -impl FormalArgs { - pub const DEFAULT_DEPTH: u64 = 20; -} - -#[derive(Debug)] -#[non_exhaustive] -pub struct FormalOutput { - pub verilog: VerilogOutput, -} - -impl FormalOutput { - pub fn sby_file(&self) -> PathBuf { - self.verilog.firrtl.file_with_ext("sby") - } - pub fn cache_file(&self) -> PathBuf { - self.verilog.firrtl.file_with_ext("cache.json") - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] -pub struct FormalCacheOutput {} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] -pub enum FormalCacheVersion { - V1, -} - -impl FormalCacheVersion { - pub const CURRENT: Self = Self::V1; -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] -pub struct FormalCache { - pub version: FormalCacheVersion, - pub contents_hash: blake3::Hash, - pub stdout_stderr: String, - pub result: Result, -} - -impl FormalCache { - pub fn new( - version: FormalCacheVersion, - contents_hash: blake3::Hash, - stdout_stderr: String, - result: Result, - ) -> Self { - Self { - version, - contents_hash, - stdout_stderr, - result, - } - } -} - -impl FormalArgs { - fn sby_contents(&self, output: &FormalOutput) -> Result { - let Self { - verilog: _, - sby: _, - sby_extra_args: _, - mode, - depth, - smtbmc_extra_args, - solver, - cache_results: _, - _formal_adjust_args: _, - } = self; - let smtbmc_options = smtbmc_extra_args.join(" "); - let top_module = &output.verilog.firrtl.top_module; - let mut retval = format!( - "[options]\n\ - mode {mode}\n\ - depth {depth}\n\ - wait on\n\ - \n\ - [engines]\n\ - smtbmc {solver} -- -- {smtbmc_options}\n\ - \n\ - [script]\n" - ); - for verilog_file in &output.verilog.verilog_files { - let verilog_file = verilog_file - .to_str() - .ok_or_else(|| CliError(eyre!("verilog file path is not UTF-8")))?; - if verilog_file.contains(|ch: char| { - (ch != ' ' && ch != '\t' && ch.is_ascii_whitespace()) || ch == '"' - }) { - return Err(CliError(eyre!( - "verilog file path contains characters that aren't permitted" - ))); - } - writeln!(retval, "read_verilog -sv -formal \"{verilog_file}\"").unwrap(); - } - // workaround for wires disappearing -- set `keep` on all wires - writeln!(retval, "hierarchy -top {top_module}").unwrap(); - writeln!(retval, "proc").unwrap(); - writeln!(retval, "setattr -set keep 1 w:\\*").unwrap(); - writeln!(retval, "prep").unwrap(); - Ok(retval) - } - fn run_impl( - &self, - verilog_output: VerilogOutput, - acquired_job: &mut AcquiredJob, - ) -> Result { - let output = FormalOutput { - verilog: verilog_output, - }; - let sby_file = output.sby_file(); - let sby_contents = self.sby_contents(&output)?; - let contents_hash = output.verilog.contents_hash.map(|verilog_hash| { - let mut hasher = blake3::Hasher::new(); - hasher.update(verilog_hash.as_bytes()); - hasher.update(sby_contents.as_bytes()); - hasher.update(&(self.sby_extra_args.len() as u64).to_le_bytes()); - for sby_extra_arg in self.sby_extra_args.iter() { - hasher.update(&(sby_extra_arg.len() as u64).to_le_bytes()); - hasher.update(sby_extra_arg.as_bytes()); - } - hasher.finalize() - }); - std::fs::write(&sby_file, sby_contents)?; - let mut cmd = process::Command::new(&self.sby); - cmd.arg("-j1"); // sby seems not to respect job count in parallel mode - cmd.arg("-f"); - cmd.arg(sby_file.file_name().unwrap()); - cmd.args(&self.sby_extra_args); - cmd.current_dir(&output.verilog.firrtl.output_dir); - let mut captured_output = String::new(); - let cache_file = output.cache_file(); - let do_cache = if let Some(contents_hash) = contents_hash.filter(|_| self.cache_results) { - if let Some(FormalCache { - version: FormalCacheVersion::CURRENT, - contents_hash: cache_contents_hash, - stdout_stderr, - result, - }) = fs::read(&cache_file) - .ok() - .and_then(|v| serde_json::from_slice(&v).ok()) - { - if cache_contents_hash == contents_hash { - println!("Using cached formal result:\n{stdout_stderr}"); - return match result { - Ok(FormalCacheOutput {}) => Ok(output), - Err(error) => Err(CliError(eyre::Report::msg(error))), - }; - } - } - true - } else { - false - }; - let _ = fs::remove_file(&cache_file); - let status = self.verilog.firrtl.base.run_external_command( - acquired_job, - cmd, - do_cache.then_some(&mut captured_output), - )?; - let result = if status.success() { - Ok(output) - } else { - Err(CliError(eyre!( - "running {} failed: {status}", - self.sby.display() - ))) - }; - fs::write( - cache_file, - serde_json::to_string_pretty(&FormalCache { - version: FormalCacheVersion::CURRENT, - contents_hash: contents_hash.unwrap(), - stdout_stderr: captured_output, - result: match &result { - Ok(FormalOutput { verilog: _ }) => Ok(FormalCacheOutput {}), - Err(error) => Err(error.to_string()), - }, - }) - .expect("serialization shouldn't ever fail"), - )?; - result - } -} - -impl RunPhase for FormalArgs -where - VerilogArgs: RunPhase, -{ - type Output = FormalOutput; - fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result { - let verilog_output = self.verilog.run_with_job(arg, acquired_job)?; - self.run_impl(verilog_output, acquired_job) + fn run(&self, arg: Arg) -> Result { + let firrtl_output = self.firrtl.run(arg)?; + self.run_impl(firrtl_output) } } @@ -694,8 +215,6 @@ enum CliCommand { Firrtl(FirrtlArgs), /// Generate Verilog Verilog(VerilogArgs), - /// Run a formal proof - Formal(FormalArgs), } /// a simple CLI @@ -773,16 +292,13 @@ where FirrtlArgs: RunPhase, { type Output = (); - fn run_with_job(&self, arg: T, acquired_job: &mut AcquiredJob) -> Result { + fn run(&self, arg: T) -> Result { match &self.subcommand { CliCommand::Firrtl(c) => { - c.run_with_job(arg, acquired_job)?; + c.run(arg)?; } CliCommand::Verilog(c) => { - c.run_with_job(arg, acquired_job)?; - } - CliCommand::Formal(c) => { - c.run_with_job(arg, acquired_job)?; + c.run(arg)?; } } Ok(()) diff --git a/crates/fayalite/src/clock.rs b/crates/fayalite/src/clock.rs index f0623d4..fe99653 100644 --- a/crates/fayalite/src/clock.rs +++ b/crates/fayalite/src/clock.rs @@ -4,11 +4,10 @@ use crate::{ expr::{Expr, ToExpr}, hdl, int::Bool, - reset::{Reset, ResetType}, + reset::Reset, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; -use bitvec::slice::BitSlice; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct Clock; @@ -16,7 +15,6 @@ pub struct Clock; impl Type for Clock { type BaseType = Clock; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); @@ -38,21 +36,6 @@ impl Type for Clock { }; retval } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), 1); - bits[0] - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), 1); - *value = bits[0]; - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), 1); - bits.set(0, *value); - } } impl Clock { @@ -105,9 +88,9 @@ impl ToClock for Expr { } #[hdl] -pub struct ClockDomain { +pub struct ClockDomain { pub clk: Clock, - pub rst: R, + pub rst: Reset, } impl ToClock for bool { diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 36b5aa7..384414c 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -2,30 +2,21 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ExprPartialEq, VariantAccess}, - Expr, ToExpr, - }, + expr::{ops::VariantAccess, Expr, ToExpr}, hdl, - int::{Bool, UIntValue}, + int::Bool, intern::{Intern, Interned}, module::{ - connect, enum_match_variants_helper, incomplete_wire, wire, - EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, + enum_match_variants_helper, EnumMatchVariantAndInactiveScopeImpl, + EnumMatchVariantsIterImpl, Scope, }, - sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, - ty::{ - CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type, - TypeProperties, - }, - util::HashMap, + ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties}, }; -use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; -use serde::{Deserialize, Serialize}; -use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc}; +use hashbrown::HashMap; +use std::{fmt, iter::FusedIterator}; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct EnumVariant { pub name: Interned, pub ty: Option, @@ -158,12 +149,6 @@ impl EnumTypePropertiesBuilder { variant_count: variant_count + 1, } } - #[must_use] - pub fn variants(self, variants: impl IntoIterator) -> Self { - variants.into_iter().fold(self, |this, variant| { - this.variant(variant.ty.map(CanonicalType::type_properties)) - }) - } pub const fn finish(self) -> TypeProperties { assert!( self.variant_count != 0, @@ -184,17 +169,10 @@ impl EnumTypePropertiesBuilder { } } -impl Default for EnumTypePropertiesBuilder { - fn default() -> Self { - Self::new() - } -} - impl Enum { #[track_caller] pub fn new(variants: Interned<[EnumVariant]>) -> Self { - let mut name_indexes = - HashMap::with_capacity_and_hasher(variants.len(), Default::default()); + let mut name_indexes = HashMap::with_capacity(variants.len()); let mut type_props_builder = EnumTypePropertiesBuilder::new(); for (index, EnumVariant { name, ty }) in variants.iter().enumerate() { if let Some(old_index) = name_indexes.insert(*name, index) { @@ -261,7 +239,6 @@ pub trait EnumType: MatchVariantsIter = EnumMatchVariantsIter, > { - type SimBuilder: From; fn variants(&self) -> Interned<[EnumVariant]>; fn match_activate_scope( v: Self::MatchVariantAndInactiveScope, @@ -324,18 +301,7 @@ impl DoubleEndedIterator for EnumMatchVariantsIter { } } -pub struct NoBuilder { - _ty: Enum, -} - -impl From for NoBuilder { - fn from(_ty: Enum) -> Self { - Self { _ty } - } -} - impl EnumType for Enum { - type SimBuilder = NoBuilder; fn match_activate_scope( v: Self::MatchVariantAndInactiveScope, ) -> (Self::MatchVariant, Self::MatchActiveScope) { @@ -350,7 +316,6 @@ impl EnumType for Enum { impl Type for Enum { type BaseType = Enum; type MaskType = Bool; - type SimValue = OpaqueSimValue; type MatchVariant = Option>; type MatchActiveScope = Scope; type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope; @@ -381,309 +346,6 @@ impl Type for Enum { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), self.type_properties().bit_width); - OpaqueSimValue::from_bitslice(bits) - } - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), self.type_properties().bit_width); - assert_eq!(value.bit_width(), self.type_properties().bit_width); - value.bits_mut().bits_mut().copy_from_bitslice(bits); - } - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), self.type_properties().bit_width); - assert_eq!(value.bit_width(), self.type_properties().bit_width); - bits.copy_from_bitslice(value.bits().bits()); - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct EnumPaddingSimValue { - bits: Option, -} - -impl EnumPaddingSimValue { - pub const fn new() -> Self { - Self { bits: None } - } - pub fn bit_width(&self) -> Option { - self.bits.as_ref().map(UIntValue::width) - } - pub fn bits(&self) -> &Option { - &self.bits - } - pub fn bits_mut(&mut self) -> &mut Option { - &mut self.bits - } - pub fn into_bits(self) -> Option { - self.bits - } - pub fn from_bits(bits: Option) -> Self { - Self { bits } - } - pub fn from_bitslice(v: &BitSlice) -> Self { - Self { - bits: Some(UIntValue::new(Arc::new(v.to_bitvec()))), - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct UnknownVariantSimValue { - discriminant: usize, - body_bits: UIntValue, -} - -impl UnknownVariantSimValue { - pub fn discriminant(&self) -> usize { - self.discriminant - } - pub fn body_bits(&self) -> &UIntValue { - &self.body_bits - } - pub fn body_bits_mut(&mut self) -> &mut UIntValue { - &mut self.body_bits - } - pub fn into_body_bits(self) -> UIntValue { - self.body_bits - } - pub fn into_parts(self) -> (usize, UIntValue) { - (self.discriminant, self.body_bits) - } - pub fn new(discriminant: usize, body_bits: UIntValue) -> Self { - Self { - discriminant, - body_bits, - } - } -} - -pub struct EnumSimValueFromBits<'a> { - variants: Interned<[EnumVariant]>, - discriminant: usize, - body_bits: &'a BitSlice, -} - -impl<'a> EnumSimValueFromBits<'a> { - #[track_caller] - pub fn new(ty: T, bits: &'a BitSlice) -> Self { - let variants = ty.variants(); - let bit_width = EnumTypePropertiesBuilder::new() - .variants(variants) - .finish() - .bit_width; - assert_eq!(bit_width, bits.len()); - let (discriminant_bits, body_bits) = - bits.split_at(discriminant_bit_width_impl(variants.len())); - let mut discriminant = 0usize; - discriminant.view_bits_mut::()[..discriminant_bits.len()] - .copy_from_bitslice(discriminant_bits); - Self { - variants, - discriminant, - body_bits, - } - } - pub fn discriminant(&self) -> usize { - self.discriminant - } - #[track_caller] - #[cold] - fn usage_error(&self, clone: bool) -> ! { - let clone = if clone { "clone_" } else { "" }; - match self.variants.get(self.discriminant) { - None => { - panic!("should have called EnumSimValueFromBits::unknown_variant_{clone}from_bits"); - } - Some(EnumVariant { ty: None, .. }) => { - panic!( - "should have called EnumSimValueFromBits::variant_no_field_{clone}from_bits" - ); - } - Some(EnumVariant { ty: Some(_), .. }) => { - panic!( - "should have called EnumSimValueFromBits::variant_with_field_{clone}from_bits" - ); - } - } - } - #[track_caller] - fn known_variant(&self, clone: bool) -> (Option, &'a BitSlice, &'a BitSlice) { - let Some(EnumVariant { ty, .. }) = self.variants.get(self.discriminant) else { - self.usage_error(clone); - }; - let variant_bit_width = ty.map_or(0, CanonicalType::bit_width); - let (variant_bits, padding_bits) = self.body_bits.split_at(variant_bit_width); - (*ty, variant_bits, padding_bits) - } - #[track_caller] - pub fn unknown_variant_from_bits(self) -> UnknownVariantSimValue { - let None = self.variants.get(self.discriminant) else { - self.usage_error(false); - }; - UnknownVariantSimValue::new( - self.discriminant, - UIntValue::new(Arc::new(self.body_bits.to_bitvec())), - ) - } - #[track_caller] - pub fn unknown_variant_clone_from_bits(self, value: &mut UnknownVariantSimValue) { - let None = self.variants.get(self.discriminant) else { - self.usage_error(true); - }; - value.discriminant = self.discriminant; - assert_eq!(value.body_bits.width(), self.body_bits.len()); - value - .body_bits - .bits_mut() - .copy_from_bitslice(self.body_bits); - } - #[track_caller] - pub fn variant_no_field_from_bits(self) -> EnumPaddingSimValue { - let (None, _variant_bits, padding_bits) = self.known_variant(false) else { - self.usage_error(false); - }; - EnumPaddingSimValue::from_bitslice(padding_bits) - } - #[track_caller] - pub fn variant_with_field_from_bits(self) -> (SimValue, EnumPaddingSimValue) { - let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { - self.usage_error(false); - }; - ( - SimValue::from_bitslice(T::from_canonical(variant_ty), variant_bits), - EnumPaddingSimValue::from_bitslice(padding_bits), - ) - } - #[track_caller] - fn clone_padding_from_bits(padding: &mut EnumPaddingSimValue, padding_bits: &BitSlice) { - match padding.bits_mut() { - None => *padding = EnumPaddingSimValue::from_bitslice(padding_bits), - Some(padding) => { - assert_eq!(padding.width(), padding_bits.len()); - padding.bits_mut().copy_from_bitslice(padding_bits); - } - } - } - #[track_caller] - pub fn variant_no_field_clone_from_bits(self, padding: &mut EnumPaddingSimValue) { - let (None, _variant_bits, padding_bits) = self.known_variant(true) else { - self.usage_error(true); - }; - Self::clone_padding_from_bits(padding, padding_bits); - } - #[track_caller] - pub fn variant_with_field_clone_from_bits( - self, - value: &mut SimValue, - padding: &mut EnumPaddingSimValue, - ) { - let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else { - self.usage_error(true); - }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); - SimValue::bits_mut(value) - .bits_mut() - .copy_from_bitslice(variant_bits); - Self::clone_padding_from_bits(padding, padding_bits); - } -} - -pub struct EnumSimValueToBits<'a> { - variants: Interned<[EnumVariant]>, - bit_width: usize, - discriminant_bit_width: usize, - bits: &'a mut BitSlice, -} - -impl<'a> EnumSimValueToBits<'a> { - #[track_caller] - pub fn new(ty: T, bits: &'a mut BitSlice) -> Self { - let variants = ty.variants(); - let bit_width = EnumTypePropertiesBuilder::new() - .variants(variants) - .finish() - .bit_width; - assert_eq!(bit_width, bits.len()); - Self { - variants, - bit_width, - discriminant_bit_width: discriminant_bit_width_impl(variants.len()), - bits, - } - } - #[track_caller] - fn discriminant_to_bits(&mut self, mut discriminant: usize) { - let orig_discriminant = discriminant; - let discriminant_bits = - &mut discriminant.view_bits_mut::()[..self.discriminant_bit_width]; - self.bits[..self.discriminant_bit_width].copy_from_bitslice(discriminant_bits); - discriminant_bits.fill(false); - assert!( - discriminant == 0, - "{orig_discriminant:#x} is too big to fit in enum discriminant bits", - ); - } - #[track_caller] - pub fn unknown_variant_to_bits(mut self, value: &UnknownVariantSimValue) { - self.discriminant_to_bits(value.discriminant); - let None = self.variants.get(value.discriminant) else { - panic!("can't use UnknownVariantSimValue to set known discriminant"); - }; - assert_eq!( - self.bit_width - self.discriminant_bit_width, - value.body_bits.width() - ); - self.bits[self.discriminant_bit_width..].copy_from_bitslice(value.body_bits.bits()); - } - #[track_caller] - fn known_variant( - mut self, - discriminant: usize, - padding: &EnumPaddingSimValue, - ) -> (Option, &'a mut BitSlice) { - self.discriminant_to_bits(discriminant); - let variant_ty = self.variants[discriminant].ty; - let variant_bit_width = variant_ty.map_or(0, CanonicalType::bit_width); - let padding_bits = &mut self.bits[self.discriminant_bit_width..][variant_bit_width..]; - if let Some(padding) = padding.bits() { - assert_eq!(padding.width(), padding_bits.len()); - padding_bits.copy_from_bitslice(padding.bits()); - } else { - padding_bits.fill(false); - } - let variant_bits = &mut self.bits[self.discriminant_bit_width..][..variant_bit_width]; - (variant_ty, variant_bits) - } - #[track_caller] - pub fn variant_no_field_to_bits(self, discriminant: usize, padding: &EnumPaddingSimValue) { - let (None, _variant_bits) = self.known_variant(discriminant, padding) else { - panic!("expected variant to have no field"); - }; - } - #[track_caller] - pub fn variant_with_field_to_bits( - self, - discriminant: usize, - value: &SimValue, - padding: &EnumPaddingSimValue, - ) { - let (Some(variant_ty), variant_bits) = self.known_variant(discriminant, padding) else { - panic!("expected variant to have a field"); - }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); - variant_bits.copy_from_bitslice(SimValue::bits(value).bits()); - } -} - -#[doc(hidden)] -pub fn assert_is_enum_type(v: T) -> T { - v -} - -#[doc(hidden)] -pub fn enum_type_to_sim_builder(v: T) -> T::SimBuilder { - v.into() } #[hdl] @@ -692,79 +354,6 @@ pub enum HdlOption { HdlSome(T), } -impl, Rhs: Type> ExprPartialEq> for HdlOption { - #[hdl] - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_eq = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)), - HdlNone => connect(cmp_eq, false), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_eq, false), - HdlNone => connect(cmp_eq, true), - } - } - } - cmp_eq - } - - #[hdl] - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_ne = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)), - HdlNone => connect(cmp_ne, true), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_ne, true), - HdlNone => connect(cmp_ne, false), - } - } - } - cmp_ne - } -} - -impl, Rhs: Type> SimValuePartialEq> for HdlOption { - fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { - type SimValueMatch = ::SimValue; - match (&**this, &**other) { - (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlNone(_)) => { - true - } - (SimValueMatch::::HdlSome(..), SimValueMatch::>::HdlNone(_)) - | (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlSome(..)) => { - false - } - ( - SimValueMatch::::HdlSome(l, _), - SimValueMatch::>::HdlSome(r, _), - ) => l == r, - } - } -} - #[allow(non_snake_case)] pub fn HdlNone() -> Expr> { HdlOption[T::TYPE].HdlNone() @@ -775,307 +364,3 @@ pub fn HdlSome(value: impl ToExpr) -> Expr> { let value = value.to_expr(); HdlOption[Expr::ty(value)].HdlSome(value) } - -impl HdlOption { - #[track_caller] - pub fn try_map( - expr: Expr, - f: impl FnOnce(Expr) -> Result, E>, - ) -> Result>, E> { - Self::try_and_then(expr, |v| Ok(HdlSome(f(v)?))) - } - #[track_caller] - pub fn map( - expr: Expr, - f: impl FnOnce(Expr) -> Expr, - ) -> Expr> { - Self::and_then(expr, |v| HdlSome(f(v))) - } - #[hdl] - #[track_caller] - pub fn try_and_then( - expr: Expr, - f: impl FnOnce(Expr) -> Result>, E>, - ) -> Result>, E> { - // manually run match steps so we can extract the return type to construct HdlNone - type Wrap = T; - #[hdl] - let mut and_then_out = incomplete_wire(); - let mut iter = Self::match_variants(expr, SourceLocation::caller()); - let none = iter.next().unwrap(); - let some = iter.next().unwrap(); - assert!(iter.next().is_none()); - let (Wrap::<::MatchVariant>::HdlSome(value), some_scope) = - Self::match_activate_scope(some) - else { - unreachable!(); - }; - let value = f(value).inspect_err(|_| { - and_then_out.complete(()); // avoid error - })?; - let and_then_out = and_then_out.complete(Expr::ty(value)); - connect(and_then_out, value); - drop(some_scope); - let (Wrap::<::MatchVariant>::HdlNone, none_scope) = - Self::match_activate_scope(none) - else { - unreachable!(); - }; - connect(and_then_out, Expr::ty(and_then_out).HdlNone()); - drop(none_scope); - Ok(and_then_out) - } - #[track_caller] - pub fn and_then( - expr: Expr, - f: impl FnOnce(Expr) -> Expr>, - ) -> Expr> { - match Self::try_and_then(expr, |v| Ok::<_, Infallible>(f(v))) { - Ok(v) => v, - Err(e) => match e {}, - } - } - #[hdl] - #[track_caller] - pub fn and(expr: Expr, opt_b: Expr>) -> Expr> { - #[hdl] - let and_out = wire(Expr::ty(opt_b)); - connect(and_out, Expr::ty(opt_b).HdlNone()); - #[hdl] - if let HdlSome(_) = expr { - connect(and_out, opt_b); - } - and_out - } - #[hdl] - #[track_caller] - pub fn try_filter( - expr: Expr, - f: impl FnOnce(Expr) -> Result, E>, - ) -> Result, E> { - #[hdl] - let filtered = wire(Expr::ty(expr)); - connect(filtered, Expr::ty(expr).HdlNone()); - let mut f = Some(f); - #[hdl] - if let HdlSome(v) = expr { - #[hdl] - if f.take().unwrap()(v)? { - connect(filtered, HdlSome(v)); - } - } - Ok(filtered) - } - #[hdl] - #[track_caller] - pub fn filter(expr: Expr, f: impl FnOnce(Expr) -> Expr) -> Expr { - match Self::try_filter(expr, |v| Ok::<_, Infallible>(f(v))) { - Ok(v) => v, - Err(e) => match e {}, - } - } - #[hdl] - #[track_caller] - pub fn try_inspect( - expr: Expr, - f: impl FnOnce(Expr) -> Result<(), E>, - ) -> Result, E> { - let mut f = Some(f); - #[hdl] - if let HdlSome(v) = expr { - f.take().unwrap()(v)?; - } - Ok(expr) - } - #[hdl] - #[track_caller] - pub fn inspect(expr: Expr, f: impl FnOnce(Expr)) -> Expr { - let mut f = Some(f); - #[hdl] - if let HdlSome(v) = expr { - f.take().unwrap()(v); - } - expr - } - #[hdl] - #[track_caller] - pub fn is_none(expr: Expr) -> Expr { - #[hdl] - let is_none_out: Bool = wire(); - connect(is_none_out, false); - #[hdl] - if let HdlNone = expr { - connect(is_none_out, true); - } - is_none_out - } - #[hdl] - #[track_caller] - pub fn is_some(expr: Expr) -> Expr { - #[hdl] - let is_some_out: Bool = wire(); - connect(is_some_out, false); - #[hdl] - if let HdlSome(_) = expr { - connect(is_some_out, true); - } - is_some_out - } - #[hdl] - #[track_caller] - pub fn map_or( - expr: Expr, - default: Expr, - f: impl FnOnce(Expr) -> Expr, - ) -> Expr { - #[hdl] - let mapped = wire(Expr::ty(default)); - let mut f = Some(f); - #[hdl] - match expr { - HdlSome(v) => connect(mapped, f.take().unwrap()(v)), - HdlNone => connect(mapped, default), - } - mapped - } - #[hdl] - #[track_caller] - pub fn map_or_else( - expr: Expr, - default: impl FnOnce() -> Expr, - f: impl FnOnce(Expr) -> Expr, - ) -> Expr { - #[hdl] - let mut mapped = incomplete_wire(); - let mut default = Some(default); - let mut f = Some(f); - let mut retval = None; - #[hdl] - match expr { - HdlSome(v) => { - let v = f.take().unwrap()(v); - let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v))); - connect(mapped, v); - } - HdlNone => { - let v = default.take().unwrap()(); - let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v))); - connect(mapped, v); - } - } - retval.unwrap() - } - #[hdl] - #[track_caller] - pub fn or(expr: Expr, opt_b: Expr) -> Expr { - #[hdl] - let or_out = wire(Expr::ty(expr)); - connect(or_out, opt_b); - #[hdl] - if let HdlSome(_) = expr { - connect(or_out, expr); - } - or_out - } - #[hdl] - #[track_caller] - pub fn or_else(expr: Expr, f: impl FnOnce() -> Expr) -> Expr { - #[hdl] - let or_else_out = wire(Expr::ty(expr)); - connect(or_else_out, f()); - #[hdl] - if let HdlSome(_) = expr { - connect(or_else_out, expr); - } - or_else_out - } - #[hdl] - #[track_caller] - pub fn unwrap_or(expr: Expr, default: Expr) -> Expr { - #[hdl] - let unwrap_or_else_out = wire(Expr::ty(default)); - connect(unwrap_or_else_out, default); - #[hdl] - if let HdlSome(v) = expr { - connect(unwrap_or_else_out, v); - } - unwrap_or_else_out - } - #[hdl] - #[track_caller] - pub fn unwrap_or_else(expr: Expr, f: impl FnOnce() -> Expr) -> Expr { - #[hdl] - let unwrap_or_else_out = wire(Expr::ty(expr).HdlSome); - connect(unwrap_or_else_out, f()); - #[hdl] - if let HdlSome(v) = expr { - connect(unwrap_or_else_out, v); - } - unwrap_or_else_out - } - #[hdl] - #[track_caller] - pub fn xor(expr: Expr, opt_b: Expr) -> Expr { - #[hdl] - let xor_out = wire(Expr::ty(expr)); - #[hdl] - if let HdlSome(_) = expr { - #[hdl] - if let HdlNone = opt_b { - connect(xor_out, expr); - } else { - connect(xor_out, Expr::ty(expr).HdlNone()); - } - } else { - connect(xor_out, opt_b); - } - xor_out - } - #[hdl] - #[track_caller] - pub fn zip(expr: Expr, other: Expr>) -> Expr> { - #[hdl] - let zip_out = wire(HdlOption[(Expr::ty(expr).HdlSome, Expr::ty(other).HdlSome)]); - connect(zip_out, Expr::ty(zip_out).HdlNone()); - #[hdl] - if let HdlSome(l) = expr { - #[hdl] - if let HdlSome(r) = other { - connect(zip_out, HdlSome((l, r))); - } - } - zip_out - } -} - -impl HdlOption> { - #[hdl] - #[track_caller] - pub fn flatten(expr: Expr) -> Expr> { - #[hdl] - let flattened = wire(Expr::ty(expr).HdlSome); - #[hdl] - match expr { - HdlSome(v) => connect(flattened, v), - HdlNone => connect(flattened, Expr::ty(expr).HdlSome.HdlNone()), - } - flattened - } -} - -impl HdlOption<(T, U)> { - #[hdl] - #[track_caller] - pub fn unzip(expr: Expr) -> Expr<(HdlOption, HdlOption)> { - let (t, u) = Expr::ty(expr).HdlSome; - #[hdl] - let unzipped = wire((HdlOption[t], HdlOption[u])); - connect(unzipped, (HdlOption[t].HdlNone(), HdlOption[u].HdlNone())); - #[hdl] - if let HdlSome(v) = expr { - connect(unzipped.0, HdlSome(v.0)); - connect(unzipped.1, HdlSome(v.1)); - } - unzipped - } -} diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index e070674..607ff1e 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -9,16 +9,14 @@ use crate::{ ops::ExprCastTo, target::{GetTarget, Target}, }, - int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue}, + int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{DynPortType, MemPort, PortType}, module::{ transform::visit::{Fold, Folder, Visit, Visitor}, Instance, ModuleIO, }, - phantom_const::PhantomConst, reg::Reg, - reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, ty::{CanonicalType, StaticType, Type, TypeWithDeref}, wire::Wire, }; @@ -110,11 +108,9 @@ expr_enum! { UIntLiteral(Interned), SIntLiteral(Interned), BoolLiteral(bool), - PhantomConst(PhantomConst), BundleLiteral(ops::BundleLiteral), ArrayLiteral(ops::ArrayLiteral), EnumLiteral(ops::EnumLiteral), - Uninit(ops::Uninit), NotU(ops::NotU), NotS(ops::NotS), NotB(ops::NotB), @@ -212,9 +208,7 @@ expr_enum! { ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), - Reg(Reg), - RegSync(Reg), - RegAsync(Reg), + Reg(Reg), MemPort(MemPort), } } @@ -274,17 +268,6 @@ pub struct Expr { impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(debug_assertions)] - { - let Self { - __enum, - __ty, - __flow, - } = self; - let expr_ty = __ty.canonical(); - let enum_ty = __enum.to_expr().__ty; - assert_eq!(expr_ty, enum_ty, "expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}"); - } self.__enum.fmt(f) } } @@ -609,42 +592,25 @@ impl GetTarget for Wire { } } -impl ToExpr for Reg { +impl ToExpr for Reg { type Type = T; fn to_expr(&self) -> Expr { - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = Reg; - type Output = ExprEnum; - - fn reset(self, input: Self::Input) -> Self::Output { - ExprEnum::Reg(input) - } - - fn sync_reset(self, input: Self::Input) -> Self::Output { - ExprEnum::RegSync(input) - } - - fn async_reset(self, input: Self::Input) -> Self::Output { - ExprEnum::RegAsync(input) - } - } Expr { - __enum: R::dispatch(self.canonical(), Dispatch).intern_sized(), + __enum: ExprEnum::Reg(self.canonical()).intern_sized(), __ty: self.ty(), __flow: self.flow(), } } } -impl ToLiteralBits for Reg { +impl ToLiteralBits for Reg { fn to_literal_bits(&self) -> Result, NotALiteralExpr> { Err(NotALiteralExpr) } } -impl GetTarget for Reg { +impl GetTarget for Reg { fn target(&self) -> Option> { Some(Intern::intern_sized(self.canonical().into())) } @@ -674,18 +640,6 @@ impl GetTarget for MemPort { } } -pub trait HdlPartialEq { - fn cmp_eq(self, rhs: Rhs) -> Expr; - fn cmp_ne(self, rhs: Rhs) -> Expr; -} - -pub trait HdlPartialOrd: HdlPartialEq { - fn cmp_lt(self, rhs: Rhs) -> Expr; - fn cmp_le(self, rhs: Rhs) -> Expr; - fn cmp_gt(self, rhs: Rhs) -> Expr; - fn cmp_ge(self, rhs: Rhs) -> Expr; -} - pub trait ReduceBits { type UIntOutput; type BoolOutput; @@ -711,7 +665,6 @@ impl CastToBits for T { } pub trait CastBitsTo { - #[track_caller] fn cast_bits_to(&self, ty: T) -> Expr; } @@ -744,52 +697,3 @@ pub fn check_match_expr( _check_fn: impl FnOnce(T::MatchVariant, Infallible), ) { } - -pub trait MakeUninitExpr: Type { - fn uninit(self) -> Expr; -} - -impl MakeUninitExpr for T { - fn uninit(self) -> Expr { - ops::Uninit::new(self).to_expr() - } -} - -pub fn repeat( - element: impl ToExpr, - len: L, -) -> Expr> { - let element = element.to_expr(); - let canonical_element = Expr::canonical(element); - ops::ArrayLiteral::new( - Expr::ty(element), - std::iter::repeat(canonical_element) - .take(L::Size::as_usize(len)) - .collect(), - ) - .to_expr() -} - -impl ToExpr for PhantomConst { - type Type = Self; - - fn to_expr(&self) -> Expr { - Expr { - __enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(), - __ty: *self, - __flow: Flow::Source, - } - } -} - -impl GetTarget for PhantomConst { - fn target(&self) -> Option> { - None - } -} - -impl ToLiteralBits for PhantomConst { - fn to_literal_bits(&self) -> Result, NotALiteralExpr> { - Ok(Interned::default()) - } -} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index e794a68..4814d2d 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -11,19 +11,14 @@ use crate::{ GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, }, - CastBitsTo as _, CastTo, CastToBits as _, Expr, ExprEnum, Flow, HdlPartialEq, - HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits, + CastTo, Expr, ExprEnum, Flow, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits, }, int::{ - Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, - UIntType, UIntValue, + Bool, BoolOrIntType, DynSize, IntCmp, IntType, KnownSize, SInt, SIntType, SIntValue, Size, + UInt, UIntType, UIntValue, }, intern::{Intern, Interned}, - phantom_const::{PhantomConst, PhantomConstValue}, - reset::{ - AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset, - ToSyncReset, - }, + reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset}, ty::{CanonicalType, StaticType, Type}, util::ConstUsize, }; @@ -266,7 +261,7 @@ impl Neg { }; let result_ty = retval.ty(); retval.literal_bits = arg.to_literal_bits().map(|bits| { - Intern::intern_owned(result_ty.bits_from_bigint_wrapping(&-SInt::bits_to_bigint(&bits))) + Intern::intern_owned(result_ty.bits_from_bigint_wrapping(-SInt::bits_to_bigint(&bits))) }); retval } @@ -373,7 +368,7 @@ fn binary_op_literal_bits Shl>> for Expr<$ty> { - type Output = Expr<$ty>; - - fn shl(self, rhs: Expr>) -> Self::Output { - $name::new(Expr::as_dyn_int(self), Expr::as_dyn_int(rhs)).to_expr() + impl_binary_op_trait! { + #[generics(LhsWidth: Size, RhsWidth: Size)] + fn Shl::shl(lhs: $ty, rhs: UIntType) -> $ty { + $name::new(Expr::as_dyn_int(lhs), Expr::as_dyn_int(rhs)).to_expr() } } }; @@ -1314,11 +1308,10 @@ macro_rules! impl_dyn_shr { } } - impl Shr>> for Expr<$ty> { - type Output = Expr<$ty>; - - fn shr(self, rhs: Expr>) -> Self::Output { - $name::new(self, Expr::as_dyn_int(rhs)).to_expr() + impl_binary_op_trait! { + #[generics(LhsWidth: Size, RhsWidth: Size)] + fn Shr::shr(lhs: $ty, rhs: UIntType) -> $ty { + $name::new(lhs, Expr::as_dyn_int(rhs)).to_expr() } } }; @@ -1348,7 +1341,7 @@ macro_rules! binary_op_fixed_shift { literal_bits: Err(NotALiteralExpr), }; retval.literal_bits = lhs.to_literal_bits().map(|bits| { - Intern::intern_owned(retval.ty().bits_from_bigint_wrapping(&$Trait::$method( + Intern::intern_owned(retval.ty().bits_from_bigint_wrapping($Trait::$method( $ty::bits_to_bigint(&bits), rhs, ))) @@ -1427,45 +1420,36 @@ forward_value_to_expr_binary_op_trait! { Shr::shr } -pub trait ExprPartialEq: Type { +pub trait IntCmpExpr: Type { fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr; fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr; -} - -pub trait ExprPartialOrd: ExprPartialEq { fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr; fn cmp_le(lhs: Expr, rhs: Expr) -> Expr; fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr; fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr; } -impl HdlPartialEq for Lhs +impl IntCmp for Lhs where - Lhs::Type: ExprPartialEq, + Lhs::Type: IntCmpExpr, { fn cmp_eq(self, rhs: Rhs) -> Expr { - ExprPartialEq::cmp_eq(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_eq(self.to_expr(), rhs.to_expr()) } fn cmp_ne(self, rhs: Rhs) -> Expr { - ExprPartialEq::cmp_ne(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_ne(self.to_expr(), rhs.to_expr()) } -} - -impl HdlPartialOrd for Lhs -where - Lhs::Type: ExprPartialOrd, -{ fn cmp_lt(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_lt(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_lt(self.to_expr(), rhs.to_expr()) } fn cmp_le(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_le(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_le(self.to_expr(), rhs.to_expr()) } fn cmp_gt(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_gt(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_gt(self.to_expr(), rhs.to_expr()) } fn cmp_ge(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_ge(self.to_expr(), rhs.to_expr()) + IntCmpExpr::cmp_ge(self.to_expr(), rhs.to_expr()) } } @@ -1475,7 +1459,6 @@ macro_rules! impl_compare_op { #[dyn_type($DynTy:ident)] #[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)] #[type($Lhs:ty, $Rhs:ty)] - #[trait($Trait:ident)] $( struct $name:ident; fn $method:ident(); @@ -1527,7 +1510,7 @@ macro_rules! impl_compare_op { } })* - impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs { + impl$(<$LhsWidth: Size, $RhsWidth: Size>)? IntCmpExpr<$Rhs> for $Lhs { $(fn $method($lhs: Expr, $rhs: Expr<$Rhs>) -> Expr { $name::new($dyn_lhs, $dyn_rhs).to_expr() })* @@ -1539,16 +1522,8 @@ impl_compare_op! { #[dyn_type(Bool)] #[to_dyn_type(lhs => lhs, rhs => rhs)] #[type(Bool, Bool)] - #[trait(ExprPartialEq)] struct CmpEqB; fn cmp_eq(); PartialEq::eq(); struct CmpNeB; fn cmp_ne(); PartialEq::ne(); -} - -impl_compare_op! { - #[dyn_type(Bool)] - #[to_dyn_type(lhs => lhs, rhs => rhs)] - #[type(Bool, Bool)] - #[trait(ExprPartialOrd)] struct CmpLtB; fn cmp_lt(); PartialOrd::lt(); struct CmpLeB; fn cmp_le(); PartialOrd::le(); struct CmpGtB; fn cmp_gt(); PartialOrd::gt(); @@ -1560,17 +1535,8 @@ impl_compare_op! { #[dyn_type(UInt)] #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[type(UIntType, UIntType)] - #[trait(ExprPartialEq)] struct CmpEqU; fn cmp_eq(); PartialEq::eq(); struct CmpNeU; fn cmp_ne(); PartialEq::ne(); -} - -impl_compare_op! { - #[width(LhsWidth, RhsWidth)] - #[dyn_type(UInt)] - #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] - #[type(UIntType, UIntType)] - #[trait(ExprPartialOrd)] struct CmpLtU; fn cmp_lt(); PartialOrd::lt(); struct CmpLeU; fn cmp_le(); PartialOrd::le(); struct CmpGtU; fn cmp_gt(); PartialOrd::gt(); @@ -1582,17 +1548,8 @@ impl_compare_op! { #[dyn_type(SInt)] #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[type(SIntType, SIntType)] - #[trait(ExprPartialEq)] struct CmpEqS; fn cmp_eq(); PartialEq::eq(); struct CmpNeS; fn cmp_ne(); PartialEq::ne(); -} - -impl_compare_op! { - #[width(LhsWidth, RhsWidth)] - #[dyn_type(SInt)] - #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] - #[type(SIntType, SIntType)] - #[trait(ExprPartialOrd)] struct CmpLtS; fn cmp_lt(); PartialOrd::lt(); struct CmpLeS; fn cmp_le(); PartialOrd::le(); struct CmpGtS; fn cmp_gt(); PartialOrd::gt(); @@ -1625,7 +1582,7 @@ macro_rules! impl_cast_int_op { ty, literal_bits: arg.to_literal_bits().map(|bits| { Intern::intern_owned( - ty.bits_from_bigint_wrapping(&$from::bits_to_bigint(&bits)), + ty.bits_from_bigint_wrapping($from::bits_to_bigint(&bits)), ) }), } @@ -1777,11 +1734,11 @@ impl_cast_bit_op!(CastSIntToAsyncReset, SInt<1>, #[dyn] SInt, AsyncReset, #[trai impl_cast_bit_op!(CastSyncResetToBool, SyncReset, Bool); impl_cast_bit_op!(CastSyncResetToUInt, SyncReset, UInt<1>, #[dyn] UInt); impl_cast_bit_op!(CastSyncResetToSInt, SyncReset, SInt<1>, #[dyn] SInt); -impl_cast_bit_op!(CastSyncResetToReset, SyncReset, Reset); +impl_cast_bit_op!(CastSyncResetToReset, SyncReset, Reset, #[trait] ToReset::to_reset); impl_cast_bit_op!(CastAsyncResetToBool, AsyncReset, Bool); impl_cast_bit_op!(CastAsyncResetToUInt, AsyncReset, UInt<1>, #[dyn] UInt); impl_cast_bit_op!(CastAsyncResetToSInt, AsyncReset, SInt<1>, #[dyn] SInt); -impl_cast_bit_op!(CastAsyncResetToReset, AsyncReset, Reset); +impl_cast_bit_op!(CastAsyncResetToReset, AsyncReset, Reset, #[trait] ToReset::to_reset); impl_cast_bit_op!(CastResetToBool, Reset, Bool); impl_cast_bit_op!(CastResetToUInt, Reset, UInt<1>, #[dyn] UInt); impl_cast_bit_op!(CastResetToSInt, Reset, SInt<1>, #[dyn] SInt); @@ -1792,127 +1749,6 @@ impl_cast_bit_op!(CastClockToBool, Clock, Bool); impl_cast_bit_op!(CastClockToUInt, Clock, UInt<1>, #[dyn] UInt); impl_cast_bit_op!(CastClockToSInt, Clock, SInt<1>, #[dyn] SInt); -impl ToReset for Expr { - fn to_reset(&self) -> Expr { - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = Expr; - type Output = Expr; - - fn reset(self, input: Self::Input) -> Self::Output { - input - } - - fn sync_reset(self, input: Self::Input) -> Self::Output { - input.cast_to_static() - } - - fn async_reset(self, input: Self::Input) -> Self::Output { - input.cast_to_static() - } - } - T::dispatch(*self, Dispatch) - } -} - -impl ExprCastTo for AsyncReset { - fn cast_to(src: Expr, _to_type: AsyncReset) -> Expr { - src - } -} - -impl ExprCastTo for AsyncReset { - fn cast_to(src: Expr, to_type: SyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for AsyncReset { - fn cast_to(src: Expr, to_type: Clock) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for SyncReset { - fn cast_to(src: Expr, to_type: AsyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for SyncReset { - fn cast_to(src: Expr, _to_type: SyncReset) -> Expr { - src - } -} - -impl ExprCastTo for SyncReset { - fn cast_to(src: Expr, to_type: Clock) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Reset { - fn cast_to(src: Expr, to_type: AsyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Reset { - fn cast_to(src: Expr, to_type: SyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Reset { - fn cast_to(src: Expr, _to_type: Reset) -> Expr { - src - } -} - -impl ExprCastTo for Reset { - fn cast_to(src: Expr, to_type: Clock) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Clock { - fn cast_to(src: Expr, to_type: AsyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Clock { - fn cast_to(src: Expr, to_type: SyncReset) -> Expr { - src.cast_to(Bool).cast_to(to_type) - } -} - -impl ExprCastTo for Clock { - fn cast_to(src: Expr, _to_type: Clock) -> Expr { - src - } -} - -impl ExprCastTo<()> for PhantomConst { - fn cast_to(src: Expr, to_type: ()) -> Expr<()> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - -impl ExprCastTo> for () { - fn cast_to(src: Expr, to_type: PhantomConst) -> Expr> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - -impl ExprCastTo> - for PhantomConst -{ - fn cast_to(src: Expr, to_type: PhantomConst) -> Expr> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct FieldAccess { base: Expr, @@ -2182,7 +2018,7 @@ impl ExprIndex for ArrayType, index: usize) -> &Expr { - Interned::into_inner( + Interned::<_>::into_inner( ArrayIndex::::new(Expr::as_dyn_array(*this), index) .to_expr() .intern_sized(), @@ -2279,7 +2115,7 @@ impl ExprIndex>> type Output = ElementType; fn expr_index(this: &Expr, index: Expr>) -> &Expr { - Interned::into_inner( + Interned::<_>::into_inner( DynArrayIndex::::new(Expr::as_dyn_array(*this), Expr::as_dyn_int(index)) .to_expr() .intern_sized(), @@ -2404,7 +2240,7 @@ macro_rules! impl_int_slice { let base = Expr::as_dyn_int(*this); let base_ty = Expr::ty(base); let range = base_ty.slice_index_to_range(index); - Interned::into_inner($name::new(base, range).to_expr().intern_sized()) + Interned::<_>::into_inner($name::new(base, range).to_expr().intern_sized()) } } @@ -2416,7 +2252,7 @@ macro_rules! impl_int_slice { let base = Expr::as_dyn_int(*this); let base_ty = Expr::ty(base); assert!(index < base_ty.width()); - Interned::into_inner( + Interned::<_>::into_inner( $name::new(base, index..(index + 1)) .to_expr() .cast_to_static::() @@ -2691,85 +2527,3 @@ impl ToExpr for CastBitsTo { } } } - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Uninit { - ty: T, -} - -impl Uninit { - #[track_caller] - pub fn new(ty: T) -> Self { - Self { ty } - } - pub fn ty(self) -> T { - self.ty - } -} - -impl ToLiteralBits for Uninit { - fn to_literal_bits(&self) -> Result, NotALiteralExpr> { - Err(NotALiteralExpr) - } -} - -impl_get_target_none!([T: Type] Uninit); - -impl ToExpr for Uninit { - type Type = T; - - fn to_expr(&self) -> Expr { - Expr { - __enum: ExprEnum::Uninit(Uninit { - ty: self.ty.canonical(), - }) - .intern(), - __ty: self.ty, - __flow: Flow::Source, - } - } -} - -pub trait ExprIntoIterator: Type { - type Item: Type; - type ExprIntoIter: Iterator>; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter; -} - -impl IntoIterator for Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(self) - } -} - -impl IntoIterator for &'_ Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -impl IntoIterator for &'_ mut Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -pub trait ExprFromIterator: Type { - fn expr_from_iter>(iter: T) -> Expr; -} - -impl, A> FromIterator for Expr { - fn from_iter>(iter: T) -> Self { - This::expr_from_iter(iter) - } -} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index c8c55e9..f33b286 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -1,21 +1,18 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information use crate::{ array::Array, bundle::{Bundle, BundleField}, - expr::{Expr, Flow, ToExpr}, + expr::Flow, intern::{Intern, Interned}, memory::{DynPortType, MemPort}, module::{Instance, ModuleIO, TargetName}, reg::Reg, - reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, wire::Wire, }; use std::fmt; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TargetPathBundleField { pub name: Interned, } @@ -26,7 +23,7 @@ impl fmt::Display for TargetPathBundleField { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TargetPathArrayElement { pub index: usize, } @@ -37,7 +34,7 @@ impl fmt::Display for TargetPathArrayElement { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TargetPathDynArrayElement {} impl fmt::Display for TargetPathDynArrayElement { @@ -46,7 +43,7 @@ impl fmt::Display for TargetPathDynArrayElement { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TargetPathElement { BundleField(TargetPathBundleField), ArrayElement(TargetPathArrayElement), @@ -128,7 +125,6 @@ macro_rules! impl_target_base { $(#[$enum_meta:meta])* $enum_vis:vis enum $TargetBase:ident { $( - $(#[from = $from:ident])? #[is = $is_fn:ident] #[to = $to_fn:ident] $(#[$variant_meta:meta])* @@ -152,19 +148,19 @@ macro_rules! impl_target_base { } } - $($( + $( impl From<$VariantTy> for $TargetBase { - fn $from(value: $VariantTy) -> Self { + fn from(value: $VariantTy) -> Self { Self::$Variant(value) } } impl From<$VariantTy> for Target { - fn $from(value: $VariantTy) -> Self { + fn from(value: $VariantTy) -> Self { $TargetBase::$Variant(value).into() } } - )*)? + )* impl $TargetBase { $( @@ -195,79 +191,30 @@ macro_rules! impl_target_base { } } } - - impl ToExpr for $TargetBase { - type Type = CanonicalType; - - fn to_expr(&self) -> Expr { - match self { - $(Self::$Variant(v) => Expr::canonical(v.to_expr()),)* - } - } - } }; } impl_target_base! { - #[derive(Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Clone, PartialEq, Eq, Hash)] pub enum TargetBase { - #[from = from] #[is = is_module_io] #[to = module_io] ModuleIO(ModuleIO), - #[from = from] #[is = is_mem_port] #[to = mem_port] MemPort(MemPort), #[is = is_reg] #[to = reg] - Reg(Reg), - #[is = is_reg_sync] - #[to = reg_sync] - RegSync(Reg), - #[is = is_reg_async] - #[to = reg_async] - RegAsync(Reg), - #[from = from] + Reg(Reg), #[is = is_wire] #[to = wire] Wire(Wire), - #[from = from] #[is = is_instance] #[to = instance] Instance(Instance), } } -impl From> for TargetBase { - fn from(value: Reg) -> Self { - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = Reg; - type Output = TargetBase; - - fn reset(self, input: Self::Input) -> Self::Output { - TargetBase::Reg(input) - } - - fn sync_reset(self, input: Self::Input) -> Self::Output { - TargetBase::RegSync(input) - } - - fn async_reset(self, input: Self::Input) -> Self::Output { - TargetBase::RegAsync(input) - } - } - R::dispatch(value, Dispatch) - } -} - -impl From> for Target { - fn from(value: Reg) -> Self { - TargetBase::from(value).into() - } -} - impl fmt::Display for TargetBase { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.target_name()) @@ -280,8 +227,6 @@ impl TargetBase { TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None), TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())), TargetBase::Reg(v) => TargetName(v.scoped_name(), None), - TargetBase::RegSync(v) => TargetName(v.scoped_name(), None), - TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None), TargetBase::Wire(v) => TargetName(v.scoped_name(), None), TargetBase::Instance(v) => TargetName(v.scoped_name(), None), } @@ -291,8 +236,6 @@ impl TargetBase { TargetBase::ModuleIO(v) => v.ty(), TargetBase::MemPort(v) => v.ty().canonical(), TargetBase::Reg(v) => v.ty(), - TargetBase::RegSync(v) => v.ty(), - TargetBase::RegAsync(v) => v.ty(), TargetBase::Wire(v) => v.ty(), TargetBase::Instance(v) => v.ty().canonical(), } @@ -368,7 +311,7 @@ impl TargetChild { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] pub enum Target { Base(Interned), Child(TargetChild), diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index d33c7a9..5a562c0 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2,10 +2,7 @@ // See Notices.txt for copyright information #![allow(clippy::type_complexity)] use crate::{ - annotations::{ - Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, - }, + annotations::CustomFirrtlAnnotation, array::Array, bundle::{Bundle, BundleField, BundleType}, clock::Clock, @@ -15,32 +12,27 @@ use crate::{ target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, }, - CastBitsTo, Expr, ExprEnum, + Expr, ExprEnum, }, - formal::FormalKind, int::{Bool, DynSize, IntType, SIntValue, UInt, UIntValue}, intern::{Intern, Interned}, memory::{Mem, PortKind, PortName, ReadUnderWrite}, module::{ - transform::{ - simplify_enums::{simplify_enums, SimplifyEnumsError, SimplifyEnumsKind}, - simplify_memories::simplify_memories, - }, - AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Module, ModuleBody, NameOptId, NormalModuleBody, Stmt, - StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, - StmtWire, + transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block, + ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody, + NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance, + StmtMatch, StmtReg, StmtWire, }, - reset::{AsyncReset, Reset, ResetType, SyncReset}, + reset::{AsyncReset, Reset, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, util::{ const_str_array_is_strictly_ascending, BitSliceWriteWithBase, DebugAsRawString, - GenericConstBool, HashMap, HashSet, + GenericConstBool, }, }; use bitvec::slice::BitSlice; -use clap::value_parser; +use hashbrown::{HashMap, HashSet}; use num_traits::Signed; use serde::Serialize; use std::{ @@ -186,9 +178,9 @@ struct NameMaker { } impl NameMaker { - fn make(&mut self, name: impl Into) -> Ident { - let mut num = 0usize; - let name: String = name.into(); + fn make(&mut self, name: NameId) -> Ident { + let mut num: usize = name.1; + let name = String::from(&*name.0); // remove all invalid characters -- all valid characters are ASCII, so we can just remove invalid bytes let mut name = String::from_iter( name.bytes() @@ -220,7 +212,7 @@ impl NameMaker { #[derive(Default)] struct Namespace { name_maker: NameMaker, - map: HashMap, + map: HashMap, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -246,11 +238,10 @@ impl From for Ident { } impl Namespace { - fn get(&mut self, name: impl Into) -> Ident { - let name: NameOptId = name.into(); + fn get(&mut self, name: NameId) -> Ident { #[cold] - fn make(name_maker: &mut NameMaker, name: NameOptId) -> Ident { - name_maker.make(name.0) + fn make(name_maker: &mut NameMaker, name: NameId) -> Ident { + name_maker.make(name) } *self .map @@ -258,7 +249,7 @@ impl Namespace { .or_insert_with(|| make(&mut self.name_maker, name)) } fn make_new(&mut self, prefix: &str) -> Ident { - self.name_maker.make(prefix) + self.name_maker.make(NameId(prefix.intern(), 0)) } } @@ -368,7 +359,7 @@ impl TypeState { Ident(Intern::intern_owned(format!("Ty{id}"))) } fn get_bundle_field(&mut self, ty: Bundle, name: Interned) -> Ident { - self.bundle_ns(ty).borrow_mut().get(name) + self.bundle_ns(ty).borrow_mut().get(NameId(name, 0)) } fn bundle_def(&self, ty: Bundle) -> (Ident, Rc>) { self.bundle_defs.get_or_make(ty, |&ty, definitions| { @@ -382,7 +373,7 @@ impl TypeState { if flipped { body.push_str("flip "); } - write!(body, "{}: ", ns.get(name)).unwrap(); + write!(body, "{}: ", ns.get(NameId(name, 0))).unwrap(); body.push_str(&self.ty(ty)); } body.push('}'); @@ -406,7 +397,7 @@ impl TypeState { for EnumVariant { name, ty } in ty.variants() { body.push_str(separator); separator = ", "; - write!(body, "{}", variants.get(name)).unwrap(); + write!(body, "{}", variants.get(NameId(name, 0))).unwrap(); if let Some(ty) = ty { body.push_str(": "); body.push_str(&self.ty(ty)); @@ -428,7 +419,11 @@ impl TypeState { self.enum_def(ty).0 } fn get_enum_variant(&mut self, ty: Enum, name: Interned) -> Ident { - self.enum_def(ty).1.variants.borrow_mut().get(name) + self.enum_def(ty) + .1 + .variants + .borrow_mut() + .get(NameId(name, 0)) } fn ty(&self, ty: T) -> String { match ty.canonical() { @@ -446,7 +441,6 @@ impl TypeState { CanonicalType::AsyncReset(AsyncReset {}) => "AsyncReset".into(), CanonicalType::SyncReset(SyncReset {}) => "UInt<1>".into(), CanonicalType::Reset(Reset {}) => "Reset".into(), - CanonicalType::PhantomConst(_) => "{}".into(), } } } @@ -482,7 +476,6 @@ trait WrappedFileBackendTrait { circuit_name: String, contents: String, ) -> Result<(), WrappedError>; - fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError; } struct WrappedFileBackend { @@ -540,11 +533,6 @@ impl WrappedFileBackendTrait for WrappedFileBackend { WrappedError }) } - - fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError { - self.error = Err(error.into()); - WrappedError - } } #[derive(Clone)] @@ -666,17 +654,6 @@ enum AnnotationData { }, #[serde(rename = "firrtl.transforms.DontTouchAnnotation")] DontTouch, - #[serde(rename = "firrtl.AttributeAnnotation")] - AttributeAnnotation { description: Interned }, - #[serde(rename = "firrtl.transforms.BlackBoxInlineAnno")] - BlackBoxInlineAnno { - name: Interned, - text: Interned, - }, - #[serde(rename = "firrtl.transforms.BlackBoxPathAnno")] - BlackBoxPathAnno { path: Interned }, - #[serde(rename = "firrtl.DocStringAnnotation")] - DocStringAnnotation { description: Interned }, #[allow(dead_code)] #[serde(untagged)] Other { @@ -687,7 +664,7 @@ enum AnnotationData { } #[derive(Serialize)] -struct FirrtlAnnotation { +struct Annotation { #[serde(flatten)] data: AnnotationData, target: AnnotationTarget, @@ -702,7 +679,7 @@ struct Exporter<'a> { module: ModuleState, type_state: TypeState, circuit_name: Ident, - annotations: Vec, + annotations: Vec, } struct PushIndent<'a> { @@ -926,7 +903,7 @@ impl<'a> Exporter<'a> { ) in expr.field_values().into_iter().zip(ty.fields()) { debug_assert!(!flipped, "can't have bundle literal with flipped field -- this should have been caught in BundleLiteral::new_unchecked"); - let name = bundle_ns.borrow_mut().get(name); + let name = bundle_ns.borrow_mut().get(NameId(name, 0)); let field_value = self.expr(Expr::canonical(field_value), definitions, const_ty); definitions.add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); } @@ -935,20 +912,6 @@ impl<'a> Exporter<'a> { } ident.to_string() } - fn uninit_expr( - &mut self, - expr: ops::Uninit, - definitions: &RcDefinitions, - const_ty: bool, - ) -> String { - let ident = self.module.ns.make_new("_uninit_expr"); - let ty = expr.ty(); - let ty_ident = self.type_state.ty(ty); - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); - definitions.add_definition_line(format_args!("invalidate {ident}")); - ident.to_string() - } fn enum_literal_expr( &mut self, expr: ops::EnumLiteral, @@ -1152,7 +1115,6 @@ impl<'a> Exporter<'a> { | CanonicalType::Clock(_) | CanonicalType::AsyncReset(_) | CanonicalType::Reset(_) => format!("asUInt({value_str})"), - CanonicalType::PhantomConst(_) => "UInt<0>(0)".into(), } } fn expr_cast_bits_to_bundle( @@ -1358,12 +1320,6 @@ impl<'a> Exporter<'a> { CanonicalType::AsyncReset(_) => format!("asAsyncReset({value_str})"), CanonicalType::SyncReset(_) => value_str, CanonicalType::Reset(_) => unreachable!("Reset is not bit castable to"), - CanonicalType::PhantomConst(_) => { - let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return retval.to_string(); - } } } fn expr_unary( @@ -1402,11 +1358,6 @@ impl<'a> Exporter<'a> { ExprEnum::UIntLiteral(literal) => self.uint_literal(&literal), ExprEnum::SIntLiteral(literal) => self.sint_literal(&literal), ExprEnum::BoolLiteral(literal) => self.bool_literal(literal), - ExprEnum::PhantomConst(ty) => self.expr( - UInt[0].zero().cast_bits_to(ty.canonical()), - definitions, - const_ty, - ), ExprEnum::ArrayLiteral(array_literal) => { self.array_literal_expr(array_literal, definitions, const_ty) } @@ -1416,7 +1367,6 @@ impl<'a> Exporter<'a> { ExprEnum::EnumLiteral(enum_literal) => { self.enum_literal_expr(enum_literal, definitions, const_ty) } - ExprEnum::Uninit(uninit) => self.uninit_expr(uninit, definitions, const_ty), ExprEnum::NotU(expr) => self.expr_unary("not", expr.arg(), definitions, const_ty), ExprEnum::NotS(expr) => self.expr_unary("not", expr.arg(), definitions, const_ty), ExprEnum::NotB(expr) => self.expr_unary("not", expr.arg(), definitions, const_ty), @@ -1751,14 +1701,6 @@ impl<'a> Exporter<'a> { assert!(!const_ty, "not a constant"); self.module.ns.get(expr.scoped_name().1).to_string() } - ExprEnum::RegSync(expr) => { - assert!(!const_ty, "not a constant"); - self.module.ns.get(expr.scoped_name().1).to_string() - } - ExprEnum::RegAsync(expr) => { - assert!(!const_ty, "not a constant"); - self.module.ns.get(expr.scoped_name().1).to_string() - } ExprEnum::MemPort(expr) => { assert!(!const_ty, "not a constant"); let mem_name = self.module.ns.get(expr.mem_name().1); @@ -1802,7 +1744,7 @@ impl<'a> Exporter<'a> { memory_name.0.to_string(), contents, )?; - self.annotations.push(FirrtlAnnotation { + self.annotations.push(Annotation { data: AnnotationData::MemoryFileInline { filename, hex_or_binary, @@ -1821,25 +1763,14 @@ impl<'a> Exporter<'a> { }); Ok(()) } - fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) { + fn annotation( + &mut self, + path: AnnotationTargetPath, + annotation: &crate::annotations::Annotation, + ) { let data = match annotation { - Annotation::DontTouch(DontTouchAnnotation {}) => AnnotationData::DontTouch, - Annotation::SVAttribute(SVAttributeAnnotation { text }) => { - AnnotationData::AttributeAnnotation { description: *text } - } - Annotation::BlackBoxInline(BlackBoxInlineAnnotation { path, text }) => { - AnnotationData::BlackBoxInlineAnno { - name: *path, - text: *text, - } - } - Annotation::BlackBoxPath(BlackBoxPathAnnotation { path }) => { - AnnotationData::BlackBoxPathAnno { path: *path } - } - Annotation::DocString(DocStringAnnotation { text }) => { - AnnotationData::DocStringAnnotation { description: *text } - } - Annotation::CustomFirrtl(CustomFirrtlAnnotation { + crate::annotations::Annotation::DontTouch => AnnotationData::DontTouch, + crate::annotations::Annotation::CustomFirrtl(CustomFirrtlAnnotation { class, additional_fields, }) => AnnotationData::Other { @@ -1847,7 +1778,7 @@ impl<'a> Exporter<'a> { additional_fields: (*additional_fields).into(), }, }; - self.annotations.push(FirrtlAnnotation { + self.annotations.push(Annotation { data, target: AnnotationTarget { circuit: self.circuit_name, @@ -1868,8 +1799,6 @@ impl<'a> Exporter<'a> { self.module.ns.get(v.mem_name().1) } TargetBase::Reg(v) => self.module.ns.get(v.name_id()), - TargetBase::RegSync(v) => self.module.ns.get(v.name_id()), - TargetBase::RegAsync(v) => self.module.ns.get(v.name_id()), TargetBase::Wire(v) => self.module.ns.get(v.name_id()), TargetBase::Instance(v) => self.module.ns.get(v.name_id()), }; @@ -1978,37 +1907,6 @@ impl<'a> Exporter<'a> { drop(memory_indent); Ok(body) } - fn stmt_reg( - &mut self, - stmt_reg: StmtReg, - module_name: Ident, - definitions: &RcDefinitions, - body: &mut String, - ) { - let StmtReg { annotations, reg } = stmt_reg; - let indent = self.indent; - self.targeted_annotations(module_name, vec![], &annotations); - let name = self.module.ns.get(reg.name_id()); - let ty = self.type_state.ty(reg.ty()); - let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false); - if let Some(init) = reg.init() { - let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false); - let init = self.expr(init, definitions, false); - writeln!( - body, - "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", - FileInfo::new(reg.source_location()), - ) - .unwrap(); - } else { - writeln!( - body, - "{indent}reg {name}: {ty}, {clk}{}", - FileInfo::new(reg.source_location()), - ) - .unwrap(); - } - } fn block( &mut self, module: Interned>, @@ -2032,15 +1930,6 @@ impl<'a> Exporter<'a> { rhs, source_location, }) => { - if Expr::ty(lhs) != Expr::ty(rhs) { - writeln!( - body, - "{indent}; connect different types:\n{indent}; lhs: {:?}\n{indent}; rhs: {:?}", - Expr::ty(lhs), - Expr::ty(rhs), - ) - .unwrap(); - } let lhs = self.expr(lhs, &definitions, false); let rhs = self.expr(rhs, &definitions, false); writeln!( @@ -2050,33 +1939,6 @@ impl<'a> Exporter<'a> { ) .unwrap(); } - Stmt::Formal(StmtFormal { - kind, - clk, - pred, - en, - text, - source_location, - }) => { - let clk = self.expr(Expr::canonical(clk), &definitions, false); - let pred = self.expr(Expr::canonical(pred), &definitions, false); - let en = self.expr(Expr::canonical(en), &definitions, false); - let kind = match kind { - FormalKind::Assert => "assert", - FormalKind::Assume => "assume", - FormalKind::Cover => "cover", - }; - let text = EscapedString { - value: &text, - raw: false, - }; - writeln!( - body, - "{indent}{kind}({clk}, {pred}, {en}, {text}){}", - FileInfo::new(source_location), - ) - .unwrap(); - } Stmt::If(StmtIf { mut cond, mut source_location, @@ -2179,14 +2041,30 @@ impl<'a> Exporter<'a> { ) .unwrap(); } - Stmt::Declaration(StmtDeclaration::Reg(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); - } - Stmt::Declaration(StmtDeclaration::RegSync(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); - } - Stmt::Declaration(StmtDeclaration::RegAsync(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); + Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations, reg })) => { + self.targeted_annotations(module_name, vec![], &annotations); + let name = self.module.ns.get(reg.name_id()); + let ty = self.type_state.ty(reg.ty()); + let clk = + self.expr(Expr::canonical(reg.clock_domain().clk), &definitions, false); + if let Some(init) = reg.init() { + let rst = + self.expr(Expr::canonical(reg.clock_domain().rst), &definitions, false); + let init = self.expr(init, &definitions, false); + writeln!( + body, + "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", + FileInfo::new(reg.source_location()), + ) + .unwrap(); + } else { + writeln!( + body, + "{indent}reg {name}: {ty}, {clk}{}", + FileInfo::new(reg.source_location()), + ) + .unwrap(); + } } Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations, @@ -2233,7 +2111,7 @@ impl<'a> Exporter<'a> { } in module.module_io().iter() { self.targeted_annotations(module_name, vec![], annotations); - let name = self.module.ns.get(module_io.name_id()); + let name = self.module.ns.get(NameId(module_io.name(), 0)); let ty = self.type_state.ty(module_io.ty()); if module_io.is_input() { writeln!( @@ -2257,7 +2135,6 @@ impl<'a> Exporter<'a> { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, - simulation: _, }) => { let verilog_name = Ident(verilog_name); writeln!(body, "{indent}defname = {verilog_name}").unwrap(); @@ -2306,7 +2183,7 @@ impl<'a> Exporter<'a> { } pub trait FileBackendTrait { - type Error: From; + type Error; type Path: AsRef + fmt::Debug + ?Sized; type PathBuf: AsRef + fmt::Debug; fn path_to_string(&mut self, path: &Self::Path) -> Result; @@ -2381,7 +2258,6 @@ impl FileBackendTrait for &'_ mut T { #[non_exhaustive] pub struct FileBackend { pub dir_path: PathBuf, - pub circuit_name: Option, pub top_fir_file_stem: Option, } @@ -2389,7 +2265,6 @@ impl FileBackend { pub fn new(dir_path: impl AsRef) -> Self { Self { dir_path: dir_path.as_ref().to_owned(), - circuit_name: None, top_fir_file_stem: None, } } @@ -2425,10 +2300,7 @@ impl FileBackendTrait for FileBackend { circuit_name: String, contents: String, ) -> Result<(), Self::Error> { - let top_fir_file_stem = self - .top_fir_file_stem - .get_or_insert_with(|| circuit_name.clone()); - self.circuit_name = Some(circuit_name); + let top_fir_file_stem = self.top_fir_file_stem.get_or_insert(circuit_name); let mut path = self.dir_path.join(top_fir_file_stem); if let Some(parent) = path.parent().filter(|v| !v.as_os_str().is_empty()) { fs::create_dir_all(parent)?; @@ -2439,17 +2311,15 @@ impl FileBackendTrait for FileBackend { } #[doc(hidden)] -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq)] pub struct TestBackendPrivate { pub module_var_name: &'static str, - pub included_fields: &'static [&'static str], } impl Default for TestBackendPrivate { fn default() -> Self { Self { module_var_name: "m", - included_fields: &[], } } } @@ -2458,7 +2328,6 @@ impl Default for TestBackendPrivate { pub struct TestBackend { pub files: BTreeMap, pub error_after: Option, - pub options: ExportOptions, #[doc(hidden)] /// `#[non_exhaustive]` except allowing struct update syntax pub __private: TestBackendPrivate, @@ -2469,12 +2338,7 @@ impl fmt::Debug for TestBackend { let Self { files, error_after, - options, - __private: - TestBackendPrivate { - module_var_name, - included_fields, - }, + __private: TestBackendPrivate { module_var_name }, } = self; writeln!( f, @@ -2482,44 +2346,12 @@ impl fmt::Debug for TestBackend { )?; writeln!(f, " assert_export_firrtl! {{")?; writeln!(f, " {module_var_name} =>")?; - if *error_after != Option::default() || included_fields.contains(&"error_after") { - writeln!(f, " error_after: {error_after:?},")?; - } - if *options != ExportOptions::default() || included_fields.contains(&"options") { - struct DebugWithForceIncludeFields<'a> { - options: ExportOptions, - included_fields: &'a [&'a str], - } - impl fmt::Debug for DebugWithForceIncludeFields<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.options.debug_fmt(f, |field| { - self.included_fields.iter().any(|included_field| { - if let Some(("options", suffix)) = included_field.split_once(".") { - suffix == field - } else { - false - } - }) - }) - } - } - let options_str = format!( - "{:#?}", - DebugWithForceIncludeFields { - options: *options, - included_fields - } - ); - let mut sep = " options: "; - for line in options_str.lines() { - write!(f, "{sep}{line}")?; - sep = "\n "; - } - writeln!(f, ",")?; - } for (file, content) in files { writeln!(f, " {file:?}: {:?},", DebugAsRawString(content))?; } + if *error_after != Option::default() { + writeln!(f, " error_after: {error_after:?},")?; + } write!(f, " }};") } } @@ -2535,12 +2367,6 @@ impl fmt::Display for TestBackendError { impl Error for TestBackendError {} -impl From for TestBackendError { - fn from(value: SimplifyEnumsError) -> Self { - TestBackendError(value.to_string()) - } -} - impl TestBackend { #[track_caller] pub fn step_error_after(&mut self, args: &dyn fmt::Debug) -> Result<(), TestBackendError> { @@ -2597,21 +2423,9 @@ impl FileBackendTrait for TestBackend { fn export_impl( file_backend: &mut dyn WrappedFileBackendTrait, - mut top_module: Interned>, - options: ExportOptions, + top_module: Interned>, ) -> Result<(), WrappedError> { - let ExportOptions { - simplify_memories: do_simplify_memories, - simplify_enums: do_simplify_enums, - __private: _, - } = options; - if let Some(kind) = do_simplify_enums { - top_module = - simplify_enums(top_module, kind).map_err(|e| file_backend.simplify_enums_error(e))?; - } - if do_simplify_memories { - top_module = simplify_memories(top_module); - } + let top_module = simplify_memories(top_module); let indent_depth = Cell::new(0); let mut global_ns = Namespace::default(); let circuit_name = global_ns.get(top_module.name_id()); @@ -2621,7 +2435,7 @@ fn export_impl( indent_depth: &indent_depth, indent: " ", }, - seen_modules: HashSet::default(), + seen_modules: HashSet::new(), unwritten_modules: VecDeque::new(), global_ns, module: ModuleState::default(), @@ -2632,154 +2446,20 @@ fn export_impl( .run(top_module) } -#[derive(Clone)] -struct OptionSimplifyEnumsKindValueParser; - -impl OptionSimplifyEnumsKindValueParser { - const NONE_NAME: &'static str = "off"; -} - -impl clap::builder::TypedValueParser for OptionSimplifyEnumsKindValueParser { - type Value = Option; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> Result { - if value == Self::NONE_NAME { - Ok(None) - } else { - Ok(Some( - value_parser!(SimplifyEnumsKind).parse_ref(cmd, arg, value)?, - )) - } - } - - fn possible_values( - &self, - ) -> Option + '_>> { - Some(Box::new( - [Self::NONE_NAME.into()] - .into_iter() - .chain(value_parser!(SimplifyEnumsKind).possible_values()?) - .collect::>() - .into_iter(), - )) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct ExportOptionsPrivate(()); - -#[derive(clap::Parser, Copy, Clone, PartialEq, Eq, Hash)] -pub struct ExportOptions { - #[clap(long = "no-simplify-memories", action = clap::ArgAction::SetFalse)] - pub simplify_memories: bool, - #[clap(long, value_parser = OptionSimplifyEnumsKindValueParser, default_value = "replace-with-bundle-of-uints")] - pub simplify_enums: std::option::Option, - #[doc(hidden)] - #[clap(skip = ExportOptionsPrivate(()))] - /// `#[non_exhaustive]` except allowing struct update syntax - pub __private: ExportOptionsPrivate, -} - -impl fmt::Debug for ExportOptions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt(f, |_| false) - } -} - -impl ExportOptions { - fn debug_fmt( - &self, - f: &mut fmt::Formatter<'_>, - force_include_field: impl Fn(&str) -> bool, - ) -> fmt::Result { - let Self { - simplify_memories, - simplify_enums, - __private: _, - } = *self; - f.write_str("ExportOptions {")?; - let mut sep = if f.alternate() { "\n " } else { " " }; - let comma_sep = if f.alternate() { ",\n " } else { ", " }; - let default = ExportOptions::default(); - if simplify_memories != default.simplify_memories - || force_include_field("simplify_memories") - { - write!(f, "{sep}simplify_memories: {:?}", simplify_memories)?; - sep = comma_sep; - } - if simplify_enums != default.simplify_enums || force_include_field("simplify_enums") { - write!(f, "{sep}simplify_enums: ")?; - macro_rules! debug_cases { - ($($ident:ident $(($($args:tt)*))?,)*) => { - match simplify_enums { - // use more complex stringify to avoid the compiler inserting spaces - $($ident $(($($args)*))? => { - f.write_str(concat!( - stringify!($ident), - $("(", - $(stringify!($args),)* - ")")? - ))?; - })* - } - }; - } - debug_cases! { - Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody), - Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts), - Some(SimplifyEnumsKind::ReplaceWithUInt), - None, - } - sep = comma_sep; - } - write!( - f, - "{sep}..ExportOptions::default(){}", - if f.alternate() { "\n}" } else { " }" } - ) - } -} - -impl Default for ExportOptions { - fn default() -> Self { - Self { - simplify_memories: true, - simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts), - __private: ExportOptionsPrivate(()), - } - } -} - pub fn export( file_backend: B, top_module: &Module, - options: ExportOptions, ) -> Result { let top_module = Intern::intern_sized(top_module.canonical()); WrappedFileBackend::with(file_backend, |file_backend| { - export_impl(file_backend, top_module, options) + export_impl(file_backend, top_module) }) } #[doc(hidden)] #[track_caller] pub fn assert_export_firrtl_impl(top_module: &Module, expected: TestBackend) { - let result = export( - TestBackend { - files: BTreeMap::default(), - error_after: expected.error_after, - options: expected.options, - __private: expected.__private, - }, - top_module, - expected.options, - ) - .unwrap(); + let result = export(TestBackend::default(), top_module).unwrap(); if result != expected { panic!( "assert_export_firrtl failed:\nyou can update the expected output by using:\n-------START-------\n{result:?}\n-------END-------" @@ -2796,69 +2476,21 @@ pub fn make_test_expected_files(v: &[(&str, &str)]) -> BTreeMap macro_rules! assert_export_firrtl { { $m:ident => - $($field:ident: $value:expr,)* - @parsed_fields($($field_strings:expr,)*) $($file_name:literal: $file_contents:literal,)* + $($field:ident: $value:expr,)* } => { $crate::firrtl::assert_export_firrtl_impl( &$m, $crate::firrtl::TestBackend { - $($field: $value,)* files: $crate::firrtl::make_test_expected_files(&[ $(($file_name, $file_contents),)* ]), + $($field: $value,)* __private: $crate::firrtl::TestBackendPrivate { module_var_name: stringify!($m), - included_fields: &[$($field_strings,)*], }, ..<$crate::firrtl::TestBackend as $crate::__std::default::Default>::default() }, ); }; - { - $m:ident => - $($parsed_fields:ident: $parsed_field_values:expr,)* - @parsed_fields($($field_strings:expr,)*) - options: ExportOptions { - $($export_option_fields:ident: $parsed_export_option_field_values:expr,)* - ..$export_option_default:expr - }, - $($rest:tt)* - } => { - $crate::assert_export_firrtl!( - $m => - $($parsed_fields: $parsed_field_values,)* - options: ExportOptions { - $($export_option_fields: $parsed_export_option_field_values,)* - ..$export_option_default - }, - @parsed_fields($($field_strings,)* "options", $(concat!("options.", stringify!($export_option_fields)),)*) - $($rest)* - ); - }; - { - $m:ident => - $($parsed_fields:ident: $parsed_field_values:expr,)* - @parsed_fields($($field_strings:expr,)*) - $field:ident: $field_value:expr, - $($rest:tt)* - } => { - $crate::assert_export_firrtl!( - $m => - $($parsed_fields: $parsed_field_values,)* - $field: $field_value, - @parsed_fields($($field_strings,)* stringify!($field),) - $($rest)* - ); - }; - { - $m:ident => - $($rest:tt)* - } => { - $crate::assert_export_firrtl!( - $m => - @parsed_fields() - $($rest)* - ); - }; } diff --git a/crates/fayalite/src/formal.rs b/crates/fayalite/src/formal.rs deleted file mode 100644 index 17d3122..0000000 --- a/crates/fayalite/src/formal.rs +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -use crate::{ - int::BoolOrIntType, - intern::{Intern, Interned, Memoize}, - prelude::*, -}; -use std::sync::OnceLock; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum FormalKind { - Assert, - Assume, - Cover, -} - -impl FormalKind { - pub fn as_str(self) -> &'static str { - match self { - Self::Assert => "assert", - Self::Assume => "assume", - Self::Cover => "cover", - } - } -} - -#[track_caller] -pub fn formal_stmt_with_enable_and_loc( - kind: FormalKind, - clk: Expr, - pred: Expr, - en: Expr, - text: &str, - source_location: SourceLocation, -) { - crate::module::add_stmt_formal(crate::module::StmtFormal { - kind, - clk, - pred, - en: en & !formal_reset().cast_to_static::(), - text: text.intern(), - source_location, - }); -} - -#[track_caller] -pub fn formal_stmt_with_enable( - kind: FormalKind, - clk: Expr, - pred: Expr, - en: Expr, - text: &str, -) { - formal_stmt_with_enable_and_loc(kind, clk, pred, en, text, SourceLocation::caller()); -} - -#[track_caller] -pub fn formal_stmt_with_loc( - kind: FormalKind, - clk: Expr, - pred: Expr, - text: &str, - source_location: SourceLocation, -) { - formal_stmt_with_enable_and_loc(kind, clk, pred, true.to_expr(), text, source_location); -} - -#[track_caller] -pub fn formal_stmt(kind: FormalKind, clk: Expr, pred: Expr, text: &str) { - formal_stmt_with_loc(kind, clk, pred, text, SourceLocation::caller()); -} - -macro_rules! make_formal { - ($kind:ident, $formal_stmt_with_enable_and_loc:ident, $formal_stmt_with_enable:ident, $formal_stmt_with_loc:ident, $formal_stmt:ident) => { - #[track_caller] - pub fn $formal_stmt_with_enable_and_loc( - clk: Expr, - pred: Expr, - en: Expr, - text: &str, - source_location: SourceLocation, - ) { - formal_stmt_with_enable_and_loc( - FormalKind::$kind, - clk, - pred, - en, - text, - source_location, - ); - } - #[track_caller] - pub fn $formal_stmt_with_enable( - clk: Expr, - pred: Expr, - en: Expr, - text: &str, - ) { - formal_stmt_with_enable(FormalKind::$kind, clk, pred, en, text); - } - #[track_caller] - pub fn $formal_stmt_with_loc( - clk: Expr, - pred: Expr, - text: &str, - source_location: SourceLocation, - ) { - formal_stmt_with_loc(FormalKind::$kind, clk, pred, text, source_location); - } - #[track_caller] - pub fn $formal_stmt(clk: Expr, pred: Expr, text: &str) { - formal_stmt(FormalKind::$kind, clk, pred, text); - } - }; -} - -make_formal!( - Assert, - hdl_assert_with_enable_and_loc, - hdl_assert_with_enable, - hdl_assert_with_loc, - hdl_assert -); - -make_formal!( - Assume, - hdl_assume_with_enable_and_loc, - hdl_assume_with_enable, - hdl_assume_with_loc, - hdl_assume -); - -make_formal!( - Cover, - hdl_cover_with_enable_and_loc, - hdl_cover_with_enable, - hdl_cover_with_loc, - hdl_cover -); - -pub trait MakeFormalExpr: Type {} - -impl MakeFormalExpr for T {} - -#[hdl] -pub fn formal_global_clock() -> Expr { - #[hdl_module(extern)] - fn formal_global_clock() { - #[hdl] - let clk: Clock = m.output(); - m.annotate_module(BlackBoxInlineAnnotation { - path: "fayalite_formal_global_clock.v".intern(), - text: r"module __fayalite_formal_global_clock(output clk); - (* gclk *) - reg clk; -endmodule -" - .intern(), - }); - m.verilog_name("__fayalite_formal_global_clock"); - } - #[hdl] - let formal_global_clock = instance(formal_global_clock()); - formal_global_clock.clk -} - -#[hdl] -pub fn formal_reset() -> Expr { - #[hdl_module(extern)] - fn formal_reset() { - #[hdl] - let rst: SyncReset = m.output(); - m.annotate_module(BlackBoxInlineAnnotation { - path: "fayalite_formal_reset.v".intern(), - text: r"module __fayalite_formal_reset(output rst); - assign rst = $initstate; -endmodule -" - .intern(), - }); - m.verilog_name("__fayalite_formal_reset"); - } - static MOD: OnceLock>> = OnceLock::new(); - #[hdl] - let formal_reset = instance(*MOD.get_or_init(formal_reset)); - formal_reset.rst -} - -macro_rules! make_any_const_fn { - ($ident:ident, $verilog_attribute:literal) => { - #[hdl] - pub fn $ident(ty: T) -> Expr { - #[hdl_module(extern)] - pub(super) fn $ident(ty: T) { - #[hdl] - let out: T = m.output(ty); - let width = ty.width(); - let verilog_bitslice = if width == 1 { - String::new() - } else { - format!(" [{}:0]", width - 1) - }; - m.annotate_module(BlackBoxInlineAnnotation { - path: Intern::intern_owned(format!( - "fayalite_{}_{width}.v", - stringify!($ident), - )), - text: Intern::intern_owned(format!( - r"module __fayalite_{}_{width}(output{verilog_bitslice} out); - (* {} *) - reg{verilog_bitslice} out; -endmodule -", - stringify!($ident), - $verilog_attribute, - )), - }); - m.verilog_name(format!("__fayalite_{}_{width}", stringify!($ident))); - } - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - struct TheMemoize(T); - impl Memoize for TheMemoize { - type Input = (); - type InputOwned = (); - type Output = Option>>>; - fn inner(self, _input: &Self::Input) -> Self::Output { - if self.0.width() == 0 { - None - } else { - Some($ident(self.0)) - } - } - } - let Some(module) = TheMemoize(ty).get_owned(()) else { - return 0_hdl_u0.cast_bits_to(ty); - }; - #[hdl] - let $ident = instance(module); - $ident.out - } - }; -} - -make_any_const_fn!(any_const, "anyconst"); -make_any_const_fn!(any_seq, "anyseq"); -make_any_const_fn!(all_const, "allconst"); -make_any_const_fn!(all_seq, "allseq"); diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index d8364b1..2950086 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -2,52 +2,26 @@ // See Notices.txt for copyright information use crate::{ - array::ArrayType, expr::{ target::{GetTarget, Target}, Expr, NotALiteralExpr, ToExpr, ToLiteralBits, }, - hdl, intern::{Intern, Interned, Memoize}, - sim::value::{SimValue, ToSimValueWithType}, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, }; -use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; +use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec}; use num_bigint::{BigInt, BigUint, Sign}; -use num_traits::{One, Signed, Zero}; -use serde::{ - de::{DeserializeOwned, Error, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use num_traits::{Signed, Zero}; use std::{ borrow::{BorrowMut, Cow}, fmt, marker::PhantomData, - num::NonZero, ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive}, - str::FromStr, sync::Arc, }; -mod uint_in_range; - -#[hdl] -pub type UIntInRangeType = uint_in_range::UIntInRangeType; - -#[hdl] -pub type UIntInRange = - UIntInRangeType, ConstUsize>; - -#[hdl] -pub type UIntInRangeInclusiveType = - uint_in_range::UIntInRangeInclusiveType; - -#[hdl] -pub type UIntInRangeInclusive = - UIntInRangeInclusiveType, ConstUsize>; - mod sealed { pub trait BoolOrIntTypeSealed {} pub trait SizeSealed {} @@ -57,33 +31,8 @@ mod sealed { pub const DYN_SIZE: usize = !0; pub type DynSize = ConstUsize; -pub trait KnownSize: - GenericConstUsize + sealed::SizeTypeSealed + sealed::SizeSealed + Default -{ +pub trait KnownSize: GenericConstUsize + Size { const SIZE: Self; - type ArrayMatch: AsRef<[Expr]> - + AsMut<[Expr]> - + BorrowMut<[Expr]> - + 'static - + Send - + Sync - + Eq - + Clone - + std::hash::Hash - + std::fmt::Debug - + IntoIterator> - + TryFrom>> - + Into>>; - type ArraySimValue: AsRef<[SimValue]> - + AsMut<[SimValue]> - + BorrowMut<[SimValue]> - + 'static - + Clone - + std::fmt::Debug - + IntoIterator> - + TryFrom>> - + Into>> - + ToSimValueWithType>; } macro_rules! known_widths { @@ -94,8 +43,6 @@ macro_rules! known_widths { v }> { const SIZE: Self = Self; - type ArrayMatch = [Expr; Self::VALUE]; - type ArraySimValue = [SimValue; Self::VALUE]; } }; ([2 $($rest:tt)*] $($bits:literal)+) => { @@ -107,8 +54,6 @@ macro_rules! known_widths { known_widths!([$($rest)*] 1); impl KnownSize for ConstUsize<{2 $(* $rest)*}> { const SIZE: Self = Self; - type ArrayMatch = [Expr; Self::VALUE]; - type ArraySimValue = [SimValue; Self::VALUE]; } }; } @@ -116,31 +61,13 @@ macro_rules! known_widths { known_widths!([2 2 2 2 2 2 2 2 2]); pub trait SizeType: - sealed::SizeTypeSealed - + Copy - + Ord - + std::hash::Hash - + std::fmt::Debug - + Send - + Sync - + 'static - + Serialize - + DeserializeOwned + sealed::SizeTypeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static { type Size: Size; } pub trait Size: - sealed::SizeSealed - + Copy - + Ord - + std::hash::Hash - + std::fmt::Debug - + Send - + Sync - + 'static - + Serialize - + DeserializeOwned + sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static { type ArrayMatch: AsRef<[Expr]> + AsMut<[Expr]> @@ -155,16 +82,6 @@ pub trait Size: + IntoIterator> + TryFrom>> + Into>>; - type ArraySimValue: AsRef<[SimValue]> - + AsMut<[SimValue]> - + BorrowMut<[SimValue]> - + 'static - + Clone - + std::fmt::Debug - + IntoIterator> - + TryFrom>> - + Into>> - + ToSimValueWithType>; const KNOWN_VALUE: Option; type SizeType: SizeType + Copy @@ -190,7 +107,6 @@ impl SizeType for usize { impl Size for DynSize { type ArrayMatch = Box<[Expr]>; - type ArraySimValue = Box<[SimValue]>; const KNOWN_VALUE: Option = None; type SizeType = usize; @@ -207,330 +123,36 @@ impl sealed::SizeSealed for ConstUsize {} impl sealed::SizeTypeSealed for ConstUsize {} -impl SizeType for T { - type Size = T; +impl SizeType for ConstUsize +where + ConstUsize: KnownSize, +{ + type Size = ConstUsize; } -impl Size for T { - type ArrayMatch = ::ArrayMatch; - type ArraySimValue = ::ArraySimValue; +impl Size for ConstUsize +where + ConstUsize: KnownSize, +{ + type ArrayMatch = [Expr; VALUE]; - const KNOWN_VALUE: Option = Some(T::VALUE); + const KNOWN_VALUE: Option = Some(VALUE); - type SizeType = T; + type SizeType = ConstUsize; fn as_usize(_size_type: Self::SizeType) -> usize { - T::VALUE + VALUE } fn try_from_usize(v: usize) -> Option { - if v == T::VALUE { - Some(T::SIZE) + if v == VALUE { + Some(Self::SizeType::default()) } else { None } } } -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ParseIntValueError { - Empty, - InvalidDigit, - MissingDigits, - InvalidRadix, - MissingType, - InvalidType, - TypeMismatch { - parsed_signed: bool, - parsed_width: usize, - expected_signed: bool, - expected_width: usize, - }, - PosOverflow, - NegOverflow, - WidthOverflow, - MissingWidth, -} - -impl std::error::Error for ParseIntValueError {} - -impl fmt::Display for ParseIntValueError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Empty => "can't parse integer from empty string", - Self::InvalidDigit => "invalid digit", - Self::MissingDigits => "missing digits", - Self::InvalidRadix => "invalid radix", - Self::MissingType => "missing type", - Self::InvalidType => "invalid type", - Self::TypeMismatch { - parsed_signed, - parsed_width, - expected_signed, - expected_width, - } => { - return write!( - f, - "type mismatch: parsed type {parsed_signed_str}{parsed_width}, \ - expected type {expected_signed_str}{expected_width}", - parsed_signed_str = if *parsed_signed { "i" } else { "u" }, - expected_signed_str = if *expected_signed { "i" } else { "u" }, - ); - } - Self::PosOverflow => "value too large to fit in type", - Self::NegOverflow => "value too small to fit in type", - Self::WidthOverflow => "width is too large", - Self::MissingWidth => "missing width", - }) - } -} - -fn parse_int_value( - s: &str, - type_is_signed: bool, - type_width: Option, - parse_type: bool, -) -> Result, ParseIntValueError> { - if !parse_type && type_width.is_none() { - return Err(ParseIntValueError::MissingWidth); - } - let mut s = s.trim(); - if s.is_empty() { - return Err(ParseIntValueError::Empty); - } - let negative = match s.bytes().next() { - Some(ch @ (b'+' | b'-')) => { - s = s[1..].trim_start(); - ch == b'-' - } - _ => false, - }; - let radix = match s.bytes().next() { - Some(b'0') => match s.bytes().nth(1) { - Some(b'x' | b'X') => { - s = &s[2..]; - 16 - } - Some(b'b' | b'B') => { - s = &s[2..]; - 2 - } - Some(b'o' | b'O') => { - s = &s[2..]; - 8 - } - _ => 10, - }, - Some(b'1'..=b'9') => 10, - _ => return Err(ParseIntValueError::InvalidDigit), - }; - let mut any_digits = false; - let digits_end = s - .as_bytes() - .iter() - .position(|&ch| { - if ch == b'_' { - false - } else if (ch as char).to_digit(radix).is_some() { - any_digits = true; - false - } else { - true - } - }) - .unwrap_or(s.len()); - let digits = &s[..digits_end]; - s = &s[digits_end..]; - if !any_digits { - return Err(ParseIntValueError::MissingDigits); - } - let width = if parse_type { - const HDL_PREFIX: &[u8] = b"hdl_"; - let mut missing_type = ParseIntValueError::MissingType; - if s.as_bytes() - .get(..HDL_PREFIX.len()) - .is_some_and(|bytes| bytes.eq_ignore_ascii_case(HDL_PREFIX)) - { - s = &s[HDL_PREFIX.len()..]; - missing_type = ParseIntValueError::InvalidType; - } - let signed = match s.bytes().next() { - Some(b'u' | b'U') => false, - Some(b'i' | b'I') => true, - Some(_) => return Err(ParseIntValueError::InvalidType), - None => return Err(missing_type), - }; - s = &s[1..]; - let mut width = 0usize; - let mut any_digits = false; - for ch in s.bytes() { - let digit = (ch as char) - .to_digit(10) - .ok_or(ParseIntValueError::InvalidDigit)?; - any_digits = true; - width = width - .checked_mul(10) - .and_then(|v| v.checked_add(digit as usize)) - .ok_or(ParseIntValueError::WidthOverflow)?; - } - if !any_digits { - return Err(ParseIntValueError::MissingDigits); - } - if width > ::MAX_BITS { - return Err(ParseIntValueError::WidthOverflow); - } - let expected_width = type_width.unwrap_or(width); - if type_is_signed != signed || expected_width != width { - let expected_width = type_width.unwrap_or(width); - return Err(ParseIntValueError::TypeMismatch { - parsed_signed: signed, - parsed_width: width, - expected_signed: type_is_signed, - expected_width, - }); - } - width - } else { - if !s.is_empty() { - return Err(ParseIntValueError::InvalidDigit); - } - type_width.expect("checked earlier") - }; - if !type_is_signed && negative { - return Err(ParseIntValueError::InvalidDigit); - } - if radix == 10 { - let mut value: BigInt = digits - .replace("_", "") - .parse() - .expect("checked that the digits are valid already"); - if negative { - value = -value; - } - let uint_value: UIntValue = UInt::new(width).from_bigint_wrapping(&value); - if value.is_zero() { - Ok(uint_value.into_bits()) - } else { - for i in 0..width { - value.set_bit(i as u64, type_is_signed && negative); - } - if value.is_zero() { - Ok(uint_value.into_bits()) - } else if type_is_signed && negative { - if value.sign() == Sign::Minus && value.magnitude().is_one() { - Ok(uint_value.into_bits()) - } else { - Err(ParseIntValueError::NegOverflow) - } - } else { - Err(ParseIntValueError::PosOverflow) - } - } - } else { - let mut value = BitVec::repeat(false, width); - let bits_per_digit = match radix { - 2 => 1, - 8 => 3, - 16 => 4, - _ => unreachable!(), - }; - let mut digits = digits - .bytes() - .rev() - .filter_map(|ch| (ch as char).to_digit(radix)); - let overflow_error = if negative { - ParseIntValueError::NegOverflow - } else { - ParseIntValueError::PosOverflow - }; - for chunk in value.chunks_mut(bits_per_digit) { - if let Some(mut digit) = digits.next() { - let digit_bits = &mut digit.view_bits_mut::()[..chunk.len()]; - chunk.clone_from_bitslice(digit_bits); - digit_bits.fill(false); - if digit != 0 { - return Err(overflow_error); - } - } else { - break; - } - } - for digit in digits { - if digit != 0 { - return Err(overflow_error); - } - } - let negative_zero = if negative { - // negating a value happens in three regions: - // * the least-significant zeros, which are left as zeros - // * the least-significant one bit, which is left as a one bit - // * all the most-significant bits, which are inverted - // e.g.: - const { - let inp = 0b1010_1_000_u8; - let out = 0b0101_1_000_u8; - assert!(inp.wrapping_neg() == out); - }; - if let Some(first_one) = value.first_one() { - let most_significant_bits = &mut value[first_one + 1..]; - // modifies in-place despite using `Not::not` - let _ = Not::not(most_significant_bits); - false - } else { - true - } - } else { - false - }; - if !negative_zero && type_is_signed && negative != value[value.len() - 1] { - Err(overflow_error) - } else { - Ok(Arc::new(value)) - } - } -} - -fn deserialize_int_value<'de, D: Deserializer<'de>>( - deserializer: D, - type_is_signed: bool, - type_width: Option, -) -> Result, D::Error> { - struct IntValueVisitor { - type_is_signed: bool, - type_width: Option, - } - impl<'de> Visitor<'de> for IntValueVisitor { - type Value = Arc; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(if self.type_is_signed { - "SIntValue" - } else { - "UIntValue" - })?; - if let Some(type_width) = self.type_width { - write!(f, "<{type_width}>")?; - } - Ok(()) - } - - fn visit_str(self, v: &str) -> Result { - parse_int_value(v, self.type_is_signed, self.type_width, true).map_err(E::custom) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - match std::str::from_utf8(v) { - Ok(v) => self.visit_str(v), - Err(_) => Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)), - } - } - } - deserializer.deserialize_str(IntValueVisitor { - type_is_signed, - type_width, - }) -} - macro_rules! impl_int { ($pretty_name:ident, $name:ident, $generic_name:ident, $value:ident, $SIGNED:literal) => { #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -554,26 +176,31 @@ macro_rules! impl_int { pub const $name: $generic_name = $generic_name; impl $name { - pub const fn new(width: Width::SizeType) -> Self { + pub fn new(width: Width::SizeType) -> Self { Self { width } } pub fn width(self) -> usize { Width::as_usize(self.width) } pub fn type_properties(self) -> TypeProperties { - self.as_dyn_int().type_properties_dyn() + TypeProperties { + is_passive: true, + is_storable: true, + is_castable_from_bits: true, + bit_width: self.width(), + } } - pub fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec { + pub fn bits_from_bigint_wrapping(self, v: BigInt) -> BitVec { BoolOrIntType::bits_from_bigint_wrapping(self, v) } - pub fn from_bigint_wrapping(self, v: &BigInt) -> $value { + pub fn from_bigint_wrapping(self, v: BigInt) -> $value { $value { bits: Arc::new(self.bits_from_bigint_wrapping(v)), _phantom: PhantomData, } } pub fn from_int_wrapping(self, v: impl Into) -> $value { - self.from_bigint_wrapping(&v.into()) + self.from_bigint_wrapping(v.into()) } pub fn zero(self) -> $value { self.from_int_wrapping(0u8) @@ -588,29 +215,12 @@ macro_rules! impl_int { impl BoolOrIntType for $name { type Width = Width; type Signed = ConstBool<$SIGNED>; - type Value = $value; fn width(self) -> usize { $name::width(self) } fn new(width: Width::SizeType) -> Self { $name { width } } - fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value { - $value::::from_bigint_wrapping(self, v) - } - fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value { - #[derive(Copy, Clone, Eq, PartialEq, Hash)] - struct MemoizeBitsToValue; - impl Memoize for MemoizeBitsToValue { - type Input = BitSlice; - type InputOwned = BitVec; - type Output = Arc; - fn inner(self, input: &Self::Input) -> Self::Output { - Arc::new(input.to_bitvec()) - } - } - $value::new(MemoizeBitsToValue.get_cow(bits)) - } fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr { #[derive(Copy, Clone, Eq, PartialEq, Hash)] struct MemoizeBitsToExpr; @@ -624,12 +234,6 @@ macro_rules! impl_int { } Expr::from_dyn_int(MemoizeBitsToExpr.get_cow(bits)) } - fn from_str_without_ty( - self, - s: &str, - ) -> Result::Err> { - parse_int_value(s, $SIGNED, Some(self.width()), false).map(Self::Value::new) - } } impl IntType for $name { @@ -637,32 +241,25 @@ macro_rules! impl_int { } impl $name { - pub const fn new_dyn(width: usize) -> Self { + pub fn new_dyn(width: usize) -> Self { Self { width } } pub fn bits_to_bigint(bits: &BitSlice) -> BigInt { ::bits_to_bigint(bits) } - pub const fn type_properties_dyn(self) -> TypeProperties { - TypeProperties { - is_passive: true, - is_storable: true, - is_castable_from_bits: true, - bit_width: self.width, - } - } } impl $name { pub fn new_static() -> Self { - Self { width: Width::SIZE } + Self { + width: Width::SizeType::default(), + } } } impl Type for $name { type BaseType = $pretty_name; type MaskType = Bool; - type SimValue = $value; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -673,7 +270,7 @@ macro_rules! impl_int { #[track_caller] fn from_canonical(canonical_type: CanonicalType) -> Self { let CanonicalType::$pretty_name(retval) = canonical_type else { - panic!("expected {}", stringify!($pretty_name)); + panic!("expected {}", stringify!($name)); }; $name { width: Width::from_usize(retval.width), @@ -682,78 +279,20 @@ macro_rules! impl_int { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), self.width()); - $value::new(Arc::new(bits.to_bitvec())) - } - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), self.width()); - assert_eq!(value.width(), self.width()); - value.bits_mut().copy_from_bitslice(bits); - } - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), self.width()); - assert_eq!(value.width(), self.width()); - bits.copy_from_bitslice(value.bits()); - } - } - - impl Default for $name { - fn default() -> Self { - Self::TYPE - } } impl StaticType for $name { const TYPE: Self = Self { width: Width::SIZE }; const MASK_TYPE: Self::MaskType = Bool; - const TYPE_PROPERTIES: TypeProperties = $name { - width: Width::VALUE, - } - .type_properties_dyn(); + const TYPE_PROPERTIES: TypeProperties = TypeProperties { + is_passive: true, + is_storable: true, + is_castable_from_bits: true, + bit_width: Width::VALUE, + }; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } - impl Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.canonical().serialize(serializer) - } - } - - impl<'de, Width: Size> Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = |width| -> String { - if let Some(width) = width { - format!("a {}<{width}>", stringify!($pretty_name)) - } else { - format!("a {}", stringify!($pretty_name)) - } - }; - match CanonicalType::deserialize(deserializer)? { - CanonicalType::$pretty_name(retval) => { - if let Some(width) = Width::try_from_usize(retval.width()) { - Ok($name { width }) - } else { - Err(Error::invalid_value( - serde::de::Unexpected::Other(&name(Some(retval.width()))), - &&*name(Width::KNOWN_VALUE), - )) - } - } - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &&*name(Width::KNOWN_VALUE), - )), - } - } - } - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct $generic_name; @@ -761,7 +300,7 @@ macro_rules! impl_int { type Output = $name; fn index(&self, width: Width) -> &Self::Output { - Interned::into_inner(Intern::intern_sized($name::new(width))) + Interned::<_>::into_inner(Intern::intern_sized($name::new(width))) } } @@ -771,7 +310,7 @@ macro_rules! impl_int { _phantom: PhantomData, } - impl fmt::Display for $value { + impl fmt::Debug for $value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let value = self.to_bigint(); let (sign, magnitude) = value.into_parts(); @@ -785,47 +324,6 @@ macro_rules! impl_int { } } - impl fmt::Debug for $value { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } - - impl std::str::FromStr for $value { - type Err = ParseIntValueError; - - fn from_str(s: &str) -> Result { - parse_int_value(s, $SIGNED, Width::KNOWN_VALUE, true).map(Self::new) - } - } - - impl Serialize for $value { - fn serialize(&self, serializer: S) -> Result { - self.to_string().serialize(serializer) - } - } - - impl<'de, Width: Size> Deserialize<'de> for $value { - fn deserialize>(deserializer: D) -> Result { - deserialize_int_value(deserializer, $SIGNED, Width::KNOWN_VALUE).map(Self::new) - } - } - - impl PartialOrd for $value { - fn partial_cmp(&self, other: &Self) -> Option { - if self.width() != other.width() { - return None; - } - Some(self.to_bigint().cmp(&other.to_bigint())) - } - } - - impl From<$value> for BigInt { - fn from(v: $value) -> BigInt { - v.to_bigint() - } - } - impl $value { pub fn width(&self) -> usize { if let Some(retval) = Width::KNOWN_VALUE { @@ -835,7 +333,7 @@ macro_rules! impl_int { self.bits.len() } } - pub fn from_bigint_wrapping(ty: $name, v: &BigInt) -> $value { + pub fn from_bigint_wrapping(ty: $name, v: BigInt) -> $value { ty.from_bigint_wrapping(v) } pub fn to_bigint(&self) -> BigInt { @@ -858,9 +356,6 @@ macro_rules! impl_int { pub fn bits(&self) -> &Arc { &self.bits } - pub fn bits_mut(&mut self) -> &mut BitSlice { - Arc::::make_mut(&mut self.bits) - } } impl ToLiteralBits for $value { @@ -915,10 +410,6 @@ impl UInt { let v: BigUint = v.into(); Self::new(v.bits().try_into().expect("too big")) } - /// gets the smallest `UInt` that fits `v` losslessly - pub const fn for_value_usize(v: usize) -> Self { - Self::new((usize::BITS - v.leading_zeros()) as usize) - } /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty #[track_caller] pub fn range(r: Range>) -> Self { @@ -929,12 +420,6 @@ impl UInt { } /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty #[track_caller] - pub const fn range_usize(r: Range) -> Self { - assert!(r.end != 0, "empty range"); - Self::range_inclusive_usize(r.start..=(r.end - 1)) - } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] pub fn range_inclusive(r: RangeInclusive>) -> Self { let (start, end) = r.into_inner(); let start: BigUint = start.into(); @@ -944,16 +429,6 @@ impl UInt { // so must not take more bits than `end` Self::for_value(end) } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub const fn range_inclusive_usize(r: RangeInclusive) -> Self { - let start = *r.start(); - let end = *r.end(); - assert!(start <= end, "empty range"); - // no need to check `start`` since it's no larger than `end` - // so must not take more bits than `end` - Self::for_value_usize(end) - } } impl SInt { @@ -968,10 +443,7 @@ impl SInt { v.not().bits().checked_add(1).expect("too big") } Sign::NoSign => 0, - Sign::Plus => { - // account for sign bit - v.bits().checked_add(1).expect("too big") - } + Sign::Plus => v.bits(), } .try_into() .expect("too big"), @@ -996,24 +468,7 @@ impl SInt { } macro_rules! impl_prim_int { - ( - $(#[$meta:meta])* - $prim_int:ident, $ty:ty - ) => { - impl From<$prim_int> for <$ty as BoolOrIntType>::Value { - fn from(v: $prim_int) -> Self { - <$ty>::le_bytes_to_value_wrapping( - &v.to_le_bytes(), - <$ty as BoolOrIntType>::Width::VALUE, - ) - } - } - impl From> for <$ty as BoolOrIntType>::Value { - fn from(v: NonZero<$prim_int>) -> Self { - v.get().into() - } - } - $(#[$meta])* + ($prim_int:ident, $ty:ty) => { impl ToExpr for $prim_int { type Type = $ty; @@ -1024,14 +479,6 @@ macro_rules! impl_prim_int { ) } } - $(#[$meta])* - impl ToExpr for NonZero<$prim_int> { - type Type = $ty; - - fn to_expr(&self) -> Expr { - self.get().to_expr() - } - } }; } @@ -1046,38 +493,16 @@ impl_prim_int!(i32, SInt<32>); impl_prim_int!(i64, SInt<64>); impl_prim_int!(i128, SInt<128>); -impl_prim_int!( - /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] - usize, UInt<64> -); - -impl_prim_int!( - /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] - isize, SInt<64> -); - pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { type Width: Size; type Signed: GenericConstBool; - type Value: Clone - + PartialOrd - + Eq - + std::hash::Hash - + fmt::Debug - + fmt::Display - + Send - + Sync - + 'static - + ToExpr - + Into - + std::str::FromStr; fn width(self) -> usize; fn new(width: ::SizeType) -> Self; fn new_static() -> Self where - Self::Width: KnownSize + Size, + Self::Width: KnownSize, { - Self::new(Self::Width::default()) + Self::new(::SizeType::default()) } fn as_same_width_sint(self) -> SIntType { SIntType::new(Self::Width::from_usize(self.width())) @@ -1085,30 +510,17 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { fn as_same_width_uint(self) -> UIntType { UIntType::new(Self::Width::from_usize(self.width())) } - fn value_from_int_wrapping(self, v: impl Into) -> Self::Value { - self.value_from_bigint_wrapping(&v.into()) - } - fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value; - fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec { - let mut bits = BitVec::repeat(false, self.width()); - Self::copy_bits_from_bigint_wrapping(v, &mut bits); - bits - } - fn copy_bits_from_bigint_wrapping(v: &BigInt, bits: &mut BitSlice) { - let width = bits.len(); + fn bits_from_bigint_wrapping(self, v: BigInt) -> BitVec { + let width = self.width(); let mut bytes = v.to_signed_bytes_le(); bytes.resize( width.div_ceil(u8::BITS as usize), if v.is_negative() { 0xFF } else { 0 }, ); let bitslice = &BitSlice::::from_slice(&bytes)[..width]; - bits.clone_from_bitslice(bitslice); - } - fn bits_equal_bigint_wrapping(v: &BigInt, bits: &BitSlice) -> bool { - bits.iter() - .by_vals() - .enumerate() - .all(|(bit_index, bit): (usize, bool)| v.bit(bit_index as u64) == bit) + let mut bits = BitVec::new(); + bits.extend_from_bitslice(bitslice); + bits } fn bits_to_bigint(bits: &BitSlice) -> BigInt { let sign_byte = if Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false) { @@ -1120,10 +532,9 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { BitSlice::::from_slice_mut(&mut bytes)[..bits.len()].clone_from_bitslice(bits); BigInt::from_signed_bytes_le(&bytes) } - fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value; fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr; - fn le_bytes_to_bits_wrapping(bytes: &[u8], bit_width: usize) -> BitVec { - let bitslice = BitSlice::::from_slice(bytes); + fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr { + let bitslice = BitSlice::::from_slice(&bytes); let bitslice = &bitslice[..bit_width.min(bitslice.len())]; let mut bits = BitVec::new(); bits.extend_from_bitslice(bitslice); @@ -1131,24 +542,11 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { bit_width, Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false), ); - bits + Self::bits_to_expr(Cow::Owned(bits)) } - fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr { - Self::bits_to_expr(Cow::Owned(Self::le_bytes_to_bits_wrapping( - bytes, bit_width, - ))) - } - fn le_bytes_to_value_wrapping(bytes: &[u8], bit_width: usize) -> Self::Value { - Self::bits_to_value(Cow::Owned(Self::le_bytes_to_bits_wrapping( - bytes, bit_width, - ))) - } - fn from_str_without_ty(self, s: &str) -> Result::Err>; } -pub trait IntType: - BoolOrIntType::Dyn, Value: FromStr> -{ +pub trait IntType: BoolOrIntType::Dyn> { type Dyn: IntType; fn as_dyn_int(self) -> Self::Dyn { Self::new_dyn(self.width()) @@ -1188,7 +586,7 @@ pub trait IntType: } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Bool; impl sealed::BoolOrIntTypeSealed for Bool {} @@ -1196,7 +594,6 @@ impl sealed::BoolOrIntTypeSealed for Bool {} impl BoolOrIntType for Bool { type Width = ConstUsize<1>; type Signed = ConstBool; - type Value = bool; fn width(self) -> usize { 1 @@ -1207,23 +604,10 @@ impl BoolOrIntType for Bool { Bool } - fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value { - v.bit(0) - } - fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr { assert_eq!(bits.len(), 1); bits[0].to_expr() } - - fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value { - assert_eq!(bits.len(), 1); - bits[0] - } - - fn from_str_without_ty(self, s: &str) -> Result::Err> { - FromStr::from_str(s) - } } impl Bool { @@ -1238,7 +622,6 @@ impl Bool { impl Type for Bool { type BaseType = Bool; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -1256,18 +639,6 @@ impl Type for Bool { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), 1); - bits[0] - } - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), 1); - *value = bits[0]; - } - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), 1); - bits.set(0, *value); - } } impl StaticType for Bool { @@ -1282,143 +653,17 @@ impl StaticType for Bool { const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } +pub trait IntCmp { + fn cmp_eq(self, rhs: Rhs) -> Expr; + fn cmp_ne(self, rhs: Rhs) -> Expr; + fn cmp_lt(self, rhs: Rhs) -> Expr; + fn cmp_le(self, rhs: Rhs) -> Expr; + fn cmp_gt(self, rhs: Rhs) -> Expr; + fn cmp_ge(self, rhs: Rhs) -> Expr; +} + impl ToLiteralBits for bool { fn to_literal_bits(&self) -> Result, NotALiteralExpr> { Ok(interned_bit(*self)) } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_different_value_widths_compare_ne() { - // interning relies on [SU]IntValue with different `width` comparing not equal - assert_ne!(UInt[3].from_int_wrapping(0), UInt[4].from_int_wrapping(0)); - assert_ne!(SInt[3].from_int_wrapping(0), SInt[4].from_int_wrapping(0)); - } - - #[test] - fn test_uint_for_value() { - assert_eq!(UInt::for_value(0u8).width, 0); - assert_eq!(UInt::for_value(1u8).width, 1); - assert_eq!(UInt::for_value(2u8).width, 2); - assert_eq!(UInt::for_value(3u8).width, 2); - assert_eq!(UInt::for_value(4u8).width, 3); - } - - #[test] - fn test_sint_for_value() { - assert_eq!(SInt::for_value(-5).width, 4); - assert_eq!(SInt::for_value(-4).width, 3); - assert_eq!(SInt::for_value(-3).width, 3); - assert_eq!(SInt::for_value(-2).width, 2); - assert_eq!(SInt::for_value(-1).width, 1); - assert_eq!(SInt::for_value(0).width, 0); - assert_eq!(SInt::for_value(1).width, 2); - assert_eq!(SInt::for_value(2).width, 3); - assert_eq!(SInt::for_value(3).width, 3); - assert_eq!(SInt::for_value(4).width, 4); - } - - #[test] - fn test_serde_round_trip() { - use serde_json::json; - #[track_caller] - fn check( - value: T, - expected: serde_json::Value, - ) { - assert_eq!(serde_json::to_value(&value).unwrap(), expected); - assert_eq!(value, T::deserialize(expected).unwrap()); - } - check(UInt[0], json! { { "UInt": { "width": 0 } } }); - check(UInt::<0>::TYPE, json! { { "UInt": { "width": 0 } } }); - check(UInt::<35>::TYPE, json! { { "UInt": { "width": 35 } } }); - check(SInt[0], json! { { "SInt": { "width": 0 } } }); - check(SInt::<0>::TYPE, json! { { "SInt": { "width": 0 } } }); - check(SInt::<35>::TYPE, json! { { "SInt": { "width": 35 } } }); - check(Bool, json! { "Bool" }); - check(UIntValue::from(0u8), json! { "0x0_u8" }); - check(SIntValue::from(-128i8), json! { "-0x80_i8" }); - check(UInt[3].from_int_wrapping(5), json! { "0x5_u3" }); - check(UInt[12].from_int_wrapping(0x1123), json! { "0x123_u12" }); - check(SInt[12].from_int_wrapping(0xFEE), json! { "-0x12_i12" }); - check(SInt[12].from_int_wrapping(0x7EE), json! { "0x7EE_i12" }); - } - - #[test] - fn test_deserialize() { - use serde_json::json; - #[track_caller] - fn check( - expected: Result, - input: serde_json::Value, - ) { - let mut error = String::new(); - let value = T::deserialize(input).map_err(|e| -> &str { - error = e.to_string(); - &error - }); - assert_eq!(value, expected); - } - check::>( - Err("invalid value: a UInt<2>, expected a UInt<0>"), - json! { { "UInt": { "width": 2 } } }, - ); - check::>( - Err("invalid value: a Bool, expected a UInt<0>"), - json! { "Bool" }, - ); - check::>( - Err("invalid value: a Bool, expected a SInt<0>"), - json! { "Bool" }, - ); - check::( - Err("invalid value: a Bool, expected a UInt"), - json! { "Bool" }, - ); - check::( - Err("invalid value: a Bool, expected a SInt"), - json! { "Bool" }, - ); - check::(Err("value too large to fit in type"), json! { "2_u1" }); - check::(Err("value too large to fit in type"), json! { "10_u1" }); - check::(Err("value too large to fit in type"), json! { "0x2_u1" }); - check::(Err("value too large to fit in type"), json! { "0b10_u1" }); - check::(Err("value too large to fit in type"), json! { "0o2_u1" }); - check::(Err("value too large to fit in type"), json! { "0o377_i8" }); - check::(Err("value too large to fit in type"), json! { "0o200_i8" }); - check(Ok(SInt[8].from_int_wrapping(i8::MAX)), json! { "0o177_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o201_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o377_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o400_i8" }); - check::( - Err("value too small to fit in type"), - json! { "-0o4000_i8" }, - ); - check(Ok(UIntValue::from(0u8)), json! { "0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0b0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "00_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0x0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0o0_u8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0x000_80_i8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0o002_00_hdl_i8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0b1__000_0000_i8" }); - check(Ok(UInt[3].from_int_wrapping(5)), json! { " + 0x5_u3 " }); - check( - Ok(UInt[12].from_int_wrapping(0x1123)), - json! { "0x1_2_3_hdl_u12" }, - ); - check(Ok(SInt[12].from_int_wrapping(0xFEE)), json! { "-0x12_i12" }); - check( - Ok(SInt[12].from_int_wrapping(0x7EE)), - json! { " + \t0x7__E_e_i012\n" }, - ); - check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0i0" }); - check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0i1" }); - check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0x0i0" }); - check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0x0i1" }); - } -} diff --git a/crates/fayalite/src/int/uint_in_range.rs b/crates/fayalite/src/int/uint_in_range.rs deleted file mode 100644 index 0e2d07e..0000000 --- a/crates/fayalite/src/int/uint_in_range.rs +++ /dev/null @@ -1,614 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder}, - expr::{ - ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd}, - CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, - }, - int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType}, - intern::{Intern, Interned}, - phantom_const::PhantomConst, - sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, - source_location::SourceLocation, - ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, -}; -use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; -use serde::{ - de::{value::UsizeDeserializer, Error, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use std::{fmt, marker::PhantomData, ops::Index}; - -const UINT_IN_RANGE_TYPE_FIELD_NAMES: [&'static str; 2] = ["value", "range"]; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct UIntInRangeMaskType { - value: Bool, - range: PhantomConstRangeMaskType, -} - -impl Type for UIntInRangeMaskType { - type BaseType = Bundle; - type MaskType = Self; - type SimValue = bool; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - *self - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::Bundle(Bundle::new(self.fields())) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let fields = Bundle::from_canonical(canonical_type).fields(); - let [BundleField { - name: value_name, - flipped: false, - ty: value, - }, BundleField { - name: range_name, - flipped: false, - ty: range, - }] = *fields - else { - panic!("expected UIntInRangeMaskType"); - }; - assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); - let value = Bool::from_canonical(value); - let range = PhantomConstRangeMaskType::from_canonical(range); - Self { value, range } - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - Bool.sim_value_from_bits(bits) - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - Bool.sim_value_clone_from_bits(value, bits); - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - Bool.sim_value_to_bits(value, bits); - } -} - -impl BundleType for UIntInRangeMaskType { - type Builder = NoBuilder; - type FilledBuilder = Expr; - - fn fields(&self) -> Interned<[BundleField]> { - let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; - let Self { value, range } = self; - [ - BundleField { - name: value_name.intern(), - flipped: false, - ty: value.canonical(), - }, - BundleField { - name: range_name.intern(), - flipped: false, - ty: range.canonical(), - }, - ][..] - .intern() - } -} - -impl StaticType for UIntInRangeMaskType { - const TYPE: Self = Self { - value: Bool, - range: PhantomConstRangeMaskType::TYPE, - }; - const MASK_TYPE: Self::MaskType = Self::TYPE; - const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() - .field(false, Bool::TYPE_PROPERTIES) - .field(false, PhantomConstRangeMaskType::TYPE_PROPERTIES) - .finish(); - const MASK_TYPE_PROPERTIES: TypeProperties = Self::TYPE_PROPERTIES; -} - -impl ToSimValueWithType for bool { - fn to_sim_value_with_type(&self, ty: UIntInRangeMaskType) -> SimValue { - SimValue::from_value(ty, *self) - } -} - -impl ExprCastTo for UIntInRangeMaskType { - fn cast_to(src: Expr, to_type: Bool) -> Expr { - src.cast_to_bits().cast_to(to_type) - } -} - -impl ExprCastTo for Bool { - fn cast_to(src: Expr, to_type: UIntInRangeMaskType) -> Expr { - src.cast_to_static::>().cast_bits_to(to_type) - } -} - -impl ExprPartialEq for UIntInRangeMaskType { - fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) - } -} - -impl SimValuePartialEq for UIntInRangeMaskType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other - } -} - -type PhantomConstRangeMaskType = > as Type>::MaskType; - -#[derive(Default, Copy, Clone, Debug)] -struct RangeParseError; - -macro_rules! define_uint_in_range_type { - ( - $UIntInRange:ident, - $UIntInRangeType:ident, - $UIntInRangeTypeWithoutGenerics:ident, - $UIntInRangeTypeWithStart:ident, - $SerdeRange:ident, - $range_operator_str:literal, - |$uint_range_usize_start:ident, $uint_range_usize_end:ident| $uint_range_usize:expr, - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct $SerdeRange { - start: Start::SizeType, - end: End::SizeType, - } - - impl Default for $SerdeRange { - fn default() -> Self { - Self { - start: Start::SIZE, - end: End::SIZE, - } - } - } - - impl std::str::FromStr for $SerdeRange { - type Err = RangeParseError; - - fn from_str(s: &str) -> Result { - let Some((start, end)) = s.split_once($range_operator_str) else { - return Err(RangeParseError); - }; - if start.is_empty() - || start.bytes().any(|b| !b.is_ascii_digit()) - || end.is_empty() - || end.bytes().any(|b| !b.is_ascii_digit()) - { - return Err(RangeParseError); - } - let start = start.parse().map_err(|_| RangeParseError)?; - let end = end.parse().map_err(|_| RangeParseError)?; - let retval = Self { start, end }; - if retval.is_empty() { - Err(RangeParseError) - } else { - Ok(retval) - } - } - } - - impl fmt::Display for $SerdeRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { start, end } = *self; - write!( - f, - "{}{}{}", - Start::as_usize(start), - $range_operator_str, - End::as_usize(end), - ) - } - } - - impl Serialize for $SerdeRange { - fn serialize(&self, serializer: S) -> Result { - serializer.collect_str(self) - } - } - - impl<'de, Start: Size, End: Size> Deserialize<'de> for $SerdeRange { - fn deserialize>(deserializer: D) -> Result { - struct SerdeRangeVisitor(PhantomData<(Start, End)>); - impl<'de, Start: Size, End: Size> Visitor<'de> for SerdeRangeVisitor { - type Value = $SerdeRange; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("a string with format \"")?; - if let Some(start) = Start::KNOWN_VALUE { - write!(f, "{start}")?; - } else { - f.write_str("")?; - }; - f.write_str($range_operator_str)?; - if let Some(end) = End::KNOWN_VALUE { - write!(f, "{end}")?; - } else { - f.write_str("")?; - }; - f.write_str("\" that is a non-empty range") - } - - fn visit_str(self, v: &str) -> Result { - let $SerdeRange:: { start, end } = - v.parse().map_err(|_| { - Error::invalid_value(serde::de::Unexpected::Str(v), &self) - })?; - let start = - Start::SizeType::deserialize(UsizeDeserializer::::new(start))?; - let end = End::SizeType::deserialize(UsizeDeserializer::::new(end))?; - Ok($SerdeRange { start, end }) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - match std::str::from_utf8(v) { - Ok(v) => self.visit_str(v), - Err(_) => { - Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)) - } - } - } - } - deserializer.deserialize_str(SerdeRangeVisitor(PhantomData)) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub struct $UIntInRangeType { - value: UInt, - range: PhantomConst<$SerdeRange>, - } - - impl $UIntInRangeType { - fn from_phantom_const_range(range: PhantomConst<$SerdeRange>) -> Self { - let $SerdeRange { start, end } = *range.get(); - let $uint_range_usize_start = Start::as_usize(start); - let $uint_range_usize_end = End::as_usize(end); - Self { - value: $uint_range_usize, - range, - } - } - pub fn new(start: Start::SizeType, end: End::SizeType) -> Self { - Self::from_phantom_const_range(PhantomConst::new( - $SerdeRange { start, end }.intern_sized(), - )) - } - } - - impl fmt::Debug for $UIntInRangeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { value, range } = self; - let $SerdeRange { start, end } = *range.get(); - f.debug_struct(&format!( - "{}<{}, {}>", - stringify!($UIntInRange), - Start::as_usize(start), - End::as_usize(end), - )) - .field("value", value) - .finish_non_exhaustive() - } - } - - impl Type for $UIntInRangeType { - type BaseType = Bundle; - type MaskType = UIntInRangeMaskType; - type SimValue = usize; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - UIntInRangeMaskType::TYPE - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::Bundle(Bundle::new(self.fields())) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let fields = Bundle::from_canonical(canonical_type).fields(); - let [BundleField { - name: value_name, - flipped: false, - ty: value, - }, BundleField { - name: range_name, - flipped: false, - ty: range, - }] = *fields - else { - panic!("expected {}", stringify!($UIntInRange)); - }; - assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); - let value = UInt::from_canonical(value); - let range = PhantomConst::<$SerdeRange>::from_canonical(range); - let retval = Self::from_phantom_const_range(range); - assert_eq!(retval, Self { value, range }); - retval - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - let mut retval = 0usize; - retval.view_bits_mut::()[..bits.len()].clone_from_bitslice(bits); - retval - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - *value = self.sim_value_from_bits(bits); - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - bits.clone_from_bitslice(&value.view_bits::()[..bits.len()]); - } - } - - impl BundleType for $UIntInRangeType { - type Builder = NoBuilder; - type FilledBuilder = Expr; - - fn fields(&self) -> Interned<[BundleField]> { - let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; - let Self { value, range } = self; - [ - BundleField { - name: value_name.intern(), - flipped: false, - ty: value.canonical(), - }, - BundleField { - name: range_name.intern(), - flipped: false, - ty: range.canonical(), - }, - ][..] - .intern() - } - } - - impl Default for $UIntInRangeType { - fn default() -> Self { - Self::TYPE - } - } - - impl StaticType for $UIntInRangeType { - const TYPE: Self = { - let $uint_range_usize_start = Start::VALUE; - let $uint_range_usize_end = End::VALUE; - Self { - value: $uint_range_usize, - range: PhantomConst::<$SerdeRange>::TYPE, - } - }; - const MASK_TYPE: Self::MaskType = UIntInRangeMaskType::TYPE; - const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() - .field(false, Self::TYPE.value.type_properties_dyn()) - .field( - false, - PhantomConst::<$SerdeRange>::TYPE_PROPERTIES, - ) - .finish(); - const MASK_TYPE_PROPERTIES: TypeProperties = UIntInRangeMaskType::TYPE_PROPERTIES; - } - - impl ToSimValueWithType<$UIntInRangeType> for usize { - fn to_sim_value_with_type( - &self, - ty: $UIntInRangeType, - ) -> SimValue<$UIntInRangeType> { - SimValue::from_value(ty, *self) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub struct $UIntInRangeTypeWithoutGenerics; - - #[allow(non_upper_case_globals)] - pub const $UIntInRangeType: $UIntInRangeTypeWithoutGenerics = - $UIntInRangeTypeWithoutGenerics; - - impl Index for $UIntInRangeTypeWithoutGenerics { - type Output = $UIntInRangeTypeWithStart; - - fn index(&self, start: StartSize) -> &Self::Output { - Interned::into_inner($UIntInRangeTypeWithStart(start).intern_sized()) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub struct $UIntInRangeTypeWithStart(Start::SizeType); - - impl, End: Size> - Index for $UIntInRangeTypeWithStart - { - type Output = $UIntInRangeType; - - fn index(&self, end: EndSize) -> &Self::Output { - Interned::into_inner($UIntInRangeType::new(self.0, end).intern_sized()) - } - } - - impl ExprCastTo for $UIntInRangeType { - fn cast_to(src: Expr, to_type: UInt) -> Expr { - src.cast_to_bits().cast_to(to_type) - } - } - - impl ExprCastTo<$UIntInRangeType> for UInt { - fn cast_to( - src: Expr, - to_type: $UIntInRangeType, - ) -> Expr<$UIntInRangeType> { - src.cast_bits_to(to_type) - } - } - - impl - ExprPartialEq<$UIntInRangeType> - for $UIntInRangeType - { - fn cmp_eq( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) - } - } - - impl - ExprPartialOrd<$UIntInRangeType> - for $UIntInRangeType - { - fn cmp_lt( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits()) - } - fn cmp_le( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_le(rhs.cast_to_bits()) - } - fn cmp_gt( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits()) - } - fn cmp_ge( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_ge(rhs.cast_to_bits()) - } - } - - impl - SimValuePartialEq<$UIntInRangeType> - for $UIntInRangeType - { - fn sim_value_eq( - this: &SimValue, - other: &SimValue<$UIntInRangeType>, - ) -> bool { - **this == **other - } - } - - impl ExprPartialEq> - for $UIntInRangeType - { - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs) - } - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs) - } - } - - impl ExprPartialEq<$UIntInRangeType> - for UIntType - { - fn cmp_eq(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_ne(rhs.cast_to_bits()) - } - } - - impl ExprPartialOrd> - for $UIntInRangeType - { - fn cmp_lt(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_lt(rhs) - } - fn cmp_le(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_le(rhs) - } - fn cmp_gt(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_gt(rhs) - } - fn cmp_ge(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_ge(rhs) - } - } - - impl ExprPartialOrd<$UIntInRangeType> - for UIntType - { - fn cmp_lt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_lt(rhs.cast_to_bits()) - } - fn cmp_le(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_le(rhs.cast_to_bits()) - } - fn cmp_gt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_gt(rhs.cast_to_bits()) - } - fn cmp_ge(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_ge(rhs.cast_to_bits()) - } - } - }; -} - -define_uint_in_range_type! { - UIntInRange, - UIntInRangeType, - UIntInRangeTypeWithoutGenerics, - UIntInRangeTypeWithStart, - SerdeRange, - "..", - |start, end| UInt::range_usize(start..end), -} - -define_uint_in_range_type! { - UIntInRangeInclusive, - UIntInRangeInclusiveType, - UIntInRangeInclusiveTypeWithoutGenerics, - UIntInRangeInclusiveTypeWithStart, - SerdeRangeInclusive, - "..=", - |start, end| UInt::range_inclusive_usize(start..=end), -} - -impl SerdeRange { - fn is_empty(self) -> bool { - self.start >= self.end - } -} - -impl SerdeRangeInclusive { - fn is_empty(self) -> bool { - self.start > self.end - } -} diff --git a/crates/fayalite/src/intern.rs b/crates/fayalite/src/intern.rs index af91f0a..81d8434 100644 --- a/crates/fayalite/src/intern.rs +++ b/crates/fayalite/src/intern.rs @@ -1,9 +1,12 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information #![allow(clippy::type_complexity)] -use crate::{intern::type_map::TypeIdMap, util::DefaultBuildHasher}; +use crate::{ + intern::type_map::TypeIdMap, + util::{ConstBool, GenericConstBool}, +}; use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec}; -use hashbrown::HashTable; +use hashbrown::{hash_map::RawEntryMut, HashMap, HashTable}; use serde::{Deserialize, Serialize}; use std::{ any::{Any, TypeId}, @@ -17,7 +20,7 @@ use std::{ sync::{Mutex, RwLock}, }; -mod type_map; +pub mod type_map; pub trait LazyInternedTrait: Send + Sync + Any { fn get(&self) -> Interned; @@ -195,6 +198,7 @@ impl LazyInterned { pub trait InternedCompare { type InternedCompareKey: Ord + Hash; fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey; + fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey; } /// Warning: doesn't do what you want with `T = dyn Trait`, @@ -268,6 +272,9 @@ impl InternedCompare for T { fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(this) } + fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey { + PtrEqWithMetadata(this.as_ptr()) + } } impl InternedCompare for [T] { @@ -275,6 +282,9 @@ impl InternedCompare for [T] { fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(this) } + fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey { + PtrEqWithMetadata(this.as_ptr()) + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -285,6 +295,9 @@ impl InternedCompare for BitSlice { fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { BitSlicePtrEq(this.as_bitptr(), this.len()) } + fn interned_compare_key_weak(_this: &std::sync::Weak) -> Self::InternedCompareKey { + unreachable!("not currently implementable since Weak can't be constructed") + } } impl InternedCompare for str { @@ -292,103 +305,341 @@ impl InternedCompare for str { fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { PtrEqWithMetadata(this) } -} - -pub trait Intern: Any + Send + Sync { - fn intern(&self) -> Interned; - fn intern_sized(self) -> Interned - where - Self: Clone, - { - Self::intern_owned(self) - } - fn intern_owned(this: ::Owned) -> Interned - where - Self: ToOwned, - { - Self::intern_cow(Cow::Owned(this)) - } - fn intern_cow(this: Cow<'_, Self>) -> Interned - where - Self: ToOwned, - { - this.intern() + fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey { + PtrEqWithMetadata(this.as_ptr()) } } -struct InternerState { - table: HashTable<&'static T>, - hasher: DefaultBuildHasher, +pub trait InternContext: 'static + Send + Sync + Hash + Ord + fmt::Debug + Clone { + type InternedImpl: 'static + Send + Sync + Clone; + type InternedGuardImpl: 'static + + Send + + Sync + + Clone + + Borrow; + type AllContextsAreIdentical: GenericConstBool; + fn interned_compare_key( + v: &Self::InternedImpl, + ) -> T::InternedCompareKey { + T::interned_compare_key_ref(Self::guard(v).borrow()) + } + fn guard( + v: &Self::InternedImpl, + ) -> Self::InternedGuardImpl; + fn try_guard( + v: &Self::InternedImpl, + ) -> Option>; + fn into_guard( + v: Self::InternedImpl, + ) -> Self::InternedGuardImpl { + Self::guard(&v) + } + fn unguard( + v: &Self::InternedGuardImpl, + ) -> Self::InternedImpl; + fn unguard_move( + v: Self::InternedGuardImpl, + ) -> Self::InternedImpl { + Self::unguard(&v) + } + fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl; + fn alloc_slice( + &self, + value: Cow<'_, [T]>, + ) -> Self::InternedGuardImpl<[T]>; + fn alloc_sized( + &self, + value: Cow<'_, T>, + ) -> Self::InternedGuardImpl; + fn interner(&self) -> &Interner; } -pub struct Interner { - state: Mutex>, +pub trait BitSliceInternContext: InternContext { + fn alloc_bit_slice(&self, value: Cow<'_, BitSlice>) -> Self::InternedGuardImpl; } -impl Interner { - fn get() -> &'static Interner { +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] +pub struct GlobalContext; + +impl InternContext for GlobalContext { + type InternedImpl = &'static T; + type InternedGuardImpl = &'static T; + type AllContextsAreIdentical = ConstBool; + + fn guard( + v: &Self::InternedImpl, + ) -> Self::InternedGuardImpl { + *v + } + fn try_guard( + v: &Self::InternedImpl, + ) -> Option> { + Some(*v) + } + fn unguard( + v: &Self::InternedGuardImpl, + ) -> Self::InternedImpl { + *v + } + fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl { + value.into_owned().leak() + } + fn alloc_slice( + &self, + value: Cow<'_, [T]>, + ) -> Self::InternedGuardImpl<[T]> { + value.into_owned().leak() + } + fn alloc_sized( + &self, + value: Cow<'_, T>, + ) -> Self::InternedGuardImpl { + Box::leak(Box::new(value.into_owned())) + } + fn interner(&self) -> &Interner { static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); TYPE_ID_MAP.get_or_insert_default() } } -impl Default for Interner { +impl BitSliceInternContext for GlobalContext { + fn alloc_bit_slice(&self, value: Cow<'_, BitSlice>) -> Self::InternedGuardImpl { + value.into_owned().leak() + } +} + +#[derive(Clone)] +pub struct AGCContext(std::sync::Arc); + +impl AGCContext { + pub fn new() -> Self { + Self(std::sync::Arc::new(TypeIdMap::new())) + } +} + +impl Default for AGCContext { + fn default() -> Self { + Self::new() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AGCContextId(*const ()); + +impl fmt::Debug for AGCContextId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl AGCContext { + pub fn id(&self) -> AGCContextId { + AGCContextId(std::sync::Arc::as_ptr(&self.0).cast()) + } +} + +impl Hash for AGCContext { + fn hash(&self, state: &mut H) { + self.id().hash(state); + } +} + +impl Ord for AGCContext { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialOrd for AGCContext { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Eq for AGCContext {} + +impl PartialEq for AGCContext { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl fmt::Debug for AGCContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AGCContext") + .field("id", &self.id()) + .finish_non_exhaustive() + } +} + +impl InternContext for AGCContext { + type InternedImpl = std::sync::Weak; + type InternedGuardImpl = std::sync::Arc; + type AllContextsAreIdentical = ConstBool; + + fn interned_compare_key( + v: &Self::InternedImpl, + ) -> T::InternedCompareKey { + T::interned_compare_key_weak(v) + } + fn guard( + v: &Self::InternedImpl, + ) -> Self::InternedGuardImpl { + v.upgrade().expect("expired") + } + fn try_guard( + v: &Self::InternedImpl, + ) -> Option> { + v.upgrade() + } + fn unguard( + v: &Self::InternedGuardImpl, + ) -> Self::InternedImpl { + std::sync::Arc::downgrade(v) + } + fn alloc_str(&self, value: Cow<'_, str>) -> Self::InternedGuardImpl { + match value { + Cow::Borrowed(value) => value.into(), + Cow::Owned(value) => value.into(), + } + } + fn alloc_slice( + &self, + value: Cow<'_, [T]>, + ) -> Self::InternedGuardImpl<[T]> { + match value { + Cow::Borrowed(value) => value.into(), + Cow::Owned(value) => value.into(), + } + } + fn alloc_sized( + &self, + value: Cow<'_, T>, + ) -> Self::InternedGuardImpl { + std::sync::Arc::new(value.into_owned()) + } + fn interner(&self) -> &Interner { + self.0.get_or_insert_default() + } +} + +pub trait Intern: Any + Send + Sync { + fn intern_with_ctx(&self, context: &C) -> Interned; + fn intern_sized_with_ctx(self, context: &C) -> Interned + where + Self: Clone, + { + Self::intern_owned_with_ctx(self, context) + } + fn intern_owned_with_ctx(this: ::Owned, context: &C) -> Interned + where + Self: ToOwned, + { + Self::intern_cow_with_ctx(Cow::Owned(this), context) + } + fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned + where + Self: ToOwned, + { + this.intern_with_ctx(context) + } + fn intern(&self) -> Interned + where + C: InternContext> + Default, + { + self.intern_with_ctx(&C::default()) + } + fn intern_sized(self) -> Interned + where + Self: Clone, + C: InternContext> + Default, + { + self.intern_sized_with_ctx(&C::default()) + } + fn intern_owned(this: ::Owned) -> Interned + where + Self: ToOwned, + C: InternContext> + Default, + { + Self::intern_owned_with_ctx(this, &C::default()) + } + fn intern_cow(this: Cow<'_, Self>) -> Interned + where + Self: ToOwned, + C: InternContext> + Default, + { + Self::intern_cow_with_ctx(this, &C::default()) + } +} + +pub struct Interner { + map: Mutex, ()>>, + _phantom: PhantomData, +} + +impl Default for Interner { fn default() -> Self { Self { - state: Mutex::new(InternerState { - table: HashTable::new(), - hasher: Default::default(), - }), + map: Default::default(), + _phantom: Default::default(), } } } -impl Interner { - fn intern) -> &'static T>( +impl Interner { + fn intern) -> C::InternedGuardImpl>( &self, alloc: F, value: Cow<'_, T>, - ) -> Interned { - let mut state = self.state.lock().unwrap(); - let InternerState { table, hasher } = &mut *state; - let inner = *table - .entry( - hasher.hash_one(&*value), - |k| **k == *value, - |k| hasher.hash_one(&**k), - ) - .or_insert_with(|| alloc(value)) - .get(); - Interned { inner } + ) -> Interned { + let mut map = self.map.lock().unwrap(); + let hasher = map.hasher().clone(); + let hash = hasher.hash_one(&*value); + let inner = match map + .raw_entry_mut() + .from_hash(hash, |k| k.borrow() == &*value) + { + RawEntryMut::Occupied(entry) => C::unguard(entry.key()), + RawEntryMut::Vacant(entry) => C::unguard( + entry + .insert_with_hasher(hash, alloc(value), (), |k| hasher.hash_one(k.borrow())) + .0, + ), + }; + Interned { + inner, + _phantom: PhantomData, + } } } -impl Interner { - fn intern_sized(&self, value: Cow<'_, T>) -> Interned { - self.intern(|value| Box::leak(Box::new(value.into_owned())), value) +impl Interner { + fn intern_sized(&self, context: &C, value: Cow<'_, T>) -> Interned { + self.intern(|value| context.alloc_sized(value), value) } } -impl Interner<[T]> { - fn intern_slice(&self, value: Cow<'_, [T]>) -> Interned<[T]> { - self.intern(|value| value.into_owned().leak(), value) +impl Interner<[T], C> { + fn intern_slice(&self, context: &C, value: Cow<'_, [T]>) -> Interned<[T], C> { + self.intern(|value| context.alloc_slice(value), value) } } -impl Interner { - fn intern_bit_slice(&self, value: Cow<'_, BitSlice>) -> Interned { - self.intern(|value| value.into_owned().leak(), value) +impl Interner { + fn intern_bit_slice(&self, context: &C, value: Cow<'_, BitSlice>) -> Interned { + self.intern(|value| context.alloc_bit_slice(value), value) } } -impl Interner { - fn intern_str(&self, value: Cow<'_, str>) -> Interned { - self.intern(|value| value.into_owned().leak(), value) +impl Interner { + fn intern_str(&self, context: &C, value: Cow<'_, str>) -> Interned { + self.intern(|value| context.alloc_str(value), value) } } -pub struct Interned { - inner: &'static T, +pub struct Interned { + inner: C::InternedImpl, + _phantom: PhantomData<&'static C>, } macro_rules! forward_fmt_trait { @@ -399,9 +650,23 @@ macro_rules! forward_fmt_trait { } } - impl fmt::$Tr for Interned { + impl fmt::$Tr + for Interned + { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) + if let Some(guard) = C::try_guard(&self.inner) { + guard.borrow().fmt(f) + } else { + write!(f, "") + } + } + } + + impl fmt::$Tr + for Guard + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.borrow().fmt(f) } } }; @@ -417,16 +682,18 @@ forward_fmt_trait!(UpperExp); forward_fmt_trait!(UpperHex); #[derive(Clone, Debug)] -pub struct InternedSliceIter { - slice: Interned<[T]>, +pub struct InternedSliceIter { + slice: Interned<[T], C>, index: std::ops::Range, } -impl Iterator for InternedSliceIter { +impl Iterator for InternedSliceIter { type Item = T; fn next(&mut self) -> Option { - self.index.next().map(|index| self.slice[index].clone()) + self.index + .next() + .map(|index| self.slice.guard()[index].clone()) } fn size_hint(&self) -> (usize, Option) { @@ -434,186 +701,215 @@ impl Iterator for InternedSliceIter { } } -impl DoubleEndedIterator for InternedSliceIter { +impl DoubleEndedIterator + for InternedSliceIter +{ fn next_back(&mut self) -> Option { self.index .next_back() - .map(|index| self.slice[index].clone()) + .map(|index| self.slice.guard()[index].clone()) } } -impl FusedIterator for InternedSliceIter {} +impl FusedIterator for InternedSliceIter {} -impl ExactSizeIterator for InternedSliceIter {} +impl ExactSizeIterator + for InternedSliceIter +{ +} -impl IntoIterator for Interned<[T]> { +impl IntoIterator for Interned<[T], C> { type Item = T; - type IntoIter = InternedSliceIter; + type IntoIter = InternedSliceIter; fn into_iter(self) -> Self::IntoIter { InternedSliceIter { - index: 0..self.len(), + index: 0..self.guard().len(), slice: self, } } } -impl<'a, T: 'static + Send + Sync> IntoIterator for &'a Interned<[T]> { - type Item = &'a T; - type IntoIter = std::slice::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.inner.iter() - } -} - -impl<'a, T: 'static + Send + Sync> IntoIterator for &'a mut Interned<[T]> { - type Item = &'a T; - type IntoIter = std::slice::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.inner.iter() - } -} - -impl FromIterator for Interned<[I]> +impl<'a, T: 'static + Send + Sync, C: InternContext> IntoIterator for &'a Interned<[T], C> where - [I]: Intern, + C::InternedImpl<[T]>: Borrow<[T]>, +{ + type Item = &'a T; + type IntoIter = std::slice::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.inner.borrow().iter() + } +} + +impl<'a, T: 'static + Send + Sync, C: InternContext> IntoIterator for &'a mut Interned<[T], C> +where + C::InternedImpl<[T]>: Borrow<[T]>, +{ + type Item = &'a T; + type IntoIter = std::slice::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.inner.borrow().iter() + } +} + +impl> + Default> + FromIterator for Interned<[I], C> +where + [I]: Intern, { fn from_iter>(iter: T) -> Self { Intern::intern_owned(Vec::from_iter(iter)) } } -impl From> for Vec { - fn from(value: Interned<[T]>) -> Self { - Vec::from(&*value) - } -} - -impl From> for Box<[T]> { - fn from(value: Interned<[T]>) -> Self { - Box::from(&*value) - } -} - -impl From> for String { - fn from(value: Interned) -> Self { - String::from(&*value) - } -} - -impl Default for Interned<[I]> +impl> + Default> Default + for Interned<[I], C> where - [I]: Intern, + [I]: Intern, { fn default() -> Self { [][..].intern() } } -impl Default for Interned { +impl> + Default> Default + for Interned +where + str: Intern, +{ fn default() -> Self { "".intern() } } -impl Default for Interned { +impl> + Default> Default + for Interned +where + BitSlice: Intern, +{ fn default() -> Self { <&BitSlice>::default().intern() } } -impl Default for Interned +impl> + Default> + Default for Interned where - I: Intern, + I: Intern, { fn default() -> Self { I::default().intern() } } -impl Interned { +impl Interned { pub fn cast_unchecked( this: Self, - f: impl FnOnce(&'static T) -> &'static U, - ) -> Interned { + f: impl FnOnce(C::InternedImpl) -> C::InternedImpl, + ) -> Interned { Interned { inner: f(this.inner), + _phantom: PhantomData, } } pub fn try_cast_unchecked( this: Self, - f: impl FnOnce(&'static T) -> Result<&'static U, E>, - ) -> Result, E> { + f: impl FnOnce(C::InternedImpl) -> Result, E>, + ) -> Result, E> { Ok(Interned { inner: f(this.inner)?, + _phantom: PhantomData, }) } - pub fn into_inner(this: Self) -> &'static T { + pub fn into_inner(this: Self) -> C::InternedImpl { this.inner } - pub fn get_ref(this: &Self) -> &&'static T { + pub fn get_ref(this: &Self) -> &C::InternedImpl { &this.inner } -} - -impl Clone for Interned { - fn clone(&self) -> Self { - *self + pub fn guard(&self) -> Guard { + Guard { + inner: C::guard(&self.inner), + _phantom: PhantomData, + } } } -impl Copy for Interned where &'static T: Copy {} +impl Clone for Interned { + fn clone(&self) -> Self { + Interned { + inner: self.inner.clone(), + _phantom: PhantomData, + } + } +} -impl Deref for Interned +impl Copy for Interned where + C::InternedImpl: Copy +{ +} + +impl Deref for Interned where - &'static T: Borrow, + C::InternedImpl: Borrow, { type Target = T; fn deref(&self) -> &Self::Target { - self.inner + self.inner.borrow() } } -impl PartialEq for Interned { +impl PartialEq + for Interned +{ fn eq(&self, other: &Self) -> bool { - T::interned_compare_key_ref(self.inner) == T::interned_compare_key_ref(other.inner) + ::interned_compare_key(&self.inner) + == ::interned_compare_key(&other.inner) } } -impl Eq for Interned {} +impl Eq for Interned {} -impl PartialOrd for Interned { +impl PartialOrd + for Interned +{ fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for Interned { +impl Ord for Interned { fn cmp(&self, other: &Self) -> Ordering { - T::interned_compare_key_ref(self.inner).cmp(&T::interned_compare_key_ref(other.inner)) + ::interned_compare_key(&self.inner) + .cmp(&::interned_compare_key(&other.inner)) } } -impl Hash for Interned { +impl Hash + for Interned +{ fn hash(&self, state: &mut H) { - T::interned_compare_key_ref(self.inner).hash(state); + ::interned_compare_key(&self.inner).hash(state); } } -impl Serialize for Interned { +impl Serialize for Interned { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - T::serialize(self, serializer) + self.guard().serialize(serializer) } } -impl<'de, T: 'static + Send + Sync + Deserialize<'de> + Clone + Intern> Deserialize<'de> - for Interned +impl< + 'de, + T: 'static + Send + Sync + Deserialize<'de> + Clone + Intern, + C: InternContext> + Default, + > Deserialize<'de> for Interned { fn deserialize(deserializer: D) -> Result where @@ -623,9 +919,13 @@ impl<'de, T: 'static + Send + Sync + Deserialize<'de> + Clone + Intern> Deserial } } -impl<'de, T: 'static + Send + Sync + Clone> Deserialize<'de> for Interned<[T]> +impl< + 'de, + T: 'static + Send + Sync + Clone, + C: InternContext> + Default, + > Deserialize<'de> for Interned<[T], C> where - [T]: Intern, + [T]: Intern, Vec: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result @@ -636,7 +936,11 @@ where } } -impl<'de> Deserialize<'de> for Interned { +impl<'de, C: BitSliceInternContext> + Default> + Deserialize<'de> for Interned +where + BitSlice: Intern, +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -645,7 +949,11 @@ impl<'de> Deserialize<'de> for Interned { } } -impl<'de> Deserialize<'de> for Interned { +impl<'de, C: InternContext> + Default> Deserialize<'de> + for Interned +where + str: Intern, +{ fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -654,83 +962,175 @@ impl<'de> Deserialize<'de> for Interned { } } -impl Intern for T { - fn intern(&self) -> Interned { - Self::intern_cow(Cow::Borrowed(self)) - } +pub struct Guard { + inner: C::InternedGuardImpl, + _phantom: PhantomData<&'static C>, +} - fn intern_owned(this: ::Owned) -> Interned - where - Self: ToOwned, - { - Self::intern_cow(Cow::Owned(this)) +impl Guard { + pub fn cast_unchecked( + this: Self, + f: impl FnOnce(C::InternedGuardImpl) -> C::InternedGuardImpl, + ) -> Guard { + Guard { + inner: f(this.inner), + _phantom: PhantomData, + } } - - fn intern_cow(this: Cow<'_, Self>) -> Interned - where - Self: ToOwned, - { - Interner::get().intern_sized(this) + pub fn try_cast_unchecked( + this: Self, + f: impl FnOnce(C::InternedGuardImpl) -> Result, E>, + ) -> Result, E> { + Ok(Guard { + inner: f(this.inner)?, + _phantom: PhantomData, + }) + } + pub fn into_inner(this: Self) -> C::InternedGuardImpl { + this.inner + } + pub fn get_ref(this: &Self) -> &C::InternedGuardImpl { + &this.inner + } + pub fn unguard(&self) -> Interned { + Interned { + inner: C::unguard(&self.inner), + _phantom: PhantomData, + } } } -impl Intern for [T] { - fn intern(&self) -> Interned { - Self::intern_cow(Cow::Borrowed(self)) - } - - fn intern_owned(this: ::Owned) -> Interned - where - Self: ToOwned, - { - Self::intern_cow(Cow::Owned(this)) - } - - fn intern_cow(this: Cow<'_, Self>) -> Interned - where - Self: ToOwned, - { - Interner::get().intern_slice(this) +impl Clone for Guard { + fn clone(&self) -> Self { + Guard { + inner: self.inner.clone(), + _phantom: PhantomData, + } } } -impl Intern for BitSlice { - fn intern(&self) -> Interned { - Self::intern_cow(Cow::Borrowed(self)) - } +impl Copy for Guard where + C::InternedGuardImpl: Copy +{ +} - fn intern_owned(this: ::Owned) -> Interned - where - Self: ToOwned, - { - Self::intern_cow(Cow::Owned(this)) - } +impl Deref for Guard { + type Target = T; - fn intern_cow(this: Cow<'_, Self>) -> Interned - where - Self: ToOwned, - { - Interner::get().intern_bit_slice(this) + fn deref(&self) -> &Self::Target { + self.inner.borrow() } } -impl Intern for str { - fn intern(&self) -> Interned { - Self::intern_cow(Cow::Borrowed(self)) +impl PartialEq + for Guard +{ + fn eq(&self, other: &Self) -> bool { + T::interned_compare_key_ref(self.inner.borrow()) + == T::interned_compare_key_ref(other.inner.borrow()) + } +} + +impl Eq for Guard {} + +impl PartialOrd + for Guard +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Guard { + fn cmp(&self, other: &Self) -> Ordering { + T::interned_compare_key_ref(self.inner.borrow()) + .cmp(&T::interned_compare_key_ref(other.inner.borrow())) + } +} + +impl Hash for Guard { + fn hash(&self, state: &mut H) { + T::interned_compare_key_ref(self.inner.borrow()).hash(state); + } +} + +impl Intern for T { + fn intern_with_ctx(&self, context: &C) -> Interned { + Self::intern_cow_with_ctx(Cow::Borrowed(self), context) } - fn intern_owned(this: ::Owned) -> Interned + fn intern_owned_with_ctx(this: ::Owned, context: &C) -> Interned where Self: ToOwned, { - Self::intern_cow(Cow::Owned(this)) + Self::intern_cow_with_ctx(Cow::Owned(this), context) } - fn intern_cow(this: Cow<'_, Self>) -> Interned + fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned where Self: ToOwned, { - Interner::get().intern_str(this) + context.interner().intern_sized(context, this) + } +} + +impl Intern for [T] { + fn intern_with_ctx(&self, context: &C) -> Interned { + Self::intern_cow_with_ctx(Cow::Borrowed(self), context) + } + + fn intern_owned_with_ctx(this: ::Owned, context: &C) -> Interned + where + Self: ToOwned, + { + Self::intern_cow_with_ctx(Cow::Owned(this), context) + } + + fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned + where + Self: ToOwned, + { + context.interner().intern_slice(context, this) + } +} + +impl Intern for BitSlice { + fn intern_with_ctx(&self, context: &C) -> Interned { + Self::intern_cow_with_ctx(Cow::Borrowed(self), context) + } + + fn intern_owned_with_ctx(this: ::Owned, context: &C) -> Interned + where + Self: ToOwned, + { + Self::intern_cow_with_ctx(Cow::Owned(this), context) + } + + fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned + where + Self: ToOwned, + { + context.interner().intern_bit_slice(context, this) + } +} + +impl Intern for str { + fn intern_with_ctx(&self, context: &C) -> Interned { + Self::intern_cow_with_ctx(Cow::Borrowed(self), context) + } + + fn intern_owned_with_ctx(this: ::Owned, context: &C) -> Interned + where + Self: ToOwned, + { + Self::intern_cow_with_ctx(Cow::Owned(this), context) + } + + fn intern_cow_with_ctx(this: Cow<'_, Self>, context: &C) -> Interned + where + Self: ToOwned, + { + context.interner().intern_str(context, this) } } @@ -749,7 +1149,7 @@ pub trait MemoizeGeneric: 'static + Send + Sync + Hash + Eq + Copy { fn get_cow(self, input: Self::InputCow<'_>) -> Self::Output { static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); let map: &RwLock<( - DefaultBuildHasher, + hashbrown::hash_map::DefaultHashBuilder, HashTable<(Self, Self::InputOwned, Self::Output)>, )> = TYPE_ID_MAP.get_or_insert_default(); fn hash_eq_key<'a, 'b, T: MemoizeGeneric>( diff --git a/crates/fayalite/src/intern/type_map.rs b/crates/fayalite/src/intern/type_map.rs index 945116b..48433af 100644 --- a/crates/fayalite/src/intern/type_map.rs +++ b/crates/fayalite/src/intern/type_map.rs @@ -1,8 +1,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +use hashbrown::HashMap; use std::{ any::{Any, TypeId}, hash::{BuildHasher, Hasher}, + ptr::NonNull, sync::RwLock, }; @@ -73,36 +75,59 @@ impl BuildHasher for TypeIdBuildHasher { } } -pub(crate) struct TypeIdMap( - RwLock>, -); +struct Value(NonNull); + +impl Value { + unsafe fn get_transmute_lifetime<'b>(&self) -> &'b (dyn Any + Send + Sync) { + unsafe { &*self.0.as_ptr() } + } + fn new(v: Box) -> Self { + unsafe { Self(NonNull::new_unchecked(Box::into_raw(v))) } + } +} + +unsafe impl Send for Value {} +unsafe impl Sync for Value {} + +impl Drop for Value { + fn drop(&mut self) { + unsafe { std::ptr::drop_in_place(self.0.as_ptr()) } + } +} + +pub struct TypeIdMap(RwLock>); impl TypeIdMap { - pub(crate) const fn new() -> Self { - Self(RwLock::new(hashbrown::HashMap::with_hasher( - TypeIdBuildHasher, - ))) + pub const fn new() -> Self { + Self(RwLock::new(HashMap::with_hasher(TypeIdBuildHasher))) } #[cold] - fn insert_slow( + unsafe fn insert_slow( &self, type_id: TypeId, make: fn() -> Box, - ) -> &'static (dyn Any + Sync + Send) { - let value = Box::leak(make()); + ) -> &(dyn Any + Sync + Send) { + let value = Value::new(make()); let mut write_guard = self.0.write().unwrap(); - *write_guard.entry(type_id).or_insert(value) + unsafe { + write_guard + .entry(type_id) + .or_insert(value) + .get_transmute_lifetime() + } } - pub(crate) fn get_or_insert_default(&self) -> &T { + pub fn get_or_insert_default(&self) -> &T { let type_id = TypeId::of::(); let read_guard = self.0.read().unwrap(); - let retval = read_guard.get(&type_id).map(|v| *v); + let retval = read_guard + .get(&type_id) + .map(|v| unsafe { Value::get_transmute_lifetime(v) }); drop(read_guard); let retval = match retval { Some(retval) => retval, - None => self.insert_slow(type_id, move || Box::new(T::default())), + None => unsafe { self.insert_slow(type_id, move || Box::new(T::default())) }, }; - retval.downcast_ref().expect("known to have correct TypeId") + unsafe { &*(retval as *const dyn Any as *const T) } } } diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index 932464b..83b61b2 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -11,59 +11,6 @@ extern crate self as fayalite; #[doc(hidden)] pub use std as __std; -#[doc(hidden)] -#[macro_export] -macro_rules! __cfg_expansion_helper { - ( - [ - $($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)* - ] - [ - $cfg:ident($($expr:tt)*), - $($unevaluated_cfgs:ident($($unevaluated_exprs:tt)*),)* - ] - // pass as tt so we get right span for attribute - $after_evaluation_attr:tt $after_evaluation_body:tt - ) => { - #[$cfg($($expr)*)] - $crate::__cfg_expansion_helper! { - [ - $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* - $cfg($($expr)*) = true, - ] - [ - $($unevaluated_cfgs($($unevaluated_exprs)*),)* - ] - $after_evaluation_attr $after_evaluation_body - } - #[$cfg(not($($expr)*))] - $crate::__cfg_expansion_helper! { - [ - $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* - $cfg($($expr)*) = false, - ] - [ - $($unevaluated_cfgs($($unevaluated_exprs)*),)* - ] - $after_evaluation_attr $after_evaluation_body - } - }; - ( - [ - $($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)* - ] - [] - // don't use #[...] so we get right span for `#` and `[]` of attribute - {$($after_evaluation_attr:tt)*} {$($after_evaluation_body:tt)*} - ) => { - $($after_evaluation_attr)* - #[__evaluated_cfgs([ - $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* - ])] - $($after_evaluation_body)* - }; -} - #[doc(inline)] /// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates /// a [`Module`][`::fayalite::module::Module`] when called. @@ -76,8 +23,6 @@ pub use fayalite_proc_macros::hdl_module; #[doc(inline)] pub use fayalite_proc_macros::hdl; -pub use bitvec; - /// struct used as a placeholder when applying defaults #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct __; @@ -85,6 +30,7 @@ pub struct __; #[cfg(feature = "unstable-doc")] pub mod _docs; +// FIXME: finish pub mod annotations; pub mod array; pub mod bundle; @@ -93,18 +39,15 @@ pub mod clock; pub mod enum_; pub mod expr; pub mod firrtl; -pub mod formal; pub mod int; pub mod intern; pub mod memory; pub mod module; -pub mod phantom_const; -pub mod prelude; pub mod reg; pub mod reset; -pub mod sim; pub mod source_location; -pub mod testing; pub mod ty; pub mod util; +//pub mod valueless; +pub mod prelude; pub mod wire; diff --git a/crates/fayalite/src/memory.rs b/crates/fayalite/src/memory.rs index 622ffc6..e6bbea5 100644 --- a/crates/fayalite/src/memory.rs +++ b/crates/fayalite/src/memory.rs @@ -7,7 +7,7 @@ use crate::{ array::{Array, ArrayType}, bundle::{Bundle, BundleType}, clock::Clock, - expr::{ops::BundleLiteral, repeat, Expr, Flow, ToExpr, ToLiteralBits}, + expr::{Expr, Flow, ToExpr, ToLiteralBits}, hdl, int::{Bool, DynSize, Size, UInt, UIntType}, intern::{Intern, Interned}, @@ -22,7 +22,7 @@ use std::{ fmt, hash::{Hash, Hasher}, marker::PhantomData, - num::NonZeroUsize, + num::NonZeroU32, rc::Rc, }; @@ -470,7 +470,7 @@ pub enum ReadUnderWrite { Undefined, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] struct MemImpl { scoped_name: ScopedNameId, source_location: SourceLocation, @@ -478,7 +478,7 @@ struct MemImpl { initial_value: Option>, ports: P, read_latency: usize, - write_latency: NonZeroUsize, + write_latency: NonZeroU32, read_under_write: ReadUnderWrite, port_annotations: Interned<[TargetedAnnotation]>, mem_annotations: Interned<[Annotation]>, @@ -519,12 +519,7 @@ impl fmt::Debug for Mem { f.debug_struct("Mem") .field("name", scoped_name) .field("array_type", array_type) - .field( - "initial_value", - &initial_value.as_ref().map(|initial_value| { - DebugMemoryData::from_bit_slice(*array_type, initial_value) - }), - ) + .field("initial_value", initial_value) .field("read_latency", read_latency) .field("write_latency", write_latency) .field("read_under_write", read_under_write) @@ -567,7 +562,7 @@ impl Mem { initial_value: Option>, ports: Interned<[MemPort]>, read_latency: usize, - write_latency: NonZeroUsize, + write_latency: NonZeroU32, read_under_write: ReadUnderWrite, port_annotations: Interned<[TargetedAnnotation]>, mem_annotations: Interned<[Annotation]>, @@ -639,7 +634,7 @@ impl Mem { self.0.source_location } pub fn array_type(self) -> ArrayType { - self.0.array_type + self.0.array_type.clone() } pub fn initial_value(self) -> Option> { self.0.initial_value @@ -650,7 +645,7 @@ impl Mem { pub fn read_latency(self) -> usize { self.0.read_latency } - pub fn write_latency(self) -> NonZeroUsize { + pub fn write_latency(self) -> NonZeroU32 { self.0.write_latency } pub fn read_under_write(self) -> ReadUnderWrite { @@ -712,7 +707,7 @@ pub(crate) struct MemBuilderTarget { pub(crate) initial_value: Option>, pub(crate) ports: Vec>, pub(crate) read_latency: usize, - pub(crate) write_latency: NonZeroUsize, + pub(crate) write_latency: NonZeroU32, pub(crate) read_under_write: ReadUnderWrite, pub(crate) port_annotations: Vec, pub(crate) mem_annotations: Vec, @@ -872,7 +867,7 @@ impl MemBuilder { initial_value: None, ports: vec![], read_latency: 0, - write_latency: NonZeroUsize::new(1).unwrap(), + write_latency: NonZeroU32::new(1).unwrap(), read_under_write: ReadUnderWrite::Old, port_annotations: vec![], mem_annotations: vec![], @@ -992,7 +987,7 @@ impl MemBuilder { #[allow(clippy::result_unit_err)] pub fn get_array_type(&self) -> Result, ()> { Ok(ArrayType::new( - self.mem_element_type, + self.mem_element_type.clone(), Len::from_usize(self.get_depth()?), )) } @@ -1035,10 +1030,10 @@ impl MemBuilder { pub fn read_latency(&mut self, read_latency: usize) { self.target.borrow_mut().read_latency = read_latency; } - pub fn get_write_latency(&self) -> NonZeroUsize { + pub fn get_write_latency(&self) -> NonZeroU32 { self.target.borrow().write_latency } - pub fn write_latency(&mut self, write_latency: NonZeroUsize) { + pub fn write_latency(&mut self, write_latency: NonZeroU32) { self.target.borrow_mut().write_latency = write_latency; } pub fn get_read_under_write(&self) -> ReadUnderWrite { @@ -1055,91 +1050,3 @@ impl MemBuilder { .extend(annotations.into_annotations()); } } - -pub fn splat_mask(ty: T, value: Expr) -> Expr> { - let canonical_ty = ty.canonical(); - match canonical_ty { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)), - CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( - splat_mask(array.element(), value), - array.len(), - ))), - CanonicalType::Bundle(bundle) => Expr::from_canonical(Expr::canonical( - BundleLiteral::new( - bundle.mask_type(), - bundle - .fields() - .iter() - .map(|field| splat_mask(field.ty, value)) - .collect(), - ) - .to_expr(), - )), - CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())), - } -} - -pub trait DebugMemoryDataGetElement { - fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice; -} - -impl<'a, F: ?Sized + Fn(usize, Array) -> &'a BitSlice> DebugMemoryDataGetElement for &'a F { - fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice { - self(element_index, array_type) - } -} - -#[derive(Clone)] -pub struct DebugMemoryData { - pub array_type: Array, - pub get_element: GetElement, -} - -impl DebugMemoryDataGetElement for &'_ BitSlice { - fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice { - assert!(element_index < array_type.len()); - let stride = array_type.element().bit_width(); - let start = element_index - .checked_mul(stride) - .expect("memory is too big"); - let end = start.checked_add(stride).expect("memory is too big"); - &self[start..end] - } -} - -impl<'a> DebugMemoryData<&'a BitSlice> { - pub fn from_bit_slice( - array_type: ArrayType, - bit_slice: &'a BitSlice, - ) -> Self { - let array_type = array_type.as_dyn_array(); - assert_eq!(bit_slice.len(), array_type.type_properties().bit_width); - Self { - array_type, - get_element: bit_slice, - } - } -} - -impl fmt::Debug for DebugMemoryData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.array_type.len() == 0 { - return f.write_str("[]"); - } - writeln!(f, "[\n // len = {:#x}", self.array_type.len())?; - for element_index in 0..self.array_type.len() { - let element = crate::util::BitSliceWriteWithBase( - self.get_element.get_element(element_index, self.array_type), - ); - writeln!(f, " [{element_index:#x}]: {element:#x},")?; - } - f.write_str("]") - } -} diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 920b0af..cb57758 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -5,7 +5,7 @@ use crate::{ annotations::{Annotation, IntoAnnotations, TargetedAnnotation}, array::ArrayType, bundle::{Bundle, BundleField, BundleType}, - clock::{Clock, ClockDomain}, + clock::ClockDomain, enum_::{Enum, EnumMatchVariantsIter, EnumType}, expr::{ ops::VariantAccess, @@ -15,34 +15,29 @@ use crate::{ }, Expr, Flow, ToExpr, }, - formal::FormalKind, int::{Bool, DynSize, Size}, intern::{Intern, Interned}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, reg::Reg, - reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, - sim::{ExternModuleSimGenerator, ExternModuleSimulation}, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::{HashMap, HashSet, ScopedRef}, - wire::{IncompleteWire, Wire}, + util::ScopedRef, + wire::Wire, }; -use hashbrown::hash_map::Entry; +use hashbrown::{hash_map::Entry, HashMap, HashSet}; use num_bigint::BigInt; use std::{ cell::RefCell, collections::VecDeque, convert::Infallible, fmt, - future::IntoFuture, hash::{Hash, Hasher}, iter::FusedIterator, marker::PhantomData, mem, - num::NonZeroU64, ops::Deref, rc::Rc, - sync::atomic::AtomicU64, + sync::Mutex, }; pub mod transform; @@ -123,35 +118,9 @@ pub trait BlockRef: 'static + Send + Sync + Copy + Eq + Hash + fmt::Debug {} impl BlockRef for BlockId {} -pub(crate) enum IncompleteDeclaration { - Incomplete { - name: ScopedNameId, - source_location: SourceLocation, - }, - Complete(StmtDeclaration), - Taken, -} - -impl fmt::Debug for IncompleteDeclaration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Incomplete { - name, - source_location: _, - } => f - .debug_struct("Incomplete") - .field("name", name) - .finish_non_exhaustive(), - Self::Complete(v) => v.fmt(f), - Self::Taken => f.write_str("Taken"), - } - } -} - #[derive(Debug)] pub struct BuilderBlock { memories: Vec>>, - incomplete_declarations: Vec>>, stmts: Vec>, } @@ -183,47 +152,13 @@ impl Block { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct StmtConnect { pub lhs: Expr, pub rhs: Expr, pub source_location: SourceLocation, } -impl StmtConnect { - #[track_caller] - fn assert_validity_with_original_types(&self, lhs_orig_ty: impl Type, rhs_orig_ty: impl Type) { - let Self { - lhs, - rhs, - source_location, - } = *self; - assert!( - Expr::ty(lhs).can_connect(Expr::ty(rhs)), - "can't connect types that are not equivalent:\nlhs type:\n{lhs_orig_ty:?}\nrhs type:\n{rhs_orig_ty:?}\nat: {source_location}", - ); - assert!( - matches!(Expr::flow(lhs), Flow::Sink | Flow::Duplex), - "can't connect to source, connect lhs must have sink or duplex flow\nat: {source_location}" - ); - assert!( - lhs.target().is_some(), - "can't connect to non-target\nat: {source_location}" - ); - match Expr::flow(rhs) { - Flow::Source | Flow::Duplex => {} - Flow::Sink => assert!( - Expr::ty(rhs).is_passive(), - "can't connect from sink with non-passive type\nat: {source_location}" - ), - } - } - #[track_caller] - fn assert_validity(&self) { - self.assert_validity_with_original_types(Expr::ty(self.lhs), Expr::ty(self.rhs)); - } -} - impl fmt::Debug for StmtConnect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { @@ -238,48 +173,6 @@ impl fmt::Debug for StmtConnect { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct StmtFormal { - pub kind: FormalKind, - pub clk: Expr, - pub pred: Expr, - pub en: Expr, - pub text: Interned, - pub source_location: SourceLocation, -} - -impl fmt::Debug for StmtFormal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - kind, - clk, - pred, - en, - text, - source_location: _, - } = self; - f.debug_struct(kind.as_str()) - .field("clk", clk) - .field("pred", pred) - .field("en", en) - .field("text", text) - .finish_non_exhaustive() - } -} - -#[track_caller] -pub(crate) fn add_stmt_formal(formal: StmtFormal) { - ModuleBuilder::with(|m| { - m.impl_ - .borrow_mut() - .body - .builder_normal_body() - .block(m.block_stack.top()) - .stmts - .push(formal.into()); - }); -} - #[derive(Clone, PartialEq, Eq, Hash)] pub struct StmtIf { pub cond: Expr, @@ -287,8 +180,6 @@ pub struct StmtIf { pub blocks: [S::Block; 2], } -impl Copy for StmtIf {} - impl StmtIf { pub fn then_block(&self) -> S::Block { self.blocks[0] @@ -320,15 +211,6 @@ pub struct StmtMatch { pub blocks: Interned<[S::Block]>, } -impl Copy for StmtMatch {} - -impl StmtMatch { - #[track_caller] - fn assert_validity(&self) { - assert_eq!(Expr::ty(self.expr).variants().len(), self.blocks.len()); - } -} - impl fmt::Debug for StmtMatch { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { @@ -353,7 +235,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -365,7 +247,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta])* $vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $( - #[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?] + #[is = $is_fn, as_ref = $as_ref_fn] $(#[$variant_meta])* $Variant($VariantTy), )* @@ -392,7 +274,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -404,22 +286,22 @@ macro_rules! wrapper_enum { $(#[$enum_meta])* $vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> { $( - #[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?] + #[is = $is_fn, as_ref = $as_ref_fn] $(#[$variant_meta])* $Variant($VariantTy), )* } } - $($( + $( wrapper_enum! { impl $T_to From<$VariantTy> for $to_type { - fn $from(value: $VariantTy) -> Self { + fn from(value: $VariantTy) -> Self { $enum_name::$Variant(value).into() } } } - )?)* + )* }; ( #[impl()] @@ -427,7 +309,7 @@ macro_rules! wrapper_enum { $(#[$enum_meta:meta])* $vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> { $( - #[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?] + #[is = $is_fn:ident, as_ref = $as_ref_fn:ident] $(#[$variant_meta:meta])* $Variant:ident($VariantTy:ty), )* @@ -466,15 +348,13 @@ pub struct StmtWire { pub wire: Wire, } -impl Copy for StmtWire {} - #[derive(Hash, Clone, PartialEq, Eq, Debug)] -pub struct StmtReg { +pub struct StmtReg { pub annotations: S::StmtAnnotations, - pub reg: Reg, + pub reg: Reg, } -impl Copy for StmtReg {} +impl Copy for StmtReg {} #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct StmtInstance { @@ -482,8 +362,6 @@ pub struct StmtInstance { pub instance: Instance, } -impl Copy for StmtInstance {} - wrapper_enum! { #[impl( () self: StmtDeclaration = self, @@ -492,57 +370,20 @@ wrapper_enum! { #[to(() StmtDeclaration, () Stmt)] #[derive(Clone, PartialEq, Eq, Hash)] pub enum StmtDeclaration { - #[is = is_wire, as_ref = wire, from = from] + #[is = is_wire, as_ref = wire] Wire(StmtWire), #[is = is_reg, as_ref = reg] - Reg(StmtReg), - #[is = is_reg_sync, as_ref = reg_sync] - RegSync(StmtReg), - #[is = is_reg_async, as_ref = reg_async] - RegAsync(StmtReg), - #[is = is_instance, as_ref = instance, from = from] + Reg(StmtReg), + #[is = is_instance, as_ref = instance] Instance(StmtInstance), } } -impl Copy for StmtDeclaration {} - -impl From> for Stmt { - fn from(value: StmtReg) -> Self { - StmtDeclaration::from(value).into() - } -} - -impl From> for StmtDeclaration { - fn from(value: StmtReg) -> Self { - struct Dispatch(PhantomData); - impl ResetTypeDispatch for Dispatch { - type Input = StmtReg; - type Output = StmtDeclaration; - - fn reset(self, input: Self::Input) -> Self::Output { - StmtDeclaration::Reg(input) - } - - fn sync_reset(self, input: Self::Input) -> Self::Output { - StmtDeclaration::RegSync(input) - } - - fn async_reset(self, input: Self::Input) -> Self::Output { - StmtDeclaration::RegAsync(input) - } - } - R::dispatch(value, Dispatch(PhantomData)) - } -} - impl StmtDeclaration { pub fn annotations(&self) -> S::StmtAnnotations { match self { StmtDeclaration::Wire(v) => v.annotations, StmtDeclaration::Reg(v) => v.annotations, - StmtDeclaration::RegSync(v) => v.annotations, - StmtDeclaration::RegAsync(v) => v.annotations, StmtDeclaration::Instance(v) => v.annotations, } } @@ -550,8 +391,6 @@ impl StmtDeclaration { match self { StmtDeclaration::Wire(v) => v.wire.source_location(), StmtDeclaration::Reg(v) => v.reg.source_location(), - StmtDeclaration::RegSync(v) => v.reg.source_location(), - StmtDeclaration::RegAsync(v) => v.reg.source_location(), StmtDeclaration::Instance(v) => v.instance.source_location(), } } @@ -559,26 +398,20 @@ impl StmtDeclaration { match self { StmtDeclaration::Wire(v) => v.wire.scoped_name(), StmtDeclaration::Reg(v) => v.reg.scoped_name(), - StmtDeclaration::RegSync(v) => v.reg.scoped_name(), - StmtDeclaration::RegAsync(v) => v.reg.scoped_name(), StmtDeclaration::Instance(v) => v.instance.scoped_name(), } } pub fn sub_stmt_blocks(&self) -> &[S::Block] { match self { - StmtDeclaration::Wire(_) - | StmtDeclaration::Reg(_) - | StmtDeclaration::RegSync(_) - | StmtDeclaration::RegAsync(_) - | StmtDeclaration::Instance(_) => &[], + StmtDeclaration::Wire(_) | StmtDeclaration::Reg(_) | StmtDeclaration::Instance(_) => { + &[] + } } } pub fn canonical_ty(&self) -> CanonicalType { match self { StmtDeclaration::Wire(v) => v.wire.ty(), StmtDeclaration::Reg(v) => v.reg.ty(), - StmtDeclaration::RegSync(v) => v.reg.ty(), - StmtDeclaration::RegAsync(v) => v.reg.ty(), StmtDeclaration::Instance(v) => CanonicalType::Bundle(v.instance.ty()), } } @@ -589,25 +422,21 @@ wrapper_enum! { #[to(() Stmt)] #[derive(Clone, PartialEq, Eq, Hash)] pub enum Stmt { - #[is = is_connect, as_ref = connect, from = from] + #[is = is_connect, as_ref = connect] Connect(StmtConnect), - #[is = is_formal, as_ref = formal, from = from] - Formal(StmtFormal), - #[is = is_if, as_ref = if_, from = from] + #[is = is_if, as_ref = if_] If(StmtIf), - #[is = is_match, as_ref = match_, from = from] + #[is = is_match, as_ref = match_] Match(StmtMatch), - #[is = is_declaration, as_ref = declaration, from = from] + #[is = is_declaration, as_ref = declaration] Declaration(StmtDeclaration), } } -impl Copy for Stmt {} - impl Stmt { pub fn sub_stmt_blocks(&self) -> &[S::Block] { match self { - Stmt::Connect(_) | Stmt::Formal(_) => &[], + Stmt::Connect(_) => &[], Stmt::If(v) => &v.blocks, Stmt::Match(v) => &v.blocks, Stmt::Declaration(v) => v.sub_stmt_blocks(), @@ -661,50 +490,8 @@ impl BlockStack { } } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct Id(NonZeroU64); - -impl Id { - // returns a different value each time, so there isn't really a default value - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - static NEXT_ID: AtomicU64 = AtomicU64::new(1); - Self( - NonZeroU64::new(NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) - .expect("Id::new ran out of ids"), - ) - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct NameOptId(pub Interned, pub Option); - -impl fmt::Debug for NameOptId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for NameOptId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.0) - } -} - -impl From> for NameOptId { - fn from(name: Interned) -> Self { - Self(name, None) - } -} - -impl From for NameOptId { - fn from(name_id: NameId) -> Self { - Self(name_id.0, Some(name_id.1)) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct NameId(pub Interned, pub Id); +pub struct NameId(pub Interned, pub usize); impl fmt::Debug for NameId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -714,7 +501,13 @@ impl fmt::Debug for NameId { impl fmt::Display for NameId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.0) + if self.0.is_empty() { + write!(f, "{}", self.1) + } else if self.1 == 0 { + f.write_str(&self.0) + } else { + write!(f, "{}_{}", self.0, self.1) + } } } @@ -743,6 +536,98 @@ impl fmt::Debug for TargetName { } } +#[derive(Default)] +pub struct NameIdGen(HashMap, usize>); + +impl NameIdGen { + pub fn gen(&mut self, name: Interned) -> NameId { + let next_id = self.0.entry(name).or_default(); + let id = *next_id; + *next_id += 1; + NameId(name, id) + } + pub fn mark_as_used(&mut self, name_id: NameId) { + let next_id = self.0.entry(name_id.0).or_default(); + *next_id = (*next_id).max(name_id.1 + 1); + } + pub fn for_module(module: Module) -> Self { + let mut retval = Self::default(); + let Module { + name: _, + source_location: _, + body, + io_ty: _, + module_io, + module_annotations: _, + } = module; + for module_io in &module_io { + retval.mark_as_used(module_io.module_io.name_id()); + } + match body { + ModuleBody::Extern(ExternModuleBody { + verilog_name: _, + parameters: _, + }) => {} + ModuleBody::Normal(NormalModuleBody { body }) => { + let mut blocks = vec![body]; + while let Some(block) = blocks.pop() { + let Block { memories, stmts } = block; + for memory in memories { + retval.mark_as_used(memory.scoped_name().1); + } + for stmt in &stmts { + blocks.extend_from_slice(stmt.sub_stmt_blocks()); + match stmt { + Stmt::Connect(StmtConnect { + lhs: _, + rhs: _, + source_location: _, + }) + | Stmt::If(StmtIf { + cond: _, + source_location: _, + blocks: _, + }) + | Stmt::Match(StmtMatch { + expr: _, + source_location: _, + blocks: _, + }) => {} + Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { + annotations: _, + instance, + })) => { + retval.mark_as_used(instance.name_id()); + } + Stmt::Declaration(StmtDeclaration::Reg(StmtReg { + annotations: _, + reg, + })) => { + retval.mark_as_used(reg.name_id()); + } + Stmt::Declaration(StmtDeclaration::Wire(StmtWire { + annotations: _, + wire, + })) => { + retval.mark_as_used(wire.name_id()); + } + } + } + } + } + } + retval + } + pub fn gen_module_name(name: Interned) -> NameId { + static MODULE_NAME_GEN: Mutex> = Mutex::new(None); + MODULE_NAME_GEN + .lock() + .unwrap() + .get_or_insert_with(NameIdGen::default) + .gen(name) + } +} + #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct Instance { scoped_name: ScopedNameId, @@ -772,18 +657,6 @@ impl Instance { source_location, } } - pub fn from_canonical(v: Instance) -> Self { - let Instance { - scoped_name, - instantiated, - source_location, - } = v; - Self { - scoped_name, - instantiated: Module::from_canonical(*instantiated).intern_sized(), - source_location, - } - } pub fn containing_module_name(self) -> Interned { self.containing_module_name_id().0 } @@ -843,6 +716,7 @@ struct ModuleBuilderImpl { body: ModuleBodyBuilding, io: Vec>, io_indexes: HashMap, usize>, + name_id_gen: NameIdGen, module_annotations: Vec, } @@ -957,38 +831,16 @@ impl From> for NormalModuleBody { annotations_map: &mut HashMap, Vec>, block_id: BlockId, ) -> Block { - let BuilderBlock { - memories, - incomplete_declarations, - stmts, - } = &mut blocks[block_id.as_usize()]; + let BuilderBlock { memories, stmts } = &mut blocks[block_id.as_usize()]; let memories = Interned::from_iter( memories .drain(..) .filter_map(|memory| memory.borrow().make_memory()), ); - let stmts = Vec::from_iter( - incomplete_declarations - .drain(..) - .map(|decl| { - match std::mem::replace( - &mut *decl.borrow_mut(), - IncompleteDeclaration::Taken, - ) { - IncompleteDeclaration::Incomplete { - name, - source_location, - } => panic!("incomplete declaration: {name:?}\nat: {source_location}"), - IncompleteDeclaration::Complete(v) => Stmt::Declaration(v), - IncompleteDeclaration::Taken => unreachable!(), - } - }) - .chain(stmts.drain(..)), - ); + let stmts = std::mem::take(stmts); let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| { match stmt { Stmt::Connect(stmt) => stmt.into(), - Stmt::Formal(stmt) => stmt.into(), Stmt::If(StmtIf { cond, source_location, @@ -1017,7 +869,7 @@ impl From> for NormalModuleBody { Stmt::Declaration(decl) => { let annotations = annotations_map .remove(&decl) - .map(Intern::intern_owned) + .map(|v| Intern::intern_owned(v)) .unwrap_or_default(); match decl { StmtDeclaration::Wire(StmtWire { @@ -1028,14 +880,6 @@ impl From> for NormalModuleBody { annotations: (), reg, }) => StmtReg { annotations, reg }.into(), - StmtDeclaration::RegSync(StmtReg { - annotations: (), - reg, - }) => StmtReg { annotations, reg }.into(), - StmtDeclaration::RegAsync(StmtReg { - annotations: (), - reg, - }) => StmtReg { annotations, reg }.into(), StmtDeclaration::Instance(StmtInstance { annotations: (), instance, @@ -1064,7 +908,6 @@ impl NormalModuleBody { let index = self.body.blocks.len(); self.body.blocks.push(BuilderBlock { memories: vec![], - incomplete_declarations: vec![], stmts: vec![], }); BlockId(index) @@ -1083,7 +926,6 @@ pub struct ExternModuleBody< > { pub verilog_name: Interned, pub parameters: P, - pub simulation: Option, } impl From>> for ExternModuleBody { @@ -1091,13 +933,11 @@ impl From>> for ExternModuleBody { let ExternModuleBody { verilog_name, parameters, - simulation, } = value; let parameters = Intern::intern_owned(parameters); Self { verilog_name, parameters, - simulation, } } } @@ -1288,12 +1128,10 @@ impl fmt::Debug for DebugModuleBody { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, - simulation, }) => { debug_struct .field("verilog_name", verilog_name) - .field("parameters", parameters) - .field("simulation", simulation); + .field("parameters", parameters); } } debug_struct.finish_non_exhaustive() @@ -1497,9 +1335,6 @@ impl TargetState { }) .collect(), }, - CanonicalType::PhantomConst(_) => TargetStateInner::Decomposed { - subtargets: HashMap::default(), - }, CanonicalType::Array(ty) => TargetStateInner::Decomposed { subtargets: (0..ty.len()) .map(|index| { @@ -1703,7 +1538,10 @@ impl AssertValidityState { let module = self.module; if block == 0 { for module_io in &*module.module_io { - self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block); + self.insert_new_base( + TargetBase::intern_sized(module_io.module_io.clone().into()), + block, + ); } } let Block { memories, stmts } = self.blocks[block]; @@ -1714,23 +1552,19 @@ impl AssertValidityState { } for stmt in stmts { match stmt { - Stmt::Connect(connect) => { - connect.assert_validity(); - let StmtConnect { - lhs, - rhs, - source_location, - } = connect; + Stmt::Connect(StmtConnect { + lhs, + rhs, + source_location, + }) => { self.set_connect_side_written(lhs, source_location, true, block); self.set_connect_side_written(rhs, source_location, false, block); } - Stmt::Formal(_) => {} Stmt::If(if_stmt) => { let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block)); self.process_conditional_sub_blocks(block, sub_blocks) } Stmt::Match(match_stmt) => { - match_stmt.assert_validity(); let sub_blocks = Vec::from_iter( match_stmt .blocks @@ -1747,14 +1581,6 @@ impl AssertValidityState { annotations: _, reg, })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), - Stmt::Declaration(StmtDeclaration::RegSync(StmtReg { - annotations: _, - reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), - Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg { - annotations: _, - reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations: _, instance, @@ -1768,7 +1594,6 @@ impl AssertValidityState { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, - simulation: _, }) => {} ModuleBody::Normal(NormalModuleBody { body }) => { let body = self.make_block_index(body); @@ -1864,7 +1689,7 @@ impl Module { AssertValidityState { module: self.canonical(), blocks: vec![], - target_states: HashMap::with_capacity_and_hasher(64, Default::default()), + target_states: HashMap::with_capacity(64), } .assert_validity(); } @@ -1937,10 +1762,10 @@ impl RegBuilder { } impl RegBuilder<(), I, T> { - pub fn clock_domain( + pub fn clock_domain( self, - clock_domain: impl ToExpr>, - ) -> RegBuilder>, I, T> { + clock_domain: impl ToExpr, + ) -> RegBuilder, I, T> { let Self { name, source_location, @@ -1958,7 +1783,7 @@ impl RegBuilder<(), I, T> { } } -impl RegBuilder>, Option>, T> { +impl RegBuilder, Option>, T> { #[track_caller] pub fn build(self) -> Expr { let Self { @@ -1969,7 +1794,9 @@ impl RegBuilder>, Option>, T> ty, } = self; ModuleBuilder::with(|module_builder| { - let scoped_name = ScopedNameId(module_builder.name, NameId(name, Id::new())); + let mut impl_ = module_builder.impl_.borrow_mut(); + let scoped_name = ScopedNameId(module_builder.name, impl_.name_id_gen.gen(name)); + drop(impl_); let reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init); let retval = reg.to_expr(); // convert before borrow_mut since ModuleBuilder could be reentered by T::canonical() @@ -2017,18 +1844,13 @@ impl ModuleBuilder { is_input: bool, ty: IO, ) -> Expr { - let module_io = ModuleIO::::new_unchecked( - self.name, - NameId(name.intern(), Id::new()), - source_location, - is_input, - ty, - ); + let module_io = + ModuleIO::::new_unchecked(self.name, name.intern(), source_location, is_input, ty); let retval = module_io.to_expr(); let module_io = module_io.canonical(); let mut impl_ = self.impl_.borrow_mut(); let impl_ = &mut *impl_; - impl_.io_indexes.insert(module_io, impl_.io.len()); + impl_.io_indexes.insert(module_io.clone(), impl_.io.len()); impl_.io.push(AnnotatedModuleIO { annotations: vec![], module_io, @@ -2111,22 +1933,20 @@ impl ModuleBuilder { module_kind: ModuleKind, f: impl FnOnce(&Self) -> Result<(), E>, ) -> Result>, E> { - let name = NameId(name.intern(), Id::new()); + let name = NameIdGen::gen_module_name(name.intern()); let body = match module_kind { ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody { verilog_name: name.0, parameters: vec![], - simulation: None, }), ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody { body: BuilderModuleBody { blocks: vec![BuilderBlock { memories: vec![], - incomplete_declarations: vec![], stmts: vec![], }], - annotations_map: HashMap::default(), - memory_map: HashMap::default(), + annotations_map: HashMap::new(), + memory_map: HashMap::new(), }, }), }; @@ -2136,7 +1956,8 @@ impl ModuleBuilder { impl_: RefCell::new(ModuleBuilderImpl { body, io: vec![], - io_indexes: HashMap::default(), + io_indexes: HashMap::new(), + name_id_gen: NameIdGen::default(), module_annotations: vec![], }), }; @@ -2183,7 +2004,6 @@ impl ModuleBuilder { .builder_extern_body() .verilog_name = name.intern(); } - #[track_caller] pub fn parameter(&self, name: impl AsRef, value: ExternModuleParameterValue) { let name = name.as_ref(); self.impl_ @@ -2196,7 +2016,6 @@ impl ModuleBuilder { value, }); } - #[track_caller] pub fn parameter_int(&self, name: impl AsRef, value: impl Into) { let name = name.as_ref(); let value = value.into(); @@ -2210,7 +2029,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::Integer(value), }); } - #[track_caller] pub fn parameter_str(&self, name: impl AsRef, value: impl AsRef) { let name = name.as_ref(); let value = value.as_ref(); @@ -2224,7 +2042,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::String(value.intern()), }); } - #[track_caller] pub fn parameter_raw_verilog(&self, name: impl AsRef, raw_verilog: impl AsRef) { let name = name.as_ref(); let raw_verilog = raw_verilog.as_ref(); @@ -2238,26 +2055,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()), }); } - #[track_caller] - pub fn extern_module_simulation(&self, generator: G) { - let mut impl_ = self.impl_.borrow_mut(); - let simulation = &mut impl_.body.builder_extern_body().simulation; - if simulation.is_some() { - panic!("already added an extern module simulation"); - } - *simulation = Some(ExternModuleSimulation::new(generator)); - } - #[track_caller] - pub fn extern_module_simulation_fn< - Args: fmt::Debug + Clone + Hash + Eq + Send + Sync + 'static, - Fut: IntoFuture + 'static, - >( - &self, - args: Args, - f: fn(Args, crate::sim::ExternModuleSimulationState) -> Fut, - ) { - self.extern_module_simulation(crate::sim::SimGeneratorFn { args, f }); - } } #[track_caller] @@ -2308,16 +2105,6 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { reg, } .into(), - TargetBase::RegSync(reg) => StmtReg { - annotations: (), - reg, - } - .into(), - TargetBase::RegAsync(reg) => StmtReg { - annotations: (), - reg, - } - .into(), TargetBase::Wire(wire) => StmtWire { annotations: (), wire, @@ -2334,15 +2121,16 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { .body .annotations_map .entry(decl) - .or_default() - .extend(annotations); + .or_default(); }); } #[track_caller] pub fn wire_with_loc(name: &str, source_location: SourceLocation, ty: T) -> Expr { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let mut impl_ = m.impl_.borrow_mut(); + let scoped_name = ScopedNameId(m.name, impl_.name_id_gen.gen(name.intern())); + drop(impl_); let wire = Wire::::new_unchecked(scoped_name, source_location, ty); let retval = wire.to_expr(); let canonical_wire = wire.canonical(); @@ -2368,40 +2156,6 @@ pub fn wire(implicit_name: ImplicitName<'_>, ty: T) -> Expr { wire_with_loc(implicit_name.0, SourceLocation::caller(), ty) } -#[track_caller] -fn incomplete_declaration( - name: &str, - source_location: SourceLocation, -) -> Rc> { - ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); - let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete { - name: scoped_name, - source_location, - })); - let mut impl_ = m.impl_.borrow_mut(); - impl_ - .body - .builder_normal_body() - .block(m.block_stack.top()) - .incomplete_declarations - .push(retval.clone()); - retval - }) -} - -#[track_caller] -pub fn incomplete_wire_with_loc(name: &str, source_location: SourceLocation) -> IncompleteWire { - IncompleteWire { - declaration: incomplete_declaration(name, source_location), - } -} - -#[track_caller] -pub fn incomplete_wire(implicit_name: ImplicitName<'_>) -> IncompleteWire { - incomplete_wire_with_loc(implicit_name.0, SourceLocation::caller()) -} - #[track_caller] pub fn reg_builder_with_loc(name: &str, source_location: SourceLocation) -> RegBuilder<(), (), ()> { ModuleBuilder::with(|m| { @@ -2507,12 +2261,24 @@ pub fn connect_any_with_loc( let rhs_orig = rhs.to_expr(); let lhs = Expr::canonical(lhs_orig); let rhs = Expr::canonical(rhs_orig); - let connect = StmtConnect { - lhs, - rhs, - source_location, - }; - connect.assert_validity_with_original_types(Expr::ty(lhs_orig), Expr::ty(rhs_orig)); + assert!( + Expr::ty(lhs).can_connect(Expr::ty(rhs)), + "can't connect types that are not equivalent:\nlhs type:\n{:?}\nrhs type:\n{:?}", + Expr::ty(lhs_orig), + Expr::ty(rhs_orig) + ); + assert!( + matches!(Expr::flow(lhs), Flow::Sink | Flow::Duplex), + "can't connect to source, connect lhs must have sink or duplex flow" + ); + assert!(lhs.target().is_some(), "can't connect to non-target"); + match Expr::flow(rhs) { + Flow::Source | Flow::Duplex => {} + Flow::Sink => assert!( + Expr::ty(rhs).is_passive(), + "can't connect from sink with non-passive type" + ), + } ModuleBuilder::with(|m| { m.impl_ .borrow_mut() @@ -2520,7 +2286,14 @@ pub fn connect_any_with_loc( .builder_normal_body() .block(m.block_stack.top()) .stmts - .push(connect.into()); + .push( + StmtConnect { + lhs, + rhs, + source_location, + } + .into(), + ); }); } @@ -2550,7 +2323,9 @@ pub fn instance_with_loc( source_location: SourceLocation, ) -> Expr { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let mut impl_ = m.impl_.borrow_mut(); + let scoped_name = ScopedNameId(m.name, impl_.name_id_gen.gen(name.intern())); + drop(impl_); let instance = Instance:: { scoped_name, instantiated, @@ -2589,7 +2364,9 @@ fn memory_impl( source_location: SourceLocation, ) -> MemBuilder { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let mut impl_ = m.impl_.borrow_mut(); + let scoped_name = ScopedNameId(m.name, impl_.name_id_gen.gen(name.intern())); + drop(impl_); let (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type); let mut impl_ = m.impl_.borrow_mut(); let body = impl_.body.builder_normal_body(); @@ -2607,7 +2384,7 @@ pub fn memory_array_with_loc( mem_array_type: ArrayType, source_location: SourceLocation, ) -> MemBuilder { - let mut retval = memory_impl(name, mem_array_type.element(), source_location); + let mut retval = memory_impl(name, mem_array_type.element().clone(), source_location); retval.depth(mem_array_type.len()); retval } @@ -2665,7 +2442,6 @@ pub fn memory( pub struct ModuleIO { containing_module_name: NameId, bundle_field: BundleField, - id: Id, ty: T, source_location: SourceLocation, } @@ -2685,14 +2461,12 @@ impl ModuleIO { let Self { containing_module_name, bundle_field, - id, ty: _, source_location, } = *self; ModuleIO { containing_module_name, bundle_field, - id, ty: bundle_field.ty, source_location, } @@ -2716,7 +2490,7 @@ impl ModuleIO { self.bundle_field.name } pub fn name_id(&self) -> NameId { - NameId(self.bundle_field.name, self.id) + NameId(self.bundle_field.name, 0) } pub fn scoped_name(&self) -> ScopedNameId { ScopedNameId(self.containing_module_name, self.name_id()) @@ -2726,7 +2500,7 @@ impl ModuleIO { } pub fn new_unchecked( containing_module_name: NameId, - name: NameId, + name: Interned, source_location: SourceLocation, is_input: bool, ty: T, @@ -2734,11 +2508,10 @@ impl ModuleIO { Self { containing_module_name, bundle_field: BundleField { - name: name.0, + name, flipped: is_input, ty: ty.canonical(), }, - id: name.1, ty, source_location, } @@ -2759,50 +2532,3 @@ impl ModuleIO { self.ty } } - -#[derive(PartialEq, Eq, Hash, Clone, Copy)] -pub enum InstantiatedModule { - Base(Interned>), - Child { - parent: Interned, - instance: Interned>, - }, -} - -impl InstantiatedModule { - pub fn leaf_module(self) -> Interned> { - match self { - InstantiatedModule::Base(base) => base, - InstantiatedModule::Child { instance, .. } => instance.instantiated(), - } - } - fn write_path(self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - InstantiatedModule::Base(base) => fmt::Debug::fmt(&base.name_id(), f), - InstantiatedModule::Child { parent, instance } => { - parent.write_path(f)?; - write!(f, ".{}", instance.name_id()) - } - } - } -} - -impl fmt::Debug for InstantiatedModule { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "InstantiatedModule(")?; - self.write_path(f)?; - write!(f, ": {})", self.leaf_module().name_id()) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct TargetInInstantiatedModule { - pub instantiated_module: InstantiatedModule, - pub target: Target, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct ExprInInstantiatedModule { - pub instantiated_module: InstantiatedModule, - pub expr: Expr, -} diff --git a/crates/fayalite/src/module/transform.rs b/crates/fayalite/src/module/transform.rs index 063a1a3..4117087 100644 --- a/crates/fayalite/src/module/transform.rs +++ b/crates/fayalite/src/module/transform.rs @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -pub mod deduce_resets; pub mod simplify_enums; pub mod simplify_memories; pub mod visit; diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs deleted file mode 100644 index 5fb829e..0000000 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ /dev/null @@ -1,2281 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - annotations::{Annotation, TargetedAnnotation}, - bundle::{BundleField, BundleType}, - enum_::{EnumType, EnumVariant}, - expr::{ - ops::{self, ArrayLiteral}, - target::{ - Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, - }, - ExprEnum, - }, - formal::FormalKind, - int::{SIntValue, UIntValue}, - intern::{Intern, Interned, Memoize}, - memory::{DynPortType, MemPort}, - module::{ - AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, InstantiatedModule, - ModuleBody, ModuleIO, NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, - StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, - }, - prelude::*, - reset::{ResetType, ResetTypeDispatch}, - util::{HashMap, HashSet}, -}; -use hashbrown::hash_map::Entry; -use num_bigint::BigInt; -use petgraph::unionfind::UnionFind; -use std::{fmt, marker::PhantomData}; - -#[derive(Debug)] -pub enum DeduceResetsError { - ResetIsNotDrivenByAsyncOrSync { source_location: SourceLocation }, - ResetIsDrivenByBothAsyncAndSync { source_location: SourceLocation }, -} - -impl fmt::Display for DeduceResetsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { source_location } => { - write!(f, "deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {source_location}") - } - DeduceResetsError::ResetIsDrivenByBothAsyncAndSync { source_location } => { - write!(f, "deduce_reset failed: Reset signal is driven by both AsyncReset and SyncReset signals: {source_location}") - } - } - } -} - -impl std::error::Error for DeduceResetsError {} - -impl From for std::io::Error { - fn from(value: DeduceResetsError) -> Self { - std::io::Error::new(std::io::ErrorKind::Other, value) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum AnyReg { - Reg(Reg), - RegSync(Reg), - RegAsync(Reg), -} - -macro_rules! match_any_reg { - ( - $match_expr:expr, $fn:expr - ) => { - match $match_expr { - AnyReg::Reg(reg) => $fn(reg), - AnyReg::RegSync(reg) => $fn(reg), - AnyReg::RegAsync(reg) => $fn(reg), - } - }; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum ResetsLayout { - NoResets, - Reset, - SyncReset, - AsyncReset, - Bundle { - fields: Interned<[ResetsLayout]>, - reset_count: usize, - }, - Enum { - variants: Interned<[ResetsLayout]>, - reset_count: usize, - }, - Array { - element: Interned, - reset_count: usize, - }, -} - -impl ResetsLayout { - fn reset_count(self) -> usize { - match self { - ResetsLayout::NoResets => 0, - ResetsLayout::Reset | ResetsLayout::SyncReset | ResetsLayout::AsyncReset => 1, - ResetsLayout::Bundle { reset_count, .. } - | ResetsLayout::Enum { reset_count, .. } - | ResetsLayout::Array { reset_count, .. } => reset_count, - } - } - fn new(ty: CanonicalType) -> Self { - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - struct MyMemoize; - impl Memoize for MyMemoize { - type Input = CanonicalType; - type InputOwned = CanonicalType; - type Output = ResetsLayout; - - fn inner(self, ty: &Self::Input) -> Self::Output { - match *ty { - CanonicalType::UInt(_) => ResetsLayout::NoResets, - CanonicalType::SInt(_) => ResetsLayout::NoResets, - CanonicalType::Bool(_) => ResetsLayout::NoResets, - CanonicalType::Array(ty) => { - let element = ResetsLayout::new(ty.element()).intern_sized(); - ResetsLayout::Array { - element, - reset_count: element.reset_count(), - } - } - CanonicalType::Enum(ty) => { - let mut reset_count = 0; - let variants = Interned::from_iter(ty.variants().iter().map(|variant| { - let resets_layout = - variant.ty.map_or(ResetsLayout::NoResets, ResetsLayout::new); - reset_count += resets_layout.reset_count(); - resets_layout - })); - ResetsLayout::Enum { - variants, - reset_count, - } - } - CanonicalType::Bundle(ty) => { - let mut reset_count = 0; - let fields = Interned::from_iter(ty.fields().iter().map(|field| { - let resets_layout = ResetsLayout::new(field.ty); - reset_count += resets_layout.reset_count(); - resets_layout - })); - ResetsLayout::Bundle { - fields, - reset_count, - } - } - CanonicalType::AsyncReset(_) => ResetsLayout::AsyncReset, - CanonicalType::SyncReset(_) => ResetsLayout::SyncReset, - CanonicalType::Reset(_) => ResetsLayout::Reset, - CanonicalType::Clock(_) => ResetsLayout::NoResets, - CanonicalType::PhantomConst(_) => ResetsLayout::NoResets, - } - } - } - MyMemoize.get_owned(ty) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -struct ResetNodeIndex(usize); - -#[derive(Copy, Clone, Debug)] -struct ResetNode { - is_async: Option, - source_location: Option, -} - -impl ResetNode { - fn union( - self, - other: Self, - fallback_error_source_location: SourceLocation, - ) -> Result { - match (self.is_async, other.is_async) { - (None, None) => Ok(Self { - is_async: None, - source_location: self.source_location.or(other.source_location), - }), - (None, is_async @ Some(_)) => Ok(Self { - is_async, - // prioritize `other` - source_location: other.source_location.or(self.source_location), - }), - (is_async @ Some(_), None) => Ok(Self { - is_async, - // prioritize `self` - source_location: self.source_location.or(other.source_location), - }), - (Some(self_is_async), Some(other_is_async)) => { - if self_is_async == other_is_async { - Ok(Self { - is_async: Some(self_is_async), - source_location: self.source_location.or(other.source_location), - }) - } else { - Err(DeduceResetsError::ResetIsDrivenByBothAsyncAndSync { - source_location: self - .source_location - .or(other.source_location) - .unwrap_or(fallback_error_source_location), - }) - } - } - } - } -} - -#[derive(Debug, Default)] -struct ResetGraph { - union_find: UnionFind, - nodes: Vec, -} - -impl ResetGraph { - fn new_node( - &mut self, - is_async: Option, - source_location: Option, - ) -> ResetNodeIndex { - let index = self.union_find.new_set(); - assert_eq!(index, self.nodes.len()); - self.nodes.push(ResetNode { - is_async, - source_location, - }); - ResetNodeIndex(index) - } - fn union( - &mut self, - a: ResetNodeIndex, - b: ResetNodeIndex, - fallback_error_source_location: SourceLocation, - ) -> Result<(), DeduceResetsError> { - let a = self.union_find.find_mut(a.0); - let b = self.union_find.find_mut(b.0); - if a != b { - self.union_find.union(a, b); - let merged = self.union_find.find_mut(a); - self.nodes[merged] = - self.nodes[a].union(self.nodes[b], fallback_error_source_location)?; - } - Ok(()) - } - fn is_async( - &mut self, - node: ResetNodeIndex, - fallback_to_sync_reset: bool, - fallback_error_source_location: SourceLocation, - ) -> Result { - let ResetNode { - is_async, - source_location, - } = self.nodes[self.union_find.find_mut(node.0)]; - if let Some(is_async) = is_async { - Ok(is_async) - } else if fallback_to_sync_reset { - Ok(false) - } else { - Err(DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { - source_location: source_location.unwrap_or(fallback_error_source_location), - }) - } - } - fn append_new_nodes_for_layout( - &mut self, - layout: ResetsLayout, - node_indexes: &mut Vec, - source_location: Option, - ) { - match layout { - ResetsLayout::NoResets => {} - ResetsLayout::Reset => node_indexes.push(self.new_node(None, source_location)), - ResetsLayout::SyncReset => { - node_indexes.push(self.new_node(Some(false), source_location)) - } - ResetsLayout::AsyncReset => { - node_indexes.push(self.new_node(Some(true), source_location)) - } - ResetsLayout::Bundle { - fields, - reset_count: _, - } => { - for field in fields { - self.append_new_nodes_for_layout(field, node_indexes, source_location); - } - } - ResetsLayout::Enum { - variants, - reset_count: _, - } => { - for variant in variants { - self.append_new_nodes_for_layout(variant, node_indexes, source_location); - } - } - ResetsLayout::Array { - element, - reset_count: _, - } => { - self.append_new_nodes_for_layout(*element, node_indexes, source_location); - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -struct Resets { - ty: CanonicalType, - layout: ResetsLayout, - node_indexes: Interned<[ResetNodeIndex]>, -} - -impl Resets { - fn with_new_nodes( - reset_graph: &mut ResetGraph, - ty: CanonicalType, - source_location: Option, - ) -> Self { - let layout = ResetsLayout::new(ty); - let mut node_indexes = Vec::with_capacity(layout.reset_count()); - reset_graph.append_new_nodes_for_layout(layout, &mut node_indexes, source_location); - let node_indexes = Intern::intern_owned(node_indexes); - Self { - ty, - layout, - node_indexes, - } - } - fn array_elements(self) -> Self { - let array = ::from_canonical(self.ty); - let ResetsLayout::Array { - element, - reset_count: _, - } = self.layout - else { - unreachable!(); - }; - Self { - ty: array.element(), - layout: *element, - node_indexes: self.node_indexes, - } - } - fn bundle_fields(self) -> impl Iterator { - let bundle = Bundle::from_canonical(self.ty); - let ResetsLayout::Bundle { - fields, - reset_count: _, - } = self.layout - else { - unreachable!(); - }; - bundle.fields().into_iter().zip(fields).scan( - 0, - move |start_index, (BundleField { ty, .. }, layout)| { - let end_index = *start_index + layout.reset_count(); - let node_indexes = self.node_indexes[*start_index..end_index].intern(); - *start_index = end_index; - Some(Self { - ty, - layout, - node_indexes, - }) - }, - ) - } - fn enum_variants(self) -> impl Iterator> { - let enum_ = Enum::from_canonical(self.ty); - let ResetsLayout::Enum { - variants, - reset_count: _, - } = self.layout - else { - unreachable!(); - }; - enum_.variants().into_iter().zip(variants).scan( - 0, - move |start_index, (EnumVariant { ty, .. }, layout)| { - let end_index = *start_index + layout.reset_count(); - let node_indexes = self.node_indexes[*start_index..end_index].intern(); - *start_index = end_index; - Some(ty.map(|ty| Self { - ty, - layout, - node_indexes, - })) - }, - ) - } - fn substituted_type( - self, - reset_graph: &mut ResetGraph, - fallback_to_sync_reset: bool, - fallback_error_source_location: SourceLocation, - ) -> Result { - if self.layout.reset_count() == 0 { - return Ok(self.ty); - } - match self.ty { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) => Ok(self.ty), - CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn( - self.array_elements().substituted_type( - reset_graph, - fallback_to_sync_reset, - fallback_error_source_location, - )?, - ty.len(), - ))), - CanonicalType::Enum(ty) => Ok(CanonicalType::Enum(Enum::new(Result::from_iter( - self.enum_variants().zip(ty.variants()).map( - |(resets, EnumVariant { name, ty: _ })| { - Ok(EnumVariant { - name, - ty: resets - .map(|resets| { - resets.substituted_type( - reset_graph, - fallback_to_sync_reset, - fallback_error_source_location, - ) - }) - .transpose()?, - }) - }, - ), - )?))), - CanonicalType::Bundle(ty) => Ok(CanonicalType::Bundle(Bundle::new(Result::from_iter( - self.bundle_fields().zip(ty.fields()).map( - |( - resets, - BundleField { - name, - flipped, - ty: _, - }, - )| { - Ok(BundleField { - name, - flipped, - ty: resets.substituted_type( - reset_graph, - fallback_to_sync_reset, - fallback_error_source_location, - )?, - }) - }, - ), - )?))), - CanonicalType::Reset(_) => Ok( - if reset_graph.is_async( - self.node_indexes[0], - fallback_to_sync_reset, - fallback_error_source_location, - )? { - CanonicalType::AsyncReset(AsyncReset) - } else { - CanonicalType::SyncReset(SyncReset) - }, - ), - } - } -} - -#[derive(Debug)] -struct State { - modules_added_to_graph: HashSet, - substituted_modules: HashMap>, - expr_resets: HashMap, Resets>, - reset_graph: ResetGraph, - fallback_to_sync_reset: bool, -} - -impl State { - fn get_resets( - &self, - instantiated_module: InstantiatedModule, - expr: impl ToExpr, - ) -> Option { - self.expr_resets - .get(&ExprInInstantiatedModule { - instantiated_module, - expr: Expr::canonical(expr.to_expr()), - }) - .copied() - } - fn get_or_make_resets( - &mut self, - instantiated_module: InstantiatedModule, - expr: impl ToExpr, - source_location: Option, - ) -> (Resets, bool) { - let expr = Expr::canonical(expr.to_expr()); - match self.expr_resets.entry(ExprInInstantiatedModule { - instantiated_module, - expr, - }) { - Entry::Occupied(entry) => (*entry.get(), false), - Entry::Vacant(entry) => ( - *entry.insert(Resets::with_new_nodes( - &mut self.reset_graph, - Expr::ty(expr), - source_location, - )), - true, - ), - } - } -} - -struct PassOutput(P::Output); - -impl PassOutput { - fn new(v: T) -> Self { - P::output_new(v) - } - fn from_fn(f: impl FnOnce() -> T) -> Self { - PassOutput::new(()).map(|()| f()) - } - fn map(self, f: impl FnOnce(T) -> U) -> PassOutput { - P::map(self, f) - } -} - -trait PassOutputZip: Sized { - type Zipped; - fn zip(self) -> PassOutput; - fn call(self, f: impl FnOnce(Self::Zipped) -> U) -> PassOutput { - self.zip().map(f) - } -} - -impl PassOutputZip

for () { - type Zipped = (); - fn zip(self) -> PassOutput { - PassOutput::new(()) - } -} - -impl PassOutputZip

for (PassOutput,) { - type Zipped = (T,); - fn zip(self) -> PassOutput { - self.0.map(|v| (v,)) - } -} - -macro_rules! impl_zip { - ($first_arg:ident: $first_T:ident, $($arg:ident: $T:ident),* $(,)?) => { - impl_zip!(@step [], [($first_arg: $first_T) $(($arg: $T))*], (),); - }; - ( - @impl($first_arg:tt,), - $tuple_pat:tt, - ) => {}; - ( - @impl(($first_arg:ident: $first_T:ident), - $(($arg:ident: $T:ident),)*), - $tuple_pat:tt, - ) => { - impl<$first_T, $($T,)* P: Pass> PassOutputZip

for (PassOutput<$first_T, P>, $(PassOutput<$T, P>),*) { - type Zipped = ($first_T, $($T),*); - fn zip(self) -> PassOutput<($first_T, $($T),*), P> { - let (tuples, $($arg),*) = self; - $(let tuples = P::zip(tuples, $arg);)* - tuples.map(|$tuple_pat| ($first_arg, $($arg),*)) - } - } - }; - ( - @step [$($cur:tt)*], - [], - $tuple_pat:tt, - ) => {}; - ( - @step [$($cur:tt)*], - [($next_arg:ident: $next_T:ident) $($rest:tt)*], - (), - ) => { - impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), $next_arg,); - impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], $next_arg,); - }; - ( - @step [$($cur:tt)*], - [($next_arg:ident: $next_T:ident) $($rest:tt)*], - $tuple_pat:tt, - ) => { - impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), ($tuple_pat, $next_arg),); - impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], ($tuple_pat, $next_arg),); - }; -} - -impl_zip!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, t11: T11); - -impl, P: Pass, A> FromIterator> for PassOutput { - fn from_iter>>(iter: I) -> Self { - P::output_from_iter(iter) - } -} - -trait PassDispatch: Sized { - type Input; - type Output; - fn build_reset_graph( - self, - input: Self::Input, - ) -> Self::Output; - fn substitute_resets( - self, - input: Self::Input, - ) -> Self::Output; -} - -trait Pass: Sized { - type Output; - fn output_new(v: T) -> PassOutput; - fn output_from_iter, A>( - iter: impl IntoIterator>, - ) -> PassOutput; - fn try_array_from_fn( - f: impl FnMut(usize) -> Result, E>, - ) -> Result, E>; - fn map(v: PassOutput, f: impl FnOnce(T) -> U) -> PassOutput; - fn zip(t: PassOutput, u: PassOutput) -> PassOutput<(T, U), Self>; - fn dispatch(dispatch: D, input: D::Input) -> D::Output; -} - -struct BuildResetGraph; - -impl Pass for BuildResetGraph { - type Output = (); - - fn output_new(_v: T) -> PassOutput { - PassOutput(()) - } - - fn output_from_iter, A>( - iter: impl IntoIterator>, - ) -> PassOutput { - iter.into_iter().for_each(|_| {}); - PassOutput(()) - } - - fn try_array_from_fn( - mut f: impl FnMut(usize) -> Result, E>, - ) -> Result, E> { - for i in 0..N { - f(i)?; - } - Ok(PassOutput(())) - } - - fn map(_v: PassOutput, _f: impl FnOnce(T) -> U) -> PassOutput { - PassOutput(()) - } - - fn zip(_t: PassOutput, _u: PassOutput) -> PassOutput<(T, U), Self> { - PassOutput(()) - } - - fn dispatch(dispatch: D, input: D::Input) -> D::Output { - dispatch.build_reset_graph(input) - } -} - -struct SubstituteResets; - -impl Pass for SubstituteResets { - type Output = T; - - fn output_new(v: T) -> PassOutput { - PassOutput(v) - } - - fn output_from_iter, A>( - iter: impl IntoIterator>, - ) -> PassOutput { - PassOutput(T::from_iter(iter.into_iter().map(|PassOutput(v)| v))) - } - - fn try_array_from_fn( - mut f: impl FnMut(usize) -> Result, E>, - ) -> Result, E> { - let mut retval = [const { None }; N]; - for i in 0..N { - retval[i] = Some(f(i)?.0); - } - Ok(PassOutput( - retval.map(|v| v.expect("just wrote Some to all elements")), - )) - } - - fn map(v: PassOutput, f: impl FnOnce(T) -> U) -> PassOutput { - PassOutput(f(v.0)) - } - - fn zip(t: PassOutput, u: PassOutput) -> PassOutput<(T, U), Self> { - PassOutput((t.0, u.0)) - } - - fn dispatch(dispatch: D, input: D::Input) -> D::Output { - dispatch.substitute_resets(input) - } -} - -struct PassArgs<'a, P: Pass> { - state: &'a mut State, - instantiated_module: InstantiatedModule, - fallback_error_source_location: SourceLocation, - _phantom: PhantomData

, -} - -impl<'a, P: Pass> fmt::Debug for PassArgs<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - state, - instantiated_module, - fallback_error_source_location, - _phantom: _, - } = self; - f.debug_struct("PassArgs") - .field("state", state) - .field("instantiated_module", instantiated_module) - .field( - "fallback_error_source_location", - fallback_error_source_location, - ) - .finish() - } -} - -impl<'a, P: Pass> PassArgs<'a, P> { - fn as_mut(&mut self) -> PassArgs<'_, P> { - let PassArgs { - ref mut state, - instantiated_module, - fallback_error_source_location, - _phantom: _, - } = *self; - PassArgs { - state: &mut **state, - instantiated_module, - fallback_error_source_location, - _phantom: PhantomData, - } - } - fn get_resets(&self, expr: impl ToExpr) -> Option { - self.state.get_resets(self.instantiated_module, expr) - } - fn get_or_make_resets( - &mut self, - expr: impl ToExpr, - source_location: Option, - ) -> (Resets, bool) { - self.state - .get_or_make_resets(self.instantiated_module, expr, source_location) - } - fn union( - &mut self, - a: Resets, - b: Resets, - fallback_error_source_location: Option, - ) -> Result<(), DeduceResetsError> { - assert_eq!(a.layout, b.layout); - assert!( - a.ty.can_connect(b.ty), - "can't connect types! a:\n{a:?}\nb:\n{b:?}" - ); - for (a_node_index, b_node_index) in a.node_indexes.into_iter().zip(b.node_indexes) { - self.state.reset_graph.union( - a_node_index, - b_node_index, - fallback_error_source_location.unwrap_or(self.fallback_error_source_location), - )?; - } - Ok(()) - } -} - -trait RunPass: Sized { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError>; -} - -trait RunPassDispatch: Sized { - fn build_reset_graph( - &self, - pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError>; - fn substitute_resets( - &self, - pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError>; - fn dispatch( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - struct Dispatch<'a, T>(T, PhantomData<&'a mut ()>); - impl<'a, T: RunPassDispatch> PassDispatch for Dispatch<'a, &'_ T> { - type Input = PassArgs<'a, P>; - type Output = Result, DeduceResetsError>; - - fn build_reset_graph( - self, - input: Self::Input, - ) -> Self::Output { - self.0.build_reset_graph(input) - } - fn substitute_resets( - self, - input: Self::Input, - ) -> Self::Output { - self.0.substitute_resets(input) - } - } - P::dispatch(Dispatch(self, PhantomData), pass_args) - } -} - -impl RunPass

for T { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - T::dispatch(self, pass_args) - } -} - -trait RunPassExpr: ToExpr + Sized { - type Args<'a>: IntoIterator> + 'a - where - Self: 'a; - fn args<'a>(&'a self) -> Self::Args<'a>; - fn source_location(&self) -> Option; - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError>; - fn new( - &self, - ty: CanonicalType, - new_args: Vec>, - ) -> Result; -} - -impl RunPassDispatch for T { - fn build_reset_graph( - &self, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError> { - let source_location = self.source_location(); - let (resets, _) = pass_args.get_or_make_resets(self, source_location); - let args_resets = Result::from_iter(self.args().into_iter().map(|arg| { - arg.run_pass(pass_args.as_mut())?; - let (resets, _) = pass_args.get_or_make_resets(arg, source_location); - Ok(resets) - }))?; - self.union_parts(resets, args_resets, pass_args)?; - Ok(PassOutput(())) - } - - fn substitute_resets( - &self, - mut pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError> { - let source_location = self.source_location(); - let (resets, _) = pass_args.get_or_make_resets(self, source_location); - let ty = resets.substituted_type( - &mut pass_args.state.reset_graph, - pass_args.state.fallback_to_sync_reset, - pass_args.fallback_error_source_location, - )?; - let new_args = Result::from_iter( - self.args() - .into_iter() - .map(|arg| Ok(arg.run_pass(pass_args.as_mut())?.0)), - )?; - Ok(PassOutput(self.new(ty, new_args)?)) - } -} - -impl + Intern + Clone, P: Pass> RunPass

for Interned { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(T::run_pass(self, pass_args)?.map(Intern::intern_sized)) - } -} - -impl + Clone, P: Pass> RunPass

for Interned<[T]> -where - [T]: Intern, -{ - fn run_pass( - &self, - mut pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Result::from_iter(self.iter().map(|v| v.run_pass(pass_args.as_mut()))) - } -} - -impl, P: Pass, const N: usize> RunPass

for [T; N] { - fn run_pass( - &self, - mut pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - P::try_array_from_fn(|i| self[i].run_pass(pass_args.as_mut())) - } -} - -impl, P: Pass> RunPass

for Option { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - match self { - Some(v) => Ok(v.run_pass(pass_args)?.map(Some)), - None => Ok(PassOutput::new(None)), - } - } -} - -fn reg_expr_run_pass( - reg: &Reg, - pass_args: PassArgs<'_, P>, -) -> Result, DeduceResetsError> { - Ok(AnyReg::from(*reg) - .run_pass(pass_args)? - .map(|reg| match_any_reg!(reg, ExprEnum::from))) -} - -fn cast_bit_op( - expr: impl ToExpr, - arg: Expr, - pass_args: PassArgs<'_, P>, -) -> Result, DeduceResetsError> { - struct Dispatch<'a, T: Type, A: Type> { - expr: Expr, - arg: Expr, - _phantom: PhantomData<&'a mut ()>, - } - impl<'a, T: Type, A: Type> PassDispatch for Dispatch<'a, T, A> { - type Input = PassArgs<'a, P>; - type Output = Result, DeduceResetsError>; - - fn build_reset_graph( - self, - mut pass_args: Self::Input, - ) -> Self::Output { - Expr::canonical(self.arg).run_pass(pass_args.as_mut())?; - let (expr_resets, _) = pass_args.get_or_make_resets(self.expr, None); - let (arg_resets, _) = pass_args.get_or_make_resets(self.arg, None); - // don't use PassArgs::union since types don't match and we want to just union resets if they exist - for (expr_node_index, arg_node_index) in expr_resets - .node_indexes - .into_iter() - .zip(arg_resets.node_indexes) - { - pass_args.state.reset_graph.union( - expr_node_index, - arg_node_index, - pass_args.fallback_error_source_location, - )?; - } - Ok(PassOutput(())) - } - - fn substitute_resets( - self, - mut pass_args: Self::Input, - ) -> Self::Output { - let resets = pass_args - .get_resets(self.expr) - .expect("added resets in build_reset_graph"); - let arg = Expr::canonical(self.arg).run_pass(pass_args.as_mut())?; - let ty = resets.substituted_type( - &mut pass_args.state.reset_graph, - pass_args.state.fallback_to_sync_reset, - pass_args.fallback_error_source_location, - )?; - Ok(arg.map(|arg| { - macro_rules! match_expr_ty { - ($arg:ident, $($Variant:ident),*) => { - match ty { - CanonicalType::Array(_) - | CanonicalType::Enum(_) - | CanonicalType::Bundle(_) - | CanonicalType::Reset(_) - | CanonicalType::PhantomConst(_) => unreachable!(), - $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* - } - }; - } - macro_rules! match_arg_ty { - ($($Variant:ident),*) => { - *match Expr::ty(arg) { - CanonicalType::Array(_) - | CanonicalType::Enum(_) - | CanonicalType::Bundle(_) - | CanonicalType::Reset(_) => unreachable!(), - CanonicalType::PhantomConst(_) => Expr::expr_enum(arg), - $(CanonicalType::$Variant(_) => { - let arg = Expr::<$Variant>::from_canonical(arg); - match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) - })* - } - }; - } - match_arg_ty!(UInt, SInt, Bool, AsyncReset, SyncReset, Clock) - })) - } - } - P::dispatch( - Dispatch { - expr: expr.to_expr(), - arg, - _phantom: PhantomData, - }, - pass_args, - ) -} - -impl RunPass

for ExprEnum { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - match self { - ExprEnum::UIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::SIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BoolLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::PhantomConst(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BundleLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ArrayLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::EnumLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::Uninit(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::NotU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::NotS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::NotB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::Neg(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitAndU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitAndS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitAndB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitOrU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitOrS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitOrB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitXorU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitXorS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::BitXorB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::AddU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::AddS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::SubU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::SubS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::MulU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::MulS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DivU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DivS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::RemU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::RemS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DynShlU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DynShlS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DynShrU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DynShrS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::FixedShlU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::FixedShlS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::FixedShrU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::FixedShrS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLtB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLeB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGtB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGeB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpEqB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpNeB(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLtU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLeU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGtU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGeU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpEqU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpNeU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLtS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpLeS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGtS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpGeS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpEqS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CmpNeS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastUIntToUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastUIntToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastSIntToUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastSIntToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastBoolToUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastBoolToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastUIntToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastSIntToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastBoolToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastUIntToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSIntToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastBoolToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastUIntToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSIntToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSyncResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSyncResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSyncResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastSyncResetToReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastAsyncResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastAsyncResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastAsyncResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastAsyncResetToReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), - ExprEnum::CastBoolToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastUIntToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastSIntToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastClockToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastClockToUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastClockToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::FieldAccess(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::VariantAccess(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ArrayIndex(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::DynArrayIndex(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitAndU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitAndS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitOrU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitOrS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitXorU(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ReduceBitXorS(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::SliceUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::SliceSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastToBits(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastBitsTo(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::Reg(expr) => reg_expr_run_pass(expr, pass_args), - ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args), - ExprEnum::RegAsync(expr) => reg_expr_run_pass(expr, pass_args), - ExprEnum::MemPort(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - } - } -} - -impl RunPass

for Expr { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::expr_enum(*self) - .run_pass(pass_args)? - .map(|expr_enum| expr_enum.to_expr())) - } -} - -impl RunPass

for Expr> { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::canonical(*self) - .run_pass(pass_args)? - .map(Expr::from_canonical)) - } -} - -impl RunPass

for Expr> { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::canonical(*self) - .run_pass(pass_args)? - .map(Expr::from_canonical)) - } -} - -impl RunPass

for Expr { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::canonical(*self) - .run_pass(pass_args)? - .map(Expr::from_canonical)) - } -} - -impl RunPass

for Expr { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::canonical(*self) - .run_pass(pass_args)? - .map(Expr::from_canonical)) - } -} - -impl RunPass

for Expr { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(Expr::canonical(*self) - .run_pass(pass_args)? - .map(Expr::from_canonical)) - } -} - -impl RunPassExpr for ops::Uninit { - type Args<'a> = [Expr; 0]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - _resets: Resets, - _args_resets: Vec, - _pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - _new_args: Vec>, - ) -> Result { - Ok(ops::Uninit::new(ty)) - } -} - -impl RunPassExpr for ops::BundleLiteral { - type Args<'a> = Interned<[Expr]>; - - fn args<'a>(&'a self) -> Self::Args<'a> { - self.field_values() - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - for (resets_field, field_expr_resets) in resets.bundle_fields().zip(args_resets) { - pass_args.union(resets_field, field_expr_resets, None)?; - } - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(ops::BundleLiteral::new( - Bundle::from_canonical(ty), - Intern::intern_owned(new_args), - )) - } -} - -impl RunPassExpr for ArrayLiteral { - type Args<'a> = Interned<[Expr]>; - - fn args<'a>(&'a self) -> Self::Args<'a> { - self.element_values() - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - let resets_elements = resets.array_elements(); - for arg_resets in args_resets { - pass_args.union(resets_elements, arg_resets, None)?; - } - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new( - ::from_canonical(ty).element(), - Intern::intern_owned(new_args), - )) - } -} - -impl RunPassExpr for ops::EnumLiteral { - type Args<'a> = Option>; - - fn args<'a>(&'a self) -> Self::Args<'a> { - self.variant_value() - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - if let Some(Some(variant_resets)) = resets.enum_variants().nth(self.variant_index()) { - pass_args.union(variant_resets, args_resets[0], None)?; - } - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new_by_index( - Enum::from_canonical(ty), - self.variant_index(), - new_args.get(0).copied(), - )) - } -} - -impl RunPassExpr for ops::FieldAccess { - type Args<'a> = [Expr; 1]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [Expr::canonical(self.base())] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - let Some(field_resets) = args_resets[0].bundle_fields().nth(self.field_index()) else { - unreachable!(); - }; - pass_args.union(resets, field_resets, None) - } - - fn new( - &self, - _ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new_by_index( - Expr::from_canonical(new_args[0]), - self.field_index(), - )) - } -} - -impl RunPassExpr for ops::VariantAccess { - type Args<'a> = [Expr; 1]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [Expr::canonical(self.base())] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - if let Some(Some(variant_resets)) = args_resets[0].enum_variants().nth(self.variant_index()) - { - pass_args.union(resets, variant_resets, None)?; - } - Ok(()) - } - - fn new( - &self, - _ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new_by_index( - Expr::from_canonical(new_args[0]), - self.variant_index(), - )) - } -} - -impl RunPassExpr for ops::ArrayIndex { - type Args<'a> = [Expr; 1]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [Expr::canonical(self.base())] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - pass_args.union(resets, args_resets[0].array_elements(), None) - } - - fn new( - &self, - _ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new( - Expr::from_canonical(new_args[0]), - self.element_index(), - )) - } -} - -impl RunPassExpr for ops::DynArrayIndex { - type Args<'a> = [Expr; 2]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [ - Expr::canonical(self.base()), - Expr::canonical(self.element_index()), - ] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - resets: Resets, - args_resets: Vec, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - pass_args.union(resets, args_resets[0].array_elements(), None) - } - - fn new( - &self, - _ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new( - Expr::from_canonical(new_args[0]), - Expr::from_canonical(new_args[1]), - )) - } -} - -impl RunPassExpr for ops::CastBitsTo { - type Args<'a> = [Expr; 1]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [Expr::canonical(self.arg())] - } - - fn source_location(&self) -> Option { - None - } - - fn union_parts( - &self, - _resets: Resets, - _args_resets: Vec, - _pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - new_args: Vec>, - ) -> Result { - Ok(Self::new(Expr::from_canonical(new_args[0]), ty)) - } -} - -impl RunPassExpr for ModuleIO { - type Args<'a> = [Expr; 0]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [] - } - - fn source_location(&self) -> Option { - Some(self.source_location()) - } - - fn union_parts( - &self, - _resets: Resets, - _args_resets: Vec, - _pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - _new_args: Vec>, - ) -> Result { - Ok(Self::new_unchecked( - self.containing_module_name_id(), - self.name_id(), - self.source_location(), - self.is_input(), - ty, - )) - } -} - -impl RunPassExpr for Wire { - type Args<'a> = [Expr; 0]; - - fn args<'a>(&'a self) -> Self::Args<'a> { - [] - } - - fn source_location(&self) -> Option { - Some(self.source_location()) - } - - fn union_parts( - &self, - _resets: Resets, - _args_resets: Vec, - _pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result<(), DeduceResetsError> { - Ok(()) - } - - fn new( - &self, - ty: CanonicalType, - _new_args: Vec>, - ) -> Result { - Ok(Self::new_unchecked( - self.scoped_name(), - self.source_location(), - ty, - )) - } -} - -impl From> for AnyReg { - fn from(value: Reg) -> Self { - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = Reg; - type Output = AnyReg; - - fn reset(self, input: Self::Input) -> Self::Output { - AnyReg::Reg(input) - } - - fn sync_reset(self, input: Self::Input) -> Self::Output { - AnyReg::RegSync(input) - } - - fn async_reset(self, input: Self::Input) -> Self::Output { - AnyReg::RegAsync(input) - } - } - T::dispatch(value, Dispatch) - } -} - -impl RunPassDispatch for AnyReg { - fn build_reset_graph( - &self, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError> { - match_any_reg!(self, |reg: &Reg| { - pass_args - .get_or_make_resets(Expr::canonical(reg.to_expr()), Some(reg.source_location())); - reg.init().run_pass(pass_args.as_mut())?; - Expr::canonical(reg.clock_domain()).run_pass(pass_args)?; - Ok(PassOutput(())) - }) - } - - fn substitute_resets( - &self, - mut pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError> { - match_any_reg!(self, |reg: &Reg| { - let scoped_name = reg.scoped_name(); - let source_location = reg.source_location(); - let resets = pass_args - .get_resets(Expr::canonical(reg.to_expr())) - .expect("added resets in build_reset_graph"); - let ty = resets.substituted_type( - &mut pass_args.state.reset_graph, - pass_args.state.fallback_to_sync_reset, - source_location, - )?; - let init = reg.init().run_pass(pass_args.as_mut())?.0; - let clock_domain = Expr::::from_canonical( - Expr::canonical(reg.clock_domain()).run_pass(pass_args)?.0, - ); - match Expr::ty(clock_domain) - .field_by_name("rst".intern()) - .expect("ClockDomain has rst field") - .ty - { - CanonicalType::AsyncReset(_) => { - Ok(PassOutput(AnyReg::RegAsync(Reg::new_unchecked( - scoped_name, - source_location, - ty, - Expr::from_bundle(clock_domain), - init, - )))) - } - CanonicalType::SyncReset(_) => Ok(PassOutput(AnyReg::RegSync(Reg::new_unchecked( - scoped_name, - source_location, - ty, - Expr::from_bundle(clock_domain), - init, - )))), - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::Array(_) - | CanonicalType::Enum(_) - | CanonicalType::Bundle(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) => unreachable!(), - } - }) - } -} - -impl RunPassDispatch for Instance { - fn build_reset_graph( - &self, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError> { - self.instantiated().run_pass(PassArgs:: { - state: pass_args.state, - instantiated_module: InstantiatedModule::Child { - parent: pass_args.instantiated_module.intern_sized(), - instance: self.intern(), - }, - fallback_error_source_location: self.instantiated().source_location(), - _phantom: PhantomData, - })?; - let (resets, _) = pass_args.get_or_make_resets(self, Some(self.source_location())); - for (resets_field, module_io) in resets.bundle_fields().zip(self.instantiated().module_io()) - { - let (module_io_resets, _) = pass_args.get_or_make_resets( - module_io.module_io, - Some(self.instantiated().source_location()), - ); - pass_args.union(resets_field, module_io_resets, Some(self.source_location()))?; - } - Ok(PassOutput(())) - } - - fn substitute_resets( - &self, - pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError> { - let PassOutput(instantiated) = - self.instantiated().run_pass(PassArgs:: { - state: pass_args.state, - instantiated_module: InstantiatedModule::Child { - parent: pass_args.instantiated_module.intern_sized(), - instance: self.intern(), - }, - fallback_error_source_location: self.instantiated().source_location(), - _phantom: PhantomData, - })?; - Ok(PassOutput(Self::new_unchecked( - self.scoped_name(), - instantiated, - self.source_location(), - ))) - } -} - -macro_rules! impl_run_pass_copy { - ([$($generics:tt)*] $ty:ty) => { - impl RunPass

for $ty { - fn run_pass( - &self, - _pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(PassOutput::new(*self)) - } - } - }; -} - -macro_rules! impl_run_pass_clone { - ([$($generics:tt)*] $ty:ty) => { - impl RunPass

for $ty { - fn run_pass( - &self, - _pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - Ok(PassOutput::from_fn(|| self.clone())) - } - } - }; -} - -impl_run_pass_clone!([] BigInt); -impl_run_pass_clone!([] SIntValue); -impl_run_pass_clone!([] std::ops::Range); -impl_run_pass_clone!([] UIntValue); -impl_run_pass_copy!([] BlackBoxInlineAnnotation); -impl_run_pass_copy!([] BlackBoxPathAnnotation); -impl_run_pass_copy!([] bool); -impl_run_pass_copy!([] CustomFirrtlAnnotation); -impl_run_pass_copy!([] DocStringAnnotation); -impl_run_pass_copy!([] DontTouchAnnotation); -impl_run_pass_copy!([] ExternModuleBody); -impl_run_pass_copy!([] Interned); -impl_run_pass_copy!([] NameId); -impl_run_pass_copy!([] SInt); -impl_run_pass_copy!([] SourceLocation); -impl_run_pass_copy!([] SVAttributeAnnotation); -impl_run_pass_copy!([] UInt); -impl_run_pass_copy!([] usize); -impl_run_pass_copy!([] FormalKind); -impl_run_pass_copy!([] PhantomConst); - -macro_rules! impl_run_pass_for_struct { - ( - $(#[adjust_pass_args = $adjust_pass_args:expr])? - #[constructor = $constructor:expr] - impl[$($generics:tt)*] $RunPass:ident for $ty:ty { - $($field:ident $(($($args:tt)*))?: _,)* - } - ) => { - impl $RunPass

for $ty { - #[allow(unused_mut, unused_variables)] - fn run_pass( - &self, - mut pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - $($adjust_pass_args(self, &mut pass_args);)? - Ok(($(self.$field$(($($args)*))?.run_pass(pass_args.as_mut())?,)*).call(|($($field,)*)| $constructor)) - } - } - }; - ( - $(#[adjust_pass_args = $adjust_pass_args:expr])? - impl[$($generics:tt)*] $RunPass:ident for $ty:ty { - $($field:ident: _,)* - } - ) => { - impl_run_pass_for_struct! { - $(#[adjust_pass_args = $adjust_pass_args])? - #[constructor = { - type Ty = T; - Ty::<$ty> { $($field,)* } - }] - impl[$($generics)*] $RunPass for $ty { - $($field: _,)* - } - } - }; -} - -macro_rules! impl_run_pass_for_enum { - (impl[$($generics:tt)*] $RunPass:ident for $ty:ty { - $($variant:ident($arg:ident),)* - }) => { - impl $RunPass

for $ty { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - type Ty = T; - match self { - $(Ty::<$ty>::$variant($arg) => Ok($arg.run_pass(pass_args)?.map(<$ty>::$variant)),)* - } - } - } - }; -} - -macro_rules! impl_run_pass_for_unary_op { - ($path:path) => { - impl_run_pass_for_struct! { - #[constructor = <$path>::new(arg)] - impl[] RunPass for $path { - arg(): _, - } - } - }; -} - -impl_run_pass_for_unary_op!(ops::NotU); -impl_run_pass_for_unary_op!(ops::NotS); -impl_run_pass_for_unary_op!(ops::NotB); -impl_run_pass_for_unary_op!(ops::Neg); -impl_run_pass_for_unary_op!(ops::CastBoolToUInt); -impl_run_pass_for_unary_op!(ops::CastBoolToSInt); -impl_run_pass_for_unary_op!(ops::CastUIntToBool); -impl_run_pass_for_unary_op!(ops::CastSIntToBool); -impl_run_pass_for_unary_op!(ops::CastBoolToClock); -impl_run_pass_for_unary_op!(ops::CastUIntToClock); -impl_run_pass_for_unary_op!(ops::CastSIntToClock); -impl_run_pass_for_unary_op!(ops::CastClockToBool); -impl_run_pass_for_unary_op!(ops::CastClockToUInt); -impl_run_pass_for_unary_op!(ops::CastClockToSInt); -impl_run_pass_for_unary_op!(ops::ReduceBitAndU); -impl_run_pass_for_unary_op!(ops::ReduceBitAndS); -impl_run_pass_for_unary_op!(ops::ReduceBitOrU); -impl_run_pass_for_unary_op!(ops::ReduceBitOrS); -impl_run_pass_for_unary_op!(ops::ReduceBitXorU); -impl_run_pass_for_unary_op!(ops::ReduceBitXorS); - -macro_rules! impl_run_pass_for_binary_op { - ($path:path) => { - impl_run_pass_for_struct! { - #[constructor = <$path>::new(lhs, rhs)] - impl[] RunPass for $path { - lhs(): _, - rhs(): _, - } - } - }; -} - -impl_run_pass_for_binary_op!(ops::BitAndU); -impl_run_pass_for_binary_op!(ops::BitAndS); -impl_run_pass_for_binary_op!(ops::BitAndB); -impl_run_pass_for_binary_op!(ops::BitOrU); -impl_run_pass_for_binary_op!(ops::BitOrS); -impl_run_pass_for_binary_op!(ops::BitOrB); -impl_run_pass_for_binary_op!(ops::BitXorU); -impl_run_pass_for_binary_op!(ops::BitXorS); -impl_run_pass_for_binary_op!(ops::BitXorB); -impl_run_pass_for_binary_op!(ops::AddU); -impl_run_pass_for_binary_op!(ops::AddS); -impl_run_pass_for_binary_op!(ops::SubU); -impl_run_pass_for_binary_op!(ops::SubS); -impl_run_pass_for_binary_op!(ops::MulU); -impl_run_pass_for_binary_op!(ops::MulS); -impl_run_pass_for_binary_op!(ops::DivU); -impl_run_pass_for_binary_op!(ops::DivS); -impl_run_pass_for_binary_op!(ops::RemU); -impl_run_pass_for_binary_op!(ops::RemS); -impl_run_pass_for_binary_op!(ops::DynShlU); -impl_run_pass_for_binary_op!(ops::DynShlS); -impl_run_pass_for_binary_op!(ops::DynShrU); -impl_run_pass_for_binary_op!(ops::DynShrS); -impl_run_pass_for_binary_op!(ops::FixedShlU); -impl_run_pass_for_binary_op!(ops::FixedShlS); -impl_run_pass_for_binary_op!(ops::FixedShrU); -impl_run_pass_for_binary_op!(ops::FixedShrS); -impl_run_pass_for_binary_op!(ops::CmpLtB); -impl_run_pass_for_binary_op!(ops::CmpLeB); -impl_run_pass_for_binary_op!(ops::CmpGtB); -impl_run_pass_for_binary_op!(ops::CmpGeB); -impl_run_pass_for_binary_op!(ops::CmpEqB); -impl_run_pass_for_binary_op!(ops::CmpNeB); -impl_run_pass_for_binary_op!(ops::CmpLtU); -impl_run_pass_for_binary_op!(ops::CmpLeU); -impl_run_pass_for_binary_op!(ops::CmpGtU); -impl_run_pass_for_binary_op!(ops::CmpGeU); -impl_run_pass_for_binary_op!(ops::CmpEqU); -impl_run_pass_for_binary_op!(ops::CmpNeU); -impl_run_pass_for_binary_op!(ops::CmpLtS); -impl_run_pass_for_binary_op!(ops::CmpLeS); -impl_run_pass_for_binary_op!(ops::CmpGtS); -impl_run_pass_for_binary_op!(ops::CmpGeS); -impl_run_pass_for_binary_op!(ops::CmpEqS); -impl_run_pass_for_binary_op!(ops::CmpNeS); - -macro_rules! impl_run_pass_for_int_cast_op { - ($path:path) => { - impl_run_pass_for_struct! { - #[constructor = <$path>::new(arg, ty)] - impl[] RunPass for $path { - arg(): _, - ty(): _, - } - } - }; -} - -impl_run_pass_for_int_cast_op!(ops::CastUIntToUInt); -impl_run_pass_for_int_cast_op!(ops::CastUIntToSInt); -impl_run_pass_for_int_cast_op!(ops::CastSIntToUInt); -impl_run_pass_for_int_cast_op!(ops::CastSIntToSInt); - -impl_run_pass_for_struct! { - #[constructor = ops::SliceUInt::new(base, range)] - impl[] RunPass for ops::SliceUInt { - base(): _, - range(): _, - } -} - -impl_run_pass_for_struct! { - #[constructor = ops::SliceSInt::new(base, range)] - impl[] RunPass for ops::SliceSInt { - base(): _, - range(): _, - } -} - -impl_run_pass_for_struct! { - #[constructor = ops::CastToBits::new(arg)] - impl[] RunPass for ops::CastToBits { - arg(): _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for StmtFormal { - kind: _, - clk: _, - pred: _, - en: _, - text: _, - source_location: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for StmtIf { - cond: _, - source_location: _, - blocks: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for StmtMatch { - expr: _, - source_location: _, - blocks: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for StmtWire { - annotations: _, - wire: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for StmtInstance { - annotations: _, - instance: _, - } -} - -impl_run_pass_for_enum! { - impl[] RunPass for Stmt { - Connect(v), - Formal(v), - If(v), - Match(v), - Declaration(v), - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for Block { - memories: _, - stmts: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for NormalModuleBody { - body: _, - } -} - -impl_run_pass_copy!([] MemPort); // Mem can't contain any `Reset` types -impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types - -impl RunPassDispatch for StmtConnect { - fn build_reset_graph( - &self, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError> { - let Self { - lhs, - rhs, - source_location, - } = *self; - pass_args.fallback_error_source_location = source_location; - lhs.run_pass(pass_args.as_mut())?; - rhs.run_pass(pass_args.as_mut())?; - let (lhs_resets, _) = pass_args.get_or_make_resets(lhs, Some(source_location)); - let (rhs_resets, _) = pass_args.get_or_make_resets(rhs, Some(source_location)); - pass_args.union(lhs_resets, rhs_resets, Some(source_location))?; - Ok(PassOutput(())) - } - - fn substitute_resets( - &self, - mut pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError> { - let StmtConnect { - lhs, - rhs, - source_location, - } = *self; - pass_args.fallback_error_source_location = source_location; - let lhs = lhs.run_pass(pass_args.as_mut())?.0; - let rhs = rhs.run_pass(pass_args)?.0; - Ok(PassOutput(StmtConnect { - lhs, - rhs, - source_location, - })) - } -} - -impl RunPass

for TargetBase { - fn run_pass( - &self, - pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - let reg: AnyReg = match self { - TargetBase::ModuleIO(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::ModuleIO)), - TargetBase::MemPort(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::MemPort)), - &TargetBase::Reg(v) => v.into(), - &TargetBase::RegSync(v) => v.into(), - &TargetBase::RegAsync(v) => v.into(), - TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)), - TargetBase::Instance(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Instance)), - }; - Ok(reg.run_pass(pass_args)?.map(|reg| match reg { - AnyReg::Reg(reg) => TargetBase::Reg(reg), - AnyReg::RegSync(reg) => TargetBase::RegSync(reg), - AnyReg::RegAsync(reg) => TargetBase::RegAsync(reg), - })) - } -} - -impl RunPass

for StmtDeclaration { - fn run_pass( - &self, - mut pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - let (annotations, reg) = match self { - StmtDeclaration::Wire(v) => { - return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Wire)) - } - &StmtDeclaration::Reg(StmtReg { annotations, reg }) => (annotations, AnyReg::from(reg)), - &StmtDeclaration::RegSync(StmtReg { annotations, reg }) => { - (annotations, AnyReg::from(reg)) - } - &StmtDeclaration::RegAsync(StmtReg { annotations, reg }) => { - (annotations, AnyReg::from(reg)) - } - StmtDeclaration::Instance(v) => { - return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Instance)) - } - }; - let annotations = annotations.run_pass(pass_args.as_mut())?; - let reg = reg.run_pass(pass_args)?; - Ok((annotations, reg).call(|(annotations, reg)| match reg { - AnyReg::Reg(reg) => StmtReg { annotations, reg }.into(), - AnyReg::RegSync(reg) => StmtReg { annotations, reg }.into(), - AnyReg::RegAsync(reg) => StmtReg { annotations, reg }.into(), - })) - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathBundleField { - name: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathArrayElement { - index: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathDynArrayElement {} -} - -impl_run_pass_for_enum! { - impl[] RunPass for TargetPathElement { - BundleField(v), - ArrayElement(v), - DynArrayElement(v), - } -} - -impl_run_pass_for_enum! { - impl[] RunPass for Target { - Base(v), - Child(v), - } -} - -impl_run_pass_for_struct! { - #[constructor = TargetChild::new(parent, path_element)] - impl[] RunPass for TargetChild { - parent(): _, - path_element(): _, - } -} - -impl_run_pass_for_enum! { - impl[] RunPass for Annotation { - DontTouch(v), - SVAttribute(v), - BlackBoxInline(v), - BlackBoxPath(v), - DocString(v), - CustomFirrtl(v), - } -} - -impl_run_pass_for_enum! { - impl[] RunPass for ModuleBody { - Normal(v), - Extern(v), - } -} - -impl_run_pass_for_struct! { - #[constructor = TargetedAnnotation::new(target, annotation)] - impl[] RunPass for TargetedAnnotation { - target(): _, - annotation(): _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for AnnotatedModuleIO { - annotations: _, - module_io: _, - } -} - -impl RunPassDispatch for Module { - fn build_reset_graph( - &self, - mut pass_args: PassArgs<'_, BuildResetGraph>, - ) -> Result, DeduceResetsError> { - pass_args.fallback_error_source_location = self.source_location(); - if pass_args - .state - .modules_added_to_graph - .insert(pass_args.instantiated_module) - { - self.name_id().run_pass(pass_args.as_mut())?; - self.source_location().run_pass(pass_args.as_mut())?; - self.module_io().run_pass(pass_args.as_mut())?; - self.body().run_pass(pass_args.as_mut())?; - self.module_annotations().run_pass(pass_args.as_mut())?; - } - Ok(PassOutput(())) - } - - fn substitute_resets( - &self, - mut pass_args: PassArgs<'_, SubstituteResets>, - ) -> Result, DeduceResetsError> { - pass_args.fallback_error_source_location = self.source_location(); - if let Some(&retval) = pass_args - .state - .substituted_modules - .get(&pass_args.instantiated_module) - { - return Ok(PassOutput(retval)); - } - let PassOutput(name_id) = self.name_id().run_pass(pass_args.as_mut())?; - let PassOutput(source_location) = self.source_location().run_pass(pass_args.as_mut())?; - let PassOutput(module_io) = self.module_io().run_pass(pass_args.as_mut())?; - let PassOutput(body) = self.body().run_pass(pass_args.as_mut())?; - let PassOutput(module_annotations) = - self.module_annotations().run_pass(pass_args.as_mut())?; - let retval = Module::new_unchecked( - name_id, - source_location, - body, - module_io, - module_annotations, - ); - pass_args - .state - .substituted_modules - .insert(pass_args.instantiated_module, retval); - Ok(PassOutput(retval)) - } -} - -pub fn deduce_resets( - module: Interned>, - fallback_to_sync_reset: bool, -) -> Result>, DeduceResetsError> { - let mut state = State { - modules_added_to_graph: HashSet::default(), - substituted_modules: HashMap::default(), - expr_resets: HashMap::default(), - reset_graph: ResetGraph::default(), - fallback_to_sync_reset, - }; - RunPass::::run_pass( - &*module, - PassArgs { - state: &mut state, - instantiated_module: InstantiatedModule::Base(module), - fallback_error_source_location: module.source_location(), - _phantom: PhantomData, - }, - )?; - Ok(RunPass::::run_pass( - &*module, - PassArgs { - state: &mut state, - instantiated_module: InstantiatedModule::Base(module), - fallback_error_source_location: module.source_location(), - _phantom: PhantomData, - }, - )? - .0 - .intern_sized()) -} diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index 333451d..91bbba5 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -2,26 +2,26 @@ // See Notices.txt for copyright information use crate::{ array::{Array, ArrayType}, - bundle::{Bundle, BundleField, BundleType}, + bundle::{Bundle, BundleType}, enum_::{Enum, EnumType, EnumVariant}, expr::{ ops::{self, EnumLiteral}, - CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, + CastBitsTo, CastToBits, Expr, ExprEnum, ToExpr, }, hdl, - int::UInt, - intern::{Intern, Interned, Memoize}, + int::{DynSize, IntCmp, Size, UInt, UIntType}, + intern::{Intern, Interned}, memory::{DynPortType, Mem, MemPort}, module::{ transform::visit::{Fold, Folder}, - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, + Block, Module, NameIdGen, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, }, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::HashMap, wire::Wire, }; use core::fmt; +use hashbrown::HashMap; #[derive(Debug)] pub enum SimplifyEnumsError { @@ -41,71 +41,25 @@ impl fmt::Display for SimplifyEnumsError { impl std::error::Error for SimplifyEnumsError {} -impl From for std::io::Error { - fn from(value: SimplifyEnumsError) -> Self { - std::io::Error::new(std::io::ErrorKind::Other, value) - } -} - -fn contains_any_enum_types(ty: CanonicalType) -> bool { - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - struct TheMemoize; - impl Memoize for TheMemoize { - type Input = CanonicalType; - type InputOwned = CanonicalType; - type Output = bool; - - fn inner(self, ty: &Self::Input) -> Self::Output { - match *ty { - CanonicalType::Array(array_type) => contains_any_enum_types(array_type.element()), - CanonicalType::Enum(_) => true, - CanonicalType::Bundle(bundle) => bundle - .fields() - .iter() - .any(|field| contains_any_enum_types(field.ty)), - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) => false, - } - } - } - TheMemoize.get_owned(ty) -} - #[hdl] -struct TagAndBody { - tag: Tag, - body: Body, +struct TagAndBody { + tag: T, + body: UIntType, } #[derive(Clone, Debug)] enum EnumTypeState { - TagEnumAndBody(TagAndBody), - TagUIntAndBody(TagAndBody), + TagEnumAndBody(TagAndBody), + TagUIntAndBody(TagAndBody), UInt(UInt), Unchanged, } -struct ModuleState { - module_name: NameId, -} - -impl ModuleState { - fn gen_name(&mut self, name: &str) -> ScopedNameId { - ScopedNameId(self.module_name, NameId(name.intern(), Id::new())) - } -} - struct State { enum_types: HashMap, replacement_mem_ports: HashMap, Wire>, kind: SimplifyEnumsKind, - module_state_stack: Vec, + name_id_gen: NameIdGen, } impl State { @@ -153,370 +107,6 @@ impl State { self.enum_types.insert(enum_type, retval.clone()); Ok(retval) } - #[hdl] - fn handle_enum_literal( - &mut self, - unfolded_enum_type: Enum, - variant_index: usize, - folded_variant_value: Option>, - ) -> Result, SimplifyEnumsError> { - Ok( - match self.get_or_make_enum_type_state(unfolded_enum_type)? { - EnumTypeState::TagEnumAndBody(TagAndBody { tag, body }) => Expr::canonical( - #[hdl] - TagAndBody { - tag: EnumLiteral::new_by_index(tag, variant_index, None), - body: match folded_variant_value { - Some(variant_value) => variant_value.cast_to_bits().cast_to(body), - None => body.zero().to_expr(), - }, - }, - ), - EnumTypeState::TagUIntAndBody(TagAndBody { tag, body }) => Expr::canonical( - #[hdl] - TagAndBody { - tag: tag.from_int_wrapping(variant_index), - body: match folded_variant_value { - Some(folded_variant_value) => { - folded_variant_value.cast_to_bits().cast_to(body) - } - None => body.zero().to_expr(), - }, - }, - ), - EnumTypeState::UInt(_) => { - let tag = UInt[unfolded_enum_type.discriminant_bit_width()]; - let body = UInt[unfolded_enum_type.type_properties().bit_width - tag.width()]; - Expr::canonical( - (#[hdl] - TagAndBody { - tag: tag.from_int_wrapping(variant_index), - body: match folded_variant_value { - Some(folded_variant_value) => { - folded_variant_value.cast_to_bits().cast_to(body) - } - None => body.zero().to_expr(), - }, - }) - .cast_to_bits(), - ) - } - EnumTypeState::Unchanged => Expr::canonical( - ops::EnumLiteral::new_by_index( - unfolded_enum_type, - variant_index, - folded_variant_value, - ) - .to_expr(), - ), - }, - ) - } - fn handle_variant_access( - &mut self, - unfolded_enum_type: Enum, - folded_base_expr: Expr, - variant_index: usize, - ) -> Result, SimplifyEnumsError> { - let unfolded_variant_type = unfolded_enum_type.variants()[variant_index].ty; - Ok( - match self.get_or_make_enum_type_state(unfolded_enum_type)? { - EnumTypeState::TagEnumAndBody(_) | EnumTypeState::TagUIntAndBody(_) => { - match unfolded_variant_type { - Some(variant_type) => Expr::canonical( - Expr::>::from_canonical( - folded_base_expr, - ) - .body[..variant_type.bit_width()] - .cast_bits_to(variant_type.fold(self)?), - ), - None => Expr::canonical(().to_expr()), - } - } - EnumTypeState::UInt(_) => match unfolded_variant_type { - Some(variant_type) => { - let base_int = Expr::::from_canonical(folded_base_expr); - let variant_type_bit_width = variant_type.bit_width(); - Expr::canonical( - base_int[unfolded_enum_type.discriminant_bit_width()..] - [..variant_type_bit_width] - .cast_bits_to(variant_type.fold(self)?), - ) - } - None => Expr::canonical(().to_expr()), - }, - EnumTypeState::Unchanged => match unfolded_variant_type { - Some(_) => ops::VariantAccess::new_by_index( - Expr::from_canonical(folded_base_expr), - variant_index, - ) - .to_expr(), - None => Expr::canonical(().to_expr()), - }, - }, - ) - } - fn handle_match( - &mut self, - unfolded_enum_type: Enum, - folded_expr: Expr, - source_location: SourceLocation, - folded_blocks: &[Block], - ) -> Result { - match self.get_or_make_enum_type_state(unfolded_enum_type)? { - EnumTypeState::TagEnumAndBody(_) => Ok(StmtMatch { - expr: Expr::>::from_canonical(folded_expr).tag, - source_location, - blocks: folded_blocks.intern(), - } - .into()), - EnumTypeState::TagUIntAndBody(_) => { - let int_tag_expr = Expr::>::from_canonical(folded_expr).tag; - Ok(match_int_tag(int_tag_expr, source_location, folded_blocks).into()) - } - EnumTypeState::UInt(_) => { - let int_tag_expr = Expr::::from_canonical(folded_expr) - [..unfolded_enum_type.discriminant_bit_width()]; - Ok(match_int_tag(int_tag_expr, source_location, folded_blocks).into()) - } - EnumTypeState::Unchanged => Ok(StmtMatch { - expr: Expr::from_canonical(folded_expr), - source_location, - blocks: folded_blocks.intern(), - } - .into()), - } - } - fn handle_stmt_connect_array( - &mut self, - unfolded_lhs_ty: Array, - unfolded_rhs_ty: Array, - folded_lhs: Expr, - folded_rhs: Expr, - source_location: SourceLocation, - output_stmts: &mut Vec, - ) -> Result<(), SimplifyEnumsError> { - assert_eq!(unfolded_lhs_ty.len(), unfolded_rhs_ty.len()); - let unfolded_lhs_element_ty = unfolded_lhs_ty.element(); - let unfolded_rhs_element_ty = unfolded_rhs_ty.element(); - for array_index in 0..unfolded_lhs_ty.len() { - self.handle_stmt_connect( - unfolded_lhs_element_ty, - unfolded_rhs_element_ty, - folded_lhs[array_index], - folded_rhs[array_index], - source_location, - output_stmts, - )?; - } - Ok(()) - } - fn handle_stmt_connect_bundle( - &mut self, - unfolded_lhs_ty: Bundle, - unfolded_rhs_ty: Bundle, - folded_lhs: Expr, - folded_rhs: Expr, - source_location: SourceLocation, - output_stmts: &mut Vec, - ) -> Result<(), SimplifyEnumsError> { - let unfolded_lhs_fields = unfolded_lhs_ty.fields(); - let unfolded_rhs_fields = unfolded_rhs_ty.fields(); - assert_eq!(unfolded_lhs_fields.len(), unfolded_rhs_fields.len()); - for ( - field_index, - ( - &BundleField { - name, - flipped, - ty: unfolded_lhs_field_ty, - }, - unfolded_rhs_field, - ), - ) in unfolded_lhs_fields - .iter() - .zip(&unfolded_rhs_fields) - .enumerate() - { - assert_eq!(name, unfolded_rhs_field.name); - assert_eq!(flipped, unfolded_rhs_field.flipped); - let folded_lhs_field = - ops::FieldAccess::new_by_index(folded_lhs, field_index).to_expr(); - let folded_rhs_field = - ops::FieldAccess::new_by_index(folded_rhs, field_index).to_expr(); - if flipped { - // swap lhs/rhs - self.handle_stmt_connect( - unfolded_rhs_field.ty, - unfolded_lhs_field_ty, - folded_rhs_field, - folded_lhs_field, - source_location, - output_stmts, - )?; - } else { - self.handle_stmt_connect( - unfolded_lhs_field_ty, - unfolded_rhs_field.ty, - folded_lhs_field, - folded_rhs_field, - source_location, - output_stmts, - )?; - } - } - Ok(()) - } - fn handle_stmt_connect_enum( - &mut self, - unfolded_lhs_ty: Enum, - unfolded_rhs_ty: Enum, - folded_lhs: Expr, - folded_rhs: Expr, - source_location: SourceLocation, - output_stmts: &mut Vec, - ) -> Result<(), SimplifyEnumsError> { - let unfolded_lhs_variants = unfolded_lhs_ty.variants(); - let unfolded_rhs_variants = unfolded_rhs_ty.variants(); - assert_eq!(unfolded_lhs_variants.len(), unfolded_rhs_variants.len()); - let mut folded_blocks = vec![]; - for ( - variant_index, - ( - &EnumVariant { - name, - ty: unfolded_lhs_variant_ty, - }, - unfolded_rhs_variant, - ), - ) in unfolded_lhs_variants - .iter() - .zip(&unfolded_rhs_variants) - .enumerate() - { - let mut output_stmts = vec![]; - assert_eq!(name, unfolded_rhs_variant.name); - assert_eq!( - unfolded_lhs_variant_ty.is_some(), - unfolded_rhs_variant.ty.is_some() - ); - let folded_variant_value = - if let (Some(unfolded_lhs_variant_ty), Some(unfolded_rhs_variant_ty)) = - (unfolded_lhs_variant_ty, unfolded_rhs_variant.ty) - { - let lhs_wire = Wire::new_unchecked( - self.module_state_stack - .last_mut() - .unwrap() - .gen_name("__connect_variant_body"), - source_location, - unfolded_lhs_variant_ty.fold(self)?, - ); - output_stmts.push( - StmtWire { - annotations: Interned::default(), - wire: lhs_wire, - } - .into(), - ); - let lhs_wire = lhs_wire.to_expr(); - let folded_rhs_variant = - self.handle_variant_access(unfolded_rhs_ty, folded_rhs, variant_index)?; - self.handle_stmt_connect( - unfolded_lhs_variant_ty, - unfolded_rhs_variant_ty, - lhs_wire, - folded_rhs_variant, - source_location, - &mut output_stmts, - )?; - Some(lhs_wire) - } else { - None - }; - output_stmts.push( - StmtConnect { - lhs: folded_lhs, - rhs: self.handle_enum_literal( - unfolded_lhs_ty, - variant_index, - folded_variant_value, - )?, - source_location, - } - .into(), - ); - folded_blocks.push(Block { - memories: Interned::default(), - stmts: Intern::intern_owned(output_stmts), - }); - } - output_stmts.push(self.handle_match( - unfolded_rhs_ty, - folded_rhs, - source_location, - &folded_blocks, - )?); - Ok(()) - } - fn handle_stmt_connect( - &mut self, - unfolded_lhs_ty: CanonicalType, - unfolded_rhs_ty: CanonicalType, - folded_lhs: Expr, - folded_rhs: Expr, - source_location: SourceLocation, - output_stmts: &mut Vec, - ) -> Result<(), SimplifyEnumsError> { - let needs_expansion = unfolded_lhs_ty != unfolded_rhs_ty - && (contains_any_enum_types(unfolded_lhs_ty) - || contains_any_enum_types(unfolded_rhs_ty)); - if !needs_expansion { - output_stmts.push( - StmtConnect { - lhs: folded_lhs, - rhs: folded_rhs, - source_location, - } - .into(), - ); - return Ok(()); - } - match unfolded_lhs_ty { - CanonicalType::Array(unfolded_lhs_ty) => self.handle_stmt_connect_array( - unfolded_lhs_ty, - Array::from_canonical(unfolded_rhs_ty), - Expr::from_canonical(folded_lhs), - Expr::from_canonical(folded_rhs), - source_location, - output_stmts, - ), - CanonicalType::Enum(unfolded_lhs_ty) => self.handle_stmt_connect_enum( - unfolded_lhs_ty, - Enum::from_canonical(unfolded_rhs_ty), - folded_lhs, - folded_rhs, - source_location, - output_stmts, - ), - CanonicalType::Bundle(unfolded_lhs_ty) => self.handle_stmt_connect_bundle( - unfolded_lhs_ty, - Bundle::from_canonical(unfolded_rhs_ty), - Expr::from_canonical(folded_lhs), - Expr::from_canonical(folded_rhs), - source_location, - output_stmts, - ), - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) => unreachable!(), - } - } } fn connect_port( @@ -527,11 +117,11 @@ fn connect_port( ) { if Expr::ty(lhs) == Expr::ty(rhs) { stmts.push( - StmtConnect { + dbg!(StmtConnect { lhs, rhs, source_location, - } + }) .into(), ); return; @@ -579,8 +169,7 @@ fn connect_port( | (CanonicalType::Clock(_), _) | (CanonicalType::AsyncReset(_), _) | (CanonicalType::SyncReset(_), _) - | (CanonicalType::Reset(_), _) - | (CanonicalType::PhantomConst(_), _) => unreachable!( + | (CanonicalType::Reset(_), _) => unreachable!( "trying to connect memory ports:\n{:?}\n{:?}", Expr::ty(lhs), Expr::ty(rhs), @@ -588,42 +177,6 @@ fn connect_port( } } -fn match_int_tag( - int_tag_expr: Expr, - source_location: SourceLocation, - folded_blocks: &[Block], -) -> StmtIf { - let mut blocks_iter = folded_blocks.iter().copied().enumerate(); - let (_, last_block) = blocks_iter.next_back().unwrap_or_default(); - let Some((next_to_last_variant_index, next_to_last_block)) = blocks_iter.next_back() else { - return StmtIf { - cond: true.to_expr(), - source_location, - blocks: [last_block, Block::default()], - }; - }; - let mut retval = StmtIf { - cond: int_tag_expr - .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(next_to_last_variant_index)), - source_location, - blocks: [next_to_last_block, last_block], - }; - for (variant_index, block) in blocks_iter.rev() { - retval = StmtIf { - cond: int_tag_expr.cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(variant_index)), - source_location, - blocks: [ - block, - Block { - memories: Default::default(), - stmts: [Stmt::from(retval)][..].intern(), - }, - ], - }; - } - retval -} - impl Folder for State { type Error = SimplifyEnumsError; @@ -632,32 +185,96 @@ impl Folder for State { } fn fold_module(&mut self, v: Module) -> Result, Self::Error> { - self.module_state_stack.push(ModuleState { - module_name: v.name_id(), - }); + let old_name_id_gen = + std::mem::replace(&mut self.name_id_gen, NameIdGen::for_module(v.canonical())); let retval = Fold::default_fold(v, self); - self.module_state_stack.pop(); + self.name_id_gen = old_name_id_gen; retval } fn fold_expr_enum(&mut self, op: ExprEnum) -> Result { match op { - ExprEnum::EnumLiteral(op) => { - let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?; - Ok(*Expr::expr_enum(self.handle_enum_literal( + ExprEnum::EnumLiteral(op) => Ok(match self.get_or_make_enum_type_state(op.ty())? { + EnumTypeState::TagEnumAndBody(TagAndBody { tag, body }) => *Expr::expr_enum( + as BundleType>::Builder::default() + .field_tag(EnumLiteral::new_by_index(tag, op.variant_index(), None)) + .field_body(match op.variant_value() { + Some(variant_value) => variant_value.fold(self)?.cast_to_bits(), + None => body.zero().to_expr(), + }) + .to_expr(), + ), + EnumTypeState::TagUIntAndBody(TagAndBody { tag, body }) => *Expr::expr_enum( + as BundleType>::Builder::default() + .field_tag(tag.from_int_wrapping(op.variant_index())) + .field_body(match op.variant_value() { + Some(variant_value) => variant_value.fold(self)?.cast_to_bits(), + None => body.zero().to_expr(), + }) + .to_expr(), + ), + EnumTypeState::UInt(_) => *Expr::expr_enum( + as BundleType>::Builder::default() + .field_tag( + UIntType::new(op.ty().discriminant_bit_width()) + .from_int_wrapping(op.variant_index()), + ) + .field_body(match op.variant_value() { + Some(variant_value) => variant_value.fold(self)?.cast_to_bits(), + None => UIntType::new( + op.ty().type_properties().bit_width + - op.ty().discriminant_bit_width(), + ) + .zero() + .to_expr(), + }) + .cast_to_bits(), + ), + EnumTypeState::Unchanged => ExprEnum::EnumLiteral(ops::EnumLiteral::new_by_index( op.ty(), op.variant_index(), - folded_variant_value, - )?)) - } - ExprEnum::VariantAccess(op) => { - let folded_base_expr = Expr::canonical(op.base()).fold(self)?; - Ok(*Expr::expr_enum(self.handle_variant_access( - Expr::ty(op.base()), - folded_base_expr, - op.variant_index(), - )?)) - } + op.variant_value().map(|v| v.fold(self)).transpose()?, + )), + }), + ExprEnum::VariantAccess(op) => Ok( + match self.get_or_make_enum_type_state(Expr::ty(op.base()))? { + EnumTypeState::TagEnumAndBody(_) | EnumTypeState::TagUIntAndBody(_) => { + match op.variant_type() { + Some(variant_type) => *Expr::expr_enum( + Expr::>::from_canonical( + (*Expr::expr_enum(op.base())).fold(self)?.to_expr(), + ) + .body[..variant_type.bit_width()] + .cast_bits_to(variant_type), + ), + None => *Expr::expr_enum(().to_expr()), + } + } + EnumTypeState::UInt(_) => match op.variant_type() { + Some(variant_type) => { + let base_int = Expr::::from_canonical( + (*Expr::expr_enum(op.base())).fold(self)?.to_expr(), + ); + dbg!(base_int); + let base_ty = Expr::ty(op.base()); + let variant_type_bit_width = variant_type.bit_width(); + *Expr::expr_enum( + base_int[base_ty.discriminant_bit_width()..] + [..variant_type_bit_width] + .cast_bits_to(variant_type), + ) + } + None => *Expr::expr_enum(().to_expr()), + }, + EnumTypeState::Unchanged => match op.variant_type() { + Some(_) => ExprEnum::VariantAccess(ops::VariantAccess::new_by_index( + op.base().fold(self)?, + op.variant_index(), + )), + None => *Expr::expr_enum(().to_expr()), + }, + }, + ), ExprEnum::MemPort(mem_port) => Ok( if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) { ExprEnum::Wire(wire) @@ -668,10 +285,8 @@ impl Folder for State { ExprEnum::UIntLiteral(_) | ExprEnum::SIntLiteral(_) | ExprEnum::BoolLiteral(_) - | ExprEnum::PhantomConst(_) | ExprEnum::BundleLiteral(_) | ExprEnum::ArrayLiteral(_) - | ExprEnum::Uninit(_) | ExprEnum::NotU(_) | ExprEnum::NotS(_) | ExprEnum::NotB(_) @@ -768,9 +383,7 @@ impl Folder for State { | ExprEnum::ModuleIO(_) | ExprEnum::Instance(_) | ExprEnum::Wire(_) - | ExprEnum::Reg(_) - | ExprEnum::RegSync(_) - | ExprEnum::RegAsync(_) => op.default_fold(self), + | ExprEnum::Reg(_) => op.default_fold(self), } } @@ -804,15 +417,11 @@ impl Folder for State { if wire_ty == new_port_ty { continue; } + let wire_name = self.name_id_gen.gen( + (*format!("{}_{}", memory.scoped_name().1 .0, port.port_name())).intern(), + ); let wire = Wire::new_unchecked( - self.module_state_stack - .last_mut() - .unwrap() - .gen_name(&format!( - "{}_{}", - memory.scoped_name().1 .0, - port.port_name() - )), + ScopedNameId(memory.scoped_name().0, wire_name), port.source_location(), wire_ty, ); @@ -855,50 +464,80 @@ impl Folder for State { } fn fold_stmt(&mut self, stmt: Stmt) -> Result { + fn match_int_tag( + state: &mut State, + int_tag_expr: Expr, + source_location: SourceLocation, + blocks: Interned<[Block]>, + ) -> Result { + let mut blocks_iter = blocks.iter().copied().enumerate(); + let (_, last_block) = blocks_iter.next_back().unwrap_or_default(); + let Some((next_to_last_variant_index, next_to_last_block)) = blocks_iter.next_back() + else { + return Ok(StmtIf { + cond: true.to_expr(), + source_location, + blocks: [last_block.fold(state)?, Block::default()], + }); + }; + let mut retval = StmtIf { + cond: int_tag_expr + .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(next_to_last_variant_index)), + source_location, + blocks: [next_to_last_block.fold(state)?, last_block.fold(state)?], + }; + for (variant_index, block) in blocks_iter.rev() { + retval = StmtIf { + cond: int_tag_expr + .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(variant_index)), + source_location, + blocks: [ + block.fold(state)?, + Block { + memories: Default::default(), + stmts: [Stmt::from(retval)][..].intern(), + }, + ], + }; + } + Ok(retval) + } match stmt { Stmt::Match(StmtMatch { expr, source_location, blocks, - }) => { - let folded_expr = Expr::canonical(expr).fold(self)?; - let folded_blocks = blocks.fold(self)?; - self.handle_match(Expr::ty(expr), folded_expr, source_location, &folded_blocks) - } - Stmt::Connect(StmtConnect { - lhs, - rhs, - source_location, - }) => { - let folded_lhs = lhs.fold(self)?; - let folded_rhs = rhs.fold(self)?; - let mut output_stmts = vec![]; - self.handle_stmt_connect( - Expr::ty(lhs), - Expr::ty(rhs), - folded_lhs, - folded_rhs, + }) => match self.get_or_make_enum_type_state(Expr::ty(expr))? { + EnumTypeState::TagEnumAndBody(_) => Ok(StmtMatch { + expr: Expr::>::from_canonical( + Expr::canonical(expr).fold(self)?, + ) + .tag, source_location, - &mut output_stmts, - )?; - if output_stmts.len() == 1 { - Ok(output_stmts.pop().unwrap()) - } else { - Ok(StmtIf { - cond: true.to_expr(), - source_location, - blocks: [ - Block { - memories: Interned::default(), - stmts: Intern::intern_owned(output_stmts), - }, - Block::default(), - ], - } - .into()) + blocks: blocks.fold(self)?, } - } - Stmt::Formal(_) | Stmt::If(_) | Stmt::Declaration(_) => stmt.default_fold(self), + .into()), + EnumTypeState::TagUIntAndBody(_) => { + let int_tag_expr = Expr::>::from_canonical( + Expr::canonical(expr).fold(self)?, + ) + .tag; + Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into()) + } + EnumTypeState::UInt(_) => { + let int_tag_expr = + Expr::::from_canonical(Expr::canonical(expr).fold(self)?) + [..Expr::ty(expr).discriminant_bit_width()]; + Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into()) + } + EnumTypeState::Unchanged => Ok(StmtMatch { + expr: expr.fold(self)?, + source_location, + blocks: blocks.fold(self)?, + } + .into()), + }, + Stmt::Connect(_) | Stmt::If(_) | Stmt::Declaration(_) => stmt.default_fold(self), } } @@ -927,8 +566,7 @@ impl Folder for State { | CanonicalType::Clock(_) | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::PhantomConst(_) => canonical_type.default_fold(self), + | CanonicalType::Reset(_) => canonical_type.default_fold(self), } } @@ -936,10 +574,13 @@ impl Folder for State { unreachable!() } - fn fold_enum_literal>( + fn fold_enum_literal( &mut self, _v: ops::EnumLiteral, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> + where + T: Fold, + { unreachable!() } @@ -951,12 +592,10 @@ impl Folder for State { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, clap::ValueEnum)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum SimplifyEnumsKind { SimplifyToEnumsWithNoBody, - #[clap(name = "replace-with-bundle-of-uints")] ReplaceWithBundleOfUInts, - #[clap(name = "replace-with-uint")] ReplaceWithUInt, } @@ -965,9 +604,9 @@ pub fn simplify_enums( kind: SimplifyEnumsKind, ) -> Result>, SimplifyEnumsError> { module.fold(&mut State { - enum_types: HashMap::default(), - replacement_mem_ports: HashMap::default(), + enum_types: HashMap::new(), + replacement_mem_ports: HashMap::new(), kind, - module_state_stack: vec![], + name_id_gen: NameIdGen::default(), }) } diff --git a/crates/fayalite/src/module/transform/simplify_memories.rs b/crates/fayalite/src/module/transform/simplify_memories.rs index 6357843..0df1e81 100644 --- a/crates/fayalite/src/module/transform/simplify_memories.rs +++ b/crates/fayalite/src/module/transform/simplify_memories.rs @@ -10,14 +10,15 @@ use crate::{ memory::{Mem, MemPort, PortType}, module::{ transform::visit::{Fold, Folder}, - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtWire, + Block, Module, NameId, NameIdGen, ScopedNameId, Stmt, StmtConnect, StmtWire, }, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::{HashMap, MakeMutSlice}, + util::MakeMutSlice, wire::Wire, }; use bitvec::{slice::BitSlice, vec::BitVec}; +use hashbrown::HashMap; use std::{ convert::Infallible, fmt::Write, @@ -61,7 +62,6 @@ enum MemSplit { Bundle { fields: Rc<[MemSplit]>, }, - PhantomConst, Single { output_mem: Option, element_type: SingleType, @@ -76,7 +76,6 @@ impl MemSplit { fn mark_changed_element_type(self) -> Self { match self { MemSplit::Bundle { fields: _ } => self, - MemSplit::PhantomConst => self, MemSplit::Single { output_mem, element_type, @@ -98,7 +97,6 @@ impl MemSplit { .map(|field| Self::new(field.ty).mark_changed_element_type()) .collect(), }, - CanonicalType::PhantomConst(_) => MemSplit::PhantomConst, CanonicalType::Array(ty) => { let element = MemSplit::new(ty.element()); if let Self::Single { @@ -341,7 +339,6 @@ impl SplitMemState<'_, '_> { self.split_state_stack.pop(); } } - MemSplit::PhantomConst => {} MemSplit::Single { output_mem, element_type: single_type, @@ -420,6 +417,7 @@ impl SplitMemState<'_, '_> { struct ModuleState { output_module: Option>>, + name_id_gen: NameIdGen, memories: HashMap, } @@ -541,12 +539,7 @@ impl ModuleState { }; loop { match input_element_type { - CanonicalType::Bundle(_) => { - unreachable!("bundle types are always split") - } - CanonicalType::PhantomConst(_) => { - unreachable!("PhantomConst are always removed") - } + CanonicalType::Bundle(_) => unreachable!("bundle types are always split"), CanonicalType::Enum(_) if input_array_types .first() @@ -576,7 +569,7 @@ impl ModuleState { port_wmask.map(Expr::from_canonical), connect_read_enum, connect_write_enum, - connect_write, + connect_write_enum, ), CanonicalType::Array(array_type) => { input_array_types.push(array_type); @@ -633,10 +626,10 @@ impl ModuleState { mem_name_path: &str, split_state: &SplitState<'_>, ) -> Mem { - let mem_name = NameId( - Intern::intern_owned(format!("{}{mem_name_path}", input_mem.scoped_name().1 .0)), - Id::new(), - ); + let mem_name = self.name_id_gen.gen(Intern::intern_owned(format!( + "{}{mem_name_path}", + input_mem.scoped_name().1 .0 + ))); let mem_name = ScopedNameId(input_mem.scoped_name().0, mem_name); let output_element_type = match single_type { SingleType::UInt(ty) => ty.canonical(), @@ -751,8 +744,7 @@ impl ModuleState { .. } | MemSplit::Bundle { .. } - | MemSplit::Array { .. } - | MemSplit::PhantomConst => { + | MemSplit::Array { .. } => { let mut replacement_ports = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_rdata = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_wdata = Vec::with_capacity(input_mem.ports().len()); @@ -761,10 +753,9 @@ impl ModuleState { let port_ty = port.ty(); let NameId(mem_name, _) = input_mem.scoped_name().1; let port_name = port.port_name(); - let wire_name = NameId( - Intern::intern_owned(format!("{mem_name}_{port_name}")), - Id::new(), - ); + let wire_name = self + .name_id_gen + .gen(Intern::intern_owned(format!("{mem_name}_{port_name}"))); let wire = Wire::new_unchecked( ScopedNameId(input_mem.scoped_name().0, wire_name), port.source_location(), @@ -775,7 +766,7 @@ impl ModuleState { output_stmts.push( StmtWire { annotations: Default::default(), - wire: canonical_wire, + wire: canonical_wire.clone(), } .into(), ); @@ -896,7 +887,8 @@ impl Folder for State { module, ModuleState { output_module: None, - memories: HashMap::default(), + name_id_gen: NameIdGen::for_module(*module), + memories: HashMap::new(), }, ); let mut this = PushedState::push_module(self, module); diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 526a62c..7edfe04 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -2,10 +2,7 @@ // See Notices.txt for copyright information #![allow(clippy::multiple_bound_locations)] use crate::{ - annotations::{ - Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation, - }, + annotations::{Annotation, CustomFirrtlAnnotation, TargetedAnnotation}, array::ArrayType, bundle::{Bundle, BundleField, BundleType}, clock::Clock, @@ -18,20 +15,17 @@ use crate::{ }, Expr, ExprEnum, }, - formal::FormalKind, int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite}, module::{ AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId, - NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, - StmtInstance, StmtMatch, StmtReg, StmtWire, + NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance, + StmtMatch, StmtReg, StmtWire, }, - phantom_const::PhantomConst, reg::Reg, - reset::{AsyncReset, Reset, ResetType, SyncReset}, - sim::ExternModuleSimulation, + reset::{AsyncReset, Reset, SyncReset}, source_location::SourceLocation, ty::{CanonicalType, Type}, wire::Wire, diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs deleted file mode 100644 index c481692..0000000 --- a/crates/fayalite/src/phantom_const.rs +++ /dev/null @@ -1,410 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - expr::{ - ops::{ExprPartialEq, ExprPartialOrd}, - Expr, ToExpr, - }, - int::Bool, - intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize}, - sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, - source_location::SourceLocation, - ty::{ - impl_match_variant_as_self, - serde_impls::{SerdeCanonicalType, SerdePhantomConst}, - CanonicalType, StaticType, Type, TypeProperties, - }, -}; -use bitvec::slice::BitSlice; -use serde::{ - de::{DeserializeOwned, Error}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use std::{ - any::Any, - fmt, - hash::{Hash, Hasher}, - marker::PhantomData, - ops::Index, -}; - -#[derive(Clone)] -pub struct PhantomConstCanonicalValue { - parsed: serde_json::Value, - serialized: Interned, -} - -impl PhantomConstCanonicalValue { - pub fn from_json_value(parsed: serde_json::Value) -> Self { - let serialized = Intern::intern_owned( - serde_json::to_string(&parsed) - .expect("conversion from json value to text shouldn't fail"), - ); - Self { parsed, serialized } - } - pub fn as_json_value(&self) -> &serde_json::Value { - &self.parsed - } - pub fn as_str(&self) -> Interned { - self.serialized - } -} - -impl fmt::Debug for PhantomConstCanonicalValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.serialized) - } -} - -impl fmt::Display for PhantomConstCanonicalValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.serialized) - } -} - -impl PartialEq for PhantomConstCanonicalValue { - fn eq(&self, other: &Self) -> bool { - self.serialized == other.serialized - } -} - -impl Eq for PhantomConstCanonicalValue {} - -impl Hash for PhantomConstCanonicalValue { - fn hash(&self, state: &mut H) { - self.serialized.hash(state); - } -} - -impl Serialize for PhantomConstCanonicalValue { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.parsed.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for PhantomConstCanonicalValue { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(Self::from_json_value(serde_json::Value::deserialize( - deserializer, - )?)) - } -} - -pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug { - fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>; -} - -impl PhantomConstValue for T -where - T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug, - Interned: DeserializeOwned, -{ - fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - { - as Deserialize<'de>>::deserialize(deserializer) - } -} - -/// Wrapper type that allows any Rust value to be smuggled as a HDL [`Type`]. -/// This only works for values that can be [serialized][Serialize] to and [deserialized][Deserialize] from [JSON][serde_json]. -pub struct PhantomConst { - value: LazyInterned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct PhantomConstWithoutGenerics; - -#[allow(non_upper_case_globals)] -pub const PhantomConst: PhantomConstWithoutGenerics = PhantomConstWithoutGenerics; - -impl Index for PhantomConstWithoutGenerics { - type Output = PhantomConst; - - fn index(&self, value: T) -> &Self::Output { - Interned::into_inner(PhantomConst::new(value.intern()).intern_sized()) - } -} - -impl fmt::Debug for PhantomConst { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("PhantomConst").field(&self.get()).finish() - } -} - -impl Clone for PhantomConst { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for PhantomConst {} - -impl PartialEq for PhantomConst { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -impl Eq for PhantomConst {} - -impl Hash for PhantomConst { - fn hash(&self, state: &mut H) { - self.get().hash(state); - } -} - -struct PhantomConstCanonicalMemoize(PhantomData); - -impl Copy - for PhantomConstCanonicalMemoize -{ -} - -impl Clone - for PhantomConstCanonicalMemoize -{ - fn clone(&self) -> Self { - *self - } -} - -impl Eq - for PhantomConstCanonicalMemoize -{ -} - -impl PartialEq - for PhantomConstCanonicalMemoize -{ - fn eq(&self, _other: &Self) -> bool { - true - } -} - -impl Hash - for PhantomConstCanonicalMemoize -{ - fn hash(&self, _state: &mut H) {} -} - -impl Memoize for PhantomConstCanonicalMemoize { - type Input = Interned; - type InputOwned = Interned; - type Output = Interned; - - fn inner(self, input: &Self::Input) -> Self::Output { - Intern::intern_sized(PhantomConstCanonicalValue::from_json_value( - serde_json::to_value(input) - .expect("serialization failed when constructing a canonical PhantomConst"), - )) - } -} - -impl Memoize for PhantomConstCanonicalMemoize { - type Input = Interned; - type InputOwned = Interned; - type Output = Interned; - - fn inner(self, input: &Self::Input) -> Self::Output { - PhantomConstValue::deserialize_value(input.as_json_value()) - .expect("deserialization failed ") - } -} - -impl PhantomConst { - pub fn new(value: Interned) -> Self { - Self { - value: LazyInterned::Interned(value), - } - } - pub const fn new_lazy(v: &'static dyn LazyInternedTrait) -> Self { - Self { - value: LazyInterned::new_lazy(v), - } - } - pub fn get(self) -> Interned { - self.value.interned() - } - pub fn type_properties(self) -> TypeProperties { - <()>::TYPE_PROPERTIES - } - pub fn can_connect(self, other: Self) -> bool { - self == other - } - pub fn canonical_phantom_const(self) -> PhantomConst { - if let Some(&retval) = ::downcast_ref::(&self) { - return retval; - } - ::new( - PhantomConstCanonicalMemoize::(PhantomData).get_owned(self.get()), - ) - } - pub fn from_canonical_phantom_const(canonical_type: PhantomConst) -> Self { - if let Some(&retval) = ::downcast_ref::(&canonical_type) { - return retval; - } - Self::new( - PhantomConstCanonicalMemoize::(PhantomData).get_owned(canonical_type.get()), - ) - } -} - -impl Type for PhantomConst { - type BaseType = PhantomConst; - type MaskType = (); - type SimValue = PhantomConst; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - () - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::PhantomConst(self.canonical_phantom_const()) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let CanonicalType::PhantomConst(phantom_const) = canonical_type else { - panic!("expected PhantomConst"); - }; - Self::from_canonical_phantom_const(phantom_const) - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert!(bits.is_empty()); - *self - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert!(bits.is_empty()); - assert_eq!(*value, *self); - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert!(bits.is_empty()); - assert_eq!(*value, *self); - } -} - -impl Default for PhantomConst -where - Interned: Default, -{ - fn default() -> Self { - Self::TYPE - } -} - -impl StaticType for PhantomConst -where - Interned: Default, -{ - const TYPE: Self = PhantomConst { - value: LazyInterned::new_lazy(&Interned::::default), - }; - const MASK_TYPE: Self::MaskType = (); - const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; - const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; -} - -type SerdeType = SerdeCanonicalType>>; - -impl Serialize for PhantomConst { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeType::::PhantomConst(SerdePhantomConst(self.get())).serialize(serializer) - } -} - -impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - match SerdeType::::deserialize(deserializer)? { - SerdeCanonicalType::PhantomConst(SerdePhantomConst(value)) => Ok(Self::new(value)), - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &"a PhantomConst", - )), - } - } -} - -impl ExprPartialEq for PhantomConst { - fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } - - fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } -} - -impl ExprPartialOrd for PhantomConst { - fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } - - fn cmp_le(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } - - fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } - - fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } -} - -impl SimValuePartialEq for PhantomConst { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - assert_eq!(SimValue::ty(this), SimValue::ty(other)); - true - } -} - -impl ToSimValue for PhantomConst { - type Type = PhantomConst; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(*self, *self) - } -} - -impl ToSimValueWithType> for PhantomConst { - fn to_sim_value_with_type(&self, ty: PhantomConst) -> SimValue> { - SimValue::from_value(ty, *self) - } -} - -impl ToSimValueWithType for PhantomConst { - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self)) - } -} diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 519210f..14c3aa7 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -1,43 +1,22 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information pub use crate::{ - annotations::{ - BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, - }, + annotations::Annotation, array::{Array, ArrayType}, - bundle::Bundle, cli::Cli, clock::{Clock, ClockDomain, ToClock}, - enum_::{Enum, HdlNone, HdlOption, HdlSome}, - expr::{ - repeat, CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, - ReduceBits, ToExpr, - }, - formal::{ - all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert, - hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, - hdl_cover_with_enable, MakeFormalExpr, - }, + enum_::{HdlNone, HdlOption, HdlSome}, + expr::{CastBitsTo, CastTo, CastToBits, Expr, ReduceBits, ToExpr}, hdl, hdl_module, - int::{Bool, DynSize, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, + int::{Bool, DynSize, IntCmp, KnownSize, SInt, SIntType, Size, UInt, UIntType}, memory::{Mem, MemBuilder, ReadUnderWrite}, module::{ - annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array, - memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder, + annotate, connect, connect_any, instance, memory, memory_array, memory_with_init, + reg_builder, wire, Instance, Module, ModuleBuilder, }, - phantom_const::PhantomConst, reg::Reg, reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset}, - sim::{ - time::{SimDuration, SimInstant}, - value::{SimValue, ToSimValue, ToSimValueWithType}, - ExternModuleSimulationState, Simulation, - }, source_location::SourceLocation, ty::{AsMask, CanonicalType, Type}, util::{ConstUsize, GenericConstUsize}, wire::Wire, __, }; -pub use bitvec::{slice::BitSlice, vec::BitVec}; diff --git a/crates/fayalite/src/reg.rs b/crates/fayalite/src/reg.rs index 20e0b94..8f757f2 100644 --- a/crates/fayalite/src/reg.rs +++ b/crates/fayalite/src/reg.rs @@ -5,22 +5,21 @@ use crate::{ expr::{Expr, Flow}, intern::Interned, module::{NameId, ScopedNameId}, - reset::{Reset, ResetType}, source_location::SourceLocation, ty::{CanonicalType, Type}, }; use std::fmt; #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Reg { +pub struct Reg { name: ScopedNameId, source_location: SourceLocation, ty: T, - clock_domain: Expr>, + clock_domain: Expr, init: Option>, } -impl fmt::Debug for Reg { +impl fmt::Debug for Reg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { name, @@ -38,8 +37,8 @@ impl fmt::Debug for Reg { } } -impl Reg { - pub fn canonical(&self) -> Reg { +impl Reg { + pub fn canonical(&self) -> Reg { let Self { name, source_location, @@ -60,7 +59,7 @@ impl Reg { scoped_name: ScopedNameId, source_location: SourceLocation, ty: T, - clock_domain: Expr>, + clock_domain: Expr, init: Option>, ) -> Self { assert!( @@ -99,7 +98,7 @@ impl Reg { pub fn scoped_name(&self) -> ScopedNameId { self.name } - pub fn clock_domain(&self) -> Expr> { + pub fn clock_domain(&self) -> Expr { self.clock_domain } pub fn init(&self) -> Option> { diff --git a/crates/fayalite/src/reset.rs b/crates/fayalite/src/reset.rs index 312a8ea..70d5f02 100644 --- a/crates/fayalite/src/reset.rs +++ b/crates/fayalite/src/reset.rs @@ -1,52 +1,26 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - clock::Clock, - expr::{ops, Expr, ToExpr}, - int::{Bool, SInt, UInt}, + expr::{Expr, ToExpr}, + int::Bool, source_location::SourceLocation, ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; -use bitvec::slice::BitSlice; mod sealed { pub trait ResetTypeSealed {} } -pub trait ResetType: - StaticType - + sealed::ResetTypeSealed - + ops::ExprCastTo - + ops::ExprCastTo - + ops::ExprCastTo - + ops::ExprCastTo - + ops::ExprCastTo - + ops::ExprCastTo> - + ops::ExprCastTo> - + ops::ExprCastTo - + ops::ExprCastTo -{ - fn dispatch(input: D::Input, dispatch: D) -> D::Output; -} - -pub trait ResetTypeDispatch: Sized { - type Input; - type Output; - - fn reset(self, input: Self::Input) -> Self::Output; - fn sync_reset(self, input: Self::Input) -> Self::Output; - fn async_reset(self, input: Self::Input) -> Self::Output; -} +pub trait ResetType: StaticType + sealed::ResetTypeSealed {} macro_rules! reset_type { - ($name:ident, $(#[$impl_trait:ident])? $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal, $dispatch_fn:ident) => { + ($name:ident, $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal) => { #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct $name; impl Type for $name { type BaseType = $name; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); @@ -68,21 +42,6 @@ macro_rules! reset_type { }; retval } - - fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { - assert_eq!(bits.len(), 1); - bits[0] - } - - fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { - assert_eq!(bits.len(), 1); - *value = bits[0]; - } - - fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { - assert_eq!(bits.len(), 1); - bits.set(0, *value); - } } impl $name { @@ -108,14 +67,7 @@ macro_rules! reset_type { impl sealed::ResetTypeSealed for $name {} - impl ResetType for $name { - fn dispatch( - input: D::Input, - dispatch: D, - ) -> D::Output { - dispatch.$dispatch_fn(input) - } - } + impl ResetType for $name {} pub trait $Trait { fn $trait_fn(&self) -> Expr<$name>; @@ -139,21 +91,20 @@ macro_rules! reset_type { } } - $($impl_trait $Trait for Expr<$name> { + impl $Trait for Expr<$name> { fn $trait_fn(&self) -> Expr<$name> { *self } - })? + } }; } -reset_type!(AsyncReset, #[impl] ToAsyncReset::to_async_reset, true, async_reset); -reset_type!(SyncReset, #[impl] ToSyncReset::to_sync_reset, true, sync_reset); +reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true); +reset_type!(SyncReset, ToSyncReset::to_sync_reset, true); reset_type!( Reset, ToReset::to_reset, - false, // Reset is not castable from bits because we don't know if it's async or sync - reset + false // Reset is not castable from bits because we don't know if it's async or sync ); impl ToSyncReset for bool { diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs deleted file mode 100644 index 6659391..0000000 --- a/crates/fayalite/src/sim.rs +++ /dev/null @@ -1,7812 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -//! Fayalite Simulation - -use crate::{ - bundle::{BundleField, BundleType}, - enum_::{EnumType, EnumVariant}, - expr::{ - ops, - target::{ - GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, - }, - ExprEnum, Flow, ToLiteralBits, - }, - int::{BoolOrIntType, UIntValue}, - intern::{ - Intern, Interned, InternedCompare, Memoize, PtrEqWithTypeId, SupportsPtrEqWithTypeId, - }, - memory::PortKind, - module::{ - transform::deduce_resets::deduce_resets, AnnotatedModuleIO, Block, ExternModuleBody, Id, - InstantiatedModule, ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, - StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, - TargetInInstantiatedModule, - }, - prelude::*, - reset::{ResetType, ResetTypeDispatch}, - sim::{ - interpreter::{ - BreakAction, BreakpointsSet, Insn, InsnField, InsnFieldKind, InsnFieldType, - InsnOrLabel, Insns, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, Label, - MemoryData, RunResult, SlotDebugData, SmallUInt, State, StatePartArrayIndex, - StatePartArrayIndexed, StatePartIndex, StatePartIndexRange, StatePartKind, - StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, StatePartLayout, - StatePartLen, StatePartsValue, TypeArrayIndex, TypeArrayIndexes, TypeIndex, - TypeIndexRange, TypeLayout, TypeLen, TypeParts, - }, - time::{SimDuration, SimInstant}, - value::SimValue, - }, - ty::StaticType, - util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, -}; -use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; -use num_bigint::BigInt; -use num_traits::{Signed, Zero}; -use petgraph::{ - data::FromElements, - visit::{ - EdgeRef, GraphBase, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected, - IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable, - }, -}; -use std::{ - any::Any, - borrow::Cow, - cell::RefCell, - collections::BTreeSet, - fmt, - future::{Future, IntoFuture}, - hash::Hash, - marker::PhantomData, - mem, - ops::IndexMut, - pin::Pin, - rc::Rc, - sync::Arc, - task::Poll, -}; - -mod interpreter; -pub mod time; -pub mod value; -pub mod vcd; - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -enum CondBody { - IfTrue { - cond: CompiledValue, - }, - IfFalse { - cond: CompiledValue, - }, - MatchArm { - discriminant: StatePartIndex, - variant_index: usize, - }, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct Cond { - body: CondBody, - source_location: SourceLocation, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct CompiledBundleField { - offset: TypeIndex, - ty: CompiledTypeLayout, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -enum CompiledTypeLayoutBody { - Scalar, - Array { - /// debug names are ignored, use parent's layout instead - element: Interned>, - }, - Bundle { - /// debug names are ignored, use parent's layout instead - fields: Interned<[CompiledBundleField]>, - }, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct CompiledTypeLayout { - ty: T, - layout: TypeLayout, - body: CompiledTypeLayoutBody, -} - -impl CompiledTypeLayout { - fn with_prefixed_debug_names(self, prefix: &str) -> Self { - let Self { ty, layout, body } = self; - Self { - ty, - layout: layout.with_prefixed_debug_names(prefix), - body, - } - } - fn with_anonymized_debug_info(self) -> Self { - let Self { ty, layout, body } = self; - Self { - ty, - layout: layout.with_anonymized_debug_info(), - body, - } - } - fn get(ty: T) -> Self { - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] - struct MyMemoize; - impl Memoize for MyMemoize { - type Input = CanonicalType; - type InputOwned = CanonicalType; - type Output = CompiledTypeLayout; - - fn inner(self, input: &Self::Input) -> Self::Output { - match input { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::Enum(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => { - let mut layout = TypeLayout::empty(); - let debug_data = SlotDebugData { - name: Interned::default(), - ty: *input, - }; - layout.big_slots = StatePartLayout::scalar(debug_data, ()); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Scalar, - } - } - CanonicalType::Array(array) => { - let mut layout = TypeLayout::empty(); - let element = CompiledTypeLayout::get(array.element()).intern_sized(); - for index in 0..array.len() { - layout.allocate( - &element - .layout - .with_prefixed_debug_names(&format!("[{index}]")), - ); - } - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Array { element }, - } - } - CanonicalType::PhantomConst(_) => { - let unit_layout = CompiledTypeLayout::get(()); - CompiledTypeLayout { - ty: *input, - layout: unit_layout.layout, - body: unit_layout.body, - } - } - CanonicalType::Bundle(bundle) => { - let mut layout = TypeLayout::empty(); - let fields = bundle - .fields() - .iter() - .map( - |BundleField { - name, - flipped: _, - ty, - }| { - let ty = CompiledTypeLayout::get(*ty); - let offset = layout - .allocate( - &ty.layout - .with_prefixed_debug_names(&format!(".{name}")), - ) - .start(); - CompiledBundleField { offset, ty } - }, - ) - .collect(); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Bundle { fields }, - } - } - } - } - } - let CompiledTypeLayout { - ty: _, - layout, - body, - } = MyMemoize.get_owned(ty.canonical()); - Self { ty, layout, body } - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct CompiledValue { - layout: CompiledTypeLayout, - range: TypeIndexRange, - write: Option<(CompiledTypeLayout, TypeIndexRange)>, -} - -impl CompiledValue { - fn write(self) -> (CompiledTypeLayout, TypeIndexRange) { - self.write.unwrap_or((self.layout, self.range)) - } - fn write_value(self) -> Self { - let (layout, range) = self.write(); - Self { - layout, - range, - write: None, - } - } - fn map( - self, - mut f: impl FnMut( - CompiledTypeLayout, - TypeIndexRange, - ) -> (CompiledTypeLayout, TypeIndexRange), - ) -> CompiledValue { - let (layout, range) = f(self.layout, self.range); - CompiledValue { - layout, - range, - write: self.write.map(|(layout, range)| f(layout, range)), - } - } - fn map_ty(self, mut f: impl FnMut(T) -> U) -> CompiledValue { - self.map(|CompiledTypeLayout { ty, layout, body }, range| { - ( - CompiledTypeLayout { - ty: f(ty), - layout, - body, - }, - range, - ) - }) - } -} - -impl CompiledValue { - fn field_by_index(self, field_index: usize) -> CompiledValue { - self.map(|layout, range| { - let CompiledTypeLayout { - ty: _, - layout: _, - body: CompiledTypeLayoutBody::Bundle { fields }, - } = layout - else { - unreachable!(); - }; - ( - fields[field_index].ty, - range.slice(TypeIndexRange::new( - fields[field_index].offset, - fields[field_index].ty.layout.len(), - )), - ) - }) - } - fn field_by_name(self, name: Interned) -> CompiledValue { - self.field_by_index(self.layout.ty.name_indexes()[&name]) - } -} - -impl CompiledValue { - fn element(self, index: usize) -> CompiledValue { - self.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { - unreachable!(); - }; - (*element, range.index_array(element.layout.len(), index)) - }) - } - fn element_dyn( - self, - index_slot: StatePartIndex, - ) -> CompiledExpr { - CompiledExpr::from(self).element_dyn(index_slot) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -struct CompiledExpr { - static_part: CompiledValue, - indexes: TypeArrayIndexes, -} - -impl From> for CompiledExpr { - fn from(static_part: CompiledValue) -> Self { - Self { - static_part, - indexes: TypeArrayIndexes::default(), - } - } -} - -impl CompiledExpr { - fn map_ty(self, f: impl FnMut(T) -> U) -> CompiledExpr { - let Self { - static_part, - indexes, - } = self; - CompiledExpr { - static_part: static_part.map_ty(f), - indexes, - } - } - fn add_target_without_indexes_to_set(self, inputs: &mut SlotSet) { - let Self { - static_part, - indexes, - } = self; - indexes.as_ref().for_each_offset(|offset| { - inputs.extend([static_part.range.offset(offset)]); - }); - } - fn add_target_and_indexes_to_set(self, inputs: &mut SlotSet) { - let Self { - static_part: _, - indexes, - } = self; - self.add_target_without_indexes_to_set(inputs); - inputs.extend(indexes.as_ref().iter()); - } -} - -impl CompiledExpr { - fn field_by_index(self, field_index: usize) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.field_by_index(field_index), - indexes: self.indexes, - } - } - fn field_by_name(self, name: Interned) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.field_by_name(name), - indexes: self.indexes, - } - } -} - -impl CompiledExpr { - fn element(self, index: usize) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.element(index), - indexes: self.indexes, - } - } - fn element_dyn( - self, - index_slot: StatePartIndex, - ) -> CompiledExpr { - let CompiledTypeLayoutBody::Array { element } = self.static_part.layout.body else { - unreachable!(); - }; - let stride = element.layout.len(); - let indexes = self.indexes.join(TypeArrayIndex::from_parts( - index_slot, - self.static_part.layout.ty.len(), - stride, - )); - CompiledExpr { - static_part: self.static_part.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { - unreachable!(); - }; - (*element, range.index_array(stride, 0)) - }), - indexes, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -enum AssignmentOrSlotIndex { - AssignmentIndex(usize), - SmallSlot(StatePartIndex), - BigSlot(StatePartIndex), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -enum AssignmentIO { - BigInput { - assignment_index: usize, - slot: StatePartIndex, - }, - SmallInput { - assignment_index: usize, - slot: StatePartIndex, - }, - BigOutput { - assignment_index: usize, - slot: StatePartIndex, - }, - SmallOutput { - assignment_index: usize, - slot: StatePartIndex, - }, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -enum AssignmentsEdge { - IO(AssignmentIO), - AssignmentImmediatePredecessor { - predecessor_assignment_index: usize, - assignment_index: usize, - }, -} - -#[derive(Debug)] -enum Assignments { - Accumulating { - assignments: Vec, - }, - Finalized { - assignments: Box<[Assignment]>, - slots_layout: TypeLayout, - slot_readers: SlotToAssignmentIndexFullMap, - slot_writers: SlotToAssignmentIndexFullMap, - assignment_immediate_predecessors: Box<[Box<[usize]>]>, - assignment_immediate_successors: Box<[Box<[usize]>]>, - }, -} - -impl Default for Assignments { - fn default() -> Self { - Self::Accumulating { - assignments: Vec::new(), - } - } -} - -impl Assignments { - fn finalize(&mut self, slots_layout: TypeLayout) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - let assignments = mem::take(assignments).into_boxed_slice(); - let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()]; - let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()]; - for (assignment_index, assignment) in assignments.iter().enumerate() { - slot_readers - .keys_for_assignment(assignment_index) - .extend([&assignment.inputs]); - slot_readers - .keys_for_assignment(assignment_index) - .extend(&assignment.conditions); - let SlotSet(TypeParts { - small_slots, - big_slots, - }) = &assignment.outputs; - for &slot in small_slots { - if let Some(&pred) = slot_writers[slot].last() { - assignment_immediate_predecessors[assignment_index].insert(pred); - assignment_immediate_successors[pred].insert(assignment_index); - } - slot_writers[slot].push(assignment_index); - } - for &slot in big_slots { - if let Some(&pred) = slot_writers[slot].last() { - assignment_immediate_predecessors[assignment_index].insert(pred); - assignment_immediate_successors[pred].insert(assignment_index); - } - slot_writers[slot].push(assignment_index); - } - } - *self = Self::Finalized { - assignments, - slots_layout, - slot_readers, - slot_writers, - assignment_immediate_predecessors: assignment_immediate_predecessors - .into_iter() - .map(Box::from_iter) - .collect(), - assignment_immediate_successors: assignment_immediate_successors - .into_iter() - .map(Box::from_iter) - .collect(), - }; - } - fn push(&mut self, v: Assignment) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - assignments.push(v); - } - fn assignments(&self) -> &[Assignment] { - let Self::Finalized { assignments, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - assignments - } - fn slots_layout(&self) -> TypeLayout { - let Self::Finalized { slots_layout, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - *slots_layout - } - fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_readers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_readers - } - fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_writers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_writers - } - fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_predecessors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_predecessors - } - fn assignment_immediate_successors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_successors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_successors - } - fn elements(&self) -> AssignmentsElements<'_> { - let SlotToAssignmentIndexFullMap(TypeParts { - small_slots, - big_slots, - }) = self.slot_readers(); - AssignmentsElements { - node_indexes: HashMap::with_capacity_and_hasher( - self.assignments().len() + small_slots.len() + big_slots.len(), - Default::default(), - ), - nodes: self.node_references(), - edges: self.edge_references(), - } - } -} - -impl GraphBase for Assignments { - type EdgeId = AssignmentsEdge; - type NodeId = AssignmentOrSlotIndex; -} - -#[derive(Debug, Clone, Copy)] -enum AssignmentsNodeRef<'a> { - Assignment { - index: usize, - assignment: &'a Assignment, - }, - SmallSlot(StatePartIndex, SlotDebugData), - BigSlot(StatePartIndex, SlotDebugData), -} - -impl<'a> NodeRef for AssignmentsNodeRef<'a> { - type NodeId = AssignmentOrSlotIndex; - type Weight = AssignmentsNodeRef<'a>; - - fn id(&self) -> Self::NodeId { - match *self { - AssignmentsNodeRef::Assignment { - index, - assignment: _, - } => AssignmentOrSlotIndex::AssignmentIndex(index), - AssignmentsNodeRef::SmallSlot(slot, _) => AssignmentOrSlotIndex::SmallSlot(slot), - AssignmentsNodeRef::BigSlot(slot, _) => AssignmentOrSlotIndex::BigSlot(slot), - } - } - - fn weight(&self) -> &Self::Weight { - self - } -} - -impl<'a> petgraph::visit::Data for &'a Assignments { - type NodeWeight = AssignmentsNodeRef<'a>; - type EdgeWeight = AssignmentsEdge; -} - -struct AssignmentsElements<'a> { - node_indexes: HashMap, - nodes: AssignmentsNodes<'a>, - edges: AssignmentsEdges<'a>, -} - -impl<'a> Iterator for AssignmentsElements<'a> { - type Item = petgraph::data::Element< - <&'a Assignments as petgraph::visit::Data>::NodeWeight, - <&'a Assignments as petgraph::visit::Data>::EdgeWeight, - >; - - fn next(&mut self) -> Option { - let Self { - node_indexes, - nodes, - edges, - } = self; - if let Some(node) = nodes.next() { - node_indexes.insert(node.id(), node_indexes.len()); - return Some(petgraph::data::Element::Node { weight: node }); - } - let edge = edges.next()?; - Some(petgraph::data::Element::Edge { - source: node_indexes[&edge.source()], - target: node_indexes[&edge.target()], - weight: *edge.weight(), - }) - } -} - -#[derive(Clone)] -struct AssignmentsNodeIdentifiers { - assignment_indexes: std::ops::Range, - small_slots: std::ops::Range, - big_slots: std::ops::Range, -} - -impl AssignmentsNodeIdentifiers { - fn internal_iter<'a>(&'a mut self) -> impl Iterator + 'a { - let Self { - assignment_indexes, - small_slots, - big_slots, - } = self; - assignment_indexes - .map(AssignmentOrSlotIndex::AssignmentIndex) - .chain(small_slots.map(|value| { - AssignmentOrSlotIndex::SmallSlot(StatePartIndex { - value, - _phantom: PhantomData, - }) - })) - .chain(big_slots.map(|value| { - AssignmentOrSlotIndex::BigSlot(StatePartIndex { - value, - _phantom: PhantomData, - }) - })) - } -} - -impl Iterator for AssignmentsNodeIdentifiers { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - self.internal_iter().next() - } - - fn nth(&mut self, n: usize) -> Option { - self.internal_iter().nth(n) - } -} - -impl<'a> IntoNodeIdentifiers for &'a Assignments { - type NodeIdentifiers = AssignmentsNodeIdentifiers; - - fn node_identifiers(self) -> Self::NodeIdentifiers { - let TypeLen { - small_slots, - big_slots, - } = self.slot_readers().len(); - AssignmentsNodeIdentifiers { - assignment_indexes: 0..self.assignments().len(), - small_slots: 0..small_slots.value, - big_slots: 0..big_slots.value, - } - } -} - -struct AssignmentsNodes<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, -} - -impl<'a> Iterator for AssignmentsNodes<'a> { - type Item = AssignmentsNodeRef<'a>; - - fn next(&mut self) -> Option { - self.nodes.next().map(|node| match node { - AssignmentOrSlotIndex::AssignmentIndex(index) => AssignmentsNodeRef::Assignment { - index, - assignment: &self.assignments.assignments()[index], - }, - AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNodeRef::SmallSlot( - slot, - *self.assignments.slots_layout().small_slots.debug_data(slot), - ), - AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNodeRef::BigSlot( - slot, - *self.assignments.slots_layout().big_slots.debug_data(slot), - ), - }) - } -} - -impl<'a> IntoNodeReferences for &'a Assignments { - type NodeRef = AssignmentsNodeRef<'a>; - type NodeReferences = AssignmentsNodes<'a>; - - fn node_references(self) -> Self::NodeReferences { - AssignmentsNodes { - assignments: self, - nodes: self.node_identifiers(), - } - } -} - -struct AssignmentsNeighborsDirected<'a> { - assignment_indexes: std::slice::Iter<'a, usize>, - small_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, - big_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, -} - -impl Iterator for AssignmentsNeighborsDirected<'_> { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - let Self { - assignment_indexes, - small_slots, - big_slots, - } = self; - if let retval @ Some(_) = assignment_indexes - .next() - .copied() - .map(AssignmentOrSlotIndex::AssignmentIndex) - { - retval - } else if let retval @ Some(_) = small_slots - .next() - .copied() - .map(AssignmentOrSlotIndex::SmallSlot) - { - retval - } else if let retval @ Some(_) = big_slots - .next() - .copied() - .map(AssignmentOrSlotIndex::BigSlot) - { - retval - } else { - None - } - } -} - -impl<'a> IntoNeighbors for &'a Assignments { - type Neighbors = AssignmentsNeighborsDirected<'a>; - - fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { - self.neighbors_directed(n, petgraph::Direction::Outgoing) - } -} - -impl<'a> IntoNeighborsDirected for &'a Assignments { - type NeighborsDirected = AssignmentsNeighborsDirected<'a>; - - fn neighbors_directed( - self, - n: Self::NodeId, - d: petgraph::Direction, - ) -> Self::NeighborsDirected { - use petgraph::Direction::*; - let slot_map = match d { - Outgoing => self.slot_readers(), - Incoming => self.slot_writers(), - }; - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - let assignment = &self.assignments()[assignment_index]; - let ( - assignment_indexes, - SlotSet(TypeParts { - small_slots, - big_slots, - }), - ) = match d { - Outgoing => ( - &self.assignment_immediate_successors()[assignment_index], - &assignment.outputs, - ), - Incoming => ( - &self.assignment_immediate_predecessors()[assignment_index], - &assignment.inputs, - ), - }; - AssignmentsNeighborsDirected { - assignment_indexes: assignment_indexes.iter(), - small_slots: small_slots.iter(), - big_slots: big_slots.iter(), - } - } - AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNeighborsDirected { - assignment_indexes: slot_map[slot].iter(), - small_slots: Default::default(), - big_slots: Default::default(), - }, - AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNeighborsDirected { - assignment_indexes: slot_map[slot].iter(), - small_slots: Default::default(), - big_slots: Default::default(), - }, - } - } -} - -impl EdgeRef for AssignmentsEdge { - type NodeId = AssignmentOrSlotIndex; - type EdgeId = AssignmentsEdge; - type Weight = AssignmentsEdge; - - fn source(&self) -> Self::NodeId { - match *self { - AssignmentsEdge::IO(AssignmentIO::BigInput { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::BigSlot(slot), - AssignmentsEdge::IO(AssignmentIO::SmallInput { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::SmallSlot(slot), - AssignmentsEdge::IO(AssignmentIO::BigOutput { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentsEdge::IO(AssignmentIO::SmallOutput { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index: _, - } => AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - } - } - - fn target(&self) -> Self::NodeId { - match *self { - AssignmentsEdge::IO(AssignmentIO::BigInput { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentsEdge::IO(AssignmentIO::SmallInput { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentsEdge::IO(AssignmentIO::BigOutput { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::BigSlot(slot), - AssignmentsEdge::IO(AssignmentIO::SmallOutput { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::SmallSlot(slot), - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index: _, - assignment_index, - } => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - } - } - - fn weight(&self) -> &Self::Weight { - self - } - - fn id(&self) -> Self::EdgeId { - *self - } -} - -struct AssignmentsEdges<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, - outgoing_neighbors: Option<(AssignmentOrSlotIndex, AssignmentsNeighborsDirected<'a>)>, -} - -impl Iterator for AssignmentsEdges<'_> { - type Item = AssignmentsEdge; - - fn next(&mut self) -> Option { - loop { - if let Some((node, outgoing_neighbors)) = &mut self.outgoing_neighbors { - if let Some(outgoing_neighbor) = outgoing_neighbors.next() { - return Some(match (*node, outgoing_neighbor) { - ( - AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), - AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), - ) => unreachable!(), - ( - AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index, - }, - ( - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentOrSlotIndex::SmallSlot(slot), - ) => AssignmentsEdge::IO(AssignmentIO::SmallOutput { - assignment_index, - slot, - }), - ( - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentOrSlotIndex::BigSlot(slot), - ) => AssignmentsEdge::IO(AssignmentIO::BigOutput { - assignment_index, - slot, - }), - ( - AssignmentOrSlotIndex::SmallSlot(slot), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::IO(AssignmentIO::SmallInput { - assignment_index, - slot, - }), - ( - AssignmentOrSlotIndex::BigSlot(slot), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::IO(AssignmentIO::BigInput { - assignment_index, - slot, - }), - }); - } - } - let node = self.nodes.next()?; - self.outgoing_neighbors = Some(( - node, - self.assignments - .neighbors_directed(node, petgraph::Direction::Outgoing), - )); - } - } -} - -impl<'a> IntoEdgeReferences for &'a Assignments { - type EdgeRef = AssignmentsEdge; - type EdgeReferences = AssignmentsEdges<'a>; - - fn edge_references(self) -> Self::EdgeReferences { - AssignmentsEdges { - assignments: self, - nodes: self.node_identifiers(), - outgoing_neighbors: None, - } - } -} - -struct AssignmentsVisitMap { - assignments: Vec, - slots: DenseSlotSet, -} - -impl VisitMap for AssignmentsVisitMap { - fn visit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - !mem::replace(&mut self.assignments[assignment_index], true) - } - AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.insert(slot), - AssignmentOrSlotIndex::BigSlot(slot) => self.slots.insert(slot), - } - } - - fn is_visited(&self, n: &AssignmentOrSlotIndex) -> bool { - match *n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - self.assignments[assignment_index] - } - AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.contains(slot), - AssignmentOrSlotIndex::BigSlot(slot) => self.slots.contains(slot), - } - } - - fn unvisit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - mem::replace(&mut self.assignments[assignment_index], false) - } - AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.remove(slot), - AssignmentOrSlotIndex::BigSlot(slot) => self.slots.remove(slot), - } - } -} - -impl Visitable for Assignments { - type Map = AssignmentsVisitMap; - - fn visit_map(self: &Self) -> Self::Map { - AssignmentsVisitMap { - assignments: vec![false; self.assignments().len()], - slots: DenseSlotSet::new(self.slot_readers().len()), - } - } - - fn reset_map(self: &Self, map: &mut Self::Map) { - let AssignmentsVisitMap { assignments, slots } = map; - assignments.clear(); - assignments.resize(self.assignments().len(), false); - if slots.len() != self.slot_readers().len() { - *slots = DenseSlotSet::new(self.slot_readers().len()); - } else { - slots.clear(); - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct DenseSlotSet(TypeParts); - -impl DenseSlotSet { - fn new(len: TypeLen) -> Self { - let TypeLen { - small_slots, - big_slots, - } = len; - Self(TypeParts { - small_slots: vec![false; small_slots.value.try_into().expect("length too big")] - .into_boxed_slice(), - big_slots: vec![false; big_slots.value.try_into().expect("length too big")] - .into_boxed_slice(), - }) - } - fn len(&self) -> TypeLen { - TypeLen { - small_slots: StatePartLen { - value: self.0.small_slots.len() as _, - _phantom: PhantomData, - }, - big_slots: StatePartLen { - value: self.0.big_slots.len() as _, - _phantom: PhantomData, - }, - } - } - fn clear(&mut self) { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.fill(false); - big_slots.fill(false); - } -} - -impl StatePartsValue for DenseSlotSet { - type Value = Box<[bool]>; -} - -trait DenseSlotSetMethods: Extend> { - fn contains(&self, k: StatePartIndex) -> bool; - fn remove(&mut self, k: StatePartIndex) -> bool { - self.take(k).is_some() - } - fn take(&mut self, k: StatePartIndex) -> Option>; - fn replace(&mut self, k: StatePartIndex) -> Option>; - fn insert(&mut self, k: StatePartIndex) -> bool { - self.replace(k).is_none() - } -} - -impl Extend> for DenseSlotSet -where - Self: DenseSlotSetMethods, -{ - fn extend>>(&mut self, iter: T) { - iter.into_iter().for_each(|v| { - self.insert(v); - }); - } -} - -impl DenseSlotSetMethods for DenseSlotSet { - fn contains(&self, k: StatePartIndex) -> bool { - self.0.small_slots[k.as_usize()] - } - - fn take( - &mut self, - k: StatePartIndex, - ) -> Option> { - mem::replace(self.0.small_slots.get_mut(k.as_usize())?, false).then_some(k) - } - - fn replace( - &mut self, - k: StatePartIndex, - ) -> Option> { - mem::replace(&mut self.0.small_slots[k.as_usize()], true).then_some(k) - } -} - -impl DenseSlotSetMethods for DenseSlotSet { - fn contains(&self, k: StatePartIndex) -> bool { - self.0.big_slots[k.as_usize()] - } - - fn take( - &mut self, - k: StatePartIndex, - ) -> Option> { - mem::replace(self.0.big_slots.get_mut(k.as_usize())?, false).then_some(k) - } - - fn replace( - &mut self, - k: StatePartIndex, - ) -> Option> { - mem::replace(&mut self.0.big_slots[k.as_usize()], true).then_some(k) - } -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -struct SlotVec(TypeParts); - -impl SlotVec { - fn is_empty(&self) -> bool { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.is_empty() && big_slots.is_empty() - } -} - -impl StatePartsValue for SlotVec { - type Value = Vec>; -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -struct SlotSet(TypeParts); - -impl SlotSet { - fn is_empty(&self) -> bool { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.is_empty() && big_slots.is_empty() - } - fn for_each( - &self, - small_slots_fn: impl FnMut(StatePartIndex), - big_slots_fn: impl FnMut(StatePartIndex), - ) { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.iter().copied().for_each(small_slots_fn); - big_slots.iter().copied().for_each(big_slots_fn); - } - fn all( - &self, - small_slots_fn: impl FnMut(StatePartIndex) -> bool, - big_slots_fn: impl FnMut(StatePartIndex) -> bool, - ) -> bool { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.iter().copied().all(small_slots_fn) - && big_slots.iter().copied().all(big_slots_fn) - } -} - -impl StatePartsValue for SlotSet { - type Value = BTreeSet>; -} - -impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.0.small_slots.extend(iter); - } -} - -impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.0.big_slots.extend(iter); - } -} - -impl Extend> for SlotSet -where - Self: Extend>, -{ - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().flat_map(|v| v.iter())); - } -} - -impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |TypeIndexRange { - small_slots, - big_slots, - }| { - self.extend(small_slots.iter()); - self.extend(big_slots.iter()); - }, - ) - } -} - -impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |TypeArrayIndex { - small_slots, - big_slots, - }| { - self.extend([small_slots]); - self.extend([big_slots]); - }, - ) - } -} - -impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.index)); - } -} - -impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond_body| match cond_body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - self.extend([cond.range]); - } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }) - } -} - -impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.body)) - } -} - -#[derive(Debug)] -struct Assignment { - inputs: SlotSet, - outputs: SlotSet, - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, -} - -#[derive(Debug)] -struct SlotToAssignmentIndexFullMap(TypeParts); - -impl StatePartsValue for SlotToAssignmentIndexFullMap { - type Value = Box<[Vec]>; -} - -impl SlotToAssignmentIndexFullMap { - fn new(len: TypeLen) -> Self { - let TypeLen { - small_slots, - big_slots, - } = len; - Self(TypeParts { - small_slots: vec![Vec::new(); small_slots.value.try_into().expect("length too big")] - .into_boxed_slice(), - big_slots: vec![Vec::new(); big_slots.value.try_into().expect("length too big")] - .into_boxed_slice(), - }) - } - fn len(&self) -> TypeLen { - TypeLen { - small_slots: StatePartLen { - value: self.0.small_slots.len() as _, - _phantom: PhantomData, - }, - big_slots: StatePartLen { - value: self.0.big_slots.len() as _, - _phantom: PhantomData, - }, - } - } - fn keys_for_assignment( - &mut self, - assignment_index: usize, - ) -> SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - SlotToAssignmentIndexFullMapKeysForAssignment { - map: self, - assignment_index, - } - } - fn for_each( - &self, - mut small_slots_fn: impl FnMut(StatePartIndex, &[usize]), - mut big_slots_fn: impl FnMut(StatePartIndex, &[usize]), - ) { - let Self(TypeParts { - small_slots, - big_slots, - }) = self; - small_slots.iter().enumerate().for_each(|(k, v)| { - small_slots_fn( - StatePartIndex { - value: k as _, - _phantom: PhantomData, - }, - v, - ) - }); - big_slots.iter().enumerate().for_each(|(k, v)| { - big_slots_fn( - StatePartIndex { - value: k as _, - _phantom: PhantomData, - }, - v, - ) - }); - } -} - -impl std::ops::Index> for SlotToAssignmentIndexFullMap { - type Output = Vec; - - fn index(&self, index: StatePartIndex) -> &Self::Output { - &self.0.small_slots[index.as_usize()] - } -} - -impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { - fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { - &mut self.0.small_slots[index.as_usize()] - } -} - -impl std::ops::Index> for SlotToAssignmentIndexFullMap { - type Output = Vec; - - fn index(&self, index: StatePartIndex) -> &Self::Output { - &self.0.big_slots[index.as_usize()] - } -} - -impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { - fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { - &mut self.0.big_slots[index.as_usize()] - } -} - -struct SlotToAssignmentIndexFullMapKeysForAssignment<'a> { - map: &'a mut SlotToAssignmentIndexFullMap, - assignment_index: usize, -} - -impl<'a, K: StatePartKind> Extend<&'a StatePartIndex> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> -where - Self: Extend>, -{ - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().copied()); - } -} - -impl Extend> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> -where - SlotToAssignmentIndexFullMap: IndexMut, Output = Vec>, -{ - fn extend>>(&mut self, iter: T) { - iter.into_iter() - .for_each(|slot| self.map[slot].push(self.assignment_index)); - } -} - -impl<'a> Extend<&'a SlotSet> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |SlotSet(TypeParts { - small_slots, - big_slots, - })| { - self.extend(small_slots); - self.extend(big_slots); - }, - ); - } -} - -impl<'a> Extend<&'a Cond> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond| match cond.body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - let CompiledValue { - range: - TypeIndexRange { - small_slots, - big_slots, - }, - layout: _, - write: _, - } = cond; - self.extend(small_slots.iter()); - self.extend(big_slots.iter()); - } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }); - } -} - -impl Assignment { - fn new( - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, - ) -> Self { - let mut inputs = SlotSet::default(); - let mut outputs = SlotSet::default(); - for insn in &insns { - let insn = match insn { - InsnOrLabel::Insn(insn) => insn, - InsnOrLabel::Label(_) => continue, - }; - for InsnField { ty, kind } in insn.fields() { - match (kind, ty) { - (InsnFieldKind::Input, InsnFieldType::SmallSlot(&slot)) => { - inputs.extend([slot]); - } - (InsnFieldKind::Input, InsnFieldType::BigSlot(&slot)) => { - inputs.extend([slot]); - } - ( - InsnFieldKind::Input, - InsnFieldType::SmallSlotArrayIndexed(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| inputs.extend([slot])); - inputs.extend(array_indexed.indexes); - } - (InsnFieldKind::Input, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { - array_indexed.for_each_target(|slot| inputs.extend([slot])); - inputs.extend(array_indexed.indexes); - } - (InsnFieldKind::Output, InsnFieldType::SmallSlot(&slot)) => { - outputs.extend([slot]); - } - (InsnFieldKind::Output, InsnFieldType::BigSlot(&slot)) => { - outputs.extend([slot]); - } - ( - InsnFieldKind::Output, - InsnFieldType::SmallSlotArrayIndexed(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| { - outputs.extend([slot]); - }); - inputs.extend(array_indexed.indexes); - } - (InsnFieldKind::Output, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { - array_indexed.for_each_target(|slot| { - outputs.extend([slot]); - }); - inputs.extend(array_indexed.indexes); - } - ( - _, - InsnFieldType::Memory(_) - | InsnFieldType::SmallUInt(_) - | InsnFieldType::SmallSInt(_) - | InsnFieldType::InternedBigInt(_) - | InsnFieldType::U8(_) - | InsnFieldType::USize(_) - | InsnFieldType::Empty(_), - ) - | ( - InsnFieldKind::Immediate - | InsnFieldKind::Memory - | InsnFieldKind::BranchTarget, - _, - ) => {} - } - } - } - Self { - inputs, - outputs, - conditions, - insns, - source_location, - } - } -} - -#[derive(Debug)] -struct RegisterReset { - is_async: bool, - init: CompiledValue, - rst: StatePartIndex, -} - -#[derive(Debug, Clone, Copy)] -struct ClockTrigger { - last_clk_was_low: StatePartIndex, - clk: StatePartIndex, - clk_triggered: StatePartIndex, - source_location: SourceLocation, -} - -#[derive(Debug)] -struct Register { - value: CompiledValue, - clk_triggered: StatePartIndex, - reset: Option, - source_location: SourceLocation, -} - -#[derive(Debug)] - -struct MemoryPort { - clk_triggered: StatePartIndex, - addr_delayed: Vec>, - en_delayed: Vec>, - data_layout: CompiledTypeLayout, - read_data_delayed: Vec, - write_data_delayed: Vec, - write_mask_delayed: Vec, - write_mode_delayed: Vec>, - write_insns: Vec, -} - -struct MemoryPortReadInsns<'a> { - addr: StatePartIndex, - en: StatePartIndex, - write_mode: Option>, - data: TypeIndexRange, - insns: &'a mut Vec, -} - -struct MemoryPortWriteInsns<'a> { - addr: StatePartIndex, - en: StatePartIndex, - write_mode: Option>, - data: TypeIndexRange, - mask: TypeIndexRange, - insns: &'a mut Vec, -} - -#[derive(Debug)] -struct Memory { - mem: Mem, - memory: StatePartIndex, - trace: TraceMem, - ports: Vec, -} - -#[derive(Copy, Clone)] -enum MakeTraceDeclTarget { - Expr(Expr), - Memory { - id: TraceMemoryId, - depth: usize, - stride: usize, - start: usize, - ty: CanonicalType, - }, -} - -impl MakeTraceDeclTarget { - fn flow(self) -> Flow { - match self { - MakeTraceDeclTarget::Expr(expr) => Expr::flow(expr), - MakeTraceDeclTarget::Memory { .. } => Flow::Duplex, - } - } - fn ty(self) -> CanonicalType { - match self { - MakeTraceDeclTarget::Expr(expr) => Expr::ty(expr), - MakeTraceDeclTarget::Memory { ty, .. } => ty, - } - } -} - -struct DebugOpaque(T); - -impl fmt::Debug for DebugOpaque { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("<...>") - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -struct CompiledExternModule { - module_io_targets: Interned<[Target]>, - module_io: Interned<[CompiledValue]>, - simulation: ExternModuleSimulation, -} - -#[derive(Debug)] -pub struct Compiler { - insns: Insns, - original_base_module: Interned>, - base_module: Interned>, - modules: HashMap, - extern_modules: Vec, - compiled_values: HashMap>, - compiled_exprs: HashMap, CompiledExpr>, - compiled_exprs_to_values: HashMap, CompiledValue>, - decl_conditions: HashMap>, - compiled_values_to_dyn_array_indexes: - HashMap, StatePartIndex>, - compiled_value_bool_dest_is_small_map: - HashMap, StatePartIndex>, - assignments: Assignments, - clock_triggers: Vec, - compiled_value_to_clock_trigger_map: HashMap, ClockTrigger>, - enum_discriminants: HashMap, StatePartIndex>, - registers: Vec, - traces: SimTraces>>, - memories: Vec, - dump_assignments_dot: Option>>, -} - -impl Compiler { - pub fn new(base_module: Interned>) -> Self { - let original_base_module = base_module; - let base_module = deduce_resets(base_module, true) - .unwrap_or_else(|e| panic!("failed to deduce reset types: {e}")); - Self { - insns: Insns::new(), - original_base_module, - base_module, - modules: HashMap::default(), - extern_modules: Vec::new(), - compiled_values: HashMap::default(), - compiled_exprs: HashMap::default(), - compiled_exprs_to_values: HashMap::default(), - decl_conditions: HashMap::default(), - compiled_values_to_dyn_array_indexes: HashMap::default(), - compiled_value_bool_dest_is_small_map: HashMap::default(), - assignments: Assignments::default(), - clock_triggers: Vec::new(), - compiled_value_to_clock_trigger_map: HashMap::default(), - enum_discriminants: HashMap::default(), - registers: Vec::new(), - traces: SimTraces(Vec::new()), - memories: Vec::new(), - dump_assignments_dot: None, - } - } - #[doc(hidden)] - /// This is explicitly unstable and may be changed/removed at any time - pub fn dump_assignments_dot(&mut self, callback: Box) { - self.dump_assignments_dot = Some(DebugOpaque(callback)); - } - fn new_sim_trace(&mut self, kind: SimTraceKind) -> TraceScalarId { - let id = TraceScalarId(self.traces.0.len()); - self.traces.0.push(SimTrace { - kind, - state: (), - last_state: (), - }); - id - } - fn make_trace_scalar_helper( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - source_location: SourceLocation, - small_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, - big_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, - ) -> TraceLocation { - match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); - TraceLocation::Scalar(self.new_sim_trace(match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), - TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), - _ => unreachable!(), - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.bit_width(), - }), - } - } - fn make_trace_scalar( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - name: Interned, - source_location: SourceLocation, - ) -> TraceDecl { - let flow = target.flow(); - match target.ty() { - CanonicalType::UInt(ty) => TraceUInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallUInt { index, ty }, - |index| SimTraceKind::BigUInt { index, ty }, - ), - name, - ty, - flow, - } - .into(), - CanonicalType::SInt(ty) => TraceSInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSInt { index, ty }, - |index| SimTraceKind::BigSInt { index, ty }, - ), - name, - ty, - flow, - } - .into(), - CanonicalType::Bool(_) => TraceBool { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallBool { index }, - |index| SimTraceKind::BigBool { index }, - ), - name, - flow, - } - .into(), - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(ty) => { - assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); - let location = match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = - self.compiled_expr_to_value(compiled_value, source_location); - let discriminant = self.compile_enum_discriminant( - compiled_value.map_ty(Enum::from_canonical), - source_location, - ); - TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::EnumDiscriminant { - index: discriminant, - ty, - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.type_properties().bit_width, - }), - }; - TraceFieldlessEnum { - location, - name, - ty, - flow, - } - .into() - } - CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::AsyncReset(_) => TraceAsyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallAsyncReset { index }, - |index| SimTraceKind::BigAsyncReset { index }, - ), - name, - flow, - } - .into(), - CanonicalType::SyncReset(_) => TraceSyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSyncReset { index }, - |index| SimTraceKind::BigSyncReset { index }, - ), - name, - flow, - } - .into(), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(_) => TraceClock { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallClock { index }, - |index| SimTraceKind::BigClock { index }, - ), - name, - flow, - } - .into(), - } - } - fn make_trace_decl_child( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - name: Interned, - source_location: SourceLocation, - ) -> TraceDecl { - match target.ty() { - CanonicalType::Array(ty) => { - let elements = Interned::from_iter((0..ty.len()).map(|index| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => MakeTraceDeclTarget::Expr( - Expr::::from_canonical(target)[index], - ), - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + ty.element().bit_width() * index, - ty: ty.element(), - }, - }, - Intern::intern_owned(format!("[{index}]")), - source_location, - ) - })); - TraceArray { - name, - elements, - ty, - flow: target.flow(), - } - .into() - } - CanonicalType::Enum(ty) => { - if ty.variants().iter().all(|v| v.ty.is_none()) { - self.make_trace_scalar(instantiated_module, target, name, source_location) - } else { - let flow = target.flow(); - let location = match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = - self.compiled_expr_to_value(compiled_value, source_location); - let discriminant = self.compile_enum_discriminant( - compiled_value.map_ty(Enum::from_canonical), - source_location, - ); - TraceLocation::Scalar(self.new_sim_trace( - SimTraceKind::EnumDiscriminant { - index: discriminant, - ty, - }, - )) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.discriminant_bit_width(), - }), - }; - let discriminant = TraceEnumDiscriminant { - location, - name: "$tag".intern(), - ty, - flow, - }; - let non_empty_fields = - Interned::from_iter(ty.variants().into_iter().enumerate().flat_map( - |(variant_index, variant)| { - variant.ty.map(|variant_ty| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => { - MakeTraceDeclTarget::Expr( - ops::VariantAccess::new_by_index( - Expr::::from_canonical(target), - variant_index, - ) - .to_expr(), - ) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + ty.discriminant_bit_width(), - ty: variant_ty, - }, - }, - variant.name, - source_location, - ) - }) - }, - )); - TraceEnumWithFields { - name, - discriminant, - non_empty_fields, - ty, - flow, - } - .into() - } - } - CanonicalType::Bundle(ty) => { - let fields = Interned::from_iter(ty.fields().iter().zip(ty.field_offsets()).map( - |(field, field_offset)| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => { - MakeTraceDeclTarget::Expr(Expr::field( - Expr::::from_canonical(target), - &field.name, - )) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + field_offset, - ty: field.ty, - }, - }, - field.name, - source_location, - ) - }, - )); - TraceBundle { - name, - fields, - ty, - flow: target.flow(), - } - .into() - } - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => { - self.make_trace_scalar(instantiated_module, target, name, source_location) - } - CanonicalType::PhantomConst(_) => TraceBundle { - name, - fields: Interned::default(), - ty: Bundle::new(Interned::default()), - flow: target.flow(), - } - .into(), - } - } - fn make_trace_decl( - &mut self, - instantiated_module: InstantiatedModule, - target_base: TargetBase, - ) -> TraceDecl { - let target = MakeTraceDeclTarget::Expr(target_base.to_expr()); - match target_base { - TargetBase::ModuleIO(module_io) => TraceModuleIO { - name: module_io.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - module_io.name(), - module_io.source_location(), - ) - .intern(), - ty: module_io.ty(), - flow: module_io.flow(), - } - .into(), - TargetBase::MemPort(mem_port) => { - let name = Intern::intern_owned(mem_port.port_name().to_string()); - let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( - instantiated_module, - target, - name, - mem_port.source_location(), - ) else { - unreachable!() - }; - TraceMemPort { - name, - bundle, - ty: mem_port.ty(), - } - .into() - } - TargetBase::Reg(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::RegSync(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::RegAsync(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::Wire(wire) => TraceWire { - name: wire.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - wire.name(), - wire.source_location(), - ) - .intern(), - ty: wire.ty(), - } - .into(), - TargetBase::Instance(instance) => { - let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( - instantiated_module, - target, - instance.name(), - instance.source_location(), - ) else { - unreachable!() - }; - let compiled_module = &self.modules[&InstantiatedModule::Child { - parent: instantiated_module.intern(), - instance: instance.intern(), - }]; - TraceInstance { - name: instance.name(), - instance_io, - module: compiled_module.trace_decls, - ty: instance.ty(), - } - .into() - } - } - } - fn compile_value( - &mut self, - target: TargetInInstantiatedModule, - ) -> CompiledValue { - if let Some(&retval) = self.compiled_values.get(&target) { - return retval; - } - let retval = match target.target { - Target::Base(base) => { - let unprefixed_layout = CompiledTypeLayout::get(base.canonical_ty()); - let layout = unprefixed_layout.with_prefixed_debug_names(&format!( - "{:?}.{:?}", - target.instantiated_module, - base.target_name() - )); - let range = self.insns.allocate_variable(&layout.layout); - let write = match *base { - TargetBase::ModuleIO(_) - | TargetBase::MemPort(_) - | TargetBase::Wire(_) - | TargetBase::Instance(_) => None, - TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => { - let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( - "{:?}.{:?}$next", - target.instantiated_module, - base.target_name() - )); - Some(( - write_layout, - self.insns.allocate_variable(&write_layout.layout), - )) - } - }; - CompiledValue { - range, - layout, - write, - } - } - Target::Child(target_child) => { - let parent = self.compile_value(TargetInInstantiatedModule { - instantiated_module: target.instantiated_module, - target: *target_child.parent(), - }); - match *target_child.path_element() { - TargetPathElement::BundleField(TargetPathBundleField { name }) => { - parent.map_ty(Bundle::from_canonical).field_by_name(name) - } - TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => { - parent.map_ty(Array::from_canonical).element(index) - } - TargetPathElement::DynArrayElement(_) => unreachable!(), - } - } - }; - self.compiled_values.insert(target, retval); - retval - } - fn compiled_expr_to_value( - &mut self, - expr: CompiledExpr, - source_location: SourceLocation, - ) -> CompiledValue { - if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { - return retval; - } - assert!( - expr.static_part.layout.ty.is_passive(), - "invalid expression passed to compiled_expr_to_value -- type must be passive", - ); - let CompiledExpr { - static_part, - indexes, - } = expr; - let retval = if indexes.as_ref().is_empty() { - CompiledValue { - layout: static_part.layout, - range: static_part.range, - write: None, - } - } else { - let layout = static_part.layout.with_anonymized_debug_info(); - let retval = CompiledValue { - layout, - range: self.insns.allocate_variable(&layout.layout), - write: None, - }; - let TypeIndexRange { - small_slots, - big_slots, - } = retval.range; - self.add_assignment( - Interned::default(), - small_slots - .iter() - .zip(static_part.range.small_slots.iter()) - .map(|(dest, base)| Insn::ReadSmallIndexed { - dest, - src: StatePartArrayIndexed { - base, - indexes: indexes.small_slots, - }, - }) - .chain( - big_slots - .iter() - .zip(static_part.range.big_slots.iter()) - .map(|(dest, base)| Insn::ReadIndexed { - dest, - src: StatePartArrayIndexed { - base, - indexes: indexes.big_slots, - }, - }), - ), - source_location, - ); - retval - }; - self.compiled_exprs_to_values.insert(expr, retval); - retval - } - fn add_assignment>( - &mut self, - conditions: Interned<[Cond]>, - insns: impl IntoIterator, - source_location: SourceLocation, - ) { - let insns = Vec::from_iter(insns.into_iter().map(Into::into)); - self.assignments - .push(Assignment::new(conditions, insns, source_location)); - } - fn simple_big_expr_input( - &mut self, - instantiated_module: InstantiatedModule, - input: Expr, - ) -> StatePartIndex { - let input = self.compile_expr(instantiated_module, input); - let input = - self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); - assert_eq!(input.range.len(), TypeLen::A_BIG_SLOT); - input.range.big_slots.start - } - fn compile_expr_helper( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - make_insns: impl FnOnce(&mut Self, TypeIndexRange) -> Vec, - ) -> CompiledValue { - let layout = CompiledTypeLayout::get(dest_ty); - let range = self.insns.allocate_variable(&layout.layout); - let retval = CompiledValue { - layout, - range, - write: None, - }; - let insns = make_insns(self, range); - self.add_assignment( - Interned::default(), - insns, - instantiated_module.leaf_module().source_location(), - ); - retval - } - fn simple_nary_big_expr_helper( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - make_insns: impl FnOnce(StatePartIndex) -> Vec, - ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { - assert_eq!(dest.len(), TypeLen::A_BIG_SLOT); - make_insns(dest.big_slots.start) - }) - } - fn simple_nary_big_expr( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - inputs: [Expr; N], - make_insns: impl FnOnce( - StatePartIndex, - [StatePartIndex; N], - ) -> Vec, - ) -> CompiledValue { - let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); - self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { - make_insns(dest, inputs) - }) - } - fn compiled_value_to_dyn_array_index( - &mut self, - compiled_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self - .compiled_values_to_dyn_array_indexes - .get(&compiled_value) - { - return retval; - } - let mut ty = compiled_value.layout.ty; - ty.width = ty.width.min(SmallUInt::BITS as usize); - let retval = match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, - TypeLen::A_BIG_SLOT => { - let debug_data = SlotDebugData { - name: Interned::default(), - ty: ty.canonical(), - }; - let dest = self - .insns - .allocate_variable(&TypeLayout { - small_slots: StatePartLayout::scalar(debug_data, ()), - big_slots: StatePartLayout::empty(), - }) - .small_slots - .start; - self.add_assignment( - Interned::default(), - vec![Insn::CastBigToArrayIndex { - dest, - src: compiled_value.range.big_slots.start, - }], - source_location, - ); - dest - } - _ => unreachable!(), - }; - self.compiled_values_to_dyn_array_indexes - .insert(compiled_value, retval); - retval - } - fn compiled_value_bool_dest_is_small( - &mut self, - compiled_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self - .compiled_value_bool_dest_is_small_map - .get(&compiled_value) - { - return retval; - } - let retval = match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, - TypeLen::A_BIG_SLOT => { - let debug_data = SlotDebugData { - name: Interned::default(), - ty: Bool.canonical(), - }; - let dest = self - .insns - .allocate_variable(&TypeLayout { - small_slots: StatePartLayout::scalar(debug_data, ()), - big_slots: StatePartLayout::empty(), - }) - .small_slots - .start; - self.add_assignment( - Interned::default(), - vec![Insn::IsNonZeroDestIsSmall { - dest, - src: compiled_value.range.big_slots.start, - }], - source_location, - ); - dest - } - _ => unreachable!(), - }; - self.compiled_value_bool_dest_is_small_map - .insert(compiled_value, retval); - retval - } - fn compile_cast_scalar_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - arg: Expr, - cast_fn: impl FnOnce(Expr) -> Expr, - ) -> CompiledValue { - let arg = Expr::::from_canonical(arg); - let retval = cast_fn(arg); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); - retval.map_ty(UInt::from_canonical) - } - fn compile_cast_aggregate_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - parts: impl IntoIterator>, - ) -> CompiledValue { - let retval = parts - .into_iter() - .map(|part| part.cast_to_bits()) - .reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width)) - .unwrap_or_else(|| UInt[0].zero().to_expr()); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); - retval.map_ty(UInt::from_canonical) - } - fn compile_cast_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - expr: ops::CastToBits, - ) -> CompiledValue { - match Expr::ty(expr.arg()) { - CanonicalType::UInt(_) => { - self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) - } - CanonicalType::SInt(ty) => self.compile_cast_scalar_to_bits( - instantiated_module, - expr.arg(), - |arg: Expr| arg.cast_to(ty.as_same_width_uint()), - ), - CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => self.compile_cast_scalar_to_bits( - instantiated_module, - expr.arg(), - |arg: Expr| arg.cast_to(UInt[1]), - ), - CanonicalType::Array(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, - (0..ty.len()).map(|index| Expr::::from_canonical(expr.arg())[index]), - ), - CanonicalType::Enum(ty) => self - .simple_nary_big_expr( - instantiated_module, - UInt[ty.type_properties().bit_width].canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::Copy { dest, src }], - ) - .map_ty(UInt::from_canonical), - CanonicalType::Bundle(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, - ty.fields().iter().map(|field| { - Expr::field(Expr::::from_canonical(expr.arg()), &field.name) - }), - ), - CanonicalType::PhantomConst(_) => { - self.compile_cast_aggregate_to_bits(instantiated_module, []) - } - } - } - fn compile_cast_bits_to( - &mut self, - instantiated_module: InstantiatedModule, - expr: ops::CastBitsTo, - ) -> CompiledValue { - let retval = match expr.ty() { - CanonicalType::UInt(_) => Expr::canonical(expr.arg()), - CanonicalType::SInt(ty) => Expr::canonical(expr.arg().cast_to(ty)), - CanonicalType::Bool(ty) => Expr::canonical(expr.arg().cast_to(ty)), - CanonicalType::Array(ty) => { - let stride = ty.element().bit_width(); - Expr::::canonical( - ops::ArrayLiteral::new( - ty.element(), - Interned::from_iter((0..ty.len()).map(|index| { - let start = stride * index; - let end = start + stride; - expr.arg()[start..end].cast_bits_to(ty.element()) - })), - ) - .to_expr(), - ) - } - ty @ CanonicalType::Enum(_) => { - return self.simple_nary_big_expr( - instantiated_module, - ty, - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::Copy { dest, src }], - ); - } - CanonicalType::Bundle(ty) => Expr::canonical( - ops::BundleLiteral::new( - ty, - Interned::from_iter(ty.field_offsets().iter().zip(&ty.fields()).map( - |(&offset, &field)| { - let end = offset + field.ty.bit_width(); - expr.arg()[offset..end].cast_bits_to(field.ty) - }, - )), - ) - .to_expr(), - ), - CanonicalType::AsyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), - CanonicalType::SyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(ty) => Expr::canonical(expr.arg().cast_to(ty)), - CanonicalType::PhantomConst(ty) => { - let _ = self.compile_expr(instantiated_module, Expr::canonical(expr.arg())); - Expr::canonical(ty.to_expr()) - } - }; - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) - } - fn compile_aggregate_literal( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - inputs: Interned<[Expr]>, - ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |this, dest| { - let mut insns = Vec::new(); - let mut offset = TypeIndex::ZERO; - for input in inputs { - let input = this.compile_expr(instantiated_module, input); - let input = this - .compiled_expr_to_value( - input, - instantiated_module.leaf_module().source_location(), - ) - .range; - insns.extend( - input.insns_for_copy_to(dest.slice(TypeIndexRange::new(offset, input.len()))), - ); - offset = offset.offset(input.len().as_index()); - } - insns - }) - } - fn compile_expr( - &mut self, - instantiated_module: InstantiatedModule, - expr: Expr, - ) -> CompiledExpr { - if let Some(&retval) = self.compiled_exprs.get(&expr) { - return retval; - } - let mut cast_bit = |arg: Expr| { - let src_signed = match Expr::ty(arg) { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => unreachable!(), - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - }; - let dest_signed = match Expr::ty(expr) { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => unreachable!(), - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - }; - self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| { - match (src_signed, dest_signed) { - (false, false) | (true, true) => { - vec![Insn::Copy { dest, src }] - } - (false, true) => vec![Insn::CastToSInt { - dest, - src, - dest_width: 1, - }], - (true, false) => vec![Insn::CastToUInt { - dest, - src, - dest_width: 1, - }], - } - }) - .into() - }; - let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) { - ExprEnum::UIntLiteral(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [], - |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }, - ) - .into(), - ExprEnum::SIntLiteral(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [], - |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }, - ) - .into(), - ExprEnum::BoolLiteral(expr) => self - .simple_nary_big_expr(instantiated_module, Bool.canonical(), [], |dest, []| { - vec![Insn::Const { - dest, - value: BigInt::from(expr).intern_sized(), - }] - }) - .into(), - ExprEnum::PhantomConst(_) => self - .compile_aggregate_literal(instantiated_module, Expr::ty(expr), Interned::default()) - .into(), - ExprEnum::BundleLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.field_values(), - ) - .into(), - ExprEnum::ArrayLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.element_values(), - ) - .into(), - ExprEnum::EnumLiteral(expr) => { - let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; - let enum_bits = if let Some(variant_value) = expr.variant_value() { - ( - UInt[expr.ty().discriminant_bit_width()] - .from_int_wrapping(expr.variant_index()), - variant_value, - ) - .cast_to_bits() - .cast_to(enum_bits_ty) - } else { - enum_bits_ty - .from_int_wrapping(expr.variant_index()) - .to_expr() - }; - self.compile_expr( - instantiated_module, - enum_bits.cast_bits_to(expr.ty().canonical()), - ) - } - ExprEnum::Uninit(expr) => self.compile_expr( - instantiated_module, - UInt[expr.ty().bit_width()].zero().cast_bits_to(expr.ty()), - ), - ExprEnum::NotU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::NotU { - dest, - src, - width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::NotS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::NotS { dest, src }], - ) - .into(), - ExprEnum::NotB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::NotU { - dest, - src, - width: 1, - }] - }, - ) - .into(), - ExprEnum::Neg(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::Neg { dest, src }], - ) - .into(), - ExprEnum::BitAndU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitAndS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitAndB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::AddU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], - ) - .into(), - ExprEnum::AddS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], - ) - .into(), - ExprEnum::SubU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| { - vec![Insn::SubU { - dest, - lhs, - rhs, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::SubS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::SubS { dest, lhs, rhs }], - ) - .into(), - ExprEnum::MulU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], - ) - .into(), - ExprEnum::MulS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DivU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DivS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], - ) - .into(), - ExprEnum::RemU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], - ) - .into(), - ExprEnum::RemS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShlU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShlS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], - ) - .into(), - ExprEnum::FixedShlU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shl { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShlS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shl { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shr { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shr { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::CmpLtB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLtU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLtS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CastUIntToUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToUInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastUIntToSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToSInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastSIntToUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToUInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastSIntToSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToSInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastBoolToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::FieldAccess(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Bundle::from_canonical) - .field_by_index(expr.field_index()), - ExprEnum::VariantAccess(variant_access) => { - let start = Expr::ty(variant_access.base()).discriminant_bit_width(); - let len = Expr::ty(expr).bit_width(); - self.compile_expr( - instantiated_module, - variant_access.base().cast_to_bits()[start..start + len] - .cast_bits_to(Expr::ty(expr)), - ) - } - ExprEnum::ArrayIndex(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Array::from_canonical) - .element(expr.element_index()), - ExprEnum::DynArrayIndex(expr) => { - let element_index = - self.compile_expr(instantiated_module, Expr::canonical(expr.element_index())); - let element_index = self.compiled_expr_to_value( - element_index, - instantiated_module.leaf_module().source_location(), - ); - let index_slot = self.compiled_value_to_dyn_array_index( - element_index.map_ty(UInt::from_canonical), - instantiated_module.leaf_module().source_location(), - ); - self.compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Array::from_canonical) - .element_dyn(index_slot) - } - ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), - ) - } - .into(), - ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), - ) - } - .into(), - ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), - ) - } - .into(), - ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), - ) - } - .into(), - ExprEnum::ReduceBitXorU(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::<1>::TYPE.canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::ReduceBitXor { - dest, - src, - input_width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::ReduceBitXorS(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::<1>::TYPE.canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::ReduceBitXor { - dest, - src, - input_width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::SliceUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::new_dyn(expr.range().len()).canonical(), - [Expr::canonical(expr.base())], - |dest, [src]| { - vec![Insn::SliceInt { - dest, - src, - start: expr.range().start, - len: expr.range().len(), - }] - }, - ) - .into(), - ExprEnum::SliceSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::new_dyn(expr.range().len()).canonical(), - [Expr::canonical(expr.base())], - |dest, [src]| { - vec![Insn::SliceInt { - dest, - src, - start: expr.range().start, - len: expr.range().len(), - }] - }, - ) - .into(), - ExprEnum::CastToBits(expr) => self - .compile_cast_to_bits(instantiated_module, expr) - .map_ty(CanonicalType::UInt) - .into(), - ExprEnum::CastBitsTo(expr) => { - self.compile_cast_bits_to(instantiated_module, expr).into() - } - ExprEnum::ModuleIO(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Instance(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Wire(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Reg(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::RegSync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::RegAsync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::MemPort(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - }; - self.compiled_exprs.insert(expr, retval); - retval - } - fn compile_simple_connect( - &mut self, - conditions: Interned<[Cond]>, - lhs: CompiledExpr, - rhs: CompiledValue, - source_location: SourceLocation, - ) { - let CompiledExpr { - static_part: lhs_static_part, - indexes, - } = lhs; - let (lhs_layout, lhs_range) = lhs_static_part.write(); - assert!( - lhs_layout.ty.is_passive(), - "invalid expression passed to compile_simple_connect -- type must be passive", - ); - let TypeIndexRange { - small_slots, - big_slots, - } = lhs_range; - self.add_assignment( - conditions, - small_slots - .iter() - .zip(rhs.range.small_slots.iter()) - .map(|(base, src)| { - if indexes.small_slots.is_empty() { - Insn::CopySmall { dest: base, src } - } else { - Insn::WriteSmallIndexed { - dest: StatePartArrayIndexed { - base, - indexes: indexes.small_slots, - }, - src, - } - } - }) - .chain( - big_slots - .iter() - .zip(rhs.range.big_slots.iter()) - .map(|(base, src)| { - if indexes.big_slots.is_empty() { - Insn::Copy { dest: base, src } - } else { - Insn::WriteIndexed { - dest: StatePartArrayIndexed { - base, - indexes: indexes.big_slots, - }, - src, - } - } - }), - ), - source_location, - ); - } - fn compile_connect( - &mut self, - lhs_instantiated_module: InstantiatedModule, - lhs_conditions: Interned<[Cond]>, - lhs: Expr, - rhs_instantiated_module: InstantiatedModule, - rhs_conditions: Interned<[Cond]>, - mut rhs: Expr, - source_location: SourceLocation, - ) { - if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() { - match Expr::ty(lhs) { - CanonicalType::UInt(lhs_ty) => { - rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); - } - CanonicalType::SInt(lhs_ty) => { - rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); - } - CanonicalType::Bool(_) => unreachable!(), - CanonicalType::Array(lhs_ty) => { - let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - assert_eq!(lhs_ty.len(), rhs_ty.len()); - let lhs = Expr::::from_canonical(lhs); - let rhs = Expr::::from_canonical(rhs); - for index in 0..lhs_ty.len() { - self.compile_connect( - lhs_instantiated_module, - lhs_conditions, - lhs[index], - rhs_instantiated_module, - rhs_conditions, - rhs[index], - source_location, - ); - } - return; - } - CanonicalType::Enum(lhs_ty) => { - let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - todo!("handle connect with different enum types"); - } - CanonicalType::Bundle(lhs_ty) => { - let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len()); - let lhs = Expr::::from_canonical(lhs); - let rhs = Expr::::from_canonical(rhs); - for ( - field_index, - ( - BundleField { - name, - flipped, - ty: _, - }, - rhs_field, - ), - ) in lhs_ty.fields().into_iter().zip(rhs_ty.fields()).enumerate() - { - assert_eq!(name, rhs_field.name); - assert_eq!(flipped, rhs_field.flipped); - let lhs_expr = ops::FieldAccess::new_by_index(lhs, field_index).to_expr(); - let rhs_expr = ops::FieldAccess::new_by_index(rhs, field_index).to_expr(); - if flipped { - // swap lhs/rhs - self.compile_connect( - rhs_instantiated_module, - rhs_conditions, - rhs_expr, - lhs_instantiated_module, - lhs_conditions, - lhs_expr, - source_location, - ); - } else { - self.compile_connect( - lhs_instantiated_module, - lhs_conditions, - lhs_expr, - rhs_instantiated_module, - rhs_conditions, - rhs_expr, - source_location, - ); - } - } - return; - } - CanonicalType::AsyncReset(_) => unreachable!(), - CanonicalType::SyncReset(_) => unreachable!(), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(_) => unreachable!(), - CanonicalType::PhantomConst(_) => unreachable!("PhantomConst mismatch"), - } - } - let Some(target) = lhs.target() else { - unreachable!("connect lhs must have target"); - }; - let lhs_decl_conditions = self.decl_conditions[&TargetInInstantiatedModule { - instantiated_module: lhs_instantiated_module, - target: target.base().into(), - }]; - let lhs = self.compile_expr(lhs_instantiated_module, lhs); - let rhs = self.compile_expr(rhs_instantiated_module, rhs); - let rhs = self.compiled_expr_to_value(rhs, source_location); - self.compile_simple_connect( - lhs_conditions[lhs_decl_conditions.len()..].intern(), - lhs, - rhs, - source_location, - ); - } - fn compile_clock( - &mut self, - clk: CompiledValue, - source_location: SourceLocation, - ) -> ClockTrigger { - if let Some(&retval) = self.compiled_value_to_clock_trigger_map.get(&clk) { - return retval; - } - let mut alloc_small_slot = |part_name: &str| { - self.insns - .state_layout - .ty - .small_slots - .allocate(&StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty: Bool.canonical(), - }, - (), - )) - .start - }; - let last_clk_was_low = alloc_small_slot("last_clk_was_low"); - let clk_triggered = alloc_small_slot("clk_triggered"); - let retval = ClockTrigger { - last_clk_was_low, - clk: self.compiled_value_bool_dest_is_small( - clk.map_ty(CanonicalType::Clock), - source_location, - ), - clk_triggered, - source_location, - }; - self.add_assignment( - Interned::default(), - [Insn::AndSmall { - dest: clk_triggered, - lhs: retval.clk, - rhs: last_clk_was_low, - }], - source_location, - ); - self.clock_triggers.push(retval); - self.compiled_value_to_clock_trigger_map.insert(clk, retval); - retval - } - fn compile_enum_discriminant( - &mut self, - enum_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self.enum_discriminants.get(&enum_value) { - return retval; - } - let retval_ty = Enum::new( - enum_value - .layout - .ty - .variants() - .iter() - .map(|variant| EnumVariant { - name: variant.name, - ty: None, - }) - .collect(), - ); - let retval = if retval_ty == enum_value.layout.ty - && enum_value.range.len() == TypeLen::A_SMALL_SLOT - { - enum_value.range.small_slots.start - } else { - let retval = self - .insns - .state_layout - .ty - .small_slots - .allocate(&StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty: retval_ty.canonical(), - }, - (), - )) - .start; - let discriminant_bit_width = enum_value.layout.ty.discriminant_bit_width(); - let discriminant_mask = !(!0u64 << discriminant_bit_width); - let insn = match enum_value.range.len() { - TypeLen::A_BIG_SLOT => Insn::AndBigWithSmallImmediate { - dest: retval, - lhs: enum_value.range.big_slots.start, - rhs: discriminant_mask, - }, - TypeLen::A_SMALL_SLOT => { - if discriminant_bit_width == enum_value.layout.ty.type_properties().bit_width { - Insn::CopySmall { - dest: retval, - src: enum_value.range.small_slots.start, - } - } else { - Insn::AndSmallImmediate { - dest: retval, - lhs: enum_value.range.small_slots.start, - rhs: discriminant_mask, - } - } - } - _ => unreachable!(), - }; - self.add_assignment(Interned::default(), [insn], source_location); - retval - }; - self.enum_discriminants.insert(enum_value, retval); - retval - } - fn compile_stmt_reg( - &mut self, - stmt_reg: StmtReg, - instantiated_module: InstantiatedModule, - value: CompiledValue, - ) { - let StmtReg { annotations, reg } = stmt_reg; - let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); - let clk = self - .compiled_expr_to_value(clk, reg.source_location()) - .map_ty(Clock::from_canonical); - let clk = self.compile_clock(clk, reg.source_location()); - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = (); - - type Output = bool; - - fn reset(self, _input: Self::Input) -> Self::Output { - unreachable!() - } - - fn sync_reset(self, _input: Self::Input) -> Self::Output { - false - } - - fn async_reset(self, _input: Self::Input) -> Self::Output { - true - } - } - let reset = if let Some(init) = reg.init() { - let init = self.compile_expr(instantiated_module, init); - let init = self.compiled_expr_to_value(init, reg.source_location()); - let rst = - self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst)); - let rst = self.compiled_expr_to_value(rst, reg.source_location()); - let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location()); - let is_async = R::dispatch((), Dispatch); - if is_async { - let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool)); - let cond = self.compile_expr(instantiated_module, cond); - let cond = self.compiled_expr_to_value(cond, reg.source_location()); - let cond = cond.map_ty(Bool::from_canonical); - // write to the register's current value since asynchronous reset is combinational - let lhs = CompiledValue { - layout: value.layout, - range: value.range, - write: None, - } - .into(); - self.compile_simple_connect( - [Cond { - body: CondBody::IfTrue { cond }, - source_location: reg.source_location(), - }][..] - .intern(), - lhs, - init, - reg.source_location(), - ); - } - Some(RegisterReset { - is_async, - init, - rst, - }) - } else { - None - }; - self.registers.push(Register { - value, - clk_triggered: clk.clk_triggered, - reset, - source_location: reg.source_location(), - }); - } - fn compile_declaration( - &mut self, - declaration: StmtDeclaration, - parent_module: Interned, - conditions: Interned<[Cond]>, - ) -> TraceDecl { - let target_base: TargetBase = match &declaration { - StmtDeclaration::Wire(v) => v.wire.into(), - StmtDeclaration::Reg(v) => v.reg.into(), - StmtDeclaration::RegSync(v) => v.reg.into(), - StmtDeclaration::RegAsync(v) => v.reg.into(), - StmtDeclaration::Instance(v) => v.instance.into(), - }; - let target = TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: target_base.into(), - }; - self.decl_conditions.insert(target, conditions); - let compiled_value = self.compile_value(target); - match declaration { - StmtDeclaration::Wire(StmtWire { annotations, wire }) => {} - StmtDeclaration::Reg(_) => { - unreachable!("Reset types were already replaced by SyncReset or AsyncReset"); - } - StmtDeclaration::RegSync(stmt_reg) => { - self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) - } - StmtDeclaration::RegAsync(stmt_reg) => { - self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) - } - StmtDeclaration::Instance(StmtInstance { - annotations, - instance, - }) => { - let inner_instantiated_module = InstantiatedModule::Child { - parent: parent_module, - instance: instance.intern_sized(), - } - .intern_sized(); - let instance_expr = instance.to_expr(); - self.compile_module(inner_instantiated_module); - for (field_index, module_io) in - instance.instantiated().module_io().into_iter().enumerate() - { - let instance_field = - ops::FieldAccess::new_by_index(instance_expr, field_index).to_expr(); - match Expr::flow(instance_field) { - Flow::Source => { - // we need to supply the value to the instance since the - // parent module expects to read from the instance - self.compile_connect( - *parent_module, - conditions, - instance_field, - *inner_instantiated_module, - Interned::default(), - module_io.module_io.to_expr(), - instance.source_location(), - ); - } - Flow::Sink => { - // we need to take the value from the instance since the - // parent module expects to write to the instance - self.compile_connect( - *inner_instantiated_module, - Interned::default(), - module_io.module_io.to_expr(), - *parent_module, - conditions, - instance_field, - instance.source_location(), - ); - } - Flow::Duplex => unreachable!(), - } - } - } - } - self.make_trace_decl(*parent_module, target_base) - } - fn allocate_delay_chain( - &mut self, - len: usize, - layout: &TypeLayout, - first: Option, - last: Option, - mut from_allocation: impl FnMut(TypeIndexRange) -> T, - ) -> Vec { - match (len, first, last) { - (0, _, _) => Vec::new(), - (1, Some(v), _) | (1, None, Some(v)) => vec![v], - (2, Some(first), Some(last)) => vec![first, last], - (len, first, last) => { - let inner_len = len - first.is_some() as usize - last.is_some() as usize; - first - .into_iter() - .chain( - (0..inner_len) - .map(|_| from_allocation(self.insns.allocate_variable(layout))), - ) - .chain(last) - .collect() - } - } - } - fn allocate_delay_chain_small( - &mut self, - len: usize, - ty: CanonicalType, - first: Option>, - last: Option>, - ) -> Vec> { - self.allocate_delay_chain( - len, - &TypeLayout { - small_slots: StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty, - }, - (), - ), - big_slots: StatePartLayout::empty(), - }, - first, - last, - |range| range.small_slots.start, - ) - } - fn compile_memory_port_rw_helper( - &mut self, - memory: StatePartIndex, - stride: usize, - mut start: usize, - data_layout: CompiledTypeLayout, - mask_layout: CompiledTypeLayout, - mut read: Option>, - mut write: Option>, - ) { - match data_layout.body { - CompiledTypeLayoutBody::Scalar => { - let CompiledTypeLayoutBody::Scalar = mask_layout.body else { - unreachable!(); - }; - let signed = match data_layout.ty { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => false, - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - }; - let width = data_layout.ty.bit_width(); - if let Some(MemoryPortReadInsns { - addr, - en: _, - write_mode: _, - data, - insns, - }) = read - { - insns.push( - match data.len() { - TypeLen::A_BIG_SLOT => { - let dest = data.big_slots.start; - if signed { - Insn::MemoryReadSInt { - dest, - memory, - addr, - stride, - start, - width, - } - } else { - Insn::MemoryReadUInt { - dest, - memory, - addr, - stride, - start, - width, - } - } - } - TypeLen::A_SMALL_SLOT => { - let _dest = data.small_slots.start; - todo!("memory ports' data are always big for now"); - } - _ => unreachable!(), - } - .into(), - ); - } - if let Some(MemoryPortWriteInsns { - addr, - en: _, - write_mode: _, - data, - mask, - insns, - }) = write - { - let end_label = self.insns.new_label(); - insns.push( - match mask.len() { - TypeLen::A_BIG_SLOT => Insn::BranchIfZero { - target: end_label.0, - value: mask.big_slots.start, - }, - TypeLen::A_SMALL_SLOT => Insn::BranchIfSmallZero { - target: end_label.0, - value: mask.small_slots.start, - }, - _ => unreachable!(), - } - .into(), - ); - insns.push( - match data.len() { - TypeLen::A_BIG_SLOT => { - let value = data.big_slots.start; - if signed { - Insn::MemoryWriteSInt { - value, - memory, - addr, - stride, - start, - width, - } - } else { - Insn::MemoryWriteUInt { - value, - memory, - addr, - stride, - start, - width, - } - } - } - TypeLen::A_SMALL_SLOT => { - let _value = data.small_slots.start; - todo!("memory ports' data are always big for now"); - } - _ => unreachable!(), - } - .into(), - ); - insns.push(end_label.into()); - } - } - CompiledTypeLayoutBody::Array { element } => { - let CompiledTypeLayoutBody::Array { - element: mask_element, - } = mask_layout.body - else { - unreachable!(); - }; - let ty = ::from_canonical(data_layout.ty); - let element_bit_width = ty.element().bit_width(); - let element_size = element.layout.len(); - let mask_element_size = mask_element.layout.len(); - for element_index in 0..ty.len() { - self.compile_memory_port_rw_helper( - memory, - stride, - start, - *element, - *mask_element, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.index_array(element_size, element_index), - insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| { - MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.index_array(element_size, element_index), - mask: mask.index_array(mask_element_size, element_index), - insns, - } - }, - ), - ); - start += element_bit_width; - } - } - CompiledTypeLayoutBody::Bundle { fields } => { - let CompiledTypeLayoutBody::Bundle { - fields: mask_fields, - } = mask_layout.body - else { - unreachable!(); - }; - assert_eq!(fields.len(), mask_fields.len()); - for (field, mask_field) in fields.into_iter().zip(mask_fields) { - let field_index_range = - TypeIndexRange::new(field.offset, field.ty.layout.len()); - let mask_field_index_range = - TypeIndexRange::new(mask_field.offset, mask_field.ty.layout.len()); - self.compile_memory_port_rw_helper( - memory, - stride, - start, - field.ty, - mask_field.ty, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.slice(field_index_range), - insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| { - MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.slice(field_index_range), - mask: mask.slice(mask_field_index_range), - insns, - } - }, - ), - ); - start = start + field.ty.ty.bit_width(); - } - } - } - } - fn compile_memory_port_rw( - &mut self, - memory: StatePartIndex, - data_layout: CompiledTypeLayout, - mask_layout: CompiledTypeLayout, - mut read: Option>, - mut write: Option>, - ) { - let read_else_label = read.as_mut().map( - |MemoryPortReadInsns { - addr: _, - en, - write_mode, - data: _, - insns, - }| { - let else_label = self.insns.new_label(); - insns.push( - Insn::BranchIfSmallZero { - target: else_label.0, - value: *en, - } - .into(), - ); - if let Some(write_mode) = *write_mode { - insns.push( - Insn::BranchIfSmallNonZero { - target: else_label.0, - value: write_mode, - } - .into(), - ); - } - else_label - }, - ); - let write_end_label = write.as_mut().map( - |MemoryPortWriteInsns { - addr: _, - en, - write_mode, - data: _, - mask: _, - insns, - }| { - let end_label = self.insns.new_label(); - insns.push( - Insn::BranchIfSmallZero { - target: end_label.0, - value: *en, - } - .into(), - ); - if let Some(write_mode) = *write_mode { - insns.push( - Insn::BranchIfSmallZero { - target: end_label.0, - value: write_mode, - } - .into(), - ); - } - end_label - }, - ); - self.compile_memory_port_rw_helper( - memory, - data_layout.ty.bit_width(), - 0, - data_layout, - mask_layout, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: *data, - insns: *insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: *data, - mask: *mask, - insns: *insns, - }, - ), - ); - if let ( - Some(else_label), - Some(MemoryPortReadInsns { - addr: _, - en: _, - write_mode: _, - data, - insns, - }), - ) = (read_else_label, read) - { - let end_label = self.insns.new_label(); - insns.push( - Insn::Branch { - target: end_label.0, - } - .into(), - ); - insns.push(else_label.into()); - let TypeIndexRange { - small_slots, - big_slots, - } = data; - for dest in small_slots.iter() { - insns.push(Insn::ConstSmall { dest, value: 0 }.into()); - } - for dest in big_slots.iter() { - insns.push( - Insn::Const { - dest, - value: BigInt::ZERO.intern_sized(), - } - .into(), - ); - } - insns.push(end_label.into()); - } - if let (Some(end_label), Some(write)) = (write_end_label, write) { - write.insns.push(end_label.into()); - } - } - fn compile_memory( - &mut self, - mem: Mem, - instantiated_module: InstantiatedModule, - conditions: Interned<[Cond]>, - trace_decls: &mut Vec, - ) { - let data_layout = CompiledTypeLayout::get(mem.array_type().element()); - let mask_layout = CompiledTypeLayout::get(mem.array_type().element().mask_type()); - let read_latency_plus_1 = mem - .read_latency() - .checked_add(1) - .expect("read latency too big"); - let write_latency_plus_1 = mem - .write_latency() - .get() - .checked_add(1) - .expect("write latency too big"); - let read_cycle = match mem.read_under_write() { - ReadUnderWrite::Old => 0, - ReadUnderWrite::New => mem.read_latency(), - ReadUnderWrite::Undefined => mem.read_latency() / 2, // something other than Old or New - }; - let memory = self - .insns - .state_layout - .memories - .allocate(&StatePartLayout::scalar( - (), - MemoryData { - array_type: mem.array_type(), - data: mem.initial_value().unwrap_or_else(|| { - Intern::intern_owned(BitVec::repeat( - false, - mem.array_type().type_properties().bit_width, - )) - }), - }, - )) - .start; - let (ports, trace_ports) = mem - .ports() - .iter() - .map(|&port| { - let target_base = TargetBase::MemPort(port); - let target = TargetInInstantiatedModule { - instantiated_module, - target: target_base.into(), - }; - self.decl_conditions.insert(target, conditions); - let TraceDecl::Scope(TraceScope::MemPort(trace_port)) = - self.make_trace_decl(instantiated_module, target_base) - else { - unreachable!(); - }; - let clk = Expr::field(port.to_expr(), "clk"); - let clk = self.compile_expr(instantiated_module, clk); - let clk = self.compiled_expr_to_value(clk, mem.source_location()); - let clk_triggered = self - .compile_clock(clk.map_ty(Clock::from_canonical), mem.source_location()) - .clk_triggered; - let en = Expr::field(port.to_expr(), "en"); - let en = self.compile_expr(instantiated_module, en); - let en = self.compiled_expr_to_value(en, mem.source_location()); - let en = self.compiled_value_bool_dest_is_small(en, mem.source_location()); - let addr = Expr::field(port.to_expr(), "addr"); - let addr = self.compile_expr(instantiated_module, addr); - let addr = self.compiled_expr_to_value(addr, mem.source_location()); - let addr_ty = addr.layout.ty; - let addr = self.compiled_value_to_dyn_array_index( - addr.map_ty(UInt::from_canonical), - mem.source_location(), - ); - let read_data = port.port_kind().rdata_name().map(|name| { - let read_data = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let read_data = self.compiled_expr_to_value(read_data, mem.source_location()); - read_data.range - }); - let write_data = port.port_kind().wdata_name().map(|name| { - let write_data = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_data = self.compiled_expr_to_value(write_data, mem.source_location()); - write_data.range - }); - let write_mask = port.port_kind().wmask_name().map(|name| { - let write_mask = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_mask = self.compiled_expr_to_value(write_mask, mem.source_location()); - write_mask.range - }); - let write_mode = port.port_kind().wmode_name().map(|name| { - let write_mode = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_mode = self.compiled_expr_to_value(write_mode, mem.source_location()); - self.compiled_value_bool_dest_is_small(write_mode, mem.source_location()) - }); - struct PortParts { - en_delayed_len: usize, - addr_delayed_len: usize, - read_data_delayed_len: usize, - write_data_delayed_len: usize, - write_mask_delayed_len: usize, - write_mode_delayed_len: usize, - read_cycle: Option, - write_cycle: Option, - } - let PortParts { - en_delayed_len, - addr_delayed_len, - read_data_delayed_len, - write_data_delayed_len, - write_mask_delayed_len, - write_mode_delayed_len, - read_cycle, - write_cycle, - } = match port.port_kind() { - PortKind::ReadOnly => PortParts { - en_delayed_len: read_cycle + 1, - addr_delayed_len: read_cycle + 1, - read_data_delayed_len: read_latency_plus_1 - read_cycle, - write_data_delayed_len: 0, - write_mask_delayed_len: 0, - write_mode_delayed_len: 0, - read_cycle: Some(read_cycle), - write_cycle: None, - }, - PortKind::WriteOnly => PortParts { - en_delayed_len: write_latency_plus_1, - addr_delayed_len: write_latency_plus_1, - read_data_delayed_len: 0, - write_data_delayed_len: write_latency_plus_1, - write_mask_delayed_len: write_latency_plus_1, - write_mode_delayed_len: 0, - read_cycle: None, - write_cycle: Some(mem.write_latency().get()), - }, - PortKind::ReadWrite => { - let can_rw_at_end = match mem.read_under_write() { - ReadUnderWrite::Old => false, - ReadUnderWrite::New | ReadUnderWrite::Undefined => true, - }; - let latency_plus_1 = read_latency_plus_1; - if latency_plus_1 != write_latency_plus_1 || !can_rw_at_end { - todo!( - "not sure what to do, issue: \ - https://github.com/chipsalliance/firrtl-spec/issues/263" - ); - } - PortParts { - en_delayed_len: latency_plus_1, - addr_delayed_len: latency_plus_1, - read_data_delayed_len: 1, - write_data_delayed_len: latency_plus_1, - write_mask_delayed_len: latency_plus_1, - write_mode_delayed_len: latency_plus_1, - read_cycle: Some(latency_plus_1 - 1), - write_cycle: Some(latency_plus_1 - 1), - } - } - }; - let addr_delayed = self.allocate_delay_chain_small( - addr_delayed_len, - addr_ty.canonical(), - Some(addr), - None, - ); - let en_delayed = self.allocate_delay_chain_small( - en_delayed_len, - Bool.canonical(), - Some(en), - None, - ); - let read_data_delayed = self.allocate_delay_chain( - read_data_delayed_len, - &data_layout.layout, - None, - read_data, - |v| v, - ); - let write_data_delayed = self.allocate_delay_chain( - write_data_delayed_len, - &data_layout.layout, - write_data, - None, - |v| v, - ); - let write_mask_delayed = self.allocate_delay_chain( - write_mask_delayed_len, - &mask_layout.layout, - write_mask, - None, - |v| v, - ); - let write_mode_delayed = self.allocate_delay_chain_small( - write_mode_delayed_len, - Bool.canonical(), - write_mode, - None, - ); - let mut read_insns = Vec::new(); - let mut write_insns = Vec::new(); - self.compile_memory_port_rw( - memory, - data_layout, - mask_layout, - read_cycle.map(|read_cycle| MemoryPortReadInsns { - addr: addr_delayed[read_cycle], - en: en_delayed[read_cycle], - write_mode: write_mode_delayed.get(read_cycle).copied(), - data: read_data_delayed[0], - insns: &mut read_insns, - }), - write_cycle.map(|write_cycle| MemoryPortWriteInsns { - addr: addr_delayed[write_cycle], - en: en_delayed[write_cycle], - write_mode: write_mode_delayed.get(write_cycle).copied(), - data: write_data_delayed[write_cycle], - mask: write_mask_delayed[write_cycle], - insns: &mut write_insns, - }), - ); - self.add_assignment(Interned::default(), read_insns, mem.source_location()); - ( - MemoryPort { - clk_triggered, - addr_delayed, - en_delayed, - data_layout, - read_data_delayed, - write_data_delayed, - write_mask_delayed, - write_mode_delayed, - write_insns, - }, - trace_port, - ) - }) - .unzip(); - let name = mem.scoped_name().1 .0; - let id = TraceMemoryId(self.memories.len()); - let stride = mem.array_type().element().bit_width(); - let trace = TraceMem { - id, - name, - stride, - element_type: self - .make_trace_decl_child( - instantiated_module, - MakeTraceDeclTarget::Memory { - id, - depth: mem.array_type().len(), - stride, - start: 0, - ty: mem.array_type().element(), - }, - name, - mem.source_location(), - ) - .intern_sized(), - ports: Intern::intern_owned(trace_ports), - array_type: mem.array_type(), - }; - trace_decls.push(trace.into()); - self.memories.push(Memory { - mem, - memory, - trace, - ports, - }); - } - fn compile_block( - &mut self, - parent_module: Interned, - block: Block, - conditions: Interned<[Cond]>, - trace_decls: &mut Vec, - ) { - let Block { memories, stmts } = block; - for memory in memories { - self.compile_memory(memory, *parent_module, conditions, trace_decls); - } - for stmt in stmts { - match stmt { - Stmt::Connect(StmtConnect { - lhs, - rhs, - source_location, - }) => self.compile_connect( - *parent_module, - conditions, - lhs, - *parent_module, - conditions, - rhs, - source_location, - ), - Stmt::Formal(StmtFormal { .. }) => todo!("implement simulating formal statements"), - Stmt::If(StmtIf { - cond, - source_location, - blocks: [then_block, else_block], - }) => { - let cond = self.compile_expr(*parent_module, Expr::canonical(cond)); - let cond = self.compiled_expr_to_value(cond, source_location); - let cond = cond.map_ty(Bool::from_canonical); - self.compile_block( - parent_module, - then_block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::IfTrue { cond }, - source_location, - }])), - trace_decls, - ); - self.compile_block( - parent_module, - else_block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::IfFalse { cond }, - source_location, - }])), - trace_decls, - ); - } - Stmt::Match(StmtMatch { - expr, - source_location, - blocks, - }) => { - let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr)); - let enum_expr = self.compiled_expr_to_value(enum_expr, source_location); - let enum_expr = enum_expr.map_ty(Enum::from_canonical); - let discriminant = self.compile_enum_discriminant(enum_expr, source_location); - for (variant_index, block) in blocks.into_iter().enumerate() { - self.compile_block( - parent_module, - block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::MatchArm { - discriminant, - variant_index, - }, - source_location, - }])), - trace_decls, - ); - } - } - Stmt::Declaration(declaration) => { - trace_decls.push(self.compile_declaration( - declaration, - parent_module, - conditions, - )); - } - } - } - } - fn compile_module(&mut self, module: Interned) -> &CompiledModule { - let mut trace_decls = Vec::new(); - let module_io = module - .leaf_module() - .module_io() - .iter() - .map( - |&AnnotatedModuleIO { - annotations: _, - module_io, - }| { - let target = TargetInInstantiatedModule { - instantiated_module: *module, - target: Target::from(module_io), - }; - self.decl_conditions.insert(target, Interned::default()); - trace_decls.push(self.make_trace_decl(*module, module_io.into())); - self.compile_value(target) - }, - ) - .collect(); - match module.leaf_module().body() { - ModuleBody::Normal(NormalModuleBody { body }) => { - self.compile_block(module, body, Interned::default(), &mut trace_decls); - } - ModuleBody::Extern(ExternModuleBody { - verilog_name: _, - parameters: _, - simulation, - }) => { - let Some(simulation) = simulation else { - panic!( - "can't simulate extern module without extern_module_simulation: {}", - module.leaf_module().source_location() - ); - }; - self.extern_modules.push(CompiledExternModule { - module_io_targets: module - .leaf_module() - .module_io() - .iter() - .map(|v| Target::from(v.module_io)) - .collect(), - module_io, - simulation, - }); - } - } - let hashbrown::hash_map::Entry::Vacant(entry) = self.modules.entry(*module) else { - unreachable!("compiled same instantiated module twice"); - }; - entry.insert(CompiledModule { - module_io, - trace_decls: TraceModule { - name: module.leaf_module().name(), - children: Intern::intern_owned(trace_decls), - }, - }) - } - fn process_assignments(&mut self) { - self.assignments - .finalize(self.insns.state_layout().ty.clone().into()); - if let Some(DebugOpaque(dump_assignments_dot)) = &self.dump_assignments_dot { - let graph = - petgraph::graph::DiGraph::<_, _, usize>::from_elements(self.assignments.elements()); - dump_assignments_dot(&petgraph::dot::Dot::new(&graph)); - } - let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) { - Ok(nodes) => nodes - .into_iter() - .filter_map(|n| match n { - AssignmentOrSlotIndex::AssignmentIndex(v) => Some(v), - _ => None, - }) - .collect(), - Err(e) => match e.node_id() { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( - "combinatorial logic cycle detected at: {}", - self.assignments.assignments()[assignment_index].source_location, - ), - AssignmentOrSlotIndex::SmallSlot(slot) => panic!( - "combinatorial logic cycle detected through: {}", - self.insns.state_layout().ty.small_slots.debug_data[slot.as_usize()].name, - ), - AssignmentOrSlotIndex::BigSlot(slot) => panic!( - "combinatorial logic cycle detected through: {}", - self.insns.state_layout().ty.big_slots.debug_data[slot.as_usize()].name, - ), - }, - }; - struct CondStackEntry<'a> { - cond: &'a Cond, - end_label: Label, - } - let mut cond_stack = Vec::>::new(); - for assignment_index in assignments_order { - let Assignment { - inputs: _, - outputs: _, - conditions, - insns, - source_location, - } = &self.assignments.assignments()[assignment_index]; - let mut same_len = 0; - for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() { - if entry.cond != cond { - break; - } - same_len = index + 1; - } - while cond_stack.len() > same_len { - let CondStackEntry { cond: _, end_label } = - cond_stack.pop().expect("just checked len"); - self.insns.define_label_at_next_insn(end_label); - } - for cond in &conditions[cond_stack.len()..] { - let end_label = self.insns.new_label(); - match cond.body { - CondBody::IfTrue { cond: cond_value } - | CondBody::IfFalse { cond: cond_value } => { - let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len() { - TypeLen::A_SMALL_SLOT => ( - Insn::BranchIfSmallZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - Insn::BranchIfSmallNonZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - ), - TypeLen::A_BIG_SLOT => ( - Insn::BranchIfZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - Insn::BranchIfNonZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - ), - _ => unreachable!(), - }; - self.insns.push( - if let CondBody::IfTrue { .. } = cond.body { - branch_if_zero - } else { - branch_if_non_zero - }, - cond.source_location, - ); - } - CondBody::MatchArm { - discriminant, - variant_index, - } => { - self.insns.push( - Insn::BranchIfSmallNeImmediate { - target: end_label.0, - lhs: discriminant, - rhs: variant_index as _, - }, - cond.source_location, - ); - } - } - cond_stack.push(CondStackEntry { cond, end_label }); - } - self.insns.extend(insns.iter().copied(), *source_location); - } - for CondStackEntry { cond: _, end_label } in cond_stack { - self.insns.define_label_at_next_insn(end_label); - } - } - fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { - mem::take(&mut self.clock_triggers) - .into_iter() - .map( - |ClockTrigger { - last_clk_was_low, - clk, - clk_triggered, - source_location, - }| { - self.insns.push( - Insn::XorSmallImmediate { - dest: last_clk_was_low, - lhs: clk, - rhs: 1, - }, - source_location, - ); - clk_triggered - }, - ) - .collect() - } - fn process_registers(&mut self) { - for Register { - value, - clk_triggered, - reset, - source_location, - } in mem::take(&mut self.registers) - { - match reset { - Some(RegisterReset { - is_async, - init, - rst, - }) => { - let reg_end = self.insns.new_label(); - let reg_reset = self.insns.new_label(); - let branch_if_reset = Insn::BranchIfSmallNonZero { - target: reg_reset.0, - value: rst, - }; - let branch_if_not_triggered = Insn::BranchIfSmallZero { - target: reg_end.0, - value: clk_triggered, - }; - if is_async { - self.insns.push(branch_if_reset, source_location); - self.insns.push(branch_if_not_triggered, source_location); - } else { - self.insns.push(branch_if_not_triggered, source_location); - self.insns.push(branch_if_reset, source_location); - } - self.insns.extend( - value.range.insns_for_copy_from(value.write_value().range), - source_location, - ); - self.insns - .push(Insn::Branch { target: reg_end.0 }, source_location); - self.insns.define_label_at_next_insn(reg_reset); - self.insns - .extend(value.range.insns_for_copy_from(init.range), source_location); - self.insns.define_label_at_next_insn(reg_end); - } - None => { - let reg_end = self.insns.new_label(); - self.insns.push( - Insn::BranchIfSmallZero { - target: reg_end.0, - value: clk_triggered, - }, - source_location, - ); - self.insns.extend( - value.range.insns_for_copy_from(value.write_value().range), - source_location, - ); - self.insns.define_label_at_next_insn(reg_end); - } - } - } - } - fn process_memories(&mut self) { - for memory_index in 0..self.memories.len() { - let Memory { - mem, - memory: _, - trace: _, - ref mut ports, - } = self.memories[memory_index]; - for MemoryPort { - clk_triggered, - addr_delayed, - en_delayed, - data_layout: _, - read_data_delayed, - write_data_delayed, - write_mask_delayed, - write_mode_delayed, - write_insns, - } in mem::take(ports) - { - let port_end = self.insns.new_label(); - let small_shift_reg = - |this: &mut Self, values: &[StatePartIndex]| { - for pair in values.windows(2).rev() { - this.insns.push( - Insn::CopySmall { - dest: pair[1], - src: pair[0], - }, - mem.source_location(), - ); - } - }; - let shift_reg = |this: &mut Self, values: &[TypeIndexRange]| { - for pair in values.windows(2).rev() { - this.insns - .extend(pair[0].insns_for_copy_to(pair[1]), mem.source_location()); - } - }; - self.insns.push( - Insn::BranchIfSmallZero { - target: port_end.0, - value: clk_triggered, - }, - mem.source_location(), - ); - small_shift_reg(self, &addr_delayed); - small_shift_reg(self, &en_delayed); - shift_reg(self, &write_data_delayed); - shift_reg(self, &write_mask_delayed); - small_shift_reg(self, &write_mode_delayed); - shift_reg(self, &read_data_delayed); - self.insns.extend(write_insns, mem.source_location()); - self.insns.define_label_at_next_insn(port_end); - } - } - } - pub fn compile(mut self) -> Compiled { - let base_module = - *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); - self.process_assignments(); - self.process_registers(); - self.process_memories(); - let clocks_triggered = self.process_clocks(); - self.insns - .push(Insn::Return, self.base_module.source_location()); - Compiled { - insns: Insns::from(self.insns).intern_sized(), - base_module, - extern_modules: Intern::intern_owned(self.extern_modules), - io: Instance::new_unchecked( - ScopedNameId( - NameId("".intern(), Id::new()), - self.original_base_module.name_id(), - ), - self.original_base_module, - self.original_base_module.source_location(), - ), - traces: SimTraces(Intern::intern_owned(self.traces.0)), - trace_memories: Interned::from_iter(self.memories.iter().map( - |&Memory { - mem: _, - memory, - trace, - ports: _, - }| (memory, trace), - )), - clocks_triggered, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -struct CompiledModule { - module_io: Interned<[CompiledValue]>, - trace_decls: TraceModule, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Compiled { - insns: Interned>, - base_module: CompiledModule, - extern_modules: Interned<[CompiledExternModule]>, - io: Instance, - traces: SimTraces]>>, - trace_memories: Interned<[(StatePartIndex, TraceMem)]>, - clocks_triggered: Interned<[StatePartIndex]>, -} - -impl Compiled { - pub fn new(module: Interned>) -> Self { - Self::from_canonical(Compiler::new(module.canonical().intern()).compile()) - } - pub fn canonical(self) -> Compiled { - let Self { - insns, - base_module, - extern_modules, - io, - traces, - trace_memories, - clocks_triggered, - } = self; - Compiled { - insns, - base_module, - extern_modules, - io: Instance::from_canonical(io.canonical()), - traces, - trace_memories, - clocks_triggered, - } - } - pub fn from_canonical(canonical: Compiled) -> Self { - let Compiled { - insns, - base_module, - extern_modules, - io, - traces, - trace_memories, - clocks_triggered, - } = canonical; - Self { - insns, - base_module, - extern_modules, - io: Instance::from_canonical(io.canonical()), - traces, - trace_memories, - clocks_triggered, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct TraceScalarId(usize); - -impl fmt::Debug for TraceScalarId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraceScalarId({})", self.0) - } -} - -impl TraceScalarId { - pub fn as_usize(self) -> usize { - self.0 - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct TraceMemoryId(usize); - -impl fmt::Debug for TraceMemoryId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraceMemoryId({})", self.0) - } -} - -impl TraceMemoryId { - pub fn as_usize(self) -> usize { - self.0 - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct TraceMemoryLocation { - pub id: TraceMemoryId, - pub depth: usize, - pub stride: usize, - pub start: usize, - pub len: usize, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum TraceLocation { - Scalar(TraceScalarId), - Memory(TraceMemoryLocation), -} - -impl fmt::Debug for TraceLocation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Scalar(v) => v.fmt(f), - Self::Memory(v) => v.fmt(f), - } - } -} - -macro_rules! impl_trace_decl { - ( - $( - #[kind = $category_kind:ident] - $(#[$category_meta:meta])* - $category_variant:ident($category_enum:ident { - fn $category_property_fn:ident(self) -> $category_property_fn_ret_ty:ty; - $( - $(#[$meta:meta])* - $variant:ident($struct:ident { - fn $property_fn:ident($property_fn_self:ident) -> _ $property_fn_block:block - $($(#[$field_meta:meta])* - $field_name:ident: $field_ty:ty,)* - }), - )* - }), - )* - ) => { - $( - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - #[non_exhaustive] - $(#[$category_meta])* - pub enum $category_kind { - $($(#[$meta])* - $variant,)* - } - - impl From<$category_kind> for TraceKind { - fn from(v: $category_kind) -> Self { - TraceKind::$category_variant(v) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - #[non_exhaustive] - $(#[$category_meta])* - pub enum $category_enum { - $($(#[$meta])* - $variant($struct),)* - } - - impl fmt::Debug for $category_enum { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - $(Self::$variant(v) => v.fmt(f),)* - } - } - } - - impl $category_enum { - pub fn kind(self) -> $category_kind { - match self { - $(Self::$variant(_) => $category_kind::$variant,)* - } - } - pub fn name(self) -> Interned { - match self { - $(Self::$variant(v) => v.name,)* - } - } - pub fn $category_property_fn(self) -> $category_property_fn_ret_ty { - match self { - $(Self::$variant(v) => v.$property_fn(),)* - } - } - } - - impl From<$category_enum> for TraceDecl { - fn from(v: $category_enum) -> Self { - TraceDecl::$category_variant(v) - } - } - - $( - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - #[non_exhaustive] - $(#[$meta])* - pub struct $struct { - $($(#[$field_meta])* - pub $field_name: $field_ty,)* - } - - impl $struct { - pub fn $property_fn($property_fn_self) -> $category_property_fn_ret_ty $property_fn_block - } - - impl From<$struct> for $category_enum { - fn from(v: $struct) -> Self { - $category_enum::$variant(v) - } - } - - impl From<$struct> for TraceDecl { - fn from(v: $struct) -> Self { - TraceDecl::$category_variant($category_enum::$variant(v)) - } - } - )* - )* - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub enum TraceKind { - $($(#[$category_meta])* - $category_variant($category_kind),)* - } - - impl fmt::Debug for TraceKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - $(Self::$category_variant(v) => v.fmt(f),)* - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub enum TraceDecl { - $($(#[$category_meta])* - $category_variant($category_enum),)* - } - - impl fmt::Debug for TraceDecl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - $(Self::$category_variant(v) => v.fmt(f),)* - } - } - } - }; -} - -impl_trace_decl! { - #[kind = TraceScopeKind] - Scope(TraceScope { - fn children(self) -> Interned<[TraceDecl]>; - Module(TraceModule { - fn children(self) -> _ { - self.children - } - name: Interned, - children: Interned<[TraceDecl]>, - }), - Instance(TraceInstance { - fn children(self) -> _ { - [self.instance_io.into(), self.module.into()][..].intern() - } - name: Interned, - instance_io: TraceBundle, - module: TraceModule, - ty: Bundle, - }), - Mem(TraceMem { - fn children(self) -> _ { - Interned::from_iter([*self.element_type].into_iter().chain(self.ports.iter().map(|&v| v.into()))) - } - id: TraceMemoryId, - name: Interned, - stride: usize, - element_type: Interned, - ports: Interned<[TraceMemPort]>, - array_type: Array, - }), - MemPort(TraceMemPort { - fn children(self) -> _ { - [self.bundle.into()][..].intern() - } - name: Interned, - bundle: TraceBundle, - ty: Bundle, - }), - Wire(TraceWire { - fn children(self) -> _ { - [*self.child][..].intern() - } - name: Interned, - child: Interned, - ty: CanonicalType, - }), - Reg(TraceReg { - fn children(self) -> _ { - [*self.child][..].intern() - } - name: Interned, - child: Interned, - ty: CanonicalType, - }), - ModuleIO(TraceModuleIO { - fn children(self) -> _ { - [*self.child][..].intern() - } - name: Interned, - child: Interned, - ty: CanonicalType, - flow: Flow, - }), - Bundle(TraceBundle { - fn children(self) -> _ { - self.fields - } - name: Interned, - fields: Interned<[TraceDecl]>, - ty: Bundle, - flow: Flow, - }), - Array(TraceArray { - fn children(self) -> _ { - self.elements - } - name: Interned, - elements: Interned<[TraceDecl]>, - ty: Array, - flow: Flow, - }), - EnumWithFields(TraceEnumWithFields { - fn children(self) -> _ { - Interned::from_iter([self.discriminant.into()].into_iter().chain(self.non_empty_fields)) - } - name: Interned, - discriminant: TraceEnumDiscriminant, - non_empty_fields: Interned<[TraceDecl]>, - ty: Enum, - flow: Flow, - }), - }), - #[kind = TraceScalarKind] - Scalar(TraceScalar { - fn location(self) -> TraceLocation; - UInt(TraceUInt { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - ty: UInt, - flow: Flow, - }), - SInt(TraceSInt { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - ty: SInt, - flow: Flow, - }), - Bool(TraceBool { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - flow: Flow, - }), - FieldlessEnum(TraceFieldlessEnum { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - ty: Enum, - flow: Flow, - }), - EnumDiscriminant(TraceEnumDiscriminant { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - ty: Enum, - flow: Flow, - }), - Clock(TraceClock { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - flow: Flow, - }), - SyncReset(TraceSyncReset { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - flow: Flow, - }), - AsyncReset(TraceAsyncReset { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - flow: Flow, - }), - }), -} - -pub trait TraceWriterDecls: fmt::Debug + 'static + Sized { - type Error: std::error::Error + Send + Sync + 'static; - type TraceWriter: TraceWriter; - fn write_decls( - self, - module: TraceModule, - trace_scalar_id_count: usize, - trace_memory_id_count: usize, - ) -> Result; -} - -trait TraceWriterDeclsDynTrait: fmt::Debug { - fn write_decls_dyn( - self: Box, - module: TraceModule, - trace_scalar_id_count: usize, - trace_memory_id_count: usize, - ) -> std::io::Result; -} - -fn err_into_io(e: E) -> std::io::Error { - match ::downcast::(Box::new(e)) { - Ok(retval) => *retval, - Err(e) => std::io::Error::other(e), - } -} - -impl TraceWriterDeclsDynTrait for T { - fn write_decls_dyn( - self: Box, - module: TraceModule, - trace_scalar_id_count: usize, - trace_memory_id_count: usize, - ) -> std::io::Result { - Ok(DynTraceWriter(Box::new( - TraceWriterDecls::write_decls( - *self, - module, - trace_scalar_id_count, - trace_memory_id_count, - ) - .map_err(err_into_io)?, - ))) - } -} - -pub trait TraceWriter: fmt::Debug + 'static { - type Error: std::error::Error + Send + Sync + 'static; - fn finish_init(&mut self) -> Result<(), Self::Error> { - Ok(()) - } - fn change_time_to(&mut self, instant: SimInstant) -> Result<(), Self::Error> { - let _ = instant; - Ok(()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } - fn close(self) -> Result<(), Self::Error> - where - Self: Sized, - { - Ok(()) - } - fn set_memory_element( - &mut self, - memory: TraceMemoryId, - element_index: usize, - element_data: &BitSlice, - ) -> Result<(), Self::Error>; - fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error>; - fn set_signal_sint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error>; - fn set_signal_bool(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - if value { - self.set_signal_uint(id, bits![1]) - } else { - self.set_signal_uint(id, bits![0]) - } - } - fn set_signal_clock(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - self.set_signal_bool(id, value) - } - fn set_signal_sync_reset(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - self.set_signal_bool(id, value) - } - fn set_signal_async_reset( - &mut self, - id: TraceScalarId, - value: bool, - ) -> Result<(), Self::Error> { - self.set_signal_bool(id, value) - } - fn set_signal_enum_discriminant( - &mut self, - id: TraceScalarId, - variant_index: usize, - ty: Enum, - ) -> Result<(), Self::Error>; -} - -pub struct DynTraceWriterDecls(Box); - -impl DynTraceWriterDecls { - pub fn new(writer: W) -> Self { - Self(Box::new(writer)) - } -} - -impl fmt::Debug for DynTraceWriterDecls { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl TraceWriterDecls for DynTraceWriterDecls { - type Error = std::io::Error; - type TraceWriter = DynTraceWriter; - fn write_decls( - self, - module: TraceModule, - trace_scalar_id_count: usize, - trace_memory_id_count: usize, - ) -> Result { - self.0 - .write_decls_dyn(module, trace_scalar_id_count, trace_memory_id_count) - } -} - -trait TraceWriterDynTrait: fmt::Debug + 'static { - fn finish_init_dyn(&mut self) -> std::io::Result<()>; - fn change_time_to_dyn(&mut self, instant: SimInstant) -> std::io::Result<()>; - fn flush_dyn(&mut self) -> std::io::Result<()>; - fn close_dyn(self: Box) -> std::io::Result<()>; - fn set_memory_element_dyn( - &mut self, - memory: TraceMemoryId, - element_index: usize, - element_data: &BitSlice, - ) -> std::io::Result<()>; - fn set_signal_uint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()>; - fn set_signal_sint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()>; - fn set_signal_bool_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; - fn set_signal_clock_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; - fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; - fn set_signal_async_reset_dyn(&mut self, id: TraceScalarId, value: bool) - -> std::io::Result<()>; - fn set_signal_enum_discriminant_dyn( - &mut self, - id: TraceScalarId, - variant_index: usize, - ty: Enum, - ) -> std::io::Result<()>; -} - -impl TraceWriterDynTrait for T { - fn finish_init_dyn(&mut self) -> std::io::Result<()> { - Ok(TraceWriter::finish_init(self).map_err(err_into_io)?) - } - fn change_time_to_dyn(&mut self, instant: SimInstant) -> std::io::Result<()> { - Ok(TraceWriter::change_time_to(self, instant).map_err(err_into_io)?) - } - fn flush_dyn(&mut self) -> std::io::Result<()> { - Ok(TraceWriter::flush(self).map_err(err_into_io)?) - } - fn close_dyn(self: Box) -> std::io::Result<()> { - Ok(TraceWriter::close(*self).map_err(err_into_io)?) - } - fn set_memory_element_dyn( - &mut self, - memory: TraceMemoryId, - element_index: usize, - element_data: &BitSlice, - ) -> std::io::Result<()> { - Ok( - TraceWriter::set_memory_element(self, memory, element_index, element_data) - .map_err(err_into_io)?, - ) - } - fn set_signal_uint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_uint(self, id, value).map_err(err_into_io)?) - } - fn set_signal_sint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_sint(self, id, value).map_err(err_into_io)?) - } - fn set_signal_bool_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_bool(self, id, value).map_err(err_into_io)?) - } - fn set_signal_clock_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_clock(self, id, value).map_err(err_into_io)?) - } - fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_sync_reset(self, id, value).map_err(err_into_io)?) - } - fn set_signal_async_reset_dyn( - &mut self, - id: TraceScalarId, - value: bool, - ) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_async_reset(self, id, value).map_err(err_into_io)?) - } - fn set_signal_enum_discriminant_dyn( - &mut self, - id: TraceScalarId, - variant_index: usize, - ty: Enum, - ) -> std::io::Result<()> { - Ok( - TraceWriter::set_signal_enum_discriminant(self, id, variant_index, ty) - .map_err(err_into_io)?, - ) - } -} - -pub struct DynTraceWriter(Box); - -impl fmt::Debug for DynTraceWriter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl TraceWriter for DynTraceWriter { - type Error = std::io::Error; - fn finish_init(&mut self) -> Result<(), Self::Error> { - self.0.finish_init_dyn() - } - fn flush(&mut self) -> Result<(), Self::Error> { - self.0.flush_dyn() - } - fn close(self) -> Result<(), Self::Error> { - self.0.close_dyn() - } - fn set_memory_element( - &mut self, - memory: TraceMemoryId, - element_index: usize, - element_data: &BitSlice, - ) -> Result<(), Self::Error> { - self.0 - .set_memory_element_dyn(memory, element_index, element_data) - } - fn change_time_to(&mut self, instant: SimInstant) -> Result<(), Self::Error> { - self.0.change_time_to_dyn(instant) - } - fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> { - self.0.set_signal_uint_dyn(id, value) - } - fn set_signal_sint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> { - self.0.set_signal_sint_dyn(id, value) - } - fn set_signal_bool(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - self.0.set_signal_bool_dyn(id, value) - } - fn set_signal_clock(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - self.0.set_signal_clock_dyn(id, value) - } - fn set_signal_sync_reset(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { - self.0.set_signal_sync_reset_dyn(id, value) - } - fn set_signal_async_reset( - &mut self, - id: TraceScalarId, - value: bool, - ) -> Result<(), Self::Error> { - self.0.set_signal_async_reset_dyn(id, value) - } - fn set_signal_enum_discriminant( - &mut self, - id: TraceScalarId, - variant_index: usize, - ty: Enum, - ) -> Result<(), Self::Error> { - self.0 - .set_signal_enum_discriminant_dyn(id, variant_index, ty) - } -} - -#[derive(Debug)] -enum TraceWriterState { - Decls(T), - Init(T::TraceWriter), - Running(T::TraceWriter), - Errored(Option), -} - -trait SimTraceDebug { - fn fmt(&self, id: I, f: &mut fmt::Formatter<'_>) -> fmt::Result; -} - -struct SimTraceDebugAsDebug(T, I); - -impl fmt::Debug for SimTraceDebugAsDebug<&'_ T, I> -where - T: SimTraceDebug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(self.1, f) - } -} - -impl SimTraceDebug for Vec -where - [T]: SimTraceDebug, -{ - fn fmt(&self, id: I, f: &mut fmt::Formatter<'_>) -> fmt::Result { - <[T]>::fmt(&**self, id, f) - } -} - -impl SimTraceDebug for Interned -where - T: SimTraceDebug, -{ - fn fmt(&self, id: I, f: &mut fmt::Formatter<'_>) -> fmt::Result { - T::fmt(&**self, id, f) - } -} - -impl SimTraceDebug for Box -where - T: SimTraceDebug, -{ - fn fmt(&self, id: I, f: &mut fmt::Formatter<'_>) -> fmt::Result { - T::fmt(&**self, id, f) - } -} - -impl SimTraceDebug<()> for [T] -where - T: SimTraceDebug, -{ - fn fmt(&self, _id: (), f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list() - .entries( - self.iter() - .enumerate() - .map(|(id, v)| SimTraceDebugAsDebug(v, TraceScalarId(id))), - ) - .finish() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -struct SimTrace { - kind: K, - state: S, - last_state: S, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct SimTraces(T); - -impl fmt::Debug for SimTraces -where - T: SimTraceDebug<()>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt((), f) - } -} - -impl SimTraceDebug for SimTrace { - fn fmt(&self, id: TraceScalarId, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - kind, - state, - last_state, - } = self; - f.debug_struct("SimTrace") - .field("id", &id) - .field("kind", kind) - .field("state", state) - .field("last_state", last_state) - .finish() - } -} - -impl SimTraceDebug for SimTrace { - fn fmt(&self, id: TraceScalarId, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - kind, - state, - last_state, - } = self; - f.debug_struct("SimTrace") - .field("id", &id) - .field("kind", kind) - .field("state", &BitSliceWriteWithBase(state)) - .field("last_state", &BitSliceWriteWithBase(last_state)) - .finish() - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum SimTraceKind { - BigUInt { - index: StatePartIndex, - ty: UInt, - }, - BigSInt { - index: StatePartIndex, - ty: SInt, - }, - BigBool { - index: StatePartIndex, - }, - BigAsyncReset { - index: StatePartIndex, - }, - BigSyncReset { - index: StatePartIndex, - }, - BigClock { - index: StatePartIndex, - }, - SmallUInt { - index: StatePartIndex, - ty: UInt, - }, - SmallSInt { - index: StatePartIndex, - ty: SInt, - }, - SmallBool { - index: StatePartIndex, - }, - SmallAsyncReset { - index: StatePartIndex, - }, - SmallSyncReset { - index: StatePartIndex, - }, - SmallClock { - index: StatePartIndex, - }, - EnumDiscriminant { - index: StatePartIndex, - ty: Enum, - }, -} - -impl SimTraceKind { - fn make_state(self) -> BitVec { - match self { - SimTraceKind::BigUInt { index: _, ty } | SimTraceKind::SmallUInt { index: _, ty } => { - BitVec::repeat(false, ty.width) - } - SimTraceKind::BigSInt { index: _, ty } | SimTraceKind::SmallSInt { index: _, ty } => { - BitVec::repeat(false, ty.width) - } - SimTraceKind::BigBool { index: _ } - | SimTraceKind::BigAsyncReset { index: _ } - | SimTraceKind::BigSyncReset { index: _ } - | SimTraceKind::BigClock { index: _ } - | SimTraceKind::SmallBool { index: _ } - | SimTraceKind::SmallAsyncReset { index: _ } - | SimTraceKind::SmallSyncReset { index: _ } - | SimTraceKind::SmallClock { index: _ } => BitVec::repeat(false, 1), - SimTraceKind::EnumDiscriminant { index: _, ty } => { - BitVec::repeat(false, ty.discriminant_bit_width()) - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum MaybeNeedsSettle { - NeedsSettle(S), - NoSettleNeeded(N), -} - -impl MaybeNeedsSettle { - fn map(self, f: impl FnOnce(T) -> U) -> MaybeNeedsSettle { - match self { - MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(f(v)), - MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(f(v)), - } - } -} - -// workaround implementing FnOnce not being stable -trait MaybeNeedsSettleFn { - type Output; - - fn call(self, arg: A) -> Self::Output; -} - -impl O, A, O> MaybeNeedsSettleFn for T { - type Output = O; - - fn call(self, arg: A) -> Self::Output { - self(arg) - } -} - -impl MaybeNeedsSettle { - fn apply_no_settle(self, arg: T) -> MaybeNeedsSettle - where - N: MaybeNeedsSettleFn, - { - match self { - MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(v), - MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(v.call(arg)), - } - } -} - -struct SimulationModuleState { - base_targets: Vec, - uninitialized_ios: HashMap>, - io_targets: HashMap>, - did_initial_settle: bool, -} - -impl fmt::Debug for SimulationModuleState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - base_targets, - uninitialized_ios, - io_targets, - did_initial_settle, - } = self; - f.debug_struct("SimulationModuleState") - .field("base_targets", base_targets) - .field("uninitialized_ios", &SortedSetDebug(uninitialized_ios)) - .field("io_targets", &SortedSetDebug(io_targets)) - .field("did_initial_settle", did_initial_settle) - .finish() - } -} - -impl SimulationModuleState { - fn new(base_targets: impl IntoIterator)>) -> Self { - let mut retval = Self { - base_targets: Vec::new(), - uninitialized_ios: HashMap::default(), - io_targets: HashMap::default(), - did_initial_settle: false, - }; - for (base_target, value) in base_targets { - retval.base_targets.push(base_target); - retval.parse_io(base_target, value); - } - retval - } - /// returns `true` if `target` or any sub-targets are uninitialized inputs - fn parse_io(&mut self, target: Target, value: CompiledValue) -> bool { - self.io_targets.insert(target, value); - match value.layout.body { - CompiledTypeLayoutBody::Scalar => match target.flow() { - Flow::Source => false, - Flow::Sink => { - self.uninitialized_ios.insert(target, vec![]); - true - } - Flow::Duplex => unreachable!(), - }, - CompiledTypeLayoutBody::Array { .. } => { - let value = value.map_ty(Array::from_canonical); - let mut sub_targets = Vec::new(); - for index in 0..value.layout.ty.len() { - let sub_target = target.join( - TargetPathElement::from(TargetPathArrayElement { index }).intern_sized(), - ); - if self.parse_io(sub_target, value.element(index)) { - sub_targets.push(sub_target); - } - } - if sub_targets.is_empty() { - false - } else { - self.uninitialized_ios.insert(target, sub_targets); - true - } - } - CompiledTypeLayoutBody::Bundle { .. } => { - let value = value.map_ty(Bundle::from_canonical); - let mut sub_targets = Vec::new(); - for BundleField { name, .. } in value.layout.ty.fields() { - let sub_target = target.join( - TargetPathElement::from(TargetPathBundleField { name }).intern_sized(), - ); - if self.parse_io(sub_target, value.field_by_name(name)) { - sub_targets.push(sub_target); - } - } - if sub_targets.is_empty() { - false - } else { - self.uninitialized_ios.insert(target, sub_targets); - true - } - } - } - } - fn mark_target_as_initialized(&mut self, mut target: Target) { - fn remove_target_and_children( - uninitialized_ios: &mut HashMap>, - target: Target, - ) { - let Some(children) = uninitialized_ios.remove(&target) else { - return; - }; - for child in children { - remove_target_and_children(uninitialized_ios, child); - } - } - remove_target_and_children(&mut self.uninitialized_ios, target); - while let Some(target_child) = target.child() { - let parent = target_child.parent(); - for child in self - .uninitialized_ios - .get(&*parent) - .map(|v| &**v) - .unwrap_or(&[]) - { - if self.uninitialized_ios.contains_key(child) { - return; - } - } - target = *parent; - self.uninitialized_ios.remove(&target); - } - } - #[track_caller] - fn get_io( - &self, - mut target: Target, - which_module: WhichModule, - ) -> CompiledValue { - assert!( - target.canonical_ty().is_passive(), - "simulator read/write expression must have a passive type \ - (recursively contains no fields with `#[hdl(flip)]`)" - ); - if let Some(&retval) = self.io_targets.get(&target) { - return retval; - } - loop { - target = match target { - Target::Base(_) => break, - Target::Child(child) => { - match *child.path_element() { - TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} - TargetPathElement::DynArrayElement(_) => panic!( - "simulator read/write expression must not have dynamic array indexes" - ), - } - *child.parent() - } - }; - } - match which_module { - WhichModule::Main => panic!( - "simulator read/write expression must be \ - an array element/field of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "simulator read/write expression must be \ - one of this module's inputs/outputs or an \ - array element/field of one of this module's inputs/outputs" - ), - } - } - #[track_caller] - fn read_helper( - &self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle> { - let Some(target) = io.target() else { - match which_module { - WhichModule::Main => panic!( - "can't read from an expression that's not a field/element of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "can't read from an expression that's not based on one of this module's inputs/outputs" - ), - } - }; - let compiled_value = self.get_io(*target, which_module); - match target.flow() { - Flow::Source => { - if !self.uninitialized_ios.is_empty() { - match which_module { - WhichModule::Main => { - panic!("can't read from an output before initializing all inputs"); - } - WhichModule::Extern { .. } => { - panic!("can't read from an input before initializing all outputs"); - } - } - } - MaybeNeedsSettle::NeedsSettle(compiled_value) - } - Flow::Sink => { - if self.uninitialized_ios.contains_key(&*target) { - match which_module { - WhichModule::Main => panic!("can't read from an uninitialized input"), - WhichModule::Extern { .. } => { - panic!("can't read from an uninitialized output"); - } - } - } - MaybeNeedsSettle::NoSettleNeeded(compiled_value) - } - Flow::Duplex => unreachable!(), - } - } - #[track_caller] - fn write_helper( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> CompiledValue { - let Some(target) = io.target() else { - match which_module { - WhichModule::Main => panic!( - "can't write to an expression that's not a field/element of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "can't write to an expression that's not based on one of this module's outputs" - ), - } - }; - let compiled_value = self.get_io(*target, which_module); - match target.flow() { - Flow::Source => match which_module { - WhichModule::Main => panic!("can't write to an output"), - WhichModule::Extern { .. } => panic!("can't write to an input"), - }, - Flow::Sink => {} - Flow::Duplex => unreachable!(), - } - if !self.did_initial_settle { - self.mark_target_as_initialized(*target); - } - compiled_value - } -} - -#[derive(Copy, Clone, Debug)] -enum WaitTarget { - Settle, - Instant(SimInstant), - Change { key: ChangeKey, value: ChangeValue }, -} - -#[derive(Clone)] -struct EarliestWaitTargets { - settle: bool, - instant: Option, - changes: HashMap, SimValue>, -} - -impl fmt::Debug for EarliestWaitTargets { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -impl Default for EarliestWaitTargets { - fn default() -> Self { - Self { - settle: false, - instant: None, - changes: HashMap::default(), - } - } -} - -impl EarliestWaitTargets { - fn settle() -> Self { - Self { - settle: true, - instant: None, - changes: HashMap::default(), - } - } - fn instant(instant: SimInstant) -> Self { - Self { - settle: false, - instant: Some(instant), - changes: HashMap::default(), - } - } - fn len(&self) -> usize { - self.settle as usize + self.instant.is_some() as usize + self.changes.len() - } - fn is_empty(&self) -> bool { - self.len() == 0 - } - fn clear(&mut self) { - let Self { - settle, - instant, - changes, - } = self; - *settle = false; - *instant = None; - changes.clear(); - } - fn insert( - &mut self, - value: impl std::borrow::Borrow, ChangeValue>>, - ) where - ChangeValue: std::borrow::Borrow>, - { - let value = value.borrow(); - match value { - WaitTarget::Settle => self.settle = true, - WaitTarget::Instant(instant) => { - if self.instant.is_none_or(|v| v > *instant) { - self.instant = Some(*instant); - } - } - WaitTarget::Change { key, value } => { - self.changes - .entry(*key) - .or_insert_with(|| value.borrow().clone()); - } - } - } - fn convert_earlier_instants_to_settle(&mut self, instant: SimInstant) { - if self.instant.is_some_and(|v| v <= instant) { - self.settle = true; - self.instant = None; - } - } - fn iter<'a>( - &'a self, - ) -> impl Clone - + Iterator, &'a SimValue>> - + 'a { - self.settle - .then_some(WaitTarget::Settle) - .into_iter() - .chain(self.instant.map(|instant| WaitTarget::Instant(instant))) - .chain( - self.changes - .iter() - .map(|(&key, value)| WaitTarget::Change { key, value }), - ) - } -} - -impl>> - Extend, ChangeValue>> for EarliestWaitTargets -{ - fn extend, ChangeValue>>>( - &mut self, - iter: T, - ) { - iter.into_iter().for_each(|v| self.insert(v)) - } -} - -impl<'a, ChangeValue: std::borrow::Borrow>> - Extend<&'a WaitTarget, ChangeValue>> for EarliestWaitTargets -{ - fn extend, ChangeValue>>>( - &mut self, - iter: T, - ) { - iter.into_iter().for_each(|v| self.insert(v)) - } -} - -impl FromIterator for EarliestWaitTargets -where - Self: Extend, -{ - fn from_iter>(iter: T) -> Self { - let mut retval = Self::default(); - retval.extend(iter); - retval - } -} - -struct SimulationExternModuleState { - module_state: SimulationModuleState, - sim: ExternModuleSimulation, - running_generator: Option + 'static>>>, - wait_targets: EarliestWaitTargets, -} - -impl fmt::Debug for SimulationExternModuleState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - module_state, - sim, - running_generator, - wait_targets, - } = self; - f.debug_struct("SimulationExternModuleState") - .field("module_state", module_state) - .field("sim", sim) - .field( - "running_generator", - &running_generator.as_ref().map(|_| DebugAsDisplay("...")), - ) - .field("wait_targets", wait_targets) - .finish() - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum WhichModule { - Main, - Extern { module_index: usize }, -} - -struct ReadBitFn { - compiled_value: CompiledValue, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBitFn { - type Output = bool; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - match self.compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => { - state.small_slots[self.compiled_value.range.small_slots.start] != 0 - } - TypeLen::A_BIG_SLOT => !state.big_slots[self.compiled_value.range.big_slots.start] - .clone() - .is_zero(), - _ => unreachable!(), - } - } -} - -struct ReadBoolOrIntFn { - compiled_value: CompiledValue, - io: Expr, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBoolOrIntFn { - type Output = I::Value; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { compiled_value, io } = self; - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => Expr::ty(io) - .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), - TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( - state.big_slots[compiled_value.range.big_slots.start].clone(), - ), - _ => unreachable!(), - } - } -} - -struct ReadFn { - compiled_value: CompiledValue, - io: Expr, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn { - type Output = SimValue; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { compiled_value, io } = self; - SimulationImpl::read_no_settle_helper( - state, - io, - compiled_value, - UIntValue::new(Arc::new(BitVec::repeat(false, Expr::ty(io).bit_width()))), - ) - } -} - -struct GeneratorWaker; - -impl std::task::Wake for GeneratorWaker { - fn wake(self: Arc) { - panic!("can't await other kinds of futures in function passed to ExternalModuleSimulation"); - } -} - -#[derive(Default)] -struct ReadyToRunSet { - state_ready_to_run: bool, - extern_modules_ready_to_run: Vec, -} - -impl ReadyToRunSet { - fn clear(&mut self) { - let Self { - state_ready_to_run, - extern_modules_ready_to_run, - } = self; - *state_ready_to_run = false; - extern_modules_ready_to_run.clear(); - } -} - -struct SimulationImpl { - state: interpreter::State, - io: Expr, - main_module: SimulationModuleState, - extern_modules: Box<[SimulationExternModuleState]>, - state_ready_to_run: bool, - trace_decls: TraceModule, - traces: SimTraces]>>, - trace_memories: HashMap, TraceMem>, - trace_writers: Vec>, - instant: SimInstant, - clocks_triggered: Interned<[StatePartIndex]>, - breakpoints: Option, - generator_waker: std::task::Waker, -} - -impl fmt::Debug for SimulationImpl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt(None, f) - } -} - -impl SimulationImpl { - fn debug_fmt(&self, io: Option<&dyn fmt::Debug>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - state, - io: self_io, - main_module, - extern_modules, - state_ready_to_run, - trace_decls, - traces, - trace_memories, - trace_writers, - instant, - clocks_triggered, - breakpoints: _, - generator_waker: _, - } = self; - f.debug_struct("Simulation") - .field("state", state) - .field("io", io.unwrap_or(self_io)) - .field("main_module", main_module) - .field("extern_modules", extern_modules) - .field("state_ready_to_run", state_ready_to_run) - .field("trace_decls", trace_decls) - .field("traces", traces) - .field("trace_memories", trace_memories) - .field("trace_writers", trace_writers) - .field("instant", instant) - .field("clocks_triggered", clocks_triggered) - .finish_non_exhaustive() - } - fn new(compiled: Compiled) -> Self { - let io_target = Target::from(compiled.io); - let extern_modules = Box::from_iter(compiled.extern_modules.iter().map( - |&CompiledExternModule { - module_io_targets, - module_io, - simulation, - }| { - SimulationExternModuleState { - module_state: SimulationModuleState::new( - module_io_targets - .iter() - .copied() - .zip(module_io.iter().copied()), - ), - sim: simulation, - running_generator: None, - wait_targets: EarliestWaitTargets::settle(), - } - }, - )); - Self { - state: State::new(compiled.insns), - io: compiled.io.to_expr(), - main_module: SimulationModuleState::new( - compiled - .io - .ty() - .fields() - .into_iter() - .zip(compiled.base_module.module_io) - .map(|(BundleField { name, .. }, value)| { - ( - io_target.join( - TargetPathElement::from(TargetPathBundleField { name }) - .intern_sized(), - ), - value, - ) - }), - ), - extern_modules, - state_ready_to_run: true, - trace_decls: compiled.base_module.trace_decls, - traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map( - |&SimTrace { - kind, - state: _, - last_state: _, - }| SimTrace { - kind, - state: kind.make_state(), - last_state: kind.make_state(), - }, - ))), - trace_memories: HashMap::from_iter(compiled.trace_memories.iter().copied()), - trace_writers: vec![], - instant: SimInstant::START, - clocks_triggered: compiled.clocks_triggered, - breakpoints: None, - generator_waker: Arc::new(GeneratorWaker).into(), - } - } - fn write_traces( - &mut self, - mut trace_writer: DynTraceWriter, - ) -> std::io::Result { - let mut set_memory_element = |memory: StatePartIndex, - trace_mem: &TraceMem, - element_index: usize| { - let start = trace_mem.stride * element_index; - let end = start + trace_mem.stride; - trace_writer.set_memory_element( - self.trace_memories[&memory].id, - element_index, - &self.state.memories[memory].data[start..end], - ) - }; - if ONLY_IF_CHANGED { - for &(memory, element_index) in &self.state.memory_write_log { - set_memory_element(memory, &self.trace_memories[&memory], element_index)?; - } - } else { - for (&memory, trace_mem) in &self.trace_memories { - for element_index in 0..trace_mem.array_type.len() { - set_memory_element(memory, trace_mem, element_index)?; - } - } - } - for ( - id, - &SimTrace { - kind, - ref state, - ref last_state, - }, - ) in self.traces.0.iter().enumerate() - { - if ONLY_IF_CHANGED && state == last_state { - continue; - } - let id = TraceScalarId(id); - match kind { - SimTraceKind::BigUInt { .. } | SimTraceKind::SmallUInt { .. } => { - trace_writer.set_signal_uint(id, state)?; - } - SimTraceKind::BigSInt { .. } | SimTraceKind::SmallSInt { .. } => { - trace_writer.set_signal_sint(id, state)?; - } - SimTraceKind::BigBool { .. } | SimTraceKind::SmallBool { .. } => { - trace_writer.set_signal_bool(id, state[0])?; - } - SimTraceKind::BigAsyncReset { .. } | SimTraceKind::SmallAsyncReset { .. } => { - trace_writer.set_signal_async_reset(id, state[0])?; - } - SimTraceKind::BigSyncReset { .. } | SimTraceKind::SmallSyncReset { .. } => { - trace_writer.set_signal_sync_reset(id, state[0])?; - } - SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => { - trace_writer.set_signal_clock(id, state[0])?; - } - SimTraceKind::EnumDiscriminant { ty, .. } => { - let mut variant_index = [0; mem::size_of::()]; - variant_index.view_bits_mut::()[0..state.len()] - .clone_from_bitslice(state); - trace_writer.set_signal_enum_discriminant( - id, - usize::from_le_bytes(variant_index), - ty, - )?; - } - } - } - Ok(trace_writer) - } - fn init_trace_writer( - &mut self, - trace_writer: DynTraceWriter, - ) -> std::io::Result { - let mut trace_writer = self.write_traces::(trace_writer)?; - trace_writer.finish_init()?; - Ok(trace_writer) - } - fn update_trace_writer( - &mut self, - trace_writer: DynTraceWriter, - ) -> std::io::Result { - self.write_traces::(trace_writer) - } - #[inline(never)] - fn read_traces(&mut self) { - for &mut SimTrace { - kind, - ref mut state, - ref mut last_state, - } in &mut self.traces.0 - { - if !IS_INITIAL_STEP { - mem::swap(state, last_state); - } - match kind { - SimTraceKind::BigUInt { index, ty: _ } | SimTraceKind::BigSInt { index, ty: _ } => { - let bigint = &self.state.big_slots[index]; - let mut bytes = bigint.to_signed_bytes_le(); - bytes.resize( - state.len().div_ceil(8), - if bigint.is_negative() { 0xFF } else { 0 }, - ); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..state.len()]; - state.clone_from_bitslice(bitslice); - } - SimTraceKind::BigBool { index } - | SimTraceKind::BigAsyncReset { index } - | SimTraceKind::BigSyncReset { index } - | SimTraceKind::BigClock { index } => { - state.set(0, !self.state.big_slots[index].is_zero()); - } - SimTraceKind::SmallUInt { index, ty: _ } - | SimTraceKind::SmallSInt { index, ty: _ } - | SimTraceKind::EnumDiscriminant { index, ty: _ } => { - let bytes = self.state.small_slots[index].to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..state.len()]; - state.clone_from_bitslice(bitslice); - } - SimTraceKind::SmallBool { index } - | SimTraceKind::SmallAsyncReset { index } - | SimTraceKind::SmallSyncReset { index } - | SimTraceKind::SmallClock { index } => { - state.set(0, self.state.small_slots[index] != 0); - } - } - if IS_INITIAL_STEP { - last_state.copy_from_bitslice(state); - } - } - } - #[track_caller] - fn advance_time(this_ref: &Rc>, duration: SimDuration) { - let run_target = this_ref.borrow().instant + duration; - Self::run_until(this_ref, run_target); - } - /// clears `targets` - #[must_use] - fn yield_wait<'a>( - this: Rc>, - module_index: usize, - targets: &'a mut EarliestWaitTargets, - ) -> impl Future + 'a { - struct MyGenerator<'a> { - sim: Rc>, - yielded_at_all: bool, - module_index: usize, - targets: &'a mut EarliestWaitTargets, - } - impl Future for MyGenerator<'_> { - type Output = (); - - fn poll( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll { - let this = &mut *self; - let mut sim = this.sim.borrow_mut(); - let sim = &mut *sim; - assert!(cx.waker().will_wake(&sim.generator_waker), "can't use ExternModuleSimulationState's methods outside of ExternModuleSimulation"); - this.targets.convert_earlier_instants_to_settle(sim.instant); - if this.targets.is_empty() { - this.targets.settle = true; - } - if this.targets.settle { - if this.yielded_at_all { - this.targets.clear(); - return Poll::Ready(()); - } - } - sim.extern_modules[this.module_index] - .wait_targets - .extend(this.targets.iter()); - this.targets.clear(); - this.yielded_at_all = true; - Poll::Pending - } - } - MyGenerator { - sim: this, - yielded_at_all: false, - module_index, - targets, - } - } - async fn yield_advance_time_or_settle( - this: Rc>, - module_index: usize, - duration: Option, - ) { - let mut targets = duration.map_or(EarliestWaitTargets::settle(), |duration| { - EarliestWaitTargets::instant(this.borrow().instant + duration) - }); - Self::yield_wait(this, module_index, &mut targets).await; - } - fn is_extern_module_ready_to_run(&mut self, module_index: usize) -> Option { - let module = &self.extern_modules[module_index]; - let mut retval = None; - for wait_target in module.wait_targets.iter() { - retval = match (wait_target, retval) { - (WaitTarget::Settle, _) => Some(self.instant), - (WaitTarget::Instant(instant), _) if instant <= self.instant => Some(self.instant), - (WaitTarget::Instant(instant), None) => Some(instant), - (WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)), - (WaitTarget::Change { key, value }, retval) => { - if Self::value_changed(&mut self.state, key, SimValue::bits(value).bits()) { - Some(self.instant) - } else { - retval - } - } - }; - if retval == Some(self.instant) { - break; - } - } - retval - } - fn get_ready_to_run_set(&mut self, ready_to_run_set: &mut ReadyToRunSet) -> Option { - ready_to_run_set.clear(); - let mut retval = None; - if self.state_ready_to_run { - ready_to_run_set.state_ready_to_run = true; - retval = Some(self.instant); - } - for module_index in 0..self.extern_modules.len() { - let Some(instant) = self.is_extern_module_ready_to_run(module_index) else { - continue; - }; - if let Some(retval) = &mut retval { - match instant.cmp(retval) { - std::cmp::Ordering::Less => ready_to_run_set.clear(), - std::cmp::Ordering::Equal => {} - std::cmp::Ordering::Greater => continue, - } - } else { - retval = Some(instant); - } - ready_to_run_set - .extern_modules_ready_to_run - .push(module_index); - } - retval - } - fn set_instant_no_sim(&mut self, instant: SimInstant) { - self.instant = instant; - self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { - match &mut trace_writer_state { - TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(), - TraceWriterState::Running(trace_writer) => { - trace_writer.change_time_to(this.instant)?; - } - TraceWriterState::Errored(_) => {} - } - Ok(trace_writer_state) - }); - } - #[must_use] - #[track_caller] - fn run_state_settle_cycle(&mut self) -> bool { - self.state_ready_to_run = false; - self.state.setup_call(0); - if self.breakpoints.is_some() { - loop { - match self - .state - .run(self.breakpoints.as_mut().expect("just checked")) - { - RunResult::Break(break_action) => { - println!( - "hit breakpoint at:\n{:?}", - self.state.debug_insn_at(self.state.pc), - ); - match break_action { - BreakAction::DumpStateAndContinue => { - println!("{self:#?}"); - } - BreakAction::Continue => {} - } - } - RunResult::Return(()) => break, - } - } - } else { - let RunResult::Return(()) = self.state.run(()); - } - if self - .clocks_triggered - .iter() - .any(|i| self.state.small_slots[*i] != 0) - { - self.state_ready_to_run = true; - true - } else { - false - } - } - #[track_caller] - fn run_extern_modules_cycle( - this_ref: &Rc>, - generator_waker: &std::task::Waker, - extern_modules_ready_to_run: &[usize], - ) { - let mut this = this_ref.borrow_mut(); - for module_index in extern_modules_ready_to_run.iter().copied() { - let extern_module = &mut this.extern_modules[module_index]; - extern_module.wait_targets.clear(); - let mut generator = if !extern_module.module_state.did_initial_settle { - let sim = extern_module.sim; - drop(this); - Box::into_pin(sim.run(ExternModuleSimulationState { - sim_impl: this_ref.clone(), - module_index, - wait_for_changes_wait_targets: EarliestWaitTargets::default(), - })) - } else if let Some(generator) = extern_module.running_generator.take() { - drop(this); - generator - } else { - continue; - }; - let generator = match generator - .as_mut() - .poll(&mut std::task::Context::from_waker(generator_waker)) - { - Poll::Ready(()) => None, - Poll::Pending => Some(generator), - }; - this = this_ref.borrow_mut(); - this.extern_modules[module_index] - .module_state - .did_initial_settle = true; - if !this.extern_modules[module_index] - .module_state - .uninitialized_ios - .is_empty() - { - panic!( - "extern module didn't initialize all outputs before \ - waiting, settling, or reading any inputs: {}", - this.extern_modules[module_index].sim.source_location - ); - } - this.extern_modules[module_index].running_generator = generator; - } - } - /// clears `targets` - #[track_caller] - fn run_until(this_ref: &Rc>, run_target: SimInstant) { - let mut this = this_ref.borrow_mut(); - let mut ready_to_run_set = ReadyToRunSet::default(); - let generator_waker = this.generator_waker.clone(); - assert!( - this.main_module.uninitialized_ios.is_empty(), - "didn't initialize all inputs", - ); - let run_target = run_target.max(this.instant); - let mut settle_cycle = 0; - let mut run_extern_modules = true; - loop { - assert!(settle_cycle < 100000, "settle(): took too many steps"); - settle_cycle += 1; - let next_wait_target = match this.get_ready_to_run_set(&mut ready_to_run_set) { - Some(next_wait_target) if next_wait_target <= run_target => next_wait_target, - _ => break, - }; - if next_wait_target > this.instant { - settle_cycle = 0; - this.set_instant_no_sim(next_wait_target); - } - if run_extern_modules { - drop(this); - Self::run_extern_modules_cycle( - this_ref, - &generator_waker, - &ready_to_run_set.extern_modules_ready_to_run, - ); - this = this_ref.borrow_mut(); - } - if ready_to_run_set.state_ready_to_run { - if this.run_state_settle_cycle() { - // wait for clocks to settle before running extern modules again - run_extern_modules = false; - } else { - run_extern_modules = true; - } - } - if this.main_module.did_initial_settle { - this.read_traces::(); - } else { - this.read_traces::(); - } - this.state.memory_write_log.sort_unstable(); - this.state.memory_write_log.dedup(); - this.main_module.did_initial_settle = true; - this.for_each_trace_writer_storing_error(|this, trace_writer_state| { - Ok(match trace_writer_state { - TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( - this.init_trace_writer(trace_writer_decls.write_decls( - this.trace_decls, - this.traces.0.len(), - this.trace_memories.len(), - )?)?, - ), - TraceWriterState::Init(trace_writer) => { - TraceWriterState::Running(this.init_trace_writer(trace_writer)?) - } - TraceWriterState::Running(trace_writer) => { - TraceWriterState::Running(this.update_trace_writer(trace_writer)?) - } - TraceWriterState::Errored(e) => TraceWriterState::Errored(e), - }) - }); - this.state.memory_write_log.clear(); - } - if run_target > this.instant { - this.set_instant_no_sim(run_target); - } - } - #[track_caller] - fn settle(this_ref: &Rc>) { - let run_target = this_ref.borrow().instant; - Self::run_until(this_ref, run_target); - } - fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState { - match which_module { - WhichModule::Main => &self.main_module, - WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state, - } - } - fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState { - match which_module { - WhichModule::Main => &mut self.main_module, - WhichModule::Extern { module_index } => { - &mut self.extern_modules[module_index].module_state - } - } - } - #[track_caller] - fn read_bit( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle { - self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) - .map(|compiled_value| ReadBitFn { compiled_value }) - .apply_no_settle(&mut self.state) - } - #[track_caller] - fn write_bit(&mut self, io: Expr, value: bool, which_module: WhichModule) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); - self.state_ready_to_run = true; - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => { - self.state.small_slots[compiled_value.range.small_slots.start] = value as _; - } - TypeLen::A_BIG_SLOT => { - self.state.big_slots[compiled_value.range.big_slots.start] = value.into() - } - _ => unreachable!(), - } - } - #[track_caller] - fn read_bool_or_int( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle, I::Value> { - self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) - .map(|compiled_value| ReadBoolOrIntFn { compiled_value, io }) - .apply_no_settle(&mut self.state) - } - #[track_caller] - fn write_bool_or_int( - &mut self, - io: Expr, - value: I::Value, - which_module: WhichModule, - ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(Expr::canonical(io), which_module); - self.state_ready_to_run = true; - let value: BigInt = value.into(); - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => { - let mut small_value = value.iter_u64_digits().next().unwrap_or(0); - if value.is_negative() { - small_value = small_value.wrapping_neg(); - } - self.state.small_slots[compiled_value.range.small_slots.start] = small_value; - } - TypeLen::A_BIG_SLOT => { - self.state.big_slots[compiled_value.range.big_slots.start] = value - } - _ => unreachable!(), - } - } - #[track_caller] - fn read_write_sim_value_helper( - state: &mut interpreter::State, - compiled_value: CompiledValue, - start_bit_index: usize, - bits: &mut Bits, - read_write_big_scalar: impl Fn(bool, std::ops::Range, &mut Bits, &mut BigInt) + Copy, - read_write_small_scalar: impl Fn(bool, std::ops::Range, &mut Bits, &mut SmallUInt) + Copy, - ) { - match compiled_value.layout.body { - CompiledTypeLayoutBody::Scalar => { - let signed = match compiled_value.layout.ty { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => false, - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - }; - let bit_indexes = - start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); - match compiled_value.range.len() { - TypeLen::A_SMALL_SLOT => read_write_small_scalar( - signed, - bit_indexes, - bits, - &mut state.small_slots[compiled_value.range.small_slots.start], - ), - TypeLen::A_BIG_SLOT => read_write_big_scalar( - signed, - bit_indexes, - bits, - &mut state.big_slots[compiled_value.range.big_slots.start], - ), - _ => unreachable!(), - } - } - CompiledTypeLayoutBody::Array { element } => { - let ty = ::from_canonical(compiled_value.layout.ty); - let element_bit_width = ty.element().bit_width(); - for element_index in 0..ty.len() { - Self::read_write_sim_value_helper( - state, - CompiledValue { - layout: *element, - range: compiled_value - .range - .index_array(element.layout.len(), element_index), - write: None, - }, - start_bit_index + element_index * element_bit_width, - bits, - read_write_big_scalar, - read_write_small_scalar, - ); - } - } - CompiledTypeLayoutBody::Bundle { fields } => { - let ty = Bundle::from_canonical(compiled_value.layout.ty); - for ( - (_field, offset), - CompiledBundleField { - offset: layout_offset, - ty: field_layout, - }, - ) in ty.fields().iter().zip(ty.field_offsets()).zip(fields) - { - Self::read_write_sim_value_helper( - state, - CompiledValue { - layout: field_layout, - range: compiled_value.range.slice(TypeIndexRange::new( - layout_offset, - field_layout.layout.len(), - )), - write: None, - }, - start_bit_index + offset, - bits, - read_write_big_scalar, - read_write_small_scalar, - ); - } - } - } - } - #[track_caller] - fn read_no_settle_helper( - state: &mut interpreter::State, - io: Expr, - compiled_value: CompiledValue, - mut bits: UIntValue, - ) -> SimValue { - SimulationImpl::read_write_sim_value_helper( - state, - compiled_value, - 0, - bits.bits_mut(), - |_signed, bit_range, bits, value| { - ::copy_bits_from_bigint_wrapping(value, &mut bits[bit_range]); - }, - |_signed, bit_range, bits, value| { - let bytes = value.to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..bit_range.len()]; - bits[bit_range].clone_from_bitslice(bitslice); - }, - ); - SimValue::from_bits(Expr::ty(io), bits) - } - /// doesn't modify `bits` - fn value_changed( - state: &mut interpreter::State, - compiled_value: CompiledValue, - mut bits: &BitSlice, - ) -> bool { - assert_eq!(bits.len(), compiled_value.layout.ty.bit_width()); - let any_change = std::cell::Cell::new(false); - SimulationImpl::read_write_sim_value_helper( - state, - compiled_value, - 0, - &mut bits, - |_signed, bit_range, bits, value| { - if !::bits_equal_bigint_wrapping(value, &bits[bit_range]) { - any_change.set(true); - } - }, - |_signed, bit_range, bits, value| { - let bytes = value.to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..bit_range.len()]; - if bits[bit_range] != *bitslice { - any_change.set(true); - } - }, - ); - any_change.get() - } - #[track_caller] - fn read( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> ( - CompiledValue, - MaybeNeedsSettle>, - ) { - let compiled_value = self.get_module(which_module).read_helper(io, which_module); - let value = compiled_value - .map(|compiled_value| ReadFn { compiled_value, io }) - .apply_no_settle(&mut self.state); - let (MaybeNeedsSettle::NeedsSettle(compiled_value) - | MaybeNeedsSettle::NoSettleNeeded(compiled_value)) = compiled_value; - (compiled_value, value) - } - #[track_caller] - fn write( - &mut self, - io: Expr, - value: &SimValue, - which_module: WhichModule, - ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); - self.state_ready_to_run = true; - assert_eq!(Expr::ty(io), SimValue::ty(value)); - Self::read_write_sim_value_helper( - &mut self.state, - compiled_value, - 0, - &mut value.bits().bits(), - |signed, bit_range, bits, value| { - if signed { - *value = SInt::bits_to_bigint(&bits[bit_range]); - } else { - *value = UInt::bits_to_bigint(&bits[bit_range]); - } - }, - |signed, bit_range, bits, value| { - let mut small_value = [0; mem::size_of::()]; - if signed && bits[bit_range.clone()].last().as_deref().copied() == Some(true) { - small_value.fill(u8::MAX); - } - small_value.view_bits_mut::()[0..bit_range.len()] - .clone_from_bitslice(&bits[bit_range]); - *value = SmallUInt::from_le_bytes(small_value); - }, - ); - } - #[track_caller] - fn settle_if_needed(this_ref: &Rc>, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - match v { - MaybeNeedsSettle::NeedsSettle(v) => { - Self::settle(this_ref); - v.call(&mut this_ref.borrow_mut().state) - } - MaybeNeedsSettle::NoSettleNeeded(v) => v, - } - } - async fn yield_settle_if_needed( - this_ref: &Rc>, - module_index: usize, - v: MaybeNeedsSettle, - ) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - match v { - MaybeNeedsSettle::NeedsSettle(v) => { - Self::yield_advance_time_or_settle(this_ref.clone(), module_index, None).await; - v.call(&mut this_ref.borrow_mut().state) - } - MaybeNeedsSettle::NoSettleNeeded(v) => v, - } - } - fn close_all_trace_writers(&mut self) -> std::io::Result<()> { - let trace_writers = mem::take(&mut self.trace_writers); - let mut retval = Ok(()); - let close_trace_writer = - |trace_writer: TraceWriterState| match trace_writer { - TraceWriterState::Decls(v) => v - .write_decls( - self.trace_decls, - self.traces.0.len(), - self.trace_memories.len(), - )? - .close(), - TraceWriterState::Init(v) => v.close(), - TraceWriterState::Running(v) => v.close(), - TraceWriterState::Errored(Some(e)) => Err(e), - TraceWriterState::Errored(None) => Ok(()), - }; - for trace_writer in trace_writers { - retval = retval.and(close_trace_writer(trace_writer)); - } - retval - } - fn for_each_trace_writer_storing_error( - &mut self, - mut f: impl FnMut( - &mut Self, - TraceWriterState, - ) -> std::io::Result>, - ) { - let mut trace_writers = mem::take(&mut self.trace_writers); - for trace_writer in &mut trace_writers { - *trace_writer = match f( - self, - mem::replace(trace_writer, TraceWriterState::Errored(None)), - ) { - Ok(v) => v, - Err(e) => TraceWriterState::Errored(Some(e)), - }; - } - self.trace_writers = trace_writers; - } - fn for_each_trace_writer_getting_error( - &mut self, - mut f: impl FnMut( - &mut Self, - TraceWriterState, - ) -> std::io::Result>, - ) -> std::io::Result<()> { - let mut retval = Ok(()); - let mut trace_writers = mem::take(&mut self.trace_writers); - for trace_writer in &mut trace_writers { - *trace_writer = match f( - self, - mem::replace(trace_writer, TraceWriterState::Errored(None)), - ) { - Ok(v) => v, - Err(e) => { - if retval.is_ok() { - retval = Err(e); - TraceWriterState::Errored(None) - } else { - TraceWriterState::Errored(Some(e)) - } - } - }; - } - self.trace_writers = trace_writers; - retval - } - fn close(this: Rc>) -> std::io::Result<()> { - if this.borrow().main_module.did_initial_settle { - Self::settle(&this); - } - this.borrow_mut().close_all_trace_writers() - } - fn flush_traces(this_ref: &Rc>) -> std::io::Result<()> { - if this_ref.borrow().main_module.did_initial_settle { - Self::settle(this_ref); - } - this_ref.borrow_mut().for_each_trace_writer_getting_error( - |this, trace_writer: TraceWriterState| match trace_writer { - TraceWriterState::Decls(v) => { - let mut v = v.write_decls( - this.trace_decls, - this.traces.0.len(), - this.trace_memories.len(), - )?; - v.flush()?; - Ok(TraceWriterState::Init(v)) - } - TraceWriterState::Init(mut v) => { - v.flush()?; - Ok(TraceWriterState::Init(v)) - } - TraceWriterState::Running(mut v) => { - v.flush()?; - Ok(TraceWriterState::Running(v)) - } - TraceWriterState::Errored(Some(e)) => Err(e), - TraceWriterState::Errored(None) => Ok(TraceWriterState::Errored(None)), - }, - ) - } -} - -impl Drop for SimulationImpl { - fn drop(&mut self) { - self.close_all_trace_writers() - .expect("error closing trace writers"); - } -} - -pub struct Simulation { - sim_impl: Rc>, - io: Expr, -} - -struct SortedSetDebug<'a, T, V>(&'a HashMap); - -impl fmt::Debug for SortedSetDebug<'_, T, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut entries = Vec::from_iter(self.0.iter().map(|(v, _)| { - if f.alternate() { - format!("{v:#?}") - } else { - format!("{v:?}") - } - })); - entries.sort(); - f.debug_set() - .entries(entries.iter().map(DebugAsDisplay)) - .finish() - } -} - -struct SortedMapDebug<'a, K, V>(&'a HashMap); - -impl fmt::Debug for SortedMapDebug<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut entries = Vec::from_iter(self.0.iter().map(|(k, v)| { - if f.alternate() { - (format!("{k:#?}"), format!("{v:#?}")) - } else { - (format!("{k:?}"), format!("{v:?}")) - } - })); - entries.sort(); - f.debug_map() - .entries( - entries - .iter() - .map(|(k, v)| (DebugAsDisplay(k), DebugAsDisplay(v))), - ) - .finish() - } -} - -impl fmt::Debug for Simulation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { sim_impl, io } = self; - sim_impl.borrow().debug_fmt(Some(io), f) - } -} - -macro_rules! impl_simulation_methods { - ( - async_await = ($($async:tt, $await:tt)?), - track_caller = ($(#[$track_caller:tt])?), - which_module = |$self:ident| $which_module:expr, - ) => { - $(#[$track_caller])? - pub $($async)? fn read_bool_or_int(&mut $self, io: Expr) -> I::Value { - let retval = $self - .sim_impl - .borrow_mut() - .read_bool_or_int(io, $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_bool_or_int( - &mut $self, - io: Expr, - value: impl ToExpr, - ) { - let value = value.to_expr(); - assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); - let value = value - .to_literal_bits() - .expect("the value that is being written to an input must be a literal"); - $self.sim_impl.borrow_mut().write_bool_or_int( - io, - I::bits_to_value(Cow::Borrowed(&value)), - $which_module, - ); - } - $(#[$track_caller])? - pub $($async)? fn write_clock(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_clock(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_bool(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_bool(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_reset(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_reset(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn read(&mut $self, io: Expr) -> SimValue { - let retval = $self - .sim_impl - .borrow_mut() - .read(Expr::canonical(io), $which_module).1; - SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) - } - $(#[$track_caller])? - pub $($async)? fn write>(&mut $self, io: Expr, value: V) { - $self.sim_impl.borrow_mut().write( - Expr::canonical(io), - &SimValue::into_canonical(value.into_sim_value_with_type(Expr::ty(io))), - $which_module, - ); - } - }; -} - -impl Simulation { - pub fn new(module: Interned>) -> Self { - Self::from_compiled(Compiled::new(module)) - } - pub fn add_trace_writer(&mut self, writer: W) { - self.sim_impl - .borrow_mut() - .trace_writers - .push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer))); - } - pub fn flush_traces(&mut self) -> std::io::Result<()> { - SimulationImpl::flush_traces(&self.sim_impl) - } - pub fn close(self) -> std::io::Result<()> { - SimulationImpl::close(self.sim_impl) - } - pub fn canonical(self) -> Simulation { - let Self { sim_impl, io } = self; - Simulation { - sim_impl, - io: Expr::as_bundle(io), - } - } - pub fn from_canonical(canonical: Simulation) -> Self { - let Simulation { sim_impl, io } = canonical; - Self { - sim_impl, - io: Expr::from_bundle(io), - } - } - pub fn io(&self) -> Expr { - self.io.to_expr() - } - pub fn from_compiled(compiled: Compiled) -> Self { - let sim_impl = SimulationImpl::new(compiled.canonical()); - Self { - io: Expr::from_bundle(sim_impl.io), - sim_impl: Rc::new(RefCell::new(sim_impl)), - } - } - #[track_caller] - pub fn settle(&mut self) { - SimulationImpl::settle(&self.sim_impl); - } - #[track_caller] - pub fn advance_time(&mut self, duration: SimDuration) { - SimulationImpl::advance_time(&self.sim_impl, duration); - } - #[track_caller] - fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - SimulationImpl::settle_if_needed(&self.sim_impl, v) - } - impl_simulation_methods!( - async_await = (), - track_caller = (#[track_caller]), - which_module = |self| WhichModule::Main, - ); - #[doc(hidden)] - /// This is explicitly unstable and may be changed/removed at any time - pub fn set_breakpoints_unstable(&mut self, pcs: HashSet, trace: bool) { - self.sim_impl.borrow_mut().breakpoints = Some(BreakpointsSet { - last_was_break: false, - set: pcs, - trace, - }); - } -} - -pub struct ExternModuleSimulationState { - sim_impl: Rc>, - module_index: usize, - wait_for_changes_wait_targets: EarliestWaitTargets, -} - -impl fmt::Debug for ExternModuleSimulationState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - sim_impl: _, - module_index, - wait_for_changes_wait_targets: _, - } = self; - f.debug_struct("ExternModuleSimulationState") - .field("sim_impl", &DebugAsDisplay("...")) - .field("module_index", module_index) - .finish_non_exhaustive() - } -} - -impl ExternModuleSimulationState { - pub async fn settle(&mut self) { - SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None) - .await - } - pub async fn advance_time(&mut self, duration: SimDuration) { - SimulationImpl::yield_advance_time_or_settle( - self.sim_impl.clone(), - self.module_index, - Some(duration), - ) - .await - } - pub async fn wait_for_changes>( - &mut self, - iter: I, - timeout: Option, - ) { - self.wait_for_changes_wait_targets.clear(); - let which_module = WhichModule::Extern { - module_index: self.module_index, - }; - for io in iter { - let io = Expr::canonical(io.to_expr()); - let (key, value) = self.sim_impl.borrow_mut().read(io, which_module); - let value = self.settle_if_needed(value).await; - self.wait_for_changes_wait_targets - .insert(WaitTarget::Change { key, value }); - } - if let Some(timeout) = timeout { - self.wait_for_changes_wait_targets.instant = - Some(self.sim_impl.borrow().instant + timeout); - } - SimulationImpl::yield_wait( - self.sim_impl.clone(), - self.module_index, - &mut self.wait_for_changes_wait_targets, - ) - .await; - } - pub async fn wait_for_clock_edge(&mut self, clk: impl ToExpr) { - let clk = clk.to_expr(); - while self.read_clock(clk).await { - self.wait_for_changes([clk], None).await; - } - while !self.read_clock(clk).await { - self.wait_for_changes([clk], None).await; - } - } - async fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - SimulationImpl::yield_settle_if_needed(&self.sim_impl, self.module_index, v).await - } - impl_simulation_methods!( - async_await = (async, await), - track_caller = (), - which_module = |self| WhichModule::Extern { module_index: self.module_index }, - ); -} - -pub trait ExternModuleSimGenerator: Clone + Eq + Hash + Any + Send + Sync + fmt::Debug { - fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a; -} - -pub struct SimGeneratorFn { - pub args: Args, - pub f: fn(Args, ExternModuleSimulationState) -> Fut, -} - -impl fmt::Debug for SimGeneratorFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { args, f: _ } = self; - f.debug_struct("SimGeneratorFn") - .field("args", args) - .field("f", &DebugAsDisplay("...")) - .finish() - } -} - -impl Hash for SimGeneratorFn { - fn hash(&self, state: &mut H) { - let Self { args, f } = self; - args.hash(state); - f.hash(state); - } -} - -impl Eq for SimGeneratorFn {} - -impl PartialEq for SimGeneratorFn { - fn eq(&self, other: &Self) -> bool { - let Self { args, f } = self; - *args == other.args && *f == other.f - } -} - -impl Clone for SimGeneratorFn { - fn clone(&self) -> Self { - Self { - args: self.args.clone(), - f: self.f, - } - } -} - -impl Copy for SimGeneratorFn {} - -impl< - T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static, - Fut: IntoFuture + 'static, - > ExternModuleSimGenerator for SimGeneratorFn -{ - fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a { - (self.f)(self.args.clone(), sim) - } -} - -trait DynExternModuleSimGenerator: Any + Send + Sync + SupportsPtrEqWithTypeId + fmt::Debug { - fn dyn_run<'a>(&'a self, sim: ExternModuleSimulationState) - -> Box + 'a>; -} - -impl DynExternModuleSimGenerator for T { - fn dyn_run<'a>( - &'a self, - sim: ExternModuleSimulationState, - ) -> Box + 'a> { - Box::new(self.run(sim).into_future()) - } -} - -impl InternedCompare for dyn DynExternModuleSimGenerator { - type InternedCompareKey = PtrEqWithTypeId; - - fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { - this.get_ptr_eq_with_type_id() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct ExternModuleSimulation { - generator: Interned, - source_location: SourceLocation, -} - -impl ExternModuleSimulation { - pub fn new_with_loc( - source_location: SourceLocation, - generator: G, - ) -> Self { - Self { - generator: Interned::cast_unchecked( - generator.intern(), - |v| -> &dyn DynExternModuleSimGenerator { v }, - ), - source_location, - } - } - #[track_caller] - pub fn new(generator: G) -> Self { - Self::new_with_loc(SourceLocation::caller(), generator) - } - fn run(&self, sim: ExternModuleSimulationState) -> Box + 'static> { - Interned::into_inner(self.generator).dyn_run(sim) - } -} diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs deleted file mode 100644 index de582f0..0000000 --- a/crates/fayalite/src/sim/interpreter.rs +++ /dev/null @@ -1,3184 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - array::Array, - int::{BoolOrIntType, SInt, UInt}, - intern::{Intern, Interned, Memoize}, - source_location::SourceLocation, - ty::CanonicalType, - util::{get_many_mut, HashMap, HashSet}, -}; -use bitvec::{boxed::BitBox, slice::BitSlice}; -use num_bigint::BigInt; -use num_traits::{One, Signed, ToPrimitive, Zero}; -use std::{ - any::TypeId, - borrow::BorrowMut, - convert::Infallible, - fmt::{self, Write}, - hash::{Hash, Hasher}, - marker::PhantomData, - ops::{ControlFlow, Deref, DerefMut, Index, IndexMut}, -}; -use vec_map::VecMap; - -pub(crate) type SmallUInt = u64; -pub(crate) type SmallSInt = i64; -pub(crate) const MIN_BITS_FOR_NEEDING_BIG: usize = SmallUInt::BITS as usize + 1; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) enum InsnFieldKind { - Input, - Output, - Memory, - Immediate, - BranchTarget, -} - -pub(crate) trait InsnFieldTypeTransform: Eq + Hash + fmt::Debug + Send + Sync { - type Type: Eq + Hash + fmt::Debug + Send + Sync; - fn empty_type() -> Self::Type<[(); 0]>; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub(crate) struct InsnFieldTypeTransformUnit; - -impl InsnFieldTypeTransform for InsnFieldTypeTransformUnit { - type Type = (); - fn empty_type() -> Self::Type<[(); 0]> { - () - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct InsnFieldTypeTransformRef<'a>(PhantomData<&'a ()>); - -impl<'a> InsnFieldTypeTransform for InsnFieldTypeTransformRef<'a> { - type Type = &'a FieldType; - fn empty_type() -> Self::Type<[(); 0]> { - &[] - } -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub(crate) struct InsnFieldTypeTransformRefMut<'a>(PhantomData<&'a mut ()>); - -impl<'a> InsnFieldTypeTransform for InsnFieldTypeTransformRefMut<'a> { - type Type = &'a mut FieldType; - fn empty_type() -> Self::Type<[(); 0]> { - &mut [] - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct InsnFieldTypeTransformValue; - -impl InsnFieldTypeTransform for InsnFieldTypeTransformValue { - type Type = FieldType; - fn empty_type() -> Self::Type<[(); 0]> { - [] - } -} - -pub trait InsnFieldTrait: Send + Sync + 'static + Copy + Eq + Hash + fmt::Debug { - const UNIT: InsnFieldType; - fn variant( - v: Transform::Type, - ) -> InsnFieldType; -} - -macro_rules! insn_field_enum { - ( - $enum_vis:vis enum $InsnFieldType:ident<$Transform:ident: $InsnFieldTypeTransform:ident> { - $($Variant:ident($Transform2:ident::$Type:ident<$variant_ty:ty>),)* - } - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - $enum_vis enum $InsnFieldType<$Transform: $InsnFieldTypeTransform> { - $($Variant($Transform2::$Type<$variant_ty>),)* - } - - $(impl InsnFieldTrait for $variant_ty { - const UNIT: $InsnFieldType = $InsnFieldType::$Variant(()); - fn variant<$Transform2: $InsnFieldTypeTransform>( - v: $Transform2::$Type, - ) -> $InsnFieldType<$Transform2> { - $InsnFieldType::$Variant(v) - } - })* - }; -} - -insn_field_enum! { - pub(crate) enum InsnFieldType { - Memory(Transform::Type>), - SmallSlot(Transform::Type>), - BigSlot(Transform::Type>), - SmallSlotArrayIndexed(Transform::Type>), - BigSlotArrayIndexed(Transform::Type>), - SmallUInt(Transform::Type), - SmallSInt(Transform::Type), - InternedBigInt(Transform::Type>), - U8(Transform::Type), - USize(Transform::Type), - Empty(Transform::Type<[(); 0]>), - } -} - -impl InsnFieldType { - pub(crate) fn empty() -> Self { - Self::Empty(Transform::empty_type()) - } -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub(crate) struct InsnField { - pub(crate) ty: InsnFieldType, - pub(crate) kind: InsnFieldKind, -} - -impl Clone for InsnField -where - InsnFieldType: Clone, -{ - fn clone(&self) -> Self { - Self { - ty: self.ty.clone(), - kind: self.kind.clone(), - } - } -} - -impl Copy for InsnField where - InsnFieldType: Copy -{ -} - -fn make_array_into_iter( - input: [T; I], - mut default: impl FnMut() -> T, -) -> std::array::IntoIter { - const { - assert!(I <= N); - }; - let mut input = input.into_iter(); - let array = std::array::from_fn(|_| input.next().unwrap_or_else(&mut default)); - let mut retval = array.into_iter(); - // remove unneeded trailing elements - if I < N { - retval.nth_back(N - I - 1); - } - retval -} - -impl fmt::Debug for Insn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt::(f, None, None, None) - } -} - -struct PrefixLinesWrapper<'a, W> { - writer: W, - at_beginning_of_line: bool, - blank_line_prefix: &'a str, - line_prefix: &'a str, -} - -impl fmt::Write for PrefixLinesWrapper<'_, T> { - fn write_str(&mut self, input: &str) -> fmt::Result { - for part in input.split_inclusive('\n') { - if part.is_empty() { - continue; - } - if self.at_beginning_of_line { - let prefix = match part { - "\n" => self.blank_line_prefix, - _ => self.line_prefix, - }; - if !prefix.is_empty() { - self.writer.write_str(prefix)?; - } - self.at_beginning_of_line = false; - } - self.writer.write_str(part)?; - self.at_beginning_of_line = part.ends_with('\n'); - } - Ok(()) - } -} - -impl Insn { - fn debug_fmt( - &self, - f: &mut fmt::Formatter<'_>, - labels: Option<&Labels>, - state_layout: Option<&StateLayout>, - state: Option<&State>, - ) -> fmt::Result { - let (insn_name, fields) = self.fields_with_names(); - write!(f, "{insn_name}")?; - if fields.len() == 0 { - return Ok(()); - } - let mut f = PrefixLinesWrapper { - writer: f, - at_beginning_of_line: false, - blank_line_prefix: "", - line_prefix: " ", - }; - writeln!(f, " {{")?; - for (field_name, field) in fields { - write!(f, "{field_name}: ")?; - match field.kind { - InsnFieldKind::BranchTarget => match field.ty { - InsnFieldType::USize(&label_index) => { - if let Some(labels) = labels { - write!(f, "L{label_index}")?; - if let Some(label) = labels.labels.get(label_index) { - if let Some(address) = label.address { - write!(f, " (at {address})")?; - } else { - write!(f, " (not yet defined)")?; - } - } else { - write!(f, " (invalid)")?; - } - writeln!(f, ",")?; - continue; - } - } - InsnFieldType::Memory(_) - | InsnFieldType::SmallSlot(_) - | InsnFieldType::BigSlot(_) - | InsnFieldType::SmallSlotArrayIndexed(_) - | InsnFieldType::BigSlotArrayIndexed(_) - | InsnFieldType::SmallUInt(_) - | InsnFieldType::SmallSInt(_) - | InsnFieldType::InternedBigInt(_) - | InsnFieldType::U8(_) - | InsnFieldType::Empty(_) => {} - }, - InsnFieldKind::Input - | InsnFieldKind::Memory - | InsnFieldKind::Output - | InsnFieldKind::Immediate => {} - } - macro_rules! debug_fmt_state_part { - ($v:expr) => { - $v.debug_fmt(&mut f, ",", " // ", " // ", "", state_layout, state) - }; - } - match field.ty { - InsnFieldType::Memory(v) => { - debug_fmt_state_part!(v)?; - } - InsnFieldType::SmallSlot(v) => { - debug_fmt_state_part!(v)?; - } - InsnFieldType::BigSlot(v) => { - debug_fmt_state_part!(v)?; - } - InsnFieldType::SmallSlotArrayIndexed(v) => { - debug_fmt_state_part!(v)?; - } - InsnFieldType::BigSlotArrayIndexed(v) => { - debug_fmt_state_part!(v)?; - } - InsnFieldType::SmallUInt(v) => write!(f, "{v:#x}")?, - InsnFieldType::SmallSInt(v) => write!(f, "{v:#x}")?, - InsnFieldType::InternedBigInt(v) => write!(f, "{v:#x}")?, - InsnFieldType::U8(v) => write!(f, "{v:#x}")?, - InsnFieldType::USize(v) => write!(f, "{v}")?, - InsnFieldType::Empty(v) => write!(f, "{v:?}")?, - } - writeln!(f, ",")?; - } - write!(f.writer, "}}") - } -} - -pub(crate) trait Breakpoints { - type Break; - fn check_for_breakpoint(&mut self, pc: usize) -> ControlFlow; -} - -impl Breakpoints for &'_ mut T { - type Break = T::Break; - fn check_for_breakpoint(&mut self, pc: usize) -> ControlFlow { - T::check_for_breakpoint(self, pc) - } -} - -impl Breakpoints for Box { - type Break = T::Break; - fn check_for_breakpoint(&mut self, pc: usize) -> ControlFlow { - T::check_for_breakpoint(self, pc) - } -} - -impl Breakpoints for () { - type Break = Infallible; - fn check_for_breakpoint(&mut self, _pc: usize) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -pub(crate) struct BreakpointsSet { - pub(crate) last_was_break: bool, - pub(crate) set: HashSet, - pub(crate) trace: bool, -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub(crate) enum BreakAction { - DumpStateAndContinue, - Continue, -} - -impl Breakpoints for BreakpointsSet { - type Break = BreakAction; - fn check_for_breakpoint(&mut self, pc: usize) -> ControlFlow { - let retval = if self.last_was_break { - ControlFlow::Continue(()) - } else if self.set.contains(&pc) { - ControlFlow::Break(BreakAction::DumpStateAndContinue) - } else if self.trace { - ControlFlow::Break(BreakAction::Continue) - } else { - ControlFlow::Continue(()) - }; - self.last_was_break = retval.is_break(); - retval - } -} - -pub(crate) enum RunResult { - Break(Break), - Return(Return), -} - -macro_rules! impl_insns { - ( - #[insn = $Insn:ident, next_macro = $next_macro:ident, branch_macro = $branch_macro:ident] - $vis:vis fn $State:ident::$run:ident(&mut $self:ident) -> $run_ret_ty:ty { - #[state] - let mut $state:ident = $state_init:expr; - setup! { - $($setup:tt)* - } - main_loop!(); - cleanup! { - $($cleanup:tt)* - } - } - $( - $(#[$insn_meta:meta])* - $insn_name:ident $({ - $( - #[kind = $field_kind:ident] - $(#[$field_meta:meta])* - $field_name:ident: $field_ty:ty, - )* - })? => $block:block - )* - ) => { - #[derive(Copy, Clone, Eq, PartialEq, Hash)] - $vis enum $Insn { - $( - $(#[$insn_meta])* - $insn_name $({ - $( - $(#[$field_meta])* - $field_name: $field_ty, - )* - })?, - )* - } - - impl $Insn { - $vis const MAX_FIELDS: usize = { - let mut retval = 0; - $($( - let fields = [$(stringify!($field_name),)*].len(); - if retval < fields { - retval = fields; - } - )?)* - retval - }; - } - - impl $Insn { - $vis const fn fields_unit(&self) -> &'static [InsnField] { - match self { - $( - $Insn::$insn_name {..} => &[ - $($(InsnField { - ty: <$field_ty as InsnFieldTrait>::UNIT, - kind: InsnFieldKind::$field_kind, - },)*)? - ], - )* - } - } - $vis fn fields<'a>(&'a self) -> std::array::IntoIter>, { $Insn::MAX_FIELDS }> { - match self { - $( - $Insn::$insn_name $({ - $($field_name,)* - })? => make_array_into_iter([ - $($(InsnField { - ty: <$field_ty as InsnFieldTrait>::variant($field_name), - kind: InsnFieldKind::$field_kind, - },)*)? - ], - || InsnField { - ty: InsnFieldType::empty(), - kind: InsnFieldKind::Immediate, - }, - ), - )* - } - } - $vis fn fields_with_names<'a>(&'a self) -> (&'static str, std::array::IntoIter<(&'static str, InsnField>), { $Insn::MAX_FIELDS }>) { - match self { - $( - $Insn::$insn_name $({ - $($field_name,)* - })? => ( - stringify!($insn_name), - make_array_into_iter([ - $($((stringify!($field_name), InsnField { - ty: <$field_ty as InsnFieldTrait>::variant($field_name), - kind: InsnFieldKind::$field_kind, - }),)*)? - ], - || ("", InsnField { - ty: InsnFieldType::empty(), - kind: InsnFieldKind::Immediate, - }), - ), - ), - )* - } - } - $vis fn fields_mut<'a>(&'a mut self) -> std::array::IntoIter>, { $Insn::MAX_FIELDS }> { - match self { - $( - $Insn::$insn_name $({ - $($field_name,)* - })? => make_array_into_iter([ - $($(InsnField { - ty: <$field_ty as InsnFieldTrait>::variant($field_name), - kind: InsnFieldKind::$field_kind, - },)*)? - ], - || InsnField { - ty: InsnFieldType::empty(), - kind: InsnFieldKind::Immediate, - }, - ), - )* - } - } - $vis fn into_fields(self) -> std::array::IntoIter, { $Insn::MAX_FIELDS }> { - match self { - $( - $Insn::$insn_name $({ - $($field_name,)* - })? => make_array_into_iter([ - $($(InsnField { - ty: <$field_ty as InsnFieldTrait>::variant($field_name), - kind: InsnFieldKind::$field_kind, - },)*)? - ], - || InsnField { - ty: InsnFieldType::empty(), - kind: InsnFieldKind::Immediate, - }, - ), - )* - } - } - } - - impl $State { - $vis fn $run(&mut $self, mut breakpoints: B) -> RunResult { - let mut $state = $state_init; - $($setup)* - let mut insn = $state.insns[$state.pc]; - let retval = 'main_loop: loop { - if let ControlFlow::Break(b) = breakpoints.check_for_breakpoint($state.pc) { - break RunResult::Break(b); - } - macro_rules! $next_macro { - () => { - $state.pc += 1; - insn = $state.insns[$state.pc]; - continue 'main_loop; - }; - } - macro_rules! $branch_macro { - ($next_pc:expr) => { - $state.pc = $next_pc; - insn = $state.insns[$state.pc]; - continue 'main_loop; - }; - } - let _: Infallible = match insn { - $( - $Insn::$insn_name $({ - $( - $field_name, - )* - })? => { - $block - } - )* - }; - }; - $($cleanup)* - retval - } - } - }; -} - -pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default { - type Vec: fmt::Debug - + Clone - + Eq - + Hash - + Send - + Sync - + 'static - + Default - + Deref - + FromIterator; - type Labels: Default; - fn labels(labels: &Self::Labels) -> Option<&Labels>; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub(crate) struct InsnsBuildingDone; - -impl InsnsBuildingKind for InsnsBuildingDone { - type Vec = Interned<[T]>; - type Labels = (); - fn labels(_labels: &Self::Labels) -> Option<&Labels> { - None - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub(crate) struct InsnsBuilding; - -impl InsnsBuildingKind for InsnsBuilding { - type Vec = Vec; - type Labels = Labels; - fn labels(labels: &Self::Labels) -> Option<&Labels> { - Some(labels) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Label(pub(crate) usize); - -impl fmt::Debug for Label { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "L{}:", self.0) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub(crate) enum InsnOrLabel { - Insn(Insn), - Label(Label), -} - -impl From for InsnOrLabel { - fn from(value: Insn) -> Self { - Self::Insn(value) - } -} - -impl From