Bug 1668398: vendor Cranelift b8f0dc429f2b886e7423122223393b2c7ee3cd4f. r=bbouvier

This patch pulls in the latest version of Cranelift, which includes
necessary updates to support some recent work on the Wasm backend (e.g.,
support for the new ABI in PR #2223).

Differential Revision: https://phabricator.services.mozilla.com/D92000
This commit is contained in:
Chris Fallin 2020-10-01 17:28:30 +00:00
Родитель 915ff484ea
Коммит 65f126f9c6
68 изменённых файлов: 8044 добавлений и 1484 удалений

Просмотреть файл

@ -60,7 +60,7 @@ rev = "3224e2dee65c0726c448484d4c3c43956b9330ec"
[source."https://github.com/bytecodealliance/wasmtime"]
git = "https://github.com/bytecodealliance/wasmtime"
replace-with = "vendored-sources"
rev = "379aed8092cd1241ec7839e77d05557b1dceb234"
rev = "b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
[source."https://github.com/badboy/failure"]
git = "https://github.com/badboy/failure"

44
Cargo.lock сгенерированный
Просмотреть файл

@ -761,42 +761,42 @@ dependencies = [
[[package]]
name = "cranelift-bforest"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
dependencies = [
"cranelift-entity 0.66.0",
"cranelift-entity 0.67.0",
]
[[package]]
name = "cranelift-codegen"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
dependencies = [
"byteorder",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity 0.66.0",
"cranelift-entity 0.67.0",
"log",
"regalloc",
"smallvec",
"target-lexicon 0.10.0",
"target-lexicon 0.11.0",
"thiserror",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity 0.66.0",
"cranelift-entity 0.67.0",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
[[package]]
name = "cranelift-entity"
@ -805,27 +805,27 @@ source = "git+https://github.com/PLSysSec/lucet_sandbox_compiler?rev=477d8fc53a6
[[package]]
name = "cranelift-entity"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
[[package]]
name = "cranelift-frontend"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
dependencies = [
"cranelift-codegen",
"log",
"smallvec",
"target-lexicon 0.10.0",
"target-lexicon 0.11.0",
]
[[package]]
name = "cranelift-wasm"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=379aed8092cd1241ec7839e77d05557b1dceb234#379aed8092cd1241ec7839e77d05557b1dceb234"
version = "0.67.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=b8f0dc429f2b886e7423122223393b2c7ee3cd4f#b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
dependencies = [
"cranelift-codegen",
"cranelift-entity 0.66.0",
"cranelift-entity 0.67.0",
"cranelift-frontend",
"log",
"thiserror",
@ -4917,9 +4917,9 @@ checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"
[[package]]
name = "target-lexicon"
version = "0.10.0"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
checksum = "fe2635952a442a01fd4cb53d98858b5e4bb461b02c0d111f22f31772e3e7a8b2"
[[package]]
name = "tempfile"

Просмотреть файл

@ -75,8 +75,8 @@ failure_derive = { git = "https://github.com/badboy/failure", rev = "64af847bc5f
[patch.crates-io.cranelift-codegen]
git = "https://github.com/bytecodealliance/wasmtime"
rev = "379aed8092cd1241ec7839e77d05557b1dceb234"
rev = "b8f0dc429f2b886e7423122223393b2c7ee3cd4f"
[patch.crates-io.cranelift-wasm]
git = "https://github.com/bytecodealliance/wasmtime"
rev = "379aed8092cd1241ec7839e77d05557b1dceb234"
rev = "b8f0dc429f2b886e7423122223393b2c7ee3cd4f"

Просмотреть файл

@ -13,8 +13,8 @@ name = "baldrdash"
# cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
# you should update the following $TOP_LEVEL/Cargo.toml file: look for the
# revision (rev) hashes of both cranelift dependencies (codegen and wasm).
cranelift-codegen = { version = "0.66.0", default-features = false }
cranelift-wasm = { version = "0.66.0" }
cranelift-codegen = { version = "0.67.0", default-features = false }
cranelift-wasm = { version = "0.67.0" }
log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] }
env_logger = "0.6"
smallvec = "1.0"

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"dbbc3b62d88aec50ed9e05a6306e3aa4c5d12bf473dff48cf020843a5db31a85","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"23a5c42d477197a947122e662068e681bb9ed31041c0b668c3267c3fce15d39e","src/map.rs":"a3b7f64cae7ec9c2a8038def315bcf90e8751552b1bc1c20b62fbb8c763866c4","src/node.rs":"28f7edd979f7b9712bc4ab30b0d2a1b8ad5485a4b1e8c09f3dcaf501b9b5ccd1","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"f6337b5417f7772e6878a160c1a40629199ff09997bdff18eb2a0ba770158600","src/set.rs":"281eb8b5ead1ffd395946464d881f9bb0e7fb61092aed701d72d2314b5f80994"},"package":null}
{"files":{"Cargo.toml":"d0317b98ce3e0ec774584aba422be0a19c1f5ce8b309fda2f4c3d5889fce3e12","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"23a5c42d477197a947122e662068e681bb9ed31041c0b668c3267c3fce15d39e","src/map.rs":"a3b7f64cae7ec9c2a8038def315bcf90e8751552b1bc1c20b62fbb8c763866c4","src/node.rs":"28f7edd979f7b9712bc4ab30b0d2a1b8ad5485a4b1e8c09f3dcaf501b9b5ccd1","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"f6337b5417f7772e6878a160c1a40629199ff09997bdff18eb2a0ba770158600","src/set.rs":"281eb8b5ead1ffd395946464d881f9bb0e7fb61092aed701d72d2314b5f80994"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-bforest"
version = "0.66.0"
version = "0.67.0"
description = "A forest of B+-trees"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://docs.rs/cranelift-bforest"
@ -12,7 +12,7 @@ keywords = ["btree", "forest", "set", "map"]
edition = "2018"
[dependencies]
cranelift-entity = { path = "../entity", version = "0.66.0", default-features = false }
cranelift-entity = { path = "../entity", version = "0.67.0", default-features = false }
[badges]
maintenance = { status = "experimental" }

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"d01629d478557c181b999c1722b6284435f45f04957d7cb55735b9605136a23e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"84a4b7e3301e3249716958a7aa4ea5ba8c6172e3c02f57ee3880504c4433ff19","src/cdsl/cpu_modes.rs":"996e45b374cfe85ac47c8c86c4459fe4c04b3158102b4c63b6ee434d5eed6a9e","src/cdsl/encodings.rs":"d884a564815a03c23369bcf31d13b122ae5ba84d0c80eda9312f0c0a829bf794","src/cdsl/formats.rs":"63e638305aa3ca6dd409ddf0e5e9605eeac1cc2631103e42fc6cbc87703d9b63","src/cdsl/instructions.rs":"a0f5212fa593caf66371f5ee4b15e501939a9407c4663bff6b3ba356b11ca1b4","src/cdsl/isa.rs":"ccabd6848b69eb069c10db61c7e7f86080777495714bb53d03e663c40541be94","src/cdsl/mod.rs":"0aa827923bf4c45e5ee2359573bd863e00f474acd532739f49dcd74a27553882","src/cdsl/operands.rs":"1c3411504de9c83112ff48e0ff1cfbb2e4ba5a9a15c1716f411ef31a4df59899","src/cdsl/recipes.rs":"80b7cd87332229b569e38086ceee8d557e679b9a32ad2e50bdb15c33337c3418","src/cdsl/regs.rs":"466a42a43355fc7623fe5d8e8d330622207a3af6a80cb9367bc0f06e224c9ee0","src/cdsl/settings.rs":"e6fd9a31925743b93b11f09c9c8271bab6aa2430aa053a2601957b4487df7d77","src/cdsl/type_inference.rs":"1efca8a095ffc899b7527bda6b9d9378c73d7283f8dceaa4819e8af599f8be21","src/cdsl/types.rs":"50620fb2a6271a7c9126dc30c433a1bf25646a4d84511f5745650aaaec700f42","src/cdsl/typevar.rs":"5ae9e5453c3aa8b12a37e5579b602162fa9e153b444e89bb89342614b6a5ed13","src/cdsl/xform.rs":"55da0c3f2403147b535ab6ae5d69c623fbe839edecf2a3af1de84420cd58402d","src/default_map.rs":"101bb0282a124f9c921f6bd095f529e8753621450d783c3273b0b0394c2c5c03","src/error.rs":"e9b11b2feb2d867b94c8810fdc5a6c4e0d9131604a0bfa5340ff2639a55100b4","src/gen_binemit.rs":"515e243420b30d1e01f8ea630282d9b6d78a715e1951f3f20392e19a48164442","src/gen_encodings.rs":"f00cded6b68a9b48c9e3cd39a8b6f0ba136f4062c8f8666109158a72c62c3ed1","src/gen_inst.rs":"1ff123ab481b48d82e13363043dfc98eaef837bbf6af485b8259c3863550e29c","src/gen_legalizer.rs":"a5e507eb46649a28252582cfc1907c77c9266fec7f92e959a03258bed7d124e9","src/gen_registers.rs":"a904119ed803c9de24dedd15149a65337ffc168bb1d63df53d7fdebfb5f4b158","src/gen_settings.rs":"f3cc3d31f6cc898f30606caf084f0de220db2d3b1b5e5e4145fa7c9a9a1597e2","src/gen_types.rs":"f6c090e1646a43bf2fe81ae0a7029cc6f7dc6d43285368f56d86c35a21c469a6","src/isa/arm32/mod.rs":"da18cb40c1a0a6b613ddefcc38a5d01d02c95de6f233ebd4ad84fefb992c008b","src/isa/arm64/mod.rs":"3a815eaa478d82b7f8b536b83f9debb6b79ec860f99fea6485f209a836c6939a","src/isa/mod.rs":"be483f9a406f603e69603f9489a41a53ee02aa0ece07f7ca396956dfe3815f71","src/isa/riscv/encodings.rs":"8abb1968d917588bc5fc5f5be6dd66bdec23ac456ba65f8138237c8e891e843c","src/isa/riscv/mod.rs":"a7b461a30bbfbc1e3b33645422ff40d5b1761c30cb5d4a8aa12e9a3b7f7aee51","src/isa/riscv/recipes.rs":"5be3bf7c9ba3c51ece384b7eee75a8f7fa0cbacc6a5babc9d0e1d92a2e54a4c2","src/isa/x86/encodings.rs":"e9f1645fec6e4b5cfba9b08cfff70f9d1a5ad3b392f5ee9f40cb1a8669a7c689","src/isa/x86/instructions.rs":"d4d581448f8f7bd5afb033650af0026468eecc6f4184b3bb7c06232bf08c456b","src/isa/x86/legalize.rs":"186c688dd8ac773f2b2c4c1f1cbdb7a66ca13a8ed90c03f87dfe7fdaa12c15b3","src/isa/x86/mod.rs":"31571c281318e6f9bf17680feb96830983f5c1f9811aa4a89736f99f3d9a1831","src/isa/x86/opcodes.rs":"745ef09f4927b5334d68155fa047910ef96311feef7ec20964bb033c3419cd3c","src/isa/x86/recipes.rs":"744292109344363b2210ac1b42cb4704b4b692aa8bf5583e4230557cf3749298","src/isa/x86/registers.rs":"4be0a45d8acd465c31746b7976124025b06b453e3f6d587f93efb5af0e12b1a8","src/isa/x86/settings.rs":"47a5e9fb3b7917cfe817d56dcc77c0470545e451e0f38a875af0531fbd9b6a58","src/lib.rs":"23259ba28aa8f0b3586e9c60f4e67ae50660369f146f2a94249e8cff7d07b27b","src/shared/entities.rs":"90f774a70e1c2a2e9a553c07a5e80e0fe54cf127434bd83e67274bba4e1a19ba","src/shared/formats.rs":"14b668244b2afd71197c2dd8469af0e0602d590fcb14252c2b0b40cb9905a4ae","src/shared/immediates.rs":"563fa33accb992eb11a43f0f63259c62a2c44db59801431cc67ceec4b94f2ca3","src/shared/instructions.rs":"25d321a9ee48c7a40058c27aef85f4b7af3f18ece88841e3ee6335c06f3bded0","src/shared/legalize.rs":"e8fd35104c1907c0e9453fb98372373aea20b54af10457156f6abd86929099dc","src/shared/mod.rs":"c219625990bf15507ac1077b349ce20e5312d4e4707426183676d469e78792b7","src/shared/settings.rs":"cba764a0e404b9fd827b4bc5ec07071251e6c506f4cf3053430dc9fa49d39737","src/shared/types.rs":"4702df132f4b5d70cc9411ec5221ba0b1bd4479252274e0223ae57b6d0331247","src/srcgen.rs":"dcfc159c8599270f17e6a978c4be255abca51556b5ef0da497faec4a4a1e62ce","src/unique_table.rs":"31aa54330ca4786af772d32e8cb6158b6504b88fa93fe177bf0c6cbe545a8d35"},"package":null}
{"files":{"Cargo.toml":"7c40668950dc4e8edbacfc6d7e8cc2c66b8b92ae3f8a65d90c8c4d356dd1f69a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"84a4b7e3301e3249716958a7aa4ea5ba8c6172e3c02f57ee3880504c4433ff19","src/cdsl/cpu_modes.rs":"996e45b374cfe85ac47c8c86c4459fe4c04b3158102b4c63b6ee434d5eed6a9e","src/cdsl/encodings.rs":"d884a564815a03c23369bcf31d13b122ae5ba84d0c80eda9312f0c0a829bf794","src/cdsl/formats.rs":"63e638305aa3ca6dd409ddf0e5e9605eeac1cc2631103e42fc6cbc87703d9b63","src/cdsl/instructions.rs":"a0f5212fa593caf66371f5ee4b15e501939a9407c4663bff6b3ba356b11ca1b4","src/cdsl/isa.rs":"ccabd6848b69eb069c10db61c7e7f86080777495714bb53d03e663c40541be94","src/cdsl/mod.rs":"0aa827923bf4c45e5ee2359573bd863e00f474acd532739f49dcd74a27553882","src/cdsl/operands.rs":"1c3411504de9c83112ff48e0ff1cfbb2e4ba5a9a15c1716f411ef31a4df59899","src/cdsl/recipes.rs":"80b7cd87332229b569e38086ceee8d557e679b9a32ad2e50bdb15c33337c3418","src/cdsl/regs.rs":"466a42a43355fc7623fe5d8e8d330622207a3af6a80cb9367bc0f06e224c9ee0","src/cdsl/settings.rs":"e6fd9a31925743b93b11f09c9c8271bab6aa2430aa053a2601957b4487df7d77","src/cdsl/type_inference.rs":"1efca8a095ffc899b7527bda6b9d9378c73d7283f8dceaa4819e8af599f8be21","src/cdsl/types.rs":"50620fb2a6271a7c9126dc30c433a1bf25646a4d84511f5745650aaaec700f42","src/cdsl/typevar.rs":"3cbe83a09d2402511b20415a8356f848fb82536926386bb42eaaa7740fb2457e","src/cdsl/xform.rs":"55da0c3f2403147b535ab6ae5d69c623fbe839edecf2a3af1de84420cd58402d","src/default_map.rs":"101bb0282a124f9c921f6bd095f529e8753621450d783c3273b0b0394c2c5c03","src/error.rs":"e9b11b2feb2d867b94c8810fdc5a6c4e0d9131604a0bfa5340ff2639a55100b4","src/gen_binemit.rs":"515e243420b30d1e01f8ea630282d9b6d78a715e1951f3f20392e19a48164442","src/gen_encodings.rs":"f00cded6b68a9b48c9e3cd39a8b6f0ba136f4062c8f8666109158a72c62c3ed1","src/gen_inst.rs":"1ff123ab481b48d82e13363043dfc98eaef837bbf6af485b8259c3863550e29c","src/gen_legalizer.rs":"a5e507eb46649a28252582cfc1907c77c9266fec7f92e959a03258bed7d124e9","src/gen_registers.rs":"a904119ed803c9de24dedd15149a65337ffc168bb1d63df53d7fdebfb5f4b158","src/gen_settings.rs":"f3cc3d31f6cc898f30606caf084f0de220db2d3b1b5e5e4145fa7c9a9a1597e2","src/gen_types.rs":"f6c090e1646a43bf2fe81ae0a7029cc6f7dc6d43285368f56d86c35a21c469a6","src/isa/arm32/mod.rs":"da18cb40c1a0a6b613ddefcc38a5d01d02c95de6f233ebd4ad84fefb992c008b","src/isa/arm64/mod.rs":"3a815eaa478d82b7f8b536b83f9debb6b79ec860f99fea6485f209a836c6939a","src/isa/mod.rs":"be483f9a406f603e69603f9489a41a53ee02aa0ece07f7ca396956dfe3815f71","src/isa/riscv/encodings.rs":"8abb1968d917588bc5fc5f5be6dd66bdec23ac456ba65f8138237c8e891e843c","src/isa/riscv/mod.rs":"a7b461a30bbfbc1e3b33645422ff40d5b1761c30cb5d4a8aa12e9a3b7f7aee51","src/isa/riscv/recipes.rs":"5be3bf7c9ba3c51ece384b7eee75a8f7fa0cbacc6a5babc9d0e1d92a2e54a4c2","src/isa/x86/encodings.rs":"e9f1645fec6e4b5cfba9b08cfff70f9d1a5ad3b392f5ee9f40cb1a8669a7c689","src/isa/x86/instructions.rs":"d4d581448f8f7bd5afb033650af0026468eecc6f4184b3bb7c06232bf08c456b","src/isa/x86/legalize.rs":"186c688dd8ac773f2b2c4c1f1cbdb7a66ca13a8ed90c03f87dfe7fdaa12c15b3","src/isa/x86/mod.rs":"31571c281318e6f9bf17680feb96830983f5c1f9811aa4a89736f99f3d9a1831","src/isa/x86/opcodes.rs":"745ef09f4927b5334d68155fa047910ef96311feef7ec20964bb033c3419cd3c","src/isa/x86/recipes.rs":"744292109344363b2210ac1b42cb4704b4b692aa8bf5583e4230557cf3749298","src/isa/x86/registers.rs":"4be0a45d8acd465c31746b7976124025b06b453e3f6d587f93efb5af0e12b1a8","src/isa/x86/settings.rs":"47a5e9fb3b7917cfe817d56dcc77c0470545e451e0f38a875af0531fbd9b6a58","src/lib.rs":"23259ba28aa8f0b3586e9c60f4e67ae50660369f146f2a94249e8cff7d07b27b","src/shared/entities.rs":"90f774a70e1c2a2e9a553c07a5e80e0fe54cf127434bd83e67274bba4e1a19ba","src/shared/formats.rs":"14b668244b2afd71197c2dd8469af0e0602d590fcb14252c2b0b40cb9905a4ae","src/shared/immediates.rs":"563fa33accb992eb11a43f0f63259c62a2c44db59801431cc67ceec4b94f2ca3","src/shared/instructions.rs":"25d321a9ee48c7a40058c27aef85f4b7af3f18ece88841e3ee6335c06f3bded0","src/shared/legalize.rs":"eb5f07fa107cadd67483881ccce29cc8fb9b698a0cd4f1d89853aac275cf7bcf","src/shared/mod.rs":"c219625990bf15507ac1077b349ce20e5312d4e4707426183676d469e78792b7","src/shared/settings.rs":"e7406ce17fb313fa05397dd8103f74eed67d35170d70b6e546e08954aef2ed87","src/shared/types.rs":"4702df132f4b5d70cc9411ec5221ba0b1bd4479252274e0223ae57b6d0331247","src/srcgen.rs":"dcfc159c8599270f17e6a978c4be255abca51556b5ef0da497faec4a4a1e62ce","src/unique_table.rs":"31aa54330ca4786af772d32e8cb6158b6504b88fa93fe177bf0c6cbe545a8d35"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "cranelift-codegen-meta"
authors = ["The Cranelift Project Developers"]
version = "0.66.0"
version = "0.67.0"
description = "Metaprogram for cranelift-codegen code generator library"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"
@ -12,8 +12,8 @@ edition = "2018"
rustdoc-args = [ "--document-private-items" ]
[dependencies]
cranelift-codegen-shared = { path = "../shared", version = "0.66.0" }
cranelift-entity = { path = "../../entity", version = "0.66.0" }
cranelift-codegen-shared = { path = "../shared", version = "0.67.0" }
cranelift-entity = { path = "../../entity", version = "0.67.0" }
[badges]
maintenance = { status = "experimental" }

Просмотреть файл

@ -302,7 +302,7 @@ impl TypeVar {
pub fn to_rust_code(&self) -> String {
match &self.base {
Some(base) => format!(
"{}.{}()",
"{}.{}().unwrap()",
base.type_var.to_rust_code(),
base.derived_func.name()
),

Просмотреть файл

@ -402,6 +402,17 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
);
}
let zero = Literal::constant(&imm.imm64, 0);
narrow.legalize(
def!(a = iadd_imm.I128(x, c)),
vec![
def!(yh = iconst.I64(zero)),
def!(yl = iconst.I64(c)),
def!(y = iconcat.I64(yh, yl)),
def!(a = iadd(x, y)),
],
);
// Widen instructions with one input operand.
for &op in &[bnot, popcnt] {
for &int_ty in &[I8, I16] {

Просмотреть файл

@ -194,6 +194,7 @@ pub(crate) fn define() -> SettingGroup {
"windows_fastcall",
"baldrdash_system_v",
"baldrdash_windows",
"baldrdash_2020",
"probestack",
],
);

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"f091891e7b42864e1ef40c5c30724d785403727692ae66b623888367c329efcd","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/condcodes.rs":"b8d433b2217b86e172d25b6c65a3ce0cc8ca221062cad1b28b0c78d2159fbda9","src/constant_hash.rs":"ffc619f45aad62c6fdcb83553a05879691a72e9a0103375b2d6cc12d52cf72d0","src/constants.rs":"fed03a10a6316e06aa174091db6e7d1fbb5f73c82c31193012ec5ab52f1c603a","src/isa/mod.rs":"428a950eca14acbe783899ccb1aecf15027f8cbe205578308ebde203d10535f3","src/isa/x86/encoding_bits.rs":"7e013fb804b13f9f83a0d517c6f5105856938d08ad378cc44a6fe6a59adef270","src/isa/x86/mod.rs":"01ef4e4d7437f938badbe2137892183c1ac684da0f68a5bec7e06aad34f43b9b","src/lib.rs":"91f26f998f11fb9cb74d2ec171424e29badd417beef023674850ace57149c656"},"package":null}
{"files":{"Cargo.toml":"c87e99b6131e876d16430cd2f40de7c03e6d72a8ba1423c8778b5c733bcd4362","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/condcodes.rs":"b8d433b2217b86e172d25b6c65a3ce0cc8ca221062cad1b28b0c78d2159fbda9","src/constant_hash.rs":"ffc619f45aad62c6fdcb83553a05879691a72e9a0103375b2d6cc12d52cf72d0","src/constants.rs":"fed03a10a6316e06aa174091db6e7d1fbb5f73c82c31193012ec5ab52f1c603a","src/isa/mod.rs":"428a950eca14acbe783899ccb1aecf15027f8cbe205578308ebde203d10535f3","src/isa/x86/encoding_bits.rs":"7e013fb804b13f9f83a0d517c6f5105856938d08ad378cc44a6fe6a59adef270","src/isa/x86/mod.rs":"01ef4e4d7437f938badbe2137892183c1ac684da0f68a5bec7e06aad34f43b9b","src/lib.rs":"91f26f998f11fb9cb74d2ec171424e29badd417beef023674850ace57149c656"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-codegen-shared"
version = "0.66.0"
version = "0.67.0"
description = "For code shared between cranelift-codegen-meta and cranelift-codegen"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

23
third_party/rust/cranelift-codegen/Cargo.toml поставляемый
Просмотреть файл

@ -1,7 +1,7 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-codegen"
version = "0.66.0"
version = "0.67.0"
description = "Low-level code generator library"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://docs.rs/cranelift-codegen"
@ -13,21 +13,21 @@ build = "build.rs"
edition = "2018"
[dependencies]
cranelift-codegen-shared = { path = "./shared", version = "0.66.0" }
cranelift-entity = { path = "../entity", version = "0.66.0" }
cranelift-bforest = { path = "../bforest", version = "0.66.0" }
cranelift-codegen-shared = { path = "./shared", version = "0.67.0" }
cranelift-entity = { path = "../entity", version = "0.67.0" }
cranelift-bforest = { path = "../bforest", version = "0.67.0" }
hashbrown = { version = "0.7", optional = true }
target-lexicon = "0.10"
target-lexicon = "0.11"
log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true }
bincode = { version = "1.2.1", optional = true }
gimli = { version = "0.21.0", default-features = false, features = ["write"], optional = true }
gimli = { version = "0.22.0", default-features = false, features = ["write"], optional = true }
smallvec = { version = "1.0.0" }
thiserror = "1.0.4"
byteorder = { version = "1.3.2", default-features = false }
peepmatic = { path = "../peepmatic", optional = true, version = "0.66.0" }
peepmatic-traits = { path = "../peepmatic/crates/traits", optional = true, version = "0.66.0" }
peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.66.0" }
peepmatic = { path = "../peepmatic", optional = true, version = "0.67.0" }
peepmatic-traits = { path = "../peepmatic/crates/traits", optional = true, version = "0.67.0" }
peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.67.0" }
regalloc = "0.0.30"
souper-ir = { version = "1", optional = true }
wast = { version = "22.0.0", optional = true }
@ -37,7 +37,7 @@ wast = { version = "22.0.0", optional = true }
# accomodated in `tests`.
[build-dependencies]
cranelift-codegen-meta = { path = "meta", version = "0.66.0" }
cranelift-codegen-meta = { path = "meta", version = "0.67.0" }
[features]
default = ["std", "unwind"]
@ -61,15 +61,14 @@ unwind = ["gimli"]
# ISA targets for which we should build.
# If no ISA targets are explicitly enabled, the ISA target for the host machine is enabled.
x86 = []
arm32 = []
arm64 = []
riscv = []
x64 = [] # New work-in-progress codegen backend for x86_64 based on the new isel.
arm32 = [] # Work-in-progress codegen backend for ARM.
# Option to enable all architectures.
all-arch = [
"x86",
"arm32",
"arm64",
"riscv"
]

Просмотреть файл

@ -335,6 +335,20 @@ pub enum ArgumentPurpose {
/// This is a pointer to a stack limit. It is used to check the current stack pointer
/// against. Can only appear once in a signature.
StackLimit,
/// A callee TLS value.
///
/// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
/// TLS-register values for the caller and the callee. This argument is used to provide the
/// value for the callee.
CalleeTLS,
/// A caller TLS value.
///
/// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
/// TLS-register values for the caller and the callee. This argument is used to provide the
/// value for the caller.
CallerTLS,
}
impl fmt::Display for ArgumentPurpose {
@ -349,6 +363,8 @@ impl fmt::Display for ArgumentPurpose {
Self::VMContext => "vmctx",
Self::SignatureId => "sigid",
Self::StackLimit => "stack_limit",
Self::CalleeTLS => "callee_tls",
Self::CallerTLS => "caller_tls",
})
}
}
@ -470,6 +486,7 @@ mod tests {
CallConv::WindowsFastcall,
CallConv::BaldrdashSystemV,
CallConv::BaldrdashWindows,
CallConv::Baldrdash2020,
] {
assert_eq!(Ok(cc), cc.to_string().parse())
}

Просмотреть файл

@ -31,6 +31,11 @@ static BALDRDASH_SIG_REG: u8 = 10;
/// This is SpiderMonkey's `WasmTlsReg`.
static BALDRDASH_TLS_REG: u8 = 23;
/// Offset in stack-arg area to callee-TLS slot in Baldrdash-2020 calling convention.
static BALDRDASH_CALLEE_TLS_OFFSET: i64 = 0;
/// Offset in stack-arg area to caller-TLS slot in Baldrdash-2020 calling convention.
static BALDRDASH_CALLER_TLS_OFFSET: i64 = 8;
// These two lists represent the registers the JIT may *not* use at any point in generated code.
//
// So these are callee-preserved from the JIT's point of view, and every register not in this list
@ -75,6 +80,7 @@ fn try_fill_baldrdash_reg(call_conv: isa::CallConv, param: &ir::AbiParam) -> Opt
xreg(BALDRDASH_TLS_REG).to_real_reg(),
ir::types::I64,
param.extension,
param.purpose,
))
}
&ir::ArgumentPurpose::SignatureId => {
@ -83,6 +89,27 @@ fn try_fill_baldrdash_reg(call_conv: isa::CallConv, param: &ir::AbiParam) -> Opt
xreg(BALDRDASH_SIG_REG).to_real_reg(),
ir::types::I64,
param.extension,
param.purpose,
))
}
&ir::ArgumentPurpose::CalleeTLS => {
// This is SpiderMonkey's callee TLS slot in the extended frame of Wasm's ABI-2020.
assert!(call_conv == isa::CallConv::Baldrdash2020);
Some(ABIArg::Stack(
BALDRDASH_CALLEE_TLS_OFFSET,
ir::types::I64,
ir::ArgumentExtension::None,
param.purpose,
))
}
&ir::ArgumentPurpose::CallerTLS => {
// This is SpiderMonkey's caller TLS slot in the extended frame of Wasm's ABI-2020.
assert!(call_conv == isa::CallConv::Baldrdash2020);
Some(ABIArg::Stack(
BALDRDASH_CALLER_TLS_OFFSET,
ir::types::I64,
ir::ArgumentExtension::None,
param.purpose,
))
}
_ => None,
@ -109,6 +136,10 @@ pub(crate) struct AArch64MachineDeps;
impl ABIMachineSpec for AArch64MachineDeps {
type I = Inst;
fn word_bits() -> u32 {
64
}
fn compute_arg_locs(
call_conv: isa::CallConv,
params: &[ir::AbiParam],
@ -116,6 +147,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
add_ret_area_ptr: bool,
) -> CodegenResult<(Vec<ABIArg>, i64, Option<usize>)> {
let is_baldrdash = call_conv.extends_baldrdash();
let has_baldrdash_tls = call_conv == isa::CallConv::Baldrdash2020;
// See AArch64 ABI (https://c9x.me/compile/bib/abi-arm64.pdf), sections 5.4.
let mut next_xreg = 0;
@ -123,6 +155,12 @@ impl ABIMachineSpec for AArch64MachineDeps {
let mut next_stack: u64 = 0;
let mut ret = vec![];
if args_or_rets == ArgsOrRets::Args && has_baldrdash_tls {
// Baldrdash ABI-2020 always has two stack-arg slots reserved, for the callee and
// caller TLS-register values, respectively.
next_stack = 16;
}
// Note on return values: on the regular non-baldrdash ABI, we may return values in 8
// registers for V128 and I64 registers independently of the number of register values
// returned in the other class. That is, we can return values in up to 8 integer and 8
@ -151,7 +189,9 @@ impl ABIMachineSpec for AArch64MachineDeps {
&ir::ArgumentPurpose::VMContext
| &ir::ArgumentPurpose::Normal
| &ir::ArgumentPurpose::StackLimit
| &ir::ArgumentPurpose::SignatureId => {}
| &ir::ArgumentPurpose::SignatureId
| &ir::ArgumentPurpose::CallerTLS
| &ir::ArgumentPurpose::CalleeTLS => {}
_ => panic!(
"Unsupported argument purpose {:?} in signature: {:?}",
param.purpose, params
@ -184,6 +224,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
reg.to_real_reg(),
param.value_type,
param.extension,
param.purpose,
));
*next_reg += 1;
remaining_reg_vals -= 1;
@ -199,6 +240,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
next_stack as i64,
param.value_type,
param.extension,
param.purpose,
));
next_stack += size;
}
@ -215,12 +257,14 @@ impl ABIMachineSpec for AArch64MachineDeps {
xreg(next_xreg).to_real_reg(),
I64,
ir::ArgumentExtension::None,
ir::ArgumentPurpose::Normal,
));
} else {
ret.push(ABIArg::Stack(
next_stack as i64,
I64,
ir::ArgumentExtension::None,
ir::ArgumentPurpose::Normal,
));
next_stack += 8;
}
@ -449,6 +493,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
// nominal SP offset; abi_impl generic code will do that.
fn gen_clobber_save(
call_conv: isa::CallConv,
_: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> (u64, SmallVec<[Inst; 16]>) {
let mut insts = SmallVec::new();
@ -499,6 +544,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
fn gen_clobber_restore(
call_conv: isa::CallConv,
flags: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> SmallVec<[Inst; 16]> {
let mut insts = SmallVec::new();
@ -545,6 +591,18 @@ impl ABIMachineSpec for AArch64MachineDeps {
});
}
// If this is Baldrdash-2020, restore the callee (i.e., our) TLS
// register. We may have allocated it for something else and clobbered
// it, but the ABI expects us to leave the TLS register unchanged.
if call_conv == isa::CallConv::Baldrdash2020 {
let off = BALDRDASH_CALLEE_TLS_OFFSET + Self::fp_to_arg_offset(call_conv, flags);
insts.push(Inst::gen_load(
writable_xreg(BALDRDASH_TLS_REG),
AMode::UnsignedOffset(fp_reg(), UImm12Scaled::maybe_from_i64(off, I64).unwrap()),
I64,
));
}
insts
}

Просмотреть файл

@ -74,23 +74,51 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}
Opcode::Iadd => {
let rd = get_output_reg(ctx, outputs[0]);
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let ty = ty.unwrap();
if !ty.is_vector() {
let (rm, negated) = put_input_in_rse_imm12_maybe_negated(
ctx,
inputs[1],
ty_bits(ty),
NarrowValueMode::None,
);
let alu_op = if !negated {
choose_32_64(ty, ALUOp::Add32, ALUOp::Add64)
let mul_insn =
if let Some(mul_insn) = maybe_input_insn(ctx, inputs[1], Opcode::Imul) {
Some((mul_insn, 0))
} else if let Some(mul_insn) = maybe_input_insn(ctx, inputs[0], Opcode::Imul) {
Some((mul_insn, 1))
} else {
None
};
// If possible combine mul + add into madd.
if let Some((insn, addend_idx)) = mul_insn {
let alu_op = choose_32_64(ty, ALUOp3::MAdd32, ALUOp3::MAdd64);
let rn_input = InsnInput { insn, input: 0 };
let rm_input = InsnInput { insn, input: 1 };
let rn = put_input_in_reg(ctx, rn_input, NarrowValueMode::None);
let rm = put_input_in_reg(ctx, rm_input, NarrowValueMode::None);
let ra = put_input_in_reg(ctx, inputs[addend_idx], NarrowValueMode::None);
ctx.emit(Inst::AluRRRR {
alu_op,
rd,
rn,
rm,
ra,
});
} else {
choose_32_64(ty, ALUOp::Sub32, ALUOp::Sub64)
};
ctx.emit(alu_inst_imm12(alu_op, rd, rn, rm));
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let (rm, negated) = put_input_in_rse_imm12_maybe_negated(
ctx,
inputs[1],
ty_bits(ty),
NarrowValueMode::None,
);
let alu_op = if !negated {
choose_32_64(ty, ALUOp::Add32, ALUOp::Add64)
} else {
choose_32_64(ty, ALUOp::Sub32, ALUOp::Sub64)
};
ctx.emit(alu_inst_imm12(alu_op, rd, rn, rm));
}
} else {
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
ctx.emit(Inst::VecRRR {
rd,
rn,

Просмотреть файл

@ -1,108 +1,450 @@
//! ARM ABI implementation.
//! This is from the RISC-V target and will need to be updated for ARM32.
//! Implementation of the 32-bit ARM ABI.
use super::registers::{D, GPR, Q, S};
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 alloc::borrow::Cow;
use core::i32;
use target_lexicon::Triple;
use crate::ir;
use crate::ir::types::*;
use crate::ir::SourceLoc;
use crate::isa;
use crate::isa::arm32::inst::*;
use crate::machinst::*;
use crate::settings;
use crate::{CodegenError, CodegenResult};
use alloc::boxed::Box;
use alloc::vec::Vec;
use regalloc::{RealReg, Reg, RegClass, Set, Writable};
use smallvec::SmallVec;
struct Args {
pointer_bits: u8,
pointer_bytes: u8,
pointer_type: Type,
regs: u32,
reg_limit: u32,
offset: u32,
}
/// Support for the ARM ABI from the callee side (within a function body).
pub(crate) type Arm32ABICallee = ABICalleeImpl<Arm32MachineDeps>;
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,
/// Support for the ARM ABI from the caller side (at a callsite).
pub(crate) type Arm32ABICaller = ABICallerImpl<Arm32MachineDeps>;
/// This is the limit for the size of argument and return-value areas on the
/// stack. We place a reasonable limit here to avoid integer overflow issues
/// with 32-bit arithmetic: for now, 128 MB.
static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
/// ARM-specific ABI behavior. This struct just serves as an implementation
/// point for the trait; it is never actually instantiated.
pub(crate) struct Arm32MachineDeps;
impl Into<AMode> for StackAMode {
fn into(self) -> AMode {
match self {
StackAMode::FPOffset(off, ty) => AMode::FPOffset(off, ty),
StackAMode::NominalSPOffset(off, ty) => AMode::NominalSPOffset(off, ty),
StackAMode::SPOffset(off, ty) => AMode::SPOffset(off, ty),
}
}
}
impl ArgAssigner for Args {
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
fn align(value: u32, to: u32) -> u32 {
(value + to - 1) & !(to - 1)
}
impl ABIMachineSpec for Arm32MachineDeps {
type I = Inst;
let ty = arg.value_type;
fn word_bits() -> u32 {
32
}
// Check for a legal type.
// SIMD instructions are currently no implemented, so break down vectors
if ty.is_vector() {
return ValueConversion::VectorSplit.into();
}
fn compute_arg_locs(
_call_conv: isa::CallConv,
params: &[ir::AbiParam],
args_or_rets: ArgsOrRets,
add_ret_area_ptr: bool,
) -> CodegenResult<(Vec<ABIArg>, i64, Option<usize>)> {
let mut next_rreg = 0;
let mut next_stack: u64 = 0;
let mut ret = vec![];
let mut stack_args = vec![];
// 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();
}
let max_reg_val = 4; // r0-r3
// 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(),
for i in 0..params.len() {
let param = params[i];
// Validate "purpose".
match &param.purpose {
&ir::ArgumentPurpose::VMContext
| &ir::ArgumentPurpose::Normal
| &ir::ArgumentPurpose::StackLimit
| &ir::ArgumentPurpose::SignatureId => {}
_ => panic!(
"Unsupported argument purpose {:?} in signature: {:?}",
param.purpose, params
),
}
assert!(param.value_type.bits() <= 32);
if next_rreg < max_reg_val {
let reg = rreg(next_rreg);
ret.push(ABIArg::Reg(
reg.to_real_reg(),
param.value_type,
param.extension,
));
next_rreg += 1;
} else {
// Arguments are stored on stack in reversed order.
// https://static.docs.arm.com/ihi0042/g/aapcs32.pdf
// Stack offset is not known yet. Store param info for later.
stack_args.push((param.value_type, param.extension));
next_stack += 4;
}
}
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()
let extra_arg = if add_ret_area_ptr {
debug_assert!(args_or_rets == ArgsOrRets::Args);
if next_rreg < max_reg_val {
ret.push(ABIArg::Reg(
rreg(next_rreg).to_real_reg(),
I32,
ir::ArgumentExtension::None,
));
} else {
stack_args.push((I32, ir::ArgumentExtension::None));
next_stack += 4;
}
Some(ret.len() - 1)
} 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()
None
};
// Now we can assign proper stack offsets to params.
let max_stack = next_stack;
for (ty, ext) in stack_args.into_iter().rev() {
next_stack -= 4;
ret.push(ABIArg::Stack((max_stack - next_stack) as i64, ty, ext));
}
assert_eq!(next_stack, 0);
next_stack = (next_stack + 7) & !7;
// To avoid overflow issues, limit the arg/return size to something
// reasonable -- here, 128 MB.
if next_stack > STACK_ARG_RET_SIZE_LIMIT {
return Err(CodegenError::ImplLimitExceeded);
}
Ok((ret, next_stack as i64, extra_arg))
}
fn fp_to_arg_offset(_call_conv: isa::CallConv, _flags: &settings::Flags) -> i64 {
8 // frame pointer and link register
}
fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Inst {
Inst::gen_load(into_reg, mem.into(), ty)
}
fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst {
Inst::gen_store(from_reg, mem.into(), ty)
}
fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
Inst::gen_move(to_reg, from_reg, ty)
}
fn gen_extend(
to_reg: Writable<Reg>,
from_reg: Reg,
is_signed: bool,
from_bits: u8,
to_bits: u8,
) -> Inst {
assert!(to_bits == 32);
assert!(from_bits < 32);
Inst::Extend {
rd: to_reg,
rm: from_reg,
signed: is_signed,
from_bits,
}
}
}
/// Legalize `sig`.
pub fn legalize_signature(sig: &mut Cow<ir::Signature>, triple: &Triple, _current: bool) {
let bits = triple.pointer_width().unwrap().bits();
let mut args = Args::new(bits);
if let Some(new_params) = legalize_args(&sig.params, &mut args) {
sig.to_mut().params = new_params;
fn gen_ret() -> Inst {
Inst::Ret
}
}
/// Get register class for a type appearing in a legalized signature.
pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass {
if ty.is_int() {
GPR
} else {
match ty.bits() {
32 => S,
64 => D,
128 => Q,
_ => panic!("Unexpected {} ABI type for arm32", ty),
fn gen_epilogue_placeholder() -> Inst {
Inst::EpiloguePlaceholder
}
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallVec<[Inst; 4]> {
let mut insts = SmallVec::new();
if let Some(imm12) = UImm12::maybe_from_i64(imm as i64) {
insts.push(Inst::AluRRImm12 {
alu_op: ALUOp::Add,
rd: into_reg,
rn: from_reg,
imm12,
});
} else {
let scratch2 = writable_tmp2_reg();
insts.extend(Inst::load_constant(scratch2, imm));
insts.push(Inst::AluRRRShift {
alu_op: ALUOp::Add,
rd: into_reg,
rn: from_reg,
rm: scratch2.to_reg(),
shift: None,
});
}
insts
}
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallVec<[Inst; 2]> {
let mut insts = SmallVec::new();
insts.push(Inst::Cmp {
rn: sp_reg(),
rm: limit_reg,
});
insts.push(Inst::TrapIf {
trap_info: (ir::SourceLoc::default(), ir::TrapCode::StackOverflow),
// Here `Lo` == "less than" when interpreting the two
// operands as unsigned integers.
cond: Cond::Lo,
});
insts
}
fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>, _ty: Type) -> Inst {
let mem = mem.into();
Inst::LoadAddr { rd: into_reg, mem }
}
fn get_stacklimit_reg() -> Reg {
ip_reg()
}
fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset as i64);
Inst::gen_load(into_reg, mem, ty)
}
fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset as i64);
Inst::gen_store(from_reg, mem, ty)
}
fn gen_sp_reg_adjust(amount: i32) -> SmallVec<[Inst; 2]> {
let mut ret = SmallVec::new();
if amount == 0 {
return ret;
}
let (amount, is_sub) = if amount > 0 {
(amount, false)
} else {
(-amount, true)
};
let alu_op = if is_sub { ALUOp::Sub } else { ALUOp::Add };
if let Some(imm12) = UImm12::maybe_from_i64(amount as i64) {
ret.push(Inst::AluRRImm12 {
alu_op,
rd: writable_sp_reg(),
rn: sp_reg(),
imm12,
});
} else {
let tmp = writable_ip_reg();
ret.extend(Inst::load_constant(tmp, amount as u32));
ret.push(Inst::AluRRRShift {
alu_op,
rd: writable_sp_reg(),
rn: sp_reg(),
rm: tmp.to_reg(),
shift: None,
});
}
ret
}
fn gen_nominal_sp_adj(offset: i32) -> Inst {
let offset = i64::from(offset);
Inst::VirtualSPOffsetAdj { offset }
}
fn gen_prologue_frame_setup() -> SmallVec<[Inst; 2]> {
let mut ret = SmallVec::new();
let reg_list = vec![fp_reg(), lr_reg()];
ret.push(Inst::Push { reg_list });
ret.push(Inst::Mov {
rd: writable_fp_reg(),
rm: sp_reg(),
});
ret
}
fn gen_epilogue_frame_restore() -> SmallVec<[Inst; 2]> {
let mut ret = SmallVec::new();
ret.push(Inst::Mov {
rd: writable_sp_reg(),
rm: fp_reg(),
});
let reg_list = vec![writable_fp_reg(), writable_lr_reg()];
ret.push(Inst::Pop { reg_list });
ret
}
/// Returns stack bytes used as well as instructions. Does not adjust
/// nominal SP offset; caller will do that.
fn gen_clobber_save(
_call_conv: isa::CallConv,
clobbers: &Set<Writable<RealReg>>,
) -> (u64, SmallVec<[Inst; 16]>) {
let mut insts = SmallVec::new();
let clobbered_vec = get_callee_saves(clobbers);
let mut clobbered_vec: Vec<_> = clobbered_vec
.into_iter()
.map(|r| r.to_reg().to_reg())
.collect();
if clobbered_vec.len() % 2 == 1 {
// For alignment purposes.
clobbered_vec.push(ip_reg());
}
let stack_used = clobbered_vec.len() * 4;
if !clobbered_vec.is_empty() {
insts.push(Inst::Push {
reg_list: clobbered_vec,
});
}
(stack_used as u64, insts)
}
fn gen_clobber_restore(
_call_conv: isa::CallConv,
clobbers: &Set<Writable<RealReg>>,
) -> SmallVec<[Inst; 16]> {
let mut insts = SmallVec::new();
let clobbered_vec = get_callee_saves(clobbers);
let mut clobbered_vec: Vec<_> = clobbered_vec
.into_iter()
.map(|r| Writable::from_reg(r.to_reg().to_reg()))
.collect();
if clobbered_vec.len() % 2 == 1 {
clobbered_vec.push(writable_ip_reg());
}
if !clobbered_vec.is_empty() {
insts.push(Inst::Pop {
reg_list: clobbered_vec,
});
}
insts
}
fn gen_call(
dest: &CallDest,
uses: Vec<Reg>,
defs: Vec<Writable<Reg>>,
loc: SourceLoc,
opcode: ir::Opcode,
tmp: Writable<Reg>,
) -> SmallVec<[(InstIsSafepoint, Inst); 2]> {
let mut insts = SmallVec::new();
match &dest {
&CallDest::ExtName(ref name, RelocDistance::Near) => insts.push((
InstIsSafepoint::Yes,
Inst::Call {
info: Box::new(CallInfo {
dest: name.clone(),
uses,
defs,
loc,
opcode,
}),
},
)),
&CallDest::ExtName(ref name, RelocDistance::Far) => {
insts.push((
InstIsSafepoint::No,
Inst::LoadExtName {
rt: tmp,
name: Box::new(name.clone()),
offset: 0,
srcloc: loc,
},
));
insts.push((
InstIsSafepoint::Yes,
Inst::CallInd {
info: Box::new(CallIndInfo {
rm: tmp.to_reg(),
uses,
defs,
loc,
opcode,
}),
},
));
}
&CallDest::Reg(reg) => insts.push((
InstIsSafepoint::Yes,
Inst::CallInd {
info: Box::new(CallIndInfo {
rm: *reg,
uses,
defs,
loc,
opcode,
}),
},
)),
}
insts
}
fn get_number_of_spillslots_for_value(rc: RegClass, _ty: Type) -> u32 {
match rc {
RegClass::I32 => 1,
_ => panic!("Unexpected register class!"),
}
}
fn get_virtual_sp_offset_from_state(s: &EmitState) -> i64 {
s.virtual_sp_offset
}
fn get_nominal_sp_to_fp(s: &EmitState) -> i64 {
s.nominal_sp_to_fp
}
fn get_caller_saves(_call_conv: isa::CallConv) -> Vec<Writable<Reg>> {
let mut caller_saved = Vec::new();
for i in 0..15 {
let r = writable_rreg(i);
if is_caller_save(r.to_reg().to_real_reg()) {
caller_saved.push(r);
}
}
caller_saved
}
}
/// Get the set of allocatable registers for `func`.
pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet {
unimplemented!()
fn is_callee_save(r: RealReg) -> bool {
let enc = r.get_hw_encoding();
4 <= enc && enc <= 10
}
fn get_callee_saves(regs: &Set<Writable<RealReg>>) -> Vec<Writable<RealReg>> {
let mut ret = Vec::new();
for &reg in regs.iter() {
if is_callee_save(reg.to_reg()) {
ret.push(reg);
}
}
// Sort registers for deterministic code output.
ret.sort_by_key(|r| r.to_reg().get_index());
ret
}
fn is_caller_save(r: RealReg) -> bool {
let enc = r.get_hw_encoding();
enc <= 3
}

Просмотреть файл

@ -1,8 +0,0 @@
//! Emitting binary ARM32 machine code.
use crate::binemit::{bad_encoding, CodeSink};
use crate::ir::{Function, Inst};
use crate::isa::TargetIsa;
use crate::regalloc::RegDiversions;
include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs"));

Просмотреть файл

@ -1,10 +0,0 @@
//! Encoding tables for ARM32 ISA.
use crate::ir;
use crate::isa;
use crate::isa::constraints::*;
use crate::isa::enc_tables::*;
use crate::isa::encoding::RecipeSizing;
include!(concat!(env!("OUT_DIR"), "/encoding-arm32.rs"));
include!(concat!(env!("OUT_DIR"), "/legalize-arm32.rs"));

335
third_party/rust/cranelift-codegen/src/isa/arm32/inst/args.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,335 @@
//! 32-bit ARM ISA definitions: instruction arguments.
use crate::isa::arm32::inst::*;
use regalloc::{RealRegUniverse, Reg};
use std::string::String;
/// A shift operator for a register or immediate.
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum ShiftOp {
LSL = 0b00,
LSR = 0b01,
ASR = 0b10,
ROR = 0b11,
}
impl ShiftOp {
/// Get the encoding of this shift op.
pub fn bits(self) -> u8 {
self as u8
}
}
/// A shift operator amount.
#[derive(Clone, Copy, Debug)]
pub struct ShiftOpShiftImm(u8);
impl ShiftOpShiftImm {
/// Maximum shift for shifted-register operands.
pub const MAX_SHIFT: u32 = 31;
/// Create a new shiftop shift amount, if possible.
pub fn maybe_from_shift(shift: u32) -> Option<ShiftOpShiftImm> {
if shift <= Self::MAX_SHIFT {
Some(ShiftOpShiftImm(shift as u8))
} else {
None
}
}
/// Return the shift amount.
pub fn value(self) -> u8 {
self.0
}
}
/// A shift operator with an amount, guaranteed to be within range.
#[derive(Clone, Debug)]
pub struct ShiftOpAndAmt {
op: ShiftOp,
shift: ShiftOpShiftImm,
}
impl ShiftOpAndAmt {
pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt {
ShiftOpAndAmt { op, shift }
}
/// Get the shift op.
pub fn op(&self) -> ShiftOp {
self.op
}
/// Get the shift amount.
pub fn amt(&self) -> ShiftOpShiftImm {
self.shift
}
}
// An unsigned 8-bit immediate.
#[derive(Clone, Copy, Debug)]
pub struct UImm8 {
/// The value.
value: u8,
}
impl UImm8 {
pub fn maybe_from_i64(value: i64) -> Option<UImm8> {
if 0 <= value && value < (1 << 8) {
Some(UImm8 { value: value as u8 })
} else {
None
}
}
/// Bits for encoding.
pub fn bits(&self) -> u32 {
u32::from(self.value)
}
}
/// An unsigned 12-bit immediate.
#[derive(Clone, Copy, Debug)]
pub struct UImm12 {
/// The value.
value: u16,
}
impl UImm12 {
pub fn maybe_from_i64(value: i64) -> Option<UImm12> {
if 0 <= value && value < (1 << 12) {
Some(UImm12 {
value: value as u16,
})
} else {
None
}
}
/// Bits for encoding.
pub fn bits(&self) -> u32 {
u32::from(self.value)
}
}
/// An addressing mode specified for a load/store operation.
#[derive(Clone, Debug)]
pub enum AMode {
// Real addressing modes
/// Register plus register offset, which can be shifted left by imm2.
RegReg(Reg, Reg, u8),
/// Unsigned 12-bit immediate offset from reg.
RegOffset12(Reg, UImm12),
/// Immediate offset from program counter aligned to 4.
/// Cannot be used by store instructions.
PCRel(i32),
// Virtual addressing modes that are lowered at emission time:
/// Immediate offset from reg.
RegOffset(Reg, i64),
/// Signed immediate offset from stack pointer.
SPOffset(i64, Type),
/// Offset from the frame pointer.
FPOffset(i64, Type),
/// Signed immediate offset from "nominal stack pointer".
NominalSPOffset(i64, Type),
}
impl AMode {
/// Memory reference using the sum of two registers as an address.
pub fn reg_plus_reg(reg1: Reg, reg2: Reg, shift_amt: u8) -> AMode {
assert!(shift_amt <= 3);
AMode::RegReg(reg1, reg2, shift_amt)
}
/// Memory reference using the sum of a register and an immediate offset
/// as an address.
pub fn reg_plus_imm(reg: Reg, offset: i64) -> AMode {
AMode::RegOffset(reg, offset)
}
}
/// Condition for conditional branches.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum Cond {
Eq = 0,
Ne = 1,
Hs = 2,
Lo = 3,
Mi = 4,
Pl = 5,
Vs = 6,
Vc = 7,
Hi = 8,
Ls = 9,
Ge = 10,
Lt = 11,
Gt = 12,
Le = 13,
Al = 14,
}
impl Cond {
/// Return the inverted condition.
pub fn invert(self) -> Cond {
match self {
Cond::Eq => Cond::Ne,
Cond::Ne => Cond::Eq,
Cond::Hs => Cond::Lo,
Cond::Lo => Cond::Hs,
Cond::Mi => Cond::Pl,
Cond::Pl => Cond::Mi,
Cond::Vs => Cond::Vc,
Cond::Vc => Cond::Vs,
Cond::Hi => Cond::Ls,
Cond::Ls => Cond::Hi,
Cond::Ge => Cond::Lt,
Cond::Lt => Cond::Ge,
Cond::Gt => Cond::Le,
Cond::Le => Cond::Gt,
Cond::Al => panic!("Cannot inverse {:?} condition", self),
}
}
/// Return the machine encoding of this condition.
pub fn bits(self) -> u16 {
self as u16
}
}
/// A branch target. Either unresolved (basic-block index) or resolved (offset
/// from end of current instruction).
#[derive(Clone, Copy, Debug)]
pub enum BranchTarget {
/// An unresolved reference to a Label.
Label(MachLabel),
/// A fixed PC offset.
ResolvedOffset(i32),
}
impl BranchTarget {
/// Return the target's label, if it is a label-based target.
pub fn as_label(self) -> Option<MachLabel> {
match self {
BranchTarget::Label(l) => Some(l),
_ => None,
}
}
// Ready for embedding in instruction.
fn as_offset(self, inst_16_bit: bool) -> i32 {
match self {
BranchTarget::ResolvedOffset(off) => {
if inst_16_bit {
// pc is equal to end of the current inst + 2.
(off - 2) >> 1
} else {
// pc points to end of the current inst.
off >> 1
}
}
_ => 0,
}
}
// For 32-bit unconditional jump.
pub fn as_off24(self) -> u32 {
let off = self.as_offset(false);
assert!(off < (1 << 24));
assert!(off >= -(1 << 24));
(off as u32) & ((1 << 24) - 1)
}
// For 32-bit conditional jump.
pub fn as_off20(self) -> u32 {
let off = self.as_offset(false);
assert!(off < (1 << 20));
assert!(off >= -(1 << 20));
(off as u32) & ((1 << 20) - 1)
}
}
impl ShowWithRRU for ShiftOpAndAmt {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
let op = match self.op() {
ShiftOp::LSL => "lsl",
ShiftOp::LSR => "lsr",
ShiftOp::ASR => "asr",
ShiftOp::ROR => "ror",
};
format!("{} #{}", op, self.amt().value())
}
}
impl ShowWithRRU for UImm8 {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
format!("#{}", self.value)
}
}
impl ShowWithRRU for UImm12 {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
format!("#{}", self.value)
}
}
impl ShowWithRRU for AMode {
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
match self {
&AMode::RegReg(rn, rm, imm2) => {
let shift = if imm2 != 0 {
format!(", lsl #{}", imm2)
} else {
"".to_string()
};
format!(
"[{}, {}{}]",
rn.show_rru(mb_rru),
rm.show_rru(mb_rru),
shift
)
}
&AMode::RegOffset12(rn, off) => {
format!("[{}, {}]", rn.show_rru(mb_rru), off.show_rru(mb_rru))
}
&AMode::PCRel(off) => format!("[pc, #{}]", off),
&AMode::RegOffset(..)
| &AMode::SPOffset(..)
| &AMode::FPOffset(..)
| &AMode::NominalSPOffset(..) => panic!("unexpected mem mode"),
}
}
}
impl ShowWithRRU for Cond {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
let mut s = format!("{:?}", self);
s.make_ascii_lowercase();
s
}
}
impl ShowWithRRU for BranchTarget {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
match self {
&BranchTarget::Label(label) => format!("label{:?}", label.get()),
&BranchTarget::ResolvedOffset(off) => format!("{}", off),
}
}
}

801
third_party/rust/cranelift-codegen/src/isa/arm32/inst/emit.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,801 @@
//! 32-bit ARM ISA: binary code emission.
use crate::binemit::{Reloc, StackMap};
use crate::isa::arm32::inst::*;
use core::convert::TryFrom;
use log::debug;
/// Memory addressing mode finalization: convert "special" modes (e.g.,
/// nominal stack offset) into real addressing modes, possibly by
/// emitting some helper instructions that come immediately before the use
/// of this amode.
pub fn mem_finalize(mem: &AMode, state: &EmitState) -> (SmallVec<[Inst; 4]>, AMode) {
match mem {
&AMode::RegOffset(_, off)
| &AMode::SPOffset(off, _)
| &AMode::FPOffset(off, _)
| &AMode::NominalSPOffset(off, _) => {
let basereg = match mem {
&AMode::RegOffset(reg, _) => reg,
&AMode::SPOffset(..) | &AMode::NominalSPOffset(..) => sp_reg(),
&AMode::FPOffset(..) => fp_reg(),
_ => unreachable!(),
};
let adj = match mem {
&AMode::NominalSPOffset(..) => {
debug!(
"mem_finalize: nominal SP offset {} + adj {} -> {}",
off,
state.virtual_sp_offset,
off + state.virtual_sp_offset
);
state.virtual_sp_offset
}
_ => 0,
};
let off = off + adj;
assert!(-(1 << 31) <= off && off <= (1 << 32));
if let Some(off) = UImm12::maybe_from_i64(off) {
let mem = AMode::RegOffset12(basereg, off);
(smallvec![], mem)
} else {
let tmp = writable_ip_reg();
let const_insts = Inst::load_constant(tmp, off as u32);
let mem = AMode::reg_plus_reg(basereg, tmp.to_reg(), 0);
(const_insts, mem)
}
}
// Just assert immediate is valid here.
_ => (smallvec![], mem.clone()),
}
}
//=============================================================================
// Instructions and subcomponents: emission
fn machreg_to_gpr(m: Reg) -> u16 {
assert_eq!(m.get_class(), RegClass::I32);
u16::try_from(m.to_real_reg().get_hw_encoding()).unwrap()
}
fn machreg_to_gpr_lo(m: Reg) -> u16 {
let gpr_lo = machreg_to_gpr(m);
assert!(gpr_lo < 8);
gpr_lo
}
fn machreg_is_lo(m: Reg) -> bool {
machreg_to_gpr(m) < 8
}
fn enc_16_rr(bits_15_6: u16, rd: Reg, rm: Reg) -> u16 {
(bits_15_6 << 6) | machreg_to_gpr_lo(rd) | (machreg_to_gpr_lo(rm) << 3)
}
fn enc_16_rr_any(bits_15_8: u16, rd: Reg, rm: Reg) -> u16 {
let rd = machreg_to_gpr(rd);
(bits_15_8 << 8) | (rd & 0x7) | ((rd >> 3) << 7) | (machreg_to_gpr(rm) << 3)
}
fn enc_16_mov(rd: Writable<Reg>, rm: Reg) -> u16 {
enc_16_rr_any(0b01000110, rd.to_reg(), rm)
}
fn enc_16_it(cond: Cond, insts: &Vec<CondInst>) -> u16 {
let cond = cond.bits();
let mut mask: u16 = 0;
for inst in insts.iter().skip(1) {
if inst.then {
mask |= cond & 0x1;
} else {
mask |= (cond & 0x1) ^ 0x1;
}
mask <<= 1;
}
mask |= 0x1;
mask <<= 4 - insts.len();
0b1011_1111_0000_0000 | (cond << 4) | mask
}
fn enc_32_regs(
mut inst: u32,
reg_0: Option<Reg>,
reg_8: Option<Reg>,
reg_12: Option<Reg>,
reg_16: Option<Reg>,
) -> u32 {
if let Some(reg_0) = reg_0 {
inst |= u32::from(machreg_to_gpr(reg_0));
}
if let Some(reg_8) = reg_8 {
inst |= u32::from(machreg_to_gpr(reg_8)) << 8;
}
if let Some(reg_12) = reg_12 {
inst |= u32::from(machreg_to_gpr(reg_12)) << 12;
}
if let Some(reg_16) = reg_16 {
inst |= u32::from(machreg_to_gpr(reg_16)) << 16;
}
inst
}
fn enc_32_reg_shift(inst: u32, shift: &Option<ShiftOpAndAmt>) -> u32 {
match shift {
Some(shift) => {
let op = u32::from(shift.op().bits());
let amt = u32::from(shift.amt().value());
let imm2 = amt & 0x3;
let imm3 = (amt >> 2) & 0x7;
inst | (op << 4) | (imm2 << 6) | (imm3 << 12)
}
None => inst,
}
}
fn enc_32_r_imm16(bits_31_20: u32, rd: Reg, imm16: u16) -> u32 {
let imm16 = u32::from(imm16);
let imm8 = imm16 & 0xff;
let imm3 = (imm16 >> 8) & 0x7;
let i = (imm16 >> 11) & 0x1;
let imm4 = (imm16 >> 12) & 0xf;
let inst = ((bits_31_20 << 20) & !(1 << 26)) | imm8 | (imm3 << 12) | (imm4 << 16) | (i << 26);
enc_32_regs(inst, None, Some(rd), None, None)
}
fn enc_32_rrr(bits_31_20: u32, bits_15_12: u32, bits_7_4: u32, rd: Reg, rm: Reg, rn: Reg) -> u32 {
let inst = (bits_31_20 << 20) | (bits_15_12 << 12) | (bits_7_4 << 4);
enc_32_regs(inst, Some(rm), Some(rd), None, Some(rn))
}
fn enc_32_imm12(inst: u32, imm12: UImm12) -> u32 {
let imm12 = imm12.bits();
let imm8 = imm12 & 0xff;
let imm3 = (imm12 >> 8) & 0x7;
let i = (imm12 >> 11) & 0x1;
inst | imm8 | (imm3 << 12) | (i << 26)
}
fn enc_32_mem_r(bits_24_20: u32, rt: Reg, rn: Reg, rm: Reg, imm2: u8) -> u32 {
let imm2 = u32::from(imm2);
let inst = (imm2 << 4) | (bits_24_20 << 20) | (0b11111 << 27);
enc_32_regs(inst, Some(rm), None, Some(rt), Some(rn))
}
fn enc_32_mem_off12(bits_24_20: u32, rt: Reg, rn: Reg, off12: UImm12) -> u32 {
let off12 = off12.bits();
let inst = off12 | (bits_24_20 << 20) | (0b11111 << 27);
enc_32_regs(inst, None, None, Some(rt), Some(rn))
}
fn enc_32_jump(target: BranchTarget) -> u32 {
let off24 = target.as_off24();
let imm11 = off24 & 0x7ff;
let imm10 = (off24 >> 11) & 0x3ff;
let i2 = (off24 >> 21) & 0x1;
let i1 = (off24 >> 22) & 0x1;
let s = (off24 >> 23) & 0x1;
let j1 = (i1 ^ s) ^ 1;
let j2 = (i2 ^ s) ^ 1;
0b11110_0_0000000000_10_0_1_0_00000000000
| imm11
| (j2 << 11)
| (j1 << 13)
| (imm10 << 16)
| (s << 26)
}
fn enc_32_cond_branch(cond: Cond, target: BranchTarget) -> u32 {
let cond = u32::from(cond.bits());
let off20 = target.as_off20();
let imm11 = off20 & 0x7ff;
let imm6 = (off20 >> 11) & 0x3f;
let j1 = (off20 >> 17) & 0x1;
let j2 = (off20 >> 18) & 0x1;
let s = (off20 >> 19) & 0x1;
0b11110_0_0000_000000_10_0_0_0_00000000000
| imm11
| (j2 << 11)
| (j1 << 13)
| (imm6 << 16)
| (cond << 22)
| (s << 26)
}
fn u32_swap_halfwords(x: u32) -> u32 {
(x >> 16) | (x << 16)
}
fn emit_32(inst: u32, sink: &mut MachBuffer<Inst>) {
let inst_hi = (inst >> 16) as u16;
let inst_lo = (inst & 0xffff) as u16;
sink.put2(inst_hi);
sink.put2(inst_lo);
}
/// State carried between emissions of a sequence of instructions.
#[derive(Default, Clone, Debug)]
pub struct EmitState {
/// Addend to convert nominal-SP offsets to real-SP offsets at the current
/// program point.
pub(crate) virtual_sp_offset: i64,
/// Offset of FP from nominal-SP.
pub(crate) nominal_sp_to_fp: i64,
/// Safepoint stack map for upcoming instruction, as provided to `pre_safepoint()`.
stack_map: Option<StackMap>,
}
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
EmitState {
virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64,
stack_map: None,
}
}
fn pre_safepoint(&mut self, stack_map: StackMap) {
self.stack_map = Some(stack_map);
}
}
impl EmitState {
fn take_stack_map(&mut self) -> Option<StackMap> {
self.stack_map.take()
}
fn clear_post_insn(&mut self) {
self.stack_map = None;
}
}
impl MachInstEmit for Inst {
type State = EmitState;
fn emit(&self, sink: &mut MachBuffer<Inst>, flags: &settings::Flags, state: &mut EmitState) {
let start_off = sink.cur_offset();
match self {
&Inst::Nop0 | &Inst::EpiloguePlaceholder => {}
&Inst::Nop2 => {
sink.put2(0b1011_1111_0000_0000);
}
&Inst::AluRRR { alu_op, rd, rn, rm } => {
let (bits_31_20, bits_15_12, bits_7_4) = match alu_op {
ALUOp::Lsl => (0b111110100000, 0b1111, 0b0000),
ALUOp::Lsr => (0b111110100010, 0b1111, 0b0000),
ALUOp::Asr => (0b111110100100, 0b1111, 0b0000),
ALUOp::Ror => (0b111110100110, 0b1111, 0b0000),
ALUOp::Qadd => (0b111110101000, 0b1111, 0b1000),
ALUOp::Qsub => (0b111110101000, 0b1111, 0b1010),
ALUOp::Mul => (0b111110110000, 0b1111, 0b0000),
ALUOp::Udiv => (0b111110111011, 0b1111, 0b1111),
ALUOp::Sdiv => (0b111110111001, 0b1111, 0b1111),
_ => panic!("Invalid ALUOp {:?} in RRR form!", alu_op),
};
emit_32(
enc_32_rrr(bits_31_20, bits_15_12, bits_7_4, rd.to_reg(), rm, rn),
sink,
);
}
&Inst::AluRRRShift {
alu_op,
rd,
rn,
rm,
ref shift,
} => {
let bits_31_24 = 0b111_0101;
let bits_24_20 = match alu_op {
ALUOp::And => 0b00000,
ALUOp::Bic => 0b00010,
ALUOp::Orr => 0b00100,
ALUOp::Orn => 0b00110,
ALUOp::Eor => 0b01000,
ALUOp::Add => 0b10000,
ALUOp::Adds => 0b10001,
ALUOp::Adc => 0b10100,
ALUOp::Adcs => 0b10101,
ALUOp::Sbc => 0b10110,
ALUOp::Sbcs => 0b10111,
ALUOp::Sub => 0b11010,
ALUOp::Subs => 0b11011,
ALUOp::Rsb => 0b11100,
_ => panic!("Invalid ALUOp {:?} in RRRShift form!", alu_op),
};
let bits_31_20 = (bits_31_24 << 5) | bits_24_20;
let inst = enc_32_rrr(bits_31_20, 0, 0, rd.to_reg(), rm, rn);
let inst = enc_32_reg_shift(inst, shift);
emit_32(inst, sink);
}
&Inst::AluRRShift {
alu_op,
rd,
rm,
ref shift,
} => {
let bits_24_21 = match alu_op {
ALUOp1::Mvn => 0b0011,
ALUOp1::Mov => 0b0010,
};
let inst = 0b1110101_0000_0_1111_0_000_0000_00_00_0000 | (bits_24_21 << 21);
let inst = enc_32_regs(inst, Some(rm), Some(rd.to_reg()), None, None);
let inst = enc_32_reg_shift(inst, shift);
emit_32(inst, sink);
}
&Inst::AluRRRR {
alu_op,
rd_hi,
rd_lo,
rn,
rm,
} => {
let (bits_22_20, bits_7_4) = match alu_op {
ALUOp::Smull => (0b000, 0b0000),
ALUOp::Umull => (0b010, 0b0000),
_ => panic!("Invalid ALUOp {:?} in RRRR form!", alu_op),
};
let inst = (0b111110111 << 23) | (bits_22_20 << 20) | (bits_7_4 << 4);
let inst = enc_32_regs(
inst,
Some(rm),
Some(rd_hi.to_reg()),
Some(rd_lo.to_reg()),
Some(rn),
);
emit_32(inst, sink);
}
&Inst::AluRRImm12 {
alu_op,
rd,
rn,
imm12,
} => {
let bits_24_20 = match alu_op {
ALUOp::Add => 0b00000,
ALUOp::Sub => 0b01010,
_ => panic!("Invalid ALUOp {:?} in RRImm12 form!", alu_op),
};
let inst = (0b11110_0_1 << 25) | (bits_24_20 << 20);
let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, Some(rn));
let inst = enc_32_imm12(inst, imm12);
emit_32(inst, sink);
}
&Inst::AluRRImm8 {
alu_op,
rd,
rn,
imm8,
} => {
let bits_24_20 = match alu_op {
ALUOp::And => 0b00000,
ALUOp::Bic => 0b00010,
ALUOp::Orr => 0b00100,
ALUOp::Orn => 0b00110,
ALUOp::Eor => 0b01000,
ALUOp::Add => 0b10000,
ALUOp::Adds => 0b10001,
ALUOp::Adc => 0b10100,
ALUOp::Adcs => 0b10101,
ALUOp::Sbc => 0b10110,
ALUOp::Sbcs => 0b10111,
ALUOp::Sub => 0b11010,
ALUOp::Subs => 0b11011,
ALUOp::Rsb => 0b11100,
_ => panic!("Invalid ALUOp {:?} in RRImm8 form!", alu_op),
};
let imm8 = imm8.bits();
let inst = 0b11110_0_0_00000_0000_0_000_0000_00000000 | imm8 | (bits_24_20 << 20);
let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, Some(rn));
emit_32(inst, sink);
}
&Inst::AluRImm8 { alu_op, rd, imm8 } => {
let bits_24_20 = match alu_op {
ALUOp1::Mvn => 0b00110,
ALUOp1::Mov => 0b00100,
};
let imm8 = imm8.bits();
let inst = 0b11110_0_0_00000_1111_0_000_0000_00000000 | imm8 | (bits_24_20 << 20);
let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, None);
emit_32(inst, sink);
}
&Inst::BitOpRR { bit_op, rd, rm } => {
let (bits_22_20, bits_7_4) = match bit_op {
BitOp::Rbit => (0b001, 0b1010),
BitOp::Rev => (0b001, 0b1000),
BitOp::Clz => (0b011, 0b1000),
};
let inst =
0b111110101_000_0000_1111_0000_0000_0000 | (bits_22_20 << 20) | (bits_7_4 << 4);
let inst = enc_32_regs(inst, Some(rm), Some(rd.to_reg()), None, Some(rm));
emit_32(inst, sink);
}
&Inst::Mov { rd, rm } => {
sink.put2(enc_16_mov(rd, rm));
}
&Inst::MovImm16 { rd, imm16 } => {
emit_32(enc_32_r_imm16(0b11110_0_100100, rd.to_reg(), imm16), sink);
}
&Inst::Movt { rd, imm16 } => {
emit_32(enc_32_r_imm16(0b11110_0_101100, rd.to_reg(), imm16), sink);
}
&Inst::Cmp { rn, rm } => {
// Check which 16-bit encoding is allowed.
if machreg_is_lo(rn) && machreg_is_lo(rm) {
sink.put2(enc_16_rr(0b0100001010, rn, rm));
} else {
sink.put2(enc_16_rr_any(0b01000101, rn, rm));
}
}
&Inst::CmpImm8 { rn, imm8 } => {
let inst = 0b11110_0_011011_0000_0_000_1111_00000000 | u32::from(imm8);
let inst = enc_32_regs(inst, None, None, None, Some(rn));
emit_32(inst, sink);
}
&Inst::Store {
rt,
ref mem,
srcloc,
bits,
} => {
let (mem_insts, mem) = mem_finalize(mem, state);
for inst in mem_insts.into_iter() {
inst.emit(sink, flags, state);
}
if let Some(srcloc) = srcloc {
// Register the offset at which the store instruction starts.
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
}
match mem {
AMode::RegReg(rn, rm, imm2) => {
let bits_24_20 = match bits {
32 => 0b00100,
16 => 0b00010,
8 => 0b00000,
_ => panic!("Unsupported store case {:?}", self),
};
emit_32(enc_32_mem_r(bits_24_20, rt, rn, rm, imm2), sink);
}
AMode::RegOffset12(rn, off12) => {
let bits_24_20 = match bits {
32 => 0b01100,
16 => 0b01010,
8 => 0b01000,
_ => panic!("Unsupported store case {:?}", self),
};
emit_32(enc_32_mem_off12(bits_24_20, rt, rn, off12), sink);
}
AMode::PCRel(_) => panic!("Unsupported store case {:?}", self),
_ => unreachable!(),
}
}
&Inst::Load {
rt,
ref mem,
srcloc,
bits,
sign_extend,
} => {
let (mem_insts, mem) = mem_finalize(mem, state);
for inst in mem_insts.into_iter() {
inst.emit(sink, flags, state);
}
if let Some(srcloc) = srcloc {
// Register the offset at which the load instruction starts.
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
}
match mem {
AMode::RegReg(rn, rm, imm2) => {
let bits_24_20 = match (bits, sign_extend) {
(32, _) => 0b00101,
(16, true) => 0b10011,
(16, false) => 0b00011,
(8, true) => 0b10001,
(8, false) => 0b00001,
_ => panic!("Unsupported load case {:?}", self),
};
emit_32(enc_32_mem_r(bits_24_20, rt.to_reg(), rn, rm, imm2), sink);
}
AMode::RegOffset12(rn, off12) => {
let bits_24_20 = match (bits, sign_extend) {
(32, _) => 0b01101,
(16, true) => 0b11011,
(16, false) => 0b01011,
(8, true) => 0b11001,
(8, false) => 0b01001,
_ => panic!("Unsupported load case {:?}", self),
};
emit_32(enc_32_mem_off12(bits_24_20, rt.to_reg(), rn, off12), sink);
}
AMode::PCRel(off12) => {
let mut bits_24_20 = match (bits, sign_extend) {
(32, _) => 0b00101,
(16, true) => 0b10011,
(16, false) => 0b00011,
(8, true) => 0b10001,
(8, false) => 0b00001,
_ => panic!("Unsupported load case {:?}", self),
};
let (u, off12) = if off12 > 0 { (1, off12) } else { (0, -off12) };
let off12 = UImm12::maybe_from_i64(i64::from(off12)).unwrap();
bits_24_20 |= u << 3;
emit_32(
enc_32_mem_off12(bits_24_20, rt.to_reg(), pc_reg(), off12),
sink,
);
}
_ => unreachable!(),
}
}
&Inst::LoadAddr { rd, ref mem } => {
let (mem_insts, mem) = mem_finalize(mem, state);
for inst in mem_insts.into_iter() {
inst.emit(sink, flags, state);
}
let inst = match mem {
AMode::RegReg(reg1, reg2, shift) => {
let shift = u32::from(shift);
let shift_amt = ShiftOpShiftImm::maybe_from_shift(shift).unwrap();
let shift = ShiftOpAndAmt::new(ShiftOp::LSL, shift_amt);
Inst::AluRRRShift {
alu_op: ALUOp::Add,
rd,
rn: reg1,
rm: reg2,
shift: Some(shift),
}
}
AMode::RegOffset12(reg, imm12) => Inst::AluRRImm12 {
alu_op: ALUOp::Add,
rd,
rn: reg,
imm12,
},
AMode::PCRel(off12) => {
let (off12, alu_op) = if off12 > 0 {
(off12, ALUOp::Add)
} else {
(-off12, ALUOp::Sub)
};
let imm12 = UImm12::maybe_from_i64(i64::from(off12)).unwrap();
Inst::AluRRImm12 {
alu_op,
rd,
rn: pc_reg(),
imm12,
}
}
_ => unreachable!(),
};
inst.emit(sink, flags, state);
}
&Inst::Extend {
rd,
rm,
from_bits,
signed,
} if from_bits >= 8 => {
let rd = rd.to_reg();
if machreg_is_lo(rd) && machreg_is_lo(rm) {
let bits_15_9 = match (from_bits, signed) {
(16, true) => 0b1011001000,
(16, false) => 0b1011001010,
(8, true) => 0b1011001001,
(8, false) => 0b1011001011,
_ => panic!("Unsupported Extend case: {:?}", self),
};
sink.put2(enc_16_rr(bits_15_9, rd, rm));
} else {
let bits_22_20 = match (from_bits, signed) {
(16, true) => 0b000,
(16, false) => 0b001,
(8, true) => 0b100,
(8, false) => 0b101,
_ => panic!("Unsupported Extend case: {:?}", self),
};
let inst = 0b111110100_000_11111111_0000_1000_0000 | (bits_22_20 << 20);
let inst = enc_32_regs(inst, Some(rm), Some(rd), None, None);
emit_32(inst, sink);
}
}
&Inst::Extend {
rd,
rm,
from_bits,
signed,
} if from_bits == 1 => {
let inst = Inst::AluRRImm8 {
alu_op: ALUOp::And,
rd,
rn: rm,
imm8: UImm8::maybe_from_i64(1).unwrap(),
};
inst.emit(sink, flags, state);
if signed {
let inst = Inst::AluRRImm8 {
alu_op: ALUOp::Rsb,
rd,
rn: rd.to_reg(),
imm8: UImm8::maybe_from_i64(1).unwrap(),
};
inst.emit(sink, flags, state);
}
}
&Inst::Extend { .. } => {
panic!("Unsupported extend variant");
}
&Inst::It { cond, ref insts } => {
assert!(1 <= insts.len() && insts.len() <= 4);
assert!(insts[0].then);
sink.put2(enc_16_it(cond, insts));
for inst in insts.iter() {
inst.inst.emit(sink, flags, state);
}
}
&Inst::Push { ref reg_list } => match reg_list.len() {
0 => panic!("Unsupported Push case: {:?}", self),
1 => {
let reg = u32::from(machreg_to_gpr(reg_list[0]));
let inst: u32 = 0b1111100001001101_0000_110100000100 | (reg << 12);
emit_32(inst, sink);
}
_ => {
let mut inst: u32 = 0b1110100100101101 << 16;
for reg in reg_list {
inst |= 1 << machreg_to_gpr(*reg);
}
if inst & ((1 << 13) | (1 << 15)) != 0 {
panic!("Unsupported Push case: {:?}", self);
}
emit_32(inst, sink);
}
},
&Inst::Pop { ref reg_list } => match reg_list.len() {
0 => panic!("Unsupported Pop case: {:?}", self),
1 => {
let reg = u32::from(machreg_to_gpr(reg_list[0].to_reg()));
let inst: u32 = 0b1111100001011101_0000_101100000100 | (reg << 12);
emit_32(inst, sink);
}
_ => {
let mut inst: u32 = 0b1110100010111101 << 16;
for reg in reg_list {
inst |= 1 << machreg_to_gpr(reg.to_reg());
}
if (inst & (1 << 14) != 0) && (inst & (1 << 15) != 0) {
panic!("Unsupported Pop case: {:?}", self);
}
emit_32(inst, sink);
}
},
&Inst::Call { ref info } => {
sink.add_reloc(info.loc, Reloc::Arm32Call, &info.dest, 0);
emit_32(0b11110_0_0000000000_11_0_1_0_00000000000, sink);
if info.opcode.is_call() {
sink.add_call_site(info.loc, info.opcode);
}
}
&Inst::CallInd { ref info } => {
sink.put2(0b01000111_1_0000_000 | (machreg_to_gpr(info.rm) << 3));
if info.opcode.is_call() {
sink.add_call_site(info.loc, info.opcode);
}
}
&Inst::LoadExtName {
rt,
ref name,
offset,
srcloc,
} => {
// maybe nop2 (0|2) bytes (pc is now 4-aligned)
// ldr rt, [pc, #4] 4 bytes
// b continue 4 bytes
// addr 4 bytes
// continue:
//
if start_off & 0x3 != 0 {
Inst::Nop2.emit(sink, flags, state);
}
assert_eq!(sink.cur_offset() & 0x3, 0);
let mem = AMode::PCRel(4);
let inst = Inst::Load {
rt,
mem,
srcloc: Some(srcloc),
bits: 32,
sign_extend: false,
};
inst.emit(sink, flags, state);
let inst = Inst::Jump {
dest: BranchTarget::ResolvedOffset(4),
};
inst.emit(sink, flags, state);
sink.add_reloc(srcloc, Reloc::Abs4, name, offset.into());
sink.put4(0);
}
&Inst::Ret => {
sink.put2(0b010001110_1110_000); // bx lr
}
&Inst::Jump { dest } => {
let off = sink.cur_offset();
// Indicate that the jump uses a label, if so, so that a fixup can occur later.
if let Some(l) = dest.as_label() {
sink.use_label_at_offset(off, l, LabelUse::Branch24);
sink.add_uncond_branch(off, off + 4, l);
}
emit_32(enc_32_jump(dest), sink);
}
&Inst::CondBr {
taken,
not_taken,
cond,
} => {
// Conditional part first.
let cond_off = sink.cur_offset();
if let Some(l) = taken.as_label() {
let label_use = LabelUse::Branch20;
sink.use_label_at_offset(cond_off, l, label_use);
let inverted = enc_32_cond_branch(cond.invert(), taken);
let inverted = u32_swap_halfwords(inverted).to_le_bytes();
sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
}
emit_32(enc_32_cond_branch(cond, taken), sink);
// Unconditional part.
let uncond_off = sink.cur_offset();
if let Some(l) = not_taken.as_label() {
sink.use_label_at_offset(uncond_off, l, LabelUse::Branch24);
sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
}
emit_32(enc_32_jump(not_taken), sink);
}
&Inst::IndirectBr { rm, .. } => {
let inst = 0b010001110_0000_000 | (machreg_to_gpr(rm) << 3);
sink.put2(inst);
}
&Inst::Udf { trap_info } => {
let (srcloc, code) = trap_info;
sink.add_trap(srcloc, code);
sink.put2(0b11011110_00000000);
}
&Inst::Bkpt => {
sink.put2(0b10111110_00000000);
}
&Inst::TrapIf { cond, trap_info } => {
let cond = cond.invert();
let dest = BranchTarget::ResolvedOffset(2);
emit_32(enc_32_cond_branch(cond, dest), sink);
let trap = Inst::Udf { trap_info };
trap.emit(sink, flags, state);
}
&Inst::VirtualSPOffsetAdj { offset } => {
debug!(
"virtual sp offset adjusted by {} -> {}",
offset,
state.virtual_sp_offset + offset,
);
state.virtual_sp_offset += offset;
}
}
let end_off = sink.cur_offset();
debug_assert!((end_off - start_off) <= Inst::worst_case_size());
}
fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String {
self.print_with_state(mb_rru, state)
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1365
third_party/rust/cranelift-codegen/src/isa/arm32/inst/mod.rs поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

128
third_party/rust/cranelift-codegen/src/isa/arm32/inst/regs.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,128 @@
//! 32-bit ARM ISA definitions: registers.
use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES};
use std::string::ToString;
/// Get a reference to a GPR.
pub fn rreg(num: u8) -> Reg {
assert!(num < 16);
Reg::new_real(RegClass::I32, num, num)
}
/// Get a writable reference to a GPR.
pub fn writable_rreg(num: u8) -> Writable<Reg> {
Writable::from_reg(rreg(num))
}
/// Get a reference to the program counter (r15).
pub fn pc_reg() -> Reg {
rreg(15)
}
/// Get a writable reference to the program counter.
pub fn writable_pc_reg() -> Writable<Reg> {
Writable::from_reg(pc_reg())
}
/// Get a reference to the link register (r14).
pub fn lr_reg() -> Reg {
rreg(14)
}
/// Get a writable reference to the link register.
pub fn writable_lr_reg() -> Writable<Reg> {
Writable::from_reg(lr_reg())
}
/// Get a reference to the stack pointer (r13).
pub fn sp_reg() -> Reg {
rreg(13)
}
/// Get a writable reference to the stack pointer.
pub fn writable_sp_reg() -> Writable<Reg> {
Writable::from_reg(sp_reg())
}
/// Get a reference to the intra-procedure-call scratch register (r12),
/// which is used as a temporary register.
pub fn ip_reg() -> Reg {
rreg(12)
}
/// Get a writable reference to the Intra-Procedure-call scratch register.
pub fn writable_ip_reg() -> Writable<Reg> {
Writable::from_reg(ip_reg())
}
/// Get a reference to the frame pointer register (r11).
pub fn fp_reg() -> Reg {
rreg(11)
}
/// Get a writable reference to the frame-pointer register.
pub fn writable_fp_reg() -> Writable<Reg> {
Writable::from_reg(fp_reg())
}
/// Get a reference to the second temp register. We need this in some edge cases
/// where we need both the ip and another temporary.
///
/// We use r10 for this role.
pub fn tmp2_reg() -> Reg {
rreg(10)
}
/// Get a writable reference to the tmp2 reg.
pub fn writable_tmp2_reg() -> Writable<Reg> {
Writable::from_reg(tmp2_reg())
}
/// Create the register universe.
/// Use only GPR for now.
pub fn create_reg_universe() -> RealRegUniverse {
let mut regs = vec![];
let mut allocable_by_class = [None; NUM_REG_CLASSES];
let r_reg_base = 0u8;
let r_reg_count = 10; // to exclude r10, fp, ip, sp, lr and pc.
for i in 0..r_reg_count {
let reg = Reg::new_real(
RegClass::I32,
/* enc = */ i,
/* index = */ r_reg_base + i,
)
.to_real_reg();
let name = format!("r{}", i);
regs.push((reg, name));
}
let r_reg_last = r_reg_base + r_reg_count - 1;
allocable_by_class[RegClass::I32.rc_to_usize()] = Some(RegClassInfo {
first: r_reg_base as usize,
last: r_reg_last as usize,
suggested_scratch: None,
});
// Other regs, not available to the allocator.
let allocable = regs.len();
regs.push((tmp2_reg().to_real_reg(), "r10".to_string()));
regs.push((fp_reg().to_real_reg(), "fp".to_string()));
regs.push((ip_reg().to_real_reg(), "ip".to_string()));
regs.push((sp_reg().to_real_reg(), "sp".to_string()));
regs.push((lr_reg().to_real_reg(), "lr".to_string()));
regs.push((pc_reg().to_real_reg(), "pc".to_string()));
// The indices in the register structs must match their
// actual indices in the array.
for (i, reg) in regs.iter().enumerate() {
assert_eq!(i, reg.0.get_index());
}
RealRegUniverse {
regs,
allocable,
allocable_by_class,
}
}

240
third_party/rust/cranelift-codegen/src/isa/arm32/lower.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,240 @@
//! Lowering rules for 32-bit ARM.
use crate::ir::condcodes::IntCC;
use crate::ir::types::*;
use crate::ir::Inst as IRInst;
use crate::ir::{InstructionData, Opcode, TrapCode};
use crate::machinst::lower::*;
use crate::machinst::*;
use crate::CodegenResult;
use crate::isa::arm32::inst::*;
use crate::isa::arm32::Arm32Backend;
use super::lower_inst;
use regalloc::{Reg, RegClass, Writable};
//============================================================================
// Lowering: convert instruction outputs to result types.
/// Lower an instruction output to a 32-bit constant, if possible.
pub(crate) fn output_to_const<C: LowerCtx<I = Inst>>(ctx: &mut C, out: InsnOutput) -> Option<u64> {
if out.output > 0 {
None
} else {
let inst_data = ctx.data(out.insn);
if inst_data.opcode() == Opcode::Null {
Some(0)
} else {
match inst_data {
&InstructionData::UnaryImm { opcode: _, imm } => {
// Only has Into for i64; we use u64 elsewhere, so we cast.
let imm: i64 = imm.into();
Some(imm as u64)
}
&InstructionData::UnaryBool { opcode: _, imm } => Some(u64::from(imm)),
&InstructionData::UnaryIeee32 { .. } | &InstructionData::UnaryIeee64 { .. } => {
unimplemented!()
}
_ => None,
}
}
}
}
/// How to handle narrow values loaded into registers.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum NarrowValueMode {
None,
/// Zero-extend to 32 bits if original is < 32 bits.
ZeroExtend,
/// Sign-extend to 32 bits if original is < 32 bits.
SignExtend,
}
/// Lower an instruction output to a reg.
pub(crate) fn output_to_reg<C: LowerCtx<I = Inst>>(ctx: &mut C, out: InsnOutput) -> Writable<Reg> {
ctx.get_output(out.insn, out.output)
}
/// Lower an instruction input to a reg.
///
/// The given register will be extended appropriately, according to `narrow_mode`.
pub(crate) fn input_to_reg<C: LowerCtx<I = Inst>>(
ctx: &mut C,
input: InsnInput,
narrow_mode: NarrowValueMode,
) -> Reg {
let ty = ctx.input_ty(input.insn, input.input);
let from_bits = ty.bits() as u8;
let inputs = ctx.get_input(input.insn, input.input);
let in_reg = if let Some(c) = inputs.constant {
let to_reg = ctx.alloc_tmp(Inst::rc_for_type(ty).unwrap(), ty);
for inst in Inst::gen_constant(to_reg, c, ty, |reg_class, ty| ctx.alloc_tmp(reg_class, ty))
.into_iter()
{
ctx.emit(inst);
}
to_reg.to_reg()
} else {
ctx.use_input_reg(inputs);
inputs.reg
};
match (narrow_mode, from_bits) {
(NarrowValueMode::None, _) => in_reg,
(NarrowValueMode::ZeroExtend, 1) => {
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
ctx.emit(Inst::AluRRImm8 {
alu_op: ALUOp::And,
rd: tmp,
rn: in_reg,
imm8: UImm8::maybe_from_i64(0x1).unwrap(),
});
tmp.to_reg()
}
(NarrowValueMode::ZeroExtend, n) if n < 32 => {
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
ctx.emit(Inst::Extend {
rd: tmp,
rm: in_reg,
signed: false,
from_bits: n,
});
tmp.to_reg()
}
(NarrowValueMode::SignExtend, n) if n < 32 => {
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
ctx.emit(Inst::Extend {
rd: tmp,
rm: in_reg,
signed: true,
from_bits: n,
});
tmp.to_reg()
}
(NarrowValueMode::ZeroExtend, 32) | (NarrowValueMode::SignExtend, 32) => in_reg,
_ => panic!(
"Unsupported input width: input ty {} bits {} mode {:?}",
ty, from_bits, narrow_mode
),
}
}
pub(crate) fn lower_constant<C: LowerCtx<I = Inst>>(ctx: &mut C, rd: Writable<Reg>, value: u64) {
// We allow sign bits for high word.
assert!((value >> 32) == 0x0 || (value >> 32) == (1 << 32) - 1);
for inst in Inst::load_constant(rd, (value & ((1 << 32) - 1)) as u32) {
ctx.emit(inst);
}
}
pub(crate) fn emit_cmp<C: LowerCtx<I = Inst>>(ctx: &mut C, insn: IRInst) {
let inputs = [InsnInput { insn, input: 0 }, InsnInput { insn, input: 1 }];
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
ctx.emit(Inst::Cmp { rn, rm });
}
pub(crate) fn lower_condcode(cc: IntCC) -> Cond {
match cc {
IntCC::Equal => Cond::Eq,
IntCC::NotEqual => Cond::Ne,
IntCC::SignedGreaterThanOrEqual => Cond::Ge,
IntCC::SignedGreaterThan => Cond::Gt,
IntCC::SignedLessThanOrEqual => Cond::Le,
IntCC::SignedLessThan => Cond::Lt,
IntCC::UnsignedGreaterThanOrEqual => Cond::Hs,
IntCC::UnsignedGreaterThan => Cond::Hi,
IntCC::UnsignedLessThanOrEqual => Cond::Ls,
IntCC::UnsignedLessThan => Cond::Lo,
IntCC::Overflow => Cond::Vs,
IntCC::NotOverflow => Cond::Vc,
}
}
/// Determines whether this condcode interprets inputs as signed or unsigned.
pub(crate) fn condcode_is_signed(cc: IntCC) -> bool {
match cc {
IntCC::Equal => false,
IntCC::NotEqual => false,
IntCC::SignedGreaterThanOrEqual => true,
IntCC::SignedGreaterThan => true,
IntCC::SignedLessThanOrEqual => true,
IntCC::SignedLessThan => true,
IntCC::UnsignedGreaterThanOrEqual => false,
IntCC::UnsignedGreaterThan => false,
IntCC::UnsignedLessThanOrEqual => false,
IntCC::UnsignedLessThan => false,
IntCC::Overflow => true,
IntCC::NotOverflow => true,
}
}
//=============================================================================
// Helpers for instruction lowering.
pub(crate) fn ldst_offset(data: &InstructionData) -> Option<i32> {
match data {
&InstructionData::Load { offset, .. }
| &InstructionData::StackLoad { offset, .. }
| &InstructionData::LoadComplex { offset, .. }
| &InstructionData::Store { offset, .. }
| &InstructionData::StackStore { offset, .. }
| &InstructionData::StoreComplex { offset, .. } => Some(offset.into()),
_ => None,
}
}
pub(crate) fn inst_condcode(data: &InstructionData) -> Option<IntCC> {
match data {
&InstructionData::IntCond { cond, .. }
| &InstructionData::BranchIcmp { cond, .. }
| &InstructionData::IntCompare { cond, .. }
| &InstructionData::IntCondTrap { cond, .. }
| &InstructionData::BranchInt { cond, .. }
| &InstructionData::IntSelect { cond, .. }
| &InstructionData::IntCompareImm { cond, .. } => Some(cond),
_ => None,
}
}
pub(crate) fn inst_trapcode(data: &InstructionData) -> Option<TrapCode> {
match data {
&InstructionData::Trap { code, .. }
| &InstructionData::CondTrap { code, .. }
| &InstructionData::IntCondTrap { code, .. } => Some(code),
&InstructionData::FloatCondTrap { code, .. } => {
panic!("Unexpected float cond trap {:?}", code)
}
_ => None,
}
}
//=============================================================================
// Lowering-backend trait implementation.
impl LowerBackend for Arm32Backend {
type MInst = Inst;
fn lower<C: LowerCtx<I = Inst>>(&self, ctx: &mut C, ir_inst: IRInst) -> CodegenResult<()> {
lower_inst::lower_insn_to_regs(ctx, ir_inst)
}
fn lower_branch_group<C: LowerCtx<I = Inst>>(
&self,
ctx: &mut C,
branches: &[IRInst],
targets: &[MachLabel],
fallthrough: Option<MachLabel>,
) -> CodegenResult<()> {
lower_inst::lower_branch(ctx, branches, targets, fallthrough)
}
fn maybe_pinned_reg(&self) -> Option<Reg> {
None
}
}

623
third_party/rust/cranelift-codegen/src/isa/arm32/lower_inst.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,623 @@
//! Lower a single Cranelift instruction into vcode.
use crate::ir::types::*;
use crate::ir::Inst as IRInst;
use crate::ir::Opcode;
use crate::machinst::lower::*;
use crate::machinst::*;
use crate::CodegenResult;
use crate::isa::arm32::abi::*;
use crate::isa::arm32::inst::*;
use regalloc::RegClass;
use smallvec::SmallVec;
use super::lower::*;
/// Actually codegen an instruction's results into registers.
pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx: &mut C,
insn: IRInst,
) -> CodegenResult<()> {
let op = ctx.data(insn).opcode();
let inputs: SmallVec<[InsnInput; 4]> = (0..ctx.num_inputs(insn))
.map(|i| InsnInput { insn, input: i })
.collect();
let outputs: SmallVec<[InsnOutput; 2]> = (0..ctx.num_outputs(insn))
.map(|i| InsnOutput { insn, output: i })
.collect();
let ty = if outputs.len() > 0 {
let ty = ctx.output_ty(insn, 0);
if ty.bits() > 32 || ty.is_float() {
panic!("Cannot lower inst with type {}!", ty);
}
Some(ty)
} else {
None
};
match op {
Opcode::Iconst | Opcode::Bconst | Opcode::Null => {
let value = output_to_const(ctx, outputs[0]).unwrap();
let rd = output_to_reg(ctx, outputs[0]);
lower_constant(ctx, rd, value);
}
Opcode::Iadd
| Opcode::IaddIfcin
| Opcode::IaddIfcout
| Opcode::IaddIfcarry
| Opcode::Isub
| Opcode::IsubIfbin
| Opcode::IsubIfbout
| Opcode::IsubIfborrow
| Opcode::Band
| Opcode::Bor
| Opcode::Bxor
| Opcode::BandNot
| Opcode::BorNot => {
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let alu_op = match op {
Opcode::Iadd => ALUOp::Add,
Opcode::IaddIfcin => ALUOp::Adc,
Opcode::IaddIfcout => ALUOp::Adds,
Opcode::IaddIfcarry => ALUOp::Adcs,
Opcode::Isub => ALUOp::Sub,
Opcode::IsubIfbin => ALUOp::Sbc,
Opcode::IsubIfbout => ALUOp::Subs,
Opcode::IsubIfborrow => ALUOp::Sbcs,
Opcode::Band => ALUOp::And,
Opcode::Bor => ALUOp::Orr,
Opcode::Bxor => ALUOp::Eor,
Opcode::BandNot => ALUOp::Bic,
Opcode::BorNot => ALUOp::Orn,
_ => unreachable!(),
};
ctx.emit(Inst::AluRRRShift {
alu_op,
rd,
rn,
rm,
shift: None,
});
}
Opcode::SaddSat | Opcode::SsubSat | Opcode::Imul | Opcode::Udiv | Opcode::Sdiv => {
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let alu_op = match op {
Opcode::SaddSat => ALUOp::Qadd,
Opcode::SsubSat => ALUOp::Qsub,
Opcode::Imul => ALUOp::Mul,
Opcode::Udiv => ALUOp::Udiv,
Opcode::Sdiv => ALUOp::Sdiv,
_ => unreachable!(),
};
ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm });
}
Opcode::Ineg => {
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
ctx.emit(Inst::AluRRImm8 {
alu_op: ALUOp::Rsb,
rd,
rn,
imm8: UImm8::maybe_from_i64(0).unwrap(),
});
}
Opcode::Ishl | Opcode::Ushr | Opcode::Sshr => {
let (alu_op, ext) = match op {
Opcode::Ishl => (ALUOp::Lsl, NarrowValueMode::None),
Opcode::Ushr => (ALUOp::Lsr, NarrowValueMode::ZeroExtend),
Opcode::Sshr => (ALUOp::Asr, NarrowValueMode::SignExtend),
_ => unreachable!(),
};
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], ext);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::ZeroExtend);
ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm });
}
Opcode::Rotr => {
if ty.unwrap().bits() != 32 {
unimplemented!()
}
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Ror,
rd,
rn,
rm,
});
}
Opcode::Rotl => {
if ty.unwrap().bits() != 32 {
unimplemented!()
}
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
// ror rd, rn, 32 - (rm & 31)
ctx.emit(Inst::AluRRImm8 {
alu_op: ALUOp::And,
rd: tmp,
rn: rm,
imm8: UImm8::maybe_from_i64(31).unwrap(),
});
ctx.emit(Inst::AluRRImm8 {
alu_op: ALUOp::Rsb,
rd: tmp,
rn: tmp.to_reg(),
imm8: UImm8::maybe_from_i64(32).unwrap(),
});
ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Ror,
rd,
rn,
rm: tmp.to_reg(),
});
}
Opcode::Smulhi | Opcode::Umulhi => {
let ty = ty.unwrap();
let is_signed = op == Opcode::Smulhi;
match ty {
I32 => {
let rd_hi = output_to_reg(ctx, outputs[0]);
let rd_lo = ctx.alloc_tmp(RegClass::I32, ty);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let alu_op = if is_signed {
ALUOp::Smull
} else {
ALUOp::Umull
};
ctx.emit(Inst::AluRRRR {
alu_op,
rd_hi,
rd_lo,
rn,
rm,
});
}
I16 | I8 => {
let narrow_mode = if is_signed {
NarrowValueMode::SignExtend
} else {
NarrowValueMode::ZeroExtend
};
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], narrow_mode);
let rm = input_to_reg(ctx, inputs[1], narrow_mode);
ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Mul,
rd,
rn,
rm,
});
let shift_amt = if ty == I16 { 16 } else { 8 };
let imm8 = UImm8::maybe_from_i64(shift_amt).unwrap();
let alu_op = if is_signed { ALUOp::Asr } else { ALUOp::Lsr };
ctx.emit(Inst::AluRRImm8 {
alu_op,
rd,
rn: rd.to_reg(),
imm8,
});
}
_ => panic!("Unexpected type {} in lower {}!", ty, op),
}
}
Opcode::Bnot => {
let rd = output_to_reg(ctx, outputs[0]);
let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
ctx.emit(Inst::AluRRShift {
alu_op: ALUOp1::Mvn,
rd,
rm,
shift: None,
});
}
Opcode::Clz | Opcode::Ctz => {
let rd = output_to_reg(ctx, outputs[0]);
let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend);
let ty = ctx.output_ty(insn, 0);
let in_reg = if op == Opcode::Ctz {
ctx.emit(Inst::BitOpRR {
bit_op: BitOp::Rbit,
rd,
rm,
});
rd.to_reg()
} else {
rm
};
ctx.emit(Inst::BitOpRR {
bit_op: BitOp::Clz,
rd,
rm: in_reg,
});
if ty.bits() < 32 {
let imm12 = UImm12::maybe_from_i64(32 - ty.bits() as i64).unwrap();
ctx.emit(Inst::AluRRImm12 {
alu_op: ALUOp::Sub,
rd,
rn: rd.to_reg(),
imm12,
});
}
}
Opcode::Bitrev => {
let rd = output_to_reg(ctx, outputs[0]);
let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let ty = ctx.output_ty(insn, 0);
let bit_op = BitOp::Rbit;
match ty.bits() {
32 => ctx.emit(Inst::BitOpRR { bit_op, rd, rm }),
n if n < 32 => {
let shift = ShiftOpAndAmt::new(
ShiftOp::LSL,
ShiftOpShiftImm::maybe_from_shift(32 - n as u32).unwrap(),
);
ctx.emit(Inst::AluRRShift {
alu_op: ALUOp1::Mov,
rd,
rm,
shift: Some(shift),
});
ctx.emit(Inst::BitOpRR {
bit_op,
rd,
rm: rd.to_reg(),
});
}
_ => panic!("Unexpected output type {}", ty),
}
}
Opcode::Icmp | Opcode::Ifcmp => {
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let narrow_mode = if is_signed {
NarrowValueMode::SignExtend
} else {
NarrowValueMode::ZeroExtend
};
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], narrow_mode);
let rm = input_to_reg(ctx, inputs[1], narrow_mode);
ctx.emit(Inst::Cmp { rn, rm });
if op == Opcode::Icmp {
let mut it_insts = vec![];
it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 1 }, true));
it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 0 }, false));
ctx.emit(Inst::It {
cond,
insts: it_insts,
});
}
}
Opcode::Trueif => {
let cmp_insn = ctx
.get_input(inputs[0].insn, inputs[0].input)
.inst
.unwrap()
.0;
debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp);
emit_cmp(ctx, cmp_insn);
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let rd = output_to_reg(ctx, outputs[0]);
let mut it_insts = vec![];
it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 1 }, true));
it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 0 }, false));
ctx.emit(Inst::It {
cond,
insts: it_insts,
});
}
Opcode::Select | Opcode::Selectif => {
let cond = if op == Opcode::Select {
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend);
ctx.emit(Inst::CmpImm8 { rn, imm8: 0 });
Cond::Ne
} else {
// Verification ensures that the input is always a single-def ifcmp.
let cmp_insn = ctx
.get_input(inputs[0].insn, inputs[0].input)
.inst
.unwrap()
.0;
debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp);
emit_cmp(ctx, cmp_insn);
let condcode = inst_condcode(ctx.data(insn)).unwrap();
lower_condcode(condcode)
};
let r1 = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let r2 = input_to_reg(ctx, inputs[2], NarrowValueMode::None);
let out_reg = output_to_reg(ctx, outputs[0]);
let mut it_insts = vec![];
it_insts.push(CondInst::new(Inst::mov(out_reg, r1), true));
it_insts.push(CondInst::new(Inst::mov(out_reg, r2), false));
ctx.emit(Inst::It {
cond,
insts: it_insts,
});
}
Opcode::Store | Opcode::Istore8 | Opcode::Istore16 | Opcode::Istore32 => {
let off = ldst_offset(ctx.data(insn)).unwrap();
let elem_ty = match op {
Opcode::Istore8 => I8,
Opcode::Istore16 => I16,
Opcode::Istore32 => I32,
Opcode::Store => ctx.input_ty(insn, 0),
_ => unreachable!(),
};
if elem_ty.bits() > 32 {
unimplemented!()
}
let bits = elem_ty.bits() as u8;
assert_eq!(inputs.len(), 2, "only one input for store memory operands");
let rt = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let base = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let mem = AMode::RegOffset(base, i64::from(off));
let memflags = ctx.memflags(insn).expect("memory flags");
let srcloc = if !memflags.notrap() {
Some(ctx.srcloc(insn))
} else {
None
};
ctx.emit(Inst::Store {
rt,
mem,
srcloc,
bits,
});
}
Opcode::Load
| Opcode::Uload8
| Opcode::Sload8
| Opcode::Uload16
| Opcode::Sload16
| Opcode::Uload32
| Opcode::Sload32 => {
let off = ldst_offset(ctx.data(insn)).unwrap();
let elem_ty = match op {
Opcode::Sload8 | Opcode::Uload8 => I8,
Opcode::Sload16 | Opcode::Uload16 => I16,
Opcode::Sload32 | Opcode::Uload32 => I32,
Opcode::Load => ctx.output_ty(insn, 0),
_ => unreachable!(),
};
if elem_ty.bits() > 32 {
unimplemented!()
}
let bits = elem_ty.bits() as u8;
let sign_extend = match op {
Opcode::Sload8 | Opcode::Sload16 | Opcode::Sload32 => true,
_ => false,
};
let out_reg = output_to_reg(ctx, outputs[0]);
assert_eq!(inputs.len(), 2, "only one input for store memory operands");
let base = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
let mem = AMode::RegOffset(base, i64::from(off));
let memflags = ctx.memflags(insn).expect("memory flags");
let srcloc = if !memflags.notrap() {
Some(ctx.srcloc(insn))
} else {
None
};
ctx.emit(Inst::Load {
rt: out_reg,
mem,
srcloc,
bits,
sign_extend,
});
}
Opcode::Uextend | Opcode::Sextend => {
let output_ty = ty.unwrap();
let input_ty = ctx.input_ty(insn, 0);
let from_bits = input_ty.bits() as u8;
let to_bits = 32;
let signed = op == Opcode::Sextend;
let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let rd = output_to_reg(ctx, outputs[0]);
if output_ty.bits() > 32 {
panic!("Unexpected output type {}", output_ty);
}
if from_bits < to_bits {
ctx.emit(Inst::Extend {
rd,
rm,
from_bits,
signed,
});
}
}
Opcode::Bint | Opcode::Breduce | Opcode::Bextend | Opcode::Ireduce => {
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend);
let rd = output_to_reg(ctx, outputs[0]);
let ty = ctx.input_ty(insn, 0);
ctx.emit(Inst::gen_move(rd, rn, ty));
}
Opcode::Copy => {
let rd = output_to_reg(ctx, outputs[0]);
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
let ty = ctx.input_ty(insn, 0);
ctx.emit(Inst::gen_move(rd, rn, ty));
}
Opcode::Debugtrap => {
ctx.emit(Inst::Bkpt);
}
Opcode::Trap => {
let trap_info = (ctx.srcloc(insn), inst_trapcode(ctx.data(insn)).unwrap());
ctx.emit(Inst::Udf { trap_info })
}
Opcode::Trapif => {
let cmp_insn = ctx
.get_input(inputs[0].insn, inputs[0].input)
.inst
.unwrap()
.0;
debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp);
emit_cmp(ctx, cmp_insn);
let trap_info = (ctx.srcloc(insn), inst_trapcode(ctx.data(insn)).unwrap());
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
ctx.emit(Inst::TrapIf { cond, trap_info });
}
Opcode::FallthroughReturn | Opcode::Return => {
for (i, input) in inputs.iter().enumerate() {
let reg = input_to_reg(ctx, *input, NarrowValueMode::None);
let retval_reg = ctx.retval(i);
let ty = ctx.input_ty(insn, i);
ctx.emit(Inst::gen_move(retval_reg, reg, ty));
}
}
Opcode::Call | Opcode::CallIndirect => {
let loc = ctx.srcloc(insn);
let (mut abi, inputs) = match op {
Opcode::Call => {
let (extname, dist) = ctx.call_target(insn).unwrap();
let extname = extname.clone();
let sig = ctx.call_sig(insn).unwrap();
assert_eq!(inputs.len(), sig.params.len());
assert_eq!(outputs.len(), sig.returns.len());
(
Arm32ABICaller::from_func(sig, &extname, dist, loc)?,
&inputs[..],
)
}
Opcode::CallIndirect => {
let ptr = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend);
let sig = ctx.call_sig(insn).unwrap();
assert_eq!(inputs.len() - 1, sig.params.len());
assert_eq!(outputs.len(), sig.returns.len());
(Arm32ABICaller::from_ptr(sig, ptr, loc, op)?, &inputs[1..])
}
_ => unreachable!(),
};
assert_eq!(inputs.len(), abi.num_args());
for (i, input) in inputs.iter().enumerate().filter(|(i, _)| *i <= 3) {
let arg_reg = input_to_reg(ctx, *input, NarrowValueMode::None);
abi.emit_copy_reg_to_arg(ctx, i, arg_reg);
}
abi.emit_call(ctx);
for (i, output) in outputs.iter().enumerate() {
let retval_reg = output_to_reg(ctx, *output);
abi.emit_copy_retval_to_reg(ctx, i, retval_reg);
}
}
_ => panic!("lowering {} unimplemented!", op),
}
Ok(())
}
pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
ctx: &mut C,
branches: &[IRInst],
targets: &[MachLabel],
fallthrough: Option<MachLabel>,
) -> CodegenResult<()> {
// A block should end with at most two branches. The first may be a
// conditional branch; a conditional branch can be followed only by an
// unconditional branch or fallthrough. Otherwise, if only one branch,
// it may be an unconditional branch, a fallthrough, a return, or a
// trap. These conditions are verified by `is_ebb_basic()` during the
// verifier pass.
assert!(branches.len() <= 2);
if branches.len() == 2 {
// Must be a conditional branch followed by an unconditional branch.
let op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).opcode();
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough);
let taken = BranchTarget::Label(targets[0]);
let not_taken = match op1 {
Opcode::Jump => BranchTarget::Label(targets[1]),
Opcode::Fallthrough => BranchTarget::Label(fallthrough.unwrap()),
_ => unreachable!(), // assert above.
};
match op0 {
Opcode::Brz | Opcode::Brnz => {
let rn = input_to_reg(
ctx,
InsnInput {
insn: branches[0],
input: 0,
},
NarrowValueMode::ZeroExtend,
);
let cond = if op0 == Opcode::Brz {
Cond::Eq
} else {
Cond::Ne
};
ctx.emit(Inst::CmpImm8 { rn, imm8: 0 });
ctx.emit(Inst::CondBr {
taken,
not_taken,
cond,
});
}
_ => unimplemented!(),
}
} else {
// Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode();
match op {
Opcode::Jump | Opcode::Fallthrough => {
assert_eq!(branches.len(), 1);
// In the Fallthrough case, the machine-independent driver
// fills in `targets[0]` with our fallthrough block, so this
// is valid for both Jump and Fallthrough.
ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]),
});
}
_ => unimplemented!(),
}
}
Ok(())
}

Просмотреть файл

@ -1,149 +1,123 @@
//! ARM 32-bit Instruction Set Architecture.
//! 32-bit ARM Instruction Set Architecture.
mod abi;
mod binemit;
mod enc_tables;
mod registers;
pub mod settings;
use super::super::settings as shared_settings;
#[cfg(feature = "testing_hooks")]
use crate::binemit::CodeSink;
use crate::binemit::{emit_function, MemoryCodeSink};
use crate::ir;
use crate::isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use crate::ir::condcodes::IntCC;
use crate::ir::Function;
use crate::isa::Builder as IsaBuilder;
use crate::isa::{EncInfo, RegClass, RegInfo, TargetIsa};
use crate::regalloc;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use core::any::Any;
use core::fmt;
use target_lexicon::{Architecture, Triple};
use crate::machinst::{
compile, MachBackend, MachCompileResult, ShowWithRRU, TargetIsaAdapter, VCode,
};
use crate::result::CodegenResult;
use crate::settings;
#[allow(dead_code)]
struct Isa {
use alloc::boxed::Box;
use regalloc::RealRegUniverse;
use target_lexicon::{Architecture, ArmArchitecture, Triple};
// New backend:
mod abi;
mod inst;
mod lower;
mod lower_inst;
use inst::create_reg_universe;
/// An ARM32 backend.
pub struct Arm32Backend {
triple: Triple,
shared_flags: shared_settings::Flags,
isa_flags: settings::Flags,
cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
flags: settings::Flags,
reg_universe: RealRegUniverse,
}
/// Get an ISA builder for creating ARM32 targets.
pub fn isa_builder(triple: Triple) -> IsaBuilder {
IsaBuilder {
triple,
setup: settings::builder(),
constructor: isa_constructor,
impl Arm32Backend {
/// Create a new ARM32 backend with the given (shared) flags.
pub fn new_with_flags(triple: Triple, flags: settings::Flags) -> Arm32Backend {
let reg_universe = create_reg_universe();
Arm32Backend {
triple,
flags,
reg_universe,
}
}
fn compile_vcode(
&self,
func: &Function,
flags: settings::Flags,
) -> CodegenResult<VCode<inst::Inst>> {
// This performs lowering to VCode, register-allocates the code, computes
// block layout and finalizes branches. The result is ready for binary emission.
let abi = Box::new(abi::Arm32ABICallee::new(func, flags)?);
compile::compile::<Arm32Backend>(func, self, abi)
}
}
fn isa_constructor(
triple: Triple,
shared_flags: shared_settings::Flags,
builder: shared_settings::Builder,
) -> Box<dyn TargetIsa> {
let level1 = match triple.architecture {
Architecture::Arm(arm) => {
if arm.is_thumb() {
&enc_tables::LEVEL1_T32[..]
} else {
&enc_tables::LEVEL1_A32[..]
}
}
_ => panic!(),
};
Box::new(Isa {
triple,
isa_flags: settings::Flags::new(&shared_flags, builder),
shared_flags,
cpumode: level1,
})
}
impl MachBackend for Arm32Backend {
fn compile_function(
&self,
func: &Function,
want_disasm: bool,
) -> CodegenResult<MachCompileResult> {
let flags = self.flags();
let vcode = self.compile_vcode(func, flags.clone())?;
let buffer = vcode.emit();
let frame_size = vcode.frame_size();
let disasm = if want_disasm {
Some(vcode.show_rru(Some(&create_reg_universe())))
} else {
None
};
let buffer = buffer.finish();
Ok(MachCompileResult {
buffer,
frame_size,
disasm,
})
}
impl TargetIsa for Isa {
fn name(&self) -> &'static str {
"arm32"
}
fn triple(&self) -> &Triple {
&self.triple
fn triple(&self) -> Triple {
self.triple.clone()
}
fn flags(&self) -> &shared_settings::Flags {
&self.shared_flags
fn flags(&self) -> &settings::Flags {
&self.flags
}
fn register_info(&self) -> RegInfo {
registers::INFO.clone()
fn reg_universe(&self) -> &RealRegUniverse {
&self.reg_universe
}
fn encoding_info(&self) -> EncInfo {
enc_tables::INFO.clone()
fn unsigned_add_overflow_condition(&self) -> IntCC {
// Carry flag set.
IntCC::UnsignedGreaterThanOrEqual
}
fn legal_encodings<'a>(
&'a self,
func: &'a ir::Function,
inst: &'a ir::InstructionData,
ctrl_typevar: ir::Type,
) -> Encodings<'a> {
lookup_enclist(
ctrl_typevar,
inst,
func,
self.cpumode,
&enc_tables::LEVEL2[..],
&enc_tables::ENCLISTS[..],
&enc_tables::LEGALIZE_ACTIONS[..],
&enc_tables::RECIPE_PREDICATES[..],
&enc_tables::INST_PREDICATES[..],
self.isa_flags.predicate_view(),
)
}
fn legalize_signature(&self, sig: &mut Cow<ir::Signature>, current: bool) {
abi::legalize_signature(sig, &self.triple, current)
}
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
abi::regclass_for_abi_type(ty)
}
fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func)
}
#[cfg(feature = "testing_hooks")]
fn emit_inst(
&self,
func: &ir::Function,
inst: ir::Inst,
divert: &mut regalloc::RegDiversions,
sink: &mut dyn CodeSink,
) {
binemit::emit_inst(func, inst, divert, sink, self)
}
fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
emit_function(func, binemit::emit_inst, sink, self)
}
fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
ir::condcodes::IntCC::UnsignedLessThan
}
fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
ir::condcodes::IntCC::UnsignedGreaterThanOrEqual
}
fn as_any(&self) -> &dyn Any {
self as &dyn Any
fn unsigned_sub_overflow_condition(&self) -> IntCC {
// Carry flag clear.
IntCC::UnsignedLessThan
}
}
impl fmt::Display for Isa {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\n{}", self.shared_flags, self.isa_flags)
/// Create a new `isa::Builder`.
pub fn isa_builder(triple: Triple) -> IsaBuilder {
assert!(match triple.architecture {
Architecture::Arm(ArmArchitecture::Arm)
| Architecture::Arm(ArmArchitecture::Armv7)
| Architecture::Arm(ArmArchitecture::Armv6) => true,
_ => false,
});
IsaBuilder {
triple,
setup: settings::builder(),
constructor: |triple, shared_flags, _| {
let backend = Arm32Backend::new_with_flags(triple, shared_flags);
Box::new(TargetIsaAdapter::new(backend))
},
}
}

Просмотреть файл

@ -1,68 +0,0 @@
//! ARM32 register descriptions.
use crate::isa::registers::{RegBank, RegClass, RegClassData, RegInfo, RegUnit};
include!(concat!(env!("OUT_DIR"), "/registers-arm32.rs"));
#[cfg(test)]
mod tests {
use super::{D, GPR, INFO, S};
use crate::isa::RegUnit;
use alloc::string::{String, ToString};
#[test]
fn unit_encodings() {
assert_eq!(INFO.parse_regunit("s0"), Some(0));
assert_eq!(INFO.parse_regunit("s31"), Some(31));
assert_eq!(INFO.parse_regunit("s32"), Some(32));
assert_eq!(INFO.parse_regunit("r0"), Some(64));
assert_eq!(INFO.parse_regunit("r15"), Some(79));
}
#[test]
fn unit_names() {
fn uname(ru: RegUnit) -> String {
INFO.display_regunit(ru).to_string()
}
assert_eq!(uname(0), "%s0");
assert_eq!(uname(1), "%s1");
assert_eq!(uname(31), "%s31");
assert_eq!(uname(64), "%r0");
}
#[test]
fn overlaps() {
// arm32 has the most interesting register geometries, so test `regs_overlap()` here.
use crate::isa::regs_overlap;
let r0 = GPR.unit(0);
let r1 = GPR.unit(1);
let r2 = GPR.unit(2);
assert!(regs_overlap(GPR, r0, GPR, r0));
assert!(regs_overlap(GPR, r2, GPR, r2));
assert!(!regs_overlap(GPR, r0, GPR, r1));
assert!(!regs_overlap(GPR, r1, GPR, r0));
assert!(!regs_overlap(GPR, r2, GPR, r1));
assert!(!regs_overlap(GPR, r1, GPR, r2));
let s0 = S.unit(0);
let s1 = S.unit(1);
let s2 = S.unit(2);
let s3 = S.unit(3);
let d0 = D.unit(0);
let d1 = D.unit(1);
assert!(regs_overlap(S, s0, D, d0));
assert!(regs_overlap(S, s1, D, d0));
assert!(!regs_overlap(S, s0, D, d1));
assert!(!regs_overlap(S, s1, D, d1));
assert!(regs_overlap(S, s2, D, d1));
assert!(regs_overlap(S, s3, D, d1));
assert!(!regs_overlap(D, d1, S, s1));
assert!(regs_overlap(D, d1, S, s2));
assert!(!regs_overlap(D, d0, D, d1));
assert!(regs_overlap(D, d1, D, d1));
}
}

Просмотреть файл

@ -1,9 +0,0 @@
//! ARM32 Settings.
use crate::settings::{self, detail, Builder};
use core::fmt;
// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs`. This file contains a
// public `Flags` struct with an impl for all of the settings defined in
// `cranelift-codegen/meta/src/isa/arm32/mod.rs`.
include!(concat!(env!("OUT_DIR"), "/settings-arm32.rs"));

Просмотреть файл

@ -22,6 +22,9 @@ pub enum CallConv {
BaldrdashSystemV,
/// SpiderMonkey WebAssembly convention on Windows
BaldrdashWindows,
/// SpiderMonkey WebAssembly convention for "ABI-2020", with extra TLS
/// register slots in the frame.
Baldrdash2020,
/// Specialized convention for the probestack function
Probestack,
}
@ -48,6 +51,7 @@ impl CallConv {
LibcallCallConv::WindowsFastcall => Self::WindowsFastcall,
LibcallCallConv::BaldrdashSystemV => Self::BaldrdashSystemV,
LibcallCallConv::BaldrdashWindows => Self::BaldrdashWindows,
LibcallCallConv::Baldrdash2020 => Self::Baldrdash2020,
LibcallCallConv::Probestack => Self::Probestack,
}
}
@ -63,7 +67,7 @@ impl CallConv {
/// Is the calling convention extending the Baldrdash ABI?
pub fn extends_baldrdash(self) -> bool {
match self {
Self::BaldrdashSystemV | Self::BaldrdashWindows => true,
Self::BaldrdashSystemV | Self::BaldrdashWindows | Self::Baldrdash2020 => true,
_ => false,
}
}
@ -78,6 +82,7 @@ impl fmt::Display for CallConv {
Self::WindowsFastcall => "windows_fastcall",
Self::BaldrdashSystemV => "baldrdash_system_v",
Self::BaldrdashWindows => "baldrdash_windows",
Self::Baldrdash2020 => "baldrdash_2020",
Self::Probestack => "probestack",
})
}
@ -93,6 +98,7 @@ impl str::FromStr for CallConv {
"windows_fastcall" => Ok(Self::WindowsFastcall),
"baldrdash_system_v" => Ok(Self::BaldrdashSystemV),
"baldrdash_windows" => Ok(Self::BaldrdashWindows),
"baldrdash_2020" => Ok(Self::Baldrdash2020),
"probestack" => Ok(Self::Probestack),
_ => Err(()),
}

Просмотреть файл

@ -119,8 +119,10 @@ macro_rules! isa_builder {
/// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple),
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
Architecture::Riscv32 { .. } | Architecture::Riscv64 { .. } => {
isa_builder!(riscv, "riscv", triple)
}
Architecture::X86_32 { .. } | Architecture::X86_64 => {
if cfg!(feature = "x64") {
isa_builder!(x64, "x64", triple)
} else {

Просмотреть файл

@ -20,6 +20,11 @@ use std::convert::TryFrom;
/// with 32-bit arithmetic: for now, 128 MB.
static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
/// Offset in stack-arg area to callee-TLS slot in Baldrdash-2020 calling convention.
static BALDRDASH_CALLEE_TLS_OFFSET: i64 = 0;
/// Offset in stack-arg area to caller-TLS slot in Baldrdash-2020 calling convention.
static BALDRDASH_CALLER_TLS_OFFSET: i64 = 8;
/// Try to fill a Baldrdash register, returning it if it was found.
fn try_fill_baldrdash_reg(call_conv: CallConv, param: &ir::AbiParam) -> Option<ABIArg> {
if call_conv.extends_baldrdash() {
@ -30,6 +35,7 @@ fn try_fill_baldrdash_reg(call_conv: CallConv, param: &ir::AbiParam) -> Option<A
regs::r14().to_real_reg(),
types::I64,
param.extension,
param.purpose,
))
}
&ir::ArgumentPurpose::SignatureId => {
@ -38,6 +44,27 @@ fn try_fill_baldrdash_reg(call_conv: CallConv, param: &ir::AbiParam) -> Option<A
regs::r10().to_real_reg(),
types::I64,
param.extension,
param.purpose,
))
}
&ir::ArgumentPurpose::CalleeTLS => {
// This is SpiderMonkey's callee TLS slot in the extended frame of Wasm's ABI-2020.
assert!(call_conv == isa::CallConv::Baldrdash2020);
Some(ABIArg::Stack(
BALDRDASH_CALLEE_TLS_OFFSET,
ir::types::I64,
ir::ArgumentExtension::None,
param.purpose,
))
}
&ir::ArgumentPurpose::CallerTLS => {
// This is SpiderMonkey's caller TLS slot in the extended frame of Wasm's ABI-2020.
assert!(call_conv == isa::CallConv::Baldrdash2020);
Some(ABIArg::Stack(
BALDRDASH_CALLER_TLS_OFFSET,
ir::types::I64,
ir::ArgumentExtension::None,
param.purpose,
))
}
_ => None,
@ -59,6 +86,10 @@ pub(crate) struct X64ABIMachineSpec;
impl ABIMachineSpec for X64ABIMachineSpec {
type I = Inst;
fn word_bits() -> u32 {
64
}
fn compute_arg_locs(
call_conv: isa::CallConv,
params: &[ir::AbiParam],
@ -66,12 +97,19 @@ impl ABIMachineSpec for X64ABIMachineSpec {
add_ret_area_ptr: bool,
) -> CodegenResult<(Vec<ABIArg>, i64, Option<usize>)> {
let is_baldrdash = call_conv.extends_baldrdash();
let has_baldrdash_tls = call_conv == isa::CallConv::Baldrdash2020;
let mut next_gpr = 0;
let mut next_vreg = 0;
let mut next_stack: u64 = 0;
let mut ret = vec![];
if args_or_rets == ArgsOrRets::Args && has_baldrdash_tls {
// Baldrdash ABI-2020 always has two stack-arg slots reserved, for the callee and
// caller TLS-register values, respectively.
next_stack = 16;
}
for i in 0..params.len() {
// Process returns backward, according to the SpiderMonkey ABI (which we
// adopt internally if `is_baldrdash` is set).
@ -86,7 +124,9 @@ impl ABIMachineSpec for X64ABIMachineSpec {
&ir::ArgumentPurpose::VMContext
| &ir::ArgumentPurpose::Normal
| &ir::ArgumentPurpose::StackLimit
| &ir::ArgumentPurpose::SignatureId => {}
| &ir::ArgumentPurpose::SignatureId
| &ir::ArgumentPurpose::CalleeTLS
| &ir::ArgumentPurpose::CallerTLS => {}
_ => panic!(
"Unsupported argument purpose {:?} in signature: {:?}",
param.purpose, params
@ -126,6 +166,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
reg.to_real_reg(),
param.value_type,
param.extension,
param.purpose,
));
*next_reg += 1;
} else {
@ -140,6 +181,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
next_stack as i64,
param.value_type,
param.extension,
param.purpose,
));
next_stack += size;
}
@ -156,12 +198,14 @@ impl ABIMachineSpec for X64ABIMachineSpec {
reg.to_real_reg(),
types::I64,
ir::ArgumentExtension::None,
ir::ArgumentPurpose::Normal,
));
} else {
ret.push(ABIArg::Stack(
next_stack as i64,
types::I64,
ir::ArgumentExtension::None,
ir::ArgumentPurpose::Normal,
));
next_stack += 8;
}
@ -191,65 +235,23 @@ impl ABIMachineSpec for X64ABIMachineSpec {
}
fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Self::I {
let (is_int, ext_mode) = match ty {
types::B1 | types::B8 | types::I8 => (true, Some(ExtMode::BQ)),
types::B16 | types::I16 => (true, Some(ExtMode::WQ)),
types::B32 | types::I32 => (true, Some(ExtMode::LQ)),
types::B64 | types::I64 | types::R64 => (true, None),
types::F32 | types::F64 => (false, None),
let ext_kind = match ty {
types::B1
| types::B8
| types::I8
| types::B16
| types::I16
| types::B32
| types::I32 => ExtKind::SignExtend,
types::B64 | types::I64 | types::R64 | types::F32 | types::F64 => ExtKind::None,
_ if ty.bytes() == 16 => ExtKind::None,
_ => panic!("load_stack({})", ty),
};
let mem = SyntheticAmode::from(mem);
if is_int {
match ext_mode {
Some(ext_mode) => Inst::movsx_rm_r(
ext_mode,
RegMem::mem(mem),
into_reg,
/* infallible load */ None,
),
None => Inst::mov64_m_r(mem, into_reg, None /* infallible */),
}
} else {
let sse_op = match ty {
types::F32 => SseOpcode::Movss,
types::F64 => SseOpcode::Movsd,
_ => unreachable!(),
};
Inst::xmm_mov(
sse_op,
RegMem::mem(mem),
into_reg,
None, /* infallible */
)
}
Inst::load(ty, mem, into_reg, ext_kind, /* infallible */ None)
}
fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I {
let (is_int, size) = match ty {
types::B1 | types::B8 | types::I8 => (true, 1),
types::B16 | types::I16 => (true, 2),
types::B32 | types::I32 => (true, 4),
types::B64 | types::I64 | types::R64 => (true, 8),
types::F32 => (false, 4),
types::F64 => (false, 8),
_ => unimplemented!("store_stack({})", ty),
};
let mem = SyntheticAmode::from(mem);
if is_int {
Inst::mov_r_m(size, from_reg, mem, /* infallible store */ None)
} else {
let sse_op = match size {
4 => SseOpcode::Movss,
8 => SseOpcode::Movsd,
_ => unreachable!(),
};
Inst::xmm_mov_r_m(sse_op, from_reg, mem, /* infallible store */ None)
}
Inst::store(ty, from_reg, mem, /* infallible */ None)
}
fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Self::I {
@ -264,12 +266,8 @@ impl ABIMachineSpec for X64ABIMachineSpec {
from_bits: u8,
to_bits: u8,
) -> Self::I {
let ext_mode = match from_bits {
1 | 8 => ExtMode::BQ,
16 => ExtMode::WQ,
32 => ExtMode::LQ,
_ => panic!("Bad extension: {} bits to {} bits", from_bits, to_bits),
};
let ext_mode = ExtMode::new(from_bits as u16, to_bits as u16)
.expect(&format!("invalid extension: {} -> {}", from_bits, to_bits));
if is_signed {
Inst::movsx_rm_r(ext_mode, RegMem::reg(from_reg), to_reg, None)
} else {
@ -389,6 +387,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
fn gen_clobber_save(
call_conv: isa::CallConv,
_: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> (u64, SmallVec<[Self::I; 16]>) {
let mut insts = SmallVec::new();
@ -434,6 +433,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
fn gen_clobber_restore(
call_conv: isa::CallConv,
flags: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> SmallVec<[Self::I; 16]> {
let mut insts = SmallVec::new();
@ -468,6 +468,18 @@ impl ABIMachineSpec for X64ABIMachineSpec {
));
}
// If this is Baldrdash-2020, restore the callee (i.e., our) TLS
// register. We may have allocated it for something else and clobbered
// it, but the ABI expects us to leave the TLS register unchanged.
if call_conv == isa::CallConv::Baldrdash2020 {
let off = BALDRDASH_CALLEE_TLS_OFFSET + Self::fp_to_arg_offset(call_conv, flags);
insts.push(Inst::mov64_m_r(
Amode::imm_reg(off as u32, regs::rbp()),
Writable::from_reg(regs::r14()),
None,
));
}
insts
}
@ -636,7 +648,11 @@ fn in_vec_reg(ty: types::Type) -> bool {
fn get_intreg_for_arg_systemv(call_conv: &CallConv, idx: usize) -> Option<Reg> {
match call_conv {
CallConv::Fast | CallConv::Cold | CallConv::SystemV | CallConv::BaldrdashSystemV => {}
CallConv::Fast
| CallConv::Cold
| CallConv::SystemV
| CallConv::BaldrdashSystemV
| CallConv::Baldrdash2020 => {}
_ => panic!("int args only supported for SysV calling convention"),
};
match idx {
@ -652,7 +668,11 @@ fn get_intreg_for_arg_systemv(call_conv: &CallConv, idx: usize) -> Option<Reg> {
fn get_fltreg_for_arg_systemv(call_conv: &CallConv, idx: usize) -> Option<Reg> {
match call_conv {
CallConv::Fast | CallConv::Cold | CallConv::SystemV | CallConv::BaldrdashSystemV => {}
CallConv::Fast
| CallConv::Cold
| CallConv::SystemV
| CallConv::BaldrdashSystemV
| CallConv::Baldrdash2020 => {}
_ => panic!("float args only supported for SysV calling convention"),
};
match idx {
@ -679,7 +699,7 @@ fn get_intreg_for_retval_systemv(
1 => Some(regs::rdx()),
_ => None,
},
CallConv::BaldrdashSystemV => {
CallConv::BaldrdashSystemV | CallConv::Baldrdash2020 => {
if intreg_idx == 0 && retval_idx == 0 {
Some(regs::rax())
} else {
@ -701,7 +721,7 @@ fn get_fltreg_for_retval_systemv(
1 => Some(regs::xmm1()),
_ => None,
},
CallConv::BaldrdashSystemV => {
CallConv::BaldrdashSystemV | CallConv::Baldrdash2020 => {
if fltreg_idx == 0 && retval_idx == 0 {
Some(regs::xmm0())
} else {
@ -743,7 +763,7 @@ fn is_callee_save_baldrdash(r: RealReg) -> bool {
fn get_callee_saves(call_conv: &CallConv, regs: &Set<Writable<RealReg>>) -> Vec<Writable<RealReg>> {
let mut regs: Vec<Writable<RealReg>> = match call_conv {
CallConv::BaldrdashSystemV => regs
CallConv::BaldrdashSystemV | CallConv::Baldrdash2020 => regs
.iter()
.cloned()
.filter(|r| is_callee_save_baldrdash(r.to_reg()))

Просмотреть файл

@ -5,7 +5,7 @@ use super::EmitState;
use crate::ir::condcodes::{FloatCC, IntCC};
use crate::machinst::*;
use core::fmt::Debug;
use regalloc::{RealRegUniverse, Reg, RegClass, RegUsageCollector, RegUsageMapper};
use regalloc::{RealRegUniverse, Reg, RegClass, RegUsageCollector, RegUsageMapper, Writable};
use std::fmt;
use std::string::{String, ToString};
@ -265,6 +265,12 @@ impl RegMem {
}
}
impl From<Writable<Reg>> for RegMem {
fn from(r: Writable<Reg>) -> Self {
RegMem::reg(r.to_reg())
}
}
impl ShowWithRRU for RegMem {
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
self.show_rru_sized(mb_rru, 8)
@ -336,6 +342,7 @@ impl fmt::Display for UnaryRmROpcode {
pub(crate) enum InstructionSet {
SSE,
SSE2,
SSSE3,
SSE41,
}
@ -382,6 +389,7 @@ pub enum SseOpcode {
Movd,
Movdqa,
Movdqu,
Movlhps,
Movq,
Movss,
Movsd,
@ -393,13 +401,42 @@ pub enum SseOpcode {
Mulsd,
Orps,
Orpd,
Pabsb,
Pabsw,
Pabsd,
Paddb,
Paddd,
Paddq,
Paddw,
Paddsb,
Paddsw,
Paddusb,
Paddusw,
Pavgb,
Pavgw,
Pextrb,
Pextrw,
Pextrd,
Pinsrb,
Pinsrw,
Pinsrd,
Pmaxsb,
Pmaxsw,
Pmaxsd,
Pmaxub,
Pmaxuw,
Pmaxud,
Pminsb,
Pminsw,
Pminsd,
Pminub,
Pminuw,
Pminud,
Pmulld,
Pmullw,
Pmuludq,
Pshufb,
Pshufd,
Psllw,
Pslld,
Psllq,
@ -453,6 +490,7 @@ impl SseOpcode {
| SseOpcode::Minps
| SseOpcode::Minss
| SseOpcode::Movaps
| SseOpcode::Movlhps
| SseOpcode::Movss
| SseOpcode::Movups
| SseOpcode::Mulps
@ -499,8 +537,21 @@ impl SseOpcode {
| SseOpcode::Paddd
| SseOpcode::Paddq
| SseOpcode::Paddw
| SseOpcode::Paddsb
| SseOpcode::Paddsw
| SseOpcode::Paddusb
| SseOpcode::Paddusw
| SseOpcode::Pavgb
| SseOpcode::Pavgw
| SseOpcode::Pextrw
| SseOpcode::Pinsrw
| SseOpcode::Pmaxsw
| SseOpcode::Pmaxub
| SseOpcode::Pminsw
| SseOpcode::Pminub
| SseOpcode::Pmullw
| SseOpcode::Pmuludq
| SseOpcode::Pshufd
| SseOpcode::Psllw
| SseOpcode::Pslld
| SseOpcode::Psllq
@ -521,9 +572,24 @@ impl SseOpcode {
| SseOpcode::Ucomisd
| SseOpcode::Xorpd => SSE2,
SseOpcode::Insertps | SseOpcode::Pmulld | SseOpcode::Roundss | SseOpcode::Roundsd => {
SSE41
}
SseOpcode::Pabsb | SseOpcode::Pabsw | SseOpcode::Pabsd | SseOpcode::Pshufb => SSSE3,
SseOpcode::Insertps
| SseOpcode::Pextrb
| SseOpcode::Pextrd
| SseOpcode::Pinsrb
| SseOpcode::Pinsrd
| SseOpcode::Pmaxsb
| SseOpcode::Pmaxsd
| SseOpcode::Pmaxuw
| SseOpcode::Pmaxud
| SseOpcode::Pminsb
| SseOpcode::Pminsd
| SseOpcode::Pminuw
| SseOpcode::Pminud
| SseOpcode::Pmulld
| SseOpcode::Roundss
| SseOpcode::Roundsd => SSE41,
}
}
@ -579,6 +645,7 @@ impl fmt::Debug for SseOpcode {
SseOpcode::Movd => "movd",
SseOpcode::Movdqa => "movdqa",
SseOpcode::Movdqu => "movdqu",
SseOpcode::Movlhps => "movlhps",
SseOpcode::Movq => "movq",
SseOpcode::Movss => "movss",
SseOpcode::Movsd => "movsd",
@ -590,13 +657,42 @@ impl fmt::Debug for SseOpcode {
SseOpcode::Mulsd => "mulsd",
SseOpcode::Orpd => "orpd",
SseOpcode::Orps => "orps",
SseOpcode::Pabsb => "pabsb",
SseOpcode::Pabsw => "pabsw",
SseOpcode::Pabsd => "pabsd",
SseOpcode::Paddb => "paddb",
SseOpcode::Paddd => "paddd",
SseOpcode::Paddq => "paddq",
SseOpcode::Paddw => "paddw",
SseOpcode::Paddsb => "paddsb",
SseOpcode::Paddsw => "paddsw",
SseOpcode::Paddusb => "paddusb",
SseOpcode::Paddusw => "paddusw",
SseOpcode::Pavgb => "pavgb",
SseOpcode::Pavgw => "pavgw",
SseOpcode::Pextrb => "pextrb",
SseOpcode::Pextrw => "pextrw",
SseOpcode::Pextrd => "pextrd",
SseOpcode::Pinsrb => "pinsrb",
SseOpcode::Pinsrw => "pinsrw",
SseOpcode::Pinsrd => "pinsrd",
SseOpcode::Pmaxsb => "pmaxsb",
SseOpcode::Pmaxsw => "pmaxsw",
SseOpcode::Pmaxsd => "pmaxsd",
SseOpcode::Pmaxub => "pmaxub",
SseOpcode::Pmaxuw => "pmaxuw",
SseOpcode::Pmaxud => "pmaxud",
SseOpcode::Pminsb => "pminsb",
SseOpcode::Pminsw => "pminsw",
SseOpcode::Pminsd => "pminsd",
SseOpcode::Pminub => "pminub",
SseOpcode::Pminuw => "pminuw",
SseOpcode::Pminud => "pminud",
SseOpcode::Pmulld => "pmulld",
SseOpcode::Pmullw => "pmullw",
SseOpcode::Pmuludq => "pmuludq",
SseOpcode::Pshufb => "pshufb",
SseOpcode::Pshufd => "pshufd",
SseOpcode::Psllw => "psllw",
SseOpcode::Pslld => "pslld",
SseOpcode::Psllq => "psllq",
@ -664,6 +760,19 @@ pub enum ExtMode {
}
impl ExtMode {
/// Calculate the `ExtMode` from passed bit lengths of the from/to types.
pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
match (from_bits, to_bits) {
(1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
(1, 64) | (8, 64) => Some(ExtMode::BQ),
(16, 32) => Some(ExtMode::WL),
(16, 64) => Some(ExtMode::WQ),
(32, 64) => Some(ExtMode::LQ),
_ => None,
}
}
/// Return the source register size in bytes.
pub(crate) fn src_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::BQ => 1,
@ -671,6 +780,8 @@ impl ExtMode {
ExtMode::LQ => 4,
}
}
/// Return the destination register size in bytes.
pub(crate) fn dst_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::WL => 4,

Просмотреть файл

@ -1697,27 +1697,38 @@ pub(crate) fn emit(
} => {
let rex = RexFlags::clear_w();
let (prefix, opcode) = match op {
SseOpcode::Cvtss2sd => (LegacyPrefixes::_F3, 0x0F5A),
SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A),
SseOpcode::Movaps => (LegacyPrefixes::None, 0x0F28),
SseOpcode::Movapd => (LegacyPrefixes::_66, 0x0F28),
SseOpcode::Movdqa => (LegacyPrefixes::_66, 0x0F6F),
SseOpcode::Movdqu => (LegacyPrefixes::_F3, 0x0F6F),
SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F10),
SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F10),
SseOpcode::Movups => (LegacyPrefixes::None, 0x0F10),
SseOpcode::Movupd => (LegacyPrefixes::_66, 0x0F10),
SseOpcode::Sqrtps => (LegacyPrefixes::None, 0x0F51),
SseOpcode::Sqrtpd => (LegacyPrefixes::_66, 0x0F51),
SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51),
SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51),
let (prefix, opcode, num_opcodes) = match op {
SseOpcode::Cvtss2sd => (LegacyPrefixes::_F3, 0x0F5A, 2),
SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A, 2),
SseOpcode::Movaps => (LegacyPrefixes::None, 0x0F28, 2),
SseOpcode::Movapd => (LegacyPrefixes::_66, 0x0F28, 2),
SseOpcode::Movdqa => (LegacyPrefixes::_66, 0x0F6F, 2),
SseOpcode::Movdqu => (LegacyPrefixes::_F3, 0x0F6F, 2),
SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F10, 2),
SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F10, 2),
SseOpcode::Movups => (LegacyPrefixes::None, 0x0F10, 2),
SseOpcode::Movupd => (LegacyPrefixes::_66, 0x0F10, 2),
SseOpcode::Pabsb => (LegacyPrefixes::_66, 0x0F381C, 3),
SseOpcode::Pabsw => (LegacyPrefixes::_66, 0x0F381D, 3),
SseOpcode::Pabsd => (LegacyPrefixes::_66, 0x0F381E, 3),
SseOpcode::Sqrtps => (LegacyPrefixes::None, 0x0F51, 2),
SseOpcode::Sqrtpd => (LegacyPrefixes::_66, 0x0F51, 2),
SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51, 2),
SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51, 2),
_ => unimplemented!("Opcode {:?} not implemented", op),
};
match src_e {
RegMem::Reg { reg: reg_e } => {
emit_std_reg_reg(sink, prefix, opcode, 2, reg_g.to_reg(), *reg_e, rex);
emit_std_reg_reg(
sink,
prefix,
opcode,
num_opcodes,
reg_g.to_reg(),
*reg_e,
rex,
);
}
RegMem::Mem { addr } => {
let addr = &addr.finalize(state);
@ -1725,7 +1736,7 @@ pub(crate) fn emit(
// Register the offset at which the actual load instruction starts.
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
}
emit_std_reg_mem(sink, prefix, opcode, 2, reg_g.to_reg(), addr, rex);
emit_std_reg_mem(sink, prefix, opcode, num_opcodes, reg_g.to_reg(), addr, rex);
}
};
}
@ -1749,14 +1760,16 @@ pub(crate) fn emit(
SseOpcode::Divpd => (LegacyPrefixes::_66, 0x0F5E, 2),
SseOpcode::Divss => (LegacyPrefixes::_F3, 0x0F5E, 2),
SseOpcode::Divsd => (LegacyPrefixes::_F2, 0x0F5E, 2),
SseOpcode::Minps => (LegacyPrefixes::None, 0x0F5D, 2),
SseOpcode::Minpd => (LegacyPrefixes::_66, 0x0F5D, 2),
SseOpcode::Minss => (LegacyPrefixes::_F3, 0x0F5D, 2),
SseOpcode::Minsd => (LegacyPrefixes::_F2, 0x0F5D, 2),
SseOpcode::Maxps => (LegacyPrefixes::None, 0x0F5F, 2),
SseOpcode::Maxpd => (LegacyPrefixes::_66, 0x0F5F, 2),
SseOpcode::Maxss => (LegacyPrefixes::_F3, 0x0F5F, 2),
SseOpcode::Maxsd => (LegacyPrefixes::_F2, 0x0F5F, 2),
SseOpcode::Minps => (LegacyPrefixes::None, 0x0F5D, 2),
SseOpcode::Minpd => (LegacyPrefixes::_66, 0x0F5D, 2),
SseOpcode::Minss => (LegacyPrefixes::_F3, 0x0F5D, 2),
SseOpcode::Minsd => (LegacyPrefixes::_F2, 0x0F5D, 2),
SseOpcode::Movlhps => (LegacyPrefixes::None, 0x0F16, 2),
SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F10, 2),
SseOpcode::Mulps => (LegacyPrefixes::None, 0x0F59, 2),
SseOpcode::Mulpd => (LegacyPrefixes::_66, 0x0F59, 2),
SseOpcode::Mulss => (LegacyPrefixes::_F3, 0x0F59, 2),
@ -1767,9 +1780,28 @@ pub(crate) fn emit(
SseOpcode::Paddd => (LegacyPrefixes::_66, 0x0FFE, 2),
SseOpcode::Paddq => (LegacyPrefixes::_66, 0x0FD4, 2),
SseOpcode::Paddw => (LegacyPrefixes::_66, 0x0FFD, 2),
SseOpcode::Paddsb => (LegacyPrefixes::_66, 0x0FEC, 2),
SseOpcode::Paddsw => (LegacyPrefixes::_66, 0x0FED, 2),
SseOpcode::Paddusb => (LegacyPrefixes::_66, 0x0FDC, 2),
SseOpcode::Paddusw => (LegacyPrefixes::_66, 0x0FDD, 2),
SseOpcode::Pavgb => (LegacyPrefixes::_66, 0x0FE0, 2),
SseOpcode::Pavgw => (LegacyPrefixes::_66, 0x0FE3, 2),
SseOpcode::Pmaxsb => (LegacyPrefixes::_66, 0x0F383C, 3),
SseOpcode::Pmaxsw => (LegacyPrefixes::_66, 0x0FEE, 2),
SseOpcode::Pmaxsd => (LegacyPrefixes::_66, 0x0F383D, 3),
SseOpcode::Pmaxub => (LegacyPrefixes::_66, 0x0FDE, 2),
SseOpcode::Pmaxuw => (LegacyPrefixes::_66, 0x0F383E, 3),
SseOpcode::Pmaxud => (LegacyPrefixes::_66, 0x0F383F, 3),
SseOpcode::Pminsb => (LegacyPrefixes::_66, 0x0F3838, 3),
SseOpcode::Pminsw => (LegacyPrefixes::_66, 0x0FEA, 2),
SseOpcode::Pminsd => (LegacyPrefixes::_66, 0x0F3839, 3),
SseOpcode::Pminub => (LegacyPrefixes::_66, 0x0FDA, 2),
SseOpcode::Pminuw => (LegacyPrefixes::_66, 0x0F383A, 3),
SseOpcode::Pminud => (LegacyPrefixes::_66, 0x0F383B, 3),
SseOpcode::Pmulld => (LegacyPrefixes::_66, 0x0F3840, 3),
SseOpcode::Pmullw => (LegacyPrefixes::_66, 0x0FD5, 2),
SseOpcode::Pmuludq => (LegacyPrefixes::_66, 0x0FF4, 2),
SseOpcode::Pshufb => (LegacyPrefixes::_66, 0x0F3800, 3),
SseOpcode::Psubb => (LegacyPrefixes::_66, 0x0FF8, 2),
SseOpcode::Psubd => (LegacyPrefixes::_66, 0x0FFA, 2),
SseOpcode::Psubq => (LegacyPrefixes::_66, 0x0FFB, 2),
@ -1881,23 +1913,56 @@ pub(crate) fn emit(
sink.bind_label(done);
}
Inst::XmmRmRImm { op, src, dst, imm } => {
let prefix = match op {
SseOpcode::Cmpps => LegacyPrefixes::None,
SseOpcode::Cmppd => LegacyPrefixes::_66,
SseOpcode::Cmpss => LegacyPrefixes::_F3,
SseOpcode::Cmpsd => LegacyPrefixes::_F2,
Inst::XmmRmRImm {
op,
src,
dst,
imm,
is64: w,
} => {
let (prefix, opcode, len) = match op {
SseOpcode::Cmpps => (LegacyPrefixes::None, 0x0FC2, 2),
SseOpcode::Cmppd => (LegacyPrefixes::_66, 0x0FC2, 2),
SseOpcode::Cmpss => (LegacyPrefixes::_F3, 0x0FC2, 2),
SseOpcode::Cmpsd => (LegacyPrefixes::_F2, 0x0FC2, 2),
SseOpcode::Insertps => (LegacyPrefixes::_66, 0x0F3A21, 3),
SseOpcode::Pinsrb => (LegacyPrefixes::_66, 0x0F3A20, 3),
SseOpcode::Pinsrw => (LegacyPrefixes::_66, 0x0FC4, 2),
SseOpcode::Pinsrd => (LegacyPrefixes::_66, 0x0F3A22, 3),
SseOpcode::Pextrb => (LegacyPrefixes::_66, 0x0F3A14, 3),
SseOpcode::Pextrw => (LegacyPrefixes::_66, 0x0FC5, 2),
SseOpcode::Pextrd => (LegacyPrefixes::_66, 0x0F3A16, 3),
SseOpcode::Pshufd => (LegacyPrefixes::_66, 0x0F70, 2),
_ => unimplemented!("Opcode {:?} not implemented", op),
};
let opcode = 0x0FC2;
let rex = RexFlags::clear_w();
let rex = if *w {
RexFlags::set_w()
} else {
RexFlags::clear_w()
};
let regs_swapped = match *op {
// These opcodes (and not the SSE2 version of PEXTRW) flip the operand
// encoding: `dst` in ModRM's r/m, `src` in ModRM's reg field.
SseOpcode::Pextrb | SseOpcode::Pextrd => true,
// The rest of the opcodes have the customary encoding: `dst` in ModRM's reg,
// `src` in ModRM's r/m field.
_ => false,
};
match src {
RegMem::Reg { reg } => {
emit_std_reg_reg(sink, prefix, opcode, 2, dst.to_reg(), *reg, rex);
if regs_swapped {
emit_std_reg_reg(sink, prefix, opcode, len, *reg, dst.to_reg(), rex);
} else {
emit_std_reg_reg(sink, prefix, opcode, len, dst.to_reg(), *reg, rex);
}
}
RegMem::Mem { addr } => {
let addr = &addr.finalize(state);
emit_std_reg_mem(sink, prefix, opcode, 2, dst.to_reg(), addr, rex);
assert!(
!regs_swapped,
"No existing way to encode a mem argument in the ModRM r/m field."
);
emit_std_reg_mem(sink, prefix, opcode, len, dst.to_reg(), addr, rex);
}
}
sink.put1(*imm)

Просмотреть файл

@ -3111,6 +3111,42 @@ fn test_x64_emit() {
"paddq %xmm1, %xmm8",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Paddsb, RegMem::reg(xmm9), w_xmm5),
"66410FECE9",
"paddsb %xmm9, %xmm5",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Paddsw, RegMem::reg(xmm7), w_xmm6),
"660FEDF7",
"paddsw %xmm7, %xmm6",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Paddusb, RegMem::reg(xmm12), w_xmm13),
"66450FDCEC",
"paddusb %xmm12, %xmm13",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Paddusw, RegMem::reg(xmm1), w_xmm8),
"66440FDDC1",
"paddusw %xmm1, %xmm8",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pavgb, RegMem::reg(xmm12), w_xmm13),
"66450FE0EC",
"pavgb %xmm12, %xmm13",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pavgw, RegMem::reg(xmm1), w_xmm8),
"66440FE3C1",
"pavgw %xmm1, %xmm8",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Psubb, RegMem::reg(xmm5), w_xmm9),
"66440FF8CD",
@ -3153,12 +3189,90 @@ fn test_x64_emit() {
"pmuludq %xmm8, %xmm9",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxsb, RegMem::reg(xmm15), w_xmm6),
"66410F383CF7",
"pmaxsb %xmm15, %xmm6",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxsw, RegMem::reg(xmm15), w_xmm6),
"66410FEEF7",
"pmaxsw %xmm15, %xmm6",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxsd, RegMem::reg(xmm15), w_xmm6),
"66410F383DF7",
"pmaxsd %xmm15, %xmm6",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxub, RegMem::reg(xmm14), w_xmm1),
"66410FDECE",
"pmaxub %xmm14, %xmm1",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxuw, RegMem::reg(xmm14), w_xmm1),
"66410F383ECE",
"pmaxuw %xmm14, %xmm1",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pmaxud, RegMem::reg(xmm14), w_xmm1),
"66410F383FCE",
"pmaxud %xmm14, %xmm1",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminsb, RegMem::reg(xmm8), w_xmm9),
"66450F3838C8",
"pminsb %xmm8, %xmm9",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminsw, RegMem::reg(xmm8), w_xmm9),
"66450FEAC8",
"pminsw %xmm8, %xmm9",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminsd, RegMem::reg(xmm8), w_xmm9),
"66450F3839C8",
"pminsd %xmm8, %xmm9",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminub, RegMem::reg(xmm3), w_xmm2),
"660FDAD3",
"pminub %xmm3, %xmm2",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminuw, RegMem::reg(xmm3), w_xmm2),
"660F383AD3",
"pminuw %xmm3, %xmm2",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pminud, RegMem::reg(xmm3), w_xmm2),
"660F383BD3",
"pminud %xmm3, %xmm2",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pxor, RegMem::reg(xmm11), w_xmm2),
"66410FEFD3",
"pxor %xmm11, %xmm2",
));
insns.push((
Inst::xmm_rm_r(SseOpcode::Pshufb, RegMem::reg(xmm11), w_xmm2),
"66410F3800D3",
"pshufb %xmm11, %xmm2",
));
// XMM_Mov_R_M: float stores
insns.push((
Inst::xmm_mov_r_m(SseOpcode::Movss, xmm15, Amode::imm_reg(128, r12), None),
@ -3226,6 +3340,22 @@ fn test_x64_emit() {
"cvtsd2ss %xmm1, %xmm0",
));
insns.push((
Inst::xmm_unary_rm_r(SseOpcode::Pabsb, RegMem::reg(xmm2), w_xmm1),
"660F381CCA",
"pabsb %xmm2, %xmm1",
));
insns.push((
Inst::xmm_unary_rm_r(SseOpcode::Pabsw, RegMem::reg(xmm0), w_xmm0),
"660F381DC0",
"pabsw %xmm0, %xmm0",
));
insns.push((
Inst::xmm_unary_rm_r(SseOpcode::Pabsd, RegMem::reg(xmm10), w_xmm11),
"66450F381EDA",
"pabsd %xmm10, %xmm11",
));
// Xmm to int conversions, and conversely.
insns.push((
@ -3341,12 +3471,12 @@ fn test_x64_emit() {
// ========================================================
// XmmRmRImm
insns.push((
Inst::xmm_rm_r_imm(SseOpcode::Cmppd, RegMem::reg(xmm5), w_xmm1, 2),
Inst::xmm_rm_r_imm(SseOpcode::Cmppd, RegMem::reg(xmm5), w_xmm1, 2, false),
"660FC2CD02",
"cmppd $2, %xmm5, %xmm1",
));
insns.push((
Inst::xmm_rm_r_imm(SseOpcode::Cmpps, RegMem::reg(xmm15), w_xmm7, 0),
Inst::xmm_rm_r_imm(SseOpcode::Cmpps, RegMem::reg(xmm15), w_xmm7, 0, false),
"410FC2FF00",
"cmpps $0, %xmm15, %xmm7",
));

Просмотреть файл

@ -333,12 +333,13 @@ pub enum Inst {
dst: Reg,
},
/// A binary XMM instruction with an 8-bit immediate: cmp (ps pd) imm (reg addr) reg
/// A binary XMM instruction with an 8-bit immediate: e.g. cmp (ps pd) imm (reg addr) reg
XmmRmRImm {
op: SseOpcode,
src: RegMem,
dst: Writable<Reg>,
imm: u8,
is64: bool,
},
// =====================================
@ -780,11 +781,20 @@ impl Inst {
}
}
pub(crate) fn xmm_rm_r_imm(op: SseOpcode, src: RegMem, dst: Writable<Reg>, imm: u8) -> Inst {
src.assert_regclass_is(RegClass::V128);
debug_assert!(dst.to_reg().get_class() == RegClass::V128);
debug_assert!(imm < 8);
Inst::XmmRmRImm { op, src, dst, imm }
pub(crate) fn xmm_rm_r_imm(
op: SseOpcode,
src: RegMem,
dst: Writable<Reg>,
imm: u8,
w: bool,
) -> Inst {
Inst::XmmRmRImm {
op,
src,
dst,
imm,
is64: w,
}
}
pub(crate) fn movzx_rm_r(
@ -1118,7 +1128,9 @@ impl Inst {
|| *op == SseOpcode::Pxor)
}
Self::XmmRmRImm { op, src, dst, imm } => {
Self::XmmRmRImm {
op, src, dst, imm, ..
} => {
src.to_reg() == Some(dst.to_reg())
&& (*op == SseOpcode::Cmppd || *op == SseOpcode::Cmpps)
&& *imm == FcmpImm::Equal.encode()
@ -1300,9 +1312,9 @@ impl ShowWithRRU for Inst {
show_ireg_sized(rhs_dst.to_reg(), mb_rru, 8),
),
Inst::XmmRmRImm { op, src, dst, imm } => format!(
Inst::XmmRmRImm { op, src, dst, imm, is64 } => format!(
"{} ${}, {}, {}",
ljustify(op.to_string()),
ljustify(format!("{}{}", op.to_string(), if *is64 { ".w" } else { "" })),
imm,
src.show_rru(mb_rru),
dst.show_rru(mb_rru),
@ -1722,10 +1734,17 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
collector.add_mod(*dst);
}
}
Inst::XmmRmRImm { src, dst, .. } => {
Inst::XmmRmRImm { op, src, dst, .. } => {
if inst.produces_const() {
// No need to account for src, since src == dst.
collector.add_def(*dst);
} else if *op == SseOpcode::Pextrb
|| *op == SseOpcode::Pextrw
|| *op == SseOpcode::Pextrd
|| *op == SseOpcode::Pshufd
{
src.get_regs_as_uses(collector);
collector.add_def(*dst);
} else {
src.get_regs_as_uses(collector);
collector.add_mod(*dst);
@ -2024,6 +2043,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
map_def(mapper, dst);
}
Inst::XmmRmRImm {
ref op,
ref mut src,
ref mut dst,
..
@ -2031,6 +2051,13 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
if produces_const {
src.map_as_def(mapper);
map_def(mapper, dst);
} else if *op == SseOpcode::Pextrb
|| *op == SseOpcode::Pextrw
|| *op == SseOpcode::Pextrd
|| *op == SseOpcode::Pshufd
{
src.map_uses(mapper);
map_def(mapper, dst);
} else {
src.map_uses(mapper);
map_mod(mapper, dst);
@ -2278,18 +2305,27 @@ impl MachInst for Inst {
}
fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
// Note (carefully!) that a 32-bit mov *isn't* a no-op since it zeroes
// out the upper 32 bits of the destination. For example, we could
// conceivably use `movl %reg, %reg` to zero out the top 32 bits of
// %reg.
match self {
// Note (carefully!) that a 32-bit mov *isn't* a no-op since it zeroes
// out the upper 32 bits of the destination. For example, we could
// conceivably use `movl %reg, %reg` to zero out the top 32 bits of
// %reg.
Self::Mov_R_R {
is_64, src, dst, ..
} if *is_64 => Some((*dst, *src)),
// Note as well that MOVS[S|D] when used in the `XmmUnaryRmR` context are pure moves of
// scalar floating-point values (and annotate `dst` as `def`s to the register allocator)
// whereas the same operation in a packed context, e.g. `XMM_RM_R`, is used to merge a
// value into the lowest lane of a vector (not a move).
Self::XmmUnaryRmR { op, src, dst, .. }
if *op == SseOpcode::Movss
|| *op == SseOpcode::Movsd
|| *op == SseOpcode::Movaps =>
|| *op == SseOpcode::Movaps
|| *op == SseOpcode::Movapd
|| *op == SseOpcode::Movups
|| *op == SseOpcode::Movupd
|| *op == SseOpcode::Movdqa
|| *op == SseOpcode::Movdqu =>
{
if let RegMem::Reg { reg } = src {
Some((*dst, *reg))

Просмотреть файл

@ -131,12 +131,7 @@ fn extend_input_to_reg(ctx: Ctx, spec: InsnInput, ext_spec: ExtSpec) -> Reg {
let ext_mode = match (input_size, requested_size) {
(a, b) if a == b => return put_input_in_reg(ctx, spec),
(1, 8) => return put_input_in_reg(ctx, spec),
(a, 16) | (a, 32) if a == 1 || a == 8 => ExtMode::BL,
(a, 64) if a == 1 || a == 8 => ExtMode::BQ,
(16, 32) => ExtMode::WL,
(16, 64) => ExtMode::WQ,
(32, 64) => ExtMode::LQ,
_ => unreachable!("extend {} -> {}", input_size, requested_size),
(a, b) => ExtMode::new(a, b).expect(&format!("invalid extension: {} -> {}", a, b)),
};
let src = input_to_reg_mem(ctx, spec);
@ -506,8 +501,11 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
Opcode::Iadd
| Opcode::IaddIfcout
| Opcode::SaddSat
| Opcode::UaddSat
| Opcode::Isub
| Opcode::Imul
| Opcode::AvgRound
| Opcode::Band
| Opcode::Bor
| Opcode::Bxor => {
@ -519,14 +517,24 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
types::I16X8 => SseOpcode::Paddw,
types::I32X4 => SseOpcode::Paddd,
types::I64X2 => SseOpcode::Paddq,
_ => panic!("Unsupported type for packed Iadd instruction"),
_ => panic!("Unsupported type for packed iadd instruction: {}", ty),
},
Opcode::SaddSat => match ty {
types::I8X16 => SseOpcode::Paddsb,
types::I16X8 => SseOpcode::Paddsw,
_ => panic!("Unsupported type for packed sadd_sat instruction: {}", ty),
},
Opcode::UaddSat => match ty {
types::I8X16 => SseOpcode::Paddusb,
types::I16X8 => SseOpcode::Paddusw,
_ => panic!("Unsupported type for packed uadd_sat instruction: {}", ty),
},
Opcode::Isub => match ty {
types::I8X16 => SseOpcode::Psubb,
types::I16X8 => SseOpcode::Psubw,
types::I32X4 => SseOpcode::Psubd,
types::I64X2 => SseOpcode::Psubq,
_ => panic!("Unsupported type for packed Isub instruction"),
_ => panic!("Unsupported type for packed isub instruction: {}", ty),
},
Opcode::Imul => match ty {
types::I16X8 => SseOpcode::Pmullw,
@ -632,9 +640,14 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(dst, rhs_1.to_reg(), ty));
return Ok(());
}
_ => panic!("Unsupported type for packed Imul instruction"),
_ => panic!("Unsupported type for packed imul instruction: {}", ty),
},
_ => panic!("Unsupported packed instruction"),
Opcode::AvgRound => match ty {
types::I8X16 => SseOpcode::Pavgb,
types::I16X8 => SseOpcode::Pavgw,
_ => panic!("Unsupported type for packed avg_round instruction: {}", ty),
},
_ => panic!("Unsupported packed instruction: {}", op),
};
let lhs = put_input_in_reg(ctx, inputs[0]);
let rhs = input_to_reg_mem(ctx, inputs[1]);
@ -686,6 +699,65 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}
}
Opcode::Iabs => {
let src = input_to_reg_mem(ctx, inputs[0]);
let dst = get_output_reg(ctx, outputs[0]);
let ty = ty.unwrap();
if ty.is_vector() {
let opcode = match ty {
types::I8X16 => SseOpcode::Pabsb,
types::I16X8 => SseOpcode::Pabsw,
types::I32X4 => SseOpcode::Pabsd,
_ => panic!("Unsupported type for packed iabs instruction: {}", ty),
};
ctx.emit(Inst::xmm_unary_rm_r(opcode, src, dst));
} else {
unimplemented!("iabs is unimplemented for non-vector type: {}", ty);
}
}
Opcode::Imax | Opcode::Umax | Opcode::Imin | Opcode::Umin => {
let lhs = put_input_in_reg(ctx, inputs[0]);
let rhs = input_to_reg_mem(ctx, inputs[1]);
let dst = get_output_reg(ctx, outputs[0]);
let ty = ty.unwrap();
if ty.is_vector() {
let sse_op = match op {
Opcode::Imax => match ty {
types::I8X16 => SseOpcode::Pmaxsb,
types::I16X8 => SseOpcode::Pmaxsw,
types::I32X4 => SseOpcode::Pmaxsd,
_ => panic!("Unsupported type for packed {} instruction: {}", op, ty),
},
Opcode::Umax => match ty {
types::I8X16 => SseOpcode::Pmaxub,
types::I16X8 => SseOpcode::Pmaxuw,
types::I32X4 => SseOpcode::Pmaxud,
_ => panic!("Unsupported type for packed {} instruction: {}", op, ty),
},
Opcode::Imin => match ty {
types::I8X16 => SseOpcode::Pminsb,
types::I16X8 => SseOpcode::Pminsw,
types::I32X4 => SseOpcode::Pminsd,
_ => panic!("Unsupported type for packed {} instruction: {}", op, ty),
},
Opcode::Umin => match ty {
types::I8X16 => SseOpcode::Pminub,
types::I16X8 => SseOpcode::Pminuw,
types::I32X4 => SseOpcode::Pminud,
_ => panic!("Unsupported type for packed {} instruction: {}", op, ty),
},
_ => unreachable!("This is a bug: the external and internal `match op` should be over the same opcodes."),
};
// Move the `lhs` to the same register as `dst`.
ctx.emit(Inst::gen_move(dst, lhs, ty));
ctx.emit(Inst::xmm_rm_r(sse_op, rhs, dst));
} else {
panic!("Unsupported type for {} instruction: {}", op, ty);
}
}
Opcode::Bnot => {
let ty = ty.unwrap();
if ty.is_vector() {
@ -1189,18 +1261,13 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let src = input_to_reg_mem(ctx, inputs[0]);
let dst = get_output_reg(ctx, outputs[0]);
let ext_mode = match (src_ty.bits(), dst_ty.bits()) {
(1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
(1, 64) | (8, 64) => Some(ExtMode::BQ),
(16, 32) => Some(ExtMode::WL),
(16, 64) => Some(ExtMode::WQ),
(32, 64) => Some(ExtMode::LQ),
(x, y) if x >= y => None,
_ => unreachable!(
"unexpected extension kind from {:?} to {:?}",
src_ty, dst_ty
),
};
let ext_mode = ExtMode::new(src_ty.bits(), dst_ty.bits());
assert!(
(src_ty.bits() < dst_ty.bits() && ext_mode.is_some()) || ext_mode.is_none(),
"unexpected extension: {} -> {}",
src_ty,
dst_ty
);
// All of these other opcodes are simply a move from a zero-extended source. Here
// is why this works, in each case:
@ -1329,7 +1396,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(dst, lhs, input_ty));
// Emit the comparison.
ctx.emit(Inst::xmm_rm_r_imm(op, rhs, dst, imm.encode()));
ctx.emit(Inst::xmm_rm_r_imm(op, rhs, dst, imm.encode(), false));
}
}
@ -1794,6 +1861,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
RegMem::reg(tmp.to_reg()),
tmp,
cond.encode(),
false,
);
ctx.emit(cmpps);
@ -1937,12 +2005,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
_ => unimplemented!(),
};
let ext_mode = match elem_ty.bytes() {
1 => Some(ExtMode::BQ),
2 => Some(ExtMode::WQ),
4 => Some(ExtMode::LQ),
_ => None,
};
let ext_mode = ExtMode::new(elem_ty.bits(), 64);
let sign_extend = match op {
Opcode::Sload8
@ -2197,12 +2260,11 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
if ty_access == types::I64 {
ctx.emit(Inst::mov64_rm_r(rm, data, srcloc));
} else {
let ext_mode = match ty_access {
types::I8 => ExtMode::BQ,
types::I16 => ExtMode::WQ,
types::I32 => ExtMode::LQ,
_ => panic!("lowering AtomicLoad: invalid type"),
};
let ext_mode = ExtMode::new(ty_access.bits(), 64).expect(&format!(
"invalid extension during AtomicLoad: {} -> {}",
ty_access.bits(),
64
));
ctx.emit(Inst::movzx_rm_r(ext_mode, rm, data, srcloc));
}
}
@ -2574,6 +2636,209 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(dst, src, ty));
}
Opcode::Shuffle => {
let ty = ty.unwrap();
let dst = get_output_reg(ctx, outputs[0]);
let lhs_ty = ctx.input_ty(insn, 0);
let lhs = put_input_in_reg(ctx, inputs[0]);
let rhs = put_input_in_reg(ctx, inputs[1]);
let mask = if let &InstructionData::Shuffle { mask, .. } = ctx.data(insn) {
ctx.get_immediate(mask).clone()
} else {
unreachable!("shuffle should always have the shuffle format")
};
// A mask-building helper: in 128-bit SIMD, 0-15 indicate which lane to read from and a
// 1 in the most significant position zeroes the lane.
let zero_unknown_lane_index = |b: u8| if b > 15 { 0b10000000 } else { b };
ctx.emit(Inst::gen_move(dst, rhs, ty));
if rhs == lhs {
// If `lhs` and `rhs` are the same we can use a single PSHUFB to shuffle the XMM
// register. We statically build `constructed_mask` to zero out any unknown lane
// indices (may not be completely necessary: verification could fail incorrect mask
// values) and fix the indexes to all point to the `dst` vector.
let constructed_mask = mask
.iter()
// If the mask is greater than 15 it still may be referring to a lane in b.
.map(|&b| if b > 15 { b.wrapping_sub(16) } else { b })
.map(zero_unknown_lane_index)
.collect();
let tmp = ctx.alloc_tmp(RegClass::V128, types::I8X16);
ctx.emit(Inst::xmm_load_const_seq(constructed_mask, tmp, ty));
// After loading the constructed mask in a temporary register, we use this to
// shuffle the `dst` register (remember that, in this case, it is the same as
// `src` so we disregard this register).
ctx.emit(Inst::xmm_rm_r(SseOpcode::Pshufb, RegMem::from(tmp), dst));
} else {
// If `lhs` and `rhs` are different, we must shuffle each separately and then OR
// them together. This is necessary due to PSHUFB semantics. As in the case above,
// we build the `constructed_mask` for each case statically.
// PSHUFB the `lhs` argument into `tmp0`, placing zeroes for unused lanes.
let tmp0 = ctx.alloc_tmp(RegClass::V128, lhs_ty);
ctx.emit(Inst::gen_move(tmp0, lhs, lhs_ty));
let constructed_mask = mask.iter().cloned().map(zero_unknown_lane_index).collect();
let tmp1 = ctx.alloc_tmp(RegClass::V128, types::I8X16);
ctx.emit(Inst::xmm_load_const_seq(constructed_mask, tmp1, ty));
ctx.emit(Inst::xmm_rm_r(SseOpcode::Pshufb, RegMem::from(tmp1), tmp0));
// PSHUFB the second argument, placing zeroes for unused lanes.
let constructed_mask = mask
.iter()
.map(|b| b.wrapping_sub(16))
.map(zero_unknown_lane_index)
.collect();
let tmp2 = ctx.alloc_tmp(RegClass::V128, types::I8X16);
ctx.emit(Inst::xmm_load_const_seq(constructed_mask, tmp2, ty));
ctx.emit(Inst::xmm_rm_r(SseOpcode::Pshufb, RegMem::from(tmp2), dst));
// OR the shuffled registers (the mechanism and lane-size for OR-ing the registers
// is not important).
ctx.emit(Inst::xmm_rm_r(SseOpcode::Orps, RegMem::from(tmp0), dst));
// TODO when AVX512 is enabled we should replace this sequence with a single VPERMB
}
}
Opcode::Swizzle => {
// SIMD swizzle; the following inefficient implementation is due to the Wasm SIMD spec
// requiring mask indexes greater than 15 to have the same semantics as a 0 index. For
// the spec discussion, see https://github.com/WebAssembly/simd/issues/93. The CLIF
// semantics match the Wasm SIMD semantics for this instruction.
// The instruction format maps to variables like: %dst = swizzle %src, %mask
let ty = ty.unwrap();
let dst = get_output_reg(ctx, outputs[0]);
let src = put_input_in_reg(ctx, inputs[0]);
let swizzle_mask = put_input_in_reg(ctx, inputs[1]);
// Inform the register allocator that `src` and `dst` should be in the same register.
ctx.emit(Inst::gen_move(dst, src, ty));
// Create a mask for zeroing out-of-bounds lanes of the swizzle mask.
let zero_mask = ctx.alloc_tmp(RegClass::V128, types::I8X16);
let zero_mask_value = vec![
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
0x70, 0x70,
];
ctx.emit(Inst::xmm_load_const_seq(zero_mask_value, zero_mask, ty));
// Use the `zero_mask` on a writable `swizzle_mask`.
let swizzle_mask = Writable::from_reg(swizzle_mask);
ctx.emit(Inst::xmm_rm_r(
SseOpcode::Paddusb,
RegMem::from(zero_mask),
swizzle_mask,
));
// Shuffle `dst` using the fixed-up `swizzle_mask`.
ctx.emit(Inst::xmm_rm_r(
SseOpcode::Pshufb,
RegMem::from(swizzle_mask),
dst,
));
}
Opcode::Insertlane => {
// The instruction format maps to variables like: %dst = insertlane %in_vec, %src, %lane
let ty = ty.unwrap();
let dst = get_output_reg(ctx, outputs[0]);
let in_vec = put_input_in_reg(ctx, inputs[0]);
let src_ty = ctx.input_ty(insn, 1);
debug_assert!(!src_ty.is_vector());
let src = input_to_reg_mem(ctx, inputs[1]);
let lane = if let InstructionData::TernaryImm8 { imm, .. } = ctx.data(insn) {
*imm
} else {
unreachable!();
};
debug_assert!(lane < ty.lane_count() as u8);
ctx.emit(Inst::gen_move(dst, in_vec, ty));
if !src_ty.is_float() {
let (sse_op, w_bit) = match ty.lane_bits() {
8 => (SseOpcode::Pinsrb, false),
16 => (SseOpcode::Pinsrw, false),
32 => (SseOpcode::Pinsrd, false),
64 => (SseOpcode::Pinsrd, true),
_ => panic!("Unable to insertlane for lane size: {}", ty.lane_bits()),
};
ctx.emit(Inst::xmm_rm_r_imm(sse_op, src, dst, lane, w_bit));
} else if src_ty == types::F32 {
let sse_op = SseOpcode::Insertps;
// Insert 32-bits from replacement (at index 00, bits 7:8) to vector (lane
// shifted into bits 5:6).
let lane = 0b00_00_00_00 | lane << 4;
ctx.emit(Inst::xmm_rm_r_imm(sse_op, src, dst, lane, false));
} else if src_ty == types::F64 {
let sse_op = match lane {
// Move the lowest quadword in replacement to vector without changing
// the upper bits.
0 => SseOpcode::Movsd,
// Move the low 64 bits of replacement vector to the high 64 bits of the
// vector.
1 => SseOpcode::Movlhps,
_ => unreachable!(),
};
// Here we use the `xmm_rm_r` encoding because it correctly tells the register
// allocator how we are using `dst`: we are using `dst` as a `mod` whereas other
// encoding formats like `xmm_unary_rm_r` treat it as a `def`.
ctx.emit(Inst::xmm_rm_r(sse_op, src, dst));
} else {
panic!("Unable to insertlane for type: {}", ty);
}
}
Opcode::Extractlane => {
// The instruction format maps to variables like: %dst = extractlane %src, %lane
let ty = ty.unwrap();
let dst = get_output_reg(ctx, outputs[0]);
let src_ty = ctx.input_ty(insn, 0);
assert_eq!(src_ty.bits(), 128);
let src = put_input_in_reg(ctx, inputs[0]);
let lane = if let InstructionData::BinaryImm8 { imm, .. } = ctx.data(insn) {
*imm
} else {
unreachable!();
};
debug_assert!(lane < src_ty.lane_count() as u8);
if !ty.is_float() {
let (sse_op, w_bit) = match ty.lane_bits() {
8 => (SseOpcode::Pextrb, false),
16 => (SseOpcode::Pextrw, false),
32 => (SseOpcode::Pextrd, false),
64 => (SseOpcode::Pextrd, true),
_ => panic!("Unable to extractlane for lane size: {}", ty.lane_bits()),
};
let src = RegMem::reg(src);
ctx.emit(Inst::xmm_rm_r_imm(sse_op, src, dst, lane, w_bit));
} else {
if lane == 0 {
// Remove the extractlane instruction, leaving the float where it is. The upper
// bits will remain unchanged; for correctness, this relies on Cranelift type
// checking to avoid using those bits.
ctx.emit(Inst::gen_move(dst, src, ty));
} else {
// Otherwise, shuffle the bits in `lane` to the lowest lane.
let sse_op = SseOpcode::Pshufd;
let mask = match src_ty {
// Move the value at `lane` to lane 0, copying existing value at lane 0 to
// other lanes. Again, this relies on Cranelift type checking to avoid
// using those bits.
types::F32X4 => 0b00_00_00_00 | lane,
// Move the value at `lane` 1 (we know it must be 1 because of the `if`
// statement above) to lane 0 and leave lane 1 unchanged. The Cranelift type
// checking assumption also applies here.
types::F64X2 => 0b11_10_11_10,
_ => unreachable!(),
};
let src = RegMem::reg(src);
ctx.emit(Inst::xmm_rm_r_imm(sse_op, src, dst, mask, false));
}
}
}
Opcode::IaddImm
| Opcode::ImulImm
| Opcode::UdivImm

Просмотреть файл

@ -506,6 +506,7 @@ pub fn prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> Codege
baldrdash_prologue_epilogue(func, isa)
}
CallConv::Probestack => unimplemented!("probestack calling convention"),
CallConv::Baldrdash2020 => unimplemented!("Baldrdash ABI 2020"),
}
}

Просмотреть файл

@ -158,6 +158,7 @@ fn legalize_entry_params(func: &mut Function, entry: Block) {
has_stack_limit = true;
}
ArgumentPurpose::Link => panic!("Unexpected link arg {}", abi_type),
ArgumentPurpose::CallerTLS | ArgumentPurpose::CalleeTLS => {}
}
abi_arg += 1;
} else {
@ -217,6 +218,7 @@ fn legalize_entry_params(func: &mut Function, entry: Block) {
debug_assert!(!has_stack_limit, "Multiple stack_limit parameters found");
has_stack_limit = true;
}
ArgumentPurpose::CallerTLS | ArgumentPurpose::CalleeTLS => {}
}
// Just create entry block values to match here. We will use them in `handle_return_abi()`

Просмотреть файл

@ -44,6 +44,11 @@ pub trait ABICallee {
/// register.
fn gen_copy_arg_to_reg(&self, idx: usize, into_reg: Writable<Reg>) -> Self::I;
/// Is the given argument needed in the body (as opposed to, e.g., serving
/// only as a special ABI-specific placeholder)? This controls whether
/// lowering will copy it to a virtual reg use by CLIF instructions.
fn arg_is_needed_in_body(&self, idx: usize) -> bool;
/// Generate any setup instruction needed to save values to the
/// return-value area. This is usually used when were are multiple return
/// values or an otherwise large return value that must be passed on the

Просмотреть файл

@ -127,9 +127,24 @@ use std::mem;
#[derive(Clone, Copy, Debug)]
pub enum ABIArg {
/// In a real register.
Reg(RealReg, ir::Type, ir::ArgumentExtension),
Reg(
RealReg,
ir::Type,
ir::ArgumentExtension,
ir::ArgumentPurpose,
),
/// Arguments only: on stack, at given offset from SP at entry.
Stack(i64, ir::Type, ir::ArgumentExtension),
Stack(i64, ir::Type, ir::ArgumentExtension, ir::ArgumentPurpose),
}
impl ABIArg {
/// Get the purpose of this arg.
fn get_purpose(self) -> ir::ArgumentPurpose {
match self {
ABIArg::Reg(_, _, _, purpose) => purpose,
ABIArg::Stack(_, _, _, purpose) => purpose,
}
}
}
/// Are we computing information about arguments or return values? Much of the
@ -175,6 +190,32 @@ pub trait ABIMachineSpec {
/// The instruction type.
type I: VCodeInst;
/// Returns the number of bits in a word, that is 32/64 for 32/64-bit architecture.
fn word_bits() -> u32;
/// Returns the number of bytes in a word.
fn word_bytes() -> u32 {
return Self::word_bits() / 8;
}
/// Returns word-size integer type.
fn word_type() -> Type {
match Self::word_bits() {
32 => I32,
64 => I64,
_ => unreachable!(),
}
}
/// Returns word register class.
fn word_reg_class() -> RegClass {
match Self::word_bits() {
32 => RegClass::I32,
64 => RegClass::I64,
_ => unreachable!(),
}
}
/// Process a list of parameters or return values and allocate them to registers
/// and stack slots.
///
@ -282,6 +323,7 @@ pub trait ABIMachineSpec {
/// nominal SP offset; caller will do that.
fn gen_clobber_save(
call_conv: isa::CallConv,
flags: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> (u64, SmallVec<[Self::I; 16]>);
@ -291,6 +333,7 @@ pub trait ABIMachineSpec {
/// clobber-save sequence finished.
fn gen_clobber_restore(
call_conv: isa::CallConv,
flags: &settings::Flags,
clobbers: &Set<Writable<RealReg>>,
) -> SmallVec<[Self::I; 16]>;
@ -453,7 +496,8 @@ impl<M: ABIMachineSpec> ABICalleeImpl<M> {
for (stackslot, data) in f.stack_slots.iter() {
let off = stack_offset;
stack_offset += data.size;
stack_offset = (stack_offset + 7) & !7;
let mask = M::word_bytes() - 1;
stack_offset = (stack_offset + mask) & !mask;
debug_assert_eq!(stackslot.as_u32() as usize, stackslots.len());
stackslots.push(off);
}
@ -587,7 +631,12 @@ fn generate_gv<M: ABIMachineSpec>(
} => {
let base = generate_gv::<M>(f, abi, base, insts);
let into_reg = Writable::from_reg(M::get_stacklimit_reg());
insts.push(M::gen_load_base_offset(into_reg, base, offset.into(), I64));
insts.push(M::gen_load_base_offset(
into_reg,
base,
offset.into(),
M::word_type(),
));
return into_reg.to_reg();
}
ref other => panic!("global value for stack limit not supported: {}", other),
@ -603,13 +652,13 @@ fn generate_gv<M: ABIMachineSpec>(
/// associated vreg when needed to satisfy a safepoint (which requires all
/// ref-typed values, even those in real registers in the original vcode, to be
/// in spillslots).
fn ty_from_ty_hint_or_reg_class(r: Reg, ty: Option<Type>) -> Type {
fn ty_from_ty_hint_or_reg_class<M: ABIMachineSpec>(r: Reg, ty: Option<Type>) -> Type {
match (ty, r.get_class()) {
// If the type is provided
(Some(t), _) => t,
// If no type is provided, this should be a register spill for a
// safepoint, so we only expect I64 (integer) registers.
(None, RegClass::I64) => I64,
// safepoint, so we only expect I32/I64 (integer) registers.
(None, rc) if rc == M::word_reg_class() => M::word_type(),
_ => panic!("Unexpected register class!"),
}
}
@ -668,8 +717,8 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
match &self.sig.args[idx] {
// Extension mode doesn't matter (we're copying out, not in; we
// ignore high bits by convention).
&ABIArg::Reg(r, ty, _) => M::gen_move(into_reg, r.to_reg(), ty),
&ABIArg::Stack(off, ty, _) => M::gen_load_stack(
&ABIArg::Reg(r, ty, ..) => M::gen_move(into_reg, r.to_reg(), ty),
&ABIArg::Stack(off, ty, ..) => M::gen_load_stack(
StackAMode::FPOffset(M::fp_to_arg_offset(self.call_conv, &self.flags) + off, ty),
into_reg,
ty,
@ -677,27 +726,40 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
}
fn arg_is_needed_in_body(&self, idx: usize) -> bool {
match self.sig.args[idx].get_purpose() {
// Special Baldrdash-specific pseudo-args that are present only to
// fill stack slots. Won't ever be used as ordinary values in the
// body.
ir::ArgumentPurpose::CalleeTLS | ir::ArgumentPurpose::CallerTLS => false,
_ => true,
}
}
fn gen_copy_reg_to_retval(&self, idx: usize, from_reg: Writable<Reg>) -> Vec<Self::I> {
let mut ret = Vec::new();
let word_bits = M::word_bits() as u8;
match &self.sig.rets[idx] {
&ABIArg::Reg(r, ty, ext) => {
&ABIArg::Reg(r, ty, ext, ..) => {
let from_bits = ty_bits(ty) as u8;
let dest_reg = Writable::from_reg(r.to_reg());
match (ext, from_bits) {
(ArgumentExtension::Uext, n) | (ArgumentExtension::Sext, n) if n < 64 => {
(ArgumentExtension::Uext, n) | (ArgumentExtension::Sext, n)
if n < word_bits =>
{
let signed = ext == ArgumentExtension::Sext;
ret.push(M::gen_extend(
dest_reg,
from_reg.to_reg(),
signed,
from_bits,
/* to_bits = */ 64,
/* to_bits = */ word_bits,
));
}
_ => ret.push(M::gen_move(dest_reg, from_reg.to_reg(), ty)),
};
}
&ABIArg::Stack(off, mut ty, ext) => {
&ABIArg::Stack(off, mut ty, ext, ..) => {
let from_bits = ty_bits(ty) as u8;
// A machine ABI implementation should ensure that stack frames
// have "reasonable" size. All current ABIs for machinst
@ -706,18 +768,20 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
.expect("Argument stack offset greater than 2GB; should hit impl limit first");
// Trash the from_reg; it should be its last use.
match (ext, from_bits) {
(ArgumentExtension::Uext, n) | (ArgumentExtension::Sext, n) if n < 64 => {
assert_eq!(RegClass::I64, from_reg.to_reg().get_class());
(ArgumentExtension::Uext, n) | (ArgumentExtension::Sext, n)
if n < word_bits =>
{
assert_eq!(M::word_reg_class(), from_reg.to_reg().get_class());
let signed = ext == ArgumentExtension::Sext;
ret.push(M::gen_extend(
from_reg,
from_reg.to_reg(),
signed,
from_bits,
/* to_bits = */ 64,
/* to_bits = */ word_bits,
));
// Store the extended version.
ty = I64;
ty = M::word_type();
}
_ => {}
};
@ -802,7 +866,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
fn load_spillslot(&self, slot: SpillSlot, ty: Type, into_reg: Writable<Reg>) -> Self::I {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let islot = slot.get() as i64;
let spill_off = islot * 8; // FIXME: 64-bit machine assumed.
let spill_off = islot * M::word_bytes() as i64;
let sp_off = self.stackslots_size as i64 + spill_off;
trace!("load_spillslot: slot {:?} -> sp_off {}", slot, sp_off);
M::gen_load_stack(StackAMode::NominalSPOffset(sp_off, ty), into_reg, ty)
@ -812,7 +876,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
fn store_spillslot(&self, slot: SpillSlot, ty: Type, from_reg: Reg) -> Self::I {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let islot = slot.get() as i64;
let spill_off = islot * 8; // FIXME: 64-bit machine assumed.
let spill_off = islot * M::word_bytes() as i64;
let sp_off = self.stackslots_size as i64 + spill_off;
trace!("store_spillslot: slot {:?} -> sp_off {}", slot, sp_off);
M::gen_store_stack(StackAMode::NominalSPOffset(sp_off, ty), from_reg, ty)
@ -832,12 +896,14 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
state
);
let map_size = (virtual_sp_offset + nominal_sp_to_fp) as u32;
let map_words = (map_size + 7) / 8; // FIXME: 64-bit machine assumed.
let bytes = M::word_bytes();
let map_words = (map_size + bytes - 1) / bytes;
let mut bits = std::iter::repeat(false)
.take(map_words as usize)
.collect::<Vec<bool>>();
let first_spillslot_word = ((self.stackslots_size + virtual_sp_offset as u32) / 8) as usize;
let first_spillslot_word =
((self.stackslots_size + virtual_sp_offset as u32) / bytes) as usize;
for &slot in slots {
let slot = slot.get() as usize;
bits[first_spillslot_word + slot] = true;
@ -853,16 +919,17 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
insts.extend(M::gen_prologue_frame_setup().into_iter());
}
let mut total_stacksize = self.stackslots_size + 8 * self.spillslots.unwrap() as u32;
let bytes = M::word_bytes();
let mut total_stacksize = self.stackslots_size + bytes * self.spillslots.unwrap() as u32;
if self.call_conv.extends_baldrdash() {
debug_assert!(
!self.flags.enable_probestack(),
"baldrdash does not expect cranelift to emit stack probes"
);
// FIXME: 64-bit machine assumed.
total_stacksize += self.flags.baldrdash_prologue_words() as u32 * 8;
total_stacksize += self.flags.baldrdash_prologue_words() as u32 * bytes;
}
let total_stacksize = (total_stacksize + 15) & !15; // 16-align the stack.
let mask = 2 * bytes - 1;
let total_stacksize = (total_stacksize + mask) & !mask; // 16-align the stack.
let mut total_sp_adjust = 0;
@ -897,7 +964,8 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
// Save clobbered registers.
let (clobber_size, clobber_insts) = M::gen_clobber_save(self.call_conv, &self.clobbered);
let (clobber_size, clobber_insts) =
M::gen_clobber_save(self.call_conv, &self.flags, &self.clobbered);
insts.extend(clobber_insts);
if clobber_size > 0 {
@ -912,7 +980,11 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
let mut insts = vec![];
// Restore clobbered registers.
insts.extend(M::gen_clobber_restore(self.call_conv, &self.clobbered));
insts.extend(M::gen_clobber_restore(
self.call_conv,
&self.flags,
&self.clobbered,
));
// N.B.: we do *not* emit a nominal SP adjustment here, because (i) there will be no
// references to nominal SP offsets before the return below, and (ii) the instruction
@ -943,7 +1015,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg, ty: Option<Type>) -> Self::I {
let ty = ty_from_ty_hint_or_reg_class(from_reg.to_reg(), ty);
let ty = ty_from_ty_hint_or_reg_class::<M>(from_reg.to_reg(), ty);
self.store_spillslot(to_slot, ty, from_reg.to_reg())
}
@ -953,7 +1025,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
from_slot: SpillSlot,
ty: Option<Type>,
) -> Self::I {
let ty = ty_from_ty_hint_or_reg_class(to_reg.to_reg().to_reg(), ty);
let ty = ty_from_ty_hint_or_reg_class::<M>(to_reg.to_reg().to_reg(), ty);
self.load_spillslot(from_slot, ty, to_reg.map(|r| r.to_reg()))
}
}
@ -1092,11 +1164,13 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
idx: usize,
from_reg: Reg,
) {
let word_rc = M::word_reg_class();
let word_bits = M::word_bits() as usize;
match &self.sig.args[idx] {
&ABIArg::Reg(reg, ty, ext)
if ext != ir::ArgumentExtension::None && ty_bits(ty) < 64 =>
&ABIArg::Reg(reg, ty, ext, _)
if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits =>
{
assert_eq!(RegClass::I64, reg.get_class());
assert_eq!(word_rc, reg.get_class());
let signed = match ext {
ir::ArgumentExtension::Uext => false,
ir::ArgumentExtension::Sext => true,
@ -1107,15 +1181,15 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
from_reg,
signed,
ty_bits(ty) as u8,
64,
word_bits as u8,
));
}
&ABIArg::Reg(reg, ty, _) => {
&ABIArg::Reg(reg, ty, _, _) => {
ctx.emit(M::gen_move(Writable::from_reg(reg.to_reg()), from_reg, ty));
}
&ABIArg::Stack(off, mut ty, ext) => {
if ext != ir::ArgumentExtension::None && ty_bits(ty) < 64 {
assert_eq!(RegClass::I64, from_reg.get_class());
&ABIArg::Stack(off, mut ty, ext, _) => {
if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits {
assert_eq!(word_rc, from_reg.get_class());
let signed = match ext {
ir::ArgumentExtension::Uext => false,
ir::ArgumentExtension::Sext => true,
@ -1129,10 +1203,10 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
from_reg,
signed,
ty_bits(ty) as u8,
64,
word_bits as u8,
));
// Store the extended version.
ty = I64;
ty = M::word_type();
}
ctx.emit(M::gen_store_stack(
StackAMode::SPOffset(off, ty),
@ -1152,8 +1226,8 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
match &self.sig.rets[idx] {
// Extension mode doesn't matter because we're copying out, not in,
// and we ignore high bits in our own registers by convention.
&ABIArg::Reg(reg, ty, _) => ctx.emit(M::gen_move(into_reg, reg.to_reg(), ty)),
&ABIArg::Stack(off, ty, _) => {
&ABIArg::Reg(reg, ty, _, _) => ctx.emit(M::gen_move(into_reg, reg.to_reg(), ty)),
&ABIArg::Stack(off, ty, _, _) => {
let ret_area_base = self.sig.stack_arg_space;
ctx.emit(M::gen_load_stack(
StackAMode::SPOffset(off + ret_area_base, ty),
@ -1169,8 +1243,10 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
mem::replace(&mut self.uses, Default::default()),
mem::replace(&mut self.defs, Default::default()),
);
let word_rc = M::word_reg_class();
let word_type = M::word_type();
if let Some(i) = self.sig.stack_ret_arg {
let rd = ctx.alloc_tmp(RegClass::I64, I64);
let rd = ctx.alloc_tmp(word_rc, word_type);
let ret_area_base = self.sig.stack_arg_space;
ctx.emit(M::gen_get_stack_addr(
StackAMode::SPOffset(ret_area_base, I8),
@ -1179,7 +1255,7 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
));
self.emit_copy_reg_to_arg(ctx, i, rd.to_reg());
}
let tmp = ctx.alloc_tmp(RegClass::I64, I64);
let tmp = ctx.alloc_tmp(word_rc, word_type);
for (is_safepoint, inst) in
M::gen_call(&self.dest, uses, defs, self.loc, self.opcode, tmp).into_iter()
{

Просмотреть файл

@ -420,6 +420,9 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
self.f.dfg.block_params(entry_bb)
);
for (i, param) in self.f.dfg.block_params(entry_bb).iter().enumerate() {
if !self.vcode.abi().arg_is_needed_in_body(i) {
continue;
}
let reg = Writable::from_reg(self.value_regs[*param]);
let insn = self.vcode.abi().gen_copy_arg_to_reg(i, reg);
self.emit(insn);

Просмотреть файл

@ -274,29 +274,18 @@ impl fmt::Display for Pressure {
#[cfg(feature = "arm32")]
mod tests {
use super::Pressure;
use crate::isa::{RegClass, TargetIsa};
use crate::isa::registers::{RegBank, RegClassData};
use crate::isa::{RegClass, RegInfo, RegUnit};
use crate::regalloc::RegisterSet;
use alloc::boxed::Box;
use core::borrow::Borrow;
use core::str::FromStr;
use target_lexicon::triple;
// Make an arm32 `TargetIsa`, if possible.
fn arm32() -> Option<Box<dyn TargetIsa>> {
use crate::isa;
use crate::settings;
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
isa::lookup(triple!("arm"))
.ok()
.map(|b| b.finish(shared_flags))
}
// Arm32 `TargetIsa` is now `TargetIsaAdapter`, which does not hold any info
// about registers, so we directly access `INFO` from registers-arm32.rs.
include!(concat!(env!("OUT_DIR"), "/registers-arm32.rs"));
// Get a register class by name.
fn rc_by_name(isa: &dyn TargetIsa, name: &str) -> RegClass {
isa.register_info()
fn rc_by_name(reginfo: &RegInfo, name: &str) -> RegClass {
reginfo
.classes
.iter()
.find(|rc| rc.name == name)
@ -305,11 +294,10 @@ mod tests {
#[test]
fn basic_counting() {
let isa = arm32().expect("This test requires arm32 support");
let isa = isa.borrow();
let gpr = rc_by_name(isa, "GPR");
let s = rc_by_name(isa, "S");
let reginfo = isa.register_info();
let reginfo = INFO.borrow();
let gpr = rc_by_name(&reginfo, "GPR");
let s = rc_by_name(&reginfo, "S");
let regs = RegisterSet::new();
let mut pressure = Pressure::new(&reginfo, &regs);
@ -333,12 +321,10 @@ mod tests {
#[test]
fn arm_float_bank() {
let isa = arm32().expect("This test requires arm32 support");
let isa = isa.borrow();
let s = rc_by_name(isa, "S");
let d = rc_by_name(isa, "D");
let q = rc_by_name(isa, "Q");
let reginfo = isa.register_info();
let reginfo = INFO.borrow();
let s = rc_by_name(&reginfo, "S");
let d = rc_by_name(&reginfo, "D");
let q = rc_by_name(&reginfo, "Q");
let regs = RegisterSet::new();
let mut pressure = Pressure::new(&reginfo, &regs);

Просмотреть файл

@ -1149,24 +1149,14 @@ mod tests {
use super::{Move, Solver};
use crate::entity::EntityRef;
use crate::ir::Value;
use crate::isa::{RegClass, RegInfo, RegUnit, TargetIsa};
use crate::isa::registers::{RegBank, RegClassData};
use crate::isa::{RegClass, RegInfo, RegUnit};
use crate::regalloc::RegisterSet;
use alloc::boxed::Box;
use core::str::FromStr;
use target_lexicon::triple;
use core::borrow::Borrow;
// Make an arm32 `TargetIsa`, if possible.
fn arm32() -> Option<Box<dyn TargetIsa>> {
use crate::isa;
use crate::settings;
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
isa::lookup(triple!("arm"))
.ok()
.map(|b| b.finish(shared_flags))
}
// Arm32 `TargetIsa` is now `TargetIsaAdapter`, which does not hold any info
// about registers, so we directly access `INFO` from registers-arm32.rs.
include!(concat!(env!("OUT_DIR"), "/registers-arm32.rs"));
// Get a register class by name.
fn rc_by_name(reginfo: &RegInfo, name: &str) -> RegClass {
@ -1207,8 +1197,7 @@ mod tests {
#[test]
fn simple_moves() {
let isa = arm32().expect("This test requires arm32 support");
let reginfo = isa.register_info();
let reginfo = INFO.borrow();
let gpr = rc_by_name(&reginfo, "GPR");
let r0 = gpr.unit(0);
let r1 = gpr.unit(1);
@ -1260,8 +1249,7 @@ mod tests {
#[test]
fn harder_move_cycles() {
let isa = arm32().expect("This test requires arm32 support");
let reginfo = isa.register_info();
let reginfo = INFO.borrow();
let s = rc_by_name(&reginfo, "S");
let d = rc_by_name(&reginfo, "D");
let d0 = d.unit(0);
@ -1322,8 +1310,7 @@ mod tests {
#[test]
fn emergency_spill() {
let isa = arm32().expect("This test requires arm32 support");
let reginfo = isa.register_info();
let reginfo = INFO.borrow();
let gpr = rc_by_name(&reginfo, "GPR");
let r0 = gpr.unit(0);
let r1 = gpr.unit(1);

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"0ac209bc13b1152b67c8ab3e0a87ab512d966367758cc7fa131096dbe97a1da8","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"69d539b72460c0aba1d30e0b72efb0c29d61558574d751c784794e14abf41352","src/iter.rs":"61fefdc49cafad4cacba5f5a7ad2396a23160642c688a7f0b0734277391847cd","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"72aca3bf830dce85a8b5f2325b589810ca06ae09e8d2daf137524ad6e6737bbe","src/list.rs":"4bf609eb7cc7c000c18da746596d5fcc67eece3f919ee2d76e19f6ac371640d1","src/map.rs":"e5ce79a7536dc147092be4965785b55e24b11356554be57afab38a7a93f47f4e","src/packed_option.rs":"d931ba5ce07a5c77c8a62bb07316db21c101bc3fa1eb6ffd396f8a8944958185","src/primary.rs":"20fe2c1b9645606c5fd5d416225f1e6a4bea17ee7de73ef5492c113263a29dd6","src/set.rs":"b040054b8baa0599e64df9ee841640688e2a73b6eabbdc5a4f15334412db052a","src/sparse.rs":"536e31fdcf64450526f5e5b85e97406c26b998bc7e0d8161b6b449c24265449f"},"package":null}
{"files":{"Cargo.toml":"6caa0a14fad8486a13273989457e57d6180be91eb57ded8977f67a784d982f4a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"69d539b72460c0aba1d30e0b72efb0c29d61558574d751c784794e14abf41352","src/iter.rs":"61fefdc49cafad4cacba5f5a7ad2396a23160642c688a7f0b0734277391847cd","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"72aca3bf830dce85a8b5f2325b589810ca06ae09e8d2daf137524ad6e6737bbe","src/list.rs":"4bf609eb7cc7c000c18da746596d5fcc67eece3f919ee2d76e19f6ac371640d1","src/map.rs":"e5ce79a7536dc147092be4965785b55e24b11356554be57afab38a7a93f47f4e","src/packed_option.rs":"d931ba5ce07a5c77c8a62bb07316db21c101bc3fa1eb6ffd396f8a8944958185","src/primary.rs":"20fe2c1b9645606c5fd5d416225f1e6a4bea17ee7de73ef5492c113263a29dd6","src/set.rs":"b040054b8baa0599e64df9ee841640688e2a73b6eabbdc5a4f15334412db052a","src/sparse.rs":"536e31fdcf64450526f5e5b85e97406c26b998bc7e0d8161b6b449c24265449f"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-entity"
version = "0.66.0"
version = "0.67.0"
description = "Data structures using entity references as mapping keys"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://docs.rs/cranelift-entity"

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"52587586762dcb18c8ae39de76ef388a78b857d8fecd87b77b6a30dc8f85e1f5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"ac3a1e3070b1ab0bdec84e4d73ec182b50d0b9a4017e6a95c37adab57571b827","src/lib.rs":"5197f467d1625ee2b117a168f4b1886b4b69d4250faea6618360a5adc70b4e0c","src/ssa.rs":"650d26025706cfb63935f956bca6f166b0edfa32260cd2a8c27f9b49fcc743c3","src/switch.rs":"2d394292c4eafee3476eb159bbb52e1da2108b0ba8fc4cf8dd663fca1ee887d9","src/variable.rs":"399437bd7d2ac11a7a748bad7dd1f6dac58824d374ec318f36367a9d077cc225"},"package":null}
{"files":{"Cargo.toml":"c58c988dd6e749bd15cbae1115575fdf4f43bdf952bd3c90bbb28d805759984a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"53e108a04ead6890ee78f674b9ed6862443c66dd85ec214e4c27e0da3f67228e","src/lib.rs":"5197f467d1625ee2b117a168f4b1886b4b69d4250faea6618360a5adc70b4e0c","src/ssa.rs":"650d26025706cfb63935f956bca6f166b0edfa32260cd2a8c27f9b49fcc743c3","src/switch.rs":"73f9058a899d2b19ed7135e028cc6005c6e3016f8530619519eac9627cb1383e","src/variable.rs":"399437bd7d2ac11a7a748bad7dd1f6dac58824d374ec318f36367a9d077cc225"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-frontend"
version = "0.66.0"
version = "0.67.0"
description = "Cranelift IR builder helper"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://docs.rs/cranelift-frontend"
@ -11,8 +11,8 @@ readme = "README.md"
edition = "2018"
[dependencies]
cranelift-codegen = { path = "../codegen", version = "0.66.0", default-features = false }
target-lexicon = "0.10"
cranelift-codegen = { path = "../codegen", version = "0.67.0", default-features = false }
target-lexicon = "0.11"
log = { version = "0.4.6", default-features = false }
hashbrown = { version = "0.7", optional = true }
smallvec = { version = "1.0.0" }

Просмотреть файл

@ -972,12 +972,13 @@ mod tests {
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
let triple =
::target_lexicon::Triple::from_str("riscv32").expect("Couldn't create riscv32 triple");
let target = isa::lookup(triple)
.ok()
.map(|b| b.finish(shared_flags))
.expect("This test requires arm support.");
.expect("This test requires riscv32 support.");
let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32));
@ -1033,12 +1034,13 @@ block0:
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
let triple =
::target_lexicon::Triple::from_str("riscv32").expect("Couldn't create riscv32 triple");
let target = isa::lookup(triple)
.ok()
.map(|b| b.finish(shared_flags))
.expect("This test requires arm support.");
.expect("This test requires riscv32 support.");
let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32));
@ -1090,12 +1092,13 @@ block0:
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
let triple =
::target_lexicon::Triple::from_str("riscv32").expect("Couldn't create riscv32 triple");
let target = isa::lookup(triple)
.ok()
.map(|b| b.finish(shared_flags))
.expect("This test requires arm support.");
.expect("This test requires riscv32 support.");
let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32));
@ -1150,12 +1153,13 @@ block0:
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
let triple =
::target_lexicon::Triple::from_str("riscv32").expect("Couldn't create riscv32 triple");
let target = isa::lookup(triple)
.ok()
.map(|b| b.finish(shared_flags))
.expect("This test requires arm support.");
.expect("This test requires riscv32 support.");
let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32));
@ -1202,12 +1206,13 @@ block0:
let shared_builder = settings::builder();
let shared_flags = settings::Flags::new(shared_builder);
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
let triple =
::target_lexicon::Triple::from_str("riscv32").expect("Couldn't create riscv32 triple");
let target = isa::lookup(triple)
.ok()
.map(|b| b.finish(shared_flags))
.expect("This test requires arm support.");
.expect("This test requires riscv32 support.");
let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32));

Просмотреть файл

@ -276,6 +276,11 @@ impl Switch {
bx.switch_to_block(new_block);
// Cast to u32, as br_table is not implemented for integers bigger than 32bits.
let discr = if bx.func.dfg.value_type(discr) == types::I128 {
bx.ins().isplit(discr).0
} else {
discr
};
bx.ins().ireduce(types::I32, discr)
} else {
discr
@ -648,8 +653,9 @@ block4:
jump block5
block5:
v2 = ireduce.i32 v0
br_table v2, block3, jt0"
v2, v3 = isplit.i128 v0
v4 = ireduce.i32 v2
br_table v4, block3, jt0"
);
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"3c6ff4a157eea9e347e0d23f4f23628f77233a3e897e48a32b4a4a7679b7548a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c82c252fbeeaa101a0eef042b9a925eb1fa3d2b51d19481b9c22e593e6a8d772","src/code_translator.rs":"d85885a51f19f25a1c60c94f6f35815273547a18b04d73584d7a8d283c099651","src/environ/dummy.rs":"0c05a77ab37a305c799f1b0e99c9debe1b8f59a3e3aa764e2fe39a923716b2ee","src/environ/mod.rs":"692f35d75f125f9c071f7166252f427e4bac29401356f73307c6c36e23c667fb","src/environ/spec.rs":"0f97fff3cc545772a1959f7d0439713fd7dc8d8adf43a2636f8174126dc1393c","src/func_translator.rs":"48ee25da11063743459f9e9407512413075265e67713c6f5ab733798be2bf19d","src/lib.rs":"7bdbcf638fa30fb05e8320439881f7536824f7f60a7db4f0c1b51ab369edf895","src/module_translator.rs":"1374fa56ca18a782083fa0f25f2ad675044a92bbf1a0a1cc44fcaf695807e044","src/sections_translator.rs":"11d65fd2e595e41f976e5c7d0df823f70449f79a9d2facbed61263616f8cfec1","src/state/func_state.rs":"581a5648b11fa07aef3cff0752597864c7cd44a4d44e27c50fc7349955b3fda3","src/state/mod.rs":"20014cb93615467b4d20321b52f67f66040417efcaa739a4804093bb559eed19","src/state/module_state.rs":"7ca3cb06b4481bc3ae74697fbcd437aea1d851eaa3cfe18cc013a4af43728957","src/translation_utils.rs":"69f20c47ea22f0badd21a6187b5f9764252a00d19643a7e3e691797a9fe34f1b","tests/wasm_testsuite.rs":"da8dedfd11918946e9cf6af68fd4826f020ef90a4e22742b1a30e61a3fb4aedd"},"package":null}
{"files":{"Cargo.toml":"7a4570632d7829d4596daeae9c0d17cb5a7120e34e4234022b2cd3b9700e8c93","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c82c252fbeeaa101a0eef042b9a925eb1fa3d2b51d19481b9c22e593e6a8d772","src/code_translator.rs":"d85885a51f19f25a1c60c94f6f35815273547a18b04d73584d7a8d283c099651","src/environ/dummy.rs":"0c05a77ab37a305c799f1b0e99c9debe1b8f59a3e3aa764e2fe39a923716b2ee","src/environ/mod.rs":"692f35d75f125f9c071f7166252f427e4bac29401356f73307c6c36e23c667fb","src/environ/spec.rs":"0f97fff3cc545772a1959f7d0439713fd7dc8d8adf43a2636f8174126dc1393c","src/func_translator.rs":"6af2fe6d71ab05aac84aaa7149bfb7be18f1ab056895bf9208a5fe0d502118c9","src/lib.rs":"7bdbcf638fa30fb05e8320439881f7536824f7f60a7db4f0c1b51ab369edf895","src/module_translator.rs":"1374fa56ca18a782083fa0f25f2ad675044a92bbf1a0a1cc44fcaf695807e044","src/sections_translator.rs":"11d65fd2e595e41f976e5c7d0df823f70449f79a9d2facbed61263616f8cfec1","src/state/func_state.rs":"581a5648b11fa07aef3cff0752597864c7cd44a4d44e27c50fc7349955b3fda3","src/state/mod.rs":"20014cb93615467b4d20321b52f67f66040417efcaa739a4804093bb559eed19","src/state/module_state.rs":"7ca3cb06b4481bc3ae74697fbcd437aea1d851eaa3cfe18cc013a4af43728957","src/translation_utils.rs":"69f20c47ea22f0badd21a6187b5f9764252a00d19643a7e3e691797a9fe34f1b","tests/wasm_testsuite.rs":"da8dedfd11918946e9cf6af68fd4826f020ef90a4e22742b1a30e61a3fb4aedd"},"package":null}

12
third_party/rust/cranelift-wasm/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "cranelift-wasm"
version = "0.66.0"
version = "0.67.0"
authors = ["The Cranelift Project Developers"]
description = "Translator from WebAssembly to Cranelift IR"
documentation = "https://docs.rs/cranelift-wasm"
@ -13,9 +13,9 @@ edition = "2018"
[dependencies]
wasmparser = { version = "0.59.0", default-features = false }
cranelift-codegen = { path = "../codegen", version = "0.66.0", default-features = false }
cranelift-entity = { path = "../entity", version = "0.66.0" }
cranelift-frontend = { path = "../frontend", version = "0.66.0", default-features = false }
cranelift-codegen = { path = "../codegen", version = "0.67.0", default-features = false }
cranelift-entity = { path = "../entity", version = "0.67.0" }
cranelift-frontend = { path = "../frontend", version = "0.67.0", default-features = false }
hashbrown = { version = "0.7", optional = true }
log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true }
@ -23,9 +23,9 @@ thiserror = "1.0.4"
[dev-dependencies]
wat = "1.0.23"
target-lexicon = "0.10"
target-lexicon = "0.11"
# Enable the riscv feature for cranelift-codegen, as some tests require it
cranelift-codegen = { path = "../codegen", version = "0.66.0", default-features = false, features = ["riscv"] }
cranelift-codegen = { path = "../codegen", version = "0.67.0", default-features = false, features = ["riscv"] }
[features]
default = ["std"]

Просмотреть файл

@ -14,7 +14,6 @@ use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
use cranelift_codegen::timing;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use log::info;
use wasmparser::{self, BinaryReader};
/// WebAssembly to Cranelift IR function translator.
@ -79,7 +78,7 @@ impl FuncTranslator {
environ: &mut FE,
) -> WasmResult<()> {
let _tt = timing::wasm_translate_function();
info!(
log::debug!(
"translate({} bytes, {}{})",
reader.bytes_remaining(),
func.name,

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.lock":"8e4587915716186b38c3e202791d595629d132256f27ad6869069bcac7e85253","Cargo.toml":"e3f845dc9dbe5f658993b69b09cd6ee8c4e00ef4dcc9fb083be2346f51effd04","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","a":"0063b040e749e5cc9c82e682c67c53ae1830500f0c4aa85507b1ca4ed8454886","build.rs":"85d6a1b6392b56946f48c0ff1526736a37fe012951bf3855709da1d6cfb4baa0","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","host.rs":"331a7217b0b5fae0d7c37bd6f5e8caa2762a220c51fb23f5cf354fa76d91974a","newlist":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","sorted.txt":"ea6d3912b5d1eba7be33e99f1dd45953d80863dad75c5fc0ed1cd8020373b974","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"89986c98b9a04e0f1e957e0127e23a53048a1f0d597493723c4bba031c2ca32d","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"f2048f06e3e2151a8181d8c92651fa45e64b8bfdfd18ead4b6c18ee7c9fb9003","src/triple.rs":"4704266fec8763bc70d230aad3608bdb790b51e41149056daa2ce0d5fdaef5a3","test.sh":"4458bbd0ece260fe335054b53caeb57d9022258d9a07b6b44b994f6ce2ca82c6"},"package":"ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"}
{"files":{"Cargo.lock":"764401bfb5ba50ed42c6b00274fd4444cefa31ef40183c224b11ed38abc2e68f","Cargo.toml":"d293a3613d3af95f1a0e49a08bb2c73ca0adf0ef375ffbdd4f7866c96500f0dc","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","build.rs":"03132c64805a8acee491ca7c40d090f20a53295967a442e08d9ab15acff9d076","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","scripts/rust-targets.sh":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","src/data_model.rs":"a33e047aadd048bc5846c97351df831d34fbd2321a6560dd71868875101ba3a8","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"2f4874d504386b0ace62e7089a114c8ee0426c2ff0ee293ee3af8c67b92e670b","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"0f6b07b3e7bc19e562c85a32a786cf9f551f8ea15ceef486bbd5c8cb28d11bb8","src/triple.rs":"da5705a96c6cd4cd03696ad9612e1a8a59cd9def59f16750149edbcdd1461fb4"},"package":"fe2635952a442a01fd4cb53d98858b5e4bb461b02c0d111f22f31772e3e7a8b2"}

2
third_party/rust/target-lexicon/Cargo.lock сгенерированный поставляемый
Просмотреть файл

@ -2,5 +2,5 @@
# It is not intended for manual editing.
[[package]]
name = "target-lexicon"
version = "0.10.0"
version = "0.11.0"

2
third_party/rust/target-lexicon/Cargo.toml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "target-lexicon"
version = "0.10.0"
version = "0.11.0"
authors = ["Dan Gohman <sunfish@mozilla.com>"]
description = "Targeting utilities for compilers and related tools"
documentation = "https://docs.rs/target-lexicon/"

59
third_party/rust/target-lexicon/a поставляемый
Просмотреть файл

@ -1,59 +0,0 @@
diff --git a/src/targets.rs b/src/targets.rs
index 6ae570e..3aa1044 100644
--- a/src/targets.rs
+++ b/src/targets.rs
@@ -1,6 +1,7 @@
// This file defines all the identifier enums and target-aware logic.
use crate::triple::{Endianness, PointerWidth, Triple};
+use alloc::string::String;
use core::fmt;
use core::str::FromStr;
@@ -292,7 +293,7 @@ impl Aarch64Architecture {
/// The "vendor" field, which in practice is little more than an arbitrary
/// modifier.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum Vendor {
Unknown,
@@ -306,6 +307,7 @@ pub enum Vendor {
Sun,
Uwp,
Wrs,
+ Custom(String),
}
/// The "operating system" field, which sometimes implies an environment, and
@@ -717,6 +719,7 @@ impl fmt::Display for Vendor {
Vendor::Sun => "sun",
Vendor::Uwp => "uwp",
Vendor::Wrs => "wrs",
+ Vendor::Custom(ref name) => name,
};
f.write_str(s)
}
@@ -738,7 +741,20 @@ impl FromStr for Vendor {
"sun" => Vendor::Sun,
"uwp" => Vendor::Uwp,
"wrs" => Vendor::Wrs,
- _ => return Err(()),
+ custom => {
+ use alloc::borrow::ToOwned;
+ if Architecture::from_str(custom).is_ok()
+ || OperatingSystem::from_str(custom).is_ok()
+ || Environment::from_str(custom).is_ok()
+ || BinaryFormat::from_str(custom).is_ok()
+ {
+ return Err(());
+ }
+ if custom.find(|c: char| !c.is_ascii_alphanumeric() && c != '_' && c != '.').is_some() {
+ return Err(());
+ }
+ Vendor::Custom(custom.to_owned())
+ }
})
}
}

46
third_party/rust/target-lexicon/build.rs поставляемый
Просмотреть файл

@ -12,6 +12,10 @@ use std::str::FromStr;
extern crate alloc;
// Include triple.rs and targets.rs so we can parse the TARGET environment variable.
// targets.rs depends on data_model
mod data_model {
include!("src/data_model.rs");
}
mod triple {
include!("src/triple.rs");
}
@ -39,7 +43,8 @@ fn main() {
let out_dir =
PathBuf::from(env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"));
let target = env::var("TARGET").expect("The TARGET environment variable must be set");
let triple = Triple::from_str(&target).expect(&format!("Invalid target name: '{}'", target));
let triple =
Triple::from_str(&target).unwrap_or_else(|_| panic!("Invalid target name: '{}'", target));
let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs");
write_host_rs(out, triple).expect("error writing host.rs");
}
@ -54,6 +59,16 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::ArmArchitecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::X86_32Architecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::Mips32Architecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::Mips64Architecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::Riscv32Architecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::Riscv64Architecture::*;")?;
writeln!(out, "#[allow(unused_imports)]")?;
writeln!(out, "use crate::CustomVendor;")?;
writeln!(out)?;
writeln!(out, "/// The `Triple` of the current host.")?;
@ -63,7 +78,11 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
" architecture: Architecture::{:?},",
triple.architecture
)?;
writeln!(out, " vendor: {},", vendor_display(&triple.vendor))?;
writeln!(
out,
" vendor: Vendor::{},",
vendor_display(&triple.vendor)
)?;
writeln!(
out,
" operating_system: OperatingSystem::{:?},",
@ -85,7 +104,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
writeln!(out, "impl Architecture {{")?;
writeln!(out, " /// Return the architecture for the current host.")?;
writeln!(out, " pub const fn host() -> Self {{")?;
writeln!(out, " Architecture::{:?}", triple.architecture)?;
writeln!(out, " Self::{:?}", triple.architecture)?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;
writeln!(out)?;
@ -93,7 +112,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
writeln!(out, "impl Vendor {{")?;
writeln!(out, " /// Return the vendor for the current host.")?;
writeln!(out, " pub const fn host() -> Self {{")?;
writeln!(out, " {}", vendor_display(&triple.vendor))?;
writeln!(out, " Self::{}", vendor_display(&triple.vendor))?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;
writeln!(out)?;
@ -104,11 +123,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
" /// Return the operating system for the current host."
)?;
writeln!(out, " pub const fn host() -> Self {{")?;
writeln!(
out,
" OperatingSystem::{:?}",
triple.operating_system
)?;
writeln!(out, " Self::{:?}", triple.operating_system)?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;
writeln!(out)?;
@ -116,7 +131,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
writeln!(out, "impl Environment {{")?;
writeln!(out, " /// Return the environment for the current host.")?;
writeln!(out, " pub const fn host() -> Self {{")?;
writeln!(out, " Environment::{:?}", triple.environment)?;
writeln!(out, " Self::{:?}", triple.environment)?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;
writeln!(out)?;
@ -127,7 +142,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
" /// Return the binary format for the current host."
)?;
writeln!(out, " pub const fn host() -> Self {{")?;
writeln!(out, " BinaryFormat::{:?}", triple.binary_format)?;
writeln!(out, " Self::{:?}", triple.binary_format)?;
writeln!(out, " }}")?;
writeln!(out, "}}")?;
writeln!(out)?;
@ -143,7 +158,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
)?;
writeln!(
out,
" vendor: {},",
" vendor: Vendor::{},",
vendor_display(&triple.vendor)
)?;
writeln!(
@ -170,10 +185,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
fn vendor_display(vendor: &Vendor) -> String {
match vendor {
Vendor::Custom(custom) => format!(
"Vendor::Custom(CustomVendor::Static({:?}))",
custom.as_str()
),
known => format!("Vendor::{:?}", known),
Vendor::Custom(custom) => format!("CustomVendor::Static({:?})", custom.as_str()),
known => format!("{:?}", known),
}
}

63
third_party/rust/target-lexicon/host.rs поставляемый
Просмотреть файл

@ -1,63 +0,0 @@
#[allow(unused_imports)]
use crate::Aarch64Architecture::*;
#[allow(unused_imports)]
use crate::ArmArchitecture::*;
#[allow(unused_imports)]
use crate::CustomVendor;
/// The `Triple` of the current host.
pub const HOST: Triple = Triple {
architecture: Architecture::Aarch64(Aarch64),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Linux,
environment: Environment::Gnu,
binary_format: BinaryFormat::Elf,
};
impl Architecture {
/// Return the architecture for the current host.
pub const fn host() -> Self {
Architecture::Aarch64(Aarch64)
}
}
impl Vendor {
/// Return the vendor for the current host.
pub const fn host() -> Self {
Vendor::Unknown
}
}
impl OperatingSystem {
/// Return the operating system for the current host.
pub const fn host() -> Self {
OperatingSystem::Linux
}
}
impl Environment {
/// Return the environment for the current host.
pub const fn host() -> Self {
Environment::Gnu
}
}
impl BinaryFormat {
/// Return the binary format for the current host.
pub const fn host() -> Self {
BinaryFormat::Elf
}
}
impl Triple {
/// Return the triple for the current host.
pub const fn host() -> Self {
Self {
architecture: Architecture::Aarch64(Aarch64),
vendor: Vendor::Unknown,
operating_system: OperatingSystem::Linux,
environment: Environment::Gnu,
binary_format: BinaryFormat::Elf,
}
}
}

Просмотреть файл

143
third_party/rust/target-lexicon/sorted.txt поставляемый
Просмотреть файл

@ -1,143 +0,0 @@
"aarch64-apple-ios",
"aarch64-fuchsia",
"aarch64-linux-android",
"aarch64-pc-windows-msvc",
"aarch64-unknown-cloudabi",
"aarch64-unknown-freebsd",
"aarch64-unknown-hermit",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-unknown-netbsd",
"aarch64-unknown-none",
"aarch64-unknown-none-softfloat",
"aarch64-unknown-openbsd",
"aarch64-unknown-redox",
"aarch64-uwp-windows-msvc",
"aarch64-wrs-vxworks",
"armebv7r-none-eabi",
"armebv7r-none-eabihf",
"arm-linux-androideabi",
"arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf",
"arm-unknown-linux-musleabi",
"arm-unknown-linux-musleabihf",
"armv4t-unknown-linux-gnueabi",
"armv5te-unknown-linux-gnueabi",
"armv5te-unknown-linux-musleabi",
"armv6-unknown-freebsd",
"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-freebsd",
"armv7-unknown-linux-gnueabi",
"armv7-unknown-linux-gnueabihf",
"armv7-unknown-linux-musleabi",
"armv7-unknown-linux-musleabihf",
"armv7-unknown-netbsd-eabihf",
"armv7-wrs-vxworks-eabihf",
"asmjs-unknown-emscripten",
"hexagon-unknown-linux-musl",
"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-cloudabi",
"i686-unknown-dragonfly",
"i686-unknown-freebsd",
"i686-unknown-haiku",
"i686-unknown-linux-gnu",
"i686-unknown-linux-musl",
"i686-unknown-netbsd",
"i686-unknown-openbsd",
"i686-unknown-uefi",
"i686-uwp-windows-gnu",
"i686-uwp-windows-msvc",
"i686-wrs-vxworks",
"mips64el-unknown-linux-gnuabi64",
"mips64el-unknown-linux-muslabi64",
"mips64-unknown-linux-gnuabi64",
"mips64-unknown-linux-muslabi64",
"mipsel-unknown-linux-gnu",
"mipsel-unknown-linux-musl",
"mipsel-unknown-linux-uclibc",
"mipsisa32r6el-unknown-linux-gnu",
"mipsisa32r6-unknown-linux-gnu",
"mipsisa64r6el-unknown-linux-gnuabi64",
"mipsisa64r6-unknown-linux-gnuabi64",
"mips-unknown-linux-gnu",
"mips-unknown-linux-musl",
"mips-unknown-linux-uclibc",
"msp430-none-elf",
"nvptx64-nvidia-cuda",
"powerpc64le-unknown-linux-gnu",
"powerpc64le-unknown-linux-musl",
"powerpc64-unknown-freebsd",
"powerpc64-unknown-linux-gnu",
"powerpc64-unknown-linux-musl",
"powerpc64-wrs-vxworks",
"powerpc-unknown-linux-gnu",
"powerpc-unknown-linux-gnuspe",
"powerpc-unknown-linux-musl",
"powerpc-unknown-netbsd",
"powerpc-wrs-vxworks",
"powerpc-wrs-vxworks-spe",
"riscv32imac-unknown-none-elf",
"riscv32imc-unknown-none-elf",
"riscv32i-unknown-none-elf",
"riscv64gc-unknown-none-elf",
"riscv64imac-unknown-none-elf",
"s390x-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"sparc64-unknown-netbsd",
"sparc64-unknown-openbsd",
"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",
"thumbv7neon-unknown-linux-musleabihf",
"thumbv8m.base-none-eabi",
"thumbv8m.main-none-eabi",
"thumbv8m.main-none-eabihf",
"wasm32-unknown-emscripten",
"wasm32-unknown-unknown",
"wasm32-wasi",
"x86_64-apple-darwin",
"x86_64-apple-ios",
"x86_64-fortanix-unknown-sgx",
"x86_64-fuchsia",
"x86_64-linux-android",
"x86_64-linux-kernel",
"x86_64-pc-solaris",
"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-dragonfly",
"x86_64-unknown-freebsd",
"x86_64-unknown-haiku",
"x86_64-unknown-hermit",
"x86_64-unknown-l4re-uclibc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-gnux32",
"x86_64-unknown-linux-musl",
"x86_64-unknown-netbsd",
"x86_64-unknown-openbsd",
"x86_64-unknown-redox",
"x86_64-unknown-uefi",
"x86_64-uwp-windows-gnu",
"x86_64-uwp-windows-msvc",
"x86_64-wrs-vxworks",

105
third_party/rust/target-lexicon/src/data_model.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,105 @@
/// The size of a type.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum Size {
U8,
U16,
U32,
U64,
}
impl Size {
/// Return the number of bits this `Size` represents.
pub fn bits(self) -> u8 {
match self {
Self::U8 => 8,
Self::U16 => 16,
Self::U32 => 32,
Self::U64 => 64,
}
}
/// Return the number of bytes in a size.
///
/// A byte is assumed to be 8 bits.
pub fn bytes(self) -> u8 {
match self {
Self::U8 => 1,
Self::U16 => 2,
Self::U32 => 4,
Self::U64 => 8,
}
}
}
/// The C data model used on a target.
///
/// See also https://en.cppreference.com/w/c/language/arithmetic_types
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum CDataModel {
/// The data model used most commonly on Win16. `long` and `pointer` are 32 bits.
LP32,
/// The data model used most commonly on Win32 and 32-bit Unix systems.
///
/// `int`, `long`, and `pointer` are all 32 bits.
ILP32,
/// The data model used most commonly on Win64
///
/// `long long`, and `pointer` are 64 bits.
LLP64,
/// The data model used most commonly on 64-bit Unix systems
///
/// `long`, and `pointer` are 64 bits.
LP64,
/// A rare data model used on early 64-bit Unix systems
///
/// `int`, `long`, and `pointer` are all 64 bits.
ILP64,
}
impl CDataModel {
/// The width of a pointer (in the default address space).
pub fn pointer_width(self) -> Size {
match self {
Self::LP32 | Self::ILP32 => Size::U32,
Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U64,
}
}
/// The size of a C `short`. This is required to be at least 16 bits.
pub fn short_size(self) -> Size {
match self {
Self::LP32 | Self::ILP32 | Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U16,
}
}
/// The size of a C `int`. This is required to be at least 16 bits.
pub fn int_size(self) -> Size {
match self {
Self::LP32 => Size::U16,
Self::ILP32 | Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U32,
}
}
/// The size of a C `long`. This is required to be at least 32 bits.
pub fn long_size(self) -> Size {
match self {
Self::LP32 | Self::ILP32 | Self::LLP64 | Self::ILP64 => Size::U32,
Self::LP64 => Size::U64,
}
}
/// The size of a C `long long`. This is required (in C99+) to be at least 64 bits.
pub fn long_long_size(self) -> Size {
match self {
Self::LP32 | Self::ILP32 | Self::LLP64 | Self::ILP64 | Self::LP64 => Size::U64,
}
}
/// The size of a C `float`.
pub fn float_size(self) -> Size {
// TODO: this is probably wrong on at least one architecture
Size::U32
}
/// The size of a C `double`.
pub fn double_size(self) -> Size {
// TODO: this is probably wrong on at least one architecture
Size::U64
}
}

27
third_party/rust/target-lexicon/src/lib.rs поставляемый
Просмотреть файл

@ -12,23 +12,46 @@
clippy::option_map_unwrap_or_else,
clippy::print_stdout,
clippy::unicode_not_nfc,
clippy::use_self
clippy::use_self,
)
)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod data_model;
mod host;
mod parse_error;
mod targets;
#[macro_use]
mod triple;
pub use self::data_model::{CDataModel, Size};
pub use self::host::HOST;
pub use self::parse_error::ParseError;
pub use self::targets::{
Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, CustomVendor, Environment,
OperatingSystem, Vendor,
Mips32Architecture, Mips64Architecture, OperatingSystem, Riscv32Architecture,
Riscv64Architecture, Vendor, X86_32Architecture,
};
pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple};
/// A simple wrapper around `Triple` that provides an implementation of
/// `Default` which defaults to `Triple::host()`.
pub struct DefaultToHost(pub Triple);
impl Default for DefaultToHost {
fn default() -> Self {
Self(Triple::host())
}
}
/// A simple wrapper around `Triple` that provides an implementation of
/// `Default` which defaults to `Triple::unknown()`.
pub struct DefaultToUnknown(pub Triple);
impl Default for DefaultToUnknown {
fn default() -> Self {
Self(Triple::unknown())
}
}

1153
third_party/rust/target-lexicon/src/targets.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

101
third_party/rust/target-lexicon/src/triple.rs поставляемый
Просмотреть файл

@ -1,5 +1,6 @@
// This file defines the `Triple` type and support code shared by all targets.
use crate::data_model::CDataModel;
use crate::parse_error::ParseError;
use crate::targets::{
default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment,
@ -30,9 +31,9 @@ impl PointerWidth {
/// Return the number of bits in a pointer.
pub fn bits(self) -> u8 {
match self {
PointerWidth::U16 => 16,
PointerWidth::U32 => 32,
PointerWidth::U64 => 64,
Self::U16 => 16,
Self::U32 => 32,
Self::U64 => 64,
}
}
@ -41,9 +42,9 @@ impl PointerWidth {
/// For these purposes, there are 8 bits in a byte.
pub fn bytes(self) -> u8 {
match self {
PointerWidth::U16 => 2,
PointerWidth::U32 => 4,
PointerWidth::U64 => 8,
Self::U16 => 2,
Self::U32 => 4,
Self::U64 => 8,
}
}
}
@ -51,7 +52,6 @@ impl PointerWidth {
/// The calling convention, which specifies things like which registers are
/// used for passing arguments, which registers are callee-saved, and so on.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum CallingConvention {
/// "System V", which is used on most Unix-like platfoms. Note that the
/// specific conventions vary between hardware architectures; for example,
@ -72,6 +72,10 @@ pub enum CallingConvention {
/// A target "triple". Historically such things had three fields, though they've
/// added additional fields over time.
///
/// Note that `Triple` doesn't implement `Default` itself. If you want a type
/// which defaults to the host triple, or defaults to unknown-unknown-unknown,
/// use `DefaultToHost` or `DefaultToUnknown`, respectively.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Triple {
/// The "architecture" (and sometimes the subarchitecture).
@ -108,6 +112,7 @@ impl Triple {
| OperatingSystem::Freebsd
| OperatingSystem::Fuchsia
| OperatingSystem::Haiku
| OperatingSystem::Hermit
| OperatingSystem::Ios
| OperatingSystem::L4re
| OperatingSystem::Linux
@ -127,10 +132,41 @@ impl Triple {
_ => return Err(()),
})
}
}
impl Default for Triple {
fn default() -> Self {
/// The C data model for a given target. If the model is not known, returns `Err(())`.
pub fn data_model(&self) -> Result<CDataModel, ()> {
match self.pointer_width()? {
PointerWidth::U64 => {
if self.operating_system == OperatingSystem::Windows {
Ok(CDataModel::LLP64)
} else if self.default_calling_convention() == Ok(CallingConvention::SystemV)
|| self.architecture == Architecture::Wasm64
{
Ok(CDataModel::LP64)
} else {
Err(())
}
}
PointerWidth::U32 => {
if self.operating_system == OperatingSystem::Windows
|| self.default_calling_convention() == Ok(CallingConvention::SystemV)
|| self.architecture == Architecture::Wasm32
{
Ok(CDataModel::ILP32)
} else {
Err(())
}
}
// TODO: on 16-bit machines there is usually a distinction
// between near-pointers and far-pointers.
// Additionally, code pointers sometimes have a different size than data pointers.
// We don't handle this case.
PointerWidth::U16 => Err(()),
}
}
/// Return a `Triple` with all unknown fields.
pub fn unknown() -> Self {
Self {
architecture: Architecture::Unknown,
vendor: Vendor::Unknown,
@ -141,36 +177,6 @@ impl Default for Triple {
}
}
impl Default for Architecture {
fn default() -> Self {
Architecture::Unknown
}
}
impl Default for Vendor {
fn default() -> Self {
Vendor::Unknown
}
}
impl Default for OperatingSystem {
fn default() -> Self {
OperatingSystem::Unknown
}
}
impl Default for Environment {
fn default() -> Self {
Environment::Unknown
}
}
impl Default for BinaryFormat {
fn default() -> Self {
BinaryFormat::Unknown
}
}
impl fmt::Display for Triple {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let implied_binary_format = default_binary_format(&self);
@ -185,6 +191,7 @@ impl fmt::Display for Triple {
|| self.operating_system == OperatingSystem::Wasi
|| (self.operating_system == OperatingSystem::None_
&& (self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r)
|| self.architecture == Architecture::Arm(ArmArchitecture::Armv7a)
|| self.architecture == Architecture::Arm(ArmArchitecture::Armv7r)
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m)
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em)
@ -218,7 +225,7 @@ impl FromStr for Triple {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split('-');
let mut result = Self::default();
let mut result = Self::unknown();
let mut current_part;
current_part = parts.next();
@ -344,22 +351,22 @@ mod tests {
fn defaults() {
assert_eq!(
Triple::from_str("unknown-unknown-unknown"),
Ok(Triple::default())
Ok(Triple::unknown())
);
assert_eq!(
Triple::from_str("unknown-unknown-unknown-unknown"),
Ok(Triple::default())
Ok(Triple::unknown())
);
assert_eq!(
Triple::from_str("unknown-unknown-unknown-unknown-unknown"),
Ok(Triple::default())
Ok(Triple::unknown())
);
}
#[test]
fn unknown_properties() {
assert_eq!(Triple::default().endianness(), Err(()));
assert_eq!(Triple::default().pointer_width(), Err(()));
assert_eq!(Triple::default().default_calling_convention(), Err(()));
assert_eq!(Triple::unknown().endianness(), Err(()));
assert_eq!(Triple::unknown().pointer_width(), Err(()));
assert_eq!(Triple::unknown().default_calling_convention(), Err(()));
}
}

12
third_party/rust/target-lexicon/test.sh поставляемый
Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
set -oeu pipefail
cargo clean
for trip in wasm32-unknown-unknown wasm32-wasi arm-unknown-linux-gnueabi aarch64-unknown-linux-gnu; do
echo TARGET $trip
cargo build --target $trip --all
cp target/$trip/debug/build/target-lexicon-*/out/host.rs host.rs
rustfmt host.rs
diff -u target/$trip/debug/build/target-lexicon-*/out/host.rs host.rs
done