зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5deee43687
Коммит
da79779db2
|
@ -22,9 +22,9 @@ git = "https://github.com/hsivonen/packed_simd"
|
|||
branch = "rust_1_32"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/CraneStation/target-lexicon"]
|
||||
git = "https://github.com/glandium/target-lexicon"
|
||||
branch = "thumbv7neon-v0.2"
|
||||
[source."https://github.com/CraneStation/Cranelift"]
|
||||
git = "https://github.com/CraneStation/Cranelift"
|
||||
rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
|
|
|
@ -168,11 +168,11 @@ name = "baldrdash"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)",
|
||||
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -568,62 +568,62 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
dependencies = [
|
||||
"cranelift-bforest 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen-meta 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)",
|
||||
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)",
|
||||
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee#542d799dd7a3b2cc15b91eefdcd85cace8fe5cee"
|
||||
dependencies = [
|
||||
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2778,8 +2778,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2#b2d4b34509abb3e12b1c93d19b8593d02ddeed76"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3203,7 +3203,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.23.0"
|
||||
version = "0.29.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -3495,12 +3495,12 @@ dependencies = [
|
|||
"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
|
||||
"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
|
||||
"checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
|
||||
"checksum cranelift-bforest 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a3a25dfe4a54449df63d592f2f6346a80350ac835d4be4bacb73c20b034ef763"
|
||||
"checksum cranelift-codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c3b15a20577e6c823475953a5e25e758d9d3a3148a937d686c09460e5f2f4a0"
|
||||
"checksum cranelift-codegen-meta 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e60ce3551e8172c966fbc6d9bfb90111d5d1cf37306c37dd7527467afe317d1"
|
||||
"checksum cranelift-entity 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e124e09cb7dc85fbe2162420aebbe8e9e3b8f9210901be7867416c5beec8226"
|
||||
"checksum cranelift-frontend 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2833c6e1a93c524ce0c2ab31266cdc84d38c906349f79f19378a5e5995727b23"
|
||||
"checksum cranelift-wasm 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e75efb45cd8d8700b4bdc225f0077bc7c615f84a5807ce001d59b4da48d85573"
|
||||
"checksum cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
|
||||
"checksum cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
|
||||
"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
|
||||
"checksum cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
|
||||
"checksum cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=542d799dd7a3b2cc15b91eefdcd85cace8fe5cee)" = "<none>"
|
||||
"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 crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
|
||||
"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
|
||||
|
@ -3691,7 +3691,7 @@ dependencies = [
|
|||
"checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d"
|
||||
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
|
||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||
"checksum target-lexicon 0.2.0 (git+https://github.com/glandium/target-lexicon?branch=thumbv7neon-v0.2)" = "<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 term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
|
@ -3736,7 +3736,7 @@ dependencies = [
|
|||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
|
||||
"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
|
||||
"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060"
|
||||
"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00"
|
||||
"checksum webidl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f807f7488d680893f7188aa09d7672a3a0a8461975a098a2edf0a52e3fee29"
|
||||
"checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
|
|
@ -61,4 +61,5 @@ libudev-sys = { path = "dom/webauthn/libudev-sys" }
|
|||
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" }
|
||||
winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
|
||||
packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
|
||||
target-lexicon = { git = "https://github.com/glandium/target-lexicon", branch = "thumbv7neon-v0.2" }
|
||||
cranelift-codegen = { git = "https://github.com/CraneStation/Cranelift", rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" }
|
||||
cranelift-wasm = { git = "https://github.com/CraneStation/Cranelift", rev = "542d799dd7a3b2cc15b91eefdcd85cace8fe5cee" }
|
||||
|
|
|
@ -8,9 +8,16 @@ crate-type = ["rlib"]
|
|||
name = "baldrdash"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = { version = "0.29.0", default-features = false }
|
||||
cranelift-wasm = "0.29.0"
|
||||
target-lexicon = "0.2.0"
|
||||
# The build system redirects the versions of cranelift-codegen and
|
||||
# cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
|
||||
# you should update the following files:
|
||||
# - $TOP_LEVEL/Cargo.toml, look for the revision (rev) hashes of both cranelift
|
||||
# dependencies (codegen and wasm).
|
||||
# - $TOP_LEVEL/.cargo/config.in, look for the revision (rev) field of the
|
||||
# Cranelift source.
|
||||
cranelift-codegen = { version = "0.30", default-features = false }
|
||||
cranelift-wasm = "0.30"
|
||||
target-lexicon = "0.4.0"
|
||||
log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] }
|
||||
env_logger = "0.5.6"
|
||||
|
||||
|
|
|
@ -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}
|
|
@ -1,37 +1,24 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-bforest"
|
||||
version = "0.29.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.30.0"
|
||||
description = "A forest of B+-trees"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
keywords = ["btree", "forest", "set", "map"]
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
|
||||
|
||||
[features]
|
||||
core = []
|
||||
default = ["std"]
|
||||
std = ["cranelift-entity/std"]
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
core = []
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
|
|
@ -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}
|
|
@ -1,28 +1,22 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.29.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
version = "0.30.0"
|
||||
description = "Metaprogram for cranelift-codegen code generator library"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.29.0"
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[dependencies]
|
||||
cranelift-entity = { path = "../../cranelift-entity", version = "0.30.0", default-features = false }
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["cranelift-entity/std"]
|
||||
# The "core" feature enables a workaround for Cargo #4866.
|
||||
core = ["cranelift-entity/core"]
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -1,16 +1,24 @@
|
|||
use super::regs::IsaRegs;
|
||||
use super::settings::SettingGroup;
|
||||
use crate::cdsl::inst::InstructionGroup;
|
||||
use crate::cdsl::regs::IsaRegs;
|
||||
use crate::cdsl::settings::SettingGroup;
|
||||
|
||||
pub struct TargetIsa {
|
||||
pub name: &'static str,
|
||||
pub instructions: InstructionGroup,
|
||||
pub settings: SettingGroup,
|
||||
pub regs: IsaRegs,
|
||||
}
|
||||
|
||||
impl TargetIsa {
|
||||
pub fn new(name: &'static str, settings: SettingGroup, regs: IsaRegs) -> Self {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
instructions: InstructionGroup,
|
||||
settings: SettingGroup,
|
||||
regs: IsaRegs,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
instructions,
|
||||
settings,
|
||||
regs,
|
||||
}
|
||||
|
|
|
@ -3,10 +3,15 @@
|
|||
//! This module defines the classes that are used to define Cranelift
|
||||
//! instructions and other entities.
|
||||
|
||||
pub mod formats;
|
||||
pub mod inst;
|
||||
pub mod isa;
|
||||
pub mod operands;
|
||||
pub mod regs;
|
||||
pub mod settings;
|
||||
pub mod type_inference;
|
||||
pub mod types;
|
||||
pub mod typevar;
|
||||
|
||||
/// A macro that converts boolean settings into predicates to look more natural.
|
||||
#[macro_export]
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
use crate::cdsl::typevar::TypeVar;
|
||||
|
||||
pub enum Constraint {
|
||||
WiderOrEq(TypeVar, TypeVar),
|
||||
}
|
|
@ -21,13 +21,13 @@ static LANE_BASE: u8 = 0x70;
|
|||
// Rust name prefix used for the `rust_name` method.
|
||||
static _RUST_NAME_PREFIX: &'static str = "ir::types::";
|
||||
|
||||
// ValueType variants (i8, i32, ...) are provided in `base::types.rs`.
|
||||
// ValueType variants (i8, i32, ...) are provided in `shared::types.rs`.
|
||||
|
||||
/// A concrete SSA value type.
|
||||
///
|
||||
/// All SSA values have a type that is described by an instance of `ValueType`
|
||||
/// or one of its subclasses.
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueType {
|
||||
BV(BVType),
|
||||
Lane(LaneType),
|
||||
|
@ -90,7 +90,7 @@ impl ValueType {
|
|||
}
|
||||
|
||||
/// Return the name of this type for generated Rust source files.
|
||||
pub fn _rust_name(&self) -> String {
|
||||
pub fn rust_name(&self) -> String {
|
||||
format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase())
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ impl From<VectorType> for ValueType {
|
|||
}
|
||||
|
||||
/// A concrete scalar type that can appear as a vector lane too.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum LaneType {
|
||||
BoolType(shared_types::Bool),
|
||||
FloatType(shared_types::Float),
|
||||
|
@ -205,6 +205,43 @@ impl LaneType {
|
|||
LaneType::FloatType(shared_types::Float::F64) => 10,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool_from_bits(num_bits: u16) -> LaneType {
|
||||
LaneType::BoolType(match num_bits {
|
||||
1 => shared_types::Bool::B1,
|
||||
8 => shared_types::Bool::B8,
|
||||
16 => shared_types::Bool::B16,
|
||||
32 => shared_types::Bool::B32,
|
||||
64 => shared_types::Bool::B64,
|
||||
_ => unreachable!("unxpected num bits for bool"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn int_from_bits(num_bits: u16) -> LaneType {
|
||||
LaneType::IntType(match num_bits {
|
||||
8 => shared_types::Int::I8,
|
||||
16 => shared_types::Int::I16,
|
||||
32 => shared_types::Int::I32,
|
||||
64 => shared_types::Int::I64,
|
||||
_ => unreachable!("unxpected num bits for int"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn float_from_bits(num_bits: u16) -> LaneType {
|
||||
LaneType::FloatType(match num_bits {
|
||||
32 => shared_types::Float::F32,
|
||||
64 => shared_types::Float::F64,
|
||||
_ => unreachable!("unxpected num bits for float"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn by(&self, lanes: u16) -> ValueType {
|
||||
if lanes == 1 {
|
||||
(*self).into()
|
||||
} else {
|
||||
ValueType::Vector(VectorType::new(*self, lanes.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LaneType {
|
||||
|
@ -290,6 +327,7 @@ impl Iterator for LaneTypeIterator {
|
|||
///
|
||||
/// A vector type has a lane type which is an instance of `LaneType`,
|
||||
/// and a positive number of lanes.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct VectorType {
|
||||
base: LaneType,
|
||||
lanes: u64,
|
||||
|
@ -320,6 +358,11 @@ impl VectorType {
|
|||
self.lanes
|
||||
}
|
||||
|
||||
/// Return the lane type.
|
||||
pub fn lane_type(&self) -> LaneType {
|
||||
self.base
|
||||
}
|
||||
|
||||
/// Find the unique number associated with this vector type.
|
||||
///
|
||||
/// Vector types are encoded with the lane type in the low 4 bits and
|
||||
|
@ -350,14 +393,15 @@ impl fmt::Debug for VectorType {
|
|||
}
|
||||
|
||||
/// A flat bitvector type. Used for semantics description only.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct BVType {
|
||||
bits: u64,
|
||||
}
|
||||
|
||||
impl BVType {
|
||||
/// Initialize a new bitvector type with `n` bits.
|
||||
pub fn _new(bits: u64) -> Self {
|
||||
Self { bits }
|
||||
pub fn new(bits: u16) -> Self {
|
||||
Self { bits: bits.into() }
|
||||
}
|
||||
|
||||
/// Return a string containing the documentation comment for this bitvector type.
|
||||
|
@ -386,7 +430,7 @@ impl fmt::Debug for BVType {
|
|||
/// A concrete scalar type that is neither a vector nor a lane type.
|
||||
///
|
||||
/// Special types cannot be used to form vectors.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum SpecialType {
|
||||
Flag(shared_types::Flag),
|
||||
}
|
||||
|
|
|
@ -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 = ©.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());
|
||||
}
|
|
@ -132,9 +132,9 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
|
|||
fmtln!(fmt, "}");
|
||||
}
|
||||
|
||||
pub fn generate(isa: &TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
pub fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
let mut fmt = Formatter::new();
|
||||
gen_isa(&isa, &mut fmt);
|
||||
fmt.update_file(format!("{}-{}.rs", base_filename, isa.name), out_dir)?;
|
||||
fmt.update_file(filename, out_dir)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
use crate::cdsl::camel_case;
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::settings::{
|
||||
BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
|
||||
};
|
||||
use crate::constant_hash::{generate_table, simple_hash};
|
||||
use crate::error;
|
||||
use crate::shared;
|
||||
use crate::srcgen::{Formatter, Match};
|
||||
use crate::unique_table::UniqueTable;
|
||||
use crate::unique_table::UniqueSeqTable;
|
||||
use std::collections::HashMap;
|
||||
|
||||
enum ParentGroup {
|
||||
pub enum ParentGroup {
|
||||
None,
|
||||
Shared,
|
||||
}
|
||||
|
@ -152,13 +150,9 @@ fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
|
|||
fmt.indent(|fmt| {
|
||||
let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
|
||||
for (i, v) in values.iter().enumerate() {
|
||||
m.arm(
|
||||
format!("{}", i),
|
||||
vec![],
|
||||
format!("{}::{}", ty, camel_case(v)),
|
||||
);
|
||||
m.arm_no_fields(format!("{}", i), format!("{}::{}", ty, camel_case(v)));
|
||||
}
|
||||
m.arm("_", vec![], "panic!(\"Invalid enum value\")");
|
||||
m.arm_no_fields("_", "panic!(\"Invalid enum value\")");
|
||||
fmt.add_match(m);
|
||||
});
|
||||
fmtln!(fmt, "}");
|
||||
|
@ -191,12 +185,12 @@ fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
|
|||
fmt.doc_comment("Get a view of the boolean predicates.");
|
||||
fmtln!(
|
||||
fmt,
|
||||
"pub fn predicate_view(&self) -> ::settings::PredicateView {"
|
||||
"pub fn predicate_view(&self) -> crate::settings::PredicateView {"
|
||||
);
|
||||
fmt.indent(|fmt| {
|
||||
fmtln!(
|
||||
fmt,
|
||||
"::settings::PredicateView::new(&self.bytes[{}..])",
|
||||
"crate::settings::PredicateView::new(&self.bytes[{}..])",
|
||||
group.bool_start_byte_offset
|
||||
);
|
||||
});
|
||||
|
@ -242,7 +236,7 @@ impl<'a> SettingOrPreset<'a> {
|
|||
|
||||
/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.
|
||||
fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
let mut enum_table: UniqueTable<&'static str> = UniqueTable::new();
|
||||
let mut enum_table = UniqueSeqTable::new();
|
||||
|
||||
let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
|
||||
|
||||
|
@ -445,17 +439,14 @@ fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
|
|||
gen_display(group, fmt);
|
||||
}
|
||||
|
||||
pub fn generate_common(filename: &str, out_dir: &str) -> Result<SettingGroup, error::Error> {
|
||||
let settings = shared::settings::generate();
|
||||
pub fn generate(
|
||||
settings: &SettingGroup,
|
||||
parent_group: ParentGroup,
|
||||
filename: &str,
|
||||
out_dir: &str,
|
||||
) -> Result<(), error::Error> {
|
||||
let mut fmt = Formatter::new();
|
||||
gen_group(&settings, ParentGroup::None, &mut fmt);
|
||||
gen_group(&settings, parent_group, &mut fmt);
|
||||
fmt.update_file(filename, out_dir)?;
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
pub fn generate(isa: &TargetIsa, prefix: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
let mut fmt = Formatter::new();
|
||||
gen_group(&isa.settings, ParentGroup::Shared, &mut fmt);
|
||||
fmt.update_file(format!("{}-{}.rs", prefix, isa.name), out_dir)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::cdsl::inst::InstructionGroup;
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
|
||||
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let setting = SettingGroupBuilder::new("arm32");
|
||||
|
@ -44,8 +46,11 @@ fn define_regs() -> IsaRegs {
|
|||
regs.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let settings = define_settings(shared_settings);
|
||||
pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
let settings = define_settings(&shared_defs.settings);
|
||||
let regs = define_regs();
|
||||
TargetIsa::new("arm32", settings, regs)
|
||||
|
||||
let inst_group = InstructionGroup::new("arm32", "arm32 specific instruction set");
|
||||
|
||||
TargetIsa::new("arm32", inst_group, settings, regs)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::cdsl::inst::InstructionGroup;
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
|
||||
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let setting = SettingGroupBuilder::new("arm64");
|
||||
|
@ -40,8 +42,11 @@ fn define_registers() -> IsaRegs {
|
|||
regs.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let settings = define_settings(shared_settings);
|
||||
pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
let settings = define_settings(&shared_defs.settings);
|
||||
let regs = define_registers();
|
||||
TargetIsa::new("arm64", settings, regs)
|
||||
|
||||
let inst_group = InstructionGroup::new("arm64", "arm64 specific instruction set");
|
||||
|
||||
TargetIsa::new("arm64", inst_group, settings, regs)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::settings::SettingGroup;
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
use std::fmt;
|
||||
|
||||
mod arm32;
|
||||
|
@ -55,13 +55,13 @@ impl fmt::Display for Isa {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn define(isas: &Vec<Isa>, shared_settings: &SettingGroup) -> Vec<TargetIsa> {
|
||||
pub fn define(isas: &Vec<Isa>, shared_defs: &mut SharedDefinitions) -> Vec<TargetIsa> {
|
||||
isas.iter()
|
||||
.map(|isa| match isa {
|
||||
Isa::Riscv => riscv::define(shared_settings),
|
||||
Isa::X86 => x86::define(shared_settings),
|
||||
Isa::Arm32 => arm32::define(shared_settings),
|
||||
Isa::Arm64 => arm64::define(shared_settings),
|
||||
Isa::Riscv => riscv::define(shared_defs),
|
||||
Isa::X86 => x86::define(shared_defs),
|
||||
Isa::Arm32 => arm32::define(shared_defs),
|
||||
Isa::Arm64 => arm64::define(shared_defs),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::cdsl::inst::InstructionGroup;
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
|
||||
use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
fn define_settings(shared: &SettingGroup) -> SettingGroup {
|
||||
let mut setting = SettingGroupBuilder::new("riscv");
|
||||
|
@ -76,8 +78,11 @@ fn define_registers() -> IsaRegs {
|
|||
regs.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let settings = define_settings(shared_settings);
|
||||
pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
let settings = define_settings(&shared_defs.settings);
|
||||
let regs = define_registers();
|
||||
TargetIsa::new("riscv", settings, regs)
|
||||
|
||||
let inst_group = InstructionGroup::new("riscv", "riscv specific instruction set");
|
||||
|
||||
TargetIsa::new("riscv", inst_group, settings, regs)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
mod instructions;
|
||||
|
||||
use crate::cdsl::isa::TargetIsa;
|
||||
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
|
||||
use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let mut settings = SettingGroupBuilder::new("x86");
|
||||
|
||||
|
@ -109,8 +113,11 @@ fn define_registers() -> IsaRegs {
|
|||
regs.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let settings = define_settings(shared_settings);
|
||||
pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
||||
let settings = define_settings(&shared_defs.settings);
|
||||
let regs = define_registers();
|
||||
TargetIsa::new("x86", settings, regs)
|
||||
|
||||
let inst_group = instructions::define(&shared_defs.format_registry);
|
||||
|
||||
TargetIsa::new("x86", inst_group, settings, regs)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error> {
|
||||
// Common definitions.
|
||||
let shared_settings = gen_settings::generate_common("new_settings.rs", &out_dir)?;
|
||||
let mut shared_defs = shared::define();
|
||||
|
||||
gen_settings::generate(
|
||||
&shared_defs.settings,
|
||||
gen_settings::ParentGroup::None,
|
||||
"new_settings.rs",
|
||||
&out_dir,
|
||||
)?;
|
||||
gen_types::generate("types.rs", &out_dir)?;
|
||||
|
||||
// Per ISA definitions.
|
||||
let isas = isa::define(isas, &shared_settings);
|
||||
let isas = isa::define(isas, &mut shared_defs);
|
||||
|
||||
for isa in isas {
|
||||
gen_registers::generate(&isa, "registers", &out_dir)?;
|
||||
gen_settings::generate(&isa, "new_settings", &out_dir)?;
|
||||
gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
|
||||
gen_settings::generate(
|
||||
&isa.settings,
|
||||
gen_settings::ParentGroup::Shared,
|
||||
&format!("new_settings-{}", isa.name),
|
||||
&out_dir,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,59 @@
|
|||
//! Shared definitions for the Cranelift intermediate language.
|
||||
|
||||
pub mod entities;
|
||||
pub mod formats;
|
||||
pub mod immediates;
|
||||
pub mod instructions;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::inst::InstructionGroup;
|
||||
use crate::cdsl::operands::OperandKind;
|
||||
use crate::cdsl::settings::SettingGroup;
|
||||
|
||||
pub struct Definitions {
|
||||
pub settings: SettingGroup,
|
||||
pub instructions: InstructionGroup,
|
||||
pub operand_kinds: OperandKinds,
|
||||
pub format_registry: FormatRegistry,
|
||||
}
|
||||
|
||||
pub struct OperandKinds(Vec<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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn generate() -> SettingGroup {
|
||||
pub fn define() -> SettingGroup {
|
||||
let mut settings = SettingGroupBuilder::new("shared");
|
||||
|
||||
settings.add_enum(
|
||||
|
|
|
@ -113,7 +113,7 @@ impl Iterator for FloatIterator {
|
|||
/// A type representing CPU flags.
|
||||
///
|
||||
/// Flags can't be stored in memory.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum Flag {
|
||||
/// CPU flags from an integer comparison.
|
||||
IFlags,
|
||||
|
|
|
@ -25,6 +25,14 @@ macro_rules! fmtln {
|
|||
($fmt:ident, $arg:expr) => {
|
||||
$fmt.line($arg);
|
||||
};
|
||||
|
||||
($_:tt, $($args:expr),+) => {
|
||||
compile_error!("This macro requires at least two arguments: the Formatter instance and a format string.");
|
||||
};
|
||||
|
||||
($_:tt) => {
|
||||
compile_error!("This macro requires at least two arguments: the Formatter instance and a format string.");
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Formatter {
|
||||
|
@ -84,6 +92,11 @@ impl Formatter {
|
|||
self.lines.push(indented_line);
|
||||
}
|
||||
|
||||
/// Pushes an empty line.
|
||||
pub fn empty_line(&mut self) {
|
||||
self.lines.push("\n".to_string());
|
||||
}
|
||||
|
||||
/// Emit a line outdented one level.
|
||||
pub fn _outdented_line(&mut self, s: &str) {
|
||||
let new_line = format!("{}{}", self._get_outdent(), s);
|
||||
|
@ -112,7 +125,7 @@ impl Formatter {
|
|||
}
|
||||
|
||||
/// Add one or more lines after stripping common indentation.
|
||||
pub fn _multi_line(&mut self, s: &str) {
|
||||
pub fn multi_line(&mut self, s: &str) {
|
||||
parse_multiline(s).into_iter().for_each(|l| self.line(&l));
|
||||
}
|
||||
|
||||
|
@ -141,7 +154,7 @@ impl Formatter {
|
|||
self.indent(|fmt| {
|
||||
for (&(ref fields, ref body), ref names) in m.arms.iter() {
|
||||
// name { fields } | name { fields } => { body }
|
||||
let conditions: Vec<String> = names
|
||||
let conditions = names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
if fields.len() > 0 {
|
||||
|
@ -150,9 +163,20 @@ impl Formatter {
|
|||
name.clone()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let lhs = conditions.join(" | ");
|
||||
fmtln!(fmt, "{} => {{", lhs);
|
||||
.collect::<Vec<_>>()
|
||||
.join(" |\n")
|
||||
+ " => {";
|
||||
|
||||
fmt.multi_line(&conditions);
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(body);
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
// Make sure to include the catch all clause last.
|
||||
if let Some(body) = m.catch_all {
|
||||
fmt.line("_ => {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(body);
|
||||
});
|
||||
|
@ -239,27 +263,57 @@ fn parse_multiline(s: &str) -> Vec<String> {
|
|||
pub struct Match {
|
||||
expr: String,
|
||||
arms: BTreeMap<(Vec<String>, String), BTreeSet<String>>,
|
||||
/// The clause for the placeholder pattern _.
|
||||
catch_all: Option<String>,
|
||||
}
|
||||
|
||||
impl Match {
|
||||
/// 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 {
|
||||
expr: expr.into(),
|
||||
arms: BTreeMap::new(),
|
||||
catch_all: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an arm to the Match statement.
|
||||
pub fn arm<T: Into<String>>(&mut self, name: T, fields: Vec<T>, body: T) {
|
||||
// let key = (fields, body);
|
||||
fn set_catch_all(&mut self, clause: String) {
|
||||
assert!(self.catch_all.is_none());
|
||||
self.catch_all = Some(clause);
|
||||
}
|
||||
|
||||
/// Add an arm that reads fields to the Match statement.
|
||||
pub fn arm<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 fields = fields.into_iter().map(|x| x.into()).collect();
|
||||
let match_arm = self
|
||||
.arms
|
||||
.entry((fields, body))
|
||||
.or_insert_with(BTreeSet::new);
|
||||
match_arm.insert(name.into());
|
||||
match_arm.insert(name);
|
||||
}
|
||||
|
||||
/// Adds an arm that doesn't read anythings from the fields to the Match statement.
|
||||
pub fn arm_no_fields(&mut self, name: impl Into<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 } => {
|
||||
different body
|
||||
}
|
||||
Orange { a, b } | Yellow { a, b } => {
|
||||
Orange { a, b } |
|
||||
Yellow { a, b } => {
|
||||
some body
|
||||
}
|
||||
Blue { x, y } => {
|
||||
|
@ -308,6 +363,36 @@ match x {
|
|||
assert_eq!(fmt.lines, expected_lines);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_with_catchall_order() {
|
||||
// The catchall placeholder must be placed after other clauses.
|
||||
let mut m = Match::new("x");
|
||||
m.arm("Orange", vec!["a", "b"], "some body");
|
||||
m.arm("Green", vec!["a", "b"], "different body");
|
||||
m.arm_no_fields("_", "unreachable!()");
|
||||
assert_eq!(m.arms.len(), 2); // catchall is not counted
|
||||
|
||||
let mut fmt = Formatter::new();
|
||||
fmt.add_match(m);
|
||||
|
||||
let expected_lines = from_raw_string(
|
||||
r#"
|
||||
match x {
|
||||
Green { a, b } => {
|
||||
different body
|
||||
}
|
||||
Orange { a, b } => {
|
||||
some body
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(fmt.lines, expected_lines);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_multiline_works() {
|
||||
let input = "\n hello\n world\n";
|
||||
|
|
|
@ -1,21 +1,76 @@
|
|||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::slice;
|
||||
|
||||
/// Collect items into the `table` list, removing duplicates.
|
||||
pub struct UniqueTable<'entries, T: Eq + Hash> {
|
||||
table: Vec<&'entries T>,
|
||||
map: HashMap<&'entries T, usize>,
|
||||
}
|
||||
|
||||
impl<'entries, T: Eq + Hash> UniqueTable<'entries, T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
table: Vec::new(),
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, entry: &'entries T) -> usize {
|
||||
match self.map.get(&entry) {
|
||||
None => {
|
||||
let i = self.table.len();
|
||||
self.table.push(entry);
|
||||
self.map.insert(entry, i);
|
||||
i
|
||||
}
|
||||
Some(&i) => i,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.table.len()
|
||||
}
|
||||
pub fn iter(&self) -> slice::Iter<&'entries T> {
|
||||
self.table.iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// A table of sequences which tries to avoid common subsequences.
|
||||
pub struct UniqueTable<T: PartialEq + Clone> {
|
||||
pub struct UniqueSeqTable<T: PartialEq + Clone> {
|
||||
table: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Clone> UniqueTable<T> {
|
||||
impl<T: PartialEq + Clone> UniqueSeqTable<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { table: Vec::new() }
|
||||
}
|
||||
pub fn add(&mut self, values: &Vec<T>) -> usize {
|
||||
if values.len() == 0 {
|
||||
return 0;
|
||||
}
|
||||
if let Some(offset) = find_subsequence(values, &self.table) {
|
||||
offset
|
||||
} else {
|
||||
let offset = self.table.len();
|
||||
self.table.extend((*values).clone());
|
||||
offset
|
||||
let table_len = self.table.len();
|
||||
|
||||
// Try to put in common the last elements of the table if they're a prefix of the new
|
||||
// sequence.
|
||||
//
|
||||
// We know there wasn't a full match, so the best prefix we can hope to find contains
|
||||
// all the values but the last one.
|
||||
let mut start_from = usize::min(table_len, values.len() - 1);
|
||||
while start_from != 0 {
|
||||
// Loop invariant: start_from <= table_len, so table_len - start_from >= 0.
|
||||
if values[0..start_from] == self.table[table_len - start_from..table_len] {
|
||||
break;
|
||||
}
|
||||
start_from -= 1;
|
||||
}
|
||||
|
||||
self.table
|
||||
.extend(values[start_from..values.len()].iter().cloned());
|
||||
table_len - start_from
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -35,17 +90,10 @@ fn find_subsequence<T: PartialEq>(sub: &Vec<T>, whole: &Vec<T>) -> Option<usize>
|
|||
if whole.len() < sub.len() {
|
||||
return None;
|
||||
}
|
||||
let max = whole.len() + 1 - sub.len();
|
||||
for i in 0..max {
|
||||
let mut found: Option<usize> = Some(i);
|
||||
for j in 0..sub.len() {
|
||||
if sub[j] != whole[i + j] {
|
||||
found = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if found.is_some() {
|
||||
return found;
|
||||
let max = whole.len() - sub.len();
|
||||
for i in 0..max + 1 {
|
||||
if whole[i..i + sub.len()] == sub[..] {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
|
@ -66,3 +114,24 @@ fn test_find_subsequence() {
|
|||
Some(1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_optimal_add() {
|
||||
let mut seq_table = UniqueSeqTable::new();
|
||||
// [0, 1, 2, 3]
|
||||
assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0);
|
||||
assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0);
|
||||
assert_eq!(seq_table.add(&vec![1, 2, 3]), 1);
|
||||
assert_eq!(seq_table.add(&vec![2, 3]), 2);
|
||||
assert_eq!(seq_table.len(), 4);
|
||||
// [0, 1, 2, 3, 4]
|
||||
assert_eq!(seq_table.add(&vec![2, 3, 4]), 2);
|
||||
assert_eq!(seq_table.len(), 5);
|
||||
// [0, 1, 2, 3, 4, 6, 5, 7]
|
||||
assert_eq!(seq_table.add(&vec![4, 6, 5, 7]), 4);
|
||||
assert_eq!(seq_table.len(), 8);
|
||||
// [0, 1, 2, 3, 4, 6, 5, 7, 8, 2, 3, 4]
|
||||
assert_eq!(seq_table.add(&vec![8, 2, 3, 4]), 8);
|
||||
assert_eq!(seq_table.add(&vec![8]), 8);
|
||||
assert_eq!(seq_table.len(), 12);
|
||||
}
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,70 +1,63 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-codegen"
|
||||
version = "0.29.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
build = "build.rs"
|
||||
name = "cranelift-codegen"
|
||||
version = "0.30.0"
|
||||
description = "Low-level code generator library"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
keywords = ["compile", "compiler", "jit"]
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-bforest]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
[dependencies]
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
|
||||
cranelift-bforest = { path = "../cranelift-bforest", version = "0.30.0", default-features = false }
|
||||
failure = { version = "0.1.1", default-features = false, features = ["derive"] }
|
||||
failure_derive = { version = "0.1.1", default-features = false }
|
||||
hashmap_core = { version = "0.1.9", optional = true }
|
||||
target-lexicon = { version = "0.4.0", default-features = false }
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
|
||||
# Please don't add any unless they are essential to the task of creating binary
|
||||
# machine code. Integration tests that need external dependencies can be
|
||||
# accomodated in `tests`.
|
||||
|
||||
[dependencies.failure]
|
||||
version = "0.1.1"
|
||||
features = ["derive"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.failure_derive]
|
||||
version = "0.1.1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.hashmap_core]
|
||||
version = "0.1.9"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.6"
|
||||
default-features = false
|
||||
|
||||
[dependencies.target-lexicon]
|
||||
version = "0.2.0"
|
||||
default-features = false
|
||||
[build-dependencies.cranelift-codegen-meta]
|
||||
version = "0.29.0"
|
||||
[build-dependencies]
|
||||
cranelift-codegen-meta = { path = "meta", version = "0.30.0", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std", "x86", "arm32", "arm64", "riscv"]
|
||||
|
||||
# The "std" feature enables use of libstd. The "core" feature enables use
|
||||
# of some minimal std-like replacement libraries. At least one of these two
|
||||
# features need to be enabled.
|
||||
std = [
|
||||
"cranelift-entity/std",
|
||||
"cranelift-bforest/std",
|
||||
"target-lexicon/std",
|
||||
"cranelift-codegen-meta/std"
|
||||
]
|
||||
|
||||
# The "core" features enables use of "hashmap_core" since core doesn't have
|
||||
# a HashMap implementation, and a workaround for Cargo #4866.
|
||||
core = [
|
||||
"hashmap_core",
|
||||
"cranelift-codegen-meta/core"
|
||||
]
|
||||
|
||||
# This enables some additional functions useful for writing tests, but which
|
||||
# can significantly increase the size of the library.
|
||||
testing_hooks = []
|
||||
|
||||
# ISA targets for which we should build.
|
||||
x86 = []
|
||||
arm32 = []
|
||||
arm64 = []
|
||||
core = ["hashmap_core"]
|
||||
default = ["std", "x86", "arm32", "arm64", "riscv"]
|
||||
riscv = []
|
||||
std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"]
|
||||
testing_hooks = []
|
||||
x86 = []
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
|
|
@ -19,7 +19,7 @@ stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
|
|||
#: A reference to a global value.
|
||||
global_value = EntityRefKind('global_value', 'A global value.')
|
||||
|
||||
#: A reference to a function sugnature declared in the function preamble.
|
||||
#: A reference to a function signature declared in the function preamble.
|
||||
#: This is used to provide the call signature in a call_indirect instruction.
|
||||
sig_ref = EntityRefKind('sig_ref', 'A function signature.')
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ class Instruction(object):
|
|||
for opnum in self.value_opnums:
|
||||
typ = self.ins[opnum].typevar
|
||||
tv = typ.free_typevar()
|
||||
# Non-polymorphic or derived form ctrl_typevar is OK.
|
||||
# Non-polymorphic or derived from ctrl_typevar is OK.
|
||||
if tv is None or tv is ctrl_typevar:
|
||||
continue
|
||||
# No other derived typevars allowed.
|
||||
|
|
|
@ -364,7 +364,7 @@ def gen_opcodes(groups, fmt):
|
|||
# We explicitly set the discriminant of the first variant to 1, which
|
||||
# allows us to take advantage of the NonZero optimization, meaning that
|
||||
# wrapping enums can use the 0 discriminant instead of increasing the size
|
||||
# if the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
|
||||
# of the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
|
||||
is_first_opcode = True
|
||||
with fmt.indented('pub enum Opcode {', '}'):
|
||||
for g in groups:
|
||||
|
@ -505,7 +505,7 @@ def gen_type_constraints(fmt, instrs):
|
|||
# Table of operand constraint sequences (as tuples). Each operand
|
||||
# constraint is represented as a string, one of:
|
||||
# - `Concrete(vt)`, where `vt` is a value type name.
|
||||
# - `Free(idx)` where `idx` isan index into `type_sets`.
|
||||
# - `Free(idx)` where `idx` is an index into `type_sets`.
|
||||
# - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints.
|
||||
operand_seqs = UniqueSeqTable()
|
||||
|
||||
|
|
|
@ -631,7 +631,7 @@ X86_64.enc(base.uextend.i32.i16, *r.urm_noflags(0x0f, 0xb7))
|
|||
|
||||
# movzbq, encoded as movzbl because it's equivalent and shorter
|
||||
X86_64.enc(base.uextend.i64.i8, *r.urm_noflags.rex(0x0f, 0xb6))
|
||||
X86_64.enc(base.uextend.i64.i8, *r.urm_noflags(0x0f, 0xb6))
|
||||
X86_64.enc(base.uextend.i64.i8, *r.urm_noflags_abcd(0x0f, 0xb6))
|
||||
|
||||
# movzwq, encoded as movzwl because it's equivalent and shorter
|
||||
X86_64.enc(base.uextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xb7))
|
||||
|
|
|
@ -62,6 +62,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
|
|||
divert.clear();
|
||||
cur.func.offsets[ebb] = offset;
|
||||
while let Some(inst) = cur.next_inst() {
|
||||
divert.apply(&cur.func.dfg[inst]);
|
||||
let enc = cur.func.encodings[inst];
|
||||
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.
|
||||
if cur.func.offsets[ebb] != offset {
|
||||
debug_assert!(
|
||||
cur.func.offsets[ebb] < offset,
|
||||
"Code shrinking during relaxation"
|
||||
);
|
||||
cur.func.offsets[ebb] = offset;
|
||||
go_again = true;
|
||||
}
|
||||
|
@ -173,12 +170,12 @@ fn relax_branch(
|
|||
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 ctrl_type = dfg.ctrl_typevar(inst);
|
||||
if let Some(enc) = isa
|
||||
.legal_encodings(cur.func, &dfg[inst], ctrl_type)
|
||||
.find(|&enc| {
|
||||
.filter(|&enc| {
|
||||
let range = encinfo.branch_range(enc).expect("Branch with no range");
|
||||
if !range.contains(offset, dest_offset) {
|
||||
debug!(" trying [{}]: out of range", encinfo.display(enc));
|
||||
|
@ -198,7 +195,9 @@ fn relax_branch(
|
|||
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;
|
||||
return encinfo.byte_size(enc, inst, &divert, &cur.func);
|
||||
}
|
||||
|
|
|
@ -91,18 +91,21 @@ impl Context {
|
|||
///
|
||||
/// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
|
||||
/// 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(
|
||||
&mut self,
|
||||
isa: &TargetIsa,
|
||||
mem: &mut Vec<u8>,
|
||||
relocs: &mut RelocSink,
|
||||
traps: &mut TrapSink,
|
||||
) -> CodegenResult<()> {
|
||||
let code_size = self.compile(isa)?;
|
||||
) -> CodegenResult<(CodeOffset, CodeOffset)> {
|
||||
let total_size = self.compile(isa)?;
|
||||
let old_len = mem.len();
|
||||
mem.resize(old_len + code_size as usize, 0);
|
||||
unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
|
||||
Ok(())
|
||||
mem.resize(old_len + total_size as usize, 0);
|
||||
let code_size =
|
||||
unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
|
||||
Ok((code_size, total_size - code_size))
|
||||
}
|
||||
|
||||
/// Compile the function.
|
||||
|
@ -111,7 +114,7 @@ impl Context {
|
|||
/// represented by `isa`. This does not include the final step of emitting machine code into a
|
||||
/// code sink.
|
||||
///
|
||||
/// Returns the size of the function's code.
|
||||
/// Returns the size of the function's code and read-only data.
|
||||
pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult<CodeOffset> {
|
||||
let _tt = timing::compile();
|
||||
self.verify_if(isa)?;
|
||||
|
@ -155,15 +158,19 @@ impl Context {
|
|||
///
|
||||
/// This function is unsafe since it does not perform bounds checking on the memory buffer,
|
||||
/// and it can't guarantee that the `mem` pointer is valid.
|
||||
///
|
||||
/// Returns the size of the function's code.
|
||||
pub unsafe fn emit_to_memory(
|
||||
&self,
|
||||
isa: &TargetIsa,
|
||||
mem: *mut u8,
|
||||
relocs: &mut RelocSink,
|
||||
traps: &mut TrapSink,
|
||||
) {
|
||||
) -> CodeOffset {
|
||||
let _tt = timing::binemit();
|
||||
isa.emit_function_to_memory(&self.func, &mut MemoryCodeSink::new(mem, relocs, traps));
|
||||
let mut sink = MemoryCodeSink::new(mem, relocs, traps);
|
||||
isa.emit_function_to_memory(&self.func, &mut sink);
|
||||
sink.code_size as CodeOffset
|
||||
}
|
||||
|
||||
/// Run the verifier on the function.
|
||||
|
|
|
@ -246,7 +246,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_magicU32() {
|
||||
fn test_magic_u32() {
|
||||
assert_eq!(magic_u32(2u32), make_mu32(0x80000000u32, false, 0));
|
||||
assert_eq!(magic_u32(3u32), make_mu32(0xaaaaaaabu32, false, 1));
|
||||
assert_eq!(magic_u32(4u32), make_mu32(0x40000000u32, false, 0));
|
||||
|
@ -279,8 +279,9 @@ mod tests {
|
|||
make_mu32(0x80000001u32, false, 31)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_magicU64() {
|
||||
fn test_magic_u64() {
|
||||
assert_eq!(magic_u64(2u64), make_mu64(0x8000000000000000u64, false, 0));
|
||||
assert_eq!(magic_u64(3u64), make_mu64(0xaaaaaaaaaaaaaaabu64, false, 1));
|
||||
assert_eq!(magic_u64(4u64), make_mu64(0x4000000000000000u64, false, 0));
|
||||
|
@ -346,8 +347,9 @@ mod tests {
|
|||
make_mu64(0x8000000000000001u64, false, 63)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_magicS32() {
|
||||
fn test_magic_s32() {
|
||||
assert_eq!(
|
||||
magic_s32(-0x80000000i32),
|
||||
make_ms32(0x7fffffffu32 as i32, 30)
|
||||
|
@ -390,8 +392,9 @@ mod tests {
|
|||
make_ms32(0x40000001u32 as i32, 29)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_magicS64() {
|
||||
fn test_magic_s64() {
|
||||
assert_eq!(
|
||||
magic_s64(-0x8000000000000000i64),
|
||||
make_ms64(0x7fffffffffffffffu64 as i64, 62)
|
||||
|
@ -515,6 +518,7 @@ mod tests {
|
|||
make_ms64(0x4000000000000001u64 as i64, 61)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_magic_generators_dont_panic() {
|
||||
// The point of this is to check that the magic number generators
|
||||
|
|
|
@ -1,18 +1,88 @@
|
|||
//! ARM ABI implementation.
|
||||
//! This is from the RISC-V target and will need to be updated for ARM32.
|
||||
|
||||
use super::registers::{D, GPR, Q, S};
|
||||
use crate::ir;
|
||||
use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
|
||||
use crate::ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, Type};
|
||||
use crate::isa::RegClass;
|
||||
use crate::regalloc::RegisterSet;
|
||||
use crate::settings as shared_settings;
|
||||
use core::i32;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
struct Args {
|
||||
pointer_bits: u8,
|
||||
pointer_bytes: u8,
|
||||
pointer_type: Type,
|
||||
regs: u32,
|
||||
reg_limit: u32,
|
||||
offset: u32,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
fn new(bits: u8) -> Self {
|
||||
Self {
|
||||
pointer_bits: bits,
|
||||
pointer_bytes: bits / 8,
|
||||
pointer_type: Type::int(u16::from(bits)).unwrap(),
|
||||
regs: 0,
|
||||
reg_limit: 8,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgAssigner for Args {
|
||||
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
|
||||
fn align(value: u32, to: u32) -> u32 {
|
||||
(value + to - 1) & !(to - 1)
|
||||
}
|
||||
|
||||
let ty = arg.value_type;
|
||||
|
||||
// Check for a legal type.
|
||||
// SIMD instructions are currently no implemented, so break down vectors
|
||||
if ty.is_vector() {
|
||||
return ValueConversion::VectorSplit.into();
|
||||
}
|
||||
|
||||
// Large integers and booleans are broken down to fit in a register.
|
||||
if !ty.is_float() && ty.bits() > u16::from(self.pointer_bits) {
|
||||
// Align registers and stack to a multiple of two pointers.
|
||||
self.regs = align(self.regs, 2);
|
||||
self.offset = align(self.offset, 2 * u32::from(self.pointer_bytes));
|
||||
return ValueConversion::IntSplit.into();
|
||||
}
|
||||
|
||||
// Small integers are extended to the size of a pointer register.
|
||||
if ty.is_int() && ty.bits() < u16::from(self.pointer_bits) {
|
||||
match arg.extension {
|
||||
ArgumentExtension::None => {}
|
||||
ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
|
||||
ArgumentExtension::Sext => return ValueConversion::Sext(self.pointer_type).into(),
|
||||
}
|
||||
}
|
||||
|
||||
if self.regs < self.reg_limit {
|
||||
// Assign to a register.
|
||||
let reg = GPR.unit(10 + self.regs as usize);
|
||||
self.regs += 1;
|
||||
ArgumentLoc::Reg(reg).into()
|
||||
} else {
|
||||
// Assign a stack location.
|
||||
let loc = ArgumentLoc::Stack(self.offset as i32);
|
||||
self.offset += u32::from(self.pointer_bytes);
|
||||
debug_assert!(self.offset <= i32::MAX as u32);
|
||||
loc.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Legalize `sig`.
|
||||
pub fn legalize_signature(
|
||||
_sig: &mut ir::Signature,
|
||||
_flags: &shared_settings::Flags,
|
||||
_current: bool,
|
||||
) {
|
||||
unimplemented!()
|
||||
pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bool) {
|
||||
let bits = triple.pointer_width().unwrap().bits();
|
||||
|
||||
let mut args = Args::new(bits);
|
||||
legalize_args(&mut sig.params, &mut args);
|
||||
}
|
||||
|
||||
/// Get register class for a type appearing in a legalized signature.
|
||||
|
|
|
@ -102,7 +102,7 @@ impl TargetIsa for Isa {
|
|||
}
|
||||
|
||||
fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
|
||||
abi::legalize_signature(sig, &self.shared_flags, current)
|
||||
abi::legalize_signature(sig, &self.triple, current)
|
||||
}
|
||||
|
||||
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
|
||||
|
|
|
@ -161,13 +161,14 @@ pub fn legalize_signature(sig: &mut ir::Signature, triple: &Triple, _current: bo
|
|||
|
||||
legalize_args(&mut sig.params, &mut args);
|
||||
|
||||
let regs = if sig.call_conv == CallConv::WindowsFastcall {
|
||||
&RET_GPRS_WIN_FASTCALL_X64[..]
|
||||
let (regs, fpr_limit) = if sig.call_conv == CallConv::WindowsFastcall {
|
||||
// windows-x64 calling convention only uses XMM0 or RAX for return values
|
||||
(&RET_GPRS_WIN_FASTCALL_X64[..], 1)
|
||||
} else {
|
||||
&RET_GPRS[..]
|
||||
(&RET_GPRS[..], 2)
|
||||
};
|
||||
|
||||
let mut rets = Args::new(bits, regs, 2, sig.call_conv);
|
||||
let mut rets = Args::new(bits, regs, fpr_limit, sig.call_conv);
|
||||
legalize_args(&mut sig.returns, &mut rets);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
//!
|
||||
//! When legalizing a single instruction, it is wrapped in splits and concatenations:
|
||||
//!
|
||||
//!```clif
|
||||
//! ```clif
|
||||
//! v1 = bxor.i64 v2, v3
|
||||
//! ```
|
||||
//!
|
||||
//! becomes:
|
||||
//!
|
||||
//!```clif
|
||||
//! ```clif
|
||||
//! v20, v21 = isplit v2
|
||||
//! v30, v31 = isplit v3
|
||||
//! v10 = bxor.i32 v20, v30
|
||||
|
|
|
@ -5,7 +5,9 @@ use crate::dominator_tree::DominatorTree;
|
|||
use crate::entity::{EntityList, ListPool};
|
||||
use crate::flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use crate::fx::FxHashSet;
|
||||
use crate::ir::{DataFlowGraph, Ebb, Function, Inst, InstBuilder, Layout, Opcode, Type, Value};
|
||||
use crate::ir::{
|
||||
DataFlowGraph, Ebb, Function, Inst, InstBuilder, InstructionData, Layout, Opcode, Type, Value,
|
||||
};
|
||||
use crate::isa::TargetIsa;
|
||||
use crate::loop_analysis::{Loop, LoopAnalysis};
|
||||
use crate::timing;
|
||||
|
@ -145,8 +147,7 @@ fn change_branch_jump_destination(inst: Inst, new_ebb: Ebb, func: &mut Function)
|
|||
|
||||
/// Test whether the given opcode is unsafe to even consider for LICM.
|
||||
fn trivially_unsafe_for_licm(opcode: Opcode) -> bool {
|
||||
opcode.can_load()
|
||||
|| opcode.can_store()
|
||||
opcode.can_store()
|
||||
|| opcode.is_call()
|
||||
|| opcode.is_branch()
|
||||
|| opcode.is_terminator()
|
||||
|
@ -156,12 +157,25 @@ fn trivially_unsafe_for_licm(opcode: Opcode) -> bool {
|
|||
|| opcode.writes_cpu_flags()
|
||||
}
|
||||
|
||||
fn is_unsafe_load(inst_data: &InstructionData) -> bool {
|
||||
match *inst_data {
|
||||
InstructionData::Load { flags, .. } | InstructionData::LoadComplex { flags, .. } => {
|
||||
!flags.readonly() || !flags.notrap()
|
||||
}
|
||||
_ => inst_data.opcode().can_load(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Test whether the given instruction is loop-invariant.
|
||||
fn is_loop_invariant(inst: Inst, dfg: &DataFlowGraph, loop_values: &FxHashSet<Value>) -> bool {
|
||||
if trivially_unsafe_for_licm(dfg[inst].opcode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if is_unsafe_load(&dfg[inst]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inst_args = dfg.inst_args(inst);
|
||||
for arg in inst_args {
|
||||
let arg = dfg.resolve_aliases(*arg);
|
||||
|
|
|
@ -128,6 +128,7 @@ fn optimize_cpu_flags(
|
|||
// We found a compare+branch pattern. Transform it to use flags.
|
||||
let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec();
|
||||
pos.goto_inst(info.cmp_inst);
|
||||
pos.use_srcloc(info.cmp_inst);
|
||||
match info.kind {
|
||||
CmpBrKind::Icmp { mut cond, arg } => {
|
||||
let flags = pos.ins().ifcmp(info.cmp_arg, arg);
|
||||
|
|
|
@ -292,6 +292,9 @@ impl<'a> Context<'a> {
|
|||
|
||||
// Insert a copy instruction at the top of `ebb`.
|
||||
let mut pos = EncCursor::new(self.func, self.isa).at_first_inst(ebb);
|
||||
if let Some(inst) = pos.current_inst() {
|
||||
pos.use_srcloc(inst);
|
||||
}
|
||||
pos.ins().with_result(param).copy(new_val);
|
||||
let inst = pos.built_inst();
|
||||
self.liveness.move_def_locally(param, inst);
|
||||
|
@ -347,6 +350,7 @@ impl<'a> Context<'a> {
|
|||
pred_val: Value,
|
||||
) -> Value {
|
||||
let mut pos = EncCursor::new(self.func, self.isa).at_inst(pred_inst);
|
||||
pos.use_srcloc(pred_inst);
|
||||
let copy = pos.ins().copy(pred_val);
|
||||
let inst = pos.built_inst();
|
||||
|
||||
|
|
|
@ -420,6 +420,7 @@ impl<'a> Context<'a> {
|
|||
// secondary `opidx` key makes it possible to use an unstable (non-allocating) sort.
|
||||
self.reg_uses.sort_unstable_by_key(|u| (u.value, u.opidx));
|
||||
|
||||
self.cur.use_srcloc(inst);
|
||||
for i in 0..self.reg_uses.len() {
|
||||
let ru = self.reg_uses[i];
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ mod details {
|
|||
}
|
||||
}
|
||||
|
||||
/// Information about passes in a single thread.
|
||||
// Information about passes in a single thread.
|
||||
thread_local! {
|
||||
static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::None);
|
||||
static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default());
|
||||
|
|
|
@ -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}
|
|
@ -1,34 +1,21 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-entity"
|
||||
version = "0.29.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-entity"
|
||||
version = "0.30.0"
|
||||
description = "Data structures using entity references as mapping keys"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
categories = ["no-std"]
|
||||
readme = "README.md"
|
||||
keywords = ["entity", "set", "map"]
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
core = []
|
||||
default = ["std"]
|
||||
std = []
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
core = []
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
|
|
@ -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}
|
|
@ -1,48 +1,26 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-frontend"
|
||||
version = "0.29.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.30.0"
|
||||
description = "Cranelift IR builder helper"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
readme = "README.md"
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
categories = ["no-std"]
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-codegen]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies.hashmap_core]
|
||||
version = "0.1.9"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.6"
|
||||
default-features = false
|
||||
|
||||
[dependencies.target-lexicon]
|
||||
version = "0.2.0"
|
||||
default-features = false
|
||||
[dependencies]
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false }
|
||||
target-lexicon = { version = "0.4.0", default-features = false }
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
hashmap_core = { version = "0.1.9", optional = true }
|
||||
|
||||
[features]
|
||||
core = ["hashmap_core", "cranelift-codegen/core"]
|
||||
default = ["std"]
|
||||
std = ["cranelift-codegen/std"]
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
core = ["hashmap_core", "cranelift-codegen/core"]
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
|
|
@ -9,6 +9,36 @@ type EntryIndex = u64;
|
|||
|
||||
/// Unlike with `br_table`, `Switch` cases may be sparse or non-0-based.
|
||||
/// They emit efficient code using branches, jump tables, or a combination of both.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cranelift_codegen::ir::types::*;
|
||||
/// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder};
|
||||
/// # use cranelift_codegen::isa::CallConv;
|
||||
/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch};
|
||||
/// #
|
||||
/// # let mut sig = Signature::new(CallConv::SystemV);
|
||||
/// # let mut fn_builder_ctx = FunctionBuilderContext::new();
|
||||
/// # let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
|
||||
/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
|
||||
/// #
|
||||
/// # let entry = builder.create_ebb();
|
||||
/// # builder.switch_to_block(entry);
|
||||
/// #
|
||||
/// let block0 = builder.create_ebb();
|
||||
/// let block1 = builder.create_ebb();
|
||||
/// let block2 = builder.create_ebb();
|
||||
/// let fallback = builder.create_ebb();
|
||||
///
|
||||
/// let val = builder.ins().iconst(I32, 1);
|
||||
///
|
||||
/// let mut switch = Switch::new();
|
||||
/// switch.set_entry(0, block0);
|
||||
/// switch.set_entry(1, block1);
|
||||
/// switch.set_entry(7, block2);
|
||||
/// switch.emit(&mut builder, val, fallback);
|
||||
/// ```
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Switch {
|
||||
cases: HashMap<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> {
|
||||
debug!("build_contiguous_case_ranges before: {:#?}", self.cases);
|
||||
let mut cases = self.cases.into_iter().collect::<Vec<(_, _)>>();
|
||||
|
@ -60,6 +98,7 @@ impl Switch {
|
|||
contiguous_case_ranges
|
||||
}
|
||||
|
||||
/// Binary search for the right `ContiguousCaseRange`.
|
||||
fn build_search_tree(
|
||||
bx: &mut FunctionBuilder,
|
||||
val: Value,
|
||||
|
@ -120,6 +159,7 @@ impl Switch {
|
|||
cases_and_jt_ebbs
|
||||
}
|
||||
|
||||
/// Linear search for the right `ContiguousCaseRange`.
|
||||
fn build_search_branches(
|
||||
bx: &mut FunctionBuilder,
|
||||
val: Value,
|
||||
|
@ -128,22 +168,41 @@ impl Switch {
|
|||
cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec<Ebb>)>,
|
||||
) {
|
||||
for ContiguousCaseRange { first_index, ebbs } in contiguous_case_ranges.into_iter().rev() {
|
||||
if ebbs.len() == 1 {
|
||||
let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64);
|
||||
bx.ins().brnz(is_good_val, ebbs[0], &[]);
|
||||
} else {
|
||||
let jt_ebb = bx.create_ebb();
|
||||
let is_good_val =
|
||||
bx.ins()
|
||||
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, val, first_index as i64);
|
||||
bx.ins().brnz(is_good_val, jt_ebb, &[]);
|
||||
cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
|
||||
match (ebbs.len(), first_index) {
|
||||
(1, 0) => {
|
||||
bx.ins().brz(val, ebbs[0], &[]);
|
||||
}
|
||||
(1, _) => {
|
||||
let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64);
|
||||
bx.ins().brnz(is_good_val, ebbs[0], &[]);
|
||||
}
|
||||
(_, 0) => {
|
||||
// if `first_index` is 0, then `icmp_imm uge val, first_index` is trivially true
|
||||
let jt_ebb = bx.create_ebb();
|
||||
bx.ins().jump(jt_ebb, &[]);
|
||||
cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
|
||||
// `jump otherwise` below must not be hit, because the current block has been
|
||||
// filled above. This is the last iteration anyway, as 0 is the smallest
|
||||
// unsigned int, so just return here.
|
||||
return;
|
||||
}
|
||||
(_, _) => {
|
||||
let jt_ebb = bx.create_ebb();
|
||||
let is_good_val = bx.ins().icmp_imm(
|
||||
IntCC::UnsignedGreaterThanOrEqual,
|
||||
val,
|
||||
first_index as i64,
|
||||
);
|
||||
bx.ins().brnz(is_good_val, jt_ebb, &[]);
|
||||
cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bx.ins().jump(otherwise, &[]);
|
||||
}
|
||||
|
||||
/// For every item in `cases_and_jt_ebbs` this will create a jump table in the specified ebb.
|
||||
fn build_jump_tables(
|
||||
bx: &mut FunctionBuilder,
|
||||
val: Value,
|
||||
|
@ -158,7 +217,11 @@ impl Switch {
|
|||
let jump_table = bx.create_jump_table(jt_data);
|
||||
|
||||
bx.switch_to_block(jt_ebb);
|
||||
let discr = bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg());
|
||||
let discr = if first_index == 0 {
|
||||
val
|
||||
} else {
|
||||
bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg())
|
||||
};
|
||||
bx.ins().br_table(discr, otherwise, jump_table);
|
||||
}
|
||||
}
|
||||
|
@ -183,9 +246,22 @@ impl Switch {
|
|||
}
|
||||
}
|
||||
|
||||
/// This represents a contiguous range of cases to switch on.
|
||||
///
|
||||
/// For example 10 => ebb1, 11 => ebb2, 12 => ebb7 will be represented as:
|
||||
///
|
||||
/// ```plain
|
||||
/// ContiguousCaseRange {
|
||||
/// first_index: 10,
|
||||
/// ebbs: vec![Ebb::from_u32(1), Ebb::from_u32(2), Ebb::from_u32(7)]
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
struct ContiguousCaseRange {
|
||||
/// The entry index of the first case. Eg. 10 when the entry indexes are 10, 11, 12 and 13.
|
||||
first_index: EntryIndex,
|
||||
|
||||
/// The ebbs to jump to sorted in ascending order of entry index.
|
||||
ebbs: Vec<Ebb>,
|
||||
}
|
||||
|
||||
|
@ -237,8 +313,7 @@ mod tests {
|
|||
"ebb0:
|
||||
v0 = iconst.i8 0
|
||||
v1 = uextend.i32 v0
|
||||
v2 = icmp_imm eq v1, 0
|
||||
brnz v2, ebb1
|
||||
brz v1, ebb1
|
||||
jump ebb0"
|
||||
);
|
||||
}
|
||||
|
@ -267,13 +342,10 @@ mod tests {
|
|||
ebb0:
|
||||
v0 = iconst.i8 0
|
||||
v1 = uextend.i32 v0
|
||||
v2 = icmp_imm uge v1, 0
|
||||
brnz v2, ebb3
|
||||
jump ebb0
|
||||
jump ebb3
|
||||
|
||||
ebb3:
|
||||
v3 = iadd_imm.i32 v1, 0
|
||||
br_table v3, ebb0, jt0"
|
||||
br_table.i32 v1, ebb0, jt0"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -287,8 +359,7 @@ ebb3:
|
|||
v1 = uextend.i32 v0
|
||||
v2 = icmp_imm eq v1, 2
|
||||
brnz v2, ebb2
|
||||
v3 = icmp_imm eq v1, 0
|
||||
brnz v3, ebb1
|
||||
brz v1, ebb1
|
||||
jump ebb0"
|
||||
);
|
||||
}
|
||||
|
@ -318,17 +389,14 @@ ebb9:
|
|||
ebb8:
|
||||
v5 = icmp_imm.i32 eq v1, 5
|
||||
brnz v5, ebb3
|
||||
v6 = icmp_imm.i32 uge v1, 0
|
||||
brnz v6, ebb11
|
||||
jump ebb0
|
||||
jump ebb11
|
||||
|
||||
ebb11:
|
||||
v7 = iadd_imm.i32 v1, 0
|
||||
br_table v7, ebb0, jt0
|
||||
br_table.i32 v1, ebb0, jt0
|
||||
|
||||
ebb10:
|
||||
v8 = iadd_imm.i32 v1, -10
|
||||
br_table v8, ebb0, jt1"
|
||||
v6 = iadd_imm.i32 v1, -10
|
||||
br_table v6, ebb0, jt1"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -363,4 +431,23 @@ ebb10:
|
|||
jump ebb0"
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn switch_optimal_codegen() {
|
||||
let func = setup!(0, [-1i64 as u64, 0, 1,]);
|
||||
assert_eq!(
|
||||
func,
|
||||
" jt0 = jump_table [ebb2, ebb3]
|
||||
|
||||
ebb0:
|
||||
v0 = iconst.i8 0
|
||||
v1 = uextend.i32 v0
|
||||
v2 = icmp_imm eq v1, -1
|
||||
brnz v2, ebb1
|
||||
jump ebb4
|
||||
|
||||
ebb4:
|
||||
br_table.i32 v1, ebb0, jt0"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
|
@ -1,74 +1,35 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "cranelift-wasm"
|
||||
version = "0.29.0"
|
||||
version = "0.30.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Translator from WebAssembly to Cranelift IR"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
categories = ["no-std", "wasm"]
|
||||
readme = "README.md"
|
||||
keywords = ["webassembly", "wasm"]
|
||||
categories = ["no-std", "wasm"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cast]
|
||||
version = "0.2.2"
|
||||
default-features = false
|
||||
edition = "2018"
|
||||
|
||||
[dependencies.cranelift-codegen]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
[dependencies]
|
||||
wasmparser = { version = "0.29.2", default-features = false }
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
|
||||
cranelift-frontend = { path = "../cranelift-frontend", version = "0.30.0", default-features = false }
|
||||
hashmap_core = { version = "0.1.9", optional = true }
|
||||
failure = { version = "0.1.1", default-features = false, features = ["derive"] }
|
||||
failure_derive = { version = "0.1.1", default-features = false }
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
cast = { version = "0.2.2", default-features = false }
|
||||
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cranelift-frontend]
|
||||
version = "0.29.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.failure]
|
||||
version = "0.1.1"
|
||||
features = ["derive"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.failure_derive]
|
||||
version = "0.1.1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.hashmap_core]
|
||||
version = "0.1.9"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.6"
|
||||
default-features = false
|
||||
|
||||
[dependencies.wasmparser]
|
||||
version = "0.23.0"
|
||||
default-features = false
|
||||
[dev-dependencies.target-lexicon]
|
||||
version = "0.2.0"
|
||||
|
||||
[dev-dependencies.wabt]
|
||||
version = "0.7.0"
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.0"
|
||||
target-lexicon = "0.4.0"
|
||||
|
||||
[features]
|
||||
core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"]
|
||||
default = ["std"]
|
||||
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmparser/std"]
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
core = ["hashmap_core", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"]
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/cranelift"
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/cranelift" }
|
||||
|
|
|
@ -886,6 +886,161 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
Operator::RefNull | Operator::RefIsNull { .. } => {
|
||||
return Err(WasmError::Unsupported("proposed reference-type operators"));
|
||||
}
|
||||
Operator::MemoryInit { .. }
|
||||
| Operator::DataDrop { .. }
|
||||
| Operator::MemoryCopy
|
||||
| Operator::MemoryFill
|
||||
| Operator::TableInit { .. }
|
||||
| Operator::ElemDrop { .. }
|
||||
| Operator::TableCopy
|
||||
| Operator::TableGet { .. }
|
||||
| Operator::TableSet { .. }
|
||||
| Operator::TableGrow { .. }
|
||||
| Operator::TableSize { .. } => {
|
||||
return Err(WasmError::Unsupported("proposed bulk memory operators"));
|
||||
}
|
||||
Operator::V128Load { .. }
|
||||
| Operator::V128Store { .. }
|
||||
| Operator::V128Const { .. }
|
||||
| Operator::V8x16Shuffle { .. }
|
||||
| Operator::I8x16Splat
|
||||
| Operator::I8x16ExtractLaneS { .. }
|
||||
| Operator::I8x16ExtractLaneU { .. }
|
||||
| Operator::I8x16ReplaceLane { .. }
|
||||
| Operator::I16x8Splat
|
||||
| Operator::I16x8ExtractLaneS { .. }
|
||||
| Operator::I16x8ExtractLaneU { .. }
|
||||
| Operator::I16x8ReplaceLane { .. }
|
||||
| Operator::I32x4Splat
|
||||
| Operator::I32x4ExtractLane { .. }
|
||||
| Operator::I32x4ReplaceLane { .. }
|
||||
| Operator::I64x2Splat
|
||||
| Operator::I64x2ExtractLane { .. }
|
||||
| Operator::I64x2ReplaceLane { .. }
|
||||
| Operator::F32x4Splat
|
||||
| Operator::F32x4ExtractLane { .. }
|
||||
| Operator::F32x4ReplaceLane { .. }
|
||||
| Operator::F64x2Splat
|
||||
| Operator::F64x2ExtractLane { .. }
|
||||
| Operator::F64x2ReplaceLane { .. }
|
||||
| Operator::I8x16Eq
|
||||
| Operator::I8x16Ne
|
||||
| Operator::I8x16LtS
|
||||
| Operator::I8x16LtU
|
||||
| Operator::I8x16GtS
|
||||
| Operator::I8x16GtU
|
||||
| Operator::I8x16LeS
|
||||
| Operator::I8x16LeU
|
||||
| Operator::I8x16GeS
|
||||
| Operator::I8x16GeU
|
||||
| Operator::I16x8Eq
|
||||
| Operator::I16x8Ne
|
||||
| Operator::I16x8LtS
|
||||
| Operator::I16x8LtU
|
||||
| Operator::I16x8GtS
|
||||
| Operator::I16x8GtU
|
||||
| Operator::I16x8LeS
|
||||
| Operator::I16x8LeU
|
||||
| Operator::I16x8GeS
|
||||
| Operator::I16x8GeU
|
||||
| Operator::I32x4Eq
|
||||
| Operator::I32x4Ne
|
||||
| Operator::I32x4LtS
|
||||
| Operator::I32x4LtU
|
||||
| Operator::I32x4GtS
|
||||
| Operator::I32x4GtU
|
||||
| Operator::I32x4LeS
|
||||
| Operator::I32x4LeU
|
||||
| Operator::I32x4GeS
|
||||
| Operator::I32x4GeU
|
||||
| Operator::F32x4Eq
|
||||
| Operator::F32x4Ne
|
||||
| Operator::F32x4Lt
|
||||
| Operator::F32x4Gt
|
||||
| Operator::F32x4Le
|
||||
| Operator::F32x4Ge
|
||||
| Operator::F64x2Eq
|
||||
| Operator::F64x2Ne
|
||||
| Operator::F64x2Lt
|
||||
| Operator::F64x2Gt
|
||||
| Operator::F64x2Le
|
||||
| Operator::F64x2Ge
|
||||
| Operator::V128Not
|
||||
| Operator::V128And
|
||||
| Operator::V128Or
|
||||
| Operator::V128Xor
|
||||
| Operator::V128Bitselect
|
||||
| Operator::I8x16Neg
|
||||
| Operator::I8x16AnyTrue
|
||||
| Operator::I8x16AllTrue
|
||||
| Operator::I8x16Shl
|
||||
| Operator::I8x16ShrS
|
||||
| Operator::I8x16ShrU
|
||||
| Operator::I8x16Add
|
||||
| Operator::I8x16AddSaturateS
|
||||
| Operator::I8x16AddSaturateU
|
||||
| Operator::I8x16Sub
|
||||
| Operator::I8x16SubSaturateS
|
||||
| Operator::I8x16SubSaturateU
|
||||
| Operator::I8x16Mul
|
||||
| Operator::I16x8Neg
|
||||
| Operator::I16x8AnyTrue
|
||||
| Operator::I16x8AllTrue
|
||||
| Operator::I16x8Shl
|
||||
| Operator::I16x8ShrS
|
||||
| Operator::I16x8ShrU
|
||||
| Operator::I16x8Add
|
||||
| Operator::I16x8AddSaturateS
|
||||
| Operator::I16x8AddSaturateU
|
||||
| Operator::I16x8Sub
|
||||
| Operator::I16x8SubSaturateS
|
||||
| Operator::I16x8SubSaturateU
|
||||
| Operator::I16x8Mul
|
||||
| Operator::I32x4Neg
|
||||
| Operator::I32x4AnyTrue
|
||||
| Operator::I32x4AllTrue
|
||||
| Operator::I32x4Shl
|
||||
| Operator::I32x4ShrS
|
||||
| Operator::I32x4ShrU
|
||||
| Operator::I32x4Add
|
||||
| Operator::I32x4Sub
|
||||
| Operator::I32x4Mul
|
||||
| Operator::I64x2Neg
|
||||
| Operator::I64x2AnyTrue
|
||||
| Operator::I64x2AllTrue
|
||||
| Operator::I64x2Shl
|
||||
| Operator::I64x2ShrS
|
||||
| Operator::I64x2ShrU
|
||||
| Operator::I64x2Add
|
||||
| Operator::I64x2Sub
|
||||
| Operator::F32x4Abs
|
||||
| Operator::F32x4Neg
|
||||
| Operator::F32x4Sqrt
|
||||
| Operator::F32x4Add
|
||||
| Operator::F32x4Sub
|
||||
| Operator::F32x4Mul
|
||||
| Operator::F32x4Div
|
||||
| Operator::F32x4Min
|
||||
| Operator::F32x4Max
|
||||
| Operator::F64x2Abs
|
||||
| Operator::F64x2Neg
|
||||
| Operator::F64x2Sqrt
|
||||
| Operator::F64x2Add
|
||||
| Operator::F64x2Sub
|
||||
| Operator::F64x2Mul
|
||||
| Operator::F64x2Div
|
||||
| Operator::F64x2Min
|
||||
| Operator::F64x2Max
|
||||
| Operator::I32x4TruncSF32x4Sat
|
||||
| Operator::I32x4TruncUF32x4Sat
|
||||
| Operator::I64x2TruncSF64x2Sat
|
||||
| Operator::I64x2TruncUF64x2Sat
|
||||
| Operator::F32x4ConvertSI32x4
|
||||
| Operator::F32x4ConvertUI32x4
|
||||
| Operator::F64x2ConvertSI64x2
|
||||
| Operator::F64x2ConvertUI64x2 => {
|
||||
return Err(WasmError::Unsupported("proposed SIMD operators"));
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -12,15 +12,15 @@ use crate::translation_utils::{
|
|||
type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex,
|
||||
Table, TableElementType, TableIndex,
|
||||
};
|
||||
use core::str::from_utf8;
|
||||
use cranelift_codegen::ir::{self, AbiParam, Signature};
|
||||
use cranelift_entity::EntityRef;
|
||||
use std::vec::Vec;
|
||||
use wasmparser::{
|
||||
self, CodeSectionReader, Data, DataSectionReader, Element, ElementSectionReader, Export,
|
||||
ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader,
|
||||
GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType,
|
||||
Operator, TableSectionReader, TypeSectionReader,
|
||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind,
|
||||
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
|
||||
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
||||
ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader,
|
||||
TypeSectionReader,
|
||||
};
|
||||
|
||||
/// Parses the Type section of the wasm module.
|
||||
|
@ -65,12 +65,8 @@ pub fn parse_import_section<'data>(
|
|||
|
||||
for entry in imports {
|
||||
let import = entry?;
|
||||
|
||||
// The input has already been validated, so we should be able to
|
||||
// assume valid UTF-8 and use `from_utf8_unchecked` if performance
|
||||
// becomes a concern here.
|
||||
let module_name = from_utf8(import.module).unwrap();
|
||||
let field_name = from_utf8(import.field).unwrap();
|
||||
let module_name = import.module;
|
||||
let field_name = import.field;
|
||||
|
||||
match import.ty {
|
||||
ImportSectionEntryType::Function(sig) => {
|
||||
|
@ -232,13 +228,12 @@ pub fn parse_export_section<'data>(
|
|||
// The input has already been validated, so we should be able to
|
||||
// assume valid UTF-8 and use `from_utf8_unchecked` if performance
|
||||
// becomes a concern here.
|
||||
let name = from_utf8(field).unwrap();
|
||||
let index = index as usize;
|
||||
match *kind {
|
||||
ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), name),
|
||||
ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name),
|
||||
ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), name),
|
||||
ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), name),
|
||||
ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), field),
|
||||
ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field),
|
||||
ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), field),
|
||||
ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), field),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,29 +255,35 @@ pub fn parse_element_section<'data>(
|
|||
environ.reserve_table_elements(elements.get_count());
|
||||
|
||||
for entry in elements {
|
||||
let Element {
|
||||
let Element { kind, items } = entry?;
|
||||
if let ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
items,
|
||||
} = entry?;
|
||||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0),
|
||||
ref s => panic!("unsupported init expr in element section: {:?}", s),
|
||||
};
|
||||
let items_reader = items.get_items_reader()?;
|
||||
let mut elems = Vec::with_capacity(cast::usize(items_reader.get_count()));
|
||||
for item in items_reader {
|
||||
let x = item?;
|
||||
elems.push(FuncIndex::from_u32(x));
|
||||
} = kind
|
||||
{
|
||||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
(Some(GlobalIndex::from_u32(global_index)), 0)
|
||||
}
|
||||
ref s => panic!("unsupported init expr in element section: {:?}", s),
|
||||
};
|
||||
let items_reader = items.get_items_reader()?;
|
||||
let mut elems = Vec::with_capacity(cast::usize(items_reader.get_count()));
|
||||
for item in items_reader {
|
||||
let x = item?;
|
||||
elems.push(FuncIndex::from_u32(x));
|
||||
}
|
||||
environ.declare_table_elements(
|
||||
TableIndex::from_u32(table_index),
|
||||
base,
|
||||
offset,
|
||||
elems.into_boxed_slice(),
|
||||
)
|
||||
} else {
|
||||
panic!("unsupported passive elements section");
|
||||
}
|
||||
environ.declare_table_elements(
|
||||
TableIndex::from_u32(table_index),
|
||||
base,
|
||||
offset,
|
||||
elems.into_boxed_slice(),
|
||||
)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -309,23 +310,29 @@ pub fn parse_data_section<'data>(
|
|||
environ.reserve_data_initializers(data.get_count());
|
||||
|
||||
for entry in data {
|
||||
let Data {
|
||||
let Data { kind, data } = entry?;
|
||||
if let DataKind::Active {
|
||||
memory_index,
|
||||
init_expr,
|
||||
data,
|
||||
} = entry?;
|
||||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => (Some(GlobalIndex::from_u32(global_index)), 0),
|
||||
ref s => panic!("unsupported init expr in data section: {:?}", s),
|
||||
};
|
||||
environ.declare_data_initialization(
|
||||
MemoryIndex::from_u32(memory_index),
|
||||
base,
|
||||
offset,
|
||||
data,
|
||||
);
|
||||
} = kind
|
||||
{
|
||||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
(Some(GlobalIndex::from_u32(global_index)), 0)
|
||||
}
|
||||
ref s => panic!("unsupported init expr in data section: {:?}", s),
|
||||
};
|
||||
environ.declare_data_initialization(
|
||||
MemoryIndex::from_u32(memory_index),
|
||||
base,
|
||||
offset,
|
||||
data,
|
||||
);
|
||||
} else {
|
||||
panic!("unsupported passive data section");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -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"}
|
|
@ -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
|
|
@ -1,6 +1,19 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "target-lexicon"
|
||||
version = "0.2.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Dan Gohman <sunfish@mozilla.com>"]
|
||||
description = "Targeting utilities for compilers and related tools"
|
||||
documentation = "https://docs.rs/target-lexicon/"
|
||||
|
@ -9,18 +22,22 @@ keywords = ["target", "host", "triple", "compiler", "jit"]
|
|||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/target-lexicon"
|
||||
[dependencies.failure]
|
||||
version = "0.1.3"
|
||||
features = ["derive"]
|
||||
default-features = false
|
||||
|
||||
[dependencies]
|
||||
failure = { version = "0.1.3", default-features = false, features = ["derive"] }
|
||||
failure_derive = { version = "0.1.3", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
serde_json = "1.0"
|
||||
[dependencies.failure_derive]
|
||||
version = "0.1.3"
|
||||
default-features = false
|
||||
[build-dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
[badges.maintenance]
|
||||
status = "passively-maintained"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "passively-maintained" }
|
||||
travis-ci = { repository = "CraneStation/target-lexicon" }
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/target-lexicon"
|
||||
|
|
|
@ -36,7 +36,7 @@ mod parse_error {
|
|||
}
|
||||
}
|
||||
|
||||
use triple::{Endianness, PointerWidth, Triple};
|
||||
use self::triple::{Endianness, PointerWidth, Triple};
|
||||
|
||||
/// Assuming `target` is a path to a custom target json config file, open it
|
||||
/// and build a `Triple` using its contents.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
extern crate target_lexicon;
|
||||
|
||||
use std::str::FromStr;
|
||||
use core::str::FromStr;
|
||||
use target_lexicon::{Triple, HOST};
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use {Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor};
|
||||
use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor};
|
||||
|
||||
// Include the implementations of the `HOST` object containing information
|
||||
// about the current host.
|
||||
|
|
|
@ -15,29 +15,24 @@
|
|||
use_self
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
extern crate alloc as std;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod std {
|
||||
pub use alloc::{borrow, string};
|
||||
pub use core::*;
|
||||
}
|
||||
|
||||
mod host;
|
||||
mod parse_error;
|
||||
mod targets;
|
||||
#[macro_use]
|
||||
mod triple;
|
||||
|
||||
pub use host::HOST;
|
||||
pub use parse_error::ParseError;
|
||||
pub use targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor};
|
||||
pub use triple::{CallingConvention, Endianness, PointerWidth, Triple};
|
||||
pub use self::host::HOST;
|
||||
pub use self::parse_error::ParseError;
|
||||
pub use self::targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor};
|
||||
pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple};
|
||||
|
|
|
@ -16,6 +16,4 @@ pub enum ParseError {
|
|||
UnrecognizedBinaryFormat(String),
|
||||
#[fail(display = "Unrecognized field: {}", _0)]
|
||||
UnrecognizedField(String),
|
||||
#[fail(display = "\"none\" requires an explicit binary format")]
|
||||
NoneWithoutBinaryFormat,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// This file defines all the identifier enums and target-aware logic.
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use triple::{Endianness, PointerWidth, Triple};
|
||||
use crate::triple::{Endianness, PointerWidth, Triple};
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
|
||||
/// The "architecture" field, which in some cases also specifies a specific
|
||||
/// subarchitecture.
|
||||
|
@ -12,9 +12,12 @@ pub enum Architecture {
|
|||
Unknown,
|
||||
Aarch64,
|
||||
Arm,
|
||||
Armebv7r,
|
||||
Armv4t,
|
||||
Armv5te,
|
||||
Armv6,
|
||||
Armv7,
|
||||
Armv7r,
|
||||
Armv7s,
|
||||
Asmjs,
|
||||
I386,
|
||||
|
@ -29,15 +32,20 @@ pub enum Architecture {
|
|||
Powerpc64,
|
||||
Powerpc64le,
|
||||
Riscv32,
|
||||
Riscv32imac,
|
||||
Riscv32imc,
|
||||
Riscv64,
|
||||
S390x,
|
||||
Sparc,
|
||||
Sparc64,
|
||||
Sparcv9,
|
||||
Thumbv6m,
|
||||
Thumbv7a,
|
||||
Thumbv7em,
|
||||
Thumbv7m,
|
||||
Thumbv7neon,
|
||||
Thumbv8mBase,
|
||||
Thumbv8mMain,
|
||||
Wasm32,
|
||||
X86_64,
|
||||
}
|
||||
|
@ -50,6 +58,7 @@ pub enum Vendor {
|
|||
Unknown,
|
||||
Apple,
|
||||
Experimental,
|
||||
Fortanix,
|
||||
Pc,
|
||||
Rumprun,
|
||||
Sun,
|
||||
|
@ -69,14 +78,17 @@ pub enum OperatingSystem {
|
|||
Freebsd,
|
||||
Fuchsia,
|
||||
Haiku,
|
||||
Hermit,
|
||||
Ios,
|
||||
L4re,
|
||||
Linux,
|
||||
Nebulet,
|
||||
Netbsd,
|
||||
None_,
|
||||
Openbsd,
|
||||
Redox,
|
||||
Solaris,
|
||||
Uefi,
|
||||
Windows,
|
||||
}
|
||||
|
||||
|
@ -102,6 +114,7 @@ pub enum Environment {
|
|||
Musleabihf,
|
||||
Msvc,
|
||||
Uclibc,
|
||||
Sgx,
|
||||
}
|
||||
|
||||
/// The "binary format" field, which is usually omitted, and the binary format
|
||||
|
@ -125,7 +138,9 @@ impl Architecture {
|
|||
| Architecture::Arm
|
||||
| Architecture::Armv4t
|
||||
| Architecture::Armv5te
|
||||
| Architecture::Armv6
|
||||
| Architecture::Armv7
|
||||
| Architecture::Armv7r
|
||||
| Architecture::Armv7s
|
||||
| Architecture::Asmjs
|
||||
| Architecture::I386
|
||||
|
@ -136,14 +151,20 @@ impl Architecture {
|
|||
| Architecture::Msp430
|
||||
| Architecture::Powerpc64le
|
||||
| Architecture::Riscv32
|
||||
| Architecture::Riscv32imac
|
||||
| Architecture::Riscv32imc
|
||||
| Architecture::Riscv64
|
||||
| Architecture::Thumbv6m
|
||||
| Architecture::Thumbv7a
|
||||
| Architecture::Thumbv7em
|
||||
| Architecture::Thumbv7m
|
||||
| Architecture::Thumbv7neon
|
||||
| Architecture::Thumbv8mBase
|
||||
| Architecture::Thumbv8mMain
|
||||
| Architecture::Wasm32
|
||||
| Architecture::X86_64 => Ok(Endianness::Little),
|
||||
Architecture::Mips
|
||||
Architecture::Armebv7r
|
||||
| Architecture::Mips
|
||||
| Architecture::Mips64
|
||||
| Architecture::Powerpc
|
||||
| Architecture::Powerpc64
|
||||
|
@ -160,9 +181,12 @@ impl Architecture {
|
|||
Architecture::Unknown => Err(()),
|
||||
Architecture::Msp430 => Ok(PointerWidth::U16),
|
||||
Architecture::Arm
|
||||
| Architecture::Armebv7r
|
||||
| Architecture::Armv4t
|
||||
| Architecture::Armv5te
|
||||
| Architecture::Armv6
|
||||
| Architecture::Armv7
|
||||
| Architecture::Armv7r
|
||||
| Architecture::Armv7s
|
||||
| Architecture::Asmjs
|
||||
| Architecture::I386
|
||||
|
@ -170,11 +194,16 @@ impl Architecture {
|
|||
| Architecture::I686
|
||||
| Architecture::Mipsel
|
||||
| Architecture::Riscv32
|
||||
| Architecture::Riscv32imac
|
||||
| Architecture::Riscv32imc
|
||||
| Architecture::Sparc
|
||||
| Architecture::Thumbv6m
|
||||
| Architecture::Thumbv7a
|
||||
| Architecture::Thumbv7em
|
||||
| Architecture::Thumbv7m
|
||||
| Architecture::Thumbv7neon
|
||||
| Architecture::Thumbv8mBase
|
||||
| Architecture::Thumbv8mMain
|
||||
| Architecture::Wasm32
|
||||
| Architecture::Mips
|
||||
| Architecture::Powerpc => Ok(PointerWidth::U32),
|
||||
|
@ -196,6 +225,7 @@ impl Architecture {
|
|||
/// `binary_format` field.
|
||||
pub fn default_binary_format(triple: &Triple) -> BinaryFormat {
|
||||
match triple.operating_system {
|
||||
OperatingSystem::None_ => BinaryFormat::Unknown,
|
||||
OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho,
|
||||
OperatingSystem::Windows => BinaryFormat::Coff,
|
||||
OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => {
|
||||
|
@ -214,9 +244,12 @@ impl fmt::Display for Architecture {
|
|||
Architecture::Unknown => "unknown",
|
||||
Architecture::Aarch64 => "aarch64",
|
||||
Architecture::Arm => "arm",
|
||||
Architecture::Armebv7r => "armebv7r",
|
||||
Architecture::Armv4t => "armv4t",
|
||||
Architecture::Armv5te => "armv5te",
|
||||
Architecture::Armv6 => "armv6",
|
||||
Architecture::Armv7 => "armv7",
|
||||
Architecture::Armv7r => "armv7r",
|
||||
Architecture::Armv7s => "armv7s",
|
||||
Architecture::Asmjs => "asmjs",
|
||||
Architecture::I386 => "i386",
|
||||
|
@ -231,15 +264,20 @@ impl fmt::Display for Architecture {
|
|||
Architecture::Powerpc64 => "powerpc64",
|
||||
Architecture::Powerpc64le => "powerpc64le",
|
||||
Architecture::Riscv32 => "riscv32",
|
||||
Architecture::Riscv32imac => "riscv32imac",
|
||||
Architecture::Riscv32imc => "riscv32imc",
|
||||
Architecture::Riscv64 => "riscv64",
|
||||
Architecture::S390x => "s390x",
|
||||
Architecture::Sparc => "sparc",
|
||||
Architecture::Sparc64 => "sparc64",
|
||||
Architecture::Sparcv9 => "sparcv9",
|
||||
Architecture::Thumbv6m => "thumbv6m",
|
||||
Architecture::Thumbv7a => "thumbv7a",
|
||||
Architecture::Thumbv7em => "thumbv7em",
|
||||
Architecture::Thumbv7m => "thumbv7m",
|
||||
Architecture::Thumbv7neon => "thumbv7neon",
|
||||
Architecture::Thumbv8mBase => "thumbv8m.base",
|
||||
Architecture::Thumbv8mMain => "thumbv8m.main",
|
||||
Architecture::Wasm32 => "wasm32",
|
||||
Architecture::X86_64 => "x86_64",
|
||||
};
|
||||
|
@ -255,9 +293,12 @@ impl FromStr for Architecture {
|
|||
"unknown" => Architecture::Unknown,
|
||||
"aarch64" => Architecture::Aarch64,
|
||||
"arm" => Architecture::Arm,
|
||||
"armebv7r" => Architecture::Armebv7r,
|
||||
"armv4t" => Architecture::Armv4t,
|
||||
"armv5te" => Architecture::Armv5te,
|
||||
"armv6" => Architecture::Armv6,
|
||||
"armv7" => Architecture::Armv7,
|
||||
"armv7r" => Architecture::Armv7r,
|
||||
"armv7s" => Architecture::Armv7s,
|
||||
"asmjs" => Architecture::Asmjs,
|
||||
"i386" => Architecture::I386,
|
||||
|
@ -272,15 +313,20 @@ impl FromStr for Architecture {
|
|||
"powerpc64" => Architecture::Powerpc64,
|
||||
"powerpc64le" => Architecture::Powerpc64le,
|
||||
"riscv32" => Architecture::Riscv32,
|
||||
"riscv32imac" => Architecture::Riscv32imac,
|
||||
"riscv32imc" => Architecture::Riscv32imc,
|
||||
"riscv64" => Architecture::Riscv64,
|
||||
"s390x" => Architecture::S390x,
|
||||
"sparc" => Architecture::Sparc,
|
||||
"sparc64" => Architecture::Sparc64,
|
||||
"sparcv9" => Architecture::Sparcv9,
|
||||
"thumbv6m" => Architecture::Thumbv6m,
|
||||
"thumbv7a" => Architecture::Thumbv7a,
|
||||
"thumbv7em" => Architecture::Thumbv7em,
|
||||
"thumbv7m" => Architecture::Thumbv7m,
|
||||
"thumbv7neon" => Architecture::Thumbv7neon,
|
||||
"thumbv8m.base" => Architecture::Thumbv8mBase,
|
||||
"thumbv8m.main" => Architecture::Thumbv8mMain,
|
||||
"wasm32" => Architecture::Wasm32,
|
||||
"x86_64" => Architecture::X86_64,
|
||||
_ => return Err(()),
|
||||
|
@ -294,6 +340,7 @@ impl fmt::Display for Vendor {
|
|||
Vendor::Unknown => "unknown",
|
||||
Vendor::Apple => "apple",
|
||||
Vendor::Experimental => "experimental",
|
||||
Vendor::Fortanix => "fortanix",
|
||||
Vendor::Pc => "pc",
|
||||
Vendor::Rumprun => "rumprun",
|
||||
Vendor::Sun => "sun",
|
||||
|
@ -310,6 +357,7 @@ impl FromStr for Vendor {
|
|||
"unknown" => Vendor::Unknown,
|
||||
"apple" => Vendor::Apple,
|
||||
"experimental" => Vendor::Experimental,
|
||||
"fortanix" => Vendor::Fortanix,
|
||||
"pc" => Vendor::Pc,
|
||||
"rumprun" => Vendor::Rumprun,
|
||||
"sun" => Vendor::Sun,
|
||||
|
@ -330,14 +378,17 @@ impl fmt::Display for OperatingSystem {
|
|||
OperatingSystem::Freebsd => "freebsd",
|
||||
OperatingSystem::Fuchsia => "fuchsia",
|
||||
OperatingSystem::Haiku => "haiku",
|
||||
OperatingSystem::Hermit => "hermit",
|
||||
OperatingSystem::Ios => "ios",
|
||||
OperatingSystem::L4re => "l4re",
|
||||
OperatingSystem::Linux => "linux",
|
||||
OperatingSystem::Nebulet => "nebulet",
|
||||
OperatingSystem::Netbsd => "netbsd",
|
||||
OperatingSystem::None_ => "none",
|
||||
OperatingSystem::Openbsd => "openbsd",
|
||||
OperatingSystem::Redox => "redox",
|
||||
OperatingSystem::Solaris => "solaris",
|
||||
OperatingSystem::Uefi => "uefi",
|
||||
OperatingSystem::Windows => "windows",
|
||||
};
|
||||
f.write_str(s)
|
||||
|
@ -358,14 +409,17 @@ impl FromStr for OperatingSystem {
|
|||
"freebsd" => OperatingSystem::Freebsd,
|
||||
"fuchsia" => OperatingSystem::Fuchsia,
|
||||
"haiku" => OperatingSystem::Haiku,
|
||||
"hermit" => OperatingSystem::Hermit,
|
||||
"ios" => OperatingSystem::Ios,
|
||||
"l4re" => OperatingSystem::L4re,
|
||||
"linux" => OperatingSystem::Linux,
|
||||
"nebulet" => OperatingSystem::Nebulet,
|
||||
"netbsd" => OperatingSystem::Netbsd,
|
||||
"none" => OperatingSystem::None_,
|
||||
"openbsd" => OperatingSystem::Openbsd,
|
||||
"redox" => OperatingSystem::Redox,
|
||||
"solaris" => OperatingSystem::Solaris,
|
||||
"uefi" => OperatingSystem::Uefi,
|
||||
"windows" => OperatingSystem::Windows,
|
||||
_ => return Err(()),
|
||||
})
|
||||
|
@ -391,6 +445,7 @@ impl fmt::Display for Environment {
|
|||
Environment::Musleabihf => "musleabihf",
|
||||
Environment::Msvc => "msvc",
|
||||
Environment::Uclibc => "uclibc",
|
||||
Environment::Sgx => "sgx",
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
|
@ -417,6 +472,7 @@ impl FromStr for Environment {
|
|||
"musleabihf" => Environment::Musleabihf,
|
||||
"msvc" => Environment::Msvc,
|
||||
"uclibc" => Environment::Uclibc,
|
||||
"sgx" => Environment::Sgx,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
|
@ -461,72 +517,19 @@ mod tests {
|
|||
// "rustup target list" and "rustc --print target-list".
|
||||
let targets = [
|
||||
"aarch64-apple-ios",
|
||||
"aarch64-fuchsia",
|
||||
"aarch64-linux-android",
|
||||
"aarch64-unknown-fuchsia",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"arm-linux-androideabi",
|
||||
"arm-unknown-linux-gnueabi",
|
||||
"arm-unknown-linux-gnueabihf",
|
||||
"arm-unknown-linux-musleabi",
|
||||
"arm-unknown-linux-musleabihf",
|
||||
"armv5te-unknown-linux-gnueabi",
|
||||
"armv7-apple-ios",
|
||||
"armv7-linux-androideabi",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"armv7-unknown-linux-musleabihf",
|
||||
"armv7s-apple-ios",
|
||||
"asmjs-unknown-emscripten",
|
||||
"i386-apple-ios",
|
||||
"i586-pc-windows-msvc",
|
||||
"i586-unknown-linux-gnu",
|
||||
"i586-unknown-linux-musl",
|
||||
"i686-apple-darwin",
|
||||
"i686-linux-android",
|
||||
"i686-pc-windows-gnu",
|
||||
"i686-pc-windows-msvc",
|
||||
"i686-unknown-freebsd",
|
||||
"i686-unknown-linux-gnu",
|
||||
"i686-unknown-linux-musl",
|
||||
"mips-unknown-linux-gnu",
|
||||
"mips-unknown-linux-musl",
|
||||
"mips64-unknown-linux-gnuabi64",
|
||||
"mips64el-unknown-linux-gnuabi64",
|
||||
"mipsel-unknown-linux-gnu",
|
||||
"mipsel-unknown-linux-musl",
|
||||
"powerpc-unknown-linux-gnu",
|
||||
"powerpc64-unknown-linux-gnu",
|
||||
"powerpc64le-unknown-linux-gnu",
|
||||
"s390x-unknown-linux-gnu",
|
||||
"sparc64-unknown-linux-gnu",
|
||||
"sparcv9-sun-solaris",
|
||||
"thumbv6m-none-eabi",
|
||||
"thumbv7em-none-eabi",
|
||||
"thumbv7em-none-eabihf",
|
||||
"thumbv7m-none-eabi",
|
||||
"wasm32-unknown-emscripten",
|
||||
"wasm32-unknown-unknown",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-apple-ios",
|
||||
"x86_64-linux-android",
|
||||
"x86_64-pc-windows-gnu",
|
||||
"x86_64-pc-windows-msvc",
|
||||
"x86_64-rumprun-netbsd",
|
||||
"x86_64-sun-solaris",
|
||||
"x86_64-unknown-cloudabi",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-fuchsia",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-unknown-linux-gnux32",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"x86_64-unknown-netbsd",
|
||||
"x86_64-unknown-redox",
|
||||
"aarch64-linux-android",
|
||||
"aarch64-pc-windows-msvc",
|
||||
"aarch64-unknown-cloudabi",
|
||||
"aarch64-unknown-freebsd",
|
||||
"aarch64-unknown-fuchsia",
|
||||
"aarch64-unknown-hermit",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"aarch64-unknown-netbsd",
|
||||
"aarch64-unknown-none",
|
||||
"aarch64-unknown-openbsd",
|
||||
"armebv7r-none-eabi",
|
||||
"armebv7r-none-eabihf",
|
||||
"arm-linux-androideabi",
|
||||
"arm-unknown-linux-gnueabi",
|
||||
"arm-unknown-linux-gnueabihf",
|
||||
|
@ -534,11 +537,19 @@ mod tests {
|
|||
"arm-unknown-linux-musleabihf",
|
||||
"armv4t-unknown-linux-gnueabi",
|
||||
"armv5te-unknown-linux-gnueabi",
|
||||
"armv5te-unknown-linux-musleabi",
|
||||
"armv6-unknown-netbsd-eabihf",
|
||||
"armv7-apple-ios",
|
||||
"armv7-linux-androideabi",
|
||||
"armv7r-none-eabi",
|
||||
"armv7r-none-eabihf",
|
||||
"armv7s-apple-ios",
|
||||
"armv7-unknown-cloudabi-eabihf",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"armv7-unknown-linux-musleabihf",
|
||||
"armv7-unknown-netbsd-eabihf",
|
||||
"asmjs-unknown-emscripten",
|
||||
"i386-apple-ios",
|
||||
"i586-pc-windows-msvc",
|
||||
"i586-unknown-linux-gnu",
|
||||
"i586-unknown-linux-musl",
|
||||
|
@ -554,33 +565,47 @@ mod tests {
|
|||
"i686-unknown-linux-musl",
|
||||
"i686-unknown-netbsd",
|
||||
"i686-unknown-openbsd",
|
||||
"mips-unknown-linux-gnu",
|
||||
"mips-unknown-linux-musl",
|
||||
"mips-unknown-linux-uclibc",
|
||||
"mips64-unknown-linux-gnuabi64",
|
||||
"mips64el-unknown-linux-gnuabi64",
|
||||
"mips64-unknown-linux-gnuabi64",
|
||||
"mipsel-unknown-linux-gnu",
|
||||
"mipsel-unknown-linux-musl",
|
||||
"mipsel-unknown-linux-uclibc",
|
||||
"mips-unknown-linux-gnu",
|
||||
"mips-unknown-linux-musl",
|
||||
"mips-unknown-linux-uclibc",
|
||||
"msp430-none-elf",
|
||||
"powerpc64le-unknown-linux-gnu",
|
||||
"powerpc64le-unknown-linux-musl",
|
||||
"powerpc64-unknown-linux-gnu",
|
||||
"powerpc64-unknown-linux-musl",
|
||||
"powerpc-unknown-linux-gnu",
|
||||
"powerpc-unknown-linux-gnuspe",
|
||||
"powerpc-unknown-linux-musl",
|
||||
"powerpc-unknown-netbsd",
|
||||
"powerpc64-unknown-linux-gnu",
|
||||
"powerpc64le-unknown-linux-gnu",
|
||||
"riscv32imac-unknown-none-elf",
|
||||
"riscv32imc-unknown-none-elf",
|
||||
"s390x-unknown-linux-gnu",
|
||||
"sparc-unknown-linux-gnu",
|
||||
"sparc64-unknown-linux-gnu",
|
||||
"sparc64-unknown-netbsd",
|
||||
"sparc-unknown-linux-gnu",
|
||||
"sparcv9-sun-solaris",
|
||||
"thumbv6m-none-eabi",
|
||||
"thumbv7a-pc-windows-msvc",
|
||||
"thumbv7em-none-eabi",
|
||||
"thumbv7em-none-eabihf",
|
||||
"thumbv7m-none-eabi",
|
||||
"thumbv7neon-linux-androideabi",
|
||||
"thumbv7neon-unknown-linux-gnueabihf",
|
||||
"thumbv8m.base-none-eabi",
|
||||
"thumbv8m.main-none-eabi",
|
||||
"thumbv8m.main-none-eabihf",
|
||||
"wasm32-experimental-emscripten",
|
||||
"wasm32-unknown-emscripten",
|
||||
"wasm32-unknown-unknown",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-apple-ios",
|
||||
"x86_64-fortanix-unknown-sgx",
|
||||
"x86_64-fuchsia",
|
||||
"x86_64-linux-android",
|
||||
"x86_64-pc-windows-gnu",
|
||||
"x86_64-pc-windows-msvc",
|
||||
|
@ -590,8 +615,8 @@ mod tests {
|
|||
"x86_64-unknown-cloudabi",
|
||||
"x86_64-unknown-dragonfly",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-fuchsia",
|
||||
"x86_64-unknown-haiku",
|
||||
"x86_64-unknown-hermit",
|
||||
"x86_64-unknown-l4re-uclibc",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-unknown-linux-gnux32",
|
||||
|
@ -599,6 +624,7 @@ mod tests {
|
|||
"x86_64-unknown-netbsd",
|
||||
"x86_64-unknown-openbsd",
|
||||
"x86_64-unknown-redox",
|
||||
"x86_64-unknown-uefi",
|
||||
];
|
||||
|
||||
for target in targets.iter() {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// This file defines the `Triple` type and support code shared by all targets.
|
||||
|
||||
use parse_error::ParseError;
|
||||
use std::borrow::ToOwned;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use targets::{
|
||||
use crate::parse_error::ParseError;
|
||||
use crate::targets::{
|
||||
default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor,
|
||||
};
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
use std::borrow::ToOwned;
|
||||
|
||||
/// The target memory endianness.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -155,17 +155,24 @@ impl fmt::Display for Triple {
|
|||
|
||||
write!(f, "{}", self.architecture)?;
|
||||
if self.vendor == Vendor::Unknown
|
||||
&& self.operating_system == OperatingSystem::Unknown
|
||||
&& (self.environment != Environment::Unknown
|
||||
|| self.binary_format != implied_binary_format)
|
||||
&& ((self.operating_system == OperatingSystem::Linux
|
||||
&& (self.environment == Environment::Android
|
||||
|| self.environment == Environment::Androideabi))
|
||||
|| self.operating_system == OperatingSystem::Fuchsia
|
||||
|| (self.operating_system == OperatingSystem::None_
|
||||
&& (self.architecture == Architecture::Armebv7r
|
||||
|| self.architecture == Architecture::Armv7r
|
||||
|| self.architecture == Architecture::Thumbv6m
|
||||
|| self.architecture == Architecture::Thumbv7em
|
||||
|| self.architecture == Architecture::Thumbv7m
|
||||
|| self.architecture == Architecture::Thumbv8mBase
|
||||
|| self.architecture == Architecture::Thumbv8mMain
|
||||
|| self.architecture == Architecture::Msp430)))
|
||||
{
|
||||
// "none" is special-case shorthand for unknown vendor and unknown operating system.
|
||||
f.write_str("-none")?;
|
||||
} else if self.operating_system == OperatingSystem::Linux
|
||||
&& (self.environment == Environment::Android
|
||||
|| self.environment == Environment::Androideabi)
|
||||
{
|
||||
// As a special case, omit the vendor for Android targets.
|
||||
// As a special case, omit the vendor for Android, Fuchsia, and sometimes
|
||||
// None_, depending on the hardware architecture. This logic is entirely
|
||||
// ad-hoc, and is just sufficient to handle the current set of recognized
|
||||
// triples.
|
||||
write!(f, "-{}", self.operating_system)?;
|
||||
} else {
|
||||
write!(f, "-{}-{}", self.vendor, self.operating_system)?;
|
||||
|
@ -203,16 +210,7 @@ impl FromStr for Triple {
|
|||
let mut has_vendor = false;
|
||||
let mut has_operating_system = false;
|
||||
if let Some(s) = current_part {
|
||||
// "none" is special-case shorthand for unknown vendor and unknown operating system.
|
||||
if s == "none" {
|
||||
has_operating_system = true;
|
||||
has_vendor = true;
|
||||
current_part = parts.next();
|
||||
// "none" requires an explicit environment or binary format.
|
||||
if current_part.is_none() {
|
||||
return Err(ParseError::NoneWithoutBinaryFormat);
|
||||
}
|
||||
} else if let Ok(vendor) = Vendor::from_str(s) {
|
||||
if let Ok(vendor) = Vendor::from_str(s) {
|
||||
has_vendor = true;
|
||||
result.vendor = vendor;
|
||||
current_part = parts.next();
|
||||
|
|
|
@ -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"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "wasmparser"
|
||||
version = "0.23.0"
|
||||
version = "0.29.2"
|
||||
authors = ["Yury Delendik <ydelendik@mozilla.com>"]
|
||||
exclude = ["fuzz/**/*", "tests/**/*"]
|
||||
description = "A simple event-driven library for parsing WebAssembly binary files.\n"
|
||||
|
|
|
@ -9,10 +9,6 @@ use wasmparser::Parser;
|
|||
use wasmparser::ParserState;
|
||||
use wasmparser::WasmDecoder;
|
||||
|
||||
fn get_name(bytes: &[u8]) -> &str {
|
||||
str::from_utf8(bytes).ok().unwrap()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
|
@ -32,9 +28,7 @@ fn main() {
|
|||
} => {
|
||||
println!(
|
||||
"ExportSectionEntry {{ field: \"{}\", kind: {:?}, index: {} }}",
|
||||
get_name(field),
|
||||
kind,
|
||||
index
|
||||
field, kind, index
|
||||
);
|
||||
}
|
||||
ParserState::ImportSectionEntry {
|
||||
|
@ -44,9 +38,7 @@ fn main() {
|
|||
} => {
|
||||
println!(
|
||||
"ImportSectionEntry {{ module: \"{}\", field: \"{}\", ty: {:?} }}",
|
||||
get_name(module),
|
||||
get_name(field),
|
||||
ty
|
||||
module, field, ty
|
||||
);
|
||||
}
|
||||
ParserState::EndWasm => break,
|
||||
|
|
|
@ -9,10 +9,6 @@ use wasmparser::Parser;
|
|||
use wasmparser::ParserState;
|
||||
use wasmparser::WasmDecoder;
|
||||
|
||||
fn get_name(bytes: &[u8]) -> &str {
|
||||
str::from_utf8(bytes).ok().unwrap()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
|
@ -31,10 +27,10 @@ fn main() {
|
|||
ParserState::ExportSectionEntry {
|
||||
field, ref kind, ..
|
||||
} => {
|
||||
println!(" Export {} {:?}", get_name(field), kind);
|
||||
println!(" Export {} {:?}", field, kind);
|
||||
}
|
||||
ParserState::ImportSectionEntry { module, field, .. } => {
|
||||
println!(" Import {}::{}", get_name(module), get_name(field))
|
||||
println!(" Import {}::{}", module, field)
|
||||
}
|
||||
ParserState::EndWasm => break,
|
||||
ParserState::Error(err) => panic!("Error: {:?}", err),
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::str;
|
||||
use std::vec::Vec;
|
||||
|
||||
use limits::{
|
||||
|
@ -24,35 +25,17 @@ use limits::{
|
|||
use primitives::{
|
||||
BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32,
|
||||
Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType,
|
||||
ResizableLimits, Result, SectionCode, TableType, Type,
|
||||
ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type, V128,
|
||||
};
|
||||
|
||||
const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
|
||||
|
||||
fn is_name(name: &[u8], expected: &'static str) -> bool {
|
||||
if name.len() != expected.len() {
|
||||
return false;
|
||||
}
|
||||
let expected_bytes = expected.as_bytes();
|
||||
for i in 0..name.len() {
|
||||
if name[i] != expected_bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
fn is_name(name: &str, expected: &'static str) -> bool {
|
||||
name == expected
|
||||
}
|
||||
|
||||
fn is_name_prefix(name: &[u8], prefix: &'static str) -> bool {
|
||||
if name.len() < prefix.len() {
|
||||
return false;
|
||||
}
|
||||
let expected_bytes = prefix.as_bytes();
|
||||
for i in 0..expected_bytes.len() {
|
||||
if name[i] != expected_bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
fn is_name_prefix(name: &str, prefix: &'static str) -> bool {
|
||||
name.starts_with(prefix)
|
||||
}
|
||||
|
||||
const WASM_MAGIC_NUMBER: u32 = 0x6d736100;
|
||||
|
@ -123,6 +106,13 @@ impl<'a> BinaryReader<'a> {
|
|||
self.original_offset + self.position
|
||||
}
|
||||
|
||||
pub fn range(&self) -> Range {
|
||||
Range {
|
||||
start: self.original_offset,
|
||||
end: self.original_offset + self.buffer.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_has_byte(&self) -> Result<()> {
|
||||
if self.position < self.buffer.len() {
|
||||
Ok(())
|
||||
|
@ -185,6 +175,7 @@ impl<'a> BinaryReader<'a> {
|
|||
-0x02 => Ok(Type::I64),
|
||||
-0x03 => Ok(Type::F32),
|
||||
-0x04 => Ok(Type::F64),
|
||||
-0x05 => Ok(Type::V128),
|
||||
-0x10 => Ok(Type::AnyFunc),
|
||||
-0x11 => Ok(Type::AnyRef),
|
||||
-0x20 => Ok(Type::Func),
|
||||
|
@ -332,6 +323,8 @@ impl<'a> BinaryReader<'a> {
|
|||
let name = self.read_string()?;
|
||||
let kind = if is_name(name, "name") {
|
||||
CustomSectionKind::Name
|
||||
} else if is_name(name, "producers") {
|
||||
CustomSectionKind::Producers
|
||||
} else if is_name(name, "sourceMappingURL") {
|
||||
CustomSectionKind::SourceMappingURL
|
||||
} else if is_name_prefix(name, "reloc.") {
|
||||
|
@ -354,6 +347,7 @@ impl<'a> BinaryReader<'a> {
|
|||
9 => Ok(SectionCode::Element),
|
||||
10 => Ok(SectionCode::Code),
|
||||
11 => Ok(SectionCode::Data),
|
||||
12 => Ok(SectionCode::DataCount),
|
||||
_ => Err(BinaryReaderError {
|
||||
message: "Invalid section code",
|
||||
offset,
|
||||
|
@ -376,6 +370,7 @@ impl<'a> BinaryReader<'a> {
|
|||
self.skip_var_32()?;
|
||||
Ok(BrTable {
|
||||
buffer: &self.buffer[start..self.position],
|
||||
cnt: targets_len as usize,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -558,7 +553,7 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok(Ieee64(value))
|
||||
}
|
||||
|
||||
pub fn read_string(&mut self) -> Result<&'a [u8]> {
|
||||
pub fn read_string(&mut self) -> Result<&'a str> {
|
||||
let len = self.read_var_u32()? as usize;
|
||||
if len > MAX_WASM_STRING_SIZE {
|
||||
return Err(BinaryReaderError {
|
||||
|
@ -566,7 +561,11 @@ impl<'a> BinaryReader<'a> {
|
|||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
self.read_bytes(len)
|
||||
let bytes = self.read_bytes(len)?;
|
||||
str::from_utf8(bytes).map_err(|_| BinaryReaderError {
|
||||
message: "non-utf8 string",
|
||||
offset: self.original_position() - 1,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_memarg_of_align(&mut self, align: u32) -> Result<MemoryImmediate> {
|
||||
|
@ -786,7 +785,7 @@ impl<'a> BinaryReader<'a> {
|
|||
return Err(BinaryReaderError {
|
||||
message: "Unknown 0xFE opcode",
|
||||
offset: self.original_position() - 1,
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -822,7 +821,7 @@ impl<'a> BinaryReader<'a> {
|
|||
},
|
||||
0x11 => Operator::CallIndirect {
|
||||
index: self.read_var_u32()?,
|
||||
table_index: self.read_var_u1()?,
|
||||
table_index: self.read_var_u32()?,
|
||||
},
|
||||
0x1a => Operator::Drop,
|
||||
0x1b => Operator::Select,
|
||||
|
@ -841,6 +840,12 @@ impl<'a> BinaryReader<'a> {
|
|||
0x24 => Operator::SetGlobal {
|
||||
global_index: self.read_var_u32()?,
|
||||
},
|
||||
0x25 => Operator::TableGet {
|
||||
table: self.read_var_u32()?,
|
||||
},
|
||||
0x26 => Operator::TableSet {
|
||||
table: self.read_var_u32()?,
|
||||
},
|
||||
0x28 => Operator::I32Load {
|
||||
memarg: self.read_memarg()?,
|
||||
},
|
||||
|
@ -1062,14 +1067,14 @@ impl<'a> BinaryReader<'a> {
|
|||
0xd1 => Operator::RefIsNull,
|
||||
|
||||
0xfc => self.read_0xfc_operator()?,
|
||||
|
||||
0xfd => self.read_0xfd_operator()?,
|
||||
0xfe => self.read_0xfe_operator()?,
|
||||
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Unknown opcode",
|
||||
offset: self.original_position() - 1,
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1086,11 +1091,304 @@ impl<'a> BinaryReader<'a> {
|
|||
0x06 => Operator::I64TruncSSatF64,
|
||||
0x07 => Operator::I64TruncUSatF64,
|
||||
|
||||
0x08 => {
|
||||
let segment = self.read_var_u32()?;
|
||||
let mem = self.read_u8()?;
|
||||
if mem != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::MemoryInit { segment }
|
||||
}
|
||||
0x09 => {
|
||||
let segment = self.read_var_u32()?;
|
||||
Operator::DataDrop { segment }
|
||||
}
|
||||
0x0a => {
|
||||
let src = self.read_u8()?;
|
||||
if src != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
let dst = self.read_u8()?;
|
||||
if dst != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::MemoryCopy
|
||||
}
|
||||
0x0b => {
|
||||
let mem = self.read_u8()?;
|
||||
if mem != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::MemoryFill
|
||||
}
|
||||
0x0c => {
|
||||
let segment = self.read_var_u32()?;
|
||||
let table = self.read_u8()?;
|
||||
if table != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::TableInit { segment }
|
||||
}
|
||||
0x0d => {
|
||||
let segment = self.read_var_u32()?;
|
||||
Operator::ElemDrop { segment }
|
||||
}
|
||||
0x0e => {
|
||||
let src = self.read_u8()?;
|
||||
if src != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
let dst = self.read_u8()?;
|
||||
if dst != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::TableCopy
|
||||
}
|
||||
|
||||
0x0f => {
|
||||
let table = self.read_var_u32()?;
|
||||
Operator::TableGrow { table }
|
||||
}
|
||||
0x10 => {
|
||||
let table = self.read_var_u32()?;
|
||||
Operator::TableSize { table }
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Unknown 0xfc opcode",
|
||||
offset: self.original_position() - 1,
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn read_line_index(&mut self, max: u32) -> Result<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> {
|
||||
/// Returns the number of `br_table` entries, not including the default
|
||||
/// label
|
||||
pub fn len(&self) -> usize {
|
||||
self.cnt
|
||||
}
|
||||
|
||||
/// Reads br_table entries.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -66,6 +66,7 @@ pub use primitives::Result;
|
|||
pub use primitives::SectionCode;
|
||||
pub use primitives::TableType;
|
||||
pub use primitives::Type;
|
||||
pub use primitives::V128;
|
||||
|
||||
pub use validator::validate;
|
||||
pub use validator::OperatorValidatorConfig;
|
||||
|
@ -76,10 +77,12 @@ pub use validator::WasmModuleResources;
|
|||
|
||||
pub use readers::CodeSectionReader;
|
||||
pub use readers::Data;
|
||||
pub use readers::DataKind;
|
||||
pub use readers::DataSectionReader;
|
||||
pub use readers::Element;
|
||||
pub use readers::ElementItems;
|
||||
pub use readers::ElementItemsReader;
|
||||
pub use readers::ElementKind;
|
||||
pub use readers::ElementSectionReader;
|
||||
pub use readers::Export;
|
||||
pub use readers::ExportSectionReader;
|
||||
|
@ -98,6 +101,9 @@ pub use readers::Name;
|
|||
pub use readers::NameSectionReader;
|
||||
pub use readers::NamingReader;
|
||||
pub use readers::OperatorsReader;
|
||||
pub use readers::ProducersField;
|
||||
pub use readers::ProducersFieldValue;
|
||||
pub use readers::ProducersSectionReader;
|
||||
pub use readers::Reloc;
|
||||
pub use readers::RelocSectionReader;
|
||||
pub use readers::Section;
|
||||
|
|
|
@ -28,11 +28,11 @@ use primitives::{
|
|||
};
|
||||
|
||||
use readers::{
|
||||
CodeSectionReader, Data, DataSectionReader, Element, ElementItems, ElementSectionReader,
|
||||
Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global, GlobalSectionReader,
|
||||
Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader, ModuleReader, Name,
|
||||
NameSectionReader, NamingReader, OperatorsReader, Reloc, RelocSectionReader, Section,
|
||||
SectionReader, TableSectionReader, TypeSectionReader,
|
||||
CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
|
||||
ElementSectionReader, Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global,
|
||||
GlobalSectionReader, Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader,
|
||||
ModuleReader, Name, NameSectionReader, NamingReader, OperatorsReader, Reloc,
|
||||
RelocSectionReader, Section, SectionReader, TableSectionReader, TypeSectionReader,
|
||||
};
|
||||
|
||||
use binary_reader::{BinaryReader, Range};
|
||||
|
@ -47,7 +47,7 @@ pub struct LocalName<'a> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum NameEntry<'a> {
|
||||
Module(&'a [u8]),
|
||||
Module(&'a str),
|
||||
Function(Box<[Naming<'a>]>),
|
||||
Local(Box<[LocalName<'a>]>),
|
||||
}
|
||||
|
@ -86,20 +86,21 @@ pub enum ParserState<'a> {
|
|||
|
||||
TypeSectionEntry(FuncType),
|
||||
ImportSectionEntry {
|
||||
module: &'a [u8],
|
||||
field: &'a [u8],
|
||||
module: &'a str,
|
||||
field: &'a str,
|
||||
ty: ImportSectionEntryType,
|
||||
},
|
||||
FunctionSectionEntry(u32),
|
||||
TableSectionEntry(TableType),
|
||||
MemorySectionEntry(MemoryType),
|
||||
ExportSectionEntry {
|
||||
field: &'a [u8],
|
||||
field: &'a str,
|
||||
kind: ExternalKind,
|
||||
index: u32,
|
||||
},
|
||||
NameSectionEntry(NameEntry<'a>),
|
||||
StartSectionEntry(u32),
|
||||
DataCountSectionEntry(u32),
|
||||
|
||||
BeginInitExpressionBody,
|
||||
InitExpressionOperator(Operator<'a>),
|
||||
|
@ -115,11 +116,13 @@ pub enum ParserState<'a> {
|
|||
EndFunctionBody,
|
||||
SkippingFunctionBody,
|
||||
|
||||
BeginElementSectionEntry(u32),
|
||||
BeginPassiveElementSectionEntry(Type),
|
||||
BeginActiveElementSectionEntry(u32),
|
||||
ElementSectionEntryBody(Box<[u32]>),
|
||||
EndElementSectionEntry,
|
||||
|
||||
BeginDataSectionEntry(u32),
|
||||
BeginPassiveDataSectionEntry,
|
||||
BeginActiveDataSectionEntry(u32),
|
||||
EndDataSectionEntry,
|
||||
BeginDataSectionEntryBody(u32),
|
||||
DataSectionEntryBodyChunk(&'a [u8]),
|
||||
|
@ -132,7 +135,7 @@ pub enum ParserState<'a> {
|
|||
RelocSectionEntry(RelocEntry),
|
||||
LinkingSectionEntry(LinkingType),
|
||||
|
||||
SourceMappingURL(&'a [u8]),
|
||||
SourceMappingURL(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -269,33 +272,33 @@ impl<'a> Parser<'a> {
|
|||
ParserSectionReader::CodeSectionReader(ref reader) => return reader.original_position(),
|
||||
ParserSectionReader::DataSectionReader(ref reader) => return reader.original_position(),
|
||||
ParserSectionReader::ElementSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::ExportSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::FunctionSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::GlobalSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::ImportSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::MemorySectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::TableSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::TypeSectionReader(ref reader) => return reader.original_position(),
|
||||
ParserSectionReader::NameSectionReader(ref reader) => return reader.original_position(),
|
||||
ParserSectionReader::LinkingSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
ParserSectionReader::RelocSectionReader(ref reader) => {
|
||||
return reader.original_position()
|
||||
return reader.original_position();
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
@ -317,7 +320,7 @@ impl<'a> Parser<'a> {
|
|||
fn read_section_header(&mut self) -> Result<()> {
|
||||
let section = self.module_reader.as_mut().expect("module reader").read()?;
|
||||
let code = section.code;
|
||||
let range = section.get_range();
|
||||
let range = section.range();
|
||||
self.current_section = Some(section);
|
||||
self.state = ParserState::BeginSection { code, range };
|
||||
Ok(())
|
||||
|
@ -408,13 +411,19 @@ impl<'a> Parser<'a> {
|
|||
if self.section_entries_left == 0 {
|
||||
return self.check_section_end();
|
||||
}
|
||||
let Element {
|
||||
table_index,
|
||||
init_expr,
|
||||
items,
|
||||
} = section_reader!(self, ElementSectionReader).read()?;
|
||||
self.state = ParserState::BeginElementSectionEntry(table_index);
|
||||
self.operators_reader = Some(init_expr.get_operators_reader());
|
||||
let Element { kind, items } = section_reader!(self, ElementSectionReader).read()?;
|
||||
match kind {
|
||||
ElementKind::Passive(ty) => {
|
||||
self.state = ParserState::BeginPassiveElementSectionEntry(ty);
|
||||
}
|
||||
ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
} => {
|
||||
self.state = ParserState::BeginActiveElementSectionEntry(table_index);
|
||||
self.operators_reader = Some(init_expr.get_operators_reader());
|
||||
}
|
||||
}
|
||||
self.element_items = Some(items);
|
||||
self.section_entries_left -= 1;
|
||||
Ok(())
|
||||
|
@ -447,7 +456,7 @@ impl<'a> Parser<'a> {
|
|||
return self.check_section_end();
|
||||
}
|
||||
let function_body = section_reader!(self, CodeSectionReader).read()?;
|
||||
let range = function_body.get_range();
|
||||
let range = function_body.range();
|
||||
self.state = ParserState::BeginFunctionBody { range };
|
||||
self.current_function_body = Some(function_body);
|
||||
self.section_entries_left -= 1;
|
||||
|
@ -529,13 +538,19 @@ impl<'a> Parser<'a> {
|
|||
if self.section_entries_left == 0 {
|
||||
return self.check_section_end();
|
||||
}
|
||||
let Data {
|
||||
memory_index,
|
||||
init_expr,
|
||||
data,
|
||||
} = section_reader!(self, DataSectionReader).read()?;
|
||||
self.state = ParserState::BeginDataSectionEntry(memory_index);
|
||||
self.operators_reader = Some(init_expr.get_operators_reader());
|
||||
let Data { kind, data } = section_reader!(self, DataSectionReader).read()?;
|
||||
match kind {
|
||||
DataKind::Passive => {
|
||||
self.state = ParserState::BeginPassiveDataSectionEntry;
|
||||
}
|
||||
DataKind::Active {
|
||||
memory_index,
|
||||
init_expr,
|
||||
} => {
|
||||
self.state = ParserState::BeginActiveDataSectionEntry(memory_index);
|
||||
self.operators_reader = Some(init_expr.get_operators_reader());
|
||||
}
|
||||
}
|
||||
self.current_data_segment = Some(data);
|
||||
self.section_entries_left -= 1;
|
||||
Ok(())
|
||||
|
@ -731,6 +746,17 @@ impl<'a> Parser<'a> {
|
|||
.get_start_section_content()?;
|
||||
self.state = ParserState::StartSectionEntry(func_index);
|
||||
}
|
||||
ParserState::BeginSection {
|
||||
code: SectionCode::DataCount,
|
||||
..
|
||||
} => {
|
||||
let func_index = self
|
||||
.current_section
|
||||
.as_ref()
|
||||
.expect("section")
|
||||
.get_data_count_section_content()?;
|
||||
self.state = ParserState::DataCountSectionEntry(func_index);
|
||||
}
|
||||
ParserState::BeginSection {
|
||||
code: SectionCode::Custom { .. },
|
||||
..
|
||||
|
@ -774,7 +800,8 @@ impl<'a> Parser<'a> {
|
|||
start_section_reader!(self, LinkingSectionReader, get_linking_section_reader);
|
||||
self.read_linking_entry()?;
|
||||
}
|
||||
ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => {
|
||||
ParserState::ReadingCustomSection(CustomSectionKind::Producers)
|
||||
| ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => {
|
||||
self.create_custom_section_binary_reader();
|
||||
self.read_section_body_bytes()?;
|
||||
}
|
||||
|
@ -875,13 +902,17 @@ impl<'a> Parser<'a> {
|
|||
self.read_init_expression_body(InitExpressionContinuation::GlobalSection)
|
||||
}
|
||||
ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
|
||||
ParserState::BeginElementSectionEntry(_) => {
|
||||
ParserState::BeginPassiveElementSectionEntry(_) => self.read_element_entry_body()?,
|
||||
ParserState::BeginActiveElementSectionEntry(_) => {
|
||||
self.read_init_expression_body(InitExpressionContinuation::ElementSection)
|
||||
}
|
||||
ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => {
|
||||
self.read_init_expression_operator()?
|
||||
}
|
||||
ParserState::BeginDataSectionEntry(_) => {
|
||||
ParserState::BeginPassiveDataSectionEntry => {
|
||||
self.read_data_entry_body()?;
|
||||
}
|
||||
ParserState::BeginActiveDataSectionEntry(_) => {
|
||||
self.read_init_expression_body(InitExpressionContinuation::DataSection)
|
||||
}
|
||||
ParserState::EndInitExpressionBody => {
|
||||
|
@ -917,6 +948,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
ParserState::EndElementSectionEntry => self.read_element_entry()?,
|
||||
ParserState::StartSectionEntry(_) => self.position_to_section_end()?,
|
||||
ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?,
|
||||
ParserState::NameSectionEntry(_) => self.read_name_entry()?,
|
||||
ParserState::SourceMappingURL(_) => self.position_to_section_end()?,
|
||||
ParserState::RelocSectionHeader(_) => {
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
*/
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -24,10 +26,19 @@ pub struct BinaryReaderError {
|
|||
|
||||
pub type Result<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)]
|
||||
pub enum CustomSectionKind {
|
||||
Unknown,
|
||||
Name,
|
||||
Producers,
|
||||
SourceMappingURL,
|
||||
Reloc,
|
||||
Linking,
|
||||
|
@ -39,20 +50,21 @@ pub enum CustomSectionKind {
|
|||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SectionCode<'a> {
|
||||
Custom {
|
||||
name: &'a [u8],
|
||||
name: &'a str,
|
||||
kind: CustomSectionKind,
|
||||
},
|
||||
Type, // Function signature declarations
|
||||
Import, // Import declarations
|
||||
Function, // Function declarations
|
||||
Table, // Indirect function table and other tables
|
||||
Memory, // Memory attributes
|
||||
Global, // Global declarations
|
||||
Export, // Exports
|
||||
Start, // Start function declaration
|
||||
Element, // Elements section
|
||||
Code, // Function bodies (code)
|
||||
Data, // Data segments
|
||||
Type, // Function signature declarations
|
||||
Import, // Import declarations
|
||||
Function, // Function declarations
|
||||
Table, // Indirect function table and other tables
|
||||
Memory, // Memory attributes
|
||||
Global, // Global declarations
|
||||
Export, // Exports
|
||||
Start, // Start function declaration
|
||||
Element, // Elements section
|
||||
Code, // Function bodies (code)
|
||||
Data, // Data segments
|
||||
DataCount, // Count of passive data segments
|
||||
}
|
||||
|
||||
/// Types as defined [here].
|
||||
|
@ -64,6 +76,7 @@ pub enum Type {
|
|||
I64,
|
||||
F32,
|
||||
F64,
|
||||
V128,
|
||||
AnyFunc,
|
||||
AnyRef,
|
||||
Func,
|
||||
|
@ -129,7 +142,7 @@ pub struct MemoryImmediate {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Naming<'a> {
|
||||
pub index: u32,
|
||||
pub name: &'a [u8],
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -160,6 +173,7 @@ pub enum RelocType {
|
|||
#[derive(Debug)]
|
||||
pub struct BrTable<'a> {
|
||||
pub(crate) buffer: &'a [u8],
|
||||
pub(crate) cnt: usize,
|
||||
}
|
||||
|
||||
/// An IEEE binary32 immediate floating point value, represented as a u32
|
||||
|
@ -188,6 +202,17 @@ impl Ieee64 {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct V128(pub(crate) [u8; 16]);
|
||||
|
||||
impl V128 {
|
||||
pub fn bytes(&self) -> &[u8; 16] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub type SIMDLineIndex = u8;
|
||||
|
||||
/// Instructions as defined [here].
|
||||
///
|
||||
/// [here]: https://webassembly.github.io/spec/binary/instructions.html
|
||||
|
@ -384,6 +409,20 @@ pub enum Operator<'a> {
|
|||
I64TruncSSatF64,
|
||||
I64TruncUSatF64,
|
||||
|
||||
// 0xFC operators
|
||||
// bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
|
||||
MemoryInit { segment: u32 },
|
||||
DataDrop { segment: u32 },
|
||||
MemoryCopy,
|
||||
MemoryFill,
|
||||
TableInit { segment: u32 },
|
||||
ElemDrop { segment: u32 },
|
||||
TableCopy,
|
||||
TableGet { table: u32 },
|
||||
TableSet { table: u32 },
|
||||
TableGrow { table: u32 },
|
||||
TableSize { table: u32 },
|
||||
|
||||
// 0xFE operators
|
||||
// https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
|
||||
Wake { memarg: MemoryImmediate },
|
||||
|
@ -452,4 +491,147 @@ pub enum Operator<'a> {
|
|||
I64AtomicRmw8UCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UCmpxchg { memarg: MemoryImmediate },
|
||||
|
||||
// 0xFD operators
|
||||
// SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md
|
||||
V128Load { memarg: MemoryImmediate },
|
||||
V128Store { memarg: MemoryImmediate },
|
||||
V128Const { value: V128 },
|
||||
V8x16Shuffle { lines: [SIMDLineIndex; 16] },
|
||||
I8x16Splat,
|
||||
I8x16ExtractLaneS { line: SIMDLineIndex },
|
||||
I8x16ExtractLaneU { line: SIMDLineIndex },
|
||||
I8x16ReplaceLane { line: SIMDLineIndex },
|
||||
I16x8Splat,
|
||||
I16x8ExtractLaneS { line: SIMDLineIndex },
|
||||
I16x8ExtractLaneU { line: SIMDLineIndex },
|
||||
I16x8ReplaceLane { line: SIMDLineIndex },
|
||||
I32x4Splat,
|
||||
I32x4ExtractLane { line: SIMDLineIndex },
|
||||
I32x4ReplaceLane { line: SIMDLineIndex },
|
||||
I64x2Splat,
|
||||
I64x2ExtractLane { line: SIMDLineIndex },
|
||||
I64x2ReplaceLane { line: SIMDLineIndex },
|
||||
F32x4Splat,
|
||||
F32x4ExtractLane { line: SIMDLineIndex },
|
||||
F32x4ReplaceLane { line: SIMDLineIndex },
|
||||
F64x2Splat,
|
||||
F64x2ExtractLane { line: SIMDLineIndex },
|
||||
F64x2ReplaceLane { line: SIMDLineIndex },
|
||||
I8x16Eq,
|
||||
I8x16Ne,
|
||||
I8x16LtS,
|
||||
I8x16LtU,
|
||||
I8x16GtS,
|
||||
I8x16GtU,
|
||||
I8x16LeS,
|
||||
I8x16LeU,
|
||||
I8x16GeS,
|
||||
I8x16GeU,
|
||||
I16x8Eq,
|
||||
I16x8Ne,
|
||||
I16x8LtS,
|
||||
I16x8LtU,
|
||||
I16x8GtS,
|
||||
I16x8GtU,
|
||||
I16x8LeS,
|
||||
I16x8LeU,
|
||||
I16x8GeS,
|
||||
I16x8GeU,
|
||||
I32x4Eq,
|
||||
I32x4Ne,
|
||||
I32x4LtS,
|
||||
I32x4LtU,
|
||||
I32x4GtS,
|
||||
I32x4GtU,
|
||||
I32x4LeS,
|
||||
I32x4LeU,
|
||||
I32x4GeS,
|
||||
I32x4GeU,
|
||||
F32x4Eq,
|
||||
F32x4Ne,
|
||||
F32x4Lt,
|
||||
F32x4Gt,
|
||||
F32x4Le,
|
||||
F32x4Ge,
|
||||
F64x2Eq,
|
||||
F64x2Ne,
|
||||
F64x2Lt,
|
||||
F64x2Gt,
|
||||
F64x2Le,
|
||||
F64x2Ge,
|
||||
V128Not,
|
||||
V128And,
|
||||
V128Or,
|
||||
V128Xor,
|
||||
V128Bitselect,
|
||||
I8x16Neg,
|
||||
I8x16AnyTrue,
|
||||
I8x16AllTrue,
|
||||
I8x16Shl,
|
||||
I8x16ShrS,
|
||||
I8x16ShrU,
|
||||
I8x16Add,
|
||||
I8x16AddSaturateS,
|
||||
I8x16AddSaturateU,
|
||||
I8x16Sub,
|
||||
I8x16SubSaturateS,
|
||||
I8x16SubSaturateU,
|
||||
I8x16Mul,
|
||||
I16x8Neg,
|
||||
I16x8AnyTrue,
|
||||
I16x8AllTrue,
|
||||
I16x8Shl,
|
||||
I16x8ShrS,
|
||||
I16x8ShrU,
|
||||
I16x8Add,
|
||||
I16x8AddSaturateS,
|
||||
I16x8AddSaturateU,
|
||||
I16x8Sub,
|
||||
I16x8SubSaturateS,
|
||||
I16x8SubSaturateU,
|
||||
I16x8Mul,
|
||||
I32x4Neg,
|
||||
I32x4AnyTrue,
|
||||
I32x4AllTrue,
|
||||
I32x4Shl,
|
||||
I32x4ShrS,
|
||||
I32x4ShrU,
|
||||
I32x4Add,
|
||||
I32x4Sub,
|
||||
I32x4Mul,
|
||||
I64x2Neg,
|
||||
I64x2AnyTrue,
|
||||
I64x2AllTrue,
|
||||
I64x2Shl,
|
||||
I64x2ShrS,
|
||||
I64x2ShrU,
|
||||
I64x2Add,
|
||||
I64x2Sub,
|
||||
F32x4Abs,
|
||||
F32x4Neg,
|
||||
F32x4Sqrt,
|
||||
F32x4Add,
|
||||
F32x4Sub,
|
||||
F32x4Mul,
|
||||
F32x4Div,
|
||||
F32x4Min,
|
||||
F32x4Max,
|
||||
F64x2Abs,
|
||||
F64x2Neg,
|
||||
F64x2Sqrt,
|
||||
F64x2Add,
|
||||
F64x2Sub,
|
||||
F64x2Mul,
|
||||
F64x2Div,
|
||||
F64x2Min,
|
||||
F64x2Max,
|
||||
I32x4TruncSF32x4Sat,
|
||||
I32x4TruncUF32x4Sat,
|
||||
I64x2TruncSF64x2Sat,
|
||||
I64x2TruncUF64x2Sat,
|
||||
F32x4ConvertSI32x4,
|
||||
F32x4ConvertUI32x4,
|
||||
F64x2ConvertSI64x2,
|
||||
F64x2ConvertUI64x2,
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ impl<'a> FunctionBody<'a> {
|
|||
Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
|
||||
}
|
||||
|
||||
pub(crate) fn get_range(&self) -> Range {
|
||||
pub fn range(&self) -> Range {
|
||||
Range {
|
||||
start: self.offset,
|
||||
end: self.offset + self.data.len(),
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -20,11 +20,19 @@ use super::{
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Data<'a> {
|
||||
pub memory_index: u32,
|
||||
pub init_expr: InitExpr<'a>,
|
||||
pub kind: DataKind<'a>,
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum DataKind<'a> {
|
||||
Passive,
|
||||
Active {
|
||||
memory_index: u32,
|
||||
init_expr: InitExpr<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct DataSectionReader<'a> {
|
||||
reader: BinaryReader<'a>,
|
||||
count: u32,
|
||||
|
@ -64,7 +72,7 @@ impl<'a> DataSectionReader<'a> {
|
|||
/// # 0x05, 0x03, 0x01, 0x00, 0x02,
|
||||
/// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b,
|
||||
/// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00];
|
||||
/// use wasmparser::ModuleReader;
|
||||
/// use wasmparser::{ModuleReader, DataKind};
|
||||
/// let mut reader = ModuleReader::new(data).expect("module reader");
|
||||
/// let section = reader.read().expect("type section");
|
||||
/// let section = reader.read().expect("function section");
|
||||
|
@ -75,32 +83,48 @@ impl<'a> DataSectionReader<'a> {
|
|||
/// for _ in 0..data_reader.get_count() {
|
||||
/// let data = data_reader.read().expect("data");
|
||||
/// println!("Data: {:?}", data);
|
||||
/// let mut init_expr_reader = data.init_expr.get_binary_reader();
|
||||
/// let op = init_expr_reader.read_operator().expect("op");
|
||||
/// println!("Init const: {:?}", op);
|
||||
/// if let DataKind::Active { init_expr, .. } = data.kind {
|
||||
/// let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
/// let op = init_expr_reader.read_operator().expect("op");
|
||||
/// println!("Init const: {:?}", op);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn read<'b>(&mut self) -> Result<Data<'b>>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
let memory_index = self.reader.read_var_u32()?;
|
||||
let init_expr = {
|
||||
let expr_offset = self.reader.position;
|
||||
self.reader.skip_init_expr()?;
|
||||
let data = &self.reader.buffer[expr_offset..self.reader.position];
|
||||
InitExpr::new(data, self.reader.original_offset + expr_offset)
|
||||
let flags = self.reader.read_var_u32()?;
|
||||
let kind = if flags == 1 {
|
||||
DataKind::Passive
|
||||
} else {
|
||||
let memory_index = match flags {
|
||||
0 => 0,
|
||||
2 => self.reader.read_var_u32()?,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid flags byte in data segment",
|
||||
offset: self.reader.original_position() - 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
let init_expr = {
|
||||
let expr_offset = self.reader.position;
|
||||
self.reader.skip_init_expr()?;
|
||||
let data = &self.reader.buffer[expr_offset..self.reader.position];
|
||||
InitExpr::new(data, self.reader.original_offset + expr_offset)
|
||||
};
|
||||
DataKind::Active {
|
||||
memory_index,
|
||||
init_expr,
|
||||
}
|
||||
};
|
||||
let data_len = self.reader.read_var_u32()? as usize;
|
||||
let data_end = self.reader.position + data_len;
|
||||
self.verify_data_end(data_end)?;
|
||||
let data = &self.reader.buffer[self.reader.position..data_end];
|
||||
self.reader.skip_to(data_end);
|
||||
Ok(Data {
|
||||
memory_index,
|
||||
init_expr,
|
||||
data,
|
||||
})
|
||||
Ok(Data { kind, data })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,16 +14,25 @@
|
|||
*/
|
||||
|
||||
use super::{
|
||||
BinaryReader, InitExpr, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems,
|
||||
BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
|
||||
SectionWithLimitedItems, Type,
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Element<'a> {
|
||||
pub table_index: u32,
|
||||
pub init_expr: InitExpr<'a>,
|
||||
pub kind: ElementKind<'a>,
|
||||
pub items: ElementItems<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ElementKind<'a> {
|
||||
Passive(Type),
|
||||
Active {
|
||||
table_index: u32,
|
||||
init_expr: InitExpr<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ElementItems<'a> {
|
||||
offset: usize,
|
||||
|
@ -129,7 +138,7 @@ impl<'a> ElementSectionReader<'a> {
|
|||
/// # 0x05, 0x03, 0x01, 0x00, 0x02,
|
||||
/// # 0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00,
|
||||
/// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
|
||||
/// use wasmparser::ModuleReader;
|
||||
/// use wasmparser::{ModuleReader, ElementKind};
|
||||
///use wasmparser::Result;
|
||||
/// let mut reader = ModuleReader::new(data).expect("module reader");
|
||||
/// let section = reader.read().expect("type section");
|
||||
|
@ -140,9 +149,11 @@ impl<'a> ElementSectionReader<'a> {
|
|||
/// for _ in 0..element_reader.get_count() {
|
||||
/// let element = element_reader.read().expect("element");
|
||||
/// println!("Element: {:?}", element);
|
||||
/// let mut init_expr_reader = element.init_expr.get_binary_reader();
|
||||
/// let op = init_expr_reader.read_operator().expect("op");
|
||||
/// println!("Init const: {:?}", op);
|
||||
/// if let ElementKind::Active { init_expr, .. } = element.kind {
|
||||
/// let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
/// let op = init_expr_reader.read_operator().expect("op");
|
||||
/// println!("Init const: {:?}", op);
|
||||
/// }
|
||||
/// let mut items_reader = element.items.get_items_reader().expect("items reader");
|
||||
/// for _ in 0..items_reader.get_count() {
|
||||
/// let item = items_reader.read().expect("item");
|
||||
|
@ -154,12 +165,31 @@ impl<'a> ElementSectionReader<'a> {
|
|||
where
|
||||
'a: 'b,
|
||||
{
|
||||
let table_index = self.reader.read_var_u32()?;
|
||||
let init_expr = {
|
||||
let expr_offset = self.reader.position;
|
||||
self.reader.skip_init_expr()?;
|
||||
let data = &self.reader.buffer[expr_offset..self.reader.position];
|
||||
InitExpr::new(data, self.reader.original_offset + expr_offset)
|
||||
let flags = self.reader.read_var_u32()?;
|
||||
let kind = if flags == 1 {
|
||||
let ty = self.reader.read_type()?;
|
||||
ElementKind::Passive(ty)
|
||||
} else {
|
||||
let table_index = match flags {
|
||||
0 => 0,
|
||||
2 => self.reader.read_var_u32()?,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid flags byte in element segment",
|
||||
offset: self.reader.original_position() - 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
let init_expr = {
|
||||
let expr_offset = self.reader.position;
|
||||
self.reader.skip_init_expr()?;
|
||||
let data = &self.reader.buffer[expr_offset..self.reader.position];
|
||||
InitExpr::new(data, self.reader.original_offset + expr_offset)
|
||||
};
|
||||
ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
}
|
||||
};
|
||||
let data_start = self.reader.position;
|
||||
let items_count = self.reader.read_var_u32()?;
|
||||
|
@ -171,11 +201,7 @@ impl<'a> ElementSectionReader<'a> {
|
|||
offset: self.reader.original_offset + data_start,
|
||||
data: &self.reader.buffer[data_start..data_end],
|
||||
};
|
||||
Ok(Element {
|
||||
table_index,
|
||||
init_expr,
|
||||
items,
|
||||
})
|
||||
Ok(Element { kind, items })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use super::{
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Export<'a> {
|
||||
pub field: &'a [u8],
|
||||
pub field: &'a str,
|
||||
pub kind: ExternalKind,
|
||||
pub index: u32,
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ use super::{
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Import<'a> {
|
||||
pub module: &'a [u8],
|
||||
pub field: &'a [u8],
|
||||
pub module: &'a str,
|
||||
pub field: &'a str,
|
||||
pub ty: ImportSectionEntryType,
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,14 @@ use super::SectionHeader;
|
|||
pub use self::code_section::CodeSectionReader;
|
||||
pub use self::code_section::FunctionBody;
|
||||
pub use self::code_section::LocalsReader;
|
||||
use self::data_count_section::read_data_count_section_content;
|
||||
pub use self::data_section::Data;
|
||||
pub use self::data_section::DataKind;
|
||||
pub use self::data_section::DataSectionReader;
|
||||
pub use self::element_section::Element;
|
||||
pub use self::element_section::ElementItems;
|
||||
pub use self::element_section::ElementItemsReader;
|
||||
pub use self::element_section::ElementKind;
|
||||
pub use self::element_section::ElementSectionReader;
|
||||
pub use self::export_section::Export;
|
||||
pub use self::export_section::ExportSectionReader;
|
||||
|
@ -57,6 +60,10 @@ pub use self::name_section::Name;
|
|||
pub use self::name_section::NameSectionReader;
|
||||
pub use self::name_section::NamingReader;
|
||||
|
||||
pub use self::producers_section::ProducersField;
|
||||
pub use self::producers_section::ProducersFieldValue;
|
||||
pub use self::producers_section::ProducersSectionReader;
|
||||
|
||||
pub use self::linking_section::LinkingSectionReader;
|
||||
|
||||
pub use self::reloc_section::Reloc;
|
||||
|
@ -67,6 +74,7 @@ use self::sourcemappingurl_section::read_sourcemappingurl_section_content;
|
|||
pub use self::operators::OperatorsReader;
|
||||
|
||||
mod code_section;
|
||||
mod data_count_section;
|
||||
mod data_section;
|
||||
mod element_section;
|
||||
mod export_section;
|
||||
|
@ -79,6 +87,7 @@ mod memory_section;
|
|||
mod module;
|
||||
mod name_section;
|
||||
mod operators;
|
||||
mod producers_section;
|
||||
mod reloc_section;
|
||||
mod section_reader;
|
||||
mod sourcemappingurl_section;
|
||||
|
|
|
@ -20,10 +20,11 @@ use super::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
read_sourcemappingurl_section_content, read_start_section_content, CodeSectionReader,
|
||||
DataSectionReader, ElementSectionReader, ExportSectionReader, FunctionSectionReader,
|
||||
GlobalSectionReader, ImportSectionReader, LinkingSectionReader, MemorySectionReader,
|
||||
NameSectionReader, RelocSectionReader, TableSectionReader, TypeSectionReader,
|
||||
read_data_count_section_content, read_sourcemappingurl_section_content,
|
||||
read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader,
|
||||
ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader,
|
||||
LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader,
|
||||
RelocSectionReader, TableSectionReader, TypeSectionReader,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -167,6 +168,19 @@ impl<'a> Section<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_producers_section_reader<'b>(&self) -> Result<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>>
|
||||
where
|
||||
'a: 'b,
|
||||
|
@ -200,7 +214,14 @@ impl<'a> Section<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b [u8]>
|
||||
pub fn get_data_count_section_content(&self) -> Result<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
|
||||
'a: 'b,
|
||||
{
|
||||
|
@ -220,7 +241,7 @@ impl<'a> Section<'a> {
|
|||
BinaryReader::new_with_offset(self.data, self.offset)
|
||||
}
|
||||
|
||||
pub(crate) fn get_range(&self) -> Range {
|
||||
pub fn range(&self) -> Range {
|
||||
Range {
|
||||
start: self.offset,
|
||||
end: self.offset + self.data.len(),
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct ModuleName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ModuleName<'a> {
|
||||
pub fn get_name<'b>(&self) -> Result<&'b [u8]>
|
||||
pub fn get_name<'b>(&self) -> Result<&'b str>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ use super::{BinaryReader, BinaryReaderError, Result};
|
|||
pub(crate) fn read_sourcemappingurl_section_content<'a>(
|
||||
data: &'a [u8],
|
||||
offset: usize,
|
||||
) -> Result<&'a [u8]> {
|
||||
) -> Result<&'a str> {
|
||||
let mut reader = BinaryReader::new_with_offset(data, offset);
|
||||
let url = reader.read_string()?;
|
||||
if !reader.eof() {
|
||||
|
|
|
@ -27,6 +27,8 @@ mod simple_tests {
|
|||
operator_config: OperatorValidatorConfig {
|
||||
enable_threads: true,
|
||||
enable_reference_types: true,
|
||||
enable_simd: true,
|
||||
enable_bulk_memory: true,
|
||||
},
|
||||
mutable_global_imports: true,
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ use binary_reader::BinaryReader;
|
|||
|
||||
use primitives::{
|
||||
BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryImmediate,
|
||||
MemoryType, Operator, ResizableLimits, Result, SectionCode, TableType, Type,
|
||||
MemoryType, Operator, ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type,
|
||||
};
|
||||
|
||||
use parser::{Parser, ParserInput, ParserState, WasmDecoder};
|
||||
|
@ -128,6 +128,7 @@ enum SectionOrderState {
|
|||
Export,
|
||||
Start,
|
||||
Element,
|
||||
DataCount,
|
||||
Code,
|
||||
Data,
|
||||
}
|
||||
|
@ -146,6 +147,7 @@ impl SectionOrderState {
|
|||
SectionCode::Element => Some(SectionOrderState::Element),
|
||||
SectionCode::Code => Some(SectionOrderState::Code),
|
||||
SectionCode::Data => Some(SectionOrderState::Data),
|
||||
SectionCode::DataCount => Some(SectionOrderState::DataCount),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -302,6 +304,8 @@ pub trait WasmModuleResources {
|
|||
fn memories(&self) -> &[MemoryType];
|
||||
fn globals(&self) -> &[GlobalType];
|
||||
fn func_type_indices(&self) -> &[u32];
|
||||
fn element_count(&self) -> u32;
|
||||
fn data_count(&self) -> u32;
|
||||
}
|
||||
|
||||
type OperatorValidatorResult<T> = result::Result<T, &'static str>;
|
||||
|
@ -310,11 +314,15 @@ type OperatorValidatorResult<T> = result::Result<T, &'static str>;
|
|||
pub struct OperatorValidatorConfig {
|
||||
pub enable_threads: bool,
|
||||
pub enable_reference_types: bool,
|
||||
pub enable_simd: bool,
|
||||
pub enable_bulk_memory: bool,
|
||||
}
|
||||
|
||||
const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = OperatorValidatorConfig {
|
||||
enable_threads: false,
|
||||
enable_reference_types: false,
|
||||
enable_simd: false,
|
||||
enable_bulk_memory: false,
|
||||
};
|
||||
|
||||
struct OperatorValidator {
|
||||
|
@ -453,7 +461,7 @@ impl OperatorValidator {
|
|||
}
|
||||
let block = func_state.block_at(relative_depth as usize);
|
||||
if block.jump_to_top {
|
||||
if !func_state.assert_last_block_stack_len_exact(reserve_items) {
|
||||
if !func_state.assert_block_stack_len(0, reserve_items) {
|
||||
return Err("stack size does not match target loop type");
|
||||
}
|
||||
return Ok(());
|
||||
|
@ -549,6 +557,20 @@ impl OperatorValidator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_simd_enabled(&self) -> OperatorValidatorResult<()> {
|
||||
if !self.config.enable_simd {
|
||||
return Err("SIMD support is not enabled");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> {
|
||||
if !self.config.enable_bulk_memory {
|
||||
return Err("bulk memory support is not enabled");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_shared_memarg_wo_align(
|
||||
&self,
|
||||
_: &MemoryImmediate,
|
||||
|
@ -558,6 +580,13 @@ impl OperatorValidator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_simd_line_index(&self, index: SIMDLineIndex, max: u8) -> OperatorValidatorResult<()> {
|
||||
if index >= max {
|
||||
return Err("SIMD index out of bounds");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_block_type(&self, ty: Type) -> OperatorValidatorResult<()> {
|
||||
match ty {
|
||||
Type::EmptyBlockType | Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
|
||||
|
@ -1244,6 +1273,338 @@ impl OperatorValidator {
|
|||
self.check_operands(func_state, &[Type::AnyRef])?;
|
||||
OperatorAction::ChangeFrameWithType(0, Type::I32)
|
||||
}
|
||||
Operator::V128Load { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 4, resources)?;
|
||||
self.check_operands_1(func_state, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::V128Store { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 4, resources)?;
|
||||
self.check_operands_2(func_state, Type::I32, Type::V128)?;
|
||||
OperatorAction::ChangeFrame(2)
|
||||
}
|
||||
Operator::V128Const { .. } => {
|
||||
self.check_simd_enabled()?;
|
||||
OperatorAction::ChangeFrameWithType(0, Type::V128)
|
||||
}
|
||||
Operator::V8x16Shuffle { ref lines } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::V128)?;
|
||||
for i in lines {
|
||||
self.check_simd_line_index(*i, 32)?;
|
||||
}
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::I64x2Splat => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::I64)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::F32x4Splat => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::F32)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::F64x2Splat => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::F64)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::I8x16ExtractLaneS { line } | Operator::I8x16ExtractLaneU { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 16)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
Operator::I16x8ExtractLaneS { line } | Operator::I16x8ExtractLaneU { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 8)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
Operator::I32x4ExtractLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 4)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
Operator::I8x16ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 16)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I16x8ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 8)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I32x4ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 4)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I64x2ExtractLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 2)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I64)
|
||||
}
|
||||
Operator::I64x2ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 2)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::I64)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::F32x4ExtractLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 4)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::F32)
|
||||
}
|
||||
Operator::F32x4ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 4)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::F32)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::F64x2ExtractLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 2)?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::F64)
|
||||
}
|
||||
Operator::F64x2ReplaceLane { line } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_simd_line_index(line, 2)?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::F64)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I8x16Eq
|
||||
| Operator::I8x16Ne
|
||||
| Operator::I8x16LtS
|
||||
| Operator::I8x16LtU
|
||||
| Operator::I8x16GtS
|
||||
| Operator::I8x16GtU
|
||||
| Operator::I8x16LeS
|
||||
| Operator::I8x16LeU
|
||||
| Operator::I8x16GeS
|
||||
| Operator::I8x16GeU
|
||||
| Operator::I16x8Eq
|
||||
| Operator::I16x8Ne
|
||||
| Operator::I16x8LtS
|
||||
| Operator::I16x8LtU
|
||||
| Operator::I16x8GtS
|
||||
| Operator::I16x8GtU
|
||||
| Operator::I16x8LeS
|
||||
| Operator::I16x8LeU
|
||||
| Operator::I16x8GeS
|
||||
| Operator::I16x8GeU
|
||||
| Operator::I32x4Eq
|
||||
| Operator::I32x4Ne
|
||||
| Operator::I32x4LtS
|
||||
| Operator::I32x4LtU
|
||||
| Operator::I32x4GtS
|
||||
| Operator::I32x4GtU
|
||||
| Operator::I32x4LeS
|
||||
| Operator::I32x4LeU
|
||||
| Operator::I32x4GeS
|
||||
| Operator::I32x4GeU
|
||||
| Operator::F32x4Eq
|
||||
| Operator::F32x4Ne
|
||||
| Operator::F32x4Lt
|
||||
| Operator::F32x4Gt
|
||||
| Operator::F32x4Le
|
||||
| Operator::F32x4Ge
|
||||
| Operator::F64x2Eq
|
||||
| Operator::F64x2Ne
|
||||
| Operator::F64x2Lt
|
||||
| Operator::F64x2Gt
|
||||
| Operator::F64x2Le
|
||||
| Operator::F64x2Ge
|
||||
| Operator::V128And
|
||||
| Operator::V128Or
|
||||
| Operator::V128Xor
|
||||
| Operator::I8x16Add
|
||||
| Operator::I8x16AddSaturateS
|
||||
| Operator::I8x16AddSaturateU
|
||||
| Operator::I8x16Sub
|
||||
| Operator::I8x16SubSaturateS
|
||||
| Operator::I8x16SubSaturateU
|
||||
| Operator::I8x16Mul
|
||||
| Operator::I16x8Add
|
||||
| Operator::I16x8AddSaturateS
|
||||
| Operator::I16x8AddSaturateU
|
||||
| Operator::I16x8Sub
|
||||
| Operator::I16x8SubSaturateS
|
||||
| Operator::I16x8SubSaturateU
|
||||
| Operator::I16x8Mul
|
||||
| Operator::I32x4Add
|
||||
| Operator::I32x4Sub
|
||||
| Operator::I32x4Mul
|
||||
| Operator::I64x2Add
|
||||
| Operator::I64x2Sub
|
||||
| Operator::F32x4Add
|
||||
| Operator::F32x4Sub
|
||||
| Operator::F32x4Mul
|
||||
| Operator::F32x4Div
|
||||
| Operator::F32x4Min
|
||||
| Operator::F32x4Max
|
||||
| Operator::F64x2Add
|
||||
| Operator::F64x2Sub
|
||||
| Operator::F64x2Mul
|
||||
| Operator::F64x2Div
|
||||
| Operator::F64x2Min
|
||||
| Operator::F64x2Max => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::V128Not
|
||||
| Operator::I8x16Neg
|
||||
| Operator::I16x8Neg
|
||||
| Operator::I32x4Neg
|
||||
| Operator::I64x2Neg
|
||||
| Operator::F32x4Abs
|
||||
| Operator::F32x4Neg
|
||||
| Operator::F32x4Sqrt
|
||||
| Operator::F64x2Abs
|
||||
| Operator::F64x2Neg
|
||||
| Operator::F64x2Sqrt
|
||||
| Operator::I32x4TruncSF32x4Sat
|
||||
| Operator::I32x4TruncUF32x4Sat
|
||||
| Operator::I64x2TruncSF64x2Sat
|
||||
| Operator::I64x2TruncUF64x2Sat
|
||||
| Operator::F32x4ConvertSI32x4
|
||||
| Operator::F32x4ConvertUI32x4
|
||||
| Operator::F64x2ConvertSI64x2
|
||||
| Operator::F64x2ConvertUI64x2 => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
Operator::V128Bitselect => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands(func_state, &[Type::V128, Type::V128, Type::V128])?;
|
||||
OperatorAction::ChangeFrameWithType(2, Type::V128)
|
||||
}
|
||||
Operator::I8x16AnyTrue
|
||||
| Operator::I8x16AllTrue
|
||||
| Operator::I16x8AnyTrue
|
||||
| Operator::I16x8AllTrue
|
||||
| Operator::I32x4AnyTrue
|
||||
| Operator::I32x4AllTrue
|
||||
| Operator::I64x2AnyTrue
|
||||
| Operator::I64x2AllTrue => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(func_state, Type::V128)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
Operator::I8x16Shl
|
||||
| Operator::I8x16ShrS
|
||||
| Operator::I8x16ShrU
|
||||
| Operator::I16x8Shl
|
||||
| Operator::I16x8ShrS
|
||||
| Operator::I16x8ShrU
|
||||
| Operator::I32x4Shl
|
||||
| Operator::I32x4ShrS
|
||||
| Operator::I32x4ShrU
|
||||
| Operator::I64x2Shl
|
||||
| Operator::I64x2ShrS
|
||||
| Operator::I64x2ShrU => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_2(func_state, Type::V128, Type::I32)?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::V128)
|
||||
}
|
||||
|
||||
Operator::MemoryInit { segment } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if segment >= resources.data_count() {
|
||||
return Err("segment index out of bounds");
|
||||
}
|
||||
self.check_memory_index(0, resources)?;
|
||||
self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?;
|
||||
OperatorAction::ChangeFrame(3)
|
||||
}
|
||||
Operator::DataDrop { segment } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if segment >= resources.data_count() {
|
||||
return Err("segment index out of bounds");
|
||||
}
|
||||
OperatorAction::None
|
||||
}
|
||||
Operator::MemoryCopy | Operator::MemoryFill => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
self.check_memory_index(0, resources)?;
|
||||
self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?;
|
||||
OperatorAction::ChangeFrame(3)
|
||||
}
|
||||
Operator::TableInit { segment } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if segment >= resources.element_count() {
|
||||
return Err("segment index out of bounds");
|
||||
}
|
||||
if 0 >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?;
|
||||
OperatorAction::ChangeFrame(3)
|
||||
}
|
||||
Operator::ElemDrop { segment } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if segment >= resources.element_count() {
|
||||
return Err("segment index out of bounds");
|
||||
}
|
||||
OperatorAction::None
|
||||
}
|
||||
Operator::TableCopy => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if 0 >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(func_state, &[Type::I32, Type::I32, Type::I32])?;
|
||||
OperatorAction::ChangeFrame(3)
|
||||
}
|
||||
Operator::TableGet { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(func_state, &[Type::I32])?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::AnyRef)
|
||||
}
|
||||
Operator::TableSet { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(func_state, &[Type::I32, Type::AnyRef])?;
|
||||
OperatorAction::ChangeFrame(2)
|
||||
}
|
||||
Operator::TableGrow { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(func_state, &[Type::I32])?;
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
Operator::TableSize { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
OperatorAction::ChangeFrameWithType(1, Type::I32)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1278,11 +1639,14 @@ pub struct ValidatingParser<'a> {
|
|||
tables: Vec<TableType>,
|
||||
memories: Vec<MemoryType>,
|
||||
globals: Vec<GlobalType>,
|
||||
element_count: u32,
|
||||
data_count: Option<u32>,
|
||||
data_found: u32,
|
||||
func_type_indices: Vec<u32>,
|
||||
current_func_index: u32,
|
||||
func_imports_count: u32,
|
||||
init_expression_state: Option<InitExpressionState>,
|
||||
exported_names: HashSet<Vec<u8>>,
|
||||
exported_names: HashSet<String>,
|
||||
current_operator_validator: Option<OperatorValidator>,
|
||||
config: ValidatingParserConfig,
|
||||
}
|
||||
|
@ -1307,6 +1671,14 @@ impl<'a> WasmModuleResources for ValidatingParser<'a> {
|
|||
fn func_type_indices(&self) -> &[u32] {
|
||||
&self.func_type_indices
|
||||
}
|
||||
|
||||
fn element_count(&self) -> u32 {
|
||||
self.element_count
|
||||
}
|
||||
|
||||
fn data_count(&self) -> u32 {
|
||||
self.data_count.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ValidatingParser<'a> {
|
||||
|
@ -1327,6 +1699,9 @@ impl<'a> ValidatingParser<'a> {
|
|||
init_expression_state: None,
|
||||
exported_names: HashSet::new(),
|
||||
config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG),
|
||||
element_count: 0,
|
||||
data_count: None,
|
||||
data_found: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1344,19 +1719,9 @@ impl<'a> ValidatingParser<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn check_utf8(&self, bytes: &[u8]) -> ValidatorResult<'a, ()> {
|
||||
match str::from_utf8(bytes) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(utf8_error) => match utf8_error.error_len() {
|
||||
None => self.create_error("Invalid utf-8: unexpected end of string"),
|
||||
Some(_) => self.create_error("Invalid utf-8: unexpected byte"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
|
||||
match ty {
|
||||
Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
|
||||
Type::I32 | Type::I64 | Type::F32 | Type::F64 | Type::V128 => Ok(()),
|
||||
_ => self.create_error("invalid value type"),
|
||||
}
|
||||
}
|
||||
|
@ -1413,14 +1778,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
self.check_value_type(global_type.content_type)
|
||||
}
|
||||
|
||||
fn check_import_entry(
|
||||
&self,
|
||||
module: &[u8],
|
||||
field: &[u8],
|
||||
import_type: &ImportSectionEntryType,
|
||||
) -> ValidatorResult<'a, ()> {
|
||||
self.check_utf8(module)?;
|
||||
self.check_utf8(field)?;
|
||||
fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> {
|
||||
match *import_type {
|
||||
ImportSectionEntryType::Function(type_index) => {
|
||||
if self.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
|
||||
|
@ -1481,12 +1839,11 @@ impl<'a> ValidatingParser<'a> {
|
|||
|
||||
fn check_export_entry(
|
||||
&self,
|
||||
field: &[u8],
|
||||
field: &str,
|
||||
kind: ExternalKind,
|
||||
index: u32,
|
||||
) -> ValidatorResult<'a, ()> {
|
||||
self.check_utf8(field)?;
|
||||
if self.exported_names.contains(&Vec::from(field)) {
|
||||
if self.exported_names.contains(field) {
|
||||
return self.create_error("non-unique export name");
|
||||
}
|
||||
match kind {
|
||||
|
@ -1532,9 +1889,6 @@ impl<'a> ValidatingParser<'a> {
|
|||
|
||||
fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> {
|
||||
let order_state = SectionOrderState::from_section_code(code);
|
||||
if let SectionCode::Custom { name, .. } = *code {
|
||||
self.check_utf8(name)?;
|
||||
}
|
||||
Ok(match self.section_order_state {
|
||||
SectionOrderState::Initial => {
|
||||
if order_state.is_none() {
|
||||
|
@ -1582,12 +1936,8 @@ impl<'a> ValidatingParser<'a> {
|
|||
self.types.push(func_type.clone());
|
||||
}
|
||||
}
|
||||
ParserState::ImportSectionEntry {
|
||||
module,
|
||||
field,
|
||||
ref ty,
|
||||
} => {
|
||||
let check = self.check_import_entry(module, field, ty);
|
||||
ParserState::ImportSectionEntry { ref ty, .. } => {
|
||||
let check = self.check_import_entry(ty);
|
||||
if check.is_err() {
|
||||
self.validation_error = check.err();
|
||||
} else {
|
||||
|
@ -1666,12 +2016,19 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::ExportSectionEntry { field, kind, index } => {
|
||||
self.validation_error = self.check_export_entry(field, kind, index).err();
|
||||
self.exported_names.insert(Vec::from(field));
|
||||
self.exported_names.insert(field.to_string());
|
||||
}
|
||||
ParserState::StartSectionEntry(func_index) => {
|
||||
self.validation_error = self.check_start(func_index).err();
|
||||
}
|
||||
ParserState::BeginElementSectionEntry(table_index) => {
|
||||
ParserState::DataCountSectionEntry(count) => {
|
||||
self.data_count = Some(count);
|
||||
}
|
||||
ParserState::BeginPassiveElementSectionEntry(_ty) => {
|
||||
self.element_count += 1;
|
||||
}
|
||||
ParserState::BeginActiveElementSectionEntry(table_index) => {
|
||||
self.element_count += 1;
|
||||
if table_index as usize >= self.tables.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("element section table index out of bounds");
|
||||
|
@ -1738,7 +2095,10 @@ impl<'a> ValidatingParser<'a> {
|
|||
self.current_func_index += 1;
|
||||
self.current_operator_validator = None;
|
||||
}
|
||||
ParserState::BeginDataSectionEntry(memory_index) => {
|
||||
ParserState::BeginDataSectionEntryBody(_) => {
|
||||
self.data_found += 1;
|
||||
}
|
||||
ParserState::BeginActiveDataSectionEntry(memory_index) => {
|
||||
if memory_index as usize >= self.memories.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("data section memory index out of bounds");
|
||||
|
@ -1750,6 +2110,22 @@ impl<'a> ValidatingParser<'a> {
|
|||
});
|
||||
}
|
||||
}
|
||||
ParserState::EndWasm => {
|
||||
if self.func_type_indices.len()
|
||||
!= self.current_func_index as usize + self.func_imports_count as usize
|
||||
{
|
||||
self.validation_error = self.create_validation_error(
|
||||
"function and code section have inconsistent lengths",
|
||||
);
|
||||
}
|
||||
if let Some(data_count) = self.data_count {
|
||||
if data_count != self.data_found {
|
||||
self.validation_error = self.create_validation_error(
|
||||
"data count section and passive data mismatch",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче