Bug 1539406: Bump Cranelift to revision 542d799dd7a3b2cc; r=lth

This is the first time we pin a specific Cranelift commit hash to use in Gecko.
The target-lexicon hack is removed and instead we introduce a vendor patch for
cranelift-codegen/cranelift-wasm themselves.

Notable changes happen in top-level Cargo.toml, .cargo/config.in and
js/src/wasm/cranelift/Cargo.toml; the rest has been generated by `mach vendor
rust`.

Differential Revision: https://phabricator.services.mozilla.com/D27316

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Benjamin Bouvier 2019-04-15 10:39:28 +00:00
parent 5deee43687
commit da79779db2
93 changed files with 8293 additions and 824 deletions

View file

@ -22,9 +22,9 @@ git = "https://github.com/hsivonen/packed_simd"
branch = "rust_1_32" branch = "rust_1_32"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."https://github.com/CraneStation/target-lexicon"] [source."https://github.com/CraneStation/Cranelift"]
git = "https://github.com/glandium/target-lexicon" git = "https://github.com/CraneStation/Cranelift"
branch = "thumbv7neon-v0.2" rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source.vendored-sources] [source.vendored-sources]

76
Cargo.lock generated
View file

@ -168,11 +168,11 @@ name = "baldrdash"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)", "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-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
"cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]
@ -568,62 +568,62 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
dependencies = [ 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]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
dependencies = [ dependencies = [
"cranelift-bforest 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.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
"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)",
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
dependencies = [ 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]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
dependencies = [ 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)", "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]] [[package]]
name = "cranelift-wasm" name = "cranelift-wasm"
version = "0.29.0" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
dependencies = [ dependencies = [
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "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-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
"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)",
"cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "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 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)", "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)", "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]] [[package]]
@ -2778,8 +2778,8 @@ dependencies = [
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.2.0" version = "0.4.0"
source = "git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2#b2d4b34509abb3e12b1c93d19b8593d02ddeed76" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3203,7 +3203,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.23.0" version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -3495,12 +3495,12 @@ dependencies = [
"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae" "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 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 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-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c3b15a20577e6c823475953a5e25e758d9d3a3148a937d686c09460e5f2f4a0" "checksum cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum cranelift-codegen-meta 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e60ce3551e8172c966fbc6d9bfb90111d5d1cf37306c37dd7527467afe317d1" "checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e124e09cb7dc85fbe2162420aebbe8e9e3b8f9210901be7867416c5beec8226" "checksum cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2833c6e1a93c524ce0c2ab31266cdc84d38c906349f79f19378a5e5995727b23" "checksum cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e75efb45cd8d8700b4bdc225f0077bc7c615f84a5807ce001d59b4da48d85573" "checksum cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "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.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" "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.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 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 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)" = "<none>" "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 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 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" "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 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 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 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 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 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" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

View file

@ -61,4 +61,5 @@ libudev-sys = { path = "dom/webauthn/libudev-sys" }
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" } serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" }
winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" } winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" } 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" }

View file

@ -8,9 +8,16 @@ crate-type = ["rlib"]
name = "baldrdash" name = "baldrdash"
[dependencies] [dependencies]
cranelift-codegen = { version = "0.29.0", default-features = false } # The build system redirects the versions of cranelift-codegen and
cranelift-wasm = "0.29.0" # cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
target-lexicon = "0.2.0" # 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"] } log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] }
env_logger = "0.5.6" env_logger = "0.5.6"

View file

@ -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"} {"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}

View file

@ -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] [package]
edition = "2018"
name = "cranelift-bforest"
version = "0.29.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
name = "cranelift-bforest"
version = "0.30.0"
description = "A forest of B+-trees" description = "A forest of B+-trees"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://cranelift.readthedocs.io/"
repository = "https://github.com/CraneStation/cranelift"
categories = ["no-std"]
readme = "README.md" readme = "README.md"
keywords = ["btree", "forest", "set", "map"] keywords = ["btree", "forest", "set", "map"]
categories = ["no-std"] edition = "2018"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/CraneStation/cranelift" [dependencies]
[dependencies.cranelift-entity] cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
version = "0.29.0"
default-features = false
[features] [features]
core = []
default = ["std"] default = ["std"]
std = ["cranelift-entity/std"] std = ["cranelift-entity/std"]
[badges.maintenance] core = []
status = "experimental"
[badges.travis-ci] [badges]
repository = "CraneStation/cranelift" maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }

View file

@ -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"} {"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}

View file

@ -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] [package]
edition = "2018"
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.29.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
version = "0.30.0"
description = "Metaprogram for cranelift-codegen code generator library" description = "Metaprogram for cranelift-codegen code generator library"
readme = "README.md"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/CraneStation/cranelift" repository = "https://github.com/CraneStation/cranelift"
[dependencies.cranelift-entity] readme = "README.md"
version = "0.29.0" edition = "2018"
[badges.maintenance]
status = "experimental"
[badges.travis-ci] [dependencies]
repository = "CraneStation/cranelift" 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"]

View file

@ -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<FormatField>,
pub typevar_operand: Option<usize>,
}
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::<Vec<_>>()
.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<FormatField>,
typevar_operand: Option<usize>,
}
pub struct ImmParameter {
kind: OperandKind,
member: &'static str,
}
impl Into<ImmParameter> for (&'static str, &OperandKind) {
fn into(self) -> ImmParameter {
ImmParameter {
kind: self.1.clone(),
member: self.0,
}
}
}
impl Into<ImmParameter> 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<ImmParameter>) -> 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<String>, usize, bool), InstructionFormatIndex>,
map: PrimaryMap<InstructionFormatIndex, InstructionFormat>,
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<Operand>) -> 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<InstructionFormat> {
self.map.values()
}
}

View file

@ -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<Instruction>,
}
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<Instruction> {
self.instructions.iter()
}
}
pub struct PolymorphicInfo {
pub use_typevar_operand: bool,
pub ctrl_typevar: TypeVar,
pub other_typevars: Vec<TypeVar>,
}
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<Operand>,
/// Output operands. The output operands must be SSA values or `variable_args`.
pub operands_out: Vec<Operand>,
/// Instruction-specific TypeConstraints.
_constraints: Vec<Constraint>,
/// 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<PolymorphicInfo>,
pub value_opnums: Vec<usize>,
pub value_results: Vec<usize>,
pub imm_opnums: Vec<usize>,
/// 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::<Vec<_>>()
.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::<Vec<_>>()
.join(", ");
fmt.write_str(" ")?;
fmt.write_str(&operands_in)?;
}
Ok(())
}
}
pub struct InstructionBuilder {
name: &'static str,
doc: &'static str,
operands_in: Option<Vec<Operand>>,
operands_out: Option<Vec<Operand>>,
constraints: Option<Vec<Constraint>>,
// 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<Constraint>) -> 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<Operand>,
operands_out: &Vec<Operand>,
format: &InstructionFormat,
value_opnums: &Vec<usize>,
) -> Option<PolymorphicInfo> {
// 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<usize>,
operands_in: &Vec<Operand>,
operands_out: &Vec<Operand>,
) -> Result<Vec<TypeVar>, 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)
}

View file

@ -1,16 +1,24 @@
use super::regs::IsaRegs; use crate::cdsl::inst::InstructionGroup;
use super::settings::SettingGroup; use crate::cdsl::regs::IsaRegs;
use crate::cdsl::settings::SettingGroup;
pub struct TargetIsa { pub struct TargetIsa {
pub name: &'static str, pub name: &'static str,
pub instructions: InstructionGroup,
pub settings: SettingGroup, pub settings: SettingGroup,
pub regs: IsaRegs, pub regs: IsaRegs,
} }
impl TargetIsa { 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 { Self {
name, name,
instructions,
settings, settings,
regs, regs,
} }

View file

@ -3,10 +3,15 @@
//! This module defines the classes that are used to define Cranelift //! This module defines the classes that are used to define Cranelift
//! instructions and other entities. //! instructions and other entities.
pub mod formats;
pub mod inst;
pub mod isa; pub mod isa;
pub mod operands;
pub mod regs; pub mod regs;
pub mod settings; pub mod settings;
pub mod type_inference;
pub mod types; pub mod types;
pub mod typevar;
/// A macro that converts boolean settings into predicates to look more natural. /// A macro that converts boolean settings into predicates to look more natural.
#[macro_export] #[macro_export]

View file

@ -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<String>,
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<String>,
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<String>) -> 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<String>,
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<String> {
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<String>,
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<String>,
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<OperandKind> for &TypeVar {
fn into(self) -> OperandKind {
OperandKindBuilder::new("value", OperandKindFields::TypeVar(self.into())).finish()
}
}
impl Into<OperandKind> 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<OperandKind>) -> 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<OperandKind>,
doc: &'static str,
) -> Operand {
OperandBuilder::new(name, kind.into()).doc(doc).finish()
}

View file

@ -0,0 +1,5 @@
use crate::cdsl::typevar::TypeVar;
pub enum Constraint {
WiderOrEq(TypeVar, TypeVar),
}

View file

@ -21,13 +21,13 @@ static LANE_BASE: u8 = 0x70;
// Rust name prefix used for the `rust_name` method. // Rust name prefix used for the `rust_name` method.
static _RUST_NAME_PREFIX: &'static str = "ir::types::"; 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. /// A concrete SSA value type.
/// ///
/// All SSA values have a type that is described by an instance of `ValueType` /// All SSA values have a type that is described by an instance of `ValueType`
/// or one of its subclasses. /// or one of its subclasses.
#[derive(Debug)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueType { pub enum ValueType {
BV(BVType), BV(BVType),
Lane(LaneType), Lane(LaneType),
@ -90,7 +90,7 @@ impl ValueType {
} }
/// Return the name of this type for generated Rust source files. /// 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()) format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase())
} }
@ -147,7 +147,7 @@ impl From<VectorType> for ValueType {
} }
/// A concrete scalar type that can appear as a vector lane too. /// A concrete scalar type that can appear as a vector lane too.
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq)]
pub enum LaneType { pub enum LaneType {
BoolType(shared_types::Bool), BoolType(shared_types::Bool),
FloatType(shared_types::Float), FloatType(shared_types::Float),
@ -205,6 +205,43 @@ impl LaneType {
LaneType::FloatType(shared_types::Float::F64) => 10, 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 { 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`, /// A vector type has a lane type which is an instance of `LaneType`,
/// and a positive number of lanes. /// and a positive number of lanes.
#[derive(Clone, PartialEq)]
pub struct VectorType { pub struct VectorType {
base: LaneType, base: LaneType,
lanes: u64, lanes: u64,
@ -320,6 +358,11 @@ impl VectorType {
self.lanes self.lanes
} }
/// Return the lane type.
pub fn lane_type(&self) -> LaneType {
self.base
}
/// Find the unique number associated with this vector type. /// Find the unique number associated with this vector type.
/// ///
/// Vector types are encoded with the lane type in the low 4 bits and /// 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. /// A flat bitvector type. Used for semantics description only.
#[derive(Clone, PartialEq)]
pub struct BVType { pub struct BVType {
bits: u64, bits: u64,
} }
impl BVType { impl BVType {
/// Initialize a new bitvector type with `n` bits. /// Initialize a new bitvector type with `n` bits.
pub fn _new(bits: u64) -> Self { pub fn new(bits: u16) -> Self {
Self { bits } Self { bits: bits.into() }
} }
/// Return a string containing the documentation comment for this bitvector type. /// 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. /// A concrete scalar type that is neither a vector nor a lane type.
/// ///
/// Special types cannot be used to form vectors. /// Special types cannot be used to form vectors.
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum SpecialType { pub enum SpecialType {
Flag(shared_types::Flag), Flag(shared_types::Flag),
} }

View file

@ -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<TypeSet>,
pub base: Option<TypeVarParent>,
}
#[derive(Clone, Debug)]
pub struct TypeVar {
content: Rc<TypeVarContent>,
}
impl TypeVar {
pub fn new(name: impl Into<String>, doc: impl Into<String>, 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<TypeSet> {
// 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<ValueType> {
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<TypeVar> {
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<TypeVar> for &TypeVar {
fn into(self) -> TypeVar {
self.clone()
}
}
impl Into<TypeVar> 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<RangeBound>;
type NumSet = BTreeSet<RangeBound>;
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<SpecialType>,
}
impl TypeSet {
fn new(
lanes: NumSet,
ints: NumSet,
floats: NumSet,
bools: NumSet,
bitvecs: NumSet,
specials: Vec<SpecialType>,
) -> 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 = &copy.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<ValueType> {
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<SpecialType>,
}
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<Interval>) -> Self {
assert!(self.ints == Interval::None);
self.ints = interval.into();
self
}
pub fn floats(mut self, interval: impl Into<Interval>) -> Self {
assert!(self.floats == Interval::None);
self.floats = interval.into();
self
}
pub fn bools(mut self, interval: impl Into<Interval>) -> 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<Interval>) -> Self {
assert!(self.simd_lanes == Interval::None);
self.simd_lanes = interval.into();
self
}
pub fn bitvecs(mut self, interval: impl Into<Interval>) -> Self {
assert!(self.bitvecs == Interval::None);
self.bitvecs = interval.into();
self
}
pub fn specials(mut self, specials: Vec<SpecialType>) -> 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<RangeBound>) -> Option<Range> {
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<Interval> 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<Range>) -> 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());
}

View file

@ -132,9 +132,9 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
fmtln!(fmt, "}"); 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(); let mut fmt = Formatter::new();
gen_isa(&isa, &mut fmt); gen_isa(&isa, &mut fmt);
fmt.update_file(format!("{}-{}.rs", base_filename, isa.name), out_dir)?; fmt.update_file(filename, out_dir)?;
Ok(()) Ok(())
} }

View file

@ -1,16 +1,14 @@
use crate::cdsl::camel_case; use crate::cdsl::camel_case;
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::settings::{ use crate::cdsl::settings::{
BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting, BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
}; };
use crate::constant_hash::{generate_table, simple_hash}; use crate::constant_hash::{generate_table, simple_hash};
use crate::error; use crate::error;
use crate::shared;
use crate::srcgen::{Formatter, Match}; use crate::srcgen::{Formatter, Match};
use crate::unique_table::UniqueTable; use crate::unique_table::UniqueSeqTable;
use std::collections::HashMap; use std::collections::HashMap;
enum ParentGroup { pub enum ParentGroup {
None, None,
Shared, Shared,
} }
@ -152,13 +150,9 @@ fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
fmt.indent(|fmt| { fmt.indent(|fmt| {
let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset)); let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
for (i, v) in values.iter().enumerate() { for (i, v) in values.iter().enumerate() {
m.arm( m.arm_no_fields(format!("{}", i), format!("{}::{}", ty, camel_case(v)));
format!("{}", i),
vec![],
format!("{}::{}", ty, camel_case(v)),
);
} }
m.arm("_", vec![], "panic!(\"Invalid enum value\")"); m.arm_no_fields("_", "panic!(\"Invalid enum value\")");
fmt.add_match(m); fmt.add_match(m);
}); });
fmtln!(fmt, "}"); fmtln!(fmt, "}");
@ -191,12 +185,12 @@ fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
fmt.doc_comment("Get a view of the boolean predicates."); fmt.doc_comment("Get a view of the boolean predicates.");
fmtln!( fmtln!(
fmt, fmt,
"pub fn predicate_view(&self) -> ::settings::PredicateView {" "pub fn predicate_view(&self) -> crate::settings::PredicateView {"
); );
fmt.indent(|fmt| { fmt.indent(|fmt| {
fmtln!( fmtln!(
fmt, fmt,
"::settings::PredicateView::new(&self.bytes[{}..])", "crate::settings::PredicateView::new(&self.bytes[{}..])",
group.bool_start_byte_offset group.bool_start_byte_offset
); );
}); });
@ -242,7 +236,7 @@ impl<'a> SettingOrPreset<'a> {
/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS. /// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.
fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) { 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<SettingOrPreset, usize> = HashMap::new(); let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
@ -445,17 +439,14 @@ fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
gen_display(group, fmt); gen_display(group, fmt);
} }
pub fn generate_common(filename: &str, out_dir: &str) -> Result<SettingGroup, error::Error> { pub fn generate(
let settings = shared::settings::generate(); settings: &SettingGroup,
parent_group: ParentGroup,
filename: &str,
out_dir: &str,
) -> Result<(), error::Error> {
let mut fmt = Formatter::new(); 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)?; 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(()) Ok(())
} }

View file

@ -1,6 +1,8 @@
use crate::cdsl::inst::InstructionGroup;
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
fn define_settings(_shared: &SettingGroup) -> SettingGroup { fn define_settings(_shared: &SettingGroup) -> SettingGroup {
let setting = SettingGroupBuilder::new("arm32"); let setting = SettingGroupBuilder::new("arm32");
@ -44,8 +46,11 @@ fn define_regs() -> IsaRegs {
regs.finish() regs.finish()
} }
pub fn define(shared_settings: &SettingGroup) -> TargetIsa { pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(shared_settings); let settings = define_settings(&shared_defs.settings);
let regs = define_regs(); 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)
} }

View file

@ -1,6 +1,8 @@
use crate::cdsl::inst::InstructionGroup;
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
fn define_settings(_shared: &SettingGroup) -> SettingGroup { fn define_settings(_shared: &SettingGroup) -> SettingGroup {
let setting = SettingGroupBuilder::new("arm64"); let setting = SettingGroupBuilder::new("arm64");
@ -40,8 +42,11 @@ fn define_registers() -> IsaRegs {
regs.finish() regs.finish()
} }
pub fn define(shared_settings: &SettingGroup) -> TargetIsa { pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(shared_settings); let settings = define_settings(&shared_defs.settings);
let regs = define_registers(); 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)
} }

View file

@ -1,5 +1,5 @@
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::settings::SettingGroup; use crate::shared::Definitions as SharedDefinitions;
use std::fmt; use std::fmt;
mod arm32; mod arm32;
@ -55,13 +55,13 @@ impl fmt::Display for Isa {
} }
} }
pub fn define(isas: &Vec<Isa>, shared_settings: &SettingGroup) -> Vec<TargetIsa> { pub fn define(isas: &Vec<Isa>, shared_defs: &mut SharedDefinitions) -> Vec<TargetIsa> {
isas.iter() isas.iter()
.map(|isa| match isa { .map(|isa| match isa {
Isa::Riscv => riscv::define(shared_settings), Isa::Riscv => riscv::define(shared_defs),
Isa::X86 => x86::define(shared_settings), Isa::X86 => x86::define(shared_defs),
Isa::Arm32 => arm32::define(shared_settings), Isa::Arm32 => arm32::define(shared_defs),
Isa::Arm64 => arm64::define(shared_settings), Isa::Arm64 => arm64::define(shared_defs),
}) })
.collect() .collect()
} }

View file

@ -1,6 +1,8 @@
use crate::cdsl::inst::InstructionGroup;
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder}; use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
fn define_settings(shared: &SettingGroup) -> SettingGroup { fn define_settings(shared: &SettingGroup) -> SettingGroup {
let mut setting = SettingGroupBuilder::new("riscv"); let mut setting = SettingGroupBuilder::new("riscv");
@ -76,8 +78,11 @@ fn define_registers() -> IsaRegs {
regs.finish() regs.finish()
} }
pub fn define(shared_settings: &SettingGroup) -> TargetIsa { pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(shared_settings); let settings = define_settings(&shared_defs.settings);
let regs = define_registers(); 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)
} }

View file

@ -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
}

View file

@ -1,7 +1,11 @@
mod instructions;
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder}; use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder}; use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
fn define_settings(_shared: &SettingGroup) -> SettingGroup { fn define_settings(_shared: &SettingGroup) -> SettingGroup {
let mut settings = SettingGroupBuilder::new("x86"); let mut settings = SettingGroupBuilder::new("x86");
@ -109,8 +113,11 @@ fn define_registers() -> IsaRegs {
regs.finish() regs.finish()
} }
pub fn define(shared_settings: &SettingGroup) -> TargetIsa { pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(shared_settings); let settings = define_settings(&shared_defs.settings);
let regs = define_registers(); 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)
} }

View file

@ -20,16 +20,27 @@ pub fn isa_from_arch(arch: &str) -> Result<isa::Isa, String> {
/// Generates all the Rust source files used in Cranelift from the meta-language. /// Generates all the Rust source files used in Cranelift from the meta-language.
pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error> { pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error> {
// Common definitions. // 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)?; gen_types::generate("types.rs", &out_dir)?;
// Per ISA definitions. // Per ISA definitions.
let isas = isa::define(isas, &shared_settings); let isas = isa::define(isas, &mut shared_defs);
for isa in isas { for isa in isas {
gen_registers::generate(&isa, "registers", &out_dir)?; gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
gen_settings::generate(&isa, "new_settings", &out_dir)?; gen_settings::generate(
&isa.settings,
gen_settings::ParentGroup::Shared,
&format!("new_settings-{}", isa.name),
&out_dir,
)?;
} }
Ok(()) Ok(())

View file

@ -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<OperandKind> {
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;
}

View file

@ -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
}

View file

@ -0,0 +1,145 @@
use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder};
use std::collections::HashMap;
pub fn define() -> Vec<OperandKind> {
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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,59 @@
//! Shared definitions for the Cranelift intermediate language. //! Shared definitions for the Cranelift intermediate language.
pub mod entities;
pub mod formats;
pub mod immediates;
pub mod instructions;
pub mod settings; pub mod settings;
pub mod types; 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<OperandKind>);
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,
}
}

View file

@ -1,6 +1,6 @@
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
pub fn generate() -> SettingGroup { pub fn define() -> SettingGroup {
let mut settings = SettingGroupBuilder::new("shared"); let mut settings = SettingGroupBuilder::new("shared");
settings.add_enum( settings.add_enum(

View file

@ -113,7 +113,7 @@ impl Iterator for FloatIterator {
/// A type representing CPU flags. /// A type representing CPU flags.
/// ///
/// Flags can't be stored in memory. /// Flags can't be stored in memory.
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Flag { pub enum Flag {
/// CPU flags from an integer comparison. /// CPU flags from an integer comparison.
IFlags, IFlags,

View file

@ -25,6 +25,14 @@ macro_rules! fmtln {
($fmt:ident, $arg:expr) => { ($fmt:ident, $arg:expr) => {
$fmt.line($arg); $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 { pub struct Formatter {
@ -84,6 +92,11 @@ impl Formatter {
self.lines.push(indented_line); 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. /// Emit a line outdented one level.
pub fn _outdented_line(&mut self, s: &str) { pub fn _outdented_line(&mut self, s: &str) {
let new_line = format!("{}{}", self._get_outdent(), s); let new_line = format!("{}{}", self._get_outdent(), s);
@ -112,7 +125,7 @@ impl Formatter {
} }
/// Add one or more lines after stripping common indentation. /// 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)); parse_multiline(s).into_iter().for_each(|l| self.line(&l));
} }
@ -141,7 +154,7 @@ impl Formatter {
self.indent(|fmt| { self.indent(|fmt| {
for (&(ref fields, ref body), ref names) in m.arms.iter() { for (&(ref fields, ref body), ref names) in m.arms.iter() {
// name { fields } | name { fields } => { body } // name { fields } | name { fields } => { body }
let conditions: Vec<String> = names let conditions = names
.iter() .iter()
.map(|name| { .map(|name| {
if fields.len() > 0 { if fields.len() > 0 {
@ -150,9 +163,20 @@ impl Formatter {
name.clone() name.clone()
} }
}) })
.collect(); .collect::<Vec<_>>()
let lhs = conditions.join(" | "); .join(" |\n")
fmtln!(fmt, "{} => {{", lhs); + " => {";
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.indent(|fmt| {
fmt.line(body); fmt.line(body);
}); });
@ -239,27 +263,57 @@ fn parse_multiline(s: &str) -> Vec<String> {
pub struct Match { pub struct Match {
expr: String, expr: String,
arms: BTreeMap<(Vec<String>, String), BTreeSet<String>>, arms: BTreeMap<(Vec<String>, String), BTreeSet<String>>,
/// The clause for the placeholder pattern _.
catch_all: Option<String>,
} }
impl Match { impl Match {
/// Create a new match statement on `expr`. /// Create a new match statement on `expr`.
pub fn new<T: Into<String>>(expr: T) -> Self { pub fn new(expr: impl Into<String>) -> Self {
Self { Self {
expr: expr.into(), expr: expr.into(),
arms: BTreeMap::new(), arms: BTreeMap::new(),
catch_all: None,
} }
} }
/// Add an arm to the Match statement. fn set_catch_all(&mut self, clause: String) {
pub fn arm<T: Into<String>>(&mut self, name: T, fields: Vec<T>, body: T) { assert!(self.catch_all.is_none());
// let key = (fields, body); self.catch_all = Some(clause);
}
/// Add an arm that reads fields to the Match statement.
pub fn arm<T: Into<String>, S: Into<String>>(&mut self, name: T, fields: Vec<S>, 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 body = body.into();
let fields = fields.into_iter().map(|x| x.into()).collect(); let fields = fields.into_iter().map(|x| x.into()).collect();
let match_arm = self let match_arm = self
.arms .arms
.entry((fields, body)) .entry((fields, body))
.or_insert_with(BTreeSet::new); .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<String>, body: impl Into<String>) {
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 } => { Green { a, b } => {
different body different body
} }
Orange { a, b } | Yellow { a, b } => { Orange { a, b } |
Yellow { a, b } => {
some body some body
} }
Blue { x, y } => { Blue { x, y } => {
@ -308,6 +363,36 @@ match x {
assert_eq!(fmt.lines, expected_lines); 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] #[test]
fn parse_multiline_works() { fn parse_multiline_works() {
let input = "\n hello\n world\n"; let input = "\n hello\n world\n";

View file

@ -1,21 +1,76 @@
use std::collections::HashMap;
use std::hash::Hash;
use std::slice; 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. /// A table of sequences which tries to avoid common subsequences.
pub struct UniqueTable<T: PartialEq + Clone> { pub struct UniqueSeqTable<T: PartialEq + Clone> {
table: Vec<T>, table: Vec<T>,
} }
impl<T: PartialEq + Clone> UniqueTable<T> { impl<T: PartialEq + Clone> UniqueSeqTable<T> {
pub fn new() -> Self { pub fn new() -> Self {
Self { table: Vec::new() } Self { table: Vec::new() }
} }
pub fn add(&mut self, values: &Vec<T>) -> usize { pub fn add(&mut self, values: &Vec<T>) -> usize {
if values.len() == 0 {
return 0;
}
if let Some(offset) = find_subsequence(values, &self.table) { if let Some(offset) = find_subsequence(values, &self.table) {
offset offset
} else { } else {
let offset = self.table.len(); let table_len = self.table.len();
self.table.extend((*values).clone());
offset // 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 { pub fn len(&self) -> usize {
@ -35,17 +90,10 @@ fn find_subsequence<T: PartialEq>(sub: &Vec<T>, whole: &Vec<T>) -> Option<usize>
if whole.len() < sub.len() { if whole.len() < sub.len() {
return None; return None;
} }
let max = whole.len() + 1 - sub.len(); let max = whole.len() - sub.len();
for i in 0..max { for i in 0..max + 1 {
let mut found: Option<usize> = Some(i); if whole[i..i + sub.len()] == sub[..] {
for j in 0..sub.len() { return Some(i);
if sub[j] != whole[i + j] {
found = None;
break;
}
}
if found.is_some() {
return found;
} }
} }
return None; return None;
@ -66,3 +114,24 @@ fn test_find_subsequence() {
Some(1) 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);
}

File diff suppressed because one or more lines are too long

View file

@ -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] [package]
edition = "2018"
name = "cranelift-codegen"
version = "0.29.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
build = "build.rs" name = "cranelift-codegen"
version = "0.30.0"
description = "Low-level code generator library" description = "Low-level code generator library"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://cranelift.readthedocs.io/"
repository = "https://github.com/CraneStation/cranelift"
categories = ["no-std"]
readme = "README.md" readme = "README.md"
keywords = ["compile", "compiler", "jit"] keywords = ["compile", "compiler", "jit"]
categories = ["no-std"] build = "build.rs"
license = "Apache-2.0 WITH LLVM-exception" edition = "2018"
repository = "https://github.com/CraneStation/cranelift"
[dependencies.cranelift-bforest]
version = "0.29.0"
default-features = false
[dependencies.cranelift-entity] [dependencies]
version = "0.29.0" cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
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] [build-dependencies]
version = "0.1.1" cranelift-codegen-meta = { path = "meta", version = "0.30.0", default-features = false }
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"
[features] [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 = [] arm32 = []
arm64 = [] arm64 = []
core = ["hashmap_core"]
default = ["std", "x86", "arm32", "arm64", "riscv"]
riscv = [] riscv = []
std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"]
testing_hooks = []
x86 = []
[badges.maintenance]
status = "experimental"
[badges.travis-ci] [badges]
repository = "CraneStation/cranelift" maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }

View file

@ -19,7 +19,7 @@ stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
#: A reference to a global value. #: A reference to a global value.
global_value = EntityRefKind('global_value', '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. #: This is used to provide the call signature in a call_indirect instruction.
sig_ref = EntityRefKind('sig_ref', 'A function signature.') sig_ref = EntityRefKind('sig_ref', 'A function signature.')

View file

@ -252,7 +252,7 @@ class Instruction(object):
for opnum in self.value_opnums: for opnum in self.value_opnums:
typ = self.ins[opnum].typevar typ = self.ins[opnum].typevar
tv = typ.free_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: if tv is None or tv is ctrl_typevar:
continue continue
# No other derived typevars allowed. # No other derived typevars allowed.

View file

@ -364,7 +364,7 @@ def gen_opcodes(groups, fmt):
# We explicitly set the discriminant of the first variant to 1, which # We explicitly set the discriminant of the first variant to 1, which
# allows us to take advantage of the NonZero optimization, meaning that # allows us to take advantage of the NonZero optimization, meaning that
# wrapping enums can use the 0 discriminant instead of increasing the size # wrapping enums can use the 0 discriminant instead of increasing the size
# if the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode) # of the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
is_first_opcode = True is_first_opcode = True
with fmt.indented('pub enum Opcode {', '}'): with fmt.indented('pub enum Opcode {', '}'):
for g in groups: for g in groups:
@ -505,7 +505,7 @@ def gen_type_constraints(fmt, instrs):
# Table of operand constraint sequences (as tuples). Each operand # Table of operand constraint sequences (as tuples). Each operand
# constraint is represented as a string, one of: # constraint is represented as a string, one of:
# - `Concrete(vt)`, where `vt` is a value type name. # - `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. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints.
operand_seqs = UniqueSeqTable() operand_seqs = UniqueSeqTable()

View file

@ -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 # 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.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 # movzwq, encoded as movzwl because it's equivalent and shorter
X86_64.enc(base.uextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xb7)) X86_64.enc(base.uextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xb7))

View file

@ -62,6 +62,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
divert.clear(); divert.clear();
cur.func.offsets[ebb] = offset; cur.func.offsets[ebb] = offset;
while let Some(inst) = cur.next_inst() { while let Some(inst) = cur.next_inst() {
divert.apply(&cur.func.dfg[inst]);
let enc = cur.func.encodings[inst]; let enc = cur.func.encodings[inst];
offset += encinfo.byte_size(enc, inst, &divert, &cur.func); offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
} }
@ -81,10 +82,6 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
// Record the offset for `ebb` and make sure we iterate until offsets are stable. // Record the offset for `ebb` and make sure we iterate until offsets are stable.
if cur.func.offsets[ebb] != offset { if cur.func.offsets[ebb] != offset {
debug_assert!(
cur.func.offsets[ebb] < offset,
"Code shrinking during relaxation"
);
cur.func.offsets[ebb] = offset; cur.func.offsets[ebb] = offset;
go_again = true; go_again = true;
} }
@ -173,12 +170,12 @@ fn relax_branch(
dest_offset dest_offset
); );
// Pick the first encoding that can handle the branch range. // Pick the smallest encoding that can handle the branch range.
let dfg = &cur.func.dfg; let dfg = &cur.func.dfg;
let ctrl_type = dfg.ctrl_typevar(inst); let ctrl_type = dfg.ctrl_typevar(inst);
if let Some(enc) = isa if let Some(enc) = isa
.legal_encodings(cur.func, &dfg[inst], ctrl_type) .legal_encodings(cur.func, &dfg[inst], ctrl_type)
.find(|&enc| { .filter(|&enc| {
let range = encinfo.branch_range(enc).expect("Branch with no range"); let range = encinfo.branch_range(enc).expect("Branch with no range");
if !range.contains(offset, dest_offset) { if !range.contains(offset, dest_offset) {
debug!(" trying [{}]: out of range", encinfo.display(enc)); debug!(" trying [{}]: out of range", encinfo.display(enc));
@ -198,7 +195,9 @@ fn relax_branch(
true true
} }
}) })
.min_by_key(|&enc| encinfo.byte_size(enc, inst, &divert, &cur.func))
{ {
debug_assert!(enc != cur.func.encodings[inst]);
cur.func.encodings[inst] = enc; cur.func.encodings[inst] = enc;
return encinfo.byte_size(enc, inst, &divert, &cur.func); return encinfo.byte_size(enc, inst, &divert, &cur.func);
} }

View file

@ -91,18 +91,21 @@ impl Context {
/// ///
/// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
/// needed, so it provides a safe interface. /// needed, so it provides a safe interface.
///
/// Returns the size of the function's code and the size of the read-only data.
pub fn compile_and_emit( pub fn compile_and_emit(
&mut self, &mut self,
isa: &TargetIsa, isa: &TargetIsa,
mem: &mut Vec<u8>, mem: &mut Vec<u8>,
relocs: &mut RelocSink, relocs: &mut RelocSink,
traps: &mut TrapSink, traps: &mut TrapSink,
) -> CodegenResult<()> { ) -> CodegenResult<(CodeOffset, CodeOffset)> {
let code_size = self.compile(isa)?; let total_size = self.compile(isa)?;
let old_len = mem.len(); let old_len = mem.len();
mem.resize(old_len + code_size as usize, 0); 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) }; unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
Ok(()) Ok((code_size, total_size - code_size))
} }
/// Compile the function. /// 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 /// represented by `isa`. This does not include the final step of emitting machine code into a
/// code sink. /// 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<CodeOffset> { pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult<CodeOffset> {
let _tt = timing::compile(); let _tt = timing::compile();
self.verify_if(isa)?; 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, /// 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. /// 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( pub unsafe fn emit_to_memory(
&self, &self,
isa: &TargetIsa, isa: &TargetIsa,
mem: *mut u8, mem: *mut u8,
relocs: &mut RelocSink, relocs: &mut RelocSink,
traps: &mut TrapSink, traps: &mut TrapSink,
) { ) -> CodeOffset {
let _tt = timing::binemit(); 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. /// Run the verifier on the function.

View file

@ -246,7 +246,7 @@ mod tests {
} }
#[test] #[test]
fn test_magicU32() { fn test_magic_u32() {
assert_eq!(magic_u32(2u32), make_mu32(0x80000000u32, false, 0)); assert_eq!(magic_u32(2u32), make_mu32(0x80000000u32, false, 0));
assert_eq!(magic_u32(3u32), make_mu32(0xaaaaaaabu32, false, 1)); assert_eq!(magic_u32(3u32), make_mu32(0xaaaaaaabu32, false, 1));
assert_eq!(magic_u32(4u32), make_mu32(0x40000000u32, false, 0)); assert_eq!(magic_u32(4u32), make_mu32(0x40000000u32, false, 0));
@ -279,8 +279,9 @@ mod tests {
make_mu32(0x80000001u32, false, 31) make_mu32(0x80000001u32, false, 31)
); );
} }
#[test] #[test]
fn test_magicU64() { fn test_magic_u64() {
assert_eq!(magic_u64(2u64), make_mu64(0x8000000000000000u64, false, 0)); assert_eq!(magic_u64(2u64), make_mu64(0x8000000000000000u64, false, 0));
assert_eq!(magic_u64(3u64), make_mu64(0xaaaaaaaaaaaaaaabu64, false, 1)); assert_eq!(magic_u64(3u64), make_mu64(0xaaaaaaaaaaaaaaabu64, false, 1));
assert_eq!(magic_u64(4u64), make_mu64(0x4000000000000000u64, false, 0)); assert_eq!(magic_u64(4u64), make_mu64(0x4000000000000000u64, false, 0));
@ -346,8 +347,9 @@ mod tests {
make_mu64(0x8000000000000001u64, false, 63) make_mu64(0x8000000000000001u64, false, 63)
); );
} }
#[test] #[test]
fn test_magicS32() { fn test_magic_s32() {
assert_eq!( assert_eq!(
magic_s32(-0x80000000i32), magic_s32(-0x80000000i32),
make_ms32(0x7fffffffu32 as i32, 30) make_ms32(0x7fffffffu32 as i32, 30)
@ -390,8 +392,9 @@ mod tests {
make_ms32(0x40000001u32 as i32, 29) make_ms32(0x40000001u32 as i32, 29)
); );
} }
#[test] #[test]
fn test_magicS64() { fn test_magic_s64() {
assert_eq!( assert_eq!(
magic_s64(-0x8000000000000000i64), magic_s64(-0x8000000000000000i64),
make_ms64(0x7fffffffffffffffu64 as i64, 62) make_ms64(0x7fffffffffffffffu64 as i64, 62)
@ -515,6 +518,7 @@ mod tests {
make_ms64(0x4000000000000001u64 as i64, 61) make_ms64(0x4000000000000001u64 as i64, 61)
); );
} }
#[test] #[test]
fn test_magic_generators_dont_panic() { fn test_magic_generators_dont_panic() {
// The point of this is to check that the magic number generators // The point of this is to check that the magic number generators

View file

@ -1,18 +1,88 @@
//! ARM ABI implementation. //! 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 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::isa::RegClass;
use crate::regalloc::RegisterSet; 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`. /// Legalize `sig`.
pub fn legalize_signature( pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bool) {
_sig: &mut ir::Signature, let bits = triple.pointer_width().unwrap().bits();
_flags: &shared_settings::Flags,
_current: bool, let mut args = Args::new(bits);
) { legalize_args(&mut sig.params, &mut args);
unimplemented!()
} }
/// Get register class for a type appearing in a legalized signature. /// Get register class for a type appearing in a legalized signature.

View file

@ -102,7 +102,7 @@ impl TargetIsa for Isa {
} }
fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { 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 { fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {

View file

@ -161,13 +161,14 @@ pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bo
legalize_args(&mut sig.params, &mut args); legalize_args(&mut sig.params, &mut args);
let regs = if sig.call_conv == CallConv::WindowsFastcall { let (regs, fpr_limit) = if sig.call_conv == CallConv::WindowsFastcall {
&RET_GPRS_WIN_FASTCALL_X64[..] // windows-x64 calling convention only uses XMM0 or RAX for return values
(&RET_GPRS_WIN_FASTCALL_X64[..], 1)
} else { } 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); legalize_args(&mut sig.returns, &mut rets);
} }

View file

@ -14,13 +14,13 @@
//! //!
//! When legalizing a single instruction, it is wrapped in splits and concatenations: //! When legalizing a single instruction, it is wrapped in splits and concatenations:
//! //!
//!```clif //! ```clif
//! v1 = bxor.i64 v2, v3 //! v1 = bxor.i64 v2, v3
//! ``` //! ```
//! //!
//! becomes: //! becomes:
//! //!
//!```clif //! ```clif
//! v20, v21 = isplit v2 //! v20, v21 = isplit v2
//! v30, v31 = isplit v3 //! v30, v31 = isplit v3
//! v10 = bxor.i32 v20, v30 //! v10 = bxor.i32 v20, v30

View file

@ -5,7 +5,9 @@ use crate::dominator_tree::DominatorTree;
use crate::entity::{EntityList, ListPool}; use crate::entity::{EntityList, ListPool};
use crate::flowgraph::{BasicBlock, ControlFlowGraph}; use crate::flowgraph::{BasicBlock, ControlFlowGraph};
use crate::fx::FxHashSet; 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::isa::TargetIsa;
use crate::loop_analysis::{Loop, LoopAnalysis}; use crate::loop_analysis::{Loop, LoopAnalysis};
use crate::timing; 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. /// Test whether the given opcode is unsafe to even consider for LICM.
fn trivially_unsafe_for_licm(opcode: Opcode) -> bool { fn trivially_unsafe_for_licm(opcode: Opcode) -> bool {
opcode.can_load() opcode.can_store()
|| opcode.can_store()
|| opcode.is_call() || opcode.is_call()
|| opcode.is_branch() || opcode.is_branch()
|| opcode.is_terminator() || opcode.is_terminator()
@ -156,12 +157,25 @@ fn trivially_unsafe_for_licm(opcode: Opcode) -> bool {
|| opcode.writes_cpu_flags() || 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. /// Test whether the given instruction is loop-invariant.
fn is_loop_invariant(inst: Inst, dfg: &DataFlowGraph, loop_values: &FxHashSet<Value>) -> bool { fn is_loop_invariant(inst: Inst, dfg: &DataFlowGraph, loop_values: &FxHashSet<Value>) -> bool {
if trivially_unsafe_for_licm(dfg[inst].opcode()) { if trivially_unsafe_for_licm(dfg[inst].opcode()) {
return false; return false;
} }
if is_unsafe_load(&dfg[inst]) {
return false;
}
let inst_args = dfg.inst_args(inst); let inst_args = dfg.inst_args(inst);
for arg in inst_args { for arg in inst_args {
let arg = dfg.resolve_aliases(*arg); let arg = dfg.resolve_aliases(*arg);

View file

@ -128,6 +128,7 @@ fn optimize_cpu_flags(
// We found a compare+branch pattern. Transform it to use 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(); let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec();
pos.goto_inst(info.cmp_inst); pos.goto_inst(info.cmp_inst);
pos.use_srcloc(info.cmp_inst);
match info.kind { match info.kind {
CmpBrKind::Icmp { mut cond, arg } => { CmpBrKind::Icmp { mut cond, arg } => {
let flags = pos.ins().ifcmp(info.cmp_arg, arg); let flags = pos.ins().ifcmp(info.cmp_arg, arg);

View file

@ -292,6 +292,9 @@ impl<'a> Context<'a> {
// Insert a copy instruction at the top of `ebb`. // Insert a copy instruction at the top of `ebb`.
let mut pos = EncCursor::new(self.func, self.isa).at_first_inst(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); pos.ins().with_result(param).copy(new_val);
let inst = pos.built_inst(); let inst = pos.built_inst();
self.liveness.move_def_locally(param, inst); self.liveness.move_def_locally(param, inst);
@ -347,6 +350,7 @@ impl<'a> Context<'a> {
pred_val: Value, pred_val: Value,
) -> Value { ) -> Value {
let mut pos = EncCursor::new(self.func, self.isa).at_inst(pred_inst); 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 copy = pos.ins().copy(pred_val);
let inst = pos.built_inst(); let inst = pos.built_inst();

View file

@ -420,6 +420,7 @@ impl<'a> Context<'a> {
// secondary `opidx` key makes it possible to use an unstable (non-allocating) sort. // 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.reg_uses.sort_unstable_by_key(|u| (u.value, u.opidx));
self.cur.use_srcloc(inst);
for i in 0..self.reg_uses.len() { for i in 0..self.reg_uses.len() {
let ru = self.reg_uses[i]; let ru = self.reg_uses[i];

View file

@ -176,7 +176,7 @@ mod details {
} }
} }
/// Information about passes in a single thread. // Information about passes in a single thread.
thread_local! { thread_local! {
static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::None); static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::None);
static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default()); static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default());

View file

@ -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"} {"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}

View file

@ -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] [package]
edition = "2018"
name = "cranelift-entity"
version = "0.29.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
name = "cranelift-entity"
version = "0.30.0"
description = "Data structures using entity references as mapping keys" description = "Data structures using entity references as mapping keys"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/" documentation = "https://cranelift.readthedocs.io/"
repository = "https://github.com/CraneStation/cranelift"
categories = ["no-std"]
readme = "README.md" readme = "README.md"
keywords = ["entity", "set", "map"] keywords = ["entity", "set", "map"]
categories = ["no-std"] edition = "2018"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/CraneStation/cranelift"
[features] [features]
core = []
default = ["std"] default = ["std"]
std = [] std = []
[badges.maintenance] core = []
status = "experimental"
[badges.travis-ci] [badges]
repository = "CraneStation/cranelift" maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }

View file

@ -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"} {"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}

View file

@ -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] [package]
edition = "2018"
name = "cranelift-frontend"
version = "0.29.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
name = "cranelift-frontend"
version = "0.30.0"
description = "Cranelift IR builder helper" description = "Cranelift IR builder helper"
documentation = "https://cranelift.readthedocs.io/"
readme = "README.md"
categories = ["no-std"]
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://cranelift.readthedocs.io/"
categories = ["no-std"]
repository = "https://github.com/CraneStation/cranelift" repository = "https://github.com/CraneStation/cranelift"
[dependencies.cranelift-codegen] readme = "README.md"
version = "0.29.0" edition = "2018"
default-features = false
[dependencies.hashmap_core] [dependencies]
version = "0.1.9" cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false }
optional = true target-lexicon = { version = "0.4.0", default-features = false }
log = { version = "0.4.6", default-features = false }
[dependencies.log] hashmap_core = { version = "0.1.9", optional = true }
version = "0.4.6"
default-features = false
[dependencies.target-lexicon]
version = "0.2.0"
default-features = false
[features] [features]
core = ["hashmap_core", "cranelift-codegen/core"]
default = ["std"] default = ["std"]
std = ["cranelift-codegen/std"] std = ["cranelift-codegen/std"]
[badges.maintenance] core = ["hashmap_core", "cranelift-codegen/core"]
status = "experimental"
[badges.travis-ci] [badges]
repository = "CraneStation/cranelift" maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }

View file

@ -9,6 +9,36 @@ type EntryIndex = u64;
/// Unlike with `br_table`, `Switch` cases may be sparse or non-0-based. /// 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. /// 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)] #[derive(Debug, Default)]
pub struct Switch { pub struct Switch {
cases: HashMap<EntryIndex, Ebb>, cases: HashMap<EntryIndex, Ebb>,
@ -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<ContiguousCaseRange> { fn collect_contiguous_case_ranges(self) -> Vec<ContiguousCaseRange> {
debug!("build_contiguous_case_ranges before: {:#?}", self.cases); debug!("build_contiguous_case_ranges before: {:#?}", self.cases);
let mut cases = self.cases.into_iter().collect::<Vec<(_, _)>>(); let mut cases = self.cases.into_iter().collect::<Vec<(_, _)>>();
@ -60,6 +98,7 @@ impl Switch {
contiguous_case_ranges contiguous_case_ranges
} }
/// Binary search for the right `ContiguousCaseRange`.
fn build_search_tree( fn build_search_tree(
bx: &mut FunctionBuilder, bx: &mut FunctionBuilder,
val: Value, val: Value,
@ -120,6 +159,7 @@ impl Switch {
cases_and_jt_ebbs cases_and_jt_ebbs
} }
/// Linear search for the right `ContiguousCaseRange`.
fn build_search_branches( fn build_search_branches(
bx: &mut FunctionBuilder, bx: &mut FunctionBuilder,
val: Value, val: Value,
@ -128,22 +168,41 @@ impl Switch {
cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec<Ebb>)>, cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec<Ebb>)>,
) { ) {
for ContiguousCaseRange { first_index, ebbs } in contiguous_case_ranges.into_iter().rev() { for ContiguousCaseRange { first_index, ebbs } in contiguous_case_ranges.into_iter().rev() {
if ebbs.len() == 1 { 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); let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64);
bx.ins().brnz(is_good_val, ebbs[0], &[]); bx.ins().brnz(is_good_val, ebbs[0], &[]);
} else { }
(_, 0) => {
// if `first_index` is 0, then `icmp_imm uge val, first_index` is trivially true
let jt_ebb = bx.create_ebb(); let jt_ebb = bx.create_ebb();
let is_good_val = bx.ins().jump(jt_ebb, &[]);
bx.ins() cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, val, first_index as i64); // `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, &[]); bx.ins().brnz(is_good_val, jt_ebb, &[]);
cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs)); cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
} }
} }
}
bx.ins().jump(otherwise, &[]); 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( fn build_jump_tables(
bx: &mut FunctionBuilder, bx: &mut FunctionBuilder,
val: Value, val: Value,
@ -158,7 +217,11 @@ impl Switch {
let jump_table = bx.create_jump_table(jt_data); let jump_table = bx.create_jump_table(jt_data);
bx.switch_to_block(jt_ebb); 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); 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)] #[derive(Debug)]
struct ContiguousCaseRange { struct ContiguousCaseRange {
/// The entry index of the first case. Eg. 10 when the entry indexes are 10, 11, 12 and 13.
first_index: EntryIndex, first_index: EntryIndex,
/// The ebbs to jump to sorted in ascending order of entry index.
ebbs: Vec<Ebb>, ebbs: Vec<Ebb>,
} }
@ -237,8 +313,7 @@ mod tests {
"ebb0: "ebb0:
v0 = iconst.i8 0 v0 = iconst.i8 0
v1 = uextend.i32 v0 v1 = uextend.i32 v0
v2 = icmp_imm eq v1, 0 brz v1, ebb1
brnz v2, ebb1
jump ebb0" jump ebb0"
); );
} }
@ -267,13 +342,10 @@ mod tests {
ebb0: ebb0:
v0 = iconst.i8 0 v0 = iconst.i8 0
v1 = uextend.i32 v0 v1 = uextend.i32 v0
v2 = icmp_imm uge v1, 0 jump ebb3
brnz v2, ebb3
jump ebb0
ebb3: ebb3:
v3 = iadd_imm.i32 v1, 0 br_table.i32 v1, ebb0, jt0"
br_table v3, ebb0, jt0"
); );
} }
@ -287,8 +359,7 @@ ebb3:
v1 = uextend.i32 v0 v1 = uextend.i32 v0
v2 = icmp_imm eq v1, 2 v2 = icmp_imm eq v1, 2
brnz v2, ebb2 brnz v2, ebb2
v3 = icmp_imm eq v1, 0 brz v1, ebb1
brnz v3, ebb1
jump ebb0" jump ebb0"
); );
} }
@ -318,17 +389,14 @@ ebb9:
ebb8: ebb8:
v5 = icmp_imm.i32 eq v1, 5 v5 = icmp_imm.i32 eq v1, 5
brnz v5, ebb3 brnz v5, ebb3
v6 = icmp_imm.i32 uge v1, 0 jump ebb11
brnz v6, ebb11
jump ebb0
ebb11: ebb11:
v7 = iadd_imm.i32 v1, 0 br_table.i32 v1, ebb0, jt0
br_table v7, ebb0, jt0
ebb10: ebb10:
v8 = iadd_imm.i32 v1, -10 v6 = iadd_imm.i32 v1, -10
br_table v8, ebb0, jt1" br_table v6, ebb0, jt1"
); );
} }
@ -363,4 +431,23 @@ ebb10:
jump ebb0" 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"
);
}
} }

View file

@ -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"} {"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}

View file

@ -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] [package]
edition = "2018"
name = "cranelift-wasm" name = "cranelift-wasm"
version = "0.29.0" version = "0.30.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "Translator from WebAssembly to Cranelift IR" 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" readme = "README.md"
keywords = ["webassembly", "wasm"] keywords = ["webassembly", "wasm"]
categories = ["no-std", "wasm"] edition = "2018"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/CraneStation/cranelift"
[dependencies.cast]
version = "0.2.2"
default-features = false
[dependencies.cranelift-codegen] [dependencies]
version = "0.29.0" wasmparser = { version = "0.29.2", default-features = false }
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] [dev-dependencies]
version = "0.29.0" wabt = "0.7.0"
default-features = false target-lexicon = "0.4.0"
[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"
[features] [features]
core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"]
default = ["std"] default = ["std"]
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmparser/std"] std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmparser/std"]
[badges.maintenance] core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"]
status = "experimental"
[badges.travis-ci] [badges]
repository = "CraneStation/cranelift" maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }

View file

@ -886,6 +886,161 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
Operator::RefNull | Operator::RefIsNull { .. } => { Operator::RefNull | Operator::RefIsNull { .. } => {
return Err(WasmError::Unsupported("proposed reference-type operators")); 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(()) Ok(())
} }

View file

@ -12,15 +12,15 @@ use crate::translation_utils::{
type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex,
Table, TableElementType, TableIndex, Table, TableElementType, TableIndex,
}; };
use core::str::from_utf8;
use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_codegen::ir::{self, AbiParam, Signature};
use cranelift_entity::EntityRef; use cranelift_entity::EntityRef;
use std::vec::Vec; use std::vec::Vec;
use wasmparser::{ use wasmparser::{
self, CodeSectionReader, Data, DataSectionReader, Element, ElementSectionReader, Export, self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind,
ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
Operator, TableSectionReader, TypeSectionReader, ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader,
TypeSectionReader,
}; };
/// Parses the Type section of the wasm module. /// Parses the Type section of the wasm module.
@ -65,12 +65,8 @@ pub fn parse_import_section<'data>(
for entry in imports { for entry in imports {
let import = entry?; let import = entry?;
let module_name = import.module;
// The input has already been validated, so we should be able to let field_name = import.field;
// 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();
match import.ty { match import.ty {
ImportSectionEntryType::Function(sig) => { 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 // The input has already been validated, so we should be able to
// assume valid UTF-8 and use `from_utf8_unchecked` if performance // assume valid UTF-8 and use `from_utf8_unchecked` if performance
// becomes a concern here. // becomes a concern here.
let name = from_utf8(field).unwrap();
let index = index as usize; let index = index as usize;
match *kind { match *kind {
ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), name), ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), field),
ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name), ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field),
ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), name), ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), field),
ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), name), ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), field),
} }
} }
@ -260,15 +255,18 @@ pub fn parse_element_section<'data>(
environ.reserve_table_elements(elements.get_count()); environ.reserve_table_elements(elements.get_count());
for entry in elements { for entry in elements {
let Element { let Element { kind, items } = entry?;
if let ElementKind::Active {
table_index, table_index,
init_expr, init_expr,
items, } = kind
} = entry?; {
let mut init_expr_reader = init_expr.get_binary_reader(); let mut init_expr_reader = init_expr.get_binary_reader();
let (base, offset) = match init_expr_reader.read_operator()? { let (base, offset) = match init_expr_reader.read_operator()? {
Operator::I32Const { value } => (None, value as u32 as usize), Operator::I32Const { value } => (None, value as u32 as usize),
Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0), Operator::GetGlobal { global_index } => {
(Some(GlobalIndex::from_u32(global_index)), 0)
}
ref s => panic!("unsupported init expr in element section: {:?}", s), ref s => panic!("unsupported init expr in element section: {:?}", s),
}; };
let items_reader = items.get_items_reader()?; let items_reader = items.get_items_reader()?;
@ -283,6 +281,9 @@ pub fn parse_element_section<'data>(
offset, offset,
elems.into_boxed_slice(), elems.into_boxed_slice(),
) )
} else {
panic!("unsupported passive elements section");
}
} }
Ok(()) Ok(())
} }
@ -309,15 +310,18 @@ pub fn parse_data_section<'data>(
environ.reserve_data_initializers(data.get_count()); environ.reserve_data_initializers(data.get_count());
for entry in data { for entry in data {
let Data { let Data { kind, data } = entry?;
if let DataKind::Active {
memory_index, memory_index,
init_expr, init_expr,
data, } = kind
} = entry?; {
let mut init_expr_reader = init_expr.get_binary_reader(); let mut init_expr_reader = init_expr.get_binary_reader();
let (base, offset) = match init_expr_reader.read_operator()? { let (base, offset) = match init_expr_reader.read_operator()? {
Operator::I32Const { value } => (None, value as u32 as usize), Operator::I32Const { value } => (None, value as u32 as usize),
Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0), Operator::GetGlobal { global_index } => {
(Some(GlobalIndex::from_u32(global_index)), 0)
}
ref s => panic!("unsupported init expr in data section: {:?}", s), ref s => panic!("unsupported init expr in data section: {:?}", s),
}; };
environ.declare_data_initialization( environ.declare_data_initialization(
@ -326,6 +330,9 @@ pub fn parse_data_section<'data>(
offset, offset,
data, data,
); );
} else {
panic!("unsupported passive data section");
}
} }
Ok(()) Ok(())

View file

@ -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} {"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"}

View file

@ -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

View file

@ -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] [package]
edition = "2018"
name = "target-lexicon" name = "target-lexicon"
version = "0.2.0" version = "0.4.0"
authors = ["Dan Gohman <sunfish@mozilla.com>"] authors = ["Dan Gohman <sunfish@mozilla.com>"]
description = "Targeting utilities for compilers and related tools" description = "Targeting utilities for compilers and related tools"
documentation = "https://docs.rs/target-lexicon/" documentation = "https://docs.rs/target-lexicon/"
@ -9,18 +22,22 @@ keywords = ["target", "host", "triple", "compiler", "jit"]
categories = ["no-std"] categories = ["no-std"]
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/CraneStation/target-lexicon" repository = "https://github.com/CraneStation/target-lexicon"
[dependencies.failure]
version = "0.1.3"
features = ["derive"]
default-features = false
[dependencies] [dependencies.failure_derive]
failure = { version = "0.1.3", default-features = false, features = ["derive"] } version = "0.1.3"
failure_derive = { version = "0.1.3", default-features = false } default-features = false
[build-dependencies.serde_json]
[build-dependencies] version = "1.0"
serde_json = "1.0"
[features] [features]
default = ["std"] default = ["std"]
std = [] std = []
[badges.maintenance]
status = "passively-maintained"
[badges] [badges.travis-ci]
maintenance = { status = "passively-maintained" } repository = "CraneStation/target-lexicon"
travis-ci = { repository = "CraneStation/target-lexicon" }

View file

@ -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 /// Assuming `target` is a path to a custom target json config file, open it
/// and build a `Triple` using its contents. /// and build a `Triple` using its contents.

View file

@ -1,6 +1,6 @@
extern crate target_lexicon; extern crate target_lexicon;
use std::str::FromStr; use core::str::FromStr;
use target_lexicon::{Triple, HOST}; use target_lexicon::{Triple, HOST};
fn main() { fn main() {

View file

@ -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 // Include the implementations of the `HOST` object containing information
// about the current host. // about the current host.

View file

@ -15,29 +15,24 @@
use_self use_self
) )
)] )]
#![cfg_attr(not(feature = "std"), no_std)] #![no_std]
#![cfg_attr(not(feature = "std"), feature(alloc))] #![cfg_attr(not(feature = "std"), feature(alloc))]
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
extern crate alloc; extern crate alloc as std;
#[cfg(feature = "std")]
extern crate std;
extern crate failure;
#[macro_use] #[macro_use]
extern crate failure_derive; extern crate failure_derive;
#[cfg(not(feature = "std"))]
mod std {
pub use alloc::{borrow, string};
pub use core::*;
}
mod host; mod host;
mod parse_error; mod parse_error;
mod targets; mod targets;
#[macro_use] #[macro_use]
mod triple; mod triple;
pub use host::HOST; pub use self::host::HOST;
pub use parse_error::ParseError; pub use self::parse_error::ParseError;
pub use targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor}; pub use self::targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor};
pub use triple::{CallingConvention, Endianness, PointerWidth, Triple}; pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple};

View file

@ -16,6 +16,4 @@ pub enum ParseError {
UnrecognizedBinaryFormat(String), UnrecognizedBinaryFormat(String),
#[fail(display = "Unrecognized field: {}", _0)] #[fail(display = "Unrecognized field: {}", _0)]
UnrecognizedField(String), UnrecognizedField(String),
#[fail(display = "\"none\" requires an explicit binary format")]
NoneWithoutBinaryFormat,
} }

View file

@ -1,8 +1,8 @@
// This file defines all the identifier enums and target-aware logic. // This file defines all the identifier enums and target-aware logic.
use std::fmt; use crate::triple::{Endianness, PointerWidth, Triple};
use std::str::FromStr; use core::fmt;
use triple::{Endianness, PointerWidth, Triple}; use core::str::FromStr;
/// The "architecture" field, which in some cases also specifies a specific /// The "architecture" field, which in some cases also specifies a specific
/// subarchitecture. /// subarchitecture.
@ -12,9 +12,12 @@ pub enum Architecture {
Unknown, Unknown,
Aarch64, Aarch64,
Arm, Arm,
Armebv7r,
Armv4t, Armv4t,
Armv5te, Armv5te,
Armv6,
Armv7, Armv7,
Armv7r,
Armv7s, Armv7s,
Asmjs, Asmjs,
I386, I386,
@ -29,15 +32,20 @@ pub enum Architecture {
Powerpc64, Powerpc64,
Powerpc64le, Powerpc64le,
Riscv32, Riscv32,
Riscv32imac,
Riscv32imc,
Riscv64, Riscv64,
S390x, S390x,
Sparc, Sparc,
Sparc64, Sparc64,
Sparcv9, Sparcv9,
Thumbv6m, Thumbv6m,
Thumbv7a,
Thumbv7em, Thumbv7em,
Thumbv7m, Thumbv7m,
Thumbv7neon, Thumbv7neon,
Thumbv8mBase,
Thumbv8mMain,
Wasm32, Wasm32,
X86_64, X86_64,
} }
@ -50,6 +58,7 @@ pub enum Vendor {
Unknown, Unknown,
Apple, Apple,
Experimental, Experimental,
Fortanix,
Pc, Pc,
Rumprun, Rumprun,
Sun, Sun,
@ -69,14 +78,17 @@ pub enum OperatingSystem {
Freebsd, Freebsd,
Fuchsia, Fuchsia,
Haiku, Haiku,
Hermit,
Ios, Ios,
L4re, L4re,
Linux, Linux,
Nebulet, Nebulet,
Netbsd, Netbsd,
None_,
Openbsd, Openbsd,
Redox, Redox,
Solaris, Solaris,
Uefi,
Windows, Windows,
} }
@ -102,6 +114,7 @@ pub enum Environment {
Musleabihf, Musleabihf,
Msvc, Msvc,
Uclibc, Uclibc,
Sgx,
} }
/// The "binary format" field, which is usually omitted, and the binary format /// The "binary format" field, which is usually omitted, and the binary format
@ -125,7 +138,9 @@ impl Architecture {
| Architecture::Arm | Architecture::Arm
| Architecture::Armv4t | Architecture::Armv4t
| Architecture::Armv5te | Architecture::Armv5te
| Architecture::Armv6
| Architecture::Armv7 | Architecture::Armv7
| Architecture::Armv7r
| Architecture::Armv7s | Architecture::Armv7s
| Architecture::Asmjs | Architecture::Asmjs
| Architecture::I386 | Architecture::I386
@ -136,14 +151,20 @@ impl Architecture {
| Architecture::Msp430 | Architecture::Msp430
| Architecture::Powerpc64le | Architecture::Powerpc64le
| Architecture::Riscv32 | Architecture::Riscv32
| Architecture::Riscv32imac
| Architecture::Riscv32imc
| Architecture::Riscv64 | Architecture::Riscv64
| Architecture::Thumbv6m | Architecture::Thumbv6m
| Architecture::Thumbv7a
| Architecture::Thumbv7em | Architecture::Thumbv7em
| Architecture::Thumbv7m | Architecture::Thumbv7m
| Architecture::Thumbv7neon | Architecture::Thumbv7neon
| Architecture::Thumbv8mBase
| Architecture::Thumbv8mMain
| Architecture::Wasm32 | Architecture::Wasm32
| Architecture::X86_64 => Ok(Endianness::Little), | Architecture::X86_64 => Ok(Endianness::Little),
Architecture::Mips Architecture::Armebv7r
| Architecture::Mips
| Architecture::Mips64 | Architecture::Mips64
| Architecture::Powerpc | Architecture::Powerpc
| Architecture::Powerpc64 | Architecture::Powerpc64
@ -160,9 +181,12 @@ impl Architecture {
Architecture::Unknown => Err(()), Architecture::Unknown => Err(()),
Architecture::Msp430 => Ok(PointerWidth::U16), Architecture::Msp430 => Ok(PointerWidth::U16),
Architecture::Arm Architecture::Arm
| Architecture::Armebv7r
| Architecture::Armv4t | Architecture::Armv4t
| Architecture::Armv5te | Architecture::Armv5te
| Architecture::Armv6
| Architecture::Armv7 | Architecture::Armv7
| Architecture::Armv7r
| Architecture::Armv7s | Architecture::Armv7s
| Architecture::Asmjs | Architecture::Asmjs
| Architecture::I386 | Architecture::I386
@ -170,11 +194,16 @@ impl Architecture {
| Architecture::I686 | Architecture::I686
| Architecture::Mipsel | Architecture::Mipsel
| Architecture::Riscv32 | Architecture::Riscv32
| Architecture::Riscv32imac
| Architecture::Riscv32imc
| Architecture::Sparc | Architecture::Sparc
| Architecture::Thumbv6m | Architecture::Thumbv6m
| Architecture::Thumbv7a
| Architecture::Thumbv7em | Architecture::Thumbv7em
| Architecture::Thumbv7m | Architecture::Thumbv7m
| Architecture::Thumbv7neon | Architecture::Thumbv7neon
| Architecture::Thumbv8mBase
| Architecture::Thumbv8mMain
| Architecture::Wasm32 | Architecture::Wasm32
| Architecture::Mips | Architecture::Mips
| Architecture::Powerpc => Ok(PointerWidth::U32), | Architecture::Powerpc => Ok(PointerWidth::U32),
@ -196,6 +225,7 @@ impl Architecture {
/// `binary_format` field. /// `binary_format` field.
pub fn default_binary_format(triple: &Triple) -> BinaryFormat { pub fn default_binary_format(triple: &Triple) -> BinaryFormat {
match triple.operating_system { match triple.operating_system {
OperatingSystem::None_ => BinaryFormat::Unknown,
OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho, OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho,
OperatingSystem::Windows => BinaryFormat::Coff, OperatingSystem::Windows => BinaryFormat::Coff,
OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => { OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => {
@ -214,9 +244,12 @@ impl fmt::Display for Architecture {
Architecture::Unknown => "unknown", Architecture::Unknown => "unknown",
Architecture::Aarch64 => "aarch64", Architecture::Aarch64 => "aarch64",
Architecture::Arm => "arm", Architecture::Arm => "arm",
Architecture::Armebv7r => "armebv7r",
Architecture::Armv4t => "armv4t", Architecture::Armv4t => "armv4t",
Architecture::Armv5te => "armv5te", Architecture::Armv5te => "armv5te",
Architecture::Armv6 => "armv6",
Architecture::Armv7 => "armv7", Architecture::Armv7 => "armv7",
Architecture::Armv7r => "armv7r",
Architecture::Armv7s => "armv7s", Architecture::Armv7s => "armv7s",
Architecture::Asmjs => "asmjs", Architecture::Asmjs => "asmjs",
Architecture::I386 => "i386", Architecture::I386 => "i386",
@ -231,15 +264,20 @@ impl fmt::Display for Architecture {
Architecture::Powerpc64 => "powerpc64", Architecture::Powerpc64 => "powerpc64",
Architecture::Powerpc64le => "powerpc64le", Architecture::Powerpc64le => "powerpc64le",
Architecture::Riscv32 => "riscv32", Architecture::Riscv32 => "riscv32",
Architecture::Riscv32imac => "riscv32imac",
Architecture::Riscv32imc => "riscv32imc",
Architecture::Riscv64 => "riscv64", Architecture::Riscv64 => "riscv64",
Architecture::S390x => "s390x", Architecture::S390x => "s390x",
Architecture::Sparc => "sparc", Architecture::Sparc => "sparc",
Architecture::Sparc64 => "sparc64", Architecture::Sparc64 => "sparc64",
Architecture::Sparcv9 => "sparcv9", Architecture::Sparcv9 => "sparcv9",
Architecture::Thumbv6m => "thumbv6m", Architecture::Thumbv6m => "thumbv6m",
Architecture::Thumbv7a => "thumbv7a",
Architecture::Thumbv7em => "thumbv7em", Architecture::Thumbv7em => "thumbv7em",
Architecture::Thumbv7m => "thumbv7m", Architecture::Thumbv7m => "thumbv7m",
Architecture::Thumbv7neon => "thumbv7neon", Architecture::Thumbv7neon => "thumbv7neon",
Architecture::Thumbv8mBase => "thumbv8m.base",
Architecture::Thumbv8mMain => "thumbv8m.main",
Architecture::Wasm32 => "wasm32", Architecture::Wasm32 => "wasm32",
Architecture::X86_64 => "x86_64", Architecture::X86_64 => "x86_64",
}; };
@ -255,9 +293,12 @@ impl FromStr for Architecture {
"unknown" => Architecture::Unknown, "unknown" => Architecture::Unknown,
"aarch64" => Architecture::Aarch64, "aarch64" => Architecture::Aarch64,
"arm" => Architecture::Arm, "arm" => Architecture::Arm,
"armebv7r" => Architecture::Armebv7r,
"armv4t" => Architecture::Armv4t, "armv4t" => Architecture::Armv4t,
"armv5te" => Architecture::Armv5te, "armv5te" => Architecture::Armv5te,
"armv6" => Architecture::Armv6,
"armv7" => Architecture::Armv7, "armv7" => Architecture::Armv7,
"armv7r" => Architecture::Armv7r,
"armv7s" => Architecture::Armv7s, "armv7s" => Architecture::Armv7s,
"asmjs" => Architecture::Asmjs, "asmjs" => Architecture::Asmjs,
"i386" => Architecture::I386, "i386" => Architecture::I386,
@ -272,15 +313,20 @@ impl FromStr for Architecture {
"powerpc64" => Architecture::Powerpc64, "powerpc64" => Architecture::Powerpc64,
"powerpc64le" => Architecture::Powerpc64le, "powerpc64le" => Architecture::Powerpc64le,
"riscv32" => Architecture::Riscv32, "riscv32" => Architecture::Riscv32,
"riscv32imac" => Architecture::Riscv32imac,
"riscv32imc" => Architecture::Riscv32imc,
"riscv64" => Architecture::Riscv64, "riscv64" => Architecture::Riscv64,
"s390x" => Architecture::S390x, "s390x" => Architecture::S390x,
"sparc" => Architecture::Sparc, "sparc" => Architecture::Sparc,
"sparc64" => Architecture::Sparc64, "sparc64" => Architecture::Sparc64,
"sparcv9" => Architecture::Sparcv9, "sparcv9" => Architecture::Sparcv9,
"thumbv6m" => Architecture::Thumbv6m, "thumbv6m" => Architecture::Thumbv6m,
"thumbv7a" => Architecture::Thumbv7a,
"thumbv7em" => Architecture::Thumbv7em, "thumbv7em" => Architecture::Thumbv7em,
"thumbv7m" => Architecture::Thumbv7m, "thumbv7m" => Architecture::Thumbv7m,
"thumbv7neon" => Architecture::Thumbv7neon, "thumbv7neon" => Architecture::Thumbv7neon,
"thumbv8m.base" => Architecture::Thumbv8mBase,
"thumbv8m.main" => Architecture::Thumbv8mMain,
"wasm32" => Architecture::Wasm32, "wasm32" => Architecture::Wasm32,
"x86_64" => Architecture::X86_64, "x86_64" => Architecture::X86_64,
_ => return Err(()), _ => return Err(()),
@ -294,6 +340,7 @@ impl fmt::Display for Vendor {
Vendor::Unknown => "unknown", Vendor::Unknown => "unknown",
Vendor::Apple => "apple", Vendor::Apple => "apple",
Vendor::Experimental => "experimental", Vendor::Experimental => "experimental",
Vendor::Fortanix => "fortanix",
Vendor::Pc => "pc", Vendor::Pc => "pc",
Vendor::Rumprun => "rumprun", Vendor::Rumprun => "rumprun",
Vendor::Sun => "sun", Vendor::Sun => "sun",
@ -310,6 +357,7 @@ impl FromStr for Vendor {
"unknown" => Vendor::Unknown, "unknown" => Vendor::Unknown,
"apple" => Vendor::Apple, "apple" => Vendor::Apple,
"experimental" => Vendor::Experimental, "experimental" => Vendor::Experimental,
"fortanix" => Vendor::Fortanix,
"pc" => Vendor::Pc, "pc" => Vendor::Pc,
"rumprun" => Vendor::Rumprun, "rumprun" => Vendor::Rumprun,
"sun" => Vendor::Sun, "sun" => Vendor::Sun,
@ -330,14 +378,17 @@ impl fmt::Display for OperatingSystem {
OperatingSystem::Freebsd => "freebsd", OperatingSystem::Freebsd => "freebsd",
OperatingSystem::Fuchsia => "fuchsia", OperatingSystem::Fuchsia => "fuchsia",
OperatingSystem::Haiku => "haiku", OperatingSystem::Haiku => "haiku",
OperatingSystem::Hermit => "hermit",
OperatingSystem::Ios => "ios", OperatingSystem::Ios => "ios",
OperatingSystem::L4re => "l4re", OperatingSystem::L4re => "l4re",
OperatingSystem::Linux => "linux", OperatingSystem::Linux => "linux",
OperatingSystem::Nebulet => "nebulet", OperatingSystem::Nebulet => "nebulet",
OperatingSystem::Netbsd => "netbsd", OperatingSystem::Netbsd => "netbsd",
OperatingSystem::None_ => "none",
OperatingSystem::Openbsd => "openbsd", OperatingSystem::Openbsd => "openbsd",
OperatingSystem::Redox => "redox", OperatingSystem::Redox => "redox",
OperatingSystem::Solaris => "solaris", OperatingSystem::Solaris => "solaris",
OperatingSystem::Uefi => "uefi",
OperatingSystem::Windows => "windows", OperatingSystem::Windows => "windows",
}; };
f.write_str(s) f.write_str(s)
@ -358,14 +409,17 @@ impl FromStr for OperatingSystem {
"freebsd" => OperatingSystem::Freebsd, "freebsd" => OperatingSystem::Freebsd,
"fuchsia" => OperatingSystem::Fuchsia, "fuchsia" => OperatingSystem::Fuchsia,
"haiku" => OperatingSystem::Haiku, "haiku" => OperatingSystem::Haiku,
"hermit" => OperatingSystem::Hermit,
"ios" => OperatingSystem::Ios, "ios" => OperatingSystem::Ios,
"l4re" => OperatingSystem::L4re, "l4re" => OperatingSystem::L4re,
"linux" => OperatingSystem::Linux, "linux" => OperatingSystem::Linux,
"nebulet" => OperatingSystem::Nebulet, "nebulet" => OperatingSystem::Nebulet,
"netbsd" => OperatingSystem::Netbsd, "netbsd" => OperatingSystem::Netbsd,
"none" => OperatingSystem::None_,
"openbsd" => OperatingSystem::Openbsd, "openbsd" => OperatingSystem::Openbsd,
"redox" => OperatingSystem::Redox, "redox" => OperatingSystem::Redox,
"solaris" => OperatingSystem::Solaris, "solaris" => OperatingSystem::Solaris,
"uefi" => OperatingSystem::Uefi,
"windows" => OperatingSystem::Windows, "windows" => OperatingSystem::Windows,
_ => return Err(()), _ => return Err(()),
}) })
@ -391,6 +445,7 @@ impl fmt::Display for Environment {
Environment::Musleabihf => "musleabihf", Environment::Musleabihf => "musleabihf",
Environment::Msvc => "msvc", Environment::Msvc => "msvc",
Environment::Uclibc => "uclibc", Environment::Uclibc => "uclibc",
Environment::Sgx => "sgx",
}; };
f.write_str(s) f.write_str(s)
} }
@ -417,6 +472,7 @@ impl FromStr for Environment {
"musleabihf" => Environment::Musleabihf, "musleabihf" => Environment::Musleabihf,
"msvc" => Environment::Msvc, "msvc" => Environment::Msvc,
"uclibc" => Environment::Uclibc, "uclibc" => Environment::Uclibc,
"sgx" => Environment::Sgx,
_ => return Err(()), _ => return Err(()),
}) })
} }
@ -461,72 +517,19 @@ mod tests {
// "rustup target list" and "rustc --print target-list". // "rustup target list" and "rustc --print target-list".
let targets = [ let targets = [
"aarch64-apple-ios", "aarch64-apple-ios",
"aarch64-fuchsia",
"aarch64-linux-android", "aarch64-linux-android",
"aarch64-unknown-fuchsia", "aarch64-pc-windows-msvc",
"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-unknown-cloudabi", "aarch64-unknown-cloudabi",
"aarch64-unknown-freebsd", "aarch64-unknown-freebsd",
"aarch64-unknown-fuchsia", "aarch64-unknown-hermit",
"aarch64-unknown-linux-gnu", "aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl", "aarch64-unknown-linux-musl",
"aarch64-unknown-netbsd",
"aarch64-unknown-none",
"aarch64-unknown-openbsd",
"armebv7r-none-eabi",
"armebv7r-none-eabihf",
"arm-linux-androideabi", "arm-linux-androideabi",
"arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf", "arm-unknown-linux-gnueabihf",
@ -534,11 +537,19 @@ mod tests {
"arm-unknown-linux-musleabihf", "arm-unknown-linux-musleabihf",
"armv4t-unknown-linux-gnueabi", "armv4t-unknown-linux-gnueabi",
"armv5te-unknown-linux-gnueabi", "armv5te-unknown-linux-gnueabi",
"armv5te-unknown-linux-musleabi",
"armv6-unknown-netbsd-eabihf",
"armv7-apple-ios",
"armv7-linux-androideabi", "armv7-linux-androideabi",
"armv7r-none-eabi",
"armv7r-none-eabihf",
"armv7s-apple-ios",
"armv7-unknown-cloudabi-eabihf", "armv7-unknown-cloudabi-eabihf",
"armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabihf",
"armv7-unknown-linux-musleabihf", "armv7-unknown-linux-musleabihf",
"armv7-unknown-netbsd-eabihf",
"asmjs-unknown-emscripten", "asmjs-unknown-emscripten",
"i386-apple-ios",
"i586-pc-windows-msvc", "i586-pc-windows-msvc",
"i586-unknown-linux-gnu", "i586-unknown-linux-gnu",
"i586-unknown-linux-musl", "i586-unknown-linux-musl",
@ -554,33 +565,47 @@ mod tests {
"i686-unknown-linux-musl", "i686-unknown-linux-musl",
"i686-unknown-netbsd", "i686-unknown-netbsd",
"i686-unknown-openbsd", "i686-unknown-openbsd",
"mips-unknown-linux-gnu",
"mips-unknown-linux-musl",
"mips-unknown-linux-uclibc",
"mips64-unknown-linux-gnuabi64",
"mips64el-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64",
"mips64-unknown-linux-gnuabi64",
"mipsel-unknown-linux-gnu", "mipsel-unknown-linux-gnu",
"mipsel-unknown-linux-musl", "mipsel-unknown-linux-musl",
"mipsel-unknown-linux-uclibc", "mipsel-unknown-linux-uclibc",
"mips-unknown-linux-gnu",
"mips-unknown-linux-musl",
"mips-unknown-linux-uclibc",
"msp430-none-elf", "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-gnu",
"powerpc-unknown-linux-gnuspe", "powerpc-unknown-linux-gnuspe",
"powerpc-unknown-linux-musl",
"powerpc-unknown-netbsd", "powerpc-unknown-netbsd",
"powerpc64-unknown-linux-gnu", "riscv32imac-unknown-none-elf",
"powerpc64le-unknown-linux-gnu", "riscv32imc-unknown-none-elf",
"s390x-unknown-linux-gnu", "s390x-unknown-linux-gnu",
"sparc-unknown-linux-gnu",
"sparc64-unknown-linux-gnu", "sparc64-unknown-linux-gnu",
"sparc64-unknown-netbsd", "sparc64-unknown-netbsd",
"sparc-unknown-linux-gnu",
"sparcv9-sun-solaris", "sparcv9-sun-solaris",
"thumbv6m-none-eabi", "thumbv6m-none-eabi",
"thumbv7a-pc-windows-msvc",
"thumbv7em-none-eabi", "thumbv7em-none-eabi",
"thumbv7em-none-eabihf", "thumbv7em-none-eabihf",
"thumbv7m-none-eabi", "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-experimental-emscripten",
"wasm32-unknown-emscripten", "wasm32-unknown-emscripten",
"wasm32-unknown-unknown", "wasm32-unknown-unknown",
"x86_64-apple-darwin", "x86_64-apple-darwin",
"x86_64-apple-ios",
"x86_64-fortanix-unknown-sgx",
"x86_64-fuchsia",
"x86_64-linux-android", "x86_64-linux-android",
"x86_64-pc-windows-gnu", "x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc", "x86_64-pc-windows-msvc",
@ -590,8 +615,8 @@ mod tests {
"x86_64-unknown-cloudabi", "x86_64-unknown-cloudabi",
"x86_64-unknown-dragonfly", "x86_64-unknown-dragonfly",
"x86_64-unknown-freebsd", "x86_64-unknown-freebsd",
"x86_64-unknown-fuchsia",
"x86_64-unknown-haiku", "x86_64-unknown-haiku",
"x86_64-unknown-hermit",
"x86_64-unknown-l4re-uclibc", "x86_64-unknown-l4re-uclibc",
"x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-gnux32", "x86_64-unknown-linux-gnux32",
@ -599,6 +624,7 @@ mod tests {
"x86_64-unknown-netbsd", "x86_64-unknown-netbsd",
"x86_64-unknown-openbsd", "x86_64-unknown-openbsd",
"x86_64-unknown-redox", "x86_64-unknown-redox",
"x86_64-unknown-uefi",
]; ];
for target in targets.iter() { for target in targets.iter() {

View file

@ -1,12 +1,12 @@
// This file defines the `Triple` type and support code shared by all targets. // This file defines the `Triple` type and support code shared by all targets.
use parse_error::ParseError; use crate::parse_error::ParseError;
use std::borrow::ToOwned; use crate::targets::{
use std::fmt;
use std::str::FromStr;
use targets::{
default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor, default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor,
}; };
use core::fmt;
use core::str::FromStr;
use std::borrow::ToOwned;
/// The target memory endianness. /// The target memory endianness.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@ -155,17 +155,24 @@ impl fmt::Display for Triple {
write!(f, "{}", self.architecture)?; write!(f, "{}", self.architecture)?;
if self.vendor == Vendor::Unknown if self.vendor == Vendor::Unknown
&& self.operating_system == OperatingSystem::Unknown && ((self.operating_system == OperatingSystem::Linux
&& (self.environment != Environment::Unknown
|| self.binary_format != implied_binary_format)
{
// "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::Android
|| self.environment == Environment::Androideabi) || 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)))
{ {
// 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)?; write!(f, "-{}", self.operating_system)?;
} else { } else {
write!(f, "-{}-{}", self.vendor, self.operating_system)?; write!(f, "-{}-{}", self.vendor, self.operating_system)?;
@ -203,16 +210,7 @@ impl FromStr for Triple {
let mut has_vendor = false; let mut has_vendor = false;
let mut has_operating_system = false; let mut has_operating_system = false;
if let Some(s) = current_part { if let Some(s) = current_part {
// "none" is special-case shorthand for unknown vendor and unknown operating system. if let Ok(vendor) = Vendor::from_str(s) {
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) {
has_vendor = true; has_vendor = true;
result.vendor = vendor; result.vendor = vendor;
current_part = parts.next(); current_part = parts.next();

View file

@ -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"} {"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"}

View file

@ -12,7 +12,7 @@
[package] [package]
name = "wasmparser" name = "wasmparser"
version = "0.23.0" version = "0.29.2"
authors = ["Yury Delendik <ydelendik@mozilla.com>"] authors = ["Yury Delendik <ydelendik@mozilla.com>"]
exclude = ["fuzz/**/*", "tests/**/*"] exclude = ["fuzz/**/*", "tests/**/*"]
description = "A simple event-driven library for parsing WebAssembly binary files.\n" description = "A simple event-driven library for parsing WebAssembly binary files.\n"

View file

@ -9,10 +9,6 @@ use wasmparser::Parser;
use wasmparser::ParserState; use wasmparser::ParserState;
use wasmparser::WasmDecoder; use wasmparser::WasmDecoder;
fn get_name(bytes: &[u8]) -> &str {
str::from_utf8(bytes).ok().unwrap()
}
fn main() { fn main() {
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 2 { if args.len() != 2 {
@ -32,9 +28,7 @@ fn main() {
} => { } => {
println!( println!(
"ExportSectionEntry {{ field: \"{}\", kind: {:?}, index: {} }}", "ExportSectionEntry {{ field: \"{}\", kind: {:?}, index: {} }}",
get_name(field), field, kind, index
kind,
index
); );
} }
ParserState::ImportSectionEntry { ParserState::ImportSectionEntry {
@ -44,9 +38,7 @@ fn main() {
} => { } => {
println!( println!(
"ImportSectionEntry {{ module: \"{}\", field: \"{}\", ty: {:?} }}", "ImportSectionEntry {{ module: \"{}\", field: \"{}\", ty: {:?} }}",
get_name(module), module, field, ty
get_name(field),
ty
); );
} }
ParserState::EndWasm => break, ParserState::EndWasm => break,

View file

@ -9,10 +9,6 @@ use wasmparser::Parser;
use wasmparser::ParserState; use wasmparser::ParserState;
use wasmparser::WasmDecoder; use wasmparser::WasmDecoder;
fn get_name(bytes: &[u8]) -> &str {
str::from_utf8(bytes).ok().unwrap()
}
fn main() { fn main() {
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 2 { if args.len() != 2 {
@ -31,10 +27,10 @@ fn main() {
ParserState::ExportSectionEntry { ParserState::ExportSectionEntry {
field, ref kind, .. field, ref kind, ..
} => { } => {
println!(" Export {} {:?}", get_name(field), kind); println!(" Export {} {:?}", field, kind);
} }
ParserState::ImportSectionEntry { module, field, .. } => { ParserState::ImportSectionEntry { module, field, .. } => {
println!(" Import {}::{}", get_name(module), get_name(field)) println!(" Import {}::{}", module, field)
} }
ParserState::EndWasm => break, ParserState::EndWasm => break,
ParserState::Error(err) => panic!("Error: {:?}", err), ParserState::Error(err) => panic!("Error: {:?}", err),

View file

@ -14,6 +14,7 @@
*/ */
use std::boxed::Box; use std::boxed::Box;
use std::str;
use std::vec::Vec; use std::vec::Vec;
use limits::{ use limits::{
@ -24,35 +25,17 @@ use limits::{
use primitives::{ use primitives::{
BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32, BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32,
Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType, 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; const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
fn is_name(name: &[u8], expected: &'static str) -> bool { fn is_name(name: &str, expected: &'static str) -> bool {
if name.len() != expected.len() { name == expected
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_prefix(name: &[u8], prefix: &'static str) -> bool { fn is_name_prefix(name: &str, prefix: &'static str) -> bool {
if name.len() < prefix.len() { name.starts_with(prefix)
return false;
}
let expected_bytes = prefix.as_bytes();
for i in 0..expected_bytes.len() {
if name[i] != expected_bytes[i] {
return false;
}
}
true
} }
const WASM_MAGIC_NUMBER: u32 = 0x6d736100; const WASM_MAGIC_NUMBER: u32 = 0x6d736100;
@ -123,6 +106,13 @@ impl<'a> BinaryReader<'a> {
self.original_offset + self.position 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<()> { fn ensure_has_byte(&self) -> Result<()> {
if self.position < self.buffer.len() { if self.position < self.buffer.len() {
Ok(()) Ok(())
@ -185,6 +175,7 @@ impl<'a> BinaryReader<'a> {
-0x02 => Ok(Type::I64), -0x02 => Ok(Type::I64),
-0x03 => Ok(Type::F32), -0x03 => Ok(Type::F32),
-0x04 => Ok(Type::F64), -0x04 => Ok(Type::F64),
-0x05 => Ok(Type::V128),
-0x10 => Ok(Type::AnyFunc), -0x10 => Ok(Type::AnyFunc),
-0x11 => Ok(Type::AnyRef), -0x11 => Ok(Type::AnyRef),
-0x20 => Ok(Type::Func), -0x20 => Ok(Type::Func),
@ -332,6 +323,8 @@ impl<'a> BinaryReader<'a> {
let name = self.read_string()?; let name = self.read_string()?;
let kind = if is_name(name, "name") { let kind = if is_name(name, "name") {
CustomSectionKind::Name CustomSectionKind::Name
} else if is_name(name, "producers") {
CustomSectionKind::Producers
} else if is_name(name, "sourceMappingURL") { } else if is_name(name, "sourceMappingURL") {
CustomSectionKind::SourceMappingURL CustomSectionKind::SourceMappingURL
} else if is_name_prefix(name, "reloc.") { } else if is_name_prefix(name, "reloc.") {
@ -354,6 +347,7 @@ impl<'a> BinaryReader<'a> {
9 => Ok(SectionCode::Element), 9 => Ok(SectionCode::Element),
10 => Ok(SectionCode::Code), 10 => Ok(SectionCode::Code),
11 => Ok(SectionCode::Data), 11 => Ok(SectionCode::Data),
12 => Ok(SectionCode::DataCount),
_ => Err(BinaryReaderError { _ => Err(BinaryReaderError {
message: "Invalid section code", message: "Invalid section code",
offset, offset,
@ -376,6 +370,7 @@ impl<'a> BinaryReader<'a> {
self.skip_var_32()?; self.skip_var_32()?;
Ok(BrTable { Ok(BrTable {
buffer: &self.buffer[start..self.position], buffer: &self.buffer[start..self.position],
cnt: targets_len as usize,
}) })
} }
@ -558,7 +553,7 @@ impl<'a> BinaryReader<'a> {
Ok(Ieee64(value)) 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; let len = self.read_var_u32()? as usize;
if len > MAX_WASM_STRING_SIZE { if len > MAX_WASM_STRING_SIZE {
return Err(BinaryReaderError { return Err(BinaryReaderError {
@ -566,7 +561,11 @@ impl<'a> BinaryReader<'a> {
offset: self.original_position() - 1, 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<MemoryImmediate> { fn read_memarg_of_align(&mut self, align: u32) -> Result<MemoryImmediate> {
@ -786,7 +785,7 @@ impl<'a> BinaryReader<'a> {
return Err(BinaryReaderError { return Err(BinaryReaderError {
message: "Unknown 0xFE opcode", message: "Unknown 0xFE opcode",
offset: self.original_position() - 1, offset: self.original_position() - 1,
}) });
} }
}) })
} }
@ -822,7 +821,7 @@ impl<'a> BinaryReader<'a> {
}, },
0x11 => Operator::CallIndirect { 0x11 => Operator::CallIndirect {
index: self.read_var_u32()?, index: self.read_var_u32()?,
table_index: self.read_var_u1()?, table_index: self.read_var_u32()?,
}, },
0x1a => Operator::Drop, 0x1a => Operator::Drop,
0x1b => Operator::Select, 0x1b => Operator::Select,
@ -841,6 +840,12 @@ impl<'a> BinaryReader<'a> {
0x24 => Operator::SetGlobal { 0x24 => Operator::SetGlobal {
global_index: self.read_var_u32()?, 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 { 0x28 => Operator::I32Load {
memarg: self.read_memarg()?, memarg: self.read_memarg()?,
}, },
@ -1062,14 +1067,14 @@ impl<'a> BinaryReader<'a> {
0xd1 => Operator::RefIsNull, 0xd1 => Operator::RefIsNull,
0xfc => self.read_0xfc_operator()?, 0xfc => self.read_0xfc_operator()?,
0xfd => self.read_0xfd_operator()?,
0xfe => self.read_0xfe_operator()?, 0xfe => self.read_0xfe_operator()?,
_ => { _ => {
return Err(BinaryReaderError { return Err(BinaryReaderError {
message: "Unknown opcode", message: "Unknown opcode",
offset: self.original_position() - 1, offset: self.original_position() - 1,
}) });
} }
}) })
} }
@ -1086,12 +1091,305 @@ impl<'a> BinaryReader<'a> {
0x06 => Operator::I64TruncSSatF64, 0x06 => Operator::I64TruncSSatF64,
0x07 => Operator::I64TruncUSatF64, 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 { return Err(BinaryReaderError {
message: "Unknown 0xfc opcode", message: "Unknown 0xfc opcode",
offset: self.original_position() - 1, offset: self.original_position() - 1,
});
}
}) })
} }
fn read_line_index(&mut self, max: u32) -> Result<SIMDLineIndex> {
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<V128> {
let mut bytes = [0; 16];
bytes.clone_from_slice(self.read_bytes(16)?);
Ok(V128(bytes))
}
fn read_0xfd_operator(&mut self) -> Result<Operator<'a>> {
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> { 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. /// Reads br_table entries.
/// ///
/// # Examples /// # Examples

View file

@ -66,6 +66,7 @@ pub use primitives::Result;
pub use primitives::SectionCode; pub use primitives::SectionCode;
pub use primitives::TableType; pub use primitives::TableType;
pub use primitives::Type; pub use primitives::Type;
pub use primitives::V128;
pub use validator::validate; pub use validator::validate;
pub use validator::OperatorValidatorConfig; pub use validator::OperatorValidatorConfig;
@ -76,10 +77,12 @@ pub use validator::WasmModuleResources;
pub use readers::CodeSectionReader; pub use readers::CodeSectionReader;
pub use readers::Data; pub use readers::Data;
pub use readers::DataKind;
pub use readers::DataSectionReader; pub use readers::DataSectionReader;
pub use readers::Element; pub use readers::Element;
pub use readers::ElementItems; pub use readers::ElementItems;
pub use readers::ElementItemsReader; pub use readers::ElementItemsReader;
pub use readers::ElementKind;
pub use readers::ElementSectionReader; pub use readers::ElementSectionReader;
pub use readers::Export; pub use readers::Export;
pub use readers::ExportSectionReader; pub use readers::ExportSectionReader;
@ -98,6 +101,9 @@ pub use readers::Name;
pub use readers::NameSectionReader; pub use readers::NameSectionReader;
pub use readers::NamingReader; pub use readers::NamingReader;
pub use readers::OperatorsReader; pub use readers::OperatorsReader;
pub use readers::ProducersField;
pub use readers::ProducersFieldValue;
pub use readers::ProducersSectionReader;
pub use readers::Reloc; pub use readers::Reloc;
pub use readers::RelocSectionReader; pub use readers::RelocSectionReader;
pub use readers::Section; pub use readers::Section;

View file

@ -28,11 +28,11 @@ use primitives::{
}; };
use readers::{ use readers::{
CodeSectionReader, Data, DataSectionReader, Element, ElementItems, ElementSectionReader, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global, GlobalSectionReader, ElementSectionReader, Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global,
Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader, ModuleReader, Name, GlobalSectionReader, Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader,
NameSectionReader, NamingReader, OperatorsReader, Reloc, RelocSectionReader, Section, ModuleReader, Name, NameSectionReader, NamingReader, OperatorsReader, Reloc,
SectionReader, TableSectionReader, TypeSectionReader, RelocSectionReader, Section, SectionReader, TableSectionReader, TypeSectionReader,
}; };
use binary_reader::{BinaryReader, Range}; use binary_reader::{BinaryReader, Range};
@ -47,7 +47,7 @@ pub struct LocalName<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum NameEntry<'a> { pub enum NameEntry<'a> {
Module(&'a [u8]), Module(&'a str),
Function(Box<[Naming<'a>]>), Function(Box<[Naming<'a>]>),
Local(Box<[LocalName<'a>]>), Local(Box<[LocalName<'a>]>),
} }
@ -86,20 +86,21 @@ pub enum ParserState<'a> {
TypeSectionEntry(FuncType), TypeSectionEntry(FuncType),
ImportSectionEntry { ImportSectionEntry {
module: &'a [u8], module: &'a str,
field: &'a [u8], field: &'a str,
ty: ImportSectionEntryType, ty: ImportSectionEntryType,
}, },
FunctionSectionEntry(u32), FunctionSectionEntry(u32),
TableSectionEntry(TableType), TableSectionEntry(TableType),
MemorySectionEntry(MemoryType), MemorySectionEntry(MemoryType),
ExportSectionEntry { ExportSectionEntry {
field: &'a [u8], field: &'a str,
kind: ExternalKind, kind: ExternalKind,
index: u32, index: u32,
}, },
NameSectionEntry(NameEntry<'a>), NameSectionEntry(NameEntry<'a>),
StartSectionEntry(u32), StartSectionEntry(u32),
DataCountSectionEntry(u32),
BeginInitExpressionBody, BeginInitExpressionBody,
InitExpressionOperator(Operator<'a>), InitExpressionOperator(Operator<'a>),
@ -115,11 +116,13 @@ pub enum ParserState<'a> {
EndFunctionBody, EndFunctionBody,
SkippingFunctionBody, SkippingFunctionBody,
BeginElementSectionEntry(u32), BeginPassiveElementSectionEntry(Type),
BeginActiveElementSectionEntry(u32),
ElementSectionEntryBody(Box<[u32]>), ElementSectionEntryBody(Box<[u32]>),
EndElementSectionEntry, EndElementSectionEntry,
BeginDataSectionEntry(u32), BeginPassiveDataSectionEntry,
BeginActiveDataSectionEntry(u32),
EndDataSectionEntry, EndDataSectionEntry,
BeginDataSectionEntryBody(u32), BeginDataSectionEntryBody(u32),
DataSectionEntryBodyChunk(&'a [u8]), DataSectionEntryBodyChunk(&'a [u8]),
@ -132,7 +135,7 @@ pub enum ParserState<'a> {
RelocSectionEntry(RelocEntry), RelocSectionEntry(RelocEntry),
LinkingSectionEntry(LinkingType), LinkingSectionEntry(LinkingType),
SourceMappingURL(&'a [u8]), SourceMappingURL(&'a str),
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -269,33 +272,33 @@ impl<'a> Parser<'a> {
ParserSectionReader::CodeSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::CodeSectionReader(ref reader) => return reader.original_position(),
ParserSectionReader::DataSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::DataSectionReader(ref reader) => return reader.original_position(),
ParserSectionReader::ElementSectionReader(ref reader) => { ParserSectionReader::ElementSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::ExportSectionReader(ref reader) => { ParserSectionReader::ExportSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::FunctionSectionReader(ref reader) => { ParserSectionReader::FunctionSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::GlobalSectionReader(ref reader) => { ParserSectionReader::GlobalSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::ImportSectionReader(ref reader) => { ParserSectionReader::ImportSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::MemorySectionReader(ref reader) => { ParserSectionReader::MemorySectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::TableSectionReader(ref reader) => { ParserSectionReader::TableSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::TypeSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::TypeSectionReader(ref reader) => return reader.original_position(),
ParserSectionReader::NameSectionReader(ref reader) => return reader.original_position(), ParserSectionReader::NameSectionReader(ref reader) => return reader.original_position(),
ParserSectionReader::LinkingSectionReader(ref reader) => { ParserSectionReader::LinkingSectionReader(ref reader) => {
return reader.original_position() return reader.original_position();
} }
ParserSectionReader::RelocSectionReader(ref reader) => { 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<()> { fn read_section_header(&mut self) -> Result<()> {
let section = self.module_reader.as_mut().expect("module reader").read()?; let section = self.module_reader.as_mut().expect("module reader").read()?;
let code = section.code; let code = section.code;
let range = section.get_range(); let range = section.range();
self.current_section = Some(section); self.current_section = Some(section);
self.state = ParserState::BeginSection { code, range }; self.state = ParserState::BeginSection { code, range };
Ok(()) Ok(())
@ -408,13 +411,19 @@ impl<'a> Parser<'a> {
if self.section_entries_left == 0 { if self.section_entries_left == 0 {
return self.check_section_end(); return self.check_section_end();
} }
let Element { let Element { kind, items } = section_reader!(self, ElementSectionReader).read()?;
match kind {
ElementKind::Passive(ty) => {
self.state = ParserState::BeginPassiveElementSectionEntry(ty);
}
ElementKind::Active {
table_index, table_index,
init_expr, init_expr,
items, } => {
} = section_reader!(self, ElementSectionReader).read()?; self.state = ParserState::BeginActiveElementSectionEntry(table_index);
self.state = ParserState::BeginElementSectionEntry(table_index);
self.operators_reader = Some(init_expr.get_operators_reader()); self.operators_reader = Some(init_expr.get_operators_reader());
}
}
self.element_items = Some(items); self.element_items = Some(items);
self.section_entries_left -= 1; self.section_entries_left -= 1;
Ok(()) Ok(())
@ -447,7 +456,7 @@ impl<'a> Parser<'a> {
return self.check_section_end(); return self.check_section_end();
} }
let function_body = section_reader!(self, CodeSectionReader).read()?; 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.state = ParserState::BeginFunctionBody { range };
self.current_function_body = Some(function_body); self.current_function_body = Some(function_body);
self.section_entries_left -= 1; self.section_entries_left -= 1;
@ -529,13 +538,19 @@ impl<'a> Parser<'a> {
if self.section_entries_left == 0 { if self.section_entries_left == 0 {
return self.check_section_end(); return self.check_section_end();
} }
let Data { let Data { kind, data } = section_reader!(self, DataSectionReader).read()?;
match kind {
DataKind::Passive => {
self.state = ParserState::BeginPassiveDataSectionEntry;
}
DataKind::Active {
memory_index, memory_index,
init_expr, init_expr,
data, } => {
} = section_reader!(self, DataSectionReader).read()?; self.state = ParserState::BeginActiveDataSectionEntry(memory_index);
self.state = ParserState::BeginDataSectionEntry(memory_index);
self.operators_reader = Some(init_expr.get_operators_reader()); self.operators_reader = Some(init_expr.get_operators_reader());
}
}
self.current_data_segment = Some(data); self.current_data_segment = Some(data);
self.section_entries_left -= 1; self.section_entries_left -= 1;
Ok(()) Ok(())
@ -731,6 +746,17 @@ impl<'a> Parser<'a> {
.get_start_section_content()?; .get_start_section_content()?;
self.state = ParserState::StartSectionEntry(func_index); 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 { ParserState::BeginSection {
code: SectionCode::Custom { .. }, code: SectionCode::Custom { .. },
.. ..
@ -774,7 +800,8 @@ impl<'a> Parser<'a> {
start_section_reader!(self, LinkingSectionReader, get_linking_section_reader); start_section_reader!(self, LinkingSectionReader, get_linking_section_reader);
self.read_linking_entry()?; self.read_linking_entry()?;
} }
ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { ParserState::ReadingCustomSection(CustomSectionKind::Producers)
| ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => {
self.create_custom_section_binary_reader(); self.create_custom_section_binary_reader();
self.read_section_body_bytes()?; self.read_section_body_bytes()?;
} }
@ -875,13 +902,17 @@ impl<'a> Parser<'a> {
self.read_init_expression_body(InitExpressionContinuation::GlobalSection) self.read_init_expression_body(InitExpressionContinuation::GlobalSection)
} }
ParserState::EndGlobalSectionEntry => self.read_global_entry()?, ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
ParserState::BeginElementSectionEntry(_) => { ParserState::BeginPassiveElementSectionEntry(_) => self.read_element_entry_body()?,
ParserState::BeginActiveElementSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::ElementSection) self.read_init_expression_body(InitExpressionContinuation::ElementSection)
} }
ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => { ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => {
self.read_init_expression_operator()? self.read_init_expression_operator()?
} }
ParserState::BeginDataSectionEntry(_) => { ParserState::BeginPassiveDataSectionEntry => {
self.read_data_entry_body()?;
}
ParserState::BeginActiveDataSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::DataSection) self.read_init_expression_body(InitExpressionContinuation::DataSection)
} }
ParserState::EndInitExpressionBody => { ParserState::EndInitExpressionBody => {
@ -917,6 +948,7 @@ impl<'a> Parser<'a> {
} }
ParserState::EndElementSectionEntry => self.read_element_entry()?, ParserState::EndElementSectionEntry => self.read_element_entry()?,
ParserState::StartSectionEntry(_) => self.position_to_section_end()?, ParserState::StartSectionEntry(_) => self.position_to_section_end()?,
ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?,
ParserState::NameSectionEntry(_) => self.read_name_entry()?, ParserState::NameSectionEntry(_) => self.read_name_entry()?,
ParserState::SourceMappingURL(_) => self.position_to_section_end()?, ParserState::SourceMappingURL(_) => self.position_to_section_end()?,
ParserState::RelocSectionHeader(_) => { ParserState::RelocSectionHeader(_) => {

View file

@ -14,6 +14,8 @@
*/ */
use std::boxed::Box; use std::boxed::Box;
use std::error::Error;
use std::fmt;
use std::result; use std::result;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -24,10 +26,19 @@ pub struct BinaryReaderError {
pub type Result<T> = result::Result<T, BinaryReaderError>; pub type Result<T> = result::Result<T, BinaryReaderError>;
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)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum CustomSectionKind { pub enum CustomSectionKind {
Unknown, Unknown,
Name, Name,
Producers,
SourceMappingURL, SourceMappingURL,
Reloc, Reloc,
Linking, Linking,
@ -39,7 +50,7 @@ pub enum CustomSectionKind {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SectionCode<'a> { pub enum SectionCode<'a> {
Custom { Custom {
name: &'a [u8], name: &'a str,
kind: CustomSectionKind, kind: CustomSectionKind,
}, },
Type, // Function signature declarations Type, // Function signature declarations
@ -53,6 +64,7 @@ pub enum SectionCode<'a> {
Element, // Elements section Element, // Elements section
Code, // Function bodies (code) Code, // Function bodies (code)
Data, // Data segments Data, // Data segments
DataCount, // Count of passive data segments
} }
/// Types as defined [here]. /// Types as defined [here].
@ -64,6 +76,7 @@ pub enum Type {
I64, I64,
F32, F32,
F64, F64,
V128,
AnyFunc, AnyFunc,
AnyRef, AnyRef,
Func, Func,
@ -129,7 +142,7 @@ pub struct MemoryImmediate {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Naming<'a> { pub struct Naming<'a> {
pub index: u32, pub index: u32,
pub name: &'a [u8], pub name: &'a str,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -160,6 +173,7 @@ pub enum RelocType {
#[derive(Debug)] #[derive(Debug)]
pub struct BrTable<'a> { pub struct BrTable<'a> {
pub(crate) buffer: &'a [u8], pub(crate) buffer: &'a [u8],
pub(crate) cnt: usize,
} }
/// An IEEE binary32 immediate floating point value, represented as a u32 /// 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]. /// Instructions as defined [here].
/// ///
/// [here]: https://webassembly.github.io/spec/binary/instructions.html /// [here]: https://webassembly.github.io/spec/binary/instructions.html
@ -384,6 +409,20 @@ pub enum Operator<'a> {
I64TruncSSatF64, I64TruncSSatF64,
I64TruncUSatF64, 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 // 0xFE operators
// https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
Wake { memarg: MemoryImmediate }, Wake { memarg: MemoryImmediate },
@ -452,4 +491,147 @@ pub enum Operator<'a> {
I64AtomicRmw8UCmpxchg { memarg: MemoryImmediate }, I64AtomicRmw8UCmpxchg { memarg: MemoryImmediate },
I64AtomicRmw16UCmpxchg { memarg: MemoryImmediate }, I64AtomicRmw16UCmpxchg { memarg: MemoryImmediate },
I64AtomicRmw32UCmpxchg { 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,
} }

View file

@ -64,7 +64,7 @@ impl<'a> FunctionBody<'a> {
Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos)) Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
} }
pub(crate) fn get_range(&self) -> Range { pub fn range(&self) -> Range {
Range { Range {
start: self.offset, start: self.offset,
end: self.offset + self.data.len(), end: self.offset + self.data.len(),

View file

@ -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<u32> {
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)
}

View file

@ -20,11 +20,19 @@ use super::{
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Data<'a> { pub struct Data<'a> {
pub memory_index: u32, pub kind: DataKind<'a>,
pub init_expr: InitExpr<'a>,
pub data: &'a [u8], 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> { pub struct DataSectionReader<'a> {
reader: BinaryReader<'a>, reader: BinaryReader<'a>,
count: u32, count: u32,
@ -64,7 +72,7 @@ impl<'a> DataSectionReader<'a> {
/// # 0x05, 0x03, 0x01, 0x00, 0x02, /// # 0x05, 0x03, 0x01, 0x00, 0x02,
/// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b, /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b,
/// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; /// # 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 mut reader = ModuleReader::new(data).expect("module reader");
/// let section = reader.read().expect("type section"); /// let section = reader.read().expect("type section");
/// let section = reader.read().expect("function section"); /// let section = reader.read().expect("function section");
@ -75,32 +83,48 @@ impl<'a> DataSectionReader<'a> {
/// for _ in 0..data_reader.get_count() { /// for _ in 0..data_reader.get_count() {
/// let data = data_reader.read().expect("data"); /// let data = data_reader.read().expect("data");
/// println!("Data: {:?}", data); /// println!("Data: {:?}", data);
/// let mut init_expr_reader = data.init_expr.get_binary_reader(); /// 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"); /// let op = init_expr_reader.read_operator().expect("op");
/// println!("Init const: {:?}", op); /// println!("Init const: {:?}", op);
/// } /// }
/// }
/// ``` /// ```
pub fn read<'b>(&mut self) -> Result<Data<'b>> pub fn read<'b>(&mut self) -> Result<Data<'b>>
where where
'a: 'b, 'a: 'b,
{ {
let memory_index = self.reader.read_var_u32()?; 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 init_expr = {
let expr_offset = self.reader.position; let expr_offset = self.reader.position;
self.reader.skip_init_expr()?; self.reader.skip_init_expr()?;
let data = &self.reader.buffer[expr_offset..self.reader.position]; let data = &self.reader.buffer[expr_offset..self.reader.position];
InitExpr::new(data, self.reader.original_offset + expr_offset) 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_len = self.reader.read_var_u32()? as usize;
let data_end = self.reader.position + data_len; let data_end = self.reader.position + data_len;
self.verify_data_end(data_end)?; self.verify_data_end(data_end)?;
let data = &self.reader.buffer[self.reader.position..data_end]; let data = &self.reader.buffer[self.reader.position..data_end];
self.reader.skip_to(data_end); self.reader.skip_to(data_end);
Ok(Data { Ok(Data { kind, data })
memory_index,
init_expr,
data,
})
} }
} }

View file

@ -14,16 +14,25 @@
*/ */
use super::{ use super::{
BinaryReader, InitExpr, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
SectionWithLimitedItems, Type,
}; };
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Element<'a> { pub struct Element<'a> {
pub table_index: u32, pub kind: ElementKind<'a>,
pub init_expr: InitExpr<'a>,
pub items: ElementItems<'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)] #[derive(Debug, Copy, Clone)]
pub struct ElementItems<'a> { pub struct ElementItems<'a> {
offset: usize, offset: usize,
@ -129,7 +138,7 @@ impl<'a> ElementSectionReader<'a> {
/// # 0x05, 0x03, 0x01, 0x00, 0x02, /// # 0x05, 0x03, 0x01, 0x00, 0x02,
/// # 0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00, /// # 0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00,
/// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
/// use wasmparser::ModuleReader; /// use wasmparser::{ModuleReader, ElementKind};
///use wasmparser::Result; ///use wasmparser::Result;
/// let mut reader = ModuleReader::new(data).expect("module reader"); /// let mut reader = ModuleReader::new(data).expect("module reader");
/// let section = reader.read().expect("type section"); /// let section = reader.read().expect("type section");
@ -140,9 +149,11 @@ impl<'a> ElementSectionReader<'a> {
/// for _ in 0..element_reader.get_count() { /// for _ in 0..element_reader.get_count() {
/// let element = element_reader.read().expect("element"); /// let element = element_reader.read().expect("element");
/// println!("Element: {:?}", element); /// println!("Element: {:?}", element);
/// let mut init_expr_reader = element.init_expr.get_binary_reader(); /// 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"); /// let op = init_expr_reader.read_operator().expect("op");
/// println!("Init const: {:?}", op); /// println!("Init const: {:?}", op);
/// }
/// let mut items_reader = element.items.get_items_reader().expect("items reader"); /// let mut items_reader = element.items.get_items_reader().expect("items reader");
/// for _ in 0..items_reader.get_count() { /// for _ in 0..items_reader.get_count() {
/// let item = items_reader.read().expect("item"); /// let item = items_reader.read().expect("item");
@ -154,13 +165,32 @@ impl<'a> ElementSectionReader<'a> {
where where
'a: 'b, 'a: 'b,
{ {
let table_index = self.reader.read_var_u32()?; 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 init_expr = {
let expr_offset = self.reader.position; let expr_offset = self.reader.position;
self.reader.skip_init_expr()?; self.reader.skip_init_expr()?;
let data = &self.reader.buffer[expr_offset..self.reader.position]; let data = &self.reader.buffer[expr_offset..self.reader.position];
InitExpr::new(data, self.reader.original_offset + expr_offset) InitExpr::new(data, self.reader.original_offset + expr_offset)
}; };
ElementKind::Active {
table_index,
init_expr,
}
};
let data_start = self.reader.position; let data_start = self.reader.position;
let items_count = self.reader.read_var_u32()?; let items_count = self.reader.read_var_u32()?;
for _ in 0..items_count { for _ in 0..items_count {
@ -171,11 +201,7 @@ impl<'a> ElementSectionReader<'a> {
offset: self.reader.original_offset + data_start, offset: self.reader.original_offset + data_start,
data: &self.reader.buffer[data_start..data_end], data: &self.reader.buffer[data_start..data_end],
}; };
Ok(Element { Ok(Element { kind, items })
table_index,
init_expr,
items,
})
} }
} }

View file

@ -20,7 +20,7 @@ use super::{
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Export<'a> { pub struct Export<'a> {
pub field: &'a [u8], pub field: &'a str,
pub kind: ExternalKind, pub kind: ExternalKind,
pub index: u32, pub index: u32,
} }

View file

@ -20,8 +20,8 @@ use super::{
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Import<'a> { pub struct Import<'a> {
pub module: &'a [u8], pub module: &'a str,
pub field: &'a [u8], pub field: &'a str,
pub ty: ImportSectionEntryType, pub ty: ImportSectionEntryType,
} }

View file

@ -24,11 +24,14 @@ use super::SectionHeader;
pub use self::code_section::CodeSectionReader; pub use self::code_section::CodeSectionReader;
pub use self::code_section::FunctionBody; pub use self::code_section::FunctionBody;
pub use self::code_section::LocalsReader; 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::Data;
pub use self::data_section::DataKind;
pub use self::data_section::DataSectionReader; pub use self::data_section::DataSectionReader;
pub use self::element_section::Element; pub use self::element_section::Element;
pub use self::element_section::ElementItems; pub use self::element_section::ElementItems;
pub use self::element_section::ElementItemsReader; pub use self::element_section::ElementItemsReader;
pub use self::element_section::ElementKind;
pub use self::element_section::ElementSectionReader; pub use self::element_section::ElementSectionReader;
pub use self::export_section::Export; pub use self::export_section::Export;
pub use self::export_section::ExportSectionReader; 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::NameSectionReader;
pub use self::name_section::NamingReader; 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::linking_section::LinkingSectionReader;
pub use self::reloc_section::Reloc; pub use self::reloc_section::Reloc;
@ -67,6 +74,7 @@ use self::sourcemappingurl_section::read_sourcemappingurl_section_content;
pub use self::operators::OperatorsReader; pub use self::operators::OperatorsReader;
mod code_section; mod code_section;
mod data_count_section;
mod data_section; mod data_section;
mod element_section; mod element_section;
mod export_section; mod export_section;
@ -79,6 +87,7 @@ mod memory_section;
mod module; mod module;
mod name_section; mod name_section;
mod operators; mod operators;
mod producers_section;
mod reloc_section; mod reloc_section;
mod section_reader; mod section_reader;
mod sourcemappingurl_section; mod sourcemappingurl_section;

View file

@ -20,10 +20,11 @@ use super::{
}; };
use super::{ use super::{
read_sourcemappingurl_section_content, read_start_section_content, CodeSectionReader, read_data_count_section_content, read_sourcemappingurl_section_content,
DataSectionReader, ElementSectionReader, ExportSectionReader, FunctionSectionReader, read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader,
GlobalSectionReader, ImportSectionReader, LinkingSectionReader, MemorySectionReader, ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader,
NameSectionReader, RelocSectionReader, TableSectionReader, TypeSectionReader, LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader,
RelocSectionReader, TableSectionReader, TypeSectionReader,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -167,6 +168,19 @@ impl<'a> Section<'a> {
} }
} }
pub fn get_producers_section_reader<'b>(&self) -> Result<ProducersSectionReader<'b>>
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<LinkingSectionReader<'b>> pub fn get_linking_section_reader<'b>(&self) -> Result<LinkingSectionReader<'b>>
where where
'a: 'b, '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<u32> {
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 where
'a: 'b, 'a: 'b,
{ {
@ -220,7 +241,7 @@ impl<'a> Section<'a> {
BinaryReader::new_with_offset(self.data, self.offset) BinaryReader::new_with_offset(self.data, self.offset)
} }
pub(crate) fn get_range(&self) -> Range { pub fn range(&self) -> Range {
Range { Range {
start: self.offset, start: self.offset,
end: self.offset + self.data.len(), end: self.offset + self.data.len(),

View file

@ -24,7 +24,7 @@ pub struct ModuleName<'a> {
} }
impl<'a> 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 where
'a: 'b, 'a: 'b,
{ {

View file

@ -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<ProducersFieldValue<'b>>
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<ProducersFieldValue<'a>>;
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<ProducersFieldValue<'a>>;
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
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<ProducersFieldValuesReader<'b>>
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::<Result<Vec<ProducersFieldValue>>>().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<ProducersSectionReader<'a>> {
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<ProducersField<'b>>
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<Self::Item> {
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<ProducersField<'a>>;
type IntoIter = SectionIteratorLimited<ProducersSectionReader<'a>>;
fn into_iter(self) -> Self::IntoIter {
SectionIteratorLimited::new(self)
}
}

View file

@ -18,7 +18,7 @@ use super::{BinaryReader, BinaryReaderError, Result};
pub(crate) fn read_sourcemappingurl_section_content<'a>( pub(crate) fn read_sourcemappingurl_section_content<'a>(
data: &'a [u8], data: &'a [u8],
offset: usize, offset: usize,
) -> Result<&'a [u8]> { ) -> Result<&'a str> {
let mut reader = BinaryReader::new_with_offset(data, offset); let mut reader = BinaryReader::new_with_offset(data, offset);
let url = reader.read_string()?; let url = reader.read_string()?;
if !reader.eof() { if !reader.eof() {

View file

@ -27,6 +27,8 @@ mod simple_tests {
operator_config: OperatorValidatorConfig { operator_config: OperatorValidatorConfig {
enable_threads: true, enable_threads: true,
enable_reference_types: true, enable_reference_types: true,
enable_simd: true,
enable_bulk_memory: true,
}, },
mutable_global_imports: true, mutable_global_imports: true,
}); });

View file

@ -29,7 +29,7 @@ use binary_reader::BinaryReader;
use primitives::{ use primitives::{
BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryImmediate, 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}; use parser::{Parser, ParserInput, ParserState, WasmDecoder};
@ -128,6 +128,7 @@ enum SectionOrderState {
Export, Export,
Start, Start,
Element, Element,
DataCount,
Code, Code,
Data, Data,
} }
@ -146,6 +147,7 @@ impl SectionOrderState {
SectionCode::Element => Some(SectionOrderState::Element), SectionCode::Element => Some(SectionOrderState::Element),
SectionCode::Code => Some(SectionOrderState::Code), SectionCode::Code => Some(SectionOrderState::Code),
SectionCode::Data => Some(SectionOrderState::Data), SectionCode::Data => Some(SectionOrderState::Data),
SectionCode::DataCount => Some(SectionOrderState::DataCount),
_ => None, _ => None,
} }
} }
@ -302,6 +304,8 @@ pub trait WasmModuleResources {
fn memories(&self) -> &[MemoryType]; fn memories(&self) -> &[MemoryType];
fn globals(&self) -> &[GlobalType]; fn globals(&self) -> &[GlobalType];
fn func_type_indices(&self) -> &[u32]; fn func_type_indices(&self) -> &[u32];
fn element_count(&self) -> u32;
fn data_count(&self) -> u32;
} }
type OperatorValidatorResult<T> = result::Result<T, &'static str>; type OperatorValidatorResult<T> = result::Result<T, &'static str>;
@ -310,11 +314,15 @@ type OperatorValidatorResult<T> = result::Result<T, &'static str>;
pub struct OperatorValidatorConfig { pub struct OperatorValidatorConfig {
pub enable_threads: bool, pub enable_threads: bool,
pub enable_reference_types: bool, pub enable_reference_types: bool,
pub enable_simd: bool,
pub enable_bulk_memory: bool,
} }
const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = OperatorValidatorConfig { const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = OperatorValidatorConfig {
enable_threads: false, enable_threads: false,
enable_reference_types: false, enable_reference_types: false,
enable_simd: false,
enable_bulk_memory: false,
}; };
struct OperatorValidator { struct OperatorValidator {
@ -453,7 +461,7 @@ impl OperatorValidator {
} }
let block = func_state.block_at(relative_depth as usize); let block = func_state.block_at(relative_depth as usize);
if block.jump_to_top { 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 Err("stack size does not match target loop type");
} }
return Ok(()); return Ok(());
@ -549,6 +557,20 @@ impl OperatorValidator {
Ok(()) 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( fn check_shared_memarg_wo_align(
&self, &self,
_: &MemoryImmediate, _: &MemoryImmediate,
@ -558,6 +580,13 @@ impl OperatorValidator {
Ok(()) 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<()> { fn check_block_type(&self, ty: Type) -> OperatorValidatorResult<()> {
match ty { match ty {
Type::EmptyBlockType | Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), Type::EmptyBlockType | Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
@ -1244,6 +1273,338 @@ impl OperatorValidator {
self.check_operands(func_state, &[Type::AnyRef])?; self.check_operands(func_state, &[Type::AnyRef])?;
OperatorAction::ChangeFrameWithType(0, Type::I32) 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<TableType>, tables: Vec<TableType>,
memories: Vec<MemoryType>, memories: Vec<MemoryType>,
globals: Vec<GlobalType>, globals: Vec<GlobalType>,
element_count: u32,
data_count: Option<u32>,
data_found: u32,
func_type_indices: Vec<u32>, func_type_indices: Vec<u32>,
current_func_index: u32, current_func_index: u32,
func_imports_count: u32, func_imports_count: u32,
init_expression_state: Option<InitExpressionState>, init_expression_state: Option<InitExpressionState>,
exported_names: HashSet<Vec<u8>>, exported_names: HashSet<String>,
current_operator_validator: Option<OperatorValidator>, current_operator_validator: Option<OperatorValidator>,
config: ValidatingParserConfig, config: ValidatingParserConfig,
} }
@ -1307,6 +1671,14 @@ impl<'a> WasmModuleResources for ValidatingParser<'a> {
fn func_type_indices(&self) -> &[u32] { fn func_type_indices(&self) -> &[u32] {
&self.func_type_indices &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> { impl<'a> ValidatingParser<'a> {
@ -1327,6 +1699,9 @@ impl<'a> ValidatingParser<'a> {
init_expression_state: None, init_expression_state: None,
exported_names: HashSet::new(), exported_names: HashSet::new(),
config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG), 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, ()> { fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
match ty { 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"), _ => self.create_error("invalid value type"),
} }
} }
@ -1413,14 +1778,7 @@ impl<'a> ValidatingParser<'a> {
self.check_value_type(global_type.content_type) self.check_value_type(global_type.content_type)
} }
fn check_import_entry( fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> {
&self,
module: &[u8],
field: &[u8],
import_type: &ImportSectionEntryType,
) -> ValidatorResult<'a, ()> {
self.check_utf8(module)?;
self.check_utf8(field)?;
match *import_type { match *import_type {
ImportSectionEntryType::Function(type_index) => { ImportSectionEntryType::Function(type_index) => {
if self.func_type_indices.len() >= MAX_WASM_FUNCTIONS { if self.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
@ -1481,12 +1839,11 @@ impl<'a> ValidatingParser<'a> {
fn check_export_entry( fn check_export_entry(
&self, &self,
field: &[u8], field: &str,
kind: ExternalKind, kind: ExternalKind,
index: u32, index: u32,
) -> ValidatorResult<'a, ()> { ) -> ValidatorResult<'a, ()> {
self.check_utf8(field)?; if self.exported_names.contains(field) {
if self.exported_names.contains(&Vec::from(field)) {
return self.create_error("non-unique export name"); return self.create_error("non-unique export name");
} }
match kind { match kind {
@ -1532,9 +1889,6 @@ impl<'a> ValidatingParser<'a> {
fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> { fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> {
let order_state = SectionOrderState::from_section_code(code); let order_state = SectionOrderState::from_section_code(code);
if let SectionCode::Custom { name, .. } = *code {
self.check_utf8(name)?;
}
Ok(match self.section_order_state { Ok(match self.section_order_state {
SectionOrderState::Initial => { SectionOrderState::Initial => {
if order_state.is_none() { if order_state.is_none() {
@ -1582,12 +1936,8 @@ impl<'a> ValidatingParser<'a> {
self.types.push(func_type.clone()); self.types.push(func_type.clone());
} }
} }
ParserState::ImportSectionEntry { ParserState::ImportSectionEntry { ref ty, .. } => {
module, let check = self.check_import_entry(ty);
field,
ref ty,
} => {
let check = self.check_import_entry(module, field, ty);
if check.is_err() { if check.is_err() {
self.validation_error = check.err(); self.validation_error = check.err();
} else { } else {
@ -1666,12 +2016,19 @@ impl<'a> ValidatingParser<'a> {
} }
ParserState::ExportSectionEntry { field, kind, index } => { ParserState::ExportSectionEntry { field, kind, index } => {
self.validation_error = self.check_export_entry(field, kind, index).err(); 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) => { ParserState::StartSectionEntry(func_index) => {
self.validation_error = self.check_start(func_index).err(); 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() { if table_index as usize >= self.tables.len() {
self.validation_error = self.validation_error =
self.create_validation_error("element section table index out of bounds"); 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_func_index += 1;
self.current_operator_validator = None; 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() { if memory_index as usize >= self.memories.len() {
self.validation_error = self.validation_error =
self.create_validation_error("data section memory index out of bounds"); 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",
);
}
}
}
_ => (), _ => (),
}; };
} }