]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '3a31c6d8272c14388a34622193baf553636fe470' into sync_cg_clif-2021-07-07
authorbjorn3 <bjorn3@users.noreply.github.com>
Wed, 7 Jul 2021 09:14:20 +0000 (11:14 +0200)
committerbjorn3 <bjorn3@users.noreply.github.com>
Wed, 7 Jul 2021 09:14:20 +0000 (11:14 +0200)
50 files changed:
1  2 
compiler/rustc_codegen_cranelift/.cirrus.yml
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
compiler/rustc_codegen_cranelift/.gitignore
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/build_system/config.rs
compiler/rustc_codegen_cranelift/build_system/prepare.rs
compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
compiler/rustc_codegen_cranelift/build_system/utils.rs
compiler/rustc_codegen_cranelift/clean_all.sh
compiler/rustc_codegen_cranelift/config.txt
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch
compiler/rustc_codegen_cranelift/patches/0001-rand-Enable-c2-chacha-simd-feature.patch
compiler/rustc_codegen_cranelift/patches/0002-rand-Disable-failing-test.patch
compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch
compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo.rs
compiler/rustc_codegen_cranelift/scripts/config.sh
compiler/rustc_codegen_cranelift/scripts/ext_config.sh
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/rustup.sh
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/optimize/mod.rs
compiler/rustc_codegen_cranelift/src/pretty_clif.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_cranelift/test.sh
compiler/rustc_codegen_cranelift/y.rs

index e173df423a76523f092160e138d648ea64c29651,0000000000000000000000000000000000000000..61da6a2491c52fcd3270195db5fb441e89c0a496
mode 100644,000000..100644
--- /dev/null
@@@ -1,25 -1,0 +1,25 @@@
-     - ./prepare.sh
 +task:
 +  name: freebsd
 +  freebsd_instance:
 +    image: freebsd-12-1-release-amd64
 +  setup_rust_script:
 +    - pkg install -y curl git bash
 +    - curl https://sh.rustup.rs -sSf --output rustup.sh
 +    - sh rustup.sh --default-toolchain none -y --profile=minimal
 +  cargo_bin_cache:
 +    folder: ~/.cargo/bin
 +  target_cache:
 +    folder: target
 +  prepare_script:
 +    - . $HOME/.cargo/env
 +    - git config --global user.email "user@example.com"
 +    - git config --global user.name "User"
++    - ./y.rs prepare
 +  test_script:
 +    - . $HOME/.cargo/env
 +    - # 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
 +    - ./test.sh
index 4d45e36c956c908f5ee1f0f295a00b0dc6c95ec7,0000000000000000000000000000000000000000..f81ac87726052c7c16e78869bd4baf2866be1fa1
mode 100644,000000..100644
--- /dev/null
@@@ -1,89 -1,0 +1,160 @@@
-         ./prepare.sh
 +name: CI
 +
 +on:
 +  - push
 +  - pull_request
 +
 +jobs:
 +  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 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 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
++      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
++    #  run: tar cvfJ cg_clif.tar.xz build
++
++    #- name: Upload prebuilt cg_clif
++    #  uses: actions/upload-artifact@v2
++    #  with:
++    #    name: cg_clif-${{ runner.os }}
++    #    path: cg_clif.tar.xz
index e01a92598bab745b4df24ef41bb5e50ccfef4701,0000000000000000000000000000000000000000..1c08e5ece33d27e67fc01b5012f1ac237f2fc51c
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,82 @@@
-         ./prepare.sh
 +name: Various rustc tests
 +
 +on:
 +  - push
 +
 +jobs:
 +  bootstrap_rustc:
 +    runs-on: ubuntu-latest
 +
 +    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"
-         ./prepare.sh
++        ./y.rs prepare
 +
 +    - name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        ./scripts/test_bootstrap.sh
 +  rustc_test_suite:
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +    - uses: actions/checkout@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"
++        ./y.rs prepare
 +
 +    - name: Test
 +      run: |
 +        # Enable backtraces for easier debugging
 +        export RUST_BACKTRACE=1
 +
 +        ./scripts/test_rustc_tests.sh
index b241bef9d1e7ff6c03aa98ee03abe04252823a6c,0000000000000000000000000000000000000000..12e779fe7c7d7b8bb050611e643a6355776ed518
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,17 @@@
 +target
 +**/*.rs.bk
 +*.rlib
 +*.o
 +perf.data
 +perf.data.old
 +*.events
 +*.string*
++/y.bin
 +/build
 +/build_sysroot/sysroot_src
 +/build_sysroot/compiler-builtins
++/build_sysroot/rustc_version
 +/rust
 +/rand
 +/regex
 +/simple-raytracer
index 9009a532c54dcc91ac5ea9943a48ba63f0803bc9,0000000000000000000000000000000000000000..f62e59cefc2414c23ecb8a3ca3418d87d4e7f7c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,54 -1,0 +1,73 @@@
-     "rust-analyzer.assist.importMergeBehavior": "last",
 +{
 +    // source for rustc_* is not included in the rust-src component; disable the errors about this
 +    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
++    "rust-analyzer.assist.importGranularity": "module",
++    "rust-analyzer.assist.importEnforceGranularity": true,
++    "rust-analyzer.assist.importPrefix": "crate",
 +    "rust-analyzer.cargo.runBuildScripts": true,
 +    "rust-analyzer.linkedProjects": [
 +        "./Cargo.toml",
 +        //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
 +        {
 +            "roots": [
 +                "./example/mini_core.rs",
 +                "./example/mini_core_hello_world.rs",
 +                "./example/mod_bench.rs"
 +            ],
 +            "crates": [
 +                {
 +                    "root_module": "./example/mini_core.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./example/mini_core_hello_world.rs",
 +                    "edition": "2018",
 +                    "deps": [{ "crate": 0, "name": "mini_core" }],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./example/mod_bench.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +            ]
 +        },
 +        {
 +            "roots": ["./scripts/filter_profile.rs"],
 +            "crates": [
 +                {
 +                    "root_module": "./scripts/filter_profile.rs",
 +                    "edition": "2018",
 +                    "deps": [{ "crate": 1, "name": "std" }],
 +                    "cfg": [],
 +                },
 +                {
 +                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
 +                    "edition": "2018",
 +                    "deps": [],
 +                    "cfg": [],
 +                },
 +            ]
++        },
++        {
++            "roots": ["./y.rs"],
++            "crates": [
++                {
++                    "root_module": "./y.rs",
++                    "edition": "2018",
++                    "deps": [{ "crate": 1, "name": "std" }],
++                    "cfg": [],
++                },
++                {
++                    "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
++                    "edition": "2018",
++                    "deps": [],
++                    "cfg": [],
++                },
++            ]
 +        }
 +    ]
 +}
index a6f5925149b925a59fab9c83719be9c2aefd7a13,0000000000000000000000000000000000000000..56d0974b25371b6e2abef4451c5eefef3879668c
mode 100644,000000..100644
--- /dev/null
@@@ -1,296 -1,0 +1,304 @@@
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "anyhow"
 +version = "1.0.38"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
 +
 +[[package]]
 +name = "ar"
 +version = "0.8.0"
 +source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 +
 +[[package]]
 +name = "cfg-if"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 +
 +[[package]]
 +name = "cranelift-bforest"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "cranelift-entity",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "cranelift-bforest",
 + "cranelift-codegen-meta",
 + "cranelift-codegen-shared",
 + "cranelift-entity",
 + "gimli",
 + "log",
 + "regalloc",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen-meta"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "cranelift-codegen-shared",
 + "cranelift-entity",
 +]
 +
 +[[package]]
 +name = "cranelift-codegen-shared"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +
 +[[package]]
 +name = "cranelift-entity"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +
 +[[package]]
 +name = "cranelift-frontend"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "cranelift-codegen",
 + "log",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-jit"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 + "cranelift-entity",
 + "cranelift-module",
 + "cranelift-native",
 + "libc",
 + "log",
 + "region",
 + "target-lexicon",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "cranelift-module"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 + "cranelift-entity",
 + "log",
 +]
 +
 +[[package]]
 +name = "cranelift-native"
- version = "0.74.0"
- source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "cranelift-codegen",
++ "libc",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "cranelift-object"
- version = "0.2.86"
++version = "0.75.0"
++source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
 +dependencies = [
 + "anyhow",
 + "cranelift-codegen",
 + "cranelift-module",
 + "log",
 + "object",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "crc32fast"
 +version = "1.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "gimli"
 +version = "0.24.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
 +dependencies = [
 + "indexmap",
 +]
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
 +
 +[[package]]
 +name = "indexmap"
 +version = "1.6.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
 +dependencies = [
 + "autocfg",
 + "hashbrown",
 +]
 +
 +[[package]]
 +name = "libc"
- checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
++version = "0.2.97"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.24.0"
++checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
 +
 +[[package]]
 +name = "libloading"
 +version = "0.6.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
 +dependencies = [
 + "cfg-if",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "log"
 +version = "0.4.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "mach"
 +version = "0.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
 +dependencies = [
 + "libc",
 +]
 +
++[[package]]
++name = "memchr"
++version = "2.4.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
++
 +[[package]]
 +name = "object"
- checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
++version = "0.25.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
 +dependencies = [
 + "crc32fast",
 + "indexmap",
++ "memchr",
 +]
 +
 +[[package]]
 +name = "regalloc"
 +version = "0.0.31"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5"
 +dependencies = [
 + "log",
 + "rustc-hash",
 + "smallvec",
 +]
 +
 +[[package]]
 +name = "region"
 +version = "2.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
 +dependencies = [
 + "bitflags",
 + "libc",
 + "mach",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "rustc-hash"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 +
 +[[package]]
 +name = "rustc_codegen_cranelift"
 +version = "0.1.0"
 +dependencies = [
 + "ar",
 + "cranelift-codegen",
 + "cranelift-frontend",
 + "cranelift-jit",
 + "cranelift-module",
 + "cranelift-native",
 + "cranelift-object",
 + "gimli",
 + "indexmap",
 + "libloading",
 + "object",
 + "smallvec",
 + "target-lexicon",
 +]
 +
 +[[package]]
 +name = "smallvec"
 +version = "1.6.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
 +
 +[[package]]
 +name = "target-lexicon"
 +version = "0.12.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 +dependencies = [
 + "winapi-i686-pc-windows-gnu",
 + "winapi-x86_64-pc-windows-gnu",
 +]
 +
 +[[package]]
 +name = "winapi-i686-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 +
 +[[package]]
 +name = "winapi-x86_64-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
index fd149af454735e528277b2290fd4c4258e64374c,0000000000000000000000000000000000000000..ef68d7ee532dd3a7561ef0539f326959e3e0857c
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,74 @@@
- cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] }
 +[package]
 +name = "rustc_codegen_cranelift"
 +version = "0.1.0"
 +authors = ["bjorn3 <bjorn3@users.noreply.github.com>"]
 +edition = "2018"
 +
 +[lib]
 +crate-type = ["dylib"]
 +
 +[dependencies]
 +# These have to be in sync with each other
- object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
++cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind", "all-arch"] }
 +cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 +cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 +cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 +cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
 +cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 +target-lexicon = "0.12.0"
 +gimli = { version = "0.24.0", default-features = false, features = ["write"]}
++object = { version = "0.25.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"
 +
 +# Uncomment to use local checkout of cranelift
 +#[patch."https://github.com/bytecodealliance/wasmtime.git"]
 +#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" }
 +
 +#[patch.crates-io]
 +#gimli = { path = "../" }
 +
 +[features]
 +default = ["jit", "inline_asm"]
 +jit = ["cranelift-jit", "libloading"]
 +inline_asm = []
 +
 +[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
 +
 +# 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.build-override]
 +opt-level = 0
 +debug = false
 +
 +[profile.release.build-override]
 +opt-level = 0
 +debug = false
 +
 +[profile.dev.package.cranelift-codegen-meta]
 +opt-level = 0
 +debug = false
 +
 +[profile.release.package.cranelift-codegen-meta]
 +opt-level = 0
 +debug = false
 +
 +[package.metadata.rust-analyzer]
 +rustc_private = true
index 08f9373be6262ba35226ceb02fb0a3f5aba22be8,0000000000000000000000000000000000000000..dad8ed90b53b8307fb1c4b72d40b15a59c2878bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
- $ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
- $ ./build.sh
 +# 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
- This will implicitly build cg_clif too. Both `build.sh` and `test.sh` accept a `--debug` argument to
++$ ./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
 +```
 +
- Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `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.
 +
- $ $cg_clif_dir/build/cargo.sh build
++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 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 923deb9aec4c082e357f9c2bc3425a14fbe8c8e8,0000000000000000000000000000000000000000..46f661107e73b43ab0b9a2713e51661a60a64708
mode 100644,000000..100644
--- /dev/null
@@@ -1,327 -1,0 +1,327 @@@
- version = "0.1.43"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "addr2line"
 +version = "0.14.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
 +dependencies = [
 + "compiler_builtins",
 + "gimli",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "adler"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "alloc"
 +version = "0.0.0"
 +dependencies = [
 + "compiler_builtins",
 + "core",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 +
 +[[package]]
 +name = "cc"
 +version = "1.0.68"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
 +
 +[[package]]
 +name = "cfg-if"
 +version = "0.1.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "compiler_builtins"
- version = "0.1.18"
++version = "0.1.46"
 +dependencies = [
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "core"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "dlmalloc"
 +version = "0.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254"
 +dependencies = [
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "fortanix-sgx-abi"
 +version = "0.3.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "getopts"
 +version = "0.2.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 +dependencies = [
 + "rustc-std-workspace-core",
 + "rustc-std-workspace-std",
 + "unicode-width",
 +]
 +
 +[[package]]
 +name = "gimli"
 +version = "0.23.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.11.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "hermit-abi"
- checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
++version = "0.1.19"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.95"
++checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 +dependencies = [
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "libc"
- checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
++version = "0.2.97"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.19"
++checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
 +dependencies = [
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "miniz_oxide"
 +version = "0.4.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
 +dependencies = [
 + "adler",
 + "autocfg",
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "object"
 +version = "0.22.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "panic_abort"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 +]
 +
 +[[package]]
 +name = "panic_unwind"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 + "unwind",
 +]
 +
 +[[package]]
 +name = "proc_macro"
 +version = "0.0.0"
 +dependencies = [
 + "std",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
- checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
++version = "0.1.20"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-alloc"
 +version = "1.99.0"
 +dependencies = [
 + "alloc",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-core"
 +version = "1.99.0"
 +dependencies = [
 + "core",
 +]
 +
 +[[package]]
 +name = "rustc-std-workspace-std"
 +version = "1.99.0"
 +dependencies = [
 + "std",
 +]
 +
 +[[package]]
 +name = "std"
 +version = "0.0.0"
 +dependencies = [
 + "addr2line",
 + "alloc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "dlmalloc",
 + "fortanix-sgx-abi",
 + "hashbrown",
 + "hermit-abi",
 + "libc",
 + "miniz_oxide",
 + "object",
 + "panic_abort",
 + "panic_unwind",
 + "rustc-demangle",
 + "std_detect",
 + "unwind",
 + "wasi",
 +]
 +
 +[[package]]
 +name = "std_detect"
 +version = "0.1.5"
 +dependencies = [
 + "cfg-if",
 + "compiler_builtins",
 + "libc",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
 +
 +[[package]]
 +name = "sysroot"
 +version = "0.0.0"
 +dependencies = [
 + "alloc",
 + "compiler_builtins",
 + "core",
 + "std",
 + "test",
 +]
 +
 +[[package]]
 +name = "term"
 +version = "0.0.0"
 +dependencies = [
 + "core",
 + "std",
 +]
 +
 +[[package]]
 +name = "test"
 +version = "0.0.0"
 +dependencies = [
 + "cfg-if",
 + "core",
 + "getopts",
 + "libc",
 + "panic_abort",
 + "panic_unwind",
 + "proc_macro",
 + "std",
 + "term",
 +]
 +
 +[[package]]
 +name = "unicode-width"
 +version = "0.1.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-core",
 + "rustc-std-workspace-std",
 +]
 +
 +[[package]]
 +name = "unwind"
 +version = "0.0.0"
 +dependencies = [
 + "cc",
 + "cfg-if",
 + "compiler_builtins",
 + "core",
 + "libc",
 +]
 +
 +[[package]]
 +name = "wasi"
 +version = "0.9.0+wasi-snapshot-preview1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
 +dependencies = [
 + "compiler_builtins",
 + "rustc-std-workspace-alloc",
 + "rustc-std-workspace-core",
 +]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1df2bcc4541ca1b9fdbad003df57ea3f6c67d265
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,40 @@@
++use std::env;
++use std::path::{Path, PathBuf};
++use std::process::Command;
++
++pub(crate) fn build_backend(channel: &str, host_triple: &str) -> PathBuf {
++    let mut cmd = Command::new("cargo");
++    cmd.arg("build").arg("--target").arg(host_triple);
++
++    match channel {
++        "debug" => {}
++        "release" => {
++            cmd.arg("--release");
++        }
++        _ => unreachable!(),
++    }
++
++    if cfg!(unix) {
++        if cfg!(target_os = "macos") {
++            cmd.env(
++                "RUSTFLAGS",
++                "-Csplit-debuginfo=unpacked \
++                -Clink-arg=-Wl,-rpath,@loader_path/../lib \
++                -Zosx-rpath-install-name"
++                    .to_string()
++                    + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
++            );
++        } else {
++            cmd.env(
++                "RUSTFLAGS",
++                "-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string()
++                    + env::var("RUSTFLAGS").as_deref().unwrap_or(""),
++            );
++        }
++    }
++
++    eprintln!("[BUILD] rustc_codegen_cranelift");
++    crate::utils::spawn_and_wait(cmd);
++
++    Path::new("target").join(host_triple).join(channel)
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9fb88c279613fb85627f262183fe23fe079553de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,216 @@@
++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("scripts/cargo.rs")
++        .arg("-o")
++        .arg(target_dir.join("cargo"))
++        .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("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"),
++    );
++    // FIXME Enable incremental again once rust-lang/rust#74946 is fixed
++    build_cmd.env("CARGO_INCREMENTAL", "0").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 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ef540cf1f822b467b80adbc23f2c490e96c647ac
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,55 @@@
++use std::{fs, process};
++
++fn load_config_file() -> Vec<(String, Option<String>)> {
++    fs::read_to_string("config.txt")
++        .unwrap()
++        .lines()
++        .map(|line| if let Some((line, _comment)) = line.split_once('#') { line } else { line })
++        .map(|line| line.trim())
++        .filter(|line| !line.is_empty())
++        .map(|line| {
++            if let Some((key, val)) = line.split_once('=') {
++                (key.trim().to_owned(), Some(val.trim().to_owned()))
++            } else {
++                (line.to_owned(), None)
++            }
++        })
++        .collect()
++}
++
++pub(crate) fn get_bool(name: &str) -> bool {
++    let values = load_config_file()
++        .into_iter()
++        .filter(|(key, _)| key == name)
++        .map(|(_, val)| val)
++        .collect::<Vec<_>>();
++    if values.is_empty() {
++        false
++    } else {
++        if values.iter().any(|val| val.is_some()) {
++            eprintln!("Boolean config `{}` has a value", name);
++            process::exit(1);
++        }
++        true
++    }
++}
++
++pub(crate) fn get_value(name: &str) -> Option<String> {
++    let values = load_config_file()
++        .into_iter()
++        .filter(|(key, _)| key == name)
++        .map(|(_, val)| val)
++        .collect::<Vec<_>>();
++    if values.is_empty() {
++        None
++    } else if values.len() == 1 {
++        if values[0].is_none() {
++            eprintln!("Config `{}` missing value", name);
++            process::exit(1);
++        }
++        values.into_iter().next().unwrap()
++    } else {
++        eprintln!("Config `{}` given multiple values: {:?}", name, values);
++        process::exit(1);
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..401b8271abcc52e63f4b4c493a5ac2ec24a59066
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,133 @@@
++use std::env;
++use std::ffi::OsStr;
++use std::ffi::OsString;
++use std::fs;
++use std::path::Path;
++use std::process::Command;
++
++use crate::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
++use crate::utils::{copy_dir_recursively, spawn_and_wait};
++
++pub(crate) fn prepare() {
++    prepare_sysroot();
++
++    eprintln!("[INSTALL] hyperfine");
++    Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
++
++    clone_repo(
++        "rand",
++        "https://github.com/rust-random/rand.git",
++        "0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
++    );
++    apply_patches("rand", Path::new("rand"));
++
++    clone_repo(
++        "regex",
++        "https://github.com/rust-lang/regex.git",
++        "341f207c1071f7290e3f228c710817c280c8dca1",
++    );
++
++    clone_repo(
++        "simple-raytracer",
++        "https://github.com/ebobby/simple-raytracer",
++        "804a7a21b9e673a482797aa289a18ed480e4d813",
++    );
++
++    eprintln!("[LLVM BUILD] simple-raytracer");
++    let mut build_cmd = Command::new("cargo");
++    build_cmd.arg("build").env_remove("CARGO_TARGET_DIR").current_dir("simple-raytracer");
++    spawn_and_wait(build_cmd);
++    fs::copy(
++        Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")),
++        // FIXME use get_file_name here too once testing is migrated to rust
++        "simple-raytracer/raytracer_cg_llvm",
++    )
++    .unwrap();
++}
++
++fn prepare_sysroot() {
++    let rustc_path = get_rustc_path();
++    let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
++    let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
++
++    assert!(sysroot_src_orig.exists());
++
++    if sysroot_src.exists() {
++        fs::remove_dir_all(&sysroot_src).unwrap();
++    }
++    fs::create_dir_all(sysroot_src.join("library")).unwrap();
++    eprintln!("[COPY] sysroot src");
++    copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
++
++    let rustc_version = get_rustc_version();
++    fs::write(
++        Path::new("build_sysroot").join("rustc_version"),
++        &rustc_version,
++    )
++    .unwrap();
++
++    eprintln!("[GIT] init");
++    let mut git_init_cmd = Command::new("git");
++    git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
++    spawn_and_wait(git_init_cmd);
++
++    let mut git_add_cmd = Command::new("git");
++    git_add_cmd.arg("add").arg(".").current_dir(&sysroot_src);
++    spawn_and_wait(git_add_cmd);
++
++    let mut git_commit_cmd = Command::new("git");
++    git_commit_cmd
++        .arg("commit")
++        .arg("-m")
++        .arg("Initial commit")
++        .arg("-q")
++        .current_dir(&sysroot_src);
++    spawn_and_wait(git_commit_cmd);
++
++    apply_patches("sysroot", &sysroot_src);
++
++    clone_repo(
++        "build_sysroot/compiler-builtins",
++        "https://github.com/rust-lang/compiler-builtins.git",
++        "0.1.46",
++    );
++    apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
++}
++
++fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
++    eprintln!("[CLONE] {}", repo);
++    // Ignore exit code as the repo may already have been checked out
++    Command::new("git").arg("clone").arg(repo).arg(target_dir).spawn().unwrap().wait().unwrap();
++
++    let mut clean_cmd = Command::new("git");
++    clean_cmd.arg("checkout").arg("--").arg(".").current_dir(target_dir);
++    spawn_and_wait(clean_cmd);
++
++    let mut checkout_cmd = Command::new("git");
++    checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(target_dir);
++    spawn_and_wait(checkout_cmd);
++}
++
++fn get_patches(crate_name: &str) -> Vec<OsString> {
++    let mut patches: Vec<_> = fs::read_dir("patches")
++        .unwrap()
++        .map(|entry| entry.unwrap().path())
++        .filter(|path| path.extension() == Some(OsStr::new("patch")))
++        .map(|path| path.file_name().unwrap().to_owned())
++        .filter(|file_name| {
++            file_name.to_str().unwrap().split_once("-").unwrap().1.starts_with(crate_name)
++        })
++        .collect();
++    patches.sort();
++    patches
++}
++
++fn apply_patches(crate_name: &str, target_dir: &Path) {
++    for patch in get_patches(crate_name) {
++        eprintln!("[PATCH] {:?} <- {:?}", target_dir.file_name().unwrap(), patch);
++        let patch_arg = env::current_dir().unwrap().join("patches").join(patch);
++        let mut apply_patch_cmd = Command::new("git");
++        apply_patch_cmd.arg("am").arg(patch_arg).arg("-q").current_dir(target_dir);
++        spawn_and_wait(apply_patch_cmd);
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9206bb02bd3da56da6959cdbbf34cf2e55a93f1c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++use std::path::{Path, PathBuf};
++use std::process::{Command, Stdio};
++
++pub(crate) fn get_rustc_version() -> String {
++    let version_info =
++        Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
++    String::from_utf8(version_info).unwrap()
++}
++
++pub(crate) fn get_host_triple() -> String {
++    let version_info =
++        Command::new("rustc").stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout;
++    String::from_utf8(version_info)
++        .unwrap()
++        .lines()
++        .to_owned()
++        .find(|line| line.starts_with("host"))
++        .unwrap()
++        .split(":")
++        .nth(1)
++        .unwrap()
++        .trim()
++        .to_owned()
++}
++
++pub(crate) fn get_rustc_path() -> PathBuf {
++    let rustc_path = Command::new("rustup")
++        .stderr(Stdio::inherit())
++        .args(&["which", "rustc"])
++        .output()
++        .unwrap()
++        .stdout;
++    Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
++}
++
++pub(crate) fn get_default_sysroot() -> PathBuf {
++    let default_sysroot = Command::new("rustc")
++        .stderr(Stdio::inherit())
++        .args(&["--print", "sysroot"])
++        .output()
++        .unwrap()
++        .stdout;
++    Path::new(String::from_utf8(default_sysroot).unwrap().trim()).to_owned()
++}
++
++pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
++    let file_name = Command::new("rustc")
++        .stderr(Stdio::inherit())
++        .args(&[
++            "--crate-name",
++            crate_name,
++            "--crate-type",
++            crate_type,
++            "--print",
++            "file-names",
++            "-",
++        ])
++        .output()
++        .unwrap()
++        .stdout;
++    let file_name = String::from_utf8(file_name).unwrap().trim().to_owned();
++    assert!(!file_name.contains('\n'));
++    assert!(file_name.contains(crate_name));
++    file_name
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..12b5d70fad853133384fb064e19fd9a2cb9d189a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++use std::fs;
++use std::path::Path;
++use std::process::{self, Command};
++
++#[track_caller]
++pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
++    let src = src.as_ref();
++    let dst = dst.as_ref();
++    if let Err(_) = fs::hard_link(src, dst) {
++        fs::copy(src, dst).unwrap(); // Fallback to copying if hardlinking failed
++    }
++}
++
++#[track_caller]
++pub(crate) fn spawn_and_wait(mut cmd: Command) {
++    if !cmd.spawn().unwrap().wait().unwrap().success() {
++        process::exit(1);
++    }
++}
++
++pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
++    for entry in fs::read_dir(from).unwrap() {
++        let entry = entry.unwrap();
++        let filename = entry.file_name();
++        if filename == "." || filename == ".." {
++            continue;
++        }
++        if entry.metadata().unwrap().is_dir() {
++            fs::create_dir(to.join(&filename)).unwrap();
++            copy_dir_recursively(&from.join(&filename), &to.join(&filename));
++        } else {
++            fs::copy(from.join(&filename), to.join(&filename)).unwrap();
++        }
++    }
++}
index a7bbeb05cac5a094bc0103d5f676452cef77f8a5,0000000000000000000000000000000000000000..f4f8c82d69f10814a052af9e45b7e79bfc61d301
mode 100755,000000..100755
--- /dev/null
@@@ -1,5 -1,0 +1,6 @@@
- rm -rf target/ build/ build_sysroot/{sysroot_src/,target/,compiler-builtins/} perf.data{,.old}
 +#!/usr/bin/env bash
 +set -e
 +
++rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
++rm -rf target/ build/ perf.data{,.old}
 +rm -rf rand/ regex/ simple-raytracer/
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b14db27d6206fc79ffa1faf4805fea0ab126e92b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++# This file allows configuring the build system.
++
++# Which triple to produce a compiler toolchain for.
++#
++# Defaults to the default triple of rustc on the host system.
++#host = x86_64-unknown-linux-gnu
++
++# Which triple to build libraries (core/alloc/std/test/proc_macro) for.
++#
++# Defaults to `host`.
++#target = x86_64-unknown-linux-gnu
++
++# Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when
++# the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified.
++# This option can be changed while the build system is already running for as long as sysroot
++# building hasn't started yet.
++#keep_sysroot
index 3eee3b554e3b62ccd06db4acbb819c5c760983e4,0000000000000000000000000000000000000000..956d5905a97adfbf460676559a73b32728b06b00
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,65 @@@
- Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`).
 +# Usage
 +
 +rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
 +
- $ $cg_clif_dir/build/cargo.sh build
++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.sh jit
++$ $cg_clif_dir/build/cargo 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
 +
 +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
- first called. It currently does not work with multi-threaded programs. When a not yet compiled
- function is called from another thread than the main thread, you will get an ICE.
++$ $cg_clif_dir/build/cargo jit
 +```
 +
 +or
 +
 +```bash
 +$ $cg_clif_dir/build/bin/cg_clif -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
- $ $cg_clif_dir/build/cargo.sh lazy-jit
++first called.
 +
 +```bash
++$ $cg_clif_dir/build/cargo 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 - -Cllvm-args=mode=jit -Cprefer-dynamic
 +}
 +
 +function jit() {
 +    jit_naked "fn main() { $@ }"
 +}
 +
 +function jit_calc() {
 +    jit 'println!("0x{:x}", ' $@ ');';
 +}
 +```
index 6570f2bf9f297fbccf66a4681d639a91f266a18f,0000000000000000000000000000000000000000..d997ce6d1b379044fd3675420e9837739ef0aa10
mode 100644,000000..100644
--- /dev/null
@@@ -1,475 -1,0 +1,475 @@@
-     #[cfg(all(not(jit), target_os = "linux"))]
 +#![feature(no_core, lang_items, box_syntax, never_type, linkage, extern_types, thread_local)]
 +#![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();
 +}
 +
 +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_os = "linux"))]
++    #[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_os = "linux"))]
++#[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 7d608df9253df85fe72e5c38bfb438b29bc267ab,0000000000000000000000000000000000000000..5bc51a541b58c7d63b0939976ab2d8869983d24b
mode 100644,000000..100644
--- /dev/null
@@@ -1,335 -1,0 +1,333 @@@
-     // FIXME support lazy jit when multi threading
-     #[cfg(not(lazy_jit))]
 +#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
 +
 +#[cfg(target_arch = "x86_64")]
 +use std::arch::x86_64::*;
 +use std::io::Write;
 +use std::ops::Generator;
 +
 +fn main() {
 +    println!("{:?}", std::env::args().collect::<Vec<_>>());
 +
 +    let mutex = std::sync::Mutex::new(());
 +    let _guard = mutex.lock().unwrap();
 +
 +    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
 +    let stderr = ::std::io::stderr();
 +    let mut stderr = stderr.lock();
 +
 +    std::thread::spawn(move || {
 +        println!("Hello from another thread!");
 +    });
 +
 +    writeln!(stderr, "some {} text", "<unknown>").unwrap();
 +
 +    let _ = std::process::Command::new("true").env("c", "d").spawn();
 +
 +    println!("cargo:rustc-link-lib=z");
 +
 +    static ONCE: std::sync::Once = std::sync::Once::new();
 +    ONCE.call_once(|| {});
 +
 +    let _eq = LoopState::Continue(()) == LoopState::Break(());
 +
 +    // Make sure ByValPair values with differently sized components are correctly passed
 +    map(None::<(u8, Box<Instruction>)>);
 +
 +    println!("{}", 2.3f32.exp());
 +    println!("{}", 2.3f32.exp2());
 +    println!("{}", 2.3f32.abs());
 +    println!("{}", 2.3f32.sqrt());
 +    println!("{}", 2.3f32.floor());
 +    println!("{}", 2.3f32.ceil());
 +    println!("{}", 2.3f32.min(1.0));
 +    println!("{}", 2.3f32.max(1.0));
 +    println!("{}", 2.3f32.powi(2));
 +    println!("{}", 2.3f32.log2());
 +    assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
 +    println!("{}", 2.3f32.powf(2.0));
 +
 +    assert_eq!(i64::MAX.checked_mul(2), None);
 +
 +    assert_eq!(-128i8, (-128i8).saturating_sub(1));
 +    assert_eq!(127i8, 127i8.saturating_sub(-128));
 +    assert_eq!(-128i8, (-128i8).saturating_add(-128));
 +    assert_eq!(127i8, 127i8.saturating_add(1));
 +
 +    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
 +    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
 +    assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128);
 +
 +    let _d = 0i128.checked_div(2i128);
 +    let _d = 0u128.checked_div(2u128);
 +    assert_eq!(1u128 + 2, 3);
 +
 +    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
 +    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
 +    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
 +
 +    let tmp = 353985398u128;
 +    assert_eq!(tmp * 932490u128, 330087843781020u128);
 +
 +    let tmp = -0x1234_5678_9ABC_DEF0i64;
 +    assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
 +
 +    // Check that all u/i128 <-> float casts work correctly.
 +    let houndred_u128 = 100u128;
 +    let houndred_i128 = 100i128;
 +    let houndred_f32 = 100.0f32;
 +    let houndred_f64 = 100.0f64;
 +    assert_eq!(houndred_u128 as f32, 100.0);
 +    assert_eq!(houndred_u128 as f64, 100.0);
 +    assert_eq!(houndred_f32 as u128, 100);
 +    assert_eq!(houndred_f64 as u128, 100);
 +    assert_eq!(houndred_i128 as f32, 100.0);
 +    assert_eq!(houndred_i128 as f64, 100.0);
 +    assert_eq!(houndred_f32 as i128, 100);
 +    assert_eq!(houndred_f64 as i128, 100);
 +    assert_eq!(1u128.rotate_left(2), 4);
 +
 +    // Test signed 128bit comparing
 +    let max = usize::MAX as i128;
 +    if 100i128 < 0i128 || 100i128 > max {
 +        panic!();
 +    }
 +
 +    test_checked_mul();
 +
 +    let _a = 1u32 << 2u8;
 +
 +    let empty: [i32; 0] = [];
 +    assert!(empty.is_sorted());
 +
 +    println!("{:?}", std::intrinsics::caller_location());
 +
 +    #[cfg(target_arch = "x86_64")]
 +    unsafe {
 +        test_simd();
 +    }
 +
 +    Box::pin(move |mut _task_context| {
 +        yield ();
 +    }).as_mut().resume(0);
 +
 +    #[derive(Copy, Clone)]
 +    enum Nums {
 +        NegOne = -1,
 +    }
 +
 +    let kind = Nums::NegOne;
 +    assert_eq!(-1i128, kind as i128);
 +
 +    let options = [1u128];
 +    match options[0] {
 +        1 => (),
 +        0 => loop {},
 +        v => panic(v),
 +    };
 +}
 +
 +fn panic(_: u128) {
 +    panic!();
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_simd() {
 +    assert!(is_x86_feature_detected!("sse2"));
 +
 +    let x = _mm_setzero_si128();
 +    let y = _mm_set1_epi16(7);
 +    let or = _mm_or_si128(x, y);
 +    let cmp_eq = _mm_cmpeq_epi8(y, y);
 +    let cmp_lt = _mm_cmplt_epi8(y, y);
 +
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
 +    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
 +
 +    test_mm_slli_si128();
 +    test_mm_movemask_epi8();
 +    test_mm256_movemask_epi8();
 +    test_mm_add_epi8();
 +    test_mm_add_pd();
 +    test_mm_cvtepi8_epi16();
 +    test_mm_cvtsi128_si64();
 +
 +    test_mm_extract_epi8();
 +    test_mm_insert_epi16();
 +
 +    let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
 +    assert_eq!(mask1, 1);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_slli_si128() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 1);
 +    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
 +    assert_eq_m128i(r, e);
 +
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 15);
 +    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
 +    assert_eq_m128i(r, e);
 +
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 +    );
 +    let r = _mm_slli_si128(a, 16);
 +    assert_eq_m128i(r, _mm_set1_epi8(0));
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_movemask_epi8() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
 +        0b0101, 0b1111_0000u8 as i8, 0, 0,
 +        0, 0, 0b1111_0000u8 as i8, 0b0101,
 +        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
 +    );
 +    let r = _mm_movemask_epi8(a);
 +    assert_eq!(r, 0b10100100_00100101);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "avx2")]
 +unsafe fn test_mm256_movemask_epi8() {
 +    let a = _mm256_set1_epi8(-1);
 +    let r = _mm256_movemask_epi8(a);
 +    let e = -1;
 +    assert_eq!(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_add_epi8() {
 +    let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
 +    #[rustfmt::skip]
 +    let b = _mm_setr_epi8(
 +        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 +    );
 +    let r = _mm_add_epi8(a, b);
 +    #[rustfmt::skip]
 +    let e = _mm_setr_epi8(
 +        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
 +    );
 +    assert_eq_m128i(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_add_pd() {
 +    let a = _mm_setr_pd(1.0, 2.0);
 +    let b = _mm_setr_pd(5.0, 10.0);
 +    let r = _mm_add_pd(a, b);
 +    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
 +    unsafe {
 +        assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
 +    }
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
 +    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
 +        panic!("{:?} != {:?}", a, b);
 +    }
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_cvtsi128_si64() {
 +    let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
 +    assert_eq!(r, 5);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse4.1")]
 +unsafe fn test_mm_cvtepi8_epi16() {
 +    let a = _mm_set1_epi8(10);
 +    let r = _mm_cvtepi8_epi16(a);
 +    let e = _mm_set1_epi16(10);
 +    assert_eq_m128i(r, e);
 +    let a = _mm_set1_epi8(-10);
 +    let r = _mm_cvtepi8_epi16(a);
 +    let e = _mm_set1_epi16(-10);
 +    assert_eq_m128i(r, e);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse4.1")]
 +unsafe fn test_mm_extract_epi8() {
 +    #[rustfmt::skip]
 +    let a = _mm_setr_epi8(
 +        -1, 1, 2, 3, 4, 5, 6, 7,
 +        8, 9, 10, 11, 12, 13, 14, 15
 +    );
 +    let r1 = _mm_extract_epi8(a, 0);
 +    let r2 = _mm_extract_epi8(a, 3);
 +    assert_eq!(r1, 0xFF);
 +    assert_eq!(r2, 3);
 +}
 +
 +#[cfg(target_arch = "x86_64")]
 +#[target_feature(enable = "sse2")]
 +unsafe fn test_mm_insert_epi16() {
 +    let a = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
 +    let r = _mm_insert_epi16(a, 9, 0);
 +    let e = _mm_setr_epi16(9, 1, 2, 3, 4, 5, 6, 7);
 +    assert_eq_m128i(r, e);
 +}
 +
 +fn test_checked_mul() {
 +    let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
 +    assert_eq!(u, None);
 +
 +    assert_eq!(1u8.checked_mul(255u8), Some(255u8));
 +    assert_eq!(255u8.checked_mul(255u8), None);
 +    assert_eq!(1i8.checked_mul(127i8), Some(127i8));
 +    assert_eq!(127i8.checked_mul(127i8), None);
 +    assert_eq!((-1i8).checked_mul(-127i8), Some(127i8));
 +    assert_eq!(1i8.checked_mul(-128i8), Some(-128i8));
 +    assert_eq!((-128i8).checked_mul(-128i8), None);
 +
 +    assert_eq!(1u64.checked_mul(u64::MAX), Some(u64::MAX));
 +    assert_eq!(u64::MAX.checked_mul(u64::MAX), None);
 +    assert_eq!(1i64.checked_mul(i64::MAX), Some(i64::MAX));
 +    assert_eq!(i64::MAX.checked_mul(i64::MAX), None);
 +    assert_eq!((-1i64).checked_mul(i64::MIN + 1), Some(i64::MAX));
 +    assert_eq!(1i64.checked_mul(i64::MIN), Some(i64::MIN));
 +    assert_eq!(i64::MIN.checked_mul(i64::MIN), None);
 +}
 +
 +#[derive(PartialEq)]
 +enum LoopState {
 +    Continue(()),
 +    Break(())
 +}
 +
 +pub enum Instruction {
 +    Increment,
 +    Loop,
 +}
 +
 +fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
 +    match a {
 +        None => None,
 +        Some((_, instr)) => Some(instr),
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7daea99f5794d2103588c152a0ac02ca1b5b14b1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,48 @@@
++From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Thu, 18 Feb 2021 18:30:55 +0100
++Subject: [PATCH] Disable 128bit atomic operations
++
++Cranelift doesn't support them yet
++---
++ src/mem/mod.rs | 12 ------------
++ 1 file changed, 12 deletions(-)
++
++diff --git a/src/mem/mod.rs b/src/mem/mod.rs
++index 107762c..2d1ae10 100644
++--- a/src/mem/mod.rs
+++++ b/src/mem/mod.rs
++@@ -137,10 +137,6 @@ intrinsics! {
++     pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
++         memcpy_element_unordered_atomic(dest, src, bytes);
++     }
++-    #[cfg(target_has_atomic_load_store = "128")]
++-    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
++-        memcpy_element_unordered_atomic(dest, src, bytes);
++-    }
++ 
++     #[cfg(target_has_atomic_load_store = "8")]
++     pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
++@@ -158,10 +154,6 @@ intrinsics! {
++     pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
++         memmove_element_unordered_atomic(dest, src, bytes);
++     }
++-    #[cfg(target_has_atomic_load_store = "128")]
++-    pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
++-        memmove_element_unordered_atomic(dest, src, bytes);
++-    }
++ 
++     #[cfg(target_has_atomic_load_store = "8")]
++     pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
++@@ -179,8 +171,4 @@ intrinsics! {
++     pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
++         memset_element_unordered_atomic(s, c, bytes);
++     }
++-    #[cfg(target_has_atomic_load_store = "128")]
++-    pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
++-        memset_element_unordered_atomic(s, c, bytes);
++-    }
++ }
++-- 
++2.26.2.7.g19db9cfb68
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..01dc0fcc5376138bccca396b78e729a5942bf94c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,23 @@@
++From 9c5663e36391fa20becf84f3af2e82afa5bb720b Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Sat, 15 Aug 2020 19:56:03 +0200
++Subject: [PATCH] [rand] Enable c2-chacha simd feature
++
++---
++ rand_chacha/Cargo.toml | 2 +-
++ 1 file changed, 1 insertion(+), 1 deletion(-)
++
++diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml
++index 9190b7f..872cca2 100644
++--- a/rand_chacha/Cargo.toml
+++++ b/rand_chacha/Cargo.toml
++@@ -24,5 +24,5 @@ ppv-lite86 = { version = "0.2.8", default-features = false }
++ 
++ [features]
++ default = ["std"]
++-std = ["ppv-lite86/std"]
+++std = ["ppv-lite86/std", "ppv-lite86/simd"]
++ simd = [] # deprecated
++-- 
++2.20.1
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..19fd20d7269017cfa1dd21a9db67999d61d4b619
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Sat, 15 Aug 2020 20:04:38 +0200
++Subject: [PATCH] [rand] Disable failing test
++
++---
++ src/distributions/uniform.rs | 3 ++-
++ 1 file changed, 2 insertions(+), 1 deletion(-)
++
++diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
++index 480b859..c80bb6f 100644
++--- a/src/distributions/uniform.rs
+++++ b/src/distributions/uniform.rs
++@@ -1085,7 +1085,7 @@ mod tests {
++             _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
++         }
++     }
++-    
+++
++     #[test]
++     #[cfg(feature = "serde1")]
++     fn test_uniform_serialization() {
++@@ -1314,6 +1314,7 @@ mod tests {
++         not(target_arch = "wasm32"),
++         not(target_arch = "asmjs")
++     ))]
+++    #[ignore] // FIXME
++     fn test_float_assertions() {
++         use super::SampleUniform;
++         use std::panic::catch_unwind;
++-- 
++2.20.1
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba0eaacd82870fd0a12952989c55b70317ef3b3a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,83 @@@
++From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Sun, 24 Nov 2019 15:10:23 +0100
++Subject: [PATCH] [core] Disable not compiling tests
++
++---
++ library/core/tests/Cargo.toml         | 8 ++++++++
++ library/core/tests/num/flt2dec/mod.rs | 1 -
++ library/core/tests/num/int_macros.rs  | 2 ++
++ library/core/tests/num/uint_macros.rs | 2 ++
++ library/core/tests/ptr.rs             | 2 ++
++ library/core/tests/slice.rs           | 2 ++
++ 6 files changed, 16 insertions(+), 1 deletion(-)
++ create mode 100644 library/core/tests/Cargo.toml
++
++diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
++new file mode 100644
++index 0000000..46fd999
++--- /dev/null
+++++ b/library/core/tests/Cargo.toml
++@@ -0,0 +1,8 @@
+++[package]
+++name = "core"
+++version = "0.0.0"
+++edition = "2018"
+++
+++[lib]
+++name = "coretests"
+++path = "lib.rs"
++diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
++index a35897e..f0bf645 100644
++--- a/library/core/tests/num/flt2dec/mod.rs
+++++ b/library/core/tests/num/flt2dec/mod.rs
++@@ -13,7 +13,6 @@ mod strategy {
++     mod dragon;
++     mod grisu;
++ }
++-mod random;
++ 
++ pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
++     match decode(v).1 {
++diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
++index 1a6be3a..42dbd59 100644
++--- a/library/core/tests/ptr.rs
+++++ b/library/core/tests/ptr.rs
++@@ -250,6 +250,7 @@ fn test_unsized_nonnull() {
++     assert!(ys == zs);
++ }
++ 
+++/*
++ #[test]
++ #[allow(warnings)]
++ // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
++@@ -289,6 +290,7 @@ fn write_unaligned_drop() {
++     }
++     DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
++ }
+++*/
++ 
++ #[test]
++ fn align_offset_zst() {
++diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
++index 6609bc3..241b497 100644
++--- a/library/core/tests/slice.rs
+++++ b/library/core/tests/slice.rs
++@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() {
++     }
++ }
++ 
+++/*
++ #[test]
++ #[cfg(not(target_arch = "wasm32"))]
++ fn sort_unstable() {
++@@ -1394,6 +1395,7 @@ fn partition_at_index() {
++     v.select_nth_unstable(0);
++     assert!(v == [0xDEADBEEF]);
++ }
+++*/
++ 
++ #[test]
++ #[should_panic(expected = "index 0 greater than length of slice")]
++--
++2.21.0 (Apple Git-122)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5d2c3049f60ebfb03d44e5885d14390d1e0371d2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,90 @@@
++From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Sun, 24 Nov 2019 15:34:06 +0100
++Subject: [PATCH] [core] Ignore failing tests
++
++---
++ library/core/tests/iter.rs       |  4 ++++
++ library/core/tests/num/bignum.rs | 10 ++++++++++
++ library/core/tests/num/mod.rs    |  5 +++--
++ library/core/tests/time.rs       |  1 +
++ 4 files changed, 18 insertions(+), 2 deletions(-)
++
++diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
++index 4bc44e9..8e3c7a4 100644
++--- a/library/core/tests/array.rs
+++++ b/library/core/tests/array.rs
++@@ -242,6 +242,7 @@ fn iterator_drops() {
++     assert_eq!(i.get(), 5);
++ }
++ 
+++/*
++ // This test does not work on targets without panic=unwind support.
++ // To work around this problem, test is marked is should_panic, so it will
++ // be automagically skipped on unsuitable targets, such as
++@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
++     assert_eq!(COUNTER.load(Relaxed), 0);
++     panic!("test succeeded")
++ }
+++*/
++ 
++ #[test]
++ fn empty_array_is_always_default() {
++@@ -304,6 +304,7 @@ fn array_map() {
++     assert_eq!(b, [1, 2, 3]);
++ }
++ 
+++/*
++ // See note on above test for why `should_panic` is used.
++ #[test]
++ #[should_panic(expected = "test succeeded")]
++@@ -332,6 +333,7 @@ fn array_map_drop_safety() {
++     assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
++     panic!("test succeeded")
++ }
+++*/
++ 
++ #[test]
++ fn cell_allows_array_cycle() {
++diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
++index a17c094..5bb11d2 100644
++--- a/library/core/tests/num/mod.rs
+++++ b/library/core/tests/num/mod.rs
++@@ -651,11 +651,12 @@ macro_rules! test_float {
++                 assert_eq!((9.0 as $fty).min($neginf), $neginf);
++                 assert_eq!(($neginf as $fty).min(-9.0), $neginf);
++                 assert_eq!((-9.0 as $fty).min($neginf), $neginf);
++-                assert_eq!(($nan as $fty).min(9.0), 9.0);
++-                assert_eq!(($nan as $fty).min(-9.0), -9.0);
++-                assert_eq!((9.0 as $fty).min($nan), 9.0);
++-                assert_eq!((-9.0 as $fty).min($nan), -9.0);
++-                assert!(($nan as $fty).min($nan).is_nan());
+++                // Cranelift fmin has NaN propagation
+++                //assert_eq!(($nan as $fty).min(9.0), 9.0);
+++                //assert_eq!(($nan as $fty).min(-9.0), -9.0);
+++                //assert_eq!((9.0 as $fty).min($nan), 9.0);
+++                //assert_eq!((-9.0 as $fty).min($nan), -9.0);
+++                //assert!(($nan as $fty).min($nan).is_nan());
++             }
++             #[test]
++             fn max() {
++@@ -673,11 +674,12 @@ macro_rules! test_float {
++                 assert_eq!((9.0 as $fty).max($neginf), 9.0);
++                 assert_eq!(($neginf as $fty).max(-9.0), -9.0);
++                 assert_eq!((-9.0 as $fty).max($neginf), -9.0);
++-                assert_eq!(($nan as $fty).max(9.0), 9.0);
++-                assert_eq!(($nan as $fty).max(-9.0), -9.0);
++-                assert_eq!((9.0 as $fty).max($nan), 9.0);
++-                assert_eq!((-9.0 as $fty).max($nan), -9.0);
++-                assert!(($nan as $fty).max($nan).is_nan());
+++                // Cranelift fmax has NaN propagation
+++                //assert_eq!(($nan as $fty).max(9.0), 9.0);
+++                //assert_eq!(($nan as $fty).max(-9.0), -9.0);
+++                //assert_eq!((9.0 as $fty).max($nan), 9.0);
+++                //assert_eq!((-9.0 as $fty).max($nan), -9.0);
+++                //assert!(($nan as $fty).max($nan).is_nan());
++             }
++             #[test]
++             fn rem_euclid() {
++-- 
++2.21.0 (Apple Git-122)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..32e5930969061f0231ecc6e89c72eb77be7002cb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,103 @@@
++From 894e07dfec2624ba539129b1c1d63e1d7d812bda Mon Sep 17 00:00:00 2001
++From: bjorn3 <bjorn3@users.noreply.github.com>
++Date: Thu, 18 Feb 2021 18:45:28 +0100
++Subject: [PATCH] Disable 128bit atomic operations
++
++Cranelift doesn't support them yet
++---
++ library/core/src/sync/atomic.rs | 38 ---------------------------------
++ library/core/tests/atomic.rs    |  4 ----
++ library/std/src/panic.rs        |  6 ------
++ 3 files changed, 48 deletions(-)
++
++diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
++index 81c9e1d..65c9503 100644
++--- a/library/core/src/sync/atomic.rs
+++++ b/library/core/src/sync/atomic.rs
++@@ -2228,44 +2228,6 @@ atomic_int! {
++     "AtomicU64::new(0)",
++     u64 AtomicU64 ATOMIC_U64_INIT
++ }
++-#[cfg(target_has_atomic_load_store = "128")]
++-atomic_int! {
++-    cfg(target_has_atomic = "128"),
++-    cfg(target_has_atomic_equal_alignment = "128"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    "i128",
++-    "#![feature(integer_atomics)]\n\n",
++-    atomic_min, atomic_max,
++-    16,
++-    "AtomicI128::new(0)",
++-    i128 AtomicI128 ATOMIC_I128_INIT
++-}
++-#[cfg(target_has_atomic_load_store = "128")]
++-atomic_int! {
++-    cfg(target_has_atomic = "128"),
++-    cfg(target_has_atomic_equal_alignment = "128"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
++-    unstable(feature = "integer_atomics", issue = "32976"),
++-    "u128",
++-    "#![feature(integer_atomics)]\n\n",
++-    atomic_umin, atomic_umax,
++-    16,
++-    "AtomicU128::new(0)",
++-    u128 AtomicU128 ATOMIC_U128_INIT
++-}
++ 
++ macro_rules! atomic_int_ptr_sized {
++     ( $($target_pointer_width:literal $align:literal)* ) => { $(
++diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
++index 2d1e449..cb6da5d 100644
++--- a/library/core/tests/atomic.rs
+++++ b/library/core/tests/atomic.rs
++@@ -145,10 +145,6 @@ fn atomic_alignment() {
++     assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
++     #[cfg(target_has_atomic = "64")]
++     assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
++-    #[cfg(target_has_atomic = "128")]
++-    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
++-    #[cfg(target_has_atomic = "128")]
++-    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
++     #[cfg(target_has_atomic = "ptr")]
++     assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
++     #[cfg(target_has_atomic = "ptr")]
++diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
++index 89a822a..779fd88 100644
++--- a/library/std/src/panic.rs
+++++ b/library/std/src/panic.rs
++@@ -279,9 +279,6 @@ impl RefUnwindSafe for atomic::AtomicI32 {}
++ #[cfg(target_has_atomic_load_store = "64")]
++ #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
++ impl RefUnwindSafe for atomic::AtomicI64 {}
++-#[cfg(target_has_atomic_load_store = "128")]
++-#[unstable(feature = "integer_atomics", issue = "32976")]
++-impl RefUnwindSafe for atomic::AtomicI128 {}
++ 
++ #[cfg(target_has_atomic_load_store = "ptr")]
++ #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
++@@ -298,9 +295,6 @@ impl RefUnwindSafe for atomic::AtomicU32 {}
++ #[cfg(target_has_atomic_load_store = "64")]
++ #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
++ impl RefUnwindSafe for atomic::AtomicU64 {}
++-#[cfg(target_has_atomic_load_store = "128")]
++-#[unstable(feature = "integer_atomics", issue = "32976")]
++-impl RefUnwindSafe for atomic::AtomicU128 {}
++ 
++ #[cfg(target_has_atomic_load_store = "8")]
++ #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
++-- 
++2.26.2.7.g19db9cfb68
++
index 9fe6e093a7b81f6577d1fb822692c77508e0ac88,0000000000000000000000000000000000000000..f806f7bdcd98a72e2c858d5b4f915be04e396bd1
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-05-26"
 +[toolchain]
++channel = "nightly-2021-07-07"
 +components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b7e8dd44974794294ac0621138ac6bdf95c1ee56
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,70 @@@
++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",
++            );
++            std::array::IntoIter::new(["rustc".to_string()])
++                .chain(env::args().skip(2))
++                .chain(["--".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",
++            );
++            std::array::IntoIter::new(["rustc".to_string()])
++                .chain(env::args().skip(2))
++                .chain(["--".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 99b302ee1d94b3cf044132fccd3401031b9c2c42,0000000000000000000000000000000000000000..53ada369b089a28ee63b3c183603a36153239821
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,6 @@@
- dylib=$(echo "" | rustc --print file-names --crate-type dylib --crate-name rustc_codegen_cranelift -)
- if echo "$RUSTC_WRAPPER" | grep sccache; then
- echo
- echo -e "\x1b[1;93m=== Warning: Unset RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
- echo
- export RUSTC_WRAPPER=
- fi
- dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
- export RUSTC=$dir"/bin/cg_clif"
- export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\
- '-Zcodegen-backend='$dir'/lib/'$dylib' --sysroot '$dir
- # FIXME fix `#[linkage = "extern_weak"]` without this
- if [[ "$(uname)" == 'Darwin' ]]; then
-    export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
- fi
- export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:"$dir"/lib"
- export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
 +# Note to people running shellcheck: this file should only be sourced, not executed directly.
 +
 +set -e
 +
++export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH"
++export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
index 3f98d77d76cad82fe2d7546f64f7b0407b576de4,0000000000000000000000000000000000000000..11d6c4c83186743f2751a2403c2996eab66746be
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,32 @@@
- # Various env vars that should only be set for the build system but not for cargo.sh
 +# Note to people running shellcheck: this file should only be sourced, not executed directly.
 +
++# Various env vars that should only be set for the build system
 +
 +set -e
 +
 +export CG_CLIF_DISPLAY_CG_TIME=1
 +export CG_CLIF_DISABLE_INCR_CACHE=1
 +
 +export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
 +export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
 +
 +export RUN_WRAPPER=''
 +export JIT_SUPPORTED=1
 +if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
 +   export JIT_SUPPORTED=0
 +   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
 +      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
 +      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
 +      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
 +   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
 +      # We are cross-compiling for Windows. Run tests in wine.
 +      export RUN_WRAPPER='wine'
 +   else
 +      echo "Unknown non-native platform"
 +   fi
 +fi
++
++# FIXME fix `#[linkage = "extern_weak"]` without this
++if [[ "$(uname)" == 'Darwin' ]]; then
++   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
++fi
index 15388926ec9ec62ddb5c707cc64c926317f75f09,0000000000000000000000000000000000000000..9e196afbe4f57c38b36576fb9621f4cee56373b5
mode 100755,000000..100755
--- /dev/null
@@@ -1,125 -1,0 +1,126 @@@
- source build/config.sh
 +#!/bin/bash
 +#![forbid(unsafe_code)]/* This line is ignored by bash
 +# This block is ignored by rustc
 +pushd $(dirname "$0")/../
- PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0
++source scripts/config.sh
++RUSTC="$(pwd)/build/bin/cg_clif"
 +popd
++PROFILE=$1 OUTPUT=$2 exec $RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic $0
 +#*/
 +
 +//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
 +//! profiles.
 +//!
 +//! Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>
 +//!
 +//! This file is specially crafted to be both a valid bash script and valid rust source file. If
 +//! executed as bash script this will run the rust source using cg_clif in JIT mode.
 +
 +use std::io::Write;
 +
 +fn main() -> Result<(), Box<dyn std::error::Error>> {
 +    let profile_name = std::env::var("PROFILE").unwrap();
 +    let output_name = std::env::var("OUTPUT").unwrap();
 +    if profile_name.is_empty() || output_name.is_empty() {
 +        println!("Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>");
 +        std::process::exit(1);
 +    }
 +    let profile = std::fs::read_to_string(profile_name)
 +        .map_err(|err| format!("Failed to read profile {}", err))?;
 +    let mut output = std::fs::OpenOptions::new()
 +        .create(true)
 +        .write(true)
 +        .truncate(true)
 +        .open(output_name)?;
 +
 +    for line in profile.lines() {
 +        let mut stack = &line[..line.rfind(" ").unwrap()];
 +        let count = &line[line.rfind(" ").unwrap() + 1..];
 +
 +        // Filter away uninteresting samples
 +        if !stack.contains("rustc_codegen_cranelift") {
 +            continue;
 +        }
 +
 +        if stack.contains("rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items")
 +            || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph")
 +            || stack.contains("rustc_symbol_mangling::test::report_symbol_names")
 +        {
 +            continue;
 +        }
 +
 +        // Trim start
 +        if let Some(index) = stack.find("rustc_interface::passes::configure_and_expand") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::passes::analysis") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::passes::start_codegen") {
 +            stack = &stack[index..];
 +        } else if let Some(index) = stack.find("rustc_interface::queries::Linker::link") {
 +            stack = &stack[index..];
 +        }
 +
 +        if let Some(index) = stack.find("rustc_codegen_cranelift::driver::aot::module_codegen") {
 +            stack = &stack[index..];
 +        }
 +
 +        // Trim end
 +        const MALLOC: &str = "malloc";
 +        if let Some(index) = stack.find(MALLOC) {
 +            stack = &stack[..index + MALLOC.len()];
 +        }
 +
 +        const FREE: &str = "free";
 +        if let Some(index) = stack.find(FREE) {
 +            stack = &stack[..index + FREE.len()];
 +        }
 +
 +        const TYPECK_ITEM_BODIES: &str = "rustc_typeck::check::typeck_item_bodies";
 +        if let Some(index) = stack.find(TYPECK_ITEM_BODIES) {
 +            stack = &stack[..index + TYPECK_ITEM_BODIES.len()];
 +        }
 +
 +        const COLLECT_AND_PARTITION_MONO_ITEMS: &str =
 +            "rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items";
 +        if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) {
 +            stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()];
 +        }
 +
 +        const ASSERT_DEP_GRAPH: &str = "rustc_incremental::assert_dep_graph::assert_dep_graph";
 +        if let Some(index) = stack.find(ASSERT_DEP_GRAPH) {
 +            stack = &stack[..index + ASSERT_DEP_GRAPH.len()];
 +        }
 +
 +        const REPORT_SYMBOL_NAMES: &str = "rustc_symbol_mangling::test::report_symbol_names";
 +        if let Some(index) = stack.find(REPORT_SYMBOL_NAMES) {
 +            stack = &stack[..index + REPORT_SYMBOL_NAMES.len()];
 +        }
 +
 +        const ENCODE_METADATA: &str = "rustc_middle::ty::context::TyCtxt::encode_metadata";
 +        if let Some(index) = stack.find(ENCODE_METADATA) {
 +            stack = &stack[..index + ENCODE_METADATA.len()];
 +        }
 +
 +        const SUBST_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::subst_and_normalize_erasing_regions";
 +        if let Some(index) = stack.find(SUBST_AND_NORMALIZE_ERASING_REGIONS) {
 +            stack = &stack[..index + SUBST_AND_NORMALIZE_ERASING_REGIONS.len()];
 +        }
 +
 +        const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_late_bound_regions";
 +        if let Some(index) = stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS) {
 +            stack = &stack[..index + NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()];
 +        }
 +
 +        const INST_BUILD: &str = "<cranelift_frontend::frontend::FuncInstBuilder as cranelift_codegen::ir::builder::InstBuilderBase>::build";
 +        if let Some(index) = stack.find(INST_BUILD) {
 +            stack = &stack[..index + INST_BUILD.len()];
 +        }
 +
 +        output.write_all(stack.as_bytes())?;
 +        output.write_all(&*b" ")?;
 +        output.write_all(count.as_bytes())?;
 +        output.write_all(&*b"\n")?;
 +    }
 +
 +    Ok(())
 +}
index fa7557653d879a161e77afdaddb0dc1822fc374f,0000000000000000000000000000000000000000..cc34c08088665bc19cdea842e961593052c28e50
mode 100755,000000..100755
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
-         ./prepare.sh
 +#!/usr/bin/env bash
 +
 +set -e
 +
 +case $1 in
 +    "prepare")
 +        TOOLCHAIN=$(date +%Y-%m-%d)
 +
 +        echo "=> Installing new nightly"
 +        rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists
 +        sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
 +        rustup component add rustfmt || true
 +
 +        echo "=> Uninstalling all old nighlies"
 +        for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do
 +            rustup toolchain uninstall "$nightly"
 +        done
 +
 +        ./clean_all.sh
++        ./y.rs prepare
 +
 +        (cd build_sysroot && cargo update)
 +
 +        ;;
 +    "commit")
 +        git add rust-toolchain build_sysroot/Cargo.lock
 +        git commit -m "Rustup to $(rustc -V)"
 +        ;;
 +    "push")
 +        cg_clif=$(pwd)
 +        pushd ../rust
 +        git pull origin master
 +        branch=sync_cg_clif-$(date +%Y-%m-%d)
 +        git checkout -b "$branch"
 +        git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master
 +        git push -u my "$branch"
 +
 +        # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing
 +        # from rust-lang/rust later
 +        git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
 +        popd
 +        git merge sync_from_rust
 +      ;;
 +    "pull")
 +        cg_clif=$(pwd)
 +        pushd ../rust
 +        git pull origin master
 +        rust_vers="$(git rev-parse HEAD)"
 +        git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust
 +        popd
 +        git merge sync_from_rust -m "Sync from rust $rust_vers"
 +        git branch -d sync_from_rust
 +        ;;
 +    *)
 +        echo "Unknown command '$1'"
 +        echo "Usage: ./rustup.sh prepare|commit"
 +        ;;
 +esac
index 43c4887669cf6a0512a87fbe8e045b359c66a14d,0000000000000000000000000000000000000000..52adaaa8de673d3661903b9353ed96ec1bbbb5dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,57 -1,0 +1,57 @@@
- ./build.sh
- source build/config.sh
 +#!/bin/bash
 +set -e
 +
- +compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] }
++./y.rs build
++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.45", 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
 +EOF
 +popd
index 347fb40e6f9e7bbf0999157ba046d052e6ab8f75,0000000000000000000000000000000000000000..2f5c2cf737b056be7560f2caa6d6c7d0d6160a8c
mode 100755,000000..100755
--- /dev/null
@@@ -1,92 -1,0 +1,94 @@@
- rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
 +#!/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/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true
 +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" 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/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/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/rt-explody-panic-payloads.rs
++rm src/test/incremental/change_crate_dep_kind.rs
 +
 +rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
 +rm src/test/ui/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/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/incremental/issue-49482.rs # same
 +rm src/test/incremental/issue-54059.rs # same
 +rm src/test/incremental/lto.rs # requires lto
 +
 +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/emit-named-files # requires full --emit support
 +
 +rm src/test/pretty/asm.rs # inline asm
 +rm src/test/pretty/raw-str-nonexpr.rs # same
 +
 +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/match/issue-82392.rs # differing error
 +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 src/test/ui/default-alloc-error-hook.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
 +
 +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}
 +popd
index 0d99d2c507c95af6819f7b8decfeb0dfbcc7bf4e,0000000000000000000000000000000000000000..5df04c533a70e38fb009dec4ec62f337e0a87a38
mode 100755,000000..100755
--- /dev/null
@@@ -1,152 -1,0 +1,154 @@@
- source build/config.sh
 +#!/usr/bin/env bash
 +
 +set -e
 +
- MY_RUSTC="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
++source scripts/config.sh
 +source scripts/ext_config.sh
-         $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE"
++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 -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 -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] 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 -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
 +
 +        echo "[JIT-lazy] std_example"
-     cargo clean
++        $MY_RUSTC -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.sh test --workspace
++    ../build/cargo clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        echo "[TEST] rust-random/rand"
-         ../build/cargo.sh build --workspace --target $TARGET_TRIPLE --tests
++        ../build/cargo test --workspace
 +    else
 +        echo "[AOT] rust-random/rand"
-         hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \
++        ../build/cargo 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.sh build"
++        hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \
 +        "RUSTC=rustc RUSTFLAGS='' cargo build" \
-         ../build/cargo.sh build --target $TARGET_TRIPLE
++        "../build/cargo 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 clean
 +        echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
 +        echo "[COMPILE] ebobby/simple-raytracer"
-     cargo clean
++        ../build/cargo 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.sh test
++    ../../../../../build/cargo clean
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
-         ../../../../../build/cargo.sh build --target $TARGET_TRIPLE --tests
++        ../../../../../build/cargo test
 +    else
-     cargo clean
++        ../../../../../build/cargo build --target $TARGET_TRIPLE --tests
 +    fi
 +    popd
 +
 +    pushd regex
 +    echo "[TEST] rust-lang/regex example shootout-regex-dna"
-     ../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE
++    ../build/cargo 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.sh run --example shootout-regex-dna --target $TARGET_TRIPLE \
++    ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE
 +    if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
 +        cat examples/regexdna-input.txt \
-         ../build/cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
++            | ../build/cargo 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.sh build --tests --target $TARGET_TRIPLE
++        ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
 +    else
 +        echo "[AOT] rust-lang/regex tests"
++        ../build/cargo build --tests --target $TARGET_TRIPLE
 +    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 ec3e17e5b758d6929cae190f6c51b92645cab5d1,0000000000000000000000000000000000000000..3d78eed77b94c373cfe533920501dbabb6f99470
mode 100644,000000..100644
--- /dev/null
@@@ -1,903 -1,0 +1,920 @@@
-         vtables: FxHashMap::default(),
 +//! Codegen of a single function
 +
 +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 +use rustc_index::vec::IndexVec;
 +use rustc_middle::ty::adjustment::PointerCast;
 +use rustc_middle::ty::layout::FnAbiExt;
 +use rustc_target::abi::call::FnAbi;
 +
 +use crate::constant::ConstantCx;
 +use crate::prelude::*;
 +
 +pub(crate) fn codegen_fn<'tcx>(
 +    cx: &mut crate::CodegenCx<'tcx>,
 +    module: &mut dyn Module,
 +    instance: Instance<'tcx>,
 +) {
 +    let tcx = cx.tcx;
 +
 +    let _inst_guard =
 +        crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
 +    debug_assert!(!instance.substs.needs_infer());
 +
 +    let mir = tcx.instance_mir(instance.def);
++    let _mir_guard = crate::PrintOnPanic(|| {
++        let mut buf = Vec::new();
++        rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap();
++        String::from_utf8_lossy(&buf).into_owned()
++    });
 +
 +    // Declare function
 +    let symbol_name = tcx.symbol_name(instance);
 +    let sig = get_function_sig(tcx, module.isa().triple(), instance);
 +    let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
 +
 +    cx.cached_context.clear();
 +
 +    // Make the FunctionBuilder
 +    let mut func_ctx = FunctionBuilderContext::new();
 +    let mut func = std::mem::replace(&mut cx.cached_context.func, Function::new());
 +    func.name = ExternalName::user(0, func_id.as_u32());
 +    func.signature = sig;
 +    func.collect_debug_info();
 +
 +    let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
 +
 +    // Predefine blocks
 +    let start_block = bcx.create_block();
 +    let block_map: IndexVec<BasicBlock, Block> =
 +        (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
 +
 +    // Make FunctionCx
 +    let pointer_type = module.target_config().pointer_type();
 +    let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
 +
 +    let mut fx = FunctionCx {
 +        cx,
 +        module,
 +        tcx,
 +        pointer_type,
-     crate::pretty_clif::write_clif_file(tcx, "unopt", None, instance, &context, &clif_comments);
 +        constants_cx: ConstantCx::new(),
 +
 +        instance,
 +        symbol_name,
 +        mir,
 +        fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
 +
 +        bcx,
 +        block_map,
 +        local_map: IndexVec::with_capacity(mir.local_decls.len()),
 +        caller_location: None, // set by `codegen_fn_prelude`
 +
 +        clif_comments,
 +        source_info_set: indexmap::IndexSet::new(),
 +        next_ssa_var: 0,
 +
 +        inline_asm_index: 0,
 +    };
 +
 +    let arg_uninhabited = fx
 +        .mir
 +        .args_iter()
 +        .any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
 +
 +    if !crate::constant::check_constants(&mut fx) {
 +        fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
 +        fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
 +        crate::trap::trap_unreachable(&mut fx, "compilation should have been aborted");
 +    } else if arg_uninhabited {
 +        fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
 +        fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
 +        crate::trap::trap_unreachable(&mut fx, "function has uninhabited argument");
 +    } else {
 +        tcx.sess.time("codegen clif ir", || {
 +            tcx.sess
 +                .time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block));
 +            codegen_fn_content(&mut fx);
 +        });
 +    }
 +
 +    // Recover all necessary data from fx, before accessing func will prevent future access to it.
 +    let instance = fx.instance;
 +    let mut clif_comments = fx.clif_comments;
 +    let source_info_set = fx.source_info_set;
 +    let local_map = fx.local_map;
 +
 +    fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
 +
 +    // Store function in context
 +    let context = &mut cx.cached_context;
 +    context.func = func;
 +
-         crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
++    crate::pretty_clif::write_clif_file(
++        tcx,
++        "unopt",
++        module.isa(),
++        instance,
++        &context,
++        &clif_comments,
++    );
 +
 +    // Verify function
 +    verify_func(tcx, &clif_comments, &context.func);
 +
 +    // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
 +    // instruction, which doesn't have an encoding.
 +    context.compute_cfg();
 +    context.compute_domtree();
 +    context.eliminate_unreachable_code(module.isa()).unwrap();
 +    context.dce(module.isa()).unwrap();
 +    // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
 +    // invalidate it when it would change.
 +    context.domtree.clear();
 +
 +    // Perform rust specific optimizations
 +    tcx.sess.time("optimize clif ir", || {
-         Some(module.isa()),
++        crate::optimize::optimize_function(
++            tcx,
++            module.isa(),
++            instance,
++            context,
++            &mut clif_comments,
++        );
 +    });
 +
 +    // Define function
 +    tcx.sess.time("define function", || {
 +        context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
 +        module
 +            .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
 +            .unwrap()
 +    });
 +
 +    // Write optimized function to file for debugging
 +    crate::pretty_clif::write_clif_file(
 +        tcx,
 +        "opt",
++        module.isa(),
 +        instance,
 +        &context,
 +        &clif_comments,
 +    );
 +
 +    if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
 +        crate::pretty_clif::write_ir_file(
 +            tcx,
 +            || format!("{}.vcode", tcx.symbol_name(instance).name),
 +            |file| file.write_all(disasm.as_bytes()),
 +        )
 +    }
 +
 +    // Define debuginfo for function
 +    let isa = module.isa();
 +    let debug_context = &mut cx.debug_context;
 +    let unwind_context = &mut cx.unwind_context;
 +    tcx.sess.time("generate debug info", || {
 +        if let Some(debug_context) = debug_context {
 +            debug_context.define_function(
 +                instance,
 +                func_id,
 +                symbol_name.name,
 +                isa,
 +                context,
 +                &source_info_set,
 +                local_map,
 +            );
 +        }
 +        unwind_context.add_function(func_id, &context, isa);
 +    });
 +
 +    // Clear context to make it usable for the next function
 +    context.clear();
 +}
 +
 +pub(crate) fn verify_func(
 +    tcx: TyCtxt<'_>,
 +    writer: &crate::pretty_clif::CommentWriter,
 +    func: &Function,
 +) {
 +    tcx.sess.time("verify clif ir", || {
 +        let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
 +        match cranelift_codegen::verify_function(&func, &flags) {
 +            Ok(_) => {}
 +            Err(err) => {
 +                tcx.sess.err(&format!("{:?}", err));
 +                let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
 +                    &func,
 +                    None,
 +                    Some(Box::new(writer)),
 +                    err,
 +                );
 +                tcx.sess.fatal(&format!("cranelift verify error:\n{}", pretty_error));
 +            }
 +        }
 +    });
 +}
 +
 +fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
 +    for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
 +        let block = fx.get_block(bb);
 +        fx.bcx.switch_to_block(block);
 +
 +        if bb_data.is_cleanup {
 +            // Unwinding after panicking is not supported
 +            continue;
 +
 +            // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
 +            // so for cleanup blocks.
 +        }
 +
 +        fx.bcx.ins().nop();
 +        for stmt in &bb_data.statements {
 +            fx.set_debug_loc(stmt.source_info);
 +            codegen_stmt(fx, block, stmt);
 +        }
 +
 +        if fx.clif_comments.enabled() {
 +            let mut terminator_head = "\n".to_string();
 +            bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
 +            let inst = fx.bcx.func.layout.last_inst(block).unwrap();
 +            fx.add_comment(inst, terminator_head);
 +        }
 +
 +        fx.set_debug_loc(bb_data.terminator().source_info);
 +
 +        match &bb_data.terminator().kind {
 +            TerminatorKind::Goto { target } => {
 +                if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
 +                    let mut can_immediately_return = true;
 +                    for stmt in &fx.mir[*target].statements {
 +                        if let StatementKind::StorageDead(_) = stmt.kind {
 +                        } else {
 +                            // FIXME Can sometimes happen, see rust-lang/rust#70531
 +                            can_immediately_return = false;
 +                            break;
 +                        }
 +                    }
 +
 +                    if can_immediately_return {
 +                        crate::abi::codegen_return(fx);
 +                        continue;
 +                    }
 +                }
 +
 +                let block = fx.get_block(*target);
 +                fx.bcx.ins().jump(block, &[]);
 +            }
 +            TerminatorKind::Return => {
 +                crate::abi::codegen_return(fx);
 +            }
 +            TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
 +                if !fx.tcx.sess.overflow_checks() {
 +                    if let mir::AssertKind::OverflowNeg(_) = *msg {
 +                        let target = fx.get_block(*target);
 +                        fx.bcx.ins().jump(target, &[]);
 +                        continue;
 +                    }
 +                }
 +                let cond = codegen_operand(fx, cond).load_scalar(fx);
 +
 +                let target = fx.get_block(*target);
 +                let failure = fx.bcx.create_block();
 +                // FIXME Mark failure block as cold once Cranelift supports it
 +
 +                if *expected {
 +                    fx.bcx.ins().brz(cond, failure, &[]);
 +                } else {
 +                    fx.bcx.ins().brnz(cond, failure, &[]);
 +                };
 +                fx.bcx.ins().jump(target, &[]);
 +
 +                fx.bcx.switch_to_block(failure);
 +                fx.bcx.ins().nop();
 +
 +                match msg {
 +                    AssertKind::BoundsCheck { ref len, ref index } => {
 +                        let len = codegen_operand(fx, len).load_scalar(fx);
 +                        let index = codegen_operand(fx, index).load_scalar(fx);
 +                        let location = fx
 +                            .get_caller_location(bb_data.terminator().source_info.span)
 +                            .load_scalar(fx);
 +
 +                        codegen_panic_inner(
 +                            fx,
 +                            rustc_hir::LangItem::PanicBoundsCheck,
 +                            &[index, len, location],
 +                            bb_data.terminator().source_info.span,
 +                        );
 +                    }
 +                    _ => {
 +                        let msg_str = msg.description();
 +                        codegen_panic(fx, msg_str, bb_data.terminator().source_info.span);
 +                    }
 +                }
 +            }
 +
 +            TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
 +                let discr = codegen_operand(fx, discr).load_scalar(fx);
 +
 +                let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
 +                    || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
 +                if use_bool_opt {
 +                    assert_eq!(targets.iter().count(), 1);
 +                    let (then_value, then_block) = targets.iter().next().unwrap();
 +                    let then_block = fx.get_block(then_block);
 +                    let else_block = fx.get_block(targets.otherwise());
 +                    let test_zero = match then_value {
 +                        0 => true,
 +                        1 => false,
 +                        _ => unreachable!("{:?}", targets),
 +                    };
 +
 +                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
 +                    let (discr, is_inverted) =
 +                        crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
 +                    let test_zero = if is_inverted { !test_zero } else { test_zero };
 +                    let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
 +                    let discr =
 +                        crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
 +                    if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
 +                        &fx.bcx, discr, test_zero,
 +                    ) {
 +                        if taken {
 +                            fx.bcx.ins().jump(then_block, &[]);
 +                        } else {
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        }
 +                    } else {
 +                        if test_zero {
 +                            fx.bcx.ins().brz(discr, then_block, &[]);
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        } else {
 +                            fx.bcx.ins().brnz(discr, then_block, &[]);
 +                            fx.bcx.ins().jump(else_block, &[]);
 +                        }
 +                    }
 +                } else {
 +                    let mut switch = ::cranelift_frontend::Switch::new();
 +                    for (value, block) in targets.iter() {
 +                        let block = fx.get_block(block);
 +                        switch.set_entry(value, block);
 +                    }
 +                    let otherwise_block = fx.get_block(targets.otherwise());
 +                    switch.emit(&mut fx.bcx, discr, otherwise_block);
 +                }
 +            }
 +            TerminatorKind::Call {
 +                func,
 +                args,
 +                destination,
 +                fn_span,
 +                cleanup: _,
 +                from_hir_call: _,
 +            } => {
 +                fx.tcx.sess.time("codegen call", || {
 +                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
 +                });
 +            }
 +            TerminatorKind::InlineAsm {
 +                template,
 +                operands,
 +                options,
 +                destination,
 +                line_spans: _,
 +            } => {
 +                crate::inline_asm::codegen_inline_asm(
 +                    fx,
 +                    bb_data.terminator().source_info.span,
 +                    template,
 +                    operands,
 +                    *options,
 +                );
 +
 +                match *destination {
 +                    Some(destination) => {
 +                        let destination_block = fx.get_block(destination);
 +                        fx.bcx.ins().jump(destination_block, &[]);
 +                    }
 +                    None => {
 +                        crate::trap::trap_unreachable(
 +                            fx,
 +                            "[corruption] Returned from noreturn inline asm",
 +                        );
 +                    }
 +                }
 +            }
 +            TerminatorKind::Resume | TerminatorKind::Abort => {
 +                trap_unreachable(fx, "[corruption] Unwinding bb reached.");
 +            }
 +            TerminatorKind::Unreachable => {
 +                trap_unreachable(fx, "[corruption] Hit unreachable code.");
 +            }
 +            TerminatorKind::Yield { .. }
 +            | TerminatorKind::FalseEdge { .. }
 +            | TerminatorKind::FalseUnwind { .. }
 +            | TerminatorKind::DropAndReplace { .. }
 +            | TerminatorKind::GeneratorDrop => {
 +                bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
 +            }
 +            TerminatorKind::Drop { place, target, unwind: _ } => {
 +                let drop_place = codegen_place(fx, *place);
 +                crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
 +
 +                let target_block = fx.get_block(*target);
 +                fx.bcx.ins().jump(target_block, &[]);
 +            }
 +        };
 +    }
 +
 +    fx.bcx.seal_all_blocks();
 +    fx.bcx.finalize();
 +}
 +
 +fn codegen_stmt<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    #[allow(unused_variables)] cur_block: Block,
 +    stmt: &Statement<'tcx>,
 +) {
 +    let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt));
 +
 +    fx.set_debug_loc(stmt.source_info);
 +
 +    #[cfg(disabled)]
 +    match &stmt.kind {
 +        StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
 +        _ => {
 +            if fx.clif_comments.enabled() {
 +                let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
 +                fx.add_comment(inst, format!("{:?}", stmt));
 +            }
 +        }
 +    }
 +
 +    match &stmt.kind {
 +        StatementKind::SetDiscriminant { place, variant_index } => {
 +            let place = codegen_place(fx, **place);
 +            crate::discriminant::codegen_set_discriminant(fx, place, *variant_index);
 +        }
 +        StatementKind::Assign(to_place_and_rval) => {
 +            let lval = codegen_place(fx, to_place_and_rval.0);
 +            let dest_layout = lval.layout();
 +            match to_place_and_rval.1 {
 +                Rvalue::Use(ref operand) => {
 +                    let val = codegen_operand(fx, operand);
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
 +                    let place = codegen_place(fx, place);
 +                    let ref_ = place.place_ref(fx, lval.layout());
 +                    lval.write_cvalue(fx, ref_);
 +                }
 +                Rvalue::ThreadLocalRef(def_id) => {
 +                    let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout());
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::BinaryOp(bin_op, ref lhs_rhs) => {
 +                    let lhs = codegen_operand(fx, &lhs_rhs.0);
 +                    let rhs = codegen_operand(fx, &lhs_rhs.1);
 +
 +                    let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
 +                    let lhs = codegen_operand(fx, &lhs_rhs.0);
 +                    let rhs = codegen_operand(fx, &lhs_rhs.1);
 +
 +                    let res = if !fx.tcx.sess.overflow_checks() {
 +                        let val =
 +                            crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx);
 +                        let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
 +                        CValue::by_val_pair(val, is_overflow, lval.layout())
 +                    } else {
 +                        crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
 +                    };
 +
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::UnaryOp(un_op, ref operand) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let layout = operand.layout();
 +                    let val = operand.load_scalar(fx);
 +                    let res = match un_op {
 +                        UnOp::Not => match layout.ty.kind() {
 +                            ty::Bool => {
 +                                let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
 +                                CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
 +                            }
 +                            ty::Uint(_) | ty::Int(_) => {
 +                                CValue::by_val(fx.bcx.ins().bnot(val), layout)
 +                            }
 +                            _ => unreachable!("un op Not for {:?}", layout.ty),
 +                        },
 +                        UnOp::Neg => match layout.ty.kind() {
 +                            ty::Int(IntTy::I128) => {
 +                                // FIXME remove this case once ineg.i128 works
 +                                let zero =
 +                                    CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
 +                                crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
 +                            }
 +                            ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
 +                            ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
 +                            _ => unreachable!("un op Neg for {:?}", layout.ty),
 +                        },
 +                    };
 +                    lval.write_cvalue(fx, res);
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ReifyFnPointer),
 +                    ref operand,
 +                    to_ty,
 +                ) => {
 +                    let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx));
 +                    let to_layout = fx.layout_of(fx.monomorphize(to_ty));
 +                    match *from_ty.kind() {
 +                        ty::FnDef(def_id, substs) => {
 +                            let func_ref = fx.get_function_ref(
 +                                Instance::resolve_for_fn_ptr(
 +                                    fx.tcx,
 +                                    ParamEnv::reveal_all(),
 +                                    def_id,
 +                                    substs,
 +                                )
 +                                .unwrap()
 +                                .polymorphize(fx.tcx),
 +                            );
 +                            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
 +                            lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
 +                        }
 +                        _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty),
 +                    }
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::UnsafeFnPointer),
 +                    ref operand,
 +                    to_ty,
 +                )
 +                | Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::MutToConstPointer),
 +                    ref operand,
 +                    to_ty,
 +                )
 +                | Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ArrayToPointer),
 +                    ref operand,
 +                    to_ty,
 +                ) => {
 +                    let to_layout = fx.layout_of(fx.monomorphize(to_ty));
 +                    let operand = codegen_operand(fx, operand);
 +                    lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
 +                }
 +                Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let from_ty = operand.layout().ty;
 +                    let to_ty = fx.monomorphize(to_ty);
 +
 +                    fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
 +                        ty.builtin_deref(true)
 +                            .map(|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
 +                                has_ptr_meta(fx.tcx, pointee_ty)
 +                            })
 +                            .unwrap_or(false)
 +                    }
 +
 +                    if is_fat_ptr(fx, from_ty) {
 +                        if is_fat_ptr(fx, to_ty) {
 +                            // fat-ptr -> fat-ptr
 +                            lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
 +                        } else {
 +                            // fat-ptr -> thin-ptr
 +                            let (ptr, _extra) = operand.load_scalar_pair(fx);
 +                            lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
 +                        }
 +                    } else if let ty::Adt(adt_def, _substs) = from_ty.kind() {
 +                        // enum -> discriminant value
 +                        assert!(adt_def.is_enum());
 +                        match to_ty.kind() {
 +                            ty::Uint(_) | ty::Int(_) => {}
 +                            _ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
 +                        }
 +                        let to_clif_ty = fx.clif_type(to_ty).unwrap();
 +
 +                        let discriminant = crate::discriminant::codegen_get_discriminant(
 +                            fx,
 +                            operand,
 +                            fx.layout_of(operand.layout().ty.discriminant_ty(fx.tcx)),
 +                        )
 +                        .load_scalar(fx);
 +
 +                        let res = crate::cast::clif_intcast(
 +                            fx,
 +                            discriminant,
 +                            to_clif_ty,
 +                            to_ty.is_signed(),
 +                        );
 +                        lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
 +                    } else {
 +                        let to_clif_ty = fx.clif_type(to_ty).unwrap();
 +                        let from = operand.load_scalar(fx);
 +
 +                        let res = clif_int_or_float_cast(
 +                            fx,
 +                            from,
 +                            type_sign(from_ty),
 +                            to_clif_ty,
 +                            type_sign(to_ty),
 +                        );
 +                        lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
 +                    }
 +                }
 +                Rvalue::Cast(
 +                    CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
 +                    ref operand,
 +                    _to_ty,
 +                ) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    match *operand.layout().ty.kind() {
 +                        ty::Closure(def_id, substs) => {
 +                            let instance = Instance::resolve_closure(
 +                                fx.tcx,
 +                                def_id,
 +                                substs,
 +                                ty::ClosureKind::FnOnce,
 +                            )
 +                            .polymorphize(fx.tcx);
 +                            let func_ref = fx.get_function_ref(instance);
 +                            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
 +                            lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
 +                        }
 +                        _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty),
 +                    }
 +                }
 +                Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    operand.unsize_value(fx, lval);
 +                }
 +                Rvalue::Discriminant(place) => {
 +                    let place = codegen_place(fx, place);
 +                    let value = place.to_cvalue(fx);
 +                    let discr =
 +                        crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
 +                    lval.write_cvalue(fx, discr);
 +                }
 +                Rvalue::Repeat(ref operand, times) => {
 +                    let operand = codegen_operand(fx, operand);
 +                    let times = fx
 +                        .monomorphize(times)
 +                        .eval(fx.tcx, ParamEnv::reveal_all())
 +                        .val
 +                        .try_to_bits(fx.tcx.data_layout.pointer_size)
 +                        .unwrap();
 +                    if operand.layout().size.bytes() == 0 {
 +                        // Do nothing for ZST's
 +                    } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
 +                        let times = fx.bcx.ins().iconst(fx.pointer_type, times as i64);
 +                        // FIXME use emit_small_memset where possible
 +                        let addr = lval.to_ptr().get_addr(fx);
 +                        let val = operand.load_scalar(fx);
 +                        fx.bcx.call_memset(fx.module.target_config(), addr, val, times);
 +                    } else {
 +                        let loop_block = fx.bcx.create_block();
 +                        let loop_block2 = fx.bcx.create_block();
 +                        let done_block = fx.bcx.create_block();
 +                        let index = fx.bcx.append_block_param(loop_block, fx.pointer_type);
 +                        let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
 +                        fx.bcx.ins().jump(loop_block, &[zero]);
 +
 +                        fx.bcx.switch_to_block(loop_block);
 +                        let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64);
 +                        fx.bcx.ins().brnz(done, done_block, &[]);
 +                        fx.bcx.ins().jump(loop_block2, &[]);
 +
 +                        fx.bcx.switch_to_block(loop_block2);
 +                        let to = lval.place_index(fx, index);
 +                        to.write_cvalue(fx, operand);
 +                        let index = fx.bcx.ins().iadd_imm(index, 1);
 +                        fx.bcx.ins().jump(loop_block, &[index]);
 +
 +                        fx.bcx.switch_to_block(done_block);
 +                        fx.bcx.ins().nop();
 +                    }
 +                }
 +                Rvalue::Len(place) => {
 +                    let place = codegen_place(fx, place);
 +                    let usize_layout = fx.layout_of(fx.tcx.types.usize);
 +                    let len = codegen_array_len(fx, place);
 +                    lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
 +                }
 +                Rvalue::NullaryOp(NullOp::Box, content_ty) => {
 +                    let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
 +                    let content_ty = fx.monomorphize(content_ty);
 +                    let layout = fx.layout_of(content_ty);
 +                    let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64);
 +                    let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64);
 +                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
 +
 +                    // Allocate space:
 +                    let def_id =
 +                        match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) {
 +                            Ok(id) => id,
 +                            Err(s) => {
 +                                fx.tcx
 +                                    .sess
 +                                    .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
 +                            }
 +                        };
 +                    let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
 +                    let func_ref = fx.get_function_ref(instance);
 +                    let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
 +                    let ptr = fx.bcx.inst_results(call)[0];
 +                    lval.write_cvalue(fx, CValue::by_val(ptr, box_layout));
 +                }
 +                Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
 +                    assert!(
 +                        lval.layout()
 +                            .ty
 +                            .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
 +                    );
 +                    let ty_size = fx.layout_of(fx.monomorphize(ty)).size.bytes();
 +                    let val =
 +                        CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into());
 +                    lval.write_cvalue(fx, val);
 +                }
 +                Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() {
 +                    AggregateKind::Array(_ty) => {
 +                        for (i, operand) in operands.iter().enumerate() {
 +                            let operand = codegen_operand(fx, operand);
 +                            let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
 +                            let to = lval.place_index(fx, index);
 +                            to.write_cvalue(fx, operand);
 +                        }
 +                    }
 +                    _ => unreachable!("shouldn't exist at codegen {:?}", to_place_and_rval.1),
 +                },
 +            }
 +        }
 +        StatementKind::StorageLive(_)
 +        | StatementKind::StorageDead(_)
 +        | StatementKind::Nop
 +        | StatementKind::FakeRead(..)
 +        | StatementKind::Retag { .. }
 +        | StatementKind::AscribeUserType(..) => {}
 +
 +        StatementKind::LlvmInlineAsm(asm) => {
 +            match asm.asm.asm.as_str().trim() {
 +                "" => {
 +                    // Black box
 +                }
 +                _ => fx.tcx.sess.span_fatal(
 +                    stmt.source_info.span,
 +                    "Legacy `llvm_asm!` inline assembly is not supported. \
 +                    Try using the new `asm!` instead.",
 +                ),
 +            }
 +        }
 +        StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
 +        StatementKind::CopyNonOverlapping(inner) => {
 +            let dst = codegen_operand(fx, &inner.dst);
 +            let pointee = dst
 +                .layout()
 +                .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
 +                .expect("Expected pointer");
 +            let dst = dst.load_scalar(fx);
 +            let src = codegen_operand(fx, &inner.src).load_scalar(fx);
 +            let count = codegen_operand(fx, &inner.count).load_scalar(fx);
 +            let elem_size: u64 = pointee.size.bytes();
 +            let bytes =
 +                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
 +            fx.bcx.call_memcpy(fx.module.target_config(), dst, src, bytes);
 +        }
 +    }
 +}
 +
 +fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value {
 +    match *place.layout().ty.kind() {
 +        ty::Array(_elem_ty, len) => {
 +            let len = fx.monomorphize(len).eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
 +            fx.bcx.ins().iconst(fx.pointer_type, len)
 +        }
 +        ty::Slice(_elem_ty) => {
 +            place.to_ptr_maybe_unsized().1.expect("Length metadata for slice place")
 +        }
 +        _ => bug!("Rvalue::Len({:?})", place),
 +    }
 +}
 +
 +pub(crate) fn codegen_place<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    place: Place<'tcx>,
 +) -> CPlace<'tcx> {
 +    let mut cplace = fx.get_local_place(place.local);
 +
 +    for elem in place.projection {
 +        match elem {
 +            PlaceElem::Deref => {
 +                cplace = cplace.place_deref(fx);
 +            }
 +            PlaceElem::Field(field, _ty) => {
 +                cplace = cplace.place_field(fx, field);
 +            }
 +            PlaceElem::Index(local) => {
 +                let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx);
 +                cplace = cplace.place_index(fx, index);
 +            }
 +            PlaceElem::ConstantIndex { offset, min_length: _, from_end } => {
 +                let offset: u64 = offset;
 +                let index = if !from_end {
 +                    fx.bcx.ins().iconst(fx.pointer_type, offset as i64)
 +                } else {
 +                    let len = codegen_array_len(fx, cplace);
 +                    fx.bcx.ins().iadd_imm(len, -(offset as i64))
 +                };
 +                cplace = cplace.place_index(fx, index);
 +            }
 +            PlaceElem::Subslice { from, to, from_end } => {
 +                // These indices are generated by slice patterns.
 +                // slice[from:-to] in Python terms.
 +
 +                let from: u64 = from;
 +                let to: u64 = to;
 +
 +                match cplace.layout().ty.kind() {
 +                    ty::Array(elem_ty, _len) => {
 +                        assert!(!from_end, "array subslices are never `from_end`");
 +                        let elem_layout = fx.layout_of(elem_ty);
 +                        let ptr = cplace.to_ptr();
 +                        cplace = CPlace::for_ptr(
 +                            ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
 +                            fx.layout_of(fx.tcx.mk_array(elem_ty, to - from)),
 +                        );
 +                    }
 +                    ty::Slice(elem_ty) => {
 +                        assert!(from_end, "slice subslices should be `from_end`");
 +                        let elem_layout = fx.layout_of(elem_ty);
 +                        let (ptr, len) = cplace.to_ptr_maybe_unsized();
 +                        let len = len.unwrap();
 +                        cplace = CPlace::for_ptr_with_extra(
 +                            ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
 +                            fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
 +                            cplace.layout(),
 +                        );
 +                    }
 +                    _ => unreachable!(),
 +                }
 +            }
 +            PlaceElem::Downcast(_adt_def, variant) => {
 +                cplace = cplace.downcast_variant(fx, variant);
 +            }
 +        }
 +    }
 +
 +    cplace
 +}
 +
 +pub(crate) fn codegen_operand<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    operand: &Operand<'tcx>,
 +) -> CValue<'tcx> {
 +    match operand {
 +        Operand::Move(place) | Operand::Copy(place) => {
 +            let cplace = codegen_place(fx, *place);
 +            cplace.to_cvalue(fx)
 +        }
 +        Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_),
 +    }
 +}
 +
 +pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
 +    let location = fx.get_caller_location(span).load_scalar(fx);
 +
 +    let msg_ptr = fx.anonymous_str(msg_str);
 +    let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
 +    let args = [msg_ptr, msg_len, location];
 +
 +    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span);
 +}
 +
 +pub(crate) fn codegen_panic_inner<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    lang_item: rustc_hir::LangItem,
 +    args: &[Value],
 +    span: Span,
 +) {
 +    let def_id =
 +        fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
 +
 +    let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
 +    let symbol_name = fx.tcx.symbol_name(instance).name;
 +
 +    fx.lib_call(
 +        &*symbol_name,
 +        vec![
 +            AbiParam::new(fx.pointer_type),
 +            AbiParam::new(fx.pointer_type),
 +            AbiParam::new(fx.pointer_type),
 +        ],
 +        vec![],
 +        args,
 +    );
 +
 +    crate::trap::trap_unreachable(fx, "panic lang item returned");
 +}
index 2643fae0a810af7d3630ed01e4ae704c6b42f173,0000000000000000000000000000000000000000..a044b43b86470a3c3e83f99ea5eb0cec9d4ea92e
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,87 @@@
- use std::panic;
 +#![feature(rustc_private, once_cell)]
 +
 +extern crate rustc_data_structures;
 +extern crate rustc_driver;
 +extern crate rustc_interface;
 +extern crate rustc_session;
 +extern crate rustc_target;
 +
 +use std::lazy::SyncLazy;
++use std::panic;
 +
 +use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 +use rustc_interface::interface;
 +use rustc_session::config::ErrorOutputType;
 +use rustc_session::early_error;
 +use rustc_target::spec::PanicStrategy;
 +
 +const BUG_REPORT_URL: &str = "https://github.com/bjorn3/rustc_codegen_cranelift/issues/new";
 +
 +static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
 +    SyncLazy::new(|| {
 +        let hook = panic::take_hook();
 +        panic::set_hook(Box::new(|info| {
 +            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
 +            (*DEFAULT_HOOK)(info);
 +
 +            // Separate the output with an empty line
 +            eprintln!();
 +
 +            // Print the ICE message
 +            rustc_driver::report_ice(info, BUG_REPORT_URL);
 +        }));
 +        hook
 +    });
 +
 +#[derive(Default)]
 +pub struct CraneliftPassesCallbacks {
 +    time_passes: bool,
 +}
 +
 +impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
 +    fn config(&mut self, config: &mut interface::Config) {
 +        // If a --prints=... option has been given, we don't print the "total"
 +        // time because it will mess up the --prints output. See #64339.
 +        self.time_passes = config.opts.prints.is_empty()
 +            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
 +
 +        config.opts.cg.panic = Some(PanicStrategy::Abort);
 +        config.opts.debugging_opts.panic_abort_tests = true;
 +        config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| {
 +            std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned()
 +        }));
 +    }
 +}
 +
 +fn main() {
 +    let start_time = std::time::Instant::now();
 +    let start_rss = get_resident_set_size();
 +    rustc_driver::init_rustc_env_logger();
 +    let mut callbacks = CraneliftPassesCallbacks::default();
 +    SyncLazy::force(&DEFAULT_HOOK); // Install ice hook
 +    let exit_code = rustc_driver::catch_with_exit_code(|| {
 +        let args = std::env::args_os()
 +            .enumerate()
 +            .map(|(i, arg)| {
 +                arg.into_string().unwrap_or_else(|arg| {
 +                    early_error(
 +                        ErrorOutputType::default(),
 +                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
 +                    )
 +                })
 +            })
 +            .collect::<Vec<_>>();
 +        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
 +        run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
 +            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
 +        })));
 +        run_compiler.run()
 +    });
 +
 +    if callbacks.time_passes {
 +        let end_rss = get_resident_set_size();
 +        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
 +    }
 +
 +    std::process::exit(exit_code)
 +}
index a8a0bb52a246e728041afe7ba14593b76db0cafb,0000000000000000000000000000000000000000..892ccf27f6df893f713a62e9cf387f951848da98
mode 100644,000000..100644
--- /dev/null
@@@ -1,406 -1,0 +1,405 @@@
-     pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer>,
 +use rustc_index::vec::IndexVec;
 +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) 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<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,
 +
 +    pub(crate) inline_asm_index: u32,
 +}
 +
 +impl<'tcx> LayoutOf for FunctionCx<'_, '_, 'tcx> {
 +    type Ty = Ty<'tcx>;
 +    type TyAndLayout = TyAndLayout<'tcx>;
 +
 +    fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
 +        RevealAllLayoutCx(self.tcx).layout_of(ty)
 +    }
 +}
 +
 +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 triple(&self) -> &target_lexicon::Triple {
 +        self.module.isa().triple()
 +    }
 +
 +    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> LayoutOf for RevealAllLayoutCx<'tcx> {
 +    type Ty = Ty<'tcx>;
 +    type TyAndLayout = TyAndLayout<'tcx>;
 +
 +    fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
 +        assert!(!ty.still_further_specializable());
 +        self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| {
 +            if let layout::LayoutError::SizeOverflow(_) = e {
 +                self.0.sess.fatal(&e.to_string())
 +            } else {
 +                bug!("failed to get layout for `{}`: {}", ty, e)
 +            }
 +        })
 +    }
 +}
 +
 +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 a87b3703949f9aebc5ec69e6e3a2bbb4cfd9b3fe,0000000000000000000000000000000000000000..2a2573aad295025f14f1d743c63b64845d9412db
mode 100644,000000..100644
--- /dev/null
@@@ -1,538 -1,0 +1,549 @@@
- use rustc_span::DUMMY_SP;
- use rustc_ast::Mutability;
 +//! Handling of `static`s, `const`s and promoted allocations
 +
-     alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
-     Scalar,
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::ErrorReported;
 +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 +use rustc_middle::mir::interpret::{
-         ConstValue::Scalar(x) => {
-             if fx.clif_type(layout.ty).is_none() {
-                 let (size, align) = (layout.size, layout.align.pref);
-                 let mut alloc = Allocation::from_bytes(
-                     std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(),
-                     align,
-                     Mutability::Not,
-                 );
-                 alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap();
-                 let alloc = fx.tcx.intern_const_alloc(alloc);
-                 return CValue::by_ref(pointer_for_allocation(fx, alloc), layout);
-             }
-             match x {
-                 Scalar::Int(int) => CValue::const_val(fx, layout, int),
-                 Scalar::Ptr(ptr) => {
-                     let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
-                     let base_addr = match alloc_kind {
-                         Some(GlobalAlloc::Memory(alloc)) => {
-                             fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
-                             let data_id = data_id_for_alloc_id(
-                                 &mut fx.constants_cx,
-                                 fx.module,
-                                 ptr.alloc_id,
-                                 alloc.mutability,
-                             );
-                             let local_data_id =
-                                 fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
-                             if fx.clif_comments.enabled() {
-                                 fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
-                             }
-                             fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
-                         }
-                         Some(GlobalAlloc::Function(instance)) => {
-                             let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
-                             let local_func_id =
-                                 fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
-                             fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
-                         }
-                         Some(GlobalAlloc::Static(def_id)) => {
-                             assert!(fx.tcx.is_static(def_id));
-                             let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
-                             let local_data_id =
-                                 fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
-                             if fx.clif_comments.enabled() {
-                                 fx.add_comment(local_data_id, format!("{:?}", def_id));
-                             }
-                             fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
++    read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
 +};
 +use rustc_middle::ty::ConstKind;
++use rustc_span::DUMMY_SP;
 +
 +use cranelift_codegen::ir::GlobalValueData;
 +use cranelift_module::*;
 +
 +use crate::prelude::*;
 +
 +pub(crate) struct ConstantCx {
 +    todo: Vec<TodoItem>,
 +    done: FxHashSet<DataId>,
 +    anon_allocs: FxHashMap<AllocId, DataId>,
 +}
 +
 +#[derive(Copy, Clone, Debug)]
 +enum TodoItem {
 +    Alloc(AllocId),
 +    Static(DefId),
 +}
 +
 +impl ConstantCx {
 +    pub(crate) fn new() -> Self {
 +        ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() }
 +    }
 +
 +    pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
 +        //println!("todo {:?}", self.todo);
 +        define_all_allocs(tcx, module, &mut self);
 +        //println!("done {:?}", self.done);
 +        self.done.clear();
 +    }
 +}
 +
 +pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
 +    let mut all_constants_ok = true;
 +    for constant in &fx.mir.required_consts {
 +        let const_ = match fx.monomorphize(constant.literal) {
 +            ConstantKind::Ty(ct) => ct,
 +            ConstantKind::Val(..) => continue,
 +        };
 +        match const_.val {
 +            ConstKind::Value(_) => {}
 +            ConstKind::Unevaluated(unevaluated) => {
 +                if let Err(err) =
 +                    fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None)
 +                {
 +                    all_constants_ok = false;
 +                    match err {
 +                        ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {
 +                            fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
 +                        }
 +                        ErrorHandled::TooGeneric => {
 +                            span_bug!(
 +                                constant.span,
 +                                "codgen encountered polymorphic constant: {:?}",
 +                                err
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +            ConstKind::Param(_)
 +            | ConstKind::Infer(_)
 +            | ConstKind::Bound(_, _)
 +            | ConstKind::Placeholder(_)
 +            | ConstKind::Error(_) => unreachable!("{:?}", const_),
 +        }
 +    }
 +    all_constants_ok
 +}
 +
 +pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
 +    let mut constants_cx = ConstantCx::new();
 +    constants_cx.todo.push(TodoItem::Static(def_id));
 +    constants_cx.finalize(tcx, module);
 +}
 +
 +pub(crate) fn codegen_tls_ref<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    def_id: DefId,
 +    layout: TyAndLayout<'tcx>,
 +) -> CValue<'tcx> {
 +    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
 +    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
 +    if fx.clif_comments.enabled() {
 +        fx.add_comment(local_data_id, format!("tls {:?}", def_id));
 +    }
 +    let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id);
 +    CValue::by_val(tls_ptr, layout)
 +}
 +
 +fn codegen_static_ref<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    def_id: DefId,
 +    layout: TyAndLayout<'tcx>,
 +) -> CPlace<'tcx> {
 +    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
 +    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
 +    if fx.clif_comments.enabled() {
 +        fx.add_comment(local_data_id, format!("{:?}", def_id));
 +    }
 +    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
 +    assert!(!layout.is_unsized(), "unsized statics aren't supported");
 +    assert!(
 +        matches!(
 +            fx.bcx.func.global_values[local_data_id],
 +            GlobalValueData::Symbol { tls: false, .. }
 +        ),
 +        "tls static referenced without Rvalue::ThreadLocalRef"
 +    );
 +    CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
 +}
 +
 +pub(crate) fn codegen_constant<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    constant: &Constant<'tcx>,
 +) -> CValue<'tcx> {
 +    let const_ = match fx.monomorphize(constant.literal) {
 +        ConstantKind::Ty(ct) => ct,
 +        ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty),
 +    };
 +    let const_val = match const_.val {
 +        ConstKind::Value(const_val) => const_val,
 +        ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
 +            if fx.tcx.is_static(def.did) =>
 +        {
 +            assert!(substs.is_empty());
 +            assert!(promoted.is_none());
 +
 +            return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
 +        }
 +        ConstKind::Unevaluated(unevaluated) => {
 +            match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
 +                Ok(const_val) => const_val,
 +                Err(_) => {
 +                    span_bug!(constant.span, "erroneous constant not captured by required_consts");
 +                }
 +            }
 +        }
 +        ConstKind::Param(_)
 +        | ConstKind::Infer(_)
 +        | ConstKind::Bound(_, _)
 +        | ConstKind::Placeholder(_)
 +        | ConstKind::Error(_) => unreachable!("{:?}", const_),
 +    };
 +
 +    codegen_const_value(fx, const_val, const_.ty)
 +}
 +
 +pub(crate) fn codegen_const_value<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    const_val: ConstValue<'tcx>,
 +    ty: Ty<'tcx>,
 +) -> CValue<'tcx> {
 +    let layout = fx.layout_of(ty);
 +    assert!(!layout.is_unsized(), "sized const value");
 +
 +    if layout.is_zst() {
 +        return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
 +    }
 +
 +    match const_val {
-                         None => bug!("missing allocation {:?}", ptr.alloc_id),
-                     };
-                     let val = if ptr.offset.bytes() != 0 {
-                         fx.bcx.ins().iadd_imm(base_addr, i64::try_from(ptr.offset.bytes()).unwrap())
-                     } else {
-                         base_addr
++        ConstValue::Scalar(x) => match x {
++            Scalar::Int(int) => {
++                if fx.clif_type(layout.ty).is_some() {
++                    return CValue::const_val(fx, layout, int);
++                } else {
++                    let raw_val = int.to_bits(int.size()).unwrap();
++                    let val = match int.size().bytes() {
++                        1 => fx.bcx.ins().iconst(types::I8, raw_val as i64),
++                        2 => fx.bcx.ins().iconst(types::I16, raw_val as i64),
++                        4 => fx.bcx.ins().iconst(types::I32, raw_val as i64),
++                        8 => fx.bcx.ins().iconst(types::I64, raw_val as i64),
++                        16 => {
++                            let lsb = fx.bcx.ins().iconst(types::I64, raw_val as u64 as i64);
++                            let msb =
++                                fx.bcx.ins().iconst(types::I64, (raw_val >> 64) as u64 as i64);
++                            fx.bcx.ins().iconcat(lsb, msb)
 +                        }
-                     CValue::by_val(val, layout)
++                        _ => unreachable!(),
 +                    };
-         }
++
++                    let place = CPlace::new_stack_slot(fx, layout);
++                    place.to_ptr().store(fx, val, MemFlags::trusted());
++                    place.to_cvalue(fx)
 +                }
 +            }
-     fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
++            Scalar::Ptr(ptr) => {
++                let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
++                let base_addr = match alloc_kind {
++                    Some(GlobalAlloc::Memory(alloc)) => {
++                        let data_id = data_id_for_alloc_id(
++                            &mut fx.constants_cx,
++                            fx.module,
++                            ptr.alloc_id,
++                            alloc.mutability,
++                        );
++                        let local_data_id =
++                            fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
++                        if fx.clif_comments.enabled() {
++                            fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
++                        }
++                        fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
++                    }
++                    Some(GlobalAlloc::Function(instance)) => {
++                        let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
++                        let local_func_id =
++                            fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
++                        fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
++                    }
++                    Some(GlobalAlloc::Static(def_id)) => {
++                        assert!(fx.tcx.is_static(def_id));
++                        let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
++                        let local_data_id =
++                            fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
++                        if fx.clif_comments.enabled() {
++                            fx.add_comment(local_data_id, format!("{:?}", def_id));
++                        }
++                        fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
++                    }
++                    None => bug!("missing allocation {:?}", ptr.alloc_id),
++                };
++                let val = if ptr.offset.bytes() != 0 {
++                    fx.bcx.ins().iadd_imm(base_addr, i64::try_from(ptr.offset.bytes()).unwrap())
++                } else {
++                    base_addr
++                };
++                CValue::by_val(val, layout)
++            }
++        },
 +        ConstValue::ByRef { alloc, offset } => CValue::by_ref(
 +            pointer_for_allocation(fx, alloc)
 +                .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()),
 +            layout,
 +        ),
 +        ConstValue::Slice { data, start, end } => {
 +            let ptr = pointer_for_allocation(fx, data)
 +                .offset_i64(fx, i64::try_from(start).unwrap())
 +                .get_addr(fx);
 +            let len = fx
 +                .bcx
 +                .ins()
 +                .iconst(fx.pointer_type, i64::try_from(end.checked_sub(start).unwrap()).unwrap());
 +            CValue::by_val_pair(ptr, len, layout)
 +        }
 +    }
 +}
 +
 +pub(crate) fn pointer_for_allocation<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    alloc: &'tcx Allocation,
 +) -> crate::pointer::Pointer {
 +    let alloc_id = fx.tcx.create_memory_alloc(alloc);
- fn data_id_for_alloc_id(
 +    let data_id =
 +        data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
 +
 +    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
 +    if fx.clif_comments.enabled() {
 +        fx.add_comment(local_data_id, format!("{:?}", alloc_id));
 +    }
 +    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
 +    crate::pointer::Pointer::new(global_ptr)
 +}
 +
-                 let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability);
++pub(crate) fn data_id_for_alloc_id(
 +    cx: &mut ConstantCx,
 +    module: &mut dyn Module,
 +    alloc_id: AllocId,
 +    mutability: rustc_hir::Mutability,
 +) -> DataId {
++    cx.todo.push(TodoItem::Alloc(alloc_id));
 +    *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
 +        module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
 +    })
 +}
 +
 +fn data_id_for_static(
 +    tcx: TyCtxt<'_>,
 +    module: &mut dyn Module,
 +    def_id: DefId,
 +    definition: bool,
 +) -> DataId {
 +    let rlinkage = tcx.codegen_fn_attrs(def_id).linkage;
 +    let linkage = if definition {
 +        crate::linkage::get_static_linkage(tcx, def_id)
 +    } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
 +        || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
 +    {
 +        Linkage::Preemptible
 +    } else {
 +        Linkage::Import
 +    };
 +
 +    let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
 +    let symbol_name = tcx.symbol_name(instance).name;
 +    let ty = instance.ty(tcx, ParamEnv::reveal_all());
 +    let is_mutable = if tcx.is_mutable_static(def_id) {
 +        true
 +    } else {
 +        !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all())
 +    };
 +    let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
 +
 +    let attrs = tcx.codegen_fn_attrs(def_id);
 +
 +    let data_id = module
 +        .declare_data(
 +            &*symbol_name,
 +            linkage,
 +            is_mutable,
 +            attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
 +        )
 +        .unwrap();
 +
 +    if rlinkage.is_some() {
 +        // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
 +        // Declare an internal global `extern_with_linkage_foo` which
 +        // is initialized with the address of `foo`.  If `foo` is
 +        // discarded during linking (for example, if `foo` has weak
 +        // linkage and there are no definitions), then
 +        // `extern_with_linkage_foo` will instead be initialized to
 +        // zero.
 +
 +        let ref_name = format!("_rust_extern_with_linkage_{}", symbol_name);
 +        let ref_data_id = module.declare_data(&ref_name, Linkage::Local, false, false).unwrap();
 +        let mut data_ctx = DataContext::new();
 +        data_ctx.set_align(align);
 +        let data = module.declare_data_in_data(data_id, &mut data_ctx);
 +        data_ctx.define(std::iter::repeat(0).take(pointer_ty(tcx).bytes() as usize).collect());
 +        data_ctx.write_data_addr(0, data, 0);
 +        match module.define_data(ref_data_id, &data_ctx) {
 +            // Every time the static is referenced there will be another definition of this global,
 +            // so duplicate definitions are expected and allowed.
 +            Err(ModuleError::DuplicateDefinition(_)) => {}
 +            res => res.unwrap(),
 +        }
 +        ref_data_id
 +    } else {
 +        data_id
 +    }
 +}
 +
 +fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) {
 +    while let Some(todo_item) = cx.todo.pop() {
 +        let (data_id, alloc, section_name) = match todo_item {
 +            TodoItem::Alloc(alloc_id) => {
 +                //println!("alloc_id {}", alloc_id);
 +                let alloc = match tcx.get_global_alloc(alloc_id).unwrap() {
 +                    GlobalAlloc::Memory(alloc) => alloc,
 +                    GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
 +                };
-                     cx.todo.push(TodoItem::Alloc(reloc));
++                let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
++                    module
++                        .declare_anonymous_data(
++                            alloc.mutability == rustc_hir::Mutability::Mut,
++                            false,
++                        )
++                        .unwrap()
++                });
 +                (data_id, alloc, None)
 +            }
 +            TodoItem::Static(def_id) => {
 +                //println!("static {:?}", def_id);
 +
 +                let section_name = tcx.codegen_fn_attrs(def_id).link_section.map(|s| s.as_str());
 +
 +                let alloc = tcx.eval_static_initializer(def_id).unwrap();
 +
 +                let data_id = data_id_for_static(tcx, module, def_id, true);
 +                (data_id, alloc, section_name)
 +            }
 +        };
 +
 +        //("data_id {}", data_id);
 +        if cx.done.contains(&data_id) {
 +            continue;
 +        }
 +
 +        let mut data_ctx = DataContext::new();
 +        data_ctx.set_align(alloc.align.bytes());
 +
 +        if let Some(section_name) = section_name {
 +            let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
 +                if let Some(names) = section_name.split_once(',') {
 +                    names
 +                } else {
 +                    tcx.sess.fatal(&format!(
 +                        "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
 +                        section_name
 +                    ));
 +                }
 +            } else {
 +                ("", &*section_name)
 +            };
 +            data_ctx.set_segment_section(segment_name, section_name);
 +        }
 +
 +        let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
 +        data_ctx.define(bytes.into_boxed_slice());
 +
 +        for &(offset, (_tag, reloc)) in alloc.relocations().iter() {
 +            let addend = {
 +                let endianness = tcx.data_layout.endian;
 +                let offset = offset.bytes() as usize;
 +                let ptr_size = tcx.data_layout.pointer_size;
 +                let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter(
 +                    offset..offset + ptr_size.bytes() as usize,
 +                );
 +                read_target_uint(endianness, bytes).unwrap()
 +            };
 +
 +            let reloc_target_alloc = tcx.get_global_alloc(reloc).unwrap();
 +            let data_id = match reloc_target_alloc {
 +                GlobalAlloc::Function(instance) => {
 +                    assert_eq!(addend, 0);
 +                    let func_id = crate::abi::import_function(tcx, module, instance);
 +                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
 +                    data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
 +                    continue;
 +                }
 +                GlobalAlloc::Memory(target_alloc) => {
 +                    data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
 +                }
 +                GlobalAlloc::Static(def_id) => {
 +                    if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
 +                    {
 +                        tcx.sess.fatal(&format!(
 +                            "Allocation {:?} contains reference to TLS value {:?}",
 +                            alloc, def_id
 +                        ));
 +                    }
 +
 +                    // Don't push a `TodoItem::Static` here, as it will cause statics used by
 +                    // multiple crates to be duplicated between them. It isn't necessary anyway,
 +                    // as it will get pushed by `codegen_static` when necessary.
 +                    data_id_for_static(tcx, module, def_id, false)
 +                }
 +            };
 +
 +            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
 +            data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
 +        }
 +
 +        module.define_data(data_id, &data_ctx).unwrap();
 +        cx.done.insert(data_id);
 +    }
 +
 +    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
 +}
 +
 +pub(crate) fn mir_operand_get_const_val<'tcx>(
 +    fx: &FunctionCx<'_, '_, 'tcx>,
 +    operand: &Operand<'tcx>,
 +) -> Option<ConstValue<'tcx>> {
 +    match operand {
 +        Operand::Constant(const_) => match const_.literal {
 +            ConstantKind::Ty(const_) => {
 +                fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
 +            }
 +            ConstantKind::Val(val, _) => Some(val),
 +        },
 +        // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
 +        // inside a temporary before being passed to the intrinsic requiring the const argument.
 +        // This code tries to find a single constant defining definition of the referenced local.
 +        Operand::Copy(place) | Operand::Move(place) => {
 +            if !place.projection.is_empty() {
 +                return None;
 +            }
 +            let mut computed_const_val = None;
 +            for bb_data in fx.mir.basic_blocks() {
 +                for stmt in &bb_data.statements {
 +                    match &stmt.kind {
 +                        StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
 +                            match &local_and_rvalue.1 {
 +                                Rvalue::Cast(CastKind::Misc, operand, ty) => {
 +                                    if computed_const_val.is_some() {
 +                                        return None; // local assigned twice
 +                                    }
 +                                    if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
 +                                        return None;
 +                                    }
 +                                    let const_val = mir_operand_get_const_val(fx, operand)?;
 +                                    if fx.layout_of(ty).size
 +                                        != const_val.try_to_scalar_int()?.size()
 +                                    {
 +                                        return None;
 +                                    }
 +                                    computed_const_val = Some(const_val);
 +                                }
 +                                Rvalue::Use(operand) => {
 +                                    computed_const_val = mir_operand_get_const_val(fx, operand)
 +                                }
 +                                _ => return None,
 +                            }
 +                        }
 +                        StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ }
 +                            if &**stmt_place == place =>
 +                        {
 +                            return None;
 +                        }
 +                        StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
 +                            return None;
 +                        } // conservative handling
 +                        StatementKind::Assign(_)
 +                        | StatementKind::FakeRead(_)
 +                        | StatementKind::SetDiscriminant { .. }
 +                        | StatementKind::StorageLive(_)
 +                        | StatementKind::StorageDead(_)
 +                        | StatementKind::Retag(_, _)
 +                        | StatementKind::AscribeUserType(_, _)
 +                        | StatementKind::Coverage(_)
 +                        | StatementKind::Nop => {}
 +                    }
 +                }
 +                match &bb_data.terminator().kind {
 +                    TerminatorKind::Goto { .. }
 +                    | TerminatorKind::SwitchInt { .. }
 +                    | TerminatorKind::Resume
 +                    | TerminatorKind::Abort
 +                    | TerminatorKind::Return
 +                    | TerminatorKind::Unreachable
 +                    | TerminatorKind::Drop { .. }
 +                    | TerminatorKind::Assert { .. } => {}
 +                    TerminatorKind::DropAndReplace { .. }
 +                    | TerminatorKind::Yield { .. }
 +                    | TerminatorKind::GeneratorDrop
 +                    | TerminatorKind::FalseEdge { .. }
 +                    | TerminatorKind::FalseUnwind { .. } => unreachable!(),
 +                    TerminatorKind::InlineAsm { .. } => return None,
 +                    TerminatorKind::Call { destination: Some((call_place, _)), .. }
 +                        if call_place == place =>
 +                    {
 +                        return None;
 +                    }
 +                    TerminatorKind::Call { .. } => {}
 +                }
 +            }
 +            computed_const_val
 +        }
 +    }
 +}
index 9eb067706309e12cebc5a06146d24e433da1f6e0,0000000000000000000000000000000000000000..c7e15f81e030104c33ff6663ca8806307dcbf7ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,219 @@@
- use cranelift_codegen::machinst::MachSrcLoc;
 +//! Line info generation (`.debug_line`)
 +
 +use std::ffi::OsStr;
 +use std::path::{Component, Path};
 +
 +use crate::prelude::*;
 +
 +use rustc_span::{
 +    FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
 +};
 +
 +use cranelift_codegen::binemit::CodeOffset;
++use cranelift_codegen::MachSrcLoc;
 +
 +use gimli::write::{
 +    Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,
 +    UnitEntryId,
 +};
 +
 +// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
 +fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
 +    let mut iter = path.components();
 +    let file_name = match iter.next_back() {
 +        Some(Component::Normal(p)) => p,
 +        component => {
 +            panic!(
 +                "Path component {:?} of path {} is an invalid filename",
 +                component,
 +                path.display()
 +            );
 +        }
 +    };
 +    let parent = iter.as_path();
 +    (parent, file_name)
 +}
 +
 +// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
 +fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
 +    #[cfg(unix)]
 +    {
 +        use std::os::unix::ffi::OsStrExt;
 +        path.as_bytes()
 +    }
 +    #[cfg(not(unix))]
 +    {
 +        path.to_str().unwrap().as_bytes()
 +    }
 +}
 +
 +pub(crate) const MD5_LEN: usize = 16;
 +
 +pub(crate) fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
 +    if hash.kind == SourceFileHashAlgorithm::Md5 {
 +        let mut buf = [0u8; MD5_LEN];
 +        buf.copy_from_slice(hash.hash_bytes());
 +        Some(FileInfo { timestamp: 0, size: 0, md5: buf })
 +    } else {
 +        None
 +    }
 +}
 +
 +fn line_program_add_file(
 +    line_program: &mut LineProgram,
 +    line_strings: &mut LineStringTable,
 +    file: &SourceFile,
 +) -> FileId {
 +    match &file.name {
 +        FileName::Real(path) => {
 +            let (dir_path, file_name) = split_path_dir_and_file(path.remapped_path_if_available());
 +            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
 +            let file_name = osstr_as_utf8_bytes(file_name);
 +
 +            let dir_id = if !dir_name.is_empty() {
 +                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
 +                line_program.add_directory(dir_name)
 +            } else {
 +                line_program.default_directory()
 +            };
 +            let file_name = LineString::new(file_name, line_program.encoding(), line_strings);
 +
 +            let info = make_file_info(file.src_hash);
 +
 +            line_program.file_has_md5 &= info.is_some();
 +            line_program.add_file(file_name, dir_id, info)
 +        }
 +        // FIXME give more appropriate file names
 +        filename => {
 +            let dir_id = line_program.default_directory();
 +            let dummy_file_name = LineString::new(
 +                filename.prefer_remapped().to_string().into_bytes(),
 +                line_program.encoding(),
 +                line_strings,
 +            );
 +            line_program.add_file(dummy_file_name, dir_id, None)
 +        }
 +    }
 +}
 +
 +impl<'tcx> DebugContext<'tcx> {
 +    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
 +        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());
 +
 +        let file_id = line_program_add_file(
 +            &mut self.dwarf.unit.line_program,
 +            &mut self.dwarf.line_strings,
 +            &loc.file,
 +        );
 +
 +        let entry = self.dwarf.unit.get_mut(entry_id);
 +
 +        entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
 +        entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(loc.line as u64));
 +        // FIXME: probably omit this
 +        entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(loc.col.to_usize() as u64));
 +    }
 +
 +    pub(super) fn create_debug_lines(
 +        &mut self,
 +        symbol: usize,
 +        entry_id: UnitEntryId,
 +        context: &Context,
 +        function_span: Span,
 +        source_info_set: &indexmap::IndexSet<SourceInfo>,
 +    ) -> CodeOffset {
 +        let tcx = self.tcx;
 +        let line_program = &mut self.dwarf.unit.line_program;
 +
 +        let line_strings = &mut self.dwarf.line_strings;
 +        let mut last_span = None;
 +        let mut last_file = None;
 +        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
 +            if let Some(last_span) = last_span {
 +                if span == last_span {
 +                    line_program.generate_row();
 +                    return;
 +                }
 +            }
 +            last_span = Some(span);
 +
 +            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
 +            // In order to have a good line stepping behavior in debugger, we overwrite debug
 +            // locations of macro expansions with that of the outermost expansion site
 +            // (unless the crate is being compiled with `-Z debug-macros`).
 +            let span = if !span.from_expansion() || tcx.sess.opts.debugging_opts.debug_macros {
 +                span
 +            } else {
 +                // Walk up the macro expansion chain until we reach a non-expanded span.
 +                // We also stop at the function body level because no line stepping can occur
 +                // at the level above that.
 +                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
 +            };
 +
 +            let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
 +                Ok(SourceFileAndLine { sf: file, line }) => {
 +                    let line_pos = file.line_begin_pos(span.lo());
 +
 +                    (
 +                        file,
 +                        u64::try_from(line).unwrap() + 1,
 +                        u64::from((span.lo() - line_pos).to_u32()) + 1,
 +                    )
 +                }
 +                Err(file) => (file, 0, 0),
 +            };
 +
 +            // line_program_add_file is very slow.
 +            // Optimize for the common case of the current file not being changed.
 +            let current_file_changed = if let Some(last_file) = &last_file {
 +                // If the allocations are not equal, then the files may still be equal, but that
 +                // is not a problem, as this is just an optimization.
 +                !rustc_data_structures::sync::Lrc::ptr_eq(last_file, &file)
 +            } else {
 +                true
 +            };
 +            if current_file_changed {
 +                let file_id = line_program_add_file(line_program, line_strings, &file);
 +                line_program.row().file = file_id;
 +                last_file = Some(file);
 +            }
 +
 +            line_program.row().line = line;
 +            line_program.row().column = col;
 +            line_program.generate_row();
 +        };
 +
 +        line_program.begin_sequence(Some(Address::Symbol { symbol, addend: 0 }));
 +
 +        let mut func_end = 0;
 +
 +        let mcr = context.mach_compile_result.as_ref().unwrap();
 +        for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() {
 +            line_program.row().address_offset = u64::from(start);
 +            if !loc.is_default() {
 +                let source_info = *source_info_set.get_index(loc.bits() as usize).unwrap();
 +                create_row_for_span(line_program, source_info.span);
 +            } else {
 +                create_row_for_span(line_program, function_span);
 +            }
 +            func_end = end;
 +        }
 +
 +        line_program.end_sequence(u64::from(func_end));
 +
 +        let func_end = mcr.buffer.total_size();
 +
 +        assert_ne!(func_end, 0);
 +
 +        let entry = self.dwarf.unit.get_mut(entry_id);
 +        entry.set(
 +            gimli::DW_AT_low_pc,
 +            AttributeValue::Address(Address::Symbol { symbol, addend: 0 }),
 +        );
 +        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end)));
 +
 +        self.emit_location(entry_id, function_span);
 +
 +        func_end
 +    }
 +}
index 61e54a76f29ba514956cb25c6066ef6182190e79,0000000000000000000000000000000000000000..c67336eb3f2c3125ee0427511991fbd3d01d2e09
mode 100644,000000..100644
--- /dev/null
@@@ -1,382 -1,0 +1,384 @@@
-         // FIXME: how to get version when building out of tree?
-         // Normally this would use option_env!("CFG_VERSION").
-         let producer = format!("cg_clif (rustc {})", "unknown version");
 +//! Handling of everything related to debuginfo.
 +
 +mod emit;
 +mod line_info;
 +mod unwind;
 +
 +use crate::prelude::*;
 +
 +use rustc_index::vec::IndexVec;
 +
 +use cranelift_codegen::entity::EntityRef;
 +use cranelift_codegen::ir::{LabelValueLoc, StackSlots, ValueLabel, ValueLoc};
 +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;
 +
 +fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
 +    use rustc_target::abi::Endian;
 +
 +    match tcx.data_layout.endian {
 +        Endian::Big => RunTimeEndian::Big,
 +        Endian::Little => RunTimeEndian::Little,
 +    }
 +}
 +
 +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,
 +            // TODO: 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 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.working_dir.to_string_lossy(false).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: target_endian(tcx),
 +
 +            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,
 +                        )
 +                        .unwrap();
 +
 +                    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 = context.build_value_labels_ranges(isa).unwrap();
 +
 +            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,
 +                    context,
 +                    &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,
 +    context: &Context,
 +    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,
 +                                &context.func.stack_slots,
 +                            )
 +                            .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), &context.func.stack_slots).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,
 +    stack_slots: &StackSlots,
 +) -> Option<Expression> {
 +    match loc {
 +        LabelValueLoc::ValueLoc(ValueLoc::Reg(reg)) => {
 +            let machine_reg = isa.map_dwarf_register(reg).unwrap();
 +            let mut expr = Expression::new();
 +            expr.op_reg(gimli::Register(machine_reg));
 +            Some(expr)
 +        }
 +        LabelValueLoc::ValueLoc(ValueLoc::Stack(ss)) => {
 +            if let Some(ss_offset) = stack_slots[ss].offset {
 +                let mut expr = Expression::new();
 +                expr.op_breg(X86_64::RBP, i64::from(ss_offset) + 16);
 +                Some(expr)
 +            } else {
 +                None
 +            }
 +        }
 +        LabelValueLoc::ValueLoc(ValueLoc::Unassigned) => unreachable!(),
 +        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 50fd53481f74580c59afbd09346dd1b5b48dfe59,0000000000000000000000000000000000000000..a8b802f449437622770ff9426fd524ac4273c1f2
mode 100644,000000..100644
--- /dev/null
@@@ -1,417 -1,0 +1,420 @@@
-             crate_info: CrateInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
 +//! 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::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
 +use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 +use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 +use rustc_middle::middle::cstore::EncodedMetadata;
 +use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
 +use rustc_session::cgu_reuse_tracker::CguReuse;
 +use rustc_session::config::{DebugInfo, OutputType};
 +
 +use cranelift_object::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 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 incr_comp_session_dir = tcx.sess.incr_comp_session_dir();
 +    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(&incr_comp_session_dir, &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 = crate::backend::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,
 +    );
 +    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,
 +                    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 =
 +        crate::backend::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(tcx, 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 obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
 +                crate::metadata::write_metadata(tcx, object);
 +            });
 +
 +            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 04ec01ad28148483519cefcf65e9615e2203d2d2,0000000000000000000000000000000000000000..76fbc9ad51e8ec8af1b9665ed2194a4b18f145a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,293 -1,0 +1,380 @@@
-     let imported_symbols = load_imported_symbols_for_jit(tcx);
 +//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
 +//! files.
 +
 +use std::cell::RefCell;
 +use std::ffi::CString;
++use std::lazy::{Lazy, SyncOnceCell};
 +use std::os::raw::{c_char, c_int};
++use std::sync::{mpsc, Mutex};
 +
 +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 +use rustc_codegen_ssa::CrateInfo;
 +use rustc_middle::mir::mono::MonoItem;
++use rustc_session::Session;
 +
 +use cranelift_jit::{JITBuilder, JITModule};
 +
 +use crate::{prelude::*, BackendConfig};
 +use crate::{CodegenCx, CodegenMode};
 +
 +struct JitState {
 +    backend_config: BackendConfig,
 +    jit_module: JITModule,
 +}
 +
 +thread_local! {
 +    static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None);
 +}
 +
++/// The Sender owned by the rustc thread
++static GLOBAL_MESSAGE_SENDER: SyncOnceCell<Mutex<mpsc::Sender<UnsafeMessage>>> =
++    SyncOnceCell::new();
++
++/// A message that is sent from the jitted runtime to the rustc thread.
++/// Senders are responsible for upholding `Send` semantics.
++enum UnsafeMessage {
++    /// Request that the specified `Instance` be lazily jitted.
++    ///
++    /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after
++    /// this message is sent.
++    JitFn {
++        instance_ptr: *const Instance<'static>,
++        trampoline_ptr: *const u8,
++        tx: mpsc::Sender<*const u8>,
++    },
++}
++unsafe impl Send for UnsafeMessage {}
++
++impl UnsafeMessage {
++    /// Send the message.
++    fn send(self) -> Result<(), mpsc::SendError<UnsafeMessage>> {
++        thread_local! {
++            /// The Sender owned by the local thread
++            static LOCAL_MESSAGE_SENDER: Lazy<mpsc::Sender<UnsafeMessage>> = Lazy::new(||
++                GLOBAL_MESSAGE_SENDER
++                    .get().unwrap()
++                    .lock().unwrap()
++                    .clone()
++            );
++        }
++        LOCAL_MESSAGE_SENDER.with(|sender| sender.send(self))
++    }
++}
++
 +fn create_jit_module<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    backend_config: &BackendConfig,
 +    hotswap: bool,
 +) -> (JITModule, CodegenCx<'tcx>) {
-     let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
-     // Push a null pointer as a terminating argument. This is required by POSIX and
-     // useful as some dynamic linkers use it as a marker to jump over.
-     argv.push(std::ptr::null());
++    let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
++    let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
 +
 +    let isa = crate::build_isa(tcx.sess, backend_config);
 +    let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
 +    jit_builder.hotswap(hotswap);
 +    crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
 +    jit_builder.symbols(imported_symbols);
 +    let mut jit_module = JITModule::new(jit_builder);
 +
 +    let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), jit_module.isa(), false);
 +
 +    crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
 +    crate::main_shim::maybe_create_entry_wrapper(
 +        tcx,
 +        &mut jit_module,
 +        &mut cx.unwind_context,
 +        true,
 +        true,
 +    );
 +
 +    (jit_module, cx)
 +}
 +
 +pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
 +    if !tcx.sess.opts.output_types.should_codegen() {
 +        tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
 +    }
 +
 +    if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
 +        tcx.sess.fatal("can't jit non-executable crate");
 +    }
 +
 +    let (mut jit_module, mut cx) = create_jit_module(
 +        tcx,
 +        &backend_config,
 +        matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
 +    );
 +
 +    let (_, cgus) = tcx.collect_and_partition_mono_items(());
 +    let mono_items = cgus
 +        .iter()
 +        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
 +        .flatten()
 +        .collect::<FxHashMap<_, (_, _)>>()
 +        .into_iter()
 +        .collect::<Vec<(_, (_, _))>>();
 +
 +    super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
 +        super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
 +        for (mono_item, _) in mono_items {
 +            match mono_item {
 +                MonoItem::Fn(inst) => match backend_config.codegen_mode {
 +                    CodegenMode::Aot => unreachable!(),
 +                    CodegenMode::Jit => {
 +                        cx.tcx.sess.time("codegen fn", || {
 +                            crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
 +                        });
 +                    }
 +                    CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
 +                },
 +                MonoItem::Static(def_id) => {
 +                    crate::constant::codegen_static(tcx, &mut jit_module, def_id);
 +                }
 +                MonoItem::GlobalAsm(item_id) => {
 +                    let item = tcx.hir().item(item_id);
 +                    tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
 +                }
 +            }
 +        }
 +    });
 +
 +    if !cx.global_asm.is_empty() {
 +        tcx.sess.fatal("Inline asm is not supported in JIT mode");
 +    }
 +
 +    tcx.sess.abort_if_errors();
 +
 +    jit_module.finalize_definitions();
 +    unsafe { cx.unwind_context.register_jit(&jit_module) };
 +
 +    println!(
 +        "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
 +    );
 +
 +    let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
 +        .chain(backend_config.jit_args.iter().map(|arg| &**arg))
 +        .map(|arg| CString::new(arg).unwrap())
 +        .collect::<Vec<_>>();
-         call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
 +
 +    let start_sig = Signature {
 +        params: vec![
 +            AbiParam::new(jit_module.target_config().pointer_type()),
 +            AbiParam::new(jit_module.target_config().pointer_type()),
 +        ],
 +        returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
-     let ret = f(args.len() as c_int, argv.as_ptr());
-     std::process::exit(ret);
++        call_conv: jit_module.target_config().default_call_conv,
 +    };
 +    let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
 +    let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
 +
 +    LAZY_JIT_STATE.with(|lazy_jit_state| {
 +        let mut lazy_jit_state = lazy_jit_state.borrow_mut();
 +        assert!(lazy_jit_state.is_none());
 +        *lazy_jit_state = Some(JitState { backend_config, jit_module });
 +    });
 +
 +    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
 +        unsafe { ::std::mem::transmute(finalized_start) };
- extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
++
++    let (tx, rx) = mpsc::channel();
++    GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap();
++
++    // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages
++    // (eg to lazily JIT further functions as required)
++    std::thread::spawn(move || {
++        let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
++
++        // Push a null pointer as a terminating argument. This is required by POSIX and
++        // useful as some dynamic linkers use it as a marker to jump over.
++        argv.push(std::ptr::null());
++
++        let ret = f(args.len() as c_int, argv.as_ptr());
++        std::process::exit(ret);
++    });
++
++    // Handle messages
++    loop {
++        match rx.recv().unwrap() {
++            // lazy JIT compilation request - compile requested instance and return pointer to result
++            UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => {
++                tx.send(jit_fn(instance_ptr, trampoline_ptr))
++                    .expect("jitted runtime hung up before response to lazy JIT request was sent");
++            }
++        }
++    }
 +}
 +
 +#[no_mangle]
- fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
++extern "C" fn __clif_jit_fn(
++    instance_ptr: *const Instance<'static>,
++    trampoline_ptr: *const u8,
++) -> *const u8 {
++    // send the JIT request to the rustc thread, with a channel for the response
++    let (tx, rx) = mpsc::channel();
++    UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }
++        .send()
++        .expect("rustc thread hung up before lazy JIT request was sent");
++
++    // block on JIT compilation result
++    rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request")
++}
++
++fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 {
 +    rustc_middle::ty::tls::with(|tcx| {
 +        // lift is used to ensure the correct lifetime for instance.
 +        let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
 +
 +        LAZY_JIT_STATE.with(|lazy_jit_state| {
 +            let mut lazy_jit_state = lazy_jit_state.borrow_mut();
 +            let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
 +            let jit_module = &mut lazy_jit_state.jit_module;
 +            let backend_config = lazy_jit_state.backend_config.clone();
 +
 +            let name = tcx.symbol_name(instance).name;
 +            let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
 +            let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
++
++            let current_ptr = jit_module.read_got_entry(func_id);
++
++            // If the function's GOT entry has already been updated to point at something other
++            // than the shim trampoline, don't re-jit but just return the new pointer instead.
++            // This does not need synchronization as this code is executed only by a sole rustc
++            // thread.
++            if current_ptr != trampoline_ptr {
++                return current_ptr;
++            }
++
 +            jit_module.prepare_for_function_redefine(func_id).unwrap();
 +
 +            let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
 +            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
 +
 +            assert!(cx.global_asm.is_empty());
 +            jit_module.finalize_definitions();
 +            unsafe { cx.unwind_context.register_jit(&jit_module) };
 +            jit_module.get_finalized_function(func_id)
 +        })
 +    })
 +}
 +
-     let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
-     let formats = tcx.dependency_formats(());
-     let data = &formats
++fn load_imported_symbols_for_jit(
++    sess: &Session,
++    crate_info: CrateInfo,
++) -> Vec<(String, *const u8)> {
 +    use rustc_middle::middle::dependency_format::Linkage;
 +
 +    let mut dylib_paths = Vec::new();
 +
-                 let name = tcx.crate_name(cnum);
-                 let mut err =
-                     tcx.sess.struct_err(&format!("Can't load static lib {}", name.as_str()));
++    let data = &crate_info
++        .dependency_formats
 +        .iter()
 +        .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
 +        .unwrap()
 +        .1;
 +    for &cnum in &crate_info.used_crates {
 +        let src = &crate_info.used_crate_source[&cnum];
 +        match data[cnum.as_usize() - 1] {
 +            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
 +            Linkage::Static => {
-     tcx.sess.abort_if_errors();
++                let name = &crate_info.crate_name[&cnum];
++                let mut err = sess.struct_err(&format!("Can't load static lib {}", name.as_str()));
 +                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
 +                err.emit();
 +            }
 +            Linkage::Dynamic => {
 +                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
 +            }
 +        }
 +    }
 +
 +    let mut imported_symbols = Vec::new();
 +    for path in dylib_paths {
 +        use object::{Object, ObjectSymbol};
 +        let lib = libloading::Library::new(&path).unwrap();
 +        let obj = std::fs::read(path).unwrap();
 +        let obj = object::File::parse(&*obj).unwrap();
 +        imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
 +            let name = symbol.name().unwrap().to_string();
 +            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
 +                return None;
 +            }
 +            if name.starts_with("rust_metadata_") {
 +                // The metadata is part of a section that is not loaded by the dynamic linker in
 +                // case of cg_llvm.
 +                return None;
 +            }
 +            let dlsym_name = if cfg!(target_os = "macos") {
 +                // On macOS `dlsym` expects the name without leading `_`.
 +                assert!(name.starts_with('_'), "{:?}", name);
 +                &name[1..]
 +            } else {
 +                &name
 +            };
 +            let symbol: libloading::Symbol<'_, *const u8> =
 +                unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
 +            Some((name, *symbol))
 +        }));
 +        std::mem::forget(lib)
 +    }
 +
-                 params: vec![AbiParam::new(pointer_type)],
++    sess.abort_if_errors();
 +
 +    imported_symbols
 +}
 +
 +fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
 +    let tcx = cx.tcx;
 +
 +    let pointer_type = module.target_config().pointer_type();
 +
 +    let name = tcx.symbol_name(inst).name;
 +    let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
 +    let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
 +
 +    let instance_ptr = Box::into_raw(Box::new(inst));
 +
 +    let jit_fn = module
 +        .declare_function(
 +            "__clif_jit_fn",
 +            Linkage::Import,
 +            &Signature {
 +                call_conv: module.target_config().default_call_conv,
-     let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]);
++                params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)],
 +                returns: vec![AbiParam::new(pointer_type)],
 +            },
 +        )
 +        .unwrap();
 +
 +    cx.cached_context.clear();
 +    let trampoline = &mut cx.cached_context.func;
 +    trampoline.signature = sig.clone();
 +
 +    let mut builder_ctx = FunctionBuilderContext::new();
 +    let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
 +
++    let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func);
 +    let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
 +    let sig_ref = trampoline_builder.func.import_signature(sig);
 +
 +    let entry_block = trampoline_builder.create_block();
 +    trampoline_builder.append_block_params_for_function_params(entry_block);
 +    let fn_args = trampoline_builder.func.dfg.block_params(entry_block).to_vec();
 +
 +    trampoline_builder.switch_to_block(entry_block);
 +    let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64);
++    let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn);
++    let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]);
 +    let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
 +    let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args);
 +    let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
 +    trampoline_builder.ins().return_(&ret_vals);
 +
 +    module
 +        .define_function(
 +            func_id,
 +            &mut cx.cached_context,
 +            &mut NullTrapSink {},
 +            &mut NullStackMapSink {},
 +        )
 +        .unwrap();
 +}
index ba4ed2162cd5d1397c38fa210e1c36445a0226a3,0000000000000000000000000000000000000000..be3704ca2768e0377a579c8206adf25c8d499fa6
mode 100644,000000..100644
--- /dev/null
@@@ -1,123 -1,0 +1,181 @@@
 +//! Emulate LLVM intrinsics
 +
 +use crate::intrinsics::*;
 +use crate::prelude::*;
 +
 +use rustc_middle::ty::subst::SubstsRef;
 +
 +pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    intrinsic: &str,
 +    substs: SubstsRef<'tcx>,
 +    args: &[mir::Operand<'tcx>],
 +    destination: Option<(CPlace<'tcx>, BasicBlock)>,
 +) {
 +    let ret = destination.unwrap().0;
 +
 +    intrinsic_match! {
 +        fx, intrinsic, substs, args,
 +        _ => {
 +            fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
 +            crate::trap::trap_unimplemented(fx, intrinsic);
 +        };
 +
 +        // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
 +        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
 +            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
 +            let lane_ty = fx.clif_type(lane_ty).unwrap();
 +            assert!(lane_count <= 32);
 +
 +            let mut res = fx.bcx.ins().iconst(types::I32, 0);
 +
 +            for lane in (0..lane_count).rev() {
 +                let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
 +
 +                // cast float to int
 +                let a_lane = match lane_ty {
 +                    types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
 +                    types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
 +                    _ => a_lane,
 +                };
 +
 +                // extract sign bit of an int
 +                let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
 +
 +                // shift sign bit into result
 +                let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
 +                res = fx.bcx.ins().ishl_imm(res, 1);
 +                res = fx.bcx.ins().bor(res, a_lane_sign);
 +            }
 +
 +            let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
 +            ret.write_cvalue(fx, res);
 +        };
 +        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
 +            let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
 +            let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) {
 +                0 => FloatCC::Equal,
 +                1 => FloatCC::LessThan,
 +                2 => FloatCC::LessThanOrEqual,
 +                7 => {
 +                    unimplemented!("Compares corresponding elements in `a` and `b` to see if neither is `NaN`.");
 +                }
 +                3 => {
 +                    unimplemented!("Compares corresponding elements in `a` and `b` to see if either is `NaN`.");
 +                }
 +                4 => FloatCC::NotEqual,
 +                5 => {
 +                    unimplemented!("not less than");
 +                }
 +                6 => {
 +                    unimplemented!("not less than or equal");
 +                }
 +                kind => unreachable!("kind {:?}", kind),
 +            };
 +
 +            simd_pair_for_each_lane(fx, x, y, ret, |fx, lane_layout, res_lane_layout, x_lane, y_lane| {
 +                let res_lane = match lane_layout.ty.kind() {
 +                    ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
 +                    _ => unreachable!("{:?}", lane_layout.ty),
 +                };
 +                bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane)
 +            });
 +        };
 +        "llvm.x86.sse2.psrli.d", (c a, o imm8) {
 +            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
 +            simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
 +                let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
 +                    imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
 +                    _ => fx.bcx.ins().iconst(types::I32, 0),
 +                };
 +                CValue::by_val(res_lane, res_lane_layout)
 +            });
 +        };
 +        "llvm.x86.sse2.pslli.d", (c a, o imm8) {
 +            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
 +            simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
 +                let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
 +                    imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
 +                    _ => fx.bcx.ins().iconst(types::I32, 0),
 +                };
 +                CValue::by_val(res_lane, res_lane_layout)
 +            });
 +        };
 +        "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
 +            // FIXME correctly handle the unalignment
 +            let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
 +            dest.write_cvalue(fx, a);
 +        };
++        "llvm.x86.addcarry.64", (v c_in, c a, c b) {
++            llvm_add_sub(
++                fx,
++                BinOp::Add,
++                ret,
++                c_in,
++                a,
++                b
++            );
++        };
++        "llvm.x86.subborrow.64", (v b_in, c a, c b) {
++            llvm_add_sub(
++                fx,
++                BinOp::Sub,
++                ret,
++                b_in,
++                a,
++                b
++            );
++        };
 +    }
 +
 +    if let Some((_, dest)) = destination {
 +        let ret_block = fx.get_block(dest);
 +        fx.bcx.ins().jump(ret_block, &[]);
 +    } else {
 +        trap_unreachable(fx, "[corruption] Diverging intrinsic returned.");
 +    }
 +}
 +
 +// llvm.x86.avx2.vperm2i128
 +// llvm.x86.ssse3.pshuf.b.128
 +// llvm.x86.avx2.pshuf.b
 +// llvm.x86.avx2.psrli.w
 +// llvm.x86.sse2.psrli.w
++
++fn llvm_add_sub<'tcx>(
++    fx: &mut FunctionCx<'_, '_, 'tcx>,
++    bin_op: BinOp,
++    ret: CPlace<'tcx>,
++    cb_in: Value,
++    a: CValue<'tcx>,
++    b: CValue<'tcx>,
++) {
++    assert_eq!(
++        a.layout().ty,
++        fx.tcx.types.u64,
++        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
++    );
++    assert_eq!(
++        b.layout().ty,
++        fx.tcx.types.u64,
++        "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
++    );
++
++    // c + carry -> c + first intermediate carry or borrow respectively
++    let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
++    let c = int0.value_field(fx, mir::Field::new(0));
++    let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
++
++    // c + carry -> c + second intermediate carry or borrow respectively
++    let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
++    let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
++    let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
++    let (c, cb1) = int1.load_scalar_pair(fx);
++
++    // carry0 | carry1 -> carry or borrow respectively
++    let cb_out = fx.bcx.ins().bor(cb0, cb1);
++
++    let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
++    let val = CValue::by_val_pair(cb_out, c, layout);
++    ret.write_cvalue(fx, val);
++}
index ebf98e8694b78f96f0e8dee0d25324256d7fcac7,0000000000000000000000000000000000000000..cb1cb3c74dbb5981317ceb4b7e677516d98ceb43
mode 100644,000000..100644
--- /dev/null
@@@ -1,302 -1,0 +1,306 @@@
- #![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
++#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
 +#![warn(rust_2018_idioms)]
 +#![warn(unused_lifetimes)]
 +#![warn(unreachable_pub)]
 +
 +extern crate snap;
 +#[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_mir;
 +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 rustc_codegen_ssa::traits::CodegenBackend;
 +use rustc_codegen_ssa::CodegenResults;
 +use rustc_errors::ErrorReported;
 +use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 +use rustc_middle::middle::cstore::EncodedMetadata;
 +use rustc_session::config::OutputFilenames;
 +use rustc_session::Session;
 +
 +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 backend;
 +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 metadata;
 +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 std::convert::{TryFrom, TryInto};
 +
 +    pub(crate) use rustc_span::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, 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, LayoutOf, 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,
 +    cached_context: Context,
 +    debug_context: Option<DebugContext<'tcx>>,
 +    unwind_context: UnwindContext,
 +}
 +
 +impl<'tcx> CodegenCx<'tcx> {
 +    fn new(
 +        tcx: TyCtxt<'tcx>,
 +        backend_config: BackendConfig,
 +        isa: &dyn TargetIsa,
 +        debug_info: bool,
 +    ) -> Self {
 +        assert_eq!(pointer_ty(tcx), isa.pointer_type());
 +
 +        let unwind_context =
 +            UnwindContext::new(tcx, 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(),
 +            cached_context: Context::new(),
 +            debug_context,
 +            unwind_context,
 +        }
 +    }
 +}
 +
 +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 {
 +            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,
 +    ) -> 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,
 +        );
 +
 +        Ok(())
 +    }
 +}
 +
 +fn target_triple(sess: &Session) -> target_lexicon::Triple {
 +    sess.target.llvm_target.parse().unwrap()
 +}
 +
 +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 variant = cranelift_codegen::isa::BackendVariant::MachInst;
 +
 +    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
 +        Some("native") => {
 +            let builder = cranelift_native::builder_with_options(variant, true).unwrap();
 +            builder
 +        }
 +        Some(value) => {
 +            let mut builder =
 +                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
 +            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_variant(target_triple, variant).unwrap();
-             // 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();
++                cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant).unwrap();
++            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 })
 +}
index 137fb5f77313cbae7d39c54291a383fa9e7e2357,0000000000000000000000000000000000000000..61033d85a12740a827d1f443c7e76e567dfd54e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,17 -1,0 +1,20 @@@
-     crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments);
 +//! Various optimizations specific to cg_clif
 +
++use cranelift_codegen::isa::TargetIsa;
++
 +use crate::prelude::*;
 +
 +pub(crate) mod peephole;
 +
 +pub(crate) fn optimize_function<'tcx>(
 +    tcx: TyCtxt<'tcx>,
++    isa: &dyn TargetIsa,
 +    instance: Instance<'tcx>,
 +    ctx: &mut Context,
 +    clif_comments: &mut crate::pretty_clif::CommentWriter,
 +) {
 +    // FIXME classify optimizations over opt levels once we have more
 +
++    crate::pretty_clif::write_clif_file(tcx, "preopt", isa, instance, &ctx, &*clif_comments);
 +    crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
 +}
index cd8c5b516083611ee316c93c816c523d29863fa3,0000000000000000000000000000000000000000..05db74745a1c0583bb5598e885ac04e8eda37c64
mode 100644,000000..100644
--- /dev/null
@@@ -1,283 -1,0 +1,284 @@@
-     isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
 +//! This module provides the [CommentWriter] which makes it possible
 +//! to add comments to the written cranelift ir.
 +//!
 +//! # Example
 +//!
 +//! ```clif
 +//! test compile
 +//! target x86_64
 +//!
 +//! function u0:0(i64, i64, i64) system_v {
 +//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
 +//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
 +//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
 +//!
 +//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
 +//! ; msg   loc.idx    param    pass mode            ssa flags  ty
 +//! ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
 +//! ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
 +//! ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
 +//!
 +//!     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
 +//!     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
 +//!     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
 +//!     sig0 = (i64, i64, i64) system_v
 +//!     sig1 = (i64, i64, i64) system_v
 +//!     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
 +//!
 +//! block0(v0: i64, v1: i64, v2: i64):
 +//!     v3 = stack_addr.i64 ss0
 +//!     v4 = stack_addr.i64 ss1
 +//!     store v2, v4
 +//!     v5 = stack_addr.i64 ss2
 +//!     jump block1
 +//!
 +//! block1:
 +//!     nop
 +//! ; _3 = &mut _1
 +//! ; _4 = _2
 +//!     v6 = load.i64 v4
 +//!     store v6, v5
 +//! ;
 +//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
 +//!     v7 = load.i64 v5
 +//!     call fn0(v0, v3, v7)
 +//!     jump block2
 +//!
 +//! block2:
 +//!     nop
 +//! ;
 +//! ; return
 +//!     return
 +//! }
 +//! ```
 +
 +use std::fmt;
 +use std::io::Write;
 +
 +use cranelift_codegen::{
 +    entity::SecondaryMap,
 +    ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
 +    write::{FuncWriter, PlainWriter},
 +};
 +
 +use rustc_middle::ty::layout::FnAbiExt;
 +use rustc_session::config::OutputType;
 +use rustc_target::abi::call::FnAbi;
 +
 +use crate::prelude::*;
 +
 +#[derive(Debug)]
 +pub(crate) struct CommentWriter {
 +    enabled: bool,
 +    global_comments: Vec<String>,
 +    entity_comments: FxHashMap<AnyEntity, String>,
 +}
 +
 +impl CommentWriter {
 +    pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
 +        let enabled = should_write_ir(tcx);
 +        let global_comments = if enabled {
 +            vec![
 +                format!("symbol {}", tcx.symbol_name(instance).name),
 +                format!("instance {:?}", instance),
 +                format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
 +                String::new(),
 +            ]
 +        } else {
 +            vec![]
 +        };
 +
 +        CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() }
 +    }
 +}
 +
 +impl CommentWriter {
 +    pub(crate) fn enabled(&self) -> bool {
 +        self.enabled
 +    }
 +
 +    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
 +        debug_assert!(self.enabled);
 +        self.global_comments.push(comment.into());
 +    }
 +
 +    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
 +        &mut self,
 +        entity: E,
 +        comment: S,
 +    ) {
 +        debug_assert!(self.enabled);
 +
 +        use std::collections::hash_map::Entry;
 +        match self.entity_comments.entry(entity.into()) {
 +            Entry::Occupied(mut occ) => {
 +                occ.get_mut().push('\n');
 +                occ.get_mut().push_str(comment.as_ref());
 +            }
 +            Entry::Vacant(vac) => {
 +                vac.insert(comment.into());
 +            }
 +        }
 +    }
 +}
 +
 +impl FuncWriter for &'_ CommentWriter {
 +    fn write_preamble(
 +        &mut self,
 +        w: &mut dyn fmt::Write,
 +        func: &Function,
 +        reg_info: Option<&isa::RegInfo>,
 +    ) -> Result<bool, fmt::Error> {
 +        for comment in &self.global_comments {
 +            if !comment.is_empty() {
 +                writeln!(w, "; {}", comment)?;
 +            } else {
 +                writeln!(w)?;
 +            }
 +        }
 +        if !self.global_comments.is_empty() {
 +            writeln!(w)?;
 +        }
 +
 +        self.super_preamble(w, func, reg_info)
 +    }
 +
 +    fn write_entity_definition(
 +        &mut self,
 +        w: &mut dyn fmt::Write,
 +        _func: &Function,
 +        entity: AnyEntity,
 +        value: &dyn fmt::Display,
 +    ) -> fmt::Result {
 +        write!(w, "    {} = {}", entity, value)?;
 +
 +        if let Some(comment) = self.entity_comments.get(&entity) {
 +            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
 +        } else {
 +            writeln!(w)
 +        }
 +    }
 +
 +    fn write_block_header(
 +        &mut self,
 +        w: &mut dyn fmt::Write,
 +        func: &Function,
 +        isa: Option<&dyn isa::TargetIsa>,
 +        block: Block,
 +        indent: usize,
 +    ) -> fmt::Result {
 +        PlainWriter.write_block_header(w, func, isa, block, indent)
 +    }
 +
 +    fn write_instruction(
 +        &mut self,
 +        w: &mut dyn fmt::Write,
 +        func: &Function,
 +        aliases: &SecondaryMap<Value, Vec<Value>>,
 +        isa: Option<&dyn isa::TargetIsa>,
 +        inst: Inst,
 +        indent: usize,
 +    ) -> fmt::Result {
 +        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
 +        if let Some(comment) = self.entity_comments.get(&inst.into()) {
 +            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl FunctionCx<'_, '_, '_> {
 +    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
 +        self.clif_comments.add_global_comment(comment);
 +    }
 +
 +    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
 +        &mut self,
 +        entity: E,
 +        comment: S,
 +    ) {
 +        self.clif_comments.add_comment(entity, comment);
 +    }
 +}
 +
 +pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
 +    tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly)
 +}
 +
 +pub(crate) fn write_ir_file(
 +    tcx: TyCtxt<'_>,
 +    name: impl FnOnce() -> String,
 +    write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
 +) {
 +    if !should_write_ir(tcx) {
 +        return;
 +    }
 +
 +    let clif_output_dir = tcx.output_filenames(()).with_extension("clif");
 +
 +    match std::fs::create_dir(&clif_output_dir) {
 +        Ok(()) => {}
 +        Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {}
 +        res @ Err(_) => res.unwrap(),
 +    }
 +
 +    let clif_file_name = clif_output_dir.join(name());
 +
 +    let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
 +    if let Err(err) = res {
 +        tcx.sess.warn(&format!("error writing ir file: {}", err));
 +    }
 +}
 +
 +pub(crate) fn write_clif_file<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    postfix: &str,
-             let value_ranges = isa
-                 .map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
++    isa: &dyn cranelift_codegen::isa::TargetIsa,
 +    instance: Instance<'tcx>,
 +    context: &cranelift_codegen::Context,
 +    mut clif_comments: &CommentWriter,
 +) {
 +    write_ir_file(
 +        tcx,
 +        || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
 +        |file| {
-                 &DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() },
 +            let mut clif = String::new();
 +            cranelift_codegen::write::decorate_function(
 +                &mut clif_comments,
 +                &mut clif,
 +                &context.func,
-             writeln!(file, "test compile")?;
-             writeln!(file, "set is_pic")?;
-             writeln!(file, "set enable_simd")?;
-             writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
++                &DisplayFunctionAnnotations { isa: Some(isa), value_ranges: None },
 +            )
 +            .unwrap();
 +
++            for flag in isa.flags().iter() {
++                writeln!(file, "set {}", flag)?;
++            }
++            write!(file, "target {}", isa.triple().architecture.to_string())?;
++            for isa_flag in isa.isa_flags().iter() {
++                write!(file, " {}", isa_flag)?;
++            }
++            writeln!(file, "\n")?;
 +            writeln!(file)?;
 +            file.write_all(clif.as_bytes())?;
 +            Ok(())
 +        },
 +    );
 +}
 +
 +impl fmt::Debug for FunctionCx<'_, '_, '_> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        writeln!(f, "{:?}", self.instance.substs)?;
 +        writeln!(f, "{:?}", self.local_map)?;
 +
 +        let mut clif = String::new();
 +        ::cranelift_codegen::write::decorate_function(
 +            &mut &self.clif_comments,
 +            &mut clif,
 +            &self.bcx.func,
 +            &DisplayFunctionAnnotations::default(),
 +        )
 +        .unwrap();
 +        writeln!(f, "\n{}", clif)
 +    }
 +}
index 12f7092d935a33732d858ddad42e2eff87f93b66,0000000000000000000000000000000000000000..4a5f9f133a2bbc8e2168fd4668036fb46f3d091f
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,79 @@@
- // FIXME dedup this logic between miri, cg_llvm and cg_clif
 +//! Codegen vtables and vtable accesses.
 +//!
 +//! See `rustc_codegen_ssa/src/meth.rs` for reference.
- use super::constant::pointer_for_allocation;
 +
++use crate::constant::data_id_for_alloc_id;
 +use crate::prelude::*;
-         (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
 +
 +fn vtable_memflags() -> MemFlags {
 +    let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
 +    flags.set_readonly(); // A vtable is always read-only.
 +    flags
 +}
 +
 +pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
 +    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
 +    fx.bcx.ins().load(
 +        pointer_ty(fx.tcx),
 +        vtable_memflags(),
 +        vtable,
 +        (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
 +    )
 +}
 +
 +pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
 +    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
 +    fx.bcx.ins().load(
 +        pointer_ty(fx.tcx),
 +        vtable_memflags(),
 +        vtable,
 +        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
 +    )
 +}
 +
 +pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
 +    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
 +    fx.bcx.ins().load(
 +        pointer_ty(fx.tcx),
 +        vtable_memflags(),
 +        vtable,
-     let vtable_ptr = if let Some(vtable_ptr) = fx.vtables.get(&(ty, trait_ref)) {
-         *vtable_ptr
-     } else {
-         let vtable_alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
-         let vtable_allocation = fx.tcx.global_alloc(vtable_alloc_id).unwrap_memory();
-         let vtable_ptr = pointer_for_allocation(fx, vtable_allocation);
-         fx.vtables.insert((ty, trait_ref), vtable_ptr);
-         vtable_ptr
-     };
-     vtable_ptr.get_addr(fx)
++        (ty::COMMON_VTABLE_ENTRIES_ALIGN * usize_size) as i32,
 +    )
 +}
 +
 +pub(crate) fn get_ptr_and_method_ref<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    arg: CValue<'tcx>,
 +    idx: usize,
 +) -> (Value, Value) {
 +    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
 +        arg.load_scalar_pair(fx)
 +    } else {
 +        let (ptr, vtable) = arg.try_to_ptr().unwrap();
 +        (ptr.get_addr(fx), vtable.unwrap())
 +    };
 +
 +    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
 +    let func_ref = fx.bcx.ins().load(
 +        pointer_ty(fx.tcx),
 +        vtable_memflags(),
 +        vtable,
 +        (idx * usize_size as usize) as i32,
 +    );
 +    (ptr, func_ref)
 +}
 +
 +pub(crate) fn get_vtable<'tcx>(
 +    fx: &mut FunctionCx<'_, '_, 'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 +) -> Value {
++    let alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
++    let data_id =
++        data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not);
++    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
++    if fx.clif_comments.enabled() {
++        fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id));
++    }
++    fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
 +}
index e222adc7b80582ec7169a0c65f2fd9d34af00341,0000000000000000000000000000000000000000..a10924628bb0eba9350b56f5603ead5b068b75f4
mode 100755,000000..100755
--- /dev/null
@@@ -1,13 -1,0 +1,13 @@@
- ./build.sh --sysroot none "$@"
 +#!/usr/bin/env bash
 +set -e
 +
- ./build.sh "$@"
++./y.rs build --sysroot none "$@"
 +
 +rm -r target/out || true
 +
 +scripts/tests.sh no_sysroot
 +
++./y.rs build "$@"
 +
 +scripts/tests.sh base_sysroot
 +scripts/tests.sh extended_sysroot
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..43937588b481da1005f68642316a3b2e3fa62c4c
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,153 @@@
++#!/usr/bin/env bash
++#![allow()] /*This line is ignored by bash
++# This block is ignored by rustc
++set -e
++echo "[BUILD] y.rs" 1>&2
++rustc $0 -o ${0/.rs/.bin} -g
++exec ${0/.rs/.bin} $@
++*/
++
++//! The build system for cg_clif
++//!
++//! # Manual compilation
++//!
++//! If your system doesn't support shell scripts you can manually compile and run this file using
++//! for example:
++//!
++//! ```shell
++//! $ rustc y.rs -o build/y.bin
++//! $ build/y.bin
++//! ```
++//!
++//! # Naming
++//!
++//! The name `y.rs` was chosen to not conflict with rustc's `x.py`.
++
++use std::env;
++use std::path::PathBuf;
++use std::process;
++
++#[path = "build_system/build_backend.rs"]
++mod build_backend;
++#[path = "build_system/build_sysroot.rs"]
++mod build_sysroot;
++#[path = "build_system/config.rs"]
++mod config;
++#[path = "build_system/prepare.rs"]
++mod prepare;
++#[path = "build_system/rustc_info.rs"]
++mod rustc_info;
++#[path = "build_system/utils.rs"]
++mod utils;
++
++fn usage() {
++    eprintln!("Usage:");
++    eprintln!("  ./y.rs prepare");
++    eprintln!("  ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR]");
++}
++
++macro_rules! arg_error {
++    ($($err:tt)*) => {{
++        eprintln!($($err)*);
++        usage();
++        std::process::exit(1);
++    }};
++}
++
++enum Command {
++    Build,
++}
++
++#[derive(Copy, Clone)]
++enum SysrootKind {
++    None,
++    Clif,
++    Llvm,
++}
++
++fn main() {
++    env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
++    env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
++    // The target dir is expected in the default location. Guard against the user changing it.
++    env::set_var("CARGO_TARGET_DIR", "target");
++
++    let mut args = env::args().skip(1);
++    let command = match args.next().as_deref() {
++        Some("prepare") => {
++            if args.next().is_some() {
++                arg_error!("./x.rs prepare doesn't expect arguments");
++            }
++            prepare::prepare();
++            process::exit(0);
++        }
++        Some("build") => Command::Build,
++        Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
++        Some(command) => arg_error!("Unknown command {}", command),
++        None => {
++            usage();
++            process::exit(0);
++        }
++    };
++
++    let mut target_dir = PathBuf::from("build");
++    let mut channel = "release";
++    let mut sysroot_kind = SysrootKind::Clif;
++    while let Some(arg) = args.next().as_deref() {
++        match arg {
++            "--target-dir" => {
++                target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
++                    arg_error!("--target-dir requires argument");
++                }))
++            }
++            "--debug" => channel = "debug",
++            "--sysroot" => {
++                sysroot_kind = match args.next().as_deref() {
++                    Some("none") => SysrootKind::None,
++                    Some("clif") => SysrootKind::Clif,
++                    Some("llvm") => SysrootKind::Llvm,
++                    Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
++                    None => arg_error!("--sysroot requires argument"),
++                }
++            }
++            flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
++            arg => arg_error!("Unexpected argument {}", arg),
++        }
++    }
++
++    let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
++        host_triple
++    } else if let Some(host_triple) = crate::config::get_value("host") {
++        host_triple
++    } else {
++        rustc_info::get_host_triple()
++    };
++    let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
++        if target_triple != "" {
++            target_triple
++        } else {
++            host_triple.clone() // Empty target triple can happen on GHA
++        }
++    } else if let Some(target_triple) = crate::config::get_value("target") {
++        target_triple
++    } else {
++        host_triple.clone()
++    };
++
++    if target_triple.ends_with("-msvc") {
++        eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
++        eprintln!("Switch to the MinGW toolchain for Windows support.");
++        eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
++        eprintln!("set the global default target to MinGW");
++        process::exit(1);
++    }
++
++    let cg_clif_build_dir = build_backend::build_backend(channel, &host_triple);
++    build_sysroot::build_sysroot(
++        channel,
++        sysroot_kind,
++        &target_dir,
++        cg_clif_build_dir,
++        &host_triple,
++        &target_triple,
++    );
++}