]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '40b00f4200fbdeefd11815398cb46394b8cb0a5e' into sync_cg_clif-2021-12-30
authorbjorn3 <bjorn3@users.noreply.github.com>
Thu, 30 Dec 2021 13:53:41 +0000 (14:53 +0100)
committerbjorn3 <bjorn3@users.noreply.github.com>
Thu, 30 Dec 2021 13:53:41 +0000 (14:53 +0100)
20 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/.gitignore
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo-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/common.rs
compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/lib.rs

index 7b73d3c00e60ef6ccdc68b053f8b92f20312ee29,0000000000000000000000000000000000000000..3aba528abfd6d193bb09847884514a4cb32d9af1
mode 100644,000000..100644
--- /dev/null
@@@ -1,169 -1,0 +1,184 @@@
 +name: CI
 +
 +on:
 +  - push
 +  - pull_request
 +
 +jobs:
++  rustfmt:
++    runs-on: ubuntu-latest
++    timeout-minutes: 10
++
++    steps:
++    - uses: actions/checkout@v2
++
++    - 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
 +
 +    - 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@v2
 +
 +    #- 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 c5b96a47828040ecb1b2d4f88590ac6eca009ed8,0000000000000000000000000000000000000000..a019793edd8d25481d6b1a4d733097b1fd3eaf89
mode 100644,000000..100644
--- /dev/null
@@@ -1,59 -1,0 +1,59 @@@
-     - cron: '1 17 * * *' # At 01:17 UTC every day.
 +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:
 +    - uses: actions/checkout@v2
 +
 +    - 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/gimli = { version = "0.25.0", default-features = false, features = \["write"\]}/gimli = { version = "0.26.1", default-features = false, features = ["write"] }/' 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 b6567aca78679cc0fe53bfd4967636832eda11ff,0000000000000000000000000000000000000000..5aeaf3a1788043134ceb20fa64b11ec7e6f09cb7
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,19 @@@
 +target
 +**/*.rs.bk
 +*.rlib
 +*.o
 +perf.data
 +perf.data.old
 +*.events
 +*.string*
 +/y.bin
++/y.bin.dSYM
 +/build
 +/build_sysroot/sysroot_src
 +/build_sysroot/compiler-builtins
 +/build_sysroot/rustc_version
 +/rust
 +/rand
 +/regex
 +/simple-raytracer
 +/portable-simd
index 900411286b52ec0855a599fb45ed588e61d6aec1,0000000000000000000000000000000000000000..3be4250296e774e1c5d2fb13def047985e97e4ec
mode 100644,000000..100644
--- /dev/null
@@@ -1,73 -1,0 +1,54 @@@
- [profile.dev]
- # By compiling dependencies with optimizations, performing tests gets much faster.
- opt-level = 3
- [profile.dev.package.rustc_codegen_cranelift]
- # Disabling optimizations for cg_clif itself makes compilation after a change faster.
- opt-level = 0
- [profile.release.package.rustc_codegen_cranelift]
- incremental = true
 +[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.78.0", features = ["unwind", "all-arch"] }
 +cranelift-frontend = "0.78.0"
 +cranelift-module = "0.78.0"
 +cranelift-native = "0.78.0"
 +cranelift-jit = { version = "0.78.0", optional = true }
 +cranelift-object = "0.78.0"
 +target-lexicon = "0.12.0"
 +gimli = { version = "0.25.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.0.2"
 +libloading = { version = "0.6.0", optional = true }
 +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 = []
 +
- [profile.dev.build-override]
- opt-level = 0
- debug = false
 +# 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.dev.package.cranelift-codegen-meta]
- opt-level = 0
- debug = false
 +[profile.release.build-override]
 +opt-level = 0
 +debug = false
 +
 +[profile.release.package.cranelift-codegen-meta]
 +opt-level = 0
 +debug = false
 +
 +[package.metadata.rust-analyzer]
 +rustc_private = true
index dad8ed90b53b8307fb1c4b72d40b15a59c2878bd,0000000000000000000000000000000000000000..8a2db5a43ecbf60488434ae6738677b8baad2d5b
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
- $ $cg_clif_dir/build/cargo build
 +# Cranelift codegen backend for rust
 +
 +The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift).
 +This has the potential to improve compilation times in debug mode.
 +If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
 +If not please open an issue.
 +
 +## Building and testing
 +
 +```bash
 +$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
 +$ cd rustc_codegen_cranelift
 +$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
 +$ ./y.rs build
 +```
 +
 +To run the test suite replace the last command with:
 +
 +```bash
 +$ ./test.sh
 +```
 +
 +This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to
 +build in debug mode.
 +
 +Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section
 +of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
 +
 +[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
 +
 +## 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`).
 +
 +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.
 +
 +For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
 +
 +## Configuration
 +
 +See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
 +configuration options.
 +
 +## Not yet supported
 +
 +* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
 +    * On Linux there is support for invoking an external assembler for `global_asm!` and `asm!`.
 +      `llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You
 +      have to specify specific registers instead.
 +* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)
 +
 +## License
 +
 +Licensed under either of
 +
 +  * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
 +    http://www.apache.org/licenses/LICENSE-2.0)
 +  * MIT license ([LICENSE-MIT](LICENSE-MIT) or
 +    http://opensource.org/licenses/MIT)
 +
 +at your option.
 +
 +### Contribution
 +
 +Unless you explicitly state otherwise, any contribution intentionally submitted
 +for inclusion in the work by you shall be dual licensed as above, without any
 +additional terms or conditions.
index ccc50ee4a59bf57544459befa117c5acf5048121,0000000000000000000000000000000000000000..1382c7e53793e997f1e2d699289c41c909664506
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,55 @@@
-             cmd.env(
-                 "RUSTFLAGS",
-                 "-Csplit-debuginfo=unpacked \
 +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!(),
 +    }
 +
++    // 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") {
-                 -Zosx-rpath-install-name"
-                     .to_string()
-                     + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
-             );
++            rustflags += " -Csplit-debuginfo=unpacked \
 +                -Clink-arg=-Wl,-rpath,@loader_path/../lib \
-             cmd.env(
-                 "RUSTFLAGS",
-                 "-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string()
-                     + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
-             );
++                -Zosx-rpath-install-name";
 +        } else {
++            rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib ";
 +        }
 +    }
 +
++    cmd.env("RUSTFLAGS", rustflags);
++
 +    eprintln!("[BUILD] rustc_codegen_cranelift");
 +    crate::utils::spawn_and_wait(cmd);
 +
 +    Path::new("target").join(host_triple).join(channel)
 +}
index 1c78e7b5171ee228f7d6463686ae5d085fb54e44,0000000000000000000000000000000000000000..2956fb698e17545307ac38dcfb701100e824da79
mode 100644,000000..100644
--- /dev/null
@@@ -1,217 -1,0 +1,217 @@@
-         .arg("scripts/cargo.rs")
 +use std::env;
 +use std::fs;
 +use std::path::{Path, PathBuf};
 +use std::process::{self, Command};
 +
 +use crate::rustc_info::{get_file_name, get_rustc_version};
 +use crate::utils::{spawn_and_wait, try_hard_link};
 +use crate::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(target_dir.join("cargo"))
++        .arg("scripts/cargo-clif.rs")
 +        .arg("-o")
++        .arg(target_dir.join("cargo-clif"))
 +        .arg("-g");
 +    spawn_and_wait(build_cargo_wrapper_cmd);
 +
 +    let default_sysroot = crate::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);
 +
 +            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);
 +            }
 +
 +            // 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-") {
 +                    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,
 +    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 !crate::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();
 +            }
 +        }
 +    }
 +
 +    // 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();
 +    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 bcc5745d9d1974af3115e83f9004151b10eeeba2,0000000000000000000000000000000000000000..785c7383783741701feea05580f26d527cfd0757
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,67 @@@
- $ $cg_clif_dir/build/cargo build
 +# 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 jit
++$ $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 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 lazy-jit
++$ $cg_clif_dir/build/cargo-clif jit
 +```
 +
 +or
 +
 +```bash
 +$ $cg_clif_dir/build/bin/cg_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/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
 +}
 +
 +function jit() {
 +    jit_naked "fn main() { $@ }"
 +}
 +
 +function jit_calc() {
 +    jit 'println!("0x{:x}", ' $@ ');';
 +}
 +```
index cbfdb3c44f33e1170c2e9d6a8b9abfb5654c7c7a,0000000000000000000000000000000000000000..ef3b575d39314f39a9b51957cd49812a0852d11a
mode 100644,000000..100644
--- /dev/null
@@@ -1,475 -1,0 +1,476 @@@
 +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)]
 +#![no_core]
 +#![allow(dead_code, non_camel_case_types)]
 +
 +extern crate mini_core;
 +
 +use mini_core::*;
 +use mini_core::libc::*;
 +
 +unsafe extern "C" fn my_puts(s: *const i8) {
 +    puts(s);
 +}
 +
 +macro_rules! assert {
 +    ($e:expr) => {
 +        if !$e {
 +            panic(stringify!(! $e));
 +        }
 +    };
 +}
 +
 +macro_rules! assert_eq {
 +    ($l:expr, $r: expr) => {
 +        if $l != $r {
 +            panic(stringify!($l != $r));
 +        }
 +    }
 +}
 +
 +#[lang = "termination"]
 +trait Termination {
 +    fn report(self) -> i32;
 +}
 +
 +impl Termination for () {
 +    fn report(self) -> i32 {
 +        unsafe {
 +            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
 +            assert_eq!(*NUM_REF as i32, 44);
 +        }
 +        0
 +    }
 +}
 +
 +trait SomeTrait {
 +    fn object_safe(&self);
 +}
 +
 +impl SomeTrait for &'static str {
 +    fn object_safe(&self) {
 +        unsafe {
 +            puts(*self as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +struct NoisyDrop {
 +    text: &'static str,
 +    inner: NoisyDropInner,
 +}
 +
 +struct NoisyDropInner;
 +
 +impl Drop for NoisyDrop {
 +    fn drop(&mut self) {
 +        unsafe {
 +            puts(self.text as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +impl Drop for NoisyDropInner {
 +    fn drop(&mut self) {
 +        unsafe {
 +            puts("Inner got dropped!\0" as *const str as *const i8);
 +        }
 +    }
 +}
 +
 +impl SomeTrait for NoisyDrop {
 +    fn object_safe(&self) {}
 +}
 +
 +enum Ordering {
 +    Less = -1,
 +    Equal = 0,
 +    Greater = 1,
 +}
 +
 +#[lang = "start"]
 +fn start<T: Termination + 'static>(
 +    main: fn() -> T,
 +    argc: isize,
 +    argv: *const *const u8,
 +) -> isize {
 +    if argc == 3 {
 +        unsafe { puts(*argv as *const i8); }
 +        unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); }
 +        unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
 +    }
 +
 +    main().report() as isize
 +}
 +
 +static mut NUM: u8 = 6 * 7;
 +static NUM_REF: &'static u8 = unsafe { &NUM };
 +
 +struct Unique<T: ?Sized> {
 +    pointer: *const T,
 +    _marker: PhantomData<T>,
 +}
 +
 +impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
 +
 +unsafe fn zeroed<T>() -> T {
 +    let mut uninit = MaybeUninit { uninit: () };
 +    intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
 +    uninit.value.value
 +}
 +
 +fn take_f32(_f: f32) {}
 +fn take_unique(_u: Unique<()>) {}
 +
 +fn return_u128_pair() -> (u128, u128) {
 +    (0, 0)
 +}
 +
 +fn call_return_u128_pair() {
 +    return_u128_pair();
 +}
 +
++#[allow(unreachable_code)] // FIXME false positive
 +fn main() {
 +    take_unique(Unique {
 +        pointer: 0 as *const (),
 +        _marker: PhantomData,
 +    });
 +    take_f32(0.1);
 +
 +    call_return_u128_pair();
 +
 +    let slice = &[0, 1] as &[i32];
 +    let slice_ptr = slice as *const [i32] as *const i32;
 +
 +    assert_eq!(slice_ptr as usize % 4, 0);
 +
 +    //return;
 +
 +    unsafe {
 +        printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
 +
 +        let hello: &[u8] = b"Hello\0" as &[u8; 6];
 +        let ptr: *const i8 = hello as *const [u8] as *const i8;
 +        puts(ptr);
 +
 +        let world: Box<&str> = box "World!\0";
 +        puts(*world as *const str as *const i8);
 +        world as Box<dyn SomeTrait>;
 +
 +        assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
 +
 +        assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
 +        assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
 +        assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32);
 +        assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64);
 +
 +        assert_eq!(intrinsics::size_of_val(hello) as u8, 6);
 +
 +        let chars = &['C', 'h', 'a', 'r', 's'];
 +        let chars = chars as &[char];
 +        assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5);
 +
 +        let a: &dyn SomeTrait = &"abc\0";
 +        a.object_safe();
 +
 +        assert_eq!(intrinsics::size_of_val(a) as u8, 16);
 +        assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
 +
 +        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
 +        assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
 +
 +        assert!(!intrinsics::needs_drop::<u8>());
 +        assert!(intrinsics::needs_drop::<NoisyDrop>());
 +
 +        Unique {
 +            pointer: 0 as *const &str,
 +            _marker: PhantomData,
 +        } as Unique<dyn SomeTrait>;
 +
 +        struct MyDst<T: ?Sized>(T);
 +
 +        intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>);
 +
 +        struct Foo {
 +            x: u8,
 +            y: !,
 +        }
 +
 +        unsafe fn uninitialized<T>() -> T {
 +            MaybeUninit { uninit: () }.value.value
 +        }
 +
 +        zeroed::<(u8, u8)>();
 +        #[allow(unreachable_code)]
 +        {
 +            if false {
 +                zeroed::<!>();
 +                zeroed::<Foo>();
 +                uninitialized::<Foo>();
 +            }
 +        }
 +    }
 +
 +    let _ = box NoisyDrop {
 +        text: "Boxed outer got dropped!\0",
 +        inner: NoisyDropInner,
 +    } as Box<dyn SomeTrait>;
 +
 +    const FUNC_REF: Option<fn()> = Some(main);
 +    match FUNC_REF {
 +        Some(_) => {},
 +        None => assert!(false),
 +    }
 +
 +    match Ordering::Less {
 +        Ordering::Less => {},
 +        _ => assert!(false),
 +    }
 +
 +    [NoisyDropInner, NoisyDropInner];
 +
 +    let x = &[0u32, 42u32] as &[u32];
 +    match x {
 +        [] => assert_eq!(0u32, 1),
 +        [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize),
 +    }
 +
 +    assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
 +
 +    #[cfg(not(any(jit, windows)))]
 +    {
 +        extern {
 +            #[linkage = "extern_weak"]
 +            static ABC: *const u8;
 +        }
 +
 +        {
 +            extern {
 +                #[linkage = "extern_weak"]
 +                static ABC: *const u8;
 +            }
 +        }
 +
 +        unsafe { assert_eq!(ABC as usize, 0); }
 +    }
 +
 +    &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
 +
 +    let f = 1000.0;
 +    assert_eq!(f as u8, 255);
 +    let f2 = -1000.0;
 +    assert_eq!(f2 as i8, -128);
 +    assert_eq!(f2 as u8, 0);
 +
 +    let amount = 0;
 +    assert_eq!(1u128 << amount, 1);
 +
 +    static ANOTHER_STATIC: &u8 = &A_STATIC;
 +    assert_eq!(*ANOTHER_STATIC, 42);
 +
 +    check_niche_behavior();
 +
 +    extern "C" {
 +        type ExternType;
 +    }
 +
 +    struct ExternTypeWrapper {
 +        _a: ExternType,
 +    }
 +
 +    let nullptr = 0 as *const ();
 +    let extern_nullptr = nullptr as *const ExternTypeWrapper;
 +    extern_nullptr as *const ();
 +    let slice_ptr = &[] as *const [u8];
 +    slice_ptr as *const u8;
 +
 +    let repeat = [Some(42); 2];
 +    assert_eq!(repeat[0], Some(42));
 +    assert_eq!(repeat[1], Some(42));
 +
 +    from_decimal_string();
 +
 +    #[cfg(not(any(jit, windows)))]
 +    test_tls();
 +
 +    #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +    unsafe {
 +        global_asm_test();
 +    }
 +
 +    // Both statics have a reference that points to the same anonymous allocation.
 +    static REF1: &u8 = &42;
 +    static REF2: &u8 = REF1;
 +    assert_eq!(*REF1, *REF2);
 +}
 +
 +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +extern "C" {
 +    fn global_asm_test();
 +}
 +
 +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
 +global_asm! {
 +    "
 +    .global global_asm_test
 +    global_asm_test:
 +    // comment that would normally be removed by LLVM
 +    ret
 +    "
 +}
 +
 +#[repr(C)]
 +enum c_void {
 +    _1,
 +    _2,
 +}
 +
 +type c_int = i32;
 +type c_ulong = u64;
 +
 +type pthread_t = c_ulong;
 +
 +#[repr(C)]
 +struct pthread_attr_t {
 +    __size: [u64; 7],
 +}
 +
 +#[link(name = "pthread")]
 +extern "C" {
 +    fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
 +
 +    fn pthread_create(
 +        native: *mut pthread_t,
 +        attr: *const pthread_attr_t,
 +        f: extern "C" fn(_: *mut c_void) -> *mut c_void,
 +        value: *mut c_void
 +    ) -> c_int;
 +
 +    fn pthread_join(
 +        native: pthread_t,
 +        value: *mut *mut c_void
 +    ) -> c_int;
 +}
 +
 +#[thread_local]
 +#[cfg(not(jit))]
 +static mut TLS: u8 = 42;
 +
 +#[cfg(not(jit))]
 +extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
 +    unsafe { TLS = 0; }
 +    0 as *mut c_void
 +}
 +
 +#[cfg(not(jit))]
 +fn test_tls() {
 +    unsafe {
 +        let mut attr: pthread_attr_t = zeroed();
 +        let mut thread: pthread_t = 0;
 +
 +        assert_eq!(TLS, 42);
 +
 +        if pthread_attr_init(&mut attr) != 0 {
 +            assert!(false);
 +        }
 +
 +        if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
 +            assert!(false);
 +        }
 +
 +        let mut res = 0 as *mut c_void;
 +        pthread_join(thread, &mut res);
 +
 +        // TLS of main thread must not have been changed by the other thread.
 +        assert_eq!(TLS, 42);
 +
 +        puts("TLS works!\n\0" as *const str as *const i8);
 +    }
 +}
 +
 +// Copied ui/issues/issue-61696.rs
 +
 +pub enum Infallible {}
 +
 +// The check that the `bool` field of `V1` is encoding a "niche variant"
 +// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect,
 +// causing valid `V1` values to be interpreted as other variants.
 +pub enum E1 {
 +    V1 { f: bool },
 +    V2 { f: Infallible },
 +    V3,
 +    V4,
 +}
 +
 +// Computing the discriminant used to be done using the niche type (here `u8`,
 +// from the `bool` field of `V1`), overflowing for variants with large enough
 +// indices (`V3` and `V4`), causing them to be interpreted as other variants.
 +pub enum E2<X> {
 +    V1 { f: bool },
 +
 +    /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
 +    _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
 +    _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
 +    _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
 +    _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
 +    _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
 +    _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
 +    _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
 +    _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
 +    _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
 +    _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
 +    _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
 +    _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
 +    _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
 +    _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
 +    _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
 +    _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
 +    _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
 +    _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
 +    _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
 +    _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
 +    _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
 +    _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
 +    _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
 +    _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
 +    _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
 +    _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
 +    _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
 +    _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
 +    _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
 +    _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
 +    _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
 +
 +    V3,
 +    V4,
 +}
 +
 +fn check_niche_behavior () {
 +    if let E1::V2 { .. } = (E1::V1 { f: true }) {
 +        intrinsics::abort();
 +    }
 +
 +    if let E2::V1 { .. } = E2::V3::<Infallible> {
 +        intrinsics::abort();
 +    }
 +}
 +
 +fn from_decimal_string() {
 +    loop {
 +        let multiplier = 1;
 +
 +        take_multiplier_ref(&multiplier);
 +
 +        if multiplier == 1 {
 +            break;
 +        }
 +
 +        unreachable();
 +    }
 +}
 +
 +fn take_multiplier_ref(_multiplier: &u128) {}
 +
 +fn unreachable() -> ! {
 +    panic("unreachable")
 +}
index 7b5db307a2dc26c1ea5e6e56c02431640b98e6c1,0000000000000000000000000000000000000000..cab94c0b8cfa7ee659f48c907789d6575ff539ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-12-20"
 +[toolchain]
++channel = "nightly-2021-12-30"
 +components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..41d82b581cd8cc07111c7f5b6a6f491a178dc801
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,78 @@@
++use std::env;
++#[cfg(unix)]
++use std::os::unix::process::CommandExt;
++use std::path::PathBuf;
++use std::process::Command;
++
++fn main() {
++    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");
++    }
++
++    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
++
++    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(
++        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(),
++    );
++    rustdoc_flags.push_str(" --sysroot ");
++    rustdoc_flags.push_str(sysroot.to_str().unwrap());
++    env::set_var("RUSTDOCFLAGS", rustdoc_flags);
++
++    // 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(),
++                    "-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-features".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 46c3b5b7f11adf890e5b4b27e321762ca792a096,0000000000000000000000000000000000000000..73600faa1e9c2ead9194c8b9fb8afef89d831910
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- ./y.rs build
 +#!/bin/bash
 +set -e
 +
++./y.rs build --no-unstable-features
 +source scripts/config.sh
 +
 +echo "[SETUP] Rust fork"
 +git clone https://github.com/rust-lang/rust.git || true
 +pushd rust
 +git fetch
 +git checkout -- .
 +git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 +
 +git apply - <<EOF
 +diff --git a/Cargo.toml b/Cargo.toml
 +index 5bd1147cad5..10d68a2ff14 100644
 +--- a/Cargo.toml
 ++++ b/Cargo.toml
 +@@ -111,5 +111,7 @@ rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' }
 + rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' }
 + rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' }
 +
 ++compiler_builtins = { path = "../build_sysroot/compiler-builtins" }
 ++
 + [patch."https://github.com/rust-lang/rust-clippy"]
 + clippy_lints = { path = "src/tools/clippy/clippy_lints" }
 +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"
 +EOF
 +
 +cat > config.toml <<EOF
 +[llvm]
 +ninja = false
 +
 +[build]
 +rustc = "$(pwd)/../build/bin/cg_clif"
 +cargo = "$(rustup which cargo)"
 +full-bootstrap = true
 +local-rebuild = true
 +
 +[rust]
 +codegen-backends = ["cranelift"]
 +deny-warnings = false
 +verbose-tests = false
 +EOF
 +popd
index 99fddf5361e43e3928e248013a460bf254a43fd5,0000000000000000000000000000000000000000..6bcc3049ecc4eefc978e75ce8f2f0ee51f54de11
mode 100755,000000..100755
--- /dev/null
@@@ -1,102 -1,0 +1,106 @@@
- rm src/test/incremental/issue-49482.rs # same
- rm src/test/incremental/issue-54059.rs # same
 +#!/bin/bash
 +set -e
 +
 +cd $(dirname "$0")/../
 +
 +source ./scripts/setup_rust_fork.sh
 +
 +echo "[TEST] Test suite of rustc"
 +pushd rust
 +
 +cargo install ripgrep
 +
 +rm -r src/test/ui/{extern/,panics/,unsized-locals/,lto/,simd*,linkage*,unwind-*.rs} || true
 +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do
 +  rm $test
 +done
 +
 +for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// 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
 +
 +# these all depend on unwinding support
 +rm src/test/ui/backtrace.rs
 +rm src/test/ui/array-slice-vec/box-of-array-of-drop-*.rs
 +rm src/test/ui/array-slice-vec/slice-panic-*.rs
 +rm src/test/ui/array-slice-vec/nested-vec-3.rs
 +rm src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
 +rm src/test/ui/issues/issue-26655.rs
 +rm src/test/ui/issues/issue-29485.rs
 +rm src/test/ui/issues/issue-30018-panic.rs
 +rm src/test/ui/process/multi-panic.rs
 +rm src/test/ui/sepcomp/sepcomp-unwind.rs
 +rm src/test/ui/structs-enums/unit-like-struct-drop-run.rs
 +rm src/test/ui/drop/terminate-in-initializer.rs
 +rm src/test/ui/threads-sendsync/task-stderr.rs
 +rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
 +rm src/test/ui/drop/drop-trait-enum.rs
 +rm src/test/ui/numbers-arithmetic/issue-8460.rs
 +rm src/test/ui/runtime/rt-explody-panic-payloads.rs
 +rm src/test/incremental/change_crate_dep_kind.rs
 +rm src/test/ui/threads-sendsync/unwind-resource.rs
 +
 +rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
 +rm src/test/ui/codegen/init-large-type.rs # same
 +rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
 +rm src/test/ui/issues/issue-33992.rs # unsupported linkages
 +rm src/test/ui/issues/issue-51947.rs # same
++rm src/test/incremental/hashes/function_interfaces.rs # same
++rm src/test/incremental/hashes/statics.rs # same
 +rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
 +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
 +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
 +rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 +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/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics
 +
 +rm src/test/incremental/hashes/inline_asm.rs # inline asm
 +rm src/test/incremental/issue-72386.rs # same
- rm src/test/pretty/asm.rs # inline asm
- rm src/test/pretty/raw-str-nonexpr.rs # same
 +rm src/test/incremental/lto.rs # requires lto
++rm src/test/incremental/dirty_clean.rs # TODO
 +
 +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
 +rm -r src/test/run-make/emit-named-files # requires full --emit support
 +
- RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui}
 +rm -r src/test/run-pass-valgrind/unsized-locals
 +
 +rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning
 +rm src/test/ui/json-bom-plus-crlf.rs # same
 +rm src/test/ui/intrinsics/const-eval-select-x86_64.rs # same
 +rm src/test/ui/match/issue-82392.rs # differing error
 +rm src/test/ui/consts/min_const_fn/address_of_const.rs # same
 +rm src/test/ui/consts/issue-miri-1910.rs # same
 +rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep
 +
 +rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
 +rm src/test/ui/cfg/cfg-panic.rs
 +rm -r src/test/ui/hygiene/
 +
 +rm -r src/test/ui/polymorphization/ # polymorphization not yet supported
 +rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same
 +
 +rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization
 +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
 +
 +rm src/test/ui/command/command-current-dir.rs # can't find libstd.so
 +
 +rm src/test/ui/abi/stack-protector.rs # requires stack protector support
 +
++rm src/test/incremental/issue-80691-bad-eval-cache.rs # wrong exit code
++rm src/test/incremental/spike-neg1.rs # errors out for some reason
++rm src/test/incremental/spike-neg2.rs # same
++
++rm src/test/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
++
 +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 fd2b3761ff0364da4aeb6ceca1c607a0d6015c61,0000000000000000000000000000000000000000..bdb3de0936dc90dc1f7b10543170b9e599e6a972
mode 100755,000000..100755
--- /dev/null
@@@ -1,167 -1,0 +1,167 @@@
-     ../build/cargo clean
 +#!/usr/bin/env bash
 +
 +set -e
 +
 +source scripts/config.sh
 +source scripts/ext_config.sh
 +export RUSTC=false # ensure that cg_llvm isn't accidentally used
 +MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
 +
 +function no_sysroot_tests() {
 +    echo "[BUILD] mini_core"
 +    $MY_RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target "$TARGET_TRIPLE"
 +
 +    echo "[BUILD] example"
 +    $MY_RUSTC example/example.rs --crate-type lib --target "$TARGET_TRIPLE"
 +
 +    if [[ "$JIT_SUPPORTED" = "1" ]]; then
 +        echo "[JIT] mini_core_hello_world"
 +        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
 +
 +        echo "[JIT-lazy] mini_core_hello_world"
 +        CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
 +    else
 +        echo "[JIT] mini_core_hello_world (skipped)"
 +    fi
 +
 +    echo "[AOT] mini_core_hello_world"
 +    $MY_RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
 +    # (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd
 +}
 +
 +function base_sysroot_tests() {
 +    echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
 +    $MY_RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
 +
 +    echo "[AOT] issue_91827_extern_types"
 +    $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/issue_91827_extern_types
 +
 +    echo "[AOT] alloc_system"
 +    $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
 +
 +    echo "[AOT] alloc_example"
 +    $MY_RUSTC example/alloc_example.rs --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/alloc_example
 +
 +    if [[ "$JIT_SUPPORTED" = "1" ]]; then
 +        echo "[JIT] std_example"
 +        $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
 +
 +        echo "[JIT-lazy] std_example"
 +        $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
 +    else
 +        echo "[JIT] std_example (skipped)"
 +    fi
 +
 +    echo "[AOT] dst_field_align"
 +    # FIXME Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
 +    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
 +
 +    echo "[AOT] std_example"
 +    $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/std_example arg
 +
 +    echo "[AOT] subslice-patterns-const-eval"
 +    $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
 +
 +    echo "[AOT] track-caller-attribute"
 +    $MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
 +    $RUN_WRAPPER ./target/out/track-caller-attribute
 +
 +    echo "[AOT] 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 test --workspace
++    ../build/cargo-clif clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        echo "[TEST] rust-random/rand"
-         ../build/cargo build --workspace --target $TARGET_TRIPLE --tests
++        ../build/cargo-clif test --workspace
 +    else
 +        echo "[AOT] rust-random/rand"
-         hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \
++        ../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"
-         "../build/cargo build"
++        hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
 +        "RUSTC=rustc RUSTFLAGS='' cargo build" \
-         ../build/cargo clean
++        "../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 build --target $TARGET_TRIPLE
++        ../build/cargo-clif clean
 +        echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
 +        echo "[COMPILE] ebobby/simple-raytracer"
-     ../../../../../build/cargo clean
++        ../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 test
++    ../../../../../build/cargo-clif clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
-         ../../../../../build/cargo build --target $TARGET_TRIPLE --tests
++        ../../../../../build/cargo-clif test
 +    else
-     ../build/cargo clean
++        ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests
 +    fi
 +    popd
 +
 +    pushd regex
 +    echo "[TEST] rust-lang/regex example shootout-regex-dna"
-     ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE
++    ../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 run --example shootout-regex-dna --target $TARGET_TRIPLE \
++    ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        cat examples/regexdna-input.txt \
-         ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
++            | ../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 build --tests --target $TARGET_TRIPLE
++        ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
 +    else
 +        echo "[AOT] rust-lang/regex tests"
-     ../build/cargo clean
-     ../build/cargo build --all-targets --target $TARGET_TRIPLE
++        ../build/cargo-clif build --tests --target $TARGET_TRIPLE
 +    fi
 +    popd
 +
 +    pushd portable-simd
 +    echo "[TEST] rust-lang/portable-simd"
-         ../build/cargo test -q
++    ../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 644204d10b8ed3a748754c88f8ffa6653616284b,0000000000000000000000000000000000000000..3b6025c73d10bd7a0113e2b31662dd7a20d9753a
mode 100644,000000..100644
--- /dev/null
@@@ -1,452 -1,0 +1,452 @@@
-     pub(crate) pointer_type: Type, // Cached from module
 +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.value {
 +        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(substs) if substs.len() == 2 => {
 +            let mut types = substs.types();
 +            let a = clif_type_from_ty(tcx, types.next().unwrap())?;
 +            let b = clif_type_from_ty(tcx, types.next().unwrap())?;
 +            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));
 +    }
 +
 +    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;
 +        }
 +
 +        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())
 +    }
 +
 +    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 4120ba6e53352099d14217c3cc5a15748b298602,0000000000000000000000000000000000000000..589910ede9688ce330e42bc2552ae3b9ea67cd54
mode 100644,000000..100644
--- /dev/null
@@@ -1,190 -1,0 +1,190 @@@
-     #[cfg(feature = "jit")]
 +//! Write the debuginfo into an object file.
 +
 +use cranelift_object::ObjectProduct;
 +use rustc_data_structures::fx::FxHashMap;
 +
 +use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
 +use gimli::{RunTimeEndian, SectionId};
 +
 +use super::object::WriteDebugInfo;
 +use super::DebugContext;
 +
 +impl DebugContext<'_> {
 +    pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
 +        let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
 +        let root = self.dwarf.unit.root();
 +        let root = self.dwarf.unit.get_mut(root);
 +        root.set(gimli::DW_AT_ranges, AttributeValue::RangeListRef(unit_range_list_id));
 +
 +        let mut sections = Sections::new(WriterRelocate::new(self.endian));
 +        self.dwarf.write(&mut sections).unwrap();
 +
 +        let mut section_map = FxHashMap::default();
 +        let _: Result<()> = sections.for_each_mut(|id, section| {
 +            if !section.writer.slice().is_empty() {
 +                let section_id = product.add_debug_section(id, section.writer.take());
 +                section_map.insert(id, section_id);
 +            }
 +            Ok(())
 +        });
 +
 +        let _: Result<()> = sections.for_each(|id, section| {
 +            if let Some(section_id) = section_map.get(&id) {
 +                for reloc in &section.relocs {
 +                    product.add_debug_reloc(&section_map, section_id, reloc);
 +                }
 +            }
 +            Ok(())
 +        });
 +    }
 +}
 +
 +#[derive(Clone)]
 +pub(crate) struct DebugReloc {
 +    pub(crate) offset: u32,
 +    pub(crate) size: u8,
 +    pub(crate) name: DebugRelocName,
 +    pub(crate) addend: i64,
 +    pub(crate) kind: object::RelocationKind,
 +}
 +
 +#[derive(Clone)]
 +pub(crate) enum DebugRelocName {
 +    Section(SectionId),
 +    Symbol(usize),
 +}
 +
 +/// A [`Writer`] that collects all necessary relocations.
 +#[derive(Clone)]
 +pub(super) struct WriterRelocate {
 +    pub(super) relocs: Vec<DebugReloc>,
 +    pub(super) writer: EndianVec<RunTimeEndian>,
 +}
 +
 +impl WriterRelocate {
 +    pub(super) fn new(endian: RunTimeEndian) -> Self {
 +        WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian) }
 +    }
 +
 +    /// Perform the collected relocations to be usable for JIT usage.
++    #[cfg(all(feature = "jit", not(windows)))]
 +    pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
 +        for reloc in self.relocs.drain(..) {
 +            match reloc.name {
 +                super::DebugRelocName::Section(_) => unreachable!(),
 +                super::DebugRelocName::Symbol(sym) => {
 +                    let addr = jit_module.get_finalized_function(
 +                        cranelift_module::FuncId::from_u32(sym.try_into().unwrap()),
 +                    );
 +                    let val = (addr as u64 as i64 + reloc.addend) as u64;
 +                    self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap();
 +                }
 +            }
 +        }
 +        self.writer.into_vec()
 +    }
 +}
 +
 +impl Writer for WriterRelocate {
 +    type Endian = RunTimeEndian;
 +
 +    fn endian(&self) -> Self::Endian {
 +        self.writer.endian()
 +    }
 +
 +    fn len(&self) -> usize {
 +        self.writer.len()
 +    }
 +
 +    fn write(&mut self, bytes: &[u8]) -> Result<()> {
 +        self.writer.write(bytes)
 +    }
 +
 +    fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
 +        self.writer.write_at(offset, bytes)
 +    }
 +
 +    fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
 +        match address {
 +            Address::Constant(val) => self.write_udata(val, size),
 +            Address::Symbol { symbol, addend } => {
 +                let offset = self.len() as u64;
 +                self.relocs.push(DebugReloc {
 +                    offset: offset as u32,
 +                    size,
 +                    name: DebugRelocName::Symbol(symbol),
 +                    addend: addend as i64,
 +                    kind: object::RelocationKind::Absolute,
 +                });
 +                self.write_udata(0, size)
 +            }
 +        }
 +    }
 +
 +    fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
 +        let offset = self.len() as u32;
 +        self.relocs.push(DebugReloc {
 +            offset,
 +            size,
 +            name: DebugRelocName::Section(section),
 +            addend: val as i64,
 +            kind: object::RelocationKind::Absolute,
 +        });
 +        self.write_udata(0, size)
 +    }
 +
 +    fn write_offset_at(
 +        &mut self,
 +        offset: usize,
 +        val: usize,
 +        section: SectionId,
 +        size: u8,
 +    ) -> Result<()> {
 +        self.relocs.push(DebugReloc {
 +            offset: offset as u32,
 +            size,
 +            name: DebugRelocName::Section(section),
 +            addend: val as i64,
 +            kind: object::RelocationKind::Absolute,
 +        });
 +        self.write_udata_at(offset, 0, size)
 +    }
 +
 +    fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> {
 +        match address {
 +            // Address::Constant arm copied from gimli
 +            Address::Constant(val) => {
 +                // Indirect doesn't matter here.
 +                let val = match eh_pe.application() {
 +                    gimli::DW_EH_PE_absptr => val,
 +                    gimli::DW_EH_PE_pcrel => {
 +                        // FIXME better handling of sign
 +                        let offset = self.len() as u64;
 +                        offset.wrapping_sub(val)
 +                    }
 +                    _ => {
 +                        return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe));
 +                    }
 +                };
 +                self.write_eh_pointer_data(val, eh_pe.format(), size)
 +            }
 +            Address::Symbol { symbol, addend } => match eh_pe.application() {
 +                gimli::DW_EH_PE_pcrel => {
 +                    let size = match eh_pe.format() {
 +                        gimli::DW_EH_PE_sdata4 => 4,
 +                        _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),
 +                    };
 +                    self.relocs.push(DebugReloc {
 +                        offset: self.len() as u32,
 +                        size,
 +                        name: DebugRelocName::Symbol(symbol),
 +                        addend,
 +                        kind: object::RelocationKind::Relative,
 +                    });
 +                    self.write_udata(0, size)
 +                }
 +                _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),
 +            },
 +        }
 +    }
 +}
index dd19dd5d2b91c02c84a7684ab0a10c64e1252ea0,0000000000000000000000000000000000000000..638b025be229d57170e607b15fc0508def83986b
mode 100644,000000..100644
--- /dev/null
@@@ -1,361 -1,0 +1,357 @@@
- use cranelift_codegen::ir::{LabelValueLoc, ValueLabel};
 +//! Handling of everything related to debuginfo.
 +
 +mod emit;
 +mod line_info;
 +mod object;
 +mod unwind;
 +
 +use crate::prelude::*;
 +
 +use rustc_index::vec::IndexVec;
 +
 +use cranelift_codegen::entity::EntityRef;
- fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
-     use rustc_target::abi::Endian;
-     match tcx.data_layout.endian {
-         Endian::Big => RunTimeEndian::Big,
-         Endian::Little => RunTimeEndian::Little,
-     }
- }
++use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel};
 +use cranelift_codegen::isa::TargetIsa;
 +use cranelift_codegen::ValueLocRange;
 +
 +use gimli::write::{
 +    Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
 +    LocationList, Range, RangeList, UnitEntryId,
 +};
 +use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};
 +
 +pub(crate) use emit::{DebugReloc, DebugRelocName};
 +pub(crate) use unwind::UnwindContext;
 +
-             endian: target_endian(tcx),
 +pub(crate) struct DebugContext<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +
 +    endian: RunTimeEndian,
 +
 +    dwarf: DwarfUnit,
 +    unit_range_list: RangeList,
 +
 +    types: FxHashMap<Ty<'tcx>, UnitEntryId>,
 +}
 +
 +impl<'tcx> DebugContext<'tcx> {
 +    pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
 +        let encoding = Encoding {
 +            format: Format::Dwarf32,
 +            // FIXME this should be configurable
 +            // macOS doesn't seem to support DWARF > 3
 +            // 5 version is required for md5 file hash
 +            version: if tcx.sess.target.is_like_osx {
 +                3
 +            } else {
 +                // FIXME change to version 5 once the gdb and lldb shipping with the latest debian
 +                // support it.
 +                4
 +            },
 +            address_size: isa.frontend_config().pointer_bytes(),
 +        };
 +
++        let endian = match isa.endianness() {
++            Endianness::Little => RunTimeEndian::Little,
++            Endianness::Big => RunTimeEndian::Big,
++        };
++
 +        let mut dwarf = DwarfUnit::new(encoding);
 +
 +        let producer = format!(
 +            "cg_clif (rustc {}, cranelift {})",
 +            rustc_interface::util::version_str().unwrap_or("unknown version"),
 +            cranelift_codegen::VERSION,
 +        );
 +        let comp_dir = tcx
 +            .sess
 +            .opts
 +            .working_dir
 +            .to_string_lossy(FileNameDisplayPreference::Remapped)
 +            .into_owned();
 +        let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
 +            Some(path) => {
 +                let name = path.to_string_lossy().into_owned();
 +                (name, None)
 +            }
 +            None => (tcx.crate_name(LOCAL_CRATE).to_string(), None),
 +        };
 +
 +        let mut line_program = LineProgram::new(
 +            encoding,
 +            LineEncoding::default(),
 +            LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
 +            LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
 +            file_info,
 +        );
 +        line_program.file_has_md5 = file_info.is_some();
 +
 +        dwarf.unit.line_program = line_program;
 +
 +        {
 +            let name = dwarf.strings.add(name);
 +            let comp_dir = dwarf.strings.add(comp_dir);
 +
 +            let root = dwarf.unit.root();
 +            let root = dwarf.unit.get_mut(root);
 +            root.set(gimli::DW_AT_producer, AttributeValue::StringRef(dwarf.strings.add(producer)));
 +            root.set(gimli::DW_AT_language, AttributeValue::Language(gimli::DW_LANG_Rust));
 +            root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
 +            root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
 +            root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0)));
 +        }
 +
 +        DebugContext {
 +            tcx,
 +
++            endian,
 +
 +            dwarf,
 +            unit_range_list: RangeList(Vec::new()),
 +
 +            types: FxHashMap::default(),
 +        }
 +    }
 +
 +    fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
 +        if let Some(type_id) = self.types.get(ty) {
 +            return *type_id;
 +        }
 +
 +        let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);
 +
 +        let primitive = |dwarf: &mut DwarfUnit, ate| {
 +            let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
 +            let type_entry = dwarf.unit.get_mut(type_id);
 +            type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
 +            type_id
 +        };
 +
 +        let name = format!("{}", ty);
 +        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
 +
 +        let type_id = match ty.kind() {
 +            ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
 +            ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
 +            ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
 +            ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
 +            ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
 +            ty::Ref(_, pointee_ty, _mutbl)
 +            | ty::RawPtr(ty::TypeAndMut { ty: pointee_ty, mutbl: _mutbl }) => {
 +                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);
 +
 +                // Ensure that type is inserted before recursing to avoid duplicates
 +                self.types.insert(ty, type_id);
 +
 +                let pointee = self.dwarf_ty(pointee_ty);
 +
 +                let type_entry = self.dwarf.unit.get_mut(type_id);
 +
 +                //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
 +                type_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(pointee));
 +
 +                type_id
 +            }
 +            ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
 +                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);
 +
 +                // Ensure that type is inserted before recursing to avoid duplicates
 +                self.types.insert(ty, type_id);
 +
 +                let variant = adt_def.non_enum_variant();
 +
 +                for (field_idx, field_def) in variant.fields.iter().enumerate() {
 +                    let field_offset = layout.fields.offset(field_idx);
 +                    let field_layout = layout.field(
 +                        &layout::LayoutCx { tcx: self.tcx, param_env: ParamEnv::reveal_all() },
 +                        field_idx,
 +                    );
 +
 +                    let field_type = self.dwarf_ty(field_layout.ty);
 +
 +                    let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
 +                    let field_entry = self.dwarf.unit.get_mut(field_id);
 +
 +                    field_entry.set(
 +                        gimli::DW_AT_name,
 +                        AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()),
 +                    );
 +                    field_entry.set(
 +                        gimli::DW_AT_data_member_location,
 +                        AttributeValue::Udata(field_offset.bytes()),
 +                    );
 +                    field_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(field_type));
 +                }
 +
 +                type_id
 +            }
 +            _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
 +        };
 +
 +        let type_entry = self.dwarf.unit.get_mut(type_id);
 +
 +        type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
 +        type_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes()));
 +
 +        self.types.insert(ty, type_id);
 +
 +        type_id
 +    }
 +
 +    fn define_local(&mut self, scope: UnitEntryId, name: String, ty: Ty<'tcx>) -> UnitEntryId {
 +        let dw_ty = self.dwarf_ty(ty);
 +
 +        let var_id = self.dwarf.unit.add(scope, gimli::DW_TAG_variable);
 +        let var_entry = self.dwarf.unit.get_mut(var_id);
 +
 +        var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
 +        var_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty));
 +
 +        var_id
 +    }
 +
 +    pub(crate) fn define_function(
 +        &mut self,
 +        instance: Instance<'tcx>,
 +        func_id: FuncId,
 +        name: &str,
 +        isa: &dyn TargetIsa,
 +        context: &Context,
 +        source_info_set: &indexmap::IndexSet<SourceInfo>,
 +        local_map: IndexVec<mir::Local, CPlace<'tcx>>,
 +    ) {
 +        let symbol = func_id.as_u32() as usize;
 +        let mir = self.tcx.instance_mir(instance.def);
 +
 +        // FIXME: add to appropriate scope instead of root
 +        let scope = self.dwarf.unit.root();
 +
 +        let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram);
 +        let entry = self.dwarf.unit.get_mut(entry_id);
 +        let name_id = self.dwarf.strings.add(name);
 +        // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
 +        entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id));
 +        entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id));
 +
 +        let end = self.create_debug_lines(symbol, entry_id, context, mir.span, source_info_set);
 +
 +        self.unit_range_list.0.push(Range::StartLength {
 +            begin: Address::Symbol { symbol, addend: 0 },
 +            length: u64::from(end),
 +        });
 +
 +        let func_entry = self.dwarf.unit.get_mut(entry_id);
 +        // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped.
 +        func_entry.set(
 +            gimli::DW_AT_low_pc,
 +            AttributeValue::Address(Address::Symbol { symbol, addend: 0 }),
 +        );
 +        // Using Udata for DW_AT_high_pc requires at least DWARF4
 +        func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end)));
 +
 +        // FIXME make it more reliable and implement scopes before re-enabling this.
 +        if false {
 +            let value_labels_ranges = std::collections::HashMap::new(); // FIXME
 +
 +            for (local, _local_decl) in mir.local_decls.iter_enumerated() {
 +                let ty = self.tcx.subst_and_normalize_erasing_regions(
 +                    instance.substs,
 +                    ty::ParamEnv::reveal_all(),
 +                    mir.local_decls[local].ty,
 +                );
 +                let var_id = self.define_local(entry_id, format!("{:?}", local), ty);
 +
 +                let location = place_location(
 +                    self,
 +                    isa,
 +                    symbol,
 +                    &local_map,
 +                    &value_labels_ranges,
 +                    Place { local, projection: ty::List::empty() },
 +                );
 +
 +                let var_entry = self.dwarf.unit.get_mut(var_id);
 +                var_entry.set(gimli::DW_AT_location, location);
 +            }
 +        }
 +
 +        // FIXME create locals for all entries in mir.var_debug_info
 +    }
 +}
 +
 +fn place_location<'tcx>(
 +    debug_context: &mut DebugContext<'tcx>,
 +    isa: &dyn TargetIsa,
 +    symbol: usize,
 +    local_map: &IndexVec<mir::Local, CPlace<'tcx>>,
 +    #[allow(rustc::default_hash_types)] value_labels_ranges: &std::collections::HashMap<
 +        ValueLabel,
 +        Vec<ValueLocRange>,
 +    >,
 +    place: Place<'tcx>,
 +) -> AttributeValue {
 +    assert!(place.projection.is_empty()); // FIXME implement them
 +
 +    match local_map[place.local].inner() {
 +        CPlaceInner::Var(_local, var) => {
 +            let value_label = cranelift_codegen::ir::ValueLabel::new(var.index());
 +            if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
 +                let loc_list = LocationList(
 +                    value_loc_ranges
 +                        .iter()
 +                        .map(|value_loc_range| Location::StartEnd {
 +                            begin: Address::Symbol {
 +                                symbol,
 +                                addend: i64::from(value_loc_range.start),
 +                            },
 +                            end: Address::Symbol { symbol, addend: i64::from(value_loc_range.end) },
 +                            data: translate_loc(isa, value_loc_range.loc).unwrap(),
 +                        })
 +                        .collect(),
 +                );
 +                let loc_list_id = debug_context.dwarf.unit.locations.add(loc_list);
 +
 +                AttributeValue::LocationListRef(loc_list_id)
 +            } else {
 +                // FIXME set value labels for unused locals
 +
 +                AttributeValue::Exprloc(Expression::new())
 +            }
 +        }
 +        CPlaceInner::VarPair(_, _, _) => {
 +            // FIXME implement this
 +
 +            AttributeValue::Exprloc(Expression::new())
 +        }
 +        CPlaceInner::VarLane(_, _, _) => {
 +            // FIXME implement this
 +
 +            AttributeValue::Exprloc(Expression::new())
 +        }
 +        CPlaceInner::Addr(_, _) => {
 +            // FIXME implement this (used by arguments and returns)
 +
 +            AttributeValue::Exprloc(Expression::new())
 +
 +            // For PointerBase::Stack:
 +            //AttributeValue::Exprloc(translate_loc(ValueLoc::Stack(*stack_slot)).unwrap())
 +        }
 +    }
 +}
 +
 +// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
 +fn translate_loc(isa: &dyn TargetIsa, loc: LabelValueLoc) -> Option<Expression> {
 +    match loc {
 +        LabelValueLoc::Reg(reg) => {
 +            let machine_reg = isa.map_regalloc_reg_to_dwarf(reg).unwrap();
 +            let mut expr = Expression::new();
 +            expr.op_reg(gimli::Register(machine_reg));
 +            Some(expr)
 +        }
 +        LabelValueLoc::SPOffset(offset) => {
 +            let mut expr = Expression::new();
 +            expr.op_breg(X86_64::RSP, offset);
 +            Some(expr)
 +        }
 +    }
 +}
index f0896ea0e167fd09d2ec81e8f29b04e86484cdee,0000000000000000000000000000000000000000..e4f28338096e1cec0175fd0c78a0d2ae567829ff
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,135 @@@
-     pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
-         let endian = super::target_endian(tcx);
 +//! Unwind info generation (`.eh_frame`)
 +
 +use crate::prelude::*;
 +
++use cranelift_codegen::ir::Endianness;
 +use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 +
 +use cranelift_object::ObjectProduct;
 +use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
 +use gimli::RunTimeEndian;
 +
 +use super::object::WriteDebugInfo;
 +
 +pub(crate) struct UnwindContext {
 +    endian: RunTimeEndian,
 +    frame_table: FrameTable,
 +    cie_id: Option<CieId>,
 +}
 +
 +impl UnwindContext {
++    pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
++        let endian = match isa.endianness() {
++            Endianness::Little => RunTimeEndian::Little,
++            Endianness::Big => RunTimeEndian::Big,
++        };
 +        let mut frame_table = FrameTable::default();
 +
 +        let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
 +            if pic_eh_frame {
 +                cie.fde_address_encoding =
 +                    gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0);
 +            }
 +            Some(frame_table.add_cie(cie))
 +        } else {
 +            None
 +        };
 +
 +        UnwindContext { endian, frame_table, cie_id }
 +    }
 +
 +    pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
 +        let unwind_info = if let Some(unwind_info) = context.create_unwind_info(isa).unwrap() {
 +            unwind_info
 +        } else {
 +            return;
 +        };
 +
 +        match unwind_info {
 +            UnwindInfo::SystemV(unwind_info) => {
 +                self.frame_table.add_fde(
 +                    self.cie_id.unwrap(),
 +                    unwind_info
 +                        .to_fde(Address::Symbol { symbol: func_id.as_u32() as usize, addend: 0 }),
 +                );
 +            }
 +            UnwindInfo::WindowsX64(_) => {
 +                // FIXME implement this
 +            }
 +            unwind_info => unimplemented!("{:?}", unwind_info),
 +        }
 +    }
 +
 +    pub(crate) fn emit(self, product: &mut ObjectProduct) {
 +        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
 +        self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 +
 +        if !eh_frame.0.writer.slice().is_empty() {
 +            let id = eh_frame.id();
 +            let section_id = product.add_debug_section(id, eh_frame.0.writer.into_vec());
 +            let mut section_map = FxHashMap::default();
 +            section_map.insert(id, section_id);
 +
 +            for reloc in &eh_frame.0.relocs {
 +                product.add_debug_reloc(&section_map, &section_id, reloc);
 +            }
 +        }
 +    }
 +
 +    #[cfg(all(feature = "jit", windows))]
 +    pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {}
 +
 +    #[cfg(all(feature = "jit", not(windows)))]
 +    pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) {
 +        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
 +        self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 +
 +        if eh_frame.0.writer.slice().is_empty() {
 +            return;
 +        }
 +
 +        let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module);
 +
 +        // GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
 +        eh_frame.extend(&[0, 0, 0, 0]);
 +
 +        // FIXME support unregistering unwind tables once cranelift-jit supports deallocating
 +        // individual functions
 +        #[allow(unused_variables)]
 +        let (eh_frame, eh_frame_len, _) = Vec::into_raw_parts(eh_frame);
 +
 +        // =======================================================================
 +        // Everything after this line up to the end of the file is loosly based on
 +        // https://github.com/bytecodealliance/wasmtime/blob/4471a82b0c540ff48960eca6757ccce5b1b5c3e4/crates/jit/src/unwind/systemv.rs
 +        #[cfg(target_os = "macos")]
 +        {
 +            // On macOS, `__register_frame` takes a pointer to a single FDE
 +            let start = eh_frame;
 +            let end = start.add(eh_frame_len);
 +            let mut current = start;
 +
 +            // Walk all of the entries in the frame table and register them
 +            while current < end {
 +                let len = std::ptr::read::<u32>(current as *const u32) as usize;
 +
 +                // Skip over the CIE
 +                if current != start {
 +                    __register_frame(current);
 +                }
 +
 +                // Move to the next table entry (+4 because the length itself is not inclusive)
 +                current = current.add(len + 4);
 +            }
 +        }
 +        #[cfg(not(target_os = "macos"))]
 +        {
 +            // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
 +            __register_frame(eh_frame);
 +        }
 +    }
 +}
 +
 +extern "C" {
 +    // libunwind import
 +    fn __register_frame(fde: *const u8);
 +}
index 7f888c80464d41fcc0502dd7d41b5e83dd353d1b,0000000000000000000000000000000000000000..046e4393a68d6c4306cae8642b10500f8b438eec
mode 100644,000000..100644
--- /dev/null
@@@ -1,431 -1,0 +1,431 @@@
-     let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
 +//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
 +//! standalone executable.
 +
 +use std::path::PathBuf;
 +
 +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 +use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
 +use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
 +use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 +use rustc_metadata::EncodedMetadata;
 +use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 +use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
 +use rustc_session::cgu_reuse_tracker::CguReuse;
 +use rustc_session::config::{DebugInfo, OutputType};
 +use rustc_session::Session;
 +
 +use cranelift_codegen::isa::TargetIsa;
 +use cranelift_object::{ObjectBuilder, ObjectModule};
 +
 +use crate::{prelude::*, BackendConfig};
 +
 +struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
 +
 +impl<HCX> HashStable<HCX> for ModuleCodegenResult {
 +    fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
 +        // do nothing
 +    }
 +}
 +
 +fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
 +    let mut builder =
 +        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
 +    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
 +    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
 +    // can easily double the amount of time necessary to perform linking.
 +    builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
 +    ObjectModule::new(builder)
 +}
 +
 +fn emit_module(
 +    tcx: TyCtxt<'_>,
 +    backend_config: &BackendConfig,
 +    name: String,
 +    kind: ModuleKind,
 +    module: ObjectModule,
 +    debug: Option<DebugContext<'_>>,
 +    unwind_context: UnwindContext,
 +) -> ModuleCodegenResult {
 +    let mut product = module.finish();
 +
 +    if let Some(mut debug) = debug {
 +        debug.emit(&mut product);
 +    }
 +
 +    unwind_context.emit(&mut product);
 +
 +    let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(&name));
 +    let obj = product.object.write().unwrap();
 +    if let Err(err) = std::fs::write(&tmp_file, obj) {
 +        tcx.sess.fatal(&format!("error writing object file: {}", err));
 +    }
 +
 +    let work_product = if backend_config.disable_incr_cache {
 +        None
 +    } else {
 +        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
 +            tcx.sess,
 +            &name,
 +            &Some(tmp_file.clone()),
 +        )
 +    };
 +
 +    ModuleCodegenResult(
 +        CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None },
 +        work_product,
 +    )
 +}
 +
 +fn reuse_workproduct_for_cgu(
 +    tcx: TyCtxt<'_>,
 +    cgu: &CodegenUnit<'_>,
 +    work_products: &mut FxHashMap<WorkProductId, WorkProduct>,
 +) -> CompiledModule {
 +    let mut object = None;
 +    let work_product = cgu.work_product(tcx);
 +    if let Some(saved_file) = &work_product.saved_file {
 +        let obj_out =
 +            tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
 +        object = Some(obj_out.clone());
 +        let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &saved_file);
 +        if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
 +            tcx.sess.err(&format!(
 +                "unable to copy {} to {}: {}",
 +                source_file.display(),
 +                obj_out.display(),
 +                err
 +            ));
 +        }
 +    }
 +
 +    work_products.insert(cgu.work_product_id(), work_product);
 +
 +    CompiledModule {
 +        name: cgu.name().to_string(),
 +        kind: ModuleKind::Regular,
 +        object,
 +        dwarf_object: None,
 +        bytecode: None,
 +    }
 +}
 +
 +fn module_codegen(
 +    tcx: TyCtxt<'_>,
 +    (backend_config, cgu_name): (BackendConfig, rustc_span::Symbol),
 +) -> ModuleCodegenResult {
 +    let cgu = tcx.codegen_unit(cgu_name);
 +    let mono_items = cgu.items_in_deterministic_order(tcx);
 +
 +    let isa = crate::build_isa(tcx.sess, &backend_config);
 +    let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string());
 +
 +    let mut cx = crate::CodegenCx::new(
 +        tcx,
 +        backend_config.clone(),
 +        module.isa(),
 +        tcx.sess.opts.debuginfo != DebugInfo::None,
 +        cgu_name,
 +    );
 +    super::predefine_mono_items(tcx, &mut module, &mono_items);
 +    for (mono_item, _) in mono_items {
 +        match mono_item {
 +            MonoItem::Fn(inst) => {
 +                cx.tcx
 +                    .sess
 +                    .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst));
 +            }
 +            MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id),
 +            MonoItem::GlobalAsm(item_id) => {
 +                let item = cx.tcx.hir().item(item_id);
 +                if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
 +                    if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
 +                        cx.global_asm.push_str("\n.intel_syntax noprefix\n");
 +                    } else {
 +                        cx.global_asm.push_str("\n.att_syntax\n");
 +                    }
 +                    for piece in asm.template {
 +                        match *piece {
 +                            InlineAsmTemplatePiece::String(ref s) => cx.global_asm.push_str(s),
 +                            InlineAsmTemplatePiece::Placeholder { .. } => todo!(),
 +                        }
 +                    }
 +                    cx.global_asm.push_str("\n.att_syntax\n\n");
 +                } else {
 +                    bug!("Expected GlobalAsm found {:?}", item);
 +                }
 +            }
 +        }
 +    }
 +    crate::main_shim::maybe_create_entry_wrapper(
 +        tcx,
 +        &mut module,
 +        &mut cx.unwind_context,
 +        false,
 +        cgu.is_primary(),
 +    );
 +
 +    let debug_context = cx.debug_context;
 +    let unwind_context = cx.unwind_context;
 +    let codegen_result = tcx.sess.time("write object file", || {
 +        emit_module(
 +            tcx,
 +            &backend_config,
 +            cgu.name().as_str().to_string(),
 +            ModuleKind::Regular,
 +            module,
 +            debug_context,
 +            unwind_context,
 +        )
 +    });
 +
 +    codegen_global_asm(tcx, cgu.name().as_str(), &cx.global_asm);
 +
 +    codegen_result
 +}
 +
 +pub(crate) fn run_aot(
 +    tcx: TyCtxt<'_>,
 +    backend_config: BackendConfig,
 +    metadata: EncodedMetadata,
 +    need_metadata_module: bool,
 +) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
 +    let mut work_products = FxHashMap::default();
 +
 +    let cgus = if tcx.sess.opts.output_types.should_codegen() {
 +        tcx.collect_and_partition_mono_items(()).1
 +    } else {
 +        // If only `--emit metadata` is used, we shouldn't perform any codegen.
 +        // Also `tcx.collect_and_partition_mono_items` may panic in that case.
 +        &[]
 +    };
 +
 +    if tcx.dep_graph.is_fully_enabled() {
 +        for cgu in &*cgus {
 +            tcx.ensure().codegen_unit(cgu.name());
 +        }
 +    }
 +
 +    let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
 +        cgus.iter()
 +            .map(|cgu| {
 +                let cgu_reuse = determine_cgu_reuse(tcx, cgu);
 +                tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
 +
 +                match cgu_reuse {
 +                    _ if backend_config.disable_incr_cache => {}
 +                    CguReuse::No => {}
 +                    CguReuse::PreLto => {
 +                        return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
 +                    }
 +                    CguReuse::PostLto => unreachable!(),
 +                }
 +
 +                let dep_node = cgu.codegen_dep_node(tcx);
 +                let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
 +                    dep_node,
 +                    tcx,
 +                    (backend_config.clone(), cgu.name()),
 +                    module_codegen,
 +                    Some(rustc_middle::dep_graph::hash_result),
 +                );
 +
 +                if let Some((id, product)) = work_product {
 +                    work_products.insert(id, product);
 +                }
 +
 +                module
 +            })
 +            .collect::<Vec<_>>()
 +    });
 +
 +    tcx.sess.abort_if_errors();
 +
 +    let isa = crate::build_isa(tcx.sess, &backend_config);
 +    let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
 +    assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
++    let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
 +    let created_alloc_shim =
 +        crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
 +
 +    let allocator_module = if created_alloc_shim {
 +        let ModuleCodegenResult(module, work_product) = emit_module(
 +            tcx,
 +            &backend_config,
 +            "allocator_shim".to_string(),
 +            ModuleKind::Allocator,
 +            allocator_module,
 +            None,
 +            allocator_unwind_context,
 +        );
 +        if let Some((id, product)) = work_product {
 +            work_products.insert(id, product);
 +        }
 +        Some(module)
 +    } else {
 +        None
 +    };
 +
 +    let metadata_module = if need_metadata_module {
 +        let _timer = tcx.prof.generic_activity("codegen crate metadata");
 +        let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
 +            use rustc_middle::mir::mono::CodegenUnitNameBuilder;
 +
 +            let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
 +            let metadata_cgu_name = cgu_name_builder
 +                .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
 +                .as_str()
 +                .to_string();
 +
 +            let tmp_file =
 +                tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
 +
 +            let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
 +            let obj = create_compressed_metadata_file(tcx.sess, &metadata, &symbol_name);
 +
 +            if let Err(err) = std::fs::write(&tmp_file, obj) {
 +                tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
 +            }
 +
 +            (metadata_cgu_name, tmp_file)
 +        });
 +
 +        Some(CompiledModule {
 +            name: metadata_cgu_name,
 +            kind: ModuleKind::Metadata,
 +            object: Some(tmp_file),
 +            dwarf_object: None,
 +            bytecode: None,
 +        })
 +    } else {
 +        None
 +    };
 +
 +    // FIXME handle `-Ctarget-cpu=native`
 +    let target_cpu =
 +        tcx.sess.opts.cg.target_cpu.as_ref().unwrap_or(&tcx.sess.target.cpu).to_owned();
 +    Box::new((
 +        CodegenResults {
 +            modules,
 +            allocator_module,
 +            metadata_module,
 +            metadata,
 +            crate_info: CrateInfo::new(tcx, target_cpu),
 +        },
 +        work_products,
 +    ))
 +}
 +
 +fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
 +    use std::io::Write;
 +    use std::process::{Command, Stdio};
 +
 +    if global_asm.is_empty() {
 +        return;
 +    }
 +
 +    if cfg!(not(feature = "inline_asm"))
 +        || tcx.sess.target.is_like_osx
 +        || tcx.sess.target.is_like_windows
 +    {
 +        if global_asm.contains("__rust_probestack") {
 +            return;
 +        }
 +
 +        // FIXME fix linker error on macOS
 +        if cfg!(not(feature = "inline_asm")) {
 +            tcx.sess.fatal(
 +                "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
 +            );
 +        } else {
 +            tcx.sess.fatal("asm! and global_asm! are not yet supported on macOS and Windows");
 +        }
 +    }
 +
 +    let assembler = crate::toolchain::get_toolchain_binary(tcx.sess, "as");
 +    let linker = crate::toolchain::get_toolchain_binary(tcx.sess, "ld");
 +
 +    // Remove all LLVM style comments
 +    let global_asm = global_asm
 +        .lines()
 +        .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
 +        .collect::<Vec<_>>()
 +        .join("\n");
 +
 +    let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
 +
 +    // Assemble `global_asm`
 +    let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
 +    let mut child = Command::new(assembler)
 +        .arg("-o")
 +        .arg(&global_asm_object_file)
 +        .stdin(Stdio::piped())
 +        .spawn()
 +        .expect("Failed to spawn `as`.");
 +    child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
 +    let status = child.wait().expect("Failed to wait for `as`.");
 +    if !status.success() {
 +        tcx.sess.fatal(&format!("Failed to assemble `{}`", global_asm));
 +    }
 +
 +    // Link the global asm and main object file together
 +    let main_object_file = add_file_stem_postfix(output_object_file.clone(), ".main");
 +    std::fs::rename(&output_object_file, &main_object_file).unwrap();
 +    let status = Command::new(linker)
 +        .arg("-r") // Create a new object file
 +        .arg("-o")
 +        .arg(output_object_file)
 +        .arg(&main_object_file)
 +        .arg(&global_asm_object_file)
 +        .status()
 +        .unwrap();
 +    if !status.success() {
 +        tcx.sess.fatal(&format!(
 +            "Failed to link `{}` and `{}` together",
 +            main_object_file.display(),
 +            global_asm_object_file.display(),
 +        ));
 +    }
 +
 +    std::fs::remove_file(global_asm_object_file).unwrap();
 +    std::fs::remove_file(main_object_file).unwrap();
 +}
 +
 +fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf {
 +    let mut new_filename = path.file_stem().unwrap().to_owned();
 +    new_filename.push(postfix);
 +    if let Some(extension) = path.extension() {
 +        new_filename.push(".");
 +        new_filename.push(extension);
 +    }
 +    path.set_file_name(new_filename);
 +    path
 +}
 +
 +// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
 +fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
 +    if !tcx.dep_graph.is_fully_enabled() {
 +        return CguReuse::No;
 +    }
 +
 +    let work_product_id = &cgu.work_product_id();
 +    if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
 +        // We don't have anything cached for this CGU. This can happen
 +        // if the CGU did not exist in the previous session.
 +        return CguReuse::No;
 +    }
 +
 +    // Try to mark the CGU as green. If it we can do so, it means that nothing
 +    // affecting the LLVM module has changed and we can re-use a cached version.
 +    // If we compile with any kind of LTO, this means we can re-use the bitcode
 +    // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
 +    // know that later). If we are not doing LTO, there is only one optimized
 +    // version of each module, so we re-use that.
 +    let dep_node = cgu.codegen_dep_node(tcx);
 +    assert!(
 +        !tcx.dep_graph.dep_node_exists(&dep_node),
 +        "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
 +        cgu.name()
 +    );
 +
 +    if tcx.try_mark_green(&dep_node) { CguReuse::PreLto } else { CguReuse::No }
 +}
index 3f2884748272a413d3b3e50729c1ff655290ebff,0000000000000000000000000000000000000000..cb18f42f741d80b208b92bcfbf9a2143b68dbede
mode 100644,000000..100644
--- /dev/null
@@@ -1,311 -1,0 +1,311 @@@
-             UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
 +#![feature(rustc_private, decl_macro)]
 +#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))]
 +#![warn(rust_2018_idioms)]
 +#![warn(unused_lifetimes)]
 +#![warn(unreachable_pub)]
 +
 +#[macro_use]
 +extern crate rustc_middle;
 +extern crate rustc_ast;
 +extern crate rustc_codegen_ssa;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_fs_util;
 +extern crate rustc_hir;
 +extern crate rustc_incremental;
 +extern crate rustc_index;
 +extern crate rustc_interface;
 +extern crate rustc_metadata;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +
 +// This prevents duplicating functions and statics that are already part of the host rustc process.
 +#[allow(unused_extern_crates)]
 +extern crate rustc_driver;
 +
 +use std::any::Any;
 +use std::cell::Cell;
 +
 +use rustc_codegen_ssa::traits::CodegenBackend;
 +use rustc_codegen_ssa::CodegenResults;
 +use rustc_errors::ErrorReported;
 +use rustc_metadata::EncodedMetadata;
 +use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 +use rustc_session::config::OutputFilenames;
 +use rustc_session::Session;
 +use rustc_span::Symbol;
 +
 +use cranelift_codegen::isa::TargetIsa;
 +use cranelift_codegen::settings::{self, Configurable};
 +
 +pub use crate::config::*;
 +use crate::prelude::*;
 +
 +mod abi;
 +mod allocator;
 +mod analyze;
 +mod archive;
 +mod base;
 +mod cast;
 +mod codegen_i128;
 +mod common;
 +mod compiler_builtins;
 +mod config;
 +mod constant;
 +mod debuginfo;
 +mod discriminant;
 +mod driver;
 +mod inline_asm;
 +mod intrinsics;
 +mod linkage;
 +mod main_shim;
 +mod num;
 +mod optimize;
 +mod pointer;
 +mod pretty_clif;
 +mod toolchain;
 +mod trap;
 +mod unsize;
 +mod value_and_place;
 +mod vtable;
 +
 +mod prelude {
 +    pub(crate) use rustc_span::{FileNameDisplayPreference, Span};
 +
 +    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 +    pub(crate) use rustc_middle::bug;
 +    pub(crate) use rustc_middle::mir::{self, *};
 +    pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
 +    pub(crate) use rustc_middle::ty::{
 +        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
 +        TypeFoldable, UintTy,
 +    };
 +    pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx};
 +
 +    pub(crate) use rustc_data_structures::fx::FxHashMap;
 +
 +    pub(crate) use rustc_index::vec::Idx;
 +
 +    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
 +    pub(crate) use cranelift_codegen::ir::function::Function;
 +    pub(crate) use cranelift_codegen::ir::types;
 +    pub(crate) use cranelift_codegen::ir::{
 +        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
 +        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
 +    };
 +    pub(crate) use cranelift_codegen::isa::{self, CallConv};
 +    pub(crate) use cranelift_codegen::Context;
 +    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
 +    pub(crate) use cranelift_module::{self, DataContext, FuncId, Linkage, Module};
 +
 +    pub(crate) use crate::abi::*;
 +    pub(crate) use crate::base::{codegen_operand, codegen_place};
 +    pub(crate) use crate::cast::*;
 +    pub(crate) use crate::common::*;
 +    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
 +    pub(crate) use crate::pointer::Pointer;
 +    pub(crate) use crate::trap::*;
 +    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
 +}
 +
 +struct PrintOnPanic<F: Fn() -> String>(F);
 +impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
 +    fn drop(&mut self) {
 +        if ::std::thread::panicking() {
 +            println!("{}", (self.0)());
 +        }
 +    }
 +}
 +
 +/// The codegen context holds any information shared between the codegen of individual functions
 +/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
 +struct CodegenCx<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +    global_asm: String,
 +    inline_asm_index: Cell<usize>,
 +    cached_context: Context,
 +    debug_context: Option<DebugContext<'tcx>>,
 +    unwind_context: UnwindContext,
 +    cgu_name: Symbol,
 +}
 +
 +impl<'tcx> CodegenCx<'tcx> {
 +    fn new(
 +        tcx: TyCtxt<'tcx>,
 +        backend_config: BackendConfig,
 +        isa: &dyn TargetIsa,
 +        debug_info: bool,
 +        cgu_name: Symbol,
 +    ) -> Self {
 +        assert_eq!(pointer_ty(tcx), isa.pointer_type());
 +
 +        let unwind_context =
++            UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
 +        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
 +        CodegenCx {
 +            tcx,
 +            global_asm: String::new(),
 +            inline_asm_index: Cell::new(0),
 +            cached_context: Context::new(),
 +            debug_context,
 +            unwind_context,
 +            cgu_name,
 +        }
 +    }
 +}
 +
 +pub struct CraneliftCodegenBackend {
 +    pub config: Option<BackendConfig>,
 +}
 +
 +impl CodegenBackend for CraneliftCodegenBackend {
 +    fn init(&self, sess: &Session) {
 +        use rustc_session::config::Lto;
 +        match sess.lto() {
 +            Lto::No | Lto::ThinLocal => {}
 +            Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
 +        }
 +    }
 +
 +    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
 +        vec![]
 +    }
 +
 +    fn print_version(&self) {
 +        println!("Cranelift version: {}", cranelift_codegen::VERSION);
 +    }
 +
 +    fn codegen_crate(
 +        &self,
 +        tcx: TyCtxt<'_>,
 +        metadata: EncodedMetadata,
 +        need_metadata_module: bool,
 +    ) -> Box<dyn Any> {
 +        tcx.sess.abort_if_errors();
 +        let config = if let Some(config) = self.config.clone() {
 +            config
 +        } else {
 +            if !tcx.sess.unstable_options() && !tcx.sess.opts.cg.llvm_args.is_empty() {
 +                tcx.sess.fatal("`-Z unstable-options` must be passed to allow configuring cg_clif");
 +            }
 +            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
 +                .unwrap_or_else(|err| tcx.sess.fatal(&err))
 +        };
 +        match config.codegen_mode {
 +            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
 +            CodegenMode::Jit | CodegenMode::JitLazy => {
 +                #[cfg(feature = "jit")]
 +                let _: ! = driver::jit::run_jit(tcx, config);
 +
 +                #[cfg(not(feature = "jit"))]
 +                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
 +            }
 +        }
 +    }
 +
 +    fn join_codegen(
 +        &self,
 +        ongoing_codegen: Box<dyn Any>,
 +        _sess: &Session,
 +        _outputs: &OutputFilenames,
 +    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
 +        Ok(*ongoing_codegen
 +            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
 +            .unwrap())
 +    }
 +
 +    fn link(
 +        &self,
 +        sess: &Session,
 +        codegen_results: CodegenResults,
 +        outputs: &OutputFilenames,
 +    ) -> Result<(), ErrorReported> {
 +        use rustc_codegen_ssa::back::link::link_binary;
 +
 +        link_binary::<crate::archive::ArArchiveBuilder<'_>>(sess, &codegen_results, outputs)
 +    }
 +}
 +
 +fn target_triple(sess: &Session) -> target_lexicon::Triple {
 +    match sess.target.llvm_target.parse() {
 +        Ok(triple) => triple,
 +        Err(err) => sess.fatal(&format!("target not recognized: {}", err)),
 +    }
 +}
 +
 +fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
 +    use target_lexicon::BinaryFormat;
 +
 +    let target_triple = crate::target_triple(sess);
 +
 +    let mut flags_builder = settings::builder();
 +    flags_builder.enable("is_pic").unwrap();
 +    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
 +    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
 +    flags_builder.set("enable_verifier", enable_verifier).unwrap();
 +
 +    let tls_model = match target_triple.binary_format {
 +        BinaryFormat::Elf => "elf_gd",
 +        BinaryFormat::Macho => "macho",
 +        BinaryFormat::Coff => "coff",
 +        _ => "none",
 +    };
 +    flags_builder.set("tls_model", tls_model).unwrap();
 +
 +    flags_builder.set("enable_simd", "true").unwrap();
 +
 +    flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
 +
 +    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
 +
 +    use rustc_session::config::OptLevel;
 +    match sess.opts.optimize {
 +        OptLevel::No => {
 +            flags_builder.set("opt_level", "none").unwrap();
 +        }
 +        OptLevel::Less | OptLevel::Default => {}
 +        OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => {
 +            flags_builder.set("opt_level", "speed_and_size").unwrap();
 +        }
 +    }
 +
 +    let flags = settings::Flags::new(flags_builder);
 +
 +    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
 +        Some("native") => {
 +            let builder = cranelift_native::builder_with_options(true).unwrap();
 +            builder
 +        }
 +        Some(value) => {
 +            let mut builder =
 +                cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
 +                    sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
 +                });
 +            if let Err(_) = builder.enable(value) {
 +                sess.fatal("the specified target cpu isn't currently supported by Cranelift.");
 +            }
 +            builder
 +        }
 +        None => {
 +            let mut builder =
 +                cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
 +                    sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
 +                });
 +            if target_triple.architecture == target_lexicon::Architecture::X86_64 {
 +                // Don't use "haswell" as the default, as it implies `has_lzcnt`.
 +                // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
 +                builder.enable("nehalem").unwrap();
 +            }
 +            builder
 +        }
 +    };
 +
 +    isa_builder.finish(flags)
 +}
 +
 +/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
 +#[no_mangle]
 +pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
 +    Box::new(CraneliftCodegenBackend { config: None })
 +}