]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '63734fcdd718cca089f84c42f3a42c0096cfd431' into sync_cg_clif-2022-05-15
authorbjorn3 <bjorn3@users.noreply.github.com>
Sun, 15 May 2022 10:32:19 +0000 (12:32 +0200)
committerbjorn3 <bjorn3@users.noreply.github.com>
Sun, 15 May 2022 10:32:19 +0000 (12:32 +0200)
24 files changed:
1  2 
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/build_system/mod.rs
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/rustc-clif.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/abi/mod.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs

index 3aba528abfd6d193bb09847884514a4cb32d9af1,0000000000000000000000000000000000000000..aa556a21bf8c30506b9f28471cf02b17af5cc5ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,184 @@@
-     - uses: actions/checkout@v2
 +name: CI
 +
 +on:
 +  - push
 +  - pull_request
 +
 +jobs:
 +  rustfmt:
 +    runs-on: ubuntu-latest
 +    timeout-minutes: 10
 +
 +    steps:
-     - uses: actions/checkout@v2
++    - uses: actions/checkout@v3
 +
 +    - name: Install rustfmt
 +      run: |
 +        rustup component add rustfmt
 +
 +    - name: Rustfmt
 +      run: |
 +        cargo fmt --check
 +
 +  build:
 +    runs-on: ${{ matrix.os }}
 +    timeout-minutes: 60
 +
 +    strategy:
 +      fail-fast: false
 +      matrix:
 +        include:
 +          - os: ubuntu-latest
 +          - os: macos-latest
 +          # cross-compile from Linux to Windows using mingw
 +          - os: ubuntu-latest
 +            env:
 +              TARGET_TRIPLE: x86_64-pc-windows-gnu
 +          - os: ubuntu-latest
 +            env:
 +              TARGET_TRIPLE: aarch64-unknown-linux-gnu
 +
 +    steps:
-     - uses: actions/checkout@v2
++    - uses: actions/checkout@v3
 +
 +    - name: Cache cargo installed crates
 +      uses: actions/cache@v2
 +      with:
 +        path: ~/.cargo/bin
 +        key: ${{ runner.os }}-cargo-installed-crates
 +
 +    - name: Cache cargo registry and index
 +      uses: actions/cache@v2
 +      with:
 +        path: |
 +            ~/.cargo/registry
 +            ~/.cargo/git
 +        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 +
 +    - name: Cache cargo target dir
 +      uses: actions/cache@v2
 +      with:
 +        path: target
 +        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 +
 +    - name: Install MinGW toolchain and wine
 +      if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
 +      run: |
 +        sudo apt-get update
 +        sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
 +        rustup target add x86_64-pc-windows-gnu
 +
 +    - name: Install AArch64 toolchain and qemu
 +      if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
 +      run: |
 +        sudo apt-get update
 +        sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
 +
 +    - name: Prepare dependencies
 +      run: |
 +        git config --global user.email "user@example.com"
 +        git config --global user.name "User"
 +        ./y.rs prepare
 +
 +    - name: Build without unstable features
 +      env:
 +        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
 +      # This is the config rust-lang/rust uses for builds
 +      run: ./y.rs build --no-unstable-features
 +
 +    - name: Build
 +      run: ./y.rs build --sysroot none
 +
 +    - name: Test
 +      env:
 +        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        # Reduce amount of benchmark runs as they are slow
 +        export COMPILE_RUNS=2
 +        export RUN_RUNS=2
 +
 +        # Enable extra checks
 +        export CG_CLIF_ENABLE_VERIFIER=1
 +
 +        ./test.sh
 +
 +    - name: Package prebuilt cg_clif
 +      run: tar cvfJ cg_clif.tar.xz build
 +
 +    - name: Upload prebuilt cg_clif
 +      if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
 +      uses: actions/upload-artifact@v2
 +      with:
 +        name: cg_clif-${{ runner.os }}
 +        path: cg_clif.tar.xz
 +
 +    - name: Upload prebuilt cg_clif (cross compile)
 +      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
 +      uses: actions/upload-artifact@v2
 +      with:
 +        name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
 +        path: cg_clif.tar.xz
 +
 +  build_windows:
 +    runs-on: windows-latest
 +    timeout-minutes: 60
 +
 +    steps:
++    - uses: actions/checkout@v3
 +
 +    #- name: Cache cargo installed crates
 +    #  uses: actions/cache@v2
 +    #  with:
 +    #    path: ~/.cargo/bin
 +    #    key: ${{ runner.os }}-cargo-installed-crates
 +
 +    #- name: Cache cargo registry and index
 +    #  uses: actions/cache@v2
 +    #  with:
 +    #    path: |
 +    #        ~/.cargo/registry
 +    #        ~/.cargo/git
 +    #    key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 +
 +    #- name: Cache cargo target dir
 +    #  uses: actions/cache@v2
 +    #  with:
 +    #    path: target
 +    #    key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 +
 +    - name: Prepare dependencies
 +      run: |
 +        git config --global user.email "user@example.com"
 +        git config --global user.name "User"
 +        git config --global core.autocrlf false
 +        rustup set default-host x86_64-pc-windows-gnu
 +        rustc y.rs -o y.exe -g
 +        ./y.exe prepare
 +
 +    - name: Build
 +      #name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        #export RUST_BACKTRACE=1
 +
 +        # Reduce amount of benchmark runs as they are slow
 +        #export COMPILE_RUNS=2
 +        #export RUN_RUNS=2
 +
 +        # Enable extra checks
 +        #export CG_CLIF_ENABLE_VERIFIER=1
 +
 +        ./y.exe build
 +
 +    - name: Package prebuilt cg_clif
 +      # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
 +      run: tar cvf cg_clif.tar build
 +
 +    - name: Upload prebuilt cg_clif
 +      uses: actions/upload-artifact@v2
 +      with:
 +        name: cg_clif-${{ runner.os }}
 +        path: cg_clif.tar
index a019793edd8d25481d6b1a4d733097b1fd3eaf89,0000000000000000000000000000000000000000..0a3e7ca073b45debb68785811cf0f727a7e0bde7
mode 100644,000000..100644
--- /dev/null
@@@ -1,59 -1,0 +1,59 @@@
-     - uses: actions/checkout@v2
 +name: Test nightly Cranelift
 +
 +on:
 +  push:
 +  schedule:
 +    - cron: '17 1 * * *' # At 01:17 UTC every day.
 +
 +jobs:
 +  build:
 +    runs-on: ubuntu-latest
 +    timeout-minutes: 60
 +
 +    steps:
-         sed -i 's/gimli = { version = "0.25.0", default-features = false, features = \["write"\]}/gimli = { version = "0.26.1", default-features = false, features = ["write"] }/' Cargo.toml
++    - uses: actions/checkout@v3
 +
 +    - name: Cache cargo installed crates
 +      uses: actions/cache@v2
 +      with:
 +        path: ~/.cargo/bin
 +        key: ubuntu-latest-cargo-installed-crates
 +
 +    - name: Prepare dependencies
 +      run: |
 +        git config --global user.email "user@example.com"
 +        git config --global user.name "User"
 +        ./y.rs prepare
 +
 +    - name: Patch Cranelift
 +      run: |
 +        sed -i 's/cranelift-codegen = { version = "\w*.\w*.\w*", features = \["unwind", "all-arch"\] }/cranelift-codegen = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", features = ["unwind", "all-arch"] }/' Cargo.toml
 +        sed -i 's/cranelift-frontend = "\w*.\w*.\w*"/cranelift-frontend = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 +        sed -i 's/cranelift-module = "\w*.\w*.\w*"/cranelift-module = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 +        sed -i 's/cranelift-native = "\w*.\w*.\w*"/cranelift-native = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 +        sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
 +        sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 +
++        sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
 +
 +        cat Cargo.toml
 +
 +    - name: Build without unstable features
 +      # This is the config rust-lang/rust uses for builds
 +      run: ./y.rs build --no-unstable-features
 +
 +    - name: Build
 +      run: ./y.rs build --sysroot none
 +    - name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        # Reduce amount of benchmark runs as they are slow
 +        export COMPILE_RUNS=2
 +        export RUN_RUNS=2
 +
 +        # Enable extra checks
 +        export CG_CLIF_ENABLE_VERIFIER=1
 +
 +        ./test.sh
index 1c08e5ece33d27e67fc01b5012f1ac237f2fc51c,0000000000000000000000000000000000000000..b8a98b83ebe5eb1a5d292f5fa6b2b7df1168a5a9
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,82 @@@
-     - uses: actions/checkout@v2
 +name: Various rustc tests
 +
 +on:
 +  - push
 +
 +jobs:
 +  bootstrap_rustc:
 +    runs-on: ubuntu-latest
 +
 +    steps:
-     - uses: actions/checkout@v2
++    - uses: actions/checkout@v3
 +
 +    - name: Cache cargo installed crates
 +      uses: actions/cache@v2
 +      with:
 +        path: ~/.cargo/bin
 +        key: ${{ runner.os }}-cargo-installed-crates
 +
 +    - name: Cache cargo registry and index
 +      uses: actions/cache@v2
 +      with:
 +        path: |
 +            ~/.cargo/registry
 +            ~/.cargo/git
 +        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 +
 +    - name: Cache cargo target dir
 +      uses: actions/cache@v2
 +      with:
 +        path: target
 +        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 +
 +    - name: Prepare dependencies
 +      run: |
 +        git config --global user.email "user@example.com"
 +        git config --global user.name "User"
 +        ./y.rs prepare
 +
 +    - name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        ./scripts/test_bootstrap.sh
 +  rustc_test_suite:
 +    runs-on: ubuntu-latest
 +
 +    steps:
++    - uses: actions/checkout@v3
 +
 +    - name: Cache cargo installed crates
 +      uses: actions/cache@v2
 +      with:
 +        path: ~/.cargo/bin
 +        key: ${{ runner.os }}-cargo-installed-crates
 +
 +    - name: Cache cargo registry and index
 +      uses: actions/cache@v2
 +      with:
 +        path: |
 +            ~/.cargo/registry
 +            ~/.cargo/git
 +        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
 +
 +    - name: Cache cargo target dir
 +      uses: actions/cache@v2
 +      with:
 +        path: target
 +        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 +
 +    - name: Prepare dependencies
 +      run: |
 +        git config --global user.email "user@example.com"
 +        git config --global user.name "User"
 +        ./y.rs prepare
 +
 +    - name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        ./scripts/test_rustc_tests.sh
index 74fde9c27c0e47475e96f95fed6dd695fce4986f,0000000000000000000000000000000000000000..ecb20f22d8c92005c4b488785c4cc428ccc8289e
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,74 @@@
-     "rust-analyzer.cargo.features": ["unstable-features"]
 +{
 +    // source for rustc_* is not included in the rust-src component; disable the errors about this
 +    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
 +    "rust-analyzer.assist.importGranularity": "module",
 +    "rust-analyzer.assist.importEnforceGranularity": true,
 +    "rust-analyzer.assist.importPrefix": "crate",
 +    "rust-analyzer.cargo.runBuildScripts": true,
++    "rust-analyzer.cargo.features": ["unstable-features"],
 +    "rust-analyzer.linkedProjects": [
 +        "./Cargo.toml",
 +        //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
 +        {
 +            "roots": [
 +                "./example/mini_core.rs",
 +                "./example/mini_core_hello_world.rs",
 +                "./example/mod_bench.rs"
 +            ],
 +            "crates": [
 +                {
 +                    "root_module": "./example/mini_core.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./example/mini_core_hello_world.rs",
 +                    "edition": "2018",
 +                    "deps": [{ "crate": 0, "name": "mini_core" }],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./example/mod_bench.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +            ]
 +        },
 +        {
 +            "roots": ["./scripts/filter_profile.rs"],
 +            "crates": [
 +                {
 +                    "root_module": "./scripts/filter_profile.rs",
 +                    "edition": "2018",
 +                    "deps": [{ "crate": 1, "name": "std" }],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +            ]
 +        },
 +        {
 +            "roots": ["./y.rs"],
 +            "crates": [
 +                {
 +                    "root_module": "./y.rs",
 +                    "edition": "2018",
 +                    "deps": [{ "crate": 1, "name": "std" }],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +            ]
 +        }
 +    ]
 +}
index 74f50808a980a7de298a943e74ac3c4301f07473,0000000000000000000000000000000000000000..18d7f41cf408a7713cf1fc4ae9066dad23987b8a
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,45 @@@
- # 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]
 +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 = []
 +
 +[package.metadata.rust-analyzer]
 +rustc_private = true
index 51ba0dbfcc7920e2868531cc897bd70c48a9909b,0000000000000000000000000000000000000000..efee6ef3f3780192943ec1b2dd34332d8692b57a
mode 100644,000000..100644
--- /dev/null
@@@ -1,332 -1,0 +1,332 @@@
- version = "0.12.0"
 +# 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"
 +version = "0.1.72"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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"
- checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
++version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.124"
++checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
 +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 = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
++version = "0.2.125"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "2.4.1"
++checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
 +dependencies = [
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "memchr"
- checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
++version = "2.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 +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 0a56eb131ed30f3a7e2a0bd13ef5e74a39569115,0000000000000000000000000000000000000000..48faec8bc4b9434f5e9f278d88d3e8a2f5149455
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,43 @@@
-     // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing
-     // LD_LIBRARY_PATH
-     if cfg!(unix) {
-         if cfg!(target_os = "macos") {
-             rustflags += " -Csplit-debuginfo=unpacked \
-                 -Clink-arg=-Wl,-rpath,@loader_path/../lib \
-                 -Zosx-rpath-install-name";
-         } else {
-             rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib ";
-         }
-     }
 +use std::env;
 +use std::path::{Path, PathBuf};
 +use std::process::Command;
 +
 +pub(crate) fn build_backend(
 +    channel: &str,
 +    host_triple: &str,
 +    use_unstable_features: bool,
 +) -> PathBuf {
 +    let mut cmd = Command::new("cargo");
 +    cmd.arg("build").arg("--target").arg(host_triple);
 +
 +    cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
 +
 +    let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
 +
 +    if env::var("CI").as_ref().map(|val| &**val) == Ok("true") {
 +        // Deny warnings on CI
 +        rustflags += " -Dwarnings";
 +
 +        // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
 +        cmd.env("CARGO_BUILD_INCREMENTAL", "false");
 +    }
 +
 +    if use_unstable_features {
 +        cmd.arg("--features").arg("unstable-features");
 +    }
 +
 +    match channel {
 +        "debug" => {}
 +        "release" => {
 +            cmd.arg("--release");
 +        }
 +        _ => unreachable!(),
 +    }
 +
 +    cmd.env("RUSTFLAGS", rustflags);
 +
 +    eprintln!("[BUILD] rustc_codegen_cranelift");
 +    super::utils::spawn_and_wait(cmd);
 +
 +    Path::new("target").join(host_triple).join(channel)
 +}
index c9c003d461095754bb0425786ab3ab796a3490b0,0000000000000000000000000000000000000000..8682204f4fd30b355fa0d11f83adbb1705af8eae
mode 100644,000000..100644
--- /dev/null
@@@ -1,217 -1,0 +1,219 @@@
- use std::env;
 +use std::fs;
 +use std::path::{Path, PathBuf};
 +use std::process::{self, Command};
 +
 +use super::rustc_info::{get_file_name, get_rustc_version};
 +use super::utils::{spawn_and_wait, try_hard_link};
 +use super::SysrootKind;
 +
 +pub(crate) fn build_sysroot(
 +    channel: &str,
 +    sysroot_kind: SysrootKind,
 +    target_dir: &Path,
 +    cg_clif_build_dir: PathBuf,
 +    host_triple: &str,
 +    target_triple: &str,
 +) {
 +    if target_dir.exists() {
 +        fs::remove_dir_all(target_dir).unwrap();
 +    }
 +    fs::create_dir_all(target_dir.join("bin")).unwrap();
 +    fs::create_dir_all(target_dir.join("lib")).unwrap();
 +
 +    // Copy the backend
-     for file in ["cg_clif", "cg_clif_build_sysroot"] {
-         try_hard_link(
-             cg_clif_build_dir.join(get_file_name(file, "bin")),
-             target_dir.join("bin").join(get_file_name(file, "bin")),
-         );
-     }
 +    let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
-     try_hard_link(
-         cg_clif_build_dir.join(&cg_clif_dylib),
-         target_dir
-             .join(if cfg!(windows) {
-                 // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
-                 // binaries.
-                 "bin"
-             } else {
-                 "lib"
-             })
-             .join(cg_clif_dylib),
-     );
-     // Build and copy cargo wrapper
-     let mut build_cargo_wrapper_cmd = Command::new("rustc");
-     build_cargo_wrapper_cmd
-         .arg("scripts/cargo-clif.rs")
-         .arg("-o")
-         .arg(target_dir.join("cargo-clif"))
-         .arg("-g");
-     spawn_and_wait(build_cargo_wrapper_cmd);
++    let cg_clif_dylib_path = target_dir
++        .join(if cfg!(windows) {
++            // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
++            // binaries.
++            "bin"
++        } else {
++            "lib"
++        })
++        .join(&cg_clif_dylib);
++    try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
++
++    // Build and copy rustc and cargo wrappers
++    for wrapper in ["rustc-clif", "cargo-clif"] {
++        let mut build_cargo_wrapper_cmd = Command::new("rustc");
++        build_cargo_wrapper_cmd
++            .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
++            .arg("-o")
++            .arg(target_dir.join(wrapper))
++            .arg("-g");
++        spawn_and_wait(build_cargo_wrapper_cmd);
++    }
 +
 +    let default_sysroot = super::rustc_info::get_default_sysroot();
 +
 +    let rustlib = target_dir.join("lib").join("rustlib");
 +    let host_rustlib_lib = rustlib.join(host_triple).join("lib");
 +    let target_rustlib_lib = rustlib.join(target_triple).join("lib");
 +    fs::create_dir_all(&host_rustlib_lib).unwrap();
 +    fs::create_dir_all(&target_rustlib_lib).unwrap();
 +
 +    if target_triple == "x86_64-pc-windows-gnu" {
 +        if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
 +            eprintln!(
 +                "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
 +                to compile a sysroot for it.",
 +            );
 +            process::exit(1);
 +        }
 +        for file in fs::read_dir(
 +            default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
 +        )
 +        .unwrap()
 +        {
 +            let file = file.unwrap().path();
 +            if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
 +                continue; // only copy object files
 +            }
 +            try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
 +        }
 +    }
 +
 +    match sysroot_kind {
 +        SysrootKind::None => {} // Nothing to do
 +        SysrootKind::Llvm => {
 +            for file in fs::read_dir(
 +                default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
 +            )
 +            .unwrap()
 +            {
 +                let file = file.unwrap().path();
 +                let file_name_str = file.file_name().unwrap().to_str().unwrap();
 +                if (file_name_str.contains("rustc_")
 +                    && !file_name_str.contains("rustc_std_workspace_")
 +                    && !file_name_str.contains("rustc_demangle"))
 +                    || file_name_str.contains("chalk")
 +                    || file_name_str.contains("tracing")
 +                    || file_name_str.contains("regex")
 +                {
 +                    // These are large crates that are part of the rustc-dev component and are not
 +                    // necessary to run regular programs.
 +                    continue;
 +                }
 +                try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
 +            }
 +
 +            if target_triple != host_triple {
 +                for file in fs::read_dir(
 +                    default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
 +                )
 +                .unwrap()
 +                {
 +                    let file = file.unwrap().path();
 +                    try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
 +                }
 +            }
 +        }
 +        SysrootKind::Clif => {
-             build_clif_sysroot_for_triple(channel, target_dir, host_triple, None);
++            build_clif_sysroot_for_triple(
++                channel,
++                target_dir,
++                host_triple,
++                &cg_clif_dylib_path,
++                None,
++            );
 +
 +            if host_triple != target_triple {
 +                // When cross-compiling it is often necessary to manually pick the right linker
 +                let linker = if target_triple == "aarch64-unknown-linux-gnu" {
 +                    Some("aarch64-linux-gnu-gcc")
 +                } else {
 +                    None
 +                };
-                 build_clif_sysroot_for_triple(channel, target_dir, target_triple, linker);
++                build_clif_sysroot_for_triple(
++                    channel,
++                    target_dir,
++                    target_triple,
++                    &cg_clif_dylib_path,
++                    linker,
++                );
 +            }
 +
 +            // Copy std for the host to the lib dir. This is necessary for the jit mode to find
 +            // libstd.
 +            for file in fs::read_dir(host_rustlib_lib).unwrap() {
 +                let file = file.unwrap().path();
-                 if file.file_name().unwrap().to_str().unwrap().contains("std-") {
++                let filename = file.file_name().unwrap().to_str().unwrap();
++                if filename.contains("std-") && !filename.contains(".rlib") {
 +                    try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn build_clif_sysroot_for_triple(
 +    channel: &str,
 +    target_dir: &Path,
 +    triple: &str,
++    cg_clif_dylib_path: &Path,
 +    linker: Option<&str>,
 +) {
 +    match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
 +        Err(e) => {
 +            eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
 +            eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
 +            process::exit(1);
 +        }
 +        Ok(source_version) => {
 +            let rustc_version = get_rustc_version();
 +            if source_version != rustc_version {
 +                eprintln!("The patched sysroot source is outdated");
 +                eprintln!("Source version: {}", source_version.trim());
 +                eprintln!("Rustc version:  {}", rustc_version.trim());
 +                eprintln!("Hint: Try `./y.rs prepare` to update the patched sysroot source");
 +                process::exit(1);
 +            }
 +        }
 +    }
 +
 +    let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
 +
 +    if !super::config::get_bool("keep_sysroot") {
-         // Cleanup the target dir with the exception of build scripts and the incremental cache
-         for dir in ["build", "deps", "examples", "native"] {
-             if build_dir.join(dir).exists() {
-                 fs::remove_dir_all(build_dir.join(dir)).unwrap();
-             }
++        // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
++        // recompilation as they are not affected by changes in cg_clif.
++        if build_dir.join("deps").exists() {
++            fs::remove_dir_all(build_dir.join("deps")).unwrap();
 +        }
 +    }
 +
 +    // Build sysroot
 +    let mut build_cmd = Command::new("cargo");
 +    build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
-     let mut rustflags = "--clif -Zforce-unstable-if-unmarked".to_string();
++    let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
++    rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
 +    if channel == "release" {
 +        build_cmd.arg("--release");
 +        rustflags.push_str(" -Zmir-opt-level=3");
 +    }
 +    if let Some(linker) = linker {
 +        use std::fmt::Write;
 +        write!(rustflags, " -Clinker={}", linker).unwrap();
 +    }
 +    build_cmd.env("RUSTFLAGS", rustflags);
-     build_cmd.env(
-         "RUSTC",
-         env::current_dir().unwrap().join(target_dir).join("bin").join("cg_clif_build_sysroot"),
-     );
 +    build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
 +    spawn_and_wait(build_cmd);
 +
 +    // Copy all relevant files to the sysroot
 +    for entry in
 +        fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
 +            .unwrap()
 +    {
 +        let entry = entry.unwrap();
 +        if let Some(ext) = entry.path().extension() {
 +            if ext == "rmeta" || ext == "d" || ext == "dSYM" {
 +                continue;
 +            }
 +        } else {
 +            continue;
 +        };
 +        try_hard_link(
 +            entry.path(),
 +            target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
 +        );
 +    }
 +}
index b228da3981fdb58913fe2ee7692188e083896f15,0000000000000000000000000000000000000000..b897b7fbacfcdf54426583790ed5116d2450ddd6
mode 100644,000000..100644
--- /dev/null
@@@ -1,127 -1,0 +1,128 @@@
 +use std::env;
 +use std::path::PathBuf;
 +use std::process;
 +
 +mod build_backend;
 +mod build_sysroot;
 +mod config;
 +mod prepare;
 +mod rustc_info;
 +mod utils;
 +
 +fn usage() {
 +    eprintln!("Usage:");
 +    eprintln!("  ./y.rs prepare");
 +    eprintln!(
 +        "  ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
 +    );
 +}
 +
 +macro_rules! arg_error {
 +    ($($err:tt)*) => {{
 +        eprintln!($($err)*);
 +        usage();
 +        std::process::exit(1);
 +    }};
 +}
 +
 +enum Command {
 +    Build,
 +}
 +
 +#[derive(Copy, Clone)]
 +pub(crate) enum SysrootKind {
 +    None,
 +    Clif,
 +    Llvm,
 +}
 +
 +pub fn main() {
 +    env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
 +    env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
 +    // The target dir is expected in the default location. Guard against the user changing it.
 +    env::set_var("CARGO_TARGET_DIR", "target");
 +
 +    let mut args = env::args().skip(1);
 +    let command = match args.next().as_deref() {
 +        Some("prepare") => {
 +            if args.next().is_some() {
 +                arg_error!("./x.rs prepare doesn't expect arguments");
 +            }
 +            prepare::prepare();
 +            process::exit(0);
 +        }
 +        Some("build") => Command::Build,
 +        Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
 +        Some(command) => arg_error!("Unknown command {}", command),
 +        None => {
 +            usage();
 +            process::exit(0);
 +        }
 +    };
 +
 +    let mut target_dir = PathBuf::from("build");
 +    let mut channel = "release";
 +    let mut sysroot_kind = SysrootKind::Clif;
 +    let mut use_unstable_features = true;
 +    while let Some(arg) = args.next().as_deref() {
 +        match arg {
 +            "--target-dir" => {
 +                target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
 +                    arg_error!("--target-dir requires argument");
 +                }))
 +            }
 +            "--debug" => channel = "debug",
 +            "--sysroot" => {
 +                sysroot_kind = match args.next().as_deref() {
 +                    Some("none") => SysrootKind::None,
 +                    Some("clif") => SysrootKind::Clif,
 +                    Some("llvm") => SysrootKind::Llvm,
 +                    Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
 +                    None => arg_error!("--sysroot requires argument"),
 +                }
 +            }
 +            "--no-unstable-features" => use_unstable_features = false,
 +            flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
 +            arg => arg_error!("Unexpected argument {}", arg),
 +        }
 +    }
++    target_dir = std::env::current_dir().unwrap().join(target_dir);
 +
 +    let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
 +        host_triple
 +    } else if let Some(host_triple) = config::get_value("host") {
 +        host_triple
 +    } else {
 +        rustc_info::get_host_triple()
 +    };
 +    let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
 +        if target_triple != "" {
 +            target_triple
 +        } else {
 +            host_triple.clone() // Empty target triple can happen on GHA
 +        }
 +    } else if let Some(target_triple) = config::get_value("target") {
 +        target_triple
 +    } else {
 +        host_triple.clone()
 +    };
 +
 +    if target_triple.ends_with("-msvc") {
 +        eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
 +        eprintln!("Switch to the MinGW toolchain for Windows support.");
 +        eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
 +        eprintln!("set the global default target to MinGW");
 +        process::exit(1);
 +    }
 +
 +    let cg_clif_build_dir =
 +        build_backend::build_backend(channel, &host_triple, use_unstable_features);
 +    build_sysroot::build_sysroot(
 +        channel,
 +        sysroot_kind,
 +        &target_dir,
 +        cg_clif_build_dir,
 +        &host_triple,
 +        &target_triple,
 +    );
 +}
index 785c7383783741701feea05580f26d527cfd0757,0000000000000000000000000000000000000000..33f146e7ba27aec13e57e55d40ebb79e3f28e359
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,67 @@@
- $ $cg_clif_dir/build/bin/cg_clif my_crate.rs
 +# Usage
 +
 +rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
 +
 +Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.rs prepare` and `y.rs build` or `test.sh`).
 +
 +## Cargo
 +
 +In the directory with your project (where you can do the usual `cargo build`), run:
 +
 +```bash
 +$ $cg_clif_dir/build/cargo-clif build
 +```
 +
 +This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
 +
 +## Rustc
 +
 +> You should prefer using the Cargo method.
 +
 +```bash
- $ $cg_clif_dir/build/bin/cg_clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
++$ $cg_clif_dir/build/rustc-clif my_crate.rs
 +```
 +
 +## Jit mode
 +
 +> âš âš âš  The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. âš âš âš 
 +
 +In jit mode cg_clif will immediately execute your code without creating an executable file.
 +
 +> This requires all dependencies to be available as dynamic library.
 +> The jit mode will probably need cargo integration to make this possible.
 +
 +```bash
 +$ $cg_clif_dir/build/cargo-clif jit
 +```
 +
 +or
 +
 +```bash
-     echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
++$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
 +```
 +
 +There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
 +first called.
 +
 +```bash
 +$ $cg_clif_dir/build/cargo-clif lazy-jit
 +```
 +
 +## Shell
 +
 +These are a few functions that allow you to easily run rust code from the shell using cg_clif as jit.
 +
 +```bash
 +function jit_naked() {
++    echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
 +}
 +
 +function jit() {
 +    jit_naked "fn main() { $@ }"
 +}
 +
 +function jit_calc() {
 +    jit 'println!("0x{:x}", ' $@ ');';
 +}
 +```
index 8e6652af3747b8bb6a93fceade8da19c371251f8,0000000000000000000000000000000000000000..ce1c6c99b40c8b9964e8549c9d82eb2c43b7d5f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,103 -1,0 +1,105 @@@
-  
 +From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001
 +From: bjorn3 <bjorn3@users.noreply.github.com>
 +Date: Thu, 18 Feb 2021 18:45:28 +0100
 +Subject: [PATCH] Disable 128bit atomic operations
 +
 +Cranelift doesn't support them yet
 +---
 + library/core/src/panic/unwind_safe.rs |  6 -----
 + library/core/src/sync/atomic.rs       | 38 ---------------------------
 + library/core/tests/atomic.rs          |  4 ---
 + 4 files changed, 4 insertions(+), 50 deletions(-)
 +
 +diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
 +index 092b7cf..158cf71 100644
 +--- a/library/core/src/panic/unwind_safe.rs
 ++++ b/library/core/src/panic/unwind_safe.rs
 +@@ -216,9 +216,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {}
 + #[cfg(target_has_atomic_load_store = "64")]
 + #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
 + impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
 +-#[cfg(target_has_atomic_load_store = "128")]
 +-#[unstable(feature = "integer_atomics", issue = "32976")]
 +-impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
-  
++
 + #[cfg(target_has_atomic_load_store = "ptr")]
 + #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 +@@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
 + #[cfg(target_has_atomic_load_store = "64")]
 + #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
 + impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
 +-#[cfg(target_has_atomic_load_store = "128")]
 +-#[unstable(feature = "integer_atomics", issue = "32976")]
 +-impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
- @@ -2234,44 +2234,6 @@ atomic_int! {
++
 + #[cfg(target_has_atomic_load_store = "8")]
 + #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 +diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
 +index d9de37e..8293fce 100644
 +--- a/library/core/src/sync/atomic.rs
 ++++ b/library/core/src/sync/atomic.rs
- -- 
++@@ -2234,46 +2234,6 @@ atomic_int! {
 +     "AtomicU64::new(0)",
 +     u64 AtomicU64 ATOMIC_U64_INIT
 + }
 +-#[cfg(target_has_atomic_load_store = "128")]
 +-atomic_int! {
 +-    cfg(target_has_atomic = "128"),
 +-    cfg(target_has_atomic_equal_alignment = "128"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
++-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
 +-    "i128",
 +-    "#![feature(integer_atomics)]\n\n",
 +-    atomic_min, atomic_max,
 +-    16,
 +-    "AtomicI128::new(0)",
 +-    i128 AtomicI128 ATOMIC_I128_INIT
 +-}
 +-#[cfg(target_has_atomic_load_store = "128")]
 +-atomic_int! {
 +-    cfg(target_has_atomic = "128"),
 +-    cfg(target_has_atomic_equal_alignment = "128"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
 +-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 +-    unstable(feature = "integer_atomics", issue = "32976"),
++-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
 +-    "u128",
 +-    "#![feature(integer_atomics)]\n\n",
 +-    atomic_umin, atomic_umax,
 +-    16,
 +-    "AtomicU128::new(0)",
 +-    u128 AtomicU128 ATOMIC_U128_INIT
 +-}
 + 
 + macro_rules! atomic_int_ptr_sized {
 +     ( $($target_pointer_width:literal $align:literal)* ) => { $(
 +diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
 +index b735957..ea728b6 100644
 +--- a/library/core/tests/atomic.rs
 ++++ b/library/core/tests/atomic.rs
 +@@ -185,10 +185,6 @@ fn atomic_alignment() {
 +     assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
 +     #[cfg(target_has_atomic = "64")]
 +     assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
 +-    #[cfg(target_has_atomic = "128")]
 +-    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
 +-    #[cfg(target_has_atomic = "128")]
 +-    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
 +     #[cfg(target_has_atomic = "ptr")]
 +     assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
 +     #[cfg(target_has_atomic = "ptr")]
++--
 +2.26.2.7.g19db9cfb68
 +
index 966097c248b6f6c98d6d250a369f5df0b8d797c9,0000000000000000000000000000000000000000..e98e92e468e93dacc140a5c23b22a147710917e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2022-04-21"
 +[toolchain]
++channel = "nightly-2022-05-15"
 +components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 41d82b581cd8cc07111c7f5b6a6f491a178dc801,0000000000000000000000000000000000000000..9362b47fa6d83137701069fc9c9aced1a9b0ab22
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,70 @@@
-     if env::var("RUSTC_WRAPPER").map_or(false, |wrapper| wrapper.contains("sccache")) {
-         eprintln!(
-             "\x1b[1;93m=== Warning: Unsetting RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
-         );
-         env::remove_var("RUSTC_WRAPPER");
-     }
 +use std::env;
 +#[cfg(unix)]
 +use std::os::unix::process::CommandExt;
 +use std::path::PathBuf;
 +use std::process::Command;
 +
 +fn main() {
-     env::set_var("RUSTC", sysroot.join("bin/cg_clif".to_string() + env::consts::EXE_SUFFIX));
-     let mut rustdoc_flags = env::var("RUSTDOCFLAGS").unwrap_or(String::new());
-     rustdoc_flags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
-     rustdoc_flags.push_str(
 +    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
 +
-     rustdoc_flags.push_str(" --sysroot ");
-     rustdoc_flags.push_str(sysroot.to_str().unwrap());
-     env::set_var("RUSTDOCFLAGS", rustdoc_flags);
++    let mut rustflags = String::new();
++    rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
++    rustflags.push_str(
 +        sysroot
 +            .join(if cfg!(windows) { "bin" } else { "lib" })
 +            .join(
 +                env::consts::DLL_PREFIX.to_string()
 +                    + "rustc_codegen_cranelift"
 +                    + env::consts::DLL_SUFFIX,
 +            )
 +            .to_str()
 +            .unwrap(),
 +    );
-                     "-Zunstable-features".to_string(),
++    rustflags.push_str(" --sysroot ");
++    rustflags.push_str(sysroot.to_str().unwrap());
++    env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags);
++    env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
 +
 +    // Ensure that the right toolchain is used
 +    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
 +
 +    let args: Vec<_> = match env::args().nth(1).as_deref() {
 +        Some("jit") => {
 +            env::set_var(
 +                "RUSTFLAGS",
 +                env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
 +            );
 +            IntoIterator::into_iter(["rustc".to_string()])
 +                .chain(env::args().skip(2))
 +                .chain([
 +                    "--".to_string(),
-                     "-Zunstable-features".to_string(),
++                    "-Zunstable-options".to_string(),
 +                    "-Cllvm-args=mode=jit".to_string(),
 +                ])
 +                .collect()
 +        }
 +        Some("lazy-jit") => {
 +            env::set_var(
 +                "RUSTFLAGS",
 +                env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
 +            );
 +            IntoIterator::into_iter(["rustc".to_string()])
 +                .chain(env::args().skip(2))
 +                .chain([
 +                    "--".to_string(),
++                    "-Zunstable-options".to_string(),
 +                    "-Cllvm-args=mode=jit-lazy".to_string(),
 +                ])
 +                .collect()
 +        }
 +        _ => env::args().skip(1).collect(),
 +    };
 +
 +    #[cfg(unix)]
 +    Command::new("cargo").args(args).exec();
 +
 +    #[cfg(not(unix))]
 +    std::process::exit(
 +        Command::new("cargo").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
 +    );
 +}
index f4e863e5494b51f34154bfc0730cd9758e73b999,0000000000000000000000000000000000000000..e6f60d1c0cb230985bf85311076b15199291a807
mode 100755,000000..100755
--- /dev/null
@@@ -1,126 -1,0 +1,125 @@@
- source scripts/config.sh
- RUSTC="$(pwd)/build/bin/cg_clif"
 +#!/usr/bin/env bash
 +#![forbid(unsafe_code)]/* This line is ignored by bash
 +# This block is ignored by rustc
 +pushd $(dirname "$0")/../
++RUSTC="$(pwd)/build/rustc-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 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3abfcd8ddc824e493c5f3a3f4086c6a9b4c989f4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,36 @@@
++use std::env;
++use std::ffi::OsString;
++#[cfg(unix)]
++use std::os::unix::process::CommandExt;
++use std::path::PathBuf;
++use std::process::Command;
++
++fn main() {
++    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
++
++    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
++        env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
++    );
++
++    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
++    args.push(OsString::from("-Cpanic=abort"));
++    args.push(OsString::from("-Zpanic-abort-tests"));
++    let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
++    codegen_backend_arg.push(cg_clif_dylib_path);
++    args.push(codegen_backend_arg);
++    if !args.contains(&OsString::from("--sysroot")) {
++        args.push(OsString::from("--sysroot"));
++        args.push(OsString::from(sysroot.to_str().unwrap()));
++    }
++
++    // Ensure that the right toolchain is used
++    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
++
++    #[cfg(unix)]
++    Command::new("rustc").args(args).exec();
++
++    #[cfg(not(unix))]
++    std::process::exit(
++        Command::new("rustc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
++    );
++}
index cabbaaa8922517351dc70eeb3bb0730f752b0c17,0000000000000000000000000000000000000000..4d0dfa16c5ecf88488e6a360b752e65fbb200012
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,64 @@@
- source scripts/config.sh
 +#!/usr/bin/env bash
 +set -e
 +
 +./y.rs build --no-unstable-features
- 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();
 +
 +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"
- rustc = "$(pwd)/../build/bin/cg_clif"
 +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/rustc-clif"
 +cargo = "$(rustup which cargo)"
 +full-bootstrap = true
 +local-rebuild = true
 +
 +[rust]
 +codegen-backends = ["cranelift"]
 +deny-warnings = false
 +verbose-tests = false
 +EOF
 +popd
index 4cf24c02235df731a81e36def7900d4c9e390afd,0000000000000000000000000000000000000000..9bdb9f22c549a56d34850f97cbf2461a0d83585d
mode 100755,000000..100755
--- /dev/null
@@@ -1,118 -1,0 +1,117 @@@
- rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
 +#!/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 "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/incremental/change_crate_dep_kind.rs
 +rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
 +
 +# 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/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/type-alias-impl-trait/assoc-projection-ice.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
 +
 +# bugs in the test suite
 +# ======================
 +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 aae626081f62be5c93b3e7d92c08c811105c4d8f,0000000000000000000000000000000000000000..9b5ffa4096049c04b9b2b509e9ec80107a7e1a92
mode 100755,000000..100755
--- /dev/null
@@@ -1,170 -1,0 +1,203 @@@
- 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"
 +#!/usr/bin/env bash
 +
 +set -e
 +
-     echo "[AOT] alloc_system"
++export CG_CLIF_DISPLAY_CG_TIME=1
++export CG_CLIF_DISABLE_INCR_CACHE=1
++
++export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
++export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
++
++export RUN_WRAPPER=''
++
++case "$TARGET_TRIPLE" in
++   x86_64*)
++      export JIT_SUPPORTED=1
++      ;;
++   *)
++      export JIT_SUPPORTED=0
++      ;;
++esac
++
++if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
++   export JIT_SUPPORTED=0
++   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
++      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
++      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
++      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
++   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
++      # We are cross-compiling for Windows. Run tests in wine.
++      export RUN_WRAPPER='wine'
++   else
++      echo "Unknown non-native platform"
++   fi
++fi
++
++# FIXME fix `#[linkage = "extern_weak"]` without this
++if [[ "$(uname)" == 'Darwin' ]]; then
++   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
++fi
++
++MY_RUSTC="$(pwd)/build/rustc-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] 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 "[BUILD] 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
 +
-         "RUSTC=rustc RUSTFLAGS='' cargo build" \
 +    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] 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 "[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" \
++        "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 ef56fb191bff5aabbbb884150ea83421b560c5b3,0000000000000000000000000000000000000000..b163a42619172d2739142d1f689a821ab8fcb3e1
mode 100644,000000..100644
--- /dev/null
@@@ -1,574 -1,0 +1,582 @@@
-     span: Span,
 +//! Handling of everything related to the calling convention. Also fills `fx.local_map`.
 +
 +mod comments;
 +mod pass_mode;
 +mod returning;
 +
 +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 +use rustc_middle::ty::layout::FnAbiOf;
 +use rustc_target::abi::call::{Conv, FnAbi};
 +use rustc_target::spec::abi::Abi;
 +
 +use cranelift_codegen::ir::{AbiParam, SigRef};
 +
 +use self::pass_mode::*;
 +use crate::prelude::*;
 +
 +pub(crate) use self::returning::codegen_return;
 +
 +fn clif_sig_from_fn_abi<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    default_call_conv: CallConv,
 +    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 +) -> Signature {
 +    let call_conv = match fn_abi.conv {
 +        Conv::Rust | Conv::C => default_call_conv,
 +        Conv::X86_64SysV => CallConv::SystemV,
 +        Conv::X86_64Win64 => CallConv::WindowsFastcall,
 +        Conv::ArmAapcs
 +        | Conv::CCmseNonSecureCall
 +        | Conv::Msp430Intr
 +        | Conv::PtxKernel
 +        | Conv::X86Fastcall
 +        | Conv::X86Intr
 +        | Conv::X86Stdcall
 +        | Conv::X86ThisCall
 +        | Conv::X86VectorCall
 +        | Conv::AmdGpuKernel
 +        | Conv::AvrInterrupt
 +        | Conv::AvrNonBlockingInterrupt => todo!("{:?}", fn_abi.conv),
 +    };
 +    let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
 +
 +    let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
 +    // Sometimes the first param is an pointer to the place where the return value needs to be stored.
 +    let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
 +
 +    Signature { params, returns, call_conv }
 +}
 +
 +pub(crate) fn get_function_sig<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    triple: &target_lexicon::Triple,
 +    inst: Instance<'tcx>,
 +) -> Signature {
 +    assert!(!inst.substs.needs_infer());
 +    clif_sig_from_fn_abi(
 +        tcx,
 +        CallConv::triple_default(triple),
 +        &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
 +    )
 +}
 +
 +/// Instance must be monomorphized
 +pub(crate) fn import_function<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    module: &mut dyn Module,
 +    inst: Instance<'tcx>,
 +) -> FuncId {
 +    let name = tcx.symbol_name(inst).name;
 +    let sig = get_function_sig(tcx, module.isa().triple(), inst);
 +    module.declare_function(name, Linkage::Import, &sig).unwrap()
 +}
 +
 +impl<'tcx> FunctionCx<'_, '_, 'tcx> {
 +    /// Instance must be monomorphized
 +    pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
 +        let func_id = import_function(self.tcx, self.module, inst);
 +        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
 +
 +        if self.clif_comments.enabled() {
 +            self.add_comment(func_ref, format!("{:?}", inst));
 +        }
 +
 +        func_ref
 +    }
 +
 +    pub(crate) fn lib_call(
 +        &mut self,
 +        name: &str,
 +        params: Vec<AbiParam>,
 +        returns: Vec<AbiParam>,
 +        args: &[Value],
 +    ) -> &[Value] {
 +        let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
 +        let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
 +        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
 +        if self.clif_comments.enabled() {
 +            self.add_comment(func_ref, format!("{:?}", name));
 +        }
 +        let call_inst = self.bcx.ins().call(func_ref, args);
 +        if self.clif_comments.enabled() {
 +            self.add_comment(call_inst, format!("easy_call {}", name));
 +        }
 +        let results = self.bcx.inst_results(call_inst);
 +        assert!(results.len() <= 2, "{}", results.len());
 +        results
 +    }
 +
 +    pub(crate) fn easy_call(
 +        &mut self,
 +        name: &str,
 +        args: &[CValue<'tcx>],
 +        return_ty: Ty<'tcx>,
 +    ) -> CValue<'tcx> {
 +        let (input_tys, args): (Vec<_>, Vec<_>) = args
 +            .iter()
 +            .map(|arg| {
 +                (AbiParam::new(self.clif_type(arg.layout().ty).unwrap()), arg.load_scalar(self))
 +            })
 +            .unzip();
 +        let return_layout = self.layout_of(return_ty);
 +        let return_tys = if let ty::Tuple(tup) = return_ty.kind() {
 +            tup.iter().map(|ty| AbiParam::new(self.clif_type(ty).unwrap())).collect()
 +        } else {
 +            vec![AbiParam::new(self.clif_type(return_ty).unwrap())]
 +        };
 +        let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
 +        match *ret_vals {
 +            [] => CValue::by_ref(
 +                Pointer::const_addr(self, i64::from(self.pointer_type.bytes())),
 +                return_layout,
 +            ),
 +            [val] => CValue::by_val(val, return_layout),
 +            [val, extra] => CValue::by_val_pair(val, extra, return_layout),
 +            _ => unreachable!(),
 +        }
 +    }
 +}
 +
 +/// Make a [`CPlace`] capable of holding value of the specified type.
 +fn make_local_place<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    local: Local,
 +    layout: TyAndLayout<'tcx>,
 +    is_ssa: bool,
 +) -> CPlace<'tcx> {
 +    let place = if is_ssa {
 +        if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
 +            CPlace::new_var_pair(fx, local, layout)
 +        } else {
 +            CPlace::new_var(fx, local, layout)
 +        }
 +    } else {
 +        CPlace::new_stack_slot(fx, layout)
 +    };
 +
 +    self::comments::add_local_place_comments(fx, place, local);
 +
 +    place
 +}
 +
 +pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_block: Block) {
 +    fx.bcx.append_block_params_for_function_params(start_block);
 +
 +    fx.bcx.switch_to_block(start_block);
 +    fx.bcx.ins().nop();
 +
 +    let ssa_analyzed = crate::analyze::analyze(fx);
 +
 +    self::comments::add_args_header_comment(fx);
 +
 +    let mut block_params_iter = fx.bcx.func.dfg.block_params(start_block).to_vec().into_iter();
 +    let ret_place =
 +        self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
 +    assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);
 +
 +    // None means pass_mode == NoPass
 +    enum ArgKind<'tcx> {
 +        Normal(Option<CValue<'tcx>>),
 +        Spread(Vec<Option<CValue<'tcx>>>),
 +    }
 +
 +    let fn_abi = fx.fn_abi.take().unwrap();
 +    let mut arg_abis_iter = fn_abi.args.iter();
 +
 +    let func_params = fx
 +        .mir
 +        .args_iter()
 +        .map(|local| {
 +            let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);
 +
 +            // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
 +            if Some(local) == fx.mir.spread_arg {
 +                // This argument (e.g. the last argument in the "rust-call" ABI)
 +                // is a tuple that was spread at the ABI level and now we have
 +                // to reconstruct it into a tuple local variable, from multiple
 +                // individual function arguments.
 +
 +                let tupled_arg_tys = match arg_ty.kind() {
 +                    ty::Tuple(ref tys) => tys,
 +                    _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
 +                };
 +
 +                let mut params = Vec::new();
 +                for (i, _arg_ty) in tupled_arg_tys.iter().enumerate() {
 +                    let arg_abi = arg_abis_iter.next().unwrap();
 +                    let param =
 +                        cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
 +                    params.push(param);
 +                }
 +
 +                (local, ArgKind::Spread(params), arg_ty)
 +            } else {
 +                let arg_abi = arg_abis_iter.next().unwrap();
 +                let param =
 +                    cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
 +                (local, ArgKind::Normal(param), arg_ty)
 +            }
 +        })
 +        .collect::<Vec<(Local, ArgKind<'tcx>, Ty<'tcx>)>>();
 +
 +    assert!(fx.caller_location.is_none());
 +    if fx.instance.def.requires_caller_location(fx.tcx) {
 +        // Store caller location for `#[track_caller]`.
 +        let arg_abi = arg_abis_iter.next().unwrap();
 +        fx.caller_location =
 +            Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
 +    }
 +
 +    assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind");
 +    fx.fn_abi = Some(fn_abi);
 +    assert!(block_params_iter.next().is_none(), "arg_value left behind");
 +
 +    self::comments::add_locals_header_comment(fx);
 +
 +    for (local, arg_kind, ty) in func_params {
 +        let layout = fx.layout_of(ty);
 +
 +        let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
 +
 +        // While this is normally an optimization to prevent an unnecessary copy when an argument is
 +        // not mutated by the current function, this is necessary to support unsized arguments.
 +        if let ArgKind::Normal(Some(val)) = arg_kind {
 +            if let Some((addr, meta)) = val.try_to_ptr() {
 +                // Ownership of the value at the backing storage for an argument is passed to the
 +                // callee per the ABI, so it is fine to borrow the backing storage of this argument
 +                // to prevent a copy.
 +
 +                let place = if let Some(meta) = meta {
 +                    CPlace::for_ptr_with_extra(addr, meta, val.layout())
 +                } else {
 +                    CPlace::for_ptr(addr, val.layout())
 +                };
 +
 +                self::comments::add_local_place_comments(fx, place, local);
 +
 +                assert_eq!(fx.local_map.push(place), local);
 +                continue;
 +            }
 +        }
 +
 +        let place = make_local_place(fx, local, layout, is_ssa);
 +        assert_eq!(fx.local_map.push(place), local);
 +
 +        match arg_kind {
 +            ArgKind::Normal(param) => {
 +                if let Some(param) = param {
 +                    place.write_cvalue(fx, param);
 +                }
 +            }
 +            ArgKind::Spread(params) => {
 +                for (i, param) in params.into_iter().enumerate() {
 +                    if let Some(param) = param {
 +                        place.place_field(fx, mir::Field::new(i)).write_cvalue(fx, param);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    for local in fx.mir.vars_and_temps_iter() {
 +        let ty = fx.monomorphize(fx.mir.local_decls[local].ty);
 +        let layout = fx.layout_of(ty);
 +
 +        let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
 +
 +        let place = make_local_place(fx, local, layout, is_ssa);
 +        assert_eq!(fx.local_map.push(place), local);
 +    }
 +
 +    fx.bcx.ins().jump(*fx.block_map.get(START_BLOCK).unwrap(), &[]);
 +}
 +
 +struct CallArgument<'tcx> {
 +    value: CValue<'tcx>,
 +    is_owned: bool,
 +}
 +
 +// FIXME avoid intermediate `CValue` before calling `adjust_arg_for_abi`
 +fn codegen_call_argument_operand<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    operand: &Operand<'tcx>,
 +) -> CallArgument<'tcx> {
 +    CallArgument {
 +        value: codegen_operand(fx, operand),
 +        is_owned: matches!(operand, Operand::Move(_)),
 +    }
 +}
 +
 +pub(crate) fn codegen_terminator_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
-                 crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span);
++    source_info: mir::SourceInfo,
 +    func: &Operand<'tcx>,
 +    args: &[Operand<'tcx>],
 +    mir_dest: Option<(Place<'tcx>, BasicBlock)>,
 +) {
 +    let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
 +    let fn_sig =
 +        fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
 +
 +    let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb));
 +
 +    // Handle special calls like instrinsics and empty drop glue.
 +    let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
 +        let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
 +            .unwrap()
 +            .unwrap()
 +            .polymorphize(fx.tcx);
 +
 +        if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
 +            crate::intrinsics::codegen_llvm_intrinsic_call(
 +                fx,
 +                &fx.tcx.symbol_name(instance).name,
 +                substs,
 +                args,
 +                destination,
 +            );
 +            return;
 +        }
 +
 +        match instance.def {
 +            InstanceDef::Intrinsic(_) => {
-         let caller_location = fx.get_caller_location(span);
++                crate::intrinsics::codegen_intrinsic_call(
++                    fx,
++                    instance,
++                    args,
++                    destination,
++                    source_info,
++                );
 +                return;
 +            }
 +            InstanceDef::DropGlue(_, None) => {
 +                // empty drop glue - a nop.
 +                let (_, dest) = destination.expect("Non terminating drop_in_place_real???");
 +                let ret_block = fx.get_block(dest);
 +                fx.bcx.ins().jump(ret_block, &[]);
 +                return;
 +            }
 +            _ => Some(instance),
 +        }
 +    } else {
 +        None
 +    };
 +
 +    let extra_args = &args[fn_sig.inputs().len()..];
 +    let extra_args = fx
 +        .tcx
 +        .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
 +    let fn_abi = if let Some(instance) = instance {
 +        RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
 +    } else {
 +        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
 +    };
 +
 +    let is_cold = instance
 +        .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
 +        .unwrap_or(false);
 +    if is_cold {
 +        fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
 +        if let Some((_place, destination_block)) = destination {
 +            fx.bcx.set_cold_block(fx.get_block(destination_block));
 +        }
 +    }
 +
 +    // Unpack arguments tuple for closures
 +    let mut args = if fn_sig.abi == Abi::RustCall {
 +        assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
 +        let self_arg = codegen_call_argument_operand(fx, &args[0]);
 +        let pack_arg = codegen_call_argument_operand(fx, &args[1]);
 +
 +        let tupled_arguments = match pack_arg.value.layout().ty.kind() {
 +            ty::Tuple(ref tupled_arguments) => tupled_arguments,
 +            _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
 +        };
 +
 +        let mut args = Vec::with_capacity(1 + tupled_arguments.len());
 +        args.push(self_arg);
 +        for i in 0..tupled_arguments.len() {
 +            args.push(CallArgument {
 +                value: pack_arg.value.value_field(fx, mir::Field::new(i)),
 +                is_owned: pack_arg.is_owned,
 +            });
 +        }
 +        args
 +    } else {
 +        args.iter().map(|arg| codegen_call_argument_operand(fx, arg)).collect::<Vec<_>>()
 +    };
 +
 +    // Pass the caller location for `#[track_caller]`.
 +    if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
-                 fx.tcx
-                     .sess
-                     .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
++        let caller_location = fx.get_caller_location(source_info);
 +        args.push(CallArgument { value: caller_location, is_owned: false });
 +    }
 +
 +    let args = args;
 +    assert_eq!(fn_abi.args.len(), args.len());
 +
 +    enum CallTarget {
 +        Direct(FuncRef),
 +        Indirect(SigRef, Value),
 +    }
 +
 +    let (func_ref, first_arg_override) = match instance {
 +        // Trait object call
 +        Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => {
 +            if fx.clif_comments.enabled() {
 +                let nop_inst = fx.bcx.ins().nop();
 +                fx.add_comment(
 +                    nop_inst,
 +                    format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]),
 +                );
 +            }
 +
 +            let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx);
 +            let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
 +            let sig = fx.bcx.import_signature(sig);
 +
 +            (CallTarget::Indirect(sig, method), Some(ptr))
 +        }
 +
 +        // Normal call
 +        Some(instance) => {
 +            let func_ref = fx.get_function_ref(instance);
 +            (CallTarget::Direct(func_ref), None)
 +        }
 +
 +        // Indirect call
 +        None => {
 +            if fx.clif_comments.enabled() {
 +                let nop_inst = fx.bcx.ins().nop();
 +                fx.add_comment(nop_inst, "indirect call");
 +            }
 +
 +            let func = codegen_operand(fx, func).load_scalar(fx);
 +            let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
 +            let sig = fx.bcx.import_signature(sig);
 +
 +            (CallTarget::Indirect(sig, func), None)
 +        }
 +    };
 +
 +    let ret_place = destination.map(|(place, _)| place);
 +    self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
 +        let call_args = return_ptr
 +            .into_iter()
 +            .chain(first_arg_override.into_iter())
 +            .chain(
 +                args.into_iter()
 +                    .enumerate()
 +                    .skip(if first_arg_override.is_some() { 1 } else { 0 })
 +                    .map(|(i, arg)| {
 +                        adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
 +                    })
 +                    .flatten(),
 +            )
 +            .collect::<Vec<Value>>();
 +
 +        let call_inst = match func_ref {
 +            CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
 +            CallTarget::Indirect(sig, func_ptr) => {
 +                fx.bcx.ins().call_indirect(sig, func_ptr, &call_args)
 +            }
 +        };
 +
 +        // FIXME find a cleaner way to support varargs
 +        if fn_sig.c_variadic {
 +            if !matches!(fn_sig.abi, Abi::C { .. }) {
-                         fx.tcx
-                             .sess
-                             .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
++                fx.tcx.sess.span_fatal(
++                    source_info.span,
++                    &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
++                );
 +            }
 +            let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
 +            let abi_params = call_args
 +                .into_iter()
 +                .map(|arg| {
 +                    let ty = fx.bcx.func.dfg.value_type(arg);
 +                    if !ty.is_int() {
 +                        // FIXME set %al to upperbound on float args once floats are supported
-     span: Span,
++                        fx.tcx.sess.span_fatal(
++                            source_info.span,
++                            &format!("Non int ty {:?} for variadic call", ty),
++                        );
 +                    }
 +                    AbiParam::new(ty)
 +                })
 +                .collect::<Vec<AbiParam>>();
 +            fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
 +        }
 +
 +        call_inst
 +    });
 +
 +    if let Some((_, dest)) = destination {
 +        let ret_block = fx.get_block(dest);
 +        fx.bcx.ins().jump(ret_block, &[]);
 +    } else {
 +        fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 +    }
 +}
 +
 +pub(crate) fn codegen_drop<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
-                     let caller_location = fx.get_caller_location(span);
++    source_info: mir::SourceInfo,
 +    drop_place: CPlace<'tcx>,
 +) {
 +    let ty = drop_place.layout().ty;
 +    let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
 +
 +    if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
 +        // we don't actually need to drop anything
 +    } else {
 +        match ty.kind() {
 +            ty::Dynamic(..) => {
 +                let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
 +                let ptr = ptr.get_addr(fx);
 +                let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
 +
 +                // FIXME(eddyb) perhaps move some of this logic into
 +                // `Instance::resolve_drop_in_place`?
 +                let virtual_drop = Instance {
 +                    def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
 +                    substs: drop_instance.substs,
 +                };
 +                let fn_abi =
 +                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
 +
 +                let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
 +                let sig = fx.bcx.import_signature(sig);
 +                fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
 +            }
 +            _ => {
 +                assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
 +
 +                let fn_abi =
 +                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
 +
 +                let arg_value = drop_place.place_ref(
 +                    fx,
 +                    fx.layout_of(fx.tcx.mk_ref(
 +                        fx.tcx.lifetimes.re_erased,
 +                        TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
 +                    )),
 +                );
 +                let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true);
 +
 +                let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>();
 +
 +                if drop_instance.def.requires_caller_location(fx.tcx) {
 +                    // Pass the caller location for `#[track_caller]`.
++                    let caller_location = fx.get_caller_location(source_info);
 +                    call_args.extend(
 +                        adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
 +                    );
 +                }
 +
 +                let func_ref = fx.get_function_ref(drop_instance);
 +                fx.bcx.ins().call(func_ref, &call_args);
 +            }
 +        }
 +    }
 +}
index 65346cb39622aa0e7bc2a7de747820af62b3d519,0000000000000000000000000000000000000000..65e5812a8a5b0e00f35b57a5ddf399af51c040f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,935 -1,0 +1,945 @@@
-                         let location = fx.get_caller_location(source_info.span).load_scalar(fx);
 +//! 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);
-                         codegen_panic(fx, msg_str, source_info.span);
++                        let location = fx.get_caller_location(source_info).load_scalar(fx);
 +
 +                        codegen_panic_inner(
 +                            fx,
 +                            rustc_hir::LangItem::PanicBoundsCheck,
 +                            &[index, len, location],
 +                            source_info.span,
 +                        );
 +                    }
 +                    _ => {
 +                        let msg_str = msg.description();
-                     crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
++                        codegen_panic(fx, msg_str, source_info);
 +                    }
 +                }
 +            }
 +
 +            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_drop(fx, source_info.span, drop_place);
++                    crate::abi::codegen_terminator_call(
++                        fx,
++                        mir::SourceInfo { span: *fn_span, ..source_info },
++                        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);
-     #[cfg(disabled)]
++                crate::abi::codegen_drop(fx, source_info, 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);
 +
- 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);
++    #[cfg(any())] // This is never true
 +    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_),
 +    }
 +}
 +
-     codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span);
++pub(crate) fn codegen_panic<'tcx>(
++    fx: &mut FunctionCx<'_, '_, 'tcx>,
++    msg_str: &str,
++    source_info: mir::SourceInfo,
++) {
++    let location = fx.get_caller_location(source_info).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, source_info.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 ffa629ca16c8b19d7bbc372fcc4055c8d94262a8,0000000000000000000000000000000000000000..f9dc1b5169e1a624c35949691a5a8f0f6f0e6f8c
mode 100644,000000..100644
--- /dev/null
@@@ -1,451 -1,0 +1,475 @@@
-     pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
-         if let Some(loc) = self.caller_location {
-             // `#[track_caller]` is used; return caller location instead of current location.
-             return loc;
 +use cranelift_codegen::isa::TargetFrontendConfig;
 +use rustc_index::vec::IndexVec;
 +use rustc_middle::ty::layout::{
 +    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
 +};
 +use rustc_middle::ty::SymbolName;
 +use rustc_target::abi::call::FnAbi;
 +use rustc_target::abi::{Integer, Primitive};
 +use rustc_target::spec::{HasTargetSpec, Target};
 +
 +use crate::constant::ConstantCx;
 +use crate::prelude::*;
 +
 +pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
 +    match tcx.data_layout.pointer_size.bits() {
 +        16 => types::I16,
 +        32 => types::I32,
 +        64 => types::I64,
 +        bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
 +    }
 +}
 +
 +pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
 +    match scalar.primitive() {
 +        Primitive::Int(int, _sign) => match int {
 +            Integer::I8 => types::I8,
 +            Integer::I16 => types::I16,
 +            Integer::I32 => types::I32,
 +            Integer::I64 => types::I64,
 +            Integer::I128 => types::I128,
 +        },
 +        Primitive::F32 => types::F32,
 +        Primitive::F64 => types::F64,
 +        Primitive::Pointer => pointer_ty(tcx),
 +    }
 +}
 +
 +fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Type> {
 +    Some(match ty.kind() {
 +        ty::Bool => types::I8,
 +        ty::Uint(size) => match size {
 +            UintTy::U8 => types::I8,
 +            UintTy::U16 => types::I16,
 +            UintTy::U32 => types::I32,
 +            UintTy::U64 => types::I64,
 +            UintTy::U128 => types::I128,
 +            UintTy::Usize => pointer_ty(tcx),
 +        },
 +        ty::Int(size) => match size {
 +            IntTy::I8 => types::I8,
 +            IntTy::I16 => types::I16,
 +            IntTy::I32 => types::I32,
 +            IntTy::I64 => types::I64,
 +            IntTy::I128 => types::I128,
 +            IntTy::Isize => pointer_ty(tcx),
 +        },
 +        ty::Char => types::I32,
 +        ty::Float(size) => match size {
 +            FloatTy::F32 => types::F32,
 +            FloatTy::F64 => types::F64,
 +        },
 +        ty::FnPtr(_) => pointer_ty(tcx),
 +        ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
 +            if has_ptr_meta(tcx, *pointee_ty) {
 +                return None;
 +            } else {
 +                pointer_ty(tcx)
 +            }
 +        }
 +        ty::Adt(adt_def, _) if adt_def.repr().simd() => {
 +            let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi
 +            {
 +                Abi::Vector { element, count } => (element.clone(), *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 => vector_ty,
 +                _ => return None,
 +            }
 +        }
 +        ty::Param(_) => bug!("ty param {:?}", ty),
 +        _ => return None,
 +    })
 +}
 +
 +fn clif_pair_type_from_ty<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    ty: Ty<'tcx>,
 +) -> Option<(types::Type, types::Type)> {
 +    Some(match ty.kind() {
 +        ty::Tuple(types) if types.len() == 2 => {
 +            let a = clif_type_from_ty(tcx, types[0])?;
 +            let b = clif_type_from_ty(tcx, types[1])?;
 +            if a.is_vector() || b.is_vector() {
 +                return None;
 +            }
 +            (a, b)
 +        }
 +        ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
 +            if has_ptr_meta(tcx, *pointee_ty) {
 +                (pointer_ty(tcx), pointer_ty(tcx))
 +            } else {
 +                return None;
 +            }
 +        }
 +        _ => return None,
 +    })
 +}
 +
 +/// Is a pointer to this type a fat ptr?
 +pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
 +    let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
 +    match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi {
 +        Abi::Scalar(_) => false,
 +        Abi::ScalarPair(_, _) => true,
 +        abi => unreachable!("Abi of ptr to {:?} is {:?}???", ty, abi),
 +    }
 +}
 +
 +pub(crate) fn codegen_icmp_imm(
 +    fx: &mut FunctionCx<'_, '_, '_>,
 +    intcc: IntCC,
 +    lhs: Value,
 +    rhs: i128,
 +) -> Value {
 +    let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
 +    if lhs_ty == types::I128 {
 +        // FIXME legalize `icmp_imm.i128` in Cranelift
 +
 +        let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs);
 +        let (rhs_lsb, rhs_msb) = (rhs as u128 as u64 as i64, (rhs as u128 >> 64) as u64 as i64);
 +
 +        match intcc {
 +            IntCC::Equal => {
 +                let lsb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_lsb, rhs_lsb);
 +                let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb);
 +                fx.bcx.ins().band(lsb_eq, msb_eq)
 +            }
 +            IntCC::NotEqual => {
 +                let lsb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_lsb, rhs_lsb);
 +                let msb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_msb, rhs_msb);
 +                fx.bcx.ins().bor(lsb_ne, msb_ne)
 +            }
 +            _ => {
 +                // if msb_eq {
 +                //     lsb_cc
 +                // } else {
 +                //     msb_cc
 +                // }
 +
 +                let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb);
 +                let lsb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_lsb, rhs_lsb);
 +                let msb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_msb, rhs_msb);
 +
 +                fx.bcx.ins().select(msb_eq, lsb_cc, msb_cc)
 +            }
 +        }
 +    } else {
 +        let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int");
 +        fx.bcx.ins().icmp_imm(intcc, lhs, rhs)
 +    }
 +}
 +
 +pub(crate) fn type_min_max_value(
 +    bcx: &mut FunctionBuilder<'_>,
 +    ty: Type,
 +    signed: bool,
 +) -> (Value, Value) {
 +    assert!(ty.is_int());
 +
 +    if ty == types::I128 {
 +        if signed {
 +            let min = i128::MIN as u128;
 +            let min_lsb = bcx.ins().iconst(types::I64, min as u64 as i64);
 +            let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64);
 +            let min = bcx.ins().iconcat(min_lsb, min_msb);
 +
 +            let max = i128::MAX as u128;
 +            let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64);
 +            let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64);
 +            let max = bcx.ins().iconcat(max_lsb, max_msb);
 +
 +            return (min, max);
 +        } else {
 +            let min_half = bcx.ins().iconst(types::I64, 0);
 +            let min = bcx.ins().iconcat(min_half, min_half);
 +
 +            let max_half = bcx.ins().iconst(types::I64, u64::MAX as i64);
 +            let max = bcx.ins().iconcat(max_half, max_half);
 +
 +            return (min, max);
 +        }
 +    }
 +
 +    let min = match (ty, signed) {
 +        (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => {
 +            0i64
 +        }
 +        (types::I8, true) => i64::from(i8::MIN),
 +        (types::I16, true) => i64::from(i16::MIN),
 +        (types::I32, true) => i64::from(i32::MIN),
 +        (types::I64, true) => i64::MIN,
 +        _ => unreachable!(),
 +    };
 +
 +    let max = match (ty, signed) {
 +        (types::I8, false) => i64::from(u8::MAX),
 +        (types::I16, false) => i64::from(u16::MAX),
 +        (types::I32, false) => i64::from(u32::MAX),
 +        (types::I64, false) => u64::MAX as i64,
 +        (types::I8, true) => i64::from(i8::MAX),
 +        (types::I16, true) => i64::from(i16::MAX),
 +        (types::I32, true) => i64::from(i32::MAX),
 +        (types::I64, true) => i64::MAX,
 +        _ => unreachable!(),
 +    };
 +
 +    let (min, max) = (bcx.ins().iconst(ty, min), bcx.ins().iconst(ty, max));
 +
 +    (min, max)
 +}
 +
 +pub(crate) fn type_sign(ty: Ty<'_>) -> bool {
 +    match ty.kind() {
 +        ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false,
 +        ty::Int(..) => true,
 +        ty::Float(..) => false, // `signed` is unused for floats
 +        _ => panic!("{}", ty),
 +    }
 +}
 +
 +pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
 +    pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>,
 +    pub(crate) module: &'m mut dyn Module,
 +    pub(crate) tcx: TyCtxt<'tcx>,
 +    pub(crate) target_config: TargetFrontendConfig, // Cached from module
 +    pub(crate) pointer_type: Type,                  // Cached from module
 +    pub(crate) constants_cx: ConstantCx,
 +
 +    pub(crate) instance: Instance<'tcx>,
 +    pub(crate) symbol_name: SymbolName<'tcx>,
 +    pub(crate) mir: &'tcx Body<'tcx>,
 +    pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>,
 +
 +    pub(crate) bcx: FunctionBuilder<'clif>,
 +    pub(crate) block_map: IndexVec<BasicBlock, Block>,
 +    pub(crate) local_map: IndexVec<Local, CPlace<'tcx>>,
 +
 +    /// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
 +    pub(crate) caller_location: Option<CValue<'tcx>>,
 +
 +    pub(crate) clif_comments: crate::pretty_clif::CommentWriter,
 +    pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>,
 +
 +    /// This should only be accessed by `CPlace::new_var`.
 +    pub(crate) next_ssa_var: u32,
 +}
 +
 +impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
 +    type LayoutOfResult = TyAndLayout<'tcx>;
 +
 +    #[inline]
 +    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
 +        RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty)
 +    }
 +}
 +
 +impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
 +    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
 +
 +    #[inline]
 +    fn handle_fn_abi_err(
 +        &self,
 +        err: FnAbiError<'tcx>,
 +        span: Span,
 +        fn_abi_request: FnAbiRequest<'tcx>,
 +    ) -> ! {
 +        RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
 +    }
 +}
 +
 +impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> {
 +    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
 +        self.tcx
 +    }
 +}
 +
 +impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
 +    fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
 +        &self.tcx.data_layout
 +    }
 +}
 +
 +impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> {
 +    fn param_env(&self) -> ParamEnv<'tcx> {
 +        ParamEnv::reveal_all()
 +    }
 +}
 +
 +impl<'tcx> HasTargetSpec for FunctionCx<'_, '_, 'tcx> {
 +    fn target_spec(&self) -> &Target {
 +        &self.tcx.sess.target
 +    }
 +}
 +
 +impl<'tcx> FunctionCx<'_, '_, 'tcx> {
 +    pub(crate) fn monomorphize<T>(&self, value: T) -> T
 +    where
 +        T: TypeFoldable<'tcx> + Copy,
 +    {
 +        self.instance.subst_mir_and_normalize_erasing_regions(
 +            self.tcx,
 +            ty::ParamEnv::reveal_all(),
 +            value,
 +        )
 +    }
 +
 +    pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
 +        clif_type_from_ty(self.tcx, ty)
 +    }
 +
 +    pub(crate) fn clif_pair_type(&self, ty: Ty<'tcx>) -> Option<(Type, Type)> {
 +        clif_pair_type_from_ty(self.tcx, ty)
 +    }
 +
 +    pub(crate) fn get_block(&self, bb: BasicBlock) -> Block {
 +        *self.block_map.get(bb).unwrap()
 +    }
 +
 +    pub(crate) fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
 +        *self.local_map.get(local).unwrap_or_else(|| {
 +            panic!("Local {:?} doesn't exist", local);
 +        })
 +    }
 +
 +    pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
 +        let (index, _) = self.source_info_set.insert_full(source_info);
 +        self.bcx.set_srcloc(SourceLoc::new(index as u32));
 +    }
 +
-         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
-         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
-         let const_loc = self.tcx.const_caller_location((
-             rustc_span::symbol::Symbol::intern(
-                 &caller.file.name.prefer_remapped().to_string_lossy(),
-             ),
-             caller.line as u32,
-             caller.col_display as u32 + 1,
-         ));
-         crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty())
++    // Note: must be kept in sync with get_caller_location from cg_ssa
++    pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
++        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
++            let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
++            let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
++            let const_loc = fx.tcx.const_caller_location((
++                rustc_span::symbol::Symbol::intern(
++                    &caller.file.name.prefer_remapped().to_string_lossy(),
++                ),
++                caller.line as u32,
++                caller.col_display as u32 + 1,
++            ));
++            crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty())
++        };
++
++        // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
++        // If so, the starting `source_info.span` is in the innermost inlined
++        // function, and will be replaced with outer callsite spans as long
++        // as the inlined functions were `#[track_caller]`.
++        loop {
++            let scope_data = &self.mir.source_scopes[source_info.scope];
++
++            if let Some((callee, callsite_span)) = scope_data.inlined {
++                // Stop inside the most nested non-`#[track_caller]` function,
++                // before ever reaching its caller (which is irrelevant).
++                if !callee.def.requires_caller_location(self.tcx) {
++                    return span_to_caller_location(self, source_info.span);
++                }
++                source_info.span = callsite_span;
++            }
++
++            // Skip past all of the parents with `inlined: None`.
++            match scope_data.inlined_parent_scope {
++                Some(parent) => source_info.scope = parent,
++                None => break,
++            }
 +        }
 +
++        // No inlined `SourceScope`s, or all of them were `#[track_caller]`.
++        self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span))
 +    }
 +
 +    pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
 +        let mut data_ctx = DataContext::new();
 +        data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
 +        let msg_id = self.module.declare_anonymous_data(false, false).unwrap();
 +
 +        // Ignore DuplicateDefinition error, as the data will be the same
 +        let _ = self.module.define_data(msg_id, &data_ctx);
 +
 +        let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func);
 +        if self.clif_comments.enabled() {
 +            self.add_comment(local_msg_id, msg);
 +        }
 +        self.bcx.ins().global_value(self.pointer_type, local_msg_id)
 +    }
 +}
 +
 +pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
 +
 +impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
 +    type LayoutOfResult = TyAndLayout<'tcx>;
 +
 +    #[inline]
 +    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
 +        if let layout::LayoutError::SizeOverflow(_) = err {
 +            self.0.sess.span_fatal(span, &err.to_string())
 +        } else {
 +            span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
 +        }
 +    }
 +}
 +
 +impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
 +    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
 +
 +    #[inline]
 +    fn handle_fn_abi_err(
 +        &self,
 +        err: FnAbiError<'tcx>,
 +        span: Span,
 +        fn_abi_request: FnAbiRequest<'tcx>,
 +    ) -> ! {
 +        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
 +            self.0.sess.span_fatal(span, &err.to_string())
 +        } else {
 +            match fn_abi_request {
 +                FnAbiRequest::OfFnPtr { sig, extra_args } => {
 +                    span_bug!(
 +                        span,
 +                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
 +                        sig,
 +                        extra_args,
 +                        err
 +                    );
 +                }
 +                FnAbiRequest::OfInstance { instance, extra_args } => {
 +                    span_bug!(
 +                        span,
 +                        "`fn_abi_of_instance({}, {:?})` failed: {}",
 +                        instance,
 +                        extra_args,
 +                        err
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
 +    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
 +        self.0
 +    }
 +}
 +
 +impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
 +    fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
 +        &self.0.data_layout
 +    }
 +}
 +
 +impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> {
 +    fn param_env(&self) -> ParamEnv<'tcx> {
 +        ParamEnv::reveal_all()
 +    }
 +}
 +
 +impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> {
 +    fn target_spec(&self) -> &Target {
 +        &self.0.sess.target
 +    }
 +}
index 7f15bc75fda23e8fc933c892d4b94712ce9afa20,0000000000000000000000000000000000000000..1b01f4edbb3f3313bdd1ba9a4943822e3625667d
mode 100644,000000..100644
--- /dev/null
@@@ -1,385 -1,0 +1,385 @@@
- #[no_mangle]
- extern "C" fn __clif_jit_fn(
 +//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
 +//! files.
 +
 +use std::cell::RefCell;
 +use std::ffi::CString;
 +use std::os::raw::{c_char, c_int};
 +use std::sync::{mpsc, Mutex};
 +
 +use rustc_codegen_ssa::CrateInfo;
 +use rustc_middle::mir::mono::MonoItem;
 +use rustc_session::Session;
 +use rustc_span::Symbol;
 +
 +use cranelift_jit::{JITBuilder, JITModule};
 +
 +// FIXME use std::lazy::SyncOnceCell once it stabilizes
 +use once_cell::sync::OnceCell;
 +
 +use crate::{prelude::*, BackendConfig};
 +use crate::{CodegenCx, CodegenMode};
 +
 +struct JitState {
 +    backend_config: BackendConfig,
 +    jit_module: JITModule,
 +}
 +
 +thread_local! {
 +    static LAZY_JIT_STATE: RefCell<Option<JitState>> = const { RefCell::new(None) };
 +}
 +
 +/// The Sender owned by the rustc thread
 +static GLOBAL_MESSAGE_SENDER: OnceCell<Mutex<mpsc::Sender<UnsafeMessage>>> = OnceCell::new();
 +
 +/// A message that is sent from the jitted runtime to the rustc thread.
 +/// Senders are responsible for upholding `Send` semantics.
 +enum UnsafeMessage {
 +    /// Request that the specified `Instance` be lazily jitted.
 +    ///
 +    /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after
 +    /// this message is sent.
 +    JitFn {
 +        instance_ptr: *const Instance<'static>,
 +        trampoline_ptr: *const u8,
 +        tx: mpsc::Sender<*const u8>,
 +    },
 +}
 +unsafe impl Send for UnsafeMessage {}
 +
 +impl UnsafeMessage {
 +    /// Send the message.
 +    fn send(self) -> Result<(), mpsc::SendError<UnsafeMessage>> {
 +        thread_local! {
 +            /// The Sender owned by the local thread
 +            static LOCAL_MESSAGE_SENDER: mpsc::Sender<UnsafeMessage> =
 +                GLOBAL_MESSAGE_SENDER
 +                    .get().unwrap()
 +                    .lock().unwrap()
 +                    .clone();
 +        }
 +        LOCAL_MESSAGE_SENDER.with(|sender| sender.send(self))
 +    }
 +}
 +
 +fn create_jit_module<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    backend_config: &BackendConfig,
 +    hotswap: bool,
 +) -> (JITModule, CodegenCx<'tcx>) {
 +    let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
 +    let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
 +
 +    let isa = crate::build_isa(tcx.sess, backend_config);
 +    let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
 +    jit_builder.hotswap(hotswap);
 +    crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
 +    jit_builder.symbols(imported_symbols);
++    jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
 +    let mut jit_module = JITModule::new(jit_builder);
 +
 +    let mut cx = crate::CodegenCx::new(
 +        tcx,
 +        backend_config.clone(),
 +        jit_module.isa(),
 +        false,
 +        Symbol::intern("dummy_cgu_name"),
 +    );
 +
 +    crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
 +    crate::main_shim::maybe_create_entry_wrapper(
 +        tcx,
 +        &mut jit_module,
 +        &mut cx.unwind_context,
 +        true,
 +        true,
 +    );
 +
 +    (jit_module, cx)
 +}
 +
 +pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
 +    if !tcx.sess.opts.output_types.should_codegen() {
 +        tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
 +    }
 +
 +    if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
 +        tcx.sess.fatal("can't jit non-executable crate");
 +    }
 +
 +    let (mut jit_module, mut cx) = create_jit_module(
 +        tcx,
 +        &backend_config,
 +        matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
 +    );
 +
 +    let (_, cgus) = tcx.collect_and_partition_mono_items(());
 +    let mono_items = cgus
 +        .iter()
 +        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
 +        .flatten()
 +        .collect::<FxHashMap<_, (_, _)>>()
 +        .into_iter()
 +        .collect::<Vec<(_, (_, _))>>();
 +
 +    super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
 +        super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
 +        for (mono_item, _) in mono_items {
 +            match mono_item {
 +                MonoItem::Fn(inst) => match backend_config.codegen_mode {
 +                    CodegenMode::Aot => unreachable!(),
 +                    CodegenMode::Jit => {
 +                        cx.tcx.sess.time("codegen fn", || {
 +                            crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
 +                        });
 +                    }
 +                    CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
 +                },
 +                MonoItem::Static(def_id) => {
 +                    crate::constant::codegen_static(tcx, &mut jit_module, def_id);
 +                }
 +                MonoItem::GlobalAsm(item_id) => {
 +                    let item = tcx.hir().item(item_id);
 +                    tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
 +                }
 +            }
 +        }
 +    });
 +
 +    if !cx.global_asm.is_empty() {
 +        tcx.sess.fatal("Inline asm is not supported in JIT mode");
 +    }
 +
 +    tcx.sess.abort_if_errors();
 +
 +    jit_module.finalize_definitions();
 +    unsafe { cx.unwind_context.register_jit(&jit_module) };
 +
 +    println!(
 +        "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
 +    );
 +
 +    let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
 +        .chain(backend_config.jit_args.iter().map(|arg| &**arg))
 +        .map(|arg| CString::new(arg).unwrap())
 +        .collect::<Vec<_>>();
 +
 +    let start_sig = Signature {
 +        params: vec![
 +            AbiParam::new(jit_module.target_config().pointer_type()),
 +            AbiParam::new(jit_module.target_config().pointer_type()),
 +        ],
 +        returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
 +        call_conv: jit_module.target_config().default_call_conv,
 +    };
 +    let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
 +    let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
 +
 +    LAZY_JIT_STATE.with(|lazy_jit_state| {
 +        let mut lazy_jit_state = lazy_jit_state.borrow_mut();
 +        assert!(lazy_jit_state.is_none());
 +        *lazy_jit_state = Some(JitState { backend_config, jit_module });
 +    });
 +
 +    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
 +        unsafe { ::std::mem::transmute(finalized_start) };
 +
 +    let (tx, rx) = mpsc::channel();
 +    GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap();
 +
 +    // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages
 +    // (eg to lazily JIT further functions as required)
 +    std::thread::spawn(move || {
 +        let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
 +
 +        // Push a null pointer as a terminating argument. This is required by POSIX and
 +        // useful as some dynamic linkers use it as a marker to jump over.
 +        argv.push(std::ptr::null());
 +
 +        let ret = f(args.len() as c_int, argv.as_ptr());
 +        std::process::exit(ret);
 +    });
 +
 +    // Handle messages
 +    loop {
 +        match rx.recv().unwrap() {
 +            // lazy JIT compilation request - compile requested instance and return pointer to result
 +            UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => {
 +                tx.send(jit_fn(instance_ptr, trampoline_ptr))
 +                    .expect("jitted runtime hung up before response to lazy JIT request was sent");
 +            }
 +        }
 +    }
 +}
 +
++extern "C" fn clif_jit_fn(
 +    instance_ptr: *const Instance<'static>,
 +    trampoline_ptr: *const u8,
 +) -> *const u8 {
 +    // send the JIT request to the rustc thread, with a channel for the response
 +    let (tx, rx) = mpsc::channel();
 +    UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }
 +        .send()
 +        .expect("rustc thread hung up before lazy JIT request was sent");
 +
 +    // block on JIT compilation result
 +    rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request")
 +}
 +
 +fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 {
 +    rustc_middle::ty::tls::with(|tcx| {
 +        // lift is used to ensure the correct lifetime for instance.
 +        let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
 +
 +        LAZY_JIT_STATE.with(|lazy_jit_state| {
 +            let mut lazy_jit_state = lazy_jit_state.borrow_mut();
 +            let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
 +            let jit_module = &mut lazy_jit_state.jit_module;
 +            let backend_config = lazy_jit_state.backend_config.clone();
 +
 +            let name = tcx.symbol_name(instance).name;
 +            let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
 +            let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
 +
 +            let current_ptr = jit_module.read_got_entry(func_id);
 +
 +            // If the function's GOT entry has already been updated to point at something other
 +            // than the shim trampoline, don't re-jit but just return the new pointer instead.
 +            // This does not need synchronization as this code is executed only by a sole rustc
 +            // thread.
 +            if current_ptr != trampoline_ptr {
 +                return current_ptr;
 +            }
 +
 +            jit_module.prepare_for_function_redefine(func_id).unwrap();
 +
 +            let mut cx = crate::CodegenCx::new(
 +                tcx,
 +                backend_config,
 +                jit_module.isa(),
 +                false,
 +                Symbol::intern("dummy_cgu_name"),
 +            );
 +            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
 +
 +            assert!(cx.global_asm.is_empty());
 +            jit_module.finalize_definitions();
 +            unsafe { cx.unwind_context.register_jit(&jit_module) };
 +            jit_module.get_finalized_function(func_id)
 +        })
 +    })
 +}
 +
 +fn load_imported_symbols_for_jit(
 +    sess: &Session,
 +    crate_info: CrateInfo,
 +) -> Vec<(String, *const u8)> {
 +    use rustc_middle::middle::dependency_format::Linkage;
 +
 +    let mut dylib_paths = Vec::new();
 +
 +    let data = &crate_info
 +        .dependency_formats
 +        .iter()
 +        .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
 +        .unwrap()
 +        .1;
 +    for &cnum in &crate_info.used_crates {
 +        let src = &crate_info.used_crate_source[&cnum];
 +        match data[cnum.as_usize() - 1] {
 +            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
 +            Linkage::Static => {
 +                let name = crate_info.crate_name[&cnum];
 +                let mut err = sess.struct_err(&format!("Can't load static lib {}", name));
 +                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
 +                err.emit();
 +            }
 +            Linkage::Dynamic => {
 +                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
 +            }
 +        }
 +    }
 +
 +    let mut imported_symbols = Vec::new();
 +    for path in dylib_paths {
 +        use object::{Object, ObjectSymbol};
 +        let lib = libloading::Library::new(&path).unwrap();
 +        let obj = std::fs::read(path).unwrap();
 +        let obj = object::File::parse(&*obj).unwrap();
 +        imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
 +            let name = symbol.name().unwrap().to_string();
 +            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
 +                return None;
 +            }
 +            if name.starts_with("rust_metadata_") {
 +                // The metadata is part of a section that is not loaded by the dynamic linker in
 +                // case of cg_llvm.
 +                return None;
 +            }
 +            let dlsym_name = if cfg!(target_os = "macos") {
 +                // On macOS `dlsym` expects the name without leading `_`.
 +                assert!(name.starts_with('_'), "{:?}", name);
 +                &name[1..]
 +            } else {
 +                &name
 +            };
 +            let symbol: libloading::Symbol<'_, *const u8> =
 +                unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
 +            Some((name, *symbol))
 +        }));
 +        std::mem::forget(lib)
 +    }
 +
 +    sess.abort_if_errors();
 +
 +    imported_symbols
 +}
 +
 +fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
 +    let tcx = cx.tcx;
 +
 +    let pointer_type = module.target_config().pointer_type();
 +
 +    let name = tcx.symbol_name(inst).name;
 +    let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
 +    let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
 +
 +    let instance_ptr = Box::into_raw(Box::new(inst));
 +
 +    let jit_fn = module
 +        .declare_function(
 +            "__clif_jit_fn",
 +            Linkage::Import,
 +            &Signature {
 +                call_conv: module.target_config().default_call_conv,
 +                params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)],
 +                returns: vec![AbiParam::new(pointer_type)],
 +            },
 +        )
 +        .unwrap();
 +
 +    cx.cached_context.clear();
 +    let trampoline = &mut cx.cached_context.func;
 +    trampoline.signature = sig.clone();
 +
 +    let mut builder_ctx = FunctionBuilderContext::new();
 +    let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
 +
 +    let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func);
 +    let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
 +    let sig_ref = trampoline_builder.func.import_signature(sig);
 +
 +    let entry_block = trampoline_builder.create_block();
 +    trampoline_builder.append_block_params_for_function_params(entry_block);
 +    let fn_args = trampoline_builder.func.dfg.block_params(entry_block).to_vec();
 +
 +    trampoline_builder.switch_to_block(entry_block);
 +    let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64);
 +    let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn);
 +    let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]);
 +    let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
 +    let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args);
 +    let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
 +    trampoline_builder.ins().return_(&ret_vals);
 +
 +    module.define_function(func_id, &mut cx.cached_context).unwrap();
 +}
index f7a83373e870bed0b8893c9e36e2a10484078913,0000000000000000000000000000000000000000..29b3f36b2bef2c389bb79d54bec9ebcf191a7308
mode 100644,000000..100644
--- /dev/null
@@@ -1,1135 -1,0 +1,1135 @@@
-     span: Span,
 +//! 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)>,
-                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
++    source_info: mir::SourceInfo,
 +) {
 +    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 => {
-         self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span);
++                    crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
 +                }
 +                _ => unimplemented!("unsupported instrinsic {}", intrinsic),
 +            }
 +            return;
 +        }
 +    };
 +
 +    if intrinsic.as_str().starts_with("simd_") {
-             span,
++        self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, source_info.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: Span,
++            source_info,
 +            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>,
-             fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic));
++    source_info: mir::SourceInfo,
 +    destination: Option<(CPlace<'tcx>, BasicBlock)>,
 +) {
 +    let usize_layout = fx.layout_of(fx.tcx.types.usize);
 +
 +    intrinsic_match! {
 +        fx, intrinsic, args,
 +        _ => {
-                         span,
++            fx.tcx.sess.span_fatal(source_info.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,
++                        source_info,
 +                    )
 +                });
 +                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,
++                        source_info,
 +                    );
 +                });
 +                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),
-             let isize_layout = fx.layout_of(fx.tcx.types.isize);
++                        source_info,
 +                    )
 +                });
 +                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 | ptr_offset_from_unsigned, (v ptr, v base) {
 +            let ty = substs.type_at(0);
-             let diff = if intrinsic == sym::ptr_offset_from_unsigned {
 +
 +            let pointee_size: u64 = fx.layout_of(ty).size.bytes();
 +            let diff_bytes = fx.bcx.ins().isub(ptr, base);
 +            // FIXME this can be an exact division.
-                 fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64)
++            let val = if intrinsic == sym::ptr_offset_from_unsigned {
++                let usize_layout = fx.layout_of(fx.tcx.types.usize);
 +                // Because diff_bytes ULE isize::MAX, this would be fine as signed,
 +                // but unsigned is slightly easier to codegen, so might as well.
-                 fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64)
++                CValue::by_val(fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64), usize_layout)
 +            } else {
-             let val = CValue::by_val(diff, isize_layout);
++                let isize_layout = fx.layout_of(fx.tcx.types.isize);
++                CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout)
 +            };
-             let caller_location = fx.get_caller_location(span);
 +            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, () {
-                         fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
++            let caller_location = fx.get_caller_location(source_info);
 +            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 {
-                     report_atomic_type_validation_error(fx, intrinsic, span, ty);
++                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
 +                    }
 +                }
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
-                         fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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 {
-                     report_atomic_type_validation_error(fx, intrinsic, span, ty);
++                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
 +                    }
 +                }
 +                ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
 +                _ => {
-                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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);
++                    report_atomic_type_validation_error(fx, intrinsic, source_info.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, source_info.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);
 +        };
 +
 +        minnumf32, (v a, v b) {
 +            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 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 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 8f80b02ae0d4e7d98d588cd255f2ac210bdf209e,0000000000000000000000000000000000000000..a68225de58b32d160dd2302ed54eaf352b3d8831
mode 100644,000000..100644
--- /dev/null
@@@ -1,839 -1,0 +1,840 @@@
 +//! Definition of [`CValue`] and [`CPlace`]
 +
 +use crate::prelude::*;
 +
 +use cranelift_codegen::ir::immediates::Offset32;
 +
 +fn codegen_field<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    base: Pointer,
 +    extra: Option<Value>,
 +    layout: TyAndLayout<'tcx>,
 +    field: mir::Field,
 +) -> (Pointer, TyAndLayout<'tcx>) {
 +    let field_offset = layout.fields.offset(field.index());
 +    let field_layout = layout.field(&*fx, field.index());
 +
 +    let simple = |fx: &mut FunctionCx<'_, '_, '_>| {
 +        (base.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap()), field_layout)
 +    };
 +
 +    if let Some(extra) = extra {
 +        if !field_layout.is_unsized() {
 +            return simple(fx);
 +        }
 +        match field_layout.ty.kind() {
 +            ty::Slice(..) | ty::Str | ty::Foreign(..) => simple(fx),
 +            ty::Adt(def, _) if def.repr().packed() => {
 +                assert_eq!(layout.align.abi.bytes(), 1);
 +                simple(fx)
 +            }
 +            _ => {
 +                // We have to align the offset for DST's
 +                let unaligned_offset = field_offset.bytes();
 +                let (_, unsized_align) =
 +                    crate::unsize::size_and_align_of_dst(fx, field_layout, extra);
 +
 +                let one = fx.bcx.ins().iconst(fx.pointer_type, 1);
 +                let align_sub_1 = fx.bcx.ins().isub(unsized_align, one);
 +                let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64);
 +                let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
 +                let and_rhs = fx.bcx.ins().isub(zero, unsized_align);
 +                let offset = fx.bcx.ins().band(and_lhs, and_rhs);
 +
 +                (base.offset_value(fx, offset), field_layout)
 +            }
 +        }
 +    } else {
 +        simple(fx)
 +    }
 +}
 +
 +fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 {
 +    let b_offset = a_scalar.size(&tcx).align_to(b_scalar.align(&tcx).abi);
 +    Offset32::new(b_offset.bytes().try_into().unwrap())
 +}
 +
 +/// A read-only value
 +#[derive(Debug, Copy, Clone)]
 +pub(crate) struct CValue<'tcx>(CValueInner, TyAndLayout<'tcx>);
 +
 +#[derive(Debug, Copy, Clone)]
 +enum CValueInner {
 +    ByRef(Pointer, Option<Value>),
 +    ByVal(Value),
 +    ByValPair(Value, Value),
 +}
 +
 +impl<'tcx> CValue<'tcx> {
 +    pub(crate) fn by_ref(ptr: Pointer, layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
 +        CValue(CValueInner::ByRef(ptr, None), layout)
 +    }
 +
 +    pub(crate) fn by_ref_unsized(
 +        ptr: Pointer,
 +        meta: Value,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CValue<'tcx> {
 +        CValue(CValueInner::ByRef(ptr, Some(meta)), layout)
 +    }
 +
 +    pub(crate) fn by_val(value: Value, layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
 +        CValue(CValueInner::ByVal(value), layout)
 +    }
 +
 +    pub(crate) fn by_val_pair(
 +        value: Value,
 +        extra: Value,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CValue<'tcx> {
 +        CValue(CValueInner::ByValPair(value, extra), layout)
 +    }
 +
 +    pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
 +        self.1
 +    }
 +
 +    // FIXME remove
 +    pub(crate) fn force_stack(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> (Pointer, Option<Value>) {
 +        let layout = self.1;
 +        match self.0 {
 +            CValueInner::ByRef(ptr, meta) => (ptr, meta),
 +            CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => {
 +                let cplace = CPlace::new_stack_slot(fx, layout);
 +                cplace.write_cvalue(fx, self);
 +                (cplace.to_ptr(), None)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn try_to_ptr(self) -> Option<(Pointer, Option<Value>)> {
 +        match self.0 {
 +            CValueInner::ByRef(ptr, meta) => Some((ptr, meta)),
 +            CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => None,
 +        }
 +    }
 +
 +    /// Load a value with layout.abi of scalar
 +    pub(crate) fn load_scalar(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> Value {
 +        let layout = self.1;
 +        match self.0 {
 +            CValueInner::ByRef(ptr, None) => {
 +                let clif_ty = match layout.abi {
 +                    Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar),
 +                    Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element)
 +                        .by(u16::try_from(count).unwrap())
 +                        .unwrap(),
 +                    _ => unreachable!("{:?}", layout.ty),
 +                };
 +                let mut flags = MemFlags::new();
 +                flags.set_notrap();
 +                ptr.load(fx, clif_ty, flags)
 +            }
 +            CValueInner::ByVal(value) => value,
 +            CValueInner::ByRef(_, Some(_)) => bug!("load_scalar for unsized value not allowed"),
 +            CValueInner::ByValPair(_, _) => bug!("Please use load_scalar_pair for ByValPair"),
 +        }
 +    }
 +
 +    /// Load a value pair with layout.abi of scalar pair
 +    pub(crate) fn load_scalar_pair(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> (Value, Value) {
 +        let layout = self.1;
 +        match self.0 {
 +            CValueInner::ByRef(ptr, None) => {
 +                let (a_scalar, b_scalar) = match layout.abi {
 +                    Abi::ScalarPair(a, b) => (a, b),
 +                    _ => unreachable!("load_scalar_pair({:?})", self),
 +                };
 +                let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
 +                let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar);
 +                let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
 +                let mut flags = MemFlags::new();
 +                flags.set_notrap();
 +                let val1 = ptr.load(fx, clif_ty1, flags);
 +                let val2 = ptr.offset(fx, b_offset).load(fx, clif_ty2, flags);
 +                (val1, val2)
 +            }
 +            CValueInner::ByRef(_, Some(_)) => {
 +                bug!("load_scalar_pair for unsized value not allowed")
 +            }
 +            CValueInner::ByVal(_) => bug!("Please use load_scalar for ByVal"),
 +            CValueInner::ByValPair(val1, val2) => (val1, val2),
 +        }
 +    }
 +
 +    pub(crate) fn value_field(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        field: mir::Field,
 +    ) -> CValue<'tcx> {
 +        let layout = self.1;
 +        match self.0 {
 +            CValueInner::ByVal(val) => match layout.abi {
 +                Abi::Vector { element: _, count } => {
 +                    let count = u8::try_from(count).expect("SIMD type with more than 255 lanes???");
 +                    let field = u8::try_from(field.index()).unwrap();
 +                    assert!(field < count);
 +                    let lane = fx.bcx.ins().extractlane(val, field);
 +                    let field_layout = layout.field(&*fx, usize::from(field));
 +                    CValue::by_val(lane, field_layout)
 +                }
 +                _ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
 +            },
 +            CValueInner::ByValPair(val1, val2) => match layout.abi {
 +                Abi::ScalarPair(_, _) => {
 +                    let val = match field.as_u32() {
 +                        0 => val1,
 +                        1 => val2,
 +                        _ => bug!("field should be 0 or 1"),
 +                    };
 +                    let field_layout = layout.field(&*fx, usize::from(field));
 +                    CValue::by_val(val, field_layout)
 +                }
 +                _ => unreachable!("value_field for ByValPair with abi {:?}", layout.abi),
 +            },
 +            CValueInner::ByRef(ptr, None) => {
 +                let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field);
 +                CValue::by_ref(field_ptr, field_layout)
 +            }
 +            CValueInner::ByRef(_, Some(_)) => todo!(),
 +        }
 +    }
 +
 +    /// Like [`CValue::value_field`] except handling ADTs containing a single array field in a way
 +    /// such that you can access individual lanes.
 +    pub(crate) fn value_lane(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        lane_idx: u64,
 +    ) -> CValue<'tcx> {
 +        let layout = self.1;
 +        assert!(layout.ty.is_simd());
 +        let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +        let lane_layout = fx.layout_of(lane_ty);
 +        assert!(lane_idx < lane_count);
 +        match self.0 {
 +            CValueInner::ByVal(val) => match layout.abi {
 +                Abi::Vector { element: _, count: _ } => {
 +                    assert!(lane_count <= u8::MAX.into(), "SIMD type with more than 255 lanes???");
 +                    let lane_idx = u8::try_from(lane_idx).unwrap();
 +                    let lane = fx.bcx.ins().extractlane(val, lane_idx);
 +                    CValue::by_val(lane, lane_layout)
 +                }
 +                _ => unreachable!("value_lane for ByVal with abi {:?}", layout.abi),
 +            },
 +            CValueInner::ByValPair(_, _) => unreachable!(),
 +            CValueInner::ByRef(ptr, None) => {
 +                let field_offset = lane_layout.size * lane_idx;
 +                let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
 +                CValue::by_ref(field_ptr, lane_layout)
 +            }
 +            CValueInner::ByRef(_, Some(_)) => unreachable!(),
 +        }
 +    }
 +
 +    pub(crate) fn unsize_value(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
 +        crate::unsize::coerce_unsized_into(fx, self, dest);
 +    }
 +
 +    /// If `ty` is signed, `const_val` must already be sign extended.
 +    pub(crate) fn const_val(
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        layout: TyAndLayout<'tcx>,
 +        const_val: ty::ScalarInt,
 +    ) -> CValue<'tcx> {
 +        assert_eq!(const_val.size(), layout.size, "{:#?}: {:?}", const_val, layout);
 +        use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
 +
 +        let clif_ty = fx.clif_type(layout.ty).unwrap();
 +
 +        if let ty::Bool = layout.ty.kind() {
 +            assert!(
 +                const_val == ty::ScalarInt::FALSE || const_val == ty::ScalarInt::TRUE,
 +                "Invalid bool 0x{:032X}",
 +                const_val
 +            );
 +        }
 +
 +        let val = match layout.ty.kind() {
 +            ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
 +                let const_val = const_val.to_bits(layout.size).unwrap();
 +                let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64);
 +                let msb = fx.bcx.ins().iconst(types::I64, (const_val >> 64) as u64 as i64);
 +                fx.bcx.ins().iconcat(lsb, msb)
 +            }
 +            ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Ref(..) | ty::RawPtr(..) => {
 +                fx.bcx.ins().iconst(clif_ty, const_val.to_bits(layout.size).unwrap() as i64)
 +            }
 +            ty::Float(FloatTy::F32) => {
 +                fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap()))
 +            }
 +            ty::Float(FloatTy::F64) => {
 +                fx.bcx.ins().f64const(Ieee64::with_bits(u64::try_from(const_val).unwrap()))
 +            }
 +            _ => panic!(
 +                "CValue::const_val for non bool/char/float/integer/pointer type {:?} is not allowed",
 +                layout.ty
 +            ),
 +        };
 +
 +        CValue::by_val(val, layout)
 +    }
 +
 +    pub(crate) fn cast_pointer_to(self, layout: TyAndLayout<'tcx>) -> Self {
 +        assert!(matches!(self.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..)));
 +        assert!(matches!(layout.ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..)));
 +        assert_eq!(self.layout().abi, layout.abi);
 +        CValue(self.0, layout)
 +    }
 +}
 +
 +/// A place where you can write a value to or read a value from
 +#[derive(Debug, Copy, Clone)]
 +pub(crate) struct CPlace<'tcx> {
 +    inner: CPlaceInner,
 +    layout: TyAndLayout<'tcx>,
 +}
 +
 +#[derive(Debug, Copy, Clone)]
 +pub(crate) enum CPlaceInner {
 +    Var(Local, Variable),
 +    VarPair(Local, Variable, Variable),
 +    VarLane(Local, Variable, u8),
 +    Addr(Pointer, Option<Value>),
 +}
 +
 +impl<'tcx> CPlace<'tcx> {
 +    pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
 +        self.layout
 +    }
 +
 +    pub(crate) fn inner(&self) -> &CPlaceInner {
 +        &self.inner
 +    }
 +
 +    pub(crate) fn new_stack_slot(
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CPlace<'tcx> {
 +        assert!(!layout.is_unsized());
 +        if layout.size.bytes() == 0 {
 +            return CPlace {
 +                inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None),
 +                layout,
 +            };
 +        }
 +
 +        let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
 +            kind: StackSlotKind::ExplicitSlot,
 +            // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
 +            // specify stack slot alignment.
 +            size: (u32::try_from(layout.size.bytes()).unwrap() + 15) / 16 * 16,
 +        });
 +        CPlace { inner: CPlaceInner::Addr(Pointer::stack_slot(stack_slot), None), layout }
 +    }
 +
 +    pub(crate) fn new_var(
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        local: Local,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CPlace<'tcx> {
 +        let var = Variable::with_u32(fx.next_ssa_var);
 +        fx.next_ssa_var += 1;
 +        fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap());
 +        CPlace { inner: CPlaceInner::Var(local, var), layout }
 +    }
 +
 +    pub(crate) fn new_var_pair(
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        local: Local,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CPlace<'tcx> {
 +        let var1 = Variable::with_u32(fx.next_ssa_var);
 +        fx.next_ssa_var += 1;
 +        let var2 = Variable::with_u32(fx.next_ssa_var);
 +        fx.next_ssa_var += 1;
 +
 +        let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
 +        fx.bcx.declare_var(var1, ty1);
 +        fx.bcx.declare_var(var2, ty2);
 +        CPlace { inner: CPlaceInner::VarPair(local, var1, var2), layout }
 +    }
 +
 +    pub(crate) fn for_ptr(ptr: Pointer, layout: TyAndLayout<'tcx>) -> CPlace<'tcx> {
 +        CPlace { inner: CPlaceInner::Addr(ptr, None), layout }
 +    }
 +
 +    pub(crate) fn for_ptr_with_extra(
 +        ptr: Pointer,
 +        extra: Value,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CPlace<'tcx> {
 +        CPlace { inner: CPlaceInner::Addr(ptr, Some(extra)), layout }
 +    }
 +
 +    pub(crate) fn to_cvalue(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CValue<'tcx> {
 +        let layout = self.layout();
 +        match self.inner {
 +            CPlaceInner::Var(_local, var) => {
 +                let val = fx.bcx.use_var(var);
 +                //fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
 +                CValue::by_val(val, layout)
 +            }
 +            CPlaceInner::VarPair(_local, var1, var2) => {
 +                let val1 = fx.bcx.use_var(var1);
 +                //fx.bcx.set_val_label(val1, cranelift_codegen::ir::ValueLabel::new(var1.index()));
 +                let val2 = fx.bcx.use_var(var2);
 +                //fx.bcx.set_val_label(val2, cranelift_codegen::ir::ValueLabel::new(var2.index()));
 +                CValue::by_val_pair(val1, val2, layout)
 +            }
 +            CPlaceInner::VarLane(_local, var, lane) => {
 +                let val = fx.bcx.use_var(var);
 +                //fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
 +                let val = fx.bcx.ins().extractlane(val, lane);
 +                CValue::by_val(val, layout)
 +            }
 +            CPlaceInner::Addr(ptr, extra) => {
 +                if let Some(extra) = extra {
 +                    CValue::by_ref_unsized(ptr, extra, layout)
 +                } else {
 +                    CValue::by_ref(ptr, layout)
 +                }
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn to_ptr(self) -> Pointer {
 +        match self.to_ptr_maybe_unsized() {
 +            (ptr, None) => ptr,
 +            (_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
 +        }
 +    }
 +
 +    pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
 +        match self.inner {
 +            CPlaceInner::Addr(ptr, extra) => (ptr, extra),
 +            CPlaceInner::Var(_, _)
 +            | CPlaceInner::VarPair(_, _, _)
 +            | CPlaceInner::VarLane(_, _, _) => bug!("Expected CPlace::Addr, found {:?}", self),
 +        }
 +    }
 +
 +    pub(crate) fn write_cvalue(self, fx: &mut FunctionCx<'_, '_, 'tcx>, from: CValue<'tcx>) {
 +        assert_assignable(fx, from.layout().ty, self.layout().ty);
 +
 +        self.write_cvalue_maybe_transmute(fx, from, "write_cvalue");
 +    }
 +
 +    pub(crate) fn write_cvalue_transmute(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        from: CValue<'tcx>,
 +    ) {
 +        self.write_cvalue_maybe_transmute(fx, from, "write_cvalue_transmute");
 +    }
 +
 +    fn write_cvalue_maybe_transmute(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        from: CValue<'tcx>,
 +        method: &'static str,
 +    ) {
 +        fn transmute_value<'tcx>(
 +            fx: &mut FunctionCx<'_, '_, 'tcx>,
 +            var: Variable,
 +            data: Value,
 +            dst_ty: Type,
 +        ) {
 +            let src_ty = fx.bcx.func.dfg.value_type(data);
 +            assert_eq!(
 +                src_ty.bytes(),
 +                dst_ty.bytes(),
 +                "write_cvalue_transmute: {:?} -> {:?}",
 +                src_ty,
 +                dst_ty,
 +            );
 +            let data = match (src_ty, dst_ty) {
 +                (_, _) if src_ty == dst_ty => data,
 +
 +                // This is a `write_cvalue_transmute`.
 +                (types::I32, types::F32)
 +                | (types::F32, types::I32)
 +                | (types::I64, types::F64)
 +                | (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
 +                _ if src_ty.is_vector() && dst_ty.is_vector() => {
 +                    fx.bcx.ins().raw_bitcast(dst_ty, data)
 +                }
 +                _ if src_ty.is_vector() || dst_ty.is_vector() => {
 +                    // FIXME do something more efficient for transmutes between vectors and integers.
 +                    let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
 +                        kind: StackSlotKind::ExplicitSlot,
 +                        // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
 +                        // specify stack slot alignment.
 +                        size: (src_ty.bytes() + 15) / 16 * 16,
 +                    });
 +                    let ptr = Pointer::stack_slot(stack_slot);
 +                    ptr.store(fx, data, MemFlags::trusted());
 +                    ptr.load(fx, dst_ty, MemFlags::trusted())
 +                }
 +
 +                // `CValue`s should never contain SSA-only types, so if you ended
 +                // up here having seen an error like `B1 -> I8`, then before
 +                // calling `write_cvalue` you need to add a `bint` instruction.
 +                _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty),
 +            };
 +            //fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));
 +            fx.bcx.def_var(var, data);
 +        }
 +
 +        assert_eq!(self.layout().size, from.layout().size);
 +
 +        if fx.clif_comments.enabled() {
 +            use cranelift_codegen::cursor::{Cursor, CursorPosition};
 +            let cur_block = match fx.bcx.cursor().position() {
 +                CursorPosition::After(block) => block,
 +                _ => unreachable!(),
 +            };
 +            fx.add_comment(
 +                fx.bcx.func.layout.last_inst(cur_block).unwrap(),
 +                format!(
 +                    "{}: {:?}: {:?} <- {:?}: {:?}",
 +                    method,
 +                    self.inner(),
 +                    self.layout().ty,
 +                    from.0,
 +                    from.layout().ty
 +                ),
 +            );
 +        }
 +
 +        let dst_layout = self.layout();
 +        let to_ptr = match self.inner {
 +            CPlaceInner::Var(_local, var) => {
 +                if let ty::Array(element, len) = dst_layout.ty.kind() {
 +                    // Can only happen for vector types
 +                    let len =
 +                        u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
 +                    let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
 +
 +                    let data = match from.0 {
 +                        CValueInner::ByRef(ptr, None) => {
 +                            let mut flags = MemFlags::new();
 +                            flags.set_notrap();
 +                            ptr.load(fx, vector_ty, flags)
 +                        }
 +                        CValueInner::ByVal(_)
 +                        | CValueInner::ByValPair(_, _)
 +                        | CValueInner::ByRef(_, Some(_)) => bug!("array should be ByRef"),
 +                    };
 +
 +                    fx.bcx.def_var(var, data);
 +                    return;
 +                }
 +                let data = CValue(from.0, dst_layout).load_scalar(fx);
 +                let dst_ty = fx.clif_type(self.layout().ty).unwrap();
 +                transmute_value(fx, var, data, dst_ty);
 +                return;
 +            }
 +            CPlaceInner::VarPair(_local, var1, var2) => {
 +                let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
 +                let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
 +                transmute_value(fx, var1, data1, dst_ty1);
 +                transmute_value(fx, var2, data2, dst_ty2);
 +                return;
 +            }
 +            CPlaceInner::VarLane(_local, var, lane) => {
 +                let data = from.load_scalar(fx);
 +
 +                // First get the old vector
 +                let vector = fx.bcx.use_var(var);
 +                //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
 +
 +                // Next insert the written lane into the vector
 +                let vector = fx.bcx.ins().insertlane(vector, data, lane);
 +
 +                // Finally write the new vector
 +                //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
 +                fx.bcx.def_var(var, vector);
 +
 +                return;
 +            }
 +            CPlaceInner::Addr(ptr, None) => {
 +                if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited {
 +                    return;
 +                }
 +                ptr
 +            }
 +            CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
 +        };
 +
 +        let mut flags = MemFlags::new();
 +        flags.set_notrap();
 +        match from.layout().abi {
 +            // FIXME make Abi::Vector work too
 +            Abi::Scalar(_) => {
 +                let val = from.load_scalar(fx);
 +                to_ptr.store(fx, val, flags);
 +                return;
 +            }
 +            Abi::ScalarPair(a_scalar, b_scalar) => {
 +                let (value, extra) = from.load_scalar_pair(fx);
 +                let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
 +                to_ptr.store(fx, value, flags);
 +                to_ptr.offset(fx, b_offset).store(fx, extra, flags);
 +                return;
 +            }
 +            _ => {}
 +        }
 +
 +        match from.0 {
 +            CValueInner::ByVal(val) => {
 +                to_ptr.store(fx, val, flags);
 +            }
 +            CValueInner::ByValPair(_, _) => {
 +                bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi);
 +            }
 +            CValueInner::ByRef(from_ptr, None) => {
 +                let from_addr = from_ptr.get_addr(fx);
 +                let to_addr = to_ptr.get_addr(fx);
 +                let src_layout = from.1;
 +                let size = dst_layout.size.bytes();
 +                let src_align = src_layout.align.abi.bytes() as u8;
 +                let dst_align = dst_layout.align.abi.bytes() as u8;
 +                fx.bcx.emit_small_memory_copy(
 +                    fx.target_config,
 +                    to_addr,
 +                    from_addr,
 +                    size,
 +                    dst_align,
 +                    src_align,
 +                    true,
 +                    MemFlags::trusted(),
 +                );
 +            }
 +            CValueInner::ByRef(_, Some(_)) => todo!(),
 +        }
 +    }
 +
 +    pub(crate) fn place_field(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        field: mir::Field,
 +    ) -> CPlace<'tcx> {
 +        let layout = self.layout();
 +
 +        match self.inner {
 +            CPlaceInner::Var(local, var) => match layout.ty.kind() {
 +                ty::Array(_, _) => {
 +                    // Can only happen for vector types
 +                    return CPlace {
 +                        inner: CPlaceInner::VarLane(local, var, field.as_u32().try_into().unwrap()),
 +                        layout: layout.field(fx, field.as_u32().try_into().unwrap()),
 +                    };
 +                }
 +                ty::Adt(adt_def, substs) if layout.ty.is_simd() => {
 +                    let f0_ty = adt_def.non_enum_variant().fields[0].ty(fx.tcx, substs);
 +
 +                    match f0_ty.kind() {
 +                        ty::Array(_, _) => {
 +                            assert_eq!(field.as_u32(), 0);
 +                            return CPlace {
 +                                inner: CPlaceInner::Var(local, var),
 +                                layout: layout.field(fx, field.as_u32().try_into().unwrap()),
 +                            };
 +                        }
 +                        _ => {
 +                            return CPlace {
 +                                inner: CPlaceInner::VarLane(
 +                                    local,
 +                                    var,
 +                                    field.as_u32().try_into().unwrap(),
 +                                ),
 +                                layout: layout.field(fx, field.as_u32().try_into().unwrap()),
 +                            };
 +                        }
 +                    }
 +                }
 +                _ => {}
 +            },
 +            CPlaceInner::VarPair(local, var1, var2) => {
 +                let layout = layout.field(&*fx, field.index());
 +
 +                match field.as_u32() {
 +                    0 => return CPlace { inner: CPlaceInner::Var(local, var1), layout },
 +                    1 => return CPlace { inner: CPlaceInner::Var(local, var2), layout },
 +                    _ => unreachable!("field should be 0 or 1"),
 +                }
 +            }
 +            _ => {}
 +        }
 +
 +        let (base, extra) = self.to_ptr_maybe_unsized();
 +
 +        let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
 +        if field_layout.is_unsized() {
 +            if let ty::Foreign(_) = field_layout.ty.kind() {
 +                assert!(extra.is_none());
 +                CPlace::for_ptr(field_ptr, field_layout)
 +            } else {
 +                CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout)
 +            }
 +        } else {
 +            CPlace::for_ptr(field_ptr, field_layout)
 +        }
 +    }
 +
 +    /// Like [`CPlace::place_field`] except handling ADTs containing a single array field in a way
 +    /// such that you can access individual lanes.
 +    pub(crate) fn place_lane(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        lane_idx: u64,
 +    ) -> CPlace<'tcx> {
 +        let layout = self.layout();
 +        assert!(layout.ty.is_simd());
 +        let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
 +        let lane_layout = fx.layout_of(lane_ty);
 +        assert!(lane_idx < lane_count);
 +
 +        match self.inner {
 +            CPlaceInner::Var(local, var) => {
 +                assert!(matches!(layout.abi, Abi::Vector { .. }));
 +                CPlace {
 +                    inner: CPlaceInner::VarLane(local, var, lane_idx.try_into().unwrap()),
 +                    layout: lane_layout,
 +                }
 +            }
 +            CPlaceInner::VarPair(_, _, _) => unreachable!(),
 +            CPlaceInner::VarLane(_, _, _) => unreachable!(),
 +            CPlaceInner::Addr(ptr, None) => {
 +                let field_offset = lane_layout.size * lane_idx;
 +                let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
 +                CPlace::for_ptr(field_ptr, lane_layout)
 +            }
 +            CPlaceInner::Addr(_, Some(_)) => unreachable!(),
 +        }
 +    }
 +
 +    pub(crate) fn place_index(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        index: Value,
 +    ) -> CPlace<'tcx> {
 +        let (elem_layout, ptr) = match self.layout().ty.kind() {
 +            ty::Array(elem_ty, _) => (fx.layout_of(*elem_ty), self.to_ptr()),
 +            ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
 +            _ => bug!("place_index({:?})", self.layout().ty),
 +        };
 +
 +        let offset = fx.bcx.ins().imul_imm(index, elem_layout.size.bytes() as i64);
 +
 +        CPlace::for_ptr(ptr.offset_value(fx, offset), elem_layout)
 +    }
 +
 +    pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> {
 +        let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty);
 +        if has_ptr_meta(fx.tcx, inner_layout.ty) {
 +            let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx);
 +            CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout)
 +        } else {
 +            CPlace::for_ptr(Pointer::new(self.to_cvalue(fx).load_scalar(fx)), inner_layout)
 +        }
 +    }
 +
 +    pub(crate) fn place_ref(
 +        self,
 +        fx: &mut FunctionCx<'_, '_, 'tcx>,
 +        layout: TyAndLayout<'tcx>,
 +    ) -> CValue<'tcx> {
 +        if has_ptr_meta(fx.tcx, self.layout().ty) {
 +            let (ptr, extra) = self.to_ptr_maybe_unsized();
 +            CValue::by_val_pair(
 +                ptr.get_addr(fx),
 +                extra.expect("unsized type without metadata"),
 +                layout,
 +            )
 +        } else {
 +            CValue::by_val(self.to_ptr().get_addr(fx), layout)
 +        }
 +    }
 +
 +    pub(crate) fn downcast_variant(
 +        self,
 +        fx: &FunctionCx<'_, '_, 'tcx>,
 +        variant: VariantIdx,
 +    ) -> Self {
 +        assert!(!self.layout().is_unsized());
 +        let layout = self.layout().for_variant(fx, variant);
 +        CPlace { inner: self.inner, layout }
 +    }
 +}
 +
 +#[track_caller]
 +pub(crate) fn assert_assignable<'tcx>(
 +    fx: &FunctionCx<'_, '_, 'tcx>,
 +    from_ty: Ty<'tcx>,
 +    to_ty: Ty<'tcx>,
 +) {
 +    match (from_ty.kind(), to_ty.kind()) {
 +        (ty::Ref(_, a, _), ty::Ref(_, b, _))
 +        | (
 +            ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
 +            ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
 +        ) => {
 +            assert_assignable(fx, *a, *b);
 +        }
 +        (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
 +        | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
 +            assert_assignable(fx, *a, *b);
 +        }
 +        (ty::FnPtr(_), ty::FnPtr(_)) => {
 +            let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
 +                ParamEnv::reveal_all(),
 +                from_ty.fn_sig(fx.tcx),
 +            );
 +            let to_sig = fx
 +                .tcx
 +                .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx));
 +            assert_eq!(
 +                from_sig, to_sig,
 +                "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
 +                from_sig, to_sig, fx,
 +            );
 +            // fn(&T) -> for<'l> fn(&'l T) is allowed
 +        }
 +        (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
 +            for (from, to) in from_traits.iter().zip(to_traits) {
 +                let from =
 +                    fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
 +                let to = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to);
 +                assert_eq!(
 +                    from, to,
 +                    "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}",
 +                    from_traits, to_traits, fx,
 +                );
 +            }
 +            // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
 +        }
 +        (&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b))
 +            if adt_def_a.did() == adt_def_b.did() =>
 +        {
 +            let mut types_a = substs_a.types();
 +            let mut types_b = substs_b.types();
 +            loop {
 +                match (types_a.next(), types_b.next()) {
 +                    (Some(a), Some(b)) => assert_assignable(fx, a, b),
 +                    (None, None) => return,
 +                    (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
 +                }
 +            }
 +        }
++        (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b),
 +        _ => {
 +            assert_eq!(
 +                from_ty, to_ty,
 +                "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
 +                from_ty, to_ty, fx,
 +            );
 +        }
 +    }
 +}