diff --git a/.cargo/config.in b/.cargo/config.in index afc780488adb..d38a74acbbc2 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -22,9 +22,9 @@ git = "https://github.com/hsivonen/packed_simd" branch = "rust_1_32" replace-with = "vendored-sources" -[source."https://github.com/CraneStation/target-lexicon"] -git = "https://github.com/glandium/target-lexicon" -branch = "thumbv7neon-v0.2" +[source."https://github.com/CraneStation/Cranelift"] +git = "https://github.com/CraneStation/Cranelift" +rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" replace-with = "vendored-sources" [source.vendored-sources] diff --git a/Cargo.lock b/Cargo.lock index 72a03c423bd1..c8854e60c866 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,11 +168,11 @@ name = "baldrdash" version = "0.1.0" dependencies = [ "bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", + "cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -568,62 +568,62 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" dependencies = [ - "cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", ] [[package]] name = "cranelift-codegen" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" dependencies = [ - "cranelift-bforest 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen-meta 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", + "cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", + "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" dependencies = [ - "cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", ] [[package]] name = "cranelift-entity" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" [[package]] name = "cranelift-frontend" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" dependencies = [ - "cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.30.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", + "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", + "cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2778,8 +2778,8 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.2.0" -source = "git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2#b2d4b34509abb3e12b1c93d19b8593d02ddeed76" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3203,7 +3203,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.23.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3495,12 +3495,12 @@ dependencies = [ "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae" "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d" "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94" -"checksum cranelift-bforest 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a3a25dfe4a54449df63d592f2f6346a80350ac835d4be4bacb73c20b034ef763" -"checksum cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c3b15a20577e6c823475953a5e25e758d9d3a3148a937d686c09460e5f2f4a0" -"checksum cranelift-codegen-meta 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e60ce3551e8172c966fbc6d9bfb90111d5d1cf37306c37dd7527467afe317d1" -"checksum cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e124e09cb7dc85fbe2162420aebbe8e9e3b8f9210901be7867416c5beec8226" -"checksum cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2833c6e1a93c524ce0c2ab31266cdc84d38c906349f79f19378a5e5995727b23" -"checksum cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e75efb45cd8d8700b4bdc225f0077bc7c615f84a5807ce001d59b4da48d85573" +"checksum cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" +"checksum cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" +"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" +"checksum cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" +"checksum cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" +"checksum cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" @@ -3691,7 +3691,7 @@ dependencies = [ "checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d" "checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)" = "" +"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" @@ -3736,7 +3736,7 @@ dependencies = [ "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" -"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" +"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum webidl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f807f7488d680893f7188aa09d7672a3a0a8461975a098a2edf0a52e3fee29" "checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/Cargo.toml b/Cargo.toml index 7d1a17ab7a0c..be20f586f368 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,4 +61,5 @@ libudev-sys = { path = "dom/webauthn/libudev-sys" } serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" } winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" } packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" } -target-lexicon = { git = "https://github.com/glandium/target-lexicon", branch = "thumbv7neon-v0.2" } +cranelift-codegen = { git = "https://github.com/CraneStation/Cranelift", rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" } +cranelift-wasm = { git = "https://github.com/CraneStation/Cranelift", rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" } diff --git a/js/src/wasm/cranelift/Cargo.toml b/js/src/wasm/cranelift/Cargo.toml index 7c76e8182f10..7adc2868a725 100644 --- a/js/src/wasm/cranelift/Cargo.toml +++ b/js/src/wasm/cranelift/Cargo.toml @@ -8,9 +8,16 @@ crate-type = ["rlib"] name = "baldrdash" [dependencies] -cranelift-codegen = { version = "0.29.0", default-features = false } -cranelift-wasm = "0.29.0" -target-lexicon = "0.2.0" +# The build system redirects the versions of cranelift-codegen and +# cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko, +# you should update the following files: +# - $TOP_LEVEL/Cargo.toml, look for the revision (rev) hashes of both cranelift +# dependencies (codegen and wasm). +# - $TOP_LEVEL/.cargo/config.in, look for the revision (rev) field of the +# Cranelift source. +cranelift-codegen = { version = "0.30", default-features = false } +cranelift-wasm = "0.30" +target-lexicon = "0.4.0" log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] } env_logger = "0.5.6" diff --git a/third_party/rust/cranelift-bforest/.cargo-checksum.json b/third_party/rust/cranelift-bforest/.cargo-checksum.json index e0bf9f6e55a2..b2edb2476676 100644 --- a/third_party/rust/cranelift-bforest/.cargo-checksum.json +++ b/third_party/rust/cranelift-bforest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d6c5cca60972e64e1abb435d2af6bf8af2fec2d5988d0fda9827f6bba1f6a47c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"1b23abbfe5850a4cd77ae6ae5dcfc2f678ef36b4032fd7496f2b333c51e63301","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"4868e59ff67db1c504747e4b7e202dd20c9da4cbd73d9fa82d53e5f3406dbb78","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":"a3a25dfe4a54449df63d592f2f6346a80350ac835d4be4bacb73c20b034ef763"} \ No newline at end of file +{"files":{"Cargo.toml":"4fb2be5a108736ec2eeb257fd9c90d7e4384321e34eaef0fc7c5517a8e096650","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"1b23abbfe5850a4cd77ae6ae5dcfc2f678ef36b4032fd7496f2b333c51e63301","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"4868e59ff67db1c504747e4b7e202dd20c9da4cbd73d9fa82d53e5f3406dbb78","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-bforest/Cargo.toml b/third_party/rust/cranelift-bforest/Cargo.toml index 5569828a6f0b..d5bd3565e409 100644 --- a/third_party/rust/cranelift-bforest/Cargo.toml +++ b/third_party/rust/cranelift-bforest/Cargo.toml @@ -1,37 +1,24 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" -name = "cranelift-bforest" -version = "0.29.0" authors = ["The Cranelift Project Developers"] +name = "cranelift-bforest" +version = "0.30.0" description = "A forest of B+-trees" +license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" +repository = "https://github.com/CraneStation/cranelift" +categories = ["no-std"] readme = "README.md" keywords = ["btree", "forest", "set", "map"] -categories = ["no-std"] -license = "Apache-2.0 WITH LLVM-exception" -repository = "https://github.com/CraneStation/cranelift" -[dependencies.cranelift-entity] -version = "0.29.0" -default-features = false +edition = "2018" + +[dependencies] +cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false } [features] -core = [] default = ["std"] std = ["cranelift-entity/std"] -[badges.maintenance] -status = "experimental" +core = [] -[badges.travis-ci] -repository = "CraneStation/cranelift" +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json index e9f5d6618077..d3d0a845fc34 100644 --- a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json +++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f5ea16920dd3c3f9c1ef903e26b10a913cafb5ac30eb36deabca977de04a62ae","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/isa.rs":"d3ddfc8bd3d691df034a1bacfa27b3e29eb2e7a30923508fa5c7af8d89e8a962","src/cdsl/mod.rs":"66ac1b5d095e431bcab88c4b9c5b1492a5d1ca87bcb9c9c3e544ede05b2ba925","src/cdsl/regs.rs":"b99f24c3ecb46691625dc177b4e18d53e02265bc85a2f827a8d18381fe8f39bb","src/cdsl/settings.rs":"4ddeadf1542cc2ddec0f9e6c22d1637050da519586cd9fec0243c3eab9619f82","src/cdsl/types.rs":"981ebe748973bdf2dee00fa71784f6dcaa6c7648442665f34a59ad97a05fe888","src/constant_hash.rs":"b8acd3f8712a4999819d9d9beced2938d9940a5748ba016c182f1132d97eefab","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_registers.rs":"75bbbc0f8dd546c88ed52f350175656300e35e871382a7508e7123e32d4bee1e","src/gen_settings.rs":"4689ede4e460bfcc19511c1055ba359b52f248f4a6d3afd62b1d23bc493b37a1","src/gen_types.rs":"3935da6c6a53f9332e06f74bc3a46270656b4d4231ad28ed2648d7b1d2774e90","src/isa/arm32/mod.rs":"f5b0cbbb2f6c7f00bb9a9bc6f0b1120477ff7ff683a95a6cdbbeed1677b0c9c8","src/isa/arm64/mod.rs":"c234b0df3d36d6d8765ead548e43b5304480e79da9697e14f9d98525919921b3","src/isa/mod.rs":"7038e3aa629afc28707fea379237d3c161ab459d552160438ac75e1137c6246a","src/isa/riscv/mod.rs":"322220fa67cf8623eeb27c7d23f3cc34e05873860248ae99fd02af452c232383","src/isa/x86/mod.rs":"c9183448ffe378e599ec7dc6ae7180c97d3e11d15d7644b93eb1e4a3543222f2","src/lib.rs":"4c73b35cbd68aab9b9c8c86bb71f67555e0e15f36a22101e086a346b01ee8cfb","src/shared/mod.rs":"87b55c291c5e73a9d7cd9a0ebfc8e59501956195268673d0d980de58694f4741","src/shared/settings.rs":"bc6a15221d688bf63114c53493d31070860eb7fae208596374488404a65ee41a","src/shared/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/srcgen.rs":"72435db1e0c984d95c5c5aa758907ed79eaec41ca3203ac661c6acd64c19acce","src/unique_table.rs":"f6041df1fa85f2a1ee914b84791e80165a0858a6253c212eaa99ff67cb56af26"},"package":"3e60ce3551e8172c966fbc6d9bfb90111d5d1cf37306c37dd7527467afe317d1"} \ No newline at end of file +{"files":{"Cargo.toml":"253c80832ab598570d604ae8a8108ea9835b8eef8d9b9645408ed025ce3b574a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/formats.rs":"98ab61698ad4c1fb81541b1820bd1c1561810bdcff2796dec541c98b4b1901d7","src/cdsl/inst.rs":"d5130c1a36a4e33d1374f9867119c3f2d79c384f12afc12e7b7b4518cf1f74b3","src/cdsl/isa.rs":"dd52d35fa963494b7da892a4a04a4f9978079bb2d86c6af4273a8dfdb82bdf51","src/cdsl/mod.rs":"2d2e216f8c3a81978a5113213559a5ab659bc112b6194cbe08a752313aad7f46","src/cdsl/operands.rs":"cc579fd543e36cf8e82938db331c145b77e29855ee2aa8c5dd949678f980796d","src/cdsl/regs.rs":"b99f24c3ecb46691625dc177b4e18d53e02265bc85a2f827a8d18381fe8f39bb","src/cdsl/settings.rs":"4ddeadf1542cc2ddec0f9e6c22d1637050da519586cd9fec0243c3eab9619f82","src/cdsl/type_inference.rs":"8aedb2e99dee299abbc327ce3a604d48f161580776225d2438a54bbec5b725fe","src/cdsl/types.rs":"4cc1f20eb8383fdee6a9e7ca0f7758e563a4fb715056b5edbd4db72f8dfd471b","src/cdsl/typevar.rs":"605786e2bf367879da500327fc003a4d2a663259c2dee76c87e5b99b6f6331ee","src/constant_hash.rs":"b8acd3f8712a4999819d9d9beced2938d9940a5748ba016c182f1132d97eefab","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"77ee330b85a255c49247222f4d071da839b0520eddd3dc561867f7ae84e199ac","src/gen_types.rs":"3935da6c6a53f9332e06f74bc3a46270656b4d4231ad28ed2648d7b1d2774e90","src/isa/arm32/mod.rs":"6ed3be790b28d3115421be282a06b8c376295e1776c4b77243443799015ab70d","src/isa/arm64/mod.rs":"5c46082f68c958e83ffc636de893e2ff49fd8ce21ef357f359837ca48a60eaa5","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/mod.rs":"785f0da2b04458793cb2d493c5e1eeb7ea339bc721df76dda69db3b49bcdfd27","src/isa/x86/instructions.rs":"bd6b02ccc79984ed4a5615ae3b20a60a4da3777495b72f771762a886f87d2335","src/isa/x86/mod.rs":"ba7c11aedb190f58432226a6dec8a125b385cc18fd2f70c46703d077904a3112","src/lib.rs":"7ddb2d1f1a80d3dc3a7434309a6e0890dd054e88c549c20d2959236ffe986bd9","src/shared/entities.rs":"e7a44d5f621d726479c3812384e78dd25e8c063d074c64d0908b3667e7d28af1","src/shared/formats.rs":"20908b1048c5e71a185de6b6ded79cdff2c26ddb38ba7b134b7a27f37e8324f3","src/shared/immediates.rs":"1e64836f82045d05da7c151e60cf1e66666af3e0c19179de3f37e72dc81e1bbd","src/shared/instructions.rs":"2a0993279b3529b2c31aa8e83589636104a005351463ec2d3b81b5ffe569d276","src/shared/mod.rs":"696c166d3c19bd84604583a7b8d7ec4f6671622ed581bfce8bee375d02067cbe","src/shared/settings.rs":"bad2dc0e1d71ee6fec6418aa79234296aa918e499a1671c3e5c1d4b0d84b6f49","src/shared/types.rs":"158d73840185e6aa8385463bbf6568efdda0c8de8284cf6b4e565f425ec5d921","src/srcgen.rs":"ad39143ae50f3b19f18a43131bdd3308852c70a9e532cc99f97624e7380b00d8","src/unique_table.rs":"bec9d48ee040216a7c9deab6d2c5050d7ce70e38482cc8957105fd7cbca3c33a"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-codegen-meta/Cargo.toml b/third_party/rust/cranelift-codegen-meta/Cargo.toml index 5db82fd7af0c..a5f734494d40 100644 --- a/third_party/rust/cranelift-codegen-meta/Cargo.toml +++ b/third_party/rust/cranelift-codegen-meta/Cargo.toml @@ -1,28 +1,22 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" name = "cranelift-codegen-meta" -version = "0.29.0" authors = ["The Cranelift Project Developers"] +version = "0.30.0" description = "Metaprogram for cranelift-codegen code generator library" -readme = "README.md" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/CraneStation/cranelift" -[dependencies.cranelift-entity] -version = "0.29.0" -[badges.maintenance] -status = "experimental" +readme = "README.md" +edition = "2018" -[badges.travis-ci] -repository = "CraneStation/cranelift" +[dependencies] +cranelift-entity = { path = "../../cranelift-entity", version = "0.30.0", default-features = false } + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } + +[features] +default = ["std"] +std = ["cranelift-entity/std"] +# The "core" feature enables a workaround for Cargo #4866. +core = ["cranelift-entity/core"] diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs new file mode 100644 index 000000000000..837440d2c03a --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs @@ -0,0 +1,246 @@ +use crate::cdsl::operands::{Operand, OperandKind}; + +use std::collections::{HashMap, HashSet}; +use std::fmt; +use std::slice; + +use cranelift_entity::{entity_impl, PrimaryMap}; + +/// An immediate field in an instruction format. +/// +/// This corresponds to a single member of a variant of the `InstructionData` +/// data type. +/// +/// :param iform: Parent `InstructionFormat`. +/// :param kind: Immediate Operand kind. +/// :param member: Member name in `InstructionData` variant. +#[derive(Debug)] +pub struct FormatField { + /// Immediate operand number in parent. + immnum: usize, + + /// Immediate operand kind. + pub kind: OperandKind, + + /// Member name in InstructionDate variant. + pub member: &'static str, +} + +/// Every instruction opcode has a corresponding instruction format which +/// determines the number of operands and their kinds. Instruction formats are +/// identified structurally, i.e., the format of an instruction is derived from +/// the kinds of operands used in its declaration. +/// +/// The instruction format stores two separate lists of operands: Immediates +/// and values. Immediate operands (including entity references) are +/// represented as explicit members in the `InstructionData` variants. The +/// value operands are stored differently, depending on how many there are. +/// Beyond a certain point, instruction formats switch to an external value +/// list for storing value arguments. Value lists can hold an arbitrary number +/// of values. +/// +/// All instruction formats must be predefined in the meta shared/formats module. +/// +/// :param kinds: List of `OperandKind` objects describing the operands. +/// :param name: Instruction format name in CamelCase. This is used as a Rust +/// variant name in both the `InstructionData` and `InstructionFormat` +/// enums. +/// :param typevar_operand: Index of the value input operand that is used to +/// infer the controlling type variable. By default, this is `0`, the first +/// `value` operand. The index is relative to the values only, ignoring +/// immediate operands. +#[derive(Debug)] +pub struct InstructionFormat { + pub name: &'static str, + pub num_value_operands: usize, + pub has_value_list: bool, + pub imm_fields: Vec, + pub typevar_operand: Option, +} + +impl fmt::Display for InstructionFormat { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let args = self + .imm_fields + .iter() + .map(|field| format!("{}: {}", field.member, field.kind.name)) + .collect::>() + .join(", "); + fmt.write_fmt(format_args!( + "{}(imms=({}), vals={})", + self.name, args, self.num_value_operands + ))?; + Ok(()) + } +} + +pub struct InstructionFormatBuilder { + name: &'static str, + num_value_operands: usize, + has_value_list: bool, + imm_fields: Vec, + typevar_operand: Option, +} + +pub struct ImmParameter { + kind: OperandKind, + member: &'static str, +} +impl Into for (&'static str, &OperandKind) { + fn into(self) -> ImmParameter { + ImmParameter { + kind: self.1.clone(), + member: self.0, + } + } +} +impl Into for &OperandKind { + fn into(self) -> ImmParameter { + ImmParameter { + kind: self.clone(), + member: self.default_member.unwrap(), + } + } +} + +impl InstructionFormatBuilder { + pub fn new(name: &'static str) -> Self { + Self { + name, + num_value_operands: 0, + has_value_list: false, + imm_fields: Vec::new(), + typevar_operand: None, + } + } + + pub fn value(mut self) -> Self { + self.num_value_operands += 1; + self + } + + pub fn varargs(mut self) -> Self { + self.has_value_list = true; + self + } + + pub fn imm(mut self, param: impl Into) -> Self { + let imm_param = param.into(); + let field = FormatField { + immnum: self.imm_fields.len(), + kind: imm_param.kind, + member: imm_param.member, + }; + self.imm_fields.push(field); + self + } + + pub fn typevar_operand(mut self, operand_index: usize) -> Self { + assert!(self.typevar_operand.is_none()); + assert!(self.has_value_list || operand_index < self.num_value_operands); + self.typevar_operand = Some(operand_index); + self + } + + pub fn finish(self) -> InstructionFormat { + let typevar_operand = if self.typevar_operand.is_some() { + self.typevar_operand + } else if self.has_value_list || self.num_value_operands > 0 { + // Default to the first value operand, if there's one. + Some(0) + } else { + None + }; + + InstructionFormat { + name: self.name, + num_value_operands: self.num_value_operands, + has_value_list: self.has_value_list, + imm_fields: self.imm_fields, + typevar_operand, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct InstructionFormatIndex(u32); +entity_impl!(InstructionFormatIndex); + +pub struct FormatRegistry { + /// Map (immediate kinds names, number of values, has varargs) to an instruction format index + /// in the actual map. + sig_to_index: HashMap<(Vec, usize, bool), InstructionFormatIndex>, + map: PrimaryMap, + name_set: HashSet<&'static str>, +} + +impl FormatRegistry { + pub fn new() -> Self { + Self { + sig_to_index: HashMap::new(), + map: PrimaryMap::new(), + name_set: HashSet::new(), + } + } + + /// Find an existing instruction format that matches the given lists of instruction inputs and + /// outputs. + pub fn lookup(&self, operands_in: &Vec) -> InstructionFormatIndex { + let mut imm_keys = Vec::new(); + let mut num_values = 0; + let mut has_varargs = false; + + for operand in operands_in.iter() { + if operand.is_value() { + num_values += 1; + } + has_varargs = has_varargs || operand.is_varargs(); + if let Some(imm_key) = operand.kind.imm_key() { + imm_keys.push(imm_key); + } + } + + let sig = (imm_keys, num_values, has_varargs); + *self + .sig_to_index + .get(&sig) + .expect("unknown InstructionFormat; please define it in shared/formats.rs first") + } + + pub fn get(&self, index: InstructionFormatIndex) -> &InstructionFormat { + self.map.get(index).unwrap() + } + + pub fn insert(&mut self, inst_format: InstructionFormatBuilder) { + let name = &inst_format.name; + if !self.name_set.insert(name) { + panic!( + "Trying to add an InstructionFormat named {}, but it already exists!", + name + ); + } + + let format = inst_format.finish(); + + // Compute key. + let imm_keys = format + .imm_fields + .iter() + .map(|field| field.kind.imm_key().unwrap()) + .collect(); + let key = (imm_keys, format.num_value_operands, format.has_value_list); + + let index = self.map.push(format); + if let Some(already_inserted) = self.sig_to_index.insert(key, index) { + panic!( + "duplicate InstructionFormat: trying to insert '{}' while '{}' already has the same structure.", + self.map.get(index).unwrap().name, + self.map.get(already_inserted).unwrap().name + ); + } + } + + pub fn iter(&self) -> slice::Iter { + self.map.values() + } +} diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/inst.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/inst.rs new file mode 100644 index 000000000000..4199d6424d75 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/inst.rs @@ -0,0 +1,458 @@ +use crate::cdsl::camel_case; +use crate::cdsl::formats::{FormatRegistry, InstructionFormat, InstructionFormatIndex}; +use crate::cdsl::operands::Operand; +use crate::cdsl::type_inference::Constraint; +use crate::cdsl::typevar::TypeVar; + +use std::fmt; +use std::slice; + +/// Every instruction must belong to exactly one instruction group. A given +/// target architecture can support instructions from multiple groups, and it +/// does not necessarily support all instructions in a group. +pub struct InstructionGroup { + _name: &'static str, + _doc: &'static str, + instructions: Vec, +} + +impl InstructionGroup { + pub fn new(name: &'static str, doc: &'static str) -> Self { + Self { + _name: name, + _doc: doc, + instructions: Vec::new(), + } + } + + pub fn push(&mut self, inst: Instruction) { + self.instructions.push(inst); + } + + pub fn iter(&self) -> slice::Iter { + self.instructions.iter() + } +} + +pub struct PolymorphicInfo { + pub use_typevar_operand: bool, + pub ctrl_typevar: TypeVar, + pub other_typevars: Vec, +} + +pub struct Instruction { + /// Instruction mnemonic, also becomes opcode name. + pub name: &'static str, + pub camel_name: String, + + /// Documentation string. + doc: &'static str, + + /// Input operands. This can be a mix of SSA value operands and other operand kinds. + pub operands_in: Vec, + /// Output operands. The output operands must be SSA values or `variable_args`. + pub operands_out: Vec, + /// Instruction-specific TypeConstraints. + _constraints: Vec, + + /// Instruction format, automatically derived from the input operands. + pub format: InstructionFormatIndex, + + /// One of the input or output operands is a free type variable. None if the instruction is not + /// polymorphic, set otherwise. + pub polymorphic_info: Option, + + pub value_opnums: Vec, + pub value_results: Vec, + pub imm_opnums: Vec, + + /// True for instructions that terminate the EBB. + pub is_terminator: bool, + /// True for all branch or jump instructions. + pub is_branch: bool, + /// True for all indirect branch or jump instructions.', + pub is_indirect_branch: bool, + /// Is this a call instruction? + pub is_call: bool, + /// Is this a return instruction? + pub is_return: bool, + /// Is this a ghost instruction? + pub is_ghost: bool, + /// Can this instruction read from memory? + pub can_load: bool, + /// Can this instruction write to memory? + pub can_store: bool, + /// Can this instruction cause a trap? + pub can_trap: bool, + /// Does this instruction have other side effects besides can_* flags? + pub other_side_effects: bool, + /// Does this instruction write to CPU flags? + pub writes_cpu_flags: bool, +} + +impl Instruction { + pub fn snake_name(&self) -> &'static str { + if self.name == "return" { + "return_" + } else { + self.name + } + } + + pub fn doc_comment_first_line(&self) -> &'static str { + for line in self.doc.split("\n") { + let stripped = line.trim(); + if stripped.len() > 0 { + return stripped; + } + } + "" + } +} + +impl fmt::Display for Instruction { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + if self.operands_out.len() > 0 { + let operands_out = self + .operands_out + .iter() + .map(|op| op.name) + .collect::>() + .join(", "); + fmt.write_str(&operands_out)?; + fmt.write_str(" = ")?; + } + + fmt.write_str(self.name)?; + + if self.operands_in.len() > 0 { + let operands_in = self + .operands_in + .iter() + .map(|op| op.name) + .collect::>() + .join(", "); + fmt.write_str(" ")?; + fmt.write_str(&operands_in)?; + } + + Ok(()) + } +} + +pub struct InstructionBuilder { + name: &'static str, + doc: &'static str, + operands_in: Option>, + operands_out: Option>, + constraints: Option>, + + // See Instruction comments for the meaning of these fields. + is_terminator: bool, + is_branch: bool, + is_indirect_branch: bool, + is_call: bool, + is_return: bool, + is_ghost: bool, + can_load: bool, + can_store: bool, + can_trap: bool, + other_side_effects: bool, +} + +impl InstructionBuilder { + pub fn new(name: &'static str, doc: &'static str) -> Self { + Self { + name, + doc, + operands_in: None, + operands_out: None, + constraints: None, + + is_terminator: false, + is_branch: false, + is_indirect_branch: false, + is_call: false, + is_return: false, + is_ghost: false, + can_load: false, + can_store: false, + can_trap: false, + other_side_effects: false, + } + } + + pub fn operands_in(mut self, operands: Vec<&Operand>) -> Self { + assert!(self.operands_in.is_none()); + self.operands_in = Some(operands.iter().map(|x| (*x).clone()).collect()); + self + } + pub fn operands_out(mut self, operands: Vec<&Operand>) -> Self { + assert!(self.operands_out.is_none()); + self.operands_out = Some(operands.iter().map(|x| (*x).clone()).collect()); + self + } + pub fn constraints(mut self, constraints: Vec) -> Self { + assert!(self.constraints.is_none()); + self.constraints = Some(constraints); + self + } + + pub fn is_terminator(mut self, val: bool) -> Self { + self.is_terminator = val; + self + } + pub fn is_branch(mut self, val: bool) -> Self { + self.is_branch = val; + self + } + pub fn is_indirect_branch(mut self, val: bool) -> Self { + self.is_indirect_branch = val; + self + } + pub fn is_call(mut self, val: bool) -> Self { + self.is_call = val; + self + } + pub fn is_return(mut self, val: bool) -> Self { + self.is_return = val; + self + } + pub fn is_ghost(mut self, val: bool) -> Self { + self.is_ghost = val; + self + } + pub fn can_load(mut self, val: bool) -> Self { + self.can_load = val; + self + } + pub fn can_store(mut self, val: bool) -> Self { + self.can_store = val; + self + } + pub fn can_trap(mut self, val: bool) -> Self { + self.can_trap = val; + self + } + pub fn other_side_effects(mut self, val: bool) -> Self { + self.other_side_effects = val; + self + } + + pub fn finish(self, format_registry: &FormatRegistry) -> Instruction { + let operands_in = self.operands_in.unwrap_or_else(Vec::new); + let operands_out = self.operands_out.unwrap_or_else(Vec::new); + + let format_index = format_registry.lookup(&operands_in); + + let mut value_opnums = Vec::new(); + let mut imm_opnums = Vec::new(); + for (i, op) in operands_in.iter().enumerate() { + if op.is_value() { + value_opnums.push(i); + } else if op.is_immediate() { + imm_opnums.push(i); + } else { + assert!(op.is_varargs()); + } + } + + let mut value_results = Vec::new(); + for (i, op) in operands_out.iter().enumerate() { + if op.is_value() { + value_results.push(i); + } + } + + let format = format_registry.get(format_index); + let polymorphic_info = + verify_polymorphic(&operands_in, &operands_out, &format, &value_opnums); + + // Infer from output operands whether an instruciton clobbers CPU flags or not. + let writes_cpu_flags = operands_out.iter().any(|op| op.is_cpu_flags()); + + Instruction { + name: self.name, + camel_name: camel_case(self.name), + doc: self.doc, + operands_in, + operands_out, + _constraints: self.constraints.unwrap_or_else(Vec::new), + format: format_index, + polymorphic_info, + value_opnums, + value_results, + imm_opnums, + is_terminator: self.is_terminator, + is_branch: self.is_branch, + is_indirect_branch: self.is_indirect_branch, + is_call: self.is_call, + is_return: self.is_return, + is_ghost: self.is_ghost, + can_load: self.can_load, + can_store: self.can_store, + can_trap: self.can_trap, + other_side_effects: self.other_side_effects, + writes_cpu_flags, + } + } +} + +/// Check if this instruction is polymorphic, and verify its use of type variables. +fn verify_polymorphic( + operands_in: &Vec, + operands_out: &Vec, + format: &InstructionFormat, + value_opnums: &Vec, +) -> Option { + // The instruction is polymorphic if it has one free input or output operand. + let is_polymorphic = operands_in + .iter() + .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()) + || operands_out + .iter() + .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()); + + if !is_polymorphic { + return None; + } + + // Verify the use of type variables. + let mut use_typevar_operand = false; + let mut ctrl_typevar = None; + let mut other_typevars = None; + let mut maybe_error_message = None; + + let tv_op = format.typevar_operand; + if let Some(tv_op) = tv_op { + if tv_op < value_opnums.len() { + let op_num = value_opnums[tv_op]; + let tv = operands_in[op_num].type_var().unwrap(); + let free_typevar = tv.free_typevar(); + if (free_typevar.is_some() && tv == &free_typevar.unwrap()) + || !tv.singleton_type().is_none() + { + match verify_ctrl_typevar(tv, &value_opnums, &operands_in, &operands_out) { + Ok(typevars) => { + other_typevars = Some(typevars); + ctrl_typevar = Some(tv.clone()); + use_typevar_operand = true; + } + Err(error_message) => { + maybe_error_message = Some(error_message); + } + } + } + } + }; + + if !use_typevar_operand { + if operands_out.len() == 0 { + match maybe_error_message { + Some(msg) => panic!(msg), + None => panic!("typevar_operand must be a free type variable"), + } + } + + let tv = operands_out[0].type_var().unwrap(); + let free_typevar = tv.free_typevar(); + if free_typevar.is_some() && tv != &free_typevar.unwrap() { + panic!("first result must be a free type variable"); + } + + other_typevars = + Some(verify_ctrl_typevar(tv, &value_opnums, &operands_in, &operands_out).unwrap()); + ctrl_typevar = Some(tv.clone()); + } + + // rustc is not capable to determine this statically, so enforce it with options. + assert!(ctrl_typevar.is_some()); + assert!(other_typevars.is_some()); + + Some(PolymorphicInfo { + use_typevar_operand, + ctrl_typevar: ctrl_typevar.unwrap(), + other_typevars: other_typevars.unwrap(), + }) +} + +/// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type +/// variable. +/// +/// All polymorhic inputs must either be derived from `ctrl_typevar` or be independent free type +/// variables only used once. +/// +/// All polymorphic results must be derived from `ctrl_typevar`. +/// +/// Return a vector of other type variables used, or panics. +fn verify_ctrl_typevar( + ctrl_typevar: &TypeVar, + value_opnums: &Vec, + operands_in: &Vec, + operands_out: &Vec, +) -> Result, String> { + let mut other_typevars = Vec::new(); + + // Check value inputs. + for &op_num in value_opnums { + let typ = operands_in[op_num].type_var(); + + let tv = if let Some(typ) = typ { + typ.free_typevar() + } else { + None + }; + + // Non-polymorphic or derived from ctrl_typevar is OK. + let tv = match tv { + Some(tv) => { + if &tv == ctrl_typevar { + continue; + } + tv + } + None => continue, + }; + + // No other derived typevars allowed. + if typ.is_some() && typ.unwrap() != &tv { + return Err(format!( + "{:?}: type variable {} must be derived from {:?}", + operands_in[op_num], + typ.unwrap().name, + ctrl_typevar + )); + } + + // Other free type variables can only be used once each. + for other_tv in &other_typevars { + if &tv == other_tv { + return Err(format!( + "type variable {} can't be used more than once", + tv.name + )); + } + } + + other_typevars.push(tv); + } + + // Check outputs. + for result in operands_out { + if !result.is_value() { + continue; + } + + let typ = result.type_var().unwrap(); + let tv = typ.free_typevar(); + + // Non-polymorphic or derived form ctrl_typevar is OK. + if tv.is_none() || &tv.unwrap() == ctrl_typevar { + continue; + } + + return Err("type variable in output not derived from ctrl_typevar".into()); + } + + Ok(other_typevars) +} diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs index 86b40a12c392..1091f6db8055 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs @@ -1,16 +1,24 @@ -use super::regs::IsaRegs; -use super::settings::SettingGroup; +use crate::cdsl::inst::InstructionGroup; +use crate::cdsl::regs::IsaRegs; +use crate::cdsl::settings::SettingGroup; pub struct TargetIsa { pub name: &'static str, + pub instructions: InstructionGroup, pub settings: SettingGroup, pub regs: IsaRegs, } impl TargetIsa { - pub fn new(name: &'static str, settings: SettingGroup, regs: IsaRegs) -> Self { + pub fn new( + name: &'static str, + instructions: InstructionGroup, + settings: SettingGroup, + regs: IsaRegs, + ) -> Self { Self { name, + instructions, settings, regs, } diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs index 87c615d70e85..540370624acc 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs @@ -3,10 +3,15 @@ //! This module defines the classes that are used to define Cranelift //! instructions and other entities. +pub mod formats; +pub mod inst; pub mod isa; +pub mod operands; pub mod regs; pub mod settings; +pub mod type_inference; pub mod types; +pub mod typevar; /// A macro that converts boolean settings into predicates to look more natural. #[macro_export] diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/operands.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/operands.rs new file mode 100644 index 000000000000..f460225bfe57 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/operands.rs @@ -0,0 +1,285 @@ +use std::collections::HashMap; + +use crate::cdsl::camel_case; +use crate::cdsl::typevar::TypeVar; + +/// An instruction operand can be an *immediate*, an *SSA value*, or an *entity reference*. The +/// type of the operand is one of: +/// +/// 1. A `ValueType` instance indicates an SSA value operand with a concrete type. +/// +/// 2. A `TypeVar` instance indicates an SSA value operand, and the instruction is polymorphic over +/// the possible concrete types that the type variable can assume. +/// +/// 3. An `ImmediateKind` instance indicates an immediate operand whose value is encoded in the +/// instruction itself rather than being passed as an SSA value. +/// +/// 4. An `EntityRefKind` instance indicates an operand that references another entity in the +/// function, typically something declared in the function preamble. +#[derive(Clone, Debug)] +pub struct Operand { + pub name: &'static str, + pub doc: Option, + pub kind: OperandKind, +} + +impl Operand { + pub fn is_value(&self) -> bool { + match self.kind.fields { + OperandKindFields::TypeVar(_) => true, + _ => false, + } + } + + pub fn type_var(&self) -> Option<&TypeVar> { + match &self.kind.fields { + OperandKindFields::TypeVar(typevar) => Some(typevar), + _ => None, + } + } + + pub fn is_varargs(&self) -> bool { + match self.kind.fields { + OperandKindFields::VariableArgs => true, + _ => false, + } + } + + /// Returns true if the operand has an immediate kind or is an EntityRef. + // TODO inherited name from the python, rename to is_immediate_or_entityref later. + pub fn is_immediate(&self) -> bool { + match self.kind.fields { + OperandKindFields::ImmEnum(_) + | OperandKindFields::ImmValue + | OperandKindFields::EntityRef => true, + _ => false, + } + } + + /// Returns true if the operand has an immediate kind. + pub fn is_pure_immediate(&self) -> bool { + match self.kind.fields { + OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => true, + _ => false, + } + } + + pub fn is_cpu_flags(&self) -> bool { + match &self.kind.fields { + OperandKindFields::TypeVar(type_var) + if type_var.name == "iflags" || type_var.name == "fflags" => + { + true + } + _ => false, + } + } +} + +pub struct OperandBuilder { + name: &'static str, + doc: Option, + kind: OperandKind, +} + +impl OperandBuilder { + pub fn new(name: &'static str, kind: OperandKind) -> Self { + Self { + name, + doc: None, + kind, + } + } + pub fn doc(mut self, doc: impl Into) -> Self { + assert!(self.doc.is_none()); + self.doc = Some(doc.into()); + self + } + pub fn finish(self) -> Operand { + let doc = match self.doc { + Some(doc) => Some(doc), + None => match &self.kind.fields { + OperandKindFields::TypeVar(tvar) => Some(tvar.doc.clone()), + _ => self.kind.doc.clone(), + }, + }; + + Operand { + name: self.name, + doc, + kind: self.kind, + } + } +} + +type EnumValues = HashMap<&'static str, &'static str>; + +#[derive(Clone, Debug)] +pub enum OperandKindFields { + EntityRef, + VariableArgs, + ImmValue, + ImmEnum(EnumValues), + TypeVar(TypeVar), +} + +#[derive(Clone, Debug)] +pub struct OperandKind { + pub name: &'static str, + + doc: Option, + + pub default_member: Option<&'static str>, + + /// The camel-cased name of an operand kind is also the Rust type used to represent it. + pub rust_type: String, + + fields: OperandKindFields, +} + +impl OperandKind { + pub fn imm_key(&self) -> Option { + match self.fields { + OperandKindFields::ImmEnum(_) + | OperandKindFields::ImmValue + | OperandKindFields::EntityRef => Some(self.name.to_string()), + _ => None, + } + } + + pub fn type_var(&self) -> TypeVar { + match &self.fields { + OperandKindFields::TypeVar(tvar) => tvar.clone(), + _ => panic!("not a typevar"), + } + } +} + +pub struct OperandKindBuilder { + name: &'static str, + + doc: Option, + + default_member: Option<&'static str>, + + /// The camel-cased name of an operand kind is also the Rust type used to represent it. + rust_type: Option, + + fields: OperandKindFields, +} + +impl OperandKindBuilder { + pub fn new(name: &'static str, fields: OperandKindFields) -> Self { + Self { + name, + doc: None, + default_member: None, + rust_type: None, + fields, + } + } + + pub fn new_imm(name: &'static str) -> Self { + Self { + name, + doc: None, + default_member: None, + rust_type: None, + fields: OperandKindFields::ImmValue, + } + } + + pub fn new_enum(name: &'static str, values: EnumValues) -> Self { + Self { + name, + doc: None, + default_member: None, + rust_type: None, + fields: OperandKindFields::ImmEnum(values), + } + } + + pub fn doc(mut self, doc: &'static str) -> Self { + assert!(self.doc.is_none()); + self.doc = Some(doc.to_string()); + self + } + pub fn default_member(mut self, default_member: &'static str) -> Self { + assert!(self.default_member.is_none()); + self.default_member = Some(default_member); + self + } + pub fn rust_type(mut self, rust_type: &'static str) -> Self { + assert!(self.rust_type.is_none()); + self.rust_type = Some(rust_type.to_string()); + self + } + + pub fn finish(self) -> OperandKind { + let default_member = match self.default_member { + Some(default_member) => Some(default_member), + None => match &self.fields { + OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => Some("imm"), + OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => Some(self.name), + OperandKindFields::VariableArgs => None, + }, + }; + + let rust_type = match self.rust_type { + Some(rust_type) => rust_type.to_string(), + None => match &self.fields { + OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => { + format!("ir::immediates::{}", camel_case(self.name)) + } + OperandKindFields::VariableArgs => "&[Value]".to_string(), + OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => { + format!("ir::{}", camel_case(self.name)) + } + }, + }; + + let doc = match self.doc { + Some(doc) => Some(doc), + None => match &self.fields { + OperandKindFields::TypeVar(type_var) => Some(type_var.doc.clone()), + OperandKindFields::ImmEnum(_) + | OperandKindFields::ImmValue + | OperandKindFields::EntityRef + | OperandKindFields::VariableArgs => None, + }, + }; + + OperandKind { + name: self.name, + doc, + default_member, + rust_type, + fields: self.fields, + } + } +} + +impl Into for &TypeVar { + fn into(self) -> OperandKind { + OperandKindBuilder::new("value", OperandKindFields::TypeVar(self.into())).finish() + } +} +impl Into for &OperandKind { + fn into(self) -> OperandKind { + self.clone() + } +} + +/// Helper to create an operand in definitions files. +pub fn create_operand(name: &'static str, kind: impl Into) -> Operand { + OperandBuilder::new(name, kind.into()).finish() +} + +/// Helper to create an operand with a documentation in definitions files. +pub fn create_operand_doc( + name: &'static str, + kind: impl Into, + doc: &'static str, +) -> Operand { + OperandBuilder::new(name, kind.into()).doc(doc).finish() +} diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs new file mode 100644 index 000000000000..de104f4b4739 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs @@ -0,0 +1,5 @@ +use crate::cdsl::typevar::TypeVar; + +pub enum Constraint { + WiderOrEq(TypeVar, TypeVar), +} diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs index 898c048b8bec..a8aa4020d85b 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs @@ -21,13 +21,13 @@ static LANE_BASE: u8 = 0x70; // Rust name prefix used for the `rust_name` method. static _RUST_NAME_PREFIX: &'static str = "ir::types::"; -// ValueType variants (i8, i32, ...) are provided in `base::types.rs`. +// ValueType variants (i8, i32, ...) are provided in `shared::types.rs`. /// A concrete SSA value type. /// /// All SSA values have a type that is described by an instance of `ValueType` /// or one of its subclasses. -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum ValueType { BV(BVType), Lane(LaneType), @@ -90,7 +90,7 @@ impl ValueType { } /// Return the name of this type for generated Rust source files. - pub fn _rust_name(&self) -> String { + pub fn rust_name(&self) -> String { format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase()) } @@ -147,7 +147,7 @@ impl From for ValueType { } /// A concrete scalar type that can appear as a vector lane too. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub enum LaneType { BoolType(shared_types::Bool), FloatType(shared_types::Float), @@ -205,6 +205,43 @@ impl LaneType { LaneType::FloatType(shared_types::Float::F64) => 10, } } + + pub fn bool_from_bits(num_bits: u16) -> LaneType { + LaneType::BoolType(match num_bits { + 1 => shared_types::Bool::B1, + 8 => shared_types::Bool::B8, + 16 => shared_types::Bool::B16, + 32 => shared_types::Bool::B32, + 64 => shared_types::Bool::B64, + _ => unreachable!("unxpected num bits for bool"), + }) + } + + pub fn int_from_bits(num_bits: u16) -> LaneType { + LaneType::IntType(match num_bits { + 8 => shared_types::Int::I8, + 16 => shared_types::Int::I16, + 32 => shared_types::Int::I32, + 64 => shared_types::Int::I64, + _ => unreachable!("unxpected num bits for int"), + }) + } + + pub fn float_from_bits(num_bits: u16) -> LaneType { + LaneType::FloatType(match num_bits { + 32 => shared_types::Float::F32, + 64 => shared_types::Float::F64, + _ => unreachable!("unxpected num bits for float"), + }) + } + + pub fn by(&self, lanes: u16) -> ValueType { + if lanes == 1 { + (*self).into() + } else { + ValueType::Vector(VectorType::new(*self, lanes.into())) + } + } } impl fmt::Display for LaneType { @@ -290,6 +327,7 @@ impl Iterator for LaneTypeIterator { /// /// A vector type has a lane type which is an instance of `LaneType`, /// and a positive number of lanes. +#[derive(Clone, PartialEq)] pub struct VectorType { base: LaneType, lanes: u64, @@ -320,6 +358,11 @@ impl VectorType { self.lanes } + /// Return the lane type. + pub fn lane_type(&self) -> LaneType { + self.base + } + /// Find the unique number associated with this vector type. /// /// Vector types are encoded with the lane type in the low 4 bits and @@ -350,14 +393,15 @@ impl fmt::Debug for VectorType { } /// A flat bitvector type. Used for semantics description only. +#[derive(Clone, PartialEq)] pub struct BVType { bits: u64, } impl BVType { /// Initialize a new bitvector type with `n` bits. - pub fn _new(bits: u64) -> Self { - Self { bits } + pub fn new(bits: u16) -> Self { + Self { bits: bits.into() } } /// Return a string containing the documentation comment for this bitvector type. @@ -386,7 +430,7 @@ impl fmt::Debug for BVType { /// A concrete scalar type that is neither a vector nor a lane type. /// /// Special types cannot be used to form vectors. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum SpecialType { Flag(shared_types::Flag), } diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs new file mode 100644 index 000000000000..d144eab48f14 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs @@ -0,0 +1,901 @@ +use std::collections::BTreeSet; +use std::iter::FromIterator; +use std::ops; +use std::rc::Rc; + +use crate::cdsl::types::{BVType, LaneType, SpecialType, ValueType}; + +const MAX_LANES: u16 = 256; +const MAX_BITS: u16 = 64; +const MAX_BITVEC: u16 = MAX_BITS * MAX_LANES; + +/// Type variables can be used in place of concrete types when defining +/// instructions. This makes the instructions *polymorphic*. +/// +/// A type variable is restricted to vary over a subset of the value types. +/// This subset is specified by a set of flags that control the permitted base +/// types and whether the type variable can assume scalar or vector types, or +/// both. +#[derive(Debug)] +pub struct TypeVarContent { + /// Short name of type variable used in instruction descriptions. + pub name: String, + + /// Documentation string. + pub doc: String, + + /// Type set associated to the type variable. + /// This field must remain private; use `get_typeset()` or `get_raw_typeset()` to get the + /// information you want. + type_set: Rc, + + pub base: Option, +} + +#[derive(Clone, Debug)] +pub struct TypeVar { + content: Rc, +} + +impl TypeVar { + pub fn new(name: impl Into, doc: impl Into, type_set: TypeSet) -> Self { + Self { + content: Rc::new(TypeVarContent { + name: name.into(), + doc: doc.into(), + type_set: Rc::new(type_set), + base: None, + }), + } + } + + pub fn new_singleton(value_type: ValueType) -> Self { + let (name, doc) = (value_type.to_string(), value_type.doc()); + let mut builder = TypeSetBuilder::new(); + + let (scalar_type, num_lanes) = match value_type { + ValueType::BV(bitvec_type) => { + let bits = bitvec_type.lane_bits() as RangeBound; + return TypeVar::new(name, doc, builder.bitvecs(bits..bits).finish()); + } + ValueType::Special(special_type) => { + return TypeVar::new(name, doc, builder.specials(vec![special_type]).finish()); + } + ValueType::Lane(lane_type) => (lane_type, 1), + ValueType::Vector(vec_type) => { + (vec_type.lane_type(), vec_type.lane_count() as RangeBound) + } + }; + + builder = builder.simd_lanes(num_lanes..num_lanes); + + let builder = match scalar_type { + LaneType::IntType(int_type) => { + let bits = int_type as RangeBound; + builder.ints(bits..bits) + } + LaneType::FloatType(float_type) => { + let bits = float_type as RangeBound; + builder.floats(bits..bits) + } + LaneType::BoolType(bool_type) => { + let bits = bool_type as RangeBound; + builder.bools(bits..bits) + } + }; + TypeVar::new(name, doc, builder.finish()) + } + + /// Returns this typevar's type set, maybe computing it from the parent. + fn get_typeset(&self) -> Rc { + // TODO Can this be done in a non-lazy way in derived() and we can remove this function and + // the one below? + match &self.content.base { + Some(base) => Rc::new(base.type_var.get_typeset().image(base.derived_func)), + None => self.content.type_set.clone(), + } + } + + /// Returns this typevar's type set, assuming this type var has no parent. + pub fn get_raw_typeset(&self) -> &TypeSet { + assert_eq!(self.content.type_set, self.get_typeset()); + &*self.content.type_set + } + + /// If the associated typeset has a single type return it. Otherwise return None. + pub fn singleton_type(&self) -> Option { + let type_set = self.get_typeset(); + if type_set.size() == 1 { + Some(type_set.get_singleton()) + } else { + None + } + } + + /// Get the free type variable controlling this one. + pub fn free_typevar(&self) -> Option { + match &self.content.base { + Some(base) => base.type_var.free_typevar(), + None => { + match self.singleton_type() { + // A singleton type isn't a proper free variable. + Some(_) => None, + None => Some(self.clone()), + } + } + } + } + + /// Create a type variable that is a function of another. + fn derived(&self, derived_func: DerivedFunc) -> TypeVar { + let ts = self.get_typeset(); + + // Safety checks to avoid over/underflows. + assert!(ts.specials.len() == 0, "can't derive from special types"); + match derived_func { + DerivedFunc::HalfWidth => { + assert!( + ts.ints.len() == 0 || *ts.ints.iter().min().unwrap() > 8, + "can't halve all integer types" + ); + assert!( + ts.floats.len() == 0 || *ts.floats.iter().min().unwrap() > 32, + "can't halve all float types" + ); + assert!( + ts.bools.len() == 0 || *ts.bools.iter().min().unwrap() > 8, + "can't halve all boolean types" + ); + } + DerivedFunc::DoubleWidth => { + assert!( + ts.ints.len() == 0 || *ts.ints.iter().max().unwrap() < MAX_BITS, + "can't double all integer types" + ); + assert!( + ts.floats.len() == 0 || *ts.floats.iter().max().unwrap() < MAX_BITS, + "can't double all float types" + ); + assert!( + ts.bools.len() == 0 || *ts.bools.iter().max().unwrap() < MAX_BITS, + "can't double all boolean types" + ); + } + DerivedFunc::HalfVector => { + assert!( + *ts.lanes.iter().min().unwrap() > 1, + "can't halve a scalar type" + ); + } + DerivedFunc::DoubleVector => { + assert!( + *ts.lanes.iter().max().unwrap() < MAX_LANES, + "can't double 256 lanes" + ); + } + DerivedFunc::LaneOf | DerivedFunc::ToBitVec | DerivedFunc::AsBool => { + /* no particular assertions */ + } + } + + return TypeVar { + content: Rc::new(TypeVarContent { + name: format!("{}({})", derived_func.name(), self.name), + doc: "".into(), + type_set: ts, + base: Some(TypeVarParent { + type_var: self.clone(), + derived_func, + }), + }), + }; + } + + pub fn lane_of(&self) -> TypeVar { + return self.derived(DerivedFunc::LaneOf); + } + pub fn as_bool(&self) -> TypeVar { + return self.derived(DerivedFunc::AsBool); + } + pub fn half_width(&self) -> TypeVar { + return self.derived(DerivedFunc::HalfWidth); + } + pub fn double_width(&self) -> TypeVar { + return self.derived(DerivedFunc::DoubleWidth); + } + pub fn half_vector(&self) -> TypeVar { + return self.derived(DerivedFunc::HalfVector); + } + pub fn double_vector(&self) -> TypeVar { + return self.derived(DerivedFunc::DoubleVector); + } + pub fn to_bitvec(&self) -> TypeVar { + return self.derived(DerivedFunc::ToBitVec); + } +} + +impl Into for &TypeVar { + fn into(self) -> TypeVar { + self.clone() + } +} +impl Into for ValueType { + fn into(self) -> TypeVar { + TypeVar::new_singleton(self) + } +} + +impl PartialEq for TypeVar { + fn eq(&self, other: &TypeVar) -> bool { + match (&self.content.base, &other.content.base) { + (Some(base1), Some(base2)) => base1.type_var.eq(&base2.type_var), + (None, None) => Rc::ptr_eq(&self.content, &other.content), + _ => false, + } + } +} + +impl ops::Deref for TypeVar { + type Target = TypeVarContent; + fn deref(&self) -> &Self::Target { + &*self.content + } +} + +#[derive(Clone, Copy, Debug)] +pub enum DerivedFunc { + LaneOf, + AsBool, + HalfWidth, + DoubleWidth, + HalfVector, + DoubleVector, + ToBitVec, +} + +impl DerivedFunc { + pub fn name(&self) -> &'static str { + match self { + DerivedFunc::LaneOf => "lane_of", + DerivedFunc::AsBool => "as_bool", + DerivedFunc::HalfWidth => "half_width", + DerivedFunc::DoubleWidth => "double_width", + DerivedFunc::HalfVector => "half_vector", + DerivedFunc::DoubleVector => "double_vector", + DerivedFunc::ToBitVec => "to_bitvec", + } + } +} + +#[derive(Debug)] +pub struct TypeVarParent { + pub type_var: TypeVar, + pub derived_func: DerivedFunc, +} + +/// A set of types. +/// +/// We don't allow arbitrary subsets of types, but use a parametrized approach +/// instead. +/// +/// Objects of this class can be used as dictionary keys. +/// +/// Parametrized type sets are specified in terms of ranges: +/// - The permitted range of vector lanes, where 1 indicates a scalar type. +/// - The permitted range of integer types. +/// - The permitted range of floating point types, and +/// - The permitted range of boolean types. +/// +/// The ranges are inclusive from smallest bit-width to largest bit-width. +/// +/// Finally, a type set can contain special types (derived from `SpecialType`) +/// which can't appear as lane types. + +type RangeBound = u16; +type Range = ops::Range; +type NumSet = BTreeSet; + +macro_rules! num_set { + ($($expr:expr),*) => { + NumSet::from_iter(vec![$($expr),*]) + }; +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TypeSet { + pub lanes: NumSet, + pub ints: NumSet, + pub floats: NumSet, + pub bools: NumSet, + pub bitvecs: NumSet, + pub specials: Vec, +} + +impl TypeSet { + fn new( + lanes: NumSet, + ints: NumSet, + floats: NumSet, + bools: NumSet, + bitvecs: NumSet, + specials: Vec, + ) -> Self { + Self { + lanes, + ints, + floats, + bools, + bitvecs, + specials, + } + } + + /// Return the number of concrete types represented by this typeset. + fn size(&self) -> usize { + self.lanes.len() + * (self.ints.len() + self.floats.len() + self.bools.len() + self.bitvecs.len()) + + self.specials.len() + } + + /// Return the image of self across the derived function func. + fn image(&self, derived_func: DerivedFunc) -> TypeSet { + match derived_func { + DerivedFunc::LaneOf => self.lane_of(), + DerivedFunc::AsBool => self.as_bool(), + DerivedFunc::HalfWidth => self.half_width(), + DerivedFunc::DoubleWidth => self.double_width(), + DerivedFunc::HalfVector => self.half_vector(), + DerivedFunc::DoubleVector => self.double_vector(), + DerivedFunc::ToBitVec => self.to_bitvec(), + } + } + + /// Return a TypeSet describing the image of self across lane_of. + fn lane_of(&self) -> TypeSet { + let mut copy = self.clone(); + copy.lanes = num_set![1]; + copy.bitvecs = NumSet::new(); + copy + } + + /// Return a TypeSet describing the image of self across as_bool. + fn as_bool(&self) -> TypeSet { + let mut copy = self.clone(); + copy.ints = NumSet::new(); + copy.floats = NumSet::new(); + copy.bitvecs = NumSet::new(); + if (&self.lanes - &num_set![1]).len() > 0 { + copy.bools = &self.ints | &self.floats; + copy.bools = ©.bools | &self.bools; + } + if self.lanes.contains(&1) { + copy.bools.insert(1); + } + copy + } + + /// Return a TypeSet describing the image of self across halfwidth. + fn half_width(&self) -> TypeSet { + let mut copy = self.clone(); + copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x > 8).map(|&x| x / 2)); + copy.floats = NumSet::from_iter(self.floats.iter().filter(|&&x| x > 32).map(|&x| x / 2)); + copy.bools = NumSet::from_iter(self.bools.iter().filter(|&&x| x > 8).map(|&x| x / 2)); + copy.bitvecs = NumSet::from_iter(self.bitvecs.iter().filter(|&&x| x > 1).map(|&x| x / 2)); + copy.specials = Vec::new(); + copy + } + + /// Return a TypeSet describing the image of self across doublewidth. + fn double_width(&self) -> TypeSet { + let mut copy = self.clone(); + copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x < MAX_BITS).map(|&x| x * 2)); + copy.floats = NumSet::from_iter( + self.floats + .iter() + .filter(|&&x| x < MAX_BITS) + .map(|&x| x * 2), + ); + copy.bools = NumSet::from_iter( + self.bools + .iter() + .filter(|&&x| x < MAX_BITS) + .map(|&x| x * 2) + .filter(legal_bool), + ); + copy.bitvecs = NumSet::from_iter( + self.bitvecs + .iter() + .filter(|&&x| x < MAX_BITVEC) + .map(|&x| x * 2), + ); + copy.specials = Vec::new(); + copy + } + + /// Return a TypeSet describing the image of self across halfvector. + fn half_vector(&self) -> TypeSet { + let mut copy = self.clone(); + copy.bitvecs = NumSet::new(); + copy.lanes = NumSet::from_iter(self.lanes.iter().filter(|&&x| x > 1).map(|&x| x / 2)); + copy.specials = Vec::new(); + copy + } + + /// Return a TypeSet describing the image of self across doublevector. + fn double_vector(&self) -> TypeSet { + let mut copy = self.clone(); + copy.bitvecs = NumSet::new(); + copy.lanes = NumSet::from_iter( + self.lanes + .iter() + .filter(|&&x| x < MAX_LANES) + .map(|&x| x * 2), + ); + copy.specials = Vec::new(); + copy + } + + /// Return a TypeSet describing the image of self across to_bitvec. + fn to_bitvec(&self) -> TypeSet { + assert!(self.bitvecs.is_empty()); + let all_scalars = &(&self.ints | &self.floats) | &self.bools; + + let mut copy = self.clone(); + copy.lanes = num_set![1]; + copy.ints = NumSet::new(); + copy.bools = NumSet::new(); + copy.floats = NumSet::new(); + copy.bitvecs = self + .lanes + .iter() + .cycle() + .zip(all_scalars.iter()) + .map(|(num_lanes, lane_width)| num_lanes * lane_width) + .collect(); + + copy.specials = Vec::new(); + copy + } + + fn concrete_types(&self) -> Vec { + let mut ret = Vec::new(); + for &num_lanes in &self.lanes { + for &bits in &self.ints { + ret.push(LaneType::int_from_bits(bits).by(num_lanes)); + } + for &bits in &self.floats { + ret.push(LaneType::float_from_bits(bits).by(num_lanes)); + } + for &bits in &self.bools { + ret.push(LaneType::bool_from_bits(bits).by(num_lanes)); + } + for &bits in &self.bitvecs { + assert_eq!(num_lanes, 1); + ret.push(BVType::new(bits).into()); + } + } + for &special in &self.specials { + ret.push(special.into()); + } + ret + } + + /// Return the singleton type represented by self. Can only call on typesets containing 1 type. + fn get_singleton(&self) -> ValueType { + let mut types = self.concrete_types(); + assert_eq!(types.len(), 1); + return types.remove(0); + } +} + +pub struct TypeSetBuilder { + ints: Interval, + floats: Interval, + bools: Interval, + bitvecs: Interval, + includes_scalars: bool, + simd_lanes: Interval, + specials: Vec, +} + +impl TypeSetBuilder { + pub fn new() -> Self { + Self { + ints: Interval::None, + floats: Interval::None, + bools: Interval::None, + bitvecs: Interval::None, + includes_scalars: true, + simd_lanes: Interval::None, + specials: Vec::new(), + } + } + + pub fn ints(mut self, interval: impl Into) -> Self { + assert!(self.ints == Interval::None); + self.ints = interval.into(); + self + } + pub fn floats(mut self, interval: impl Into) -> Self { + assert!(self.floats == Interval::None); + self.floats = interval.into(); + self + } + pub fn bools(mut self, interval: impl Into) -> Self { + assert!(self.bools == Interval::None); + self.bools = interval.into(); + self + } + pub fn includes_scalars(mut self, includes_scalars: bool) -> Self { + self.includes_scalars = includes_scalars; + self + } + pub fn simd_lanes(mut self, interval: impl Into) -> Self { + assert!(self.simd_lanes == Interval::None); + self.simd_lanes = interval.into(); + self + } + pub fn bitvecs(mut self, interval: impl Into) -> Self { + assert!(self.bitvecs == Interval::None); + self.bitvecs = interval.into(); + self + } + pub fn specials(mut self, specials: Vec) -> Self { + assert!(self.specials.is_empty()); + self.specials = specials; + self + } + + pub fn finish(self) -> TypeSet { + let min_lanes = if self.includes_scalars { 1 } else { 2 }; +; + let bools = range_to_set(self.bools.to_range(1..MAX_BITS, None)) + .into_iter() + .filter(legal_bool) + .collect(); + + TypeSet::new( + range_to_set(self.simd_lanes.to_range(min_lanes..MAX_LANES, Some(1))), + range_to_set(self.ints.to_range(8..MAX_BITS, None)), + range_to_set(self.floats.to_range(32..64, None)), + bools, + range_to_set(self.bitvecs.to_range(1..MAX_BITVEC, None)), + self.specials, + ) + } +} + +#[derive(PartialEq)] +pub enum Interval { + None, + All, + Range(Range), +} + +impl Interval { + fn to_range(&self, full_range: Range, default: Option) -> Option { + match self { + Interval::None => { + if let Some(default_val) = default { + Some(default_val..default_val) + } else { + None + } + } + + Interval::All => Some(full_range), + + Interval::Range(range) => { + let (low, high) = (range.start, range.end); + assert!(low.is_power_of_two()); + assert!(high.is_power_of_two()); + assert!(low <= high); + assert!(low >= full_range.start); + assert!(high <= full_range.end); + Some(low..high) + } + } + } +} + +impl Into for Range { + fn into(self) -> Interval { + Interval::Range(self) + } +} + +fn legal_bool(bits: &RangeBound) -> bool { + // Only allow legal bit widths for bool types. + *bits == 1 || (*bits >= 8 && *bits <= MAX_BITS && bits.is_power_of_two()) +} + +/// Generates a set with all the powers of two included in the range. +fn range_to_set(range: Option) -> NumSet { + let mut set = NumSet::new(); + + let (low, high) = match range { + Some(range) => (range.start, range.end), + None => return set, + }; + + assert!(low.is_power_of_two()); + assert!(high.is_power_of_two()); + assert!(low <= high); + + for i in low.trailing_zeros()..high.trailing_zeros() + 1 { + assert!(1 << i <= RangeBound::max_value()); + set.insert(1 << i); + } + set +} + +#[test] +fn test_typevar_builder() { + let type_set = TypeSetBuilder::new().ints(Interval::All).finish(); + assert_eq!(type_set.lanes, num_set![1]); + assert!(type_set.floats.is_empty()); + assert_eq!(type_set.ints, num_set![8, 16, 32, 64]); + assert!(type_set.bools.is_empty()); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); + + let type_set = TypeSetBuilder::new().bools(Interval::All).finish(); + assert_eq!(type_set.lanes, num_set![1]); + assert!(type_set.floats.is_empty()); + assert!(type_set.ints.is_empty()); + assert_eq!(type_set.bools, num_set![1, 8, 16, 32, 64]); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); + + let type_set = TypeSetBuilder::new().floats(Interval::All).finish(); + assert_eq!(type_set.lanes, num_set![1]); + assert_eq!(type_set.floats, num_set![32, 64]); + assert!(type_set.ints.is_empty()); + assert!(type_set.bools.is_empty()); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .finish(); + assert_eq!(type_set.lanes, num_set![2, 4, 8, 16, 32, 64, 128, 256]); + assert_eq!(type_set.floats, num_set![32, 64]); + assert!(type_set.ints.is_empty()); + assert!(type_set.bools.is_empty()); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .finish(); + assert_eq!(type_set.lanes, num_set![1, 2, 4, 8, 16, 32, 64, 128, 256]); + assert_eq!(type_set.floats, num_set![32, 64]); + assert!(type_set.ints.is_empty()); + assert!(type_set.bools.is_empty()); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); + + let type_set = TypeSetBuilder::new().ints(16..64).finish(); + assert_eq!(type_set.lanes, num_set![1]); + assert_eq!(type_set.ints, num_set![16, 32, 64]); + assert!(type_set.floats.is_empty()); + assert!(type_set.bools.is_empty()); + assert!(type_set.bitvecs.is_empty()); + assert!(type_set.specials.is_empty()); +} + +#[test] +#[should_panic] +fn test_typevar_builder_too_high_bound_panic() { + TypeSetBuilder::new().ints(16..2 * MAX_BITS).finish(); +} + +#[test] +#[should_panic] +fn test_typevar_builder_inverted_bounds_panic() { + TypeSetBuilder::new().ints(32..16).finish(); +} + +#[test] +fn test_as_bool() { + let a = TypeSetBuilder::new() + .simd_lanes(2..8) + .ints(8..8) + .floats(32..32) + .finish(); + assert_eq!( + a.lane_of(), + TypeSetBuilder::new().ints(8..8).floats(32..32).finish() + ); + + // Test as_bool with disjoint intervals. + let mut a_as_bool = TypeSetBuilder::new().simd_lanes(2..8).finish(); + a_as_bool.bools = num_set![8, 32]; + assert_eq!(a.as_bool(), a_as_bool); + + let b = TypeSetBuilder::new() + .simd_lanes(1..8) + .ints(8..8) + .floats(32..32) + .finish(); + let mut b_as_bool = TypeSetBuilder::new().simd_lanes(1..8).finish(); + b_as_bool.bools = num_set![1, 8, 32]; + assert_eq!(b.as_bool(), b_as_bool); +} + +#[test] +fn test_forward_images() { + let empty_set = TypeSetBuilder::new().finish(); + + // Half vector. + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(1..32) + .finish() + .half_vector(), + TypeSetBuilder::new().simd_lanes(1..16).finish() + ); + + // Double vector. + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(1..32) + .finish() + .double_vector(), + TypeSetBuilder::new().simd_lanes(2..64).finish() + ); + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(128..256) + .finish() + .double_vector(), + TypeSetBuilder::new().simd_lanes(256..256).finish() + ); + + // Half width. + assert_eq!( + TypeSetBuilder::new().ints(8..32).finish().half_width(), + TypeSetBuilder::new().ints(8..16).finish() + ); + assert_eq!( + TypeSetBuilder::new().floats(32..32).finish().half_width(), + empty_set + ); + assert_eq!( + TypeSetBuilder::new().floats(32..64).finish().half_width(), + TypeSetBuilder::new().floats(32..32).finish() + ); + assert_eq!( + TypeSetBuilder::new().bools(1..8).finish().half_width(), + empty_set + ); + assert_eq!( + TypeSetBuilder::new().bools(1..32).finish().half_width(), + TypeSetBuilder::new().bools(8..16).finish() + ); + + // Double width. + assert_eq!( + TypeSetBuilder::new().ints(8..32).finish().double_width(), + TypeSetBuilder::new().ints(16..64).finish() + ); + assert_eq!( + TypeSetBuilder::new().ints(32..64).finish().double_width(), + TypeSetBuilder::new().ints(64..64).finish() + ); + assert_eq!( + TypeSetBuilder::new().floats(32..32).finish().double_width(), + TypeSetBuilder::new().floats(64..64).finish() + ); + assert_eq!( + TypeSetBuilder::new().floats(32..64).finish().double_width(), + TypeSetBuilder::new().floats(64..64).finish() + ); + assert_eq!( + TypeSetBuilder::new().bools(1..16).finish().double_width(), + TypeSetBuilder::new().bools(16..32).finish() + ); + assert_eq!( + TypeSetBuilder::new().bools(32..64).finish().double_width(), + TypeSetBuilder::new().bools(64..64).finish() + ); +} + +#[test] +#[should_panic] +fn test_typeset_singleton_panic_nonsingleton_types() { + TypeSetBuilder::new() + .ints(8..8) + .floats(32..32) + .finish() + .get_singleton(); +} + +#[test] +#[should_panic] +fn test_typeset_singleton_panic_nonsingleton_lanes() { + TypeSetBuilder::new() + .simd_lanes(1..2) + .floats(32..32) + .finish() + .get_singleton(); +} + +#[test] +fn test_typeset_singleton() { + use crate::shared::types as shared_types; + assert_eq!( + TypeSetBuilder::new().ints(16..16).finish().get_singleton(), + ValueType::Lane(shared_types::Int::I16.into()) + ); + assert_eq!( + TypeSetBuilder::new() + .floats(64..64) + .finish() + .get_singleton(), + ValueType::Lane(shared_types::Float::F64.into()) + ); + assert_eq!( + TypeSetBuilder::new().bools(1..1).finish().get_singleton(), + ValueType::Lane(shared_types::Bool::B1.into()) + ); + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(4..4) + .ints(32..32) + .finish() + .get_singleton(), + LaneType::from(shared_types::Int::I32).by(4) + ); +} + +#[test] +fn test_typevar_functions() { + let x = TypeVar::new( + "x", + "i16 and up", + TypeSetBuilder::new().ints(16..64).finish(), + ); + assert_eq!(x.half_width().name, "half_width(x)"); + assert_eq!( + x.half_width().double_width().name, + "double_width(half_width(x))" + ); + + let x = TypeVar::new("x", "up to i32", TypeSetBuilder::new().ints(8..32).finish()); + assert_eq!(x.double_width().name, "double_width(x)"); +} + +#[test] +fn test_typevar_singleton() { + use crate::cdsl::types::VectorType; + use crate::shared::types as shared_types; + + // Test i32. + let typevar = + TypeVar::new_singleton(ValueType::Lane(LaneType::IntType(shared_types::Int::I32))); + assert_eq!(typevar.name, "i32"); + assert_eq!(typevar.type_set.ints, num_set![32]); + assert!(typevar.type_set.floats.is_empty()); + assert!(typevar.type_set.bools.is_empty()); + assert!(typevar.type_set.bitvecs.is_empty()); + assert!(typevar.type_set.specials.is_empty()); + assert_eq!(typevar.type_set.lanes, num_set![1]); + + // Test f32x4. + let typevar = TypeVar::new_singleton(ValueType::Vector(VectorType::new( + LaneType::FloatType(shared_types::Float::F32), + 4, + ))); + assert_eq!(typevar.name, "f32x4"); + assert!(typevar.type_set.ints.is_empty()); + assert_eq!(typevar.type_set.floats, num_set![32]); + assert_eq!(typevar.type_set.lanes, num_set![4]); + assert!(typevar.type_set.bools.is_empty()); + assert!(typevar.type_set.bitvecs.is_empty()); + assert!(typevar.type_set.specials.is_empty()); +} diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs index 3a75c7147a29..5e0fdac57bea 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs @@ -132,9 +132,9 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) { fmtln!(fmt, "}"); } -pub fn generate(isa: &TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> { +pub fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> { let mut fmt = Formatter::new(); gen_isa(&isa, &mut fmt); - fmt.update_file(format!("{}-{}.rs", base_filename, isa.name), out_dir)?; + fmt.update_file(filename, out_dir)?; Ok(()) } diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs b/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs index a3c97ebab8c4..b57e7a4f5111 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs @@ -1,16 +1,14 @@ use crate::cdsl::camel_case; -use crate::cdsl::isa::TargetIsa; use crate::cdsl::settings::{ BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting, }; use crate::constant_hash::{generate_table, simple_hash}; use crate::error; -use crate::shared; use crate::srcgen::{Formatter, Match}; -use crate::unique_table::UniqueTable; +use crate::unique_table::UniqueSeqTable; use std::collections::HashMap; -enum ParentGroup { +pub enum ParentGroup { None, Shared, } @@ -152,13 +150,9 @@ fn gen_getter(setting: &Setting, fmt: &mut Formatter) { fmt.indent(|fmt| { let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset)); for (i, v) in values.iter().enumerate() { - m.arm( - format!("{}", i), - vec![], - format!("{}::{}", ty, camel_case(v)), - ); + m.arm_no_fields(format!("{}", i), format!("{}::{}", ty, camel_case(v))); } - m.arm("_", vec![], "panic!(\"Invalid enum value\")"); + m.arm_no_fields("_", "panic!(\"Invalid enum value\")"); fmt.add_match(m); }); fmtln!(fmt, "}"); @@ -191,12 +185,12 @@ fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) { fmt.doc_comment("Get a view of the boolean predicates."); fmtln!( fmt, - "pub fn predicate_view(&self) -> ::settings::PredicateView {" + "pub fn predicate_view(&self) -> crate::settings::PredicateView {" ); fmt.indent(|fmt| { fmtln!( fmt, - "::settings::PredicateView::new(&self.bytes[{}..])", + "crate::settings::PredicateView::new(&self.bytes[{}..])", group.bool_start_byte_offset ); }); @@ -242,7 +236,7 @@ impl<'a> SettingOrPreset<'a> { /// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS. fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) { - let mut enum_table: UniqueTable<&'static str> = UniqueTable::new(); + let mut enum_table = UniqueSeqTable::new(); let mut descriptor_index_map: HashMap = HashMap::new(); @@ -445,17 +439,14 @@ fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) { gen_display(group, fmt); } -pub fn generate_common(filename: &str, out_dir: &str) -> Result { - let settings = shared::settings::generate(); +pub fn generate( + settings: &SettingGroup, + parent_group: ParentGroup, + filename: &str, + out_dir: &str, +) -> Result<(), error::Error> { let mut fmt = Formatter::new(); - gen_group(&settings, ParentGroup::None, &mut fmt); + gen_group(&settings, parent_group, &mut fmt); fmt.update_file(filename, out_dir)?; - Ok(settings) -} - -pub fn generate(isa: &TargetIsa, prefix: &str, out_dir: &str) -> Result<(), error::Error> { - let mut fmt = Formatter::new(); - gen_group(&isa.settings, ParentGroup::Shared, &mut fmt); - fmt.update_file(format!("{}-{}.rs", prefix, isa.name), out_dir)?; Ok(()) } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs index e3decd4da02e..8c32cdcdcd3a 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs @@ -1,6 +1,8 @@ +use crate::cdsl::inst::InstructionGroup; use crate::cdsl::isa::TargetIsa; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; +use crate::shared::Definitions as SharedDefinitions; fn define_settings(_shared: &SettingGroup) -> SettingGroup { let setting = SettingGroupBuilder::new("arm32"); @@ -44,8 +46,11 @@ fn define_regs() -> IsaRegs { regs.finish() } -pub fn define(shared_settings: &SettingGroup) -> TargetIsa { - let settings = define_settings(shared_settings); +pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { + let settings = define_settings(&shared_defs.settings); let regs = define_regs(); - TargetIsa::new("arm32", settings, regs) + + let inst_group = InstructionGroup::new("arm32", "arm32 specific instruction set"); + + TargetIsa::new("arm32", inst_group, settings, regs) } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs index baca5226ab45..46baac90e685 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs @@ -1,6 +1,8 @@ +use crate::cdsl::inst::InstructionGroup; use crate::cdsl::isa::TargetIsa; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; +use crate::shared::Definitions as SharedDefinitions; fn define_settings(_shared: &SettingGroup) -> SettingGroup { let setting = SettingGroupBuilder::new("arm64"); @@ -40,8 +42,11 @@ fn define_registers() -> IsaRegs { regs.finish() } -pub fn define(shared_settings: &SettingGroup) -> TargetIsa { - let settings = define_settings(shared_settings); +pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { + let settings = define_settings(&shared_defs.settings); let regs = define_registers(); - TargetIsa::new("arm64", settings, regs) + + let inst_group = InstructionGroup::new("arm64", "arm64 specific instruction set"); + + TargetIsa::new("arm64", inst_group, settings, regs) } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs index 96624358677f..0c2bb5eed079 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs @@ -1,5 +1,5 @@ use crate::cdsl::isa::TargetIsa; -use crate::cdsl::settings::SettingGroup; +use crate::shared::Definitions as SharedDefinitions; use std::fmt; mod arm32; @@ -55,13 +55,13 @@ impl fmt::Display for Isa { } } -pub fn define(isas: &Vec, shared_settings: &SettingGroup) -> Vec { +pub fn define(isas: &Vec, shared_defs: &mut SharedDefinitions) -> Vec { isas.iter() .map(|isa| match isa { - Isa::Riscv => riscv::define(shared_settings), - Isa::X86 => x86::define(shared_settings), - Isa::Arm32 => arm32::define(shared_settings), - Isa::Arm64 => arm64::define(shared_settings), + Isa::Riscv => riscv::define(shared_defs), + Isa::X86 => x86::define(shared_defs), + Isa::Arm32 => arm32::define(shared_defs), + Isa::Arm64 => arm64::define(shared_defs), }) .collect() } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs index 040d08838659..9d5a78a5a07b 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs @@ -1,6 +1,8 @@ +use crate::cdsl::inst::InstructionGroup; use crate::cdsl::isa::TargetIsa; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder}; +use crate::shared::Definitions as SharedDefinitions; fn define_settings(shared: &SettingGroup) -> SettingGroup { let mut setting = SettingGroupBuilder::new("riscv"); @@ -76,8 +78,11 @@ fn define_registers() -> IsaRegs { regs.finish() } -pub fn define(shared_settings: &SettingGroup) -> TargetIsa { - let settings = define_settings(shared_settings); +pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { + let settings = define_settings(&shared_defs.settings); let regs = define_registers(); - TargetIsa::new("riscv", settings, regs) + + let inst_group = InstructionGroup::new("riscv", "riscv specific instruction set"); + + TargetIsa::new("riscv", inst_group, settings, regs) } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs new file mode 100644 index 000000000000..077860cc46a4 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs @@ -0,0 +1,254 @@ +#![allow(non_snake_case)] + +use crate::cdsl::formats::FormatRegistry; +use crate::cdsl::inst::{InstructionBuilder as Inst, InstructionGroup}; +use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc}; +use crate::cdsl::types::ValueType; +use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar}; +use crate::shared::types; + +pub fn define(format_registry: &FormatRegistry) -> InstructionGroup { + let mut ig = InstructionGroup::new("x86", "x86 specific instruction set"); + + let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into(); + + let iWord = &TypeVar::new( + "iWord", + "A scalar integer machine word", + TypeSetBuilder::new().ints(32..64).finish(), + ); + let nlo = &operand_doc("nlo", iWord, "Low part of numerator"); + let nhi = &operand_doc("nhi", iWord, "High part of numerator"); + let d = &operand_doc("d", iWord, "Denominator"); + let q = &operand_doc("q", iWord, "Quotient"); + let r = &operand_doc("r", iWord, "Remainder"); + + ig.push( + Inst::new( + "x86_udivmodx", + r#" + Extended unsigned division. + + Concatenate the bits in `nhi` and `nlo` to form the numerator. + Interpret the bits as an unsigned number and divide by the unsigned + denominator `d`. Trap when `d` is zero or if the quotient is larger + than the range of the output. + + Return both quotient and remainder. + "#, + ) + .operands_in(vec![nlo, nhi, d]) + .operands_out(vec![q, r]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "x86_sdivmodx", + r#" + Extended signed division. + + Concatenate the bits in `nhi` and `nlo` to form the numerator. + Interpret the bits as a signed number and divide by the signed + denominator `d`. Trap when `d` is zero or if the quotient is outside + the range of the output. + + Return both quotient and remainder. + "#, + ) + .operands_in(vec![nlo, nhi, d]) + .operands_out(vec![q, r]) + .can_trap(true) + .finish(format_registry), + ); + + let argL = &operand("argL", iWord); + let argR = &operand("argR", iWord); + let resLo = &operand("resLo", iWord); + let resHi = &operand("resHi", iWord); + + ig.push( + Inst::new( + "x86_umulx", + r#" + Unsigned integer multiplication, producing a double-length result. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![argL, argR]) + .operands_out(vec![resLo, resHi]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "x86_smulx", + r#" + Signed integer multiplication, producing a double-length result. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![argL, argR]) + .operands_out(vec![resLo, resHi]) + .finish(format_registry), + ); + + let Float = &TypeVar::new( + "Float", + "A scalar or vector floating point number", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let IntTo = &TypeVar::new( + "IntTo", + "An integer type with the same number of lanes", + TypeSetBuilder::new() + .ints(32..64) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Float); + let a = &operand("a", IntTo); + + ig.push( + Inst::new( + "x86_cvtt2si", + r#" + Convert with truncation floating point to signed integer. + + The source floating point operand is converted to a signed integer by + rounding towards zero. If the result can't be represented in the output + type, returns the smallest signed value the output type can represent. + + This instruction does not trap. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", Float); + let a = &operand("a", Float); + let y = &operand("y", Float); + + ig.push( + Inst::new( + "x86_fmin", + r#" + Floating point minimum with x86 semantics. + + This is equivalent to the C ternary operator `x < y ? x : y` which + differs from :inst:`fmin` when either operand is NaN or when comparing + +0.0 to -0.0. + + When the two operands don't compare as LT, `y` is returned unchanged, + even if it is a signalling NaN. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "x86_fmax", + r#" + Floating point maximum with x86 semantics. + + This is equivalent to the C ternary operator `x > y ? x : y` which + differs from :inst:`fmax` when either operand is NaN or when comparing + +0.0 to -0.0. + + When the two operands don't compare as GT, `y` is returned unchanged, + even if it is a signalling NaN. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", iWord); + + ig.push( + Inst::new( + "x86_push", + r#" + Pushes a value onto the stack. + + Decrements the stack pointer and stores the specified value on to the top. + + This is polymorphic in i32 and i64. However, it is only implemented for i64 + in 64-bit mode, and only for i32 in 32-bit mode. + "#, + ) + .operands_in(vec![x]) + .other_side_effects(true) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "x86_pop", + r#" + Pops a value from the stack. + + Loads a value from the top of the stack and then increments the stack + pointer. + + This is polymorphic in i32 and i64. However, it is only implemented for i64 + in 64-bit mode, and only for i32 in 32-bit mode. + "#, + ) + .operands_out(vec![x]) + .other_side_effects(true) + .can_load(true) + .finish(format_registry), + ); + + let y = &operand("y", iWord); + let rflags = &operand("rflags", iflags); + + ig.push( + Inst::new( + "x86_bsr", + r#" + Bit Scan Reverse -- returns the bit-index of the most significant 1 + in the word. Result is undefined if the argument is zero. However, it + sets the Z flag depending on the argument, so it is at least easy to + detect and handle that case. + + This is polymorphic in i32 and i64. It is implemented for both i64 and + i32 in 64-bit mode, and only for i32 in 32-bit mode. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![y, rflags]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "x86_bsf", + r#" + Bit Scan Forwards -- returns the bit-index of the least significant 1 + in the word. Is otherwise identical to 'bsr', just above. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![y, rflags]) + .finish(format_registry), + ); + + ig +} diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs index da64f3cc5037..6c5fe4d097de 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs @@ -1,7 +1,11 @@ +mod instructions; + use crate::cdsl::isa::TargetIsa; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder}; +use crate::shared::Definitions as SharedDefinitions; + fn define_settings(_shared: &SettingGroup) -> SettingGroup { let mut settings = SettingGroupBuilder::new("x86"); @@ -109,8 +113,11 @@ fn define_registers() -> IsaRegs { regs.finish() } -pub fn define(shared_settings: &SettingGroup) -> TargetIsa { - let settings = define_settings(shared_settings); +pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { + let settings = define_settings(&shared_defs.settings); let regs = define_registers(); - TargetIsa::new("x86", settings, regs) + + let inst_group = instructions::define(&shared_defs.format_registry); + + TargetIsa::new("x86", inst_group, settings, regs) } diff --git a/third_party/rust/cranelift-codegen-meta/src/lib.rs b/third_party/rust/cranelift-codegen-meta/src/lib.rs index fe65e19d2b1c..9b50fe123297 100644 --- a/third_party/rust/cranelift-codegen-meta/src/lib.rs +++ b/third_party/rust/cranelift-codegen-meta/src/lib.rs @@ -20,16 +20,27 @@ pub fn isa_from_arch(arch: &str) -> Result { /// Generates all the Rust source files used in Cranelift from the meta-language. pub fn generate(isas: &Vec, out_dir: &str) -> Result<(), error::Error> { // Common definitions. - let shared_settings = gen_settings::generate_common("new_settings.rs", &out_dir)?; + let mut shared_defs = shared::define(); + gen_settings::generate( + &shared_defs.settings, + gen_settings::ParentGroup::None, + "new_settings.rs", + &out_dir, + )?; gen_types::generate("types.rs", &out_dir)?; // Per ISA definitions. - let isas = isa::define(isas, &shared_settings); + let isas = isa::define(isas, &mut shared_defs); for isa in isas { - gen_registers::generate(&isa, "registers", &out_dir)?; - gen_settings::generate(&isa, "new_settings", &out_dir)?; + gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?; + gen_settings::generate( + &isa.settings, + gen_settings::ParentGroup::Shared, + &format!("new_settings-{}", isa.name), + &out_dir, + )?; } Ok(()) diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs b/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs new file mode 100644 index 000000000000..e3ff8ac705f6 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs @@ -0,0 +1,65 @@ +use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder, OperandKindFields}; + +/// Small helper to initialize an OperandBuilder with the right kind, for a given name and doc. +fn create(name: &'static str, doc: &'static str) -> Builder { + Builder::new(name, OperandKindFields::EntityRef).doc(doc) +} + +pub fn define() -> Vec { + let mut kinds = Vec::new(); + + // A reference to an extended basic block in the same function. + // This is primarliy used in control flow instructions. + let ebb = create("ebb", "An extended basic block in the same function.") + .default_member("destination") + .finish(); + kinds.push(ebb); + + // A reference to a stack slot declared in the function preamble. + let stack_slot = create("stack_slot", "A stack slot").finish(); + kinds.push(stack_slot); + + // A reference to a global value. + let global_value = create("global_value", "A global value.").finish(); + kinds.push(global_value); + + // A reference to a function signature declared in the function preamble. + // This is used to provide the call signature in a call_indirect instruction. + let sig_ref = create("sig_ref", "A function signature.").finish(); + kinds.push(sig_ref); + + // A reference to an external function declared in the function preamble. + // This is used to provide the callee and signature in a call instruction. + let func_ref = create("func_ref", "An external function.").finish(); + kinds.push(func_ref); + + // A reference to a jump table declared in the function preamble. + let jump_table = create("jump_table", "A jump table.") + .default_member("table") + .finish(); + kinds.push(jump_table); + + // A reference to a heap declared in the function preamble. + let heap = create("heap", "A heap.").finish(); + kinds.push(heap); + + // A reference to a table declared in the function preamble. + let table = create("table", "A table.").finish(); + kinds.push(table); + + // A variable-sized list of value operands. Use for Ebb and function call arguments. + let varargs = Builder::new("variable_args", OperandKindFields::VariableArgs) + .doc( + r#" + A variable size list of `value` operands. + + Use this to represent arguments passed to a function call, arguments + passed to an extended basic block, or a variable number of results + returned from an instruction. + "#, + ) + .finish(); + kinds.push(varargs); + + return kinds; +} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs new file mode 100644 index 000000000000..0af3c264aec5 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs @@ -0,0 +1,184 @@ +use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder as Builder}; +use crate::shared::OperandKinds; + +pub fn define(immediates: &OperandKinds, entities: &OperandKinds) -> FormatRegistry { + // Shorthands for immediates. + let uimm8 = immediates.by_name("uimm8"); + let uimm32 = immediates.by_name("uimm32"); + let imm64 = immediates.by_name("imm64"); + let ieee32 = immediates.by_name("ieee32"); + let ieee64 = immediates.by_name("ieee64"); + let boolean = immediates.by_name("boolean"); + let intcc = immediates.by_name("intcc"); + let floatcc = immediates.by_name("floatcc"); + let memflags = immediates.by_name("memflags"); + let offset32 = immediates.by_name("offset32"); + let trapcode = immediates.by_name("trapcode"); + let regunit = immediates.by_name("regunit"); + + // Shorthands for entities. + let global_value = entities.by_name("global_value"); + let ebb = entities.by_name("ebb"); + let jump_table = entities.by_name("jump_table"); + let func_ref = entities.by_name("func_ref"); + let sig_ref = entities.by_name("sig_ref"); + let stack_slot = entities.by_name("stack_slot"); + let heap = entities.by_name("heap"); + let table = entities.by_name("table"); + + let mut registry = FormatRegistry::new(); + + registry.insert(Builder::new("Unary").value()); + registry.insert(Builder::new("UnaryImm").imm(imm64)); + registry.insert(Builder::new("UnaryIeee32").imm(ieee32)); + registry.insert(Builder::new("UnaryIeee64").imm(ieee64)); + registry.insert(Builder::new("UnaryBool").imm(boolean)); + registry.insert(Builder::new("UnaryGlobalValue").imm(global_value)); + + registry.insert(Builder::new("Binary").value().value()); + registry.insert(Builder::new("BinaryImm").value().imm(imm64)); + + // The select instructions are controlled by the second VALUE operand. + // The first VALUE operand is the controlling flag which has a derived type. + // The fma instruction has the same constraint on all inputs. + registry.insert( + Builder::new("Ternary") + .value() + .value() + .value() + .typevar_operand(1), + ); + + // Catch-all for instructions with many outputs and inputs and no immediate + // operands. + registry.insert(Builder::new("MultiAry").varargs()); + + registry.insert(Builder::new("NullAry")); + + registry.insert( + Builder::new("InsertLane") + .value() + .imm(("lane", uimm8)) + .value(), + ); + registry.insert(Builder::new("ExtractLane").value().imm(("lane", uimm8))); + + registry.insert(Builder::new("IntCompare").imm(intcc).value().value()); + registry.insert(Builder::new("IntCompareImm").imm(intcc).value().imm(imm64)); + registry.insert(Builder::new("IntCond").imm(intcc).value()); + + registry.insert(Builder::new("FloatCompare").imm(floatcc).value().value()); + registry.insert(Builder::new("FloatCond").imm(floatcc).value());; + + registry.insert(Builder::new("IntSelect").imm(intcc).value().value().value()); + + registry.insert(Builder::new("Jump").imm(ebb).varargs()); + registry.insert(Builder::new("Branch").value().imm(ebb).varargs()); + registry.insert( + Builder::new("BranchInt") + .imm(intcc) + .value() + .imm(ebb) + .varargs(), + ); + registry.insert( + Builder::new("BranchFloat") + .imm(floatcc) + .value() + .imm(ebb) + .varargs(), + ); + registry.insert( + Builder::new("BranchIcmp") + .imm(intcc) + .value() + .value() + .imm(ebb) + .varargs(), + ); + registry.insert(Builder::new("BranchTable").value().imm(ebb).imm(jump_table)); + registry.insert( + Builder::new("BranchTableEntry") + .value() + .value() + .imm(uimm8) + .imm(jump_table), + ); + registry.insert(Builder::new("BranchTableBase").imm(jump_table)); + registry.insert(Builder::new("IndirectJump").value().imm(jump_table)); + + registry.insert(Builder::new("Call").imm(func_ref).varargs()); + registry.insert(Builder::new("CallIndirect").imm(sig_ref).value().varargs()); + registry.insert(Builder::new("FuncAddr").imm(func_ref)); + + registry.insert(Builder::new("Load").imm(memflags).value().imm(offset32)); + registry.insert( + Builder::new("LoadComplex") + .imm(memflags) + .varargs() + .imm(offset32), + ); + registry.insert( + Builder::new("Store") + .imm(memflags) + .value() + .value() + .imm(offset32), + ); + registry.insert( + Builder::new("StoreComplex") + .imm(memflags) + .value() + .varargs() + .imm(offset32), + ); + registry.insert(Builder::new("StackLoad").imm(stack_slot).imm(offset32)); + registry.insert( + Builder::new("StackStore") + .value() + .imm(stack_slot) + .imm(offset32), + ); + + // Accessing a WebAssembly heap. + registry.insert(Builder::new("HeapAddr").imm(heap).value().imm(uimm32)); + + // Accessing a WebAssembly table. + registry.insert(Builder::new("TableAddr").imm(table).value().imm(offset32)); + + registry.insert( + Builder::new("RegMove") + .value() + .imm(("src", regunit)) + .imm(("dst", regunit)), + ); + registry.insert( + Builder::new("CopySpecial") + .imm(("src", regunit)) + .imm(("dst", regunit)), + ); + registry.insert( + Builder::new("RegSpill") + .value() + .imm(("src", regunit)) + .imm(("dst", stack_slot)), + ); + registry.insert( + Builder::new("RegFill") + .value() + .imm(("src", stack_slot)) + .imm(("dst", regunit)), + ); + + registry.insert(Builder::new("Trap").imm(trapcode)); + registry.insert(Builder::new("CondTrap").value().imm(trapcode)); + registry.insert(Builder::new("IntCondTrap").imm(intcc).value().imm(trapcode)); + registry.insert( + Builder::new("FloatCondTrap") + .imm(floatcc) + .value() + .imm(trapcode), + ); + + registry +} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs new file mode 100644 index 000000000000..077fe0a51121 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs @@ -0,0 +1,145 @@ +use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder}; + +use std::collections::HashMap; + +pub fn define() -> Vec { + let mut kinds = Vec::new(); + + // A 64-bit immediate integer operand. + // + // This type of immediate integer can interact with SSA values with any + // IntType type. + let imm64 = Builder::new_imm("imm64") + .doc("A 64-bit immediate integer.") + .finish(); + kinds.push(imm64); + + // An unsigned 8-bit immediate integer operand. + // + // This small operand is used to indicate lane indexes in SIMD vectors and + // immediate bit counts on shift instructions. + let uimm8 = Builder::new_imm("uimm8") + .doc("An 8-bit immediate unsigned integer.") + .finish(); + kinds.push(uimm8); + + // An unsigned 32-bit immediate integer operand. + let uimm32 = Builder::new_imm("uimm32") + .doc("A 32-bit immediate unsigned integer.") + .finish(); + kinds.push(uimm32); + + // A 32-bit immediate signed offset. + // + // This is used to represent an immediate address offset in load/store + // instructions. + let offset32 = Builder::new_imm("offset32") + .doc("A 32-bit immediate signed offset.") + .default_member("offset") + .finish(); + kinds.push(offset32); + + // A 32-bit immediate floating point operand. + // + // IEEE 754-2008 binary32 interchange format. + let ieee32 = Builder::new_imm("ieee32") + .doc("A 32-bit immediate floating point number.") + .finish(); + kinds.push(ieee32); + + // A 64-bit immediate floating point operand. + // + // IEEE 754-2008 binary64 interchange format. + let ieee64 = Builder::new_imm("ieee64") + .doc("A 64-bit immediate floating point number.") + .finish(); + kinds.push(ieee64); + + // An immediate boolean operand. + // + // This type of immediate boolean can interact with SSA values with any + // BoolType type. + let boolean = Builder::new_imm("boolean") + .doc("An immediate boolean.") + .rust_type("bool") + .finish(); + kinds.push(boolean); + + // A condition code for comparing integer values. + // This enumerated operand kind is used for the `icmp` instruction and corresponds to the + // condcodes::IntCC` Rust type. + let mut intcc_values = HashMap::new(); + intcc_values.insert("eq", "Equal"); + intcc_values.insert("ne", "NotEqual"); + intcc_values.insert("sge", "UnsignedGreaterThanOrEqual"); + intcc_values.insert("sgt", "UnsignedGreaterThan"); + intcc_values.insert("sle", "UnsignedLessThanOrEqual"); + intcc_values.insert("slt", "UnsignedLessThan"); + intcc_values.insert("uge", "UnsignedGreaterThanOrEqual"); + intcc_values.insert("ugt", "UnsignedGreaterThan"); + intcc_values.insert("ule", "UnsignedLessThanOrEqual"); + intcc_values.insert("ult", "UnsignedLessThan"); + let intcc = Builder::new_enum("intcc", intcc_values) + .doc("An integer comparison condition code.") + .default_member("cond") + .rust_type("ir::condcodes::IntCC") + .finish(); + kinds.push(intcc); + + // A condition code for comparing floating point values. This enumerated operand kind is used + // for the `fcmp` instruction and corresponds to the `condcodes::FloatCC` Rust type. + let mut floatcc_values = HashMap::new(); + floatcc_values.insert("ord", "Ordered"); + floatcc_values.insert("uno", "Unordered"); + floatcc_values.insert("eq", "Equal"); + floatcc_values.insert("ne", "NotEqual"); + floatcc_values.insert("one", "OrderedNotEqual"); + floatcc_values.insert("ueq", "UnorderedOrEqual"); + floatcc_values.insert("lt", "LessThan"); + floatcc_values.insert("le", "LessThanOrEqual"); + floatcc_values.insert("gt", "GreaterThan"); + floatcc_values.insert("ge", "GreaterThanOrEqual"); + floatcc_values.insert("ult", "UnorderedOrLessThan"); + floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual"); + floatcc_values.insert("ugt", "UnorderedOrGreaterThan"); + floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual"); + let floatcc = Builder::new_enum("floatcc", floatcc_values) + .doc("A floating point comparison condition code") + .default_member("cond") + .rust_type("ir::condcodes::FloatCC") + .finish(); + kinds.push(floatcc); + + // Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`. + let memflags = Builder::new_imm("memflags") + .doc("Memory operation flags") + .default_member("flags") + .rust_type("ir::MemFlags") + .finish(); + kinds.push(memflags); + + // A register unit in the current target ISA. + let regunit = Builder::new_imm("regunit") + .doc("A register unit in the target ISA") + .rust_type("isa::RegUnit") + .finish(); + kinds.push(regunit); + + // A trap code indicating the reason for trapping. + // + // The Rust enum type also has a `User(u16)` variant for user-provided trap + // codes. + let mut trapcode_values = HashMap::new(); + trapcode_values.insert("stk_ovf", "StackOverflow"); + trapcode_values.insert("heap_oob", "HeapOutOfBounds"); + trapcode_values.insert("int_ovf", "IntegerOverflow"); + trapcode_values.insert("int_divz", "IntegerDivisionByZero"); + let trapcode = Builder::new_enum("trapcode", trapcode_values) + .doc("A trap reason code.") + .default_member("code") + .rust_type("ir::TrapCode") + .finish(); + kinds.push(trapcode); + + return kinds; +} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs new file mode 100644 index 000000000000..b0c89b510eb7 --- /dev/null +++ b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs @@ -0,0 +1,3185 @@ +#![allow(non_snake_case)] + +use crate::cdsl::formats::FormatRegistry; +use crate::cdsl::inst::{InstructionBuilder as Inst, InstructionGroup}; +use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc}; +use crate::cdsl::type_inference::Constraint::WiderOrEq; +use crate::cdsl::types::{LaneType, ValueType}; +use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar}; +use crate::shared::{types, OperandKinds}; + +pub fn define( + format_registry: &FormatRegistry, + immediates: &OperandKinds, + entities: &OperandKinds, +) -> InstructionGroup { + let mut ig = InstructionGroup::new("base", "Shared base instruction set"); + + // Operand kind shorthands. + let intcc = immediates.by_name("intcc"); + let floatcc = immediates.by_name("floatcc"); + let trapcode = immediates.by_name("trapcode"); + let uimm8 = immediates.by_name("uimm8"); + let uimm32 = immediates.by_name("uimm32"); + let imm64 = immediates.by_name("imm64"); + let offset32 = immediates.by_name("offset32"); + let memflags = immediates.by_name("memflags"); + let ieee32 = immediates.by_name("ieee32"); + let ieee64 = immediates.by_name("ieee64"); + let boolean = immediates.by_name("boolean"); + let regunit = immediates.by_name("regunit"); + + let ebb = entities.by_name("ebb"); + let jump_table = entities.by_name("jump_table"); + let variable_args = entities.by_name("variable_args"); + let func_ref = entities.by_name("func_ref"); + let sig_ref = entities.by_name("sig_ref"); + let stack_slot = entities.by_name("stack_slot"); + let global_value = entities.by_name("global_value"); + let heap = entities.by_name("heap"); + let table = entities.by_name("table"); + + let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into(); + let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into(); + + let b1: &TypeVar = &ValueType::from(LaneType::from(types::Bool::B1)).into(); + let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into(); + let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into(); + + // Starting definitions. + let Int = &TypeVar::new( + "Int", + "A scalar or vector integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let Bool = &TypeVar::new( + "Bool", + "A scalar or vector boolean type", + TypeSetBuilder::new() + .bools(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let iB = &TypeVar::new( + "iB", + "A scalar integer type", + TypeSetBuilder::new().ints(Interval::All).finish(), + ); + + let iAddr = &TypeVar::new( + "iAddr", + "An integer address type", + TypeSetBuilder::new().ints(32..64).finish(), + ); + + let Testable = &TypeVar::new( + "Testable", + "A scalar boolean or integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .bools(Interval::All) + .finish(), + ); + + let TxN = &TypeVar::new( + "TxN", + "A SIMD vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .bools(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .finish(), + ); + + let Any = &TypeVar::new( + "Any", + "Any integer, float, or boolean scalar or vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .bools(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .finish(), + ); + + let Mem = &TypeVar::new( + "Mem", + "Any type that can be stored in memory", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let MemTo = &TypeVar::new( + "MemTo", + "Any type that can be stored in memory", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let addr = &operand("addr", iAddr); + let c = &operand_doc("c", Testable, "Controlling value to test"); + let Cond = &operand("Cond", intcc); + let x = &operand("x", iB); + let y = &operand("y", iB); + let EBB = &operand_doc("EBB", ebb, "Destination extended basic block"); + let args = &operand_doc("args", variable_args, "EBB arguments"); + + ig.push( + Inst::new( + "jump", + r#" + Jump. + + Unconditionally jump to an extended basic block, passing the specified + EBB arguments. The number and types of arguments must match the + destination EBB. + "#, + ) + .operands_in(vec![EBB, args]) + .is_terminator(true) + .is_branch(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fallthrough", + r#" + Fall through to the next EBB. + + This is the same as :inst:`jump`, except the destination EBB must be + the next one in the layout. + + Jumps are turned into fall-through instructions by the branch + relaxation pass. There is no reason to use this instruction outside + that pass. + "#, + ) + .operands_in(vec![EBB, args]) + .is_terminator(true) + .is_branch(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "brz", + r#" + Branch when zero. + + If ``c`` is a :type:`b1` value, take the branch when ``c`` is false. If + ``c`` is an integer value, take the branch when ``c = 0``. + "#, + ) + .operands_in(vec![c, EBB, args]) + .is_branch(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "brnz", + r#" + Branch when non-zero. + + If ``c`` is a :type:`b1` value, take the branch when ``c`` is true. If + ``c`` is an integer value, take the branch when ``c != 0``. + "#, + ) + .operands_in(vec![c, EBB, args]) + .is_branch(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "br_icmp", + r#" + Compare scalar integers and branch. + + Compare ``x`` and ``y`` in the same way as the :inst:`icmp` instruction + and take the branch if the condition is true:: + + br_icmp ugt v1, v2, ebb4(v5, v6) + + is semantically equivalent to:: + + v10 = icmp ugt, v1, v2 + brnz v10, ebb4(v5, v6) + + Some RISC architectures like MIPS and RISC-V provide instructions that + implement all or some of the condition codes. The instruction can also + be used to represent *macro-op fusion* on architectures like Intel's. + "#, + ) + .operands_in(vec![Cond, x, y, EBB, args]) + .is_branch(true) + .finish(format_registry), + ); + + let f = &operand("f", iflags); + + ig.push( + Inst::new( + "brif", + r#" + Branch when condition is true in integer CPU flags. + "#, + ) + .operands_in(vec![Cond, f, EBB, args]) + .is_branch(true) + .finish(format_registry), + ); + + let Cond = &operand("Cond", floatcc); + let f = &operand("f", fflags); + + ig.push( + Inst::new( + "brff", + r#" + Branch when condition is true in floating point CPU flags. + "#, + ) + .operands_in(vec![Cond, f, EBB, args]) + .is_branch(true) + .finish(format_registry), + ); + + let x = &operand_doc("x", iB, "index into jump table"); + + let Entry = &TypeVar::new( + "Entry", + "A scalar integer type", + TypeSetBuilder::new().ints(Interval::All).finish(), + ); + + let entry = &operand_doc("entry", Entry, "entry of jump table"); + let JT = &operand("JT", jump_table); + + ig.push( + Inst::new( + "br_table", + r#" + Indirect branch via jump table. + + Use ``x`` as an unsigned index into the jump table ``JT``. If a jump + table entry is found, branch to the corresponding EBB. If no entry was + found or the index is out-of-bounds, branch to the given default EBB. + + Note that this branch instruction can't pass arguments to the targeted + blocks. Split critical edges as needed to work around this. + + Do not confuse this with "tables" in WebAssembly. ``br_table`` is for + jump tables with destinations within the current function only -- think + of a ``match`` in Rust or a ``switch`` in C. If you want to call a + function in a dynamic library, that will typically use + ``call_indirect``. + "#, + ) + .operands_in(vec![x, EBB, JT]) + .is_terminator(true) + .is_branch(true) + .finish(format_registry), + ); + + let Size = &operand_doc("Size", uimm8, "Size in bytes"); + + ig.push( + Inst::new( + "jump_table_entry", + r#" + Get an entry from a jump table. + + Load a serialized ``entry`` from a jump table ``JT`` at a given index + ``addr`` with a specific ``Size``. The retrieved entry may need to be + decoded after loading, depending upon the jump table type used. + + Currently, the only type supported is entries which are relative to the + base of the jump table. + "#, + ) + .operands_in(vec![x, addr, Size, JT]) + .operands_out(vec![entry]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "jump_table_base", + r#" + Get the absolute base address of a jump table. + + This is used for jump tables wherein the entries are stored relative to + the base of jump table. In order to use these, generated code should first + load an entry using ``jump_table_entry``, then use this instruction to add + the relative base back to it. + "#, + ) + .operands_in(vec![JT]) + .operands_out(vec![addr]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "indirect_jump_table_br", + r#" + Branch indirectly via a jump table entry. + + Unconditionally jump via a jump table entry that was previously loaded + with the ``jump_table_entry`` instruction. + "#, + ) + .operands_in(vec![addr, JT]) + .is_indirect_branch(true) + .is_terminator(true) + .is_branch(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "debugtrap", + r#" + Encodes an assembly debug trap. + "#, + ) + .other_side_effects(true) + .can_load(true) + .can_store(true) + .finish(format_registry), + ); + + let code = &operand("code", trapcode); + + ig.push( + Inst::new( + "trap", + r#" + Terminate execution unconditionally. + "#, + ) + .operands_in(vec![code]) + .can_trap(true) + .is_terminator(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "trapz", + r#" + Trap when zero. + + if ``c`` is non-zero, execution continues at the following instruction. + "#, + ) + .operands_in(vec![c, code]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "trapnz", + r#" + Trap when non-zero. + + if ``c`` is zero, execution continues at the following instruction. + "#, + ) + .operands_in(vec![c, code]) + .can_trap(true) + .finish(format_registry), + ); + + let Cond = &operand("Cond", intcc); + let f = &operand("f", iflags); + + ig.push( + Inst::new( + "trapif", + r#" + Trap when condition is true in integer CPU flags. + "#, + ) + .operands_in(vec![Cond, f, code]) + .can_trap(true) + .finish(format_registry), + ); + + let Cond = &operand("Cond", floatcc); + let f = &operand("f", fflags); + + ig.push( + Inst::new( + "trapff", + r#" + Trap when condition is true in floating point CPU flags. + "#, + ) + .operands_in(vec![Cond, f, code]) + .can_trap(true) + .finish(format_registry), + ); + + let rvals = &operand_doc("rvals", variable_args, "return values"); + + ig.push( + Inst::new( + "return", + r#" + Return from the function. + + Unconditionally transfer control to the calling function, passing the + provided return values. The list of return values must match the + function signature's return types. + "#, + ) + .operands_in(vec![rvals]) + .is_return(true) + .is_terminator(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fallthrough_return", + r#" + Return from the function by fallthrough. + + This is a specialized instruction for use where one wants to append + a custom epilogue, which will then perform the real return. This + instruction has no encoding. + "#, + ) + .operands_in(vec![rvals]) + .is_return(true) + .is_terminator(true) + .finish(format_registry), + ); + + let FN = &operand_doc( + "FN", + func_ref, + "function to call, declared by :inst:`function`", + ); + let args = &operand_doc("args", variable_args, "call arguments"); + + ig.push( + Inst::new( + "call", + r#" + Direct function call. + + Call a function which has been declared in the preamble. The argument + types must match the function's signature. + "#, + ) + .operands_in(vec![FN, args]) + .operands_out(vec![rvals]) + .is_call(true) + .finish(format_registry), + ); + + let SIG = &operand_doc("SIG", sig_ref, "function signature"); + let callee = &operand_doc("callee", iAddr, "address of function to call"); + + ig.push( + Inst::new( + "call_indirect", + r#" + Indirect function call. + + Call the function pointed to by `callee` with the given arguments. The + called function must match the specified signature. + + Note that this is different from WebAssembly's ``call_indirect``; the + callee is a native address, rather than a table index. For WebAssembly, + :inst:`table_addr` and :inst:`load` are used to obtain a native address + from a table. + "#, + ) + .operands_in(vec![SIG, callee, args]) + .operands_out(vec![rvals]) + .is_call(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "func_addr", + r#" + Get the address of a function. + + Compute the absolute address of a function declared in the preamble. + The returned address can be used as a ``callee`` argument to + :inst:`call_indirect`. This is also a method for calling functions that + are too far away to be addressable by a direct :inst:`call` + instruction. + "#, + ) + .operands_in(vec![FN]) + .operands_out(vec![addr]) + .finish(format_registry), + ); + + let SS = &operand("SS", stack_slot); + let Offset = &operand_doc("Offset", offset32, "Byte offset from base address"); + let x = &operand_doc("x", Mem, "Value to be stored"); + let a = &operand_doc("a", Mem, "Value loaded"); + let p = &operand("p", iAddr); + let MemFlags = &operand("MemFlags", memflags); + let args = &operand_doc("args", variable_args, "Address arguments"); + + ig.push( + Inst::new( + "load", + r#" + Load from memory at ``p + Offset``. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "load_complex", + r#" + Load from memory at ``sum(args) + Offset``. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "store", + r#" + Store ``x`` to memory at ``p + Offset``. + + This is a polymorphic instruction that can store any value type with a + memory representation. + "#, + ) + .operands_in(vec![MemFlags, x, p, Offset]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "store_complex", + r#" + Store ``x`` to memory at ``sum(args) + Offset``. + + This is a polymorphic instruction that can store any value type with a + memory representation. + "#, + ) + .operands_in(vec![MemFlags, x, args, Offset]) + .can_store(true) + .finish(format_registry), + ); + + let iExt8 = &TypeVar::new( + "iExt8", + "An integer type with more than 8 bits", + TypeSetBuilder::new().ints(16..64).finish(), + ); + let x = &operand("x", iExt8); + let a = &operand("a", iExt8); + + ig.push( + Inst::new( + "uload8", + r#" + Load 8 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i8`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "uload8_complex", + r#" + Load 8 bits from memory at ``sum(args) + Offset`` and zero-extend. + + This is equivalent to ``load.i8`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload8", + r#" + Load 8 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i8`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload8_complex", + r#" + Load 8 bits from memory at ``sum(args) + Offset`` and sign-extend. + + This is equivalent to ``load.i8`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore8", + r#" + Store the low 8 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i8`` followed by ``store.i8``. + "#, + ) + .operands_in(vec![MemFlags, x, p, Offset]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore8_complex", + r#" + Store the low 8 bits of ``x`` to memory at ``sum(args) + Offset``. + + This is equivalent to ``ireduce.i8`` followed by ``store.i8``. + "#, + ) + .operands_in(vec![MemFlags, x, args, Offset]) + .can_store(true) + .finish(format_registry), + ); + + let iExt16 = &TypeVar::new( + "iExt16", + "An integer type with more than 16 bits", + TypeSetBuilder::new().ints(32..64).finish(), + ); + let x = &operand("x", iExt16); + let a = &operand("a", iExt16); + + ig.push( + Inst::new( + "uload16", + r#" + Load 16 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i16`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "uload16_complex", + r#" + Load 16 bits from memory at ``sum(args) + Offset`` and zero-extend. + + This is equivalent to ``load.i16`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload16", + r#" + Load 16 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i16`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload16_complex", + r#" + Load 16 bits from memory at ``sum(args) + Offset`` and sign-extend. + + This is equivalent to ``load.i16`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore16", + r#" + Store the low 16 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i16`` followed by ``store.i16``. + "#, + ) + .operands_in(vec![MemFlags, x, p, Offset]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore16_complex", + r#" + Store the low 16 bits of ``x`` to memory at ``sum(args) + Offset``. + + This is equivalent to ``ireduce.i16`` followed by ``store.i16``. + "#, + ) + .operands_in(vec![MemFlags, x, args, Offset]) + .can_store(true) + .finish(format_registry), + ); + + let iExt32 = &TypeVar::new( + "iExt32", + "An integer type with more than 32 bits", + TypeSetBuilder::new().ints(64..64).finish(), + ); + let x = &operand("x", iExt32); + let a = &operand("a", iExt32); + + ig.push( + Inst::new( + "uload32", + r#" + Load 32 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i32`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "uload32_complex", + r#" + Load 32 bits from memory at ``sum(args) + Offset`` and zero-extend. + + This is equivalent to ``load.i32`` followed by ``uextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload32", + r#" + Load 32 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i32`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, p, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sload32_complex", + r#" + Load 32 bits from memory at ``sum(args) + Offset`` and sign-extend. + + This is equivalent to ``load.i32`` followed by ``sextend``. + "#, + ) + .operands_in(vec![MemFlags, args, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore32", + r#" + Store the low 32 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i32`` followed by ``store.i32``. + "#, + ) + .operands_in(vec![MemFlags, x, p, Offset]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "istore32_complex", + r#" + Store the low 32 bits of ``x`` to memory at ``sum(args) + Offset``. + + This is equivalent to ``ireduce.i32`` followed by ``store.i32``. + "#, + ) + .operands_in(vec![MemFlags, x, args, Offset]) + .can_store(true) + .finish(format_registry), + ); + + let x = &operand_doc("x", Mem, "Value to be stored"); + let a = &operand_doc("a", Mem, "Value loaded"); + let Offset = &operand_doc("Offset", offset32, "In-bounds offset into stack slot"); + + ig.push( + Inst::new( + "stack_load", + r#" + Load a value from a stack slot at the constant offset. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + + The offset is an immediate constant, not an SSA value. The memory + access cannot go out of bounds, i.e. + :math:`sizeof(a) + Offset <= sizeof(SS)`. + "#, + ) + .operands_in(vec![SS, Offset]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "stack_store", + r#" + Store a value to a stack slot at a constant offset. + + This is a polymorphic instruction that can store any value type with a + memory representation. + + The offset is an immediate constant, not an SSA value. The memory + access cannot go out of bounds, i.e. + :math:`sizeof(a) + Offset <= sizeof(SS)`. + "#, + ) + .operands_in(vec![x, SS, Offset]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "stack_addr", + r#" + Get the address of a stack slot. + + Compute the absolute address of a byte in a stack slot. The offset must + refer to a byte inside the stack slot: + :math:`0 <= Offset < sizeof(SS)`. + "#, + ) + .operands_in(vec![SS, Offset]) + .operands_out(vec![addr]) + .finish(format_registry), + ); + + let GV = &operand("GV", global_value); + + ig.push( + Inst::new( + "global_value", + r#" + Compute the value of global GV. + "#, + ) + .operands_in(vec![GV]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "symbol_value", + r#" + Compute the value of global GV, which is a symbolic value. + "#, + ) + .operands_in(vec![GV]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let HeapOffset = &TypeVar::new( + "HeapOffset", + "An unsigned heap offset", + TypeSetBuilder::new().ints(32..64).finish(), + ); + + let H = &operand("H", heap); + let p = &operand("p", HeapOffset); + let Size = &operand_doc("Size", uimm32, "Size in bytes"); + + ig.push( + Inst::new( + "heap_addr", + r#" + Bounds check and compute absolute address of heap memory. + + Verify that the offset range ``p .. p + Size - 1`` is in bounds for the + heap H, and generate an absolute address that is safe to dereference. + + 1. If ``p + Size`` is not greater than the heap bound, return an + absolute address corresponding to a byte offset of ``p`` from the + heap's base address. + 2. If ``p + Size`` is greater than the heap bound, generate a trap. + "#, + ) + .operands_in(vec![H, p, Size]) + .operands_out(vec![addr]) + .finish(format_registry), + ); + + let TableOffset = &TypeVar::new( + "TableOffset", + "An unsigned table offset", + TypeSetBuilder::new().ints(32..64).finish(), + ); + let T = &operand("T", table); + let p = &operand("p", TableOffset); + let Offset = &operand_doc("Offset", offset32, "Byte offset from element address"); + + ig.push( + Inst::new( + "table_addr", + r#" + Bounds check and compute absolute address of a table entry. + + Verify that the offset ``p`` is in bounds for the table T, and generate + an absolute address that is safe to dereference. + + ``Offset`` must be less than the size of a table element. + + 1. If ``p`` is not greater than the table bound, return an absolute + address corresponding to a byte offset of ``p`` from the table's + base address. + 2. If ``p`` is greater than the table bound, generate a trap. + "#, + ) + .operands_in(vec![T, p, Offset]) + .operands_out(vec![addr]) + .finish(format_registry), + ); + + let N = &operand("N", imm64); + let a = &operand_doc("a", Int, "A constant integer scalar or vector value"); + + ig.push( + Inst::new( + "iconst", + r#" + Integer constant. + + Create a scalar integer SSA value with an immediate constant value, or + an integer vector where all the lanes have the same value. + "#, + ) + .operands_in(vec![N]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let N = &operand("N", ieee32); + let a = &operand_doc("a", f32_, "A constant f32 scalar value"); + + ig.push( + Inst::new( + "f32const", + r#" + Floating point constant. + + Create a :type:`f32` SSA value with an immediate constant value. + "#, + ) + .operands_in(vec![N]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let N = &operand("N", ieee64); + let a = &operand_doc("a", f64_, "A constant f64 scalar value"); + + ig.push( + Inst::new( + "f64const", + r#" + Floating point constant. + + Create a :type:`f64` SSA value with an immediate constant value. + "#, + ) + .operands_in(vec![N]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let N = &operand("N", boolean); + let a = &operand_doc("a", Bool, "A constant boolean scalar or vector value"); + + ig.push( + Inst::new( + "bconst", + r#" + Boolean constant. + + Create a scalar boolean SSA value with an immediate constant value, or + a boolean vector where all the lanes have the same value. + "#, + ) + .operands_in(vec![N]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "nop", + r#" + Just a dummy instruction + + Note: this doesn't compile to a machine code nop + "#, + ) + .finish(format_registry), + ); + + let c = &operand_doc("c", Testable, "Controlling value to test"); + let x = &operand_doc("x", Any, "Value to use when `c` is true"); + let y = &operand_doc("y", Any, "Value to use when `c` is false"); + let a = &operand("a", Any); + + ig.push( + Inst::new( + "select", + r#" + Conditional select. + + This instruction selects whole values. Use :inst:`vselect` for + lane-wise selection. + "#, + ) + .operands_in(vec![c, x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let cc = &operand_doc("cc", intcc, "Controlling condition code"); + let flags = &operand_doc("flags", iflags, "The machine's flag register"); + + ig.push( + Inst::new( + "selectif", + r#" + Conditional select, dependent on integer condition codes. + "#, + ) + .operands_in(vec![cc, flags, x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", Any); + + ig.push( + Inst::new( + "copy", + r#" + Register-register copy. + + This instruction copies its input, preserving the value type. + + A pure SSA-form program does not need to copy values, but this + instruction is useful for representing intermediate stages during + instruction transformations, and the register allocator needs a way of + representing register copies. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "spill", + r#" + Spill a register value to a stack slot. + + This instruction behaves exactly like :inst:`copy`, but the result + value is assigned to a spill slot. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .can_store(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fill", + r#" + Load a register value from a stack slot. + + This instruction behaves exactly like :inst:`copy`, but creates a new + SSA value for the spilled input value. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .can_load(true) + .finish(format_registry), + ); + + let src = &operand("src", regunit); + let dst = &operand("dst", regunit); + + ig.push( + Inst::new( + "regmove", + r#" + Temporarily divert ``x`` from ``src`` to ``dst``. + + This instruction moves the location of a value from one register to + another without creating a new SSA value. It is used by the register + allocator to temporarily rearrange register assignments in order to + satisfy instruction constraints. + + The register diversions created by this instruction must be undone + before the value leaves the EBB. At the entry to a new EBB, all live + values must be in their originally assigned registers. + "#, + ) + .operands_in(vec![x, src, dst]) + .other_side_effects(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "copy_special", + r#" + Copies the contents of ''src'' register to ''dst'' register. + + This instructions copies the contents of one register to another + register without involving any SSA values. This is used for copying + special registers, e.g. copying the stack register to the frame + register in a function prologue. + "#, + ) + .operands_in(vec![src, dst]) + .other_side_effects(true) + .finish(format_registry), + ); + + let delta = &operand("delta", Int); + + ig.push( + Inst::new( + "adjust_sp_down", + r#" + Subtracts ``delta`` offset value from the stack pointer register. + + This instruction is used to adjust the stack pointer by a dynamic amount. + "#, + ) + .operands_in(vec![delta]) + .other_side_effects(true) + .finish(format_registry), + ); + + let Offset = &operand_doc("Offset", imm64, "Offset from current stack pointer"); + + ig.push( + Inst::new( + "adjust_sp_up_imm", + r#" + Adds ``Offset`` immediate offset value to the stack pointer register. + + This instruction is used to adjust the stack pointer, primarily in function + prologues and epilogues. ``Offset`` is constrained to the size of a signed + 32-bit integer. + "#, + ) + .operands_in(vec![Offset]) + .other_side_effects(true) + .finish(format_registry), + ); + + let Offset = &operand_doc("Offset", imm64, "Offset from current stack pointer"); + + ig.push( + Inst::new( + "adjust_sp_down_imm", + r#" + Subtracts ``Offset`` immediate offset value from the stack pointer + register. + + This instruction is used to adjust the stack pointer, primarily in function + prologues and epilogues. ``Offset`` is constrained to the size of a signed + 32-bit integer. + "#, + ) + .operands_in(vec![Offset]) + .other_side_effects(true) + .finish(format_registry), + ); + + let f = &operand("f", iflags); + + ig.push( + Inst::new( + "ifcmp_sp", + r#" + Compare ``addr`` with the stack pointer and set the CPU flags. + + This is like :inst:`ifcmp` where ``addr`` is the LHS operand and the stack + pointer is the RHS. + "#, + ) + .operands_in(vec![addr]) + .operands_out(vec![f]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "regspill", + r#" + Temporarily divert ``x`` from ``src`` to ``SS``. + + This instruction moves the location of a value from a register to a + stack slot without creating a new SSA value. It is used by the register + allocator to temporarily rearrange register assignments in order to + satisfy instruction constraints. + + See also :inst:`regmove`. + "#, + ) + .operands_in(vec![x, src, SS]) + .other_side_effects(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "regfill", + r#" + Temporarily divert ``x`` from ``SS`` to ``dst``. + + This instruction moves the location of a value from a stack slot to a + register without creating a new SSA value. It is used by the register + allocator to temporarily rearrange register assignments in order to + satisfy instruction constraints. + + See also :inst:`regmove`. + "#, + ) + .operands_in(vec![x, SS, dst]) + .other_side_effects(true) + .finish(format_registry), + ); + + let x = &operand_doc("x", TxN, "Vector to split"); + let lo = &operand_doc("lo", &TxN.half_vector(), "Low-numbered lanes of `x`"); + let hi = &operand_doc("hi", &TxN.half_vector(), "High-numbered lanes of `x`"); + + ig.push( + Inst::new( + "vsplit", + r#" + Split a vector into two halves. + + Split the vector `x` into two separate values, each containing half of + the lanes from ``x``. The result may be two scalars if ``x`` only had + two lanes. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![lo, hi]) + .is_ghost(true) + .finish(format_registry), + ); + + let Any128 = &TypeVar::new( + "Any128", + "Any scalar or vector type with as most 128 lanes", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .bools(Interval::All) + .simd_lanes(1..128) + .includes_scalars(true) + .finish(), + ); + + let x = &operand_doc("x", Any128, "Low-numbered lanes"); + let y = &operand_doc("y", Any128, "High-numbered lanes"); + let a = &operand_doc("a", &Any128.double_vector(), "Concatenation of `x` and `y`"); + + ig.push( + Inst::new( + "vconcat", + r#" + Vector concatenation. + + Return a vector formed by concatenating ``x`` and ``y``. The resulting + vector type has twice as many lanes as each of the inputs. The lanes of + ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become + the high-numbered lanes of ``a``. + + It is possible to form a vector by concatenating two scalars. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .is_ghost(true) + .finish(format_registry), + ); + + let c = &operand_doc("c", &TxN.as_bool(), "Controlling vector"); + let x = &operand_doc("x", TxN, "Value to use where `c` is true"); + let y = &operand_doc("y", TxN, "Value to use where `c` is false"); + let a = &operand("a", TxN); + + ig.push( + Inst::new( + "vselect", + r#" + Vector lane select. + + Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean + vector ``c``. + "#, + ) + .operands_in(vec![c, x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", &TxN.lane_of()); + + ig.push( + Inst::new( + "splat", + r#" + Vector splat. + + Return a vector whose lanes are all ``x``. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand_doc("x", TxN, "SIMD vector to modify"); + let y = &operand_doc("y", &TxN.lane_of(), "New lane value"); + let Idx = &operand_doc("Idx", uimm8, "Lane index"); + + ig.push( + Inst::new( + "insertlane", + r#" + Insert ``y`` as lane ``Idx`` in x. + + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. + "#, + ) + .operands_in(vec![x, Idx, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", TxN); + let a = &operand("a", &TxN.lane_of()); + + ig.push( + Inst::new( + "extractlane", + r#" + Extract lane ``Idx`` from ``x``. + + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. + "#, + ) + .operands_in(vec![x, Idx]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand("a", &Int.as_bool()); + let Cond = &operand("Cond", intcc); + let x = &operand("x", Int); + let y = &operand("y", Int); + + ig.push( + Inst::new( + "icmp", + r#" + Integer comparison. + + The condition code determines if the operands are interpreted as signed + or unsigned integers. + + ====== ======== ========= + Signed Unsigned Condition + ====== ======== ========= + eq eq Equal + ne ne Not equal + slt ult Less than + sge uge Greater than or equal + sgt ugt Greater than + sle ule Less than or equal + ====== ======== ========= + + When this instruction compares integer vectors, it returns a boolean + vector of lane-wise comparisons. + "#, + ) + .operands_in(vec![Cond, x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand("a", b1); + let x = &operand("x", iB); + let Y = &operand("Y", imm64); + + ig.push( + Inst::new( + "icmp_imm", + r#" + Compare scalar integer to a constant. + + This is the same as the :inst:`icmp` instruction, except one operand is + an immediate constant. + + This instruction can only compare scalars. Use :inst:`icmp` for + lane-wise vector comparisons. + "#, + ) + .operands_in(vec![Cond, x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let f = &operand("f", iflags); + let x = &operand("x", iB); + let y = &operand("y", iB); + + ig.push( + Inst::new( + "ifcmp", + r#" + Compare scalar integers and return flags. + + Compare two scalar integer values and return integer CPU flags + representing the result. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![f]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ifcmp_imm", + r#" + Compare scalar integer to a constant and return flags. + + Like :inst:`icmp_imm`, but returns integer CPU flags instead of testing + a specific condition code. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![f]) + .finish(format_registry), + ); + + let a = &operand("a", Int); + let x = &operand("x", Int); + let y = &operand("y", Int); + + ig.push( + Inst::new( + "iadd", + r#" + Wrapping integer addition: :math:`a := x + y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the operands. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "isub", + r#" + Wrapping integer subtraction: :math:`a := x - y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the operands. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "imul", + r#" + Wrapping integer multiplication: :math:`a := x y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the + operands. + + Polymorphic over all integer types (vector and scalar). + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "umulhi", + r#" + Unsigned integer multiplication, producing the high half of a + double-length result. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "smulhi", + r#" + Signed integer multiplication, producing the high half of a + double-length result. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "udiv", + r#" + Unsigned integer division: :math:`a := \lfloor {x \over y} \rfloor`. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sdiv", + r#" + Signed integer division rounded toward zero: :math:`a := sign(xy) + \lfloor {|x| \over |y|}\rfloor`. + + This operation traps if the divisor is zero, or if the result is not + representable in :math:`B` bits two's complement. This only happens + when :math:`x = -2^{B-1}, y = -1`. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "urem", + r#" + Unsigned integer remainder. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "srem", + r#" + Signed integer remainder. The result has the sign of the dividend. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + let a = &operand("a", iB); + let x = &operand("x", iB); + let Y = &operand("Y", imm64); + + ig.push( + Inst::new( + "iadd_imm", + r#" + Add immediate integer. + + Same as :inst:`iadd`, but one operand is an immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "imul_imm", + r#" + Integer multiplication by immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "udiv_imm", + r#" + Unsigned integer division by an immediate constant. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sdiv_imm", + r#" + Signed integer division by an immediate constant. + + This operation traps if the divisor is zero, or if the result is not + representable in :math:`B` bits two's complement. This only happens + when :math:`x = -2^{B-1}, Y = -1`. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "urem_imm", + r#" + Unsigned integer remainder with immediate divisor. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "srem_imm", + r#" + Signed integer remainder with immediate divisor. + + This operation traps if the divisor is zero. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "irsub_imm", + r#" + Immediate reverse wrapping subtraction: :math:`a := Y - x \pmod{2^B}`. + + Also works as integer negation when :math:`Y = 0`. Use :inst:`iadd_imm` + with a negative immediate operand for the reverse immediate + subtraction. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand("a", iB); + let x = &operand("x", iB); + let y = &operand("y", iB); + let c_in = &operand_doc("c_in", b1, "Input carry flag"); + let c_out = &operand_doc("c_out", b1, "Output carry flag"); + let b_in = &operand_doc("b_in", b1, "Input borrow flag"); + let b_out = &operand_doc("b_out", b1, "Output borrow flag"); + + ig.push( + Inst::new( + "iadd_cin", + r#" + Add integers with carry in. + + Same as :inst:`iadd` with an additional carry input. Computes: + + .. math:: + + a = x + y + c_{in} \pmod 2^B + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y, c_in]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "iadd_cout", + r#" + Add integers with carry out. + + Same as :inst:`iadd` with an additional carry output. + + .. math:: + + a &= x + y \pmod 2^B \\ + c_{out} &= x+y >= 2^B + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a, c_out]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "iadd_carry", + r#" + Add integers with carry in and out. + + Same as :inst:`iadd` with an additional carry input and output. + + .. math:: + + a &= x + y + c_{in} \pmod 2^B \\ + c_{out} &= x + y + c_{in} >= 2^B + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y, c_in]) + .operands_out(vec![a, c_out]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "isub_bin", + r#" + Subtract integers with borrow in. + + Same as :inst:`isub` with an additional borrow flag input. Computes: + + .. math:: + + a = x - (y + b_{in}) \pmod 2^B + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y, b_in]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "isub_bout", + r#" + Subtract integers with borrow out. + + Same as :inst:`isub` with an additional borrow flag output. + + .. math:: + + a &= x - y \pmod 2^B \\ + b_{out} &= x < y + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a, b_out]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "isub_borrow", + r#" + Subtract integers with borrow in and out. + + Same as :inst:`isub` with an additional borrow flag input and output. + + .. math:: + + a &= x - (y + b_{in}) \pmod 2^B \\ + b_{out} &= x < y + b_{in} + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, y, b_in]) + .operands_out(vec![a, b_out]) + .finish(format_registry), + ); + + let bits = &TypeVar::new( + "bits", + "Any integer, float, or boolean scalar or vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .bools(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .finish(), + ); + let x = &operand("x", bits); + let y = &operand("y", bits); + let a = &operand("a", bits); + + ig.push( + Inst::new( + "band", + r#" + Bitwise and. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bor", + r#" + Bitwise or. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bxor", + r#" + Bitwise xor. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bnot", + r#" + Bitwise not. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "band_not", + r#" + Bitwise and not. + + Computes `x & ~y`. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bor_not", + r#" + Bitwise or not. + + Computes `x | ~y`. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bxor_not", + r#" + Bitwise xor not. + + Computes `x ^ ~y`. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", iB); + let Y = &operand("Y", imm64); + let a = &operand("a", iB); + + ig.push( + Inst::new( + "band_imm", + r#" + Bitwise and with immediate. + + Same as :inst:`band`, but one operand is an immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bor_imm", + r#" + Bitwise or with immediate. + + Same as :inst:`bor`, but one operand is an immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bxor_imm", + r#" + Bitwise xor with immediate. + + Same as :inst:`bxor`, but one operand is an immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand_doc("x", Int, "Scalar or vector value to shift"); + let y = &operand_doc("y", iB, "Number of bits to shift"); + let Y = &operand("Y", imm64); + let a = &operand("a", Int); + + ig.push( + Inst::new( + "rotl", + r#" + Rotate left. + + Rotate the bits in ``x`` by ``y`` places. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "rotr", + r#" + Rotate right. + + Rotate the bits in ``x`` by ``y`` places. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "rotl_imm", + r#" + Rotate left by immediate. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "rotr_imm", + r#" + Rotate right by immediate. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ishl", + r#" + Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` + places. Shift in zero bits to the LSB. + + The shift amount is masked to the size of ``x``. + + When shifting a B-bits integer type, this instruction computes: + + .. math:: + s &:= y \pmod B, \\ + a &:= x \cdot 2^s \pmod{2^B}. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ushr", + r#" + Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` + places, shifting in zero bits to the MSB. Also called a *logical + shift*. + + The shift amount is masked to the size of the register. + + When shifting a B-bits integer type, this instruction computes: + + .. math:: + s &:= y \pmod B, \\ + a &:= \lfloor x \cdot 2^{-s} \rfloor. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sshr", + r#" + Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` + places, shifting in sign bits to the MSB. Also called an *arithmetic + shift*. + + The shift amount is masked to the size of the register. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ishl_imm", + r#" + Integer shift left by immediate. + + The shift amount is masked to the size of ``x``. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ushr_imm", + r#" + Unsigned shift right by immediate. + + The shift amount is masked to the size of the register. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sshr_imm", + r#" + Signed shift right by immediate. + + The shift amount is masked to the size of the register. + "#, + ) + .operands_in(vec![x, Y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", iB); + let a = &operand("a", iB); + + ig.push( + Inst::new( + "bitrev", + r#" + Reverse the bits of a integer. + + Reverses the bits in ``x``. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "clz", + r#" + Count leading zero bits. + + Starting from the MSB in ``x``, count the number of zero bits before + reaching the first one bit. When ``x`` is zero, returns the size of x + in bits. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "cls", + r#" + Count leading sign bits. + + Starting from the MSB after the sign bit in ``x``, count the number of + consecutive bits identical to the sign bit. When ``x`` is 0 or -1, + returns one less than the size of x in bits. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "ctz", + r#" + Count trailing zeros. + + Starting from the LSB in ``x``, count the number of zero bits before + reaching the first one bit. When ``x`` is zero, returns the size of x + in bits. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "popcnt", + r#" + Population count + + Count the number of one bits in ``x``. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let Float = &TypeVar::new( + "Float", + "A scalar or vector floating point number", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let Cond = &operand("Cond", floatcc); + let x = &operand("x", Float); + let y = &operand("y", Float); + let a = &operand("a", &Float.as_bool()); + + ig.push( + Inst::new( + "fcmp", + r#" + Floating point comparison. + + Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each + other in exactly one of four ways: + + == ========================================== + UN Unordered when one or both numbers is NaN. + EQ When :math:`x = y`. (And :math:`0.0 = -0.0`). + LT When :math:`x < y`. + GT When :math:`x > y`. + == ========================================== + + The 14 :type:`floatcc` condition codes each correspond to a subset of + the four relations, except for the empty set which would always be + false, and the full set which would always be true. + + The condition codes are divided into 7 'ordered' conditions which don't + include UN, and 7 unordered conditions which all include UN. + + +-------+------------+---------+------------+-------------------------+ + |Ordered |Unordered |Condition | + +=======+============+=========+============+=========================+ + |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | + +-------+------------+---------+------------+-------------------------+ + |eq |EQ |ueq |UN | EQ |Equal | + +-------+------------+---------+------------+-------------------------+ + |one |LT | GT |ne |UN | LT | GT|Not equal | + +-------+------------+---------+------------+-------------------------+ + |lt |LT |ult |UN | LT |Less than | + +-------+------------+---------+------------+-------------------------+ + |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | + +-------+------------+---------+------------+-------------------------+ + |gt |GT |ugt |UN | GT |Greater than | + +-------+------------+---------+------------+-------------------------+ + |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | + +-------+------------+---------+------------+-------------------------+ + + The standard C comparison operators, `<, <=, >, >=`, are all ordered, + so they are false if either operand is NaN. The C equality operator, + `==`, is ordered, and since inequality is defined as the logical + inverse it is *unordered*. They map to the :type:`floatcc` condition + codes as follows: + + ==== ====== ============ + C `Cond` Subset + ==== ====== ============ + `==` eq EQ + `!=` ne UN | LT | GT + `<` lt LT + `<=` le LT | EQ + `>` gt GT + `>=` ge GT | EQ + ==== ====== ============ + + This subset of condition codes also corresponds to the WebAssembly + floating point comparisons of the same name. + + When this instruction compares floating point vectors, it returns a + boolean vector with the results of lane-wise comparisons. + "#, + ) + .operands_in(vec![Cond, x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let f = &operand("f", fflags); + + ig.push( + Inst::new( + "ffcmp", + r#" + Floating point comparison returning flags. + + Compares two numbers like :inst:`fcmp`, but returns floating point CPU + flags instead of testing a specific condition. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![f]) + .finish(format_registry), + ); + + let x = &operand("x", Float); + let y = &operand("y", Float); + let z = &operand("z", Float); + let a = &operand_doc("a", Float, "Result of applying operator to each lane"); + + ig.push( + Inst::new( + "fadd", + r#" + Floating point addition. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fsub", + r#" + Floating point subtraction. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fmul", + r#" + Floating point multiplication. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fdiv", + r#" + Floating point division. + + Unlike the integer division instructions :clif:inst:`sdiv` and + :clif:inst:`udiv`, this can't trap. Division by zero is infinity or + NaN, depending on the dividend. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sqrt", + r#" + Floating point square root. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fma", + r#" + Floating point fused multiply-and-add. + + Computes :math:`a := xy+z` without any intermediate rounding of the + product. + "#, + ) + .operands_in(vec![x, y, z]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc("a", Float, "``x`` with its sign bit inverted"); + + ig.push( + Inst::new( + "fneg", + r#" + Floating point negation. + + Note that this is a pure bitwise operation. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc("a", Float, "``x`` with its sign bit cleared"); + + ig.push( + Inst::new( + "fabs", + r#" + Floating point absolute value. + + Note that this is a pure bitwise operation. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc( + "a", + Float, + "``x`` with its sign bit changed to that of ``y``", + ); + + ig.push( + Inst::new( + "fcopysign", + r#" + Floating point copy sign. + + Note that this is a pure bitwise operation. The sign bit from ``y`` is + copied to the sign bit of ``x``. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc("a", Float, "The smaller of ``x`` and ``y``"); + + ig.push( + Inst::new( + "fmin", + r#" + Floating point minimum, propagating NaNs. + + If either operand is NaN, this returns a NaN. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc("a", Float, "The larger of ``x`` and ``y``"); + + ig.push( + Inst::new( + "fmax", + r#" + Floating point maximum, propagating NaNs. + + If either operand is NaN, this returns a NaN. + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let a = &operand_doc("a", Float, "``x`` rounded to integral value"); + + ig.push( + Inst::new( + "ceil", + r#" + Round floating point round to integral, towards positive infinity. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "floor", + r#" + Round floating point round to integral, towards negative infinity. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "trunc", + r#" + Round floating point round to integral, towards zero. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "nearest", + r#" + Round floating point round to integral, towards nearest with ties to + even. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let Cond = &operand("Cond", intcc); + let f = &operand("f", iflags); + let a = &operand("a", b1); + + ig.push( + Inst::new( + "trueif", + r#" + Test integer CPU flags for a specific condition. + + Check the CPU flags in ``f`` against the ``Cond`` condition code and + return true when the condition code is satisfied. + "#, + ) + .operands_in(vec![Cond, f]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let Cond = &operand("Cond", floatcc); + let f = &operand("f", fflags); + + ig.push( + Inst::new( + "trueff", + r#" + Test floating point CPU flags for a specific condition. + + Check the CPU flags in ``f`` against the ``Cond`` condition code and + return true when the condition code is satisfied. + "#, + ) + .operands_in(vec![Cond, f]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", Mem); + let a = &operand_doc("a", MemTo, "Bits of `x` reinterpreted"); + + ig.push( + Inst::new( + "bitcast", + r#" + Reinterpret the bits in `x` as a different type. + + The input and output types must be storable to memory and of the same + size. A bitcast is equivalent to storing one type and loading the other + type from the same address. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let Bool = &TypeVar::new( + "Bool", + "A scalar or vector boolean type", + TypeSetBuilder::new() + .bools(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let BoolTo = &TypeVar::new( + "BoolTo", + "A smaller boolean type with the same number of lanes", + TypeSetBuilder::new() + .bools(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let x = &operand("x", Bool); + let a = &operand("a", BoolTo); + + ig.push( + Inst::new( + "breduce", + r#" + Convert `x` to a smaller boolean type in the platform-defined way. + + The result type must have the same number of vector lanes as the input, + and each lane must not have more bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(Bool.clone(), BoolTo.clone())]) + .finish(format_registry), + ); + + let BoolTo = &TypeVar::new( + "BoolTo", + "A larger boolean type with the same number of lanes", + TypeSetBuilder::new() + .bools(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Bool); + let a = &operand("a", BoolTo); + + ig.push( + Inst::new( + "bextend", + r#" + Convert `x` to a larger boolean type in the platform-defined way. + + The result type must have the same number of vector lanes as the input, + and each lane must not have fewer bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(BoolTo.clone(), Bool.clone())]) + .finish(format_registry), + ); + + let IntTo = &TypeVar::new( + "IntTo", + "An integer type with the same number of lanes", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Bool); + let a = &operand("a", IntTo); + + ig.push( + Inst::new( + "bint", + r#" + Convert `x` to an integer. + + True maps to 1 and false maps to 0. The result type must have the same + number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "bmask", + r#" + Convert `x` to an integer mask. + + True maps to all 1s and false maps to all 0s. The result type must have + the same number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let Int = &TypeVar::new( + "Int", + "A scalar or vector integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + + let IntTo = &TypeVar::new( + "IntTo", + "A smaller integer type with the same number of lanes", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Int); + let a = &operand("a", IntTo); + + ig.push( + Inst::new( + "ireduce", + r#" + Convert `x` to a smaller integer type by dropping high bits. + + Each lane in `x` is converted to a smaller integer type by discarding + the most significant bits. This is the same as reducing modulo + :math:`2^n`. + + The result type must have the same number of vector lanes as the input, + and each lane must not have more bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(Int.clone(), IntTo.clone())]) + .finish(format_registry), + ); + + let IntTo = &TypeVar::new( + "IntTo", + "A larger integer type with the same number of lanes", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Int); + let a = &operand("a", IntTo); + + ig.push( + Inst::new( + "uextend", + r#" + Convert `x` to a larger integer type by zero-extending. + + Each lane in `x` is converted to a larger integer type by adding + zeroes. The result has the same numerical value as `x` when both are + interpreted as unsigned integers. + + The result type must have the same number of vector lanes as the input, + and each lane must not have fewer bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "sextend", + r#" + Convert `x` to a larger integer type by sign-extending. + + Each lane in `x` is converted to a larger integer type by replicating + the sign bit. The result has the same numerical value as `x` when both + are interpreted as signed integers. + + The result type must have the same number of vector lanes as the input, + and each lane must not have fewer bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]) + .finish(format_registry), + ); + + let FloatTo = &TypeVar::new( + "FloatTo", + "A scalar or vector floating point number", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", Float); + let a = &operand("a", FloatTo); + + ig.push( + Inst::new( + "fpromote", + r#" + Convert `x` to a larger floating point format. + + Each lane in `x` is converted to the destination floating point format. + This is an exact operation. + + Cranelift currently only supports two floating point formats + - :type:`f32` and :type:`f64`. This may change in the future. + + The result type must have the same number of vector lanes as the input, + and the result lanes must not have fewer bits than the input lanes. If + the input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(FloatTo.clone(), Float.clone())]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fdemote", + r#" + Convert `x` to a smaller floating point format. + + Each lane in `x` is converted to the destination floating point format + by rounding to nearest, ties to even. + + Cranelift currently only supports two floating point formats + - :type:`f32` and :type:`f64`. This may change in the future. + + The result type must have the same number of vector lanes as the input, + and the result lanes must not have more bits than the input lanes. If + the input and output types are the same, this is a no-op. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .constraints(vec![WiderOrEq(Float.clone(), FloatTo.clone())]) + .finish(format_registry), + ); + + let x = &operand("x", Float); + let a = &operand("a", IntTo); + + ig.push( + Inst::new( + "fcvt_to_uint", + r#" + Convert floating point to unsigned integer. + + Each lane in `x` is converted to an unsigned integer by rounding + towards zero. If `x` is NaN or if the unsigned integral value cannot be + represented in the result type, this instruction traps. + + The result type must have the same number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fcvt_to_uint_sat", + r#" + Convert floating point to unsigned integer as fcvt_to_uint does, but + saturates the input instead of trapping. NaN and negative values are + converted to 0. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fcvt_to_sint", + r#" + Convert floating point to signed integer. + + Each lane in `x` is converted to a signed integer by rounding towards + zero. If `x` is NaN or if the signed integral value cannot be + represented in the result type, this instruction traps. + + The result type must have the same number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .can_trap(true) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fcvt_to_sint_sat", + r#" + Convert floating point to signed integer as fcvt_to_sint does, but + saturates the input instead of trapping. NaN values are converted to 0. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let x = &operand("x", Int); + let a = &operand("a", FloatTo); + + ig.push( + Inst::new( + "fcvt_from_uint", + r#" + Convert unsigned integer to floating point. + + Each lane in `x` is interpreted as an unsigned integer and converted to + floating point using round to nearest, ties to even. + + The result type must have the same number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + ig.push( + Inst::new( + "fcvt_from_sint", + r#" + Convert signed integer to floating point. + + Each lane in `x` is interpreted as a signed integer and converted to + floating point using round to nearest, ties to even. + + The result type must have the same number of vector lanes as the input. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]) + .finish(format_registry), + ); + + let WideInt = &TypeVar::new( + "WideInt", + "An integer type with lanes from `i16` upwards", + TypeSetBuilder::new() + .ints(16..64) + .simd_lanes(Interval::All) + .finish(), + ); + let x = &operand("x", WideInt); + let lo = &operand_doc("lo", &WideInt.half_width(), "The low bits of `x`"); + let hi = &operand_doc("hi", &WideInt.half_width(), "The high bits of `x`"); + + ig.push( + Inst::new( + "isplit", + r#" + Split an integer into low and high parts. + + Vectors of integers are split lane-wise, so the results have the same + number of lanes as the input, but the lanes are half the size. + + Returns the low half of `x` and the high half of `x` as two independent + values. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![lo, hi]) + .is_ghost(true) + .finish(format_registry), + ); + + let NarrowInt = &TypeVar::new( + "NarrowInt", + "An integer type with lanes type to `i32`", + TypeSetBuilder::new() + .ints(8..32) + .simd_lanes(Interval::All) + .finish(), + ); + + let lo = &operand("lo", NarrowInt); + let hi = &operand("hi", NarrowInt); + let a = &operand_doc( + "a", + &NarrowInt.double_width(), + "The concatenation of `lo` and `hi`", + ); + + ig.push( + Inst::new( + "iconcat", + r#" + Concatenate low and high bits to form a larger integer type. + + Vectors of integers are concatenated lane-wise such that the result has + the same number of lanes as the inputs, but the lanes are twice the + size. + "#, + ) + .operands_in(vec![lo, hi]) + .operands_out(vec![a]) + .is_ghost(true) + .finish(format_registry), + ); + + ig +} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs b/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs index bdd9a14f2c3f..0e6a11f0e1a2 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs @@ -1,4 +1,59 @@ //! Shared definitions for the Cranelift intermediate language. +pub mod entities; +pub mod formats; +pub mod immediates; +pub mod instructions; pub mod settings; pub mod types; + +use crate::cdsl::formats::FormatRegistry; +use crate::cdsl::inst::InstructionGroup; +use crate::cdsl::operands::OperandKind; +use crate::cdsl::settings::SettingGroup; + +pub struct Definitions { + pub settings: SettingGroup, + pub instructions: InstructionGroup, + pub operand_kinds: OperandKinds, + pub format_registry: FormatRegistry, +} + +pub struct OperandKinds(Vec); + +impl OperandKinds { + pub fn new() -> Self { + Self(Vec::new()) + } + + pub fn by_name(&self, name: &'static str) -> &OperandKind { + self.0 + .iter() + .find(|op| op.name == name) + .expect(&format!("unknown Operand name: {}", name)) + } + + pub fn push(&mut self, operand_kind: OperandKind) { + assert!( + self.0 + .iter() + .find(|existing| existing.name == operand_kind.name) + .is_none(), + "trying to insert operand kind '{}' for the second time", + operand_kind.name + ); + self.0.push(operand_kind); + } +} + +pub fn define() -> Definitions { + let immediates = OperandKinds(immediates::define()); + let entities = OperandKinds(entities::define()); + let format_registry = formats::define(&immediates, &entities); + Definitions { + settings: settings::define(), + instructions: instructions::define(&format_registry, &immediates, &entities), + operand_kinds: immediates, + format_registry, + } +} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs b/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs index b792a7228337..c89efa6b02e5 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs @@ -1,6 +1,6 @@ use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; -pub fn generate() -> SettingGroup { +pub fn define() -> SettingGroup { let mut settings = SettingGroupBuilder::new("shared"); settings.add_enum( diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/types.rs b/third_party/rust/cranelift-codegen-meta/src/shared/types.rs index 7ce42b1978e9..aff837252bfc 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/types.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/types.rs @@ -113,7 +113,7 @@ impl Iterator for FloatIterator { /// A type representing CPU flags. /// /// Flags can't be stored in memory. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum Flag { /// CPU flags from an integer comparison. IFlags, diff --git a/third_party/rust/cranelift-codegen-meta/src/srcgen.rs b/third_party/rust/cranelift-codegen-meta/src/srcgen.rs index dc7f622940cf..9a6c4af03834 100644 --- a/third_party/rust/cranelift-codegen-meta/src/srcgen.rs +++ b/third_party/rust/cranelift-codegen-meta/src/srcgen.rs @@ -25,6 +25,14 @@ macro_rules! fmtln { ($fmt:ident, $arg:expr) => { $fmt.line($arg); }; + + ($_:tt, $($args:expr),+) => { + compile_error!("This macro requires at least two arguments: the Formatter instance and a format string."); + }; + + ($_:tt) => { + compile_error!("This macro requires at least two arguments: the Formatter instance and a format string."); + }; } pub struct Formatter { @@ -84,6 +92,11 @@ impl Formatter { self.lines.push(indented_line); } + /// Pushes an empty line. + pub fn empty_line(&mut self) { + self.lines.push("\n".to_string()); + } + /// Emit a line outdented one level. pub fn _outdented_line(&mut self, s: &str) { let new_line = format!("{}{}", self._get_outdent(), s); @@ -112,7 +125,7 @@ impl Formatter { } /// Add one or more lines after stripping common indentation. - pub fn _multi_line(&mut self, s: &str) { + pub fn multi_line(&mut self, s: &str) { parse_multiline(s).into_iter().for_each(|l| self.line(&l)); } @@ -141,7 +154,7 @@ impl Formatter { self.indent(|fmt| { for (&(ref fields, ref body), ref names) in m.arms.iter() { // name { fields } | name { fields } => { body } - let conditions: Vec = names + let conditions = names .iter() .map(|name| { if fields.len() > 0 { @@ -150,9 +163,20 @@ impl Formatter { name.clone() } }) - .collect(); - let lhs = conditions.join(" | "); - fmtln!(fmt, "{} => {{", lhs); + .collect::>() + .join(" |\n") + + " => {"; + + fmt.multi_line(&conditions); + fmt.indent(|fmt| { + fmt.line(body); + }); + fmt.line("}"); + } + + // Make sure to include the catch all clause last. + if let Some(body) = m.catch_all { + fmt.line("_ => {"); fmt.indent(|fmt| { fmt.line(body); }); @@ -239,27 +263,57 @@ fn parse_multiline(s: &str) -> Vec { pub struct Match { expr: String, arms: BTreeMap<(Vec, String), BTreeSet>, + /// The clause for the placeholder pattern _. + catch_all: Option, } impl Match { /// Create a new match statement on `expr`. - pub fn new>(expr: T) -> Self { + pub fn new(expr: impl Into) -> Self { Self { expr: expr.into(), arms: BTreeMap::new(), + catch_all: None, } } - /// Add an arm to the Match statement. - pub fn arm>(&mut self, name: T, fields: Vec, body: T) { - // let key = (fields, body); + fn set_catch_all(&mut self, clause: String) { + assert!(self.catch_all.is_none()); + self.catch_all = Some(clause); + } + + /// Add an arm that reads fields to the Match statement. + pub fn arm, S: Into>(&mut self, name: T, fields: Vec, body: T) { + let name = name.into(); + assert!( + name != "_", + "catch all clause can't extract fields, use arm_no_fields instead." + ); + let body = body.into(); let fields = fields.into_iter().map(|x| x.into()).collect(); let match_arm = self .arms .entry((fields, body)) .or_insert_with(BTreeSet::new); - match_arm.insert(name.into()); + match_arm.insert(name); + } + + /// Adds an arm that doesn't read anythings from the fields to the Match statement. + pub fn arm_no_fields(&mut self, name: impl Into, body: impl Into) { + let body = body.into(); + + let name = name.into(); + if name == "_" { + self.set_catch_all(body); + return; + } + + let match_arm = self + .arms + .entry((Vec::new(), body)) + .or_insert_with(BTreeSet::new); + match_arm.insert(name); } } @@ -296,7 +350,8 @@ match x { Green { a, b } => { different body } - Orange { a, b } | Yellow { a, b } => { + Orange { a, b } | + Yellow { a, b } => { some body } Blue { x, y } => { @@ -308,6 +363,36 @@ match x { assert_eq!(fmt.lines, expected_lines); } + #[test] + fn match_with_catchall_order() { + // The catchall placeholder must be placed after other clauses. + let mut m = Match::new("x"); + m.arm("Orange", vec!["a", "b"], "some body"); + m.arm("Green", vec!["a", "b"], "different body"); + m.arm_no_fields("_", "unreachable!()"); + assert_eq!(m.arms.len(), 2); // catchall is not counted + + let mut fmt = Formatter::new(); + fmt.add_match(m); + + let expected_lines = from_raw_string( + r#" +match x { + Green { a, b } => { + different body + } + Orange { a, b } => { + some body + } + _ => { + unreachable!() + } +} + "#, + ); + assert_eq!(fmt.lines, expected_lines); + } + #[test] fn parse_multiline_works() { let input = "\n hello\n world\n"; diff --git a/third_party/rust/cranelift-codegen-meta/src/unique_table.rs b/third_party/rust/cranelift-codegen-meta/src/unique_table.rs index 8e325cdeed8b..d7a26f67cc3f 100644 --- a/third_party/rust/cranelift-codegen-meta/src/unique_table.rs +++ b/third_party/rust/cranelift-codegen-meta/src/unique_table.rs @@ -1,21 +1,76 @@ +use std::collections::HashMap; +use std::hash::Hash; use std::slice; +/// Collect items into the `table` list, removing duplicates. +pub struct UniqueTable<'entries, T: Eq + Hash> { + table: Vec<&'entries T>, + map: HashMap<&'entries T, usize>, +} + +impl<'entries, T: Eq + Hash> UniqueTable<'entries, T> { + pub fn new() -> Self { + Self { + table: Vec::new(), + map: HashMap::new(), + } + } + + pub fn add(&mut self, entry: &'entries T) -> usize { + match self.map.get(&entry) { + None => { + let i = self.table.len(); + self.table.push(entry); + self.map.insert(entry, i); + i + } + Some(&i) => i, + } + } + + pub fn len(&self) -> usize { + self.table.len() + } + pub fn iter(&self) -> slice::Iter<&'entries T> { + self.table.iter() + } +} + /// A table of sequences which tries to avoid common subsequences. -pub struct UniqueTable { +pub struct UniqueSeqTable { table: Vec, } -impl UniqueTable { +impl UniqueSeqTable { pub fn new() -> Self { Self { table: Vec::new() } } pub fn add(&mut self, values: &Vec) -> usize { + if values.len() == 0 { + return 0; + } if let Some(offset) = find_subsequence(values, &self.table) { offset } else { - let offset = self.table.len(); - self.table.extend((*values).clone()); - offset + let table_len = self.table.len(); + + // Try to put in common the last elements of the table if they're a prefix of the new + // sequence. + // + // We know there wasn't a full match, so the best prefix we can hope to find contains + // all the values but the last one. + let mut start_from = usize::min(table_len, values.len() - 1); + while start_from != 0 { + // Loop invariant: start_from <= table_len, so table_len - start_from >= 0. + if values[0..start_from] == self.table[table_len - start_from..table_len] { + break; + } + start_from -= 1; + } + + self.table + .extend(values[start_from..values.len()].iter().cloned()); + table_len - start_from } } pub fn len(&self) -> usize { @@ -35,17 +90,10 @@ fn find_subsequence(sub: &Vec, whole: &Vec) -> Option if whole.len() < sub.len() { return None; } - let max = whole.len() + 1 - sub.len(); - for i in 0..max { - let mut found: Option = Some(i); - for j in 0..sub.len() { - if sub[j] != whole[i + j] { - found = None; - break; - } - } - if found.is_some() { - return found; + let max = whole.len() - sub.len(); + for i in 0..max + 1 { + if whole[i..i + sub.len()] == sub[..] { + return Some(i); } } return None; @@ -66,3 +114,24 @@ fn test_find_subsequence() { Some(1) ); } + +#[test] +fn test_optimal_add() { + let mut seq_table = UniqueSeqTable::new(); + // [0, 1, 2, 3] + assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0); + assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0); + assert_eq!(seq_table.add(&vec![1, 2, 3]), 1); + assert_eq!(seq_table.add(&vec![2, 3]), 2); + assert_eq!(seq_table.len(), 4); + // [0, 1, 2, 3, 4] + assert_eq!(seq_table.add(&vec![2, 3, 4]), 2); + assert_eq!(seq_table.len(), 5); + // [0, 1, 2, 3, 4, 6, 5, 7] + assert_eq!(seq_table.add(&vec![4, 6, 5, 7]), 4); + assert_eq!(seq_table.len(), 8); + // [0, 1, 2, 3, 4, 6, 5, 7, 8, 2, 3, 4] + assert_eq!(seq_table.add(&vec![8, 2, 3, 4]), 8); + assert_eq!(seq_table.add(&vec![8]), 8); + assert_eq!(seq_table.len(), 12); +} diff --git a/third_party/rust/cranelift-codegen/.cargo-checksum.json b/third_party/rust/cranelift-codegen/.cargo-checksum.json index 5f85db8eea0a..072e257db885 100644 --- a/third_party/rust/cranelift-codegen/.cargo-checksum.json +++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"54c100144feac8a32407bcb411f7371d84edfcd9dcb464df6373406a9824caac","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"7c0919d12ff966e0c400e7cfa0a555b2e50ede20c0dfb4f4401e35a828134ea9","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"0e146dd56dfb93cac88f9557a3501c9804cff584c2723db27435842bb5e2a1b7","meta-python/base/formats.py":"f9fb41210bc1f99a78cb7a60ee9f01c603412c6b1db7e69abbcc0f573cf9fb40","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"4f92066dc9cfa651e395afc8956b1a082b4e8591c6f7310db89593ff55322e2b","meta-python/base/legalize.py":"8455a5c7428e98d23e432d7be28cc863804781013ac614ba57f6d231cd810d28","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"97fca9ddaab347f50f1594c93283f8f474e53a7232eae65949f56a6a702c2bba","meta-python/base/types.py":"9616d6fe4cab050827ab02eeb9843eacebbb8f7555521f504b5ee2ddf7214fdb","meta-python/build.py":"5668220ffa5106c0890157ee2839870264ec8eaf60c99ddf5d5bd2d2cf57b100","meta-python/cdsl/__init__.py":"b534ec129a0e517f0d13313c2b4bb3a345d3e5b62693a31d8d42c80a219e39fa","meta-python/cdsl/ast.py":"832ac98dddea88f4f8a608ac6ac3fda009a15b52abacca30cf39e3787154521c","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"b0ddfd8fd22889bd1e610c103d47087c9c6ae5882862ed44921dafc2ae0463a0","meta-python/cdsl/isa.py":"dc530a4dd5642e3379398dfc8a90ad6ae1692302de63851370bdfa8abf4cdce0","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"fe2dc6e78ff6d4bcb6b1d5448ded343ede0f03b96a965a11aef0f5bbe7bb8f56","meta-python/cdsl/registers.py":"939dafd1b8976a6cd456c9a5e4b374af81fafb9da979ea3a1f6d14e4645914a6","meta-python/cdsl/settings.py":"a859bd006e13b245ff906977512cd4822c3b22601ed17e87ce0618503172809f","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"04656e2da99ec37875f91172bb2fa423da1ee27bf523a4d41af311ea22492d1b","meta-python/cdsl/test_typevar.py":"768bf3c35481950264ad6fd7059a532ac62b121ac439983bb4fe1ae76a1d1248","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"566e91f0bb3ebacd5abf9f5a663caee69706c2e829dee1ed735d229198689f76","meta-python/cdsl/types.py":"adee4bbc1a9478288fa4b53ee1edeb5ee3296dba2c70bfbe01e923895064999e","meta-python/cdsl/typevar.py":"b5669934eddaf5b9cc0c27b966e2566b5f669f1c5a345f005960930fb499097e","meta-python/cdsl/xform.py":"bf200b711570b905f0fb30611ba64f131f98593060eedbe5575054cca4928593","meta-python/check.sh":"707cda14534882e8d4593f93c056390560394c9bc8a687e99f10a56d7b09cb92","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"53bbdd591c91f8e28da95e4da02c9299a01a32d8be6a0c7490b6b7c60a4fbebe","meta-python/gen_encoding.py":"471c5f4ecf24a2a173864c62a48920e5fbe1aacd2229b3eb4483637570bb26b2","meta-python/gen_instr.py":"154702c5e9e875561f73d330971bfc9985f0a8303b7afa290014ee830bad108f","meta-python/gen_legalizer.py":"4108393f261e8e0f0757709072eefcafc2f68aad290aff3e5bbf30e283e87968","meta-python/gen_settings.py":"f13e47335ae87b6381134b3d334f2fcbdfc03da92a8864dd1ff1c026408062a7","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"3852e5b7aa6995fa721ba91744a0470343ce1834651e7b9cc97b5d69af7dfdc5","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"3885bcb2558e754de812f8239b4b509a32a42bcb8d3158d0b8899b18f3d90ac5","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"c9d7910cd4311ee4307460ca55070404e212727814664f2a2096b9b702ff7178","meta-python/isa/x86/registers.py":"ff934491d07ec6b51fbfd454b865a7c7c191ffbd31b1804615735266b120f4b2","meta-python/isa/x86/settings.py":"d779a768475cf00c2a8d3ddb5cd0a70ce34662e0ebb52ee26a7e1a495ec41aa2","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"c9dd72fde0ab020d3328dde532d92b39e438e4147930e41df7613c27727e11eb","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"48ef80320f21682860bbf5f79f18739f1d10f0b1fe581ebb05541e90dc2f2f4f","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_gen_legalizer.py":"d7da85622f142d2d66d0b92660b6f04b1424788bac05e6fbe0e5822b54dec705","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"ad79459de45431b04f28a296074d3613e804538911fbfd451b68058218594574","src/binemit/mod.rs":"bfd83cb1e23e7b2f6926134e1e57548af240036128033f19e557f4d130133e87","src/binemit/relaxation.rs":"7a8399d83f230acf3f2f1e2bb0248691651f196610f6d121710c6842ff2ae008","src/binemit/shrink.rs":"45434d5fb17804f5199f5fa80fd96aedaeac1ca3824766236eb16b6b529155b4","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"69b4f16132c886ef0b883c8b78b59d041ceec3c8b96dd8015e990ac06733ce91","src/constant_hash.rs":"330e8289789ee351d0abeaf4b5e859b8db8772306e0820d34864fc9905d53b38","src/context.rs":"ffd7d2324107a17bdf710a17e8acf54d58fdd92d7ba8fdd340c16655d5aa1d00","src/cursor.rs":"dcce946ad85d8fc2f1c9cc885ae8a0440c37d9e512606fb8a518aaffcc6d6f8f","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"8d475dae5281805137134dd373ade91b3ee2a861028b7c1165cf9b17727aa45d","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"bf520026c32c5454554d0b078b64a78bd44f3c0f4f198eddf71bcfd78cc963a3","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"1a12c57f4168fa3c2fcf6be2f19d0d377eee40f24ae4390e6ba9d954f85a8a3e","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/dfg.rs":"50a3a7c44b6a993f033a65682beaeae12d5ed78ff67d7ac5e205e645ef8e122f","src/ir/entities.rs":"8bae1166b59afd38953e7d9154ae141c979ab77153b9512f45db7b82a256fdf4","src/ir/extfunc.rs":"9806734eeb480724481128d8c1de78a3b1f80f1214c20f24131196a0df137872","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"907c4658865559c27fe4ee2f4064d0c64add712f2a190185236dba3cb98d4c32","src/ir/globalvalue.rs":"1f6125788a9a5c118716f87fd72e85009d2e0a7f4c13b2a7904be8c7412ee4eb","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"029a8aa905e6fd0f3334e17a28e73ac36684df2ca0829dcae0158ea8cf64ca8c","src/ir/instructions.rs":"2180de1d127ab5878c5743d8e096d551edb973e0ff1d373c4239c32e7981364c","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"55fd77f6e32370812a271f4fd5d9817c03904733be79d49e17e2683fe516e30e","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"ec1da8a8bd99a3dbbcea59e2c10aa60511488471930646ab293f47d428013224","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"37ef5fd8cef1de99620797d7d5aba3630e737171853c8471495c685dafac19b6","src/ir/stackslot.rs":"2f54359339837bb1d0d817d3af21bb4b1b050c31703885dfaced29f6e41153c2","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"1f644beba2c797f7bd89378d930c3eca1491ec5f82c4715945ac63a0a5754473","src/ir/valueloc.rs":"4c676c2d21d75611ef922a230ee82846afb565ce0f55bc71e33c70e1a1d92a07","src/isa/arm32/abi.rs":"fc4ae5286491cf7e49ca1123264c083cc37ba95a130b07406f79a3a31a0dbe39","src/isa/arm32/binemit.rs":"52b2f4b3c6d8683ed6963c1f53907ac57b6aab7cc149464c9a12d6875aa3b5c6","src/isa/arm32/enc_tables.rs":"b5b7f2fdcaf1d1878a357c54ab757e94f0d06e5bd391ac5d876e96f5b30d6b7a","src/isa/arm32/mod.rs":"3256e671c2d622c3c25b6551c571c8c3008b5433bdbe0a90b3cb5a667319922b","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"188f3cc445168b472b488e73b011e83edd31ac17e3841dacda07a55ccf923468","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"4465cceb68d03ae4d0fdf188c9b86870fb57b3617d67f0bb7d476e5afb581e81","src/isa/arm64/enc_tables.rs":"8c829c544daeed9adc8458891614a0be6f149e775bd22651465f2c165d4a9e56","src/isa/arm64/mod.rs":"f9ca60e7407b69595cb4ef42103ed079e7bcb40546f11d944ddcfc6a04a7fd11","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"0dff47e995e5d9740deb0116b59e91fbcb725a7fa1bdbd802bf83c13381b17f7","src/isa/call_conv.rs":"833ac811ff78ab8d3a5052165e76c51c6da7686020d95462c18074750fb790ed","src/isa/constraints.rs":"f2e2dee4308dabaab1071983d2edd9a9972a99c5c99edf919adbb4554b4eb067","src/isa/enc_tables.rs":"3497f3d701f21d6f952424abf31515fde9e67aea1cde26236c9ee8b033c61ae6","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"40ab1c6d86f903a88bc7ef83b7cdcbee0eedbfdf7112fb7a6749c0c8cc9ee42c","src/isa/registers.rs":"4a91d4888df5eeed1802f34c43a42b82aaf1f9928a58329b0cbc9c3c57c75485","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"0bd76b005b53b71bdb59057a20671fbcd8ab1c37d767bfd4ab0a92d05e192d9a","src/isa/riscv/enc_tables.rs":"ab73c80fef6b1256fbd3c0e1bdd8e43a20f7d132a32236f6bfc028e9003adfe0","src/isa/riscv/mod.rs":"377dfc7dc9940d284b21bf3d2433916dd9c3df79cce172a2a75ef572dcafe98f","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"d018d23418ff3fb98571bcdeeddde3277bf213b4b8ac1e55b6573e128b3931ce","src/isa/stack.rs":"d023c57feb944c94c4dc8b7138dcbc9d37ff18ca23c23d83e9bab3c88299ffa0","src/isa/x86/abi.rs":"c0ba5b15498735a694bf0b89c714f6f7126053127f5e0f1eacbda1e3c670d49c","src/isa/x86/binemit.rs":"328f5803717e095abbda0d0a49a79b8f5250a6d16a739a5912ee0a71f276d9de","src/isa/x86/enc_tables.rs":"250ab677b2a316f9826495a0719f71f4b54b3c3c26d0bb42a76dd85b55a2f8e3","src/isa/x86/mod.rs":"15488d60a950aa4cb75afb63d42d4524e1fcea3b77c7c160e2cb862ec2236a92","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"cd8f8c5255663f6e247f0634088b16b53d785ee8c62cb5c0926b3d27597c12ff","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"435707e84b5e406843238d27f5cc4886f4ae37e2c4d25a749e189a378b3af632","src/legalizer/call.rs":"6a82a9daeba5f452a7db0c47dcc43829b119b0652961bc2aa336b809c3f34ef1","src/legalizer/globalvalue.rs":"896f59dc5b8c4a5aee45e3f59211066f214d3ab9142865d80ad6610633363ac9","src/legalizer/heap.rs":"4caf9b5f98556364f16164613872c29a457dcbf44b07cc49fc415abbcd61ec6c","src/legalizer/libcall.rs":"6e58da5e1c2419192a3393debc6e9714df9728e59e1740ff569e8a9c0daa40d5","src/legalizer/mod.rs":"7df6ed89a80c9dab7f6e3ddbedcb1c4bcc86c3c6e5bdc3e71e51d5322cb1ce52","src/legalizer/split.rs":"f867daab5a4ec1549134cceb2d7223e901d87a052a8a3d70d7d8372b56716b1a","src/legalizer/table.rs":"d6e09f8340ca597fdb13f86021e5c53bd3161dc4258effc56c1f6d9be7b819ec","src/lib.rs":"12855b9aedb583859a89dd8f8a7e1ff6d6c9f68e938f60ff4d123aa3d98c2da5","src/licm.rs":"8193118dc09ada8bed5ba6c8d68dbf88fb7b0a2e268dd7b0139586b88a0408be","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"daadbf95ec5a2907fe40d8586364d7ee981732936992e7b6d0cae5a03e66f836","src/predicates.rs":"44bbc09ae0c7d5b54c05eb6061b062e92d1893edc7dda43ae2bccfedc6bb25e3","src/print_errors.rs":"0955151433563b4c305c78b9a8f192c5fe0556ac2528a5ede3b2fd4d143eb743","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"66ee6b9789ec207393c318b14177e1439a54f197b13ebefdb0c4ab77acf38c00","src/regalloc/coalescing.rs":"1426db3ee18469232678ee6975585533772fa9291c5be3cf463437b8184c591e","src/regalloc/coloring.rs":"72bef8b5e3425c805d62cf2329acd29510f1be0886ee73308b69938cf2de203f","src/regalloc/context.rs":"a7da41171ad73cd541977657f0af0d5308567fff140fa7eb7ee44e03c62d8c96","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"cc904b813a8a2fc819f0cd5ffacb5a4b82f29ae3ae6a34cccc01fc47c20d150f","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"c9d1098266c5b8b89eff84a55be3bc4838b70416c2446edf57f5257a6232d059","src/regalloc/register_set.rs":"bc58f93f22f0adbe43260fe20c6089be1fca64f5bcc4acff85dc0a5ec5b61937","src/regalloc/reload.rs":"4dd64aacc97fda5e950222df37df20bf2281cfbca93d1945f3a4f25e4b867aac","src/regalloc/solver.rs":"e2a6d2782d213676dec9781aeb5a37806e092d6daac3249a6cd4d4c92a9d117f","src/regalloc/spilling.rs":"00b5def89c310b1756826f497aa53c050757dd1d5c5fe490f7aff85f7cb94fcf","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"23eb1461f7f02f4e26cca71ddc72ead7887bb1aec64b04eb6eb0397c402bf3c8","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"3a576a993312be6a9119fb3180f609988f606f837c4430878e8becca078935ce","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"7328f12bad7767cd3a30cfa361ed40baeae5a7977c1e0592df896809488bb020","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"f4ba0e0c13fd643bdbec6466219a25a33993a6e170debb48497a859d9f79d914","src/verifier/liveness.rs":"2631037bafa88659bc47d2174e261f5acb1702ca522722a597fa28e474994d79","src/verifier/locations.rs":"9623bbc2d2f86f36893eebe60330fd51b99c9f9c8e5162c61cc89ab221e75b5a","src/verifier/mod.rs":"21e92c6b84d885882360794528afb33c828b7a232abab43d0a49a0f0bb3e0043","src/write.rs":"24b5caa5fa9145f8da78b9ef2342f52a05d04318b3b03f5b8bb1d486a3d46041"},"package":"6c3b15a20577e6c823475953a5e25e758d9d3a3148a937d686c09460e5f2f4a0"} \ No newline at end of file +{"files":{"Cargo.toml":"9e1e9d197a2fcdb9bfd3c32a7608ab772ed4301aa0b9f2e60b73c98f542ac760","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"7c0919d12ff966e0c400e7cfa0a555b2e50ede20c0dfb4f4401e35a828134ea9","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"f956b8ba863cd26f6867e13c1b2db3c202e9b07c48c1e43a9c2b41ad0deb8922","meta-python/base/formats.py":"f9fb41210bc1f99a78cb7a60ee9f01c603412c6b1db7e69abbcc0f573cf9fb40","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"4f92066dc9cfa651e395afc8956b1a082b4e8591c6f7310db89593ff55322e2b","meta-python/base/legalize.py":"8455a5c7428e98d23e432d7be28cc863804781013ac614ba57f6d231cd810d28","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"97fca9ddaab347f50f1594c93283f8f474e53a7232eae65949f56a6a702c2bba","meta-python/base/types.py":"9616d6fe4cab050827ab02eeb9843eacebbb8f7555521f504b5ee2ddf7214fdb","meta-python/build.py":"5668220ffa5106c0890157ee2839870264ec8eaf60c99ddf5d5bd2d2cf57b100","meta-python/cdsl/__init__.py":"b534ec129a0e517f0d13313c2b4bb3a345d3e5b62693a31d8d42c80a219e39fa","meta-python/cdsl/ast.py":"832ac98dddea88f4f8a608ac6ac3fda009a15b52abacca30cf39e3787154521c","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"50fe9329a56e6294a27306aad7be22c88a5b5ef42c3b030ec59218167157f62f","meta-python/cdsl/isa.py":"dc530a4dd5642e3379398dfc8a90ad6ae1692302de63851370bdfa8abf4cdce0","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"fe2dc6e78ff6d4bcb6b1d5448ded343ede0f03b96a965a11aef0f5bbe7bb8f56","meta-python/cdsl/registers.py":"939dafd1b8976a6cd456c9a5e4b374af81fafb9da979ea3a1f6d14e4645914a6","meta-python/cdsl/settings.py":"a859bd006e13b245ff906977512cd4822c3b22601ed17e87ce0618503172809f","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"04656e2da99ec37875f91172bb2fa423da1ee27bf523a4d41af311ea22492d1b","meta-python/cdsl/test_typevar.py":"768bf3c35481950264ad6fd7059a532ac62b121ac439983bb4fe1ae76a1d1248","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"566e91f0bb3ebacd5abf9f5a663caee69706c2e829dee1ed735d229198689f76","meta-python/cdsl/types.py":"adee4bbc1a9478288fa4b53ee1edeb5ee3296dba2c70bfbe01e923895064999e","meta-python/cdsl/typevar.py":"b5669934eddaf5b9cc0c27b966e2566b5f669f1c5a345f005960930fb499097e","meta-python/cdsl/xform.py":"bf200b711570b905f0fb30611ba64f131f98593060eedbe5575054cca4928593","meta-python/check.sh":"707cda14534882e8d4593f93c056390560394c9bc8a687e99f10a56d7b09cb92","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"53bbdd591c91f8e28da95e4da02c9299a01a32d8be6a0c7490b6b7c60a4fbebe","meta-python/gen_encoding.py":"471c5f4ecf24a2a173864c62a48920e5fbe1aacd2229b3eb4483637570bb26b2","meta-python/gen_instr.py":"c57caccd6329ca6ab33db1a47e1dafa37e669e4b518808b9b78b28cdf9e221e1","meta-python/gen_legalizer.py":"4108393f261e8e0f0757709072eefcafc2f68aad290aff3e5bbf30e283e87968","meta-python/gen_settings.py":"f13e47335ae87b6381134b3d334f2fcbdfc03da92a8864dd1ff1c026408062a7","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"3852e5b7aa6995fa721ba91744a0470343ce1834651e7b9cc97b5d69af7dfdc5","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"028acd4ba348ba2dfa601217b8d4597748f87cdbfbaeece477150fc09bab50a6","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"c9d7910cd4311ee4307460ca55070404e212727814664f2a2096b9b702ff7178","meta-python/isa/x86/registers.py":"ff934491d07ec6b51fbfd454b865a7c7c191ffbd31b1804615735266b120f4b2","meta-python/isa/x86/settings.py":"d779a768475cf00c2a8d3ddb5cd0a70ce34662e0ebb52ee26a7e1a495ec41aa2","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"c9dd72fde0ab020d3328dde532d92b39e438e4147930e41df7613c27727e11eb","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"48ef80320f21682860bbf5f79f18739f1d10f0b1fe581ebb05541e90dc2f2f4f","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_gen_legalizer.py":"d7da85622f142d2d66d0b92660b6f04b1424788bac05e6fbe0e5822b54dec705","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"ad79459de45431b04f28a296074d3613e804538911fbfd451b68058218594574","src/binemit/mod.rs":"bfd83cb1e23e7b2f6926134e1e57548af240036128033f19e557f4d130133e87","src/binemit/relaxation.rs":"95442e08349762b11dce3d8f5d86adea97d3554a0353d7d519bbabfe18a87b01","src/binemit/shrink.rs":"45434d5fb17804f5199f5fa80fd96aedaeac1ca3824766236eb16b6b529155b4","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"69b4f16132c886ef0b883c8b78b59d041ceec3c8b96dd8015e990ac06733ce91","src/constant_hash.rs":"330e8289789ee351d0abeaf4b5e859b8db8772306e0820d34864fc9905d53b38","src/context.rs":"e5a2d8f608e1af17ee074fe8c791cfed42ec763b4cbb5319d56a8aac7452c69f","src/cursor.rs":"dcce946ad85d8fc2f1c9cc885ae8a0440c37d9e512606fb8a518aaffcc6d6f8f","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"baccf8894bf8113b25fe3c35a16160544557d5a77290e08b27cc50f258973532","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"bf520026c32c5454554d0b078b64a78bd44f3c0f4f198eddf71bcfd78cc963a3","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"1a12c57f4168fa3c2fcf6be2f19d0d377eee40f24ae4390e6ba9d954f85a8a3e","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/dfg.rs":"50a3a7c44b6a993f033a65682beaeae12d5ed78ff67d7ac5e205e645ef8e122f","src/ir/entities.rs":"8bae1166b59afd38953e7d9154ae141c979ab77153b9512f45db7b82a256fdf4","src/ir/extfunc.rs":"9806734eeb480724481128d8c1de78a3b1f80f1214c20f24131196a0df137872","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"907c4658865559c27fe4ee2f4064d0c64add712f2a190185236dba3cb98d4c32","src/ir/globalvalue.rs":"1f6125788a9a5c118716f87fd72e85009d2e0a7f4c13b2a7904be8c7412ee4eb","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"029a8aa905e6fd0f3334e17a28e73ac36684df2ca0829dcae0158ea8cf64ca8c","src/ir/instructions.rs":"2180de1d127ab5878c5743d8e096d551edb973e0ff1d373c4239c32e7981364c","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"55fd77f6e32370812a271f4fd5d9817c03904733be79d49e17e2683fe516e30e","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"ec1da8a8bd99a3dbbcea59e2c10aa60511488471930646ab293f47d428013224","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"37ef5fd8cef1de99620797d7d5aba3630e737171853c8471495c685dafac19b6","src/ir/stackslot.rs":"2f54359339837bb1d0d817d3af21bb4b1b050c31703885dfaced29f6e41153c2","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"1f644beba2c797f7bd89378d930c3eca1491ec5f82c4715945ac63a0a5754473","src/ir/valueloc.rs":"4c676c2d21d75611ef922a230ee82846afb565ce0f55bc71e33c70e1a1d92a07","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"52b2f4b3c6d8683ed6963c1f53907ac57b6aab7cc149464c9a12d6875aa3b5c6","src/isa/arm32/enc_tables.rs":"b5b7f2fdcaf1d1878a357c54ab757e94f0d06e5bd391ac5d876e96f5b30d6b7a","src/isa/arm32/mod.rs":"24492cfe9120a3ebb199b1d0a0b58425c58970bae32349b3cf2dd390ce51e62f","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"188f3cc445168b472b488e73b011e83edd31ac17e3841dacda07a55ccf923468","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"4465cceb68d03ae4d0fdf188c9b86870fb57b3617d67f0bb7d476e5afb581e81","src/isa/arm64/enc_tables.rs":"8c829c544daeed9adc8458891614a0be6f149e775bd22651465f2c165d4a9e56","src/isa/arm64/mod.rs":"f9ca60e7407b69595cb4ef42103ed079e7bcb40546f11d944ddcfc6a04a7fd11","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"0dff47e995e5d9740deb0116b59e91fbcb725a7fa1bdbd802bf83c13381b17f7","src/isa/call_conv.rs":"833ac811ff78ab8d3a5052165e76c51c6da7686020d95462c18074750fb790ed","src/isa/constraints.rs":"f2e2dee4308dabaab1071983d2edd9a9972a99c5c99edf919adbb4554b4eb067","src/isa/enc_tables.rs":"3497f3d701f21d6f952424abf31515fde9e67aea1cde26236c9ee8b033c61ae6","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"40ab1c6d86f903a88bc7ef83b7cdcbee0eedbfdf7112fb7a6749c0c8cc9ee42c","src/isa/registers.rs":"4a91d4888df5eeed1802f34c43a42b82aaf1f9928a58329b0cbc9c3c57c75485","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"0bd76b005b53b71bdb59057a20671fbcd8ab1c37d767bfd4ab0a92d05e192d9a","src/isa/riscv/enc_tables.rs":"ab73c80fef6b1256fbd3c0e1bdd8e43a20f7d132a32236f6bfc028e9003adfe0","src/isa/riscv/mod.rs":"377dfc7dc9940d284b21bf3d2433916dd9c3df79cce172a2a75ef572dcafe98f","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"d018d23418ff3fb98571bcdeeddde3277bf213b4b8ac1e55b6573e128b3931ce","src/isa/stack.rs":"d023c57feb944c94c4dc8b7138dcbc9d37ff18ca23c23d83e9bab3c88299ffa0","src/isa/x86/abi.rs":"98092944de6b8a8171f1c7d24a63d23ee6dc77a5b4048be113582c5362ac0158","src/isa/x86/binemit.rs":"328f5803717e095abbda0d0a49a79b8f5250a6d16a739a5912ee0a71f276d9de","src/isa/x86/enc_tables.rs":"250ab677b2a316f9826495a0719f71f4b54b3c3c26d0bb42a76dd85b55a2f8e3","src/isa/x86/mod.rs":"15488d60a950aa4cb75afb63d42d4524e1fcea3b77c7c160e2cb862ec2236a92","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"cd8f8c5255663f6e247f0634088b16b53d785ee8c62cb5c0926b3d27597c12ff","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"435707e84b5e406843238d27f5cc4886f4ae37e2c4d25a749e189a378b3af632","src/legalizer/call.rs":"6a82a9daeba5f452a7db0c47dcc43829b119b0652961bc2aa336b809c3f34ef1","src/legalizer/globalvalue.rs":"896f59dc5b8c4a5aee45e3f59211066f214d3ab9142865d80ad6610633363ac9","src/legalizer/heap.rs":"4caf9b5f98556364f16164613872c29a457dcbf44b07cc49fc415abbcd61ec6c","src/legalizer/libcall.rs":"6e58da5e1c2419192a3393debc6e9714df9728e59e1740ff569e8a9c0daa40d5","src/legalizer/mod.rs":"7df6ed89a80c9dab7f6e3ddbedcb1c4bcc86c3c6e5bdc3e71e51d5322cb1ce52","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"d6e09f8340ca597fdb13f86021e5c53bd3161dc4258effc56c1f6d9be7b819ec","src/lib.rs":"12855b9aedb583859a89dd8f8a7e1ff6d6c9f68e938f60ff4d123aa3d98c2da5","src/licm.rs":"a4b482c995daf0ecf928a525747316760986a42234331554ae68fe9ef8c7145e","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"f3af3f27496de14e4e65b7efb0748ca11edff8fedd7b57d680b310de5156aa62","src/predicates.rs":"44bbc09ae0c7d5b54c05eb6061b062e92d1893edc7dda43ae2bccfedc6bb25e3","src/print_errors.rs":"0955151433563b4c305c78b9a8f192c5fe0556ac2528a5ede3b2fd4d143eb743","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"66ee6b9789ec207393c318b14177e1439a54f197b13ebefdb0c4ab77acf38c00","src/regalloc/coalescing.rs":"881c8be32eb4d4b34cf208d0dba3e18b8469bc19f19aa7120514c801562392d3","src/regalloc/coloring.rs":"72bef8b5e3425c805d62cf2329acd29510f1be0886ee73308b69938cf2de203f","src/regalloc/context.rs":"a7da41171ad73cd541977657f0af0d5308567fff140fa7eb7ee44e03c62d8c96","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"cc904b813a8a2fc819f0cd5ffacb5a4b82f29ae3ae6a34cccc01fc47c20d150f","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"c9d1098266c5b8b89eff84a55be3bc4838b70416c2446edf57f5257a6232d059","src/regalloc/register_set.rs":"bc58f93f22f0adbe43260fe20c6089be1fca64f5bcc4acff85dc0a5ec5b61937","src/regalloc/reload.rs":"4dd64aacc97fda5e950222df37df20bf2281cfbca93d1945f3a4f25e4b867aac","src/regalloc/solver.rs":"e2a6d2782d213676dec9781aeb5a37806e092d6daac3249a6cd4d4c92a9d117f","src/regalloc/spilling.rs":"f21ae054e6546b0cd774a94bb301517ba341b985223b6db36e6c9ba995eecfd8","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"23eb1461f7f02f4e26cca71ddc72ead7887bb1aec64b04eb6eb0397c402bf3c8","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"3a576a993312be6a9119fb3180f609988f606f837c4430878e8becca078935ce","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"f4ba0e0c13fd643bdbec6466219a25a33993a6e170debb48497a859d9f79d914","src/verifier/liveness.rs":"2631037bafa88659bc47d2174e261f5acb1702ca522722a597fa28e474994d79","src/verifier/locations.rs":"9623bbc2d2f86f36893eebe60330fd51b99c9f9c8e5162c61cc89ab221e75b5a","src/verifier/mod.rs":"21e92c6b84d885882360794528afb33c828b7a232abab43d0a49a0f0bb3e0043","src/write.rs":"24b5caa5fa9145f8da78b9ef2342f52a05d04318b3b03f5b8bb1d486a3d46041"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-codegen/Cargo.toml b/third_party/rust/cranelift-codegen/Cargo.toml index 6b8830784cdc..7a2f2505c851 100644 --- a/third_party/rust/cranelift-codegen/Cargo.toml +++ b/third_party/rust/cranelift-codegen/Cargo.toml @@ -1,70 +1,63 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" -name = "cranelift-codegen" -version = "0.29.0" authors = ["The Cranelift Project Developers"] -build = "build.rs" +name = "cranelift-codegen" +version = "0.30.0" description = "Low-level code generator library" +license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" +repository = "https://github.com/CraneStation/cranelift" +categories = ["no-std"] readme = "README.md" keywords = ["compile", "compiler", "jit"] -categories = ["no-std"] -license = "Apache-2.0 WITH LLVM-exception" -repository = "https://github.com/CraneStation/cranelift" -[dependencies.cranelift-bforest] -version = "0.29.0" -default-features = false +build = "build.rs" +edition = "2018" -[dependencies.cranelift-entity] -version = "0.29.0" -default-features = false +[dependencies] +cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false } +cranelift-bforest = { path = "../cranelift-bforest", version = "0.30.0", default-features = false } +failure = { version = "0.1.1", default-features = false, features = ["derive"] } +failure_derive = { version = "0.1.1", default-features = false } +hashmap_core = { version = "0.1.9", optional = true } +target-lexicon = { version = "0.4.0", default-features = false } +log = { version = "0.4.6", default-features = false } +# It is a goal of the cranelift-codegen crate to have minimal external dependencies. +# Please don't add any unless they are essential to the task of creating binary +# machine code. Integration tests that need external dependencies can be +# accomodated in `tests`. -[dependencies.failure] -version = "0.1.1" -features = ["derive"] -default-features = false - -[dependencies.failure_derive] -version = "0.1.1" -default-features = false - -[dependencies.hashmap_core] -version = "0.1.9" -optional = true - -[dependencies.log] -version = "0.4.6" -default-features = false - -[dependencies.target-lexicon] -version = "0.2.0" -default-features = false -[build-dependencies.cranelift-codegen-meta] -version = "0.29.0" +[build-dependencies] +cranelift-codegen-meta = { path = "meta", version = "0.30.0", default-features = false } [features] +default = ["std", "x86", "arm32", "arm64", "riscv"] + +# The "std" feature enables use of libstd. The "core" feature enables use +# of some minimal std-like replacement libraries. At least one of these two +# features need to be enabled. +std = [ + "cranelift-entity/std", + "cranelift-bforest/std", + "target-lexicon/std", + "cranelift-codegen-meta/std" +] + +# The "core" features enables use of "hashmap_core" since core doesn't have +# a HashMap implementation, and a workaround for Cargo #4866. +core = [ + "hashmap_core", + "cranelift-codegen-meta/core" +] + +# This enables some additional functions useful for writing tests, but which +# can significantly increase the size of the library. +testing_hooks = [] + +# ISA targets for which we should build. +x86 = [] arm32 = [] arm64 = [] -core = ["hashmap_core"] -default = ["std", "x86", "arm32", "arm64", "riscv"] riscv = [] -std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"] -testing_hooks = [] -x86 = [] -[badges.maintenance] -status = "experimental" -[badges.travis-ci] -repository = "CraneStation/cranelift" +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/third_party/rust/cranelift-codegen/meta-python/base/entities.py b/third_party/rust/cranelift-codegen/meta-python/base/entities.py index 7b11810f4876..0226b18ca4db 100644 --- a/third_party/rust/cranelift-codegen/meta-python/base/entities.py +++ b/third_party/rust/cranelift-codegen/meta-python/base/entities.py @@ -19,7 +19,7 @@ stack_slot = EntityRefKind('stack_slot', 'A stack slot.') #: A reference to a global value. global_value = EntityRefKind('global_value', 'A global value.') -#: A reference to a function sugnature declared in the function preamble. +#: A reference to a function signature declared in the function preamble. #: This is used to provide the call signature in a call_indirect instruction. sig_ref = EntityRefKind('sig_ref', 'A function signature.') diff --git a/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py b/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py index 5b2a04d7beb9..34741991da3e 100644 --- a/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py +++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py @@ -252,7 +252,7 @@ class Instruction(object): for opnum in self.value_opnums: typ = self.ins[opnum].typevar tv = typ.free_typevar() - # Non-polymorphic or derived form ctrl_typevar is OK. + # Non-polymorphic or derived from ctrl_typevar is OK. if tv is None or tv is ctrl_typevar: continue # No other derived typevars allowed. diff --git a/third_party/rust/cranelift-codegen/meta-python/gen_instr.py b/third_party/rust/cranelift-codegen/meta-python/gen_instr.py index 1c6905f1cd63..94de93b00083 100644 --- a/third_party/rust/cranelift-codegen/meta-python/gen_instr.py +++ b/third_party/rust/cranelift-codegen/meta-python/gen_instr.py @@ -364,7 +364,7 @@ def gen_opcodes(groups, fmt): # We explicitly set the discriminant of the first variant to 1, which # allows us to take advantage of the NonZero optimization, meaning that # wrapping enums can use the 0 discriminant instead of increasing the size - # if the whole type, and so SIZEOF(Option>) == SIZEOF(Opcode) + # of the whole type, and so SIZEOF(Option>) == SIZEOF(Opcode) is_first_opcode = True with fmt.indented('pub enum Opcode {', '}'): for g in groups: @@ -505,7 +505,7 @@ def gen_type_constraints(fmt, instrs): # Table of operand constraint sequences (as tuples). Each operand # constraint is represented as a string, one of: # - `Concrete(vt)`, where `vt` is a value type name. - # - `Free(idx)` where `idx` isan index into `type_sets`. + # - `Free(idx)` where `idx` is an index into `type_sets`. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. operand_seqs = UniqueSeqTable() diff --git a/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py b/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py index 4ae37c48a214..051b312167cb 100644 --- a/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py +++ b/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py @@ -631,7 +631,7 @@ X86_64.enc(base.uextend.i32.i16, *r.urm_noflags(0x0f, 0xb7)) # movzbq, encoded as movzbl because it's equivalent and shorter X86_64.enc(base.uextend.i64.i8, *r.urm_noflags.rex(0x0f, 0xb6)) -X86_64.enc(base.uextend.i64.i8, *r.urm_noflags(0x0f, 0xb6)) +X86_64.enc(base.uextend.i64.i8, *r.urm_noflags_abcd(0x0f, 0xb6)) # movzwq, encoded as movzwl because it's equivalent and shorter X86_64.enc(base.uextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xb7)) diff --git a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs index 5bfa32364656..c354a763cde5 100644 --- a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs +++ b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs @@ -62,6 +62,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult CodegenResult, relocs: &mut RelocSink, traps: &mut TrapSink, - ) -> CodegenResult<()> { - let code_size = self.compile(isa)?; + ) -> CodegenResult<(CodeOffset, CodeOffset)> { + let total_size = self.compile(isa)?; let old_len = mem.len(); - mem.resize(old_len + code_size as usize, 0); - unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) }; - Ok(()) + mem.resize(old_len + total_size as usize, 0); + let code_size = + unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) }; + Ok((code_size, total_size - code_size)) } /// Compile the function. @@ -111,7 +114,7 @@ impl Context { /// represented by `isa`. This does not include the final step of emitting machine code into a /// code sink. /// - /// Returns the size of the function's code. + /// Returns the size of the function's code and read-only data. pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult { let _tt = timing::compile(); self.verify_if(isa)?; @@ -155,15 +158,19 @@ impl Context { /// /// This function is unsafe since it does not perform bounds checking on the memory buffer, /// and it can't guarantee that the `mem` pointer is valid. + /// + /// Returns the size of the function's code. pub unsafe fn emit_to_memory( &self, isa: &TargetIsa, mem: *mut u8, relocs: &mut RelocSink, traps: &mut TrapSink, - ) { + ) -> CodeOffset { let _tt = timing::binemit(); - isa.emit_function_to_memory(&self.func, &mut MemoryCodeSink::new(mem, relocs, traps)); + let mut sink = MemoryCodeSink::new(mem, relocs, traps); + isa.emit_function_to_memory(&self.func, &mut sink); + sink.code_size as CodeOffset } /// Run the verifier on the function. diff --git a/third_party/rust/cranelift-codegen/src/divconst_magic_numbers.rs b/third_party/rust/cranelift-codegen/src/divconst_magic_numbers.rs index ebf1ae3f128f..30d828774776 100644 --- a/third_party/rust/cranelift-codegen/src/divconst_magic_numbers.rs +++ b/third_party/rust/cranelift-codegen/src/divconst_magic_numbers.rs @@ -246,7 +246,7 @@ mod tests { } #[test] - fn test_magicU32() { + fn test_magic_u32() { assert_eq!(magic_u32(2u32), make_mu32(0x80000000u32, false, 0)); assert_eq!(magic_u32(3u32), make_mu32(0xaaaaaaabu32, false, 1)); assert_eq!(magic_u32(4u32), make_mu32(0x40000000u32, false, 0)); @@ -279,8 +279,9 @@ mod tests { make_mu32(0x80000001u32, false, 31) ); } + #[test] - fn test_magicU64() { + fn test_magic_u64() { assert_eq!(magic_u64(2u64), make_mu64(0x8000000000000000u64, false, 0)); assert_eq!(magic_u64(3u64), make_mu64(0xaaaaaaaaaaaaaaabu64, false, 1)); assert_eq!(magic_u64(4u64), make_mu64(0x4000000000000000u64, false, 0)); @@ -346,8 +347,9 @@ mod tests { make_mu64(0x8000000000000001u64, false, 63) ); } + #[test] - fn test_magicS32() { + fn test_magic_s32() { assert_eq!( magic_s32(-0x80000000i32), make_ms32(0x7fffffffu32 as i32, 30) @@ -390,8 +392,9 @@ mod tests { make_ms32(0x40000001u32 as i32, 29) ); } + #[test] - fn test_magicS64() { + fn test_magic_s64() { assert_eq!( magic_s64(-0x8000000000000000i64), make_ms64(0x7fffffffffffffffu64 as i64, 62) @@ -515,6 +518,7 @@ mod tests { make_ms64(0x4000000000000001u64 as i64, 61) ); } + #[test] fn test_magic_generators_dont_panic() { // The point of this is to check that the magic number generators diff --git a/third_party/rust/cranelift-codegen/src/isa/arm32/abi.rs b/third_party/rust/cranelift-codegen/src/isa/arm32/abi.rs index a1890fa32922..894c67ecb51d 100644 --- a/third_party/rust/cranelift-codegen/src/isa/arm32/abi.rs +++ b/third_party/rust/cranelift-codegen/src/isa/arm32/abi.rs @@ -1,18 +1,88 @@ //! ARM ABI implementation. +//! This is from the RISC-V target and will need to be updated for ARM32. use super::registers::{D, GPR, Q, S}; -use crate::ir; +use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion}; +use crate::ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, Type}; use crate::isa::RegClass; use crate::regalloc::RegisterSet; -use crate::settings as shared_settings; +use core::i32; +use target_lexicon::Triple; + +struct Args { + pointer_bits: u8, + pointer_bytes: u8, + pointer_type: Type, + regs: u32, + reg_limit: u32, + offset: u32, +} + +impl Args { + fn new(bits: u8) -> Self { + Self { + pointer_bits: bits, + pointer_bytes: bits / 8, + pointer_type: Type::int(u16::from(bits)).unwrap(), + regs: 0, + reg_limit: 8, + offset: 0, + } + } +} + +impl ArgAssigner for Args { + fn assign(&mut self, arg: &AbiParam) -> ArgAction { + fn align(value: u32, to: u32) -> u32 { + (value + to - 1) & !(to - 1) + } + + let ty = arg.value_type; + + // Check for a legal type. + // SIMD instructions are currently no implemented, so break down vectors + if ty.is_vector() { + return ValueConversion::VectorSplit.into(); + } + + // Large integers and booleans are broken down to fit in a register. + if !ty.is_float() && ty.bits() > u16::from(self.pointer_bits) { + // Align registers and stack to a multiple of two pointers. + self.regs = align(self.regs, 2); + self.offset = align(self.offset, 2 * u32::from(self.pointer_bytes)); + return ValueConversion::IntSplit.into(); + } + + // Small integers are extended to the size of a pointer register. + if ty.is_int() && ty.bits() < u16::from(self.pointer_bits) { + match arg.extension { + ArgumentExtension::None => {} + ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(), + ArgumentExtension::Sext => return ValueConversion::Sext(self.pointer_type).into(), + } + } + + if self.regs < self.reg_limit { + // Assign to a register. + let reg = GPR.unit(10 + self.regs as usize); + self.regs += 1; + ArgumentLoc::Reg(reg).into() + } else { + // Assign a stack location. + let loc = ArgumentLoc::Stack(self.offset as i32); + self.offset += u32::from(self.pointer_bytes); + debug_assert!(self.offset <= i32::MAX as u32); + loc.into() + } + } +} /// Legalize `sig`. -pub fn legalize_signature( - _sig: &mut ir::Signature, - _flags: &shared_settings::Flags, - _current: bool, -) { - unimplemented!() +pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bool) { + let bits = triple.pointer_width().unwrap().bits(); + + let mut args = Args::new(bits); + legalize_args(&mut sig.params, &mut args); } /// Get register class for a type appearing in a legalized signature. diff --git a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs index 7ceacf036bd8..7bede88f3c8d 100644 --- a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs +++ b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs @@ -102,7 +102,7 @@ impl TargetIsa for Isa { } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { - abi::legalize_signature(sig, &self.shared_flags, current) + abi::legalize_signature(sig, &self.triple, current) } fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass { diff --git a/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs b/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs index b25c17e1f68b..37d9ffb2579a 100644 --- a/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs +++ b/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs @@ -161,13 +161,14 @@ pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bo legalize_args(&mut sig.params, &mut args); - let regs = if sig.call_conv == CallConv::WindowsFastcall { - &RET_GPRS_WIN_FASTCALL_X64[..] + let (regs, fpr_limit) = if sig.call_conv == CallConv::WindowsFastcall { + // windows-x64 calling convention only uses XMM0 or RAX for return values + (&RET_GPRS_WIN_FASTCALL_X64[..], 1) } else { - &RET_GPRS[..] + (&RET_GPRS[..], 2) }; - let mut rets = Args::new(bits, regs, 2, sig.call_conv); + let mut rets = Args::new(bits, regs, fpr_limit, sig.call_conv); legalize_args(&mut sig.returns, &mut rets); } diff --git a/third_party/rust/cranelift-codegen/src/legalizer/split.rs b/third_party/rust/cranelift-codegen/src/legalizer/split.rs index 67d947f4a9aa..773df1321627 100644 --- a/third_party/rust/cranelift-codegen/src/legalizer/split.rs +++ b/third_party/rust/cranelift-codegen/src/legalizer/split.rs @@ -14,13 +14,13 @@ //! //! When legalizing a single instruction, it is wrapped in splits and concatenations: //! -//!```clif +//! ```clif //! v1 = bxor.i64 v2, v3 //! ``` //! //! becomes: //! -//!```clif +//! ```clif //! v20, v21 = isplit v2 //! v30, v31 = isplit v3 //! v10 = bxor.i32 v20, v30 diff --git a/third_party/rust/cranelift-codegen/src/licm.rs b/third_party/rust/cranelift-codegen/src/licm.rs index cb3dbd87a9c4..14c4630dc778 100644 --- a/third_party/rust/cranelift-codegen/src/licm.rs +++ b/third_party/rust/cranelift-codegen/src/licm.rs @@ -5,7 +5,9 @@ use crate::dominator_tree::DominatorTree; use crate::entity::{EntityList, ListPool}; use crate::flowgraph::{BasicBlock, ControlFlowGraph}; use crate::fx::FxHashSet; -use crate::ir::{DataFlowGraph, Ebb, Function, Inst, InstBuilder, Layout, Opcode, Type, Value}; +use crate::ir::{ + DataFlowGraph, Ebb, Function, Inst, InstBuilder, InstructionData, Layout, Opcode, Type, Value, +}; use crate::isa::TargetIsa; use crate::loop_analysis::{Loop, LoopAnalysis}; use crate::timing; @@ -145,8 +147,7 @@ fn change_branch_jump_destination(inst: Inst, new_ebb: Ebb, func: &mut Function) /// Test whether the given opcode is unsafe to even consider for LICM. fn trivially_unsafe_for_licm(opcode: Opcode) -> bool { - opcode.can_load() - || opcode.can_store() + opcode.can_store() || opcode.is_call() || opcode.is_branch() || opcode.is_terminator() @@ -156,12 +157,25 @@ fn trivially_unsafe_for_licm(opcode: Opcode) -> bool { || opcode.writes_cpu_flags() } +fn is_unsafe_load(inst_data: &InstructionData) -> bool { + match *inst_data { + InstructionData::Load { flags, .. } | InstructionData::LoadComplex { flags, .. } => { + !flags.readonly() || !flags.notrap() + } + _ => inst_data.opcode().can_load(), + } +} + /// Test whether the given instruction is loop-invariant. fn is_loop_invariant(inst: Inst, dfg: &DataFlowGraph, loop_values: &FxHashSet) -> bool { if trivially_unsafe_for_licm(dfg[inst].opcode()) { return false; } + if is_unsafe_load(&dfg[inst]) { + return false; + } + let inst_args = dfg.inst_args(inst); for arg in inst_args { let arg = dfg.resolve_aliases(*arg); diff --git a/third_party/rust/cranelift-codegen/src/postopt.rs b/third_party/rust/cranelift-codegen/src/postopt.rs index 591b92ed037e..a82a3e59d3ec 100644 --- a/third_party/rust/cranelift-codegen/src/postopt.rs +++ b/third_party/rust/cranelift-codegen/src/postopt.rs @@ -128,6 +128,7 @@ fn optimize_cpu_flags( // We found a compare+branch pattern. Transform it to use flags. let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec(); pos.goto_inst(info.cmp_inst); + pos.use_srcloc(info.cmp_inst); match info.kind { CmpBrKind::Icmp { mut cond, arg } => { let flags = pos.ins().ifcmp(info.cmp_arg, arg); diff --git a/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs b/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs index f59435d17071..401b795eea89 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs @@ -292,6 +292,9 @@ impl<'a> Context<'a> { // Insert a copy instruction at the top of `ebb`. let mut pos = EncCursor::new(self.func, self.isa).at_first_inst(ebb); + if let Some(inst) = pos.current_inst() { + pos.use_srcloc(inst); + } pos.ins().with_result(param).copy(new_val); let inst = pos.built_inst(); self.liveness.move_def_locally(param, inst); @@ -347,6 +350,7 @@ impl<'a> Context<'a> { pred_val: Value, ) -> Value { let mut pos = EncCursor::new(self.func, self.isa).at_inst(pred_inst); + pos.use_srcloc(pred_inst); let copy = pos.ins().copy(pred_val); let inst = pos.built_inst(); diff --git a/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs b/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs index 61458f4066c5..9065566003d0 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs @@ -420,6 +420,7 @@ impl<'a> Context<'a> { // secondary `opidx` key makes it possible to use an unstable (non-allocating) sort. self.reg_uses.sort_unstable_by_key(|u| (u.value, u.opidx)); + self.cur.use_srcloc(inst); for i in 0..self.reg_uses.len() { let ru = self.reg_uses[i]; diff --git a/third_party/rust/cranelift-codegen/src/timing.rs b/third_party/rust/cranelift-codegen/src/timing.rs index 16f729f71dee..2a2d3938030c 100644 --- a/third_party/rust/cranelift-codegen/src/timing.rs +++ b/third_party/rust/cranelift-codegen/src/timing.rs @@ -176,7 +176,7 @@ mod details { } } - /// Information about passes in a single thread. + // Information about passes in a single thread. thread_local! { static CURRENT_PASS: Cell = Cell::new(Pass::None); static PASS_TIME: RefCell = RefCell::new(Default::default()); diff --git a/third_party/rust/cranelift-entity/.cargo-checksum.json b/third_party/rust/cranelift-entity/.cargo-checksum.json index 389bb057ecaa..2c600dba3988 100644 --- a/third_party/rust/cranelift-entity/.cargo-checksum.json +++ b/third_party/rust/cranelift-entity/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"bdfb55271249705ca4f66080d59757b97af8872bcd0080c858780d472d6094bc","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"139fc0eeed2e8cde2b82b8b7402e8c7cd079a9fbbf1ec692622e5ad0c10d9faf","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"f35031459aca446734726c132c0a571482f1ec2ca8221b352d2e18c74950e977","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"e95e4b2ed36413d80c4c0dcfc19dcf8a9f52e34467aaec196c774fd639747028","src/set.rs":"ec0ff7a9ee674c90ff9d06ea1fd4ab05039369146c2d259f476c6f612417933f","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":"4e124e09cb7dc85fbe2162420aebbe8e9e3b8f9210901be7867416c5beec8226"} \ No newline at end of file +{"files":{"Cargo.toml":"48e037bea5be27018e3f98bfba7ca7b0af1322c2083c69a137ab3320cd64b9fb","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"139fc0eeed2e8cde2b82b8b7402e8c7cd079a9fbbf1ec692622e5ad0c10d9faf","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"f35031459aca446734726c132c0a571482f1ec2ca8221b352d2e18c74950e977","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"e95e4b2ed36413d80c4c0dcfc19dcf8a9f52e34467aaec196c774fd639747028","src/set.rs":"ec0ff7a9ee674c90ff9d06ea1fd4ab05039369146c2d259f476c6f612417933f","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-entity/Cargo.toml b/third_party/rust/cranelift-entity/Cargo.toml index 8a8506102222..f050953a9438 100644 --- a/third_party/rust/cranelift-entity/Cargo.toml +++ b/third_party/rust/cranelift-entity/Cargo.toml @@ -1,34 +1,21 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" -name = "cranelift-entity" -version = "0.29.0" authors = ["The Cranelift Project Developers"] +name = "cranelift-entity" +version = "0.30.0" description = "Data structures using entity references as mapping keys" +license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" +repository = "https://github.com/CraneStation/cranelift" +categories = ["no-std"] readme = "README.md" keywords = ["entity", "set", "map"] -categories = ["no-std"] -license = "Apache-2.0 WITH LLVM-exception" -repository = "https://github.com/CraneStation/cranelift" +edition = "2018" [features] -core = [] default = ["std"] std = [] -[badges.maintenance] -status = "experimental" +core = [] -[badges.travis-ci] -repository = "CraneStation/cranelift" +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/third_party/rust/cranelift-frontend/.cargo-checksum.json b/third_party/rust/cranelift-frontend/.cargo-checksum.json index f41214bf9ecf..634d43b8c82e 100644 --- a/third_party/rust/cranelift-frontend/.cargo-checksum.json +++ b/third_party/rust/cranelift-frontend/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b5d70a2290241ca933b8bc6530f92f784c508d34448f86516ce3ddbdd62c1ba7","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"f3ad024e4895eddf83c8fe19c93ae37709a6bf27db2e1beef153fd742d99defa","src/lib.rs":"1cc2e7aaffa45bccea9e59fcc9d9c5d295a9f7adacd6bd55933834e20e969aef","src/ssa.rs":"88cb07071943f3e72a91c91afb58960689b4d9c56352b3bb7cd5d69288066190","src/switch.rs":"1afa11f037c91d6c87f8c6b88cddddc5f22c2b6ee9d0f05382ed05d0c4f29135","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":"2833c6e1a93c524ce0c2ab31266cdc84d38c906349f79f19378a5e5995727b23"} \ No newline at end of file +{"files":{"Cargo.toml":"c92f07d9959d10331c6b4770a4db12f706927a18897dfed45472abcd6e58190e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"f3ad024e4895eddf83c8fe19c93ae37709a6bf27db2e1beef153fd742d99defa","src/lib.rs":"1cc2e7aaffa45bccea9e59fcc9d9c5d295a9f7adacd6bd55933834e20e969aef","src/ssa.rs":"88cb07071943f3e72a91c91afb58960689b4d9c56352b3bb7cd5d69288066190","src/switch.rs":"b8f337966b540254feb5f979b4a146f5ef69ae199864da6332c9d7513ff3ec8b","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-frontend/Cargo.toml b/third_party/rust/cranelift-frontend/Cargo.toml index 5f59760712fd..b46737cc7c7f 100644 --- a/third_party/rust/cranelift-frontend/Cargo.toml +++ b/third_party/rust/cranelift-frontend/Cargo.toml @@ -1,48 +1,26 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" -name = "cranelift-frontend" -version = "0.29.0" authors = ["The Cranelift Project Developers"] +name = "cranelift-frontend" +version = "0.30.0" description = "Cranelift IR builder helper" -documentation = "https://cranelift.readthedocs.io/" -readme = "README.md" -categories = ["no-std"] license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://cranelift.readthedocs.io/" +categories = ["no-std"] repository = "https://github.com/CraneStation/cranelift" -[dependencies.cranelift-codegen] -version = "0.29.0" -default-features = false +readme = "README.md" +edition = "2018" -[dependencies.hashmap_core] -version = "0.1.9" -optional = true - -[dependencies.log] -version = "0.4.6" -default-features = false - -[dependencies.target-lexicon] -version = "0.2.0" -default-features = false +[dependencies] +cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false } +target-lexicon = { version = "0.4.0", default-features = false } +log = { version = "0.4.6", default-features = false } +hashmap_core = { version = "0.1.9", optional = true } [features] -core = ["hashmap_core", "cranelift-codegen/core"] default = ["std"] std = ["cranelift-codegen/std"] -[badges.maintenance] -status = "experimental" +core = ["hashmap_core", "cranelift-codegen/core"] -[badges.travis-ci] -repository = "CraneStation/cranelift" +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/third_party/rust/cranelift-frontend/src/switch.rs b/third_party/rust/cranelift-frontend/src/switch.rs index 653afbaed17a..0db3ac348e67 100644 --- a/third_party/rust/cranelift-frontend/src/switch.rs +++ b/third_party/rust/cranelift-frontend/src/switch.rs @@ -9,6 +9,36 @@ type EntryIndex = u64; /// Unlike with `br_table`, `Switch` cases may be sparse or non-0-based. /// They emit efficient code using branches, jump tables, or a combination of both. +/// +/// # Example +/// +/// ```rust +/// # use cranelift_codegen::ir::types::*; +/// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder}; +/// # use cranelift_codegen::isa::CallConv; +/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch}; +/// # +/// # let mut sig = Signature::new(CallConv::SystemV); +/// # let mut fn_builder_ctx = FunctionBuilderContext::new(); +/// # let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); +/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); +/// # +/// # let entry = builder.create_ebb(); +/// # builder.switch_to_block(entry); +/// # +/// let block0 = builder.create_ebb(); +/// let block1 = builder.create_ebb(); +/// let block2 = builder.create_ebb(); +/// let fallback = builder.create_ebb(); +/// +/// let val = builder.ins().iconst(I32, 1); +/// +/// let mut switch = Switch::new(); +/// switch.set_entry(0, block0); +/// switch.set_entry(1, block1); +/// switch.set_entry(7, block2); +/// switch.emit(&mut builder, val, fallback); +/// ``` #[derive(Debug, Default)] pub struct Switch { cases: HashMap, @@ -32,6 +62,14 @@ impl Switch { ); } + /// Turn the `cases` `HashMap` into a list of `ContiguousCaseRange`s. + /// + /// # Postconditions + /// + /// * Every entry will be represented. + /// * The `ContiguousCaseRange`s will not overlap. + /// * Between two `ContiguousCaseRange`s there will be at least one entry index. + /// * No `ContiguousCaseRange`s will be empty. fn collect_contiguous_case_ranges(self) -> Vec { debug!("build_contiguous_case_ranges before: {:#?}", self.cases); let mut cases = self.cases.into_iter().collect::>(); @@ -60,6 +98,7 @@ impl Switch { contiguous_case_ranges } + /// Binary search for the right `ContiguousCaseRange`. fn build_search_tree( bx: &mut FunctionBuilder, val: Value, @@ -120,6 +159,7 @@ impl Switch { cases_and_jt_ebbs } + /// Linear search for the right `ContiguousCaseRange`. fn build_search_branches( bx: &mut FunctionBuilder, val: Value, @@ -128,22 +168,41 @@ impl Switch { cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec)>, ) { for ContiguousCaseRange { first_index, ebbs } in contiguous_case_ranges.into_iter().rev() { - if ebbs.len() == 1 { - let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64); - bx.ins().brnz(is_good_val, ebbs[0], &[]); - } else { - let jt_ebb = bx.create_ebb(); - let is_good_val = - bx.ins() - .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, val, first_index as i64); - bx.ins().brnz(is_good_val, jt_ebb, &[]); - cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs)); + match (ebbs.len(), first_index) { + (1, 0) => { + bx.ins().brz(val, ebbs[0], &[]); + } + (1, _) => { + let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64); + bx.ins().brnz(is_good_val, ebbs[0], &[]); + } + (_, 0) => { + // if `first_index` is 0, then `icmp_imm uge val, first_index` is trivially true + let jt_ebb = bx.create_ebb(); + bx.ins().jump(jt_ebb, &[]); + cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs)); + // `jump otherwise` below must not be hit, because the current block has been + // filled above. This is the last iteration anyway, as 0 is the smallest + // unsigned int, so just return here. + return; + } + (_, _) => { + let jt_ebb = bx.create_ebb(); + let is_good_val = bx.ins().icmp_imm( + IntCC::UnsignedGreaterThanOrEqual, + val, + first_index as i64, + ); + bx.ins().brnz(is_good_val, jt_ebb, &[]); + cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs)); + } } } bx.ins().jump(otherwise, &[]); } + /// For every item in `cases_and_jt_ebbs` this will create a jump table in the specified ebb. fn build_jump_tables( bx: &mut FunctionBuilder, val: Value, @@ -158,7 +217,11 @@ impl Switch { let jump_table = bx.create_jump_table(jt_data); bx.switch_to_block(jt_ebb); - let discr = bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg()); + let discr = if first_index == 0 { + val + } else { + bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg()) + }; bx.ins().br_table(discr, otherwise, jump_table); } } @@ -183,9 +246,22 @@ impl Switch { } } +/// This represents a contiguous range of cases to switch on. +/// +/// For example 10 => ebb1, 11 => ebb2, 12 => ebb7 will be represented as: +/// +/// ```plain +/// ContiguousCaseRange { +/// first_index: 10, +/// ebbs: vec![Ebb::from_u32(1), Ebb::from_u32(2), Ebb::from_u32(7)] +/// } +/// ``` #[derive(Debug)] struct ContiguousCaseRange { + /// The entry index of the first case. Eg. 10 when the entry indexes are 10, 11, 12 and 13. first_index: EntryIndex, + + /// The ebbs to jump to sorted in ascending order of entry index. ebbs: Vec, } @@ -237,8 +313,7 @@ mod tests { "ebb0: v0 = iconst.i8 0 v1 = uextend.i32 v0 - v2 = icmp_imm eq v1, 0 - brnz v2, ebb1 + brz v1, ebb1 jump ebb0" ); } @@ -267,13 +342,10 @@ mod tests { ebb0: v0 = iconst.i8 0 v1 = uextend.i32 v0 - v2 = icmp_imm uge v1, 0 - brnz v2, ebb3 - jump ebb0 + jump ebb3 ebb3: - v3 = iadd_imm.i32 v1, 0 - br_table v3, ebb0, jt0" + br_table.i32 v1, ebb0, jt0" ); } @@ -287,8 +359,7 @@ ebb3: v1 = uextend.i32 v0 v2 = icmp_imm eq v1, 2 brnz v2, ebb2 - v3 = icmp_imm eq v1, 0 - brnz v3, ebb1 + brz v1, ebb1 jump ebb0" ); } @@ -318,17 +389,14 @@ ebb9: ebb8: v5 = icmp_imm.i32 eq v1, 5 brnz v5, ebb3 - v6 = icmp_imm.i32 uge v1, 0 - brnz v6, ebb11 - jump ebb0 + jump ebb11 ebb11: - v7 = iadd_imm.i32 v1, 0 - br_table v7, ebb0, jt0 + br_table.i32 v1, ebb0, jt0 ebb10: - v8 = iadd_imm.i32 v1, -10 - br_table v8, ebb0, jt1" + v6 = iadd_imm.i32 v1, -10 + br_table v6, ebb0, jt1" ); } @@ -363,4 +431,23 @@ ebb10: jump ebb0" ) } + + #[test] + fn switch_optimal_codegen() { + let func = setup!(0, [-1i64 as u64, 0, 1,]); + assert_eq!( + func, + " jt0 = jump_table [ebb2, ebb3] + +ebb0: + v0 = iconst.i8 0 + v1 = uextend.i32 v0 + v2 = icmp_imm eq v1, -1 + brnz v2, ebb1 + jump ebb4 + +ebb4: + br_table.i32 v1, ebb0, jt0" + ); + } } diff --git a/third_party/rust/cranelift-wasm/.cargo-checksum.json b/third_party/rust/cranelift-wasm/.cargo-checksum.json index 8043735687d4..bdb24a9b3af9 100644 --- a/third_party/rust/cranelift-wasm/.cargo-checksum.json +++ b/third_party/rust/cranelift-wasm/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ed12a641047878536a2be05241a6a59b30e029584168d15fe8dff9ef4e226cf7","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"00740be2943fe96d8588d15ec3b812b997f41e4bc9cd27510173889172aff8bc","src/environ/dummy.rs":"42df6db37892ea28e9a004934599d8bbcbd62db52f787486cd81a23f1a563613","src/environ/mod.rs":"617c147485038dfd797ab0ea71b4cfa9574d95d5d5b1ca362c6b7b6a462cf577","src/environ/spec.rs":"1c22dfbf956d80cbf34a6b8087dfb38b1f73a5cf010c341b673dba4286468bfe","src/func_translator.rs":"b27debdc0d17f30ecfa7a9bf4bdeea6054966507b5d398ccd4165574da4f674a","src/lib.rs":"95183fc86a20687e547d2edbd9868681005f0c3a2ca1ae1471e2ae38098f85c6","src/module_translator.rs":"ac54c24aaa3775f72ccd16d1781be648bb0e83ea83909f933d07e86ef1879213","src/sections_translator.rs":"499f6d1ca8a4151dab891d14bb901c292adea13b1daccdd6e2b104fb9f5a49a7","src/state.rs":"1b1fa08736702d062c49118fba67f0a13752b4d863c1d11abd90eeb219777a23","src/translation_utils.rs":"50b45794018e1c471694f4f60707329213c9fb4153798a879953a479213b8a56","tests/wasm_testsuite.rs":"c6eac90ebdb6b58d8247c22e04454d95943c5ab0621084b624eb20c0ce2a96a3"},"package":"e75efb45cd8d8700b4bdc225f0077bc7c615f84a5807ce001d59b4da48d85573"} \ No newline at end of file +{"files":{"Cargo.toml":"9827446df24b295abe90539e7ccfda7c54955f1cb44e4d49c3a4e5a66bfa5fae","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"96fc0bf7b2c2f0de0596724bfe72d7fbcf5db1b676721fe024f5555ddbcbb7b6","src/environ/dummy.rs":"42df6db37892ea28e9a004934599d8bbcbd62db52f787486cd81a23f1a563613","src/environ/mod.rs":"617c147485038dfd797ab0ea71b4cfa9574d95d5d5b1ca362c6b7b6a462cf577","src/environ/spec.rs":"1c22dfbf956d80cbf34a6b8087dfb38b1f73a5cf010c341b673dba4286468bfe","src/func_translator.rs":"b27debdc0d17f30ecfa7a9bf4bdeea6054966507b5d398ccd4165574da4f674a","src/lib.rs":"95183fc86a20687e547d2edbd9868681005f0c3a2ca1ae1471e2ae38098f85c6","src/module_translator.rs":"ac54c24aaa3775f72ccd16d1781be648bb0e83ea83909f933d07e86ef1879213","src/sections_translator.rs":"55290a6b5d2a71719404d4d5f08a389dbf37c053264d17f3b292a57d1bdd5b62","src/state.rs":"1b1fa08736702d062c49118fba67f0a13752b4d863c1d11abd90eeb219777a23","src/translation_utils.rs":"50b45794018e1c471694f4f60707329213c9fb4153798a879953a479213b8a56","tests/wasm_testsuite.rs":"c6eac90ebdb6b58d8247c22e04454d95943c5ab0621084b624eb20c0ce2a96a3"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-wasm/Cargo.toml b/third_party/rust/cranelift-wasm/Cargo.toml index 086477028716..2309322acb3c 100644 --- a/third_party/rust/cranelift-wasm/Cargo.toml +++ b/third_party/rust/cranelift-wasm/Cargo.toml @@ -1,74 +1,35 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] -edition = "2018" name = "cranelift-wasm" -version = "0.29.0" +version = "0.30.0" authors = ["The Cranelift Project Developers"] description = "Translator from WebAssembly to Cranelift IR" +repository = "https://github.com/CraneStation/cranelift" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["no-std", "wasm"] readme = "README.md" keywords = ["webassembly", "wasm"] -categories = ["no-std", "wasm"] -license = "Apache-2.0 WITH LLVM-exception" -repository = "https://github.com/CraneStation/cranelift" -[dependencies.cast] -version = "0.2.2" -default-features = false +edition = "2018" -[dependencies.cranelift-codegen] -version = "0.29.0" -default-features = false +[dependencies] +wasmparser = { version = "0.29.2", default-features = false } +cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false } +cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false } +cranelift-frontend = { path = "../cranelift-frontend", version = "0.30.0", default-features = false } +hashmap_core = { version = "0.1.9", optional = true } +failure = { version = "0.1.1", default-features = false, features = ["derive"] } +failure_derive = { version = "0.1.1", default-features = false } +log = { version = "0.4.6", default-features = false } +cast = { version = "0.2.2", default-features = false } -[dependencies.cranelift-entity] -version = "0.29.0" -default-features = false - -[dependencies.cranelift-frontend] -version = "0.29.0" -default-features = false - -[dependencies.failure] -version = "0.1.1" -features = ["derive"] -default-features = false - -[dependencies.failure_derive] -version = "0.1.1" -default-features = false - -[dependencies.hashmap_core] -version = "0.1.9" -optional = true - -[dependencies.log] -version = "0.4.6" -default-features = false - -[dependencies.wasmparser] -version = "0.23.0" -default-features = false -[dev-dependencies.target-lexicon] -version = "0.2.0" - -[dev-dependencies.wabt] -version = "0.7.0" +[dev-dependencies] +wabt = "0.7.0" +target-lexicon = "0.4.0" [features] -core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"] default = ["std"] std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmparser/std"] -[badges.maintenance] -status = "experimental" +core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"] -[badges.travis-ci] -repository = "CraneStation/cranelift" +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/third_party/rust/cranelift-wasm/src/code_translator.rs b/third_party/rust/cranelift-wasm/src/code_translator.rs index ad0d75e2daeb..f83b462cef17 100644 --- a/third_party/rust/cranelift-wasm/src/code_translator.rs +++ b/third_party/rust/cranelift-wasm/src/code_translator.rs @@ -886,6 +886,161 @@ pub fn translate_operator( Operator::RefNull | Operator::RefIsNull { .. } => { return Err(WasmError::Unsupported("proposed reference-type operators")); } + Operator::MemoryInit { .. } + | Operator::DataDrop { .. } + | Operator::MemoryCopy + | Operator::MemoryFill + | Operator::TableInit { .. } + | Operator::ElemDrop { .. } + | Operator::TableCopy + | Operator::TableGet { .. } + | Operator::TableSet { .. } + | Operator::TableGrow { .. } + | Operator::TableSize { .. } => { + return Err(WasmError::Unsupported("proposed bulk memory operators")); + } + Operator::V128Load { .. } + | Operator::V128Store { .. } + | Operator::V128Const { .. } + | Operator::V8x16Shuffle { .. } + | Operator::I8x16Splat + | Operator::I8x16ExtractLaneS { .. } + | Operator::I8x16ExtractLaneU { .. } + | Operator::I8x16ReplaceLane { .. } + | Operator::I16x8Splat + | Operator::I16x8ExtractLaneS { .. } + | Operator::I16x8ExtractLaneU { .. } + | Operator::I16x8ReplaceLane { .. } + | Operator::I32x4Splat + | Operator::I32x4ExtractLane { .. } + | Operator::I32x4ReplaceLane { .. } + | Operator::I64x2Splat + | Operator::I64x2ExtractLane { .. } + | Operator::I64x2ReplaceLane { .. } + | Operator::F32x4Splat + | Operator::F32x4ExtractLane { .. } + | Operator::F32x4ReplaceLane { .. } + | Operator::F64x2Splat + | Operator::F64x2ExtractLane { .. } + | Operator::F64x2ReplaceLane { .. } + | Operator::I8x16Eq + | Operator::I8x16Ne + | Operator::I8x16LtS + | Operator::I8x16LtU + | Operator::I8x16GtS + | Operator::I8x16GtU + | Operator::I8x16LeS + | Operator::I8x16LeU + | Operator::I8x16GeS + | Operator::I8x16GeU + | Operator::I16x8Eq + | Operator::I16x8Ne + | Operator::I16x8LtS + | Operator::I16x8LtU + | Operator::I16x8GtS + | Operator::I16x8GtU + | Operator::I16x8LeS + | Operator::I16x8LeU + | Operator::I16x8GeS + | Operator::I16x8GeU + | Operator::I32x4Eq + | Operator::I32x4Ne + | Operator::I32x4LtS + | Operator::I32x4LtU + | Operator::I32x4GtS + | Operator::I32x4GtU + | Operator::I32x4LeS + | Operator::I32x4LeU + | Operator::I32x4GeS + | Operator::I32x4GeU + | Operator::F32x4Eq + | Operator::F32x4Ne + | Operator::F32x4Lt + | Operator::F32x4Gt + | Operator::F32x4Le + | Operator::F32x4Ge + | Operator::F64x2Eq + | Operator::F64x2Ne + | Operator::F64x2Lt + | Operator::F64x2Gt + | Operator::F64x2Le + | Operator::F64x2Ge + | Operator::V128Not + | Operator::V128And + | Operator::V128Or + | Operator::V128Xor + | Operator::V128Bitselect + | Operator::I8x16Neg + | Operator::I8x16AnyTrue + | Operator::I8x16AllTrue + | Operator::I8x16Shl + | Operator::I8x16ShrS + | Operator::I8x16ShrU + | Operator::I8x16Add + | Operator::I8x16AddSaturateS + | Operator::I8x16AddSaturateU + | Operator::I8x16Sub + | Operator::I8x16SubSaturateS + | Operator::I8x16SubSaturateU + | Operator::I8x16Mul + | Operator::I16x8Neg + | Operator::I16x8AnyTrue + | Operator::I16x8AllTrue + | Operator::I16x8Shl + | Operator::I16x8ShrS + | Operator::I16x8ShrU + | Operator::I16x8Add + | Operator::I16x8AddSaturateS + | Operator::I16x8AddSaturateU + | Operator::I16x8Sub + | Operator::I16x8SubSaturateS + | Operator::I16x8SubSaturateU + | Operator::I16x8Mul + | Operator::I32x4Neg + | Operator::I32x4AnyTrue + | Operator::I32x4AllTrue + | Operator::I32x4Shl + | Operator::I32x4ShrS + | Operator::I32x4ShrU + | Operator::I32x4Add + | Operator::I32x4Sub + | Operator::I32x4Mul + | Operator::I64x2Neg + | Operator::I64x2AnyTrue + | Operator::I64x2AllTrue + | Operator::I64x2Shl + | Operator::I64x2ShrS + | Operator::I64x2ShrU + | Operator::I64x2Add + | Operator::I64x2Sub + | Operator::F32x4Abs + | Operator::F32x4Neg + | Operator::F32x4Sqrt + | Operator::F32x4Add + | Operator::F32x4Sub + | Operator::F32x4Mul + | Operator::F32x4Div + | Operator::F32x4Min + | Operator::F32x4Max + | Operator::F64x2Abs + | Operator::F64x2Neg + | Operator::F64x2Sqrt + | Operator::F64x2Add + | Operator::F64x2Sub + | Operator::F64x2Mul + | Operator::F64x2Div + | Operator::F64x2Min + | Operator::F64x2Max + | Operator::I32x4TruncSF32x4Sat + | Operator::I32x4TruncUF32x4Sat + | Operator::I64x2TruncSF64x2Sat + | Operator::I64x2TruncUF64x2Sat + | Operator::F32x4ConvertSI32x4 + | Operator::F32x4ConvertUI32x4 + | Operator::F64x2ConvertSI64x2 + | Operator::F64x2ConvertUI64x2 => { + return Err(WasmError::Unsupported("proposed SIMD operators")); + } }; Ok(()) } diff --git a/third_party/rust/cranelift-wasm/src/sections_translator.rs b/third_party/rust/cranelift-wasm/src/sections_translator.rs index 37c5d34672aa..e406ec3eee01 100644 --- a/third_party/rust/cranelift-wasm/src/sections_translator.rs +++ b/third_party/rust/cranelift-wasm/src/sections_translator.rs @@ -12,15 +12,15 @@ use crate::translation_utils::{ type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, }; -use core::str::from_utf8; use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_entity::EntityRef; use std::vec::Vec; use wasmparser::{ - self, CodeSectionReader, Data, DataSectionReader, Element, ElementSectionReader, Export, - ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader, - GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType, - Operator, TableSectionReader, TypeSectionReader, + self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind, + ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType, + FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, + ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader, + TypeSectionReader, }; /// Parses the Type section of the wasm module. @@ -65,12 +65,8 @@ pub fn parse_import_section<'data>( for entry in imports { let import = entry?; - - // The input has already been validated, so we should be able to - // assume valid UTF-8 and use `from_utf8_unchecked` if performance - // becomes a concern here. - let module_name = from_utf8(import.module).unwrap(); - let field_name = from_utf8(import.field).unwrap(); + let module_name = import.module; + let field_name = import.field; match import.ty { ImportSectionEntryType::Function(sig) => { @@ -232,13 +228,12 @@ pub fn parse_export_section<'data>( // The input has already been validated, so we should be able to // assume valid UTF-8 and use `from_utf8_unchecked` if performance // becomes a concern here. - let name = from_utf8(field).unwrap(); let index = index as usize; match *kind { - ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), name), - ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name), - ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), name), - ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), name), + ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), field), + ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field), + ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), field), + ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), field), } } @@ -260,29 +255,35 @@ pub fn parse_element_section<'data>( environ.reserve_table_elements(elements.get_count()); for entry in elements { - let Element { + let Element { kind, items } = entry?; + if let ElementKind::Active { table_index, init_expr, - items, - } = entry?; - let mut init_expr_reader = init_expr.get_binary_reader(); - let (base, offset) = match init_expr_reader.read_operator()? { - Operator::I32Const { value } => (None, value as u32 as usize), - Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0), - ref s => panic!("unsupported init expr in element section: {:?}", s), - }; - let items_reader = items.get_items_reader()?; - let mut elems = Vec::with_capacity(cast::usize(items_reader.get_count())); - for item in items_reader { - let x = item?; - elems.push(FuncIndex::from_u32(x)); + } = kind + { + let mut init_expr_reader = init_expr.get_binary_reader(); + let (base, offset) = match init_expr_reader.read_operator()? { + Operator::I32Const { value } => (None, value as u32 as usize), + Operator::GetGlobal { global_index } => { + (Some(GlobalIndex::from_u32(global_index)), 0) + } + ref s => panic!("unsupported init expr in element section: {:?}", s), + }; + let items_reader = items.get_items_reader()?; + let mut elems = Vec::with_capacity(cast::usize(items_reader.get_count())); + for item in items_reader { + let x = item?; + elems.push(FuncIndex::from_u32(x)); + } + environ.declare_table_elements( + TableIndex::from_u32(table_index), + base, + offset, + elems.into_boxed_slice(), + ) + } else { + panic!("unsupported passive elements section"); } - environ.declare_table_elements( - TableIndex::from_u32(table_index), - base, - offset, - elems.into_boxed_slice(), - ) } Ok(()) } @@ -309,23 +310,29 @@ pub fn parse_data_section<'data>( environ.reserve_data_initializers(data.get_count()); for entry in data { - let Data { + let Data { kind, data } = entry?; + if let DataKind::Active { memory_index, init_expr, - data, - } = entry?; - let mut init_expr_reader = init_expr.get_binary_reader(); - let (base, offset) = match init_expr_reader.read_operator()? { - Operator::I32Const { value } => (None, value as u32 as usize), - Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0), - ref s => panic!("unsupported init expr in data section: {:?}", s), - }; - environ.declare_data_initialization( - MemoryIndex::from_u32(memory_index), - base, - offset, - data, - ); + } = kind + { + let mut init_expr_reader = init_expr.get_binary_reader(); + let (base, offset) = match init_expr_reader.read_operator()? { + Operator::I32Const { value } => (None, value as u32 as usize), + Operator::GetGlobal { global_index } => { + (Some(GlobalIndex::from_u32(global_index)), 0) + } + ref s => panic!("unsupported init expr in data section: {:?}", s), + }; + environ.declare_data_initialization( + MemoryIndex::from_u32(memory_index), + base, + offset, + data, + ); + } else { + panic!("unsupported passive data section"); + } } Ok(()) diff --git a/third_party/rust/target-lexicon/.cargo-checksum.json b/third_party/rust/target-lexicon/.cargo-checksum.json index 4763caf427b5..e9d6fd59da72 100644 --- a/third_party/rust/target-lexicon/.cargo-checksum.json +++ b/third_party/rust/target-lexicon/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".travis.yml":"e7a5518637394467f13cb084fa7fa75783007815b17ba22d4dee567965d418bb","Cargo.toml":"5dbb0ad2824e20f91e80cc7b3ab2f9f241e8dbeb214c821e65a9add3b3f49045","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"89f73d9404c960632bef4cfde9709862dbb510081180318e0be7bf12d18e9da7","build.rs":"c349b503b884c79aef182ba27eeffa51ca439a511d8c6adefa2ed56f80a4530c","examples/misc.rs":"2e7f27fc7b7479b9cf96bdf81b402a6ef4bec71f8ef6f4f39588745b85cb2d3d","src/host.rs":"c4a0aa3364662eb2c585a69c8872d3e380f1b8537b51def6ca582b301993ce0a","src/lib.rs":"72a94fcc6b7f5dd6692cda84974b3ffb50b6c5eb9e2ebed91c6635d102202ced","src/parse_error.rs":"38c0cb21171741faa1c69c931be6a97be658b01de07bcb69aae84e5319b03920","src/targets.rs":"4f6585736061118e61c857908b8f7c539a48641c7233f7cfc856e9c94e4ffa34","src/triple.rs":"d3cdd3be7b18f04511ae59c6156983e4300bc57a3671282c74b2c7e81e699d75"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"615784e9f863ec4eeb00066ba899ab2fd8cf6619abcc35411f47ed29745b88ad","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"89f73d9404c960632bef4cfde9709862dbb510081180318e0be7bf12d18e9da7","build.rs":"800c0d76136d72e2894a7a3eb603ce02fc4da5d96c46b970edf6f909b999741e","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"69b1b9e21c0b6e447fd53991a60e7ab20f814c2ab5faa7870e3423bf588c658f","src/parse_error.rs":"9f6897c0f0b5b666ce5e7ff1f3e3001964397d3e5f933884036b14f52b612363","src/targets.rs":"ebd909b42ad8fcec6486170076f3b6454365377b2e23dbed56cf007c761ff490","src/triple.rs":"aba17839dd6895927d3d75fd5b83698df8be6d3ea64d7c0235c62acf12645a33"},"package":"1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb"} \ No newline at end of file diff --git a/third_party/rust/target-lexicon/.rustfmt.toml b/third_party/rust/target-lexicon/.rustfmt.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/rust/target-lexicon/.travis.yml b/third_party/rust/target-lexicon/.travis.yml deleted file mode 100644 index 6832cba9c02d..000000000000 --- a/third_party/rust/target-lexicon/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: rust -rust: - - stable - - beta - - nightly -matrix: - allow_failures: - - rust: beta - - rust: nightly -dist: trusty -sudo: false -before_script: - # If an old version of rustfmt from cargo is already installed, uninstall - # it, since it can prevent the installation of the new version from rustup. - - cargo uninstall rustfmt || true - - cargo install --list - # If we're testing beta or nightly, we still need to install the stable - # toolchain so that we can run the stable version of rustfmt. - - rustup toolchain install stable - # Install the stable version of rustfmt. - - rustup component add --toolchain=stable rustfmt-preview - - rustup component list --toolchain=stable - - rustup show - - rustfmt +stable --version || echo fail - # Sometimes the component isn't actually ready after being installed, and - # rustup update makes it ready. - - rustup update - - rustfmt +stable --version -script: cargo test -cache: - cargo: true diff --git a/third_party/rust/target-lexicon/Cargo.toml b/third_party/rust/target-lexicon/Cargo.toml index a053f5e813ee..2fec9435ca9c 100644 --- a/third_party/rust/target-lexicon/Cargo.toml +++ b/third_party/rust/target-lexicon/Cargo.toml @@ -1,6 +1,19 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + [package] +edition = "2018" name = "target-lexicon" -version = "0.2.0" +version = "0.4.0" authors = ["Dan Gohman "] description = "Targeting utilities for compilers and related tools" documentation = "https://docs.rs/target-lexicon/" @@ -9,18 +22,22 @@ keywords = ["target", "host", "triple", "compiler", "jit"] categories = ["no-std"] license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/CraneStation/target-lexicon" +[dependencies.failure] +version = "0.1.3" +features = ["derive"] +default-features = false -[dependencies] -failure = { version = "0.1.3", default-features = false, features = ["derive"] } -failure_derive = { version = "0.1.3", default-features = false } - -[build-dependencies] -serde_json = "1.0" +[dependencies.failure_derive] +version = "0.1.3" +default-features = false +[build-dependencies.serde_json] +version = "1.0" [features] default = ["std"] std = [] +[badges.maintenance] +status = "passively-maintained" -[badges] -maintenance = { status = "passively-maintained" } -travis-ci = { repository = "CraneStation/target-lexicon" } +[badges.travis-ci] +repository = "CraneStation/target-lexicon" diff --git a/third_party/rust/target-lexicon/build.rs b/third_party/rust/target-lexicon/build.rs index 3940064e8f5e..8d8663baad68 100644 --- a/third_party/rust/target-lexicon/build.rs +++ b/third_party/rust/target-lexicon/build.rs @@ -36,7 +36,7 @@ mod parse_error { } } -use triple::{Endianness, PointerWidth, Triple}; +use self::triple::{Endianness, PointerWidth, Triple}; /// Assuming `target` is a path to a custom target json config file, open it /// and build a `Triple` using its contents. diff --git a/third_party/rust/target-lexicon/examples/misc.rs b/third_party/rust/target-lexicon/examples/misc.rs index ff5057d3e484..25c99e867774 100644 --- a/third_party/rust/target-lexicon/examples/misc.rs +++ b/third_party/rust/target-lexicon/examples/misc.rs @@ -1,6 +1,6 @@ extern crate target_lexicon; -use std::str::FromStr; +use core::str::FromStr; use target_lexicon::{Triple, HOST}; fn main() { diff --git a/third_party/rust/target-lexicon/src/host.rs b/third_party/rust/target-lexicon/src/host.rs index 1e83d93304e6..4c6ad5ba54d1 100644 --- a/third_party/rust/target-lexicon/src/host.rs +++ b/third_party/rust/target-lexicon/src/host.rs @@ -1,4 +1,4 @@ -use {Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; +use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; // Include the implementations of the `HOST` object containing information // about the current host. diff --git a/third_party/rust/target-lexicon/src/lib.rs b/third_party/rust/target-lexicon/src/lib.rs index 001b870dcfa2..91ca5b3d6528 100644 --- a/third_party/rust/target-lexicon/src/lib.rs +++ b/third_party/rust/target-lexicon/src/lib.rs @@ -15,29 +15,24 @@ use_self ) )] -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(not(feature = "std"))] -extern crate alloc; +extern crate alloc as std; +#[cfg(feature = "std")] +extern crate std; -extern crate failure; #[macro_use] extern crate failure_derive; -#[cfg(not(feature = "std"))] -mod std { - pub use alloc::{borrow, string}; - pub use core::*; -} - mod host; mod parse_error; mod targets; #[macro_use] mod triple; -pub use host::HOST; -pub use parse_error::ParseError; -pub use targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor}; -pub use triple::{CallingConvention, Endianness, PointerWidth, Triple}; +pub use self::host::HOST; +pub use self::parse_error::ParseError; +pub use self::targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor}; +pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; diff --git a/third_party/rust/target-lexicon/src/parse_error.rs b/third_party/rust/target-lexicon/src/parse_error.rs index d8c1ed2fa754..c3e39d2e83e0 100644 --- a/third_party/rust/target-lexicon/src/parse_error.rs +++ b/third_party/rust/target-lexicon/src/parse_error.rs @@ -16,6 +16,4 @@ pub enum ParseError { UnrecognizedBinaryFormat(String), #[fail(display = "Unrecognized field: {}", _0)] UnrecognizedField(String), - #[fail(display = "\"none\" requires an explicit binary format")] - NoneWithoutBinaryFormat, } diff --git a/third_party/rust/target-lexicon/src/targets.rs b/third_party/rust/target-lexicon/src/targets.rs index 88afc07a00fa..ab0beb4e5898 100644 --- a/third_party/rust/target-lexicon/src/targets.rs +++ b/third_party/rust/target-lexicon/src/targets.rs @@ -1,8 +1,8 @@ // This file defines all the identifier enums and target-aware logic. -use std::fmt; -use std::str::FromStr; -use triple::{Endianness, PointerWidth, Triple}; +use crate::triple::{Endianness, PointerWidth, Triple}; +use core::fmt; +use core::str::FromStr; /// The "architecture" field, which in some cases also specifies a specific /// subarchitecture. @@ -12,9 +12,12 @@ pub enum Architecture { Unknown, Aarch64, Arm, + Armebv7r, Armv4t, Armv5te, + Armv6, Armv7, + Armv7r, Armv7s, Asmjs, I386, @@ -29,15 +32,20 @@ pub enum Architecture { Powerpc64, Powerpc64le, Riscv32, + Riscv32imac, + Riscv32imc, Riscv64, S390x, Sparc, Sparc64, Sparcv9, Thumbv6m, + Thumbv7a, Thumbv7em, Thumbv7m, Thumbv7neon, + Thumbv8mBase, + Thumbv8mMain, Wasm32, X86_64, } @@ -50,6 +58,7 @@ pub enum Vendor { Unknown, Apple, Experimental, + Fortanix, Pc, Rumprun, Sun, @@ -69,14 +78,17 @@ pub enum OperatingSystem { Freebsd, Fuchsia, Haiku, + Hermit, Ios, L4re, Linux, Nebulet, Netbsd, + None_, Openbsd, Redox, Solaris, + Uefi, Windows, } @@ -102,6 +114,7 @@ pub enum Environment { Musleabihf, Msvc, Uclibc, + Sgx, } /// The "binary format" field, which is usually omitted, and the binary format @@ -125,7 +138,9 @@ impl Architecture { | Architecture::Arm | Architecture::Armv4t | Architecture::Armv5te + | Architecture::Armv6 | Architecture::Armv7 + | Architecture::Armv7r | Architecture::Armv7s | Architecture::Asmjs | Architecture::I386 @@ -136,14 +151,20 @@ impl Architecture { | Architecture::Msp430 | Architecture::Powerpc64le | Architecture::Riscv32 + | Architecture::Riscv32imac + | Architecture::Riscv32imc | Architecture::Riscv64 | Architecture::Thumbv6m + | Architecture::Thumbv7a | Architecture::Thumbv7em | Architecture::Thumbv7m | Architecture::Thumbv7neon + | Architecture::Thumbv8mBase + | Architecture::Thumbv8mMain | Architecture::Wasm32 | Architecture::X86_64 => Ok(Endianness::Little), - Architecture::Mips + Architecture::Armebv7r + | Architecture::Mips | Architecture::Mips64 | Architecture::Powerpc | Architecture::Powerpc64 @@ -160,9 +181,12 @@ impl Architecture { Architecture::Unknown => Err(()), Architecture::Msp430 => Ok(PointerWidth::U16), Architecture::Arm + | Architecture::Armebv7r | Architecture::Armv4t | Architecture::Armv5te + | Architecture::Armv6 | Architecture::Armv7 + | Architecture::Armv7r | Architecture::Armv7s | Architecture::Asmjs | Architecture::I386 @@ -170,11 +194,16 @@ impl Architecture { | Architecture::I686 | Architecture::Mipsel | Architecture::Riscv32 + | Architecture::Riscv32imac + | Architecture::Riscv32imc | Architecture::Sparc | Architecture::Thumbv6m + | Architecture::Thumbv7a | Architecture::Thumbv7em | Architecture::Thumbv7m | Architecture::Thumbv7neon + | Architecture::Thumbv8mBase + | Architecture::Thumbv8mMain | Architecture::Wasm32 | Architecture::Mips | Architecture::Powerpc => Ok(PointerWidth::U32), @@ -196,6 +225,7 @@ impl Architecture { /// `binary_format` field. pub fn default_binary_format(triple: &Triple) -> BinaryFormat { match triple.operating_system { + OperatingSystem::None_ => BinaryFormat::Unknown, OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho, OperatingSystem::Windows => BinaryFormat::Coff, OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => { @@ -214,9 +244,12 @@ impl fmt::Display for Architecture { Architecture::Unknown => "unknown", Architecture::Aarch64 => "aarch64", Architecture::Arm => "arm", + Architecture::Armebv7r => "armebv7r", Architecture::Armv4t => "armv4t", Architecture::Armv5te => "armv5te", + Architecture::Armv6 => "armv6", Architecture::Armv7 => "armv7", + Architecture::Armv7r => "armv7r", Architecture::Armv7s => "armv7s", Architecture::Asmjs => "asmjs", Architecture::I386 => "i386", @@ -231,15 +264,20 @@ impl fmt::Display for Architecture { Architecture::Powerpc64 => "powerpc64", Architecture::Powerpc64le => "powerpc64le", Architecture::Riscv32 => "riscv32", + Architecture::Riscv32imac => "riscv32imac", + Architecture::Riscv32imc => "riscv32imc", Architecture::Riscv64 => "riscv64", Architecture::S390x => "s390x", Architecture::Sparc => "sparc", Architecture::Sparc64 => "sparc64", Architecture::Sparcv9 => "sparcv9", Architecture::Thumbv6m => "thumbv6m", + Architecture::Thumbv7a => "thumbv7a", Architecture::Thumbv7em => "thumbv7em", Architecture::Thumbv7m => "thumbv7m", Architecture::Thumbv7neon => "thumbv7neon", + Architecture::Thumbv8mBase => "thumbv8m.base", + Architecture::Thumbv8mMain => "thumbv8m.main", Architecture::Wasm32 => "wasm32", Architecture::X86_64 => "x86_64", }; @@ -255,9 +293,12 @@ impl FromStr for Architecture { "unknown" => Architecture::Unknown, "aarch64" => Architecture::Aarch64, "arm" => Architecture::Arm, + "armebv7r" => Architecture::Armebv7r, "armv4t" => Architecture::Armv4t, "armv5te" => Architecture::Armv5te, + "armv6" => Architecture::Armv6, "armv7" => Architecture::Armv7, + "armv7r" => Architecture::Armv7r, "armv7s" => Architecture::Armv7s, "asmjs" => Architecture::Asmjs, "i386" => Architecture::I386, @@ -272,15 +313,20 @@ impl FromStr for Architecture { "powerpc64" => Architecture::Powerpc64, "powerpc64le" => Architecture::Powerpc64le, "riscv32" => Architecture::Riscv32, + "riscv32imac" => Architecture::Riscv32imac, + "riscv32imc" => Architecture::Riscv32imc, "riscv64" => Architecture::Riscv64, "s390x" => Architecture::S390x, "sparc" => Architecture::Sparc, "sparc64" => Architecture::Sparc64, "sparcv9" => Architecture::Sparcv9, "thumbv6m" => Architecture::Thumbv6m, + "thumbv7a" => Architecture::Thumbv7a, "thumbv7em" => Architecture::Thumbv7em, "thumbv7m" => Architecture::Thumbv7m, "thumbv7neon" => Architecture::Thumbv7neon, + "thumbv8m.base" => Architecture::Thumbv8mBase, + "thumbv8m.main" => Architecture::Thumbv8mMain, "wasm32" => Architecture::Wasm32, "x86_64" => Architecture::X86_64, _ => return Err(()), @@ -294,6 +340,7 @@ impl fmt::Display for Vendor { Vendor::Unknown => "unknown", Vendor::Apple => "apple", Vendor::Experimental => "experimental", + Vendor::Fortanix => "fortanix", Vendor::Pc => "pc", Vendor::Rumprun => "rumprun", Vendor::Sun => "sun", @@ -310,6 +357,7 @@ impl FromStr for Vendor { "unknown" => Vendor::Unknown, "apple" => Vendor::Apple, "experimental" => Vendor::Experimental, + "fortanix" => Vendor::Fortanix, "pc" => Vendor::Pc, "rumprun" => Vendor::Rumprun, "sun" => Vendor::Sun, @@ -330,14 +378,17 @@ impl fmt::Display for OperatingSystem { OperatingSystem::Freebsd => "freebsd", OperatingSystem::Fuchsia => "fuchsia", OperatingSystem::Haiku => "haiku", + OperatingSystem::Hermit => "hermit", OperatingSystem::Ios => "ios", OperatingSystem::L4re => "l4re", OperatingSystem::Linux => "linux", OperatingSystem::Nebulet => "nebulet", OperatingSystem::Netbsd => "netbsd", + OperatingSystem::None_ => "none", OperatingSystem::Openbsd => "openbsd", OperatingSystem::Redox => "redox", OperatingSystem::Solaris => "solaris", + OperatingSystem::Uefi => "uefi", OperatingSystem::Windows => "windows", }; f.write_str(s) @@ -358,14 +409,17 @@ impl FromStr for OperatingSystem { "freebsd" => OperatingSystem::Freebsd, "fuchsia" => OperatingSystem::Fuchsia, "haiku" => OperatingSystem::Haiku, + "hermit" => OperatingSystem::Hermit, "ios" => OperatingSystem::Ios, "l4re" => OperatingSystem::L4re, "linux" => OperatingSystem::Linux, "nebulet" => OperatingSystem::Nebulet, "netbsd" => OperatingSystem::Netbsd, + "none" => OperatingSystem::None_, "openbsd" => OperatingSystem::Openbsd, "redox" => OperatingSystem::Redox, "solaris" => OperatingSystem::Solaris, + "uefi" => OperatingSystem::Uefi, "windows" => OperatingSystem::Windows, _ => return Err(()), }) @@ -391,6 +445,7 @@ impl fmt::Display for Environment { Environment::Musleabihf => "musleabihf", Environment::Msvc => "msvc", Environment::Uclibc => "uclibc", + Environment::Sgx => "sgx", }; f.write_str(s) } @@ -417,6 +472,7 @@ impl FromStr for Environment { "musleabihf" => Environment::Musleabihf, "msvc" => Environment::Msvc, "uclibc" => Environment::Uclibc, + "sgx" => Environment::Sgx, _ => return Err(()), }) } @@ -461,72 +517,19 @@ mod tests { // "rustup target list" and "rustc --print target-list". let targets = [ "aarch64-apple-ios", + "aarch64-fuchsia", "aarch64-linux-android", - "aarch64-unknown-fuchsia", - "aarch64-unknown-linux-gnu", - "aarch64-unknown-linux-musl", - "arm-linux-androideabi", - "arm-unknown-linux-gnueabi", - "arm-unknown-linux-gnueabihf", - "arm-unknown-linux-musleabi", - "arm-unknown-linux-musleabihf", - "armv5te-unknown-linux-gnueabi", - "armv7-apple-ios", - "armv7-linux-androideabi", - "armv7-unknown-linux-gnueabihf", - "armv7-unknown-linux-musleabihf", - "armv7s-apple-ios", - "asmjs-unknown-emscripten", - "i386-apple-ios", - "i586-pc-windows-msvc", - "i586-unknown-linux-gnu", - "i586-unknown-linux-musl", - "i686-apple-darwin", - "i686-linux-android", - "i686-pc-windows-gnu", - "i686-pc-windows-msvc", - "i686-unknown-freebsd", - "i686-unknown-linux-gnu", - "i686-unknown-linux-musl", - "mips-unknown-linux-gnu", - "mips-unknown-linux-musl", - "mips64-unknown-linux-gnuabi64", - "mips64el-unknown-linux-gnuabi64", - "mipsel-unknown-linux-gnu", - "mipsel-unknown-linux-musl", - "powerpc-unknown-linux-gnu", - "powerpc64-unknown-linux-gnu", - "powerpc64le-unknown-linux-gnu", - "s390x-unknown-linux-gnu", - "sparc64-unknown-linux-gnu", - "sparcv9-sun-solaris", - "thumbv6m-none-eabi", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv7m-none-eabi", - "wasm32-unknown-emscripten", - "wasm32-unknown-unknown", - "x86_64-apple-darwin", - "x86_64-apple-ios", - "x86_64-linux-android", - "x86_64-pc-windows-gnu", - "x86_64-pc-windows-msvc", - "x86_64-rumprun-netbsd", - "x86_64-sun-solaris", - "x86_64-unknown-cloudabi", - "x86_64-unknown-freebsd", - "x86_64-unknown-fuchsia", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-gnux32", - "x86_64-unknown-linux-musl", - "x86_64-unknown-netbsd", - "x86_64-unknown-redox", - "aarch64-linux-android", + "aarch64-pc-windows-msvc", "aarch64-unknown-cloudabi", "aarch64-unknown-freebsd", - "aarch64-unknown-fuchsia", + "aarch64-unknown-hermit", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", + "aarch64-unknown-netbsd", + "aarch64-unknown-none", + "aarch64-unknown-openbsd", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", "arm-linux-androideabi", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", @@ -534,11 +537,19 @@ mod tests { "arm-unknown-linux-musleabihf", "armv4t-unknown-linux-gnueabi", "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv6-unknown-netbsd-eabihf", + "armv7-apple-ios", "armv7-linux-androideabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "armv7s-apple-ios", "armv7-unknown-cloudabi-eabihf", "armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabihf", + "armv7-unknown-netbsd-eabihf", "asmjs-unknown-emscripten", + "i386-apple-ios", "i586-pc-windows-msvc", "i586-unknown-linux-gnu", "i586-unknown-linux-musl", @@ -554,33 +565,47 @@ mod tests { "i686-unknown-linux-musl", "i686-unknown-netbsd", "i686-unknown-openbsd", - "mips-unknown-linux-gnu", - "mips-unknown-linux-musl", - "mips-unknown-linux-uclibc", - "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", + "mips64-unknown-linux-gnuabi64", "mipsel-unknown-linux-gnu", "mipsel-unknown-linux-musl", "mipsel-unknown-linux-uclibc", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips-unknown-linux-uclibc", "msp430-none-elf", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", "powerpc-unknown-linux-gnu", "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-linux-musl", "powerpc-unknown-netbsd", - "powerpc64-unknown-linux-gnu", - "powerpc64le-unknown-linux-gnu", + "riscv32imac-unknown-none-elf", + "riscv32imc-unknown-none-elf", "s390x-unknown-linux-gnu", - "sparc-unknown-linux-gnu", "sparc64-unknown-linux-gnu", "sparc64-unknown-netbsd", + "sparc-unknown-linux-gnu", "sparcv9-sun-solaris", "thumbv6m-none-eabi", + "thumbv7a-pc-windows-msvc", "thumbv7em-none-eabi", "thumbv7em-none-eabihf", "thumbv7m-none-eabi", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", "wasm32-experimental-emscripten", "wasm32-unknown-emscripten", "wasm32-unknown-unknown", "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fortanix-unknown-sgx", + "x86_64-fuchsia", "x86_64-linux-android", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", @@ -590,8 +615,8 @@ mod tests { "x86_64-unknown-cloudabi", "x86_64-unknown-dragonfly", "x86_64-unknown-freebsd", - "x86_64-unknown-fuchsia", "x86_64-unknown-haiku", + "x86_64-unknown-hermit", "x86_64-unknown-l4re-uclibc", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnux32", @@ -599,6 +624,7 @@ mod tests { "x86_64-unknown-netbsd", "x86_64-unknown-openbsd", "x86_64-unknown-redox", + "x86_64-unknown-uefi", ]; for target in targets.iter() { diff --git a/third_party/rust/target-lexicon/src/triple.rs b/third_party/rust/target-lexicon/src/triple.rs index 454b99e55f8a..c998891a904b 100644 --- a/third_party/rust/target-lexicon/src/triple.rs +++ b/third_party/rust/target-lexicon/src/triple.rs @@ -1,12 +1,12 @@ // This file defines the `Triple` type and support code shared by all targets. -use parse_error::ParseError; -use std::borrow::ToOwned; -use std::fmt; -use std::str::FromStr; -use targets::{ +use crate::parse_error::ParseError; +use crate::targets::{ default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor, }; +use core::fmt; +use core::str::FromStr; +use std::borrow::ToOwned; /// The target memory endianness. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -155,17 +155,24 @@ impl fmt::Display for Triple { write!(f, "{}", self.architecture)?; if self.vendor == Vendor::Unknown - && self.operating_system == OperatingSystem::Unknown - && (self.environment != Environment::Unknown - || self.binary_format != implied_binary_format) + && ((self.operating_system == OperatingSystem::Linux + && (self.environment == Environment::Android + || self.environment == Environment::Androideabi)) + || self.operating_system == OperatingSystem::Fuchsia + || (self.operating_system == OperatingSystem::None_ + && (self.architecture == Architecture::Armebv7r + || self.architecture == Architecture::Armv7r + || self.architecture == Architecture::Thumbv6m + || self.architecture == Architecture::Thumbv7em + || self.architecture == Architecture::Thumbv7m + || self.architecture == Architecture::Thumbv8mBase + || self.architecture == Architecture::Thumbv8mMain + || self.architecture == Architecture::Msp430))) { - // "none" is special-case shorthand for unknown vendor and unknown operating system. - f.write_str("-none")?; - } else if self.operating_system == OperatingSystem::Linux - && (self.environment == Environment::Android - || self.environment == Environment::Androideabi) - { - // As a special case, omit the vendor for Android targets. + // As a special case, omit the vendor for Android, Fuchsia, and sometimes + // None_, depending on the hardware architecture. This logic is entirely + // ad-hoc, and is just sufficient to handle the current set of recognized + // triples. write!(f, "-{}", self.operating_system)?; } else { write!(f, "-{}-{}", self.vendor, self.operating_system)?; @@ -203,16 +210,7 @@ impl FromStr for Triple { let mut has_vendor = false; let mut has_operating_system = false; if let Some(s) = current_part { - // "none" is special-case shorthand for unknown vendor and unknown operating system. - if s == "none" { - has_operating_system = true; - has_vendor = true; - current_part = parts.next(); - // "none" requires an explicit environment or binary format. - if current_part.is_none() { - return Err(ParseError::NoneWithoutBinaryFormat); - } - } else if let Ok(vendor) = Vendor::from_str(s) { + if let Ok(vendor) = Vendor::from_str(s) { has_vendor = true; result.vendor = vendor; current_part = parts.next(); diff --git a/third_party/rust/wasmparser/.cargo-checksum.json b/third_party/rust/wasmparser/.cargo-checksum.json index 2a2fe17939db..e68beebe8689 100644 --- a/third_party/rust/wasmparser/.cargo-checksum.json +++ b/third_party/rust/wasmparser/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"7f3766bd0ddca19ad961a1da2ebcc50de261b42a0ab5b386c0a6b3704ea8d46b","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"13ea373a411dfa7371cd994736289bb000db51957da92315fecbcc9fe7dcab92","examples/dump.rs":"b0a4fbc3dd85df85f5eca39861b09f89716c55ff97657e7a32cf6fdee7a88e60","examples/simple.rs":"9726621cd8314ed3c7e293913b06847208ff98e43e1b4d5c79708a7b71c7a768","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"d6b0dd34c2a97babae84d1758df75515de372c5228450267141ebbad402c8acd","src/lib.rs":"c19b1965080115dfd5c256398f87f90cd0c35220eb6c9c71ae4e96a71bb38e2f","src/limits.rs":"2cf22e266c2828d68bb521485b8bd604a2ecb7a023204d7874b3da5837ec44f9","src/parser.rs":"8f29497795ef8b93134680ff9cb38dbb4f0520ceba270c1d6cee22694362b270","src/primitives.rs":"32d3662d7473bc770bcb14a2878ce9d21a00635d928ee142ae4bdbfbb741b159","src/readers/code_section.rs":"d71a798dce497838c8d6b3aa9744a2cae818b7aff99d45a31a4accb892985fd1","src/readers/data_section.rs":"74e751ea3cecbe29eb6d6b1b0119f859a5aec1a3240c4a71c381e7409378fa45","src/readers/element_section.rs":"b8f2e367b08f0a7097a9eece6a27e7170c175a13c007b7c4cb3517fa81250ff4","src/readers/export_section.rs":"dc11c96c4955cf18d1fdd50c2a6dddabd915c0ee8fc998e12130b534c9c2b621","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"4dc8ec40c237c30b951bb31a7150a5159430e01d62c91d58ef4922bec65b0f6a","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"9de31285cded591651108f16b9463cee7289536c722dbcf49a33847047a82bd1","src/readers/module.rs":"31329dabf177f29b40fa53fa44b19ab545c47bae8bc1e29ef995f413f572e303","src/readers/name_section.rs":"e61633a3a43f4626f15cd85d53f66a5e2bab0f016658ca792b0c94574f84b57c","src/readers/operators.rs":"da43ee8afcb0c1d6e7f1e19e8a10143101f0c598b1e533a394c7397f43881a82","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"742602c2537ba3ed50f830b1929fe2d19bb68ea04ddb59f77dc47109e84f262a","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"ef8247ba96a17505dbd08d0d9c4caee8f3c7510523680f00f147d5ff1512b744","src/validator.rs":"ad7e73c8677513598264b2f48e0cf3fefbd36b451b0c76ea6609f906884cf467","test-all.sh":"ff894f4e5e34389ad6ef697bd4ade28a2483dd456eabba8b757945546568f4c9","test-no_std.sh":"f8bc939b378fe618b7ec6297152708e7c8740858eb94e5756464934a38796b8c"},"package":"b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060"} \ No newline at end of file +{"files":{"Cargo.toml":"6f05ad46e7a84c8ae06ee90f29bb874acb68074a88aa31838554b9f9c07cd405","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"13ea373a411dfa7371cd994736289bb000db51957da92315fecbcc9fe7dcab92","examples/dump.rs":"fdebf1af451d06691d011ba7220f3f9a483b2c54a851f06b610aaa5fcb3832df","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"e8d58f2ab57123955c680e9c9e790aec8e8a36732a77349bcdbadd7d8faf1c7d","src/lib.rs":"2fae91a32fe51183d5f9d4aab48665a0e617d6127a2031d6aaf4aa257e76dca1","src/limits.rs":"2cf22e266c2828d68bb521485b8bd604a2ecb7a023204d7874b3da5837ec44f9","src/parser.rs":"40624c94c125446b0c6106e7590b35c58df2a6ceafc85a72bb013eef2018eb58","src/primitives.rs":"4627647982376ea8519f931f09108d04c7080cf6b2a4b2d85e559ba7cfb6ad70","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e31e1d819c0b10acf58b8975238554245defe36db1c3206683b056c52978fb21","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"13822fff4190b72f6ae14e29635d2c148a38ee972e148eb99a4688b0309bc2c9","src/readers/module.rs":"66473e7077b3d77ed01ed58d2796c8de7afdb2b90f2b0669c06fa90ca1b3434e","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"da43ee8afcb0c1d6e7f1e19e8a10143101f0c598b1e533a394c7397f43881a82","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"ca486d82ffaa31370534d7d1475c0603f0e9d4888d3d07287b9d5458e6d11156","src/validator.rs":"ec0d1368f3b7833ff6d6178db50e3ffc6b2878d1d6ddab37728fdf21e8256896","test-all.sh":"ff894f4e5e34389ad6ef697bd4ade28a2483dd456eabba8b757945546568f4c9","test-no_std.sh":"f8bc939b378fe618b7ec6297152708e7c8740858eb94e5756464934a38796b8c"},"package":"981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00"} \ No newline at end of file diff --git a/third_party/rust/wasmparser/Cargo.toml b/third_party/rust/wasmparser/Cargo.toml index 764a5437f1de..7ca665a02339 100644 --- a/third_party/rust/wasmparser/Cargo.toml +++ b/third_party/rust/wasmparser/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "wasmparser" -version = "0.23.0" +version = "0.29.2" authors = ["Yury Delendik "] exclude = ["fuzz/**/*", "tests/**/*"] description = "A simple event-driven library for parsing WebAssembly binary files.\n" diff --git a/third_party/rust/wasmparser/examples/dump.rs b/third_party/rust/wasmparser/examples/dump.rs index 588c3a9da2a7..d74b3ceabc98 100644 --- a/third_party/rust/wasmparser/examples/dump.rs +++ b/third_party/rust/wasmparser/examples/dump.rs @@ -9,10 +9,6 @@ use wasmparser::Parser; use wasmparser::ParserState; use wasmparser::WasmDecoder; -fn get_name(bytes: &[u8]) -> &str { - str::from_utf8(bytes).ok().unwrap() -} - fn main() { let args = env::args().collect::>(); if args.len() != 2 { @@ -32,9 +28,7 @@ fn main() { } => { println!( "ExportSectionEntry {{ field: \"{}\", kind: {:?}, index: {} }}", - get_name(field), - kind, - index + field, kind, index ); } ParserState::ImportSectionEntry { @@ -44,9 +38,7 @@ fn main() { } => { println!( "ImportSectionEntry {{ module: \"{}\", field: \"{}\", ty: {:?} }}", - get_name(module), - get_name(field), - ty + module, field, ty ); } ParserState::EndWasm => break, diff --git a/third_party/rust/wasmparser/examples/simple.rs b/third_party/rust/wasmparser/examples/simple.rs index ef0279fb69cd..132aa41f9fb5 100644 --- a/third_party/rust/wasmparser/examples/simple.rs +++ b/third_party/rust/wasmparser/examples/simple.rs @@ -9,10 +9,6 @@ use wasmparser::Parser; use wasmparser::ParserState; use wasmparser::WasmDecoder; -fn get_name(bytes: &[u8]) -> &str { - str::from_utf8(bytes).ok().unwrap() -} - fn main() { let args = env::args().collect::>(); if args.len() != 2 { @@ -31,10 +27,10 @@ fn main() { ParserState::ExportSectionEntry { field, ref kind, .. } => { - println!(" Export {} {:?}", get_name(field), kind); + println!(" Export {} {:?}", field, kind); } ParserState::ImportSectionEntry { module, field, .. } => { - println!(" Import {}::{}", get_name(module), get_name(field)) + println!(" Import {}::{}", module, field) } ParserState::EndWasm => break, ParserState::Error(err) => panic!("Error: {:?}", err), diff --git a/third_party/rust/wasmparser/src/binary_reader.rs b/third_party/rust/wasmparser/src/binary_reader.rs index 482585734b98..b1375f58aa2f 100644 --- a/third_party/rust/wasmparser/src/binary_reader.rs +++ b/third_party/rust/wasmparser/src/binary_reader.rs @@ -14,6 +14,7 @@ */ use std::boxed::Box; +use std::str; use std::vec::Vec; use limits::{ @@ -24,35 +25,17 @@ use limits::{ use primitives::{ BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32, Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType, - ResizableLimits, Result, SectionCode, TableType, Type, + ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type, V128, }; const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE; -fn is_name(name: &[u8], expected: &'static str) -> bool { - if name.len() != expected.len() { - return false; - } - let expected_bytes = expected.as_bytes(); - for i in 0..name.len() { - if name[i] != expected_bytes[i] { - return false; - } - } - true +fn is_name(name: &str, expected: &'static str) -> bool { + name == expected } -fn is_name_prefix(name: &[u8], prefix: &'static str) -> bool { - if name.len() < prefix.len() { - return false; - } - let expected_bytes = prefix.as_bytes(); - for i in 0..expected_bytes.len() { - if name[i] != expected_bytes[i] { - return false; - } - } - true +fn is_name_prefix(name: &str, prefix: &'static str) -> bool { + name.starts_with(prefix) } const WASM_MAGIC_NUMBER: u32 = 0x6d736100; @@ -123,6 +106,13 @@ impl<'a> BinaryReader<'a> { self.original_offset + self.position } + pub fn range(&self) -> Range { + Range { + start: self.original_offset, + end: self.original_offset + self.buffer.len(), + } + } + fn ensure_has_byte(&self) -> Result<()> { if self.position < self.buffer.len() { Ok(()) @@ -185,6 +175,7 @@ impl<'a> BinaryReader<'a> { -0x02 => Ok(Type::I64), -0x03 => Ok(Type::F32), -0x04 => Ok(Type::F64), + -0x05 => Ok(Type::V128), -0x10 => Ok(Type::AnyFunc), -0x11 => Ok(Type::AnyRef), -0x20 => Ok(Type::Func), @@ -332,6 +323,8 @@ impl<'a> BinaryReader<'a> { let name = self.read_string()?; let kind = if is_name(name, "name") { CustomSectionKind::Name + } else if is_name(name, "producers") { + CustomSectionKind::Producers } else if is_name(name, "sourceMappingURL") { CustomSectionKind::SourceMappingURL } else if is_name_prefix(name, "reloc.") { @@ -354,6 +347,7 @@ impl<'a> BinaryReader<'a> { 9 => Ok(SectionCode::Element), 10 => Ok(SectionCode::Code), 11 => Ok(SectionCode::Data), + 12 => Ok(SectionCode::DataCount), _ => Err(BinaryReaderError { message: "Invalid section code", offset, @@ -376,6 +370,7 @@ impl<'a> BinaryReader<'a> { self.skip_var_32()?; Ok(BrTable { buffer: &self.buffer[start..self.position], + cnt: targets_len as usize, }) } @@ -558,7 +553,7 @@ impl<'a> BinaryReader<'a> { Ok(Ieee64(value)) } - pub fn read_string(&mut self) -> Result<&'a [u8]> { + pub fn read_string(&mut self) -> Result<&'a str> { let len = self.read_var_u32()? as usize; if len > MAX_WASM_STRING_SIZE { return Err(BinaryReaderError { @@ -566,7 +561,11 @@ impl<'a> BinaryReader<'a> { offset: self.original_position() - 1, }); } - self.read_bytes(len) + let bytes = self.read_bytes(len)?; + str::from_utf8(bytes).map_err(|_| BinaryReaderError { + message: "non-utf8 string", + offset: self.original_position() - 1, + }) } fn read_memarg_of_align(&mut self, align: u32) -> Result { @@ -786,7 +785,7 @@ impl<'a> BinaryReader<'a> { return Err(BinaryReaderError { message: "Unknown 0xFE opcode", offset: self.original_position() - 1, - }) + }); } }) } @@ -822,7 +821,7 @@ impl<'a> BinaryReader<'a> { }, 0x11 => Operator::CallIndirect { index: self.read_var_u32()?, - table_index: self.read_var_u1()?, + table_index: self.read_var_u32()?, }, 0x1a => Operator::Drop, 0x1b => Operator::Select, @@ -841,6 +840,12 @@ impl<'a> BinaryReader<'a> { 0x24 => Operator::SetGlobal { global_index: self.read_var_u32()?, }, + 0x25 => Operator::TableGet { + table: self.read_var_u32()?, + }, + 0x26 => Operator::TableSet { + table: self.read_var_u32()?, + }, 0x28 => Operator::I32Load { memarg: self.read_memarg()?, }, @@ -1062,14 +1067,14 @@ impl<'a> BinaryReader<'a> { 0xd1 => Operator::RefIsNull, 0xfc => self.read_0xfc_operator()?, - + 0xfd => self.read_0xfd_operator()?, 0xfe => self.read_0xfe_operator()?, _ => { return Err(BinaryReaderError { message: "Unknown opcode", offset: self.original_position() - 1, - }) + }); } }) } @@ -1086,11 +1091,304 @@ impl<'a> BinaryReader<'a> { 0x06 => Operator::I64TruncSSatF64, 0x07 => Operator::I64TruncUSatF64, + 0x08 => { + let segment = self.read_var_u32()?; + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryInit { segment } + } + 0x09 => { + let segment = self.read_var_u32()?; + Operator::DataDrop { segment } + } + 0x0a => { + let src = self.read_u8()?; + if src != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + let dst = self.read_u8()?; + if dst != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryCopy + } + 0x0b => { + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryFill + } + 0x0c => { + let segment = self.read_var_u32()?; + let table = self.read_u8()?; + if table != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::TableInit { segment } + } + 0x0d => { + let segment = self.read_var_u32()?; + Operator::ElemDrop { segment } + } + 0x0e => { + let src = self.read_u8()?; + if src != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + let dst = self.read_u8()?; + if dst != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::TableCopy + } + + 0x0f => { + let table = self.read_var_u32()?; + Operator::TableGrow { table } + } + 0x10 => { + let table = self.read_var_u32()?; + Operator::TableSize { table } + } + _ => { return Err(BinaryReaderError { message: "Unknown 0xfc opcode", offset: self.original_position() - 1, - }) + }); + } + }) + } + + fn read_line_index(&mut self, max: u32) -> Result { + let index = self.read_u8()?; + if index >= max { + return Err(BinaryReaderError { + message: "line index out of range", + offset: self.original_position() - 1, + }); + } + Ok(index as SIMDLineIndex) + } + + fn read_v128(&mut self) -> Result { + let mut bytes = [0; 16]; + bytes.clone_from_slice(self.read_bytes(16)?); + Ok(V128(bytes)) + } + + fn read_0xfd_operator(&mut self) -> Result> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::V128Load { + memarg: self.read_memarg()?, + }, + 0x01 => Operator::V128Store { + memarg: self.read_memarg()?, + }, + 0x02 => Operator::V128Const { + value: self.read_v128()?, + }, + 0x03 => { + let mut lines = [0 as SIMDLineIndex; 16]; + for i in 0..16 { + lines[i] = self.read_line_index(32)? + } + Operator::V8x16Shuffle { lines } + } + 0x04 => Operator::I8x16Splat, + 0x05 => Operator::I8x16ExtractLaneS { + line: self.read_line_index(16)?, + }, + 0x06 => Operator::I8x16ExtractLaneU { + line: self.read_line_index(16)?, + }, + 0x07 => Operator::I8x16ReplaceLane { + line: self.read_line_index(16)?, + }, + 0x08 => Operator::I16x8Splat, + 0x09 => Operator::I16x8ExtractLaneS { + line: self.read_line_index(8)?, + }, + 0x0a => Operator::I16x8ExtractLaneU { + line: self.read_line_index(8)?, + }, + 0x0b => Operator::I16x8ReplaceLane { + line: self.read_line_index(8)?, + }, + 0x0c => Operator::I32x4Splat, + 0x0d => Operator::I32x4ExtractLane { + line: self.read_line_index(4)?, + }, + 0x0e => Operator::I32x4ReplaceLane { + line: self.read_line_index(4)?, + }, + 0x0f => Operator::I64x2Splat, + 0x10 => Operator::I64x2ExtractLane { + line: self.read_line_index(2)?, + }, + 0x11 => Operator::I64x2ReplaceLane { + line: self.read_line_index(2)?, + }, + 0x12 => Operator::F32x4Splat, + 0x13 => Operator::F32x4ExtractLane { + line: self.read_line_index(4)?, + }, + 0x14 => Operator::F32x4ReplaceLane { + line: self.read_line_index(4)?, + }, + 0x15 => Operator::F64x2Splat, + 0x16 => Operator::F64x2ExtractLane { + line: self.read_line_index(2)?, + }, + 0x17 => Operator::F64x2ReplaceLane { + line: self.read_line_index(2)?, + }, + 0x18 => Operator::I8x16Eq, + 0x19 => Operator::I8x16Ne, + 0x1a => Operator::I8x16LtS, + 0x1b => Operator::I8x16LtU, + 0x1c => Operator::I8x16GtS, + 0x1d => Operator::I8x16GtU, + 0x1e => Operator::I8x16LeS, + 0x1f => Operator::I8x16LeU, + 0x20 => Operator::I8x16GeS, + 0x21 => Operator::I8x16GeU, + 0x22 => Operator::I16x8Eq, + 0x23 => Operator::I16x8Ne, + 0x24 => Operator::I16x8LtS, + 0x25 => Operator::I16x8LtU, + 0x26 => Operator::I16x8GtS, + 0x27 => Operator::I16x8GtU, + 0x28 => Operator::I16x8LeS, + 0x29 => Operator::I16x8LeU, + 0x2a => Operator::I16x8GeS, + 0x2b => Operator::I16x8GeU, + 0x2c => Operator::I32x4Eq, + 0x2d => Operator::I32x4Ne, + 0x2e => Operator::I32x4LtS, + 0x2f => Operator::I32x4LtU, + 0x30 => Operator::I32x4GtS, + 0x31 => Operator::I32x4GtU, + 0x32 => Operator::I32x4LeS, + 0x33 => Operator::I32x4LeU, + 0x34 => Operator::I32x4GeS, + 0x35 => Operator::I32x4GeU, + 0x40 => Operator::F32x4Eq, + 0x41 => Operator::F32x4Ne, + 0x42 => Operator::F32x4Lt, + 0x43 => Operator::F32x4Gt, + 0x44 => Operator::F32x4Le, + 0x45 => Operator::F32x4Ge, + 0x46 => Operator::F64x2Eq, + 0x47 => Operator::F64x2Ne, + 0x48 => Operator::F64x2Lt, + 0x49 => Operator::F64x2Gt, + 0x4a => Operator::F64x2Le, + 0x4b => Operator::F64x2Ge, + 0x4c => Operator::V128Not, + 0x4d => Operator::V128And, + 0x4e => Operator::V128Or, + 0x4f => Operator::V128Xor, + 0x50 => Operator::V128Bitselect, + 0x51 => Operator::I8x16Neg, + 0x52 => Operator::I8x16AnyTrue, + 0x53 => Operator::I8x16AllTrue, + 0x54 => Operator::I8x16Shl, + 0x55 => Operator::I8x16ShrS, + 0x56 => Operator::I8x16ShrU, + 0x57 => Operator::I8x16Add, + 0x58 => Operator::I8x16AddSaturateS, + 0x59 => Operator::I8x16AddSaturateU, + 0x5a => Operator::I8x16Sub, + 0x5b => Operator::I8x16SubSaturateS, + 0x5c => Operator::I8x16SubSaturateU, + 0x5d => Operator::I8x16Mul, + 0x62 => Operator::I16x8Neg, + 0x63 => Operator::I16x8AnyTrue, + 0x64 => Operator::I16x8AllTrue, + 0x65 => Operator::I16x8Shl, + 0x66 => Operator::I16x8ShrS, + 0x67 => Operator::I16x8ShrU, + 0x68 => Operator::I16x8Add, + 0x69 => Operator::I16x8AddSaturateS, + 0x6a => Operator::I16x8AddSaturateU, + 0x6b => Operator::I16x8Sub, + 0x6c => Operator::I16x8SubSaturateS, + 0x6d => Operator::I16x8SubSaturateU, + 0x6e => Operator::I16x8Mul, + 0x73 => Operator::I32x4Neg, + 0x74 => Operator::I32x4AnyTrue, + 0x75 => Operator::I32x4AllTrue, + 0x76 => Operator::I32x4Shl, + 0x77 => Operator::I32x4ShrS, + 0x78 => Operator::I32x4ShrU, + 0x79 => Operator::I32x4Add, + 0x7c => Operator::I32x4Sub, + 0x7f => Operator::I32x4Mul, + 0x84 => Operator::I64x2Neg, + 0x85 => Operator::I64x2AnyTrue, + 0x86 => Operator::I64x2AllTrue, + 0x87 => Operator::I64x2Shl, + 0x88 => Operator::I64x2ShrS, + 0x89 => Operator::I64x2ShrU, + 0x8a => Operator::I64x2Add, + 0x8d => Operator::I64x2Sub, + 0x95 => Operator::F32x4Abs, + 0x96 => Operator::F32x4Neg, + 0x97 => Operator::F32x4Sqrt, + 0x9a => Operator::F32x4Add, + 0x9b => Operator::F32x4Sub, + 0x9c => Operator::F32x4Mul, + 0x9d => Operator::F32x4Div, + 0x9e => Operator::F32x4Min, + 0x9f => Operator::F32x4Max, + 0xa0 => Operator::F64x2Abs, + 0xa1 => Operator::F64x2Neg, + 0xa2 => Operator::F64x2Sqrt, + 0xa5 => Operator::F64x2Add, + 0xa6 => Operator::F64x2Sub, + 0xa7 => Operator::F64x2Mul, + 0xa8 => Operator::F64x2Div, + 0xa9 => Operator::F64x2Min, + 0xaa => Operator::F64x2Max, + 0xab => Operator::I32x4TruncSF32x4Sat, + 0xac => Operator::I32x4TruncUF32x4Sat, + 0xad => Operator::I64x2TruncSF64x2Sat, + 0xae => Operator::I64x2TruncUF64x2Sat, + 0xaf => Operator::F32x4ConvertSI32x4, + 0xb0 => Operator::F32x4ConvertUI32x4, + 0xb1 => Operator::F64x2ConvertSI64x2, + 0xb2 => Operator::F64x2ConvertUI64x2, + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xfd opcode", + offset: self.original_position() - 1, + }); } }) } @@ -1181,6 +1479,12 @@ impl<'a> BinaryReader<'a> { } impl<'a> BrTable<'a> { + /// Returns the number of `br_table` entries, not including the default + /// label + pub fn len(&self) -> usize { + self.cnt + } + /// Reads br_table entries. /// /// # Examples diff --git a/third_party/rust/wasmparser/src/lib.rs b/third_party/rust/wasmparser/src/lib.rs index 82fface79197..d0ed06d16aac 100644 --- a/third_party/rust/wasmparser/src/lib.rs +++ b/third_party/rust/wasmparser/src/lib.rs @@ -66,6 +66,7 @@ pub use primitives::Result; pub use primitives::SectionCode; pub use primitives::TableType; pub use primitives::Type; +pub use primitives::V128; pub use validator::validate; pub use validator::OperatorValidatorConfig; @@ -76,10 +77,12 @@ pub use validator::WasmModuleResources; pub use readers::CodeSectionReader; pub use readers::Data; +pub use readers::DataKind; pub use readers::DataSectionReader; pub use readers::Element; pub use readers::ElementItems; pub use readers::ElementItemsReader; +pub use readers::ElementKind; pub use readers::ElementSectionReader; pub use readers::Export; pub use readers::ExportSectionReader; @@ -98,6 +101,9 @@ pub use readers::Name; pub use readers::NameSectionReader; pub use readers::NamingReader; pub use readers::OperatorsReader; +pub use readers::ProducersField; +pub use readers::ProducersFieldValue; +pub use readers::ProducersSectionReader; pub use readers::Reloc; pub use readers::RelocSectionReader; pub use readers::Section; diff --git a/third_party/rust/wasmparser/src/parser.rs b/third_party/rust/wasmparser/src/parser.rs index 2f23a1bdbf35..5a5a30ce079a 100644 --- a/third_party/rust/wasmparser/src/parser.rs +++ b/third_party/rust/wasmparser/src/parser.rs @@ -28,11 +28,11 @@ use primitives::{ }; use readers::{ - CodeSectionReader, Data, DataSectionReader, Element, ElementItems, ElementSectionReader, - Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global, GlobalSectionReader, - Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader, ModuleReader, Name, - NameSectionReader, NamingReader, OperatorsReader, Reloc, RelocSectionReader, Section, - SectionReader, TableSectionReader, TypeSectionReader, + CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind, + ElementSectionReader, Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global, + GlobalSectionReader, Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader, + ModuleReader, Name, NameSectionReader, NamingReader, OperatorsReader, Reloc, + RelocSectionReader, Section, SectionReader, TableSectionReader, TypeSectionReader, }; use binary_reader::{BinaryReader, Range}; @@ -47,7 +47,7 @@ pub struct LocalName<'a> { #[derive(Debug)] pub enum NameEntry<'a> { - Module(&'a [u8]), + Module(&'a str), Function(Box<[Naming<'a>]>), Local(Box<[LocalName<'a>]>), } @@ -86,20 +86,21 @@ pub enum ParserState<'a> { TypeSectionEntry(FuncType), ImportSectionEntry { - module: &'a [u8], - field: &'a [u8], + module: &'a str, + field: &'a str, ty: ImportSectionEntryType, }, FunctionSectionEntry(u32), TableSectionEntry(TableType), MemorySectionEntry(MemoryType), ExportSectionEntry { - field: &'a [u8], + field: &'a str, kind: ExternalKind, index: u32, }, NameSectionEntry(NameEntry<'a>), StartSectionEntry(u32), + DataCountSectionEntry(u32), BeginInitExpressionBody, InitExpressionOperator(Operator<'a>), @@ -115,11 +116,13 @@ pub enum ParserState<'a> { EndFunctionBody, SkippingFunctionBody, - BeginElementSectionEntry(u32), + BeginPassiveElementSectionEntry(Type), + BeginActiveElementSectionEntry(u32), ElementSectionEntryBody(Box<[u32]>), EndElementSectionEntry, - BeginDataSectionEntry(u32), + BeginPassiveDataSectionEntry, + BeginActiveDataSectionEntry(u32), EndDataSectionEntry, BeginDataSectionEntryBody(u32), DataSectionEntryBodyChunk(&'a [u8]), @@ -132,7 +135,7 @@ pub enum ParserState<'a> { RelocSectionEntry(RelocEntry), LinkingSectionEntry(LinkingType), - SourceMappingURL(&'a [u8]), + SourceMappingURL(&'a str), } #[derive(Debug, Copy, Clone)] @@ -269,33 +272,33 @@ impl<'a> Parser<'a> { ParserSectionReader::CodeSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::DataSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::ElementSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::ExportSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::FunctionSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::GlobalSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::ImportSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::MemorySectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::TableSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::TypeSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::NameSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::LinkingSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } ParserSectionReader::RelocSectionReader(ref reader) => { - return reader.original_position() + return reader.original_position(); } _ => (), }; @@ -317,7 +320,7 @@ impl<'a> Parser<'a> { fn read_section_header(&mut self) -> Result<()> { let section = self.module_reader.as_mut().expect("module reader").read()?; let code = section.code; - let range = section.get_range(); + let range = section.range(); self.current_section = Some(section); self.state = ParserState::BeginSection { code, range }; Ok(()) @@ -408,13 +411,19 @@ impl<'a> Parser<'a> { if self.section_entries_left == 0 { return self.check_section_end(); } - let Element { - table_index, - init_expr, - items, - } = section_reader!(self, ElementSectionReader).read()?; - self.state = ParserState::BeginElementSectionEntry(table_index); - self.operators_reader = Some(init_expr.get_operators_reader()); + let Element { kind, items } = section_reader!(self, ElementSectionReader).read()?; + match kind { + ElementKind::Passive(ty) => { + self.state = ParserState::BeginPassiveElementSectionEntry(ty); + } + ElementKind::Active { + table_index, + init_expr, + } => { + self.state = ParserState::BeginActiveElementSectionEntry(table_index); + self.operators_reader = Some(init_expr.get_operators_reader()); + } + } self.element_items = Some(items); self.section_entries_left -= 1; Ok(()) @@ -447,7 +456,7 @@ impl<'a> Parser<'a> { return self.check_section_end(); } let function_body = section_reader!(self, CodeSectionReader).read()?; - let range = function_body.get_range(); + let range = function_body.range(); self.state = ParserState::BeginFunctionBody { range }; self.current_function_body = Some(function_body); self.section_entries_left -= 1; @@ -529,13 +538,19 @@ impl<'a> Parser<'a> { if self.section_entries_left == 0 { return self.check_section_end(); } - let Data { - memory_index, - init_expr, - data, - } = section_reader!(self, DataSectionReader).read()?; - self.state = ParserState::BeginDataSectionEntry(memory_index); - self.operators_reader = Some(init_expr.get_operators_reader()); + let Data { kind, data } = section_reader!(self, DataSectionReader).read()?; + match kind { + DataKind::Passive => { + self.state = ParserState::BeginPassiveDataSectionEntry; + } + DataKind::Active { + memory_index, + init_expr, + } => { + self.state = ParserState::BeginActiveDataSectionEntry(memory_index); + self.operators_reader = Some(init_expr.get_operators_reader()); + } + } self.current_data_segment = Some(data); self.section_entries_left -= 1; Ok(()) @@ -731,6 +746,17 @@ impl<'a> Parser<'a> { .get_start_section_content()?; self.state = ParserState::StartSectionEntry(func_index); } + ParserState::BeginSection { + code: SectionCode::DataCount, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_data_count_section_content()?; + self.state = ParserState::DataCountSectionEntry(func_index); + } ParserState::BeginSection { code: SectionCode::Custom { .. }, .. @@ -774,7 +800,8 @@ impl<'a> Parser<'a> { start_section_reader!(self, LinkingSectionReader, get_linking_section_reader); self.read_linking_entry()?; } - ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { + ParserState::ReadingCustomSection(CustomSectionKind::Producers) + | ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { self.create_custom_section_binary_reader(); self.read_section_body_bytes()?; } @@ -875,13 +902,17 @@ impl<'a> Parser<'a> { self.read_init_expression_body(InitExpressionContinuation::GlobalSection) } ParserState::EndGlobalSectionEntry => self.read_global_entry()?, - ParserState::BeginElementSectionEntry(_) => { + ParserState::BeginPassiveElementSectionEntry(_) => self.read_element_entry_body()?, + ParserState::BeginActiveElementSectionEntry(_) => { self.read_init_expression_body(InitExpressionContinuation::ElementSection) } ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => { self.read_init_expression_operator()? } - ParserState::BeginDataSectionEntry(_) => { + ParserState::BeginPassiveDataSectionEntry => { + self.read_data_entry_body()?; + } + ParserState::BeginActiveDataSectionEntry(_) => { self.read_init_expression_body(InitExpressionContinuation::DataSection) } ParserState::EndInitExpressionBody => { @@ -917,6 +948,7 @@ impl<'a> Parser<'a> { } ParserState::EndElementSectionEntry => self.read_element_entry()?, ParserState::StartSectionEntry(_) => self.position_to_section_end()?, + ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?, ParserState::NameSectionEntry(_) => self.read_name_entry()?, ParserState::SourceMappingURL(_) => self.position_to_section_end()?, ParserState::RelocSectionHeader(_) => { diff --git a/third_party/rust/wasmparser/src/primitives.rs b/third_party/rust/wasmparser/src/primitives.rs index 6ff1f36b1c8c..4ae9b43401ae 100644 --- a/third_party/rust/wasmparser/src/primitives.rs +++ b/third_party/rust/wasmparser/src/primitives.rs @@ -14,6 +14,8 @@ */ use std::boxed::Box; +use std::error::Error; +use std::fmt; use std::result; #[derive(Debug, Copy, Clone)] @@ -24,10 +26,19 @@ pub struct BinaryReaderError { pub type Result = result::Result; +impl Error for BinaryReaderError {} + +impl fmt::Display for BinaryReaderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} (at offset {})", self.message, self.offset) + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum CustomSectionKind { Unknown, Name, + Producers, SourceMappingURL, Reloc, Linking, @@ -39,20 +50,21 @@ pub enum CustomSectionKind { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum SectionCode<'a> { Custom { - name: &'a [u8], + name: &'a str, kind: CustomSectionKind, }, - Type, // Function signature declarations - Import, // Import declarations - Function, // Function declarations - Table, // Indirect function table and other tables - Memory, // Memory attributes - Global, // Global declarations - Export, // Exports - Start, // Start function declaration - Element, // Elements section - Code, // Function bodies (code) - Data, // Data segments + Type, // Function signature declarations + Import, // Import declarations + Function, // Function declarations + Table, // Indirect function table and other tables + Memory, // Memory attributes + Global, // Global declarations + Export, // Exports + Start, // Start function declaration + Element, // Elements section + Code, // Function bodies (code) + Data, // Data segments + DataCount, // Count of passive data segments } /// Types as defined [here]. @@ -64,6 +76,7 @@ pub enum Type { I64, F32, F64, + V128, AnyFunc, AnyRef, Func, @@ -129,7 +142,7 @@ pub struct MemoryImmediate { #[derive(Debug, Copy, Clone)] pub struct Naming<'a> { pub index: u32, - pub name: &'a [u8], + pub name: &'a str, } #[derive(Debug, Copy, Clone)] @@ -160,6 +173,7 @@ pub enum RelocType { #[derive(Debug)] pub struct BrTable<'a> { pub(crate) buffer: &'a [u8], + pub(crate) cnt: usize, } /// An IEEE binary32 immediate floating point value, represented as a u32 @@ -188,6 +202,17 @@ impl Ieee64 { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct V128(pub(crate) [u8; 16]); + +impl V128 { + pub fn bytes(&self) -> &[u8; 16] { + &self.0 + } +} + +pub type SIMDLineIndex = u8; + /// Instructions as defined [here]. /// /// [here]: https://webassembly.github.io/spec/binary/instructions.html @@ -384,6 +409,20 @@ pub enum Operator<'a> { I64TruncSSatF64, I64TruncUSatF64, + // 0xFC operators + // bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md + MemoryInit { segment: u32 }, + DataDrop { segment: u32 }, + MemoryCopy, + MemoryFill, + TableInit { segment: u32 }, + ElemDrop { segment: u32 }, + TableCopy, + TableGet { table: u32 }, + TableSet { table: u32 }, + TableGrow { table: u32 }, + TableSize { table: u32 }, + // 0xFE operators // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md Wake { memarg: MemoryImmediate }, @@ -452,4 +491,147 @@ pub enum Operator<'a> { I64AtomicRmw8UCmpxchg { memarg: MemoryImmediate }, I64AtomicRmw16UCmpxchg { memarg: MemoryImmediate }, I64AtomicRmw32UCmpxchg { memarg: MemoryImmediate }, + + // 0xFD operators + // SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md + V128Load { memarg: MemoryImmediate }, + V128Store { memarg: MemoryImmediate }, + V128Const { value: V128 }, + V8x16Shuffle { lines: [SIMDLineIndex; 16] }, + I8x16Splat, + I8x16ExtractLaneS { line: SIMDLineIndex }, + I8x16ExtractLaneU { line: SIMDLineIndex }, + I8x16ReplaceLane { line: SIMDLineIndex }, + I16x8Splat, + I16x8ExtractLaneS { line: SIMDLineIndex }, + I16x8ExtractLaneU { line: SIMDLineIndex }, + I16x8ReplaceLane { line: SIMDLineIndex }, + I32x4Splat, + I32x4ExtractLane { line: SIMDLineIndex }, + I32x4ReplaceLane { line: SIMDLineIndex }, + I64x2Splat, + I64x2ExtractLane { line: SIMDLineIndex }, + I64x2ReplaceLane { line: SIMDLineIndex }, + F32x4Splat, + F32x4ExtractLane { line: SIMDLineIndex }, + F32x4ReplaceLane { line: SIMDLineIndex }, + F64x2Splat, + F64x2ExtractLane { line: SIMDLineIndex }, + F64x2ReplaceLane { line: SIMDLineIndex }, + I8x16Eq, + I8x16Ne, + I8x16LtS, + I8x16LtU, + I8x16GtS, + I8x16GtU, + I8x16LeS, + I8x16LeU, + I8x16GeS, + I8x16GeU, + I16x8Eq, + I16x8Ne, + I16x8LtS, + I16x8LtU, + I16x8GtS, + I16x8GtU, + I16x8LeS, + I16x8LeU, + I16x8GeS, + I16x8GeU, + I32x4Eq, + I32x4Ne, + I32x4LtS, + I32x4LtU, + I32x4GtS, + I32x4GtU, + I32x4LeS, + I32x4LeU, + I32x4GeS, + I32x4GeU, + F32x4Eq, + F32x4Ne, + F32x4Lt, + F32x4Gt, + F32x4Le, + F32x4Ge, + F64x2Eq, + F64x2Ne, + F64x2Lt, + F64x2Gt, + F64x2Le, + F64x2Ge, + V128Not, + V128And, + V128Or, + V128Xor, + V128Bitselect, + I8x16Neg, + I8x16AnyTrue, + I8x16AllTrue, + I8x16Shl, + I8x16ShrS, + I8x16ShrU, + I8x16Add, + I8x16AddSaturateS, + I8x16AddSaturateU, + I8x16Sub, + I8x16SubSaturateS, + I8x16SubSaturateU, + I8x16Mul, + I16x8Neg, + I16x8AnyTrue, + I16x8AllTrue, + I16x8Shl, + I16x8ShrS, + I16x8ShrU, + I16x8Add, + I16x8AddSaturateS, + I16x8AddSaturateU, + I16x8Sub, + I16x8SubSaturateS, + I16x8SubSaturateU, + I16x8Mul, + I32x4Neg, + I32x4AnyTrue, + I32x4AllTrue, + I32x4Shl, + I32x4ShrS, + I32x4ShrU, + I32x4Add, + I32x4Sub, + I32x4Mul, + I64x2Neg, + I64x2AnyTrue, + I64x2AllTrue, + I64x2Shl, + I64x2ShrS, + I64x2ShrU, + I64x2Add, + I64x2Sub, + F32x4Abs, + F32x4Neg, + F32x4Sqrt, + F32x4Add, + F32x4Sub, + F32x4Mul, + F32x4Div, + F32x4Min, + F32x4Max, + F64x2Abs, + F64x2Neg, + F64x2Sqrt, + F64x2Add, + F64x2Sub, + F64x2Mul, + F64x2Div, + F64x2Min, + F64x2Max, + I32x4TruncSF32x4Sat, + I32x4TruncUF32x4Sat, + I64x2TruncSF64x2Sat, + I64x2TruncUF64x2Sat, + F32x4ConvertSI32x4, + F32x4ConvertUI32x4, + F64x2ConvertSI64x2, + F64x2ConvertUI64x2, } diff --git a/third_party/rust/wasmparser/src/readers/code_section.rs b/third_party/rust/wasmparser/src/readers/code_section.rs index 17f173b8e75a..fac9c6e2292f 100644 --- a/third_party/rust/wasmparser/src/readers/code_section.rs +++ b/third_party/rust/wasmparser/src/readers/code_section.rs @@ -64,7 +64,7 @@ impl<'a> FunctionBody<'a> { Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos)) } - pub(crate) fn get_range(&self) -> Range { + pub fn range(&self) -> Range { Range { start: self.offset, end: self.offset + self.data.len(), diff --git a/third_party/rust/wasmparser/src/readers/data_count_section.rs b/third_party/rust/wasmparser/src/readers/data_count_section.rs new file mode 100644 index 000000000000..ac0f9db0f727 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/data_count_section.rs @@ -0,0 +1,28 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_data_count_section_content(data: &[u8], offset: usize) -> Result { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the data count section", + offset: offset + reader.position, + }); + } + Ok(count) +} diff --git a/third_party/rust/wasmparser/src/readers/data_section.rs b/third_party/rust/wasmparser/src/readers/data_section.rs index 73e45dc8b2a1..29b7d8284ef9 100644 --- a/third_party/rust/wasmparser/src/readers/data_section.rs +++ b/third_party/rust/wasmparser/src/readers/data_section.rs @@ -20,11 +20,19 @@ use super::{ #[derive(Debug, Copy, Clone)] pub struct Data<'a> { - pub memory_index: u32, - pub init_expr: InitExpr<'a>, + pub kind: DataKind<'a>, pub data: &'a [u8], } +#[derive(Debug, Copy, Clone)] +pub enum DataKind<'a> { + Passive, + Active { + memory_index: u32, + init_expr: InitExpr<'a>, + }, +} + pub struct DataSectionReader<'a> { reader: BinaryReader<'a>, count: u32, @@ -64,7 +72,7 @@ impl<'a> DataSectionReader<'a> { /// # 0x05, 0x03, 0x01, 0x00, 0x02, /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b, /// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; - /// use wasmparser::ModuleReader; + /// use wasmparser::{ModuleReader, DataKind}; /// let mut reader = ModuleReader::new(data).expect("module reader"); /// let section = reader.read().expect("type section"); /// let section = reader.read().expect("function section"); @@ -75,32 +83,48 @@ impl<'a> DataSectionReader<'a> { /// for _ in 0..data_reader.get_count() { /// let data = data_reader.read().expect("data"); /// println!("Data: {:?}", data); - /// let mut init_expr_reader = data.init_expr.get_binary_reader(); - /// let op = init_expr_reader.read_operator().expect("op"); - /// println!("Init const: {:?}", op); + /// if let DataKind::Active { init_expr, .. } = data.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } /// } /// ``` pub fn read<'b>(&mut self) -> Result> where 'a: 'b, { - let memory_index = self.reader.read_var_u32()?; - let init_expr = { - let expr_offset = self.reader.position; - self.reader.skip_init_expr()?; - let data = &self.reader.buffer[expr_offset..self.reader.position]; - InitExpr::new(data, self.reader.original_offset + expr_offset) + let flags = self.reader.read_var_u32()?; + let kind = if flags == 1 { + DataKind::Passive + } else { + let memory_index = match flags { + 0 => 0, + 2 => self.reader.read_var_u32()?, + _ => { + return Err(BinaryReaderError { + message: "invalid flags byte in data segment", + offset: self.reader.original_position() - 1, + }); + } + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + DataKind::Active { + memory_index, + init_expr, + } }; let data_len = self.reader.read_var_u32()? as usize; let data_end = self.reader.position + data_len; self.verify_data_end(data_end)?; let data = &self.reader.buffer[self.reader.position..data_end]; self.reader.skip_to(data_end); - Ok(Data { - memory_index, - init_expr, - data, - }) + Ok(Data { kind, data }) } } diff --git a/third_party/rust/wasmparser/src/readers/element_section.rs b/third_party/rust/wasmparser/src/readers/element_section.rs index 1a8535b2f049..19bd87076101 100644 --- a/third_party/rust/wasmparser/src/readers/element_section.rs +++ b/third_party/rust/wasmparser/src/readers/element_section.rs @@ -14,16 +14,25 @@ */ use super::{ - BinaryReader, InitExpr, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, + BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, Type, }; #[derive(Debug, Copy, Clone)] pub struct Element<'a> { - pub table_index: u32, - pub init_expr: InitExpr<'a>, + pub kind: ElementKind<'a>, pub items: ElementItems<'a>, } +#[derive(Debug, Copy, Clone)] +pub enum ElementKind<'a> { + Passive(Type), + Active { + table_index: u32, + init_expr: InitExpr<'a>, + }, +} + #[derive(Debug, Copy, Clone)] pub struct ElementItems<'a> { offset: usize, @@ -129,7 +138,7 @@ impl<'a> ElementSectionReader<'a> { /// # 0x05, 0x03, 0x01, 0x00, 0x02, /// # 0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00, /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; - /// use wasmparser::ModuleReader; + /// use wasmparser::{ModuleReader, ElementKind}; ///use wasmparser::Result; /// let mut reader = ModuleReader::new(data).expect("module reader"); /// let section = reader.read().expect("type section"); @@ -140,9 +149,11 @@ impl<'a> ElementSectionReader<'a> { /// for _ in 0..element_reader.get_count() { /// let element = element_reader.read().expect("element"); /// println!("Element: {:?}", element); - /// let mut init_expr_reader = element.init_expr.get_binary_reader(); - /// let op = init_expr_reader.read_operator().expect("op"); - /// println!("Init const: {:?}", op); + /// if let ElementKind::Active { init_expr, .. } = element.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } /// let mut items_reader = element.items.get_items_reader().expect("items reader"); /// for _ in 0..items_reader.get_count() { /// let item = items_reader.read().expect("item"); @@ -154,12 +165,31 @@ impl<'a> ElementSectionReader<'a> { where 'a: 'b, { - let table_index = self.reader.read_var_u32()?; - let init_expr = { - let expr_offset = self.reader.position; - self.reader.skip_init_expr()?; - let data = &self.reader.buffer[expr_offset..self.reader.position]; - InitExpr::new(data, self.reader.original_offset + expr_offset) + let flags = self.reader.read_var_u32()?; + let kind = if flags == 1 { + let ty = self.reader.read_type()?; + ElementKind::Passive(ty) + } else { + let table_index = match flags { + 0 => 0, + 2 => self.reader.read_var_u32()?, + _ => { + return Err(BinaryReaderError { + message: "invalid flags byte in element segment", + offset: self.reader.original_position() - 1, + }); + } + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + ElementKind::Active { + table_index, + init_expr, + } }; let data_start = self.reader.position; let items_count = self.reader.read_var_u32()?; @@ -171,11 +201,7 @@ impl<'a> ElementSectionReader<'a> { offset: self.reader.original_offset + data_start, data: &self.reader.buffer[data_start..data_end], }; - Ok(Element { - table_index, - init_expr, - items, - }) + Ok(Element { kind, items }) } } diff --git a/third_party/rust/wasmparser/src/readers/export_section.rs b/third_party/rust/wasmparser/src/readers/export_section.rs index 229e32068aa2..636ac2bcf3c1 100644 --- a/third_party/rust/wasmparser/src/readers/export_section.rs +++ b/third_party/rust/wasmparser/src/readers/export_section.rs @@ -20,7 +20,7 @@ use super::{ #[derive(Debug, Copy, Clone)] pub struct Export<'a> { - pub field: &'a [u8], + pub field: &'a str, pub kind: ExternalKind, pub index: u32, } diff --git a/third_party/rust/wasmparser/src/readers/import_section.rs b/third_party/rust/wasmparser/src/readers/import_section.rs index d7e933224860..92fd5f5e99d7 100644 --- a/third_party/rust/wasmparser/src/readers/import_section.rs +++ b/third_party/rust/wasmparser/src/readers/import_section.rs @@ -20,8 +20,8 @@ use super::{ #[derive(Debug, Copy, Clone)] pub struct Import<'a> { - pub module: &'a [u8], - pub field: &'a [u8], + pub module: &'a str, + pub field: &'a str, pub ty: ImportSectionEntryType, } diff --git a/third_party/rust/wasmparser/src/readers/mod.rs b/third_party/rust/wasmparser/src/readers/mod.rs index 8d7ce2c01f8a..52488b195089 100644 --- a/third_party/rust/wasmparser/src/readers/mod.rs +++ b/third_party/rust/wasmparser/src/readers/mod.rs @@ -24,11 +24,14 @@ use super::SectionHeader; pub use self::code_section::CodeSectionReader; pub use self::code_section::FunctionBody; pub use self::code_section::LocalsReader; +use self::data_count_section::read_data_count_section_content; pub use self::data_section::Data; +pub use self::data_section::DataKind; pub use self::data_section::DataSectionReader; pub use self::element_section::Element; pub use self::element_section::ElementItems; pub use self::element_section::ElementItemsReader; +pub use self::element_section::ElementKind; pub use self::element_section::ElementSectionReader; pub use self::export_section::Export; pub use self::export_section::ExportSectionReader; @@ -57,6 +60,10 @@ pub use self::name_section::Name; pub use self::name_section::NameSectionReader; pub use self::name_section::NamingReader; +pub use self::producers_section::ProducersField; +pub use self::producers_section::ProducersFieldValue; +pub use self::producers_section::ProducersSectionReader; + pub use self::linking_section::LinkingSectionReader; pub use self::reloc_section::Reloc; @@ -67,6 +74,7 @@ use self::sourcemappingurl_section::read_sourcemappingurl_section_content; pub use self::operators::OperatorsReader; mod code_section; +mod data_count_section; mod data_section; mod element_section; mod export_section; @@ -79,6 +87,7 @@ mod memory_section; mod module; mod name_section; mod operators; +mod producers_section; mod reloc_section; mod section_reader; mod sourcemappingurl_section; diff --git a/third_party/rust/wasmparser/src/readers/module.rs b/third_party/rust/wasmparser/src/readers/module.rs index d0871fe22940..dcceccf9cc63 100644 --- a/third_party/rust/wasmparser/src/readers/module.rs +++ b/third_party/rust/wasmparser/src/readers/module.rs @@ -20,10 +20,11 @@ use super::{ }; use super::{ - read_sourcemappingurl_section_content, read_start_section_content, CodeSectionReader, - DataSectionReader, ElementSectionReader, ExportSectionReader, FunctionSectionReader, - GlobalSectionReader, ImportSectionReader, LinkingSectionReader, MemorySectionReader, - NameSectionReader, RelocSectionReader, TableSectionReader, TypeSectionReader, + read_data_count_section_content, read_sourcemappingurl_section_content, + read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader, + ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader, + RelocSectionReader, TableSectionReader, TypeSectionReader, }; #[derive(Debug)] @@ -167,6 +168,19 @@ impl<'a> Section<'a> { } } + pub fn get_producers_section_reader<'b>(&self) -> Result> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Producers, + .. + } => ProducersSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_producers_section_reader"), + } + } + pub fn get_linking_section_reader<'b>(&self) -> Result> where 'a: 'b, @@ -200,7 +214,14 @@ impl<'a> Section<'a> { } } - pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b [u8]> + pub fn get_data_count_section_content(&self) -> Result { + match self.code { + SectionCode::DataCount => read_data_count_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_data_count_section_content"), + } + } + + pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b str> where 'a: 'b, { @@ -220,7 +241,7 @@ impl<'a> Section<'a> { BinaryReader::new_with_offset(self.data, self.offset) } - pub(crate) fn get_range(&self) -> Range { + pub fn range(&self) -> Range { Range { start: self.offset, end: self.offset + self.data.len(), diff --git a/third_party/rust/wasmparser/src/readers/name_section.rs b/third_party/rust/wasmparser/src/readers/name_section.rs index c470370bbde6..f657c69fc766 100644 --- a/third_party/rust/wasmparser/src/readers/name_section.rs +++ b/third_party/rust/wasmparser/src/readers/name_section.rs @@ -24,7 +24,7 @@ pub struct ModuleName<'a> { } impl<'a> ModuleName<'a> { - pub fn get_name<'b>(&self) -> Result<&'b [u8]> + pub fn get_name<'b>(&self) -> Result<&'b str> where 'a: 'b, { diff --git a/third_party/rust/wasmparser/src/readers/producers_section.rs b/third_party/rust/wasmparser/src/readers/producers_section.rs new file mode 100644 index 000000000000..a65769c1d9b1 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/producers_section.rs @@ -0,0 +1,192 @@ +/* Copyright 2019 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; + +#[derive(Debug, Copy, Clone)] +pub struct ProducersFieldValue<'a> { + pub name: &'a str, + pub version: &'a str, +} + +pub struct ProducersFieldValuesReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersFieldValuesReader<'a> { + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> { + for _ in 0..values_count { + reader.skip_string()?; + reader.skip_string()?; + } + Ok(()) + } + + pub fn read<'b>(&mut self) -> Result> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let version = self.reader.read_string()?; + Ok(ProducersFieldValue { name, version }) + } +} + +impl<'a> IntoIterator for ProducersFieldValuesReader<'a> { + type Item = Result>; + type IntoIter = ProducersFieldValuesIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ProducersFieldValuesIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct ProducersFieldValuesIterator<'a> { + reader: ProducersFieldValuesReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ProducersFieldValuesIterator<'a> { + type Item = Result>; + fn next(&mut self) -> Option { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct ProducersField<'a> { + pub name: &'a str, + values_count: u32, + values_data: &'a [u8], + values_offset: usize, +} + +impl<'a> ProducersField<'a> { + pub fn get_producer_field_values_reader<'b>(&self) -> Result> + where + 'a: 'b, + { + Ok(ProducersFieldValuesReader { + reader: BinaryReader::new_with_offset(self.values_data, self.values_offset), + count: self.values_count, + }) + } +} + +pub struct ProducersSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersSectionReader<'a> { + /// Creates reader for the producers section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; + /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; + /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader"); + /// let field = reader.read().expect("producers field"); + /// assert!(field.name == "language"); + /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader"); + /// let value = values_reader.into_iter().collect::>>().expect("values"); + /// assert!(value.len() == 2); + /// assert!(value[0].name == "wat" && value[0].version == "1"); + /// assert!(value[1].name == "C" && value[1].version == "9.0"); + /// ``` + pub fn new(data: &'a [u8], offset: usize) -> Result> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ProducersSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn read<'b>(&mut self) -> Result> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let values_count = self.reader.read_var_u32()?; + let values_start = self.reader.position; + ProducersFieldValuesReader::skip(&mut self.reader, values_count)?; + let values_end = self.reader.position; + Ok(ProducersField { + name, + values_count, + values_data: &self.reader.buffer[values_start..values_end], + values_offset: self.reader.original_offset + values_start, + }) + } +} + +impl<'a> SectionReader for ProducersSectionReader<'a> { + type Item = ProducersField<'a>; + fn read(&mut self) -> Result { + ProducersSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ProducersSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> { + fn get_count(&self) -> u32 { + ProducersSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ProducersSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/sourcemappingurl_section.rs b/third_party/rust/wasmparser/src/readers/sourcemappingurl_section.rs index 059ff074ca48..6f6e5eef217c 100644 --- a/third_party/rust/wasmparser/src/readers/sourcemappingurl_section.rs +++ b/third_party/rust/wasmparser/src/readers/sourcemappingurl_section.rs @@ -18,7 +18,7 @@ use super::{BinaryReader, BinaryReaderError, Result}; pub(crate) fn read_sourcemappingurl_section_content<'a>( data: &'a [u8], offset: usize, -) -> Result<&'a [u8]> { +) -> Result<&'a str> { let mut reader = BinaryReader::new_with_offset(data, offset); let url = reader.read_string()?; if !reader.eof() { diff --git a/third_party/rust/wasmparser/src/tests.rs b/third_party/rust/wasmparser/src/tests.rs index 0f9eb5edea7d..cb6758bfa6bc 100644 --- a/third_party/rust/wasmparser/src/tests.rs +++ b/third_party/rust/wasmparser/src/tests.rs @@ -27,6 +27,8 @@ mod simple_tests { operator_config: OperatorValidatorConfig { enable_threads: true, enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, }, mutable_global_imports: true, }); diff --git a/third_party/rust/wasmparser/src/validator.rs b/third_party/rust/wasmparser/src/validator.rs index dd77efa6a459..ffc29c668f60 100644 --- a/third_party/rust/wasmparser/src/validator.rs +++ b/third_party/rust/wasmparser/src/validator.rs @@ -29,7 +29,7 @@ use binary_reader::BinaryReader; use primitives::{ BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryImmediate, - MemoryType, Operator, ResizableLimits, Result, SectionCode, TableType, Type, + MemoryType, Operator, ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type, }; use parser::{Parser, ParserInput, ParserState, WasmDecoder}; @@ -128,6 +128,7 @@ enum SectionOrderState { Export, Start, Element, + DataCount, Code, Data, } @@ -146,6 +147,7 @@ impl SectionOrderState { SectionCode::Element => Some(SectionOrderState::Element), SectionCode::Code => Some(SectionOrderState::Code), SectionCode::Data => Some(SectionOrderState::Data), + SectionCode::DataCount => Some(SectionOrderState::DataCount), _ => None, } } @@ -302,6 +304,8 @@ pub trait WasmModuleResources { fn memories(&self) -> &[MemoryType]; fn globals(&self) -> &[GlobalType]; fn func_type_indices(&self) -> &[u32]; + fn element_count(&self) -> u32; + fn data_count(&self) -> u32; } type OperatorValidatorResult = result::Result; @@ -310,11 +314,15 @@ type OperatorValidatorResult = result::Result; pub struct OperatorValidatorConfig { pub enable_threads: bool, pub enable_reference_types: bool, + pub enable_simd: bool, + pub enable_bulk_memory: bool, } const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = OperatorValidatorConfig { enable_threads: false, enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, }; struct OperatorValidator { @@ -453,7 +461,7 @@ impl OperatorValidator { } let block = func_state.block_at(relative_depth as usize); if block.jump_to_top { - if !func_state.assert_last_block_stack_len_exact(reserve_items) { + if !func_state.assert_block_stack_len(0, reserve_items) { return Err("stack size does not match target loop type"); } return Ok(()); @@ -549,6 +557,20 @@ impl OperatorValidator { Ok(()) } + fn check_simd_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_simd { + return Err("SIMD support is not enabled"); + } + Ok(()) + } + + fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_bulk_memory { + return Err("bulk memory support is not enabled"); + } + Ok(()) + } + fn check_shared_memarg_wo_align( &self, _: &MemoryImmediate, @@ -558,6 +580,13 @@ impl OperatorValidator { Ok(()) } + fn check_simd_line_index(&self, index: SIMDLineIndex, max: u8) -> OperatorValidatorResult<()> { + if index >= max { + return Err("SIMD index out of bounds"); + } + Ok(()) + } + fn check_block_type(&self, ty: Type) -> OperatorValidatorResult<()> { match ty { Type::EmptyBlockType | Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), @@ -1244,6 +1273,338 @@ impl OperatorValidator { self.check_operands(func_state, &[Type::AnyRef])?; OperatorAction::ChangeFrameWithType(0, Type::I32) } + Operator::V128Load { ref memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_1(func_state, Type::I32)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::V128Store { ref memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_2(func_state, Type::I32, Type::V128)?; + OperatorAction::ChangeFrame(2) + } + Operator::V128Const { .. } => { + self.check_simd_enabled()?; + OperatorAction::ChangeFrameWithType(0, Type::V128) + } + Operator::V8x16Shuffle { ref lines } => { + self.check_simd_enabled()?; + self.check_operands_2(func_state, Type::V128, Type::V128)?; + for i in lines { + self.check_simd_line_index(*i, 32)?; + } + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::I32)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::I64x2Splat => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::I64)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::F32x4Splat => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::F32)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::F64x2Splat => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::F64)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::I8x16ExtractLaneS { line } | Operator::I8x16ExtractLaneU { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 16)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::I32) + } + Operator::I16x8ExtractLaneS { line } | Operator::I16x8ExtractLaneU { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 8)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::I32) + } + Operator::I32x4ExtractLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 4)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::I32) + } + Operator::I8x16ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 16)?; + self.check_operands_2(func_state, Type::V128, Type::I32)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I16x8ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 8)?; + self.check_operands_2(func_state, Type::V128, Type::I32)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I32x4ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 4)?; + self.check_operands_2(func_state, Type::V128, Type::I32)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I64x2ExtractLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 2)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::I64) + } + Operator::I64x2ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 2)?; + self.check_operands_2(func_state, Type::V128, Type::I64)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::F32x4ExtractLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 4)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::F32) + } + Operator::F32x4ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 4)?; + self.check_operands_2(func_state, Type::V128, Type::F32)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::F64x2ExtractLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 2)?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::F64) + } + Operator::F64x2ReplaceLane { line } => { + self.check_simd_enabled()?; + self.check_simd_line_index(line, 2)?; + self.check_operands_2(func_state, Type::V128, Type::F64)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I8x16Eq + | Operator::I8x16Ne + | Operator::I8x16LtS + | Operator::I8x16LtU + | Operator::I8x16GtS + | Operator::I8x16GtU + | Operator::I8x16LeS + | Operator::I8x16LeU + | Operator::I8x16GeS + | Operator::I8x16GeU + | Operator::I16x8Eq + | Operator::I16x8Ne + | Operator::I16x8LtS + | Operator::I16x8LtU + | Operator::I16x8GtS + | Operator::I16x8GtU + | Operator::I16x8LeS + | Operator::I16x8LeU + | Operator::I16x8GeS + | Operator::I16x8GeU + | Operator::I32x4Eq + | Operator::I32x4Ne + | Operator::I32x4LtS + | Operator::I32x4LtU + | Operator::I32x4GtS + | Operator::I32x4GtU + | Operator::I32x4LeS + | Operator::I32x4LeU + | Operator::I32x4GeS + | Operator::I32x4GeU + | Operator::F32x4Eq + | Operator::F32x4Ne + | Operator::F32x4Lt + | Operator::F32x4Gt + | Operator::F32x4Le + | Operator::F32x4Ge + | Operator::F64x2Eq + | Operator::F64x2Ne + | Operator::F64x2Lt + | Operator::F64x2Gt + | Operator::F64x2Le + | Operator::F64x2Ge + | Operator::V128And + | Operator::V128Or + | Operator::V128Xor + | Operator::I8x16Add + | Operator::I8x16AddSaturateS + | Operator::I8x16AddSaturateU + | Operator::I8x16Sub + | Operator::I8x16SubSaturateS + | Operator::I8x16SubSaturateU + | Operator::I8x16Mul + | Operator::I16x8Add + | Operator::I16x8AddSaturateS + | Operator::I16x8AddSaturateU + | Operator::I16x8Sub + | Operator::I16x8SubSaturateS + | Operator::I16x8SubSaturateU + | Operator::I16x8Mul + | Operator::I32x4Add + | Operator::I32x4Sub + | Operator::I32x4Mul + | Operator::I64x2Add + | Operator::I64x2Sub + | Operator::F32x4Add + | Operator::F32x4Sub + | Operator::F32x4Mul + | Operator::F32x4Div + | Operator::F32x4Min + | Operator::F32x4Max + | Operator::F64x2Add + | Operator::F64x2Sub + | Operator::F64x2Mul + | Operator::F64x2Div + | Operator::F64x2Min + | Operator::F64x2Max => { + self.check_simd_enabled()?; + self.check_operands_2(func_state, Type::V128, Type::V128)?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::V128Not + | Operator::I8x16Neg + | Operator::I16x8Neg + | Operator::I32x4Neg + | Operator::I64x2Neg + | Operator::F32x4Abs + | Operator::F32x4Neg + | Operator::F32x4Sqrt + | Operator::F64x2Abs + | Operator::F64x2Neg + | Operator::F64x2Sqrt + | Operator::I32x4TruncSF32x4Sat + | Operator::I32x4TruncUF32x4Sat + | Operator::I64x2TruncSF64x2Sat + | Operator::I64x2TruncUF64x2Sat + | Operator::F32x4ConvertSI32x4 + | Operator::F32x4ConvertUI32x4 + | Operator::F64x2ConvertSI64x2 + | Operator::F64x2ConvertUI64x2 => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + Operator::V128Bitselect => { + self.check_simd_enabled()?; + self.check_operands(func_state, &[Type::V128, Type::V128, Type::V128])?; + OperatorAction::ChangeFrameWithType(2, Type::V128) + } + Operator::I8x16AnyTrue + | Operator::I8x16AllTrue + | Operator::I16x8AnyTrue + | Operator::I16x8AllTrue + | Operator::I32x4AnyTrue + | Operator::I32x4AllTrue + | Operator::I64x2AnyTrue + | Operator::I64x2AllTrue => { + self.check_simd_enabled()?; + self.check_operands_1(func_state, Type::V128)?; + OperatorAction::ChangeFrameWithType(1, Type::I32) + } + Operator::I8x16Shl + | Operator::I8x16ShrS + | Operator::I8x16ShrU + | Operator::I16x8Shl + | Operator::I16x8ShrS + | Operator::I16x8ShrU + | Operator::I32x4Shl + | Operator::I32x4ShrS + | Operator::I32x4ShrU + | Operator::I64x2Shl + | Operator::I64x2ShrS + | Operator::I64x2ShrU => { + self.check_simd_enabled()?; + self.check_operands_2(func_state, Type::V128, Type::I32)?; + OperatorAction::ChangeFrameWithType(1, Type::V128) + } + + Operator::MemoryInit { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + self.check_memory_index(0, resources)?; + self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?; + OperatorAction::ChangeFrame(3) + } + Operator::DataDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + OperatorAction::None + } + Operator::MemoryCopy | Operator::MemoryFill => { + self.check_bulk_memory_enabled()?; + self.check_memory_index(0, resources)?; + self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?; + OperatorAction::ChangeFrame(3) + } + Operator::TableInit { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + if 0 >= resources.tables().len() { + return Err("table index out of bounds"); + } + self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?; + OperatorAction::ChangeFrame(3) + } + Operator::ElemDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + OperatorAction::None + } + Operator::TableCopy => { + self.check_bulk_memory_enabled()?; + if 0 >= resources.tables().len() { + return Err("table index out of bounds"); + } + self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?; + OperatorAction::ChangeFrame(3) + } + Operator::TableGet { table } => { + self.check_reference_types_enabled()?; + if table as usize >= resources.tables().len() { + return Err("table index out of bounds"); + } + self.check_operands(func_state, &[Type::I32])?; + OperatorAction::ChangeFrameWithType(1, Type::AnyRef) + } + Operator::TableSet { table } => { + self.check_reference_types_enabled()?; + if table as usize >= resources.tables().len() { + return Err("table index out of bounds"); + } + self.check_operands(func_state, &[Type::I32, Type::AnyRef])?; + OperatorAction::ChangeFrame(2) + } + Operator::TableGrow { table } => { + self.check_reference_types_enabled()?; + if table as usize >= resources.tables().len() { + return Err("table index out of bounds"); + } + self.check_operands(func_state, &[Type::I32])?; + OperatorAction::ChangeFrameWithType(1, Type::I32) + } + Operator::TableSize { table } => { + self.check_reference_types_enabled()?; + if table as usize >= resources.tables().len() { + return Err("table index out of bounds"); + } + OperatorAction::ChangeFrameWithType(1, Type::I32) + } }) } @@ -1278,11 +1639,14 @@ pub struct ValidatingParser<'a> { tables: Vec, memories: Vec, globals: Vec, + element_count: u32, + data_count: Option, + data_found: u32, func_type_indices: Vec, current_func_index: u32, func_imports_count: u32, init_expression_state: Option, - exported_names: HashSet>, + exported_names: HashSet, current_operator_validator: Option, config: ValidatingParserConfig, } @@ -1307,6 +1671,14 @@ impl<'a> WasmModuleResources for ValidatingParser<'a> { fn func_type_indices(&self) -> &[u32] { &self.func_type_indices } + + fn element_count(&self) -> u32 { + self.element_count + } + + fn data_count(&self) -> u32 { + self.data_count.unwrap_or(0) + } } impl<'a> ValidatingParser<'a> { @@ -1327,6 +1699,9 @@ impl<'a> ValidatingParser<'a> { init_expression_state: None, exported_names: HashSet::new(), config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG), + element_count: 0, + data_count: None, + data_found: 0, } } @@ -1344,19 +1719,9 @@ impl<'a> ValidatingParser<'a> { })) } - fn check_utf8(&self, bytes: &[u8]) -> ValidatorResult<'a, ()> { - match str::from_utf8(bytes) { - Ok(_) => Ok(()), - Err(utf8_error) => match utf8_error.error_len() { - None => self.create_error("Invalid utf-8: unexpected end of string"), - Some(_) => self.create_error("Invalid utf-8: unexpected byte"), - }, - } - } - fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> { match ty { - Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), + Type::I32 | Type::I64 | Type::F32 | Type::F64 | Type::V128 => Ok(()), _ => self.create_error("invalid value type"), } } @@ -1413,14 +1778,7 @@ impl<'a> ValidatingParser<'a> { self.check_value_type(global_type.content_type) } - fn check_import_entry( - &self, - module: &[u8], - field: &[u8], - import_type: &ImportSectionEntryType, - ) -> ValidatorResult<'a, ()> { - self.check_utf8(module)?; - self.check_utf8(field)?; + fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> { match *import_type { ImportSectionEntryType::Function(type_index) => { if self.func_type_indices.len() >= MAX_WASM_FUNCTIONS { @@ -1481,12 +1839,11 @@ impl<'a> ValidatingParser<'a> { fn check_export_entry( &self, - field: &[u8], + field: &str, kind: ExternalKind, index: u32, ) -> ValidatorResult<'a, ()> { - self.check_utf8(field)?; - if self.exported_names.contains(&Vec::from(field)) { + if self.exported_names.contains(field) { return self.create_error("non-unique export name"); } match kind { @@ -1532,9 +1889,6 @@ impl<'a> ValidatingParser<'a> { fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> { let order_state = SectionOrderState::from_section_code(code); - if let SectionCode::Custom { name, .. } = *code { - self.check_utf8(name)?; - } Ok(match self.section_order_state { SectionOrderState::Initial => { if order_state.is_none() { @@ -1582,12 +1936,8 @@ impl<'a> ValidatingParser<'a> { self.types.push(func_type.clone()); } } - ParserState::ImportSectionEntry { - module, - field, - ref ty, - } => { - let check = self.check_import_entry(module, field, ty); + ParserState::ImportSectionEntry { ref ty, .. } => { + let check = self.check_import_entry(ty); if check.is_err() { self.validation_error = check.err(); } else { @@ -1666,12 +2016,19 @@ impl<'a> ValidatingParser<'a> { } ParserState::ExportSectionEntry { field, kind, index } => { self.validation_error = self.check_export_entry(field, kind, index).err(); - self.exported_names.insert(Vec::from(field)); + self.exported_names.insert(field.to_string()); } ParserState::StartSectionEntry(func_index) => { self.validation_error = self.check_start(func_index).err(); } - ParserState::BeginElementSectionEntry(table_index) => { + ParserState::DataCountSectionEntry(count) => { + self.data_count = Some(count); + } + ParserState::BeginPassiveElementSectionEntry(_ty) => { + self.element_count += 1; + } + ParserState::BeginActiveElementSectionEntry(table_index) => { + self.element_count += 1; if table_index as usize >= self.tables.len() { self.validation_error = self.create_validation_error("element section table index out of bounds"); @@ -1738,7 +2095,10 @@ impl<'a> ValidatingParser<'a> { self.current_func_index += 1; self.current_operator_validator = None; } - ParserState::BeginDataSectionEntry(memory_index) => { + ParserState::BeginDataSectionEntryBody(_) => { + self.data_found += 1; + } + ParserState::BeginActiveDataSectionEntry(memory_index) => { if memory_index as usize >= self.memories.len() { self.validation_error = self.create_validation_error("data section memory index out of bounds"); @@ -1750,6 +2110,22 @@ impl<'a> ValidatingParser<'a> { }); } } + ParserState::EndWasm => { + if self.func_type_indices.len() + != self.current_func_index as usize + self.func_imports_count as usize + { + self.validation_error = self.create_validation_error( + "function and code section have inconsistent lengths", + ); + } + if let Some(data_count) = self.data_count { + if data_count != self.data_found { + self.validation_error = self.create_validation_error( + "data count section and passive data mismatch", + ); + } + } + } _ => (), }; }