diff --git a/.cargo/config b/.cargo/config index a5294781215ec..8fe3e4ea5def7 100644 --- a/.cargo/config +++ b/.cargo/config @@ -25,7 +25,7 @@ replace-with = "vendored-sources" [source."https://github.com/CraneStation/Cranelift"] git = "https://github.com/CraneStation/Cranelift" replace-with = "vendored-sources" -rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd" +rev = "bdfd2adc6e2052319d04d9400122c5b49939f404" [source.crates-io] replace-with = "vendored-sources" diff --git a/Cargo.lock b/Cargo.lock index 47ce2d0b964c6..8b1755d4ed8be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,12 +198,12 @@ name = "baldrdash" version = "0.1.0" dependencies = [ "bindgen 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", - "cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", + "cranelift-wasm 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -602,57 +602,59 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" dependencies = [ - "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", ] [[package]] name = "cranelift-codegen" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" dependencies = [ - "cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", - "cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", - "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-bforest 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", + "cranelift-codegen-meta 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", + "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" dependencies = [ - "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", ] [[package]] name = "cranelift-entity" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" [[package]] name = "cranelift-frontend" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" dependencies = [ - "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.40.0" -source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd" +version = "0.42.0" +source = "git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404#bdfd2adc6e2052319d04d9400122c5b49939f404" dependencies = [ - "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", - "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", - "cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)", + "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", + "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", + "cranelift-frontend 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -681,7 +683,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -736,7 +738,7 @@ dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1082,7 +1084,7 @@ name = "fallible" version = "0.0.1" dependencies = [ "hashglobe 0.1.0", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1200,7 +1202,7 @@ dependencies = [ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.21.0", "servo_arc 0.1.1", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "style_traits 0.0.1", "to_shmem 0.0.1", @@ -1698,7 +1700,7 @@ dependencies = [ "selectors 0.21.0", "servo_arc 0.1.1", "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2179,7 +2181,7 @@ dependencies = [ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] @@ -2735,7 +2737,7 @@ dependencies = [ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo_arc 0.1.1", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "to_shmem 0.0.1", "to_shmem_derive 0.0.1", @@ -2898,11 +2900,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.6" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2995,7 +2996,7 @@ dependencies = [ "selectors 0.21.0", "servo_arc 0.1.1", "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "static_prefs 0.1.0", "style_derive 0.0.1", "style_traits 0.0.1", @@ -3055,7 +3056,7 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.21.0", "size_of_test 0.0.1", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "style_traits 0.0.1", "to_shmem 0.0.1", @@ -3115,6 +3116,16 @@ dependencies = [ "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "target-lexicon" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempfile" version = "3.0.2" @@ -3212,7 +3223,7 @@ dependencies = [ "cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)", "servo_arc 0.1.1", "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3626,7 +3637,7 @@ dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "svg_fmt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3919,12 +3930,12 @@ dependencies = [ "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae" "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d" "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94" -"checksum cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" -"checksum cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" -"checksum cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" -"checksum cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" -"checksum cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" -"checksum cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "" +"checksum cranelift-bforest 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" +"checksum cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" +"checksum cranelift-codegen-meta 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" +"checksum cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" +"checksum cranelift-frontend 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" +"checksum cranelift-wasm 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=bdfd2adc6e2052319d04d9400122c5b49939f404)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8d4f5844607ce8da3fff431e7dba56cda8bfcc570aa50bee36adba8a32b8cad7" @@ -4131,7 +4142,7 @@ dependencies = [ "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1764fe2b30ee783bfe3b9b37b2649d8d590b3148bb12e0079715d4d5c673562e" -"checksum smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "622df2d454c29a4d89b30dc3b27b42d7d90d6b9e587dbf8f67652eb7514da484" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum socket2 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df028e0e632c2a1823d920ad74895e7f9128e6438cbc4bc6fd1f180e644767b9" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" @@ -4142,6 +4153,7 @@ dependencies = [ "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" +"checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" diff --git a/Cargo.toml b/Cargo.toml index d24ee342e6f8d..65eae85af6dd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,11 +63,11 @@ packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_ [patch.crates-io.cranelift-codegen] git = "https://github.com/CraneStation/Cranelift" -rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd" +rev = "bdfd2adc6e2052319d04d9400122c5b49939f404" [patch.crates-io.cranelift-wasm] git = "https://github.com/CraneStation/Cranelift" -rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd" +rev = "bdfd2adc6e2052319d04d9400122c5b49939f404" [patch.crates-io.coreaudio-sys] path = "third_party/rust/coreaudio-sys" diff --git a/js/src/wasm/cranelift/Cargo.toml b/js/src/wasm/cranelift/Cargo.toml index 90eba26b343eb..b3026571077f0 100644 --- a/js/src/wasm/cranelift/Cargo.toml +++ b/js/src/wasm/cranelift/Cargo.toml @@ -16,9 +16,9 @@ name = "baldrdash" # dependencies (codegen and wasm). # - $TOP_LEVEL/.cargo/config, look for the revision (rev) field of the # Cranelift source. -cranelift-codegen = { version = "0.40", default-features = false } -cranelift-wasm = "0.40" -target-lexicon = "0.4.0" +cranelift-codegen = { version = "0.42", default-features = false } +cranelift-wasm = "0.42" +target-lexicon = "0.8.0" log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] } env_logger = "0.5.6" smallvec = { version = "0.6.6" } diff --git a/third_party/rust/cranelift-bforest/.cargo-checksum.json b/third_party/rust/cranelift-bforest/.cargo-checksum.json index 824230b9c6bd4..c8d31b7866c96 100644 --- a/third_party/rust/cranelift-bforest/.cargo-checksum.json +++ b/third_party/rust/cranelift-bforest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"634224527723f126693a4d39db56a6d4923f74c83cfb557128efa4bd24f48f01","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"1b23abbfe5850a4cd77ae6ae5dcfc2f678ef36b4032fd7496f2b333c51e63301","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"5c0fac24938cd87403f8055d56082b820a284f40a45be73c0fcd63fad0704285","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"d821f2fe04df070a05a2e1de29b913f9970dfb500b35511a39c2976f1f26c977","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-bforest/Cargo.toml b/third_party/rust/cranelift-bforest/Cargo.toml index bd7cf337016ce..fee6d19b2e112 100644 --- a/third_party/rust/cranelift-bforest/Cargo.toml +++ b/third_party/rust/cranelift-bforest/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-bforest" -version = "0.40.0" +version = "0.42.0" description = "A forest of B+-trees" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" @@ -12,7 +12,7 @@ keywords = ["btree", "forest", "set", "map"] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift-entity", version = "0.40.0", default-features = false } +cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false } [features] default = ["std"] diff --git a/third_party/rust/cranelift-bforest/src/lib.rs b/third_party/rust/cranelift-bforest/src/lib.rs index 7b6beb2599097..5d33068b7aefc 100644 --- a/third_party/rust/cranelift-bforest/src/lib.rs +++ b/third_party/rust/cranelift-bforest/src/lib.rs @@ -32,7 +32,6 @@ ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(test)] #[cfg(not(feature = "std"))] diff --git a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json index 0ff3f9ddd38f9..254c919fec721 100644 --- a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json +++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2ef029c7de319de8f2007c17a7b5baeddd980f37b8cc84197bad5332f6c97d9a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"1c9bf45110e47710ea160f30b3f3b00b531a8d91ff365bae856dd9d44b928253","src/cdsl/cpu_modes.rs":"7c59ae347d6f9c769d6356fe49c8406934153eefa59d9bf37c182474fcbb9715","src/cdsl/encodings.rs":"da6fa16c95fe4a586c2d00ef4ccf79b4b0f64cd8923b3ca5a5a527da1e799a4f","src/cdsl/formats.rs":"811dcf12f6e9c5be72f18543675ff52c3996edd029064bd0643f878d2ceca3bd","src/cdsl/instructions.rs":"0e702c6d005ce209b46e9f883d02725acbc018bb90f8402c26c71b6bf61a42ed","src/cdsl/isa.rs":"9b6030a935f69b07726d239c23a78d654566785f1fed61ccefdaf7d4f0a97d0e","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"8a92798a92b2c34c5e572e03602454c72a896d31ac301f15f43d17c101d4da6e","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"695d4fd2720f43569a52f29998bd92562951f0b4e7844cc0a239640e0c7d0b0f","src/cdsl/types.rs":"3418eb1f5d77fd3ba586b089c0d77ee45f4e581b1a6e06ec4feeddd9d2589239","src/cdsl/typevar.rs":"c66b14b43baba2e7940b74ada263ab65455c2f46cc06de3990e88d790bb061d0","src/cdsl/xform.rs":"64e9b70ef1265c0331ee9d71c1a1f33dba3f6975b1639385c34d68456cda0e0e","src/constant_hash.rs":"66d6f42c1e98cd4dbc95009997dc00256b57c11d2c2d9eac63b33e458c68a56f","src/default_map.rs":"8bbd6f4d9f93ef2126538cda633e6d9c80a5c7dc79b8d5a759c8be1fe2dbc605","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"80c27e9c66d2ac3dc8a41cc545f046bd4297ba6530805539e86461984fd2667d","src/gen_encodings.rs":"9fb5ebe9a926ad7d45614c3bcfce0f0cadea3477f3e9bea45dfa63baf947e73f","src/gen_inst.rs":"e3a54b53f4a3d2d98474094d0d662c4ba66c594f876f68562e9ba6ddc2d71226","src/gen_legalizer.rs":"e02c9f49ba9fa2bb04dbf3137011d5457c187fbdffab971b0be01693c4b83a9b","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"765ca86fa735342c1875021c34a92cbc39836ba3ad1c12aa615204372a1f7b61","src/gen_types.rs":"c062eaf3a2ed7368b87213922906107bbaec184fe821184a34dacb4e5b0fc3dc","src/isa/arm32/mod.rs":"a2500871fb270e5624f5561f24fe510f08708cdca2ab1c3163848b67694f7a7a","src/isa/arm64/mod.rs":"dc210e8dc9f179d87d2c5a72d7795a9e34bb30afb91c8053c362d43635629d19","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/encodings.rs":"d53f80b2f166e19945c0c2c89a988a1b26d393f571212a09c5abcd9e694e4857","src/isa/riscv/mod.rs":"895492f0f379cfb02aba1cbb9759dc489bbb4d51ec40759af9f4d71c45c17a86","src/isa/riscv/recipes.rs":"8edffb212f1e5174c3e148a49311f2b7e2a1ac79a5b1ea9b641d4f88aa1c3040","src/isa/x86/encodings.rs":"9bdb43f7bb9d639f4cf073e3865a0ad03d98de45b91d637716365dc0c85abbd7","src/isa/x86/instructions.rs":"eea5fa7dd804d435dfdf289fc47f4bcc77db8dfce068d78d0a428155604b9626","src/isa/x86/legalize.rs":"192d7b9dc61e967165e43bc6da424316868a576b35aad2455c4465733c0d56b8","src/isa/x86/mod.rs":"6ed9f102238c1cb9029ec953e37629767438580cf9df8b4f2d1eace75ecd86fc","src/isa/x86/recipes.rs":"e3d6d95bc56c92c83985fd6f20415e04b5da89270ba6069e6d1410bc3c720d7a","src/isa/x86/registers.rs":"c0bc60336a8c8b7b4db92dc623e9419a60af14dd6252f0b19e227e46f7166178","src/isa/x86/settings.rs":"4e84ff135d6f21595bbd8f56d2e561abd3c123566f2332ac93bb4a9c627f0c00","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"80b8ff57a09c7b2f9dab755abbcc2738317de474776fe1de0d2a581310aa9af8","src/shared/formats.rs":"9c51381b531576c577a92abba9f825a8b60aaaedba53f39d2ea3be879987a466","src/shared/immediates.rs":"9a83d69734d06279bb20050c0f610caf06322d3cb11591cdd0ebf8724274b792","src/shared/instructions.rs":"029791f400bdb0cbdfa9d1ac544063d69c473e2ceecda3ab3e9b483579a53395","src/shared/legalize.rs":"1c32c28f603b11f89e1ba9c4d301b0b8036fd81254d227836202b84573a9a446","src/shared/mod.rs":"f5bb50d8292e46380afdd83a320cb5d6021e1483741e67b1e277053c28f9b943","src/shared/settings.rs":"e2696406c7c699e125fc629d6634c75cedf96ca76871fe4e9c0adbe03eead037","src/shared/types.rs":"9d08f21523867acb89d23ce6ac60681babb0a141068c0a54948491df6644a2f3","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e4a42edddd547e9aff7d2ccc3469f3685ae1eff54cece29d8f4fa1d2e80b063d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"7ff4532bb6c3c4570918cfac54c308f345d6710ad8696aa444503a60d42408a6","src/cdsl/cpu_modes.rs":"7c59ae347d6f9c769d6356fe49c8406934153eefa59d9bf37c182474fcbb9715","src/cdsl/encodings.rs":"da6fa16c95fe4a586c2d00ef4ccf79b4b0f64cd8923b3ca5a5a527da1e799a4f","src/cdsl/formats.rs":"5ed0d689b791d928e51f9608cb139dde7be810ff1dc4e03c58a6fe79e43eeffd","src/cdsl/instructions.rs":"434786da5caa0e28036467b9934e464faf5f5e3ccc7c876480b524065a192b73","src/cdsl/isa.rs":"9b6030a935f69b07726d239c23a78d654566785f1fed61ccefdaf7d4f0a97d0e","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"3e70d11c04a123c9d91075e14af6909a885f37a0c2f86df6aca1b337e2994763","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"c576403ca05921d6a416b21e7f5bd5a2219b635ad78ed1139dc8e3363ba61beb","src/cdsl/types.rs":"9f8221b5d3987b30943ba5f168190cb220b59350e9463ca264ecfd663dbbc3a2","src/cdsl/typevar.rs":"2b67b32524cdf783aeb1fcedbf82a33190104e87ed210ca0638cf6bb28eefd98","src/cdsl/xform.rs":"120be9a35b48d4b2c474bca9684c687797045d1d07554f639e1812cda16cc743","src/constant_hash.rs":"66d6f42c1e98cd4dbc95009997dc00256b57c11d2c2d9eac63b33e458c68a56f","src/default_map.rs":"8bbd6f4d9f93ef2126538cda633e6d9c80a5c7dc79b8d5a759c8be1fe2dbc605","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"80c27e9c66d2ac3dc8a41cc545f046bd4297ba6530805539e86461984fd2667d","src/gen_encodings.rs":"bb598d4eeb8e7365a023ebbb4cc0d8c9f57163b4d0d489047f0fcdbe83880adb","src/gen_inst.rs":"c31663699705cb35697dd23ee4f34d2502414a2d2f716b872e47aac1ba56e710","src/gen_legalizer.rs":"0e8ea0810da954d812f9110e900b9ba3830ff81be46c5985e0340e69f75ebbe8","src/gen_registers.rs":"9b581bd79a1370cdc6920ed18e8da84751813a4b1c9697e891bf0da4eceefc0d","src/gen_settings.rs":"765ca86fa735342c1875021c34a92cbc39836ba3ad1c12aa615204372a1f7b61","src/gen_types.rs":"c062eaf3a2ed7368b87213922906107bbaec184fe821184a34dacb4e5b0fc3dc","src/isa/arm32/mod.rs":"7669211d52caf53140521d2cbc4e5578fde7da6f669b49fdb80eb7c91ab6e226","src/isa/arm64/mod.rs":"a56c5cedd61bca1d2ad437537dd20a657c820b593d04af03d92ff48040eb399b","src/isa/mod.rs":"a728d5063d34a4ac572ad63ff0f458da33703c58cdd901a0c36276f426fbb0d1","src/isa/riscv/encodings.rs":"695159378a75cb143482c401c4e5ffefa28082cbb996e944942ef0cdc3d10db6","src/isa/riscv/mod.rs":"abf683b39a839ce1a52ed7ef83f6a513c62b1634970c45ffabe42b473bfe32df","src/isa/riscv/recipes.rs":"5cfdc71a3d5640de6ec956eb8eb6a3a85135daa1d6e30d1d6a693b6ad2d12e0e","src/isa/x86/encodings.rs":"355029f07b34d8bb9381de0017d9ffa963e7bfa78cf09abb5a0d9e0808718d76","src/isa/x86/instructions.rs":"c438579d98562e6efb67edf5983ffab26a3c7c2d8b20dccbd2667687031fa7f4","src/isa/x86/legalize.rs":"01bef630ed22396dca52112110d2146c8289b165c567590b73acf4e95274b054","src/isa/x86/mod.rs":"e43295be61d21b48a8605be5c913a676dd68d2988b4729b5d4ee3e4678ced558","src/isa/x86/recipes.rs":"383775f286f7a5183a47bc29ce32fed387bf2c9d5b7215827729cf512e535bfb","src/isa/x86/registers.rs":"3cde7d3275971d651ae0f25c88bfb81128b7a35183a969aed81776d4c5141e0e","src/isa/x86/settings.rs":"4e84ff135d6f21595bbd8f56d2e561abd3c123566f2332ac93bb4a9c627f0c00","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"d3dc9d6cb5ba30b1bbdcbfa4505e4897618064dab0b99006fd247d0c93f0b3dc","src/shared/formats.rs":"c6a4622fad932aadb7b5341aee5453c53ff08e0f1e1ee848752cf217fbce62b1","src/shared/immediates.rs":"954ef3c5724f26d16178fc2539111e5ecabebe9ea83d24b2b90d5a8ab411c1a9","src/shared/instructions.rs":"c8d32fec42df481c19ae9796ac1c24b9f8553d2019427d5afa70faffebde9356","src/shared/legalize.rs":"739b63e591413b95e144b854226ff13867000f66690dbcbea675a86290b6e84f","src/shared/mod.rs":"6c9010c934e85c668e089fded99805e9a3aa09a9d9ad408382c5345b6cb375b6","src/shared/settings.rs":"22825dd2b9d924ec147c675836ac3644adffd6a059c31b9470581c4597905c28","src/shared/types.rs":"b47799d381f3a554adcccf40824d83be56cd3ef08245c550ceff53363dfa7ad4","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-codegen-meta/Cargo.toml b/third_party/rust/cranelift-codegen-meta/Cargo.toml index 1d1fd894f9e72..c623493e30988 100644 --- a/third_party/rust/cranelift-codegen-meta/Cargo.toml +++ b/third_party/rust/cranelift-codegen-meta/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cranelift-codegen-meta" authors = ["The Cranelift Project Developers"] -version = "0.40.0" +version = "0.42.0" description = "Metaprogram for cranelift-codegen code generator library" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/CraneStation/cranelift" @@ -9,7 +9,7 @@ readme = "README.md" edition = "2018" [dependencies] -cranelift-entity = { path = "../../cranelift-entity", version = "0.40.0", default-features = false } +cranelift-entity = { path = "../../cranelift-entity", version = "0.42.0", default-features = false } [badges] maintenance = { status = "experimental" } diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs index 5e1c192f0fbbd..798ee29d00237 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs @@ -8,10 +8,10 @@ use cranelift_entity::{entity_impl, PrimaryMap}; use std::fmt; +#[derive(Debug)] pub enum Expr { Var(VarIndex), Literal(Literal), - Apply(Apply), } impl Expr { @@ -39,7 +39,6 @@ impl Expr { match self { Expr::Var(var_index) => var_pool.get(*var_index).to_rust_code(), Expr::Literal(literal) => literal.to_rust_code(), - Expr::Apply(a) => a.to_rust_code(var_pool), } } } @@ -81,9 +80,6 @@ impl DefPool { pub fn get(&self, index: DefIndex) -> &Def { self.pool.get(index).unwrap() } - pub fn get_mut(&mut self, index: DefIndex) -> &mut Def { - self.pool.get_mut(index).unwrap() - } pub fn next_index(&self) -> DefIndex { self.pool.next_key() } @@ -368,6 +364,7 @@ impl VarPool { /// /// An `Apply` AST expression is created by using function call syntax on instructions. This /// applies to both bound and unbound polymorphic instructions. +#[derive(Debug)] pub struct Apply { pub inst: Instruction, pub args: Vec, @@ -430,16 +427,6 @@ impl Apply { format!("{}({})", inst_name, args) } - fn to_rust_code(&self, var_pool: &VarPool) -> String { - let args = self - .args - .iter() - .map(|arg| arg.to_rust_code(var_pool)) - .collect::>() - .join(", "); - format!("{}({})", self.inst.name, args) - } - pub fn inst_predicate( &self, format_registry: &FormatRegistry, diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs index b716a8a976134..cf82da180a6ab 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/formats.rs @@ -12,9 +12,6 @@ use cranelift_entity::{entity_impl, PrimaryMap}; /// data type. #[derive(Debug)] pub struct FormatField { - /// Immediate operand number in parent. - immnum: usize, - /// Immediate operand kind. pub kind: OperandKind, @@ -53,7 +50,7 @@ pub struct InstructionFormat { impl fmt::Display for InstructionFormat { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let args = self + let imm_args = self .imm_fields .iter() .map(|field| format!("{}: {}", field.member, field.kind.name)) @@ -61,7 +58,7 @@ impl fmt::Display for InstructionFormat { .join(", "); fmt.write_fmt(format_args!( "{}(imms=({}), vals={})", - self.name, args, self.num_value_operands + self.name, imm_args, self.num_value_operands ))?; Ok(()) } @@ -89,27 +86,6 @@ pub struct InstructionFormatBuilder { typevar_operand: Option, } -pub struct ImmParameter { - kind: OperandKind, - member: &'static str, -} -impl Into for (&'static str, &OperandKind) { - fn into(self) -> ImmParameter { - ImmParameter { - kind: self.1.clone(), - member: self.0, - } - } -} -impl Into for &OperandKind { - fn into(self) -> ImmParameter { - ImmParameter { - kind: self.clone(), - member: self.default_member.unwrap(), - } - } -} - impl InstructionFormatBuilder { pub fn new(name: &'static str) -> Self { Self { @@ -131,12 +107,19 @@ impl InstructionFormatBuilder { self } - pub fn imm(mut self, param: impl Into) -> Self { - let imm_param = param.into(); + pub fn imm(mut self, operand_kind: &OperandKind) -> Self { + let field = FormatField { + kind: operand_kind.clone(), + member: operand_kind.default_member.unwrap(), + }; + self.imm_fields.push(field); + self + } + + pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self { let field = FormatField { - immnum: self.imm_fields.len(), - kind: imm_param.kind, - member: imm_param.member, + kind: operand_kind.clone(), + member, }; self.imm_fields.push(field); self @@ -201,7 +184,9 @@ impl FormatRegistry { if operand.is_value() { num_values += 1; } - has_varargs = has_varargs || operand.is_varargs(); + if !has_varargs { + has_varargs = operand.is_varargs(); + } if let Some(imm_key) = operand.kind.imm_key() { imm_keys.push(imm_key); } diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs index f31e530771c1a..f061be94ed008 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs @@ -4,7 +4,6 @@ use std::collections::HashMap; use std::fmt; use std::ops; use std::rc::Rc; -use std::slice; use crate::cdsl::camel_case; use crate::cdsl::formats::{ @@ -15,7 +14,7 @@ use crate::cdsl::type_inference::Constraint; use crate::cdsl::types::{LaneType, ReferenceType, ValueType, VectorType}; use crate::cdsl::typevar::TypeVar; -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct OpcodeNumber(u32); entity_impl!(OpcodeNumber); @@ -72,10 +71,6 @@ pub struct InstructionGroup { } impl InstructionGroup { - pub fn iter(&self) -> slice::Iter { - self.instructions.iter() - } - pub fn by_name(&self, name: &'static str) -> &Instruction { self.instructions .iter() @@ -84,12 +79,14 @@ impl InstructionGroup { } } +#[derive(Debug)] pub struct PolymorphicInfo { pub use_typevar_operand: bool, pub ctrl_typevar: TypeVar, pub other_typevars: Vec, } +#[derive(Debug)] pub struct InstructionContent { /// Instruction mnemonic, also becomes opcode name. pub name: String, @@ -113,9 +110,12 @@ pub struct InstructionContent { /// polymorphic, set otherwise. pub polymorphic_info: Option, + /// Indices in operands_in of input operands that are values. pub value_opnums: Vec, - pub value_results: Vec, + /// Indices in operands_in of input operands that are immediates or entities. pub imm_opnums: Vec, + /// Indices in operands_out of output operands that are values. + pub value_results: Vec, /// True for instructions that terminate the EBB. pub is_terminator: bool, @@ -141,7 +141,7 @@ pub struct InstructionContent { pub writes_cpu_flags: bool, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Instruction { content: Rc, } @@ -332,8 +332,6 @@ impl InstructionBuilder { let operands_in = self.operands_in.unwrap_or_else(Vec::new); let operands_out = self.operands_out.unwrap_or_else(Vec::new); - let format_index = format_registry.lookup(&operands_in); - let mut value_opnums = Vec::new(); let mut imm_opnums = Vec::new(); for (i, op) in operands_in.iter().enumerate() { @@ -346,13 +344,13 @@ impl InstructionBuilder { } } - let mut value_results = Vec::new(); - for (i, op) in operands_out.iter().enumerate() { - if op.is_value() { - value_results.push(i); - } - } + let value_results = operands_out + .iter() + .enumerate() + .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None }) + .collect(); + let format_index = format_registry.lookup(&operands_in); let format = format_registry.get(format_index); let polymorphic_info = verify_polymorphic(&operands_in, &operands_out, &format, &value_opnums); @@ -461,12 +459,8 @@ fn verify_polymorphic( } // Verify the use of type variables. - let mut use_typevar_operand = false; - let mut ctrl_typevar = None; - let mut other_typevars = None; - let mut maybe_error_message = None; - let tv_op = format.typevar_operand; + let mut maybe_error_message = None; if let Some(tv_op) = tv_op { if tv_op < value_opnums.len() { let op_num = value_opnums[tv_op]; @@ -475,11 +469,13 @@ fn verify_polymorphic( if (free_typevar.is_some() && tv == &free_typevar.unwrap()) || tv.singleton_type().is_some() { - match verify_ctrl_typevar(tv, &value_opnums, &operands_in, &operands_out) { - Ok(typevars) => { - other_typevars = Some(typevars); - ctrl_typevar = Some(tv.clone()); - use_typevar_operand = true; + match is_ctrl_typevar_candidate(tv, &operands_in, &operands_out) { + Ok(other_typevars) => { + return Some(PolymorphicInfo { + use_typevar_operand: true, + ctrl_typevar: tv.clone(), + other_typevars, + }); } Err(error_message) => { maybe_error_message = Some(error_message); @@ -489,33 +485,32 @@ fn verify_polymorphic( } }; - if !use_typevar_operand { - if operands_out.len() == 0 { - match maybe_error_message { - Some(msg) => panic!(msg), - None => panic!("typevar_operand must be a free type variable"), - } - } - - let tv = operands_out[0].type_var().unwrap(); - let free_typevar = tv.free_typevar(); - if free_typevar.is_some() && tv != &free_typevar.unwrap() { - panic!("first result must be a free type variable"); + // If we reached here, it means the type variable indicated as the typevar operand couldn't + // control every other input and output type variable. We need to look at the result type + // variables. + if operands_out.len() == 0 { + // No result means no other possible type variable, so it's a type inference failure. + match maybe_error_message { + Some(msg) => panic!(msg), + None => panic!("typevar_operand must be a free type variable"), } + } - other_typevars = - Some(verify_ctrl_typevar(tv, &value_opnums, &operands_in, &operands_out).unwrap()); - ctrl_typevar = Some(tv.clone()); + // Otherwise, try to infer the controlling type variable by looking at the first result. + let tv = operands_out[0].type_var().unwrap(); + let free_typevar = tv.free_typevar(); + if free_typevar.is_some() && tv != &free_typevar.unwrap() { + panic!("first result must be a free type variable"); } - // rustc is not capable to determine this statically, so enforce it with options. - assert!(ctrl_typevar.is_some()); - assert!(other_typevars.is_some()); + // At this point, if the next unwrap() fails, it means the output type couldn't be used as a + // controlling type variable either; panicking is the right behavior. + let other_typevars = is_ctrl_typevar_candidate(tv, &operands_in, &operands_out).unwrap(); Some(PolymorphicInfo { - use_typevar_operand, - ctrl_typevar: ctrl_typevar.unwrap(), - other_typevars: other_typevars.unwrap(), + use_typevar_operand: false, + ctrl_typevar: tv.clone(), + other_typevars, }) } @@ -527,57 +522,51 @@ fn verify_polymorphic( /// /// All polymorphic results must be derived from `ctrl_typevar`. /// -/// Return a vector of other type variables used, or panics. -fn verify_ctrl_typevar( +/// Return a vector of other type variables used, or a string explaining what went wrong. +fn is_ctrl_typevar_candidate( ctrl_typevar: &TypeVar, - value_opnums: &Vec, operands_in: &Vec, operands_out: &Vec, ) -> Result, String> { let mut other_typevars = Vec::new(); // Check value inputs. - for &op_num in value_opnums { - let typ = operands_in[op_num].type_var(); + for input in operands_in { + if !input.is_value() { + continue; + } - let tv = if let Some(typ) = typ { - typ.free_typevar() - } else { - None - }; + let typ = input.type_var().unwrap(); + let free_typevar = typ.free_typevar(); // Non-polymorphic or derived from ctrl_typevar is OK. - let tv = match tv { - Some(tv) => { - if &tv == ctrl_typevar { - continue; - } - tv - } - None => continue, - }; + if free_typevar.is_none() { + continue; + } + let free_typevar = free_typevar.unwrap(); + if &free_typevar == ctrl_typevar { + continue; + } // No other derived typevars allowed. - if typ.is_some() && typ.unwrap() != &tv { + if typ != &free_typevar { return Err(format!( - "{:?}: type variable {} must be derived from {:?}", - operands_in[op_num], - typ.unwrap().name, - ctrl_typevar + "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}", + input, typ.name, ctrl_typevar, free_typevar )); } // Other free type variables can only be used once each. for other_tv in &other_typevars { - if &tv == other_tv { + if &free_typevar == other_tv { return Err(format!( - "type variable {} can't be used more than once", - tv.name + "non-controlling type variable {} can't be used more than once", + free_typevar.name )); } } - other_typevars.push(tv); + other_typevars.push(free_typevar); } // Check outputs. @@ -587,10 +576,10 @@ fn verify_ctrl_typevar( } let typ = result.type_var().unwrap(); - let tv = typ.free_typevar(); + let free_typevar = typ.free_typevar(); - // Non-polymorphic or derived form ctrl_typevar is OK. - if tv.is_none() || &tv.unwrap() == ctrl_typevar { + // Non-polymorphic or derived from ctrl_typevar is OK. + if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar { continue; } @@ -1138,6 +1127,11 @@ fn bind_vector( mut value_types: Vec, ) -> BoundInstruction { let num_lanes = vector_size_in_bits / lane_type.lane_bits(); + assert!( + num_lanes >= 2, + "Minimum lane number for bind_vector is 2, found {}.", + num_lanes, + ); let vector_type = ValueType::Vector(VectorType::new(lane_type, num_lanes)); value_types.push(ValueTypeOrAny::ValueType(vector_type)); verify_polymorphic_binding(&inst, &value_types); diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs index 60bf8f581896b..920b1f5426501 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs @@ -11,6 +11,7 @@ pub struct RegBank { pub names: Vec<&'static str>, pub prefix: &'static str, pub pressure_tracking: bool, + pub pinned_reg: Option, pub toprcs: Vec, pub classes: Vec, } @@ -23,6 +24,7 @@ impl RegBank { names: Vec<&'static str>, prefix: &'static str, pressure_tracking: bool, + pinned_reg: Option, ) -> Self { RegBank { name, @@ -31,6 +33,7 @@ impl RegBank { names, prefix, pressure_tracking, + pinned_reg, toprcs: Vec::new(), classes: Vec::new(), } @@ -43,10 +46,26 @@ impl RegBank { // Try to match without the bank prefix. assert!(name.starts_with(self.prefix)); let name_without_prefix = &name[self.prefix.len()..]; - self.names + if let Some(found) = self + .names .iter() .position(|®_name| reg_name == name_without_prefix) - .expect(&format!("invalid register name {}", name)) + { + found + } else { + // Ultimate try: try to parse a number and use this in the array, eg r15 on x86. + if let Ok(as_num) = name_without_prefix.parse::() { + assert!( + (as_num - self.first_unit) < self.units, + "trying to get {}, but bank only has {} registers!", + name, + self.units + ); + (as_num - self.first_unit) as usize + } else { + panic!("invalid register name {}", name); + } + } }; self.first_unit + (unit as u8) } @@ -167,6 +186,7 @@ pub struct RegBankBuilder { pub names: Vec<&'static str>, pub prefix: &'static str, pub pressure_tracking: Option, + pub pinned_reg: Option, } impl RegBankBuilder { @@ -177,6 +197,7 @@ impl RegBankBuilder { names: vec![], prefix, pressure_tracking: None, + pinned_reg: None, } } pub fn units(mut self, units: u8) -> Self { @@ -191,6 +212,11 @@ impl RegBankBuilder { self.pressure_tracking = Some(track); self } + pub fn pinned_reg(mut self, unit: u16) -> Self { + assert!(unit < (self.units as u16)); + self.pinned_reg = Some(unit); + self + } } pub struct IsaRegsBuilder { @@ -230,6 +256,7 @@ impl IsaRegsBuilder { builder .pressure_tracking .expect("Pressure tracking must be explicitly set"), + builder.pinned_reg, )) } diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs index 101cfa4104db5..a56d81463c558 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs @@ -4,7 +4,7 @@ use crate::cdsl::typevar::{DerivedFunc, TypeSet, TypeVar}; use std::collections::{HashMap, HashSet}; use std::iter::FromIterator; -#[derive(Hash, PartialEq, Eq)] +#[derive(Debug, Hash, PartialEq, Eq)] pub enum Constraint { /// Constraint specifying that a type var tv1 must be wider than or equal to type var tv2 at /// runtime. This requires that: diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs index eba239d1d7098..92b9ab3a2feee 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs @@ -215,12 +215,14 @@ impl LaneType { LaneType::BoolType(shared_types::Bool::B16) => 2, LaneType::BoolType(shared_types::Bool::B32) => 3, LaneType::BoolType(shared_types::Bool::B64) => 4, - LaneType::IntType(shared_types::Int::I8) => 5, - LaneType::IntType(shared_types::Int::I16) => 6, - LaneType::IntType(shared_types::Int::I32) => 7, - LaneType::IntType(shared_types::Int::I64) => 8, - LaneType::FloatType(shared_types::Float::F32) => 9, - LaneType::FloatType(shared_types::Float::F64) => 10, + LaneType::BoolType(shared_types::Bool::B128) => 5, + LaneType::IntType(shared_types::Int::I8) => 6, + LaneType::IntType(shared_types::Int::I16) => 7, + LaneType::IntType(shared_types::Int::I32) => 8, + LaneType::IntType(shared_types::Int::I64) => 9, + LaneType::IntType(shared_types::Int::I128) => 10, + LaneType::FloatType(shared_types::Float::F32) => 11, + LaneType::FloatType(shared_types::Float::F64) => 12, } } @@ -231,6 +233,7 @@ impl LaneType { 16 => shared_types::Bool::B16, 32 => shared_types::Bool::B32, 64 => shared_types::Bool::B64, + 128 => shared_types::Bool::B128, _ => unreachable!("unxpected num bits for bool"), }) } @@ -241,6 +244,7 @@ impl LaneType { 16 => shared_types::Int::I16, 32 => shared_types::Int::I32, 64 => shared_types::Int::I64, + 128 => shared_types::Int::I128, _ => unreachable!("unxpected num bits for int"), }) } @@ -260,6 +264,27 @@ impl LaneType { ValueType::Vector(VectorType::new(*self, lanes.into())) } } + + pub fn is_float(&self) -> bool { + match self { + LaneType::FloatType(_) => true, + _ => false, + } + } + + pub fn is_int(&self) -> bool { + match self { + LaneType::IntType(_) => true, + _ => false, + } + } + + pub fn is_bool(&self) -> bool { + match self { + LaneType::BoolType(_) => true, + _ => false, + } + } } impl fmt::Display for LaneType { diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs index 9ae4c33fd8a6b..71c2fd2e292a6 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs @@ -9,7 +9,8 @@ use std::rc::Rc; use crate::cdsl::types::{BVType, LaneType, ReferenceType, SpecialType, ValueType}; const MAX_LANES: u16 = 256; -const MAX_BITS: u16 = 64; +const MAX_BITS: u16 = 128; +const MAX_FLOAT_BITS: u16 = 64; const MAX_BITVEC: u16 = MAX_BITS * MAX_LANES; /// Type variables can be used in place of concrete types when defining @@ -177,7 +178,7 @@ impl TypeVar { "can't double all integer types" ); assert!( - ts.floats.len() == 0 || *ts.floats.iter().max().unwrap() < MAX_BITS, + ts.floats.len() == 0 || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS, "can't double all float types" ); assert!( @@ -503,7 +504,7 @@ impl TypeSet { copy.floats = NumSet::from_iter( self.floats .iter() - .filter(|&&x| x < MAX_BITS) + .filter(|&&x| x < MAX_FLOAT_BITS) .map(|&x| x * 2), ); copy.bools = NumSet::from_iter( @@ -621,7 +622,7 @@ impl TypeSet { let mut copy = self.clone(); copy.bitvecs = NumSet::new(); if self.bools.contains(&1) { - copy.ints = NumSet::from_iter(vec![8, 16, 32, 64]); + copy.ints = NumSet::from_iter(vec![8, 16, 32, 64, 128]); copy.floats = NumSet::from_iter(vec![32, 64]); } else { copy.ints = &self.bools - &NumSet::from_iter(vec![1]); @@ -950,7 +951,7 @@ fn test_typevar_builder() { let type_set = TypeSetBuilder::new().ints(Interval::All).build(); assert_eq!(type_set.lanes, num_set![1]); assert!(type_set.floats.is_empty()); - assert_eq!(type_set.ints, num_set![8, 16, 32, 64]); + assert_eq!(type_set.ints, num_set![8, 16, 32, 64, 128]); assert!(type_set.bools.is_empty()); assert!(type_set.bitvecs.is_empty()); assert!(type_set.specials.is_empty()); @@ -959,7 +960,7 @@ fn test_typevar_builder() { assert_eq!(type_set.lanes, num_set![1]); assert!(type_set.floats.is_empty()); assert!(type_set.ints.is_empty()); - assert_eq!(type_set.bools, num_set![1, 8, 16, 32, 64]); + assert_eq!(type_set.bools, num_set![1, 8, 16, 32, 64, 128]); assert!(type_set.bitvecs.is_empty()); assert!(type_set.specials.is_empty()); @@ -1101,7 +1102,7 @@ fn test_forward_images() { ); assert_eq!( TypeSetBuilder::new().ints(32..64).build().double_width(), - TypeSetBuilder::new().ints(64..64).build() + TypeSetBuilder::new().ints(64..128).build() ); assert_eq!( TypeSetBuilder::new().floats(32..32).build().double_width(), @@ -1117,7 +1118,7 @@ fn test_forward_images() { ); assert_eq!( TypeSetBuilder::new().bools(32..64).build().double_width(), - TypeSetBuilder::new().bools(64..64).build() + TypeSetBuilder::new().bools(64..128).build() ); } @@ -1145,7 +1146,7 @@ fn test_backward_images() { assert_eq!( TypeSetBuilder::new() .simd_lanes(1..4) - .bools(1..64) + .bools(1..128) .build() .preimage(DerivedFunc::AsBool), TypeSetBuilder::new() @@ -1205,9 +1206,9 @@ fn test_backward_images() { // Half width. assert_eq!( TypeSetBuilder::new() - .ints(64..64) + .ints(128..128) .floats(64..64) - .bools(64..64) + .bools(128..128) .build() .preimage(DerivedFunc::HalfWidth) .size(), @@ -1221,7 +1222,7 @@ fn test_backward_images() { .preimage(DerivedFunc::HalfWidth), TypeSetBuilder::new() .simd_lanes(64..256) - .bools(16..64) + .bools(16..128) .build(), ); diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs index e988bf12ace11..b90d552b9a5b0 100644 --- a/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs +++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs @@ -183,7 +183,14 @@ fn rewrite_expr( assert_eq!( apply_target.inst().operands_in.len(), dummy_args.len(), - "number of arguments in instruction is incorrect" + "number of arguments in instruction {} is incorrect\nexpected: {:?}", + apply_target.inst().name, + apply_target + .inst() + .operands_in + .iter() + .map(|operand| format!("{}: {}", operand.name, operand.kind.name)) + .collect::>(), ); let mut args = Vec::new(); @@ -384,9 +391,6 @@ impl TransformGroups { pub fn get(&self, id: TransformGroupIndex) -> &TransformGroup { &self.groups[id] } - pub fn get_mut(&mut self, id: TransformGroupIndex) -> &mut TransformGroup { - self.groups.get_mut(id).unwrap() - } fn next_key(&self) -> TransformGroupIndex { self.groups.next_key() } diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs b/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs index 71fcf1700221a..cfaa63f087ee3 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs @@ -1126,7 +1126,7 @@ fn gen_isa(defs: &SharedDefinitions, isa: &TargetIsa, fmt: &mut Formatter) { fmt.line("};"); } -pub fn generate( +pub(crate) fn generate( defs: &SharedDefinitions, isa: &TargetIsa, filename: &str, diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs b/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs index 5dbb9dc09552c..7d8353dad312d 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs @@ -1059,7 +1059,7 @@ fn gen_builder(instructions: &AllInstructions, formats: &FormatRegistry, fmt: &m fmt.line("}"); } -pub fn generate( +pub(crate) fn generate( shared_defs: &SharedDefinitions, opcode_filename: &str, inst_builder_filename: &str, diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs b/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs index 7b59844e604fd..da1fb1f58f584 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs @@ -61,10 +61,10 @@ fn unwrap_inst( fmtln!(fmt, "{},", field.member); } - if iform.num_value_operands == 1 { - fmt.line("arg,"); - } else if iform.has_value_list || iform.num_value_operands > 1 { + if iform.has_value_list || iform.num_value_operands > 1 { fmt.line("ref args,"); + } else if iform.num_value_operands == 1 { + fmt.line("arg,"); } fmt.line(".."); @@ -87,6 +87,13 @@ fn unwrap_inst( } else if op.is_value() { let n = inst.value_opnums.iter().position(|&i| i == op_num).unwrap(); fmtln!(fmt, "func.dfg.resolve_aliases(args[{}]),", n); + } else if op.is_varargs() { + let n = inst.imm_opnums.iter().chain(inst.value_opnums.iter()).max().map(|n| n + 1).unwrap_or(0); + // We need to create a `Vec` here, as using a slice would result in a borrowck + // error later on. + fmtln!(fmt, "\ + args.iter().skip({}).map(|&arg| func.dfg.resolve_aliases(arg)).collect::>(),\ + ", n); } } @@ -104,6 +111,19 @@ fn unwrap_inst( }); fmtln!(fmt, "};"); + assert_eq!(inst.operands_in.len(), apply.args.len()); + for (i, op) in inst.operands_in.iter().enumerate() { + if op.is_varargs() { + let name = var_pool + .get(apply.args[i].maybe_var().expect("vararg without name")) + .name; + + // Above name is set to an `Vec` representing the varargs. However it is expected to be + // `&[Value]` below, so we borrow it. + fmtln!(fmt, "let {} = &{};", name, name); + } + } + for &op_num in &inst.value_opnums { let arg = &apply.args[op_num]; if let Some(var_index) = arg.maybe_var() { @@ -402,6 +422,13 @@ fn gen_transform<'a>( fmt.line("let removed = pos.remove_inst();"); fmt.line("debug_assert_eq!(removed, inst);"); } + + if transform.def_pool.get(transform.src).apply.inst.is_branch { + // A branch might have been legalized into multiple branches, so we need to recompute + // the cfg. + fmt.line("cfg.recompute_ebb(pos.func, pos.current_ebb().unwrap());"); + } + fmt.line("return true;"); }); fmt.line("}"); diff --git a/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs index 5e0fdac57beaa..08edfa9e21960 100644 --- a/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs +++ b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs @@ -56,6 +56,7 @@ fn gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter) { fmtln!(fmt, "first: {},", reg_bank.first_unit + reg_class.start); fmtln!(fmt, "subclasses: {:#x},", reg_class.subclass_mask()); fmtln!(fmt, "mask: [{}],", mask); + fmtln!(fmt, "pinned_reg: {:?},", reg_bank.pinned_reg); fmtln!(fmt, "info: &INFO,"); }); fmtln!(fmt, "};"); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs index d143a151638fe..fb41db25304a3 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs @@ -49,7 +49,7 @@ fn define_regs() -> IsaRegs { regs.build() } -pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { +pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { let settings = define_settings(&shared_defs.settings); let regs = define_regs(); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs index 195fc80ae6757..697e9513c5156 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs @@ -45,7 +45,7 @@ fn define_registers() -> IsaRegs { regs.build() } -pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { +pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { let settings = define_settings(&shared_defs.settings); let regs = define_registers(); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs index 0c2bb5eed0795..6c5ba13888dad 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs @@ -55,7 +55,7 @@ impl fmt::Display for Isa { } } -pub fn define(isas: &Vec, shared_defs: &mut SharedDefinitions) -> Vec { +pub(crate) fn define(isas: &Vec, shared_defs: &mut SharedDefinitions) -> Vec { isas.iter() .map(|isa| match isa { Isa::Riscv => riscv::define(shared_defs), diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs index a5af1214aa0b8..02a3bc7b61659 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs @@ -101,7 +101,7 @@ fn lui_bits() -> u16 { 0b01101 } -pub fn define<'defs>( +pub(crate) fn define<'defs>( shared_defs: &'defs SharedDefinitions, isa_settings: &SettingGroup, recipes: &'defs RecipeGroup, @@ -230,8 +230,7 @@ pub fn define<'defs>( -> InstructionPredicateNode { let x = var_pool.create("x"); let y = var_pool.create("y"); - let cc = - Literal::enumerator_for(shared_defs.operand_kinds.by_name("intcc"), intcc_field); + let cc = Literal::enumerator_for(&shared_defs.imm.intcc, intcc_field); Apply::new( bound_inst.clone().into(), vec![Expr::Literal(cc), Expr::Var(x), Expr::Var(y)], @@ -313,8 +312,7 @@ pub fn define<'defs>( let y = var_pool.create("y"); let dest = var_pool.create("dest"); let args = var_pool.create("args"); - let cc = - Literal::enumerator_for(shared_defs.operand_kinds.by_name("intcc"), intcc_field); + let cc = Literal::enumerator_for(&shared_defs.imm.intcc, intcc_field); Apply::new( bound_inst.clone().into(), vec![ diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs index 435b38eb34387..a2683b5a8b77e 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs @@ -85,7 +85,7 @@ fn define_registers() -> IsaRegs { regs.build() } -pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { +pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { let settings = define_settings(&shared_defs.settings); let regs = define_registers(); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/recipes.rs b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/recipes.rs index 40396b4ab3d8e..f32bbd568cf85 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/recipes.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/recipes.rs @@ -50,7 +50,7 @@ impl<'formats> RecipeGroup<'formats> { } } -pub fn define<'formats>( +pub(crate) fn define<'formats>( shared_defs: &'formats SharedDefinitions, regs: &IsaRegs, ) -> RecipeGroup<'formats> { diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs index a5df9298e8d81..d773c2c6622b2 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs @@ -4,12 +4,12 @@ use std::collections::HashMap; use crate::cdsl::encodings::{Encoding, EncodingBuilder}; use crate::cdsl::instructions::{ - BoundInstruction, InstSpec, Instruction, InstructionGroup, InstructionPredicate, - InstructionPredicateNode, InstructionPredicateRegistry, + InstSpec, Instruction, InstructionGroup, InstructionPredicate, InstructionPredicateNode, + InstructionPredicateRegistry, }; use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes}; use crate::cdsl::settings::{SettingGroup, SettingPredicateNumber}; -use crate::cdsl::types::ValueType; +use crate::cdsl::types::{LaneType, ValueType}; use crate::shared::types::Bool::{B1, B16, B32, B64, B8}; use crate::shared::types::Float::{F32, F64}; use crate::shared::types::Int::{I16, I32, I64, I8}; @@ -150,6 +150,16 @@ impl PerCpuModeEncodings { self.enc64(inst.bind(I64), template.rex().w()); } + /// Add encodings for `inst.i32` to X86_32. + /// Add encodings for `inst.i32` to X86_64 with a REX prefix. + /// Add encodings for `inst.i64` to X86_64 with a REX.W prefix. + fn enc_i32_i64_rex_only(&mut self, inst: impl Into, template: Template) { + let inst: InstSpec = inst.into(); + self.enc32(inst.bind(I32), template.nonrex()); + self.enc64(inst.bind(I32), template.rex()); + self.enc64(inst.bind(I64), template.rex().w()); + } + /// Add encodings for `inst.i32` to X86_32. /// Add encodings for `inst.i32` to X86_64 with and without REX. /// Add encodings for `inst.i64` to X86_64 with a REX.W prefix. @@ -177,16 +187,10 @@ impl PerCpuModeEncodings { } /// Add encodings for `inst.r32` to X86_32. - /// Add encodings for `inst.r32` to X86_64 with and without REX. /// Add encodings for `inst.r64` to X86_64 with a REX.W prefix. - fn enc_r32_r64(&mut self, inst: impl Into, template: Template) { + fn enc_r32_r64_rex_only(&mut self, inst: impl Into, template: Template) { let inst: InstSpec = inst.into(); self.enc32(inst.bind_ref(R32), template.nonrex()); - - // REX-less encoding must come after REX encoding so we don't use it by default. Otherwise - // reg-alloc would never use r8 and up. - self.enc64(inst.bind_ref(R32), template.rex()); - self.enc64(inst.bind_ref(R32), template.nonrex()); self.enc64(inst.bind_ref(R64), template.rex().w()); } @@ -230,7 +234,7 @@ impl PerCpuModeEncodings { } fn enc_both_isap( &mut self, - inst: BoundInstruction, + inst: impl Clone + Into, template: Template, isap: SettingPredicateNumber, ) { @@ -239,7 +243,7 @@ impl PerCpuModeEncodings { } fn enc_both_instp( &mut self, - inst: BoundInstruction, + inst: impl Clone + Into, template: Template, instp: InstructionPredicateNode, ) { @@ -247,6 +251,14 @@ impl PerCpuModeEncodings { self.enc_x86_64_instp(inst, template, instp); } + /// Add two encodings for `inst`: + /// - X86_32 + /// - X86_64 with the REX prefix. + fn enc_both_rex_only(&mut self, inst: impl Clone + Into, template: Template) { + self.enc32(inst.clone(), template.clone()); + self.enc64(inst, template.rex()); + } + /// Add encodings for `inst.i32` to X86_32. /// Add encodings for `inst.i32` to X86_64 with and without REX. /// Add encodings for `inst.i64` to X86_64 with a REX prefix, using the `w_bit` @@ -267,7 +279,19 @@ impl PerCpuModeEncodings { } } - /// Add the same encoding to both X86_32 and X86_64; assumes configuration (e.g. REX, operand binding) has already happened + /// Add the same encoding/recipe pairing to both X86_32 and X86_64 + fn enc_32_64_rec( + &mut self, + inst: impl Clone + Into, + recipe: &EncodingRecipe, + bits: u16, + ) { + self.enc32_rec(inst.clone(), recipe, bits); + self.enc64_rec(inst, recipe, bits); + } + + /// Add the same encoding to both X86_32 and X86_64; assumes configuration (e.g. REX, operand + /// binding) has already happened. fn enc_32_64_maybe_isap( &mut self, inst: impl Clone + Into, @@ -305,7 +329,7 @@ impl PerCpuModeEncodings { // Definitions. -pub fn define( +pub(crate) fn define( shared_defs: &SharedDefinitions, settings: &SettingGroup, x86: &InstructionGroup, @@ -343,7 +367,6 @@ pub fn define( let copy_to_ssa = shared.by_name("copy_to_ssa"); let ctz = shared.by_name("ctz"); let debugtrap = shared.by_name("debugtrap"); - let extractlane = shared.by_name("extractlane"); let f32const = shared.by_name("f32const"); let f64const = shared.by_name("f64const"); let fadd = shared.by_name("fadd"); @@ -359,7 +382,11 @@ pub fn define( let fpromote = shared.by_name("fpromote"); let fsub = shared.by_name("fsub"); let func_addr = shared.by_name("func_addr"); + let get_pinned_reg = shared.by_name("get_pinned_reg"); let iadd = shared.by_name("iadd"); + let iadd_cout = shared.by_name("iadd_cout"); + let iadd_cin = shared.by_name("iadd_cin"); + let iadd_carry = shared.by_name("iadd_carry"); let iadd_imm = shared.by_name("iadd_imm"); let icmp = shared.by_name("icmp"); let icmp_imm = shared.by_name("icmp_imm"); @@ -369,7 +396,6 @@ pub fn define( let ifcmp_sp = shared.by_name("ifcmp_sp"); let imul = shared.by_name("imul"); let indirect_jump_table_br = shared.by_name("indirect_jump_table_br"); - let insertlane = shared.by_name("insertlane"); let ireduce = shared.by_name("ireduce"); let ishl = shared.by_name("ishl"); let ishl_imm = shared.by_name("ishl_imm"); @@ -381,6 +407,9 @@ pub fn define( let istore8 = shared.by_name("istore8"); let istore8_complex = shared.by_name("istore8_complex"); let isub = shared.by_name("isub"); + let isub_bout = shared.by_name("isub_bout"); + let isub_bin = shared.by_name("isub_bin"); + let isub_borrow = shared.by_name("isub_borrow"); let jump = shared.by_name("jump"); let jump_table_base = shared.by_name("jump_table_base"); let jump_table_entry = shared.by_name("jump_table_entry"); @@ -402,6 +431,7 @@ pub fn define( let scalar_to_vector = shared.by_name("scalar_to_vector"); let selectif = shared.by_name("selectif"); let sextend = shared.by_name("sextend"); + let set_pinned_reg = shared.by_name("set_pinned_reg"); let sload16 = shared.by_name("sload16"); let sload16_complex = shared.by_name("sload16_complex"); let sload32 = shared.by_name("sload32"); @@ -438,7 +468,12 @@ pub fn define( let x86_cvtt2si = x86.by_name("x86_cvtt2si"); let x86_fmax = x86.by_name("x86_fmax"); let x86_fmin = x86.by_name("x86_fmin"); + let x86_insertps = x86.by_name("x86_insertps"); + let x86_movlhps = x86.by_name("x86_movlhps"); + let x86_movsd = x86.by_name("x86_movsd"); let x86_pop = x86.by_name("x86_pop"); + let x86_pextr = x86.by_name("x86_pextr"); + let x86_pinsr = x86.by_name("x86_pinsr"); let x86_pshufd = x86.by_name("x86_pshufd"); let x86_pshufb = x86.by_name("x86_pshufb"); let x86_push = x86.by_name("x86_push"); @@ -469,6 +504,7 @@ pub fn define( let rec_f64imm_z = r.template("f64imm_z"); let rec_fa = r.template("fa"); let rec_fax = r.template("fax"); + let rec_fa_ib = r.template("fa_ib"); let rec_fcmp = r.template("fcmp"); let rec_fcscc = r.template("fcscc"); let rec_ffillnull = r.recipe("ffillnull"); @@ -497,6 +533,7 @@ pub fn define( let rec_furm = r.template("furm"); let rec_furm_reg_to_ssa = r.template("furm_reg_to_ssa"); let rec_furmi_rnd = r.template("furmi_rnd"); + let rec_get_pinned_reg = r.recipe("get_pinned_reg"); let rec_got_fnaddr8 = r.template("got_fnaddr8"); let rec_got_gvaddr8 = r.template("got_gvaddr8"); let rec_gvaddr4 = r.template("gvaddr4"); @@ -544,10 +581,14 @@ pub fn define( let rec_rfurm = r.template("rfurm"); let rec_rmov = r.template("rmov"); let rec_rr = r.template("rr"); + let rec_rout = r.template("rout"); + let rec_rin = r.template("rin"); + let rec_rio = r.template("rio"); let rec_rrx = r.template("rrx"); let rec_safepoint = r.recipe("safepoint"); let rec_setf_abcd = r.template("setf_abcd"); let rec_seti_abcd = r.template("seti_abcd"); + let rec_set_pinned_reg = r.template("set_pinned_reg"); let rec_spaddr4_id = r.template("spaddr4_id"); let rec_spaddr8_id = r.template("spaddr8_id"); let rec_spillSib32 = r.template("spillSib32"); @@ -598,8 +639,23 @@ pub fn define( // Definitions. let mut e = PerCpuModeEncodings::new(); + // The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing! + e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0); + e.enc_x86_64( + set_pinned_reg.bind(I64), + rec_set_pinned_reg.opcodes(vec![0x89]).rex().w(), + ); + e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01])); + e.enc_i32_i64(iadd_cout, rec_rout.opcodes(vec![0x01])); + e.enc_i32_i64(iadd_cin, rec_rin.opcodes(vec![0x11])); + e.enc_i32_i64(iadd_carry, rec_rio.opcodes(vec![0x11])); + e.enc_i32_i64(isub, rec_rr.opcodes(vec![0x29])); + e.enc_i32_i64(isub_bout, rec_rout.opcodes(vec![0x29])); + e.enc_i32_i64(isub_bin, rec_rin.opcodes(vec![0x19])); + e.enc_i32_i64(isub_borrow, rec_rio.opcodes(vec![0x19])); + e.enc_i32_i64(band, rec_rr.opcodes(vec![0x21])); e.enc_i32_i64(bor, rec_rr.opcodes(vec![0x09])); e.enc_i32_i64(bxor, rec_rr.opcodes(vec![0x31])); @@ -622,7 +678,7 @@ pub fn define( e.enc_i32_i64(x86_umulx, rec_mulx.opcodes(vec![0xf7]).rrr(4)); e.enc_i32_i64(copy, rec_umr.opcodes(vec![0x89])); - e.enc_r32_r64(copy, rec_umr.opcodes(vec![0x89])); + e.enc_r32_r64_rex_only(copy, rec_umr.opcodes(vec![0x89])); e.enc_both(copy.bind(B1), rec_umr.opcodes(vec![0x89])); e.enc_both(copy.bind(I8), rec_umr.opcodes(vec![0x89])); e.enc_both(copy.bind(I16), rec_umr.opcodes(vec![0x89])); @@ -901,8 +957,8 @@ pub fn define( e.enc_i32_i64(spill, rec_spillSib32.opcodes(vec![0x89])); e.enc_i32_i64(regspill, rec_regspill32.opcodes(vec![0x89])); - e.enc_r32_r64(spill, rec_spillSib32.opcodes(vec![0x89])); - e.enc_r32_r64(regspill, rec_regspill32.opcodes(vec![0x89])); + e.enc_r32_r64_rex_only(spill, rec_spillSib32.opcodes(vec![0x89])); + e.enc_r32_r64_rex_only(regspill, rec_regspill32.opcodes(vec![0x89])); // Use a 32-bit write for spilling `b1`, `i8` and `i16` to avoid // constraining the permitted registers. @@ -927,8 +983,8 @@ pub fn define( e.enc_i32_i64(fill, rec_fillSib32.opcodes(vec![0x8b])); e.enc_i32_i64(regfill, rec_regfill32.opcodes(vec![0x8b])); - e.enc_r32_r64(fill, rec_fillSib32.opcodes(vec![0x8b])); - e.enc_r32_r64(regfill, rec_regfill32.opcodes(vec![0x8b])); + e.enc_r32_r64_rex_only(fill, rec_fillSib32.opcodes(vec![0x8b])); + e.enc_r32_r64_rex_only(regfill, rec_regfill32.opcodes(vec![0x8b])); // No-op fills, created by late-stage redundant-fill removal. for &ty in &[I64, I32, I16, I8] { @@ -964,20 +1020,22 @@ pub fn define( e.enc64(copy_special, rec_copysp.opcodes(vec![0x89]).rex().w()); e.enc32(copy_special, rec_copysp.opcodes(vec![0x89])); - // Copy to SSA - e.enc_i32_i64(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89])); - e.enc_r32_r64(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89])); - e.enc_both(copy_to_ssa.bind(B1), rec_umr_reg_to_ssa.opcodes(vec![0x89])); - e.enc_both(copy_to_ssa.bind(I8), rec_umr_reg_to_ssa.opcodes(vec![0x89])); - e.enc_both( + // Copy to SSA. These have to be done with special _rex_only encoders, because the standard + // machinery for deciding whether a REX.{RXB} prefix is needed doesn't take into account + // the source register, which is specified directly in the instruction. + e.enc_i32_i64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89])); + e.enc_r32_r64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89])); + e.enc_both_rex_only(copy_to_ssa.bind(B1), rec_umr_reg_to_ssa.opcodes(vec![0x89])); + e.enc_both_rex_only(copy_to_ssa.bind(I8), rec_umr_reg_to_ssa.opcodes(vec![0x89])); + e.enc_both_rex_only( copy_to_ssa.bind(I16), rec_umr_reg_to_ssa.opcodes(vec![0x89]), ); - e.enc_both( + e.enc_both_rex_only( copy_to_ssa.bind(F64), rec_furm_reg_to_ssa.opcodes(vec![0xf2, 0x0f, 0x10]), ); - e.enc_both( + e.enc_both_rex_only( copy_to_ssa.bind(F32), rec_furm_reg_to_ssa.opcodes(vec![0xf3, 0x0f, 0x10]), ); @@ -1686,14 +1744,17 @@ pub fn define( e.enc_both(ffcmp.bind(F32), rec_fcmp.opcodes(vec![0x0f, 0x2e])); e.enc_both(ffcmp.bind(F64), rec_fcmp.opcodes(vec![0x66, 0x0f, 0x2e])); - // SIMD vector size: eventually multiple vector sizes may be supported but for now only SSE-sized vectors are available + // SIMD vector size: eventually multiple vector sizes may be supported but for now only + // SSE-sized vectors are available. let sse_vector_size: u64 = 128; // SIMD splat: before x86 can use vector data, it must be moved to XMM registers; see // legalize.rs for how this is done; once there, x86_pshuf* (below) is used for broadcasting the - // value across the register + // value across the register. - // PSHUFB, 8-bit shuffle using two XMM registers + let allowed_simd_type = |t: &LaneType| t.lane_bits() >= 8 && t.lane_bits() < 128; + + // PSHUFB, 8-bit shuffle using two XMM registers. for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 8) { let instruction = x86_pshufb.bind_vector_from_lane(ty, sse_vector_size); let template = rec_fa.nonrex().opcodes(vec![0x66, 0x0f, 0x38, 00]); @@ -1701,7 +1762,7 @@ pub fn define( e.enc64_isap(instruction, template, use_ssse3_simd); } - // PSHUFD, 32-bit shuffle using one XMM register and a u8 immediate + // PSHUFD, 32-bit shuffle using one XMM register and a u8 immediate. for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 32) { let instruction = x86_pshufd.bind_vector_from_lane(ty, sse_vector_size); let template = rec_r_ib_unsigned_fpr @@ -1714,76 +1775,115 @@ pub fn define( // SIMD scalar_to_vector; this uses MOV to copy the scalar value to an XMM register; according // to the Intel manual: "When the destination operand is an XMM register, the source operand is // written to the low doubleword of the register and the regiser is zero-extended to 128 bits." - for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8) { - let instruction = scalar_to_vector - .bind_vector_from_lane(ty, sse_vector_size) - .bind(ty); - let template = rec_frurm.opcodes(vec![0x66, 0x0f, 0x6e]); // MOVD/MOVQ - if ty.lane_bits() < 64 { - // no 32-bit encodings for 64-bit widths - e.enc32(instruction.clone(), template.clone()); + for ty in ValueType::all_lane_types().filter(allowed_simd_type) { + let instruction = scalar_to_vector.bind_vector_from_lane(ty, sse_vector_size); + if ty.is_float() { + e.enc_32_64_rec(instruction, rec_null_fpr, 0); + } else { + let template = rec_frurm.opcodes(vec![0x66, 0x0f, 0x6e]); // MOVD/MOVQ + if ty.lane_bits() < 64 { + // no 32-bit encodings for 64-bit widths + e.enc32(instruction.clone(), template.clone()); + } + e.enc_x86_64(instruction, template); } - e.enc_x86_64(instruction, template); } // SIMD insertlane - let mut insertlane_mapping: HashMap, Option)> = + let mut x86_pinsr_mapping: HashMap, Option)> = HashMap::new(); - insertlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x20], Some(use_sse41_simd))); // PINSRB - insertlane_mapping.insert(16, (vec![0x66, 0x0f, 0xc4], None)); // PINSRW from SSE2 - insertlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRD - insertlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRQ, only x86_64 - - for ty in ValueType::all_lane_types() { - if let Some((opcode, isap)) = insertlane_mapping.get(&ty.lane_bits()) { - let instruction = insertlane.bind_vector_from_lane(ty, sse_vector_size); + x86_pinsr_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x20], Some(use_sse41_simd))); // PINSRB + x86_pinsr_mapping.insert(16, (vec![0x66, 0x0f, 0xc4], None)); // PINSRW from SSE2 + x86_pinsr_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRD + x86_pinsr_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRQ, only x86_64 + + for ty in ValueType::all_lane_types().filter(allowed_simd_type) { + if let Some((opcode, isap)) = x86_pinsr_mapping.get(&ty.lane_bits()) { + let instruction = x86_pinsr.bind_vector_from_lane(ty, sse_vector_size); let template = rec_r_ib_unsigned_r.opcodes(opcode.clone()); if ty.lane_bits() < 64 { e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone()); } else { - // turns out the 64-bit widths have REX/W encodings and only are available on x86_64 + // It turns out the 64-bit widths have REX/W encodings and only are available on + // x86_64. e.enc64_maybe_isap(instruction, template.rex().w(), isap.clone()); } } } + // For legalizing insertlane with floats, INSERTPS from SSE4.1. + { + let instruction = x86_insertps.bind_vector_from_lane(F32, sse_vector_size); + let template = rec_fa_ib.nonrex().opcodes(vec![0x66, 0x0f, 0x3a, 0x21]); + e.enc_32_64_maybe_isap(instruction, template, Some(use_sse41_simd)); + } + + // For legalizing insertlane with floats, MOVSD from SSE2. + { + let instruction = x86_movsd.bind_vector_from_lane(F64, sse_vector_size); + let template = rec_fa.nonrex().opcodes(vec![0xf2, 0x0f, 0x10]); + e.enc_32_64_maybe_isap(instruction, template, None); // from SSE2 + } + + // For legalizing insertlane with floats, MOVLHPS from SSE. + { + let instruction = x86_movlhps.bind_vector_from_lane(F64, sse_vector_size); + let template = rec_fa.nonrex().opcodes(vec![0x0f, 0x16]); + e.enc_32_64_maybe_isap(instruction, template, None); // from SSE + } + // SIMD extractlane - let mut extractlane_mapping: HashMap, Option)> = + let mut x86_pextr_mapping: HashMap, Option)> = HashMap::new(); - extractlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x14], Some(use_sse41_simd))); // PEXTRB - extractlane_mapping.insert(16, (vec![0x66, 0x0f, 0xc5], None)); // PEXTRW from zSSE2, SSE4.1 has a PEXTRW that can move to reg/m16 but the opcode is four bytes - extractlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRD - extractlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRQ, only x86_64 - - for ty in ValueType::all_lane_types() { - if let Some((opcode, isap)) = extractlane_mapping.get(&ty.lane_bits()) { - let instruction = extractlane.bind_vector_from_lane(ty, sse_vector_size); + x86_pextr_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x14], Some(use_sse41_simd))); // PEXTRB + x86_pextr_mapping.insert(16, (vec![0x66, 0x0f, 0xc5], None)); // PEXTRW from SSE2, SSE4.1 has a PEXTRW that can move to reg/m16 but the opcode is four bytes + x86_pextr_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRD + x86_pextr_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRQ, only x86_64 + + for ty in ValueType::all_lane_types().filter(allowed_simd_type) { + if let Some((opcode, isap)) = x86_pextr_mapping.get(&ty.lane_bits()) { + let instruction = x86_pextr.bind_vector_from_lane(ty, sse_vector_size); let template = rec_r_ib_unsigned_gpr.opcodes(opcode.clone()); if ty.lane_bits() < 64 { e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone()); } else { - // turns out the 64-bit widths have REX/W encodings and only are available on x86_64 + // It turns out the 64-bit widths have REX/W encodings and only are available on + // x86_64. e.enc64_maybe_isap(instruction, template.rex().w(), isap.clone()); } } } - // SIMD bitcast f64 to all 8-bit-lane vectors (for legalizing splat.x8x16); assumes that f64 is stored in an XMM register - for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 8) { - let instruction = bitcast.bind_vector_from_lane(ty, sse_vector_size).bind(F64); - e.enc32_rec(instruction.clone(), rec_null_fpr, 0); - e.enc64_rec(instruction, rec_null_fpr, 0); - } - - // SIMD bitcast all 128-bit vectors to each other (for legalizing splat.x16x8) - for from_type in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8) { - for to_type in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8 && *t != from_type) + // SIMD bitcast all 128-bit vectors to each other (for legalizing splat.x16x8). + for from_type in ValueType::all_lane_types().filter(allowed_simd_type) { + for to_type in + ValueType::all_lane_types().filter(|t| allowed_simd_type(t) && *t != from_type) { let instruction = raw_bitcast .bind_vector_from_lane(to_type, sse_vector_size) .bind_vector_from_lane(from_type, sse_vector_size); - e.enc32_rec(instruction.clone(), rec_null_fpr, 0); - e.enc64_rec(instruction, rec_null_fpr, 0); + e.enc_32_64_rec(instruction, rec_null_fpr, 0); + } + } + + // SIMD raw bitcast floats to vector (and back); assumes that floats are already stored in an + // XMM register. + for float_type in &[F32, F64] { + for lane_type in ValueType::all_lane_types().filter(allowed_simd_type) { + e.enc_32_64_rec( + raw_bitcast + .bind_vector_from_lane(lane_type, sse_vector_size) + .bind(*float_type), + rec_null_fpr, + 0, + ); + e.enc_32_64_rec( + raw_bitcast + .bind(*float_type) + .bind_vector_from_lane(lane_type, sse_vector_size), + rec_null_fpr, + 0, + ); } } @@ -1793,7 +1893,7 @@ pub fn define( // for that; alternately, constants could be loaded into XMM registers using a sequence like: // MOVQ + MOVHPD + MOVQ + MOVLPD (this allows the constants to be immediates instead of stored // in memory) but some performance measurements are needed. - for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8) { + for ty in ValueType::all_lane_types().filter(allowed_simd_type) { let instruction = vconst.bind_vector_from_lane(ty, sse_vector_size); let template = rec_vconst.nonrex().opcodes(vec![0x0f, 0x10]); e.enc_32_64_maybe_isap(instruction, template, None); // from SSE @@ -1808,7 +1908,7 @@ pub fn define( e.enc64(null.bind_ref(R64), rec_pu_id_ref.opcodes(vec![0xb8])); // is_null, implemented by testing whether the value is 0. - e.enc_r32_r64(is_null, rec_is_zero.opcodes(vec![0x85])); + e.enc_r32_r64_rex_only(is_null, rec_is_zero.opcodes(vec![0x85])); // safepoint instruction calls sink, no actual encoding. e.enc32_rec(safepoint, rec_safepoint, 0); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs index 64642619381f2..b9f2496a857c5 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/instructions.rs @@ -7,11 +7,13 @@ use crate::cdsl::instructions::{ use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc}; use crate::cdsl::types::ValueType; use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar}; -use crate::shared::{immediates, types, OperandKinds}; +use crate::shared::immediates::Immediates; +use crate::shared::types; -pub fn define( +pub(crate) fn define( mut all_instructions: &mut AllInstructions, format_registry: &FormatRegistry, + immediates: &Immediates, ) -> InstructionGroup { let mut ig = InstructionGroupBuilder::new( "x86", @@ -249,8 +251,7 @@ pub fn define( .operands_out(vec![y, rflags]), ); - let immediates = OperandKinds::from(immediates::define()); - let uimm8 = immediates.by_name("uimm8"); + let uimm8 = &immediates.uimm8; let TxN = &TypeVar::new( "TxN", "A SIMD vector type", @@ -290,5 +291,101 @@ pub fn define( .operands_out(vec![a]), ); + let Idx = &operand_doc("Idx", uimm8, "Lane index"); + let x = &operand("x", TxN); + let a = &operand("a", &TxN.lane_of()); + + ig.push( + Inst::new( + "x86_pextr", + r#" + Extract lane ``Idx`` from ``x``. + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. + "#, + ) + .operands_in(vec![x, Idx]) + .operands_out(vec![a]), + ); + + let IBxN = &TypeVar::new( + "IBxN", + "A SIMD vector type containing only booleans and integers", + TypeSetBuilder::new() + .ints(Interval::All) + .bools(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(), + ); + let x = &operand("x", IBxN); + let y = &operand_doc("y", &IBxN.lane_of(), "New lane value"); + let a = &operand("a", IBxN); + + ig.push( + Inst::new( + "x86_pinsr", + r#" + Insert ``y`` into ``x`` at lane ``Idx``. + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. + "#, + ) + .operands_in(vec![x, Idx, y]) + .operands_out(vec![a]), + ); + + let FxN = &TypeVar::new( + "FxN", + "A SIMD vector type containing floats", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(), + ); + let x = &operand("x", FxN); + let y = &operand_doc("y", &FxN.lane_of(), "New lane value"); + let a = &operand("a", FxN); + + ig.push( + Inst::new( + "x86_insertps", + r#" + Insert a lane of ``y`` into ``x`` at using ``Idx`` to encode both which lane the value is + extracted from and which it is inserted to. This is similar to x86_pinsr but inserts + floats, which are already stored in an XMM register. + "#, + ) + .operands_in(vec![x, Idx, y]) + .operands_out(vec![a]), + ); + + let x = &operand("x", FxN); + let y = &operand("y", FxN); + let a = &operand("a", FxN); + + ig.push( + Inst::new( + "x86_movsd", + r#" + Move the low 64 bits of the float vector ``y`` to the low 64 bits of float vector ``x`` + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]), + ); + + ig.push( + Inst::new( + "x86_movlhps", + r#" + Move the low 64 bits of the float vector ``y`` to the high 64 bits of float vector ``x`` + "#, + ) + .operands_in(vec![x, y]) + .operands_out(vec![a]), + ); + ig.build() } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs index a64f631168181..555a93f9cb689 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs @@ -6,7 +6,7 @@ use crate::shared::types::Float::F64; use crate::shared::types::Int::{I32, I64}; use crate::shared::Definitions as SharedDefinitions; -pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGroup) { +pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGroup) { let mut group = TransformGroupBuilder::new( "x86_expand", r#" @@ -20,10 +20,10 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou // List of instructions. let insts = &shared.instructions; let band = insts.by_name("band"); - let bitcast = insts.by_name("bitcast"); let bor = insts.by_name("bor"); let clz = insts.by_name("clz"); let ctz = insts.by_name("ctz"); + let extractlane = insts.by_name("extractlane"); let f64const = insts.by_name("f64const"); let fcmp = insts.by_name("fcmp"); let fcvt_from_uint = insts.by_name("fcvt_from_uint"); @@ -58,12 +58,7 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou let x86_umulx = x86_instructions.by_name("x86_umulx"); let x86_smulx = x86_instructions.by_name("x86_smulx"); - // List of immediates. - let floatcc = shared.operand_kinds.by_name("floatcc"); - let imm64 = shared.operand_kinds.by_name("imm64"); - let intcc = shared.operand_kinds.by_name("intcc"); - let uimm8 = shared.operand_kinds.by_name("uimm8"); - let ieee64 = shared.operand_kinds.by_name("ieee64"); + let imm = &shared.imm; // Division and remainder. // @@ -99,12 +94,12 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou // `ucomiss` or `ucomisd` instruction. The remaining codes need legalization // patterns. - let floatcc_eq = Literal::enumerator_for(floatcc, "eq"); - let floatcc_ord = Literal::enumerator_for(floatcc, "ord"); - let floatcc_ueq = Literal::enumerator_for(floatcc, "ueq"); - let floatcc_ne = Literal::enumerator_for(floatcc, "ne"); - let floatcc_uno = Literal::enumerator_for(floatcc, "uno"); - let floatcc_one = Literal::enumerator_for(floatcc, "one"); + let floatcc_eq = Literal::enumerator_for(&imm.floatcc, "eq"); + let floatcc_ord = Literal::enumerator_for(&imm.floatcc, "ord"); + let floatcc_ueq = Literal::enumerator_for(&imm.floatcc, "ueq"); + let floatcc_ne = Literal::enumerator_for(&imm.floatcc, "ne"); + let floatcc_uno = Literal::enumerator_for(&imm.floatcc, "uno"); + let floatcc_one = Literal::enumerator_for(&imm.floatcc, "one"); // Equality needs an explicit `ord` test which checks the parity bit. group.legalize( @@ -124,14 +119,14 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou ], ); - let floatcc_lt = &Literal::enumerator_for(floatcc, "lt"); - let floatcc_gt = &Literal::enumerator_for(floatcc, "gt"); - let floatcc_le = &Literal::enumerator_for(floatcc, "le"); - let floatcc_ge = &Literal::enumerator_for(floatcc, "ge"); - let floatcc_ugt = &Literal::enumerator_for(floatcc, "ugt"); - let floatcc_ult = &Literal::enumerator_for(floatcc, "ult"); - let floatcc_uge = &Literal::enumerator_for(floatcc, "uge"); - let floatcc_ule = &Literal::enumerator_for(floatcc, "ule"); + let floatcc_lt = &Literal::enumerator_for(&imm.floatcc, "lt"); + let floatcc_gt = &Literal::enumerator_for(&imm.floatcc, "gt"); + let floatcc_le = &Literal::enumerator_for(&imm.floatcc, "le"); + let floatcc_ge = &Literal::enumerator_for(&imm.floatcc, "ge"); + let floatcc_ugt = &Literal::enumerator_for(&imm.floatcc, "ugt"); + let floatcc_ult = &Literal::enumerator_for(&imm.floatcc, "ult"); + let floatcc_uge = &Literal::enumerator_for(&imm.floatcc, "uge"); + let floatcc_ule = &Literal::enumerator_for(&imm.floatcc, "ule"); // Inequalities that need to be reversed. for &(cc, rev_cc) in &[ @@ -165,9 +160,9 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou let r2flags = var("r2flags"); let index2 = var("index2"); - let intcc_eq = Literal::enumerator_for(intcc, "eq"); - let imm64_minus_one = Literal::constant(imm64, -1); - let imm64_63 = Literal::constant(imm64, 63); + let intcc_eq = Literal::enumerator_for(&imm.intcc, "eq"); + let imm64_minus_one = Literal::constant(&imm.imm64, -1); + let imm64_63 = Literal::constant(&imm.imm64, 63); group.legalize( def!(a = clz.I64(x)), vec![ @@ -179,7 +174,7 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou ], ); - let imm64_31 = Literal::constant(imm64, 31); + let imm64_31 = Literal::constant(&imm.imm64, 31); group.legalize( def!(a = clz.I32(x)), vec![ @@ -191,7 +186,7 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou ], ); - let imm64_64 = Literal::constant(imm64, 64); + let imm64_64 = Literal::constant(&imm.imm64, 64); group.legalize( def!(a = ctz.I64(x)), vec![ @@ -201,7 +196,7 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou ], ); - let imm64_32 = Literal::constant(imm64, 32); + let imm64_32 = Literal::constant(&imm.imm64, 32); group.legalize( def!(a = ctz.I32(x)), vec![ @@ -232,13 +227,13 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou let qc0F = var("qc0F"); let qc01 = var("qc01"); - let imm64_1 = Literal::constant(imm64, 1); - let imm64_4 = Literal::constant(imm64, 4); + let imm64_1 = Literal::constant(&imm.imm64, 1); + let imm64_4 = Literal::constant(&imm.imm64, 4); group.legalize( def!(qv16 = popcnt.I64(qv1)), vec![ def!(qv3 = ushr_imm(qv1, imm64_1)), - def!(qc77 = iconst(Literal::constant(imm64, 0x7777777777777777))), + def!(qc77 = iconst(Literal::constant(&imm.imm64, 0x7777777777777777))), def!(qv4 = band(qv3, qc77)), def!(qv5 = isub(qv1, qv4)), def!(qv6 = ushr_imm(qv4, imm64_1)), @@ -249,11 +244,11 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou def!(qv11 = isub(qv8, qv10)), def!(qv12 = ushr_imm(qv11, imm64_4)), def!(qv13 = iadd(qv11, qv12)), - def!(qc0F = iconst(Literal::constant(imm64, 0x0F0F0F0F0F0F0F0F))), + def!(qc0F = iconst(Literal::constant(&imm.imm64, 0x0F0F0F0F0F0F0F0F))), def!(qv14 = band(qv13, qc0F)), - def!(qc01 = iconst(Literal::constant(imm64, 0x0101010101010101))), + def!(qc01 = iconst(Literal::constant(&imm.imm64, 0x0101010101010101))), def!(qv15 = imul(qv14, qc01)), - def!(qv16 = ushr_imm(qv15, Literal::constant(imm64, 56))), + def!(qv16 = ushr_imm(qv15, Literal::constant(&imm.imm64, 56))), ], ); @@ -281,7 +276,7 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou def!(lv16 = popcnt.I32(lv1)), vec![ def!(lv3 = ushr_imm(lv1, imm64_1)), - def!(lc77 = iconst(Literal::constant(imm64, 0x77777777))), + def!(lc77 = iconst(Literal::constant(&imm.imm64, 0x77777777))), def!(lv4 = band(lv3, lc77)), def!(lv5 = isub(lv1, lv4)), def!(lv6 = ushr_imm(lv4, imm64_1)), @@ -292,11 +287,11 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou def!(lv11 = isub(lv8, lv10)), def!(lv12 = ushr_imm(lv11, imm64_4)), def!(lv13 = iadd(lv11, lv12)), - def!(lc0F = iconst(Literal::constant(imm64, 0x0F0F0F0F))), + def!(lc0F = iconst(Literal::constant(&imm.imm64, 0x0F0F0F0F))), def!(lv14 = band(lv13, lc0F)), - def!(lc01 = iconst(Literal::constant(imm64, 0x01010101))), + def!(lc01 = iconst(Literal::constant(&imm.imm64, 0x01010101))), def!(lv15 = imul(lv14, lc01)), - def!(lv16 = ushr_imm(lv15, Literal::constant(imm64, 24))), + def!(lv16 = ushr_imm(lv15, Literal::constant(&imm.imm64, 24))), ], ); @@ -313,9 +308,9 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou .chain_with(shared.transform_groups.by_name("narrow").id); // SIMD - let uimm8_zero = Literal::constant(uimm8, 0x00); - let uimm8_one = Literal::constant(uimm8, 0x01); - let ieee64_zero = Literal::constant(ieee64, 0x00); + let uimm8_zero = Literal::constant(&imm.uimm8, 0x00); + let uimm8_one = Literal::constant(&imm.uimm8, 0x01); + let ieee64_zero = Literal::constant(&imm.ieee64, 0x00); let b = var("b"); let c = var("c"); let d = var("d"); @@ -326,7 +321,9 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou // SIMD splat: 8-bits for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 8) { let splat_any8x16 = splat.bind_vector_from_lane(ty, sse_vector_size); - let bitcast_f64_to_any8x16 = bitcast.bind_vector_from_lane(ty, sse_vector_size).bind(F64); + let bitcast_f64_to_any8x16 = raw_bitcast + .bind_vector_from_lane(ty, sse_vector_size) + .bind(F64); narrow.legalize( def!(y = splat_any8x16(x)), vec![ @@ -383,5 +380,8 @@ pub fn define(shared: &mut SharedDefinitions, x86_instructions: &InstructionGrou ); } + narrow.custom_legalize(extractlane, "convert_extractlane"); + narrow.custom_legalize(insertlane, "convert_insertlane"); + narrow.build_and_add_to(&mut shared.transform_groups); } diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs index 9f4a4a334a62a..10baf256a901b 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs @@ -13,13 +13,14 @@ mod recipes; mod registers; mod settings; -pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { +pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { let settings = settings::define(&shared_defs.settings); let regs = registers::define(); let inst_group = instructions::define( &mut shared_defs.all_instructions, &shared_defs.format_registry, + &shared_defs.imm, ); legalize::define(shared_defs, &inst_group); diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs index d12658080461f..8176effc42c75 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs @@ -325,14 +325,14 @@ fn valid_scale(format: &InstructionFormat) -> InstructionPredicate { }) } -pub fn define<'shared>( +pub(crate) fn define<'shared>( shared_defs: &'shared SharedDefinitions, settings: &'shared SettingGroup, regs: &'shared IsaRegs, ) -> RecipeGroup<'shared> { // The set of floating point condition codes that are directly supported. // Other condition codes need to be reversed or expressed as two tests. - let floatcc = shared_defs.operand_kinds.by_name("floatcc"); + let floatcc = &shared_defs.imm.floatcc; let supported_floatccs: Vec = ["ord", "uno", "one", "ueq", "gt", "ge", "ult", "ule"] .iter() .map(|name| Literal::enumerator_for(floatcc, name)) @@ -351,6 +351,7 @@ pub fn define<'shared>( let reg_rax = Register::new(gpr, regs.regunit_by_name(gpr, "rax")); let reg_rcx = Register::new(gpr, regs.regunit_by_name(gpr, "rcx")); let reg_rdx = Register::new(gpr, regs.regunit_by_name(gpr, "rdx")); + let reg_r15 = Register::new(gpr, regs.regunit_by_name(gpr, "r15")); // Stack operand with a 32-bit signed displacement from either RBP or RSP. let stack_gpr32 = Stack::new(gpr); @@ -428,6 +429,25 @@ pub fn define<'shared>( .emit(""), ); + recipes.add_recipe( + EncodingRecipeBuilder::new("get_pinned_reg", f_nullary, 0) + .operands_out(vec![reg_r15]) + .emit(""), + ); + // umr with a fixed register output that's r15. + recipes.add_template_recipe( + EncodingRecipeBuilder::new("set_pinned_reg", f_unary, 1) + .operands_in(vec![gpr]) + .clobbers_flags(false) + .emit( + r#" + let r15 = RU::r15.into(); + {{PUT_OP}}(bits, rex2(r15, in_reg0), sink); + modrm_rr(r15, in_reg0, sink); + "#, + ), + ); + // No-op fills, created by late-stage redundant-fill removal. recipes.add_recipe( EncodingRecipeBuilder::new("fillnull", f_unary, 0) @@ -546,6 +566,27 @@ pub fn define<'shared>( ), ); + // XX /r with FPR ins and outs. A form with a byte immediate. + { + let format = formats.get(f_insert_lane); + recipes.add_template_recipe( + EncodingRecipeBuilder::new("fa_ib", f_insert_lane, 2) + .operands_in(vec![fpr, fpr]) + .operands_out(vec![0]) + .inst_predicate(InstructionPredicate::new_is_unsigned_int( + format, "lane", 8, 0, + )) + .emit( + r#" + {{PUT_OP}}(bits, rex2(in_reg1, in_reg0), sink); + modrm_rr(in_reg1, in_reg0, sink); + let imm:i64 = lane.into(); + sink.put1(imm as u8); + "#, + ), + ); + } + // XX /n for a unary operation with extension bits. recipes.add_template_recipe( EncodingRecipeBuilder::new("ur", f_unary, 1) @@ -2528,6 +2569,64 @@ pub fn define<'shared>( ), ); + // Arithematic with flag I/O. + + // XX /r, MR form. Add two GPR registers and set carry flag. + recipes.add_template_recipe( + EncodingRecipeBuilder::new("rout", f_binary, 1) + .operands_in(vec![gpr, gpr]) + .operands_out(vec![ + OperandConstraint::TiedInput(0), + OperandConstraint::FixedReg(reg_rflags), + ]) + .clobbers_flags(true) + .emit( + r#" + {{PUT_OP}}(bits, rex2(in_reg0, in_reg1), sink); + modrm_rr(in_reg0, in_reg1, sink); + "#, + ), + ); + + // XX /r, MR form. Add two GPR registers and get carry flag. + recipes.add_template_recipe( + EncodingRecipeBuilder::new("rin", f_ternary, 1) + .operands_in(vec![ + OperandConstraint::RegClass(gpr), + OperandConstraint::RegClass(gpr), + OperandConstraint::FixedReg(reg_rflags), + ]) + .operands_out(vec![0]) + .clobbers_flags(true) + .emit( + r#" + {{PUT_OP}}(bits, rex2(in_reg0, in_reg1), sink); + modrm_rr(in_reg0, in_reg1, sink); + "#, + ), + ); + + // XX /r, MR form. Add two GPR registers with carry flag. + recipes.add_template_recipe( + EncodingRecipeBuilder::new("rio", f_ternary, 1) + .operands_in(vec![ + OperandConstraint::RegClass(gpr), + OperandConstraint::RegClass(gpr), + OperandConstraint::FixedReg(reg_rflags), + ]) + .operands_out(vec![ + OperandConstraint::TiedInput(0), + OperandConstraint::FixedReg(reg_rflags), + ]) + .clobbers_flags(true) + .emit( + r#" + {{PUT_OP}}(bits, rex2(in_reg0, in_reg1), sink); + modrm_rr(in_reg0, in_reg1, sink); + "#, + ), + ); + // Compare and set flags. // XX /r, MR form. Compare two GPR registers and set flags. diff --git a/third_party/rust/cranelift-codegen-meta/src/isa/x86/registers.rs b/third_party/rust/cranelift-codegen-meta/src/isa/x86/registers.rs index 3039bafba2322..4157084c15957 100644 --- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/registers.rs +++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/registers.rs @@ -6,7 +6,8 @@ pub fn define() -> IsaRegs { let builder = RegBankBuilder::new("IntRegs", "r") .units(16) .names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"]) - .track_pressure(true); + .track_pressure(true) + .pinned_reg(15); let int_regs = regs.add_bank(builder); let builder = RegBankBuilder::new("FloatRegs", "xmm") diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs b/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs index 358ef8f23e34f..910722789ba26 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/entities.rs @@ -1,65 +1,76 @@ use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder, OperandKindFields}; +pub struct EntityRefs { + /// A reference to an extended basic block in the same function. + /// This is primarliy used in control flow instructions. + pub ebb: OperandKind, + + /// A reference to a stack slot declared in the function preamble. + pub stack_slot: OperandKind, + + /// A reference to a global value. + pub global_value: OperandKind, + + /// A reference to a function signature declared in the function preamble. + /// This is used to provide the call signature in a call_indirect instruction. + pub sig_ref: OperandKind, + + /// A reference to an external function declared in the function preamble. + /// This is used to provide the callee and signature in a call instruction. + pub func_ref: OperandKind, + + /// A reference to a jump table declared in the function preamble. + pub jump_table: OperandKind, + + /// A reference to a heap declared in the function preamble. + pub heap: OperandKind, + + /// A reference to a table declared in the function preamble. + pub table: OperandKind, + + /// A variable-sized list of value operands. Use for Ebb and function call arguments. + pub varargs: OperandKind, +} + +impl EntityRefs { + pub fn new() -> Self { + Self { + ebb: create("ebb", "An extended basic block in the same function.") + .default_member("destination") + .build(), + + stack_slot: create("stack_slot", "A stack slot").build(), + + global_value: create("global_value", "A global value.").build(), + + sig_ref: create("sig_ref", "A function signature.").build(), + + func_ref: create("func_ref", "An external function.").build(), + + jump_table: create("jump_table", "A jump table.") + .default_member("table") + .build(), + + heap: create("heap", "A heap.").build(), + + table: create("table", "A table.").build(), + + varargs: Builder::new("variable_args", OperandKindFields::VariableArgs) + .doc( + r#" + A variable size list of `value` operands. + + Use this to represent arguments passed to a function call, arguments + passed to an extended basic block, or a variable number of results + returned from an instruction. + "#, + ) + .build(), + } + } +} + /// Small helper to initialize an OperandBuilder with the right kind, for a given name and doc. fn create(name: &'static str, doc: &'static str) -> Builder { Builder::new(name, OperandKindFields::EntityRef).doc(doc) } - -pub fn define() -> Vec { - let mut kinds = Vec::new(); - - // A reference to an extended basic block in the same function. - // This is primarliy used in control flow instructions. - let ebb = create("ebb", "An extended basic block in the same function.") - .default_member("destination") - .build(); - kinds.push(ebb); - - // A reference to a stack slot declared in the function preamble. - let stack_slot = create("stack_slot", "A stack slot").build(); - kinds.push(stack_slot); - - // A reference to a global value. - let global_value = create("global_value", "A global value.").build(); - kinds.push(global_value); - - // A reference to a function signature declared in the function preamble. - // This is used to provide the call signature in a call_indirect instruction. - let sig_ref = create("sig_ref", "A function signature.").build(); - kinds.push(sig_ref); - - // A reference to an external function declared in the function preamble. - // This is used to provide the callee and signature in a call instruction. - let func_ref = create("func_ref", "An external function.").build(); - kinds.push(func_ref); - - // A reference to a jump table declared in the function preamble. - let jump_table = create("jump_table", "A jump table.") - .default_member("table") - .build(); - kinds.push(jump_table); - - // A reference to a heap declared in the function preamble. - let heap = create("heap", "A heap.").build(); - kinds.push(heap); - - // A reference to a table declared in the function preamble. - let table = create("table", "A table.").build(); - kinds.push(table); - - // A variable-sized list of value operands. Use for Ebb and function call arguments. - let varargs = Builder::new("variable_args", OperandKindFields::VariableArgs) - .doc( - r#" - A variable size list of `value` operands. - - Use this to represent arguments passed to a function call, arguments - passed to an extended basic block, or a variable number of results - returned from an instruction. - "#, - ) - .build(); - kinds.push(varargs); - - return kinds; -} diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs index 394eb6d58f76a..5309afc1b0b3b 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs @@ -1,44 +1,19 @@ use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder as Builder}; -use crate::shared::OperandKinds; - -pub fn define(immediates: &OperandKinds, entities: &OperandKinds) -> FormatRegistry { - // Shorthands for immediates. - let uimm8 = immediates.by_name("uimm8"); - let uimm32 = immediates.by_name("uimm32"); - let uimm128 = immediates.by_name("uimm128"); - let imm64 = immediates.by_name("imm64"); - let ieee32 = immediates.by_name("ieee32"); - let ieee64 = immediates.by_name("ieee64"); - let boolean = immediates.by_name("boolean"); - let intcc = immediates.by_name("intcc"); - let floatcc = immediates.by_name("floatcc"); - let memflags = immediates.by_name("memflags"); - let offset32 = immediates.by_name("offset32"); - let trapcode = immediates.by_name("trapcode"); - let regunit = immediates.by_name("regunit"); - - // Shorthands for entities. - let global_value = entities.by_name("global_value"); - let ebb = entities.by_name("ebb"); - let jump_table = entities.by_name("jump_table"); - let func_ref = entities.by_name("func_ref"); - let sig_ref = entities.by_name("sig_ref"); - let stack_slot = entities.by_name("stack_slot"); - let heap = entities.by_name("heap"); - let table = entities.by_name("table"); +use crate::shared::{entities::EntityRefs, immediates::Immediates}; +pub(crate) fn define(imm: &Immediates, entities: &EntityRefs) -> FormatRegistry { let mut registry = FormatRegistry::new(); registry.insert(Builder::new("Unary").value()); - registry.insert(Builder::new("UnaryImm").imm(imm64)); - registry.insert(Builder::new("UnaryImm128").imm(uimm128)); - registry.insert(Builder::new("UnaryIeee32").imm(ieee32)); - registry.insert(Builder::new("UnaryIeee64").imm(ieee64)); - registry.insert(Builder::new("UnaryBool").imm(boolean)); - registry.insert(Builder::new("UnaryGlobalValue").imm(global_value)); + registry.insert(Builder::new("UnaryImm").imm(&imm.imm64)); + registry.insert(Builder::new("UnaryImm128").imm(&imm.uimm128)); + registry.insert(Builder::new("UnaryIeee32").imm(&imm.ieee32)); + registry.insert(Builder::new("UnaryIeee64").imm(&imm.ieee64)); + registry.insert(Builder::new("UnaryBool").imm(&imm.boolean)); + registry.insert(Builder::new("UnaryGlobalValue").imm(&entities.global_value)); registry.insert(Builder::new("Binary").value().value()); - registry.insert(Builder::new("BinaryImm").value().imm(imm64)); + registry.insert(Builder::new("BinaryImm").value().imm(&imm.imm64)); // The select instructions are controlled by the second VALUE operand. // The first VALUE operand is the controlling flag which has a derived type. @@ -60,127 +35,185 @@ pub fn define(immediates: &OperandKinds, entities: &OperandKinds) -> FormatRegis registry.insert( Builder::new("InsertLane") .value() - .imm(("lane", uimm8)) + .imm_with_name("lane", &imm.uimm8) .value(), ); - registry.insert(Builder::new("ExtractLane").value().imm(("lane", uimm8))); + registry.insert( + Builder::new("ExtractLane") + .value() + .imm_with_name("lane", &imm.uimm8), + ); - registry.insert(Builder::new("IntCompare").imm(intcc).value().value()); - registry.insert(Builder::new("IntCompareImm").imm(intcc).value().imm(imm64)); - registry.insert(Builder::new("IntCond").imm(intcc).value()); + registry.insert(Builder::new("IntCompare").imm(&imm.intcc).value().value()); + registry.insert( + Builder::new("IntCompareImm") + .imm(&imm.intcc) + .value() + .imm(&imm.imm64), + ); + registry.insert(Builder::new("IntCond").imm(&imm.intcc).value()); - registry.insert(Builder::new("FloatCompare").imm(floatcc).value().value()); - registry.insert(Builder::new("FloatCond").imm(floatcc).value());; + registry.insert( + Builder::new("FloatCompare") + .imm(&imm.floatcc) + .value() + .value(), + ); + registry.insert(Builder::new("FloatCond").imm(&imm.floatcc).value());; - registry.insert(Builder::new("IntSelect").imm(intcc).value().value().value()); + registry.insert( + Builder::new("IntSelect") + .imm(&imm.intcc) + .value() + .value() + .value(), + ); - registry.insert(Builder::new("Jump").imm(ebb).varargs()); - registry.insert(Builder::new("Branch").value().imm(ebb).varargs()); + registry.insert(Builder::new("Jump").imm(&entities.ebb).varargs()); + registry.insert(Builder::new("Branch").value().imm(&entities.ebb).varargs()); registry.insert( Builder::new("BranchInt") - .imm(intcc) + .imm(&imm.intcc) .value() - .imm(ebb) + .imm(&entities.ebb) .varargs(), ); registry.insert( Builder::new("BranchFloat") - .imm(floatcc) + .imm(&imm.floatcc) .value() - .imm(ebb) + .imm(&entities.ebb) .varargs(), ); registry.insert( Builder::new("BranchIcmp") - .imm(intcc) + .imm(&imm.intcc) .value() .value() - .imm(ebb) + .imm(&entities.ebb) .varargs(), ); - registry.insert(Builder::new("BranchTable").value().imm(ebb).imm(jump_table)); + registry.insert( + Builder::new("BranchTable") + .value() + .imm(&entities.ebb) + .imm(&entities.jump_table), + ); registry.insert( Builder::new("BranchTableEntry") .value() .value() - .imm(uimm8) - .imm(jump_table), + .imm(&imm.uimm8) + .imm(&entities.jump_table), + ); + registry.insert(Builder::new("BranchTableBase").imm(&entities.jump_table)); + registry.insert( + Builder::new("IndirectJump") + .value() + .imm(&entities.jump_table), ); - registry.insert(Builder::new("BranchTableBase").imm(jump_table)); - registry.insert(Builder::new("IndirectJump").value().imm(jump_table)); - registry.insert(Builder::new("Call").imm(func_ref).varargs()); - registry.insert(Builder::new("CallIndirect").imm(sig_ref).value().varargs()); - registry.insert(Builder::new("FuncAddr").imm(func_ref)); + registry.insert(Builder::new("Call").imm(&entities.func_ref).varargs()); + registry.insert( + Builder::new("CallIndirect") + .imm(&entities.sig_ref) + .value() + .varargs(), + ); + registry.insert(Builder::new("FuncAddr").imm(&entities.func_ref)); - registry.insert(Builder::new("Load").imm(memflags).value().imm(offset32)); + registry.insert( + Builder::new("Load") + .imm(&imm.memflags) + .value() + .imm(&imm.offset32), + ); registry.insert( Builder::new("LoadComplex") - .imm(memflags) + .imm(&imm.memflags) .varargs() - .imm(offset32), + .imm(&imm.offset32), ); registry.insert( Builder::new("Store") - .imm(memflags) + .imm(&imm.memflags) .value() .value() - .imm(offset32), + .imm(&imm.offset32), ); registry.insert( Builder::new("StoreComplex") - .imm(memflags) + .imm(&imm.memflags) .value() .varargs() - .imm(offset32), + .imm(&imm.offset32), + ); + registry.insert( + Builder::new("StackLoad") + .imm(&entities.stack_slot) + .imm(&imm.offset32), ); - registry.insert(Builder::new("StackLoad").imm(stack_slot).imm(offset32)); registry.insert( Builder::new("StackStore") .value() - .imm(stack_slot) - .imm(offset32), + .imm(&entities.stack_slot) + .imm(&imm.offset32), ); // Accessing a WebAssembly heap. - registry.insert(Builder::new("HeapAddr").imm(heap).value().imm(uimm32)); + registry.insert( + Builder::new("HeapAddr") + .imm(&entities.heap) + .value() + .imm(&imm.uimm32), + ); // Accessing a WebAssembly table. - registry.insert(Builder::new("TableAddr").imm(table).value().imm(offset32)); + registry.insert( + Builder::new("TableAddr") + .imm(&entities.table) + .value() + .imm(&imm.offset32), + ); registry.insert( Builder::new("RegMove") .value() - .imm(("src", regunit)) - .imm(("dst", regunit)), + .imm_with_name("src", &imm.regunit) + .imm_with_name("dst", &imm.regunit), ); registry.insert( Builder::new("CopySpecial") - .imm(("src", regunit)) - .imm(("dst", regunit)), + .imm_with_name("src", &imm.regunit) + .imm_with_name("dst", &imm.regunit), ); - registry.insert(Builder::new("CopyToSsa").imm(("src", regunit))); + registry.insert(Builder::new("CopyToSsa").imm_with_name("src", &imm.regunit)); registry.insert( Builder::new("RegSpill") .value() - .imm(("src", regunit)) - .imm(("dst", stack_slot)), + .imm_with_name("src", &imm.regunit) + .imm_with_name("dst", &entities.stack_slot), ); registry.insert( Builder::new("RegFill") .value() - .imm(("src", stack_slot)) - .imm(("dst", regunit)), + .imm_with_name("src", &entities.stack_slot) + .imm_with_name("dst", &imm.regunit), ); - registry.insert(Builder::new("Trap").imm(trapcode)); - registry.insert(Builder::new("CondTrap").value().imm(trapcode)); - registry.insert(Builder::new("IntCondTrap").imm(intcc).value().imm(trapcode)); + registry.insert(Builder::new("Trap").imm(&imm.trapcode)); + registry.insert(Builder::new("CondTrap").value().imm(&imm.trapcode)); + registry.insert( + Builder::new("IntCondTrap") + .imm(&imm.intcc) + .value() + .imm(&imm.trapcode), + ); registry.insert( Builder::new("FloatCondTrap") - .imm(floatcc) + .imm(&imm.floatcc) .value() - .imm(trapcode), + .imm(&imm.trapcode), ); registry diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs index 5b8baca898d6b..30c1a73970f4d 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs @@ -2,154 +2,174 @@ use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder}; use std::collections::HashMap; -pub fn define() -> Vec { - let mut kinds = Vec::new(); - - // A 64-bit immediate integer operand. - // - // This type of immediate integer can interact with SSA values with any - // IntType type. - let imm64 = Builder::new_imm("imm64") - .doc("A 64-bit immediate integer.") - .build(); - kinds.push(imm64); - - // An unsigned 8-bit immediate integer operand. - // - // This small operand is used to indicate lane indexes in SIMD vectors and - // immediate bit counts on shift instructions. - let uimm8 = Builder::new_imm("uimm8") - .doc("An 8-bit immediate unsigned integer.") - .build(); - kinds.push(uimm8); - - // An unsigned 32-bit immediate integer operand. - let uimm32 = Builder::new_imm("uimm32") - .doc("A 32-bit immediate unsigned integer.") - .build(); - kinds.push(uimm32); - - // An unsigned 128-bit immediate integer operand. - // - // This operand is used to pass entire 128-bit vectors as immediates to - // instructions like const. - let uimm128 = Builder::new_imm("uimm128") - .doc("A 128-bit immediate unsigned integer.") - .rust_type("ir::Constant") - .build(); - kinds.push(uimm128); - - // A 32-bit immediate signed offset. - // - // This is used to represent an immediate address offset in load/store - // instructions. - let offset32 = Builder::new_imm("offset32") - .doc("A 32-bit immediate signed offset.") - .default_member("offset") - .build(); - kinds.push(offset32); - - // A 32-bit immediate floating point operand. - // - // IEEE 754-2008 binary32 interchange format. - let ieee32 = Builder::new_imm("ieee32") - .doc("A 32-bit immediate floating point number.") - .build(); - kinds.push(ieee32); - - // A 64-bit immediate floating point operand. - // - // IEEE 754-2008 binary64 interchange format. - let ieee64 = Builder::new_imm("ieee64") - .doc("A 64-bit immediate floating point number.") - .build(); - kinds.push(ieee64); - - // An immediate boolean operand. - // - // This type of immediate boolean can interact with SSA values with any - // BoolType type. - let boolean = Builder::new_imm("boolean") - .doc("An immediate boolean.") - .rust_type("bool") - .build(); - kinds.push(boolean); - - // A condition code for comparing integer values. - // This enumerated operand kind is used for the `icmp` instruction and corresponds to the - // condcodes::IntCC` Rust type. - let mut intcc_values = HashMap::new(); - intcc_values.insert("eq", "Equal"); - intcc_values.insert("ne", "NotEqual"); - intcc_values.insert("sge", "SignedGreaterThanOrEqual"); - intcc_values.insert("sgt", "SignedGreaterThan"); - intcc_values.insert("sle", "SignedLessThanOrEqual"); - intcc_values.insert("slt", "SignedLessThan"); - intcc_values.insert("uge", "UnsignedGreaterThanOrEqual"); - intcc_values.insert("ugt", "UnsignedGreaterThan"); - intcc_values.insert("ule", "UnsignedLessThanOrEqual"); - intcc_values.insert("ult", "UnsignedLessThan"); - let intcc = Builder::new_enum("intcc", intcc_values) - .doc("An integer comparison condition code.") - .default_member("cond") - .rust_type("ir::condcodes::IntCC") - .build(); - kinds.push(intcc); - - // A condition code for comparing floating point values. This enumerated operand kind is used - // for the `fcmp` instruction and corresponds to the `condcodes::FloatCC` Rust type. - let mut floatcc_values = HashMap::new(); - floatcc_values.insert("ord", "Ordered"); - floatcc_values.insert("uno", "Unordered"); - floatcc_values.insert("eq", "Equal"); - floatcc_values.insert("ne", "NotEqual"); - floatcc_values.insert("one", "OrderedNotEqual"); - floatcc_values.insert("ueq", "UnorderedOrEqual"); - floatcc_values.insert("lt", "LessThan"); - floatcc_values.insert("le", "LessThanOrEqual"); - floatcc_values.insert("gt", "GreaterThan"); - floatcc_values.insert("ge", "GreaterThanOrEqual"); - floatcc_values.insert("ult", "UnorderedOrLessThan"); - floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual"); - floatcc_values.insert("ugt", "UnorderedOrGreaterThan"); - floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual"); - let floatcc = Builder::new_enum("floatcc", floatcc_values) - .doc("A floating point comparison condition code") - .default_member("cond") - .rust_type("ir::condcodes::FloatCC") - .build(); - kinds.push(floatcc); - - // Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`. - let memflags = Builder::new_imm("memflags") - .doc("Memory operation flags") - .default_member("flags") - .rust_type("ir::MemFlags") - .build(); - kinds.push(memflags); - - // A register unit in the current target ISA. - let regunit = Builder::new_imm("regunit") - .doc("A register unit in the target ISA") - .rust_type("isa::RegUnit") - .build(); - kinds.push(regunit); - - // A trap code indicating the reason for trapping. - // - // The Rust enum type also has a `User(u16)` variant for user-provided trap - // codes. - let mut trapcode_values = HashMap::new(); - trapcode_values.insert("stk_ovf", "StackOverflow"); - trapcode_values.insert("heap_oob", "HeapOutOfBounds"); - trapcode_values.insert("int_ovf", "IntegerOverflow"); - trapcode_values.insert("int_divz", "IntegerDivisionByZero"); - let trapcode = Builder::new_enum("trapcode", trapcode_values) - .doc("A trap reason code.") - .default_member("code") - .rust_type("ir::TrapCode") - .build(); - kinds.push(trapcode); - - return kinds; +pub(crate) struct Immediates { + /// A 64-bit immediate integer operand. + /// + /// This type of immediate integer can interact with SSA values with any IntType type. + pub imm64: OperandKind, + + /// An unsigned 8-bit immediate integer operand. + /// + /// This small operand is used to indicate lane indexes in SIMD vectors and immediate bit + /// counts on shift instructions. + pub uimm8: OperandKind, + + /// An unsigned 32-bit immediate integer operand. + pub uimm32: OperandKind, + + /// An unsigned 128-bit immediate integer operand. + /// + /// This operand is used to pass entire 128-bit vectors as immediates to instructions like + /// const. + pub uimm128: OperandKind, + + /// A 32-bit immediate signed offset. + /// + /// This is used to represent an immediate address offset in load/store instructions. + pub offset32: OperandKind, + + /// A 32-bit immediate floating point operand. + /// + /// IEEE 754-2008 binary32 interchange format. + pub ieee32: OperandKind, + + /// A 64-bit immediate floating point operand. + /// + /// IEEE 754-2008 binary64 interchange format. + pub ieee64: OperandKind, + + /// An immediate boolean operand. + /// + /// This type of immediate boolean can interact with SSA values with any BoolType type. + pub boolean: OperandKind, + + /// A condition code for comparing integer values. + /// + /// This enumerated operand kind is used for the `icmp` instruction and corresponds to the + /// condcodes::IntCC` Rust type. + pub intcc: OperandKind, + + /// A condition code for comparing floating point values. + /// + /// This enumerated operand kind is used for the `fcmp` instruction and corresponds to the + /// `condcodes::FloatCC` Rust type. + pub floatcc: OperandKind, + + /// Flags for memory operations like `load` and `store`. + pub memflags: OperandKind, + + /// A register unit in the current target ISA. + pub regunit: OperandKind, + + /// A trap code indicating the reason for trapping. + /// + /// The Rust enum type also has a `User(u16)` variant for user-provided trap codes. + pub trapcode: OperandKind, +} + +impl Immediates { + pub fn new() -> Self { + Self { + imm64: Builder::new_imm("imm64") + .doc("A 64-bit immediate integer.") + .build(), + + uimm8: Builder::new_imm("uimm8") + .doc("An 8-bit immediate unsigned integer.") + .build(), + + uimm32: Builder::new_imm("uimm32") + .doc("A 32-bit immediate unsigned integer.") + .build(), + + uimm128: Builder::new_imm("uimm128") + .doc("A 128-bit immediate unsigned integer.") + .rust_type("ir::Constant") + .build(), + + offset32: Builder::new_imm("offset32") + .doc("A 32-bit immediate signed offset.") + .default_member("offset") + .build(), + + ieee32: Builder::new_imm("ieee32") + .doc("A 32-bit immediate floating point number.") + .build(), + + ieee64: Builder::new_imm("ieee64") + .doc("A 64-bit immediate floating point number.") + .build(), + + boolean: Builder::new_imm("boolean") + .doc("An immediate boolean.") + .rust_type("bool") + .build(), + + intcc: { + let mut intcc_values = HashMap::new(); + intcc_values.insert("eq", "Equal"); + intcc_values.insert("ne", "NotEqual"); + intcc_values.insert("sge", "SignedGreaterThanOrEqual"); + intcc_values.insert("sgt", "SignedGreaterThan"); + intcc_values.insert("sle", "SignedLessThanOrEqual"); + intcc_values.insert("slt", "SignedLessThan"); + intcc_values.insert("uge", "UnsignedGreaterThanOrEqual"); + intcc_values.insert("ugt", "UnsignedGreaterThan"); + intcc_values.insert("ule", "UnsignedLessThanOrEqual"); + intcc_values.insert("ult", "UnsignedLessThan"); + Builder::new_enum("intcc", intcc_values) + .doc("An integer comparison condition code.") + .default_member("cond") + .rust_type("ir::condcodes::IntCC") + .build() + }, + + floatcc: { + let mut floatcc_values = HashMap::new(); + floatcc_values.insert("ord", "Ordered"); + floatcc_values.insert("uno", "Unordered"); + floatcc_values.insert("eq", "Equal"); + floatcc_values.insert("ne", "NotEqual"); + floatcc_values.insert("one", "OrderedNotEqual"); + floatcc_values.insert("ueq", "UnorderedOrEqual"); + floatcc_values.insert("lt", "LessThan"); + floatcc_values.insert("le", "LessThanOrEqual"); + floatcc_values.insert("gt", "GreaterThan"); + floatcc_values.insert("ge", "GreaterThanOrEqual"); + floatcc_values.insert("ult", "UnorderedOrLessThan"); + floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual"); + floatcc_values.insert("ugt", "UnorderedOrGreaterThan"); + floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual"); + Builder::new_enum("floatcc", floatcc_values) + .doc("A floating point comparison condition code") + .default_member("cond") + .rust_type("ir::condcodes::FloatCC") + .build() + }, + + memflags: Builder::new_imm("memflags") + .doc("Memory operation flags") + .default_member("flags") + .rust_type("ir::MemFlags") + .build(), + + regunit: Builder::new_imm("regunit") + .doc("A register unit in the target ISA") + .rust_type("isa::RegUnit") + .build(), + + trapcode: { + let mut trapcode_values = HashMap::new(); + trapcode_values.insert("stk_ovf", "StackOverflow"); + trapcode_values.insert("heap_oob", "HeapOutOfBounds"); + trapcode_values.insert("int_ovf", "IntegerOverflow"); + trapcode_values.insert("int_divz", "IntegerDivisionByZero"); + Builder::new_enum("trapcode", trapcode_values) + .doc("A trap reason code.") + .default_member("code") + .rust_type("ir::TrapCode") + .build() + }, + } + } } diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs index c11016c64d5eb..3ebebfe183830 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs @@ -8,13 +8,14 @@ use crate::cdsl::operands::{create_operand as operand, create_operand_doc as ope use crate::cdsl::type_inference::Constraint::WiderOrEq; use crate::cdsl::types::{LaneType, ValueType}; use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar}; -use crate::shared::{types, OperandKinds}; +use crate::shared::types; +use crate::shared::{entities::EntityRefs, immediates::Immediates}; -pub fn define( +pub(crate) fn define( all_instructions: &mut AllInstructions, format_registry: &FormatRegistry, - immediates: &OperandKinds, - entities: &OperandKinds, + imm: &Immediates, + entities: &EntityRefs, ) -> InstructionGroup { let mut ig = InstructionGroupBuilder::new( "base", @@ -24,30 +25,6 @@ pub fn define( ); // Operand kind shorthands. - let intcc = immediates.by_name("intcc"); - let floatcc = immediates.by_name("floatcc"); - let trapcode = immediates.by_name("trapcode"); - let uimm8 = immediates.by_name("uimm8"); - let uimm32 = immediates.by_name("uimm32"); - let imm64 = immediates.by_name("imm64"); - let uimm128 = immediates.by_name("uimm128"); - let offset32 = immediates.by_name("offset32"); - let memflags = immediates.by_name("memflags"); - let ieee32 = immediates.by_name("ieee32"); - let ieee64 = immediates.by_name("ieee64"); - let boolean = immediates.by_name("boolean"); - let regunit = immediates.by_name("regunit"); - - let ebb = entities.by_name("ebb"); - let jump_table = entities.by_name("jump_table"); - let variable_args = entities.by_name("variable_args"); - let func_ref = entities.by_name("func_ref"); - let sig_ref = entities.by_name("sig_ref"); - let stack_slot = entities.by_name("stack_slot"); - let global_value = entities.by_name("global_value"); - let heap = entities.by_name("heap"); - let table = entities.by_name("table"); - let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into(); let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into(); @@ -113,16 +90,6 @@ pub fn define( .build(), ); - let Scalar = &TypeVar::new( - "scalar", - "Any scalar value that can be used as a lane in a vector", - TypeSetBuilder::new() - .bools(Interval::All) - .ints(Interval::All) - .floats(Interval::All) - .build(), - ); - let Any = &TypeVar::new( "Any", "Any integer, float, boolean, or reference scalar or vector type", @@ -152,11 +119,11 @@ pub fn define( let addr = &operand("addr", iAddr); let c = &operand_doc("c", Testable, "Controlling value to test"); - let Cond = &operand("Cond", intcc); + let Cond = &operand("Cond", &imm.intcc); let x = &operand("x", iB); let y = &operand("y", iB); - let EBB = &operand_doc("EBB", ebb, "Destination extended basic block"); - let args = &operand_doc("args", variable_args, "EBB arguments"); + let EBB = &operand_doc("EBB", &entities.ebb, "Destination extended basic block"); + let args = &operand_doc("args", &entities.varargs, "EBB arguments"); ig.push( Inst::new( @@ -263,7 +230,7 @@ pub fn define( .is_branch(true), ); - let Cond = &operand("Cond", floatcc); + let Cond = &operand("Cond", &imm.floatcc); let f = &operand("f", fflags); ig.push( @@ -280,7 +247,7 @@ pub fn define( // The index into the br_table can be any type; legalizer will convert it to the right type. let x = &operand_doc("x", iB, "index into jump table"); let entry = &operand_doc("entry", iAddr, "entry of jump table"); - let JT = &operand("JT", jump_table); + let JT = &operand("JT", &entities.jump_table); ig.push( Inst::new( @@ -310,7 +277,7 @@ pub fn define( // These are the instructions which br_table legalizes to: they perform address computations, // using pointer-sized integers, so their type variables are more constrained. let x = &operand_doc("x", iAddr, "index into jump table"); - let Size = &operand_doc("Size", uimm8, "Size in bytes"); + let Size = &operand_doc("Size", &imm.uimm8, "Size in bytes"); ig.push( Inst::new( @@ -375,7 +342,7 @@ pub fn define( .can_store(true), ); - let code = &operand("code", trapcode); + let code = &operand("code", &imm.trapcode); ig.push( Inst::new( @@ -407,7 +374,7 @@ pub fn define( "resumable_trap", r#" A resumable trap. - + This instruction allows non-conditional traps to be used as non-terminal instructions. "#, ) @@ -428,7 +395,7 @@ pub fn define( .can_trap(true), ); - let Cond = &operand("Cond", intcc); + let Cond = &operand("Cond", &imm.intcc); let f = &operand("f", iflags); ig.push( @@ -442,7 +409,7 @@ pub fn define( .can_trap(true), ); - let Cond = &operand("Cond", floatcc); + let Cond = &operand("Cond", &imm.floatcc); let f = &operand("f", fflags); ig.push( @@ -456,7 +423,7 @@ pub fn define( .can_trap(true), ); - let rvals = &operand_doc("rvals", variable_args, "return values"); + let rvals = &operand_doc("rvals", &entities.varargs, "return values"); ig.push( Inst::new( @@ -490,8 +457,12 @@ pub fn define( .is_terminator(true), ); - let FN = &operand_doc("FN", func_ref, "function to call, declared by `function`"); - let args = &operand_doc("args", variable_args, "call arguments"); + let FN = &operand_doc( + "FN", + &entities.func_ref, + "function to call, declared by `function`", + ); + let args = &operand_doc("args", &entities.varargs, "call arguments"); ig.push( Inst::new( @@ -508,7 +479,7 @@ pub fn define( .is_call(true), ); - let SIG = &operand_doc("SIG", sig_ref, "function signature"); + let SIG = &operand_doc("SIG", &entities.sig_ref, "function signature"); let callee = &operand_doc("callee", iAddr, "address of function to call"); ig.push( @@ -548,13 +519,13 @@ pub fn define( .operands_out(vec![addr]), ); - let SS = &operand("SS", stack_slot); - let Offset = &operand_doc("Offset", offset32, "Byte offset from base address"); + let SS = &operand("SS", &entities.stack_slot); + let Offset = &operand_doc("Offset", &imm.offset32, "Byte offset from base address"); let x = &operand_doc("x", Mem, "Value to be stored"); let a = &operand_doc("a", Mem, "Value loaded"); let p = &operand("p", iAddr); - let MemFlags = &operand("MemFlags", memflags); - let args = &operand_doc("args", variable_args, "Address arguments"); + let MemFlags = &operand("MemFlags", &imm.memflags); + let args = &operand_doc("args", &entities.varargs, "Address arguments"); ig.push( Inst::new( @@ -886,7 +857,7 @@ pub fn define( let x = &operand_doc("x", Mem, "Value to be stored"); let a = &operand_doc("a", Mem, "Value loaded"); - let Offset = &operand_doc("Offset", offset32, "In-bounds offset into stack slot"); + let Offset = &operand_doc("Offset", &imm.offset32, "In-bounds offset into stack slot"); ig.push( Inst::new( @@ -940,7 +911,7 @@ pub fn define( .operands_out(vec![addr]), ); - let GV = &operand("GV", global_value); + let GV = &operand("GV", &entities.global_value); ig.push( Inst::new( @@ -970,9 +941,9 @@ pub fn define( TypeSetBuilder::new().ints(32..64).build(), ); - let H = &operand("H", heap); + let H = &operand("H", &entities.heap); let p = &operand("p", HeapOffset); - let Size = &operand_doc("Size", uimm32, "Size in bytes"); + let Size = &operand_doc("Size", &imm.uimm32, "Size in bytes"); ig.push( Inst::new( @@ -993,14 +964,42 @@ pub fn define( .operands_out(vec![addr]), ); + // Note this instruction is marked as having other side-effects, so GVN won't try to hoist it, + // which would result in it being subject to spilling. While not hoisting would generally hurt + // performance, since a computed value used many times may need to be regenerated before each + // use, it is not the case here: this instruction doesn't generate any code. That's because, + // by definition the pinned register is never used by the register allocator, but is written to + // and read explicitly and exclusively by set_pinned_reg and get_pinned_reg. + ig.push( + Inst::new( + "get_pinned_reg", + r#" + Gets the content of the pinned register, when it's enabled. + "#, + ) + .operands_out(vec![addr]) + .other_side_effects(true), + ); + + ig.push( + Inst::new( + "set_pinned_reg", + r#" + Sets the content of the pinned register, when it's enabled. + "#, + ) + .operands_in(vec![addr]) + .other_side_effects(true), + ); + let TableOffset = &TypeVar::new( "TableOffset", "An unsigned table offset", TypeSetBuilder::new().ints(32..64).build(), ); - let T = &operand("T", table); + let T = &operand("T", &entities.table); let p = &operand("p", TableOffset); - let Offset = &operand_doc("Offset", offset32, "Byte offset from element address"); + let Offset = &operand_doc("Offset", &imm.offset32, "Byte offset from element address"); ig.push( Inst::new( @@ -1023,7 +1022,7 @@ pub fn define( .operands_out(vec![addr]), ); - let N = &operand("N", imm64); + let N = &operand("N", &imm.imm64); let a = &operand_doc("a", Int, "A constant integer scalar or vector value"); ig.push( @@ -1040,7 +1039,7 @@ pub fn define( .operands_out(vec![a]), ); - let N = &operand("N", ieee32); + let N = &operand("N", &imm.ieee32); let a = &operand_doc("a", f32_, "A constant f32 scalar value"); ig.push( @@ -1056,7 +1055,7 @@ pub fn define( .operands_out(vec![a]), ); - let N = &operand("N", ieee64); + let N = &operand("N", &imm.ieee64); let a = &operand_doc("a", f64_, "A constant f64 scalar value"); ig.push( @@ -1072,7 +1071,7 @@ pub fn define( .operands_out(vec![a]), ); - let N = &operand("N", boolean); + let N = &operand("N", &imm.boolean); let a = &operand_doc("a", Bool, "A constant boolean scalar or vector value"); ig.push( @@ -1089,7 +1088,11 @@ pub fn define( .operands_out(vec![a]), ); - let N = &operand_doc("N", uimm128, "The 16 immediate bytes of a 128-bit vector"); + let N = &operand_doc( + "N", + &imm.uimm128, + "The 16 immediate bytes of a 128-bit vector", + ); let a = &operand_doc("a", TxN, "A constant vector value"); ig.push( @@ -1147,7 +1150,7 @@ pub fn define( .operands_out(vec![a]), ); - let cc = &operand_doc("cc", intcc, "Controlling condition code"); + let cc = &operand_doc("cc", &imm.intcc, "Controlling condition code"); let flags = &operand_doc("flags", iflags, "The machine's flag register"); ig.push( @@ -1227,8 +1230,8 @@ pub fn define( .can_load(true), ); - let src = &operand("src", regunit); - let dst = &operand("dst", regunit); + let src = &operand("src", &imm.regunit); + let dst = &operand("dst", &imm.regunit); ig.push( Inst::new( @@ -1312,7 +1315,7 @@ pub fn define( .other_side_effects(true), ); - let Offset = &operand_doc("Offset", imm64, "Offset from current stack pointer"); + let Offset = &operand_doc("Offset", &imm.imm64, "Offset from current stack pointer"); ig.push( Inst::new( @@ -1329,7 +1332,7 @@ pub fn define( .other_side_effects(true), ); - let Offset = &operand_doc("Offset", imm64, "Offset from current stack pointer"); + let Offset = &operand_doc("Offset", &imm.imm64, "Offset from current stack pointer"); ig.push( Inst::new( @@ -1401,7 +1404,7 @@ pub fn define( let N = &operand_doc( "args", - variable_args, + &entities.varargs, "Variable number of args for Stackmap", ); @@ -1508,7 +1511,7 @@ pub fn define( let x = &operand_doc("x", TxN, "SIMD vector to modify"); let y = &operand_doc("y", &TxN.lane_of(), "New lane value"); - let Idx = &operand_doc("Idx", uimm8, "Lane index"); + let Idx = &operand_doc("Idx", &imm.uimm8, "Lane index"); ig.push( Inst::new( @@ -1534,7 +1537,9 @@ pub fn define( Extract lane ``Idx`` from ``x``. The lane index, ``Idx``, is an immediate value, not an SSA value. It - must indicate a valid lane index for the type of ``x``. + must indicate a valid lane index for the type of ``x``. Note that the upper bits of ``a`` + may or may not be zeroed depending on the ISA but the type system should prevent using + ``a`` as anything other than the extracted value. "#, ) .operands_in(vec![x, Idx]) @@ -1542,7 +1547,7 @@ pub fn define( ); let a = &operand("a", &Int.as_bool()); - let Cond = &operand("Cond", intcc); + let Cond = &operand("Cond", &imm.intcc); let x = &operand("x", Int); let y = &operand("y", Int); @@ -1576,7 +1581,7 @@ pub fn define( let a = &operand("a", b1); let x = &operand("x", iB); - let Y = &operand("Y", imm64); + let Y = &operand("Y", &imm.imm64); ig.push( Inst::new( @@ -1767,7 +1772,7 @@ pub fn define( let a = &operand("a", iB); let x = &operand("x", iB); - let Y = &operand("Y", imm64); + let Y = &operand("Y", &imm.imm64); ig.push( Inst::new( @@ -1874,10 +1879,10 @@ pub fn define( let a = &operand("a", iB); let x = &operand("x", iB); let y = &operand("y", iB); - let c_in = &operand_doc("c_in", b1, "Input carry flag"); - let c_out = &operand_doc("c_out", b1, "Output carry flag"); - let b_in = &operand_doc("b_in", b1, "Input borrow flag"); - let b_out = &operand_doc("b_out", b1, "Output borrow flag"); + let c_in = &operand_doc("c_in", iflags, "Input carry flag"); + let c_out = &operand_doc("c_out", iflags, "Output carry flag"); + let b_in = &operand_doc("b_in", iflags, "Input borrow flag"); + let b_out = &operand_doc("b_out", iflags, "Output borrow flag"); ig.push( Inst::new( @@ -2102,7 +2107,7 @@ pub fn define( ); let x = &operand("x", iB); - let Y = &operand("Y", imm64); + let Y = &operand("Y", &imm.imm64); let a = &operand("a", iB); ig.push( @@ -2155,7 +2160,7 @@ pub fn define( let x = &operand_doc("x", Int, "Scalar or vector value to shift"); let y = &operand_doc("y", iB, "Number of bits to shift"); - let Y = &operand("Y", imm64); + let Y = &operand("Y", &imm.imm64); let a = &operand("a", Int); ig.push( @@ -2385,7 +2390,7 @@ pub fn define( .simd_lanes(Interval::All) .build(), ); - let Cond = &operand("Cond", floatcc); + let Cond = &operand("Cond", &imm.floatcc); let x = &operand("x", Float); let y = &operand("y", Float); let a = &operand("a", &Float.as_bool()); @@ -2697,7 +2702,7 @@ pub fn define( .operands_out(vec![a]), ); - let Cond = &operand("Cond", intcc); + let Cond = &operand("Cond", &imm.intcc); let f = &operand("f", iflags); let a = &operand("a", b1); @@ -2715,7 +2720,7 @@ pub fn define( .operands_out(vec![a]), ); - let Cond = &operand("Cond", floatcc); + let Cond = &operand("Cond", &imm.floatcc); let f = &operand("f", fflags); ig.push( @@ -2772,16 +2777,18 @@ pub fn define( .operands_out(vec![a]), ); - let s = &operand_doc("s", Scalar, "A scalar value"); - let a = &operand_doc("a", TxN, "A vector value (i.e. held in an XMM register)"); + let a = &operand_doc("a", TxN, "A vector value"); + let s = &operand_doc("s", &TxN.lane_of(), "A scalar value"); ig.push( Inst::new( "scalar_to_vector", r#" - Scalar To Vector -- move a value out of a scalar register and into a vector - register; the scalar will be moved to the lowest-order bits of the vector - register and any higher bits will be zeroed. + Scalar To Vector -- move a value out of a scalar register and into a vector register; the + scalar will be moved to the lowest-order bits of the vector register. Note that this + instruction is intended as a low-level legalization instruction and frontends should prefer + insertlane; on certain architectures, scalar_to_vector may zero the highest-order bits for some + types (e.g. integers) but not for others (e.g. floats). "#, ) .operands_in(vec![s]) @@ -3140,7 +3147,7 @@ pub fn define( "WideInt", "An integer type with lanes from `i16` upwards", TypeSetBuilder::new() - .ints(16..64) + .ints(16..128) .simd_lanes(Interval::All) .build(), ); @@ -3168,9 +3175,9 @@ pub fn define( let NarrowInt = &TypeVar::new( "NarrowInt", - "An integer type with lanes type to `i32`", + "An integer type with lanes type to `i64`", TypeSetBuilder::new() - .ints(8..32) + .ints(8..64) .simd_lanes(Interval::All) .build(), ); diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs b/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs index 004bdff95ba67..1c2c510460c6d 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs @@ -2,12 +2,11 @@ use crate::cdsl::ast::{var, ExprBuilder, Literal}; use crate::cdsl::instructions::{Instruction, InstructionGroup}; use crate::cdsl::xform::{TransformGroupBuilder, TransformGroups}; -use crate::shared::OperandKinds; - +use crate::shared::immediates::Immediates; use crate::shared::types::Float::{F32, F64}; -use crate::shared::types::Int::{I16, I32, I64, I8}; +use crate::shared::types::Int::{I128, I16, I32, I64, I8}; -pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformGroups { +pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGroups { let mut narrow = TransformGroupBuilder::new( "narrow", r#" @@ -50,6 +49,8 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG let bor = insts.by_name("bor"); let bor_imm = insts.by_name("bor_imm"); let bor_not = insts.by_name("bor_not"); + let brnz = insts.by_name("brnz"); + let brz = insts.by_name("brz"); let br_icmp = insts.by_name("br_icmp"); let br_table = insts.by_name("br_table"); let bxor = insts.by_name("bxor"); @@ -66,7 +67,6 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG let fcvt_from_uint = insts.by_name("fcvt_from_uint"); let fneg = insts.by_name("fneg"); let iadd = insts.by_name("iadd"); - let iadd_carry = insts.by_name("iadd_carry"); let iadd_cin = insts.by_name("iadd_cin"); let iadd_cout = insts.by_name("iadd_cout"); let iadd_imm = insts.by_name("iadd_imm"); @@ -87,7 +87,6 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG let istore16 = insts.by_name("istore16"); let isub = insts.by_name("isub"); let isub_bin = insts.by_name("isub_bin"); - let isub_borrow = insts.by_name("isub_borrow"); let isub_bout = insts.by_name("isub_bout"); let load = insts.by_name("load"); let popcnt = insts.by_name("popcnt"); @@ -141,12 +140,6 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG expand.custom_legalize(insts.by_name("stack_load"), "expand_stack_load"); expand.custom_legalize(insts.by_name("stack_store"), "expand_stack_store"); - // List of immediates. - let imm64 = immediates.by_name("imm64"); - let ieee32 = immediates.by_name("ieee32"); - let ieee64 = immediates.by_name("ieee64"); - let intcc = immediates.by_name("intcc"); - // List of variables to reuse in patterns. let x = var("x"); let y = var("y"); @@ -161,15 +154,11 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG let b2 = var("b2"); let b3 = var("b3"); let b4 = var("b4"); - let b_in = var("b_in"); - let b_int = var("b_int"); let c = var("c"); let c1 = var("c1"); let c2 = var("c2"); let c3 = var("c3"); let c4 = var("c4"); - let c_in = var("c_in"); - let c_int = var("c_int"); let d = var("d"); let d1 = var("d1"); let d2 = var("d2"); @@ -190,9 +179,18 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG let al = var("al"); let ah = var("ah"); let cc = var("cc"); + let ebb = var("ebb"); let ptr = var("ptr"); let flags = var("flags"); let offset = var("off"); + let vararg = var("vararg"); + + narrow.custom_legalize(load, "narrow_load"); + narrow.custom_legalize(store, "narrow_store"); + + // iconst.i64 can't be legalized in the meta langage (because integer literals can't be + // embedded as part of arguments), so use a custom legalization for now. + narrow.custom_legalize(iconst, "narrow_iconst"); narrow.legalize( def!(a = iadd(x, y)), @@ -216,7 +214,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG ], ); - for &bin_op in &[band, bor, bxor] { + for &bin_op in &[band, bor, bxor, band_not, bor_not, bxor_not] { narrow.legalize( def!(a = bin_op(x, y)), vec![ @@ -229,6 +227,16 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG ); } + narrow.legalize( + def!(a = bnot(x)), + vec![ + def!((xl, xh) = isplit(x)), + def!(al = bnot(xl)), + def!(ah = bnot(xh)), + def!(a = iconcat(al, ah)), + ], + ); + narrow.legalize( def!(a = select(c, x, y)), vec![ @@ -240,6 +248,38 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG ], ); + narrow.legalize( + def!(brz.I128(x, ebb, vararg)), + vec![ + def!((xl, xh) = isplit(x)), + def!( + a = icmp_imm( + Literal::enumerator_for(&imm.intcc, "eq"), + xl, + Literal::constant(&imm.imm64, 0) + ) + ), + def!( + b = icmp_imm( + Literal::enumerator_for(&imm.intcc, "eq"), + xh, + Literal::constant(&imm.imm64, 0) + ) + ), + def!(c = band(a, b)), + def!(brz(c, ebb, vararg)), + ], + ); + + narrow.legalize( + def!(brnz.I128(x, ebb, vararg)), + vec![ + def!((xl, xh) = isplit(x)), + def!(brnz(xl, ebb, vararg)), + def!(brnz(xh, ebb, vararg)), + ], + ); + // Widen instructions with one input operand. for &op in &[bnot, popcnt] { for &int_ty in &[I8, I16] { @@ -304,7 +344,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } for &(int_ty, num) in &[(I8, 24), (I16, 16)] { - let imm = Literal::constant(imm64, -num); + let imm = Literal::constant(&imm.imm64, -num); widen.legalize( def!(a = clz.int_ty(b)), @@ -328,7 +368,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } for &(int_ty, num) in &[(I8, 1 << 8), (I16, 1 << 16)] { - let num = Literal::constant(imm64, num); + let num = Literal::constant(&imm.imm64, num); widen.legalize( def!(a = ctz.int_ty(b)), vec![ @@ -429,7 +469,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } for cc in &["eq", "ne", "ugt", "ult", "uge", "ule"] { - let w_cc = Literal::enumerator_for(intcc, cc); + let w_cc = Literal::enumerator_for(&imm.intcc, cc); widen.legalize( def!(a = icmp_imm.int_ty(w_cc, b, c)), vec![def!(x = uextend.I32(b)), def!(a = icmp_imm(w_cc, x, c))], @@ -445,7 +485,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } for cc in &["sgt", "slt", "sge", "sle"] { - let w_cc = Literal::enumerator_for(intcc, cc); + let w_cc = Literal::enumerator_for(&imm.intcc, cc); widen.legalize( def!(a = icmp_imm.int_ty(w_cc, b, c)), vec![def!(x = sextend.I32(b)), def!(a = icmp_imm(w_cc, x, c))], @@ -462,58 +502,6 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } } - // Expand integer operations with carry for RISC architectures that don't have - // the flags. - let intcc_ult = Literal::enumerator_for(intcc, "ult"); - expand.legalize( - def!((a, c) = iadd_cout(x, y)), - vec![def!(a = iadd(x, y)), def!(c = icmp(intcc_ult, a, x))], - ); - - let intcc_ugt = Literal::enumerator_for(intcc, "ugt"); - expand.legalize( - def!((a, b) = isub_bout(x, y)), - vec![def!(a = isub(x, y)), def!(b = icmp(intcc_ugt, a, x))], - ); - - expand.legalize( - def!(a = iadd_cin(x, y, c)), - vec![ - def!(a1 = iadd(x, y)), - def!(c_int = bint(c)), - def!(a = iadd(a1, c_int)), - ], - ); - - expand.legalize( - def!(a = isub_bin(x, y, b)), - vec![ - def!(a1 = isub(x, y)), - def!(b_int = bint(b)), - def!(a = isub(a1, b_int)), - ], - ); - - expand.legalize( - def!((a, c) = iadd_carry(x, y, c_in)), - vec![ - def!((a1, c1) = iadd_cout(x, y)), - def!(c_int = bint(c_in)), - def!((a, c2) = iadd_cout(a1, c_int)), - def!(c = bor(c1, c2)), - ], - ); - - expand.legalize( - def!((a, b) = isub_borrow(x, y, b_in)), - vec![ - def!((a1, b1) = isub_bout(x, y)), - def!(b_int = bint(b_in)), - def!((a, b2) = isub_bout(a1, b_int)), - def!(b = bor(b1, b2)), - ], - ); - // Expansions for fcvt_from_{u,s}int for smaller integer types. // These use expand and not widen because the controlling type variable for // these instructions are f32/f64, which are legalized as part of the expand @@ -592,7 +580,7 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG } //# Expand bnot using xor. - let minus_one = Literal::constant(imm64, -1); + let minus_one = Literal::constant(&imm.imm64, -1); expand.legalize( def!(a = bnot(x)), vec![def!(y = iconst(minus_one)), def!(a = bxor(x, y))], @@ -601,82 +589,82 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG //# Expand bitrev //# Adapted from Stack Overflow. //# https://stackoverflow.com/questions/746171/most-efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c - let imm64_1 = Literal::constant(imm64, 1); - let imm64_2 = Literal::constant(imm64, 2); - let imm64_4 = Literal::constant(imm64, 4); + let imm64_1 = Literal::constant(&imm.imm64, 1); + let imm64_2 = Literal::constant(&imm.imm64, 2); + let imm64_4 = Literal::constant(&imm.imm64, 4); widen.legalize( def!(a = bitrev.I8(x)), vec![ - def!(a1 = band_imm(x, Literal::constant(imm64, 0xaa))), + def!(a1 = band_imm(x, Literal::constant(&imm.imm64, 0xaa))), def!(a2 = ushr_imm(a1, imm64_1)), - def!(a3 = band_imm(x, Literal::constant(imm64, 0x55))), + def!(a3 = band_imm(x, Literal::constant(&imm.imm64, 0x55))), def!(a4 = ishl_imm(a3, imm64_1)), def!(b = bor(a2, a4)), - def!(b1 = band_imm(b, Literal::constant(imm64, 0xcc))), + def!(b1 = band_imm(b, Literal::constant(&imm.imm64, 0xcc))), def!(b2 = ushr_imm(b1, imm64_2)), - def!(b3 = band_imm(b, Literal::constant(imm64, 0x33))), + def!(b3 = band_imm(b, Literal::constant(&imm.imm64, 0x33))), def!(b4 = ishl_imm(b3, imm64_2)), def!(c = bor(b2, b4)), - def!(c1 = band_imm(c, Literal::constant(imm64, 0xf0))), + def!(c1 = band_imm(c, Literal::constant(&imm.imm64, 0xf0))), def!(c2 = ushr_imm(c1, imm64_4)), - def!(c3 = band_imm(c, Literal::constant(imm64, 0x0f))), + def!(c3 = band_imm(c, Literal::constant(&imm.imm64, 0x0f))), def!(c4 = ishl_imm(c3, imm64_4)), def!(a = bor(c2, c4)), ], ); - let imm64_8 = Literal::constant(imm64, 8); + let imm64_8 = Literal::constant(&imm.imm64, 8); widen.legalize( def!(a = bitrev.I16(x)), vec![ - def!(a1 = band_imm(x, Literal::constant(imm64, 0xaaaa))), + def!(a1 = band_imm(x, Literal::constant(&imm.imm64, 0xaaaa))), def!(a2 = ushr_imm(a1, imm64_1)), - def!(a3 = band_imm(x, Literal::constant(imm64, 0x5555))), + def!(a3 = band_imm(x, Literal::constant(&imm.imm64, 0x5555))), def!(a4 = ishl_imm(a3, imm64_1)), def!(b = bor(a2, a4)), - def!(b1 = band_imm(b, Literal::constant(imm64, 0xcccc))), + def!(b1 = band_imm(b, Literal::constant(&imm.imm64, 0xcccc))), def!(b2 = ushr_imm(b1, imm64_2)), - def!(b3 = band_imm(b, Literal::constant(imm64, 0x3333))), + def!(b3 = band_imm(b, Literal::constant(&imm.imm64, 0x3333))), def!(b4 = ishl_imm(b3, imm64_2)), def!(c = bor(b2, b4)), - def!(c1 = band_imm(c, Literal::constant(imm64, 0xf0f0))), + def!(c1 = band_imm(c, Literal::constant(&imm.imm64, 0xf0f0))), def!(c2 = ushr_imm(c1, imm64_4)), - def!(c3 = band_imm(c, Literal::constant(imm64, 0x0f0f))), + def!(c3 = band_imm(c, Literal::constant(&imm.imm64, 0x0f0f))), def!(c4 = ishl_imm(c3, imm64_4)), def!(d = bor(c2, c4)), - def!(d1 = band_imm(d, Literal::constant(imm64, 0xff00))), + def!(d1 = band_imm(d, Literal::constant(&imm.imm64, 0xff00))), def!(d2 = ushr_imm(d1, imm64_8)), - def!(d3 = band_imm(d, Literal::constant(imm64, 0x00ff))), + def!(d3 = band_imm(d, Literal::constant(&imm.imm64, 0x00ff))), def!(d4 = ishl_imm(d3, imm64_8)), def!(a = bor(d2, d4)), ], ); - let imm64_16 = Literal::constant(imm64, 16); + let imm64_16 = Literal::constant(&imm.imm64, 16); expand.legalize( def!(a = bitrev.I32(x)), vec![ - def!(a1 = band_imm(x, Literal::constant(imm64, 0xaaaaaaaa))), + def!(a1 = band_imm(x, Literal::constant(&imm.imm64, 0xaaaaaaaa))), def!(a2 = ushr_imm(a1, imm64_1)), - def!(a3 = band_imm(x, Literal::constant(imm64, 0x55555555))), + def!(a3 = band_imm(x, Literal::constant(&imm.imm64, 0x55555555))), def!(a4 = ishl_imm(a3, imm64_1)), def!(b = bor(a2, a4)), - def!(b1 = band_imm(b, Literal::constant(imm64, 0xcccccccc))), + def!(b1 = band_imm(b, Literal::constant(&imm.imm64, 0xcccccccc))), def!(b2 = ushr_imm(b1, imm64_2)), - def!(b3 = band_imm(b, Literal::constant(imm64, 0x33333333))), + def!(b3 = band_imm(b, Literal::constant(&imm.imm64, 0x33333333))), def!(b4 = ishl_imm(b3, imm64_2)), def!(c = bor(b2, b4)), - def!(c1 = band_imm(c, Literal::constant(imm64, 0xf0f0f0f0))), + def!(c1 = band_imm(c, Literal::constant(&imm.imm64, 0xf0f0f0f0))), def!(c2 = ushr_imm(c1, imm64_4)), - def!(c3 = band_imm(c, Literal::constant(imm64, 0x0f0f0f0f))), + def!(c3 = band_imm(c, Literal::constant(&imm.imm64, 0x0f0f0f0f))), def!(c4 = ishl_imm(c3, imm64_4)), def!(d = bor(c2, c4)), - def!(d1 = band_imm(d, Literal::constant(imm64, 0xff00ff00))), + def!(d1 = band_imm(d, Literal::constant(&imm.imm64, 0xff00ff00))), def!(d2 = ushr_imm(d1, imm64_8)), - def!(d3 = band_imm(d, Literal::constant(imm64, 0x00ff00ff))), + def!(d3 = band_imm(d, Literal::constant(&imm.imm64, 0x00ff00ff))), def!(d4 = ishl_imm(d3, imm64_8)), def!(e = bor(d2, d4)), def!(e1 = ushr_imm(e, imm64_16)), @@ -686,21 +674,21 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG ); #[allow(overflowing_literals)] - let imm64_0xaaaaaaaaaaaaaaaa = Literal::constant(imm64, 0xaaaaaaaaaaaaaaaa); - let imm64_0x5555555555555555 = Literal::constant(imm64, 0x5555555555555555); + let imm64_0xaaaaaaaaaaaaaaaa = Literal::constant(&imm.imm64, 0xaaaaaaaaaaaaaaaa); + let imm64_0x5555555555555555 = Literal::constant(&imm.imm64, 0x5555555555555555); #[allow(overflowing_literals)] - let imm64_0xcccccccccccccccc = Literal::constant(imm64, 0xcccccccccccccccc); - let imm64_0x3333333333333333 = Literal::constant(imm64, 0x3333333333333333); + let imm64_0xcccccccccccccccc = Literal::constant(&imm.imm64, 0xcccccccccccccccc); + let imm64_0x3333333333333333 = Literal::constant(&imm.imm64, 0x3333333333333333); #[allow(overflowing_literals)] - let imm64_0xf0f0f0f0f0f0f0f0 = Literal::constant(imm64, 0xf0f0f0f0f0f0f0f0); - let imm64_0x0f0f0f0f0f0f0f0f = Literal::constant(imm64, 0x0f0f0f0f0f0f0f0f); + let imm64_0xf0f0f0f0f0f0f0f0 = Literal::constant(&imm.imm64, 0xf0f0f0f0f0f0f0f0); + let imm64_0x0f0f0f0f0f0f0f0f = Literal::constant(&imm.imm64, 0x0f0f0f0f0f0f0f0f); #[allow(overflowing_literals)] - let imm64_0xff00ff00ff00ff00 = Literal::constant(imm64, 0xff00ff00ff00ff00); - let imm64_0x00ff00ff00ff00ff = Literal::constant(imm64, 0x00ff00ff00ff00ff); + let imm64_0xff00ff00ff00ff00 = Literal::constant(&imm.imm64, 0xff00ff00ff00ff00); + let imm64_0x00ff00ff00ff00ff = Literal::constant(&imm.imm64, 0x00ff00ff00ff00ff); #[allow(overflowing_literals)] - let imm64_0xffff0000ffff0000 = Literal::constant(imm64, 0xffff0000ffff0000); - let imm64_0x0000ffff0000ffff = Literal::constant(imm64, 0x0000ffff0000ffff); - let imm64_32 = Literal::constant(imm64, 32); + let imm64_0xffff0000ffff0000 = Literal::constant(&imm.imm64, 0xffff0000ffff0000); + let imm64_0x0000ffff0000ffff = Literal::constant(&imm.imm64, 0x0000ffff0000ffff); + let imm64_32 = Literal::constant(&imm.imm64, 32); expand.legalize( def!(a = bitrev.I64(x)), @@ -738,8 +726,12 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG // Floating-point sign manipulations. for &(ty, const_inst, minus_zero) in &[ - (F32, f32const, &Literal::bits(ieee32, 0x80000000)), - (F64, f64const, &Literal::bits(ieee64, 0x8000000000000000)), + (F32, f32const, &Literal::bits(&imm.ieee32, 0x80000000)), + ( + F64, + f64const, + &Literal::bits(&imm.ieee64, 0x8000000000000000), + ), ] { expand.legalize( def!(a = fabs.ty(x)), @@ -782,9 +774,9 @@ pub fn define(insts: &InstructionGroup, immediates: &OperandKinds) -> TransformG ) .chain_with(expand_id); - let imm64_0 = Literal::constant(imm64, 0); - let intcc_ne = Literal::enumerator_for(intcc, "ne"); - let intcc_eq = Literal::enumerator_for(intcc, "eq"); + let imm64_0 = Literal::constant(&imm.imm64, 0); + let intcc_ne = Literal::enumerator_for(&imm.intcc, "ne"); + let intcc_eq = Literal::enumerator_for(&imm.intcc, "eq"); expand_flags.legalize( def!(trapnz(x, c)), diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs b/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs index ba1425b844721..12921da5ef8a6 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs @@ -1,6 +1,6 @@ //! Shared definitions for the Cranelift intermediate language. -pub mod entities; +mod entities; pub mod formats; pub mod immediates; pub mod instructions; @@ -10,57 +10,26 @@ pub mod types; use crate::cdsl::formats::FormatRegistry; use crate::cdsl::instructions::{AllInstructions, InstructionGroup}; -use crate::cdsl::operands::OperandKind; use crate::cdsl::settings::SettingGroup; use crate::cdsl::xform::TransformGroups; -pub struct Definitions { +use crate::shared::entities::EntityRefs; +use crate::shared::immediates::Immediates; + +pub(crate) struct Definitions { pub settings: SettingGroup, pub all_instructions: AllInstructions, pub instructions: InstructionGroup, - pub operand_kinds: OperandKinds, + pub imm: Immediates, pub format_registry: FormatRegistry, pub transform_groups: TransformGroups, } -pub struct OperandKinds(Vec); - -impl OperandKinds { - pub fn new() -> Self { - Self(Vec::new()) - } - - pub fn by_name(&self, name: &'static str) -> &OperandKind { - self.0 - .iter() - .find(|op| op.name == name) - .expect(&format!("unknown Operand name: {}", name)) - } - - pub fn push(&mut self, operand_kind: OperandKind) { - assert!( - self.0 - .iter() - .find(|existing| existing.name == operand_kind.name) - .is_none(), - "trying to insert operand kind '{}' for the second time", - operand_kind.name - ); - self.0.push(operand_kind); - } -} - -impl From> for OperandKinds { - fn from(kinds: Vec) -> Self { - OperandKinds(kinds) - } -} - -pub fn define() -> Definitions { +pub(crate) fn define() -> Definitions { let mut all_instructions = AllInstructions::new(); - let immediates = OperandKinds(immediates::define()); - let entities = OperandKinds(entities::define()); + let immediates = Immediates::new(); + let entities = EntityRefs::new();; let format_registry = formats::define(&immediates, &entities); let instructions = instructions::define( &mut all_instructions, @@ -74,7 +43,7 @@ pub fn define() -> Definitions { settings: settings::define(), all_instructions, instructions, - operand_kinds: immediates, + imm: immediates, format_registry, transform_groups, } diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs b/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs index 6561ee9856ed5..63c5d3c01aeb5 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs @@ -84,6 +84,32 @@ pub fn define() -> SettingGroup { false, ); + settings.add_bool( + "enable_pinned_reg", + r#"Enable the use of the pinned register. + + This register is excluded from register allocation, and is completely under the control of + the end-user. It is possible to read it via the get_pinned_reg instruction, and to set it + with the set_pinned_reg instruction. + "#, + false, + ); + + settings.add_bool( + "use_pinned_reg_as_heap_base", + r#"Use the pinned register as the heap base. + + Enabling this requires the enable_pinned_reg setting to be set to true. It enables a custom + legalization of the `heap_addr` instruction so it will use the pinned register as the heap + base, instead of fetching it from a global value. + + Warning! Enabling this means that the pinned register *must* be maintained to contain the + heap base address at all times, during the lifetime of a function. Using the pinned + register for other purposes when this is set is very likely to cause crashes. + "#, + false, + ); + settings.add_bool("enable_simd", "Enable the use of SIMD instructions.", false); settings.add_bool( diff --git a/third_party/rust/cranelift-codegen-meta/src/shared/types.rs b/third_party/rust/cranelift-codegen-meta/src/shared/types.rs index 266c30b3d8be9..52fa9545c6a0b 100644 --- a/third_party/rust/cranelift-codegen-meta/src/shared/types.rs +++ b/third_party/rust/cranelift-codegen-meta/src/shared/types.rs @@ -12,6 +12,8 @@ pub enum Bool { B32 = 32, /// 64-bit bool. B64 = 64, + /// 128-bit bool. + B128 = 128, } /// This provides an iterator through all of the supported bool variants. @@ -34,6 +36,7 @@ impl Iterator for BoolIterator { 2 => Some(Bool::B16), 3 => Some(Bool::B32), 4 => Some(Bool::B64), + 5 => Some(Bool::B128), _ => return None, }; self.index += 1; @@ -51,6 +54,8 @@ pub enum Int { I32 = 32, /// 64-bit int. I64 = 64, + /// 128-bit int. + I128 = 128, } /// This provides an iterator through all of the supported int variants. @@ -72,6 +77,7 @@ impl Iterator for IntIterator { 1 => Some(Int::I16), 2 => Some(Int::I32), 3 => Some(Int::I64), + 4 => Some(Int::I128), _ => return None, }; self.index += 1; @@ -189,6 +195,7 @@ mod iter_tests { assert_eq!(bool_iter.next(), Some(Bool::B16)); assert_eq!(bool_iter.next(), Some(Bool::B32)); assert_eq!(bool_iter.next(), Some(Bool::B64)); + assert_eq!(bool_iter.next(), Some(Bool::B128)); assert_eq!(bool_iter.next(), None); } @@ -199,6 +206,7 @@ mod iter_tests { assert_eq!(int_iter.next(), Some(Int::I16)); assert_eq!(int_iter.next(), Some(Int::I32)); assert_eq!(int_iter.next(), Some(Int::I64)); + assert_eq!(int_iter.next(), Some(Int::I128)); assert_eq!(int_iter.next(), None); } diff --git a/third_party/rust/cranelift-codegen/.cargo-checksum.json b/third_party/rust/cranelift-codegen/.cargo-checksum.json index e43dc92fb2b45..ecfc93c9c5b60 100644 --- a/third_party/rust/cranelift-codegen/.cargo-checksum.json +++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f797893f65d711c9e0df429ec0b85816c3526e87f0d6baa3300bc5d667f36d20","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"da415b20c563e636bcccaafb43dbdb77d6c48f9c205b16229865abb1afa40964","src/binemit/mod.rs":"b05271c3b1d4e44c2f8f9fe0669778775d33e9dda4c70101ddc420275286e72c","src/binemit/relaxation.rs":"1d61f9e9eef5f81b1649aa3918f821d870d712ee5a56b02a18c704d43d344ace","src/binemit/shrink.rs":"79a2dcca2633c8449d49bf7cfb1e2fe14b46753a4d52ef412078c53d7742fe86","src/binemit/stackmap.rs":"da3187d96d21b14927279061ccaba4c880d0ad7169b83bd32c1381d45a39af70","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"ee09647590a7a583c37df398fe3eb51dca034a5aca4e164288c9f7ed2b30274e","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/constant.rs":"cffcc1817b4881b87731d59f33f434ffe9be769c0604e3069b1c5e8ee0ebd7d1","src/ir/dfg.rs":"ad5a597584966c3202774bd3cd8bbf3138c474b8fb89347855915b6f4edc8ae8","src/ir/entities.rs":"976f51a1e704b63b0bc701eb814b10ec8eee373d8f93ee73ceeeaeeea2c5b821","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"01dd3b9c7e95324a5683f3d9edb8f272c5e551c0eb84673ca3bf6740e9707b8e","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"90e5c07d25d093b084adc3c086c8aeddc4c380aa0a1f67c82c59aec9adb00915","src/ir/instructions.rs":"7fe853efeb0379486d7878f7925962144ce208d230107d83e5a9165997a07587","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"64eeae70e767424ddc8dd01167dc56019df45c3fba5c96bf05fa0d3d7670f344","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"7590a2035a6f88a830e6c440d3c5a22102e921445806d04627e46ee42d82d167","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"3828c0ff0aee4c101135dcbf0a9a39cd8d89cc9f9d52ca0ce7a42d549a9a4a50","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"1e02aef8ad188d347a17a7ecce42a9064b2d46ac2a5d246bf9b5cd44180a9b60","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"49b7f398ec8baa2802a283f780bd039e2a630591e74cf1dddc8d9147345c2816","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"46a03271aed9cb38f87f2d0301721725f99a4f513ee77e39931ea338f13aa0f7","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"cb5e4ffba5575d23b8ec5897393a5e2d7eb3259397f76a47e717b41340879de1","src/isa/registers.rs":"2050f34d87dd6e8a3d1cefc6248383ac5a888ec9b6766359edd883714ef03bda","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"41136889df9512d8311f8c015cf3f654557a17d784a17fcefeb0afa2f0ec3674","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"52df0eb35643a721d2d1acbee550b2194a4407205a340acd139e8e717dfc2801","src/isa/x86/binemit.rs":"66fb00826397a5c6c99b9ef6b9daedaec0753d4e87279e2ecbca81863bc4309c","src/isa/x86/enc_tables.rs":"b67d453834e0fdcc2885dfe359502755514c9190a8699bae2c4b5026f1ab4017","src/isa/x86/mod.rs":"77879d642905156885b8f502a6b53423dea8a33cf465d74326049a658c8118d8","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"b83dc83a5876b024db058023692f71d8f910f6b212f34200e9bcf61a19daeb8e","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"aef4a458f3ab26239e8ac18c0c20791875fbd21e02085fa130be057e5f899a68","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"49ad98df2949c815d717e5a076a8654994fe5b71a7b639b058cb86c2183067fd","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"2d62e2f25a6c4327e75716a5f3508edf810c4957d0b20d855ed5a865359c8dfb","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"45fa9a5f19f790f6bcee66ed3d578144712f8f6f19f564b5b84323f63353a8f7","src/regalloc/context.rs":"25e67e8562bbf757e3198d3a70c56d7b9fc5c86e1ada54cd556aac4144ec7ef2","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"594e059f9f2cbb1e1e2d45ec080c7544c3549bf8b309e6a1b30fcb36b8d7810e","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"a816187bc0ca7e0fd9464fde9a37cdeaf09c5f5e7b10faee0eb12f6873034e1c","src/regalloc/reload.rs":"ccccb716a694b53103bd4d55efb2323e788c1127469233c17b648fa06baa67b1","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"0787ddf732fae9112fb905d6a1dc0c29673800985e67bd57d900426269847e7b","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"6c86c3d9b7b9a6424010c08cf6649d405edea5c1955645fa8ec43b9d6f22c3cb","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"9ee5b9deff729ee6b5b7111a15897f989ff26b9316848fcd5c22930df857467a","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"b81376e0b79252de8dff19d003bcdae210c0848229e63e7682b0148bbcde5961","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"04635edc12bc741a23c9318611aac4abcb42f01effbebee6d858f108f9393a44","src/verifier/mod.rs":"4d013e70bdc90743637fb91a8f3d32790c25aeff168219d147431c02c44f37b7","src/write.rs":"35dff9d0f5ed74779e536cbc6b1de7381cec521a0c54f6d8513041d118bbfc4b"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"99b4b834ec33e1d1917296497e286dad5819fed0600b5ce288a114133efbe734","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"da415b20c563e636bcccaafb43dbdb77d6c48f9c205b16229865abb1afa40964","src/binemit/mod.rs":"90c56d36091646bba7f0ab1b5064d68b8b0c24ece874fcf8c621830b743e9688","src/binemit/relaxation.rs":"7b1082203c688beab4d705e601ad4fde10c5bf1fec414ad1ee6993e4f6b95e01","src/binemit/shrink.rs":"5755efc978f5056a33c0ecb1bd5e08310397f54a67434ecead184fc6ee047133","src/binemit/stackmap.rs":"da3187d96d21b14927279061ccaba4c880d0ad7169b83bd32c1381d45a39af70","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"54b0acb1fb10e98f20804c367d5b2343f8ec918900f8f843e12e0925649b7515","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"6817b893c2c5ba5f2fc4e632fb8f8b7210a9ea9862d389d5247ff94b992b0d27","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/constant.rs":"378d02256c3e21d89b70c6b0956ef70c034a5f14c1d2aaaec1f172a38b7b2279","src/ir/dfg.rs":"e139e85a59cc5ffca5b2e55daa2e9887f579765e748c42566ca957a305dd8b6b","src/ir/entities.rs":"976f51a1e704b63b0bc701eb814b10ec8eee373d8f93ee73ceeeaeeea2c5b821","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"fdbd33def70bfc49648c232d9fdb65eb8ed694a6a1a8bde1e06d6e40d4970230","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"671cc8bfcc347d7409ddba2bc661d985979f144cd663da232d9ba6a54e5c94c5","src/ir/instructions.rs":"7fe853efeb0379486d7878f7925962144ce208d230107d83e5a9165997a07587","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"b80c4609e6101228b6d7fa341b60730137ecdcc2f918120f6473dbf62f31b9ad","src/ir/libcall.rs":"3e540afdd1d9a68b1be0ddb983a8db39312a052aae9ba92fb2440746f69fef06","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"7590a2035a6f88a830e6c440d3c5a22102e921445806d04627e46ee42d82d167","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"8cfe8028008c93c37a593e82c230f95e8674d727cce5715aa55c93e140da4ced","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"bf862e984034f09a83bf0f5f18eb93e09cb23f1a5a994b554c478d174d672c64","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"49b7f398ec8baa2802a283f780bd039e2a630591e74cf1dddc8d9147345c2816","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"56dfbf8f23a82942566d2a81deaf2147777061b3b49532b4f9fdcd3aae51aa56","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"79ecb214ca28d4690b2ace20f6d4cdc36f393ef03f679a9d18a03653d230e160","src/isa/registers.rs":"004b090b7390fa07c1add81ef4a8c79bd7a6001a22cb014a4a83a9fa6ae3aeca","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"41136889df9512d8311f8c015cf3f654557a17d784a17fcefeb0afa2f0ec3674","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"13013f247c8e0fca46fe43568ef3186616fa469a321dee0a41fc2cc25220ec10","src/isa/x86/binemit.rs":"75d88b4ce66ec125940a2543a28e975c542a81a841c3c81282fc98ef78c1e032","src/isa/x86/enc_tables.rs":"ad7e3e384a784c24cc9750bb75f16f3b1cc231ae8f34b6b5d4138ee76d66b2cc","src/isa/x86/mod.rs":"d69e7f441c049b87aa1820639aaf12436bde1b0286757b03bec19fe7492049cc","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"6040ed7db062885093ba2e2881194d8025c76719994e24cf8c2570f01abd2a0f","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"7911a03e4229fa6ea371b714b3a50b677adbeeab749b8809bf29fe298cd9d7ff","src/legalizer/split.rs":"2b61ece481f40aa5b706e40056aec66bd1cd8e97072391b0d72b74e37ebbc251","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"357c72bc31010fdf0e412000efd7e5538a36361f8562accec6a60e750c111876","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"2d62e2f25a6c4327e75716a5f3508edf810c4957d0b20d855ed5a865359c8dfb","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/branch_splitting.rs":"50ff6a6d257a9cb35d302ed61fa45ff1be4d2ff0f695aa2cedd161bd725a598c","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"6308e0f4f71b24e8d5abc94a98c4d20eff753c02238872119c7f4390f026e0a4","src/regalloc/context.rs":"0b3d5009c23b58cc9ccca2ece9d85dbdea52f843f52452e7813dd7a3229547d3","src/regalloc/diversion.rs":"49edbe958591acb304093e601179de7a79de0a4557748b98ddb736a865ef6a43","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"50399d6569687a87bf1481304aca42506d946e34465e38ca8093e06485ab5fb6","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"739909ac35f48619d67f161ffec30c398d6839797ebea00ba5abd4b0ad0065f0","src/regalloc/reload.rs":"0dc6620ac72545065c14fda91f37bbe7904bf8f99e578d5fe532f1ccc76b9b21","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"3e133a4cd81a029cf34cc329fcaa0169ce6ce4a8642eb5b24faabc4a8a120191","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"865d5cdd7a6e87c8a2e5d41f89ba9c1a95531653363fd43c19a4d80b309534d8","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"a9bbb526efd0f88f35448d2d560cc41c2d804cca46ca1973d2be9e508c016c65","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"f54526eecc1ddc07069900bd3fbcf998abbfb594582bd700423c50ee5fba34b8","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"d3f4422bdea00f1efe7f2b35384f8e3dfa609dee5eae629721d45bedfe087e9f","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"05db00e49552a1ca6cfa0e8ccf38d35778edd0ececc4f20a50b0fb81b37a8312","src/verifier/mod.rs":"8162be3e9008dd661075700285bc9ef39ea0dd152d5fd66c64cf578c214c155d","src/write.rs":"35dff9d0f5ed74779e536cbc6b1de7381cec521a0c54f6d8513041d118bbfc4b"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-codegen/Cargo.toml b/third_party/rust/cranelift-codegen/Cargo.toml index 868db6ca3b26c..2d81a660e84ee 100644 --- a/third_party/rust/cranelift-codegen/Cargo.toml +++ b/third_party/rust/cranelift-codegen/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-codegen" -version = "0.40.0" +version = "0.42.0" description = "Low-level code generator library" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" @@ -13,21 +13,22 @@ build = "build.rs" edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift-entity", version = "0.40.0", default-features = false } -cranelift-bforest = { path = "../cranelift-bforest", version = "0.40.0", default-features = false } +cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false } +cranelift-bforest = { path = "../cranelift-bforest", version = "0.42.0", default-features = false } failure = { version = "0.1.1", default-features = false, features = ["derive"] } failure_derive = { version = "0.1.1", default-features = false } hashmap_core = { version = "0.1.9", optional = true } -target-lexicon = { version = "0.4.0", default-features = false } +target-lexicon = "0.8.1" log = { version = "0.4.6", default-features = false } serde = { version = "1.0.94", features = ["derive"], optional = true } +smallvec = { version = "0.6.10" } # It is a goal of the cranelift-codegen crate to have minimal external dependencies. # Please don't add any unless they are essential to the task of creating binary # machine code. Integration tests that need external dependencies can be # accomodated in `tests`. [build-dependencies] -cranelift-codegen-meta = { path = "meta", version = "0.40.0", default-features = false } +cranelift-codegen-meta = { path = "meta", version = "0.42.0", default-features = false } [features] default = ["std"] @@ -38,7 +39,6 @@ default = ["std"] std = [ "cranelift-entity/std", "cranelift-bforest/std", - "target-lexicon/std", "cranelift-codegen-meta/std" ] diff --git a/third_party/rust/cranelift-codegen/src/binemit/mod.rs b/third_party/rust/cranelift-codegen/src/binemit/mod.rs index e5d0cbbec55ff..0123e4dbd3020 100644 --- a/third_party/rust/cranelift-codegen/src/binemit/mod.rs +++ b/third_party/rust/cranelift-codegen/src/binemit/mod.rs @@ -133,7 +133,7 @@ pub trait CodeSink { /// Add a relocation referencing an external symbol plus the addend at the current offset. fn reloc_external(&mut self, _: Reloc, _: &ExternalName, _: Addend); - /// Add a relocation referencing a jump table. + /// Add a relocation referencing a constant. fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset); /// Add a relocation referencing a jump table. @@ -176,7 +176,7 @@ where { let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { - divert.clear(); + divert.at_ebb(&func.entry_diversions, ebb); debug_assert_eq!(func.offsets[ebb], sink.offset()); for inst in func.layout.ebb_insts(ebb) { emit_inst(func, inst, &mut divert, sink, isa); @@ -185,7 +185,7 @@ where sink.begin_jumptables(); - // output jump tables + // Output jump tables. for (jt, jt_data) in func.jump_tables.iter() { let jt_offset = func.jt_offsets[jt]; for ebb in jt_data.iter() { @@ -196,7 +196,7 @@ where sink.begin_rodata(); - // output constants + // Output constants. for (_, constant_data) in func.dfg.constants.iter() { for byte in constant_data.iter() { sink.put1(*byte) diff --git a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs index 1fdf51ea0e04c..43f361885a717 100644 --- a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs +++ b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs @@ -74,7 +74,7 @@ pub fn relax_branches( { let mut cur = FuncCursor::new(func); while let Some(ebb) = cur.next_ebb() { - divert.clear(); + divert.at_ebb(&cur.func.entry_diversions, ebb); cur.func.offsets[ebb] = offset; while let Some(inst) = cur.next_inst() { divert.apply(&cur.func.dfg[inst]); @@ -93,7 +93,8 @@ pub fn relax_branches( // Visit all instructions in layout order. let mut cur = FuncCursor::new(func); while let Some(ebb) = cur.next_ebb() { - divert.clear(); + divert.at_ebb(&cur.func.entry_diversions, ebb); + // Record the offset for `ebb` and make sure we iterate until offsets are stable. if cur.func.offsets[ebb] != offset { cur.func.offsets[ebb] = offset; @@ -128,8 +129,7 @@ pub fn relax_branches( for (jt, jt_data) in func.jump_tables.iter() { func.jt_offsets[jt] = offset; - // TODO: this should be computed based on the min size needed to hold - // the furthest branch. + // TODO: this should be computed based on the min size needed to hold the furthest branch. offset += jt_data.len() as u32 * 4; } @@ -168,6 +168,14 @@ fn try_fold_redundant_jump( } }; + // For the moment, only attempt to fold a branch to an ebb that is parameterless. + // These blocks are mainly produced by critical edge splitting. + // + // TODO: Allow folding blocks that define SSA values and function as phi nodes. + if func.dfg.num_ebb_params(first_dest) != 0 { + return false; + } + // Look at the first instruction of the first branch's destination. // If it is an unconditional branch, maybe the second jump can be bypassed. let second_inst = func.layout.first_inst(first_dest).expect("Instructions"); diff --git a/third_party/rust/cranelift-codegen/src/binemit/shrink.rs b/third_party/rust/cranelift-codegen/src/binemit/shrink.rs index 0f9838c8abd15..084ed2bc3dd99 100644 --- a/third_party/rust/cranelift-codegen/src/binemit/shrink.rs +++ b/third_party/rust/cranelift-codegen/src/binemit/shrink.rs @@ -20,7 +20,9 @@ pub fn shrink_instructions(func: &mut Function, isa: &dyn TargetIsa) { let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { - divert.clear(); + // Load diversions from predecessors. + divert.at_ebb(&func.entry_diversions, ebb); + for inst in func.layout.ebb_insts(ebb) { let enc = func.encodings[inst]; if enc.is_legal() { diff --git a/third_party/rust/cranelift-codegen/src/context.rs b/third_party/rust/cranelift-codegen/src/context.rs index 3953f7e4d43d3..0f4e9ad420cbe 100644 --- a/third_party/rust/cranelift-codegen/src/context.rs +++ b/third_party/rust/cranelift-codegen/src/context.rs @@ -33,6 +33,7 @@ use crate::timing; use crate::unreachable_code::eliminate_unreachable_code; use crate::value_label::{build_value_labels_ranges, ComparableSourceLoc, ValueLabelsRanges}; use crate::verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult}; +use log::debug; use std::vec::Vec; /// Persistent data structures and compilation pipeline. @@ -129,6 +130,7 @@ impl Context { pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult { let _tt = timing::compile(); self.verify_if(isa)?; + debug!("Compiling:\n{}", self.func.display(isa)); self.compute_cfg(); if isa.flags().opt_level() != OptLevel::Fastest { @@ -158,7 +160,10 @@ impl Context { self.redundant_reload_remover(isa)?; self.shrink_instructions(isa)?; } - self.relax_branches(isa) + let result = self.relax_branches(isa); + + debug!("Compiled:\n{}", self.func.display(isa)); + result } /// Emit machine code directly into raw memory. @@ -212,7 +217,7 @@ impl Context { /// Run the locations verifier on the function. pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> { let mut errors = VerifierErrors::default(); - let _ = verify_locations(isa, &self.func, None, &mut errors); + let _ = verify_locations(isa, &self.func, &self.cfg, None, &mut errors); if errors.is_empty() { Ok(()) @@ -238,7 +243,7 @@ impl Context { /// Perform pre-legalization rewrites on the function. pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { - do_preopt(&mut self.func, &mut self.cfg); + do_preopt(&mut self.func, &mut self.cfg, isa); self.verify_if(isa)?; Ok(()) } @@ -256,6 +261,7 @@ impl Context { self.domtree.clear(); self.loop_analysis.clear(); legalize_function(&mut self.func, &mut self.cfg, isa); + debug!("Legalized:\n{}", self.func.display(isa)); self.verify_if(isa) } @@ -318,7 +324,7 @@ impl Context { /// Run the register allocator. pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { self.regalloc - .run(isa, &mut self.func, &self.cfg, &mut self.domtree) + .run(isa, &mut self.func, &mut self.cfg, &mut self.domtree) } /// Insert prologue and epilogues after computing the stack frame layout. diff --git a/third_party/rust/cranelift-codegen/src/dominator_tree.rs b/third_party/rust/cranelift-codegen/src/dominator_tree.rs index feea33a0ef0ff..8191c310ebcbb 100644 --- a/third_party/rust/cranelift-codegen/src/dominator_tree.rs +++ b/third_party/rust/cranelift-codegen/src/dominator_tree.rs @@ -226,7 +226,13 @@ impl DominatorTree { /// Allocate and compute a dominator tree. pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self { - let mut domtree = Self::new(); + let ebb_capacity = func.layout.ebb_capacity(); + let mut domtree = Self { + nodes: SecondaryMap::with_capacity(ebb_capacity), + postorder: Vec::with_capacity(ebb_capacity), + stack: Vec::new(), + valid: false, + }; domtree.compute(func, cfg); domtree } diff --git a/third_party/rust/cranelift-codegen/src/ir/constant.rs b/third_party/rust/cranelift-codegen/src/ir/constant.rs index 50e93df1abf3d..c22380db55349 100644 --- a/third_party/rust/cranelift-codegen/src/ir/constant.rs +++ b/third_party/rust/cranelift-codegen/src/ir/constant.rs @@ -1,9 +1,12 @@ //! Constants //! -//! The constant pool defined here allows cranelift to avoid emitting the same constant multiple -//! times. As constants are inserted in the pool, a handle is returned; the handle is a cranelift -//! Entity. Inserting the same data multiple times will always return the same handle. Future work -//! could include: ensuring alignment of constants within the pool, bucketing constants by size. +//! The constant pool defined here allows Cranelift to avoid emitting the same constant multiple +//! times. As constants are inserted in the pool, a handle is returned; the handle is a Cranelift +//! Entity. Inserting the same data multiple times will always return the same handle. +//! +//! Future work could include: +//! - ensuring alignment of constants within the pool, +//! - bucketing constants by size. use crate::ir::Constant; use cranelift_entity::EntityRef; @@ -19,8 +22,8 @@ pub type ConstantOffset = u32; /// Inner type for storing data and offset together in the constant pool. The offset is optional /// because it must be set relative to the function code size (i.e. constants are emitted after the /// function body); because the function is not yet compiled when constants are inserted, -/// [`set_offset`](crate::ir::ConstantPool::set_offset) must be called once a constant's -/// offset from the beginning of the function is known (see +/// [`set_offset`](crate::ir::ConstantPool::set_offset) must be called once a constant's offset +/// from the beginning of the function is known (see /// [`relaxation.rs`](crate::binemit::relaxation)). #[derive(Clone)] pub struct ConstantPoolEntry { @@ -30,7 +33,7 @@ pub struct ConstantPoolEntry { impl ConstantPoolEntry { fn new(data: ConstantData) -> Self { - ConstantPoolEntry { data, offset: None } + Self { data, offset: None } } /// Return the size of the constant at this entry. @@ -44,21 +47,23 @@ impl ConstantPoolEntry { } } -/// Maintains the mapping between a constant handle (i.e. -/// [`Constant`](crate::ir::Constant)) and its constant data (i.e. -/// [`ConstantData`](crate::ir::ConstantData)). +/// Maintains the mapping between a constant handle (i.e. [`Constant`](crate::ir::Constant)) and +/// its constant data (i.e. [`ConstantData`](crate::ir::ConstantData)). #[derive(Clone)] pub struct ConstantPool { - /// This mapping maintains the insertion order as long as Constants are created with sequentially increasing integers. + /// This mapping maintains the insertion order as long as Constants are created with + /// sequentially increasing integers. handles_to_values: BTreeMap, - /// This mapping is unordered (no need for lexicographic ordering) but allows us to map constant data back to handles. + + /// This mapping is unordered (no need for lexicographic ordering) but allows us to map + /// constant data back to handles. values_to_handles: HashMap, } impl ConstantPool { /// Create a new constant pool instance. pub fn new() -> Self { - ConstantPool { + Self { handles_to_values: BTreeMap::new(), values_to_handles: HashMap::new(), } @@ -75,10 +80,7 @@ impl ConstantPool { /// returned. pub fn insert(&mut self, constant_value: ConstantData) -> Constant { if self.values_to_handles.contains_key(&constant_value) { - self.values_to_handles - .get(&constant_value) - .expect("A constant handle must have a corresponding constant value; this is an implementation error in ConstantPool") - .clone() + self.values_to_handles.get(&constant_value).unwrap().clone() } else { let constant_handle = Constant::new(self.len()); self.values_to_handles @@ -94,16 +96,17 @@ impl ConstantPool { /// Retrieve the constant data given a handle. pub fn get(&self, constant_handle: Constant) -> &ConstantData { assert!(self.handles_to_values.contains_key(&constant_handle)); - &self.handles_to_values - .get(&constant_handle) - .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?") - .data + &self.handles_to_values.get(&constant_handle).unwrap().data } /// Assign an offset to a given constant, where the offset is the number of bytes from the /// beginning of the function to the beginning of the constant data inside the pool. pub fn set_offset(&mut self, constant_handle: Constant, constant_offset: ConstantOffset) { - assert!(self.handles_to_values.contains_key(&constant_handle), "A constant handle must have already been inserted into the pool; perhaps a constant pool was created outside of the pool?"); + assert!( + self.handles_to_values.contains_key(&constant_handle), + "A constant handle must have already been inserted into the pool; perhaps a \ + constant pool was created outside of the pool?" + ); self.handles_to_values .entry(constant_handle) .and_modify(|e| e.offset = Some(constant_offset)); @@ -112,10 +115,17 @@ impl ConstantPool { /// Retrieve the offset of a given constant, where the offset is the number of bytes from the /// beginning of the function to the beginning of the constant data inside the pool. pub fn get_offset(&self, constant_handle: Constant) -> ConstantOffset { - self.handles_to_values.get(&constant_handle) - .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?") + self.handles_to_values + .get(&constant_handle) + .expect( + "A constant handle must have a corresponding constant value; was a constant \ + handle created outside of the pool?", + ) .offset - .expect("A constant offset has not yet been set; verify that `set_offset` has been called before this point") + .expect( + "A constant offset has not yet been set; verify that `set_offset` has been \ + called before this point", + ) } /// Iterate over the constants in insertion order. diff --git a/third_party/rust/cranelift-codegen/src/ir/dfg.rs b/third_party/rust/cranelift-codegen/src/ir/dfg.rs index 7392e893e7ec6..24eeff4eec7b9 100644 --- a/third_party/rust/cranelift-codegen/src/ir/dfg.rs +++ b/third_party/rust/cranelift-codegen/src/ir/dfg.rs @@ -1239,7 +1239,6 @@ mod tests { #[test] fn aliases() { - use crate::ir::condcodes::IntCC; use crate::ir::InstBuilder; let mut func = Function::new(); @@ -1264,9 +1263,9 @@ mod tests { pos.func.dfg.clear_results(iadd); pos.func.dfg.attach_result(iadd, s); - // Replace `iadd_cout` with a normal `iadd` and an `icmp`. + // Replace `iadd_cout` with a normal `iadd` and an `ifcmp`. pos.func.dfg.replace(iadd).iadd(v1, arg0); - let c2 = pos.ins().icmp(IntCC::UnsignedLessThan, s, v1); + let c2 = pos.ins().ifcmp(s, v1); pos.func.dfg.change_to_alias(c, c2); assert_eq!(pos.func.dfg.resolve_aliases(c2), c2); diff --git a/third_party/rust/cranelift-codegen/src/ir/function.rs b/third_party/rust/cranelift-codegen/src/ir/function.rs index 1dcdeee91c45d..00827240d976a 100644 --- a/third_party/rust/cranelift-codegen/src/ir/function.rs +++ b/third_party/rust/cranelift-codegen/src/ir/function.rs @@ -14,7 +14,7 @@ use crate::ir::{ use crate::ir::{EbbOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations}; use crate::ir::{JumpTableOffsets, JumpTables}; use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa}; -use crate::regalloc::RegDiversions; +use crate::regalloc::{EntryRegDiversions, RegDiversions}; use crate::value_label::ValueLabelsRanges; use crate::write::write_function; use core::fmt; @@ -62,6 +62,12 @@ pub struct Function { /// Location assigned to every value. pub locations: ValueLocations, + /// Non-default locations assigned to value at the entry of basic blocks. + /// + /// At the entry of each basic block, we might have values which are not in their default + /// ValueLocation. This field records these register-to-register moves as Diversions. + pub entry_diversions: EntryRegDiversions, + /// Code offsets of the EBB headers. /// /// This information is only transiently available after the `binemit::relax_branches` function @@ -94,6 +100,7 @@ impl Function { layout: Layout::new(), encodings: SecondaryMap::new(), locations: SecondaryMap::new(), + entry_diversions: EntryRegDiversions::new(), offsets: SecondaryMap::new(), jt_offsets: SecondaryMap::new(), srclocs: SecondaryMap::new(), @@ -112,6 +119,7 @@ impl Function { self.layout.clear(); self.encodings.clear(); self.locations.clear(); + self.entry_diversions.clear(); self.offsets.clear(); self.jt_offsets.clear(); self.srclocs.clear(); @@ -198,10 +206,12 @@ impl Function { !self.offsets.is_empty(), "Code layout must be computed first" ); + let mut divert = RegDiversions::new(); + divert.at_ebb(&self.entry_diversions, ebb); InstOffsetIter { encinfo: encinfo.clone(), func: self, - divert: RegDiversions::new(), + divert, encodings: &self.encodings, offset: self.offsets[ebb], iter: self.layout.ebb_insts(ebb), diff --git a/third_party/rust/cranelift-codegen/src/ir/immediates.rs b/third_party/rust/cranelift-codegen/src/ir/immediates.rs index 8917d96d4b989..2c5ee27c473ae 100644 --- a/third_party/rust/cranelift-codegen/src/ir/immediates.rs +++ b/third_party/rust/cranelift-codegen/src/ir/immediates.rs @@ -5,9 +5,29 @@ //! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language. use core::fmt::{self, Display, Formatter}; +use core::iter::FromIterator; use core::mem; -use core::str::FromStr; +use core::str::{from_utf8, FromStr}; use core::{i32, u32}; +use std::vec::Vec; + +/// Convert a type into a vector of bytes; all implementors in this file must use little-endian +/// orderings of bytes to match WebAssembly's little-endianness. +trait IntoBytes { + fn into_bytes(self) -> Vec; +} + +impl IntoBytes for u8 { + fn into_bytes(self) -> Vec { + vec![self] + } +} + +impl IntoBytes for i32 { + fn into_bytes(self) -> Vec { + self.to_le_bytes().to_vec() + } +} /// 64-bit immediate signed integer operand. /// @@ -34,6 +54,12 @@ impl Into for Imm64 { } } +impl IntoBytes for Imm64 { + fn into_bytes(self) -> Vec { + self.0.to_le_bytes().to_vec() + } +} + impl From for Imm64 { fn from(x: i64) -> Self { Imm64(x) @@ -266,12 +292,29 @@ impl FromStr for Uimm32 { /// A 128-bit unsigned integer immediate operand. /// -/// This is used as an immediate value in SIMD instructions +/// This is used as an immediate value in SIMD instructions. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct Uimm128(pub [u8; 16]); +impl Uimm128 { + /// Iterate over the bytes in the constant + pub fn bytes(&self) -> impl Iterator { + self.0.iter() + } + + /// Convert the immediate into a vector + pub fn to_vec(self) -> Vec { + self.0.to_vec() + } + + /// Convert the immediate into a slice + pub fn as_slice(&self) -> &[u8] { + &self.0[..] + } +} + impl Display for Uimm128 { - // print a 128-bit vector in hexadecimal, e.g. 0x000102030405060708090a0b0c0d0e0f + // Print a 128-bit vector in hexadecimal, e.g. 0x000102030405060708090a0b0c0d0e0f. fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "0x")?; let mut anything_written = false; @@ -314,24 +357,84 @@ impl FromStr for Uimm128 { fn from_str(s: &str) -> Result { if s.len() <= 2 || &s[0..2] != "0x" { Err("Expected a hexadecimal string, e.g. 0x1234") - } else if s.len() % 2 != 0 { - Err("Hexadecimal string must have an even number of digits") - } else if s.len() > 34 { - Err("Hexadecimal string has too many digits to fit in a 128-bit vector") } else { - let mut buffer = [0; 16]; // zero-fill - let start_at = s.len() / 2 - 1; - for i in (2..s.len()).step_by(2) { - let byte = u8::from_str_radix(&s[i..i + 2], 16) - .or_else(|_| Err("Unable to parse as hexadecimal"))?; - let position = start_at - (i / 2); - buffer[position] = byte; + // clean and check the string + let cleaned: Vec = s[2..] + .as_bytes() + .iter() + .filter(|&&b| b as char != '_') + .cloned() + .collect(); // remove 0x prefix and any intervening _ characters + + if cleaned.len() == 0 { + Err("Hexadecimal string must have some digits") + } else if cleaned.len() % 2 != 0 { + Err("Hexadecimal string must have an even number of digits") + } else if cleaned.len() > 32 { + Err("Hexadecimal string has too many digits to fit in a 128-bit vector") + } else { + let mut buffer = [0; 16]; // zero-fill the buffer + let mut position = cleaned.len() / 2 - 1; // since Uimm128 is little-endian but the string is not, we write from back to front but must start at the highest position required by the string + for i in (0..cleaned.len()).step_by(2) { + let pair = from_utf8(&cleaned[i..i + 2]) + .or_else(|_| Err("Unable to parse hexadecimal pair as UTF-8"))?; + let byte = u8::from_str_radix(pair, 16) + .or_else(|_| Err("Unable to parse as hexadecimal"))?; + buffer[position] = byte; + position = position.wrapping_sub(1); // should only wrap on the last iteration + } + + Ok(Uimm128(buffer)) + } + } + } +} + +/// Implement a way to convert an iterator of immediates to a Uimm128: +/// - this expects the items in reverse order (e.g. last lane first) which is the natural output of pushing items into a vector +/// - this may not fully consume the iterator or may fail if it cannot take the expected number of items +/// - this requires the input type (i.e. $ty) to implement ToBytes +macro_rules! construct_uimm128_from_iterator_of { + ( $ty:ident, $lanes:expr ) => { + impl FromIterator<$ty> for Uimm128 { + fn from_iter>(iter: T) -> Self { + let mut buffer: [u8; 16] = [0; 16]; + iter.into_iter() + .take($lanes) + .map(|f| f.into_bytes()) + .flat_map(|b| b) + .enumerate() + .for_each(|(i, b)| buffer[i] = b); + Uimm128(buffer) } - Ok(Uimm128(buffer)) } + }; +} + +/// Special case for booleans since we have to decide the bit-width based on the number of items +impl FromIterator for Uimm128 { + fn from_iter>(iter: T) -> Self { + let bools = Vec::from_iter(iter); + let count = bools.len(); + assert!(count > 0 && count <= 16); // ensure we don't have too many booleans + assert_eq!(count & (count - 1), 0); // ensure count is a power of two, see https://stackoverflow.com/questions/600293 + let mut buffer: [u8; 16] = [0; 16]; + let step = 16 / count; + bools + .iter() + .enumerate() + .map(|(i, &b)| (i * step, if b { 1 } else { 0 })) + .for_each(|(i, b)| buffer[i] = b); + Uimm128(buffer) } } +construct_uimm128_from_iterator_of!(u8, 16); +construct_uimm128_from_iterator_of!(i32, 4); +construct_uimm128_from_iterator_of!(Ieee32, 4); +construct_uimm128_from_iterator_of!(Imm64, 2); +construct_uimm128_from_iterator_of!(Ieee64, 2); + /// 32-bit signed immediate offset. /// /// This is used to encode an immediate offset for load/store instructions. All supported ISAs have @@ -739,6 +842,12 @@ impl From for Ieee32 { } } +impl IntoBytes for Ieee32 { + fn into_bytes(self) -> Vec { + self.0.to_le_bytes().to_vec() + } +} + impl Ieee64 { /// Create a new `Ieee64` containing the bits of `x`. pub fn with_bits(x: u64) -> Self { @@ -812,6 +921,12 @@ impl From for Ieee64 { } } +impl IntoBytes for Ieee64 { + fn into_bytes(self) -> Vec { + self.0.to_le_bytes().to_vec() + } +} + #[cfg(test)] mod tests { use super::*; @@ -968,9 +1083,10 @@ mod tests { parse_ok::("0x00", "0x00"); parse_ok::("0x00000042", "0x42"); parse_ok::( - "0x0102030405060708090a0b0c0d0e0f", - "0x0102030405060708090a0b0c0d0e0f", + "0x0102030405060708090a0b0c0d0e0f00", + "0x0102030405060708090a0b0c0d0e0f00", ); + parse_ok::("0x_0000_0043_21", "0x4321"); parse_err::("", "Expected a hexadecimal string, e.g. 0x1234"); parse_err::("0x", "Expected a hexadecimal string, e.g. 0x1234"); @@ -982,6 +1098,24 @@ mod tests { "0x00000000000000000000000000000000000000000000000000", "Hexadecimal string has too many digits to fit in a 128-bit vector", ); + parse_err::("0xrstu", "Unable to parse as hexadecimal"); + parse_err::("0x__", "Hexadecimal string must have some digits"); + } + + #[test] + fn uimm128_equivalence() { + assert_eq!( + "0x01".parse::().unwrap().0, + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + Uimm128::from_iter(vec![1, 0, 0, 0]).0, + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + Uimm128::from(1).0, + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); } #[test] @@ -997,6 +1131,50 @@ mod tests { assert_eq!( "0x12345678".parse::().unwrap().0, [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + "0x1234_5678".parse::().unwrap().0, + [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + } + + #[test] + fn uimm128_from_iter() { + assert_eq!( + Uimm128::from_iter(vec![4, 3, 2, 1]).0, + [4, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0] + ); + + assert_eq!( + Uimm128::from_iter(vec![false, true]).0, + [/* false */ 0, 0, 0, 0, 0, 0, 0, 0, /* true */ 1, 0, 0, 0, 0, 0, 0, 0] + ); + + assert_eq!( + Uimm128::from_iter(vec![false, true, false, true, false, true, false, true]).0, + [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0] + ); + + #[allow(trivial_numeric_casts)] + let u8s = vec![ + 1 as u8, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, + ]; + assert_eq!( + Uimm128::from_iter(u8s).0, + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0] + ); + + #[allow(trivial_numeric_casts)] + let ieee32s: Vec = vec![32.4 as f32, 0.0, 1.0, 6.6666] + .iter() + .map(|&f| Ieee32::from(f)) + .collect(); + assert_eq!( + Uimm128::from_iter(ieee32s).0, + [ + /* 32.4 == */ 0x9a, 0x99, 0x01, 0x42, /* 0 == */ 0, 0, 0, 0, + /* 1 == */ 0, 0, 0x80, 0x3f, /* 6.6666 == */ 0xca, 0x54, 0xd5, 0x40, + ] ) } diff --git a/third_party/rust/cranelift-codegen/src/ir/layout.rs b/third_party/rust/cranelift-codegen/src/ir/layout.rs index e1015f7f3f253..78a46285767ee 100644 --- a/third_party/rust/cranelift-codegen/src/ir/layout.rs +++ b/third_party/rust/cranelift-codegen/src/ir/layout.rs @@ -60,6 +60,11 @@ impl Layout { self.first_ebb = None; self.last_ebb = None; } + + /// Returns the capacity of the `EbbData` map. + pub fn ebb_capacity(&self) -> usize { + self.ebbs.capacity() + } } /// Sequence numbers. diff --git a/third_party/rust/cranelift-codegen/src/ir/libcall.rs b/third_party/rust/cranelift-codegen/src/ir/libcall.rs index 59fb951a32e27..1e19891221fa3 100644 --- a/third_party/rust/cranelift-codegen/src/ir/libcall.rs +++ b/third_party/rust/cranelift-codegen/src/ir/libcall.rs @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize}; /// convention in the embedding VM's runtime library. /// /// This list is likely to grow over time. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum LibCall { /// probe for stack overflow. These are emitted for functions which need diff --git a/third_party/rust/cranelift-codegen/src/ir/types.rs b/third_party/rust/cranelift-codegen/src/ir/types.rs index 4eb72f3fc0aca..10fca8aaa896d 100644 --- a/third_party/rust/cranelift-codegen/src/ir/types.rs +++ b/third_party/rust/cranelift-codegen/src/ir/types.rs @@ -10,11 +10,11 @@ use target_lexicon::{PointerWidth, Triple}; /// field is present put no type is needed, such as the controlling type variable for a /// non-polymorphic instruction. /// -/// Basic integer types: `I8`, `I16`, `I32`, and `I64`. These types are sign-agnostic. +/// Basic integer types: `I8`, `I16`, `I32`, `I64`, and `I128`. These types are sign-agnostic. /// /// Basic floating point types: `F32` and `F64`. IEEE single and double precision. /// -/// Boolean types: `B1`, `B8`, `B16`, `B32`, and `B64`. These all encode 'true' or 'false'. The +/// Boolean types: `B1`, `B8`, `B16`, `B32`, `B64`, and `B128`. These all encode 'true' or 'false'. The /// larger types use redundant bits. /// /// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type. @@ -63,6 +63,7 @@ impl Type { B16 | I16 => 4, B32 | I32 | F32 | R32 => 5, B64 | I64 | F64 | R64 => 6, + B128 | I128 => 7, _ => 0, } } @@ -75,6 +76,7 @@ impl Type { B16 | I16 => 16, B32 | I32 | F32 | R32 => 32, B64 | I64 | F64 | R64 => 64, + B128 | I128 => 128, _ => 0, } } @@ -86,6 +88,7 @@ impl Type { 16 => Some(I16), 32 => Some(I32), 64 => Some(I64), + 128 => Some(I128), _ => None, } } @@ -109,6 +112,7 @@ impl Type { B32 | I32 | F32 => B32, B64 | I64 | F64 => B64, R32 | R64 => panic!("Reference types should not convert to bool"), + B128 | I128 => B128, _ => B1, }) } @@ -132,10 +136,12 @@ impl Type { I16 => I8, I32 => I16, I64 => I32, + I128 => I64, F64 => F32, B16 => B8, B32 => B16, B64 => B32, + B128 => B64, _ => return None, })) } @@ -147,10 +153,12 @@ impl Type { I8 => I16, I16 => I32, I32 => I64, + I64 => I128, F32 => F64, B8 => B16, B16 => B32, B32 => B64, + B64 => B128, _ => return None, })) } @@ -182,7 +190,7 @@ impl Type { /// Is this a scalar boolean type? pub fn is_bool(self) -> bool { match self { - B1 | B8 | B16 | B32 | B64 => true, + B1 | B8 | B16 | B32 | B64 | B128 => true, _ => false, } } @@ -190,7 +198,7 @@ impl Type { /// Is this a scalar integer type? pub fn is_int(self) -> bool { match self { - I8 | I16 | I32 | I64 => true, + I8 | I16 | I32 | I64 | I128 => true, _ => false, } } @@ -370,10 +378,12 @@ mod tests { assert_eq!(B16, B16.lane_type()); assert_eq!(B32, B32.lane_type()); assert_eq!(B64, B64.lane_type()); + assert_eq!(B128, B128.lane_type()); assert_eq!(I8, I8.lane_type()); assert_eq!(I16, I16.lane_type()); assert_eq!(I32, I32.lane_type()); assert_eq!(I64, I64.lane_type()); + assert_eq!(I128, I128.lane_type()); assert_eq!(F32, F32.lane_type()); assert_eq!(F64, F64.lane_type()); assert_eq!(B1, B1.by(8).unwrap().lane_type()); @@ -390,10 +400,12 @@ mod tests { assert_eq!(B16.lane_bits(), 16); assert_eq!(B32.lane_bits(), 32); assert_eq!(B64.lane_bits(), 64); + assert_eq!(B128.lane_bits(), 128); assert_eq!(I8.lane_bits(), 8); assert_eq!(I16.lane_bits(), 16); assert_eq!(I32.lane_bits(), 32); assert_eq!(I64.lane_bits(), 64); + assert_eq!(I128.lane_bits(), 128); assert_eq!(F32.lane_bits(), 32); assert_eq!(F64.lane_bits(), 64); assert_eq!(R32.lane_bits(), 32); @@ -410,11 +422,13 @@ mod tests { assert_eq!(B16.half_width(), Some(B8)); assert_eq!(B32.half_width(), Some(B16)); assert_eq!(B64.half_width(), Some(B32)); + assert_eq!(B128.half_width(), Some(B64)); assert_eq!(I8.half_width(), None); assert_eq!(I16.half_width(), Some(I8)); assert_eq!(I32.half_width(), Some(I16)); assert_eq!(I32X4.half_width(), Some(I16X4)); assert_eq!(I64.half_width(), Some(I32)); + assert_eq!(I128.half_width(), Some(I64)); assert_eq!(F32.half_width(), None); assert_eq!(F64.half_width(), Some(F32)); @@ -425,12 +439,14 @@ mod tests { assert_eq!(B8.double_width(), Some(B16)); assert_eq!(B16.double_width(), Some(B32)); assert_eq!(B32.double_width(), Some(B64)); - assert_eq!(B64.double_width(), None); + assert_eq!(B64.double_width(), Some(B128)); + assert_eq!(B128.double_width(), None); assert_eq!(I8.double_width(), Some(I16)); assert_eq!(I16.double_width(), Some(I32)); assert_eq!(I32.double_width(), Some(I64)); assert_eq!(I32X4.double_width(), Some(I64X4)); - assert_eq!(I64.double_width(), None); + assert_eq!(I64.double_width(), Some(I128)); + assert_eq!(I128.double_width(), None); assert_eq!(F32.double_width(), Some(F64)); assert_eq!(F64.double_width(), None); } @@ -461,10 +477,12 @@ mod tests { assert_eq!(B16.to_string(), "b16"); assert_eq!(B32.to_string(), "b32"); assert_eq!(B64.to_string(), "b64"); + assert_eq!(B128.to_string(), "b128"); assert_eq!(I8.to_string(), "i8"); assert_eq!(I16.to_string(), "i16"); assert_eq!(I32.to_string(), "i32"); assert_eq!(I64.to_string(), "i64"); + assert_eq!(I128.to_string(), "i128"); assert_eq!(F32.to_string(), "f32"); assert_eq!(F64.to_string(), "f64"); assert_eq!(R32.to_string(), "r32"); diff --git a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs index fde3339700c94..ced1b88767e9c 100644 --- a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs +++ b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs @@ -42,14 +42,13 @@ fn isa_constructor( builder: shared_settings::Builder, ) -> Box { let level1 = match triple.architecture { - Architecture::Thumbv6m | Architecture::Thumbv7em | Architecture::Thumbv7m => { - &enc_tables::LEVEL1_T32[..] + Architecture::Arm(arm) => { + if arm.is_thumb() { + &enc_tables::LEVEL1_T32[..] + } else { + &enc_tables::LEVEL1_A32[..] + } } - Architecture::Arm - | Architecture::Armv4t - | Architecture::Armv5te - | Architecture::Armv7 - | Architecture::Armv7s => &enc_tables::LEVEL1_A32[..], _ => panic!(), }; Box::new(Isa { diff --git a/third_party/rust/cranelift-codegen/src/isa/call_conv.rs b/third_party/rust/cranelift-codegen/src/isa/call_conv.rs index dddd4bbd8a923..e834ad25159b1 100644 --- a/third_party/rust/cranelift-codegen/src/isa/call_conv.rs +++ b/third_party/rust/cranelift-codegen/src/isa/call_conv.rs @@ -31,6 +31,7 @@ impl CallConv { // uses System V. Ok(CallingConvention::SystemV) | Err(()) => CallConv::SystemV, Ok(CallingConvention::WindowsFastcall) => CallConv::WindowsFastcall, + Ok(unimp) => unimplemented!("calling convention: {:?}", unimp), } } diff --git a/third_party/rust/cranelift-codegen/src/isa/mod.rs b/third_party/rust/cranelift-codegen/src/isa/mod.rs index 407afc5f39430..c36d29ce2b742 100644 --- a/third_party/rust/cranelift-codegen/src/isa/mod.rs +++ b/third_party/rust/cranelift-codegen/src/isa/mod.rs @@ -66,7 +66,7 @@ use crate::timing; use core::fmt; use failure_derive::Fail; use std::boxed::Box; -use target_lexicon::{Architecture, PointerWidth, Triple}; +use target_lexicon::{triple, Architecture, PointerWidth, Triple}; #[cfg(feature = "riscv")] mod riscv; @@ -88,42 +88,41 @@ pub mod registers; mod stack; /// Returns a builder that can create a corresponding `TargetIsa` -/// or `Err(LookupError::Unsupported)` if not enabled. +/// or `Err(LookupError::SupportDisabled)` if not enabled. macro_rules! isa_builder { - ($name:ident, $feature:tt) => {{ + ($name: ident, $feature: tt, $triple: ident) => {{ #[cfg(feature = $feature)] - fn $name(triple: Triple) -> Result { - Ok($name::isa_builder(triple)) - }; + { + Ok($name::isa_builder($triple)) + } #[cfg(not(feature = $feature))] - fn $name(_triple: Triple) -> Result { - Err(LookupError::Unsupported) + { + Err(LookupError::SupportDisabled) } - $name }}; } -/// Look for a supported ISA with the given `name`. +/// Look for an ISA for the given `triple`. /// Return a builder that can create a corresponding `TargetIsa`. pub fn lookup(triple: Triple) -> Result { match triple.architecture { - Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv")(triple), + Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv", triple), Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => { - isa_builder!(x86, "x86")(triple) + isa_builder!(x86, "x86", triple) } - Architecture::Thumbv6m - | Architecture::Thumbv7em - | Architecture::Thumbv7m - | Architecture::Arm - | Architecture::Armv4t - | Architecture::Armv5te - | Architecture::Armv7 - | Architecture::Armv7s => isa_builder!(arm32, "arm32")(triple), - Architecture::Aarch64 => isa_builder!(arm64, "arm64")(triple), + Architecture::Arm { .. } => isa_builder!(arm32, "arm32", triple), + Architecture::Aarch64 { .. } => isa_builder!(arm64, "arm64", triple), _ => Err(LookupError::Unsupported), } } +/// Look for a supported ISA with the given `name`. +/// Return a builder that can create a corresponding `TargetIsa`. +pub fn lookup_by_name(name: &str) -> Result { + use std::str::FromStr; + lookup(triple!(name)) +} + /// Describes reason for target lookup failure #[derive(Fail, PartialEq, Eq, Copy, Clone, Debug)] pub enum LookupError { diff --git a/third_party/rust/cranelift-codegen/src/isa/registers.rs b/third_party/rust/cranelift-codegen/src/isa/registers.rs index 3c1b4262c1863..f7fcdcac2e727 100644 --- a/third_party/rust/cranelift-codegen/src/isa/registers.rs +++ b/third_party/rust/cranelift-codegen/src/isa/registers.rs @@ -154,6 +154,12 @@ pub struct RegClassData { /// The global `RegInfo` instance containing this register class. pub info: &'static RegInfo, + + /// The "pinned" register of the associated register bank. + /// + /// This register must be non-volatile (callee-preserved) and must not be the fixed + /// output register of any instruction. + pub pinned_reg: Option, } impl RegClassData { @@ -201,6 +207,15 @@ impl RegClassData { pub fn contains(&self, regunit: RegUnit) -> bool { self.mask[(regunit / 32) as usize] & (1u32 << (regunit % 32)) != 0 } + + /// If the pinned register is used, is the given regunit the pinned register of this class? + #[inline] + pub fn is_pinned_reg(&self, enabled: bool, regunit: RegUnit) -> bool { + enabled + && self + .pinned_reg + .map_or(false, |pinned_reg| pinned_reg == regunit) + } } impl fmt::Display for RegClassData { diff --git a/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs b/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs index 00729352294bd..6252a3fb77b0c 100644 --- a/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs +++ b/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs @@ -89,9 +89,8 @@ impl ArgAssigner for Args { let reg = FPR.unit(self.fpr_used); self.fpr_used += 1; return ArgumentLoc::Reg(reg).into(); - } else { - return ValueConversion::VectorSplit.into(); } + return ValueConversion::VectorSplit.into(); } // Large integers and booleans are broken down to fit in a register. @@ -229,7 +228,7 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { } /// Get the set of allocatable registers for `func`. -pub fn allocatable_registers(_func: &ir::Function, triple: &Triple) -> RegisterSet { +pub fn allocatable_registers(triple: &Triple, flags: &shared_settings::Flags) -> RegisterSet { let mut regs = RegisterSet::new(); regs.take(GPR, RU::rsp as RegUnit); regs.take(GPR, RU::rbp as RegUnit); @@ -240,6 +239,15 @@ pub fn allocatable_registers(_func: &ir::Function, triple: &Triple) -> RegisterS regs.take(GPR, GPR.unit(i)); regs.take(FPR, FPR.unit(i)); } + if flags.enable_pinned_reg() { + unimplemented!("Pinned register not implemented on x86-32."); + } + } else { + // Choose r15 as the pinned register on 64-bits: it is non-volatile on native ABIs and + // isn't the fixed output register of any instruction. + if flags.enable_pinned_reg() { + regs.take(GPR, RU::r15 as RegUnit); + } } regs diff --git a/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs b/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs index afe2c2611fc90..a5924ed030312 100644 --- a/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs +++ b/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs @@ -342,7 +342,7 @@ fn jt_disp4(jt: JumpTable, func: &Function, sink: &mut CS sink.reloc_jt(Reloc::X86PCRelRodata4, jt); } -/// Emit a four-byte displacement to `constant` +/// Emit a four-byte displacement to `constant`. fn const_disp4(constant: Constant, func: &Function, sink: &mut CS) { let offset = func.dfg.constants.get_offset(constant); let delta = offset.wrapping_sub(sink.offset() + 4); diff --git a/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs b/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs index e0fc05178dc1b..f67d7f0b69831 100644 --- a/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs +++ b/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs @@ -5,6 +5,7 @@ use crate::bitset::BitSet; use crate::cursor::{Cursor, FuncCursor}; use crate::flowgraph::ControlFlowGraph; use crate::ir::condcodes::{FloatCC, IntCC}; +use crate::ir::types::*; use crate::ir::{self, Function, Inst, InstBuilder}; use crate::isa::constraints::*; use crate::isa::enc_tables::*; @@ -893,3 +894,121 @@ fn expand_fcvt_to_uint_sat( cfg.recompute_ebb(pos.func, uint_large_ebb); cfg.recompute_ebb(pos.func, done); } + +/// Because floats already exist in XMM registers, we can keep them there when executing a CLIF +/// extractlane instruction +fn convert_extractlane( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + _isa: &dyn TargetIsa, +) { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + if let ir::InstructionData::ExtractLane { + opcode: ir::Opcode::Extractlane, + arg, + lane, + } = pos.func.dfg[inst] + { + // NOTE: the following legalization assumes that the upper bits of the XMM register do + // not need to be zeroed during extractlane. + let value_type = pos.func.dfg.value_type(arg); + if value_type.lane_type().is_float() { + // Floats are already in XMM registers and can stay there. + let shuffled = if lane != 0 { + // Replace the extractlane with a PSHUFD to get the float in the right place. + match value_type { + F32X4 => { + // Move the selected lane to the 0 lane. + let shuffle_mask: u8 = 0b00_00_00_00 | lane; + pos.ins().x86_pshufd(arg, shuffle_mask) + } + F64X2 => { + assert_eq!(lane, 1); + // Because we know the lane == 1, we move the upper 64 bits to the lower + // 64 bits, leaving the top 64 bits as-is. + let shuffle_mask = 0b11_10_11_10; + let bitcast = pos.ins().raw_bitcast(F32X4, arg); + pos.ins().x86_pshufd(bitcast, shuffle_mask) + } + _ => unreachable!(), + } + } else { + // Remove the extractlane instruction, leaving the float where it is. + arg + }; + // Then we must bitcast to the right type. + pos.func + .dfg + .replace(inst) + .raw_bitcast(value_type.lane_type(), shuffled); + } else { + // For non-floats, lower with the usual PEXTR* instruction. + pos.func.dfg.replace(inst).x86_pextr(arg, lane); + } + } +} + +/// Because floats exist in XMM registers, we can keep them there when executing a CLIF +/// insertlane instruction +fn convert_insertlane( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + _isa: &dyn TargetIsa, +) { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + if let ir::InstructionData::InsertLane { + opcode: ir::Opcode::Insertlane, + args: [vector, replacement], + lane, + } = pos.func.dfg[inst] + { + let value_type = pos.func.dfg.value_type(vector); + if value_type.lane_type().is_float() { + // Floats are already in XMM registers and can stay there. + match value_type { + F32X4 => { + assert!(lane > 0 && lane <= 3); + let immediate = 0b00_00_00_00 | lane << 4; + // Insert 32-bits from replacement (at index 00, bits 7:8) to vector (lane + // shifted into bits 5:6). + pos.func + .dfg + .replace(inst) + .x86_insertps(vector, immediate, replacement) + } + F64X2 => { + let replacement_as_vector = pos.ins().raw_bitcast(F64X2, replacement); // only necessary due to SSA types + if lane == 0 { + // Move the lowest quadword in replacement to vector without changing + // the upper bits. + pos.func + .dfg + .replace(inst) + .x86_movsd(vector, replacement_as_vector) + } else { + assert_eq!(lane, 1); + // Move the low 64 bits of replacement vector to the high 64 bits of the + // vector. + pos.func + .dfg + .replace(inst) + .x86_movlhps(vector, replacement_as_vector) + } + } + _ => unreachable!(), + }; + } else { + // For non-floats, lower with the usual PINSR* instruction. + pos.func + .dfg + .replace(inst) + .x86_pinsr(vector, lane, replacement); + } + } +} diff --git a/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs b/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs index 9244791ea8c80..52ab055440f74 100644 --- a/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs +++ b/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs @@ -119,8 +119,8 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet { - abi::allocatable_registers(func, &self.triple) + fn allocatable_registers(&self, _func: &ir::Function) -> regalloc::RegisterSet { + abi::allocatable_registers(&self.triple, &self.shared_flags) } #[cfg(feature = "testing_hooks")] diff --git a/third_party/rust/cranelift-codegen/src/legalizer/heap.rs b/third_party/rust/cranelift-codegen/src/legalizer/heap.rs index 33f37155ee316..dfada10dc5e4e 100644 --- a/third_party/rust/cranelift-codegen/src/legalizer/heap.rs +++ b/third_party/rust/cranelift-codegen/src/legalizer/heap.rs @@ -14,7 +14,7 @@ pub fn expand_heap_addr( inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph, - _isa: &dyn TargetIsa, + isa: &dyn TargetIsa, ) { // Unpack the instruction. let (heap, offset, access_size) = match func.dfg[inst] { @@ -32,16 +32,24 @@ pub fn expand_heap_addr( match func.heaps[heap].style { ir::HeapStyle::Dynamic { bound_gv } => { - dynamic_addr(inst, heap, offset, access_size, bound_gv, func) - } - ir::HeapStyle::Static { bound } => { - static_addr(inst, heap, offset, access_size, bound.into(), func, cfg) + dynamic_addr(isa, inst, heap, offset, access_size, bound_gv, func) } + ir::HeapStyle::Static { bound } => static_addr( + isa, + inst, + heap, + offset, + access_size, + bound.into(), + func, + cfg, + ), } } /// Expand a `heap_addr` for a dynamic heap. fn dynamic_addr( + isa: &dyn TargetIsa, inst: ir::Inst, heap: ir::Heap, offset: ir::Value, @@ -82,11 +90,12 @@ fn dynamic_addr( } pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds); - compute_addr(inst, heap, addr_ty, offset, offset_ty, pos.func); + compute_addr(isa, inst, heap, addr_ty, offset, offset_ty, pos.func); } /// Expand a `heap_addr` for a static heap. fn static_addr( + isa: &dyn TargetIsa, inst: ir::Inst, heap: ir::Heap, offset: ir::Value, @@ -134,11 +143,12 @@ fn static_addr( pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds); } - compute_addr(inst, heap, addr_ty, offset, offset_ty, pos.func); + compute_addr(isa, inst, heap, addr_ty, offset, offset_ty, pos.func); } /// Emit code for the base address computation of a `heap_addr` instruction. fn compute_addr( + isa: &dyn TargetIsa, inst: ir::Inst, heap: ir::Heap, addr_ty: ir::Type, @@ -165,7 +175,12 @@ fn compute_addr( } // Add the heap base address base - let base_gv = pos.func.heaps[heap].base; - let base = pos.ins().global_value(addr_ty, base_gv); + let base = if isa.flags().enable_pinned_reg() && isa.flags().use_pinned_reg_as_heap_base() { + pos.ins().get_pinned_reg(isa.pointer_type()) + } else { + let base_gv = pos.func.heaps[heap].base; + pos.ins().global_value(addr_ty, base_gv) + }; + pos.func.dfg.replace(inst).iadd(base, offset); } diff --git a/third_party/rust/cranelift-codegen/src/legalizer/mod.rs b/third_party/rust/cranelift-codegen/src/legalizer/mod.rs index e6f7bcb00d29b..2fd353c7b9eab 100644 --- a/third_party/rust/cranelift-codegen/src/legalizer/mod.rs +++ b/third_party/rust/cranelift-codegen/src/legalizer/mod.rs @@ -16,11 +16,13 @@ use crate::bitset::BitSet; use crate::cursor::{Cursor, FuncCursor}; use crate::flowgraph::ControlFlowGraph; -use crate::ir::types::I32; +use crate::ir::types::{I32, I64}; use crate::ir::{self, InstBuilder, MemFlags}; use crate::isa::TargetIsa; use crate::predicates; use crate::timing; +use std::collections::BTreeSet; +use std::vec::Vec; mod boundary; mod call; @@ -36,31 +38,78 @@ use self::heap::expand_heap_addr; use self::libcall::expand_as_libcall; use self::table::expand_table_addr; -/// Legalize `inst` for `isa`. Return true if any changes to the code were -/// made; return false if the instruction was successfully encoded as is. +enum LegalizeInstResult { + Done, + Legalized, + SplitLegalizePending, +} + +/// Legalize `inst` for `isa`. fn legalize_inst( inst: ir::Inst, pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa, -) -> bool { +) -> LegalizeInstResult { let opcode = pos.func.dfg[inst].opcode(); // Check for ABI boundaries that need to be converted to the legalized signature. if opcode.is_call() { if boundary::handle_call_abi(inst, pos.func, cfg) { - return true; + return LegalizeInstResult::Legalized; } } else if opcode.is_return() { if boundary::handle_return_abi(inst, pos.func, cfg) { - return true; + return LegalizeInstResult::Legalized; } } else if opcode.is_branch() { split::simplify_branch_arguments(&mut pos.func.dfg, inst); + } else if opcode == ir::Opcode::Isplit { + pos.use_srcloc(inst); + + let arg = match pos.func.dfg[inst] { + ir::InstructionData::Unary { arg, .. } => pos.func.dfg.resolve_aliases(arg), + _ => panic!("Expected isplit: {}", pos.func.dfg.display_inst(inst, None)), + }; + + match pos.func.dfg.value_def(arg) { + ir::ValueDef::Result(inst, _num) => { + if let ir::InstructionData::Binary { + opcode: ir::Opcode::Iconcat, + .. + } = pos.func.dfg[inst] + { + // `arg` was created by an `iconcat` instruction. + } else { + // `arg` was not created by an `iconcat` instruction. Don't try to resolve it, + // as otherwise `split::isplit` will re-insert the original `isplit`, causing + // an endless loop. + return LegalizeInstResult::SplitLegalizePending; + } + } + ir::ValueDef::Param(_ebb, _num) => {} + } + + let res = pos.func.dfg.inst_results(inst).to_vec(); + assert_eq!(res.len(), 2); + let (resl, resh) = (res[0], res[1]); // Prevent borrowck error + + // Remove old isplit + pos.func.dfg.clear_results(inst); + pos.remove_inst(); + + let curpos = pos.position(); + let srcloc = pos.srcloc(); + let (xl, xh) = split::isplit(pos.func, cfg, curpos, srcloc, arg); + + pos.func.dfg.change_to_alias(resl, xl); + pos.func.dfg.change_to_alias(resh, xh); + + return LegalizeInstResult::Legalized; } match pos.func.update_encoding(inst, isa) { - Ok(()) => false, + Ok(()) => LegalizeInstResult::Done, Err(action) => { // We should transform the instruction into legal equivalents. // If the current instruction was replaced, we need to double back and revisit @@ -69,12 +118,16 @@ fn legalize_inst( // There's a risk of infinite looping here if the legalization patterns are // unsound. Should we attempt to detect that? if action(inst, pos.func, cfg, isa) { - return true; + return LegalizeInstResult::Legalized; } // We don't have any pattern expansion for this instruction either. // Try converting it to a library call as a last resort. - expand_as_libcall(inst, pos.func, isa) + if expand_as_libcall(inst, pos.func, isa) { + LegalizeInstResult::Legalized + } else { + LegalizeInstResult::Done + } } } } @@ -94,24 +147,42 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is let mut pos = FuncCursor::new(func); + // This must be a set to prevent trying to legalize `isplit` and `vsplit` twice in certain cases. + let mut pending_splits = BTreeSet::new(); + // Process EBBs in layout order. Some legalization actions may split the current EBB or append // new ones to the end. We need to make sure we visit those new EBBs too. - while let Some(_ebb) = pos.next_ebb() { + while let Some(ebb) = pos.next_ebb() { + split::split_ebb_params(pos.func, cfg, ebb); + // Keep track of the cursor position before the instruction being processed, so we can // double back when replacing instructions. let mut prev_pos = pos.position(); while let Some(inst) = pos.next_inst() { - if legalize_inst(inst, &mut pos, cfg, isa) { - // Go back and legalize the inserted return value conversion instructions. - pos.set_position(prev_pos); - } else { + match legalize_inst(inst, &mut pos, cfg, isa) { // Remember this position in case we need to double back. - prev_pos = pos.position(); + LegalizeInstResult::Done => prev_pos = pos.position(), + + // Go back and legalize the inserted return value conversion instructions. + LegalizeInstResult::Legalized => pos.set_position(prev_pos), + + // The argument of a `isplit` or `vsplit` instruction didn't resolve to a + // `iconcat` or `vconcat` instruction. Try again after legalizing the rest of + // the instructions. + LegalizeInstResult::SplitLegalizePending => { + pending_splits.insert(inst); + } } } } + // Try legalizing `isplit` and `vsplit` instructions, which could not previously be legalized. + for inst in pending_splits { + pos.goto_inst(inst); + legalize_inst(inst, &mut pos, cfg, isa); + } + // Now that we've lowered all br_tables, we don't need the jump tables anymore. if !isa.flags().jump_tables_enabled() { pos.func.jump_tables.clear(); @@ -498,3 +569,99 @@ fn expand_stack_store( mflags.set_aligned(); pos.func.dfg.replace(inst).store(mflags, val, addr, 0); } + +/// Split a load into two parts before `iconcat`ing the result together. +fn narrow_load( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + _isa: &dyn TargetIsa, +) { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + let (ptr, offset, flags) = match pos.func.dfg[inst] { + ir::InstructionData::Load { + opcode: ir::Opcode::Load, + arg, + offset, + flags, + } => (arg, offset, flags), + _ => panic!("Expected load: {}", pos.func.dfg.display_inst(inst, None)), + }; + + let res_ty = pos.func.dfg.ctrl_typevar(inst); + let small_ty = res_ty.half_width().expect("Can't narrow load"); + + let al = pos.ins().load(small_ty, flags, ptr, offset); + let ah = pos.ins().load( + small_ty, + flags, + ptr, + offset.try_add_i64(8).expect("load offset overflow"), + ); + pos.func.dfg.replace(inst).iconcat(al, ah); +} + +/// Split a store into two parts after `isplit`ing the value. +fn narrow_store( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + _isa: &dyn TargetIsa, +) { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + let (val, ptr, offset, flags) = match pos.func.dfg[inst] { + ir::InstructionData::Store { + opcode: ir::Opcode::Store, + args, + offset, + flags, + } => (args[0], args[1], offset, flags), + _ => panic!("Expected store: {}", pos.func.dfg.display_inst(inst, None)), + }; + + let (al, ah) = pos.ins().isplit(val); + pos.ins().store(flags, al, ptr, offset); + pos.ins().store( + flags, + ah, + ptr, + offset.try_add_i64(8).expect("store offset overflow"), + ); + pos.remove_inst(); +} + +/// Expands an illegal iconst value by splitting it into two. +fn narrow_iconst( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + isa: &dyn TargetIsa, +) { + let imm: i64 = if let ir::InstructionData::UnaryImm { + opcode: ir::Opcode::Iconst, + imm, + } = &func.dfg[inst] + { + (*imm).into() + } else { + panic!("unexpected instruction in narrow_iconst"); + }; + + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + let ty = pos.func.dfg.ctrl_typevar(inst); + if isa.pointer_bits() == 32 && ty == I64 { + let low = pos.ins().iconst(I32, imm & 0xffffffff); + let high = pos.ins().iconst(I32, imm >> 32); + // The instruction has as many results as iconcat, so no need to replace them. + pos.func.dfg.replace(inst).iconcat(low, high); + return; + } + + unimplemented!("missing encoding or legalization for iconst.{:?}", ty); +} diff --git a/third_party/rust/cranelift-codegen/src/legalizer/split.rs b/third_party/rust/cranelift-codegen/src/legalizer/split.rs index 773df13216270..9f689922f1aaf 100644 --- a/third_party/rust/cranelift-codegen/src/legalizer/split.rs +++ b/third_party/rust/cranelift-codegen/src/legalizer/split.rs @@ -68,6 +68,7 @@ use crate::cursor::{Cursor, CursorPosition, FuncCursor}; use crate::flowgraph::{BasicBlock, ControlFlowGraph}; use crate::ir::{self, Ebb, Inst, InstBuilder, InstructionData, Opcode, Type, Value, ValueDef}; use core::iter; +use smallvec::SmallVec; use std::vec::Vec; /// Split `value` into two values using the `isplit` semantics. Do this by reusing existing values @@ -124,6 +125,35 @@ fn split_any( let pos = &mut FuncCursor::new(func).at_position(pos).with_srcloc(srcloc); let result = split_value(pos, value, concat, &mut repairs); + perform_repairs(pos, cfg, repairs); + + result +} + +pub fn split_ebb_params(func: &mut ir::Function, cfg: &ControlFlowGraph, ebb: Ebb) { + let mut repairs = Vec::new(); + let pos = &mut FuncCursor::new(func).at_top(ebb); + + for (num, ebb_param) in pos + .func + .dfg + .ebb_params(ebb) + .to_vec() + .into_iter() + .enumerate() + { + let ty = pos.func.dfg.value_type(ebb_param); + if ty != ir::types::I128 { + continue; + } + + split_ebb_param(pos, ebb, num, ebb_param, Opcode::Iconcat, &mut repairs); + } + + perform_repairs(pos, cfg, repairs); +} + +fn perform_repairs(pos: &mut FuncCursor, cfg: &ControlFlowGraph, mut repairs: Vec) { // We have split the value requested, and now we may need to fix some EBB predecessors. while let Some(repair) = repairs.pop() { for BasicBlock { inst, .. } in cfg.pred_iter(repair.ebb) { @@ -181,8 +211,6 @@ fn split_any( pos.func.dfg[inst].put_value_list(args); } } - - result } /// Split a single value using the integer or vector semantics given by the `concat` opcode. @@ -215,40 +243,7 @@ fn split_value( // This is an EBB parameter. We can split the parameter value unless this is the entry // block. if pos.func.layout.entry_block() != Some(ebb) { - // We are going to replace the parameter at `num` with two new arguments. - // Determine the new value types. - let ty = pos.func.dfg.value_type(value); - let split_type = match concat { - Opcode::Iconcat => ty.half_width().expect("Invalid type for isplit"), - Opcode::Vconcat => ty.half_vector().expect("Invalid type for vsplit"), - _ => panic!("Unhandled concat opcode: {}", concat), - }; - - // Since the `repairs` stack potentially contains other parameter numbers for - // `ebb`, avoid shifting and renumbering EBB parameters. It could invalidate other - // `repairs` entries. - // - // Replace the original `value` with the low part, and append the high part at the - // end of the argument list. - let lo = pos.func.dfg.replace_ebb_param(value, split_type); - let hi_num = pos.func.dfg.num_ebb_params(ebb); - let hi = pos.func.dfg.append_ebb_param(ebb, split_type); - reuse = Some((lo, hi)); - - // Now the original value is dangling. Insert a concatenation instruction that can - // compute it from the two new parameters. This also serves as a record of what we - // did so a future call to this function doesn't have to redo the work. - // - // Note that it is safe to move `pos` here since `reuse` was set above, so we don't - // need to insert a split instruction before returning. - pos.goto_first_inst(ebb); - pos.ins() - .with_result(value) - .Binary(concat, split_type, lo, hi); - - // Finally, splitting the EBB parameter is not enough. We also have to repair all - // of the predecessor instructions that branch here. - add_repair(concat, split_type, ebb, num, hi_num, repairs); + reuse = Some(split_ebb_param(pos, ebb, num, value, concat, repairs)); } } } @@ -267,6 +262,51 @@ fn split_value( } } +fn split_ebb_param( + pos: &mut FuncCursor, + ebb: Ebb, + param_num: usize, + value: Value, + concat: Opcode, + repairs: &mut Vec, +) -> (Value, Value) { + // We are going to replace the parameter at `num` with two new arguments. + // Determine the new value types. + let ty = pos.func.dfg.value_type(value); + let split_type = match concat { + Opcode::Iconcat => ty.half_width().expect("Invalid type for isplit"), + Opcode::Vconcat => ty.half_vector().expect("Invalid type for vsplit"), + _ => panic!("Unhandled concat opcode: {}", concat), + }; + + // Since the `repairs` stack potentially contains other parameter numbers for + // `ebb`, avoid shifting and renumbering EBB parameters. It could invalidate other + // `repairs` entries. + // + // Replace the original `value` with the low part, and append the high part at the + // end of the argument list. + let lo = pos.func.dfg.replace_ebb_param(value, split_type); + let hi_num = pos.func.dfg.num_ebb_params(ebb); + let hi = pos.func.dfg.append_ebb_param(ebb, split_type); + + // Now the original value is dangling. Insert a concatenation instruction that can + // compute it from the two new parameters. This also serves as a record of what we + // did so a future call to this function doesn't have to redo the work. + // + // Note that it is safe to move `pos` here since `reuse` was set above, so we don't + // need to insert a split instruction before returning. + pos.goto_first_inst(ebb); + pos.ins() + .with_result(value) + .Binary(concat, split_type, lo, hi); + + // Finally, splitting the EBB parameter is not enough. We also have to repair all + // of the predecessor instructions that branch here. + add_repair(concat, split_type, ebb, param_num, hi_num, repairs); + + (lo, hi) +} + // Add a repair entry to the work list. fn add_repair( concat: Opcode, @@ -334,7 +374,7 @@ fn resolve_splits(dfg: &ir::DataFlowGraph, value: Value) -> Value { /// After legalizing the instructions computing the value that was split, it is likely that we can /// avoid depending on the split instruction. Its input probably comes from a concatenation. pub fn simplify_branch_arguments(dfg: &mut ir::DataFlowGraph, branch: Inst) { - let mut new_args = Vec::new(); + let mut new_args = SmallVec::<[Value; 32]>::new(); for &arg in dfg.inst_args(branch) { let new_arg = resolve_splits(dfg, arg); diff --git a/third_party/rust/cranelift-codegen/src/lib.rs b/third_party/rust/cranelift-codegen/src/lib.rs index b682ea38678d6..1e97dfd6e0d17 100644 --- a/third_party/rust/cranelift-codegen/src/lib.rs +++ b/third_party/rust/cranelift-codegen/src/lib.rs @@ -41,7 +41,6 @@ ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(not(feature = "std"))] #[macro_use] diff --git a/third_party/rust/cranelift-codegen/src/regalloc/branch_splitting.rs b/third_party/rust/cranelift-codegen/src/regalloc/branch_splitting.rs new file mode 100644 index 0000000000000..e44f45229656a --- /dev/null +++ b/third_party/rust/cranelift-codegen/src/regalloc/branch_splitting.rs @@ -0,0 +1,197 @@ +//! Split the outgoing edges of conditional branches that pass parameters. +//! +//! One of the reason for splitting edges is to be able to insert `copy` and `regmove` instructions +//! between a conditional branch and the following terminator. +#![cfg(feature = "basic-blocks")] + +use std::vec::Vec; + +use crate::cursor::{Cursor, EncCursor}; +use crate::dominator_tree::DominatorTree; +use crate::flowgraph::ControlFlowGraph; +use crate::ir::{Ebb, Function, Inst, InstBuilder, InstructionData, Opcode, ValueList}; +use crate::isa::TargetIsa; +use crate::topo_order::TopoOrder; + +pub fn run( + isa: &dyn TargetIsa, + func: &mut Function, + cfg: &mut ControlFlowGraph, + domtree: &mut DominatorTree, + topo: &mut TopoOrder, +) { + let mut ctx = Context { + has_new_blocks: false, + has_fallthrough_return: None, + cur: EncCursor::new(func, isa), + domtree, + topo, + cfg, + }; + ctx.run() +} + +struct Context<'a> { + /// True if new blocks were inserted. + has_new_blocks: bool, + + /// Record whether newly inserted empty blocks should be inserted last, or before the last, to + /// avoid disturbing the expected control flow of `fallthroug_return` statements. + /// + /// This value is computed when needed. The Option wraps the computed value if any. + has_fallthrough_return: Option, + + /// Current instruction as well as reference to function and ISA. + cur: EncCursor<'a>, + + /// References to contextual data structures we need. + domtree: &'a mut DominatorTree, + topo: &'a mut TopoOrder, + cfg: &'a mut ControlFlowGraph, +} + +impl<'a> Context<'a> { + fn run(&mut self) { + // Any ebb order will do. + self.topo.reset(self.cur.func.layout.ebbs()); + while let Some(ebb) = self.topo.next(&self.cur.func.layout, self.domtree) { + // Branches can only be at the last or second to last position in an extended basic + // block. + self.cur.goto_last_inst(ebb); + let terminator_inst = self.cur.current_inst().expect("terminator"); + if let Some(inst) = self.cur.prev_inst() { + let opcode = self.cur.func.dfg[inst].opcode(); + if opcode.is_branch() { + self.visit_conditional_branch(inst, opcode); + self.cur.goto_inst(terminator_inst); + self.visit_terminator_branch(terminator_inst); + } + } + } + + // If blocks were added the cfg and domtree are inconsistent and must be recomputed. + if self.has_new_blocks { + self.cfg.compute(&self.cur.func); + self.domtree.compute(&self.cur.func, self.cfg); + } + } + + fn visit_conditional_branch(&mut self, branch: Inst, opcode: Opcode) { + // TODO: target = dfg[branch].branch_destination().expect("conditional branch"); + let target = match self.cur.func.dfg[branch] { + InstructionData::Branch { destination, .. } + | InstructionData::BranchIcmp { destination, .. } + | InstructionData::BranchInt { destination, .. } + | InstructionData::BranchFloat { destination, .. } => destination, + _ => panic!("Unexpected instruction in visit_conditional_branch"), + }; + + // If there are any parameters, split the edge. + if self.should_split_edge(target) { + // Create the block the branch will jump to. + let new_ebb = self.make_empty_ebb(); + + // Extract the arguments of the branch instruction, split the Ebb parameters and the + // branch arguments + let num_fixed = opcode.constraints().num_fixed_value_arguments(); + let dfg = &mut self.cur.func.dfg; + let old_args: Vec<_> = { + let args = dfg[branch].take_value_list().expect("ebb parameters"); + args.as_slice(&dfg.value_lists).iter().map(|x| *x).collect() + }; + let (branch_args, ebb_params) = old_args.split_at(num_fixed); + + // Replace the branch destination by the new Ebb created with no parameters, and restore + // the branch arguments, without the original Ebb parameters. + { + let branch_args = ValueList::from_slice(branch_args, &mut dfg.value_lists); + let data = &mut dfg[branch]; + *data.branch_destination_mut().expect("branch") = new_ebb; + data.put_value_list(branch_args); + } + let ok = self.cur.func.update_encoding(branch, self.cur.isa).is_ok(); + debug_assert!(ok); + + // Insert a jump to the original target with its arguments into the new block. + self.cur.goto_first_insertion_point(new_ebb); + self.cur.ins().jump(target, ebb_params); + + // Reset the cursor to point to the branch. + self.cur.goto_inst(branch); + } + } + + fn visit_terminator_branch(&mut self, inst: Inst) { + let inst_data = &self.cur.func.dfg[inst]; + let opcode = inst_data.opcode(); + if opcode != Opcode::Jump && opcode != Opcode::Fallthrough { + // This opcode is ignored as it does not have any EBB parameters. + if opcode != Opcode::IndirectJumpTableBr { + debug_assert!(!opcode.is_branch()) + } + return; + } + + let target = match inst_data { + InstructionData::Jump { destination, .. } => destination, + _ => panic!( + "Unexpected instruction {} in visit_terminator_branch", + self.cur.display_inst(inst) + ), + }; + debug_assert!(self.cur.func.dfg[inst].opcode().is_terminator()); + + // If there are any parameters, split the edge. + if self.should_split_edge(*target) { + // Create the block the branch will jump to. + let new_ebb = self.cur.func.dfg.make_ebb(); + self.has_new_blocks = true; + + // Split the current block before its terminator, and insert a new jump instruction to + // jump to it. + let jump = self.cur.ins().jump(new_ebb, &[]); + self.cur.insert_ebb(new_ebb); + + // Reset the cursor to point to new terminator of the old ebb. + self.cur.goto_inst(jump); + } + } + + // A new ebb must be inserted before the last ebb because the last ebb may have a + // fallthrough_return and can't have anything after it. + fn make_empty_ebb(&mut self) -> Ebb { + let last_ebb = self.cur.layout().last_ebb().unwrap(); + if self.has_fallthrough_return == None { + let last_inst = self.cur.layout().last_inst(last_ebb).unwrap(); + self.has_fallthrough_return = + Some(self.cur.func.dfg[last_inst].opcode() == Opcode::FallthroughReturn); + } + let new_ebb = self.cur.func.dfg.make_ebb(); + if self.has_fallthrough_return == Some(true) { + // Insert before the last block which has a fallthrough_return + // instruction. + self.cur.layout_mut().insert_ebb(new_ebb, last_ebb); + } else { + // Insert after the last block. + self.cur.layout_mut().insert_ebb_after(new_ebb, last_ebb); + } + self.has_new_blocks = true; + new_ebb + } + + /// Returns whether we should introduce a new branch. + fn should_split_edge(&self, target: Ebb) -> bool { + // We should split the edge if the target has any parameters. + if self.cur.func.dfg.ebb_params(target).len() > 0 { + return true; + }; + + // Or, if the target has more than one block reaching it. + debug_assert!(self.cfg.pred_iter(target).next() != None); + if let Some(_) = self.cfg.pred_iter(target).skip(1).next() { + return true; + }; + + false + } +} diff --git a/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs b/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs index fa158863a4e91..1e69c342a9121 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs @@ -44,18 +44,19 @@ use crate::cursor::{Cursor, EncCursor}; use crate::dominator_tree::DominatorTree; -use crate::ir::{AbiParam, ArgumentLoc, InstBuilder, ValueDef}; +use crate::flowgraph::ControlFlowGraph; +use crate::ir::{ArgumentLoc, InstBuilder, ValueDef}; use crate::ir::{Ebb, Function, Inst, InstructionData, Layout, Opcode, SigRef, Value, ValueLoc}; use crate::isa::{regs_overlap, RegClass, RegInfo, RegUnit}; use crate::isa::{ConstraintKind, EncInfo, OperandConstraint, RecipeConstraints, TargetIsa}; use crate::packed_option::PackedOption; use crate::regalloc::affinity::Affinity; +use crate::regalloc::diversion::RegDiversions; use crate::regalloc::live_value_tracker::{LiveValue, LiveValueTracker}; use crate::regalloc::liveness::Liveness; use crate::regalloc::liverange::{LiveRange, LiveRangeContext}; use crate::regalloc::register_set::RegisterSet; use crate::regalloc::solver::{Solver, SolverError}; -use crate::regalloc::RegDiversions; use crate::timing; use core::mem; use log::debug; @@ -68,6 +69,12 @@ pub struct Coloring { solver: Solver, } +/// Kinds of ABI parameters. +enum AbiParams { + Parameters(SigRef), + Returns, +} + /// Bundle of references that the coloring algorithm needs. /// /// Some of the needed mutable references are passed around as explicit function arguments so we @@ -86,6 +93,7 @@ struct Context<'a> { encinfo: EncInfo, // References to contextual data structures we need. + cfg: &'a ControlFlowGraph, domtree: &'a DominatorTree, liveness: &'a mut Liveness, @@ -98,6 +106,8 @@ struct Context<'a> { // Pristine set of registers that the allocator can use. // This set remains immutable, we make clones. usable_regs: RegisterSet, + + uses_pinned_reg: bool, } impl Coloring { @@ -120,6 +130,7 @@ impl Coloring { &mut self, isa: &dyn TargetIsa, func: &mut Function, + cfg: &ControlFlowGraph, domtree: &DominatorTree, liveness: &mut Liveness, tracker: &mut LiveValueTracker, @@ -128,9 +139,11 @@ impl Coloring { debug!("Coloring for:\n{}", func.display(isa)); let mut ctx = Context { usable_regs: isa.allocatable_registers(func), + uses_pinned_reg: isa.flags().enable_pinned_reg(), cur: EncCursor::new(func, isa), reginfo: isa.register_info(), encinfo: isa.encoding_info(), + cfg, domtree, liveness, divert: &mut self.divert, @@ -141,6 +154,12 @@ impl Coloring { } impl<'a> Context<'a> { + /// Is the pinned register usage enabled, and is this register the pinned register? + #[inline] + fn is_pinned_reg(&self, rc: RegClass, reg: RegUnit) -> bool { + rc.is_pinned_reg(self.uses_pinned_reg, reg) + } + /// Run the coloring algorithm. fn run(&mut self, tracker: &mut LiveValueTracker) { self.cur @@ -160,13 +179,13 @@ impl<'a> Context<'a> { debug!("Coloring {}:", ebb); let mut regs = self.visit_ebb_header(ebb, tracker); tracker.drop_dead_params(); - self.divert.clear(); // Now go through the instructions in `ebb` and color the values they define. self.cur.goto_top(ebb); while let Some(inst) = self.cur.next_inst() { self.cur.use_srcloc(inst); - if !self.cur.func.dfg[inst].opcode().is_ghost() { + let opcode = self.cur.func.dfg[inst].opcode(); + if !opcode.is_ghost() { // This is an instruction which either has an encoding or carries ABI-related // register allocation constraints. let enc = self.cur.func.encodings[inst]; @@ -183,6 +202,54 @@ impl<'a> Context<'a> { self.process_ghost_kills(kills, &mut regs); } tracker.drop_dead(inst); + + // We are not able to insert any regmove for diversion or un-diversion after the first + // branch. Instead, we record the diversion to be restored at the entry of the next EBB, + // which should have a single predecessor. + if opcode.is_branch() && cfg!(feature = "basic-blocks") { + // The next instruction is necessarily an unconditional branch. + if let Some(branch) = self.cur.next_inst() { + debug!( + "Skip coloring {}\n from {}\n with diversions {}", + self.cur.display_inst(branch), + regs.input.display(&self.reginfo), + self.divert.display(&self.reginfo) + ); + use crate::ir::instructions::BranchInfo::*; + let target = match self.cur.func.dfg.analyze_branch(branch) { + NotABranch | Table(_, _) => panic!( + "unexpected instruction {} after a conditional branch", + self.cur.display_inst(branch) + ), + SingleDest(ebb, _) => ebb, + }; + + // We have a single branch with a single target, and an EBB with a single + // predecessor. Thus we can forward the diversion set to the next EBB. + if self.cfg.pred_iter(target).count() == 1 { + // Transfer the diversion to the next EBB. + self.divert + .save_for_ebb(&mut self.cur.func.entry_diversions, target); + debug!( + "Set entry-diversion for {} to\n {}", + target, + self.divert.display(&self.reginfo) + ); + } else { + debug_assert!( + self.divert.is_empty(), + "Divert set is non-empty after the terminator." + ); + } + assert_eq!( + self.cur.next_inst(), + None, + "Unexpected instruction after a branch group." + ); + } else { + assert!(opcode.is_terminator()); + } + } } } @@ -199,6 +266,15 @@ impl<'a> Context<'a> { self.domtree, ); + // Copy the content of the registered diversions to be reused at the + // entry of this basic block. + self.divert.at_ebb(&self.cur.func.entry_diversions, ebb); + debug!( + "Start {} with entry-diversion set to\n {}", + ebb, + self.divert.display(&self.reginfo) + ); + if self.cur.func.layout.entry_block() == Some(ebb) { // Parameters on the entry block have ABI constraints. self.color_entry_params(tracker.live()) @@ -224,17 +300,35 @@ impl<'a> Context<'a> { "Live-in: {}:{} in {}", lv.value, lv.affinity.display(&self.reginfo), - self.cur.func.locations[lv.value].display(&self.reginfo) + self.divert + .get(lv.value, &self.cur.func.locations) + .display(&self.reginfo) ); if let Affinity::Reg(rci) = lv.affinity { let rc = self.reginfo.rc(rci); let loc = self.cur.func.locations[lv.value]; - match loc { - ValueLoc::Reg(reg) => regs.take(rc, reg, lv.is_local), + let reg = match loc { + ValueLoc::Reg(reg) => reg, ValueLoc::Unassigned => panic!("Live-in {} wasn't assigned", lv.value), ValueLoc::Stack(ss) => { panic!("Live-in {} is in {}, should be register", lv.value, ss) } + }; + if lv.is_local { + regs.take(rc, reg, lv.is_local); + } else { + let loc = self.divert.get(lv.value, &self.cur.func.locations); + let reg_divert = match loc { + ValueLoc::Reg(reg) => reg, + ValueLoc::Unassigned => { + panic!("Diversion: Live-in {} wasn't assigned", lv.value) + } + ValueLoc::Stack(ss) => panic!( + "Diversion: Live-in {} is in {}, should be register", + lv.value, ss + ), + }; + regs.take_divert(rc, reg, reg_divert); } } } @@ -284,6 +378,36 @@ impl<'a> Context<'a> { regs } + /// Program the input-side ABI constraints for `inst` into the constraint solver. + /// + /// ABI constraints are the fixed register assignments useds for calls and returns. + fn program_input_abi(&mut self, inst: Inst, abi_params: AbiParams) { + let abi_types = match abi_params { + AbiParams::Parameters(sig) => &self.cur.func.dfg.signatures[sig].params, + AbiParams::Returns => &self.cur.func.signature.returns, + }; + + for (abi, &value) in abi_types + .iter() + .zip(self.cur.func.dfg.inst_variable_args(inst)) + { + if let ArgumentLoc::Reg(reg) = abi.location { + if let Affinity::Reg(rci) = self + .liveness + .get(value) + .expect("ABI register must have live range") + .affinity + { + let rc = self.reginfo.rc(rci); + let cur_reg = self.divert.reg(value, &self.cur.func.locations); + self.solver.reassign_in(value, rc, cur_reg, reg); + } else { + panic!("ABI argument {} should be in a register", value); + } + } + } + } + /// Color the values defined by `inst` and insert any necessary shuffle code to satisfy /// instruction constraints. /// @@ -310,30 +434,16 @@ impl<'a> Context<'a> { // Program the solver with register constraints for the input side. self.solver.reset(®s.input); + if let Some(constraints) = constraints { self.program_input_constraints(inst, constraints.ins); } + let call_sig = self.cur.func.dfg.call_signature(inst); if let Some(sig) = call_sig { - program_input_abi( - &mut self.solver, - inst, - &self.cur.func.dfg.signatures[sig].params, - &self.cur.func, - &self.liveness, - &self.reginfo, - &self.divert, - ); + self.program_input_abi(inst, AbiParams::Parameters(sig)); } else if self.cur.func.dfg[inst].opcode().is_return() { - program_input_abi( - &mut self.solver, - inst, - &self.cur.func.signature.returns, - &self.cur.func, - &self.liveness, - &self.reginfo, - &self.divert, - ); + self.program_input_abi(inst, AbiParams::Returns); } else if self.cur.func.dfg[inst].opcode().is_branch() { // This is a branch, so we need to make sure that globally live values are in their // global registers. For EBBs that take arguments, we also need to place the argument @@ -358,6 +468,7 @@ impl<'a> Context<'a> { if self.solver.has_fixed_input_conflicts() { self.divert_fixed_input_conflicts(tracker.live()); } + self.solver.inputs_done(); // Update the live value tracker with this instruction. @@ -368,6 +479,13 @@ impl<'a> Context<'a> { if let Affinity::Reg(rci) = lv.affinity { let rc = self.reginfo.rc(rci); let reg = self.divert.reg(lv.value, &self.cur.func.locations); + + if self.is_pinned_reg(rc, reg) { + // Don't kill the pinned reg, either in the local or global register sets. + debug_assert!(lv.is_local, "pinned register SSA value can't be global"); + continue; + } + debug!( " kill {} in {} ({} {})", lv.value, @@ -407,6 +525,7 @@ impl<'a> Context<'a> { ); } } + if let Some(sig) = call_sig { self.program_output_abi( sig, @@ -416,6 +535,7 @@ impl<'a> Context<'a> { ®s.global, ); } + if let Some(constraints) = constraints { self.program_output_constraints( inst, @@ -497,16 +617,28 @@ impl<'a> Context<'a> { if let Affinity::Reg(rci) = lv.affinity { let rc = self.reginfo.rc(rci); + let reg = loc.unwrap_reg(); + + debug_assert!( + !self.is_pinned_reg(rc, reg) + || self.cur.func.dfg[inst].opcode() == Opcode::GetPinnedReg, + "pinned register may not be part of outputs for '{}'.", + self.cur.func.dfg[inst].opcode() + ); + + if self.is_pinned_reg(rc, reg) { + continue; + } // Remove the dead defs. if lv.endpoint == inst { - regs.input.free(rc, loc.unwrap_reg()); + regs.input.free(rc, reg); debug_assert!(lv.is_local); } // Track globals in their undiverted locations. if !lv.is_local && !replace_global_defines { - regs.global.take(rc, loc.unwrap_reg()); + regs.global.take(rc, reg); } } } @@ -527,14 +659,35 @@ impl<'a> Context<'a> { // already in a register. let cur_reg = self.divert.reg(value, &self.cur.func.locations); match op.kind { - ConstraintKind::FixedReg(regunit) | ConstraintKind::FixedTied(regunit) => { + ConstraintKind::FixedReg(regunit) => { // Add the fixed constraint even if `cur_reg == regunit`. // It is possible that we will want to convert the value to a variable later, // and this identity assignment prevents that from happening. self.solver .reassign_in(value, op.regclass, cur_reg, regunit); } - ConstraintKind::Reg | ConstraintKind::Tied(_) => { + ConstraintKind::FixedTied(regunit) => { + // The pinned register may not be part of a fixed tied requirement. If this + // becomes the case, then it must be changed to a different register. + debug_assert!( + !self.is_pinned_reg(op.regclass, regunit), + "see comment above" + ); + // See comment right above. + self.solver + .reassign_in(value, op.regclass, cur_reg, regunit); + } + ConstraintKind::Tied(_) => { + if self.is_pinned_reg(op.regclass, cur_reg) { + // Divert the pinned register; it shouldn't be reused for a tied input. + if self.solver.can_add_var(op.regclass, cur_reg) { + self.solver.add_var(value, op.regclass, cur_reg); + } + } else if !op.regclass.contains(cur_reg) { + self.solver.add_var(value, op.regclass, cur_reg); + } + } + ConstraintKind::Reg => { if !op.regclass.contains(cur_reg) { self.solver.add_var(value, op.regclass, cur_reg); } @@ -565,10 +718,13 @@ impl<'a> Context<'a> { match op.kind { ConstraintKind::Reg | ConstraintKind::Tied(_) => { let cur_reg = self.divert.reg(value, &self.cur.func.locations); - // This is the opposite condition of `program_input_constraints()`. - if op.regclass.contains(cur_reg) { + + // This is the opposite condition of `program_input_constraints()`. The pinned + // register mustn't be added back as a variable. + if op.regclass.contains(cur_reg) && !self.is_pinned_reg(op.regclass, cur_reg) { // This code runs after calling `solver.inputs_done()` so we must identify - // the new variable as killed or live-through. + // the new variable as killed or live-through. Always special-case the + // pinned register as a through variable. let ctx = self.liveness.context(&self.cur.func.layout); if self.liveness[value].killed_at(inst, ctx.order.pp_ebb(inst), ctx) { self.solver.add_killed_var(value, op.regclass, cur_reg); @@ -679,7 +835,7 @@ impl<'a> Context<'a> { if pred(lr, self.liveness.context(&self.cur.func.layout)) { if let Affinity::Reg(rci) = lr.affinity { let rc = self.reginfo.rc(rci); - // Stack diversions should not be possible here. The only live transiently + // Stack diversions should not be possible here. They only live transiently // during `shuffle_inputs()`. self.solver.reassign_in( value, @@ -698,8 +854,8 @@ impl<'a> Context<'a> { } } - // Find existing live values that conflict with the fixed input register constraints programmed - // into the constraint solver. Convert them to solver variables so they can be diverted. + /// Find existing live values that conflict with the fixed input register constraints programmed + /// into the constraint solver. Convert them to solver variables so they can be diverted. fn divert_fixed_input_conflicts(&mut self, live: &[LiveValue]) { for lv in live { if let Affinity::Reg(rci) = lv.affinity { @@ -787,7 +943,9 @@ impl<'a> Context<'a> { reg: RegUnit, throughs: &[LiveValue], ) { - if !self.solver.add_fixed_output(rc, reg) { + // Pinned register is already unavailable in the solver, since it is copied in the + // available registers on entry. + if !self.is_pinned_reg(rc, reg) && !self.solver.add_fixed_output(rc, reg) { // The fixed output conflicts with some of the live-through registers. for lv in throughs { if let Affinity::Reg(rci) = lv.affinity { @@ -830,12 +988,12 @@ impl<'a> Context<'a> { // Find the input operand we're tied to. // The solver doesn't care about the output value. let arg = self.cur.func.dfg.inst_args(inst)[num as usize]; - if let Some(reg) = self.solver.add_tied_input( - arg, - op.regclass, - self.divert.reg(arg, &self.cur.func.locations), - !lv.is_local, - ) { + let reg = self.divert.reg(arg, &self.cur.func.locations); + + if let Some(reg) = + self.solver + .add_tied_input(arg, op.regclass, reg, !lv.is_local) + { // The value we're tied to has been assigned to a fixed register. // We need to make sure that fixed output register is compatible with the // global register set. @@ -901,7 +1059,7 @@ impl<'a> Context<'a> { let toprc2 = self.reginfo.toprc(rci); let reg2 = self.divert.reg(lv.value, &self.cur.func.locations); if rc.contains(reg2) - && self.solver.can_add_var(lv.value, toprc2, reg2) + && self.solver.can_add_var(toprc2, reg2) && !self.is_live_on_outgoing_edge(lv.value) { self.solver.add_through_var(lv.value, toprc2, reg2); @@ -962,8 +1120,15 @@ impl<'a> Context<'a> { for m in self.solver.moves() { match *m { Reg { - value, from, to, .. + value, + from, + to, + rc, } => { + debug_assert!( + !self.is_pinned_reg(rc, to), + "pinned register used in a regmove" + ); self.divert.regmove(value, from, to); self.cur.ins().regmove(value, from, to); } @@ -987,8 +1152,12 @@ impl<'a> Context<'a> { value, from_slot, to, - .. + rc, } => { + debug_assert!( + !self.is_pinned_reg(rc, to), + "pinned register used in a regfill" + ); // These slots are single use, so mark `ss` as available again. let ss = slot[from_slot].take().expect("Using unallocated slot"); self.divert.regfill(value, ss, to); @@ -1103,35 +1272,6 @@ impl<'a> Context<'a> { } } -/// Program the input-side ABI constraints for `inst` into the constraint solver. -/// -/// ABI constraints are the fixed register assignments used for calls and returns. -fn program_input_abi( - solver: &mut Solver, - inst: Inst, - abi_types: &[AbiParam], - func: &Function, - liveness: &Liveness, - reginfo: &RegInfo, - divert: &RegDiversions, -) { - for (abi, &value) in abi_types.iter().zip(func.dfg.inst_variable_args(inst)) { - if let ArgumentLoc::Reg(reg) = abi.location { - if let Affinity::Reg(rci) = liveness - .get(value) - .expect("ABI register must have live range") - .affinity - { - let rc = reginfo.rc(rci); - let cur_reg = divert.reg(value, &func.locations); - solver.reassign_in(value, rc, cur_reg, reg); - } else { - panic!("ABI argument {} should be in a register", value); - } - } - } -} - /// Keep track of the set of available registers in two interference domains: all registers /// considering diversions and global registers not considering diversions. struct AvailableRegs { @@ -1163,4 +1303,10 @@ impl AvailableRegs { self.global.take(rc, reg); } } + + /// Take a diverted register from both sets for a non-local allocation. + pub fn take_divert(&mut self, rc: RegClass, reg: RegUnit, reg_divert: RegUnit) { + self.input.take(rc, reg_divert); + self.global.take(rc, reg); + } } diff --git a/third_party/rust/cranelift-codegen/src/regalloc/context.rs b/third_party/rust/cranelift-codegen/src/regalloc/context.rs index fe2e702647829..c5f5da4ecb319 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/context.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/context.rs @@ -8,6 +8,8 @@ use crate::dominator_tree::DominatorTree; use crate::flowgraph::ControlFlowGraph; use crate::ir::Function; use crate::isa::TargetIsa; +#[cfg(feature = "basic-blocks")] +use crate::regalloc::branch_splitting; use crate::regalloc::coalescing::Coalescing; use crate::regalloc::coloring::Coloring; use crate::regalloc::live_value_tracker::LiveValueTracker; @@ -78,7 +80,7 @@ impl Context { &mut self, isa: &dyn TargetIsa, func: &mut Function, - cfg: &ControlFlowGraph, + cfg: &mut ControlFlowGraph, domtree: &mut DominatorTree, ) -> CodegenResult<()> { let _tt = timing::regalloc(); @@ -93,6 +95,12 @@ impl Context { // phases. self.tracker.clear(); + // Pass: Split branches, add space where to add copy & regmove instructions. + #[cfg(feature = "basic-blocks")] + { + branch_splitting::run(isa, func, cfg, domtree, &mut self.topo); + } + // Pass: Liveness analysis. self.liveness.compute(isa, func, cfg); @@ -190,8 +198,14 @@ impl Context { } // Pass: Coloring. - self.coloring - .run(isa, func, domtree, &mut self.liveness, &mut self.tracker); + self.coloring.run( + isa, + func, + cfg, + domtree, + &mut self.liveness, + &mut self.tracker, + ); // This function runs after register allocation has taken // place, meaning values have locations assigned already. @@ -210,7 +224,7 @@ impl Context { if isa.flags().enable_verifier() { let ok = verify_context(func, cfg, domtree, isa, &mut errors).is_ok() && verify_liveness(isa, func, cfg, &self.liveness, &mut errors).is_ok() - && verify_locations(isa, func, Some(&self.liveness), &mut errors).is_ok() + && verify_locations(isa, func, cfg, Some(&self.liveness), &mut errors).is_ok() && verify_cssa( func, cfg, diff --git a/third_party/rust/cranelift-codegen/src/regalloc/diversion.rs b/third_party/rust/cranelift-codegen/src/regalloc/diversion.rs index 6e9b1f23cd166..12461c5ceadb7 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/diversion.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/diversion.rs @@ -9,10 +9,11 @@ use crate::fx::FxHashMap; use crate::hash_map::{Entry, Iter}; +use crate::ir::{Ebb, StackSlot, Value, ValueLoc, ValueLocations}; use crate::ir::{InstructionData, Opcode}; -use crate::ir::{StackSlot, Value, ValueLoc, ValueLocations}; use crate::isa::{RegInfo, RegUnit}; use core::fmt; +use cranelift_entity::{SparseMap, SparseMapValue}; /// A diversion of a value from its original location to a new register or stack location. /// @@ -38,10 +39,23 @@ impl Diversion { } /// Keep track of diversions in an EBB. +#[derive(Clone)] pub struct RegDiversions { current: FxHashMap, } +/// Keep track of diversions at the entry of EBB. +#[derive(Clone)] +struct EntryRegDiversionsValue { + key: Ebb, + divert: RegDiversions, +} + +/// Map EBB to their matching RegDiversions at basic blocks entry. +pub struct EntryRegDiversions { + map: SparseMap, +} + impl RegDiversions { /// Create a new empty diversion tracker. pub fn new() -> Self { @@ -50,7 +64,7 @@ impl RegDiversions { } } - /// Clear the tracker, preparing for a new EBB. + /// Clear the content of the diversions, to reset the state of the compiler. pub fn clear(&mut self) { self.current.clear() } @@ -92,7 +106,7 @@ impl RegDiversions { /// Record any kind of move. /// /// The `from` location must match an existing `to` location, if any. - pub fn divert(&mut self, value: Value, from: ValueLoc, to: ValueLoc) { + fn divert(&mut self, value: Value, from: ValueLoc, to: ValueLoc) { debug_assert!(from.is_assigned() && to.is_assigned()); match self.current.entry(value) { Entry::Occupied(mut e) => { @@ -163,9 +177,92 @@ impl RegDiversions { self.current.remove(&value).map(|d| d.to) } + /// Resets the state of the current diversions to the recorded diversions at the entry of the + /// given `ebb`. The recoded diversions is available after coloring on `func.entry_diversions` + /// field. + pub fn at_ebb(&mut self, entry_diversions: &EntryRegDiversions, ebb: Ebb) { + self.clear(); + if let Some(entry_divert) = entry_diversions.map.get(ebb) { + let iter = entry_divert.divert.current.iter(); + self.current.extend(iter); + } + } + + /// Copy the current state of the diversions, and save it for the entry of the `ebb` given as + /// argument. + /// + /// Note: This function can only be called once on an `ebb` with a given `entry_diversions` + /// argument, otherwise it would panic. + pub fn save_for_ebb(&mut self, entry_diversions: &mut EntryRegDiversions, target: Ebb) { + // No need to save anything if there is no diversions to be recorded. + if self.is_empty() { + return; + } + debug_assert!(!entry_diversions.map.contains_key(target)); + let iter = self.current.iter(); + let mut entry_divert = RegDiversions::new(); + entry_divert.current.extend(iter); + entry_diversions.map.insert(EntryRegDiversionsValue { + key: target, + divert: entry_divert, + }); + } + + /// Check that the recorded entry for a given `ebb` matches what is recorded in the + /// `entry_diversions`. + pub fn check_ebb_entry(&self, entry_diversions: &EntryRegDiversions, target: Ebb) -> bool { + let entry_divert = match entry_diversions.map.get(target) { + Some(entry_divert) => entry_divert, + None => return self.is_empty(), + }; + + if entry_divert.divert.current.len() != self.current.len() { + return false; + } + + for (val, _) in entry_divert.divert.current.iter() { + if !self.current.contains_key(val) { + return false; + } + } + return true; + } + /// Return an object that can display the diversions. pub fn display<'a, R: Into>>(&'a self, regs: R) -> DisplayDiversions<'a> { - DisplayDiversions(self, regs.into()) + DisplayDiversions(&self, regs.into()) + } +} + +impl EntryRegDiversions { + /// Create a new empty entry diversion, to associate diversions to each EBB entry. + pub fn new() -> Self { + EntryRegDiversions { + map: SparseMap::new(), + } + } + + pub fn clear(&mut self) { + self.map.clear(); + } +} + +impl Clone for EntryRegDiversions { + /// The Clone trait is required by `ir::Function`. + fn clone(&self) -> Self { + let mut tmp = Self::new(); + for v in self.map.values() { + tmp.map.insert(v.clone()); + } + tmp + } +} + +/// Implement `SparseMapValue`, as required to make use of a `SparseMap` for mapping the entry +/// diversions for each EBB. +impl SparseMapValue for EntryRegDiversionsValue { + fn key(&self) -> Ebb { + self.key } } @@ -175,7 +272,7 @@ pub struct DisplayDiversions<'a>(&'a RegDiversions, Option<&'a RegInfo>); impl<'a> fmt::Display for DisplayDiversions<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; - for (value, div) in self.0.iter() { + for (value, div) in self.0.current.iter() { write!( f, " {}: {} -> {}", diff --git a/third_party/rust/cranelift-codegen/src/regalloc/mod.rs b/third_party/rust/cranelift-codegen/src/regalloc/mod.rs index cfa3ca7323bfd..37fcccb3b0231 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/mod.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/mod.rs @@ -10,6 +10,7 @@ pub mod register_set; pub mod virtregs; mod affinity; +mod branch_splitting; mod coalescing; mod context; mod diversion; @@ -20,6 +21,6 @@ mod solver; mod spilling; pub use self::context::Context; -pub use self::diversion::RegDiversions; +pub use self::diversion::{EntryRegDiversions, RegDiversions}; pub use self::register_set::RegisterSet; pub use self::safepoint::emit_stackmaps; diff --git a/third_party/rust/cranelift-codegen/src/regalloc/register_set.rs b/third_party/rust/cranelift-codegen/src/regalloc/register_set.rs index fb7f208c59733..e5edaa96d6d82 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/register_set.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/register_set.rs @@ -268,6 +268,7 @@ mod tests { subclasses: 0, mask: [0xf0000000, 0x0000000f, 0], info: &INFO, + pinned_reg: None, }; const DPR: RegClass = &RegClassData { @@ -280,6 +281,7 @@ mod tests { subclasses: 0, mask: [0x50000000, 0x0000000a, 0], info: &INFO, + pinned_reg: None, }; const INFO: RegInfo = RegInfo { diff --git a/third_party/rust/cranelift-codegen/src/regalloc/reload.rs b/third_party/rust/cranelift-codegen/src/regalloc/reload.rs index fb6b61ec6fb62..bbc198c45d21f 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/reload.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/reload.rs @@ -233,7 +233,7 @@ impl<'a> Context<'a> { let dst_ty = self.cur.func.dfg.value_type(dst_val); debug_assert!(src_ty == dst_ty); // This limits the transformation to copies of the - // types: I64 I32 I16 I8 F64 and F32, since that's + // types: I128 I64 I32 I16 I8 F64 and F32, since that's // the set of `copy_nop` encodings available. src_ty.is_int() || src_ty.is_float() } diff --git a/third_party/rust/cranelift-codegen/src/regalloc/solver.rs b/third_party/rust/cranelift-codegen/src/regalloc/solver.rs index ec517028cc837..35e17b050d720 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/solver.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/solver.rs @@ -877,6 +877,7 @@ impl Solver { let d = v.iter(&self.regs_in, &self.regs_out, global_regs).len(); v.domain = cmp::min(d, u16::MAX as usize) as u16; } + // Solve for vars with small domains first to increase the chance of finding a solution. // // Also consider this case: @@ -949,9 +950,8 @@ impl Solver { // live registers be diverted. We need to make it a non-global value. if v.is_global && gregs.iter(rc).next().is_none() { return Err(SolverError::Global(v.value)); - } else { - return Err(SolverError::Divert(rc)); } + return Err(SolverError::Divert(rc)); } }; @@ -976,7 +976,7 @@ impl Solver { } /// Check if `value` can be added as a variable to help find a solution. - pub fn can_add_var(&mut self, _value: Value, constraint: RegClass, from: RegUnit) -> bool { + pub fn can_add_var(&mut self, constraint: RegClass, from: RegUnit) -> bool { !self.regs_in.is_avail(constraint, from) } } @@ -1030,7 +1030,7 @@ impl Solver { let mut avail = regs.clone(); let mut i = 0; while i < self.moves.len() + self.fills.len() { - // Don't even look at the fills until we've spent all the moves. Deferring these let's + // Don't even look at the fills until we've spent all the moves. Deferring these lets // us potentially reuse the claimed registers to resolve multiple cycles. if i >= self.moves.len() { self.moves.append(&mut self.fills); diff --git a/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs b/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs index 584ad9c53a27c..fc267c3f610d3 100644 --- a/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs +++ b/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs @@ -21,6 +21,7 @@ use crate::packed_option::PackedOption; use crate::ref_slice::ref_slice; use core::cmp::Ordering; use core::fmt; +use smallvec::SmallVec; use std::vec::Vec; /// A virtual register reference. @@ -292,7 +293,7 @@ impl VirtRegs { /// Find the leader value and rank of the set containing `v`. /// Compress the path if needed. fn find(&mut self, mut val: Value) -> (Value, u32) { - let mut val_stack = vec![]; + let mut val_stack = SmallVec::<[Value; 8]>::new(); let found = loop { match UFEntry::decode(self.union_find[val]) { UFEntry::Rank(rank) => break (val, rank), diff --git a/third_party/rust/cranelift-codegen/src/settings.rs b/third_party/rust/cranelift-codegen/src/settings.rs index f9bc9f6d1a9a2..99d3647cbdeb7 100644 --- a/third_party/rust/cranelift-codegen/src/settings.rs +++ b/third_party/rust/cranelift-codegen/src/settings.rs @@ -388,6 +388,8 @@ mod tests { avoid_div_traps = false\n\ enable_float = true\n\ enable_nan_canonicalization = false\n\ + enable_pinned_reg = false\n\ + use_pinned_reg_as_heap_base = false\n\ enable_simd = false\n\ enable_atomics = true\n\ enable_safepoints = false\n\ diff --git a/third_party/rust/cranelift-codegen/src/simple_preopt.rs b/third_party/rust/cranelift-codegen/src/simple_preopt.rs index 8219f6627cda2..221e8a57b0f66 100644 --- a/third_party/rust/cranelift-codegen/src/simple_preopt.rs +++ b/third_party/rust/cranelift-codegen/src/simple_preopt.rs @@ -16,6 +16,7 @@ use crate::ir::{ types::{I16, I32, I64, I8}, DataFlowGraph, Ebb, Function, Inst, InstBuilder, InstructionData, Type, Value, }; +use crate::isa::TargetIsa; use crate::timing; #[inline] @@ -533,9 +534,14 @@ fn try_fold_extended_move( /// Apply basic simplifications. /// -/// This folds constants with arithmetic to form `_imm` instructions, and other -/// minor simplifications. -fn simplify(pos: &mut FuncCursor, inst: Inst) { +/// This folds constants with arithmetic to form `_imm` instructions, and other minor +/// simplifications. +/// +/// Doesn't apply some simplifications if the native word width (in bytes) is smaller than the +/// controlling type's width of the instruction. This would result in an illegal instruction that +/// would likely be expanded back into an instruction on smaller types with the same initial +/// opcode, creating unnecessary churn. +fn simplify(pos: &mut FuncCursor, inst: Inst, native_word_width: u32) { match pos.func.dfg[inst] { InstructionData::Binary { opcode, args } => { if let Some(mut imm) = resolve_imm64_value(&pos.func.dfg, args[1]) { @@ -562,13 +568,15 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { _ => return, }; let ty = pos.func.dfg.ctrl_typevar(inst); - pos.func - .dfg - .replace(inst) - .BinaryImm(new_opcode, ty, imm, args[0]); - - // Repeat for BinaryImm simplification. - simplify(pos, inst); + if ty.bytes() <= native_word_width { + pos.func + .dfg + .replace(inst) + .BinaryImm(new_opcode, ty, imm, args[0]); + + // Repeat for BinaryImm simplification. + simplify(pos, inst, native_word_width); + } } else if let Some(imm) = resolve_imm64_value(&pos.func.dfg, args[0]) { let new_opcode = match opcode { Opcode::Iadd => Opcode::IaddImm, @@ -580,10 +588,12 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { _ => return, }; let ty = pos.func.dfg.ctrl_typevar(inst); - pos.func - .dfg - .replace(inst) - .BinaryImm(new_opcode, ty, imm, args[1]); + if ty.bytes() <= native_word_width { + pos.func + .dfg + .replace(inst) + .BinaryImm(new_opcode, ty, imm, args[1]); + } } } @@ -643,7 +653,9 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { } Opcode::UshrImm | Opcode::SshrImm => { - if try_fold_extended_move(pos, inst, opcode, arg, imm) { + if pos.func.dfg.ctrl_typevar(inst).bytes() <= native_word_width + && try_fold_extended_move(pos, inst, opcode, arg, imm) + { return; } } @@ -686,7 +698,9 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { InstructionData::IntCompare { opcode, cond, args } => { debug_assert_eq!(opcode, Opcode::Icmp); if let Some(imm) = resolve_imm64_value(&pos.func.dfg, args[1]) { - pos.func.dfg.replace(inst).icmp_imm(cond, args[0], imm); + if pos.func.dfg.ctrl_typevar(inst).bytes() <= native_word_width { + pos.func.dfg.replace(inst).icmp_imm(cond, args[0], imm); + } } } @@ -937,13 +951,14 @@ fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, ebb: Ebb, inst } /// The main pre-opt pass. -pub fn do_preopt(func: &mut Function, cfg: &mut ControlFlowGraph) { +pub fn do_preopt(func: &mut Function, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa) { let _tt = timing::preopt(); let mut pos = FuncCursor::new(func); + let native_word_width = isa.pointer_bytes(); while let Some(ebb) = pos.next_ebb() { while let Some(inst) = pos.next_inst() { // Apply basic simplifications. - simplify(&mut pos, inst); + simplify(&mut pos, inst, native_word_width as u32); // Try to transform divide-by-constant into simpler operations. if let Some(divrem_info) = get_div_info(inst, &pos.func.dfg) { diff --git a/third_party/rust/cranelift-codegen/src/value_label.rs b/third_party/rust/cranelift-codegen/src/value_label.rs index 60ea7b342ae2c..2bd3bdc13df70 100644 --- a/third_party/rust/cranelift-codegen/src/value_label.rs +++ b/third_party/rust/cranelift-codegen/src/value_label.rs @@ -118,7 +118,7 @@ where let mut tracked_values: Vec<(Value, ValueLabel, u32, ValueLoc)> = Vec::new(); let mut divert = RegDiversions::new(); for ebb in ebbs { - divert.clear(); + divert.at_ebb(&func.entry_diversions, ebb); let mut last_srcloc: Option = None; for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) { divert.apply(&func.dfg[inst]); diff --git a/third_party/rust/cranelift-codegen/src/verifier/locations.rs b/third_party/rust/cranelift-codegen/src/verifier/locations.rs index bcf006e7f5e53..cf17ae13de669 100644 --- a/third_party/rust/cranelift-codegen/src/verifier/locations.rs +++ b/third_party/rust/cranelift-codegen/src/verifier/locations.rs @@ -1,5 +1,6 @@ //! Verify value locations. +use crate::flowgraph::ControlFlowGraph; use crate::ir; use crate::isa; use crate::regalloc::liveness::Liveness; @@ -21,6 +22,7 @@ use crate::verifier::{VerifierErrors, VerifierStepResult}; pub fn verify_locations( isa: &dyn isa::TargetIsa, func: &ir::Function, + cfg: &ControlFlowGraph, liveness: Option<&Liveness>, errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { @@ -30,6 +32,7 @@ pub fn verify_locations( func, reginfo: isa.register_info(), encinfo: isa.encoding_info(), + cfg, liveness, }; verifier.check_constraints(errors)?; @@ -41,6 +44,7 @@ struct LocationVerifier<'a> { func: &'a ir::Function, reginfo: isa::RegInfo, encinfo: isa::EncInfo, + cfg: &'a ControlFlowGraph, liveness: Option<&'a Liveness>, } @@ -51,9 +55,9 @@ impl<'a> LocationVerifier<'a> { let mut divert = RegDiversions::new(); for ebb in self.func.layout.ebbs() { - // Diversions are reset at the top of each EBB. No diversions can exist across control - // flow edges. - divert.clear(); + divert.at_ebb(&self.func.entry_diversions, ebb); + + let mut is_after_branch = false; for inst in self.func.layout.ebb_insts(ebb) { let enc = self.func.encodings[inst]; @@ -71,10 +75,11 @@ impl<'a> LocationVerifier<'a> { if opcode.is_return() { self.check_return_abi(inst, &divert, errors)?; } else if opcode.is_branch() && !divert.is_empty() { - self.check_cfg_edges(inst, &divert, errors)?; + self.check_cfg_edges(inst, &mut divert, is_after_branch, errors)?; } self.update_diversions(inst, &mut divert, errors)?; + is_after_branch = opcode.is_branch(); } } @@ -102,8 +107,10 @@ impl<'a> LocationVerifier<'a> { fatal!( errors, inst, - "{} constraints not satisfied", - self.encinfo.display(enc) + "{} constraints not satisfied in: {}\n{}", + self.encinfo.display(enc), + self.func.dfg.display_inst(inst, self.isa), + self.func.display(self.isa) ) } @@ -285,8 +292,9 @@ impl<'a> LocationVerifier<'a> { return fatal!( errors, inst, - "inconsistent with global location {}", - self.func.locations[arg].display(&self.reginfo) + "inconsistent with global location {} ({})", + self.func.locations[arg].display(&self.reginfo), + self.func.dfg.display_inst(inst, None) ); } @@ -300,37 +308,52 @@ impl<'a> LocationVerifier<'a> { fn check_cfg_edges( &self, inst: ir::Inst, - divert: &RegDiversions, + divert: &mut RegDiversions, + is_after_branch: bool, errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { use crate::ir::instructions::BranchInfo::*; + let dfg = &self.func.dfg; + let branch_kind = dfg.analyze_branch(inst); // We can only check CFG edges if we have a liveness analysis. let liveness = match self.liveness { Some(l) => l, None => return Ok(()), }; - let dfg = &self.func.dfg; - match dfg.analyze_branch(inst) { + match branch_kind { NotABranch => panic!( "No branch information for {}", dfg.display_inst(inst, self.isa) ), SingleDest(ebb, _) => { + let unique_predecessor = self.cfg.pred_iter(ebb).count() == 1; + let mut val_to_remove = vec![]; for (&value, d) in divert.iter() { let lr = &liveness[value]; - if lr.is_livein(ebb, liveness.context(&self.func.layout)) { + if is_after_branch && unique_predecessor { + // Forward diversions based on the targeted branch. + if !lr.is_livein(ebb, liveness.context(&self.func.layout)) { + val_to_remove.push(value) + } + } else if lr.is_livein(ebb, liveness.context(&self.func.layout)) { return fatal!( errors, inst, - "{} is diverted to {} and live in to {}", + "SingleDest: {} is diverted to {} and live in to {}", value, d.to.display(&self.reginfo), ebb ); } } + if is_after_branch && unique_predecessor { + for val in val_to_remove.into_iter() { + divert.remove(val); + } + debug_assert!(divert.check_ebb_entry(&self.func.entry_diversions, ebb)); + } } Table(jt, ebb) => { for (&value, d) in divert.iter() { @@ -340,7 +363,7 @@ impl<'a> LocationVerifier<'a> { return fatal!( errors, inst, - "{} is diverted to {} and live in to {}", + "Table.default: {} is diverted to {} and live in to {}", value, d.to.display(&self.reginfo), ebb @@ -352,7 +375,7 @@ impl<'a> LocationVerifier<'a> { return fatal!( errors, inst, - "{} is diverted to {} and live in to {}", + "Table.case: {} is diverted to {} and live in to {}", value, d.to.display(&self.reginfo), ebb diff --git a/third_party/rust/cranelift-codegen/src/verifier/mod.rs b/third_party/rust/cranelift-codegen/src/verifier/mod.rs index 72fa1f7e17a08..5bc10d9d92eb3 100644 --- a/third_party/rust/cranelift-codegen/src/verifier/mod.rs +++ b/third_party/rust/cranelift-codegen/src/verifier/mod.rs @@ -676,6 +676,26 @@ impl<'a> Verifier<'a> { self.verify_value_list(inst, args, errors)?; } + NullAry { + opcode: Opcode::GetPinnedReg, + } + | Unary { + opcode: Opcode::SetPinnedReg, + .. + } => { + if let Some(isa) = &self.isa { + if !isa.flags().enable_pinned_reg() { + return fatal!( + errors, + inst, + "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg" + ); + } + } else { + return fatal!(errors, inst, "GetPinnedReg/SetPinnedReg need an ISA!"); + } + } + // Exhaustive list so we can't forget to add new formats Unary { .. } | UnaryImm { .. } diff --git a/third_party/rust/cranelift-entity/.cargo-checksum.json b/third_party/rust/cranelift-entity/.cargo-checksum.json index 5850f7f004778..c59319077a7c9 100644 --- a/third_party/rust/cranelift-entity/.cargo-checksum.json +++ b/third_party/rust/cranelift-entity/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"737c4600276d3a4afb1523f7ddbc446f9a79de866a796b414a5c419a6cb8ea7d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"f83cdc6c4a2cd0d75e85c355ee2c8b19b25194c86468c2285bde1f725656062f","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"cf4d7d3cc928f7bd0217fdbcb2ac97623fde530f438cae8e66818d93b27a5e43","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"8237b5c473fd219dc606efd7c989ec5216e4ae62c6cbb2857fbe11593c42aae9","src/set.rs":"97b860818c9577546201271f7ca457a5784c2e4447b68202a274f7fe75e937f2","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"6625897aa38b637e103d905200be02306f4efd8fb06681d69ecf005468a965cb","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"c47e858b6a46f8b5f584ca7f83c466e0fa616bbed9cb28622c53d4c1faf197c4","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"8ee5e0789e6107a5ca7aaa4663fa2b2c8a5e51aa08dceb554f518ea503d94101","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"8237b5c473fd219dc606efd7c989ec5216e4ae62c6cbb2857fbe11593c42aae9","src/set.rs":"97b860818c9577546201271f7ca457a5784c2e4447b68202a274f7fe75e937f2","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-entity/Cargo.toml b/third_party/rust/cranelift-entity/Cargo.toml index 538d1299df90e..22b34d33d77df 100644 --- a/third_party/rust/cranelift-entity/Cargo.toml +++ b/third_party/rust/cranelift-entity/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-entity" -version = "0.40.0" +version = "0.42.0" description = "Data structures using entity references as mapping keys" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" diff --git a/third_party/rust/cranelift-entity/src/lib.rs b/third_party/rust/cranelift-entity/src/lib.rs index 57287d6c79608..aa10264ab8827 100644 --- a/third_party/rust/cranelift-entity/src/lib.rs +++ b/third_party/rust/cranelift-entity/src/lib.rs @@ -51,7 +51,6 @@ ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(not(feature = "std"))] #[macro_use] diff --git a/third_party/rust/cranelift-entity/src/map.rs b/third_party/rust/cranelift-entity/src/map.rs index bb1b94aeca1a0..f46c3074268cd 100644 --- a/third_party/rust/cranelift-entity/src/map.rs +++ b/third_party/rust/cranelift-entity/src/map.rs @@ -52,6 +52,20 @@ where } } + /// Create a new, empty map with the specified capacity. + /// + /// The map will be able to hold exactly `capacity` elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self + where + V: Default, + { + Self { + elems: Vec::with_capacity(capacity), + default: Default::default(), + unused: PhantomData, + } + } + /// Create a new empty map with a specified default value. /// /// This constructor does not require V to implement Default. @@ -63,6 +77,11 @@ where } } + /// Returns the number of elements the map can hold without reallocating. + pub fn capacity(&self) -> usize { + self.elems.capacity() + } + /// Get the element at `k` if it exists. pub fn get(&self, k: K) -> Option<&V> { self.elems.get(k.index()) diff --git a/third_party/rust/cranelift-frontend/.cargo-checksum.json b/third_party/rust/cranelift-frontend/.cargo-checksum.json index ec5874c364169..1bb10c231ea61 100644 --- a/third_party/rust/cranelift-frontend/.cargo-checksum.json +++ b/third_party/rust/cranelift-frontend/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2889efa82a23e4ad2e862fb21e758b2adb9f7b7bdcce988d98016e5ff654404a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"beb75f0b47ecf5e8b91edf603a4d8d522420af2d6ef08227f30cb6000b865b20","src/lib.rs":"1cc2e7aaffa45bccea9e59fcc9d9c5d295a9f7adacd6bd55933834e20e969aef","src/ssa.rs":"fb13242a1b72539139ac5de49f862ecf8ff9be7655049665fd8feebe7ba172f3","src/switch.rs":"b8f337966b540254feb5f979b4a146f5ef69ae199864da6332c9d7513ff3ec8b","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"d3ad74a39dc6d5efeb4c02171789e53f50b2ecbe34d4bd6dcfc7856b52e50be5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"c51394028c6abfe5b1a56461e28a39e2da092a5c4fe3cf80c6d554c9684bfd05","src/lib.rs":"19e12c5148c31f5c6e0d1b6283c5a170c771606a8d1ae227acb4b61d825d0190","src/ssa.rs":"2e7c9409022f1b41d79a658069fdef9559236094d044e046d0fdde4c1798dc34","src/switch.rs":"48c2857d3f9d12ee0db5fb788c9b58963fd316ca70086a7c1014f908791995b5","src/variable.rs":"b5bae996345e2a52e902ebd037e4b270ee89092c748458556c7de667d236dd00"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-frontend/Cargo.toml b/third_party/rust/cranelift-frontend/Cargo.toml index fec5f408e448f..3cd888220165e 100644 --- a/third_party/rust/cranelift-frontend/Cargo.toml +++ b/third_party/rust/cranelift-frontend/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-frontend" -version = "0.40.0" +version = "0.42.0" description = "Cranelift IR builder helper" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://cranelift.readthedocs.io/" @@ -11,10 +11,11 @@ readme = "README.md" edition = "2018" [dependencies] -cranelift-codegen = { path = "../cranelift-codegen", version = "0.40.0", default-features = false } -target-lexicon = { version = "0.4.0", default-features = false } +cranelift-codegen = { path = "../cranelift-codegen", version = "0.42.0", default-features = false } +target-lexicon = "0.8.1" log = { version = "0.4.6", default-features = false } hashmap_core = { version = "0.1.9", optional = true } +smallvec = { version = "0.6.10" } [features] default = ["std"] diff --git a/third_party/rust/cranelift-frontend/src/frontend.rs b/third_party/rust/cranelift-frontend/src/frontend.rs index 0961314559fe8..064ab7053c352 100644 --- a/third_party/rust/cranelift-frontend/src/frontend.rs +++ b/third_party/rust/cranelift-frontend/src/frontend.rs @@ -20,22 +20,22 @@ use std::vec::Vec; /// In order to reduce memory reallocations when compiling multiple functions, /// `FunctionBuilderContext` holds various data structures which are cleared between /// functions, rather than dropped, preserving the underlying allocations. -pub struct FunctionBuilderContext { +struct FunctionBuilderContext { ssa: SSABuilder, ebbs: SecondaryMap, types: SecondaryMap, } /// Temporary object used to build a single Cranelift IR `Function`. -pub struct FunctionBuilder<'a> { +pub struct FunctionBuilder { /// The function currently being built. /// This field is public so the function can be re-borrowed. - pub func: &'a mut Function, + pub func: Function, /// Source location to assign to all new instructions. srcloc: ir::SourceLoc, - func_ctx: &'a mut FunctionBuilderContext, + func_ctx: FunctionBuilderContext, position: Position, } @@ -75,8 +75,9 @@ impl Position { } impl FunctionBuilderContext { - /// Creates a FunctionBuilderContext structure. The structure is automatically cleared after - /// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function. + /// Creates a FunctionBuilderContext structure. The structure is + /// automatically cleared after each `FunctionBuilder` completes translating + /// a function. pub fn new() -> Self { Self { ssa: SSABuilder::new(), @@ -90,26 +91,22 @@ impl FunctionBuilderContext { self.ebbs.clear(); self.types.clear(); } - - fn is_empty(&self) -> bool { - self.ssa.is_empty() && self.ebbs.is_empty() && self.types.is_empty() - } } /// Implementation of the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) that has /// one convenience method per Cranelift IR instruction. -pub struct FuncInstBuilder<'short, 'long: 'short> { - builder: &'short mut FunctionBuilder<'long>, +pub struct FuncInstBuilder<'short> { + builder: &'short mut FunctionBuilder, ebb: Ebb, } -impl<'short, 'long> FuncInstBuilder<'short, 'long> { - fn new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self { +impl<'short> FuncInstBuilder<'short> { + fn new(builder: &'short mut FunctionBuilder, ebb: Ebb) -> Self { Self { builder, ebb } } } -impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { +impl<'short> InstBuilderBase<'short> for FuncInstBuilder<'short> { fn data_flow_graph(&self) -> &DataFlowGraph { &self.builder.func.dfg } @@ -203,12 +200,9 @@ impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { /// The first block for which you call `switch_to_block` will be assumed to be the beginning of /// the function. /// -/// At creation, a `FunctionBuilder` instance borrows an already allocated `Function` which it -/// modifies with the information stored in the mutable borrowed -/// [`FunctionBuilderContext`](struct.FunctionBuilderContext.html). The function passed in -/// argument should be newly created with -/// [`Function::with_name_signature()`](Function::with_name_signature), whereas the -/// `FunctionBuilderContext` can be kept as is between two function translations. +/// At creation, a `FunctionBuilder` instance borrows an already allocated +/// `Function`. The function passed in should be newly created with +/// [`Function::with_name_signature()`](Function::with_name_signature). /// /// # Errors /// @@ -216,15 +210,13 @@ impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { /// function in a way that violate the coherence of the code. For instance: switching to a new /// `Ebb` when you haven't filled the current one with a terminator instruction, inserting a /// return instruction with arguments that don't match the function's signature. -impl<'a> FunctionBuilder<'a> { - /// Creates a new FunctionBuilder structure that will operate on a `Function` using a - /// `FunctionBuilderContext`. - pub fn new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self { - debug_assert!(func_ctx.is_empty()); +impl FunctionBuilder { + /// Creates a new FunctionBuilder structure that will operate on a `Function`. + pub fn new(func: Function) -> Self { Self { func, srcloc: Default::default(), - func_ctx, + func_ctx: FunctionBuilderContext::new(), position: Position::default(), } } @@ -279,7 +271,7 @@ impl<'a> FunctionBuilder<'a> { /// created. Forgetting to call this method on every block will cause inconsistencies in the /// produced functions. pub fn seal_block(&mut self, ebb: Ebb) { - let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, self.func); + let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, &mut self.func); self.handle_ssa_side_effects(side_effects); } @@ -290,7 +282,7 @@ impl<'a> FunctionBuilder<'a> { /// function can be used at the end of translating all blocks to ensure /// that everything is sealed. pub fn seal_all_blocks(&mut self) { - let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(self.func); + let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(&mut self.func); self.handle_ssa_side_effects(side_effects); } @@ -311,7 +303,7 @@ impl<'a> FunctionBuilder<'a> { }); self.func_ctx .ssa - .use_var(self.func, var, ty, self.position.basic_block.unwrap()) + .use_var(&mut self.func, var, ty, self.position.basic_block.unwrap()) }; self.handle_ssa_side_effects(side_effects); val @@ -393,7 +385,7 @@ impl<'a> FunctionBuilder<'a> { /// Returns an object with the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) /// trait that allows to conveniently append an instruction to the current `Ebb` being built. - pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> { + pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short> { let ebb = self .position .ebb @@ -423,7 +415,7 @@ impl<'a> FunctionBuilder<'a> { /// need to know about `FunctionBuilder` at all. pub fn cursor(&mut self) -> FuncCursor { self.ensure_inserted_ebb(); - FuncCursor::new(self.func) + FuncCursor::new(&mut self.func) .with_srcloc(self.srcloc) .at_bottom(self.position.ebb.unwrap()) } @@ -459,10 +451,21 @@ impl<'a> FunctionBuilder<'a> { } } - /// Declare that translation of the current function is complete. This - /// resets the state of the `FunctionBuilder` in preparation to be used + /// Clears the current state of the `FunctionBuilder` while preserving + /// allocations for reuse in translating another function. + pub fn clear(&mut self) { + // Clear the state (but preserve the allocated buffers) in preparation + // for translation another function. + self.func_ctx.clear(); + // Reset srcloc and position to initial states. + self.srcloc = Default::default(); + self.position = Position::default(); + } + + /// Declare that translation of the current function is complete, and return the completed + /// function. This resets the state of the `FunctionBuilder` in preparation to be used /// for another function. - pub fn finalize(&mut self) { + pub fn finalize(&mut self) -> ir::Function { // Check that all the `Ebb`s are filled and sealed. debug_assert!( self.func_ctx @@ -492,13 +495,8 @@ impl<'a> FunctionBuilder<'a> { } } - // Clear the state (but preserve the allocated buffers) in preparation - // for translation another function. - self.func_ctx.clear(); - - // Reset srcloc and position to initial states. - self.srcloc = Default::default(); - self.position = Position::default(); + self.clear(); + std::mem::replace(&mut self.func, Function::new()) } } @@ -507,7 +505,7 @@ impl<'a> FunctionBuilder<'a> { /// performance of your translation perform more complex transformations to your Cranelift IR /// function. The functions below help you inspect the function you're creating and modify it /// in ways that can be unsafe if used incorrectly. -impl<'a> FunctionBuilder<'a> { +impl FunctionBuilder { /// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions /// inserted that target it and the SSA construction. pub fn ebb_params(&self, ebb: Ebb) -> &[Value] { @@ -593,7 +591,7 @@ impl<'a> FunctionBuilder<'a> { } /// Helper functions -impl<'a> FunctionBuilder<'a> { +impl FunctionBuilder { /// Calls libc.memcpy /// /// Copies the `size` bytes from `src` to `dest`, assumes that `src + size` @@ -853,7 +851,7 @@ fn greatest_divisible_power_of_two(size: u64) -> u64 { } // Helper functions -impl<'a> FunctionBuilder<'a> { +impl FunctionBuilder { fn move_to_next_basic_block(&mut self) { self.position.basic_block = PackedOption::from( self.func_ctx @@ -888,7 +886,7 @@ impl<'a> FunctionBuilder<'a> { #[cfg(test)] mod tests { use super::greatest_divisible_power_of_two; - use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; + use crate::frontend::FunctionBuilder; use crate::Variable; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::types::*; @@ -903,14 +901,14 @@ mod tests { sig.returns.push(AbiParam::new(I32)); sig.params.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let block1 = builder.create_ebb(); let block2 = builder.create_ebb(); + let block3 = builder.create_ebb(); let x = Variable::new(0); let y = Variable::new(1); let z = Variable::new(2); @@ -948,7 +946,13 @@ mod tests { } { let arg = builder.use_var(y); - builder.ins().brnz(arg, block2, &[]); + builder.ins().brnz(arg, block3, &[]); + } + builder.ins().jump(block2, &[]); + + builder.switch_to_block(block2); + if !lazy_seal { + builder.seal_block(block2); } { let arg1 = builder.use_var(z); @@ -961,9 +965,9 @@ mod tests { builder.ins().return_(&[arg]); } - builder.switch_to_block(block2); + builder.switch_to_block(block3); if !lazy_seal { - builder.seal_block(block2); + builder.seal_block(block3); } { @@ -981,8 +985,8 @@ mod tests { builder.seal_all_blocks(); } - builder.finalize(); - } + builder.finalize() + }; let flags = settings::Flags::new(settings::builder()); // println!("{}", func.display(None)); @@ -1019,10 +1023,9 @@ mod tests { let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1041,8 +1044,8 @@ mod tests { builder.ins().return_(&[size]); builder.seal_all_blocks(); - builder.finalize(); - } + builder.finalize() + }; assert_eq!( func.display(None).to_string(), @@ -1080,10 +1083,9 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1100,8 +1102,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize(); - } + builder.finalize() + }; assert_eq!( func.display(None).to_string(), @@ -1137,10 +1139,9 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1157,8 +1158,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize(); - } + builder.finalize() + }; assert_eq!( func.display(None).to_string(), @@ -1197,10 +1198,9 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let y = Variable::new(16); @@ -1214,8 +1214,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize(); - } + builder.finalize() + }; assert_eq!( func.display(None).to_string(), @@ -1249,10 +1249,9 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let mut fn_ctx = FunctionBuilderContext::new(); - let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - { - let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + let func = { + let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(func); let block0 = builder.create_ebb(); let y = Variable::new(16); @@ -1266,8 +1265,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize(); - } + builder.finalize() + }; assert_eq!( func.display(None).to_string(), diff --git a/third_party/rust/cranelift-frontend/src/lib.rs b/third_party/rust/cranelift-frontend/src/lib.rs index 4cfb49939a303..14cd7502dc027 100644 --- a/third_party/rust/cranelift-frontend/src/lib.rs +++ b/third_party/rust/cranelift-frontend/src/lib.rs @@ -3,7 +3,7 @@ //! Provides a straightforward way to create a Cranelift IR function and fill it with instructions //! corresponding to your source program written in another language. //! -//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and +//! To get started, create an [`Function`](../cranelift_codegen/ir/function/struct.Function.html) and //! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html). //! //! # Mutable variables and Cranelift IR values @@ -50,16 +50,18 @@ //! jump block1 //! block1: //! z = z + y; -//! brnz y, block2; +//! brnz y, block3; +//! jump block2 +//! block2: //! z = z - x; //! return y -//! block2: +//! block3: //! y = y - x //! jump block1 //! } //! ``` //! -//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`: +//! Here is how you build the corresponding Cranelift IR function using `Function`: //! //! ```rust //! extern crate cranelift_codegen; @@ -71,20 +73,20 @@ //! use cranelift_codegen::isa::CallConv; //! use cranelift_codegen::settings; //! use cranelift_codegen::verifier::verify_function; -//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +//! use cranelift_frontend::{FunctionBuilder, Variable}; //! //! fn main() { //! let mut sig = Signature::new(CallConv::SystemV); //! sig.returns.push(AbiParam::new(I32)); //! sig.params.push(AbiParam::new(I32)); -//! let mut fn_builder_ctx = FunctionBuilderContext::new(); -//! let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); -//! { -//! let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); +//! let func = { +//! let func = Function::with_name_signature(ExternalName::user(0, 0), sig); +//! let mut builder = FunctionBuilder::new(func); //! //! let block0 = builder.create_ebb(); //! let block1 = builder.create_ebb(); //! let block2 = builder.create_ebb(); +//! let block3 = builder.create_ebb(); //! let x = Variable::new(0); //! let y = Variable::new(1); //! let z = Variable::new(2); @@ -120,8 +122,12 @@ //! } //! { //! let arg = builder.use_var(y); -//! builder.ins().brnz(arg, block2, &[]); +//! builder.ins().brnz(arg, block3, &[]); //! } +//! builder.ins().jump(block2, &[]); +//! +//! builder.switch_to_block(block2); +//! builder.seal_block(block2); //! { //! let arg1 = builder.use_var(z); //! let arg2 = builder.use_var(x); @@ -133,8 +139,8 @@ //! builder.ins().return_(&[arg]); //! } //! -//! builder.switch_to_block(block2); -//! builder.seal_block(block2); +//! builder.switch_to_block(block3); +//! builder.seal_block(block3); //! //! { //! let arg1 = builder.use_var(y); @@ -145,8 +151,8 @@ //! builder.ins().jump(block1, &[]); //! builder.seal_block(block1); //! -//! builder.finalize(); -//! } +//! builder.finalize() +//! }; //! //! let flags = settings::Flags::new(settings::builder()); //! let res = verify_function(&func, &flags); @@ -175,7 +181,6 @@ ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(not(feature = "std"))] #[macro_use] @@ -189,7 +194,7 @@ use hashmap_core::HashMap; #[cfg(feature = "std")] use std::collections::HashMap; -pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; +pub use crate::frontend::FunctionBuilder; pub use crate::switch::Switch; pub use crate::variable::Variable; diff --git a/third_party/rust/cranelift-frontend/src/ssa.rs b/third_party/rust/cranelift-frontend/src/ssa.rs index aa735f7747140..43300f4deda94 100644 --- a/third_party/rust/cranelift-frontend/src/ssa.rs +++ b/third_party/rust/cranelift-frontend/src/ssa.rs @@ -16,6 +16,7 @@ use cranelift_codegen::ir::types::{F32, F64}; use cranelift_codegen::ir::{Ebb, Function, Inst, InstBuilder, InstructionData, Type, Value}; use cranelift_codegen::packed_option::PackedOption; use cranelift_codegen::packed_option::ReservedValue; +use smallvec::SmallVec; use std::vec::Vec; /// Structure containing the data relevant the construction of SSA for a given function. @@ -123,9 +124,11 @@ impl PredBlock { } } +type PredBlockSmallVec = SmallVec<[PredBlock; 4]>; + struct EbbHeaderBlockData { // The predecessors of the Ebb header block, with the block and branch instruction. - predecessors: Vec, + predecessors: PredBlockSmallVec, // A ebb header block is sealed if all of its predecessors have been declared. sealed: bool, // The ebb which this block is part of. @@ -173,9 +176,7 @@ impl SSABuilder { self.variables.clear(); self.blocks.clear(); self.ebb_headers.clear(); - debug_assert!(self.calls.is_empty()); - debug_assert!(self.results.is_empty()); - debug_assert!(self.side_effects.is_empty()); + debug_assert!(self.is_empty()); } /// Tests whether an `SSABuilder` is in a cleared state. @@ -368,7 +369,7 @@ impl SSABuilder { /// Predecessors have to be added with `declare_ebb_predecessor`. pub fn declare_ebb_header_block(&mut self, ebb: Ebb) -> Block { let block = self.blocks.push(BlockData::EbbHeader(EbbHeaderBlockData { - predecessors: Vec::new(), + predecessors: PredBlockSmallVec::new(), sealed: false, ebb, undef_variables: Vec::new(), @@ -589,7 +590,8 @@ impl SSABuilder { // There is disagreement in the predecessors on which value to use so we have // to keep the ebb argument. To avoid borrowing `self` for the whole loop, // temporarily detach the predecessors list and replace it with an empty list. - let mut preds = mem::replace(self.predecessors_mut(dest_ebb), Vec::new()); + let mut preds = + mem::replace(self.predecessors_mut(dest_ebb), PredBlockSmallVec::new()); for &mut PredBlock { block: ref mut pred_block, branch: ref mut last_inst, @@ -701,7 +703,7 @@ impl SSABuilder { } /// Same as predecessors, but for &mut. - fn predecessors_mut(&mut self, ebb: Ebb) -> &mut Vec { + fn predecessors_mut(&mut self, ebb: Ebb) -> &mut PredBlockSmallVec { let block = self.header_block(ebb); match self.blocks[block] { BlockData::EbbBody { .. } => panic!("should not happen"), diff --git a/third_party/rust/cranelift-frontend/src/switch.rs b/third_party/rust/cranelift-frontend/src/switch.rs index 0db3ac348e67f..33b2001655e79 100644 --- a/third_party/rust/cranelift-frontend/src/switch.rs +++ b/third_party/rust/cranelift-frontend/src/switch.rs @@ -16,12 +16,11 @@ type EntryIndex = u64; /// # use cranelift_codegen::ir::types::*; /// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder}; /// # use cranelift_codegen::isa::CallConv; -/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch}; +/// # use cranelift_frontend::{FunctionBuilder, Switch}; /// # /// # let mut sig = Signature::new(CallConv::SystemV); -/// # let mut fn_builder_ctx = FunctionBuilderContext::new(); /// # let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); -/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); +/// # let mut builder = FunctionBuilder::new(func); /// # /// # let entry = builder.create_ebb(); /// # builder.switch_to_block(entry); @@ -167,12 +166,22 @@ impl Switch { contiguous_case_ranges: Vec, cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec)>, ) { + let mut was_branch = false; + let ins_fallthrough_jump = |was_branch: bool, bx: &mut FunctionBuilder| { + if was_branch { + let ebb = bx.create_ebb(); + bx.ins().jump(ebb, &[]); + bx.switch_to_block(ebb); + } + }; for ContiguousCaseRange { first_index, ebbs } in contiguous_case_ranges.into_iter().rev() { match (ebbs.len(), first_index) { (1, 0) => { + ins_fallthrough_jump(was_branch, bx); bx.ins().brz(val, ebbs[0], &[]); } (1, _) => { + ins_fallthrough_jump(was_branch, bx); let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64); bx.ins().brnz(is_good_val, ebbs[0], &[]); } @@ -187,6 +196,7 @@ impl Switch { return; } (_, _) => { + ins_fallthrough_jump(was_branch, bx); let jt_ebb = bx.create_ebb(); let is_good_val = bx.ins().icmp_imm( IntCC::UnsignedGreaterThanOrEqual, @@ -197,6 +207,7 @@ impl Switch { cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs)); } } + was_branch = true; } bx.ins().jump(otherwise, &[]); @@ -277,16 +288,13 @@ impl ContiguousCaseRange { #[cfg(test)] mod tests { use super::*; - use crate::frontend::FunctionBuilderContext; use cranelift_codegen::ir::Function; use std::string::ToString; macro_rules! setup { ($default:expr, [$($index:expr,)*]) => {{ - let mut func = Function::new(); - let mut func_ctx = FunctionBuilderContext::new(); - { - let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); + let func = { + let mut bx = FunctionBuilder::new(Function::new()); let ebb = bx.create_ebb(); bx.switch_to_block(ebb); let val = bx.ins().iconst(types::I8, 0); @@ -296,7 +304,9 @@ mod tests { switch.set_entry($index, ebb); )* switch.emit(&mut bx, val, Ebb::with_number($default).unwrap()); - } + bx.seal_all_blocks(); + bx.finalize() + }; func .to_string() .trim_start_matches("function u0:0() fast {\n") @@ -359,7 +369,10 @@ ebb3: v1 = uextend.i32 v0 v2 = icmp_imm eq v1, 2 brnz v2, ebb2 - brz v1, ebb1 + jump ebb3 + +ebb3: + brz.i32 v1, ebb1 jump ebb0" ); } @@ -382,6 +395,9 @@ ebb0: ebb9: v3 = icmp_imm.i32 uge v1, 10 brnz v3, ebb10 + jump ebb11 + +ebb11: v4 = icmp_imm.i32 eq v1, 7 brnz v4, ebb4 jump ebb0 @@ -389,9 +405,9 @@ ebb9: ebb8: v5 = icmp_imm.i32 eq v1, 5 brnz v5, ebb3 - jump ebb11 + jump ebb12 -ebb11: +ebb12: br_table.i32 v1, ebb0, jt0 ebb10: @@ -410,7 +426,10 @@ ebb10: v1 = uextend.i32 v0 v2 = icmp_imm eq v1, 0x8000_0000_0000_0000 brnz v2, ebb1 - v3 = icmp_imm eq v1, 1 + jump ebb3 + +ebb3: + v3 = icmp_imm.i32 eq v1, 1 brnz v3, ebb2 jump ebb0" ); @@ -426,7 +445,10 @@ ebb10: v1 = uextend.i32 v0 v2 = icmp_imm eq v1, 0x7fff_ffff_ffff_ffff brnz v2, ebb1 - v3 = icmp_imm eq v1, 1 + jump ebb3 + +ebb3: + v3 = icmp_imm.i32 eq v1, 1 brnz v3, ebb2 jump ebb0" ) diff --git a/third_party/rust/cranelift-frontend/src/variable.rs b/third_party/rust/cranelift-frontend/src/variable.rs index dddcd7490b422..1a061beb971d5 100644 --- a/third_party/rust/cranelift-frontend/src/variable.rs +++ b/third_party/rust/cranelift-frontend/src/variable.rs @@ -1,6 +1,6 @@ //! A basic `Variable` implementation. //! -//! `FunctionBuilderContext`, `FunctionBuilder`, and related types have a `Variable` +//! `FunctionBuilder` and related types have a `Variable` //! type parameter, to allow frontends that identify variables with //! their own index types to use them directly. Frontends which don't //! can use the `Variable` defined here. diff --git a/third_party/rust/cranelift-wasm/.cargo-checksum.json b/third_party/rust/cranelift-wasm/.cargo-checksum.json index e5c3118abdb63..553842057b753 100644 --- a/third_party/rust/cranelift-wasm/.cargo-checksum.json +++ b/third_party/rust/cranelift-wasm/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0acc3911c582b0f38099b4694d7600e6d5bb59a701c0b71144ba4cdd0ee2babf","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"1a830b7a75c868246ee6a648187da60fd60b3620bc47c3dfaa716c2712765def","src/environ/dummy.rs":"cca4a867849e82d3fe6793d306d24e89080198e74a58947085edbc12aab2a4ff","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"5f92d6da837267f85543f2700b658b4fb80052816f77d9fbfaa6e511d1ca3116","src/func_translator.rs":"2f1a80ede583cb14cfc2714c1d96855d6d0fdc5e044e092b0257179cd118d876","src/lib.rs":"4664114c8f4c174bea6c0385d36f29198fc9b01a8503308c7d75ea094987744b","src/module_translator.rs":"8f23a0e17c512b6fcb19fc3f19b41aebce6bde51923e812ddd326409ac967efd","src/sections_translator.rs":"cab0e57e173cf752a8ada6cff74abb364c3191a9c3341e5c686d750f51c83995","src/state.rs":"fc2a8d468b4b681d9262fdb8762f3300ffce709cb0b2e48f3835a5b9164e7c93","src/translation_utils.rs":"134ab514ba2a21cca88d603419cf233ffa00f671c8552fd3262a8cd85d3bb97d","tests/wasm_testsuite.rs":"9e01f9053516ce6a411449aaf41438867fc83c83d45cdbe5e84a9a34d4a1ca02"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"3a4cfc0e561c29c298b550e6681a10a8bd99d5d33503604f9cb422c4f52831d3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"12d05978eba1307f264280dbfecad57fcf42d66efcc2a39c5a29dfb20082bd82","src/environ/dummy.rs":"b981a1ca09565978d9e85c5d37915478683a92b4068648d9fa02048cf6b0483f","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"d3363a0989ee2c31d5d31d7bd74d0bb23c3ae3b838b56661749f1f33ef986523","src/func_translator.rs":"89ef0761c4b48ebf9b3134e4ba772a0c97d5d0335da33c0466ee3610cfe4e888","src/lib.rs":"43a29f5dfb3f3f0d3cf85a89eee68e699aae2f80252c09b62b56673c763a1c74","src/module_translator.rs":"7d41cd6b8c09eab6b9448cba46cc4c2f843ed6952b393338d257d5629dabfd62","src/sections_translator.rs":"e49fed0596052b82d0e0010d1fcfdf52e214a16a3aeaa8e57e871927b522c77d","src/state.rs":"fc2a8d468b4b681d9262fdb8762f3300ffce709cb0b2e48f3835a5b9164e7c93","src/translation_utils.rs":"aae22673eb5227840a225c9af831e68a272c6b2ad1300f54c3f0a6116ce88a65","tests/wasm_testsuite.rs":"fc3c9c7b7b504b199cb524b29a18e633f68704de289c865049496ac636c38e0b"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cranelift-wasm/Cargo.toml b/third_party/rust/cranelift-wasm/Cargo.toml index 5beb48fdbf5f7..c140de53a7f2e 100644 --- a/third_party/rust/cranelift-wasm/Cargo.toml +++ b/third_party/rust/cranelift-wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-wasm" -version = "0.40.0" +version = "0.42.0" authors = ["The Cranelift Project Developers"] description = "Translator from WebAssembly to Cranelift IR" repository = "https://github.com/CraneStation/cranelift" @@ -12,9 +12,9 @@ edition = "2018" [dependencies] wasmparser = { version = "0.37.0", default-features = false } -cranelift-codegen = { path = "../cranelift-codegen", version = "0.40.0", default-features = false } -cranelift-entity = { path = "../cranelift-entity", version = "0.40.0", default-features = false } -cranelift-frontend = { path = "../cranelift-frontend", version = "0.40.0", default-features = false } +cranelift-codegen = { path = "../cranelift-codegen", version = "0.42.0", default-features = false } +cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false } +cranelift-frontend = { path = "../cranelift-frontend", version = "0.42.0", default-features = false } hashmap_core = { version = "0.1.9", optional = true } failure = { version = "0.1.1", default-features = false, features = ["derive"] } failure_derive = { version = "0.1.1", default-features = false } @@ -23,7 +23,7 @@ serde = { version = "1.0.94", features = ["derive"], optional = true } [dev-dependencies] wabt = "0.9.1" -target-lexicon = "0.4.0" +target-lexicon = "0.8.1" [features] default = ["std"] diff --git a/third_party/rust/cranelift-wasm/src/code_translator.rs b/third_party/rust/cranelift-wasm/src/code_translator.rs index b87844bfd4bbd..e5ce5a0c322ba 100644 --- a/third_party/rust/cranelift-wasm/src/code_translator.rs +++ b/third_party/rust/cranelift-wasm/src/code_translator.rs @@ -81,7 +81,7 @@ pub fn translate_operator( * `get_global` and `set_global` are handled by the environment. ***********************************************************************************/ Operator::GetGlobal { global_index } => { - let val = match state.get_global(builder.func, *global_index, environ)? { + let val = match state.get_global(&mut builder.func, *global_index, environ)? { GlobalVariable::Const(val) => val, GlobalVariable::Memory { gv, offset, ty } => { let addr = builder.ins().global_value(environ.pointer_type(), gv); @@ -92,7 +92,7 @@ pub fn translate_operator( state.push1(val); } Operator::SetGlobal { global_index } => { - match state.get_global(builder.func, *global_index, environ)? { + match state.get_global(&mut builder.func, *global_index, environ)? { GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index), GlobalVariable::Memory { gv, offset, ty } => { let addr = builder.ins().global_value(environ.pointer_type(), gv); @@ -133,7 +133,7 @@ pub fn translate_operator( ***********************************************************************************/ Operator::Block { ty } => { let next = builder.create_ebb(); - if let Ok(ty_cre) = blocktype_to_type(*ty) { + if let Some(ty_cre) = blocktype_to_type(*ty)? { builder.append_ebb_param(next, ty_cre); } state.push_block(next, num_return_values(*ty)?); @@ -141,7 +141,7 @@ pub fn translate_operator( Operator::Loop { ty } => { let loop_body = builder.create_ebb(); let next = builder.create_ebb(); - if let Ok(ty_cre) = blocktype_to_type(*ty) { + if let Some(ty_cre) = blocktype_to_type(*ty)? { builder.append_ebb_param(next, ty_cre); } builder.ins().jump(loop_body, &[]); @@ -168,7 +168,7 @@ pub fn translate_operator( // and we add nothing; // - either the If have an Else clause, in that case the destination of this jump // instruction will be changed later when we translate the Else operator. - if let Ok(ty_cre) = blocktype_to_type(*ty) { + if let Some(ty_cre) = blocktype_to_type(*ty)? { builder.append_ebb_param(if_not, ty_cre); } state.push_if(jump_inst, if_not, num_return_values(*ty)?); @@ -367,7 +367,8 @@ pub fn translate_operator( * argument referring to an index in the external functions table of the module. ************************************************************************************/ Operator::Call { function_index } => { - let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?; + let (fref, num_args) = + state.get_direct_func(&mut builder.func, *function_index, environ)?; let call = environ.translate_call( builder.cursor(), FuncIndex::from_u32(*function_index), @@ -388,8 +389,8 @@ pub fn translate_operator( Operator::CallIndirect { index, table_index } => { // `index` is the index of the function's signature and `table_index` is the index of // the table to search the function in. - let (sigref, num_args) = state.get_indirect_sig(builder.func, *index, environ)?; - let table = state.get_table(builder.func, *table_index, environ)?; + let (sigref, num_args) = state.get_indirect_sig(&mut builder.func, *index, environ)?; + let table = state.get_table(&mut builder.func, *table_index, environ)?; let callee = state.pop1(); let call = environ.translate_call_indirect( builder.cursor(), @@ -417,13 +418,13 @@ pub fn translate_operator( // The WebAssembly MVP only supports one linear memory, but we expect the reserved // argument to be a memory index. let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(builder.func, *reserved, environ)?; + let heap = state.get_heap(&mut builder.func, *reserved, environ)?; let val = state.pop1(); state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) } Operator::MemorySize { reserved } => { let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(builder.func, *reserved, environ)?; + let heap = state.get_heap(&mut builder.func, *reserved, environ)?; state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?); } /******************************* Load instructions *********************************** @@ -939,6 +940,16 @@ pub fn translate_operator( let splatted = builder.ins().splat(ty, value_to_splat); state.push1(splatted) } + Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => { + let vector = optionally_bitcast_vector(state.pop1(), type_of(op), builder); + let extracted = builder.ins().extractlane(vector, lane.clone()); + state.push1(builder.ins().sextend(I32, extracted)) + } + Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => { + let vector = optionally_bitcast_vector(state.pop1(), type_of(op), builder); + state.push1(builder.ins().extractlane(vector, lane.clone())); + // on x86, PEXTRB zeroes the upper bits of the destination register of extractlane so uextend is elided; of course, this depends on extractlane being legalized to a PEXTRB + } Operator::I32x4ExtractLane { lane } | Operator::I64x2ExtractLane { lane } | Operator::F32x4ExtractLane { lane } @@ -966,10 +977,6 @@ pub fn translate_operator( } Operator::V128Load { .. } | Operator::V128Store { .. } - | Operator::I8x16ExtractLaneS { .. } - | Operator::I8x16ExtractLaneU { .. } - | Operator::I16x8ExtractLaneS { .. } - | Operator::I16x8ExtractLaneU { .. } | Operator::V8x16Shuffle { .. } | Operator::I8x16Eq | Operator::I8x16Ne @@ -1231,7 +1238,7 @@ fn translate_load( ) -> WasmResult<()> { let addr32 = state.pop1(); // We don't yet support multiple linear memories. - let heap = state.get_heap(builder.func, 0, environ)?; + let heap = state.get_heap(&mut builder.func, 0, environ)?; let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); // Note that we don't set `is_aligned` here, even if the load instruction's // alignment immediate says it's aligned, because WebAssembly's immediate @@ -1256,7 +1263,7 @@ fn translate_store( let val_ty = builder.func.dfg.value_type(val); // We don't yet support multiple linear memories. - let heap = state.get_heap(builder.func, 0, environ)?; + let heap = state.get_heap(&mut builder.func, 0, environ)?; let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); // See the comments in `translate_load` about the flags. let flags = MemFlags::new(); diff --git a/third_party/rust/cranelift-wasm/src/environ/dummy.rs b/third_party/rust/cranelift-wasm/src/environ/dummy.rs index fcec4e648cc70..98cdb3f44e994 100644 --- a/third_party/rust/cranelift-wasm/src/environ/dummy.rs +++ b/third_party/rust/cranelift-wasm/src/environ/dummy.rs @@ -17,7 +17,7 @@ use cranelift_codegen::ir::immediates::{Offset32, Uimm64}; use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; -use cranelift_entity::{EntityRef, PrimaryMap}; +use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap}; use std::boxed::Box; use std::string::String; use std::vec::Vec; @@ -124,6 +124,9 @@ pub struct DummyEnvironment { /// Instructs to collect debug data during translation. debug_info: bool, + + /// Function names. + function_names: SecondaryMap, } impl DummyEnvironment { @@ -135,6 +138,7 @@ impl DummyEnvironment { func_bytecode_sizes: Vec::new(), return_mode, debug_info, + function_names: SecondaryMap::new(), } } @@ -152,6 +156,12 @@ impl DummyEnvironment { pub fn get_num_func_imports(&self) -> usize { self.info.imported_funcs.len() } + + /// Return the name of the function, if a name for the function with + /// the corresponding index exists. + pub fn get_func_name(&self, func_index: FuncIndex) -> Option<&str> { + self.function_names.get(func_index).map(String::as_ref) + } } /// The `FuncEnvironment` implementation for use by the `DummyEnvironment`. @@ -533,11 +543,15 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { func.collect_debug_info(); } self.trans - .translate(body_bytes, body_offset, &mut func, &mut func_environ)?; - func + .translate(body_bytes, body_offset, func, &mut func_environ)? }; self.func_bytecode_sizes.push(body_bytes.len()); self.info.function_bodies.push(func); Ok(()) } + + fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> { + self.function_names[func_index] = String::from(name); + Ok(()) + } } diff --git a/third_party/rust/cranelift-wasm/src/environ/spec.rs b/third_party/rust/cranelift-wasm/src/environ/spec.rs index 59208ea562e12..ba87cc992a9ca 100644 --- a/third_party/rust/cranelift-wasm/src/environ/spec.rs +++ b/third_party/rust/cranelift-wasm/src/environ/spec.rs @@ -467,4 +467,18 @@ pub trait ModuleEnvironment<'data> { offset: usize, data: &'data [u8], ) -> WasmResult<()>; + + /// Declares the name of a function to the environment. + /// + /// By default this does nothing, but implementations can use this to read + /// the function name subsection of the custom name section if desired. + fn declare_func_name(&mut self, _func_index: FuncIndex, _name: &'data str) -> WasmResult<()> { + Ok(()) + } + + /// Indicates that a custom section has been found in the wasm file + fn custom_section(&mut self, name: &'data str, data: &'data [u8]) -> WasmResult<()> { + drop((name, data)); + Ok(()) + } } diff --git a/third_party/rust/cranelift-wasm/src/func_translator.rs b/third_party/rust/cranelift-wasm/src/func_translator.rs index b49cffd47489b..ed5c51e59f4c4 100644 --- a/third_party/rust/cranelift-wasm/src/func_translator.rs +++ b/third_party/rust/cranelift-wasm/src/func_translator.rs @@ -12,7 +12,7 @@ use crate::wasm_unsupported; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; use cranelift_codegen::timing; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +use cranelift_frontend::{FunctionBuilder, Variable}; use log::info; use wasmparser::{self, BinaryReader}; @@ -22,7 +22,7 @@ use wasmparser::{self, BinaryReader}; /// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple /// functions which will reduce heap allocation traffic. pub struct FuncTranslator { - func_ctx: FunctionBuilderContext, + builder: FunctionBuilder, state: TranslationState, } @@ -30,7 +30,7 @@ impl FuncTranslator { /// Create a new translator. pub fn new() -> Self { Self { - func_ctx: FunctionBuilderContext::new(), + builder: FunctionBuilder::new(ir::Function::new()), state: TranslationState::new(), } } @@ -57,9 +57,9 @@ impl FuncTranslator { &mut self, code: &[u8], code_offset: usize, - func: &mut ir::Function, + func: ir::Function, environ: &mut FE, - ) -> WasmResult<()> { + ) -> WasmResult { self.translate_from_reader( BinaryReader::new_with_offset(code, code_offset), func, @@ -71,9 +71,9 @@ impl FuncTranslator { pub fn translate_from_reader( &mut self, mut reader: BinaryReader, - func: &mut ir::Function, + func: ir::Function, environ: &mut FE, - ) -> WasmResult<()> { + ) -> WasmResult { let _tt = timing::wasm_translate_function(); info!( "translate({} bytes, {}{})", @@ -84,31 +84,32 @@ impl FuncTranslator { debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty"); debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty"); - // This clears the `FunctionBuilderContext`. - let mut builder = FunctionBuilder::new(func, &mut self.func_ctx); - builder.set_srcloc(cur_srcloc(&reader)); - let entry_block = builder.create_ebb(); - builder.append_ebb_params_for_function_params(entry_block); - builder.switch_to_block(entry_block); // This also creates values for the arguments. - builder.seal_block(entry_block); // Declare all predecessors known. + self.builder.func = func; + self.builder.set_srcloc(cur_srcloc(&reader)); + let entry_block = self.builder.create_ebb(); + self.builder + .append_ebb_params_for_function_params(entry_block); + self.builder.switch_to_block(entry_block); // This also creates values for the arguments. + self.builder.seal_block(entry_block); // Declare all predecessors known. // Make sure the entry block is inserted in the layout before we make any callbacks to // `environ`. The callback functions may need to insert things in the entry block. - builder.ensure_inserted_ebb(); + self.builder.ensure_inserted_ebb(); - let num_params = declare_wasm_parameters(&mut builder, entry_block); + let num_params = declare_wasm_parameters(&mut self.builder, entry_block); // Set up the translation state with a single pushed control block representing the whole // function and its return values. - let exit_block = builder.create_ebb(); - builder.append_ebb_params_for_function_returns(exit_block); - self.state.initialize(&builder.func.signature, exit_block); + let exit_block = self.builder.create_ebb(); + self.builder + .append_ebb_params_for_function_returns(exit_block); + self.state + .initialize(&self.builder.func.signature, exit_block); - parse_local_decls(&mut reader, &mut builder, num_params, environ)?; - parse_function_body(reader, &mut builder, &mut self.state, environ)?; + parse_local_decls(&mut reader, &mut self.builder, num_params, environ)?; + parse_function_body(reader, &mut self.builder, &mut self.state, environ)?; - builder.finalize(); - Ok(()) + Ok(self.builder.finalize()) } } @@ -288,8 +289,8 @@ mod tests { ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - trans - .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) + ctx.func = trans + .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -327,8 +328,8 @@ mod tests { ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - trans - .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) + ctx.func = trans + .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -374,8 +375,8 @@ mod tests { ctx.func.name = ir::ExternalName::testcase("infloop"); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - trans - .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) + ctx.func = trans + .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); diff --git a/third_party/rust/cranelift-wasm/src/lib.rs b/third_party/rust/cranelift-wasm/src/lib.rs index c4770a68ea6b0..3c1065228baba 100644 --- a/third_party/rust/cranelift-wasm/src/lib.rs +++ b/third_party/rust/cranelift-wasm/src/lib.rs @@ -28,7 +28,6 @@ ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(not(feature = "std"))] #[macro_use] diff --git a/third_party/rust/cranelift-wasm/src/module_translator.rs b/third_party/rust/cranelift-wasm/src/module_translator.rs index b35d1d4e38622..8d8b55397de2a 100644 --- a/third_party/rust/cranelift-wasm/src/module_translator.rs +++ b/third_party/rust/cranelift-wasm/src/module_translator.rs @@ -4,10 +4,10 @@ use crate::environ::{ModuleEnvironment, WasmError, WasmResult}; use crate::sections_translator::{ parse_code_section, parse_data_section, parse_element_section, parse_export_section, parse_function_section, parse_global_section, parse_import_section, parse_memory_section, - parse_start_section, parse_table_section, parse_type_section, + parse_name_section, parse_start_section, parse_table_section, parse_type_section, }; use cranelift_codegen::timing; -use wasmparser::{ModuleReader, SectionCode}; +use wasmparser::{CustomSectionKind, ModuleReader, SectionCode}; /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR /// [`Function`](cranelift_codegen::ir::Function). @@ -18,133 +18,86 @@ pub fn translate_module<'data>( let _tt = timing::wasm_translate_module(); let mut reader = ModuleReader::new(data)?; - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - let mut section = reader.read()?; - - if let SectionCode::Type = section.code { - let types = section.get_type_section_reader()?; - parse_type_section(types, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Import = section.code { - let imports = section.get_import_section_reader()?; - parse_import_section(imports, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Function = section.code { - let functions = section.get_function_section_reader()?; - parse_function_section(functions, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); + while !reader.eof() { + let section = reader.read()?; + match section.code { + SectionCode::Type => { + let types = section.get_type_section_reader()?; + parse_type_section(types, environ)?; + } + + SectionCode::Import => { + let imports = section.get_import_section_reader()?; + parse_import_section(imports, environ)?; + } + + SectionCode::Function => { + let functions = section.get_function_section_reader()?; + parse_function_section(functions, environ)?; + } + + SectionCode::Table => { + let tables = section.get_table_section_reader()?; + parse_table_section(tables, environ)?; + } + + SectionCode::Memory => { + let memories = section.get_memory_section_reader()?; + parse_memory_section(memories, environ)?; + } + + SectionCode::Global => { + let globals = section.get_global_section_reader()?; + parse_global_section(globals, environ)?; + } + + SectionCode::Export => { + let exports = section.get_export_section_reader()?; + parse_export_section(exports, environ)?; + } + + SectionCode::Start => { + let start = section.get_start_section_content()?; + parse_start_section(start, environ)?; + } + + SectionCode::Element => { + let elements = section.get_element_section_reader()?; + parse_element_section(elements, environ)?; + } + + SectionCode::Code => { + let code = section.get_code_section_reader()?; + parse_code_section(code, environ)?; + } + + SectionCode::Data => { + let data = section.get_data_section_reader()?; + parse_data_section(data, environ)?; + } + + SectionCode::DataCount => { + return Err(WasmError::InvalidWebAssembly { + message: "don't know how to handle the data count section yet", + offset: reader.current_position(), + }); + } + + SectionCode::Custom { + kind: CustomSectionKind::Name, + name: _, + } => { + let names = section.get_name_section_reader()?; + parse_name_section(names, environ)?; + } + + SectionCode::Custom { name, kind: _ } => { + let mut reader = section.get_binary_reader(); + let len = reader.bytes_remaining(); + let payload = reader.read_bytes(len)?; + environ.custom_section(name, payload)?; + } } - section = reader.read()?; - } - - if let SectionCode::Table = section.code { - let tables = section.get_table_section_reader()?; - parse_table_section(tables, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Memory = section.code { - let memories = section.get_memory_section_reader()?; - parse_memory_section(memories, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Global = section.code { - let globals = section.get_global_section_reader()?; - parse_global_section(globals, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Export = section.code { - let exports = section.get_export_section_reader()?; - parse_export_section(exports, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Start = section.code { - let start = section.get_start_section_content()?; - parse_start_section(start, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Element = section.code { - let elements = section.get_element_section_reader()?; - parse_element_section(elements, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Code = section.code { - let code = section.get_code_section_reader()?; - parse_code_section(code, environ)?; - - reader.skip_custom_sections()?; - if reader.eof() { - return Ok(()); - } - section = reader.read()?; - } - - if let SectionCode::Data = section.code { - let data = section.get_data_section_reader()?; - parse_data_section(data, environ)?; - } - - reader.skip_custom_sections()?; - if !reader.eof() { - return Err(WasmError::InvalidWebAssembly { - message: "sections must occur at most once and in the prescribed order", - offset: reader.current_position(), - }); } Ok(()) diff --git a/third_party/rust/cranelift-wasm/src/sections_translator.rs b/third_party/rust/cranelift-wasm/src/sections_translator.rs index 4ca8a66b87ff6..67830af3ff1bb 100644 --- a/third_party/rust/cranelift-wasm/src/sections_translator.rs +++ b/third_party/rust/cranelift-wasm/src/sections_translator.rs @@ -12,7 +12,7 @@ use crate::translation_utils::{ tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, }; -use crate::wasm_unsupported; +use crate::{wasm_unsupported, HashMap}; use core::convert::TryFrom; use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_entity::EntityRef; @@ -21,8 +21,8 @@ use wasmparser::{ self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, - ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader, - TypeSectionReader, + ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader, + Operator, TableSectionReader, TypeSectionReader, }; /// Parses the Type section of the wasm module. @@ -351,3 +351,47 @@ pub fn parse_data_section<'data>( Ok(()) } + +/// Parses the Name section of the wasm module. +pub fn parse_name_section<'data>( + mut names: NameSectionReader<'data>, + environ: &mut dyn ModuleEnvironment<'data>, +) -> WasmResult<()> { + while let Ok(subsection) = names.read() { + match subsection { + wasmparser::Name::Function(function_subsection) => { + if let Some(function_names) = function_subsection + .get_map() + .ok() + .and_then(parse_function_name_subsection) + { + for (index, name) in function_names { + environ.declare_func_name(index, name)?; + } + } + return Ok(()); + } + wasmparser::Name::Local(_) | wasmparser::Name::Module(_) => {} + }; + } + Ok(()) +} + +fn parse_function_name_subsection<'data>( + mut naming_reader: NamingReader<'data>, +) -> Option> { + let mut function_names = HashMap::new(); + for _ in 0..naming_reader.get_count() { + let Naming { index, name } = naming_reader.read().ok()?; + if function_names + .insert(FuncIndex::from_u32(index), name) + .is_some() + { + // If the function index has been previously seen, then we + // break out of the loop and early return `None`, because these + // should be unique. + return None; + } + } + return Some(function_names); +} diff --git a/third_party/rust/cranelift-wasm/src/translation_utils.rs b/third_party/rust/cranelift-wasm/src/translation_utils.rs index 90967d410208c..f033b8660c730 100644 --- a/third_party/rust/cranelift-wasm/src/translation_utils.rs +++ b/third_party/rust/cranelift-wasm/src/translation_utils.rs @@ -115,35 +115,43 @@ pub struct Memory { /// Helper function translating wasmparser types to Cranelift types when possible. pub fn type_to_type(ty: wasmparser::Type) -> WasmResult { - Ok(match ty { - wasmparser::Type::I32 => ir::types::I32, - wasmparser::Type::I64 => ir::types::I64, - wasmparser::Type::F32 => ir::types::F32, - wasmparser::Type::F64 => ir::types::F64, - ty => wasm_unsupported!("unsupported wasm type {:?}", ty), - }) + match ty { + wasmparser::Type::I32 => Ok(ir::types::I32), + wasmparser::Type::I64 => Ok(ir::types::I64), + wasmparser::Type::F32 => Ok(ir::types::F32), + wasmparser::Type::F64 => Ok(ir::types::F64), + ty => wasm_unsupported!("type_to_type: wasm type {:?}", ty), + } } /// Helper function translating wasmparser possible table types to Cranelift types when possible, /// or None for Func tables. pub fn tabletype_to_type(ty: wasmparser::Type) -> WasmResult> { - Ok(match ty { - wasmparser::Type::I32 => Some(ir::types::I32), - wasmparser::Type::I64 => Some(ir::types::I64), - wasmparser::Type::F32 => Some(ir::types::F32), - wasmparser::Type::F64 => Some(ir::types::F64), - wasmparser::Type::AnyFunc => None, - ty => wasm_unsupported!("unsupported table wasm type {:?}", ty), - }) + match ty { + wasmparser::Type::I32 => Ok(Some(ir::types::I32)), + wasmparser::Type::I64 => Ok(Some(ir::types::I64)), + wasmparser::Type::F32 => Ok(Some(ir::types::F32)), + wasmparser::Type::F64 => Ok(Some(ir::types::F64)), + wasmparser::Type::AnyFunc => Ok(None), + ty => wasm_unsupported!("tabletype_to_type: table wasm type {:?}", ty), + } } /// Helper function translating wasmparser block signatures to Cranelift types when possible. -pub fn blocktype_to_type(ty: wasmparser::TypeOrFuncType) -> WasmResult { - match ty { - wasmparser::TypeOrFuncType::Type(ty) => type_to_type(ty), - wasmparser::TypeOrFuncType::FuncType(_) => { - wasm_unsupported!("multi-value block signature {:?}", ty); - } +pub fn blocktype_to_type(ty_or_ft: wasmparser::TypeOrFuncType) -> WasmResult> { + match ty_or_ft { + wasmparser::TypeOrFuncType::Type(ty) => match ty { + wasmparser::Type::I32 => Ok(Some(ir::types::I32)), + wasmparser::Type::I64 => Ok(Some(ir::types::I64)), + wasmparser::Type::F32 => Ok(Some(ir::types::F32)), + wasmparser::Type::F64 => Ok(Some(ir::types::F64)), + wasmparser::Type::EmptyBlockType => Ok(None), + ty => wasm_unsupported!("blocktype_to_type: type {:?}", ty), + }, + wasmparser::TypeOrFuncType::FuncType(_) => wasm_unsupported!( + "blocktype_to_type: multi-value block signature {:?}", + ty_or_ft + ), } } diff --git a/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs b/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs index fd46458d5339b..69db90ca6c3c0 100644 --- a/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs +++ b/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs @@ -2,7 +2,7 @@ use cranelift_codegen::isa; use cranelift_codegen::print_errors::pretty_verifier_error; use cranelift_codegen::settings::{self, Flags}; use cranelift_codegen::verifier; -use cranelift_wasm::{translate_module, DummyEnvironment, ReturnMode}; +use cranelift_wasm::{translate_module, DummyEnvironment, FuncIndex, ReturnMode}; use std::fs; use std::fs::File; use std::io; @@ -10,7 +10,7 @@ use std::io::prelude::*; use std::path::Path; use std::str::FromStr; use target_lexicon::triple; -use wabt::{wat2wasm_with_features, Features}; +use wabt::{wat2wasm_with_features, Features, Wat2Wasm}; #[test] fn testsuite() { @@ -31,17 +31,42 @@ fn testsuite() { let flags = Flags::new(settings::builder()); for path in paths { let path = path.path(); - handle_module(&path, &flags, ReturnMode::NormalReturns); + let data = read_module(&path); + handle_module(data, &flags, ReturnMode::NormalReturns); } } #[test] fn use_fallthrough_return() { let flags = Flags::new(settings::builder()); - handle_module( - Path::new("../wasmtests/use_fallthrough_return.wat"), - &flags, - ReturnMode::FallthroughReturn, + let path = Path::new("../wasmtests/use_fallthrough_return.wat"); + let data = read_module(&path); + handle_module(data, &flags, ReturnMode::FallthroughReturn); +} + +#[test] +fn use_name_section() { + let wat = r#" + (module $module_name + (func $func_name (local $loc_name i32) + ) + )"#; + let data = Wat2Wasm::new() + .write_debug_names(true) + .convert(wat) + .unwrap_or_else(|e| panic!("error converting wat to wasm: {:?}", e)); + + let flags = Flags::new(settings::builder()); + let triple = triple!("riscv64"); + let isa = isa::lookup(triple).unwrap().finish(flags.clone()); + let return_mode = ReturnMode::NormalReturns; + let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false); + + translate_module(data.as_ref(), &mut dummy_environ).unwrap(); + + assert_eq!( + dummy_environ.get_func_name(FuncIndex::from_u32(0)).unwrap(), + "func_name" ); } @@ -52,10 +77,10 @@ fn read_file(path: &Path) -> io::Result> { Ok(buf) } -fn handle_module(path: &Path, flags: &Flags, return_mode: ReturnMode) { +fn read_module(path: &Path) -> Vec { let mut features = Features::new(); features.enable_all(); - let data = match path.extension() { + match path.extension() { None => { panic!("the file extension is not wasm or wat"); } @@ -72,7 +97,10 @@ fn handle_module(path: &Path, flags: &Flags, return_mode: ReturnMode) { } None | Some(&_) => panic!("the file extension for {:?} is not wasm or wat", path), }, - }; + } +} + +fn handle_module(data: Vec, flags: &Flags, return_mode: ReturnMode) { let triple = triple!("riscv64"); let isa = isa::lookup(triple).unwrap().finish(flags.clone()); let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false); diff --git a/third_party/rust/object/.cargo-checksum.json b/third_party/rust/object/.cargo-checksum.json index 9ab70479c84bf..53386b13ef8f9 100644 --- a/third_party/rust/object/.cargo-checksum.json +++ b/third_party/rust/object/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3dd7528275c4d0eef0dd1b918dc6247c7e996383657355b43362f826f59b31fe","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b74dfa0bcee5c420c6b7f67b4b2658f9ab8388c97b8e733975f2cecbdd668a6","README.md":"5c498b93ff10c038784c5b62c346858c0d53d9d6d1591841c5b6724b0abc9415","examples/nm.rs":"9885cb85700512d63e537b4b60bd2c840aa076721eae2059ba6ae3651be1282e","examples/objcopy.rs":"a05e1b87318be30b6dd67c061c59d77b97efde2af9d5191c9c97978c0410a5eb","examples/objdump.rs":"07a23a2f74b7e46d4cdcf4dab23357a39410b4c4db43179c17e059011e40d45c","src/common.rs":"143f42a0e085e82a022b85680d42322ac912eefc4ab2cb2bee687368fa8615a5","src/lib.rs":"7e559b0af48faca419086a743e3f99794e10a91e8619f8c6e26f113d1935fe14","src/read/any.rs":"12be08836fb2f66026b34434b47cfe275f82cf31b05039ef0545fc324a3b9bce","src/read/coff.rs":"f3a16d71ec8c5692f5435bf51a3ecda49dc727d5d93f5cdef67e7853e31e6dfa","src/read/elf.rs":"68939fc291b2f2c0b6d3d112fd7edf5eaed8b5987d6fda35a1a843843511d325","src/read/macho.rs":"ee575a49c194fdaa9132e1230266269dc4cb497b9a8f1fed635173bba492ead2","src/read/mod.rs":"efdb99a566a971bca815e1d1dd85b9e9800fbe4e3572cf54a7b0ff54111469c2","src/read/pe.rs":"423527bb5fb5b234057d51925f6ac3ea05603618c1d8c6165de2f9c819978d02","src/read/traits.rs":"c73dd0ca832fc74a9addb414ab5ffe430e6c076a0bd934b31e6608e04c61dc5e","src/read/wasm.rs":"5f6e1e24d53429ac9d80f87e7784183a4608d08b3f465df629c86c68f1af56d4","src/write/coff.rs":"9c9ebc226cb585a61e3c96085099b69de0b2b75877093f644b3caacf03b6d03d","src/write/elf.rs":"d6e7bb6db9b29de1c105dfa75c7e561c85e42a05c75c70cf7baffe25d3009d06","src/write/macho.rs":"1ca4e4d75e45badc4bf5b5dfc8a663d1060d85e6c6a94236ffe9db3c09531c5e","src/write/mod.rs":"248ccbc34aa0cdd84e3c413913f05fe1478a4837ad41e3448414289bb73b2671","src/write/string.rs":"a0640f9e0626ca4618a2ac88e17e0d14b053f880d60635ea932ca78b50a114f5","src/write/util.rs":"9629903d556036aa7d6031cffce1fd38c033453a28c0a30eb34fc77aded4a11d","tests/round_trip.rs":"a28b57931275c31b704aed5350da92e43abf4c09c5fb94360c9ab5db6a7c4a78"},"package":"d89ec45bc6b810c6ee998e22953fbf387a40fcbf5014dcbb9e5ba9a09a81ee15"} \ No newline at end of file +{"files":{"Cargo.lock":"440af8ab126af2257c67fdd2e1f0b144ed63f17a4a0a223211ec31ad1fda4d08","Cargo.toml":"3dd7528275c4d0eef0dd1b918dc6247c7e996383657355b43362f826f59b31fe","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b74dfa0bcee5c420c6b7f67b4b2658f9ab8388c97b8e733975f2cecbdd668a6","README.md":"5c498b93ff10c038784c5b62c346858c0d53d9d6d1591841c5b6724b0abc9415","examples/nm.rs":"9885cb85700512d63e537b4b60bd2c840aa076721eae2059ba6ae3651be1282e","examples/objcopy.rs":"a05e1b87318be30b6dd67c061c59d77b97efde2af9d5191c9c97978c0410a5eb","examples/objdump.rs":"07a23a2f74b7e46d4cdcf4dab23357a39410b4c4db43179c17e059011e40d45c","src/common.rs":"143f42a0e085e82a022b85680d42322ac912eefc4ab2cb2bee687368fa8615a5","src/lib.rs":"7e559b0af48faca419086a743e3f99794e10a91e8619f8c6e26f113d1935fe14","src/read/any.rs":"12be08836fb2f66026b34434b47cfe275f82cf31b05039ef0545fc324a3b9bce","src/read/coff.rs":"f3a16d71ec8c5692f5435bf51a3ecda49dc727d5d93f5cdef67e7853e31e6dfa","src/read/elf.rs":"68939fc291b2f2c0b6d3d112fd7edf5eaed8b5987d6fda35a1a843843511d325","src/read/macho.rs":"ee575a49c194fdaa9132e1230266269dc4cb497b9a8f1fed635173bba492ead2","src/read/mod.rs":"efdb99a566a971bca815e1d1dd85b9e9800fbe4e3572cf54a7b0ff54111469c2","src/read/pe.rs":"423527bb5fb5b234057d51925f6ac3ea05603618c1d8c6165de2f9c819978d02","src/read/traits.rs":"c73dd0ca832fc74a9addb414ab5ffe430e6c076a0bd934b31e6608e04c61dc5e","src/read/wasm.rs":"5f6e1e24d53429ac9d80f87e7784183a4608d08b3f465df629c86c68f1af56d4","src/write/coff.rs":"9c9ebc226cb585a61e3c96085099b69de0b2b75877093f644b3caacf03b6d03d","src/write/elf.rs":"d6e7bb6db9b29de1c105dfa75c7e561c85e42a05c75c70cf7baffe25d3009d06","src/write/macho.rs":"1ca4e4d75e45badc4bf5b5dfc8a663d1060d85e6c6a94236ffe9db3c09531c5e","src/write/mod.rs":"248ccbc34aa0cdd84e3c413913f05fe1478a4837ad41e3448414289bb73b2671","src/write/string.rs":"a0640f9e0626ca4618a2ac88e17e0d14b053f880d60635ea932ca78b50a114f5","src/write/util.rs":"9629903d556036aa7d6031cffce1fd38c033453a28c0a30eb34fc77aded4a11d","tests/round_trip.rs":"a28b57931275c31b704aed5350da92e43abf4c09c5fb94360c9ab5db6a7c4a78"},"package":"d89ec45bc6b810c6ee998e22953fbf387a40fcbf5014dcbb9e5ba9a09a81ee15"} \ No newline at end of file diff --git a/third_party/rust/object/Cargo.lock b/third_party/rust/object/Cargo.lock new file mode 100644 index 0000000000000..fb4a987f9a6a6 --- /dev/null +++ b/third_party/rust/object/Cargo.lock @@ -0,0 +1,338 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "goblin" +version = "0.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indexmap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide_c_api" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "object" +version = "0.13.0" +dependencies = [ + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-wasm" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scroll" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scroll_derive" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "target-lexicon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" +"checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" +"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" +"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" +"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" +"checksum parity-wasm 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee68a5b3b7c7f818f982ff75579410b4b8c611d58d623c5bb5c70e9cbb6e16a" +"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ba92c84f814b3f9a44c5cfca7d2ad77fa10710867d2bbb1b3d175ab5f47daa12" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" +"checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rust/smallvec/.cargo-checksum.json b/third_party/rust/smallvec/.cargo-checksum.json index ab5882c20b11b..57d87f2e00bb6 100644 --- a/third_party/rust/smallvec/.cargo-checksum.json +++ b/third_party/rust/smallvec/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"6dfd8546c3b51b9b1cca1c1c52996e8bcaa899ee5edba5b8b077f0e111d962ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9","README.md":"38eef4ebde6fe6effa12a2dbca3bd69d6446b2935f19a329ac4926f1cb2e5013","benches/bench.rs":"9dca7122a3dcb2c099e49807e4d3b8f01d9220e2b3db0a54e9901ee74392866f","lib.rs":"b30f38a737a71c82237e5dfc45bcfe23faf894ef22de9350f302a9603d20ac0f"},"package":"622df2d454c29a4d89b30dc3b27b42d7d90d6b9e587dbf8f67652eb7514da484"} \ No newline at end of file +{"files":{"Cargo.toml":"a064123fc22a52158c37be025c3b70d413c4b1ee743e92a2e80ed419e2992d65","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9","README.md":"38eef4ebde6fe6effa12a2dbca3bd69d6446b2935f19a329ac4926f1cb2e5013","benches/bench.rs":"9dca7122a3dcb2c099e49807e4d3b8f01d9220e2b3db0a54e9901ee74392866f","lib.rs":"4d6998b0b80a85e85cf00bd317a88518067e9e8ba191185418263dec67069c16"},"package":"ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"} \ No newline at end of file diff --git a/third_party/rust/smallvec/Cargo.toml b/third_party/rust/smallvec/Cargo.toml index 678469d572865..5b23e5a16be9d 100644 --- a/third_party/rust/smallvec/Cargo.toml +++ b/third_party/rust/smallvec/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,7 +12,7 @@ [package] name = "smallvec" -version = "0.6.6" +version = "0.6.10" authors = ["Simon Sapin "] description = "'Small vector' optimization: store up to a small number of items on the stack" documentation = "https://doc.servo.org/smallvec/" @@ -28,14 +28,12 @@ path = "lib.rs" [dependencies.serde] version = "1" optional = true - -[dependencies.unreachable] -version = "1.0.0" [dev-dependencies.bincode] version = "1.0.1" [features] default = ["std"] +may_dangle = [] specialization = [] std = [] union = [] diff --git a/third_party/rust/smallvec/lib.rs b/third_party/rust/smallvec/lib.rs index d3699c09132f0..e45ca7aebdb00 100644 --- a/third_party/rust/smallvec/lib.rs +++ b/third_party/rust/smallvec/lib.rs @@ -32,6 +32,7 @@ #![cfg_attr(not(feature = "std"), feature(alloc))] #![cfg_attr(feature = "union", feature(untagged_unions))] #![cfg_attr(feature = "specialization", feature(specialization))] +#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #![deny(missing_docs)] @@ -45,9 +46,6 @@ use alloc::vec::Vec; #[cfg(feature = "serde")] extern crate serde; -extern crate unreachable; -use unreachable::UncheckedOptionExt; - #[cfg(not(feature = "std"))] mod std { pub use core::*; @@ -59,7 +57,6 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::{IntoIterator, FromIterator, repeat}; use std::mem; -#[cfg(not(feature = "union"))] use std::mem::ManuallyDrop; use std::ops; use std::ptr; @@ -131,13 +128,24 @@ macro_rules! smallvec { }); } +/// Hint to the optimizer that any code path which calls this function is +/// statically unreachable and can be removed. +/// +/// Equivalent to `std::hint::unreachable_unchecked` but works in older versions of Rust. +#[inline] +pub unsafe fn unreachable() -> ! { + enum Void {} + let x: &Void = mem::transmute(1usize); + match *x {} +} + /// `panic!()` in debug builds, optimization hint in release. #[cfg(not(feature = "union"))] macro_rules! debug_unreachable { () => { debug_unreachable!("entered unreachable code") }; ($e:expr) => { if cfg!(not(debug_assertions)) { - unreachable::unreachable(); + unreachable(); } else { panic!($e); } @@ -267,9 +275,8 @@ impl<'a, T: 'a> Drop for Drain<'a,T> { } #[cfg(feature = "union")] -#[allow(unions_with_drop_fields)] union SmallVecData { - inline: A, + inline: ManuallyDrop, heap: (*mut A::Item, usize), } @@ -285,10 +292,10 @@ impl SmallVecData { } #[inline] fn from_inline(inline: A) -> SmallVecData { - SmallVecData { inline } + SmallVecData { inline: ManuallyDrop::new(inline) } } #[inline] - unsafe fn into_inline(self) -> A { self.inline } + unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) } #[inline] unsafe fn heap(&self) -> (*mut A::Item, usize) { self.heap @@ -362,7 +369,7 @@ unsafe impl Sync for SmallVecData {} /// A `Vec`-like container that can store a small number of elements inline. /// /// `SmallVec` acts like a vector, but can store a limited amount of data inline within the -/// `Smallvec` struct rather than in a separate allocation. If the data exceeds this limit, the +/// `SmallVec` struct rather than in a separate allocation. If the data exceeds this limit, the /// `SmallVec` will "spill" its data onto the heap, allocating a new buffer to hold it. /// /// The amount of data that a `SmallVec` can store inline depends on its backing store. The backing @@ -647,6 +654,7 @@ impl SmallVec { } self.data = SmallVecData::from_inline(mem::uninitialized()); ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); + self.capacity = len; } else if new_cap != cap { let mut vec = Vec::with_capacity(new_cap); let new_alloc = vec.as_mut_ptr(); @@ -657,6 +665,8 @@ impl SmallVec { if unspilled { return; } + } else { + return; } deallocate(ptr, cap); } @@ -759,7 +769,7 @@ impl SmallVec { pub fn swap_remove(&mut self, index: usize) -> A::Item { let len = self.len(); self.swap(len - 1, index); - unsafe { self.pop().unchecked_unwrap() } + self.pop().unwrap_or_else(|| unsafe { unreachable() }) } /// Remove all elements from the vector. @@ -1341,18 +1351,16 @@ impl Extend for SmallVec { self.reserve(lower_size_bound); unsafe { - let len = self.len(); - let ptr = self.as_mut_ptr().offset(len as isize); - let mut count = 0; - while count < lower_size_bound { + let (ptr, len_ptr, cap) = self.triple_mut(); + let mut len = SetLenOnDrop::new(len_ptr); + while len.get() < cap { if let Some(out) = iter.next() { - ptr::write(ptr.offset(count as isize), out); - count += 1; + ptr::write(ptr.offset(len.get() as isize), out); + len.increment_len(1); } else { - break; + return; } } - self.set_len(len + count); } for elem in iter { @@ -1374,6 +1382,21 @@ impl Default for SmallVec { } } +#[cfg(feature = "may_dangle")] +unsafe impl<#[may_dangle] A: Array> Drop for SmallVec { + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } + } +} + +#[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { unsafe { @@ -1546,6 +1569,11 @@ impl<'a> SetLenOnDrop<'a> { SetLenOnDrop { local_len: *len, len: len } } + #[inline] + fn get(&self) -> usize { + self.local_len + } + #[inline] fn increment_len(&mut self, increment: usize) { self.local_len += increment; @@ -2286,4 +2314,47 @@ mod tests { let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); assert_eq!(small_vec, decoded); } + + #[test] + fn grow_to_shrink() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(1); + v.push(2); + v.push(3); + assert!(v.spilled()); + v.clear(); + // Shrink to inline. + v.grow(2); + assert!(!v.spilled()); + assert_eq!(v.capacity(), 2); + assert_eq!(v.len(), 0); + v.push(4); + assert_eq!(v[..], [4]); + } + + #[test] + fn resumable_extend() { + let s = "a b c"; + // This iterator yields: (Some('a'), None, Some('b'), None, Some('c')), None + let it = s + .chars() + .scan(0, |_, ch| if ch.is_whitespace() { None } else { Some(ch) }); + let mut v: SmallVec<[char; 4]> = SmallVec::new(); + v.extend(it); + assert_eq!(v[..], ['a']); + } + + #[test] + fn grow_spilled_same_size() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(0); + v.push(1); + v.push(2); + assert!(v.spilled()); + assert_eq!(v.capacity(), 4); + // grow with the same capacity + v.grow(4); + assert_eq!(v.capacity(), 4); + assert_eq!(v[..], [0, 1, 2]); + } } diff --git a/third_party/rust/target-lexicon-0.4.0/.cargo-checksum.json b/third_party/rust/target-lexicon-0.4.0/.cargo-checksum.json new file mode 100644 index 0000000000000..e9d6fd59da72c --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"615784e9f863ec4eeb00066ba899ab2fd8cf6619abcc35411f47ed29745b88ad","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"89f73d9404c960632bef4cfde9709862dbb510081180318e0be7bf12d18e9da7","build.rs":"800c0d76136d72e2894a7a3eb603ce02fc4da5d96c46b970edf6f909b999741e","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"69b1b9e21c0b6e447fd53991a60e7ab20f814c2ab5faa7870e3423bf588c658f","src/parse_error.rs":"9f6897c0f0b5b666ce5e7ff1f3e3001964397d3e5f933884036b14f52b612363","src/targets.rs":"ebd909b42ad8fcec6486170076f3b6454365377b2e23dbed56cf007c761ff490","src/triple.rs":"aba17839dd6895927d3d75fd5b83698df8be6d3ea64d7c0235c62acf12645a33"},"package":"1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb"} \ No newline at end of file diff --git a/third_party/rust/target-lexicon-0.4.0/Cargo.toml b/third_party/rust/target-lexicon-0.4.0/Cargo.toml new file mode 100644 index 0000000000000..2fec9435ca9c2 --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "target-lexicon" +version = "0.4.0" +authors = ["Dan Gohman "] +description = "Targeting utilities for compilers and related tools" +documentation = "https://docs.rs/target-lexicon/" +readme = "README.md" +keywords = ["target", "host", "triple", "compiler", "jit"] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/CraneStation/target-lexicon" +[dependencies.failure] +version = "0.1.3" +features = ["derive"] +default-features = false + +[dependencies.failure_derive] +version = "0.1.3" +default-features = false +[build-dependencies.serde_json] +version = "1.0" + +[features] +default = ["std"] +std = [] +[badges.maintenance] +status = "passively-maintained" + +[badges.travis-ci] +repository = "CraneStation/target-lexicon" diff --git a/third_party/rust/target-lexicon-0.4.0/LICENSE b/third_party/rust/target-lexicon-0.4.0/LICENSE new file mode 100644 index 0000000000000..f9d81955f4bcb --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/third_party/rust/target-lexicon-0.4.0/README.md b/third_party/rust/target-lexicon-0.4.0/README.md new file mode 100644 index 0000000000000..582db4617e1ed --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/README.md @@ -0,0 +1,18 @@ +This is a library for managing targets for compilers and related tools. + +Currently, the main feature is support for decoding "triples", which +are strings that identify a particular target configuration. This library +provides a `Triple` struct containing enums for each of fields of a +triple. `Triple` implements `FromStr` and `fmt::Display` so it can be +converted to and from the conventional string representation of a triple. + +`Triple` also has functions for querying a triple's endianness, +pointer bit width, and binary format. + +And, `Triple` and the enum types have `host()` constructors, for targeting +the host. + +It supports all triples currently used by rustc and rustup. + +It does not support reading JSON target files itself. To use it with a JSON +target file, construct a `Triple` using the value of the "llvm-target" field. diff --git a/third_party/rust/target-lexicon-0.4.0/build.rs b/third_party/rust/target-lexicon-0.4.0/build.rs new file mode 100644 index 0000000000000..8d8663baad68f --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/build.rs @@ -0,0 +1,229 @@ +//! build.rs file to obtain the host information. + +// Allow dead code in triple.rs and targets.rs for our purposes here. +#![allow(dead_code)] + +use serde_json::Value; +use std::env; +use std::ffi::OsString; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +extern crate serde_json; + +// Include triple.rs and targets.rs so we can parse the TARGET environment variable. +mod triple { + include!("src/triple.rs"); +} +mod targets { + include!("src/targets.rs"); +} + +// Stub out `ParseError` to minimally support triple.rs and targets.rs. +mod parse_error { + #[derive(Debug)] + pub enum ParseError { + UnrecognizedArchitecture(String), + UnrecognizedVendor(String), + UnrecognizedOperatingSystem(String), + UnrecognizedEnvironment(String), + UnrecognizedBinaryFormat(String), + UnrecognizedField(String), + NoneWithoutBinaryFormat, + } +} + +use self::triple::{Endianness, PointerWidth, Triple}; + +/// Assuming `target` is a path to a custom target json config file, open it +/// and build a `Triple` using its contents. +fn read_target_from_file(path: &Path) -> Triple { + let mut file = File::open(path).expect("error opening target file"); + let mut json = String::new(); + file.read_to_string(&mut json) + .expect("error reading target file"); + + let v: Value = serde_json::from_str(&json).expect("error parsing target file as json"); + let target = v["llvm-target"] + .as_str() + .expect("error parsing \"llvm-target\" as a string"); + let triple = Triple::from_str(target).expect("error parsing host target"); + + // Check that the JSON describes a known target configuration. + // + // Unfortunately, none of Rust's "arch", "os", "env", nor "vendor" + // fields directly correspond to triple fields, so we can't easily + // check them. + if let Some(endian) = v["target-endian"].as_str() { + assert_eq!( + endian, + match triple.endianness().unwrap() { + Endianness::Little => "little", + Endianness::Big => "big", + }, + "\"target-endian\" field disagrees with the target triple" + ); + } + if let Some(pointer_width) = v["target-pointer-width"].as_str() { + assert_eq!( + pointer_width, + match triple.pointer_width().unwrap() { + PointerWidth::U16 => "16", + PointerWidth::U32 => "32", + PointerWidth::U64 => "64", + }, + "\"target-pointer-width\" field disagrees with the target triple" + ); + } + + triple +} + +/// Assuming `target` is a target identifier, search for an appropriate custom +/// target json config file in the way that rustc does, and then call +/// `read_target_from_file` on that. +fn read_target_from_file_in_path(target: &str) -> Triple { + let mut target_filename = target.to_owned(); + target_filename.push_str(".json"); + let target_basename = PathBuf::from(target_filename); + let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_else(|| OsString::new()); + for dir in env::split_paths(&target_path) { + let p = dir.join(&target_basename); + if p.is_file() { + return read_target_from_file(&p); + } + } + panic!("can't find custom target {}", target); +} + +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"); + + // The following intends to match the logic in rustc. + let triple = if target.ends_with(".json") { + read_target_from_file(Path::new(&target)) + } else { + match Triple::from_str(&target) { + Ok(triple) => triple, + Err(_) => read_target_from_file_in_path(&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"); +} + +fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { + writeln!(out, "/// The `Triple` of the current host.")?; + writeln!(out, "pub static HOST: Triple = Triple {{")?; + writeln!( + out, + " architecture: Architecture::{:?},", + triple.architecture + )?; + writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?; + writeln!( + out, + " operating_system: OperatingSystem::{:?},", + triple.operating_system + )?; + writeln!( + out, + " environment: Environment::{:?},", + triple.environment + )?; + writeln!( + out, + " binary_format: BinaryFormat::{:?},", + triple.binary_format + )?; + writeln!(out, "}};")?; + writeln!(out)?; + + writeln!(out, "impl Architecture {{")?; + writeln!(out, " /// Return the architecture for the current host.")?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " Architecture::{:?}", triple.architecture)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Vendor {{")?; + writeln!(out, " /// Return the vendor for the current host.")?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " Vendor::{:?}", triple.vendor)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl OperatingSystem {{")?; + writeln!( + out, + " /// Return the operating system for the current host." + )?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!( + out, + " OperatingSystem::{:?}", + triple.operating_system + )?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Environment {{")?; + writeln!(out, " /// Return the environment for the current host.")?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " Environment::{:?}", triple.environment)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl BinaryFormat {{")?; + writeln!( + out, + " /// Return the binary format for the current host." + )?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " BinaryFormat::{:?}", triple.binary_format)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Triple {{")?; + writeln!(out, " /// Return the triple for the current host.")?; + writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " Self {{")?; + writeln!( + out, + " architecture: Architecture::{:?},", + triple.architecture + )?; + writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?; + writeln!( + out, + " operating_system: OperatingSystem::{:?},", + triple.operating_system + )?; + writeln!( + out, + " environment: Environment::{:?},", + triple.environment + )?; + writeln!( + out, + " binary_format: BinaryFormat::{:?},", + triple.binary_format + )?; + writeln!(out, " }}")?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + + Ok(()) +} diff --git a/third_party/rust/target-lexicon-0.4.0/examples/misc.rs b/third_party/rust/target-lexicon-0.4.0/examples/misc.rs new file mode 100644 index 0000000000000..25c99e867774c --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/examples/misc.rs @@ -0,0 +1,14 @@ +extern crate target_lexicon; + +use core::str::FromStr; +use target_lexicon::{Triple, HOST}; + +fn main() { + println!("The host triple is {}.", HOST); + + let e = Triple::from_str("riscv32-unknown-unknown") + .expect("expected to recognize the RISC-V target") + .endianness() + .expect("expected to know the endianness of RISC-V"); + println!("The endianness of RISC-V is {:?}.", e); +} diff --git a/third_party/rust/target-lexicon-0.4.0/src/host.rs b/third_party/rust/target-lexicon-0.4.0/src/host.rs new file mode 100644 index 0000000000000..4c6ad5ba54d13 --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/src/host.rs @@ -0,0 +1,56 @@ +use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; + +// Include the implementations of the `HOST` object containing information +// about the current host. +include!(concat!(env!("OUT_DIR"), "/host.rs")); + +#[cfg(test)] +mod tests { + #[cfg(target_os = "linux")] + #[test] + fn test_linux() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Linux); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_macos() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Darwin); + } + + #[cfg(windows)] + #[test] + fn test_windows() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Windows); + } + + #[cfg(target_pointer_width = "16")] + #[test] + fn test_ptr16() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 16); + } + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_ptr32() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 32); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_ptr64() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 64); + } + + #[test] + fn host_object() { + use super::*; + assert_eq!(HOST, Triple::host()); + } +} diff --git a/third_party/rust/target-lexicon-0.4.0/src/lib.rs b/third_party/rust/target-lexicon-0.4.0/src/lib.rs new file mode 100644 index 0000000000000..91ca5b3d6528c --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/src/lib.rs @@ -0,0 +1,38 @@ +//! Target "triple" support. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![warn(unused_import_braces)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + float_arithmetic, + mut_mut, + nonminimal_bool, + option_map_unwrap_or, + option_map_unwrap_or_else, + print_stdout, + unicode_not_nfc, + use_self + ) +)] +#![no_std] +#![cfg_attr(not(feature = "std"), feature(alloc))] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; +#[cfg(feature = "std")] +extern crate std; + +#[macro_use] +extern crate failure_derive; + +mod host; +mod parse_error; +mod targets; +#[macro_use] +mod triple; + +pub use self::host::HOST; +pub use self::parse_error::ParseError; +pub use self::targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor}; +pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; diff --git a/third_party/rust/target-lexicon-0.4.0/src/parse_error.rs b/third_party/rust/target-lexicon-0.4.0/src/parse_error.rs new file mode 100644 index 0000000000000..c3e39d2e83e0a --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/src/parse_error.rs @@ -0,0 +1,19 @@ +use std::string::String; + +/// An error returned from parsing a triple. +#[derive(Fail, Clone, Debug, PartialEq, Eq)] +#[allow(missing_docs)] +pub enum ParseError { + #[fail(display = "Unrecognized architecture: {}", _0)] + UnrecognizedArchitecture(String), + #[fail(display = "Unrecognized vendor: {}", _0)] + UnrecognizedVendor(String), + #[fail(display = "Unrecognized operating system: {}", _0)] + UnrecognizedOperatingSystem(String), + #[fail(display = "Unrecognized environment: {}", _0)] + UnrecognizedEnvironment(String), + #[fail(display = "Unrecognized binary format: {}", _0)] + UnrecognizedBinaryFormat(String), + #[fail(display = "Unrecognized field: {}", _0)] + UnrecognizedField(String), +} diff --git a/third_party/rust/target-lexicon-0.4.0/src/targets.rs b/third_party/rust/target-lexicon-0.4.0/src/targets.rs new file mode 100644 index 0000000000000..ab0beb4e5898e --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/src/targets.rs @@ -0,0 +1,636 @@ +// This file defines all the identifier enums and target-aware logic. + +use crate::triple::{Endianness, PointerWidth, Triple}; +use core::fmt; +use core::str::FromStr; + +/// The "architecture" field, which in some cases also specifies a specific +/// subarchitecture. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Architecture { + Unknown, + Aarch64, + Arm, + Armebv7r, + Armv4t, + Armv5te, + Armv6, + Armv7, + Armv7r, + Armv7s, + Asmjs, + I386, + I586, + I686, + Mips, + Mips64, + Mips64el, + Mipsel, + Msp430, + Powerpc, + Powerpc64, + Powerpc64le, + Riscv32, + Riscv32imac, + Riscv32imc, + Riscv64, + S390x, + Sparc, + Sparc64, + Sparcv9, + Thumbv6m, + Thumbv7a, + Thumbv7em, + Thumbv7m, + Thumbv7neon, + Thumbv8mBase, + Thumbv8mMain, + Wasm32, + X86_64, +} + +/// The "vendor" field, which in practice is little more than an arbitrary +/// modifier. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Vendor { + Unknown, + Apple, + Experimental, + Fortanix, + Pc, + Rumprun, + Sun, +} + +/// The "operating system" field, which sometimes implies an environment, and +/// sometimes isn't an actual operating system. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum OperatingSystem { + Unknown, + Bitrig, + Cloudabi, + Darwin, + Dragonfly, + Emscripten, + Freebsd, + Fuchsia, + Haiku, + Hermit, + Ios, + L4re, + Linux, + Nebulet, + Netbsd, + None_, + Openbsd, + Redox, + Solaris, + Uefi, + Windows, +} + +/// The "environment" field, which specifies an ABI environment on top of the +/// operating system. In many configurations, this field is omitted, and the +/// environment is implied by the operating system. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Environment { + Unknown, + Android, + Androideabi, + Eabi, + Eabihf, + Gnu, + Gnuabi64, + Gnueabi, + Gnueabihf, + Gnuspe, + Gnux32, + Musl, + Musleabi, + Musleabihf, + Msvc, + Uclibc, + Sgx, +} + +/// The "binary format" field, which is usually omitted, and the binary format +/// is implied by the other fields. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum BinaryFormat { + Unknown, + Elf, + Coff, + Macho, + Wasm, +} + +impl Architecture { + /// Return the endianness of this architecture. + pub fn endianness(self) -> Result { + match self { + Architecture::Unknown => Err(()), + Architecture::Aarch64 + | Architecture::Arm + | Architecture::Armv4t + | Architecture::Armv5te + | Architecture::Armv6 + | Architecture::Armv7 + | Architecture::Armv7r + | Architecture::Armv7s + | Architecture::Asmjs + | Architecture::I386 + | Architecture::I586 + | Architecture::I686 + | Architecture::Mips64el + | Architecture::Mipsel + | Architecture::Msp430 + | Architecture::Powerpc64le + | Architecture::Riscv32 + | Architecture::Riscv32imac + | Architecture::Riscv32imc + | Architecture::Riscv64 + | Architecture::Thumbv6m + | Architecture::Thumbv7a + | Architecture::Thumbv7em + | Architecture::Thumbv7m + | Architecture::Thumbv7neon + | Architecture::Thumbv8mBase + | Architecture::Thumbv8mMain + | Architecture::Wasm32 + | Architecture::X86_64 => Ok(Endianness::Little), + Architecture::Armebv7r + | Architecture::Mips + | Architecture::Mips64 + | Architecture::Powerpc + | Architecture::Powerpc64 + | Architecture::S390x + | Architecture::Sparc + | Architecture::Sparc64 + | Architecture::Sparcv9 => Ok(Endianness::Big), + } + } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> Result { + match self { + Architecture::Unknown => Err(()), + Architecture::Msp430 => Ok(PointerWidth::U16), + Architecture::Arm + | Architecture::Armebv7r + | Architecture::Armv4t + | Architecture::Armv5te + | Architecture::Armv6 + | Architecture::Armv7 + | Architecture::Armv7r + | Architecture::Armv7s + | Architecture::Asmjs + | Architecture::I386 + | Architecture::I586 + | Architecture::I686 + | Architecture::Mipsel + | Architecture::Riscv32 + | Architecture::Riscv32imac + | Architecture::Riscv32imc + | Architecture::Sparc + | Architecture::Thumbv6m + | Architecture::Thumbv7a + | Architecture::Thumbv7em + | Architecture::Thumbv7m + | Architecture::Thumbv7neon + | Architecture::Thumbv8mBase + | Architecture::Thumbv8mMain + | Architecture::Wasm32 + | Architecture::Mips + | Architecture::Powerpc => Ok(PointerWidth::U32), + Architecture::Aarch64 + | Architecture::Mips64el + | Architecture::Powerpc64le + | Architecture::Riscv64 + | Architecture::X86_64 + | Architecture::Mips64 + | Architecture::Powerpc64 + | Architecture::S390x + | Architecture::Sparc64 + | Architecture::Sparcv9 => Ok(PointerWidth::U64), + } + } +} + +/// Return the binary format implied by this target triple, ignoring its +/// `binary_format` field. +pub fn default_binary_format(triple: &Triple) -> BinaryFormat { + match triple.operating_system { + OperatingSystem::None_ => BinaryFormat::Unknown, + OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho, + OperatingSystem::Windows => BinaryFormat::Coff, + OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => { + match triple.architecture { + Architecture::Wasm32 => BinaryFormat::Wasm, + _ => BinaryFormat::Unknown, + } + } + _ => BinaryFormat::Elf, + } +} + +impl fmt::Display for Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Architecture::Unknown => "unknown", + Architecture::Aarch64 => "aarch64", + Architecture::Arm => "arm", + Architecture::Armebv7r => "armebv7r", + Architecture::Armv4t => "armv4t", + Architecture::Armv5te => "armv5te", + Architecture::Armv6 => "armv6", + Architecture::Armv7 => "armv7", + Architecture::Armv7r => "armv7r", + Architecture::Armv7s => "armv7s", + Architecture::Asmjs => "asmjs", + Architecture::I386 => "i386", + Architecture::I586 => "i586", + Architecture::I686 => "i686", + Architecture::Mips => "mips", + Architecture::Mips64 => "mips64", + Architecture::Mips64el => "mips64el", + Architecture::Mipsel => "mipsel", + Architecture::Msp430 => "msp430", + Architecture::Powerpc => "powerpc", + Architecture::Powerpc64 => "powerpc64", + Architecture::Powerpc64le => "powerpc64le", + Architecture::Riscv32 => "riscv32", + Architecture::Riscv32imac => "riscv32imac", + Architecture::Riscv32imc => "riscv32imc", + Architecture::Riscv64 => "riscv64", + Architecture::S390x => "s390x", + Architecture::Sparc => "sparc", + Architecture::Sparc64 => "sparc64", + Architecture::Sparcv9 => "sparcv9", + Architecture::Thumbv6m => "thumbv6m", + Architecture::Thumbv7a => "thumbv7a", + Architecture::Thumbv7em => "thumbv7em", + Architecture::Thumbv7m => "thumbv7m", + Architecture::Thumbv7neon => "thumbv7neon", + Architecture::Thumbv8mBase => "thumbv8m.base", + Architecture::Thumbv8mMain => "thumbv8m.main", + Architecture::Wasm32 => "wasm32", + Architecture::X86_64 => "x86_64", + }; + f.write_str(s) + } +} + +impl FromStr for Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "unknown" => Architecture::Unknown, + "aarch64" => Architecture::Aarch64, + "arm" => Architecture::Arm, + "armebv7r" => Architecture::Armebv7r, + "armv4t" => Architecture::Armv4t, + "armv5te" => Architecture::Armv5te, + "armv6" => Architecture::Armv6, + "armv7" => Architecture::Armv7, + "armv7r" => Architecture::Armv7r, + "armv7s" => Architecture::Armv7s, + "asmjs" => Architecture::Asmjs, + "i386" => Architecture::I386, + "i586" => Architecture::I586, + "i686" => Architecture::I686, + "mips" => Architecture::Mips, + "mips64" => Architecture::Mips64, + "mips64el" => Architecture::Mips64el, + "mipsel" => Architecture::Mipsel, + "msp430" => Architecture::Msp430, + "powerpc" => Architecture::Powerpc, + "powerpc64" => Architecture::Powerpc64, + "powerpc64le" => Architecture::Powerpc64le, + "riscv32" => Architecture::Riscv32, + "riscv32imac" => Architecture::Riscv32imac, + "riscv32imc" => Architecture::Riscv32imc, + "riscv64" => Architecture::Riscv64, + "s390x" => Architecture::S390x, + "sparc" => Architecture::Sparc, + "sparc64" => Architecture::Sparc64, + "sparcv9" => Architecture::Sparcv9, + "thumbv6m" => Architecture::Thumbv6m, + "thumbv7a" => Architecture::Thumbv7a, + "thumbv7em" => Architecture::Thumbv7em, + "thumbv7m" => Architecture::Thumbv7m, + "thumbv7neon" => Architecture::Thumbv7neon, + "thumbv8m.base" => Architecture::Thumbv8mBase, + "thumbv8m.main" => Architecture::Thumbv8mMain, + "wasm32" => Architecture::Wasm32, + "x86_64" => Architecture::X86_64, + _ => return Err(()), + }) + } +} + +impl fmt::Display for Vendor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Vendor::Unknown => "unknown", + Vendor::Apple => "apple", + Vendor::Experimental => "experimental", + Vendor::Fortanix => "fortanix", + Vendor::Pc => "pc", + Vendor::Rumprun => "rumprun", + Vendor::Sun => "sun", + }; + f.write_str(s) + } +} + +impl FromStr for Vendor { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "unknown" => Vendor::Unknown, + "apple" => Vendor::Apple, + "experimental" => Vendor::Experimental, + "fortanix" => Vendor::Fortanix, + "pc" => Vendor::Pc, + "rumprun" => Vendor::Rumprun, + "sun" => Vendor::Sun, + _ => return Err(()), + }) + } +} + +impl fmt::Display for OperatingSystem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + OperatingSystem::Unknown => "unknown", + OperatingSystem::Bitrig => "bitrig", + OperatingSystem::Cloudabi => "cloudabi", + OperatingSystem::Darwin => "darwin", + OperatingSystem::Dragonfly => "dragonfly", + OperatingSystem::Emscripten => "emscripten", + OperatingSystem::Freebsd => "freebsd", + OperatingSystem::Fuchsia => "fuchsia", + OperatingSystem::Haiku => "haiku", + OperatingSystem::Hermit => "hermit", + OperatingSystem::Ios => "ios", + OperatingSystem::L4re => "l4re", + OperatingSystem::Linux => "linux", + OperatingSystem::Nebulet => "nebulet", + OperatingSystem::Netbsd => "netbsd", + OperatingSystem::None_ => "none", + OperatingSystem::Openbsd => "openbsd", + OperatingSystem::Redox => "redox", + OperatingSystem::Solaris => "solaris", + OperatingSystem::Uefi => "uefi", + OperatingSystem::Windows => "windows", + }; + f.write_str(s) + } +} + +impl FromStr for OperatingSystem { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "unknown" => OperatingSystem::Unknown, + "bitrig" => OperatingSystem::Bitrig, + "cloudabi" => OperatingSystem::Cloudabi, + "darwin" => OperatingSystem::Darwin, + "dragonfly" => OperatingSystem::Dragonfly, + "emscripten" => OperatingSystem::Emscripten, + "freebsd" => OperatingSystem::Freebsd, + "fuchsia" => OperatingSystem::Fuchsia, + "haiku" => OperatingSystem::Haiku, + "hermit" => OperatingSystem::Hermit, + "ios" => OperatingSystem::Ios, + "l4re" => OperatingSystem::L4re, + "linux" => OperatingSystem::Linux, + "nebulet" => OperatingSystem::Nebulet, + "netbsd" => OperatingSystem::Netbsd, + "none" => OperatingSystem::None_, + "openbsd" => OperatingSystem::Openbsd, + "redox" => OperatingSystem::Redox, + "solaris" => OperatingSystem::Solaris, + "uefi" => OperatingSystem::Uefi, + "windows" => OperatingSystem::Windows, + _ => return Err(()), + }) + } +} + +impl fmt::Display for Environment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Environment::Unknown => "unknown", + Environment::Android => "android", + Environment::Androideabi => "androideabi", + Environment::Eabi => "eabi", + Environment::Eabihf => "eabihf", + Environment::Gnu => "gnu", + Environment::Gnuabi64 => "gnuabi64", + Environment::Gnueabi => "gnueabi", + Environment::Gnueabihf => "gnueabihf", + Environment::Gnuspe => "gnuspe", + Environment::Gnux32 => "gnux32", + Environment::Musl => "musl", + Environment::Musleabi => "musleabi", + Environment::Musleabihf => "musleabihf", + Environment::Msvc => "msvc", + Environment::Uclibc => "uclibc", + Environment::Sgx => "sgx", + }; + f.write_str(s) + } +} + +impl FromStr for Environment { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "unknown" => Environment::Unknown, + "android" => Environment::Android, + "androideabi" => Environment::Androideabi, + "eabi" => Environment::Eabi, + "eabihf" => Environment::Eabihf, + "gnu" => Environment::Gnu, + "gnuabi64" => Environment::Gnuabi64, + "gnueabi" => Environment::Gnueabi, + "gnueabihf" => Environment::Gnueabihf, + "gnuspe" => Environment::Gnuspe, + "gnux32" => Environment::Gnux32, + "musl" => Environment::Musl, + "musleabi" => Environment::Musleabi, + "musleabihf" => Environment::Musleabihf, + "msvc" => Environment::Msvc, + "uclibc" => Environment::Uclibc, + "sgx" => Environment::Sgx, + _ => return Err(()), + }) + } +} + +impl fmt::Display for BinaryFormat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + BinaryFormat::Unknown => "unknown", + BinaryFormat::Elf => "elf", + BinaryFormat::Coff => "coff", + BinaryFormat::Macho => "macho", + BinaryFormat::Wasm => "wasm", + }; + f.write_str(s) + } +} + +impl FromStr for BinaryFormat { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "unknown" => BinaryFormat::Unknown, + "elf" => BinaryFormat::Elf, + "coff" => BinaryFormat::Coff, + "macho" => BinaryFormat::Macho, + "wasm" => BinaryFormat::Wasm, + _ => return Err(()), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::ToString; + + #[test] + fn rust_targets() { + // At the time of writing this, these are all the targets emitted by + // "rustup target list" and "rustc --print target-list". + let targets = [ + "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-openbsd", + "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-netbsd-eabihf", + "armv7-apple-ios", + "armv7-linux-androideabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "armv7s-apple-ios", + "armv7-unknown-cloudabi-eabihf", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabihf", + "armv7-unknown-netbsd-eabihf", + "asmjs-unknown-emscripten", + "i386-apple-ios", + "i586-pc-windows-msvc", + "i586-unknown-linux-gnu", + "i586-unknown-linux-musl", + "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", + "mips64el-unknown-linux-gnuabi64", + "mips64-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "mipsel-unknown-linux-uclibc", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips-unknown-linux-uclibc", + "msp430-none-elf", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", + "powerpc-unknown-linux-gnu", + "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-linux-musl", + "powerpc-unknown-netbsd", + "riscv32imac-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "s390x-unknown-linux-gnu", + "sparc64-unknown-linux-gnu", + "sparc64-unknown-netbsd", + "sparc-unknown-linux-gnu", + "sparcv9-sun-solaris", + "thumbv6m-none-eabi", + "thumbv7a-pc-windows-msvc", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", + "wasm32-experimental-emscripten", + "wasm32-unknown-emscripten", + "wasm32-unknown-unknown", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fortanix-unknown-sgx", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-rumprun-netbsd", + "x86_64-sun-solaris", + "x86_64-unknown-bitrig", + "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", + ]; + + for target in targets.iter() { + let t = Triple::from_str(target).expect("can't parse target"); + assert_ne!(t.architecture, Architecture::Unknown); + assert_eq!(t.to_string(), *target); + } + } +} diff --git a/third_party/rust/target-lexicon-0.4.0/src/triple.rs b/third_party/rust/target-lexicon-0.4.0/src/triple.rs new file mode 100644 index 0000000000000..c998891a904b6 --- /dev/null +++ b/third_party/rust/target-lexicon-0.4.0/src/triple.rs @@ -0,0 +1,342 @@ +// This file defines the `Triple` type and support code shared by all targets. + +use crate::parse_error::ParseError; +use crate::targets::{ + default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor, +}; +use core::fmt; +use core::str::FromStr; +use std::borrow::ToOwned; + +/// The target memory endianness. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Endianness { + Little, + Big, +} + +/// The width of a pointer (in the default address space). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum PointerWidth { + U16, + U32, + U64, +} + +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, + } + } + + /// Return the number of bytes in a pointer. + /// + /// 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, + } + } +} + +/// 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 { + SystemV, + WindowsFastcall, +} + +/// A target "triple", because historically such things had three fields, though +/// they've grown more features over time. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Triple { + /// The "architecture" (and sometimes the subarchitecture). + pub architecture: Architecture, + /// The "vendor" (whatever that means). + pub vendor: Vendor, + /// The "operating system" (sometimes also the environment). + pub operating_system: OperatingSystem, + /// The "environment" on top of the operating system. + pub environment: Environment, + /// The "binary format" (rarely used). + pub binary_format: BinaryFormat, +} + +impl Triple { + /// Return the endianness of this target's architecture. + pub fn endianness(&self) -> Result { + self.architecture.endianness() + } + + /// Return the pointer width of this target's architecture. + pub fn pointer_width(&self) -> Result { + self.architecture.pointer_width() + } + + /// Return the default calling convention for the given target triple. + pub fn default_calling_convention(&self) -> Result { + Ok(match self.operating_system { + OperatingSystem::Bitrig + | OperatingSystem::Cloudabi + | OperatingSystem::Darwin + | OperatingSystem::Dragonfly + | OperatingSystem::Freebsd + | OperatingSystem::Fuchsia + | OperatingSystem::Haiku + | OperatingSystem::Ios + | OperatingSystem::L4re + | OperatingSystem::Linux + | OperatingSystem::Nebulet + | OperatingSystem::Netbsd + | OperatingSystem::Openbsd + | OperatingSystem::Redox + | OperatingSystem::Solaris => CallingConvention::SystemV, + OperatingSystem::Windows => CallingConvention::WindowsFastcall, + _ => return Err(()), + }) + } +} + +impl Default for Triple { + fn default() -> Self { + Self { + architecture: Architecture::Unknown, + vendor: Vendor::Unknown, + operating_system: OperatingSystem::Unknown, + environment: Environment::Unknown, + binary_format: BinaryFormat::Unknown, + } + } +} + +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); + + write!(f, "{}", self.architecture)?; + if self.vendor == Vendor::Unknown + && ((self.operating_system == OperatingSystem::Linux + && (self.environment == Environment::Android + || self.environment == Environment::Androideabi)) + || self.operating_system == OperatingSystem::Fuchsia + || (self.operating_system == OperatingSystem::None_ + && (self.architecture == Architecture::Armebv7r + || self.architecture == Architecture::Armv7r + || self.architecture == Architecture::Thumbv6m + || self.architecture == Architecture::Thumbv7em + || self.architecture == Architecture::Thumbv7m + || self.architecture == Architecture::Thumbv8mBase + || self.architecture == Architecture::Thumbv8mMain + || self.architecture == Architecture::Msp430))) + { + // As a special case, omit the vendor for Android, Fuchsia, and sometimes + // None_, depending on the hardware architecture. This logic is entirely + // ad-hoc, and is just sufficient to handle the current set of recognized + // triples. + write!(f, "-{}", self.operating_system)?; + } else { + write!(f, "-{}-{}", self.vendor, self.operating_system)?; + } + if self.environment != Environment::Unknown { + write!(f, "-{}", self.environment)?; + } + + if self.binary_format != implied_binary_format { + write!(f, "-{}", self.binary_format)?; + } + Ok(()) + } +} + +impl FromStr for Triple { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + let mut parts = s.split('-'); + let mut result = Self::default(); + let mut current_part; + + current_part = parts.next(); + if let Some(s) = current_part { + if let Ok(architecture) = Architecture::from_str(s) { + result.architecture = architecture; + current_part = parts.next(); + } else { + // Insist that the triple start with a valid architecture. + return Err(ParseError::UnrecognizedArchitecture(s.to_owned())); + } + } + + let mut has_vendor = false; + let mut has_operating_system = false; + if let Some(s) = current_part { + if let Ok(vendor) = Vendor::from_str(s) { + has_vendor = true; + result.vendor = vendor; + current_part = parts.next(); + } + } + + if !has_operating_system { + if let Some(s) = current_part { + if let Ok(operating_system) = OperatingSystem::from_str(s) { + has_operating_system = true; + result.operating_system = operating_system; + current_part = parts.next(); + } + } + } + + let mut has_environment = false; + if let Some(s) = current_part { + if let Ok(environment) = Environment::from_str(s) { + has_environment = true; + result.environment = environment; + current_part = parts.next(); + } + } + + let mut has_binary_format = false; + if let Some(s) = current_part { + if let Ok(binary_format) = BinaryFormat::from_str(s) { + has_binary_format = true; + result.binary_format = binary_format; + current_part = parts.next(); + } + } + + // The binary format is frequently omitted; if that's the case here, + // infer it from the other fields. + if !has_binary_format { + result.binary_format = default_binary_format(&result); + } + + if let Some(s) = current_part { + Err(if !has_vendor { + ParseError::UnrecognizedVendor(s.to_owned()) + } else if !has_operating_system { + ParseError::UnrecognizedOperatingSystem(s.to_owned()) + } else if !has_environment { + ParseError::UnrecognizedEnvironment(s.to_owned()) + } else if !has_binary_format { + ParseError::UnrecognizedBinaryFormat(s.to_owned()) + } else { + ParseError::UnrecognizedField(s.to_owned()) + }) + } else { + Ok(result) + } + } +} + +/// A convenient syntax for triple "literals". +/// +/// This currently expands to code that just calls `Triple::from_str` and does +/// an `expect`, though in the future it would be cool to use procedural macros +/// or so to report errors at compile time instead. +#[macro_export] +macro_rules! triple { + ($str:tt) => { + target_lexicon::Triple::from_str($str).expect("invalid triple literal") + }; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_errors() { + assert_eq!( + Triple::from_str(""), + Err(ParseError::UnrecognizedArchitecture("".to_owned())) + ); + assert_eq!( + Triple::from_str("foo"), + Err(ParseError::UnrecognizedArchitecture("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-foo"), + Err(ParseError::UnrecognizedVendor("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-foo"), + Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedEnvironment("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedField("foo".to_owned())) + ); + } + + #[test] + fn defaults() { + assert_eq!( + Triple::from_str("unknown-unknown-unknown"), + Ok(Triple::default()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown"), + Ok(Triple::default()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown"), + Ok(Triple::default()) + ); + } + + #[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(())); + } +} diff --git a/third_party/rust/target-lexicon/.cargo-checksum.json b/third_party/rust/target-lexicon/.cargo-checksum.json index e9d6fd59da72c..fb4b8b4b2d897 100644 --- a/third_party/rust/target-lexicon/.cargo-checksum.json +++ b/third_party/rust/target-lexicon/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"615784e9f863ec4eeb00066ba899ab2fd8cf6619abcc35411f47ed29745b88ad","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"89f73d9404c960632bef4cfde9709862dbb510081180318e0be7bf12d18e9da7","build.rs":"800c0d76136d72e2894a7a3eb603ce02fc4da5d96c46b970edf6f909b999741e","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"69b1b9e21c0b6e447fd53991a60e7ab20f814c2ab5faa7870e3423bf588c658f","src/parse_error.rs":"9f6897c0f0b5b666ce5e7ff1f3e3001964397d3e5f933884036b14f52b612363","src/targets.rs":"ebd909b42ad8fcec6486170076f3b6454365377b2e23dbed56cf007c761ff490","src/triple.rs":"aba17839dd6895927d3d75fd5b83698df8be6d3ea64d7c0235c62acf12645a33"},"package":"1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb"} \ No newline at end of file +{"files":{"Cargo.lock":"75d1f84b3d9e98d87e2f74984f7d032f5b28d7610cccf5e13977367189a77acd","Cargo.toml":"fe18dc2e0c86e6b28ed0244ced50e26f481087c693cb7cc1ff3062929894b0d4","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","build.rs":"a9f00c32de64b949c3bb23442304fc7943154efcc831aa0d87c9b83247e4e28a","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","host.rs":"4ef91a2c26405151454c2695dc0a7f455374207900ea6814d4eafdfef5f7b630","newlist":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","sorted.txt":"5548c14054ea61b51e2d8a495da662546523c3c13e8f742f6dd57754e11f46b5","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"5ad3a9418a6cb52cacc0a662645ccc671c326df954671b5ec0db667653dd125a","src/parse_error.rs":"f6689a741589ca8e659b1639728696f987c9da4948701f3b7ab6dc3e35754dab","src/targets.rs":"81320bd0280c96846a328689afe22be283cb7df9c37f005ff693ee1834b345a8","src/triple.rs":"ae2895bb2ee8451b90aa6e92d7fbf24c021230416fef030fb6ad0ef051c786c3","test.sh":"40761ee2ab0b361bdce4dc17708e671f32661f62cb56a45724d60510f9498b74"},"package":"7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a"} \ No newline at end of file diff --git a/third_party/rust/target-lexicon/Cargo.lock b/third_party/rust/target-lexicon/Cargo.lock new file mode 100644 index 0000000000000..ce652ab013972 --- /dev/null +++ b/third_party/rust/target-lexicon/Cargo.lock @@ -0,0 +1,109 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "target-lexicon" +version = "0.8.1" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/third_party/rust/target-lexicon/Cargo.toml b/third_party/rust/target-lexicon/Cargo.toml index 2fec9435ca9c2..26f7cbd9dcae9 100644 --- a/third_party/rust/target-lexicon/Cargo.toml +++ b/third_party/rust/target-lexicon/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -13,7 +13,7 @@ [package] edition = "2018" name = "target-lexicon" -version = "0.4.0" +version = "0.8.1" authors = ["Dan Gohman "] description = "Targeting utilities for compilers and related tools" documentation = "https://docs.rs/target-lexicon/" @@ -32,10 +32,6 @@ version = "0.1.3" default-features = false [build-dependencies.serde_json] version = "1.0" - -[features] -default = ["std"] -std = [] [badges.maintenance] status = "passively-maintained" diff --git a/third_party/rust/target-lexicon/README.md b/third_party/rust/target-lexicon/README.md index 582db4617e1ed..2e539eb716345 100644 --- a/third_party/rust/target-lexicon/README.md +++ b/third_party/rust/target-lexicon/README.md @@ -1,10 +1,12 @@ This is a library for managing targets for compilers and related tools. Currently, the main feature is support for decoding "triples", which -are strings that identify a particular target configuration. This library -provides a `Triple` struct containing enums for each of fields of a -triple. `Triple` implements `FromStr` and `fmt::Display` so it can be -converted to and from the conventional string representation of a triple. +are strings that identify a particular target configuration. They're named +"triples" because historically they contained three fields, though over time +they've added additional fields. This library provides a `Triple` struct +containing enums for each of fields of a triple. `Triple` implements +`FromStr` and `fmt::Display` so it can be converted to and from the +conventional string representation of a triple. `Triple` also has functions for querying a triple's endianness, pointer bit width, and binary format. diff --git a/third_party/rust/target-lexicon/build.rs b/third_party/rust/target-lexicon/build.rs index 8d8663baad68f..51ef295639961 100644 --- a/third_party/rust/target-lexicon/build.rs +++ b/third_party/rust/target-lexicon/build.rs @@ -12,6 +12,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::str::FromStr; +extern crate alloc; extern crate serde_json; // Include triple.rs and targets.rs so we can parse the TARGET environment variable. @@ -120,8 +121,17 @@ fn main() { } fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { + // The generated Debug implementation for the inner architecture variants + // doesn't print the enum name qualifier, so import them here. There + // shouldn't be any conflicts because these enums all share a namespace + // in the triple string format. + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Aarch64Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::ArmArchitecture::*;")?; + writeln!(out)?; writeln!(out, "/// The `Triple` of the current host.")?; - writeln!(out, "pub static HOST: Triple = Triple {{")?; + writeln!(out, "pub const HOST: Triple = Triple {{")?; writeln!( out, " architecture: Architecture::{:?},", @@ -148,7 +158,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 fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!(out, " Architecture::{:?}", triple.architecture)?; writeln!(out, " }}")?; writeln!(out, "}}")?; @@ -156,7 +166,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 fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!(out, " Vendor::{:?}", triple.vendor)?; writeln!(out, " }}")?; writeln!(out, "}}")?; @@ -167,7 +177,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { out, " /// Return the operating system for the current host." )?; - writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!( out, " OperatingSystem::{:?}", @@ -179,7 +189,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 fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!(out, " Environment::{:?}", triple.environment)?; writeln!(out, " }}")?; writeln!(out, "}}")?; @@ -190,7 +200,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { out, " /// Return the binary format for the current host." )?; - writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!(out, " BinaryFormat::{:?}", triple.binary_format)?; writeln!(out, " }}")?; writeln!(out, "}}")?; @@ -198,7 +208,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { writeln!(out, "impl Triple {{")?; writeln!(out, " /// Return the triple for the current host.")?; - writeln!(out, " pub fn host() -> Self {{")?; + writeln!(out, " pub const fn host() -> Self {{")?; writeln!(out, " Self {{")?; writeln!( out, diff --git a/third_party/rust/target-lexicon/examples/host.rs b/third_party/rust/target-lexicon/examples/host.rs new file mode 100644 index 0000000000000..055e0bffdbbae --- /dev/null +++ b/third_party/rust/target-lexicon/examples/host.rs @@ -0,0 +1,12 @@ +extern crate target_lexicon; + +use target_lexicon::HOST; + +fn main() { + println!( + "{}", + HOST.pointer_width() + .expect("architecture should be known") + .bytes() + ); +} diff --git a/third_party/rust/target-lexicon/host.rs b/third_party/rust/target-lexicon/host.rs new file mode 100644 index 0000000000000..c4f8d78e3081c --- /dev/null +++ b/third_party/rust/target-lexicon/host.rs @@ -0,0 +1,61 @@ +#[allow(unused_imports)] +use crate::Aarch64Architecture::*; +#[allow(unused_imports)] +use crate::ArmArchitecture::*; + +/// 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, + } + } +} diff --git a/third_party/rust/target-lexicon/newlist b/third_party/rust/target-lexicon/newlist new file mode 100755 index 0000000000000..922950d0a0c83 --- /dev/null +++ b/third_party/rust/target-lexicon/newlist @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +rustup target list | sed 's/ (.*//' > list.txt +rustc +nightly --print target-list >> list.txt +cat list.txt | sort | uniq |sed 's/\(.*\)/ "\1",/' > sorted.txt +rm list.txt diff --git a/third_party/rust/target-lexicon/sorted.txt b/third_party/rust/target-lexicon/sorted.txt new file mode 100644 index 0000000000000..38ab3c06b89e0 --- /dev/null +++ b/third_party/rust/target-lexicon/sorted.txt @@ -0,0 +1,140 @@ + "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-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-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", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", + "wasm32-experimental-emscripten", + "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-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", diff --git a/third_party/rust/target-lexicon/src/lib.rs b/third_party/rust/target-lexicon/src/lib.rs index 91ca5b3d6528c..e08f69f9a27b6 100644 --- a/third_party/rust/target-lexicon/src/lib.rs +++ b/third_party/rust/target-lexicon/src/lib.rs @@ -1,27 +1,23 @@ -//! Target "triple" support. +//! Target triple support. #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] #![cfg_attr( feature = "cargo-clippy", warn( - float_arithmetic, - mut_mut, - nonminimal_bool, - option_map_unwrap_or, - option_map_unwrap_or_else, - print_stdout, - unicode_not_nfc, - use_self + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self ) )] #![no_std] -#![cfg_attr(not(feature = "std"), feature(alloc))] -#[cfg(not(feature = "std"))] -extern crate alloc as std; -#[cfg(feature = "std")] -extern crate std; +extern crate alloc; #[macro_use] extern crate failure_derive; @@ -34,5 +30,8 @@ mod triple; pub use self::host::HOST; pub use self::parse_error::ParseError; -pub use self::targets::{Architecture, BinaryFormat, Environment, OperatingSystem, Vendor}; +pub use self::targets::{ + Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, Environment, OperatingSystem, + Vendor, +}; pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; diff --git a/third_party/rust/target-lexicon/src/parse_error.rs b/third_party/rust/target-lexicon/src/parse_error.rs index c3e39d2e83e0a..32a5ee24644f2 100644 --- a/third_party/rust/target-lexicon/src/parse_error.rs +++ b/third_party/rust/target-lexicon/src/parse_error.rs @@ -1,4 +1,4 @@ -use std::string::String; +use alloc::string::String; /// An error returned from parsing a triple. #[derive(Fail, Clone, Debug, PartialEq, Eq)] diff --git a/third_party/rust/target-lexicon/src/targets.rs b/third_party/rust/target-lexicon/src/targets.rs index ab0beb4e5898e..0d1cc06881947 100644 --- a/third_party/rust/target-lexicon/src/targets.rs +++ b/third_party/rust/target-lexicon/src/targets.rs @@ -10,16 +10,11 @@ use core::str::FromStr; #[allow(missing_docs)] pub enum Architecture { Unknown, - Aarch64, - Arm, - Armebv7r, - Armv4t, - Armv5te, - Armv6, - Armv7, - Armv7r, - Armv7s, + Arm(ArmArchitecture), + AmdGcn, + Aarch64(Aarch64Architecture), Asmjs, + Hexagon, I386, I586, I686, @@ -27,18 +22,67 @@ pub enum Architecture { Mips64, Mips64el, Mipsel, + Mipsisa32r6, + Mipsisa32r6el, + Mipsisa64r6, + Mipsisa64r6el, Msp430, + Nvptx64, Powerpc, Powerpc64, Powerpc64le, Riscv32, + Riscv32i, Riscv32imac, Riscv32imc, Riscv64, + Riscv64gc, + Riscv64imac, S390x, Sparc, Sparc64, Sparcv9, + Wasm32, + X86_64, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum ArmArchitecture { + Arm, // Generic arm + Armeb, + Armv4, + Armv4t, + Armv5t, + Armv5te, + Armv5tej, + Armv6, + Armv6j, + Armv6k, + Armv6z, + Armv6kz, + Armv6t2, + Armv6m, + Armv7, + Armv7a, + Armv7ve, + Armv7m, + Armv7r, + Armv7s, + Armv8, + Armv8a, + Armv8_1a, + Armv8_2a, + Armv8_3a, + Armv8_4a, + Armv8_5a, + Armv8mBase, + Armv8mMain, + Armv8r, + + Armebv7r, + + Thumbeb, Thumbv6m, Thumbv7a, Thumbv7em, @@ -46,8 +90,204 @@ pub enum Architecture { Thumbv7neon, Thumbv8mBase, Thumbv8mMain, - Wasm32, - X86_64, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Aarch64Architecture { + Aarch64, + Aarch64be, +} + +// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +// #[allow(missing_docs)] +// pub enum ArmFpu { +// Vfp, +// Vfpv2, +// Vfpv3, +// Vfpv3Fp16, +// Vfpv3Xd, +// Vfpv3XdFp16, +// Neon, +// NeonVfpv3, +// NeonVfpv4, +// Vfpv4, +// Vfpv4D16, +// Fpv4SpD16, +// Fpv5SpD16, +// Fpv5D16, +// FpArmv8, +// NeonFpArmv8, +// CryptoNeonFpArmv8, +// } + +impl ArmArchitecture { + /// Test if this architecture uses the Thumb instruction set. + pub fn is_thumb(self) -> bool { + match self { + ArmArchitecture::Arm + | ArmArchitecture::Armeb + | ArmArchitecture::Armv4 + | ArmArchitecture::Armv4t + | ArmArchitecture::Armv5t + | ArmArchitecture::Armv5te + | ArmArchitecture::Armv5tej + | ArmArchitecture::Armv6 + | ArmArchitecture::Armv6j + | ArmArchitecture::Armv6k + | ArmArchitecture::Armv6z + | ArmArchitecture::Armv6kz + | ArmArchitecture::Armv6t2 + | ArmArchitecture::Armv6m + | ArmArchitecture::Armv7 + | ArmArchitecture::Armv7a + | ArmArchitecture::Armv7ve + | ArmArchitecture::Armv7m + | ArmArchitecture::Armv7r + | ArmArchitecture::Armv7s + | ArmArchitecture::Armv8 + | ArmArchitecture::Armv8a + | ArmArchitecture::Armv8_1a + | ArmArchitecture::Armv8_2a + | ArmArchitecture::Armv8_3a + | ArmArchitecture::Armv8_4a + | ArmArchitecture::Armv8_5a + | ArmArchitecture::Armv8mBase + | ArmArchitecture::Armv8mMain + | ArmArchitecture::Armv8r + | ArmArchitecture::Armebv7r => false, + ArmArchitecture::Thumbeb + | ArmArchitecture::Thumbv6m + | ArmArchitecture::Thumbv7a + | ArmArchitecture::Thumbv7em + | ArmArchitecture::Thumbv7m + | ArmArchitecture::Thumbv7neon + | ArmArchitecture::Thumbv8mBase + | ArmArchitecture::Thumbv8mMain => true, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> PointerWidth { + match self { + ArmArchitecture::Arm + | ArmArchitecture::Armeb + | ArmArchitecture::Armv4 + | ArmArchitecture::Armv4t + | ArmArchitecture::Armv5t + | ArmArchitecture::Armv5te + | ArmArchitecture::Armv5tej + | ArmArchitecture::Armv6 + | ArmArchitecture::Armv6j + | ArmArchitecture::Armv6k + | ArmArchitecture::Armv6z + | ArmArchitecture::Armv6kz + | ArmArchitecture::Armv6t2 + | ArmArchitecture::Armv6m + | ArmArchitecture::Armv7 + | ArmArchitecture::Armv7a + | ArmArchitecture::Armv7ve + | ArmArchitecture::Armv7m + | ArmArchitecture::Armv7r + | ArmArchitecture::Armv7s + | ArmArchitecture::Armv8 + | ArmArchitecture::Armv8a + | ArmArchitecture::Armv8_1a + | ArmArchitecture::Armv8_2a + | ArmArchitecture::Armv8_3a + | ArmArchitecture::Armv8_4a + | ArmArchitecture::Armv8_5a + | ArmArchitecture::Armv8mBase + | ArmArchitecture::Armv8mMain + | ArmArchitecture::Armv8r + | ArmArchitecture::Armebv7r + | ArmArchitecture::Thumbeb + | ArmArchitecture::Thumbv6m + | ArmArchitecture::Thumbv7a + | ArmArchitecture::Thumbv7em + | ArmArchitecture::Thumbv7m + | ArmArchitecture::Thumbv7neon + | ArmArchitecture::Thumbv8mBase + | ArmArchitecture::Thumbv8mMain => PointerWidth::U32, + } + } + + /// Return the endianness of this architecture. + pub fn endianness(self) -> Endianness { + match self { + ArmArchitecture::Arm + | ArmArchitecture::Armv4 + | ArmArchitecture::Armv4t + | ArmArchitecture::Armv5t + | ArmArchitecture::Armv5te + | ArmArchitecture::Armv5tej + | ArmArchitecture::Armv6 + | ArmArchitecture::Armv6j + | ArmArchitecture::Armv6k + | ArmArchitecture::Armv6z + | ArmArchitecture::Armv6kz + | ArmArchitecture::Armv6t2 + | ArmArchitecture::Armv6m + | ArmArchitecture::Armv7 + | ArmArchitecture::Armv7a + | ArmArchitecture::Armv7ve + | ArmArchitecture::Armv7m + | ArmArchitecture::Armv7r + | ArmArchitecture::Armv7s + | ArmArchitecture::Armv8 + | ArmArchitecture::Armv8a + | ArmArchitecture::Armv8_1a + | ArmArchitecture::Armv8_2a + | ArmArchitecture::Armv8_3a + | ArmArchitecture::Armv8_4a + | ArmArchitecture::Armv8_5a + | ArmArchitecture::Armv8mBase + | ArmArchitecture::Armv8mMain + | ArmArchitecture::Armv8r + | ArmArchitecture::Thumbv6m + | ArmArchitecture::Thumbv7a + | ArmArchitecture::Thumbv7em + | ArmArchitecture::Thumbv7m + | ArmArchitecture::Thumbv7neon + | ArmArchitecture::Thumbv8mBase + | ArmArchitecture::Thumbv8mMain => Endianness::Little, + ArmArchitecture::Armeb | ArmArchitecture::Armebv7r | ArmArchitecture::Thumbeb => { + Endianness::Big + } + } + } +} + +impl Aarch64Architecture { + /// Test if this architecture uses the Thumb instruction set. + pub fn is_thumb(self) -> bool { + match self { + Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => false, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> PointerWidth { + match self { + Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => PointerWidth::U64, + } + } + + /// Return the endianness of this architecture. + pub fn endianness(self) -> Endianness { + match self { + Aarch64Architecture::Aarch64 => Endianness::Little, + Aarch64Architecture::Aarch64be => Endianness::Big, + } + } } /// The "vendor" field, which in practice is little more than an arbitrary @@ -56,12 +296,16 @@ pub enum Architecture { #[allow(missing_docs)] pub enum Vendor { Unknown, + Amd, Apple, Experimental, Fortanix, + Nvidia, Pc, Rumprun, Sun, + Uwp, + Wrs, } /// The "operating system" field, which sometimes implies an environment, and @@ -70,8 +314,10 @@ pub enum Vendor { #[allow(missing_docs)] pub enum OperatingSystem { Unknown, + AmdHsa, Bitrig, Cloudabi, + Cuda, Darwin, Dragonfly, Emscripten, @@ -82,6 +328,7 @@ pub enum OperatingSystem { Ios, L4re, Linux, + MacOSX { major: u16, minor: u16, patch: u16 }, Nebulet, Netbsd, None_, @@ -89,6 +336,8 @@ pub enum OperatingSystem { Redox, Solaris, Uefi, + VxWorks, + Wasi, Windows, } @@ -99,6 +348,7 @@ pub enum OperatingSystem { #[allow(missing_docs)] pub enum Environment { Unknown, + AmdGiz, Android, Androideabi, Eabi, @@ -112,9 +362,11 @@ pub enum Environment { Musl, Musleabi, Musleabihf, + Muslabi64, Msvc, Uclibc, Sgx, + Spe, } /// The "binary format" field, which is usually omitted, and the binary format @@ -134,38 +386,34 @@ impl Architecture { pub fn endianness(self) -> Result { match self { Architecture::Unknown => Err(()), - Architecture::Aarch64 - | Architecture::Arm - | Architecture::Armv4t - | Architecture::Armv5te - | Architecture::Armv6 - | Architecture::Armv7 - | Architecture::Armv7r - | Architecture::Armv7s + Architecture::Arm(arm) => Ok(arm.endianness()), + Architecture::Aarch64(aarch) => Ok(aarch.endianness()), + Architecture::AmdGcn | Architecture::Asmjs + | Architecture::Hexagon | Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::Mips64el | Architecture::Mipsel + | Architecture::Mipsisa32r6el + | Architecture::Mipsisa64r6el | Architecture::Msp430 + | Architecture::Nvptx64 | Architecture::Powerpc64le | Architecture::Riscv32 + | Architecture::Riscv32i | Architecture::Riscv32imac | Architecture::Riscv32imc | Architecture::Riscv64 - | Architecture::Thumbv6m - | Architecture::Thumbv7a - | Architecture::Thumbv7em - | Architecture::Thumbv7m - | Architecture::Thumbv7neon - | Architecture::Thumbv8mBase - | Architecture::Thumbv8mMain + | Architecture::Riscv64gc + | Architecture::Riscv64imac | Architecture::Wasm32 | Architecture::X86_64 => Ok(Endianness::Little), - Architecture::Armebv7r - | Architecture::Mips + Architecture::Mips | Architecture::Mips64 + | Architecture::Mipsisa32r6 + | Architecture::Mipsisa64r6 | Architecture::Powerpc | Architecture::Powerpc64 | Architecture::S390x @@ -180,39 +428,35 @@ impl Architecture { match self { Architecture::Unknown => Err(()), Architecture::Msp430 => Ok(PointerWidth::U16), - Architecture::Arm - | Architecture::Armebv7r - | Architecture::Armv4t - | Architecture::Armv5te - | Architecture::Armv6 - | Architecture::Armv7 - | Architecture::Armv7r - | Architecture::Armv7s - | Architecture::Asmjs + Architecture::Arm(arm) => Ok(arm.pointer_width()), + Architecture::Aarch64(aarch) => Ok(aarch.pointer_width()), + Architecture::Asmjs + | Architecture::Hexagon | Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::Mipsel + | Architecture::Mipsisa32r6 + | Architecture::Mipsisa32r6el | Architecture::Riscv32 + | Architecture::Riscv32i | Architecture::Riscv32imac | Architecture::Riscv32imc | Architecture::Sparc - | Architecture::Thumbv6m - | Architecture::Thumbv7a - | Architecture::Thumbv7em - | Architecture::Thumbv7m - | Architecture::Thumbv7neon - | Architecture::Thumbv8mBase - | Architecture::Thumbv8mMain | Architecture::Wasm32 | Architecture::Mips | Architecture::Powerpc => Ok(PointerWidth::U32), - Architecture::Aarch64 + Architecture::AmdGcn | Architecture::Mips64el + | Architecture::Mipsisa64r6 + | Architecture::Mipsisa64r6el | Architecture::Powerpc64le | Architecture::Riscv64 + | Architecture::Riscv64gc + | Architecture::Riscv64imac | Architecture::X86_64 | Architecture::Mips64 + | Architecture::Nvptx64 | Architecture::Powerpc64 | Architecture::S390x | Architecture::Sparc64 @@ -223,84 +467,198 @@ impl Architecture { /// Return the binary format implied by this target triple, ignoring its /// `binary_format` field. -pub fn default_binary_format(triple: &Triple) -> BinaryFormat { +pub(crate) fn default_binary_format(triple: &Triple) -> BinaryFormat { match triple.operating_system { - OperatingSystem::None_ => BinaryFormat::Unknown, - OperatingSystem::Darwin | OperatingSystem::Ios => BinaryFormat::Macho, - OperatingSystem::Windows => BinaryFormat::Coff, - OperatingSystem::Nebulet | OperatingSystem::Emscripten | OperatingSystem::Unknown => { - match triple.architecture { - Architecture::Wasm32 => BinaryFormat::Wasm, - _ => BinaryFormat::Unknown, - } + OperatingSystem::None_ => match triple.environment { + Environment::Eabi | Environment::Eabihf => BinaryFormat::Elf, + _ => BinaryFormat::Unknown, + }, + OperatingSystem::Darwin | OperatingSystem::Ios | OperatingSystem::MacOSX { .. } => { + BinaryFormat::Macho } + OperatingSystem::Windows => BinaryFormat::Coff, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::VxWorks + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match triple.architecture { + Architecture::Wasm32 => BinaryFormat::Wasm, + _ => BinaryFormat::Unknown, + }, _ => BinaryFormat::Elf, } } -impl fmt::Display for Architecture { +impl fmt::Display for ArmArchitecture { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match *self { - Architecture::Unknown => "unknown", - Architecture::Aarch64 => "aarch64", - Architecture::Arm => "arm", - Architecture::Armebv7r => "armebv7r", - Architecture::Armv4t => "armv4t", - Architecture::Armv5te => "armv5te", - Architecture::Armv6 => "armv6", - Architecture::Armv7 => "armv7", - Architecture::Armv7r => "armv7r", - Architecture::Armv7s => "armv7s", - Architecture::Asmjs => "asmjs", - Architecture::I386 => "i386", - Architecture::I586 => "i586", - Architecture::I686 => "i686", - Architecture::Mips => "mips", - Architecture::Mips64 => "mips64", - Architecture::Mips64el => "mips64el", - Architecture::Mipsel => "mipsel", - Architecture::Msp430 => "msp430", - Architecture::Powerpc => "powerpc", - Architecture::Powerpc64 => "powerpc64", - Architecture::Powerpc64le => "powerpc64le", - Architecture::Riscv32 => "riscv32", - Architecture::Riscv32imac => "riscv32imac", - Architecture::Riscv32imc => "riscv32imc", - Architecture::Riscv64 => "riscv64", - Architecture::S390x => "s390x", - Architecture::Sparc => "sparc", - Architecture::Sparc64 => "sparc64", - Architecture::Sparcv9 => "sparcv9", - Architecture::Thumbv6m => "thumbv6m", - Architecture::Thumbv7a => "thumbv7a", - Architecture::Thumbv7em => "thumbv7em", - Architecture::Thumbv7m => "thumbv7m", - Architecture::Thumbv7neon => "thumbv7neon", - Architecture::Thumbv8mBase => "thumbv8m.base", - Architecture::Thumbv8mMain => "thumbv8m.main", - Architecture::Wasm32 => "wasm32", - Architecture::X86_64 => "x86_64", + ArmArchitecture::Arm => "arm", + ArmArchitecture::Armeb => "armeb", + ArmArchitecture::Armv4 => "armv4", + ArmArchitecture::Armv4t => "armv4t", + ArmArchitecture::Armv5t => "armv5t", + ArmArchitecture::Armv5te => "armv5te", + ArmArchitecture::Armv5tej => "armv5tej", + ArmArchitecture::Armv6 => "armv6", + ArmArchitecture::Armv6j => "armv6j", + ArmArchitecture::Armv6k => "armv6k", + ArmArchitecture::Armv6z => "armv6z", + ArmArchitecture::Armv6kz => "armv6kz", + ArmArchitecture::Armv6t2 => "armv6t2", + ArmArchitecture::Armv6m => "armv6m", + ArmArchitecture::Armv7 => "armv7", + ArmArchitecture::Armv7a => "armv7a", + ArmArchitecture::Armv7ve => "armv7ve", + ArmArchitecture::Armv7m => "armv7m", + ArmArchitecture::Armv7r => "armv7r", + ArmArchitecture::Armv7s => "armv7s", + ArmArchitecture::Armv8 => "armv8", + ArmArchitecture::Armv8a => "armv8a", + ArmArchitecture::Armv8_1a => "armv8.1a", + ArmArchitecture::Armv8_2a => "armv8.2a", + ArmArchitecture::Armv8_3a => "armv8.3a", + ArmArchitecture::Armv8_4a => "armv8.4a", + ArmArchitecture::Armv8_5a => "armv8.5a", + ArmArchitecture::Armv8mBase => "armv8m.base", + ArmArchitecture::Armv8mMain => "armv8m.main", + ArmArchitecture::Armv8r => "armv8r", + ArmArchitecture::Thumbeb => "thumbeb", + ArmArchitecture::Thumbv6m => "thumbv6m", + ArmArchitecture::Thumbv7a => "thumbv7a", + ArmArchitecture::Thumbv7em => "thumbv7em", + ArmArchitecture::Thumbv7m => "thumbv7m", + ArmArchitecture::Thumbv7neon => "thumbv7neon", + ArmArchitecture::Thumbv8mBase => "thumbv8m.base", + ArmArchitecture::Thumbv8mMain => "thumbv8m.main", + ArmArchitecture::Armebv7r => "armebv7r", }; f.write_str(s) } } +impl fmt::Display for Aarch64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Aarch64Architecture::Aarch64 => "aarch64", + Aarch64Architecture::Aarch64be => "aarch64be", + }; + f.write_str(s) + } +} + +impl fmt::Display for Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Architecture::Arm(arm) => arm.fmt(f), + Architecture::Aarch64(aarch) => aarch.fmt(f), + Architecture::Unknown => f.write_str("unknown"), + Architecture::AmdGcn => f.write_str("amdgcn"), + Architecture::Asmjs => f.write_str("asmjs"), + Architecture::Hexagon => f.write_str("hexagon"), + Architecture::I386 => f.write_str("i386"), + Architecture::I586 => f.write_str("i586"), + Architecture::I686 => f.write_str("i686"), + Architecture::Mips => f.write_str("mips"), + Architecture::Mips64 => f.write_str("mips64"), + Architecture::Mips64el => f.write_str("mips64el"), + Architecture::Mipsel => f.write_str("mipsel"), + Architecture::Mipsisa32r6 => f.write_str("mipsisa32r6"), + Architecture::Mipsisa32r6el => f.write_str("mipsisa32r6el"), + Architecture::Mipsisa64r6 => f.write_str("mipsisa64r6"), + Architecture::Mipsisa64r6el => f.write_str("mipsisa64r6el"), + Architecture::Msp430 => f.write_str("msp430"), + Architecture::Nvptx64 => f.write_str("nvptx64"), + Architecture::Powerpc => f.write_str("powerpc"), + Architecture::Powerpc64 => f.write_str("powerpc64"), + Architecture::Powerpc64le => f.write_str("powerpc64le"), + Architecture::Riscv32 => f.write_str("riscv32"), + Architecture::Riscv32i => f.write_str("riscv32i"), + Architecture::Riscv32imac => f.write_str("riscv32imac"), + Architecture::Riscv32imc => f.write_str("riscv32imc"), + Architecture::Riscv64 => f.write_str("riscv64"), + Architecture::Riscv64gc => f.write_str("riscv64gc"), + Architecture::Riscv64imac => f.write_str("riscv64imac"), + Architecture::S390x => f.write_str("s390x"), + Architecture::Sparc => f.write_str("sparc"), + Architecture::Sparc64 => f.write_str("sparc64"), + Architecture::Sparcv9 => f.write_str("sparcv9"), + Architecture::Wasm32 => f.write_str("wasm32"), + Architecture::X86_64 => f.write_str("x86_64"), + } + } +} + +impl FromStr for ArmArchitecture { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "arm" => ArmArchitecture::Arm, + "armeb" => ArmArchitecture::Armeb, + "armv4" => ArmArchitecture::Armv4, + "armv4t" => ArmArchitecture::Armv4t, + "armv5t" => ArmArchitecture::Armv5t, + "armv5te" => ArmArchitecture::Armv5te, + "armv5tej" => ArmArchitecture::Armv5tej, + "armv6" => ArmArchitecture::Armv6, + "armv6j" => ArmArchitecture::Armv6j, + "armv6k" => ArmArchitecture::Armv6k, + "armv6z" => ArmArchitecture::Armv6z, + "armv6kz" => ArmArchitecture::Armv6kz, + "armv6t2" => ArmArchitecture::Armv6t2, + "armv6m" => ArmArchitecture::Armv6m, + "armv7" => ArmArchitecture::Armv7, + "armv7a" => ArmArchitecture::Armv7a, + "armv7ve" => ArmArchitecture::Armv7ve, + "armv7m" => ArmArchitecture::Armv7m, + "armv7r" => ArmArchitecture::Armv7r, + "armv7s" => ArmArchitecture::Armv7s, + "armv8" => ArmArchitecture::Armv8, + "armv8a" => ArmArchitecture::Armv8a, + "armv8.1a" => ArmArchitecture::Armv8_1a, + "armv8.2a" => ArmArchitecture::Armv8_2a, + "armv8.3a" => ArmArchitecture::Armv8_3a, + "armv8.4a" => ArmArchitecture::Armv8_4a, + "armv8.5a" => ArmArchitecture::Armv8_5a, + "armv8m.base" => ArmArchitecture::Armv8mBase, + "armv8m.main" => ArmArchitecture::Armv8mMain, + "armv8r" => ArmArchitecture::Armv8r, + "thumbeb" => ArmArchitecture::Thumbeb, + "thumbv6m" => ArmArchitecture::Thumbv6m, + "thumbv7a" => ArmArchitecture::Thumbv7a, + "thumbv7em" => ArmArchitecture::Thumbv7em, + "thumbv7m" => ArmArchitecture::Thumbv7m, + "thumbv7neon" => ArmArchitecture::Thumbv7neon, + "thumbv8m.base" => ArmArchitecture::Thumbv8mBase, + "thumbv8m.main" => ArmArchitecture::Thumbv8mMain, + "armebv7r" => ArmArchitecture::Armebv7r, + _ => return Err(()), + }) + } +} + +impl FromStr for Aarch64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "aarch64" => Aarch64Architecture::Aarch64, + "arm64" => Aarch64Architecture::Aarch64, + "aarch64be" => Aarch64Architecture::Aarch64be, + _ => return Err(()), + }) + } +} + impl FromStr for Architecture { type Err = (); fn from_str(s: &str) -> Result { Ok(match s { "unknown" => Architecture::Unknown, - "aarch64" => Architecture::Aarch64, - "arm" => Architecture::Arm, - "armebv7r" => Architecture::Armebv7r, - "armv4t" => Architecture::Armv4t, - "armv5te" => Architecture::Armv5te, - "armv6" => Architecture::Armv6, - "armv7" => Architecture::Armv7, - "armv7r" => Architecture::Armv7r, - "armv7s" => Architecture::Armv7s, + "amdgcn" => Architecture::AmdGcn, "asmjs" => Architecture::Asmjs, + "hexagon" => Architecture::Hexagon, "i386" => Architecture::I386, "i586" => Architecture::I586, "i686" => Architecture::I686, @@ -308,28 +666,37 @@ impl FromStr for Architecture { "mips64" => Architecture::Mips64, "mips64el" => Architecture::Mips64el, "mipsel" => Architecture::Mipsel, + "mipsisa32r6" => Architecture::Mipsisa32r6, + "mipsisa32r6el" => Architecture::Mipsisa32r6el, + "mipsisa64r6" => Architecture::Mipsisa64r6, + "mipsisa64r6el" => Architecture::Mipsisa64r6el, "msp430" => Architecture::Msp430, + "nvptx64" => Architecture::Nvptx64, "powerpc" => Architecture::Powerpc, "powerpc64" => Architecture::Powerpc64, "powerpc64le" => Architecture::Powerpc64le, "riscv32" => Architecture::Riscv32, + "riscv32i" => Architecture::Riscv32i, "riscv32imac" => Architecture::Riscv32imac, "riscv32imc" => Architecture::Riscv32imc, "riscv64" => Architecture::Riscv64, + "riscv64gc" => Architecture::Riscv64gc, + "riscv64imac" => Architecture::Riscv64imac, "s390x" => Architecture::S390x, "sparc" => Architecture::Sparc, "sparc64" => Architecture::Sparc64, "sparcv9" => Architecture::Sparcv9, - "thumbv6m" => Architecture::Thumbv6m, - "thumbv7a" => Architecture::Thumbv7a, - "thumbv7em" => Architecture::Thumbv7em, - "thumbv7m" => Architecture::Thumbv7m, - "thumbv7neon" => Architecture::Thumbv7neon, - "thumbv8m.base" => Architecture::Thumbv8mBase, - "thumbv8m.main" => Architecture::Thumbv8mMain, "wasm32" => Architecture::Wasm32, "x86_64" => Architecture::X86_64, - _ => return Err(()), + _ => { + if let Ok(arm) = ArmArchitecture::from_str(s) { + Architecture::Arm(arm) + } else if let Ok(aarch64) = Aarch64Architecture::from_str(s) { + Architecture::Aarch64(aarch64) + } else { + return Err(()); + } + } }) } } @@ -338,12 +705,16 @@ impl fmt::Display for Vendor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match *self { Vendor::Unknown => "unknown", + Vendor::Amd => "amd", Vendor::Apple => "apple", Vendor::Experimental => "experimental", Vendor::Fortanix => "fortanix", + Vendor::Nvidia => "nvidia", Vendor::Pc => "pc", Vendor::Rumprun => "rumprun", Vendor::Sun => "sun", + Vendor::Uwp => "uwp", + Vendor::Wrs => "wrs", }; f.write_str(s) } @@ -355,12 +726,16 @@ impl FromStr for Vendor { fn from_str(s: &str) -> Result { Ok(match s { "unknown" => Vendor::Unknown, + "amd" => Vendor::Amd, "apple" => Vendor::Apple, "experimental" => Vendor::Experimental, "fortanix" => Vendor::Fortanix, + "nvidia" => Vendor::Nvidia, "pc" => Vendor::Pc, "rumprun" => Vendor::Rumprun, "sun" => Vendor::Sun, + "uwp" => Vendor::Uwp, + "wrs" => Vendor::Wrs, _ => return Err(()), }) } @@ -370,8 +745,10 @@ impl fmt::Display for OperatingSystem { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match *self { OperatingSystem::Unknown => "unknown", + OperatingSystem::AmdHsa => "amdhsa", OperatingSystem::Bitrig => "bitrig", OperatingSystem::Cloudabi => "cloudabi", + OperatingSystem::Cuda => "cuda", OperatingSystem::Darwin => "darwin", OperatingSystem::Dragonfly => "dragonfly", OperatingSystem::Emscripten => "emscripten", @@ -382,6 +759,13 @@ impl fmt::Display for OperatingSystem { OperatingSystem::Ios => "ios", OperatingSystem::L4re => "l4re", OperatingSystem::Linux => "linux", + OperatingSystem::MacOSX { + major, + minor, + patch, + } => { + return write!(f, "macosx{}.{}.{}", major, minor, patch); + } OperatingSystem::Nebulet => "nebulet", OperatingSystem::Netbsd => "netbsd", OperatingSystem::None_ => "none", @@ -389,6 +773,8 @@ impl fmt::Display for OperatingSystem { OperatingSystem::Redox => "redox", OperatingSystem::Solaris => "solaris", OperatingSystem::Uefi => "uefi", + OperatingSystem::VxWorks => "vxworks", + OperatingSystem::Wasi => "wasi", OperatingSystem::Windows => "windows", }; f.write_str(s) @@ -399,10 +785,43 @@ impl FromStr for OperatingSystem { type Err = (); fn from_str(s: &str) -> Result { + // TODO also parse version number for darwin and ios OSes + if s.starts_with("macosx") { + // Parse operating system names like `macosx10.7.0`. + let s = &s["macosx".len()..]; + let mut parts = s.split('.').map(|num| num.parse::()); + + macro_rules! get_part { + () => { + if let Some(Ok(part)) = parts.next() { + part + } else { + return Err(()); + } + }; + } + + let major = get_part!(); + let minor = get_part!(); + let patch = get_part!(); + + if parts.next().is_some() { + return Err(()); + } + + return Ok(OperatingSystem::MacOSX { + major, + minor, + patch, + }); + } + Ok(match s { "unknown" => OperatingSystem::Unknown, + "amdhsa" => OperatingSystem::AmdHsa, "bitrig" => OperatingSystem::Bitrig, "cloudabi" => OperatingSystem::Cloudabi, + "cuda" => OperatingSystem::Cuda, "darwin" => OperatingSystem::Darwin, "dragonfly" => OperatingSystem::Dragonfly, "emscripten" => OperatingSystem::Emscripten, @@ -420,6 +839,8 @@ impl FromStr for OperatingSystem { "redox" => OperatingSystem::Redox, "solaris" => OperatingSystem::Solaris, "uefi" => OperatingSystem::Uefi, + "vxworks" => OperatingSystem::VxWorks, + "wasi" => OperatingSystem::Wasi, "windows" => OperatingSystem::Windows, _ => return Err(()), }) @@ -430,6 +851,7 @@ impl fmt::Display for Environment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match *self { Environment::Unknown => "unknown", + Environment::AmdGiz => "amdgiz", Environment::Android => "android", Environment::Androideabi => "androideabi", Environment::Eabi => "eabi", @@ -443,9 +865,11 @@ impl fmt::Display for Environment { Environment::Musl => "musl", Environment::Musleabi => "musleabi", Environment::Musleabihf => "musleabihf", + Environment::Muslabi64 => "muslabi64", Environment::Msvc => "msvc", Environment::Uclibc => "uclibc", Environment::Sgx => "sgx", + Environment::Spe => "spe", }; f.write_str(s) } @@ -457,6 +881,7 @@ impl FromStr for Environment { fn from_str(s: &str) -> Result { Ok(match s { "unknown" => Environment::Unknown, + "amdgiz" => Environment::AmdGiz, "android" => Environment::Android, "androideabi" => Environment::Androideabi, "eabi" => Environment::Eabi, @@ -470,9 +895,11 @@ impl FromStr for Environment { "musl" => Environment::Musl, "musleabi" => Environment::Musleabi, "musleabihf" => Environment::Musleabihf, + "muslabi64" => Environment::Muslabi64, "msvc" => Environment::Msvc, "uclibc" => Environment::Uclibc, "sgx" => Environment::Sgx, + "spe" => Environment::Spe, _ => return Err(()), }) } @@ -509,12 +936,14 @@ impl FromStr for BinaryFormat { #[cfg(test)] mod tests { use super::*; - use std::string::ToString; + use alloc::string::ToString; #[test] - fn rust_targets() { - // At the time of writing this, these are all the targets emitted by - // "rustup target list" and "rustc --print target-list". + fn roundtrip_known_triples() { + // This list is constructed from: + // - targets emitted by "rustup target list" + // - targets emitted by "rustc +nightly --print target-list" + // - targets contributors have added let targets = [ "aarch64-apple-ios", "aarch64-fuchsia", @@ -528,6 +957,11 @@ mod tests { "aarch64-unknown-netbsd", "aarch64-unknown-none", "aarch64-unknown-openbsd", + "aarch64-unknown-redox", + "aarch64-uwp-windows-msvc", + "aarch64-wrs-vxworks", + "amdgcn-amd-amdhsa", + "amdgcn-amd-amdhsa-amdgiz", "armebv7r-none-eabi", "armebv7r-none-eabihf", "arm-linux-androideabi", @@ -538,6 +972,7 @@ mod tests { "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", @@ -545,16 +980,22 @@ mod tests { "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-apple-macosx10.7.0", "i686-pc-windows-gnu", "i686-pc-windows-msvc", "i686-unknown-cloudabi", @@ -565,28 +1006,46 @@ mod tests { "i686-unknown-linux-musl", "i686-unknown-netbsd", "i686-unknown-openbsd", + "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", @@ -602,11 +1061,14 @@ mod tests { "wasm32-experimental-emscripten", "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-apple-macosx10.7.0", + "x86_64-pc-solaris", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", "x86_64-rumprun-netbsd", @@ -625,6 +1087,9 @@ mod tests { "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", ]; for target in targets.iter() { @@ -633,4 +1098,17 @@ mod tests { assert_eq!(t.to_string(), *target); } } + + #[test] + fn thumbv7em_none_eabihf() { + let t = Triple::from_str("thumbv7em-none-eabihf").expect("can't parse target"); + assert_eq!( + t.architecture, + Architecture::Arm(ArmArchitecture::Thumbv7em) + ); + assert_eq!(t.vendor, Vendor::Unknown); + assert_eq!(t.operating_system, OperatingSystem::None_); + assert_eq!(t.environment, Environment::Eabihf); + assert_eq!(t.binary_format, BinaryFormat::Elf); + } } diff --git a/third_party/rust/target-lexicon/src/triple.rs b/third_party/rust/target-lexicon/src/triple.rs index c998891a904b6..c81335665db40 100644 --- a/third_party/rust/target-lexicon/src/triple.rs +++ b/third_party/rust/target-lexicon/src/triple.rs @@ -2,11 +2,12 @@ use crate::parse_error::ParseError; use crate::targets::{ - default_binary_format, Architecture, BinaryFormat, Environment, OperatingSystem, Vendor, + default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment, + OperatingSystem, Vendor, }; +use alloc::borrow::ToOwned; use core::fmt; use core::str::FromStr; -use std::borrow::ToOwned; /// The target memory endianness. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -53,11 +54,13 @@ impl PointerWidth { #[allow(missing_docs)] pub enum CallingConvention { SystemV, + /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md + WasmBasicCAbi, WindowsFastcall, } -/// A target "triple", because historically such things had three fields, though -/// they've grown more features over time. +/// A target "triple". Historically such things had three fields, though they've +/// added additional fields over time. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Triple { /// The "architecture" (and sometimes the subarchitecture). @@ -66,7 +69,8 @@ pub struct Triple { pub vendor: Vendor, /// The "operating system" (sometimes also the environment). pub operating_system: OperatingSystem, - /// The "environment" on top of the operating system. + /// The "environment" on top of the operating system (often omitted for + /// operating systems with a single predominant environment). pub environment: Environment, /// The "binary format" (rarely used). pub binary_format: BinaryFormat, @@ -96,12 +100,19 @@ impl Triple { | OperatingSystem::Ios | OperatingSystem::L4re | OperatingSystem::Linux - | OperatingSystem::Nebulet + | OperatingSystem::MacOSX { .. } | OperatingSystem::Netbsd | OperatingSystem::Openbsd | OperatingSystem::Redox | OperatingSystem::Solaris => CallingConvention::SystemV, OperatingSystem::Windows => CallingConvention::WindowsFastcall, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match self.architecture { + Architecture::Wasm32 => CallingConvention::WasmBasicCAbi, + _ => return Err(()), + }, _ => return Err(()), }) } @@ -159,17 +170,18 @@ impl fmt::Display for Triple { && (self.environment == Environment::Android || self.environment == Environment::Androideabi)) || self.operating_system == OperatingSystem::Fuchsia + || self.operating_system == OperatingSystem::Wasi || (self.operating_system == OperatingSystem::None_ - && (self.architecture == Architecture::Armebv7r - || self.architecture == Architecture::Armv7r - || self.architecture == Architecture::Thumbv6m - || self.architecture == Architecture::Thumbv7em - || self.architecture == Architecture::Thumbv7m - || self.architecture == Architecture::Thumbv8mBase - || self.architecture == Architecture::Thumbv8mMain + && (self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain) || self.architecture == Architecture::Msp430))) { - // As a special case, omit the vendor for Android, Fuchsia, and sometimes + // As a special case, omit the vendor for Android, Fuchsia, Wasi, and sometimes // None_, depending on the hardware architecture. This logic is entirely // ad-hoc, and is just sufficient to handle the current set of recognized // triples. @@ -269,7 +281,7 @@ impl FromStr for Triple { } } -/// A convenient syntax for triple "literals". +/// A convenient syntax for triple literals. /// /// This currently expands to code that just calls `Triple::from_str` and does /// an `expect`, though in the future it would be cool to use procedural macros diff --git a/third_party/rust/target-lexicon/test.sh b/third_party/rust/target-lexicon/test.sh new file mode 100755 index 0000000000000..9363dbfa77bae --- /dev/null +++ b/third_party/rust/target-lexicon/test.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -oeu pipefail + + +for trip in wasm32-unknown-unknown wasm32-wasi arm-unknown-linux-gnueabi aarch64-unknown-linux-gnu; do + echo TARGET $trip + cargo build --target $trip + 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