]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit 'f2cdd4a78d89c009342197cf5844a21f8aa813df' into sync_cg_clif-2022-04-22
authorbjorn3 <bjorn3@users.noreply.github.com>
Fri, 22 Apr 2022 19:11:38 +0000 (21:11 +0200)
committerbjorn3 <bjorn3@users.noreply.github.com>
Fri, 22 Apr 2022 19:11:38 +0000 (21:11 +0200)
21 files changed:
1  2 
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs
compiler/rustc_codegen_cranelift/example/mini_core.rs
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/cast.rs
compiler/rustc_codegen_cranelift/src/config.rs
compiler/rustc_codegen_cranelift/src/discriminant.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/num.rs

index 30e9627c48d749f17324ba2dab559af13ba4e956,0000000000000000000000000000000000000000..7b8e43b639f993f97aec41c1da60d8775fdb613a
mode 100644,000000..100644
--- /dev/null
@@@ -1,318 -1,0 +1,318 @@@
- version = "0.82.1"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "anyhow"
 +version = "1.0.56"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
 +
 +[[package]]
 +name = "ar"
 +version = "0.8.0"
 +source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 +
 +[[package]]
 +name = "cfg-if"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 +
 +[[package]]
 +name = "cranelift-bforest"
- checksum = "d16922317bd7dd104d509a373887822caa0242fc1def00de66abb538db221db4"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b"
 +dependencies = [
 + "cranelift-entity",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen"
- checksum = "8b80bf40380256307b68a3dcbe1b91cac92a533e212b5b635abc3e4525781a0a"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c"
 +dependencies = [
 + "cranelift-bforest",
 + "cranelift-codegen-meta",
 + "cranelift-codegen-shared",
 + "cranelift-entity",
 + "gimli",
 + "log",
 + "regalloc",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen-meta"
- checksum = "703d0ed7d3bc6c7a814ca12858175bf4e93167a3584127858c686e4b5dd6e432"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d"
 +dependencies = [
 + "cranelift-codegen-shared",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen-shared"
- checksum = "80f52311e1c90de12dcf8c4b9999c6ebfd1ed360373e88c357160936844511f6"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455"
 +
 +[[package]]
 +name = "cranelift-entity"
- checksum = "66bc82ef522c1f643baf7d4d40b7c52643ee4549d8960b0e6a047daacb83f897"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed"
 +
 +[[package]]
 +name = "cranelift-frontend"
- checksum = "3cc35e4251864b17515845ba47447bca88fec9ca1a4186b19fe42526e36140e8"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654"
 +dependencies = [
 + "cranelift-codegen",
 + "log",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-jit"
- checksum = "93c66d594ad3bfe4e58b1fbd8d17877a7c6564a5f2d6f78cbbf4b0182af1927f"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 + "cranelift-entity",
 + "cranelift-module",
 + "cranelift-native",
 + "libc",
 + "log",
 + "region",
 + "target-lexicon",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "cranelift-module"
- checksum = "bf356697c40232aa09e1e3fb8a350ee894e849ccecc4eac56ff0570a4575c325"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 +]
 +
 +[[package]]
 +name = "cranelift-native"
- checksum = "b882b2251c9845d509d92aebfdb6c8bb3b3b48e207ac951f21fbd20cfe7f90b3"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.82.1"
++checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c"
 +dependencies = [
 + "cranelift-codegen",
 + "libc",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-object"
- checksum = "2d3f1a88e654e567d2591169239ed157ab290811a729a6468f53999c01001263"
++version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 + "cranelift-module",
 + "log",
 + "object",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "crc32fast"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "gimli"
 +version = "0.26.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
 +dependencies = [
 + "indexmap",
 +]
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.11.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 +
 +[[package]]
 +name = "indexmap"
 +version = "1.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
 +dependencies = [
 + "autocfg",
 + "hashbrown",
 +]
 +
 +[[package]]
 +name = "libc"
 +version = "0.2.119"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
 +
 +[[package]]
 +name = "libloading"
 +version = "0.6.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
 +dependencies = [
 + "cfg-if",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "log"
 +version = "0.4.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "mach"
 +version = "0.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.4.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 +
 +[[package]]
 +name = "object"
 +version = "0.27.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
 +dependencies = [
 + "crc32fast",
 + "indexmap",
 + "memchr",
 +]
 +
 +[[package]]
 +name = "once_cell"
 +version = "1.10.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 +
 +[[package]]
 +name = "regalloc"
 +version = "0.0.34"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02"
 +dependencies = [
 + "log",
 + "rustc-hash",
 + "smallvec",
 +]
 +
 +[[package]]
 +name = "region"
 +version = "2.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
 +dependencies = [
 + "bitflags",
 + "libc",
 + "mach",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "rustc-hash"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 +
 +[[package]]
 +name = "rustc_codegen_cranelift"
 +version = "0.1.0"
 +dependencies = [
 + "ar",
 + "cranelift-codegen",
 + "cranelift-frontend",
 + "cranelift-jit",
 + "cranelift-module",
 + "cranelift-native",
 + "cranelift-object",
 + "gimli",
 + "indexmap",
 + "libloading",
 + "object",
 + "once_cell",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "smallvec"
 +version = "1.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
 +
 +[[package]]
 +name = "target-lexicon"
 +version = "0.12.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 +dependencies = [
 + "winapi-i686-pc-windows-gnu",
 + "winapi-x86_64-pc-windows-gnu",
 +]
 +
 +[[package]]
 +name = "winapi-i686-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 +
 +[[package]]
 +name = "winapi-x86_64-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
index 70c03da3f29fa9808169e415ae6417cb99e3eefd,0000000000000000000000000000000000000000..74f50808a980a7de298a943e74ac3c4301f07473
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,55 @@@
- cranelift-codegen = { version = "0.82.1", features = ["unwind", "all-arch"] }
- cranelift-frontend = "0.82.1"
- cranelift-module = "0.82.1"
- cranelift-native = "0.82.1"
- cranelift-jit = { version = "0.82.1", optional = true }
- cranelift-object = "0.82.1"
 +[package]
 +name = "rustc_codegen_cranelift"
 +version = "0.1.0"
 +edition = "2021"
 +
 +[lib]
 +crate-type = ["dylib"]
 +
 +[dependencies]
 +# These have to be in sync with each other
++cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] }
++cranelift-frontend = "0.83.0"
++cranelift-module = "0.83.0"
++cranelift-native = "0.83.0"
++cranelift-jit = { version = "0.83.0", optional = true }
++cranelift-object = "0.83.0"
 +target-lexicon = "0.12.0"
 +gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 +object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 +
 +ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 +indexmap = "1.8.0"
 +libloading = { version = "0.6.0", optional = true }
 +once_cell = "1.10.0"
 +smallvec = "1.6.1"
 +
 +[patch.crates-io]
 +# Uncomment to use local checkout of cranelift
 +#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 +#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 +#cranelift-module = { path = "../wasmtime/cranelift/module" }
 +#cranelift-native = { path = "../wasmtime/cranelift/native" }
 +#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 +#cranelift-object = { path = "../wasmtime/cranelift/object" }
 +
 +#gimli = { path = "../" }
 +
 +[features]
 +# Enable features not ready to be enabled when compiling as part of rustc
 +unstable-features = ["jit", "inline_asm"]
 +jit = ["cranelift-jit", "libloading"]
 +inline_asm = []
 +
 +# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
 +# execution time of build scripts is so fast that optimizing them slows down the total build time.
 +[profile.release.build-override]
 +opt-level = 0
 +debug = false
 +
 +[profile.release.package.cranelift-codegen-meta]
 +opt-level = 0
 +debug = false
 +
 +[package.metadata.rust-analyzer]
 +rustc_private = true
index f584f54e106ac060900e01924f65d5e0a17804df,0000000000000000000000000000000000000000..51ba0dbfcc7920e2868531cc897bd70c48a9909b
mode 100644,000000..100644
--- /dev/null
@@@ -1,331 -1,0 +1,332 @@@
- version = "0.1.71"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "addr2line"
 +version = "0.16.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 +dependencies = [
 + "compiler_builtins",
 + "gimli",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "adler"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "alloc"
 +version = "0.0.0"
 +dependencies = [
 + "compiler_builtins",
 + "core",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "cc"
 +version = "1.0.73"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 +
 +[[package]]
 +name = "cfg-if"
 +version = "0.1.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "compiler_builtins"
- checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
++version = "0.1.72"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.121"
++checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff"
 +dependencies = [
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "core"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "dlmalloc"
 +version = "0.2.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a6fe28e0bf9357092740362502f5cc7955d8dc125ebda71dec72336c2e15c62e"
 +dependencies = [
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "fortanix-sgx-abi"
 +version = "0.3.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "getopts"
 +version = "0.2.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 +dependencies = [
 + "rustc-std-workspace-core",
 + "rustc-std-workspace-std",
 + "unicode-width",
 +]
 +
 +[[package]]
 +name = "gimli"
 +version = "0.25.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.12.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "hermit-abi"
 +version = "0.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
 +dependencies = [
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "libc"
- checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
++version = "0.2.124"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
 +dependencies = [
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.4.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "miniz_oxide"
 +version = "0.4.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
 +dependencies = [
 + "adler",
 + "autocfg",
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "object"
 +version = "0.26.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
 +dependencies = [
 + "compiler_builtins",
 + "memchr",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "panic_abort"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 +]
 +
 +[[package]]
 +name = "panic_unwind"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 + "unwind",
 +]
 +
 +[[package]]
 +name = "proc_macro"
 +version = "0.0.0"
 +dependencies = [
++ "core",
 + "std",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-alloc"
 +version = "1.99.0"
 +dependencies = [
 + "alloc",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-core"
 +version = "1.99.0"
 +dependencies = [
 + "core",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-std"
 +version = "1.99.0"
 +dependencies = [
 + "std",
 +]
 +
 +[[package]]
 +name = "std"
 +version = "0.0.0"
 +dependencies = [
 + "addr2line",
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "dlmalloc",
 + "fortanix-sgx-abi",
 + "hashbrown",
 + "hermit-abi",
 + "libc",
 + "miniz_oxide",
 + "object",
 + "panic_abort",
 + "panic_unwind",
 + "rustc-demangle",
 + "std_detect",
 + "unwind",
 + "wasi",
 +]
 +
 +[[package]]
 +name = "std_detect"
 +version = "0.1.5"
 +dependencies = [
 + "cfg-if",
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "sysroot"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "compiler_builtins",
 + "core",
 + "std",
 + "test",
 +]
 +
 +[[package]]
 +name = "test"
 +version = "0.0.0"
 +dependencies = [
 + "cfg-if",
 + "core",
 + "getopts",
 + "libc",
 + "panic_abort",
 + "panic_unwind",
 + "proc_macro",
 + "std",
 +]
 +
 +[[package]]
 +name = "unicode-width"
 +version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 + "rustc-std-workspace-std",
 +]
 +
 +[[package]]
 +name = "unwind"
 +version = "0.0.0"
 +dependencies = [
 + "cc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 +]
 +
 +[[package]]
 +name = "wasi"
 +version = "0.11.0+wasi-snapshot-preview1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b8f901d1ba176274185f3f6b6ea0ce427110c673
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,53 @@@
++// Copied from https://github.com/rust-lang/rust/blob/3fe3b89cd57229343eeca753fdd8c63d9b03c65c/src/test/ui/simd/intrinsic/float-minmax-pass.rs
++// run-pass
++// ignore-emscripten
++
++// Test that the simd_f{min,max} intrinsics produce the correct results.
++
++#![feature(repr_simd, platform_intrinsics)]
++#![allow(non_camel_case_types)]
++
++#[repr(simd)]
++#[derive(Copy, Clone, PartialEq, Debug)]
++struct f32x4(pub f32, pub f32, pub f32, pub f32);
++
++extern "platform-intrinsic" {
++    fn simd_fmin<T>(x: T, y: T) -> T;
++    fn simd_fmax<T>(x: T, y: T) -> T;
++}
++
++fn main() {
++    let x = f32x4(1.0, 2.0, 3.0, 4.0);
++    let y = f32x4(2.0, 1.0, 4.0, 3.0);
++
++    #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
++    let nan = f32::NAN;
++    // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit.
++    // See https://github.com/rust-lang/rust/issues/52746.
++    #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
++    let nan = f32::from_bits(f32::NAN.to_bits() - 1);
++
++    let n = f32x4(nan, nan, nan, nan);
++
++    unsafe {
++        let min0 = simd_fmin(x, y);
++        let min1 = simd_fmin(y, x);
++        assert_eq!(min0, min1);
++        let e = f32x4(1.0, 1.0, 3.0, 3.0);
++        assert_eq!(min0, e);
++        let minn = simd_fmin(x, n);
++        assert_eq!(minn, x);
++        let minn = simd_fmin(y, n);
++        assert_eq!(minn, y);
++
++        let max0 = simd_fmax(x, y);
++        let max1 = simd_fmax(y, x);
++        assert_eq!(max0, max1);
++        let e = f32x4(2.0, 2.0, 4.0, 4.0);
++        assert_eq!(max0, e);
++        let maxn = simd_fmax(x, n);
++        assert_eq!(maxn, x);
++        let maxn = simd_fmax(y, n);
++        assert_eq!(maxn, y);
++    }
++}
index 7efc8dc785a1912476b3d6e93e9f3f5896d6e39c,0000000000000000000000000000000000000000..8da705e0cb06dbf7f0232bdad8e9ab6f899636d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,647 -1,0 +1,657 @@@
-     pub pointer: *const T,
 +#![feature(
 +    no_core,
 +    lang_items,
 +    intrinsics,
 +    unboxed_closures,
 +    extern_types,
 +    decl_macro,
 +    rustc_attrs,
 +    transparent_unions,
 +    auto_traits,
 +    thread_local
 +)]
 +#![no_core]
 +#![allow(dead_code)]
 +
 +#[lang = "sized"]
 +pub trait Sized {}
 +
++#[lang = "destruct"]
++pub trait Destruct {}
++
 +#[lang = "unsize"]
 +pub trait Unsize<T: ?Sized> {}
 +
 +#[lang = "coerce_unsized"]
 +pub trait CoerceUnsized<T> {}
 +
 +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
 +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
 +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
 +
 +#[lang = "dispatch_from_dyn"]
 +pub trait DispatchFromDyn<T> {}
 +
 +// &T -> &U
 +impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
 +// &mut T -> &mut U
 +impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 +// *const T -> *const U
 +impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
 +// *mut T -> *mut U
 +impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
 +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
 +
 +#[lang = "receiver"]
 +pub trait Receiver {}
 +
 +impl<T: ?Sized> Receiver for &T {}
 +impl<T: ?Sized> Receiver for &mut T {}
 +impl<T: ?Sized> Receiver for Box<T> {}
 +
 +#[lang = "copy"]
 +pub unsafe trait Copy {}
 +
 +unsafe impl Copy for bool {}
 +unsafe impl Copy for u8 {}
 +unsafe impl Copy for u16 {}
 +unsafe impl Copy for u32 {}
 +unsafe impl Copy for u64 {}
 +unsafe impl Copy for u128 {}
 +unsafe impl Copy for usize {}
 +unsafe impl Copy for i8 {}
 +unsafe impl Copy for i16 {}
 +unsafe impl Copy for i32 {}
 +unsafe impl Copy for isize {}
 +unsafe impl Copy for f32 {}
 +unsafe impl Copy for f64 {}
 +unsafe impl Copy for char {}
 +unsafe impl<'a, T: ?Sized> Copy for &'a T {}
 +unsafe impl<T: ?Sized> Copy for *const T {}
 +unsafe impl<T: ?Sized> Copy for *mut T {}
 +unsafe impl<T: Copy> Copy for Option<T> {}
 +
 +#[lang = "sync"]
 +pub unsafe trait Sync {}
 +
 +unsafe impl Sync for bool {}
 +unsafe impl Sync for u8 {}
 +unsafe impl Sync for u16 {}
 +unsafe impl Sync for u32 {}
 +unsafe impl Sync for u64 {}
 +unsafe impl Sync for usize {}
 +unsafe impl Sync for i8 {}
 +unsafe impl Sync for i16 {}
 +unsafe impl Sync for i32 {}
 +unsafe impl Sync for isize {}
 +unsafe impl Sync for char {}
 +unsafe impl<'a, T: ?Sized> Sync for &'a T {}
 +unsafe impl Sync for [u8; 16] {}
 +
 +#[lang = "freeze"]
 +unsafe auto trait Freeze {}
 +
 +unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
 +unsafe impl<T: ?Sized> Freeze for *const T {}
 +unsafe impl<T: ?Sized> Freeze for *mut T {}
 +unsafe impl<T: ?Sized> Freeze for &T {}
 +unsafe impl<T: ?Sized> Freeze for &mut T {}
 +
 +#[lang = "structural_peq"]
 +pub trait StructuralPartialEq {}
 +
 +#[lang = "structural_teq"]
 +pub trait StructuralEq {}
 +
 +#[lang = "not"]
 +pub trait Not {
 +    type Output;
 +
 +    fn not(self) -> Self::Output;
 +}
 +
 +impl Not for bool {
 +    type Output = bool;
 +
 +    fn not(self) -> bool {
 +        !self
 +    }
 +}
 +
 +#[lang = "mul"]
 +pub trait Mul<RHS = Self> {
 +    type Output;
 +
 +    #[must_use]
 +    fn mul(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Mul for u8 {
 +    type Output = Self;
 +
 +    fn mul(self, rhs: Self) -> Self::Output {
 +        self * rhs
 +    }
 +}
 +
 +impl Mul for usize {
 +    type Output = Self;
 +
 +    fn mul(self, rhs: Self) -> Self::Output {
 +        self * rhs
 +    }
 +}
 +
 +#[lang = "add"]
 +pub trait Add<RHS = Self> {
 +    type Output;
 +
 +    fn add(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Add for u8 {
 +    type Output = Self;
 +
 +    fn add(self, rhs: Self) -> Self {
 +        self + rhs
 +    }
 +}
 +
 +impl Add for i8 {
 +    type Output = Self;
 +
 +    fn add(self, rhs: Self) -> Self {
 +        self + rhs
 +    }
 +}
 +
 +impl Add for usize {
 +    type Output = Self;
 +
 +    fn add(self, rhs: Self) -> Self {
 +        self + rhs
 +    }
 +}
 +
 +#[lang = "sub"]
 +pub trait Sub<RHS = Self> {
 +    type Output;
 +
 +    fn sub(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Sub for usize {
 +    type Output = Self;
 +
 +    fn sub(self, rhs: Self) -> Self {
 +        self - rhs
 +    }
 +}
 +
 +impl Sub for u8 {
 +    type Output = Self;
 +
 +    fn sub(self, rhs: Self) -> Self {
 +        self - rhs
 +    }
 +}
 +
 +impl Sub for i8 {
 +    type Output = Self;
 +
 +    fn sub(self, rhs: Self) -> Self {
 +        self - rhs
 +    }
 +}
 +
 +impl Sub for i16 {
 +    type Output = Self;
 +
 +    fn sub(self, rhs: Self) -> Self {
 +        self - rhs
 +    }
 +}
 +
 +#[lang = "rem"]
 +pub trait Rem<RHS = Self> {
 +    type Output;
 +
 +    fn rem(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Rem for usize {
 +    type Output = Self;
 +
 +    fn rem(self, rhs: Self) -> Self {
 +        self % rhs
 +    }
 +}
 +
 +#[lang = "bitor"]
 +pub trait BitOr<RHS = Self> {
 +    type Output;
 +
 +    #[must_use]
 +    fn bitor(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl BitOr for bool {
 +    type Output = bool;
 +
 +    fn bitor(self, rhs: bool) -> bool {
 +        self | rhs
 +    }
 +}
 +
 +impl<'a> BitOr<bool> for &'a bool {
 +    type Output = bool;
 +
 +    fn bitor(self, rhs: bool) -> bool {
 +        *self | rhs
 +    }
 +}
 +
 +#[lang = "eq"]
 +pub trait PartialEq<Rhs: ?Sized = Self> {
 +    fn eq(&self, other: &Rhs) -> bool;
 +    fn ne(&self, other: &Rhs) -> bool;
 +}
 +
 +impl PartialEq for u8 {
 +    fn eq(&self, other: &u8) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &u8) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for u16 {
 +    fn eq(&self, other: &u16) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &u16) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for u32 {
 +    fn eq(&self, other: &u32) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &u32) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +
 +impl PartialEq for u64 {
 +    fn eq(&self, other: &u64) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &u64) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for u128 {
 +    fn eq(&self, other: &u128) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &u128) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for usize {
 +    fn eq(&self, other: &usize) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &usize) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for i8 {
 +    fn eq(&self, other: &i8) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &i8) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for i32 {
 +    fn eq(&self, other: &i32) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &i32) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for isize {
 +    fn eq(&self, other: &isize) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &isize) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl PartialEq for char {
 +    fn eq(&self, other: &char) -> bool {
 +        (*self) == (*other)
 +    }
 +    fn ne(&self, other: &char) -> bool {
 +        (*self) != (*other)
 +    }
 +}
 +
 +impl<T: ?Sized> PartialEq for *const T {
 +    fn eq(&self, other: &*const T) -> bool {
 +        *self == *other
 +    }
 +    fn ne(&self, other: &*const T) -> bool {
 +        *self != *other
 +    }
 +}
 +
 +impl <T: PartialEq> PartialEq for Option<T> {
 +    fn eq(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (Some(lhs), Some(rhs)) => *lhs == *rhs,
 +            (None, None) => true,
 +            _ => false,
 +        }
 +    }
 +
 +    fn ne(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (Some(lhs), Some(rhs)) => *lhs != *rhs,
 +            (None, None) => false,
 +            _ => true,
 +        }
 +    }
 +}
 +
 +#[lang = "shl"]
 +pub trait Shl<RHS = Self> {
 +    type Output;
 +
 +    #[must_use]
 +    fn shl(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Shl for u128 {
 +    type Output = u128;
 +
 +    fn shl(self, rhs: u128) -> u128 {
 +        self << rhs
 +    }
 +}
 +
 +#[lang = "neg"]
 +pub trait Neg {
 +    type Output;
 +
 +    fn neg(self) -> Self::Output;
 +}
 +
 +impl Neg for i8 {
 +    type Output = i8;
 +
 +    fn neg(self) -> i8 {
 +        -self
 +    }
 +}
 +
 +impl Neg for i16 {
 +    type Output = i16;
 +
 +    fn neg(self) -> i16 {
 +        self
 +    }
 +}
 +
 +impl Neg for isize {
 +    type Output = isize;
 +
 +    fn neg(self) -> isize {
 +        -self
 +    }
 +}
 +
 +impl Neg for f32 {
 +    type Output = f32;
 +
 +    fn neg(self) -> f32 {
 +        -self
 +    }
 +}
 +
 +pub enum Option<T> {
 +    Some(T),
 +    None,
 +}
 +
 +pub use Option::*;
 +
 +#[lang = "phantom_data"]
 +pub struct PhantomData<T: ?Sized>;
 +
 +#[lang = "fn_once"]
 +#[rustc_paren_sugar]
 +pub trait FnOnce<Args> {
 +    #[lang = "fn_once_output"]
 +    type Output;
 +
 +    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 +}
 +
 +#[lang = "fn_mut"]
 +#[rustc_paren_sugar]
 +pub trait FnMut<Args>: FnOnce<Args> {
 +    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 +}
 +
 +#[lang = "panic"]
 +#[track_caller]
 +pub fn panic(_msg: &str) -> ! {
 +    unsafe {
 +        libc::puts("Panicking\n\0" as *const str as *const i8);
 +        intrinsics::abort();
 +    }
 +}
 +
 +#[lang = "panic_bounds_check"]
 +#[track_caller]
 +fn panic_bounds_check(index: usize, len: usize) -> ! {
 +    unsafe {
 +        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
 +        intrinsics::abort();
 +    }
 +}
 +
 +#[lang = "eh_personality"]
 +fn eh_personality() -> ! {
 +    loop {}
 +}
 +
 +#[lang = "drop_in_place"]
 +#[allow(unconditional_recursion)]
 +pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 +    // Code here does not matter - this is replaced by the
 +    // real drop glue by the compiler.
 +    drop_in_place(to_drop);
 +}
 +
 +#[lang = "deref"]
 +pub trait Deref {
 +    type Target: ?Sized;
 +
 +    fn deref(&self) -> &Self::Target;
 +}
 +
++#[repr(transparent)]
++#[rustc_layout_scalar_valid_range_start(1)]
++#[rustc_nonnull_optimization_guaranteed]
++pub struct NonNull<T: ?Sized>(pub *mut T);
++
++impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
++impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
++
 +pub struct Unique<T: ?Sized> {
++    pub pointer: NonNull<T>,
 +    pub _marker: PhantomData<T>,
 +}
 +
 +impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
-     libc::free(ptr.pointer as *mut u8);
 +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 +
 +#[lang = "owned_box"]
 +pub struct Box<T: ?Sized>(Unique<T>, ());
 +
 +impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
 +
 +impl<T: ?Sized> Drop for Box<T> {
 +    fn drop(&mut self) {
 +        // drop is currently performed by compiler.
 +    }
 +}
 +
 +impl<T> Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &**self
 +    }
 +}
 +
 +#[lang = "exchange_malloc"]
 +unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
 +    libc::malloc(size)
 +}
 +
 +#[lang = "box_free"]
 +unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, alloc: ()) {
++    libc::free(ptr.pointer.0 as *mut u8);
 +}
 +
 +#[lang = "drop"]
 +pub trait Drop {
 +    fn drop(&mut self);
 +}
 +
 +#[lang = "manually_drop"]
 +#[repr(transparent)]
 +pub struct ManuallyDrop<T: ?Sized> {
 +    pub value: T,
 +}
 +
 +#[lang = "maybe_uninit"]
 +#[repr(transparent)]
 +pub union MaybeUninit<T> {
 +    pub uninit: (),
 +    pub value: ManuallyDrop<T>,
 +}
 +
 +pub mod intrinsics {
 +    extern "rust-intrinsic" {
 +        pub fn abort() -> !;
 +        pub fn size_of<T>() -> usize;
 +        pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
 +        pub fn min_align_of<T>() -> usize;
 +        pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
 +        pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 +        pub fn transmute<T, U>(e: T) -> U;
 +        pub fn ctlz_nonzero<T>(x: T) -> T;
 +        pub fn needs_drop<T>() -> bool;
 +        pub fn bitreverse<T>(x: T) -> T;
 +        pub fn bswap<T>(x: T) -> T;
 +        pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 +    }
 +}
 +
 +pub mod libc {
 +    #[cfg_attr(unix, link(name = "c"))]
 +    #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
 +    extern "C" {
 +        pub fn puts(s: *const i8) -> i32;
 +        pub fn printf(format: *const i8, ...) -> i32;
 +        pub fn malloc(size: usize) -> *mut u8;
 +        pub fn free(ptr: *mut u8);
 +        pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
 +        pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
 +        pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
 +    }
 +}
 +
 +#[lang = "index"]
 +pub trait Index<Idx: ?Sized> {
 +    type Output: ?Sized;
 +    fn index(&self, index: Idx) -> &Self::Output;
 +}
 +
 +impl<T> Index<usize> for [T; 3] {
 +    type Output = T;
 +
 +    fn index(&self, index: usize) -> &Self::Output {
 +        &self[index]
 +    }
 +}
 +
 +impl<T> Index<usize> for [T] {
 +    type Output = T;
 +
 +    fn index(&self, index: usize) -> &Self::Output {
 +        &self[index]
 +    }
 +}
 +
 +extern {
 +    type VaListImpl;
 +}
 +
 +#[lang = "va_list"]
 +#[repr(transparent)]
 +pub struct VaList<'a>(&'a mut VaListImpl);
 +
 +#[rustc_builtin_macro]
 +#[rustc_macro_transparency = "semitransparent"]
 +pub macro stringify($($t:tt)*) { /* compiler built-in */ }
 +
 +#[rustc_builtin_macro]
 +#[rustc_macro_transparency = "semitransparent"]
 +pub macro file() { /* compiler built-in */ }
 +
 +#[rustc_builtin_macro]
 +#[rustc_macro_transparency = "semitransparent"]
 +pub macro line() { /* compiler built-in */ }
 +
 +#[rustc_builtin_macro]
 +#[rustc_macro_transparency = "semitransparent"]
 +pub macro cfg() { /* compiler built-in */ }
 +
 +#[rustc_builtin_macro]
 +#[rustc_macro_transparency = "semitransparent"]
 +pub macro global_asm() { /* compiler built-in */ }
 +
 +pub static A_STATIC: u8 = 42;
 +
 +#[lang = "panic_location"]
 +struct PanicLocation {
 +    file: &'static str,
 +    line: u32,
 +    column: u32,
 +}
 +
 +#[no_mangle]
 +#[cfg(not(windows))]
 +pub fn get_tls() -> u8 {
 +    #[thread_local]
 +    static A: u8 = 42;
 +
 +    A
 +}
index c4730581335ecbffa29d3c58fc1cfc187b052b86,0000000000000000000000000000000000000000..85ca908d0a266f2e1012ea4d166d1068d7e538dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,466 -1,0 +1,466 @@@
-         pointer: 0 as *const (),
 +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)]
 +#![no_core]
 +#![allow(dead_code, non_camel_case_types)]
 +
 +extern crate mini_core;
 +
 +use mini_core::*;
 +use mini_core::libc::*;
 +
 +macro_rules! assert {
 +    ($e:expr) => {
 +        if !$e {
 +            panic(stringify!(! $e));
 +        }
 +    };
 +}
 +
 +macro_rules! assert_eq {
 +    ($l:expr, $r: expr) => {
 +        if $l != $r {
 +            panic(stringify!($l != $r));
 +        }
 +    }
 +}
 +
 +#[lang = "termination"]
 +trait Termination {
 +    fn report(self) -> i32;
 +}
 +
 +impl Termination for () {
 +    fn report(self) -> i32 {
 +        unsafe {
 +            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
 +            assert_eq!(*NUM_REF as i32, 44);
 +        }
 +        0
 +    }
 +}
 +
 +trait SomeTrait {
 +    fn object_safe(&self);
 +}
 +
 +impl SomeTrait for &'static str {
 +    fn object_safe(&self) {
 +        unsafe {
 +            puts(*self as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +struct NoisyDrop {
 +    text: &'static str,
 +    inner: NoisyDropInner,
 +}
 +
 +struct NoisyDropInner;
 +
 +impl Drop for NoisyDrop {
 +    fn drop(&mut self) {
 +        unsafe {
 +            puts(self.text as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +impl Drop for NoisyDropInner {
 +    fn drop(&mut self) {
 +        unsafe {
 +            puts("Inner got dropped!\0" as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +impl SomeTrait for NoisyDrop {
 +    fn object_safe(&self) {}
 +}
 +
 +enum Ordering {
 +    Less = -1,
 +    Equal = 0,
 +    Greater = 1,
 +}
 +
 +#[lang = "start"]
 +fn start<T: Termination + 'static>(
 +    main: fn() -> T,
 +    argc: isize,
 +    argv: *const *const u8,
 +) -> isize {
 +    if argc == 3 {
 +        unsafe { puts(*argv as *const i8); }
 +        unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); }
 +        unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
 +    }
 +
 +    main().report() as isize
 +}
 +
 +static mut NUM: u8 = 6 * 7;
 +static NUM_REF: &'static u8 = unsafe { &NUM };
 +
 +
 +unsafe fn zeroed<T>() -> T {
 +    let mut uninit = MaybeUninit { uninit: () };
 +    intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
 +    uninit.value.value
 +}
 +
 +fn take_f32(_f: f32) {}
 +fn take_unique(_u: Unique<()>) {}
 +
 +fn return_u128_pair() -> (u128, u128) {
 +    (0, 0)
 +}
 +
 +fn call_return_u128_pair() {
 +    return_u128_pair();
 +}
 +
 +#[allow(unreachable_code)] // FIXME false positive
 +fn main() {
 +    take_unique(Unique {
-             pointer: 0 as *const &str,
++        pointer: unsafe { NonNull(1 as *mut ()) },
 +        _marker: PhantomData,
 +    });
 +    take_f32(0.1);
 +
 +    call_return_u128_pair();
 +
 +    let slice = &[0, 1] as &[i32];
 +    let slice_ptr = slice as *const [i32] as *const i32;
 +
 +    assert_eq!(slice_ptr as usize % 4, 0);
 +
 +    //return;
 +
 +    unsafe {
 +        printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
 +
 +        let hello: &[u8] = b"Hello\0" as &[u8; 6];
 +        let ptr: *const i8 = hello as *const [u8] as *const i8;
 +        puts(ptr);
 +
 +        let world: Box<&str> = box "World!\0";
 +        puts(*world as *const str as *const i8);
 +        world as Box<dyn SomeTrait>;
 +
 +        assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
 +
 +        assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
 +        assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
 +        assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32);
 +        assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64);
 +
 +        assert_eq!(intrinsics::size_of_val(hello) as u8, 6);
 +
 +        let chars = &['C', 'h', 'a', 'r', 's'];
 +        let chars = chars as &[char];
 +        assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5);
 +
 +        let a: &dyn SomeTrait = &"abc\0";
 +        a.object_safe();
 +
 +        assert_eq!(intrinsics::size_of_val(a) as u8, 16);
 +        assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
 +
 +        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
 +        assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
 +
 +        assert!(!intrinsics::needs_drop::<u8>());
 +        assert!(intrinsics::needs_drop::<NoisyDrop>());
 +
 +        Unique {
++            pointer: NonNull(1 as *mut &str),
 +            _marker: PhantomData,
 +        } as Unique<dyn SomeTrait>;
 +
 +        struct MyDst<T: ?Sized>(T);
 +
 +        intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>);
 +
 +        struct Foo {
 +            x: u8,
 +            y: !,
 +        }
 +
 +        unsafe fn uninitialized<T>() -> T {
 +            MaybeUninit { uninit: () }.value.value
 +        }
 +
 +        zeroed::<(u8, u8)>();
 +        #[allow(unreachable_code)]
 +        {
 +            if false {
 +                zeroed::<!>();
 +                zeroed::<Foo>();
 +                uninitialized::<Foo>();
 +            }
 +        }
 +    }
 +
 +    let _ = box NoisyDrop {
 +        text: "Boxed outer got dropped!\0",
 +        inner: NoisyDropInner,
 +    } as Box<dyn SomeTrait>;
 +
 +    const FUNC_REF: Option<fn()> = Some(main);
 +    match FUNC_REF {
 +        Some(_) => {},
 +        None => assert!(false),
 +    }
 +
 +    match Ordering::Less {
 +        Ordering::Less => {},
 +        _ => assert!(false),
 +    }
 +
 +    [NoisyDropInner, NoisyDropInner];
 +
 +    let x = &[0u32, 42u32] as &[u32];
 +    match x {
 +        [] => assert_eq!(0u32, 1),
 +        [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize),
 +    }
 +
 +    assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
 +
 +    #[cfg(not(any(jit, windows)))]
 +    {
 +        extern {
 +            #[linkage = "extern_weak"]
 +            static ABC: *const u8;
 +        }
 +
 +        {
 +            extern {
 +                #[linkage = "extern_weak"]
 +                static ABC: *const u8;
 +            }
 +        }
 +
 +        unsafe { assert_eq!(ABC as usize, 0); }
 +    }
 +
 +    &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
 +
 +    let f = 1000.0;
 +    assert_eq!(f as u8, 255);
 +    let f2 = -1000.0;
 +    assert_eq!(f2 as i8, -128);
 +    assert_eq!(f2 as u8, 0);
 +
 +    let amount = 0;
 +    assert_eq!(1u128 << amount, 1);
 +
 +    static ANOTHER_STATIC: &u8 = &A_STATIC;
 +    assert_eq!(*ANOTHER_STATIC, 42);
 +
 +    check_niche_behavior();
 +
 +    extern "C" {
 +        type ExternType;
 +    }
 +
 +    struct ExternTypeWrapper {
 +        _a: ExternType,
 +    }
 +
 +    let nullptr = 0 as *const ();
 +    let extern_nullptr = nullptr as *const ExternTypeWrapper;
 +    extern_nullptr as *const ();
 +    let slice_ptr = &[] as *const [u8];
 +    slice_ptr as *const u8;
 +
 +    let repeat = [Some(42); 2];
 +    assert_eq!(repeat[0], Some(42));
 +    assert_eq!(repeat[1], Some(42));
 +
 +    from_decimal_string();
 +
 +    #[cfg(not(any(jit, windows)))]
 +    test_tls();
 +
 +    #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +    unsafe {
 +        global_asm_test();
 +    }
 +
 +    // Both statics have a reference that points to the same anonymous allocation.
 +    static REF1: &u8 = &42;
 +    static REF2: &u8 = REF1;
 +    assert_eq!(*REF1, *REF2);
 +}
 +
 +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +extern "C" {
 +    fn global_asm_test();
 +}
 +
 +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +global_asm! {
 +    "
 +    .global global_asm_test
 +    global_asm_test:
 +    // comment that would normally be removed by LLVM
 +    ret
 +    "
 +}
 +
 +#[repr(C)]
 +enum c_void {
 +    _1,
 +    _2,
 +}
 +
 +type c_int = i32;
 +type c_ulong = u64;
 +
 +type pthread_t = c_ulong;
 +
 +#[repr(C)]
 +struct pthread_attr_t {
 +    __size: [u64; 7],
 +}
 +
 +#[link(name = "pthread")]
 +extern "C" {
 +    fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
 +
 +    fn pthread_create(
 +        native: *mut pthread_t,
 +        attr: *const pthread_attr_t,
 +        f: extern "C" fn(_: *mut c_void) -> *mut c_void,
 +        value: *mut c_void
 +    ) -> c_int;
 +
 +    fn pthread_join(
 +        native: pthread_t,
 +        value: *mut *mut c_void
 +    ) -> c_int;
 +}
 +
 +#[thread_local]
 +#[cfg(not(jit))]
 +static mut TLS: u8 = 42;
 +
 +#[cfg(not(jit))]
 +extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
 +    unsafe { TLS = 0; }
 +    0 as *mut c_void
 +}
 +
 +#[cfg(not(jit))]
 +fn test_tls() {
 +    unsafe {
 +        let mut attr: pthread_attr_t = zeroed();
 +        let mut thread: pthread_t = 0;
 +
 +        assert_eq!(TLS, 42);
 +
 +        if pthread_attr_init(&mut attr) != 0 {
 +            assert!(false);
 +        }
 +
 +        if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
 +            assert!(false);
 +        }
 +
 +        let mut res = 0 as *mut c_void;
 +        pthread_join(thread, &mut res);
 +
 +        // TLS of main thread must not have been changed by the other thread.
 +        assert_eq!(TLS, 42);
 +
 +        puts("TLS works!\n\0" as *const str as *const i8);
 +    }
 +}
 +
 +// Copied ui/issues/issue-61696.rs
 +
 +pub enum Infallible {}
 +
 +// The check that the `bool` field of `V1` is encoding a "niche variant"
 +// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect,
 +// causing valid `V1` values to be interpreted as other variants.
 +pub enum E1 {
 +    V1 { f: bool },
 +    V2 { f: Infallible },
 +    V3,
 +    V4,
 +}
 +
 +// Computing the discriminant used to be done using the niche type (here `u8`,
 +// from the `bool` field of `V1`), overflowing for variants with large enough
 +// indices (`V3` and `V4`), causing them to be interpreted as other variants.
 +pub enum E2<X> {
 +    V1 { f: bool },
 +
 +    /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
 +    _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
 +    _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
 +    _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
 +    _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
 +    _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
 +    _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
 +    _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
 +    _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
 +    _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
 +    _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
 +    _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
 +    _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
 +    _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
 +    _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
 +    _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
 +    _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
 +    _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
 +    _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
 +    _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
 +    _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
 +    _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
 +    _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
 +    _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
 +    _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
 +    _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
 +    _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
 +    _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
 +    _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
 +    _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
 +    _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
 +    _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
 +
 +    V3,
 +    V4,
 +}
 +
 +fn check_niche_behavior () {
 +    if let E1::V2 { .. } = (E1::V1 { f: true }) {
 +        intrinsics::abort();
 +    }
 +
 +    if let E2::V1 { .. } = E2::V3::<Infallible> {
 +        intrinsics::abort();
 +    }
 +}
 +
 +fn from_decimal_string() {
 +    loop {
 +        let multiplier = 1;
 +
 +        take_multiplier_ref(&multiplier);
 +
 +        if multiplier == 1 {
 +            break;
 +        }
 +
 +        unreachable();
 +    }
 +}
 +
 +fn take_multiplier_ref(_multiplier: &u128) {}
 +
 +fn unreachable() -> ! {
 +    panic("unreachable")
 +}
index 5bc51a541b58c7d63b0939976ab2d8869983d24b,0000000000000000000000000000000000000000..0a2bce2621d963f1e6d68e173c5f65522c108a89
mode 100644,000000..100644
--- /dev/null
@@@ -1,333 -1,0 +1,337 @@@
- #![feature(core_intrinsics, generators, generator_trait, is_sorted)]
++#![feature(core_intrinsics, generators, generator_trait, is_sorted, bench_black_box)]
 +
 +#[cfg(target_arch = "x86_64")]
 +use std::arch::x86_64::*;
++use std::hint::black_box;
 +use std::io::Write;
 +use std::ops::Generator;
 +
 +fn main() {
 +    println!("{:?}", std::env::args().collect::<Vec<_>>());
 +
 +    let mutex = std::sync::Mutex::new(());
 +    let _guard = mutex.lock().unwrap();
 +
 +    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
 +    let stderr = ::std::io::stderr();
 +    let mut stderr = stderr.lock();
 +
 +    std::thread::spawn(move || {
 +        println!("Hello from another thread!");
 +    });
 +
 +    writeln!(stderr, "some {} text", "<unknown>").unwrap();
 +
 +    let _ = std::process::Command::new("true").env("c", "d").spawn();
 +
 +    println!("cargo:rustc-link-lib=z");
 +
 +    static ONCE: std::sync::Once = std::sync::Once::new();
 +    ONCE.call_once(|| {});
 +
 +    let _eq = LoopState::Continue(()) == LoopState::Break(());
 +
 +    // Make sure ByValPair values with differently sized components are correctly passed
 +    map(None::<(u8, Box<Instruction>)>);
 +
 +    println!("{}", 2.3f32.exp());
 +    println!("{}", 2.3f32.exp2());
 +    println!("{}", 2.3f32.abs());
 +    println!("{}", 2.3f32.sqrt());
 +    println!("{}", 2.3f32.floor());
 +    println!("{}", 2.3f32.ceil());
 +    println!("{}", 2.3f32.min(1.0));
 +    println!("{}", 2.3f32.max(1.0));
 +    println!("{}", 2.3f32.powi(2));
 +    println!("{}", 2.3f32.log2());
 +    assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
 +    println!("{}", 2.3f32.powf(2.0));
 +
 +    assert_eq!(i64::MAX.checked_mul(2), None);
 +
 +    assert_eq!(-128i8, (-128i8).saturating_sub(1));
 +    assert_eq!(127i8, 127i8.saturating_sub(-128));
 +    assert_eq!(-128i8, (-128i8).saturating_add(-128));
 +    assert_eq!(127i8, 127i8.saturating_add(1));
 +
 +    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
 +    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
 +    assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128);
 +
 +    let _d = 0i128.checked_div(2i128);
 +    let _d = 0u128.checked_div(2u128);
 +    assert_eq!(1u128 + 2, 3);
 +
 +    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
 +    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
 +    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
 +
 +    let tmp = 353985398u128;
 +    assert_eq!(tmp * 932490u128, 330087843781020u128);
 +
 +    let tmp = -0x1234_5678_9ABC_DEF0i64;
 +    assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
 +
 +    // Check that all u/i128 <-> float casts work correctly.
 +    let houndred_u128 = 100u128;
 +    let houndred_i128 = 100i128;
 +    let houndred_f32 = 100.0f32;
 +    let houndred_f64 = 100.0f64;
 +    assert_eq!(houndred_u128 as f32, 100.0);
 +    assert_eq!(houndred_u128 as f64, 100.0);
 +    assert_eq!(houndred_f32 as u128, 100);
 +    assert_eq!(houndred_f64 as u128, 100);
 +    assert_eq!(houndred_i128 as f32, 100.0);
 +    assert_eq!(houndred_i128 as f64, 100.0);
 +    assert_eq!(houndred_f32 as i128, 100);
 +    assert_eq!(houndred_f64 as i128, 100);
 +    assert_eq!(1u128.rotate_left(2), 4);
 +
++    assert_eq!(black_box(f32::NAN) as i128, 0);
++    assert_eq!(black_box(f32::NAN) as u128, 0);
++
 +    // Test signed 128bit comparing
 +    let max = usize::MAX as i128;
 +    if 100i128 < 0i128 || 100i128 > max {
 +        panic!();
 +    }
 +
 +    test_checked_mul();
 +
 +    let _a = 1u32 << 2u8;
 +
 +    let empty: [i32; 0] = [];
 +    assert!(empty.is_sorted());
 +
 +    println!("{:?}", std::intrinsics::caller_location());
 +
 +    #[cfg(target_arch = "x86_64")]
 +    unsafe {
 +        test_simd();
 +    }
 +
 +    Box::pin(move |mut _task_context| {
 +        yield ();
 +    }).as_mut().resume(0);
 +
 +    #[derive(Copy, Clone)]
 +    enum Nums {
 +        NegOne = -1,
 +    }
 +
 +    let kind = Nums::NegOne;
 +    assert_eq!(-1i128, kind as i128);
 +
 +    let options = [1u128];
 +    match options[0] {
 +        1 => (),
 +        0 => loop {},
 +        v => panic(v),
 +    };
 +}
 +
 +fn panic(_: u128) {
 +    panic!();
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_simd() {
 +    assert!(is_x86_feature_detected!("sse2"));
 +
 +    let x = _mm_setzero_si128();
 +    let y = _mm_set1_epi16(7);
 +    let or = _mm_or_si128(x, y);
 +    let cmp_eq = _mm_cmpeq_epi8(y, y);
 +    let cmp_lt = _mm_cmplt_epi8(y, y);
 +
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
 +
 +    test_mm_slli_si128();
 +    test_mm_movemask_epi8();
 +    test_mm256_movemask_epi8();
 +    test_mm_add_epi8();
 +    test_mm_add_pd();
 +    test_mm_cvtepi8_epi16();
 +    test_mm_cvtsi128_si64();
 +
 +    test_mm_extract_epi8();
 +    test_mm_insert_epi16();
 +
 +    let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
 +    assert_eq!(mask1, 1);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_slli_si128() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 1);
 +    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
 +    assert_eq_m128i(r, e);
 +
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 15);
 +    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
 +    assert_eq_m128i(r, e);
 +
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 16);
 +    assert_eq_m128i(r, _mm_set1_epi8(0));
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_movemask_epi8() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
 +        0b0101, 0b1111_0000u8 as i8, 0, 0,
 +        0, 0, 0b1111_0000u8 as i8, 0b0101,
 +        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
 +    );
 +    let r = _mm_movemask_epi8(a);
 +    assert_eq!(r, 0b10100100_00100101);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "avx2")]
 +unsafe fn test_mm256_movemask_epi8() {
 +    let a = _mm256_set1_epi8(-1);
 +    let r = _mm256_movemask_epi8(a);
 +    let e = -1;
 +    assert_eq!(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_add_epi8() {
 +    let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
 +    #[rustfmt::skip]
 +    let b = _mm_setr_epi8(
 +        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 +    );
 +    let r = _mm_add_epi8(a, b);
 +    #[rustfmt::skip]
 +    let e = _mm_setr_epi8(
 +        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
 +    );
 +    assert_eq_m128i(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_add_pd() {
 +    let a = _mm_setr_pd(1.0, 2.0);
 +    let b = _mm_setr_pd(5.0, 10.0);
 +    let r = _mm_add_pd(a, b);
 +    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
 +    unsafe {
 +        assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
 +    }
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
 +    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
 +        panic!("{:?} != {:?}", a, b);
 +    }
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_cvtsi128_si64() {
 +    let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
 +    assert_eq!(r, 5);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse4.1")]
 +unsafe fn test_mm_cvtepi8_epi16() {
 +    let a = _mm_set1_epi8(10);
 +    let r = _mm_cvtepi8_epi16(a);
 +    let e = _mm_set1_epi16(10);
 +    assert_eq_m128i(r, e);
 +    let a = _mm_set1_epi8(-10);
 +    let r = _mm_cvtepi8_epi16(a);
 +    let e = _mm_set1_epi16(-10);
 +    assert_eq_m128i(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse4.1")]
 +unsafe fn test_mm_extract_epi8() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        -1, 1, 2, 3, 4, 5, 6, 7,
 +        8, 9, 10, 11, 12, 13, 14, 15
 +    );
 +    let r1 = _mm_extract_epi8(a, 0);
 +    let r2 = _mm_extract_epi8(a, 3);
 +    assert_eq!(r1, 0xFF);
 +    assert_eq!(r2, 3);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_insert_epi16() {
 +    let a = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
 +    let r = _mm_insert_epi16(a, 9, 0);
 +    let e = _mm_setr_epi16(9, 1, 2, 3, 4, 5, 6, 7);
 +    assert_eq_m128i(r, e);
 +}
 +
 +fn test_checked_mul() {
 +    let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
 +    assert_eq!(u, None);
 +
 +    assert_eq!(1u8.checked_mul(255u8), Some(255u8));
 +    assert_eq!(255u8.checked_mul(255u8), None);
 +    assert_eq!(1i8.checked_mul(127i8), Some(127i8));
 +    assert_eq!(127i8.checked_mul(127i8), None);
 +    assert_eq!((-1i8).checked_mul(-127i8), Some(127i8));
 +    assert_eq!(1i8.checked_mul(-128i8), Some(-128i8));
 +    assert_eq!((-128i8).checked_mul(-128i8), None);
 +
 +    assert_eq!(1u64.checked_mul(u64::MAX), Some(u64::MAX));
 +    assert_eq!(u64::MAX.checked_mul(u64::MAX), None);
 +    assert_eq!(1i64.checked_mul(i64::MAX), Some(i64::MAX));
 +    assert_eq!(i64::MAX.checked_mul(i64::MAX), None);
 +    assert_eq!((-1i64).checked_mul(i64::MIN + 1), Some(i64::MAX));
 +    assert_eq!(1i64.checked_mul(i64::MIN), Some(i64::MIN));
 +    assert_eq!(i64::MIN.checked_mul(i64::MIN), None);
 +}
 +
 +#[derive(PartialEq)]
 +enum LoopState {
 +    Continue(()),
 +    Break(())
 +}
 +
 +pub enum Instruction {
 +    Increment,
 +    Loop,
 +}
 +
 +fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
 +    match a {
 +        None => None,
 +        Some((_, instr)) => Some(instr),
 +    }
 +}
index c13259086917b9c8e996dd8b88d7a142137a0bc5,0000000000000000000000000000000000000000..54e13b090abda43a8d66147207b16c09c27dae64
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,107 @@@
- diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
- index 31b7ee2..bd04b3c 100644
- --- a/crates/core_simd/tests/ops_macros.rs
- +++ b/crates/core_simd/tests/ops_macros.rs
- @@ -567,6 +567,7 @@ macro_rules! impl_float_tests {
-                      });
-                  }
-  
- +                /*
-                  fn horizontal_max<const LANES: usize>() {
-                      test_helpers::test_1(&|x| {
-                          let vmax = Vector::<LANES>::from_array(x).horizontal_max();
- @@ -590,6 +591,7 @@ macro_rules! impl_float_tests {
-                          Ok(())
-                      });
-                  }
- +                */
-              }
-  
-              #[cfg(feature = "std")]
- @@ -604,6 +606,7 @@ macro_rules! impl_float_tests {
-                          )
-                      }
-  
- +                    /*
-                      fn mul_add<const LANES: usize>() {
-                          test_helpers::test_ternary_elementwise(
-                              &Vector::<LANES>::mul_add,
- @@ -611,6 +614,7 @@ macro_rules! impl_float_tests {
-                              &|_, _, _| true,
-                          )
-                      }
- +                    */
-                  }
-              }
-          }
 +From 97c473937382a5b5858d9cce3c947855d23b2dc5 Mon Sep 17 00:00:00 2001
 +From: bjorn3 <bjorn3@users.noreply.github.com>
 +Date: Thu, 18 Nov 2021 19:28:40 +0100
 +Subject: [PATCH] Disable unsupported tests
 +
 +---
 + crates/core_simd/src/math.rs         | 6 ++++++
 + crates/core_simd/src/vector.rs       | 2 ++
 + crates/core_simd/tests/masks.rs      | 2 ++
 + crates/core_simd/tests/ops_macros.rs | 4 ++++
 + 4 files changed, 14 insertions(+)
 +
 +diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
 +index 2bae414..2f87499 100644
 +--- a/crates/core_simd/src/math.rs
 ++++ b/crates/core_simd/src/math.rs
 +@@ -5,6 +5,7 @@ macro_rules! impl_uint_arith {
 +     ($($ty:ty),+) => {
 +         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
 + 
 ++            /*
 +             /// Lanewise saturating add.
 +             ///
 +             /// # Examples
 +@@ -43,6 +44,7 @@ macro_rules! impl_uint_arith {
 +             pub fn saturating_sub(self, second: Self) -> Self {
 +                 unsafe { simd_saturating_sub(self, second) }
 +             }
 ++            */
 +         })+
 +     }
 + }
 +@@ -51,6 +53,7 @@ macro_rules! impl_int_arith {
 +     ($($ty:ty),+) => {
 +         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
 + 
 ++            /*
 +             /// Lanewise saturating add.
 +             ///
 +             /// # Examples
 +@@ -89,6 +92,7 @@ macro_rules! impl_int_arith {
 +             pub fn saturating_sub(self, second: Self) -> Self {
 +                 unsafe { simd_saturating_sub(self, second) }
 +             }
 ++            */
 + 
 +             /// Lanewise absolute value, implemented in Rust.
 +             /// Every lane becomes its absolute value.
 +@@ -109,6 +113,7 @@ macro_rules! impl_int_arith {
 +                 (self^m) - m
 +             }
 + 
 ++            /*
 +             /// Lanewise saturating absolute value, implemented in Rust.
 +             /// As abs(), except the MIN value becomes MAX instead of itself.
 +             ///
 +@@ -151,6 +156,7 @@ macro_rules! impl_int_arith {
 +             pub fn saturating_neg(self) -> Self {
 +                 Self::splat(0).saturating_sub(self)
 +             }
 ++            */
 +         })+
 +     }
 + }
 +diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
 +index 7c5ec2b..c8631e8 100644
 +--- a/crates/core_simd/src/vector.rs
 ++++ b/crates/core_simd/src/vector.rs
 +@@ -75,6 +75,7 @@ where
 +         Self(array)
 +     }
 + 
 ++    /*
 +     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
 +     /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
 +     ///
 +@@ -297,6 +298,7 @@ where
 +             // Cleared ☢️ *mut T Zone
 +         }
 +     }
 ++    */
 + }
 + 
 + impl<T, const LANES: usize> Copy for Simd<T, LANES>
 +diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
 +index 6a8ecd3..68fcb49 100644
 +--- a/crates/core_simd/tests/masks.rs
 ++++ b/crates/core_simd/tests/masks.rs
 +@@ -68,6 +68,7 @@ macro_rules! test_mask_api {
 +                 assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
 +             }
 + 
 ++            /*
 +             #[cfg(feature = "generic_const_exprs")]
 +             #[test]
 +             fn roundtrip_bitmask_conversion() {
 +@@ -80,6 +81,7 @@ macro_rules! test_mask_api {
 +                 assert_eq!(bitmask, [0b01001001, 0b10000011]);
 +                 assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
 +             }
 ++            */
 +         }
 +     }
 + }
 +-- 
 +2.26.2.7.g19db9cfb68
 +
index 84d90e5db02539c3edcc72c5fed578f41368e06c,0000000000000000000000000000000000000000..966097c248b6f6c98d6d250a369f5df0b8d797c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2022-03-19"
 +[toolchain]
++channel = "nightly-2022-04-21"
 +components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index a0e99267c2b705771b9c9cfee2e11a41c12a5cf1,0000000000000000000000000000000000000000..f4e863e5494b51f34154bfc0730cd9758e73b999
mode 100755,000000..100755
--- /dev/null
@@@ -1,126 -1,0 +1,126 @@@
- #!/bin/bash
++#!/usr/bin/env bash
 +#![forbid(unsafe_code)]/* This line is ignored by bash
 +# This block is ignored by rustc
 +pushd $(dirname "$0")/../
 +source scripts/config.sh
 +RUSTC="$(pwd)/build/bin/cg_clif"
 +popd
 +PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
 +#*/
 +
 +//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
 +//! profiles.
 +//!
 +//! Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>
 +//!
 +//! This file is specially crafted to be both a valid bash script and valid rust source file. If
 +//! executed as bash script this will run the rust source using cg_clif in JIT mode.
 +
 +use std::io::Write;
 +
 +fn main() -> Result<(), Box<dyn std::error::Error>> {
 +    let profile_name = std::env::var("PROFILE").unwrap();
 +    let output_name = std::env::var("OUTPUT").unwrap();
 +    if profile_name.is_empty() || output_name.is_empty() {
 +        println!("Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>");
 +        std::process::exit(1);
 +    }
 +    let profile = std::fs::read_to_string(profile_name)
 +        .map_err(|err| format!("Failed to read profile {}", err))?;
 +    let mut output = std::fs::OpenOptions::new()
 +        .create(true)
 +        .write(true)
 +        .truncate(true)
 +        .open(output_name)?;
 +
 +    for line in profile.lines() {
 +        let mut stack = &line[..line.rfind(" ").unwrap()];
 +        let count = &line[line.rfind(" ").unwrap() + 1..];
 +
 +        // Filter away uninteresting samples
 +        if !stack.contains("rustc_codegen_cranelift") {
 +            continue;
 +        }
 +
 +        if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items")
 +            || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph")
 +            || stack.contains("rustc_symbol_mangling::test::report_symbol_names")
 +        {
 +            continue;
 +        }
 +
 +        // Trim start
 +        if let Some(index) = stack.find("rustc_interface::passes::configure_and_expand") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::passes::analysis") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::passes::start_codegen") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::queries::Linker::link") {
 +            stack = &stack[index..];
 +        }
 +
 +        if let Some(index) = stack.find("rustc_codegen_cranelift::driver::aot::module_codegen") {
 +            stack = &stack[index..];
 +        }
 +
 +        // Trim end
 +        const MALLOC: &str = "malloc";
 +        if let Some(index) = stack.find(MALLOC) {
 +            stack = &stack[..index + MALLOC.len()];
 +        }
 +
 +        const FREE: &str = "free";
 +        if let Some(index) = stack.find(FREE) {
 +            stack = &stack[..index + FREE.len()];
 +        }
 +
 +        const TYPECK_ITEM_BODIES: &str = "rustc_typeck::check::typeck_item_bodies";
 +        if let Some(index) = stack.find(TYPECK_ITEM_BODIES) {
 +            stack = &stack[..index + TYPECK_ITEM_BODIES.len()];
 +        }
 +
 +        const COLLECT_AND_PARTITION_MONO_ITEMS: &str =
 +            "rustc_monomorphize::partitioning::collect_and_partition_mono_items";
 +        if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) {
 +            stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()];
 +        }
 +
 +        const ASSERT_DEP_GRAPH: &str = "rustc_incremental::assert_dep_graph::assert_dep_graph";
 +        if let Some(index) = stack.find(ASSERT_DEP_GRAPH) {
 +            stack = &stack[..index + ASSERT_DEP_GRAPH.len()];
 +        }
 +
 +        const REPORT_SYMBOL_NAMES: &str = "rustc_symbol_mangling::test::report_symbol_names";
 +        if let Some(index) = stack.find(REPORT_SYMBOL_NAMES) {
 +            stack = &stack[..index + REPORT_SYMBOL_NAMES.len()];
 +        }
 +
 +        const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata";
 +        if let Some(index) = stack.find(ENCODE_METADATA) {
 +            stack = &stack[..index + ENCODE_METADATA.len()];
 +        }
 +
 +        const SUBST_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::subst_and_normalize_erasing_regions";
 +        if let Some(index) = stack.find(SUBST_AND_NORMALIZE_ERASING_REGIONS) {
 +            stack = &stack[..index + SUBST_AND_NORMALIZE_ERASING_REGIONS.len()];
 +        }
 +
 +        const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_late_bound_regions";
 +        if let Some(index) = stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS) {
 +            stack = &stack[..index + NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()];
 +        }
 +
 +        const INST_BUILD: &str = "<cranelift_frontend::frontend::FuncInstBuilder as cranelift_codegen::ir::builder::InstBuilderBase>::build";
 +        if let Some(index) = stack.find(INST_BUILD) {
 +            stack = &stack[..index + INST_BUILD.len()];
 +        }
 +
 +        output.write_all(stack.as_bytes())?;
 +        output.write_all(&*b" ")?;
 +        output.write_all(count.as_bytes())?;
 +        output.write_all(&*b"\n")?;
 +    }
 +
 +    Ok(())
 +}
index 85c0109c6f61eb6932889a6cd667e0c31cd4f352,0000000000000000000000000000000000000000..cabbaaa8922517351dc70eeb3bb0730f752b0c17
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,80 @@@
- #!/bin/bash
++#!/usr/bin/env bash
 +set -e
 +
 +./y.rs build --no-unstable-features
 +source scripts/config.sh
 +
 +echo "[SETUP] Rust fork"
 +git clone https://github.com/rust-lang/rust.git || true
 +pushd rust
 +git fetch
 +git checkout -- .
 +git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 +
 +git apply - <<EOF
 +diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
 +index d95b5b7f17f..00b6f0e3635 100644
 +--- a/library/alloc/Cargo.toml
 ++++ b/library/alloc/Cargo.toml
 +@@ -8,7 +8,7 @@ edition = "2018"
 +
 + [dependencies]
 + core = { path = "../core" }
 +-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
 ++compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] }
 +
 + [dev-dependencies]
 + rand = "0.7"
 + rand_xorshift = "0.2"
 +diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
 +index 887d27fd6dca4..2c2239f2b83d1 100644
 +--- a/src/tools/compiletest/src/header.rs
 ++++ b/src/tools/compiletest/src/header.rs
 +@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
 +     cfg: Option<&str>,
 + ) -> test::TestDesc {
 +     let mut ignore = false;
 +     #[cfg(not(bootstrap))]
 +-    let ignore_message: Option<String> = None;
 ++    let ignore_message: Option<&str> = None;
 +     let mut should_fail = false;
 +
 +     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
 +
 +diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
 +index 8431aa7b818..a3ff7e68ce5 100644
 +--- a/src/tools/compiletest/src/runtest.rs
 ++++ b/src/tools/compiletest/src/runtest.rs
 +@@ -3489,11 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
 +             .join("library");
 +         normalize_path(&src_dir, "$(echo '$SRC_DIR')");
 +
 +-        if let Some(virtual_rust_source_base_dir) =
 +-            option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
 +-        {
 +-            normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
 +-        }
 ++        normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
 +
 +         // Paths into the build directory
 +         let test_build_dir = &self.config.build_base;
 +EOF
 +
 +cat > config.toml <<EOF
 +changelog-seen = 2
 +
 +[llvm]
 +ninja = false
 +
 +[build]
 +rustc = "$(pwd)/../build/bin/cg_clif"
 +cargo = "$(rustup which cargo)"
 +full-bootstrap = true
 +local-rebuild = true
 +
 +[rust]
 +codegen-backends = ["cranelift"]
 +deny-warnings = false
 +verbose-tests = false
 +EOF
 +popd
index a32e6df220832847efaef3e86f5dd1b402dc3d5f,0000000000000000000000000000000000000000..4cf24c02235df731a81e36def7900d4c9e390afd
mode 100755,000000..100755
--- /dev/null
@@@ -1,121 -1,0 +1,118 @@@
- #!/bin/bash
++#!/usr/bin/env bash
 +set -e
 +
 +cd $(dirname "$0")/../
 +
 +source ./scripts/setup_rust_fork.sh
 +
 +echo "[TEST] Test suite of rustc"
 +pushd rust
 +
 +command -v rg >/dev/null 2>&1 || cargo install ripgrep
 +
 +rm -r src/test/ui/{extern/,unsized-locals/,lto/,linkage*} || true
- for test in $(rg --files-with-matches "asm!|lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
++for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" src/test/{ui,incremental}); do
 +  rm $test
 +done
 +
 +for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do
 +  rm $test
 +done
 +
 +git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
 +
 +# missing features
 +# ================
 +
 +# requires stack unwinding
- rm src/test/ui/backtrace.rs
- rm src/test/ui/process/multi-panic.rs
- rm src/test/ui/numbers-arithmetic/issue-8460.rs
 +rm src/test/incremental/change_crate_dep_kind.rs
 +rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
- rm src/test/ui/panic-while-printing.rs
- rm src/test/ui/test-attrs/test-panic-while-printing.rs
- rm src/test/ui/test-attrs/test-type.rs
 +
 +# requires compiling with -Cpanic=unwind
 +rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process"
 +rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
 +rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
 +rm src/test/ui/generator/size-moved-locals.rs # same
 +
 +# vendor intrinsics
 +rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
 +rm src/test/ui/intrinsics/const-eval-select-x86_64.rs # requires x86_64 vendor intrinsics
 +rm src/test/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
 +rm src/test/ui/simd/intrinsic/generic-bitmask-pass.rs # simd_bitmask unimplemented
 +rm src/test/ui/simd/intrinsic/generic-as.rs # simd_as unimplemented
 +rm src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs # simd_saturating_add unimplemented
 +rm src/test/ui/simd/intrinsic/float-math-pass.rs # simd_fcos unimplemented
 +rm src/test/ui/simd/intrinsic/generic-gather-pass.rs # simd_gather unimplemented
 +rm src/test/ui/simd/intrinsic/generic-select-pass.rs # simd_select_bitmask unimplemented
 +rm src/test/ui/simd/issue-85915-simd-ptrs.rs # simd_gather unimplemented
 +rm src/test/ui/simd/issue-89193.rs # simd_gather unimplemented
 +rm src/test/ui/simd/simd-bitmask.rs # simd_bitmask unimplemented
 +
 +# exotic linkages
 +rm src/test/ui/issues/issue-33992.rs # unsupported linkages
 +rm src/test/incremental/hashes/function_interfaces.rs # same
 +rm src/test/incremental/hashes/statics.rs # same
 +
 +# variadic arguments
 +rm src/test/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
 +rm src/test/ui/abi/variadic-ffi.rs # requires callee side vararg support
 +
 +# unsized locals
 +rm -r src/test/run-pass-valgrind/unsized-locals
 +
 +# misc unimplemented things
 +rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics
 +rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented
 +rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 +rm -r src/test/run-make/emit-named-files # requires full --emit support
 +
 +# optimization tests
 +# ==================
 +rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
 +rm src/test/ui/codegen/init-large-type.rs # same
 +rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization
 +
 +# backend specific tests
 +# ======================
 +rm src/test/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
 +rm src/test/ui/abi/stack-protector.rs # requires stack protector support
 +
 +# giving different but possibly correct results
 +# =============================================
- rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
- rm src/test/ui/simd/intrinsic/float-minmax-pass.rs # same
 +rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 +rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
 +rm src/test/ui/consts/issue-33537.rs # same
 +
 +# doesn't work due to the way the rustc test suite is invoked.
 +# should work when using ./x.py test the way it is intended
 +# ============================================================
 +rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
 +rm -r src/test/run-make/unstable-flag-required # same
 +rm -r src/test/run-make/rustdoc-* # same
 +
 +# genuine bugs
 +# ============
 +rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
 +
 +rm -r src/test/ui/polymorphization/ # polymorphization not yet supported
 +rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same
 +
 +rm src/test/incremental/spike-neg1.rs # errors out for some reason
 +rm src/test/incremental/spike-neg2.rs # same
 +rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
 +rm src/test/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
 +
 +rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 +
++rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
++
 +# bugs in the test suite
 +# ======================
- rm src/test/ui/unsafe/union.rs # has UB caught by cg_clif. see rust-lang/rust#95075
++rm src/test/ui/backtrace.rs # TODO warning
++rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
++rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
++rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
 +
 +echo "[TEST] rustc test suite"
 +RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
 +popd
index fee1012c8f1dc4196df3f6e8293c75f24faa315d,0000000000000000000000000000000000000000..aae626081f62be5c93b3e7d92c08c811105c4d8f
mode 100755,000000..100755
--- /dev/null
@@@ -1,166 -1,0 +1,170 @@@
 +#!/usr/bin/env bash
 +
 +set -e
 +
 +source scripts/config.sh
 +source scripts/ext_config.sh
 +export RUSTC=false # ensure that cg_llvm isn't accidentally used
 +MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
 +
 +function no_sysroot_tests() {
 +    echo "[BUILD] mini_core"
 +    $MY_RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target "$TARGET_TRIPLE"
 +
 +    echo "[BUILD] example"
 +    $MY_RUSTC example/example.rs --crate-type lib --target "$TARGET_TRIPLE"
 +
 +    if [[ "$JIT_SUPPORTED" = "1" ]]; then
 +        echo "[JIT] mini_core_hello_world"
 +        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
 +
 +        echo "[JIT-lazy] mini_core_hello_world"
 +        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
 +    else
 +        echo "[JIT] mini_core_hello_world (skipped)"
 +    fi
 +
 +    echo "[AOT] mini_core_hello_world"
 +    $MY_RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
 +    # (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd
 +}
 +
 +function base_sysroot_tests() {
 +    echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
 +    $MY_RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
 +
 +    echo "[AOT] issue_91827_extern_types"
 +    $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/issue_91827_extern_types
 +
 +    echo "[AOT] alloc_system"
 +    $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
 +
 +    echo "[AOT] alloc_example"
 +    $MY_RUSTC example/alloc_example.rs --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/alloc_example
 +
 +    if [[ "$JIT_SUPPORTED" = "1" ]]; then
 +        echo "[JIT] std_example"
 +        $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
 +
 +        echo "[JIT-lazy] std_example"
 +        $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
 +    else
 +        echo "[JIT] std_example (skipped)"
 +    fi
 +
 +    echo "[AOT] dst_field_align"
 +    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
 +
 +    echo "[AOT] std_example"
 +    $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/std_example arg
 +
 +    echo "[AOT] subslice-patterns-const-eval"
 +    $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
 +
 +    echo "[AOT] track-caller-attribute"
 +    $MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/track-caller-attribute
 +
++    echo "[AOT] float-minmax-pass"
++    $MY_RUSTC example/float-minmax-pass.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
++    $RUN_WRAPPER ./target/out/float-minmax-pass
++
 +    echo "[AOT] mod_bench"
 +    $MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/mod_bench
 +}
 +
 +function extended_sysroot_tests() {
 +    pushd rand
 +    ../build/cargo-clif clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        echo "[TEST] rust-random/rand"
 +        ../build/cargo-clif test --workspace
 +    else
 +        echo "[AOT] rust-random/rand"
 +        ../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests
 +    fi
 +    popd
 +
 +    pushd simple-raytracer
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        echo "[BENCH COMPILE] ebobby/simple-raytracer"
 +        hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
 +        "RUSTC=rustc RUSTFLAGS='' cargo build" \
 +        "../build/cargo-clif build"
 +
 +        echo "[BENCH RUN] ebobby/simple-raytracer"
 +        cp ./target/debug/main ./raytracer_cg_clif
 +        hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif
 +    else
 +        ../build/cargo-clif clean
 +        echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
 +        echo "[COMPILE] ebobby/simple-raytracer"
 +        ../build/cargo-clif build --target $TARGET_TRIPLE
 +        echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
 +    fi
 +    popd
 +
 +    pushd build_sysroot/sysroot_src/library/core/tests
 +    echo "[TEST] libcore"
 +    ../../../../../build/cargo-clif clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        ../../../../../build/cargo-clif test
 +    else
 +        ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests
 +    fi
 +    popd
 +
 +    pushd regex
 +    echo "[TEST] rust-lang/regex example shootout-regex-dna"
 +    ../build/cargo-clif clean
 +    export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
 +    # Make sure `[codegen mono items] start` doesn't poison the diff
 +    ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        cat examples/regexdna-input.txt \
 +            | ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \
 +            | grep -v "Spawned thread" > res.txt
 +        diff -u res.txt examples/regexdna-output.txt
 +    fi
 +
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        echo "[TEST] rust-lang/regex tests"
 +        ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
 +    else
 +        echo "[AOT] rust-lang/regex tests"
 +        ../build/cargo-clif build --tests --target $TARGET_TRIPLE
 +    fi
 +    popd
 +
 +    pushd portable-simd
 +    echo "[TEST] rust-lang/portable-simd"
 +    ../build/cargo-clif clean
 +    ../build/cargo-clif build --all-targets --target $TARGET_TRIPLE
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        ../build/cargo-clif test -q
 +    fi
 +    popd
 +}
 +
 +case "$1" in
 +    "no_sysroot")
 +        no_sysroot_tests
 +        ;;
 +    "base_sysroot")
 +        base_sysroot_tests
 +        ;;
 +    "extended_sysroot")
 +        extended_sysroot_tests
 +        ;;
 +    *)
 +        echo "unknown test suite"
 +        ;;
 +esac
index 8c45993a8b76bf7e4a171be65c81def5e6e6025c,0000000000000000000000000000000000000000..65346cb39622aa0e7bc2a7de747820af62b3d519
mode 100644,000000..100644
--- /dev/null
@@@ -1,934 -1,0 +1,935 @@@
-                         .place_field(fx, Field::new(0)) // Unique<T> -> *const T
 +//! Codegen of a single function
 +
 +use rustc_ast::InlineAsmOptions;
 +use rustc_index::vec::IndexVec;
 +use rustc_middle::ty::adjustment::PointerCast;
 +use rustc_middle::ty::layout::FnAbiOf;
 +use rustc_middle::ty::print::with_no_trimmed_paths;
 +
 +use indexmap::IndexSet;
 +
 +use crate::constant::ConstantCx;
 +use crate::prelude::*;
 +use crate::pretty_clif::CommentWriter;
 +
 +pub(crate) fn codegen_fn<'tcx>(
 +    cx: &mut crate::CodegenCx<'tcx>,
 +    module: &mut dyn Module,
 +    instance: Instance<'tcx>,
 +) {
 +    let tcx = cx.tcx;
 +
 +    let _inst_guard =
 +        crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
 +    debug_assert!(!instance.substs.needs_infer());
 +
 +    let mir = tcx.instance_mir(instance.def);
 +    let _mir_guard = crate::PrintOnPanic(|| {
 +        let mut buf = Vec::new();
 +        with_no_trimmed_paths!({
 +            rustc_middle::mir::pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf)
 +                .unwrap();
 +        });
 +        String::from_utf8_lossy(&buf).into_owned()
 +    });
 +
 +    // Declare function
 +    let symbol_name = tcx.symbol_name(instance);
 +    let sig = get_function_sig(tcx, module.isa().triple(), instance);
 +    let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
 +
 +    cx.cached_context.clear();
 +
 +    // Make the FunctionBuilder
 +    let mut func_ctx = FunctionBuilderContext::new();
 +    let mut func = std::mem::replace(&mut cx.cached_context.func, Function::new());
 +    func.name = ExternalName::user(0, func_id.as_u32());
 +    func.signature = sig;
 +    func.collect_debug_info();
 +
 +    let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
 +
 +    // Predefine blocks
 +    let start_block = bcx.create_block();
 +    let block_map: IndexVec<BasicBlock, Block> =
 +        (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
 +
 +    // Make FunctionCx
 +    let target_config = module.target_config();
 +    let pointer_type = target_config.pointer_type();
 +    let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
 +
 +    let mut fx = FunctionCx {
 +        cx,
 +        module,
 +        tcx,
 +        target_config,
 +        pointer_type,
 +        constants_cx: ConstantCx::new(),
 +
 +        instance,
 +        symbol_name,
 +        mir,
 +        fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
 +
 +        bcx,
 +        block_map,
 +        local_map: IndexVec::with_capacity(mir.local_decls.len()),
 +        caller_location: None, // set by `codegen_fn_prelude`
 +
 +        clif_comments,
 +        source_info_set: indexmap::IndexSet::new(),
 +        next_ssa_var: 0,
 +    };
 +
 +    let arg_uninhabited = fx
 +        .mir
 +        .args_iter()
 +        .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
 +
 +    if !crate::constant::check_constants(&mut fx) {
 +        fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
 +        fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
 +        crate::trap::trap_unreachable(&mut fx, "compilation should have been aborted");
 +    } else if arg_uninhabited {
 +        fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
 +        fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
 +        fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +    } else {
 +        tcx.sess.time("codegen clif ir", || {
 +            tcx.sess
 +                .time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block));
 +            codegen_fn_content(&mut fx);
 +        });
 +    }
 +
 +    // Recover all necessary data from fx, before accessing func will prevent future access to it.
 +    let instance = fx.instance;
 +    let clif_comments = fx.clif_comments;
 +    let source_info_set = fx.source_info_set;
 +    let local_map = fx.local_map;
 +
 +    fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
 +
 +    crate::pretty_clif::write_clif_file(
 +        tcx,
 +        "unopt",
 +        module.isa(),
 +        instance,
 +        &func,
 +        &clif_comments,
 +    );
 +
 +    // Verify function
 +    verify_func(tcx, &clif_comments, &func);
 +
 +    compile_fn(
 +        cx,
 +        module,
 +        instance,
 +        symbol_name.name,
 +        func_id,
 +        func,
 +        clif_comments,
 +        source_info_set,
 +        local_map,
 +    );
 +}
 +
 +fn compile_fn<'tcx>(
 +    cx: &mut crate::CodegenCx<'tcx>,
 +    module: &mut dyn Module,
 +    instance: Instance<'tcx>,
 +    symbol_name: &str,
 +    func_id: FuncId,
 +    func: Function,
 +    mut clif_comments: CommentWriter,
 +    source_info_set: IndexSet<SourceInfo>,
 +    local_map: IndexVec<mir::Local, CPlace<'tcx>>,
 +) {
 +    let tcx = cx.tcx;
 +
 +    // Store function in context
 +    let context = &mut cx.cached_context;
 +    context.clear();
 +    context.func = func;
 +
 +    // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
 +    // instruction, which doesn't have an encoding.
 +    context.compute_cfg();
 +    context.compute_domtree();
 +    context.eliminate_unreachable_code(module.isa()).unwrap();
 +    context.dce(module.isa()).unwrap();
 +    // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
 +    // invalidate it when it would change.
 +    context.domtree.clear();
 +
 +    // Perform rust specific optimizations
 +    tcx.sess.time("optimize clif ir", || {
 +        crate::optimize::optimize_function(
 +            tcx,
 +            module.isa(),
 +            instance,
 +            context,
 +            &mut clif_comments,
 +        );
 +    });
 +
 +    // Define function
 +    tcx.sess.time("define function", || {
 +        context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
 +        module.define_function(func_id, context).unwrap()
 +    });
 +
 +    // Write optimized function to file for debugging
 +    crate::pretty_clif::write_clif_file(
 +        tcx,
 +        "opt",
 +        module.isa(),
 +        instance,
 +        &context.func,
 +        &clif_comments,
 +    );
 +
 +    if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
 +        crate::pretty_clif::write_ir_file(
 +            tcx,
 +            || format!("{}.vcode", tcx.symbol_name(instance).name),
 +            |file| file.write_all(disasm.as_bytes()),
 +        )
 +    }
 +
 +    // Define debuginfo for function
 +    let isa = module.isa();
 +    let debug_context = &mut cx.debug_context;
 +    let unwind_context = &mut cx.unwind_context;
 +    tcx.sess.time("generate debug info", || {
 +        if let Some(debug_context) = debug_context {
 +            debug_context.define_function(
 +                instance,
 +                func_id,
 +                symbol_name,
 +                isa,
 +                context,
 +                &source_info_set,
 +                local_map,
 +            );
 +        }
 +        unwind_context.add_function(func_id, &context, isa);
 +    });
 +}
 +
 +pub(crate) fn verify_func(
 +    tcx: TyCtxt<'_>,
 +    writer: &crate::pretty_clif::CommentWriter,
 +    func: &Function,
 +) {
 +    tcx.sess.time("verify clif ir", || {
 +        let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
 +        match cranelift_codegen::verify_function(&func, &flags) {
 +            Ok(_) => {}
 +            Err(err) => {
 +                tcx.sess.err(&format!("{:?}", err));
 +                let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
 +                    &func,
 +                    Some(Box::new(writer)),
 +                    err,
 +                );
 +                tcx.sess.fatal(&format!("cranelift verify error:\n{}", pretty_error));
 +            }
 +        }
 +    });
 +}
 +
 +fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
 +    for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
 +        let block = fx.get_block(bb);
 +        fx.bcx.switch_to_block(block);
 +
 +        if bb_data.is_cleanup {
 +            // Unwinding after panicking is not supported
 +            continue;
 +
 +            // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
 +            // so for cleanup blocks.
 +        }
 +
 +        fx.bcx.ins().nop();
 +        for stmt in &bb_data.statements {
 +            fx.set_debug_loc(stmt.source_info);
 +            codegen_stmt(fx, block, stmt);
 +        }
 +
 +        if fx.clif_comments.enabled() {
 +            let mut terminator_head = "\n".to_string();
 +            with_no_trimmed_paths!({
 +                bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
 +            });
 +            let inst = fx.bcx.func.layout.last_inst(block).unwrap();
 +            fx.add_comment(inst, terminator_head);
 +        }
 +
 +        let source_info = bb_data.terminator().source_info;
 +        fx.set_debug_loc(source_info);
 +
 +        match &bb_data.terminator().kind {
 +            TerminatorKind::Goto { target } => {
 +                if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
 +                    let mut can_immediately_return = true;
 +                    for stmt in &fx.mir[*target].statements {
 +                        if let StatementKind::StorageDead(_) = stmt.kind {
 +                        } else {
 +                            // FIXME Can sometimes happen, see rust-lang/rust#70531
 +                            can_immediately_return = false;
 +                            break;
 +                        }
 +                    }
 +
 +                    if can_immediately_return {
 +                        crate::abi::codegen_return(fx);
 +                        continue;
 +                    }
 +                }
 +
 +                let block = fx.get_block(*target);
 +                fx.bcx.ins().jump(block, &[]);
 +            }
 +            TerminatorKind::Return => {
 +                crate::abi::codegen_return(fx);
 +            }
 +            TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
 +                if !fx.tcx.sess.overflow_checks() {
 +                    if let mir::AssertKind::OverflowNeg(_) = *msg {
 +                        let target = fx.get_block(*target);
 +                        fx.bcx.ins().jump(target, &[]);
 +                        continue;
 +                    }
 +                }
 +                let cond = codegen_operand(fx, cond).load_scalar(fx);
 +
 +                let target = fx.get_block(*target);
 +                let failure = fx.bcx.create_block();
 +                fx.bcx.set_cold_block(failure);
 +
 +                if *expected {
 +                    fx.bcx.ins().brz(cond, failure, &[]);
 +                } else {
 +                    fx.bcx.ins().brnz(cond, failure, &[]);
 +                };
 +                fx.bcx.ins().jump(target, &[]);
 +
 +                fx.bcx.switch_to_block(failure);
 +                fx.bcx.ins().nop();
 +
 +                match msg {
 +                    AssertKind::BoundsCheck { ref len, ref index } => {
 +                        let len = codegen_operand(fx, len).load_scalar(fx);
 +                        let index = codegen_operand(fx, index).load_scalar(fx);
 +                        let location = fx.get_caller_location(source_info.span).load_scalar(fx);
 +
 +                        codegen_panic_inner(
 +                            fx,
 +                            rustc_hir::LangItem::PanicBoundsCheck,
 +                            &[index, len, location],
 +                            source_info.span,
 +                        );
 +                    }
 +                    _ => {
 +                        let msg_str = msg.description();
 +                        codegen_panic(fx, msg_str, source_info.span);
 +                    }
 +                }
 +            }
 +
 +            TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
 +                let discr = codegen_operand(fx, discr).load_scalar(fx);
 +
 +                let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
 +                    || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
 +                if use_bool_opt {
 +                    assert_eq!(targets.iter().count(), 1);
 +                    let (then_value, then_block) = targets.iter().next().unwrap();
 +                    let then_block = fx.get_block(then_block);
 +                    let else_block = fx.get_block(targets.otherwise());
 +                    let test_zero = match then_value {
 +                        0 => true,
 +                        1 => false,
 +                        _ => unreachable!("{:?}", targets),
 +                    };
 +
 +                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
 +                    let (discr, is_inverted) =
 +                        crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
 +                    let test_zero = if is_inverted { !test_zero } else { test_zero };
 +                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
 +                    if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
 +                        &fx.bcx, discr, test_zero,
 +                    ) {
 +                        if taken {
 +                            fx.bcx.ins().jump(then_block, &[]);
 +                        } else {
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        }
 +                    } else {
 +                        if test_zero {
 +                            fx.bcx.ins().brz(discr, then_block, &[]);
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        } else {
 +                            fx.bcx.ins().brnz(discr, then_block, &[]);
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        }
 +                    }
 +                } else {
 +                    let mut switch = ::cranelift_frontend::Switch::new();
 +                    for (value, block) in targets.iter() {
 +                        let block = fx.get_block(block);
 +                        switch.set_entry(value, block);
 +                    }
 +                    let otherwise_block = fx.get_block(targets.otherwise());
 +                    switch.emit(&mut fx.bcx, discr, otherwise_block);
 +                }
 +            }
 +            TerminatorKind::Call {
 +                func,
 +                args,
 +                destination,
 +                fn_span,
 +                cleanup: _,
 +                from_hir_call: _,
 +            } => {
 +                fx.tcx.sess.time("codegen call", || {
 +                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
 +                });
 +            }
 +            TerminatorKind::InlineAsm {
 +                template,
 +                operands,
 +                options,
 +                destination,
 +                line_spans: _,
 +                cleanup: _,
 +            } => {
 +                if options.contains(InlineAsmOptions::MAY_UNWIND) {
 +                    fx.tcx.sess.span_fatal(
 +                        source_info.span,
 +                        "cranelift doesn't support unwinding from inline assembly.",
 +                    );
 +                }
 +
 +                crate::inline_asm::codegen_inline_asm(
 +                    fx,
 +                    source_info.span,
 +                    template,
 +                    operands,
 +                    *options,
 +                );
 +
 +                match *destination {
 +                    Some(destination) => {
 +                        let destination_block = fx.get_block(destination);
 +                        fx.bcx.ins().jump(destination_block, &[]);
 +                    }
 +                    None => {
 +                        fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +                    }
 +                }
 +            }
 +            TerminatorKind::Resume | TerminatorKind::Abort => {
 +                // FIXME implement unwinding
 +                fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +            }
 +            TerminatorKind::Unreachable => {
 +                fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +            }
 +            TerminatorKind::Yield { .. }
 +            | TerminatorKind::FalseEdge { .. }
 +            | TerminatorKind::FalseUnwind { .. }
 +            | TerminatorKind::DropAndReplace { .. }
 +            | TerminatorKind::GeneratorDrop => {
 +                bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
 +            }
 +            TerminatorKind::Drop { place, target, unwind: _ } => {
 +                let drop_place = codegen_place(fx, *place);
 +                crate::abi::codegen_drop(fx, source_info.span, drop_place);
 +
 +                let target_block = fx.get_block(*target);
 +                fx.bcx.ins().jump(target_block, &[]);
 +            }
 +        };
 +    }
 +
 +    fx.bcx.seal_all_blocks();
 +    fx.bcx.finalize();
 +}
 +
 +fn codegen_stmt<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    #[allow(unused_variables)] cur_block: Block,
 +    stmt: &Statement<'tcx>,
 +) {
 +    let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt));
 +
 +    fx.set_debug_loc(stmt.source_info);
 +
 +    #[cfg(disabled)]
 +    match &stmt.kind {
 +        StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
 +        _ => {
 +            if fx.clif_comments.enabled() {
 +                let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
 +                fx.add_comment(inst, format!("{:?}", stmt));
 +            }
 +        }
 +    }
 +
 +    match &stmt.kind {
 +        StatementKind::SetDiscriminant { place, variant_index } => {
 +            let place = codegen_place(fx, **place);
 +            crate::discriminant::codegen_set_discriminant(fx, place, *variant_index);
 +        }
 +        StatementKind::Assign(to_place_and_rval) => {
 +            let lval = codegen_place(fx, to_place_and_rval.0);
 +            let dest_layout = lval.layout();
 +            match to_place_and_rval.1 {
 +                Rvalue::Use(ref operand) => {
 +                    let val = codegen_operand(fx, operand);
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
 +                    let place = codegen_place(fx, place);
 +                    let ref_ = place.place_ref(fx, lval.layout());
 +                    lval.write_cvalue(fx, ref_);
 +                }
 +                Rvalue::ThreadLocalRef(def_id) => {
 +                    let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout());
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::BinaryOp(bin_op, ref lhs_rhs) => {
 +                    let lhs = codegen_operand(fx, &lhs_rhs.0);
 +                    let rhs = codegen_operand(fx, &lhs_rhs.1);
 +
 +                    let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
 +                    let lhs = codegen_operand(fx, &lhs_rhs.0);
 +                    let rhs = codegen_operand(fx, &lhs_rhs.1);
 +
 +                    let res = if !fx.tcx.sess.overflow_checks() {
 +                        let val =
 +                            crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx);
 +                        let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
 +                        CValue::by_val_pair(val, is_overflow, lval.layout())
 +                    } else {
 +                        crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
 +                    };
 +
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::UnaryOp(un_op, ref operand) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let layout = operand.layout();
 +                    let val = operand.load_scalar(fx);
 +                    let res = match un_op {
 +                        UnOp::Not => match layout.ty.kind() {
 +                            ty::Bool => {
 +                                let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
 +                                CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
 +                            }
 +                            ty::Uint(_) | ty::Int(_) => {
 +                                CValue::by_val(fx.bcx.ins().bnot(val), layout)
 +                            }
 +                            _ => unreachable!("un op Not for {:?}", layout.ty),
 +                        },
 +                        UnOp::Neg => match layout.ty.kind() {
 +                            ty::Int(IntTy::I128) => {
 +                                // FIXME remove this case once ineg.i128 works
 +                                let zero =
 +                                    CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
 +                                crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
 +                            }
 +                            ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
 +                            ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
 +                            _ => unreachable!("un op Neg for {:?}", layout.ty),
 +                        },
 +                    };
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ReifyFnPointer),
 +                    ref operand,
 +                    to_ty,
 +                ) => {
 +                    let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx));
 +                    let to_layout = fx.layout_of(fx.monomorphize(to_ty));
 +                    match *from_ty.kind() {
 +                        ty::FnDef(def_id, substs) => {
 +                            let func_ref = fx.get_function_ref(
 +                                Instance::resolve_for_fn_ptr(
 +                                    fx.tcx,
 +                                    ParamEnv::reveal_all(),
 +                                    def_id,
 +                                    substs,
 +                                )
 +                                .unwrap()
 +                                .polymorphize(fx.tcx),
 +                            );
 +                            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
 +                            lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
 +                        }
 +                        _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty),
 +                    }
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::UnsafeFnPointer),
 +                    ref operand,
 +                    to_ty,
 +                )
 +                | Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::MutToConstPointer),
 +                    ref operand,
 +                    to_ty,
 +                )
 +                | Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ArrayToPointer),
 +                    ref operand,
 +                    to_ty,
 +                ) => {
 +                    let to_layout = fx.layout_of(fx.monomorphize(to_ty));
 +                    let operand = codegen_operand(fx, operand);
 +                    lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
 +                }
 +                Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let from_ty = operand.layout().ty;
 +                    let to_ty = fx.monomorphize(to_ty);
 +
 +                    fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
 +                        ty.builtin_deref(true)
 +                            .map(|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
 +                                has_ptr_meta(fx.tcx, pointee_ty)
 +                            })
 +                            .unwrap_or(false)
 +                    }
 +
 +                    if is_fat_ptr(fx, from_ty) {
 +                        if is_fat_ptr(fx, to_ty) {
 +                            // fat-ptr -> fat-ptr
 +                            lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
 +                        } else {
 +                            // fat-ptr -> thin-ptr
 +                            let (ptr, _extra) = operand.load_scalar_pair(fx);
 +                            lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
 +                        }
 +                    } else if let ty::Adt(adt_def, _substs) = from_ty.kind() {
 +                        // enum -> discriminant value
 +                        assert!(adt_def.is_enum());
 +                        match to_ty.kind() {
 +                            ty::Uint(_) | ty::Int(_) => {}
 +                            _ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
 +                        }
 +                        let to_clif_ty = fx.clif_type(to_ty).unwrap();
 +
 +                        let discriminant = crate::discriminant::codegen_get_discriminant(
 +                            fx,
 +                            operand,
 +                            fx.layout_of(operand.layout().ty.discriminant_ty(fx.tcx)),
 +                        )
 +                        .load_scalar(fx);
 +
 +                        let res = crate::cast::clif_intcast(
 +                            fx,
 +                            discriminant,
 +                            to_clif_ty,
 +                            to_ty.is_signed(),
 +                        );
 +                        lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
 +                    } else {
 +                        let to_clif_ty = fx.clif_type(to_ty).unwrap();
 +                        let from = operand.load_scalar(fx);
 +
 +                        let res = clif_int_or_float_cast(
 +                            fx,
 +                            from,
 +                            type_sign(from_ty),
 +                            to_clif_ty,
 +                            type_sign(to_ty),
 +                        );
 +                        lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
 +                    }
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
 +                    ref operand,
 +                    _to_ty,
 +                ) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    match *operand.layout().ty.kind() {
 +                        ty::Closure(def_id, substs) => {
 +                            let instance = Instance::resolve_closure(
 +                                fx.tcx,
 +                                def_id,
 +                                substs,
 +                                ty::ClosureKind::FnOnce,
 +                            )
 +                            .polymorphize(fx.tcx);
 +                            let func_ref = fx.get_function_ref(instance);
 +                            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
 +                            lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
 +                        }
 +                        _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty),
 +                    }
 +                }
 +                Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    operand.unsize_value(fx, lval);
 +                }
 +                Rvalue::Discriminant(place) => {
 +                    let place = codegen_place(fx, place);
 +                    let value = place.to_cvalue(fx);
 +                    let discr =
 +                        crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
 +                    lval.write_cvalue(fx, discr);
 +                }
 +                Rvalue::Repeat(ref operand, times) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let times = fx
 +                        .monomorphize(times)
 +                        .eval(fx.tcx, ParamEnv::reveal_all())
 +                        .val()
 +                        .try_to_bits(fx.tcx.data_layout.pointer_size)
 +                        .unwrap();
 +                    if operand.layout().size.bytes() == 0 {
 +                        // Do nothing for ZST's
 +                    } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
 +                        let times = fx.bcx.ins().iconst(fx.pointer_type, times as i64);
 +                        // FIXME use emit_small_memset where possible
 +                        let addr = lval.to_ptr().get_addr(fx);
 +                        let val = operand.load_scalar(fx);
 +                        fx.bcx.call_memset(fx.target_config, addr, val, times);
 +                    } else {
 +                        let loop_block = fx.bcx.create_block();
 +                        let loop_block2 = fx.bcx.create_block();
 +                        let done_block = fx.bcx.create_block();
 +                        let index = fx.bcx.append_block_param(loop_block, fx.pointer_type);
 +                        let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
 +                        fx.bcx.ins().jump(loop_block, &[zero]);
 +
 +                        fx.bcx.switch_to_block(loop_block);
 +                        let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64);
 +                        fx.bcx.ins().brnz(done, done_block, &[]);
 +                        fx.bcx.ins().jump(loop_block2, &[]);
 +
 +                        fx.bcx.switch_to_block(loop_block2);
 +                        let to = lval.place_index(fx, index);
 +                        to.write_cvalue(fx, operand);
 +                        let index = fx.bcx.ins().iadd_imm(index, 1);
 +                        fx.bcx.ins().jump(loop_block, &[index]);
 +
 +                        fx.bcx.switch_to_block(done_block);
 +                        fx.bcx.ins().nop();
 +                    }
 +                }
 +                Rvalue::Len(place) => {
 +                    let place = codegen_place(fx, place);
 +                    let usize_layout = fx.layout_of(fx.tcx.types.usize);
 +                    let len = codegen_array_len(fx, place);
 +                    lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
 +                }
 +                Rvalue::ShallowInitBox(ref operand, content_ty) => {
 +                    let content_ty = fx.monomorphize(content_ty);
 +                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
 +                    let operand = codegen_operand(fx, operand);
 +                    let operand = operand.load_scalar(fx);
 +                    lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
 +                }
 +                Rvalue::NullaryOp(null_op, ty) => {
 +                    assert!(
 +                        lval.layout()
 +                            .ty
 +                            .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
 +                    );
 +                    let layout = fx.layout_of(fx.monomorphize(ty));
 +                    let val = match null_op {
 +                        NullOp::SizeOf => layout.size.bytes(),
 +                        NullOp::AlignOf => layout.align.abi.bytes(),
 +                    };
 +                    let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() {
 +                    AggregateKind::Array(_ty) => {
 +                        for (i, operand) in operands.iter().enumerate() {
 +                            let operand = codegen_operand(fx, operand);
 +                            let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
 +                            let to = lval.place_index(fx, index);
 +                            to.write_cvalue(fx, operand);
 +                        }
 +                    }
 +                    _ => unreachable!("shouldn't exist at codegen {:?}", to_place_and_rval.1),
 +                },
 +            }
 +        }
 +        StatementKind::StorageLive(_)
 +        | StatementKind::StorageDead(_)
 +        | StatementKind::Deinit(_)
 +        | StatementKind::Nop
 +        | StatementKind::FakeRead(..)
 +        | StatementKind::Retag { .. }
 +        | StatementKind::AscribeUserType(..) => {}
 +
 +        StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
 +        StatementKind::CopyNonOverlapping(inner) => {
 +            let dst = codegen_operand(fx, &inner.dst);
 +            let pointee = dst
 +                .layout()
 +                .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
 +                .expect("Expected pointer");
 +            let dst = dst.load_scalar(fx);
 +            let src = codegen_operand(fx, &inner.src).load_scalar(fx);
 +            let count = codegen_operand(fx, &inner.count).load_scalar(fx);
 +            let elem_size: u64 = pointee.size.bytes();
 +            let bytes =
 +                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
 +            fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
 +        }
 +    }
 +}
 +
 +fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value {
 +    match *place.layout().ty.kind() {
 +        ty::Array(_elem_ty, len) => {
 +            let len = fx.monomorphize(len).eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
 +            fx.bcx.ins().iconst(fx.pointer_type, len)
 +        }
 +        ty::Slice(_elem_ty) => {
 +            place.to_ptr_maybe_unsized().1.expect("Length metadata for slice place")
 +        }
 +        _ => bug!("Rvalue::Len({:?})", place),
 +    }
 +}
 +
 +pub(crate) fn codegen_place<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    place: Place<'tcx>,
 +) -> CPlace<'tcx> {
 +    let mut cplace = fx.get_local_place(place.local);
 +
 +    for elem in place.projection {
 +        match elem {
 +            PlaceElem::Deref => {
 +                if cplace.layout().ty.is_box() {
 +                    cplace = cplace
 +                        .place_field(fx, Field::new(0)) // Box<T> -> Unique<T>
++                        .place_field(fx, Field::new(0)) // Unique<T> -> NonNull<T>
++                        .place_field(fx, Field::new(0)) // NonNull<T> -> *mut T
 +                        .place_deref(fx);
 +                } else {
 +                    cplace = cplace.place_deref(fx);
 +                }
 +            }
 +            PlaceElem::Field(field, _ty) => {
 +                cplace = cplace.place_field(fx, field);
 +            }
 +            PlaceElem::Index(local) => {
 +                let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx);
 +                cplace = cplace.place_index(fx, index);
 +            }
 +            PlaceElem::ConstantIndex { offset, min_length: _, from_end } => {
 +                let offset: u64 = offset;
 +                let index = if !from_end {
 +                    fx.bcx.ins().iconst(fx.pointer_type, offset as i64)
 +                } else {
 +                    let len = codegen_array_len(fx, cplace);
 +                    fx.bcx.ins().iadd_imm(len, -(offset as i64))
 +                };
 +                cplace = cplace.place_index(fx, index);
 +            }
 +            PlaceElem::Subslice { from, to, from_end } => {
 +                // These indices are generated by slice patterns.
 +                // slice[from:-to] in Python terms.
 +
 +                let from: u64 = from;
 +                let to: u64 = to;
 +
 +                match cplace.layout().ty.kind() {
 +                    ty::Array(elem_ty, _len) => {
 +                        assert!(!from_end, "array subslices are never `from_end`");
 +                        let elem_layout = fx.layout_of(*elem_ty);
 +                        let ptr = cplace.to_ptr();
 +                        cplace = CPlace::for_ptr(
 +                            ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
 +                            fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)),
 +                        );
 +                    }
 +                    ty::Slice(elem_ty) => {
 +                        assert!(from_end, "slice subslices should be `from_end`");
 +                        let elem_layout = fx.layout_of(*elem_ty);
 +                        let (ptr, len) = cplace.to_ptr_maybe_unsized();
 +                        let len = len.unwrap();
 +                        cplace = CPlace::for_ptr_with_extra(
 +                            ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
 +                            fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
 +                            cplace.layout(),
 +                        );
 +                    }
 +                    _ => unreachable!(),
 +                }
 +            }
 +            PlaceElem::Downcast(_adt_def, variant) => {
 +                cplace = cplace.downcast_variant(fx, variant);
 +            }
 +        }
 +    }
 +
 +    cplace
 +}
 +
 +pub(crate) fn codegen_operand<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    operand: &Operand<'tcx>,
 +) -> CValue<'tcx> {
 +    match operand {
 +        Operand::Move(place) | Operand::Copy(place) => {
 +            let cplace = codegen_place(fx, *place);
 +            cplace.to_cvalue(fx)
 +        }
 +        Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_),
 +    }
 +}
 +
 +pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
 +    let location = fx.get_caller_location(span).load_scalar(fx);
 +
 +    let msg_ptr = fx.anonymous_str(msg_str);
 +    let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
 +    let args = [msg_ptr, msg_len, location];
 +
 +    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span);
 +}
 +
 +pub(crate) fn codegen_panic_inner<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    lang_item: rustc_hir::LangItem,
 +    args: &[Value],
 +    span: Span,
 +) {
 +    let def_id =
 +        fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
 +
 +    let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
 +    let symbol_name = fx.tcx.symbol_name(instance).name;
 +
 +    fx.lib_call(
 +        &*symbol_name,
 +        vec![
 +            AbiParam::new(fx.pointer_type),
 +            AbiParam::new(fx.pointer_type),
 +            AbiParam::new(fx.pointer_type),
 +        ],
 +        vec![],
 +        args,
 +    );
 +
 +    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +}
index e7e6afeb865bb005bf436b7ec6e2802930dc7fe2,0000000000000000000000000000000000000000..e19070774c6e0c246662f55ed06e4cf5a53f17e0
mode 100644,000000..100644
--- /dev/null
@@@ -1,160 -1,0 +1,173 @@@
-         if to_ty == types::I128 {
 +//! Various number casting functions
 +
 +use crate::prelude::*;
 +
 +pub(crate) fn clif_intcast(
 +    fx: &mut FunctionCx<'_, '_, '_>,
 +    val: Value,
 +    to: Type,
 +    signed: bool,
 +) -> Value {
 +    let from = fx.bcx.func.dfg.value_type(val);
 +    match (from, to) {
 +        // equal
 +        (_, _) if from == to => val,
 +
 +        // extend
 +        (_, _) if to.wider_or_equal(from) => {
 +            if signed {
 +                fx.bcx.ins().sextend(to, val)
 +            } else {
 +                fx.bcx.ins().uextend(to, val)
 +            }
 +        }
 +
 +        // reduce
 +        (_, _) => fx.bcx.ins().ireduce(to, val),
 +    }
 +}
 +
 +pub(crate) fn clif_int_or_float_cast(
 +    fx: &mut FunctionCx<'_, '_, '_>,
 +    from: Value,
 +    from_signed: bool,
 +    to_ty: Type,
 +    to_signed: bool,
 +) -> Value {
 +    let from_ty = fx.bcx.func.dfg.value_type(from);
 +
 +    if from_ty.is_int() && to_ty.is_int() {
 +        // int-like -> int-like
 +        clif_intcast(
 +            fx,
 +            from,
 +            to_ty,
 +            // This is correct as either from_signed == to_signed (=> this is trivially correct)
 +            // Or from_clif_ty == to_clif_ty, which means this is a no-op.
 +            from_signed,
 +        )
 +    } else if from_ty.is_int() && to_ty.is_float() {
 +        if from_ty == types::I128 {
 +            // _______ss__f_
 +            // __float  tisf: i128 -> f32
 +            // __float  tidf: i128 -> f64
 +            // __floatuntisf: u128 -> f32
 +            // __floatuntidf: u128 -> f64
 +
 +            let name = format!(
 +                "__float{sign}ti{flt}f",
 +                sign = if from_signed { "" } else { "un" },
 +                flt = match to_ty {
 +                    types::F32 => "s",
 +                    types::F64 => "d",
 +                    _ => unreachable!("{:?}", to_ty),
 +                },
 +            );
 +
 +            let from_rust_ty = if from_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
 +
 +            let to_rust_ty = match to_ty {
 +                types::F32 => fx.tcx.types.f32,
 +                types::F64 => fx.tcx.types.f64,
 +                _ => unreachable!(),
 +            };
 +
 +            return fx
 +                .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
 +                .load_scalar(fx);
 +        }
 +
 +        // int-like -> float
 +        if from_signed {
 +            fx.bcx.ins().fcvt_from_sint(to_ty, from)
 +        } else {
 +            fx.bcx.ins().fcvt_from_uint(to_ty, from)
 +        }
 +    } else if from_ty.is_float() && to_ty.is_int() {
-             return fx
-                 .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
-                 .load_scalar(fx);
-         }
-         // float -> int-like
-         if to_ty == types::I8 || to_ty == types::I16 {
++        let val = if to_ty == types::I128 {
 +            // _____sssf___
 +            // __fix   sfti: f32 -> i128
 +            // __fix   dfti: f64 -> i128
 +            // __fixunssfti: f32 -> u128
 +            // __fixunsdfti: f64 -> u128
 +
 +            let name = format!(
 +                "__fix{sign}{flt}fti",
 +                sign = if to_signed { "" } else { "uns" },
 +                flt = match from_ty {
 +                    types::F32 => "s",
 +                    types::F64 => "d",
 +                    _ => unreachable!("{:?}", to_ty),
 +                },
 +            );
 +
 +            let from_rust_ty = match from_ty {
 +                types::F32 => fx.tcx.types.f32,
 +                types::F64 => fx.tcx.types.f64,
 +                _ => unreachable!(),
 +            };
 +
 +            let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
 +
++            fx.easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
++                .load_scalar(fx)
++        } else if to_ty == types::I8 || to_ty == types::I16 {
 +            // FIXME implement fcvt_to_*int_sat.i8/i16
 +            let val = if to_signed {
 +                fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
 +            } else {
 +                fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
 +            };
 +            let (min, max) = match (to_ty, to_signed) {
 +                (types::I8, false) => (0, i64::from(u8::MAX)),
 +                (types::I16, false) => (0, i64::from(u16::MAX)),
 +                (types::I8, true) => (i64::from(i8::MIN), i64::from(i8::MAX)),
 +                (types::I16, true) => (i64::from(i16::MIN), i64::from(i16::MAX)),
 +                _ => unreachable!(),
 +            };
 +            let min_val = fx.bcx.ins().iconst(types::I32, min);
 +            let max_val = fx.bcx.ins().iconst(types::I32, max);
 +
 +            let val = if to_signed {
 +                let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min);
 +                let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max);
 +                let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val);
 +                fx.bcx.ins().select(has_overflow, max_val, bottom_capped)
 +            } else {
 +                let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max);
 +                fx.bcx.ins().select(has_overflow, max_val, val)
 +            };
 +            fx.bcx.ins().ireduce(to_ty, val)
 +        } else if to_signed {
 +            fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
 +        } else {
 +            fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
++        };
++
++        if let Some(false) = fx.tcx.sess.opts.debugging_opts.saturating_float_casts {
++            return val;
++        }
++
++        let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
++        if to_ty == types::I128 {
++            // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles
++            let (lsb, msb) = fx.bcx.ins().isplit(val);
++            let zero = fx.bcx.ins().iconst(types::I64, 0);
++            let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero);
++            let msb = fx.bcx.ins().select(is_not_nan, msb, zero);
++            fx.bcx.ins().iconcat(lsb, msb)
++        } else {
++            let zero = fx.bcx.ins().iconst(to_ty, 0);
++            fx.bcx.ins().select(is_not_nan, val, zero)
 +        }
 +    } else if from_ty.is_float() && to_ty.is_float() {
 +        // float -> float
 +        match (from_ty, to_ty) {
 +            (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from),
 +            (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from),
 +            _ => from,
 +        }
 +    } else {
 +        unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);
 +    }
 +}
index eef3c8c8d6e2b38170209854f34c5c441ad59b5b,0000000000000000000000000000000000000000..e59a0cb0a23237bfe0b4fd0164909db4d8a98e49
mode 100644,000000..100644
--- /dev/null
@@@ -1,116 -1,0 +1,107 @@@
-     /// The register allocator to use.
-     ///
-     /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
-     /// `-Cllvm-args=regalloc=...`.
-     pub regalloc: String,
 +use std::env;
 +use std::str::FromStr;
 +
 +fn bool_env_var(key: &str) -> bool {
 +    env::var(key).as_ref().map(|val| &**val) == Ok("1")
 +}
 +
 +/// The mode to use for compilation.
 +#[derive(Copy, Clone, Debug)]
 +pub enum CodegenMode {
 +    /// AOT compile the crate. This is the default.
 +    Aot,
 +    /// JIT compile and execute the crate.
 +    Jit,
 +    /// JIT compile and execute the crate, but only compile functions the first time they are used.
 +    JitLazy,
 +}
 +
 +impl FromStr for CodegenMode {
 +    type Err = String;
 +
 +    fn from_str(s: &str) -> Result<Self, Self::Err> {
 +        match s {
 +            "aot" => Ok(CodegenMode::Aot),
 +            "jit" => Ok(CodegenMode::Jit),
 +            "jit-lazy" => Ok(CodegenMode::JitLazy),
 +            _ => Err(format!("Unknown codegen mode `{}`", s)),
 +        }
 +    }
 +}
 +
 +/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
 +#[derive(Clone, Debug)]
 +pub struct BackendConfig {
 +    /// Should the crate be AOT compiled or JIT executed.
 +    ///
 +    /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`.
 +    pub codegen_mode: CodegenMode,
 +
 +    /// When JIT mode is enable pass these arguments to the program.
 +    ///
 +    /// Defaults to the value of `CG_CLIF_JIT_ARGS`.
 +    pub jit_args: Vec<String>,
 +
 +    /// Display the time it took to perform codegen for a crate.
 +    ///
 +    /// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise.
 +    /// Can be set using `-Cllvm-args=display_cg_time=...`.
 +    pub display_cg_time: bool,
 +
-             regalloc: std::env::var("CG_CLIF_REGALLOC")
-                 .unwrap_or_else(|_| "backtracking".to_string()),
 +    /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
 +    /// once before passing the clif ir to Cranelift for compilation.
 +    ///
 +    /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
 +    /// compiled with debug assertions enabled or false otherwise. Can be set using
 +    /// `-Cllvm-args=enable_verifier=...`.
 +    pub enable_verifier: bool,
 +
 +    /// Don't cache object files in the incremental cache. Useful during development of cg_clif
 +    /// to make it possible to use incremental mode for all analyses performed by rustc without
 +    /// caching object files when their content should have been changed by a change to cg_clif.
 +    ///
 +    /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
 +    /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
 +    pub disable_incr_cache: bool,
 +}
 +
 +impl Default for BackendConfig {
 +    fn default() -> Self {
 +        BackendConfig {
 +            codegen_mode: CodegenMode::Aot,
 +            jit_args: {
 +                let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
 +                args.split(' ').map(|arg| arg.to_string()).collect()
 +            },
 +            display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
-                     "regalloc" => config.regalloc = value.to_string(),
 +            enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
 +            disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
 +        }
 +    }
 +}
 +
 +impl BackendConfig {
 +    /// Parse the configuration passed in using `-Cllvm-args`.
 +    pub fn from_opts(opts: &[String]) -> Result<Self, String> {
 +        fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
 +            value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
 +        }
 +
 +        let mut config = BackendConfig::default();
 +        for opt in opts {
 +            if let Some((name, value)) = opt.split_once('=') {
 +                match name {
 +                    "mode" => config.codegen_mode = value.parse()?,
 +                    "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
 +                    "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
 +                    "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
 +                    _ => return Err(format!("Unknown option `{}`", name)),
 +                }
 +            } else {
 +                return Err(format!("Invalid option `{}`", opt));
 +            }
 +        }
 +
 +        Ok(config)
 +    }
 +}
index 357cb4a6d246fa451a1b42ff3413df5455ef3f81,0000000000000000000000000000000000000000..f619bb5ed5e586ae33f5b7711095613bdad14472
mode 100644,000000..100644
--- /dev/null
@@@ -1,168 -1,0 +1,176 @@@
-                 // FIXME handle niche_start > i64::MAX
-                 fx.bcx.ins().iadd_imm(tag, -i64::try_from(niche_start).unwrap())
 +//! Handling of enum discriminants
 +//!
 +//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
 +
 +use rustc_target::abi::{Int, TagEncoding, Variants};
 +
 +use crate::prelude::*;
 +
 +pub(crate) fn codegen_set_discriminant<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    place: CPlace<'tcx>,
 +    variant_index: VariantIdx,
 +) {
 +    let layout = place.layout();
 +    if layout.for_variant(fx, variant_index).abi.is_uninhabited() {
 +        return;
 +    }
 +    match layout.variants {
 +        Variants::Single { index } => {
 +            assert_eq!(index, variant_index);
 +        }
 +        Variants::Multiple {
 +            tag: _,
 +            tag_field,
 +            tag_encoding: TagEncoding::Direct,
 +            variants: _,
 +        } => {
 +            let ptr = place.place_field(fx, mir::Field::new(tag_field));
 +            let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val;
 +            let to = if ptr.layout().abi.is_signed() {
 +                ty::ScalarInt::try_from_int(
 +                    ptr.layout().size.sign_extend(to) as i128,
 +                    ptr.layout().size,
 +                )
 +                .unwrap()
 +            } else {
 +                ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
 +            };
 +            let discr = CValue::const_val(fx, ptr.layout(), to);
 +            ptr.write_cvalue(fx, discr);
 +        }
 +        Variants::Multiple {
 +            tag: _,
 +            tag_field,
 +            tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
 +            variants: _,
 +        } => {
 +            if variant_index != dataful_variant {
 +                let niche = place.place_field(fx, mir::Field::new(tag_field));
 +                let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
 +                let niche_value = ty::ScalarInt::try_from_uint(
 +                    u128::from(niche_value).wrapping_add(niche_start),
 +                    niche.layout().size,
 +                )
 +                .unwrap();
 +                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
 +                niche.write_cvalue(fx, niche_llval);
 +            }
 +        }
 +    }
 +}
 +
 +pub(crate) fn codegen_get_discriminant<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    value: CValue<'tcx>,
 +    dest_layout: TyAndLayout<'tcx>,
 +) -> CValue<'tcx> {
 +    let layout = value.layout();
 +
 +    if layout.abi == Abi::Uninhabited {
 +        let true_ = fx.bcx.ins().iconst(types::I32, 1);
 +        fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached);
 +        // Return a dummy value
 +        return CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout);
 +    }
 +
 +    let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
 +        Variants::Single { index } => {
 +            let discr_val = layout
 +                .ty
 +                .discriminant_for_variant(fx.tcx, *index)
 +                .map_or(u128::from(index.as_u32()), |discr| discr.val);
 +            let discr_val = if dest_layout.abi.is_signed() {
 +                ty::ScalarInt::try_from_int(
 +                    dest_layout.size.sign_extend(discr_val) as i128,
 +                    dest_layout.size,
 +                )
 +                .unwrap()
 +            } else {
 +                ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
 +            };
 +            return CValue::const_val(fx, dest_layout, discr_val);
 +        }
 +        Variants::Multiple { tag, tag_field, tag_encoding, variants: _ } => {
 +            (tag, *tag_field, tag_encoding)
 +        }
 +    };
 +
 +    let cast_to = fx.clif_type(dest_layout.ty).unwrap();
 +
 +    // Read the tag/niche-encoded discriminant from memory.
 +    let tag = value.value_field(fx, mir::Field::new(tag_field));
 +    let tag = tag.load_scalar(fx);
 +
 +    // Decode the discriminant (specifically if it's niche-encoded).
 +    match *tag_encoding {
 +        TagEncoding::Direct => {
 +            let signed = match tag_scalar.primitive() {
 +                Int(_, signed) => signed,
 +                _ => false,
 +            };
 +            let val = clif_intcast(fx, tag, cast_to, signed);
 +            CValue::by_val(val, dest_layout)
 +        }
 +        TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
 +            // Rebase from niche values to discriminants, and check
 +            // whether the result is in range for the niche variants.
 +
 +            // We first compute the "relative discriminant" (wrt `niche_variants`),
 +            // that is, if `n = niche_variants.end() - niche_variants.start()`,
 +            // we remap `niche_start..=niche_start + n` (which may wrap around)
 +            // to (non-wrap-around) `0..=n`, to be able to check whether the
 +            // discriminant corresponds to a niche variant with one comparison.
 +            // We also can't go directly to the (variant index) discriminant
 +            // and check that it is in the range `niche_variants`, because
 +            // that might not fit in the same type, on top of needing an extra
 +            // comparison (see also the comment on `let niche_discr`).
 +            let relative_discr = if niche_start == 0 {
 +                tag
 +            } else {
++                let niche_start = match fx.bcx.func.dfg.value_type(tag) {
++                    types::I128 => {
++                        let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
++                        let msb =
++                            fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64);
++                        fx.bcx.ins().iconcat(lsb, msb)
++                    }
++                    ty => fx.bcx.ins().iconst(ty, niche_start as i64),
++                };
++                fx.bcx.ins().isub(tag, niche_start)
 +            };
 +            let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
 +            let is_niche = {
 +                codegen_icmp_imm(
 +                    fx,
 +                    IntCC::UnsignedLessThanOrEqual,
 +                    relative_discr,
 +                    i128::from(relative_max),
 +                )
 +            };
 +
 +            // NOTE(eddyb) this addition needs to be performed on the final
 +            // type, in case the niche itself can't represent all variant
 +            // indices (e.g. `u8` niche with more than `256` variants,
 +            // but enough uninhabited variants so that the remaining variants
 +            // fit in the niche).
 +            // In other words, `niche_variants.end - niche_variants.start`
 +            // is representable in the niche, but `niche_variants.end`
 +            // might not be, in extreme cases.
 +            let niche_discr = {
 +                let relative_discr = if relative_max == 0 {
 +                    // HACK(eddyb) since we have only one niche, we know which
 +                    // one it is, and we can avoid having a dynamic value here.
 +                    fx.bcx.ins().iconst(cast_to, 0)
 +                } else {
 +                    clif_intcast(fx, relative_discr, cast_to, false)
 +                };
 +                fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
 +            };
 +
 +            let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
 +            let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
 +            CValue::by_val(discr, dest_layout)
 +        }
 +    }
 +}
index 310d27c6decf6c87e66bd21a5148912eb0c9f070,0000000000000000000000000000000000000000..d76dfca7960c4a220871c57b8fc1f020f5cab588
mode 100644,000000..100644
--- /dev/null
@@@ -1,1144 -1,0 +1,1128 @@@
-         // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
-         // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
-         // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
-         // a float against itself. Only in case of NaN is it not equal to itself.
 +//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"`
 +//! and LLVM intrinsics that have symbol names starting with `llvm.`.
 +
 +macro_rules! intrinsic_pat {
 +    (_) => {
 +        _
 +    };
 +    ($name:ident) => {
 +        sym::$name
 +    };
 +    (kw.$name:ident) => {
 +        kw::$name
 +    };
 +    ($name:literal) => {
 +        $name
 +    };
 +}
 +
 +macro_rules! intrinsic_arg {
 +    (o $fx:expr, $arg:ident) => {};
 +    (c $fx:expr, $arg:ident) => {
 +        let $arg = codegen_operand($fx, $arg);
 +    };
 +    (v $fx:expr, $arg:ident) => {
 +        let $arg = codegen_operand($fx, $arg).load_scalar($fx);
 +    };
 +}
 +
 +macro_rules! intrinsic_match {
 +    ($fx:expr, $intrinsic:expr, $args:expr,
 +    _ => $unknown:block;
 +    $(
 +        $($($name:tt).*)|+ $(if $cond:expr)?, ($($a:ident $arg:ident),*) $content:block;
 +    )*) => {
 +        match $intrinsic {
 +            $(
 +                $(intrinsic_pat!($($name).*))|* $(if $cond)? => {
 +                    if let [$($arg),*] = $args {
 +                        $(intrinsic_arg!($a $fx, $arg);)*
 +                        $content
 +                    } else {
 +                        bug!("wrong number of args for intrinsic {:?}", $intrinsic);
 +                    }
 +                }
 +            )*
 +            _ => $unknown,
 +        }
 +    }
 +}
 +
 +mod cpuid;
 +mod llvm;
 +mod simd;
 +
 +pub(crate) use cpuid::codegen_cpuid_call;
 +pub(crate) use llvm::codegen_llvm_intrinsic_call;
 +
 +use rustc_middle::ty::print::with_no_trimmed_paths;
 +use rustc_middle::ty::subst::SubstsRef;
 +use rustc_span::symbol::{kw, sym, Symbol};
 +
 +use crate::prelude::*;
 +use cranelift_codegen::ir::AtomicRmwOp;
 +
 +fn report_atomic_type_validation_error<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    intrinsic: Symbol,
 +    span: Span,
 +    ty: Ty<'tcx>,
 +) {
 +    fx.tcx.sess.span_err(
 +        span,
 +        &format!(
 +            "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`",
 +            intrinsic, ty
 +        ),
 +    );
 +    // Prevent verifier error
 +    crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
 +}
 +
 +pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
 +    let (element, count) = match layout.abi {
 +        Abi::Vector { element, count } => (element, count),
 +        _ => unreachable!(),
 +    };
 +
 +    match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) {
 +        // Cranelift currently only implements icmp for 128bit vectors.
 +        Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty),
 +        _ => None,
 +    }
 +}
 +
 +fn simd_for_each_lane<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    val: CValue<'tcx>,
 +    ret: CPlace<'tcx>,
 +    f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Ty<'tcx>, Value) -> Value,
 +) {
 +    let layout = val.layout();
 +
 +    let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +    let lane_layout = fx.layout_of(lane_ty);
 +    let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
 +    let ret_lane_layout = fx.layout_of(ret_lane_ty);
 +    assert_eq!(lane_count, ret_lane_count);
 +
 +    for lane_idx in 0..lane_count {
 +        let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
 +
 +        let res_lane = f(fx, lane_layout.ty, ret_lane_layout.ty, lane);
 +        let res_lane = CValue::by_val(res_lane, ret_lane_layout);
 +
 +        ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
 +    }
 +}
 +
 +fn simd_pair_for_each_lane<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    x: CValue<'tcx>,
 +    y: CValue<'tcx>,
 +    ret: CPlace<'tcx>,
 +    f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Ty<'tcx>, Value, Value) -> Value,
 +) {
 +    assert_eq!(x.layout(), y.layout());
 +    let layout = x.layout();
 +
 +    let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +    let lane_layout = fx.layout_of(lane_ty);
 +    let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
 +    let ret_lane_layout = fx.layout_of(ret_lane_ty);
 +    assert_eq!(lane_count, ret_lane_count);
 +
 +    for lane_idx in 0..lane_count {
 +        let x_lane = x.value_lane(fx, lane_idx).load_scalar(fx);
 +        let y_lane = y.value_lane(fx, lane_idx).load_scalar(fx);
 +
 +        let res_lane = f(fx, lane_layout.ty, ret_lane_layout.ty, x_lane, y_lane);
 +        let res_lane = CValue::by_val(res_lane, ret_lane_layout);
 +
 +        ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
 +    }
 +}
 +
 +fn simd_reduce<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    val: CValue<'tcx>,
 +    acc: Option<Value>,
 +    ret: CPlace<'tcx>,
 +    f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Value, Value) -> Value,
 +) {
 +    let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
 +    let lane_layout = fx.layout_of(lane_ty);
 +    assert_eq!(lane_layout, ret.layout());
 +
 +    let (mut res_val, start_lane) =
 +        if let Some(acc) = acc { (acc, 0) } else { (val.value_lane(fx, 0).load_scalar(fx), 1) };
 +    for lane_idx in start_lane..lane_count {
 +        let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
 +        res_val = f(fx, lane_layout.ty, res_val, lane);
 +    }
 +    let res = CValue::by_val(res_val, lane_layout);
 +    ret.write_cvalue(fx, res);
 +}
 +
 +// FIXME move all uses to `simd_reduce`
 +fn simd_reduce_bool<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    val: CValue<'tcx>,
 +    ret: CPlace<'tcx>,
 +    f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Value, Value) -> Value,
 +) {
 +    let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
 +    assert!(ret.layout().ty.is_bool());
 +
 +    let res_val = val.value_lane(fx, 0).load_scalar(fx);
 +    let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
 +    for lane_idx in 1..lane_count {
 +        let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
 +        let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
 +        res_val = f(fx, res_val, lane);
 +    }
 +    let res_val = if fx.bcx.func.dfg.value_type(res_val) != types::I8 {
 +        fx.bcx.ins().ireduce(types::I8, res_val)
 +    } else {
 +        res_val
 +    };
 +    let res = CValue::by_val(res_val, ret.layout());
 +    ret.write_cvalue(fx, res);
 +}
 +
 +fn bool_to_zero_or_max_uint<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    ty: Ty<'tcx>,
 +    val: Value,
 +) -> Value {
 +    let ty = fx.clif_type(ty).unwrap();
 +
 +    let int_ty = match ty {
 +        types::F32 => types::I32,
 +        types::F64 => types::I64,
 +        ty => ty,
 +    };
 +
 +    let val = fx.bcx.ins().bint(int_ty, val);
 +    let mut res = fx.bcx.ins().ineg(val);
 +
 +    if ty.is_float() {
 +        res = fx.bcx.ins().bitcast(ty, res);
 +    }
 +
 +    res
 +}
 +
 +pub(crate) fn codegen_intrinsic_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    instance: Instance<'tcx>,
 +    args: &[mir::Operand<'tcx>],
 +    destination: Option<(CPlace<'tcx>, BasicBlock)>,
 +    span: Span,
 +) {
 +    let intrinsic = fx.tcx.item_name(instance.def_id());
 +    let substs = instance.substs;
 +
 +    let ret = match destination {
 +        Some((place, _)) => place,
 +        None => {
 +            // Insert non returning intrinsics here
 +            match intrinsic {
 +                sym::abort => {
 +                    fx.bcx.ins().trap(TrapCode::User(0));
 +                }
 +                sym::transmute => {
 +                    crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
 +                }
 +                _ => unimplemented!("unsupported instrinsic {}", intrinsic),
 +            }
 +            return;
 +        }
 +    };
 +
 +    if intrinsic.as_str().starts_with("simd_") {
 +        self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span);
 +        let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
 +        fx.bcx.ins().jump(ret_block, &[]);
 +    } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) {
 +        let ret_block = fx.get_block(destination.expect("Float intrinsics don't diverge").1);
 +        fx.bcx.ins().jump(ret_block, &[]);
 +    } else {
 +        codegen_regular_intrinsic_call(
 +            fx,
 +            instance,
 +            intrinsic,
 +            substs,
 +            args,
 +            ret,
 +            span,
 +            destination,
 +        );
 +    }
 +}
 +
 +fn codegen_float_intrinsic_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    intrinsic: Symbol,
 +    args: &[mir::Operand<'tcx>],
 +    ret: CPlace<'tcx>,
 +) -> bool {
 +    let (name, arg_count, ty) = match intrinsic {
 +        sym::expf32 => ("expf", 1, fx.tcx.types.f32),
 +        sym::expf64 => ("exp", 1, fx.tcx.types.f64),
 +        sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32),
 +        sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64),
 +        sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32),
 +        sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64),
 +        sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32), // compiler-builtins
 +        sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64), // compiler-builtins
 +        sym::powf32 => ("powf", 2, fx.tcx.types.f32),
 +        sym::powf64 => ("pow", 2, fx.tcx.types.f64),
 +        sym::logf32 => ("logf", 1, fx.tcx.types.f32),
 +        sym::logf64 => ("log", 1, fx.tcx.types.f64),
 +        sym::log2f32 => ("log2f", 1, fx.tcx.types.f32),
 +        sym::log2f64 => ("log2", 1, fx.tcx.types.f64),
 +        sym::log10f32 => ("log10f", 1, fx.tcx.types.f32),
 +        sym::log10f64 => ("log10", 1, fx.tcx.types.f64),
 +        sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32),
 +        sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64),
 +        sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32),
 +        sym::fmaf64 => ("fma", 3, fx.tcx.types.f64),
 +        sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32),
 +        sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64),
 +        sym::floorf32 => ("floorf", 1, fx.tcx.types.f32),
 +        sym::floorf64 => ("floor", 1, fx.tcx.types.f64),
 +        sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32),
 +        sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64),
 +        sym::truncf32 => ("truncf", 1, fx.tcx.types.f32),
 +        sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
 +        sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
 +        sym::roundf64 => ("round", 1, fx.tcx.types.f64),
 +        sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
 +        sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
 +        sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),
 +        sym::cosf64 => ("cos", 1, fx.tcx.types.f64),
 +        _ => return false,
 +    };
 +
 +    if args.len() != arg_count {
 +        bug!("wrong number of args for intrinsic {:?}", intrinsic);
 +    }
 +
 +    let (a, b, c);
 +    let args = match args {
 +        [x] => {
 +            a = [codegen_operand(fx, x)];
 +            &a as &[_]
 +        }
 +        [x, y] => {
 +            b = [codegen_operand(fx, x), codegen_operand(fx, y)];
 +            &b
 +        }
 +        [x, y, z] => {
 +            c = [codegen_operand(fx, x), codegen_operand(fx, y), codegen_operand(fx, z)];
 +            &c
 +        }
 +        _ => unreachable!(),
 +    };
 +
 +    let res = fx.easy_call(name, &args, ty);
 +    ret.write_cvalue(fx, res);
 +
 +    true
 +}
 +
 +fn codegen_regular_intrinsic_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    instance: Instance<'tcx>,
 +    intrinsic: Symbol,
 +    substs: SubstsRef<'tcx>,
 +    args: &[mir::Operand<'tcx>],
 +    ret: CPlace<'tcx>,
 +    span: Span,
 +    destination: Option<(CPlace<'tcx>, BasicBlock)>,
 +) {
 +    let usize_layout = fx.layout_of(fx.tcx.types.usize);
 +
 +    intrinsic_match! {
 +        fx, intrinsic, args,
 +        _ => {
 +            fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic));
 +        };
 +
 +        assume, (c _a) {};
 +        likely | unlikely, (c a) {
 +            ret.write_cvalue(fx, a);
 +        };
 +        breakpoint, () {
 +            fx.bcx.ins().debugtrap();
 +        };
 +        copy | copy_nonoverlapping, (v src, v dst, v count) {
 +            let elem_ty = substs.type_at(0);
 +            let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
 +            assert_eq!(args.len(), 3);
 +            let byte_amount = if elem_size != 1 {
 +                fx.bcx.ins().imul_imm(count, elem_size as i64)
 +            } else {
 +                count
 +            };
 +
 +            if intrinsic == sym::copy_nonoverlapping {
 +                // FIXME emit_small_memcpy
 +                fx.bcx.call_memcpy(fx.target_config, dst, src, byte_amount);
 +            } else {
 +                // FIXME emit_small_memmove
 +                fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
 +            }
 +        };
 +        // NOTE: the volatile variants have src and dst swapped
 +        volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) {
 +            let elem_ty = substs.type_at(0);
 +            let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
 +            assert_eq!(args.len(), 3);
 +            let byte_amount = if elem_size != 1 {
 +                fx.bcx.ins().imul_imm(count, elem_size as i64)
 +            } else {
 +                count
 +            };
 +
 +            // FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
 +            if intrinsic == sym::volatile_copy_nonoverlapping_memory {
 +                // FIXME emit_small_memcpy
 +                fx.bcx.call_memcpy(fx.target_config, dst, src, byte_amount);
 +            } else {
 +                // FIXME emit_small_memmove
 +                fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
 +            }
 +        };
 +        size_of_val, (c ptr) {
 +            let layout = fx.layout_of(substs.type_at(0));
 +            let size = if layout.is_unsized() {
 +                let (_ptr, info) = ptr.load_scalar_pair(fx);
 +                let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
 +                size
 +            } else {
 +                fx
 +                    .bcx
 +                    .ins()
 +                    .iconst(fx.pointer_type, layout.size.bytes() as i64)
 +            };
 +            ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
 +        };
 +        min_align_of_val, (c ptr) {
 +            let layout = fx.layout_of(substs.type_at(0));
 +            let align = if layout.is_unsized() {
 +                let (_ptr, info) = ptr.load_scalar_pair(fx);
 +                let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
 +                align
 +            } else {
 +                fx
 +                    .bcx
 +                    .ins()
 +                    .iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
 +            };
 +            ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
 +        };
 +
 +        unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem
 +        | unchecked_shl | unchecked_shr, (c x, c y) {
 +            // FIXME trap on overflow
 +            let bin_op = match intrinsic {
 +                sym::unchecked_add => BinOp::Add,
 +                sym::unchecked_sub => BinOp::Sub,
 +                sym::unchecked_mul => BinOp::Mul,
 +                sym::unchecked_div | sym::exact_div => BinOp::Div,
 +                sym::unchecked_rem => BinOp::Rem,
 +                sym::unchecked_shl => BinOp::Shl,
 +                sym::unchecked_shr => BinOp::Shr,
 +                _ => unreachable!(),
 +            };
 +            let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
 +            ret.write_cvalue(fx, res);
 +        };
 +        add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
 +            assert_eq!(x.layout().ty, y.layout().ty);
 +            let bin_op = match intrinsic {
 +                sym::add_with_overflow => BinOp::Add,
 +                sym::sub_with_overflow => BinOp::Sub,
 +                sym::mul_with_overflow => BinOp::Mul,
 +                _ => unreachable!(),
 +            };
 +
 +            let res = crate::num::codegen_checked_int_binop(
 +                fx,
 +                bin_op,
 +                x,
 +                y,
 +            );
 +            ret.write_cvalue(fx, res);
 +        };
 +        saturating_add | saturating_sub, (c lhs, c rhs) {
 +            assert_eq!(lhs.layout().ty, rhs.layout().ty);
 +            let bin_op = match intrinsic {
 +                sym::saturating_add => BinOp::Add,
 +                sym::saturating_sub => BinOp::Sub,
 +                _ => unreachable!(),
 +            };
 +
 +            let signed = type_sign(lhs.layout().ty);
 +
 +            let checked_res = crate::num::codegen_checked_int_binop(
 +                fx,
 +                bin_op,
 +                lhs,
 +                rhs,
 +            );
 +
 +            let (val, has_overflow) = checked_res.load_scalar_pair(fx);
 +            let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
 +
 +            let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
 +
 +            let val = match (intrinsic, signed) {
 +                (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
 +                (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
 +                (sym::saturating_add, true) => {
 +                    let rhs = rhs.load_scalar(fx);
 +                    let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
 +                    let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
 +                    fx.bcx.ins().select(has_overflow, sat_val, val)
 +                }
 +                (sym::saturating_sub, true) => {
 +                    let rhs = rhs.load_scalar(fx);
 +                    let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
 +                    let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
 +                    fx.bcx.ins().select(has_overflow, sat_val, val)
 +                }
 +                _ => unreachable!(),
 +            };
 +
 +            let res = CValue::by_val(val, lhs.layout());
 +
 +            ret.write_cvalue(fx, res);
 +        };
 +        rotate_left, (c x, v y) {
 +            let layout = x.layout();
 +            let x = x.load_scalar(fx);
 +            let res = fx.bcx.ins().rotl(x, y);
 +            ret.write_cvalue(fx, CValue::by_val(res, layout));
 +        };
 +        rotate_right, (c x, v y) {
 +            let layout = x.layout();
 +            let x = x.load_scalar(fx);
 +            let res = fx.bcx.ins().rotr(x, y);
 +            ret.write_cvalue(fx, CValue::by_val(res, layout));
 +        };
 +
 +        // The only difference between offset and arith_offset is regarding UB. Because Cranelift
 +        // doesn't have UB both are codegen'ed the same way
 +        offset | arith_offset, (c base, v offset) {
 +            let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
 +            let pointee_size = fx.layout_of(pointee_ty).size.bytes();
 +            let ptr_diff = if pointee_size != 1 {
 +                fx.bcx.ins().imul_imm(offset, pointee_size as i64)
 +            } else {
 +                offset
 +            };
 +            let base_val = base.load_scalar(fx);
 +            let res = fx.bcx.ins().iadd(base_val, ptr_diff);
 +            ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
 +        };
 +
 +        transmute, (c from) {
 +            ret.write_cvalue_transmute(fx, from);
 +        };
 +        write_bytes | volatile_set_memory, (c dst, v val, v count) {
 +            let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty;
 +            let pointee_size = fx.layout_of(pointee_ty).size.bytes();
 +            let count = if pointee_size != 1 {
 +                fx.bcx.ins().imul_imm(count, pointee_size as i64)
 +            } else {
 +                count
 +            };
 +            let dst_ptr = dst.load_scalar(fx);
 +            // FIXME make the memset actually volatile when switching to emit_small_memset
 +            // FIXME use emit_small_memset
 +            fx.bcx.call_memset(fx.target_config, dst_ptr, val, count);
 +        };
 +        ctlz | ctlz_nonzero, (c arg) {
 +            let val = arg.load_scalar(fx);
 +            // FIXME trap on `ctlz_nonzero` with zero arg.
 +            let res = fx.bcx.ins().clz(val);
 +            let res = CValue::by_val(res, arg.layout());
 +            ret.write_cvalue(fx, res);
 +        };
 +        cttz | cttz_nonzero, (c arg) {
 +            let val = arg.load_scalar(fx);
 +            // FIXME trap on `cttz_nonzero` with zero arg.
 +            let res = fx.bcx.ins().ctz(val);
 +            let res = CValue::by_val(res, arg.layout());
 +            ret.write_cvalue(fx, res);
 +        };
 +        ctpop, (c arg) {
 +            let val = arg.load_scalar(fx);
 +            let res = fx.bcx.ins().popcnt(val);
 +            let res = CValue::by_val(res, arg.layout());
 +            ret.write_cvalue(fx, res);
 +        };
 +        bitreverse, (c arg) {
 +            let val = arg.load_scalar(fx);
 +            let res = fx.bcx.ins().bitrev(val);
 +            let res = CValue::by_val(res, arg.layout());
 +            ret.write_cvalue(fx, res);
 +        };
 +        bswap, (c arg) {
 +            // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
 +            fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 +                match bcx.func.dfg.value_type(v) {
 +                    types::I8 => v,
 +
 +                    // https://code.woboq.org/gcc/include/bits/byteswap.h.html
 +                    types::I16 => {
 +                        let tmp1 = bcx.ins().ishl_imm(v, 8);
 +                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
 +
 +                        let tmp2 = bcx.ins().ushr_imm(v, 8);
 +                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
 +
 +                        bcx.ins().bor(n1, n2)
 +                    }
 +                    types::I32 => {
 +                        let tmp1 = bcx.ins().ishl_imm(v, 24);
 +                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
 +
 +                        let tmp2 = bcx.ins().ishl_imm(v, 8);
 +                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
 +
 +                        let tmp3 = bcx.ins().ushr_imm(v, 8);
 +                        let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
 +
 +                        let tmp4 = bcx.ins().ushr_imm(v, 24);
 +                        let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
 +
 +                        let or_tmp1 = bcx.ins().bor(n1, n2);
 +                        let or_tmp2 = bcx.ins().bor(n3, n4);
 +                        bcx.ins().bor(or_tmp1, or_tmp2)
 +                    }
 +                    types::I64 => {
 +                        let tmp1 = bcx.ins().ishl_imm(v, 56);
 +                        let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
 +
 +                        let tmp2 = bcx.ins().ishl_imm(v, 40);
 +                        let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
 +
 +                        let tmp3 = bcx.ins().ishl_imm(v, 24);
 +                        let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
 +
 +                        let tmp4 = bcx.ins().ishl_imm(v, 8);
 +                        let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
 +
 +                        let tmp5 = bcx.ins().ushr_imm(v, 8);
 +                        let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
 +
 +                        let tmp6 = bcx.ins().ushr_imm(v, 24);
 +                        let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
 +
 +                        let tmp7 = bcx.ins().ushr_imm(v, 40);
 +                        let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
 +
 +                        let tmp8 = bcx.ins().ushr_imm(v, 56);
 +                        let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
 +
 +                        let or_tmp1 = bcx.ins().bor(n1, n2);
 +                        let or_tmp2 = bcx.ins().bor(n3, n4);
 +                        let or_tmp3 = bcx.ins().bor(n5, n6);
 +                        let or_tmp4 = bcx.ins().bor(n7, n8);
 +
 +                        let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
 +                        let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
 +                        bcx.ins().bor(or_tmp5, or_tmp6)
 +                    }
 +                    types::I128 => {
 +                        let (lo, hi) = bcx.ins().isplit(v);
 +                        let lo = swap(bcx, lo);
 +                        let hi = swap(bcx, hi);
 +                        bcx.ins().iconcat(hi, lo)
 +                    }
 +                    ty => unreachable!("bswap {}", ty),
 +                }
 +            }
 +            let val = arg.load_scalar(fx);
 +            let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
 +            ret.write_cvalue(fx, res);
 +        };
 +        assert_inhabited | assert_zero_valid | assert_uninit_valid, () {
 +            let layout = fx.layout_of(substs.type_at(0));
 +            if layout.abi.is_uninhabited() {
 +                with_no_trimmed_paths!({
 +                    crate::base::codegen_panic(
 +                        fx,
 +                        &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
 +                        span,
 +                    )
 +                });
 +                return;
 +            }
 +
 +            if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) {
 +                with_no_trimmed_paths!({
 +                    crate::base::codegen_panic(
 +                        fx,
 +                        &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
 +                        span,
 +                    );
 +                });
 +                return;
 +            }
 +
 +            if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) {
 +                with_no_trimmed_paths!({
 +                    crate::base::codegen_panic(
 +                        fx,
 +                        &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
 +                        span,
 +                    )
 +                });
 +                return;
 +            }
 +        };
 +
 +        volatile_load | unaligned_volatile_load, (c ptr) {
 +            // Cranelift treats loads as volatile by default
 +            // FIXME correctly handle unaligned_volatile_load
 +            let inner_layout =
 +                fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
 +            let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
 +            ret.write_cvalue(fx, val);
 +        };
 +        volatile_store | unaligned_volatile_store, (v ptr, c val) {
 +            // Cranelift treats stores as volatile by default
 +            // FIXME correctly handle unaligned_volatile_store
 +            let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
 +            dest.write_cvalue(fx, val);
 +        };
 +
 +        pref_align_of | needs_drop | type_id | type_name | variant_count, () {
 +            let const_val =
 +                fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
 +            let val = crate::constant::codegen_const_value(
 +                fx,
 +                const_val,
 +                ret.layout().ty,
 +            );
 +            ret.write_cvalue(fx, val);
 +        };
 +
 +        ptr_offset_from, (v ptr, v base) {
 +            let ty = substs.type_at(0);
 +            let isize_layout = fx.layout_of(fx.tcx.types.isize);
 +
 +            let pointee_size: u64 = fx.layout_of(ty).size.bytes();
 +            let diff = fx.bcx.ins().isub(ptr, base);
 +            // FIXME this can be an exact division.
 +            let val = CValue::by_val(fx.bcx.ins().sdiv_imm(diff, pointee_size as i64), isize_layout);
 +            ret.write_cvalue(fx, val);
 +        };
 +
 +        ptr_guaranteed_eq, (c a, c b) {
 +            let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
 +            ret.write_cvalue(fx, val);
 +        };
 +
 +        ptr_guaranteed_ne, (c a, c b) {
 +            let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
 +            ret.write_cvalue(fx, val);
 +        };
 +
 +        caller_location, () {
 +            let caller_location = fx.get_caller_location(span);
 +            ret.write_cvalue(fx, caller_location);
 +        };
 +
 +        _ if intrinsic.as_str().starts_with("atomic_fence"), () {
 +            fx.bcx.ins().fence();
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
 +            // FIXME use a compiler fence once Cranelift supports it
 +            fx.bcx.ins().fence();
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_load"), (v ptr) {
 +            let ty = substs.type_at(0);
 +            match ty.kind() {
 +                ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
 +                    // FIXME implement 128bit atomics
 +                    if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
 +                        // special case for compiler-builtins to avoid having to patch it
 +                        crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
 +                        let ret_block = fx.get_block(destination.unwrap().1);
 +                        fx.bcx.ins().jump(ret_block, &[]);
 +                        return;
 +                    } else {
 +                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
 +                    }
 +                }
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
 +                    return;
 +                }
 +            }
 +            let clif_ty = fx.clif_type(ty).unwrap();
 +
 +            let val = fx.bcx.ins().atomic_load(clif_ty, MemFlags::trusted(), ptr);
 +
 +            let val = CValue::by_val(val, fx.layout_of(ty));
 +            ret.write_cvalue(fx, val);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
 +            let ty = substs.type_at(0);
 +            match ty.kind() {
 +                ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
 +                    // FIXME implement 128bit atomics
 +                    if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
 +                        // special case for compiler-builtins to avoid having to patch it
 +                        crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
 +                        let ret_block = fx.get_block(destination.unwrap().1);
 +                        fx.bcx.ins().jump(ret_block, &[]);
 +                        return;
 +                    } else {
 +                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
 +                    }
 +                }
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
 +                    return;
 +                }
 +            }
 +
 +            let val = val.load_scalar(fx);
 +
 +            fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
 +            let layout = new.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let new = new.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xchg, ptr, new);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
 +            let layout = new.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +
 +            let test_old = test_old.load_scalar(fx);
 +            let new = new.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
 +            let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
 +
 +            let ret_val = CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
 +            ret.write_cvalue(fx, ret_val)
 +        };
 +
 +        _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
 +            let layout = amount.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let amount = amount.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
 +            let layout = amount.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let amount = amount.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::And, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Or, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xor, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Nand, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Smax, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Umax, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Smin, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +        _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
 +            let layout = src.layout();
 +            match layout.ty.kind() {
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
 +                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
 +                    return;
 +                }
 +            }
 +            let ty = fx.clif_type(layout.ty).unwrap();
 +
 +            let src = src.load_scalar(fx);
 +
 +            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Umin, ptr, src);
 +
 +            let old = CValue::by_val(old, layout);
 +            ret.write_cvalue(fx, old);
 +        };
 +
-             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-             let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
-             let temp = fx.bcx.ins().select(a_ge_b, b, a);
-             let val = fx.bcx.ins().select(a_is_nan, b, temp);
 +        minnumf32, (v a, v b) {
-             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-             let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
-             let temp = fx.bcx.ins().select(a_ge_b, b, a);
-             let val = fx.bcx.ins().select(a_is_nan, b, temp);
++            let val = crate::num::codegen_float_min(fx, a, b);
 +            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
 +            ret.write_cvalue(fx, val);
 +        };
 +        minnumf64, (v a, v b) {
-             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-             let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
-             let temp = fx.bcx.ins().select(a_le_b, b, a);
-             let val = fx.bcx.ins().select(a_is_nan, b, temp);
++            let val = crate::num::codegen_float_min(fx, a, b);
 +            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
 +            ret.write_cvalue(fx, val);
 +        };
 +        maxnumf32, (v a, v b) {
-             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
-             let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
-             let temp = fx.bcx.ins().select(a_le_b, b, a);
-             let val = fx.bcx.ins().select(a_is_nan, b, temp);
++            let val = crate::num::codegen_float_max(fx, a, b);
 +            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
 +            ret.write_cvalue(fx, val);
 +        };
 +        maxnumf64, (v a, v b) {
++            let val = crate::num::codegen_float_max(fx, a, b);
 +            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
 +            ret.write_cvalue(fx, val);
 +        };
 +
 +        kw.Try, (v f, v data, v _catch_fn) {
 +            // FIXME once unwinding is supported, change this to actually catch panics
 +            let f_sig = fx.bcx.func.import_signature(Signature {
 +                call_conv: fx.target_config.default_call_conv,
 +                params: vec![AbiParam::new(fx.bcx.func.dfg.value_type(data))],
 +                returns: vec![],
 +            });
 +
 +            fx.bcx.ins().call_indirect(f_sig, f, &[data]);
 +
 +            let layout = ret.layout();
 +            let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
 +            ret.write_cvalue(fx, ret_val);
 +        };
 +
 +        fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
 +            let res = crate::num::codegen_float_binop(fx, match intrinsic {
 +                sym::fadd_fast => BinOp::Add,
 +                sym::fsub_fast => BinOp::Sub,
 +                sym::fmul_fast => BinOp::Mul,
 +                sym::fdiv_fast => BinOp::Div,
 +                sym::frem_fast => BinOp::Rem,
 +                _ => unreachable!(),
 +            }, x, y);
 +            ret.write_cvalue(fx, res);
 +        };
 +        float_to_int_unchecked, (v f) {
 +            let res = crate::cast::clif_int_or_float_cast(
 +                fx,
 +                f,
 +                false,
 +                fx.clif_type(ret.layout().ty).unwrap(),
 +                type_sign(ret.layout().ty),
 +            );
 +            ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
 +        };
 +
 +        raw_eq, (v lhs_ref, v rhs_ref) {
 +            let size = fx.layout_of(substs.type_at(0)).layout.size();
 +            // FIXME add and use emit_small_memcmp
 +            let is_eq_value =
 +                if size == Size::ZERO {
 +                    // No bytes means they're trivially equal
 +                    fx.bcx.ins().iconst(types::I8, 1)
 +                } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
 +                    // Can't use `trusted` for these loads; they could be unaligned.
 +                    let mut flags = MemFlags::new();
 +                    flags.set_notrap();
 +                    let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
 +                    let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
 +                    let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
 +                    fx.bcx.ins().bint(types::I8, eq)
 +                } else {
 +                    // Just call `memcmp` (like slices do in core) when the
 +                    // size is too large or it's not a power-of-two.
 +                    let signed_bytes = i64::try_from(size.bytes()).unwrap();
 +                    let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
 +                    let params = vec![AbiParam::new(fx.pointer_type); 3];
 +                    let returns = vec![AbiParam::new(types::I32)];
 +                    let args = &[lhs_ref, rhs_ref, bytes_val];
 +                    let cmp = fx.lib_call("memcmp", params, returns, args)[0];
 +                    let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
 +                    fx.bcx.ins().bint(types::I8, eq)
 +                };
 +            ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
 +        };
 +
 +        const_allocate, (c _size, c _align) {
 +            // returns a null pointer at runtime.
 +            let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
 +            ret.write_cvalue(fx, CValue::by_val(null, ret.layout()));
 +        };
 +
 +        const_deallocate, (c _ptr, c _size, c _align) {
 +            // nop at runtime.
 +        };
 +
 +        black_box, (c a) {
 +            // FIXME implement black_box semantics
 +            ret.write_cvalue(fx, a);
 +        };
 +    }
 +
 +    let ret_block = fx.get_block(destination.unwrap().1);
 +    fx.bcx.ins().jump(ret_block, &[]);
 +}
index bc21d736166277ce3f664fe926b17adb34841578,0000000000000000000000000000000000000000..d1ca9edf2e0f1bb578889566bc8384c5bf5bfc1c
mode 100644,000000..100644
--- /dev/null
@@@ -1,553 -1,0 +1,554 @@@
-             let layout = a.layout();
 +//! Codegen `extern "platform-intrinsic"` intrinsics.
 +
 +use rustc_middle::ty::subst::SubstsRef;
 +use rustc_span::Symbol;
 +
 +use super::*;
 +use crate::prelude::*;
 +
 +fn report_simd_type_validation_error(
 +    fx: &mut FunctionCx<'_, '_, '_>,
 +    intrinsic: Symbol,
 +    span: Span,
 +    ty: Ty<'_>,
 +) {
 +    fx.tcx.sess.span_err(span, &format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
 +    // Prevent verifier error
 +    crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
 +}
 +
 +pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    intrinsic: Symbol,
 +    _substs: SubstsRef<'tcx>,
 +    args: &[mir::Operand<'tcx>],
 +    ret: CPlace<'tcx>,
 +    span: Span,
 +) {
 +    intrinsic_match! {
 +        fx, intrinsic, args,
 +        _ => {
 +            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
 +        };
 +
 +        simd_cast, (c a) {
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +
 +            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, ret_lane_ty, lane| {
 +                let ret_lane_clif_ty = fx.clif_type(ret_lane_ty).unwrap();
 +
 +                let from_signed = type_sign(lane_ty);
 +                let to_signed = type_sign(ret_lane_ty);
 +
 +                clif_int_or_float_cast(fx, lane, from_signed, ret_lane_clif_ty, to_signed)
 +            });
 +        };
 +
 +        simd_eq | simd_ne | simd_lt | simd_le | simd_gt | simd_ge, (c x, c y) {
 +            if !x.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
 +                return;
 +            }
 +
 +            // FIXME use vector instructions when possible
 +            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
 +                let res_lane = match (lane_ty.kind(), intrinsic) {
 +                    (ty::Uint(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
 +                    (ty::Uint(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
 +                    (ty::Uint(_), sym::simd_lt) => {
 +                        fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane)
 +                    }
 +                    (ty::Uint(_), sym::simd_le) => {
 +                        fx.bcx.ins().icmp(IntCC::UnsignedLessThanOrEqual, x_lane, y_lane)
 +                    }
 +                    (ty::Uint(_), sym::simd_gt) => {
 +                        fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane)
 +                    }
 +                    (ty::Uint(_), sym::simd_ge) => {
 +                        fx.bcx.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, x_lane, y_lane)
 +                    }
 +
 +                    (ty::Int(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
 +                    (ty::Int(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
 +                    (ty::Int(_), sym::simd_lt) => fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane),
 +                    (ty::Int(_), sym::simd_le) => {
 +                        fx.bcx.ins().icmp(IntCC::SignedLessThanOrEqual, x_lane, y_lane)
 +                    }
 +                    (ty::Int(_), sym::simd_gt) => {
 +                        fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane)
 +                    }
 +                    (ty::Int(_), sym::simd_ge) => {
 +                        fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane)
 +                    }
 +
 +                    (ty::Float(_), sym::simd_eq) => fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane),
 +                    (ty::Float(_), sym::simd_ne) => fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane),
 +                    (ty::Float(_), sym::simd_lt) => fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane),
 +                    (ty::Float(_), sym::simd_le) => {
 +                        fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane)
 +                    }
 +                    (ty::Float(_), sym::simd_gt) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane),
 +                    (ty::Float(_), sym::simd_ge) => {
 +                        fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane)
 +                    }
 +
 +                    _ => unreachable!(),
 +                };
 +
 +                let ty = fx.clif_type(res_lane_ty).unwrap();
 +
 +                let res_lane = fx.bcx.ins().bint(ty, res_lane);
 +                fx.bcx.ins().ineg(res_lane)
 +            });
 +        };
 +
 +        // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
 +        _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
 +            if !x.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
 +                return;
 +            }
 +
 +            // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
 +            // If there is no suffix, use the index array length.
 +            let n: u16 = if intrinsic == sym::simd_shuffle {
 +                // Make sure this is actually an array, since typeck only checks the length-suffixed
 +                // version of this intrinsic.
 +                let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
 +                match idx_ty.kind() {
 +                    ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
 +                        len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
 +                            span_bug!(span, "could not evaluate shuffle index array length")
 +                        }).try_into().unwrap()
 +                    }
 +                    _ => {
 +                        fx.tcx.sess.span_err(
 +                            span,
 +                            &format!(
 +                                "simd_shuffle index must be an array of `u32`, got `{}`",
 +                                idx_ty,
 +                            ),
 +                        );
 +                        // Prevent verifier error
 +                        crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
 +                        return;
 +                    }
 +                }
 +            } else {
 +                intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap()
 +            };
 +
 +            assert_eq!(x.layout(), y.layout());
 +            let layout = x.layout();
 +
 +            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
 +
 +            assert_eq!(lane_ty, ret_lane_ty);
 +            assert_eq!(u64::from(n), ret_lane_count);
 +
 +            let total_len = lane_count * 2;
 +
 +            let indexes = {
 +                use rustc_middle::mir::interpret::*;
 +                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
 +
 +                let idx_bytes = match idx_const {
 +                    ConstValue::ByRef { alloc, offset } => {
 +                        let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
 +                        alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
 +                    }
 +                    _ => unreachable!("{:?}", idx_const),
 +                };
 +
 +                (0..ret_lane_count).map(|i| {
 +                    let i = usize::try_from(i).unwrap();
 +                    let idx = rustc_middle::mir::interpret::read_target_uint(
 +                        fx.tcx.data_layout.endian,
 +                        &idx_bytes[4*i.. 4*i + 4],
 +                    ).expect("read_target_uint");
 +                    u16::try_from(idx).expect("try_from u32")
 +                }).collect::<Vec<u16>>()
 +            };
 +
 +            for &idx in &indexes {
 +                assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
 +            }
 +
 +            for (out_idx, in_idx) in indexes.into_iter().enumerate() {
 +                let in_lane = if u64::from(in_idx) < lane_count {
 +                    x.value_lane(fx, in_idx.into())
 +                } else {
 +                    y.value_lane(fx, u64::from(in_idx) - lane_count)
 +                };
 +                let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
 +                out_lane.write_cvalue(fx, in_lane);
 +            }
 +        };
 +
 +        simd_insert, (c base, o idx, c val) {
 +            // FIXME validate
 +            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
 +                idx_const
 +            } else {
 +                fx.tcx.sess.span_fatal(
 +                    span,
 +                    "Index argument for `simd_insert` is not a constant",
 +                );
 +            };
 +
 +            let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
 +            let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
 +            if idx >= lane_count.into() {
 +                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
 +            }
 +
 +            ret.write_cvalue(fx, base);
 +            let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap()));
 +            ret_lane.write_cvalue(fx, val);
 +        };
 +
 +        simd_extract, (c v, o idx) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
 +                idx_const
 +            } else {
 +                fx.tcx.sess.span_warn(
 +                    span,
 +                    "Index argument for `simd_extract` is not a constant",
 +                );
 +                let res = crate::trap::trap_unimplemented_ret_value(
 +                    fx,
 +                    ret.layout(),
 +                    "Index argument for `simd_extract` is not a constant",
 +                );
 +                ret.write_cvalue(fx, res);
 +                return;
 +            };
 +
 +            let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
 +            let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
 +            if idx >= lane_count.into() {
 +                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
 +            }
 +
 +            let ret_lane = v.value_lane(fx, idx.try_into().unwrap());
 +            ret.write_cvalue(fx, ret_lane);
 +        };
 +
 +        simd_neg, (c a) {
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +
 +            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
 +                match lane_ty.kind() {
 +                    ty::Int(_) => fx.bcx.ins().ineg(lane),
 +                    ty::Float(_) => fx.bcx.ins().fneg(lane),
 +                    _ => unreachable!(),
 +                }
 +            });
 +        };
 +
 +        simd_add | simd_sub | simd_mul | simd_div | simd_rem
 +        | simd_shl | simd_shr | simd_and | simd_or | simd_xor, (c x, c y) {
 +            if !x.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
 +                return;
 +            }
 +
 +            // FIXME use vector instructions when possible
 +            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| match (
 +                lane_ty.kind(),
 +                intrinsic,
 +            ) {
 +                (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane),
 +
 +                (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane),
 +
 +                (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane),
 +                (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane),
 +                (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane),
 +                (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane),
 +                (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call(
 +                    "fmodf",
 +                    vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
 +                    vec![AbiParam::new(types::F32)],
 +                    &[x_lane, y_lane],
 +                )[0],
 +                (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call(
 +                    "fmod",
 +                    vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
 +                    vec![AbiParam::new(types::F64)],
 +                    &[x_lane, y_lane],
 +                )[0],
 +
 +                (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
 +                (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
 +
 +                (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
 +                (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
 +
 +                _ => unreachable!(),
 +            });
 +        };
 +
 +        simd_fma, (c a, c b, c c) {
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +            assert_eq!(a.layout(), b.layout());
 +            assert_eq!(a.layout(), c.layout());
-             let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-             let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-             assert_eq!(lane_count, ret_lane_count);
-             let ret_lane_layout = fx.layout_of(ret_lane_ty);
++            assert_eq!(a.layout(), ret.layout());
 +
-                 let a_lane = a.value_lane(fx, lane).load_scalar(fx);
-                 let b_lane = b.value_lane(fx, lane).load_scalar(fx);
-                 let c_lane = c.value_lane(fx, lane).load_scalar(fx);
++            let layout = a.layout();
++            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +
 +            for lane in 0..lane_count {
-                 let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
-                 let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);
++                let a_lane = a.value_lane(fx, lane);
++                let b_lane = b.value_lane(fx, lane);
++                let c_lane = c.value_lane(fx, lane);
 +
-                     sym::simd_fmin => fx.bcx.ins().fmin(x_lane, y_lane),
-                     sym::simd_fmax => fx.bcx.ins().fmax(x_lane, y_lane),
++                let res_lane = match lane_ty.kind() {
++                    ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty),
++                    ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty),
++                    _ => unreachable!(),
++                };
 +
 +                ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
 +            }
 +        };
 +
 +        simd_fmin | simd_fmax, (c x, c y) {
 +            if !x.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
 +                return;
 +            }
 +
 +            // FIXME use vector instructions when possible
 +            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| {
 +                match lane_ty.kind() {
 +                    ty::Float(_) => {},
 +                    _ => unreachable!("{:?}", lane_ty),
 +                }
 +                match intrinsic {
-                     ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::LessThan, a, b),
++                    sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane),
++                    sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane),
 +                    _ => unreachable!(),
 +                }
 +            });
 +        };
 +
 +        simd_round, (c a) {
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +
 +            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
 +                match lane_ty.kind() {
 +                    ty::Float(FloatTy::F32) => fx.lib_call(
 +                        "roundf",
 +                        vec![AbiParam::new(types::F32)],
 +                        vec![AbiParam::new(types::F32)],
 +                        &[lane],
 +                    )[0],
 +                    ty::Float(FloatTy::F64) => fx.lib_call(
 +                        "round",
 +                        vec![AbiParam::new(types::F64)],
 +                        vec![AbiParam::new(types::F64)],
 +                        &[lane],
 +                    )[0],
 +                    _ => unreachable!("{:?}", lane_ty),
 +                }
 +            });
 +        };
 +
 +        simd_fabs | simd_fsqrt | simd_ceil | simd_floor | simd_trunc, (c a) {
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +
 +            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
 +                match lane_ty.kind() {
 +                    ty::Float(_) => {},
 +                    _ => unreachable!("{:?}", lane_ty),
 +                }
 +                match intrinsic {
 +                    sym::simd_fabs => fx.bcx.ins().fabs(lane),
 +                    sym::simd_fsqrt => fx.bcx.ins().sqrt(lane),
 +                    sym::simd_ceil => fx.bcx.ins().ceil(lane),
 +                    sym::simd_floor => fx.bcx.ins().floor(lane),
 +                    sym::simd_trunc => fx.bcx.ins().trunc(lane),
 +                    _ => unreachable!(),
 +                }
 +            });
 +        };
 +
 +        simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) {
 +            // FIXME there must be no acc param for integer vectors
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| {
 +                if lane_ty.is_floating_point() {
 +                    fx.bcx.ins().fadd(a, b)
 +                } else {
 +                    fx.bcx.ins().iadd(a, b)
 +                }
 +            });
 +        };
 +
 +        simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) {
 +            // FIXME there must be no acc param for integer vectors
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| {
 +                if lane_ty.is_floating_point() {
 +                    fx.bcx.ins().fmul(a, b)
 +                } else {
 +                    fx.bcx.ins().imul(a, b)
 +                }
 +            });
 +        };
 +
 +        simd_reduce_all, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().band(a, b));
 +        };
 +
 +        simd_reduce_any, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().bor(a, b));
 +        };
 +
 +        simd_reduce_and, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().band(a, b));
 +        };
 +
 +        simd_reduce_or, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bor(a, b));
 +        };
 +
 +        simd_reduce_xor, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bxor(a, b));
 +        };
 +
 +        simd_reduce_min, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, None, ret, &|fx, ty, a, b| {
 +                let lt = match ty.kind() {
 +                    ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b),
 +                    ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b),
-                     ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, a, b),
++                    ty::Float(_) => return crate::num::codegen_float_min(fx, a, b),
 +                    _ => unreachable!(),
 +                };
 +                fx.bcx.ins().select(lt, a, b)
 +            });
 +        };
 +
 +        simd_reduce_max, (c v) {
 +            if !v.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
 +                return;
 +            }
 +
 +            simd_reduce(fx, v, None, ret, &|fx, ty, a, b| {
 +                let gt = match ty.kind() {
 +                    ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b),
 +                    ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b),
++                    ty::Float(_) => return crate::num::codegen_float_max(fx, a, b),
 +                    _ => unreachable!(),
 +                };
 +                fx.bcx.ins().select(gt, a, b)
 +            });
 +        };
 +
 +        simd_select, (c m, c a, c b) {
 +            if !m.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, m.layout().ty);
 +                return;
 +            }
 +            if !a.layout().ty.is_simd() {
 +                report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
 +                return;
 +            }
 +            assert_eq!(a.layout(), b.layout());
 +
 +            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
 +            let lane_layout = fx.layout_of(lane_ty);
 +
 +            for lane in 0..lane_count {
 +                let m_lane = m.value_lane(fx, lane).load_scalar(fx);
 +                let a_lane = a.value_lane(fx, lane).load_scalar(fx);
 +                let b_lane = b.value_lane(fx, lane).load_scalar(fx);
 +
 +                let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
 +                let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
 +
 +                ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
 +            }
 +        };
 +
 +        // simd_saturating_*
 +        // simd_bitmask
 +        // simd_scatter
 +        // simd_gather
 +    }
 +}
index 878b9390e1318c6c650cf56fb0ed6a3b1c132682,0000000000000000000000000000000000000000..9d2e12f98984ae366b37472015543a0adcee4559
mode 100644,000000..100644
--- /dev/null
@@@ -1,313 -1,0 +1,311 @@@
-     flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
 +#![feature(rustc_private)]
 +// Note: please avoid adding other feature gates where possible
 +#![warn(rust_2018_idioms)]
 +#![warn(unused_lifetimes)]
 +#![warn(unreachable_pub)]
 +
 +#[macro_use]
 +extern crate rustc_middle;
 +extern crate rustc_ast;
 +extern crate rustc_codegen_ssa;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_fs_util;
 +extern crate rustc_hir;
 +extern crate rustc_incremental;
 +extern crate rustc_index;
 +extern crate rustc_interface;
 +extern crate rustc_metadata;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +
 +// This prevents duplicating functions and statics that are already part of the host rustc process.
 +#[allow(unused_extern_crates)]
 +extern crate rustc_driver;
 +
 +use std::any::Any;
 +use std::cell::Cell;
 +
 +use rustc_codegen_ssa::traits::CodegenBackend;
 +use rustc_codegen_ssa::CodegenResults;
 +use rustc_errors::ErrorGuaranteed;
 +use rustc_metadata::EncodedMetadata;
 +use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 +use rustc_session::config::OutputFilenames;
 +use rustc_session::Session;
 +use rustc_span::Symbol;
 +
 +use cranelift_codegen::isa::TargetIsa;
 +use cranelift_codegen::settings::{self, Configurable};
 +
 +pub use crate::config::*;
 +use crate::prelude::*;
 +
 +mod abi;
 +mod allocator;
 +mod analyze;
 +mod archive;
 +mod base;
 +mod cast;
 +mod codegen_i128;
 +mod common;
 +mod compiler_builtins;
 +mod config;
 +mod constant;
 +mod debuginfo;
 +mod discriminant;
 +mod driver;
 +mod inline_asm;
 +mod intrinsics;
 +mod linkage;
 +mod main_shim;
 +mod num;
 +mod optimize;
 +mod pointer;
 +mod pretty_clif;
 +mod toolchain;
 +mod trap;
 +mod unsize;
 +mod value_and_place;
 +mod vtable;
 +
 +mod prelude {
 +    pub(crate) use rustc_span::{FileNameDisplayPreference, Span};
 +
 +    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 +    pub(crate) use rustc_middle::bug;
 +    pub(crate) use rustc_middle::mir::{self, *};
 +    pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
 +    pub(crate) use rustc_middle::ty::{
 +        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
 +        TypeFoldable, UintTy,
 +    };
 +    pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx};
 +
 +    pub(crate) use rustc_data_structures::fx::FxHashMap;
 +
 +    pub(crate) use rustc_index::vec::Idx;
 +
 +    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
 +    pub(crate) use cranelift_codegen::ir::function::Function;
 +    pub(crate) use cranelift_codegen::ir::types;
 +    pub(crate) use cranelift_codegen::ir::{
 +        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
 +        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
 +    };
 +    pub(crate) use cranelift_codegen::isa::{self, CallConv};
 +    pub(crate) use cranelift_codegen::Context;
 +    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
 +    pub(crate) use cranelift_module::{self, DataContext, FuncId, Linkage, Module};
 +
 +    pub(crate) use crate::abi::*;
 +    pub(crate) use crate::base::{codegen_operand, codegen_place};
 +    pub(crate) use crate::cast::*;
 +    pub(crate) use crate::common::*;
 +    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
 +    pub(crate) use crate::pointer::Pointer;
 +    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
 +}
 +
 +struct PrintOnPanic<F: Fn() -> String>(F);
 +impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
 +    fn drop(&mut self) {
 +        if ::std::thread::panicking() {
 +            println!("{}", (self.0)());
 +        }
 +    }
 +}
 +
 +/// The codegen context holds any information shared between the codegen of individual functions
 +/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
 +struct CodegenCx<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +    global_asm: String,
 +    inline_asm_index: Cell<usize>,
 +    cached_context: Context,
 +    debug_context: Option<DebugContext<'tcx>>,
 +    unwind_context: UnwindContext,
 +    cgu_name: Symbol,
 +}
 +
 +impl<'tcx> CodegenCx<'tcx> {
 +    fn new(
 +        tcx: TyCtxt<'tcx>,
 +        backend_config: BackendConfig,
 +        isa: &dyn TargetIsa,
 +        debug_info: bool,
 +        cgu_name: Symbol,
 +    ) -> Self {
 +        assert_eq!(pointer_ty(tcx), isa.pointer_type());
 +
 +        let unwind_context =
 +            UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
 +        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
 +        CodegenCx {
 +            tcx,
 +            global_asm: String::new(),
 +            inline_asm_index: Cell::new(0),
 +            cached_context: Context::new(),
 +            debug_context,
 +            unwind_context,
 +            cgu_name,
 +        }
 +    }
 +}
 +
 +pub struct CraneliftCodegenBackend {
 +    pub config: Option<BackendConfig>,
 +}
 +
 +impl CodegenBackend for CraneliftCodegenBackend {
 +    fn init(&self, sess: &Session) {
 +        use rustc_session::config::Lto;
 +        match sess.lto() {
 +            Lto::No | Lto::ThinLocal => {}
 +            Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
 +        }
 +    }
 +
 +    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
 +        vec![]
 +    }
 +
 +    fn print_version(&self) {
 +        println!("Cranelift version: {}", cranelift_codegen::VERSION);
 +    }
 +
 +    fn codegen_crate(
 +        &self,
 +        tcx: TyCtxt<'_>,
 +        metadata: EncodedMetadata,
 +        need_metadata_module: bool,
 +    ) -> Box<dyn Any> {
 +        tcx.sess.abort_if_errors();
 +        let config = if let Some(config) = self.config.clone() {
 +            config
 +        } else {
 +            if !tcx.sess.unstable_options() && !tcx.sess.opts.cg.llvm_args.is_empty() {
 +                tcx.sess.fatal("`-Z unstable-options` must be passed to allow configuring cg_clif");
 +            }
 +            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
 +                .unwrap_or_else(|err| tcx.sess.fatal(&err))
 +        };
 +        match config.codegen_mode {
 +            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
 +            CodegenMode::Jit | CodegenMode::JitLazy => {
 +                #[cfg(feature = "jit")]
 +                driver::jit::run_jit(tcx, config);
 +
 +                #[cfg(not(feature = "jit"))]
 +                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
 +            }
 +        }
 +    }
 +
 +    fn join_codegen(
 +        &self,
 +        ongoing_codegen: Box<dyn Any>,
 +        _sess: &Session,
 +        _outputs: &OutputFilenames,
 +    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
 +        Ok(*ongoing_codegen
 +            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
 +            .unwrap())
 +    }
 +
 +    fn link(
 +        &self,
 +        sess: &Session,
 +        codegen_results: CodegenResults,
 +        outputs: &OutputFilenames,
 +    ) -> Result<(), ErrorGuaranteed> {
 +        use rustc_codegen_ssa::back::link::link_binary;
 +
 +        link_binary::<crate::archive::ArArchiveBuilder<'_>>(sess, &codegen_results, outputs)
 +    }
 +}
 +
 +fn target_triple(sess: &Session) -> target_lexicon::Triple {
 +    match sess.target.llvm_target.parse() {
 +        Ok(triple) => triple,
 +        Err(err) => sess.fatal(&format!("target not recognized: {}", err)),
 +    }
 +}
 +
 +fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
 +    use target_lexicon::BinaryFormat;
 +
 +    let target_triple = crate::target_triple(sess);
 +
 +    let mut flags_builder = settings::builder();
 +    flags_builder.enable("is_pic").unwrap();
 +    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
 +    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
 +    flags_builder.set("enable_verifier", enable_verifier).unwrap();
 +
 +    let tls_model = match target_triple.binary_format {
 +        BinaryFormat::Elf => "elf_gd",
 +        BinaryFormat::Macho => "macho",
 +        BinaryFormat::Coff => "coff",
 +        _ => "none",
 +    };
 +    flags_builder.set("tls_model", tls_model).unwrap();
 +
 +    flags_builder.set("enable_simd", "true").unwrap();
 +
 +    flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
 +
 +    use rustc_session::config::OptLevel;
 +    match sess.opts.optimize {
 +        OptLevel::No => {
 +            flags_builder.set("opt_level", "none").unwrap();
 +        }
 +        OptLevel::Less | OptLevel::Default => {}
 +        OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => {
 +            flags_builder.set("opt_level", "speed_and_size").unwrap();
 +        }
 +    }
 +
 +    let flags = settings::Flags::new(flags_builder);
 +
 +    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
 +        Some("native") => {
 +            let builder = cranelift_native::builder_with_options(true).unwrap();
 +            builder
 +        }
 +        Some(value) => {
 +            let mut builder =
 +                cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
 +                    sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
 +                });
 +            if let Err(_) = builder.enable(value) {
 +                sess.fatal("the specified target cpu isn't currently supported by Cranelift.");
 +            }
 +            builder
 +        }
 +        None => {
 +            let mut builder =
 +                cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
 +                    sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
 +                });
 +            if target_triple.architecture == target_lexicon::Architecture::X86_64 {
 +                // Don't use "haswell" as the default, as it implies `has_lzcnt`.
 +                // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
 +                builder.enable("nehalem").unwrap();
 +            }
 +            builder
 +        }
 +    };
 +
 +    match isa_builder.finish(flags) {
 +        Ok(target_isa) => target_isa,
 +        Err(err) => sess.fatal(&format!("failed to build TargetIsa: {}", err)),
 +    }
 +}
 +
 +/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
 +#[no_mangle]
 +pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
 +    Box::new(CraneliftCodegenBackend { config: None })
 +}
index 545d390e269957f1ef94c48b83d2c1e10b5f953f,0000000000000000000000000000000000000000..4ce8adb182e0fab68756d06f3fad196f1bf5a770
mode 100644,000000..100644
--- /dev/null
@@@ -1,422 -1,0 +1,440 @@@
 +//! Various operations on integer and floating-point numbers
 +
 +use crate::prelude::*;
 +
 +pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
 +    use BinOp::*;
 +    use IntCC::*;
 +    Some(match bin_op {
 +        Eq => Equal,
 +        Lt => {
 +            if signed {
 +                SignedLessThan
 +            } else {
 +                UnsignedLessThan
 +            }
 +        }
 +        Le => {
 +            if signed {
 +                SignedLessThanOrEqual
 +            } else {
 +                UnsignedLessThanOrEqual
 +            }
 +        }
 +        Ne => NotEqual,
 +        Ge => {
 +            if signed {
 +                SignedGreaterThanOrEqual
 +            } else {
 +                UnsignedGreaterThanOrEqual
 +            }
 +        }
 +        Gt => {
 +            if signed {
 +                SignedGreaterThan
 +            } else {
 +                UnsignedGreaterThan
 +            }
 +        }
 +        _ => return None,
 +    })
 +}
 +
 +fn codegen_compare_bin_op<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    signed: bool,
 +    lhs: Value,
 +    rhs: Value,
 +) -> CValue<'tcx> {
 +    let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
 +    let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
 +    let val = fx.bcx.ins().bint(types::I8, val);
 +    CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
 +}
 +
 +pub(crate) fn codegen_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    match bin_op {
 +        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
 +            match in_lhs.layout().ty.kind() {
 +                ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
 +                    let signed = type_sign(in_lhs.layout().ty);
 +                    let lhs = in_lhs.load_scalar(fx);
 +                    let rhs = in_rhs.load_scalar(fx);
 +
 +                    return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs);
 +                }
 +                _ => {}
 +            }
 +        }
 +        _ => {}
 +    }
 +
 +    match in_lhs.layout().ty.kind() {
 +        ty::Bool => crate::num::codegen_bool_binop(fx, bin_op, in_lhs, in_rhs),
 +        ty::Uint(_) | ty::Int(_) => crate::num::codegen_int_binop(fx, bin_op, in_lhs, in_rhs),
 +        ty::Float(_) => crate::num::codegen_float_binop(fx, bin_op, in_lhs, in_rhs),
 +        ty::RawPtr(..) | ty::FnPtr(..) => crate::num::codegen_ptr_binop(fx, bin_op, in_lhs, in_rhs),
 +        _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
 +    }
 +}
 +
 +pub(crate) fn codegen_bool_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    let lhs = in_lhs.load_scalar(fx);
 +    let rhs = in_rhs.load_scalar(fx);
 +
 +    let b = fx.bcx.ins();
 +    let res = match bin_op {
 +        BinOp::BitXor => b.bxor(lhs, rhs),
 +        BinOp::BitAnd => b.band(lhs, rhs),
 +        BinOp::BitOr => b.bor(lhs, rhs),
 +        // Compare binops handles by `codegen_binop`.
 +        _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
 +    };
 +
 +    CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
 +}
 +
 +pub(crate) fn codegen_int_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
 +        assert_eq!(
 +            in_lhs.layout().ty,
 +            in_rhs.layout().ty,
 +            "int binop requires lhs and rhs of same type"
 +        );
 +    }
 +
 +    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
 +        return res;
 +    }
 +
 +    let signed = type_sign(in_lhs.layout().ty);
 +
 +    let lhs = in_lhs.load_scalar(fx);
 +    let rhs = in_rhs.load_scalar(fx);
 +
 +    let b = fx.bcx.ins();
 +    let val = match bin_op {
 +        BinOp::Add => b.iadd(lhs, rhs),
 +        BinOp::Sub => b.isub(lhs, rhs),
 +        BinOp::Mul => b.imul(lhs, rhs),
 +        BinOp::Div => {
 +            if signed {
 +                b.sdiv(lhs, rhs)
 +            } else {
 +                b.udiv(lhs, rhs)
 +            }
 +        }
 +        BinOp::Rem => {
 +            if signed {
 +                b.srem(lhs, rhs)
 +            } else {
 +                b.urem(lhs, rhs)
 +            }
 +        }
 +        BinOp::BitXor => b.bxor(lhs, rhs),
 +        BinOp::BitAnd => b.band(lhs, rhs),
 +        BinOp::BitOr => b.bor(lhs, rhs),
 +        BinOp::Shl => {
 +            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
 +            let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
 +            fx.bcx.ins().ishl(lhs, actual_shift)
 +        }
 +        BinOp::Shr => {
 +            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
 +            let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
 +            if signed {
 +                fx.bcx.ins().sshr(lhs, actual_shift)
 +            } else {
 +                fx.bcx.ins().ushr(lhs, actual_shift)
 +            }
 +        }
 +        // Compare binops handles by `codegen_binop`.
 +        _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
 +    };
 +
 +    CValue::by_val(val, in_lhs.layout())
 +}
 +
 +pub(crate) fn codegen_checked_int_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
 +        assert_eq!(
 +            in_lhs.layout().ty,
 +            in_rhs.layout().ty,
 +            "checked int binop requires lhs and rhs of same type"
 +        );
 +    }
 +
 +    let lhs = in_lhs.load_scalar(fx);
 +    let rhs = in_rhs.load_scalar(fx);
 +
 +    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
 +        return res;
 +    }
 +
 +    let signed = type_sign(in_lhs.layout().ty);
 +
 +    let (res, has_overflow) = match bin_op {
 +        BinOp::Add => {
 +            /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
 +            (val, c_out)*/
 +            // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
 +            let val = fx.bcx.ins().iadd(lhs, rhs);
 +            let has_overflow = if !signed {
 +                fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
 +            } else {
 +                let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
 +                let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
 +                fx.bcx.ins().bxor(rhs_is_negative, slt)
 +            };
 +            (val, has_overflow)
 +        }
 +        BinOp::Sub => {
 +            /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
 +            (val, b_out)*/
 +            // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
 +            let val = fx.bcx.ins().isub(lhs, rhs);
 +            let has_overflow = if !signed {
 +                fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
 +            } else {
 +                let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
 +                let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
 +                fx.bcx.ins().bxor(rhs_is_negative, sgt)
 +            };
 +            (val, has_overflow)
 +        }
 +        BinOp::Mul => {
 +            let ty = fx.bcx.func.dfg.value_type(lhs);
 +            match ty {
 +                types::I8 | types::I16 | types::I32 if !signed => {
 +                    let lhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), lhs);
 +                    let rhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), rhs);
 +                    let val = fx.bcx.ins().imul(lhs, rhs);
 +                    let has_overflow = fx.bcx.ins().icmp_imm(
 +                        IntCC::UnsignedGreaterThan,
 +                        val,
 +                        (1 << ty.bits()) - 1,
 +                    );
 +                    let val = fx.bcx.ins().ireduce(ty, val);
 +                    (val, has_overflow)
 +                }
 +                types::I8 | types::I16 | types::I32 if signed => {
 +                    let lhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), lhs);
 +                    let rhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), rhs);
 +                    let val = fx.bcx.ins().imul(lhs, rhs);
 +                    let has_underflow =
 +                        fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, -(1 << (ty.bits() - 1)));
 +                    let has_overflow = fx.bcx.ins().icmp_imm(
 +                        IntCC::SignedGreaterThan,
 +                        val,
 +                        (1 << (ty.bits() - 1)) - 1,
 +                    );
 +                    let val = fx.bcx.ins().ireduce(ty, val);
 +                    (val, fx.bcx.ins().bor(has_underflow, has_overflow))
 +                }
 +                types::I64 => {
 +                    let val = fx.bcx.ins().imul(lhs, rhs);
 +                    let has_overflow = if !signed {
 +                        let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
 +                        fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
 +                    } else {
 +                        // Based on LLVM's instruction sequence for compiling
 +                        // a.checked_mul(b).is_some() to riscv64gc:
 +                        // mulh    a2, a0, a1
 +                        // mul     a0, a0, a1
 +                        // srai    a0, a0, 63
 +                        // xor     a0, a0, a2
 +                        // snez    a0, a0
 +                        let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
 +                        let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1));
 +                        let xor = fx.bcx.ins().bxor(val_hi, val_sign);
 +                        fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0)
 +                    };
 +                    (val, has_overflow)
 +                }
 +                types::I128 => {
 +                    unreachable!("i128 should have been handled by codegen_i128::maybe_codegen")
 +                }
 +                _ => unreachable!("invalid non-integer type {}", ty),
 +            }
 +        }
 +        BinOp::Shl => {
 +            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
 +            let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
 +            let val = fx.bcx.ins().ishl(lhs, masked_shift);
 +            let ty = fx.bcx.func.dfg.value_type(val);
 +            let max_shift = i64::from(ty.bits()) - 1;
 +            let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
 +            (val, has_overflow)
 +        }
 +        BinOp::Shr => {
 +            let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
 +            let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
 +            let val = if !signed {
 +                fx.bcx.ins().ushr(lhs, masked_shift)
 +            } else {
 +                fx.bcx.ins().sshr(lhs, masked_shift)
 +            };
 +            let ty = fx.bcx.func.dfg.value_type(val);
 +            let max_shift = i64::from(ty.bits()) - 1;
 +            let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
 +            (val, has_overflow)
 +        }
 +        _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
 +    };
 +
 +    let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
 +
 +    let out_layout = fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
 +    CValue::by_val_pair(res, has_overflow, out_layout)
 +}
 +
 +pub(crate) fn codegen_float_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
 +
 +    let lhs = in_lhs.load_scalar(fx);
 +    let rhs = in_rhs.load_scalar(fx);
 +
 +    let b = fx.bcx.ins();
 +    let res = match bin_op {
 +        BinOp::Add => b.fadd(lhs, rhs),
 +        BinOp::Sub => b.fsub(lhs, rhs),
 +        BinOp::Mul => b.fmul(lhs, rhs),
 +        BinOp::Div => b.fdiv(lhs, rhs),
 +        BinOp::Rem => {
 +            let name = match in_lhs.layout().ty.kind() {
 +                ty::Float(FloatTy::F32) => "fmodf",
 +                ty::Float(FloatTy::F64) => "fmod",
 +                _ => bug!(),
 +            };
 +            return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
 +        }
 +        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
 +            let fltcc = match bin_op {
 +                BinOp::Eq => FloatCC::Equal,
 +                BinOp::Lt => FloatCC::LessThan,
 +                BinOp::Le => FloatCC::LessThanOrEqual,
 +                BinOp::Ne => FloatCC::NotEqual,
 +                BinOp::Ge => FloatCC::GreaterThanOrEqual,
 +                BinOp::Gt => FloatCC::GreaterThan,
 +                _ => unreachable!(),
 +            };
 +            let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
 +            let val = fx.bcx.ins().bint(types::I8, val);
 +            return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
 +        }
 +        _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
 +    };
 +
 +    CValue::by_val(res, in_lhs.layout())
 +}
 +
 +pub(crate) fn codegen_ptr_binop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    bin_op: BinOp,
 +    in_lhs: CValue<'tcx>,
 +    in_rhs: CValue<'tcx>,
 +) -> CValue<'tcx> {
 +    let is_thin_ptr = in_lhs
 +        .layout()
 +        .ty
 +        .builtin_deref(true)
 +        .map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty))
 +        .unwrap_or(true);
 +
 +    if is_thin_ptr {
 +        match bin_op {
 +            BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
 +                let lhs = in_lhs.load_scalar(fx);
 +                let rhs = in_rhs.load_scalar(fx);
 +
 +                codegen_compare_bin_op(fx, bin_op, false, lhs, rhs)
 +            }
 +            BinOp::Offset => {
 +                let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty;
 +                let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
 +                let pointee_size = fx.layout_of(pointee_ty).size.bytes();
 +                let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
 +                let base_val = base.load_scalar(fx);
 +                let res = fx.bcx.ins().iadd(base_val, ptr_diff);
 +                CValue::by_val(res, base.layout())
 +            }
 +            _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
 +        }
 +    } else {
 +        let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx);
 +        let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx);
 +
 +        let res = match bin_op {
 +            BinOp::Eq => {
 +                let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
 +                let extra_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_extra, rhs_extra);
 +                fx.bcx.ins().band(ptr_eq, extra_eq)
 +            }
 +            BinOp::Ne => {
 +                let ptr_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_ptr, rhs_ptr);
 +                let extra_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_extra, rhs_extra);
 +                fx.bcx.ins().bor(ptr_ne, extra_ne)
 +            }
 +            BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
 +                let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
 +
 +                let ptr_cmp =
 +                    fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
 +                let extra_cmp = fx.bcx.ins().icmp(
 +                    bin_op_to_intcc(bin_op, false).unwrap(),
 +                    lhs_extra,
 +                    rhs_extra,
 +                );
 +
 +                fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
 +            }
 +            _ => panic!("bin_op {:?} on ptr", bin_op),
 +        };
 +
 +        CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
 +    }
 +}
++
++// In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
++// For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
++// and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
++// a float against itself. Only in case of NaN is it not equal to itself.
++pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
++    let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
++    let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
++    let temp = fx.bcx.ins().select(a_ge_b, b, a);
++    fx.bcx.ins().select(a_is_nan, b, temp)
++}
++
++pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
++    let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
++    let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
++    let temp = fx.bcx.ins().select(a_le_b, b, a);
++    fx.bcx.ins().select(a_is_nan, b, temp)
++}