mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-02 18:27:37 +00:00
Merge commit 'fda0bb9588912a3e0606e880ca9f6e913cf8a5a4' into subtree-update_cg_gcc_2025-06-18
This commit is contained in:
parent
265f4a7b63
commit
efb79975f6
27
.cspell.json
Normal file
27
.cspell.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"allowCompoundWords": true,
|
||||
"dictionaries": ["cpp", "rust-extra", "rustc_codegen_gcc"],
|
||||
"dictionaryDefinitions": [
|
||||
{
|
||||
"name": "rust-extra",
|
||||
"path": "tools/cspell_dicts/rust.txt",
|
||||
"addWords": true
|
||||
},
|
||||
{
|
||||
"name": "rustc_codegen_gcc",
|
||||
"path": "tools/cspell_dicts/rustc_codegen_gcc.txt",
|
||||
"addWords": true
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"src/**/*.rs"
|
||||
],
|
||||
"ignorePaths": [
|
||||
"src/intrinsic/archs.rs",
|
||||
"src/intrinsic/llvm.rs"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"/(FIXME|NOTE|TODO)\\([^)]+\\)/",
|
||||
"__builtin_\\w*"
|
||||
]
|
||||
}
|
43
.github/workflows/ci.yml
vendored
43
.github/workflows/ci.yml
vendored
@ -12,6 +12,8 @@ permissions:
|
||||
env:
|
||||
# Enable backtraces for easier debugging
|
||||
RUST_BACKTRACE: 1
|
||||
# For the run-make tests.
|
||||
LLVM_BIN_DIR: /usr/bin
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -48,7 +50,7 @@ jobs:
|
||||
|
||||
- name: Install packages
|
||||
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests.
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools llvm
|
||||
|
||||
- name: Install rustfmt & clippy
|
||||
run: rustup component add rustfmt clippy
|
||||
@ -61,11 +63,15 @@ jobs:
|
||||
sudo dpkg --force-overwrite -i ${{ matrix.libgccjit_version.gcc }}
|
||||
echo 'gcc-path = "/usr/lib/"' > config.toml
|
||||
|
||||
# Some run-make tests fail if we use our forked GCC because it doesn't
|
||||
# bundle libstdc++, so we switch to gcc-14 to have a GCC that has
|
||||
# libstdc++.
|
||||
- name: Set default GCC to gcc-14
|
||||
run: sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 30
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
#- name: Cache rust repository
|
||||
## We only clone the rust repository for rustc tests
|
||||
@ -76,12 +82,22 @@ jobs:
|
||||
#path: rust
|
||||
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}
|
||||
|
||||
- name: Prepare
|
||||
run: ./y.sh prepare --only-libcore
|
||||
|
||||
- name: Check formatting
|
||||
run: ./y.sh fmt --check
|
||||
|
||||
- name: clippy
|
||||
run: |
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo clippy --all-targets --no-default-features -- -D warnings
|
||||
cargo clippy --manifest-path build_system/Cargo.toml --all-targets -- -D warnings
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
./y.sh build --sysroot
|
||||
./y.sh test --mini-tests
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
|
||||
- name: Run y.sh cargo build
|
||||
run: |
|
||||
@ -101,20 +117,19 @@ jobs:
|
||||
run: |
|
||||
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
||||
- name: Check formatting
|
||||
run: ./y.sh fmt --check
|
||||
|
||||
- name: clippy
|
||||
run: |
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo clippy --all-targets --features master -- -D warnings
|
||||
|
||||
duplicates:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: python tools/check_intrinsics_duplicates.py
|
||||
|
||||
spell_check:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@v1.32.0
|
||||
- uses: streetsidesoftware/cspell-action@v7
|
||||
|
||||
build_system:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
|
4
.github/workflows/failures.yml
vendored
4
.github/workflows/failures.yml
vendored
@ -66,8 +66,8 @@ jobs:
|
||||
run: |
|
||||
sudo dpkg --force-overwrite -i gcc-15.deb
|
||||
echo 'gcc-path = "/usr/lib"' > config.toml
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
|
6
.github/workflows/m68k.yml
vendored
6
.github/workflows/m68k.yml
vendored
@ -65,8 +65,8 @@ jobs:
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
|
||||
|
||||
#- name: Cache rust repository
|
||||
## We only clone the rust repository for rustc tests
|
||||
@ -95,7 +95,7 @@ jobs:
|
||||
./y.sh prepare --only-libcore --cross
|
||||
./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
|
||||
./y.sh test --mini-tests
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests
|
||||
./y.sh clean all
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@ -12,6 +12,8 @@ permissions:
|
||||
env:
|
||||
# Enable backtraces for easier debugging
|
||||
RUST_BACKTRACE: 1
|
||||
# For the run-make tests.
|
||||
LLVM_BIN_DIR: /usr/bin
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -36,7 +38,8 @@ jobs:
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install packages
|
||||
run: sudo apt-get install ninja-build ripgrep
|
||||
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for run-make tests.
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools llvm
|
||||
|
||||
- name: Download artifact
|
||||
run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
|
||||
@ -46,18 +49,21 @@ jobs:
|
||||
sudo dpkg --force-overwrite -i gcc-15.deb
|
||||
echo 'gcc-path = "/usr/lib/"' > config.toml
|
||||
|
||||
# Some run-make tests fail if we use our forked GCC because it doesn't
|
||||
# bundle libstdc++, so we switch to gcc-14 to have a GCC that has
|
||||
# libstdc++.
|
||||
- name: Set default GCC to gcc-14
|
||||
run: sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 30
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
|
||||
./y.sh test --mini-tests
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
./y.sh clean all
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
2
.github/workflows/stdarch.yml
vendored
2
.github/workflows/stdarch.yml
vendored
@ -90,7 +90,7 @@ jobs:
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
|
||||
- name: Run stdarch tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -19,4 +19,5 @@ tools/llvmint-2
|
||||
llvm
|
||||
build_system/target
|
||||
config.toml
|
||||
build
|
||||
build
|
||||
rustlantis
|
@ -33,7 +33,7 @@ To run specific tests, use appropriate flags such as:
|
||||
|
||||
- `./y.sh test --test-libcore`
|
||||
- `./y.sh test --std-tests`
|
||||
- `cargo test -- <name of test>`
|
||||
- `./y.sh test --cargo-tests -- <name of test>`
|
||||
|
||||
Additionally, you can run the tests of `libgccjit`:
|
||||
|
||||
|
50
Cargo.lock
50
Cargo.lock
@ -81,6 +81,18 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
@ -111,9 +123,9 @@ checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@ -137,6 +149,12 @@ version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
@ -166,9 +184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@ -188,12 +206,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
@ -242,6 +260,15 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -345,3 +372,12 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
@ -31,7 +31,7 @@ gccjit = "2.7"
|
||||
[dev-dependencies]
|
||||
boml = "0.3.1"
|
||||
lang_tester = "0.8.0"
|
||||
tempfile = "3.7.1"
|
||||
tempfile = "3.20"
|
||||
|
||||
[profile.dev]
|
||||
# By compiling dependencies with optimizations, performing tests gets much faster.
|
||||
|
9
_typos.toml
Normal file
9
_typos.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[default.extend-words]
|
||||
ba = "ba"
|
||||
hsa = "hsa"
|
||||
olt = "olt"
|
||||
seh = "seh"
|
||||
typ = "typ"
|
||||
|
||||
[files]
|
||||
extend-exclude = ["src/intrinsic/archs.rs"]
|
@ -1,24 +1,24 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli 0.29.0",
|
||||
"gimli",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
@ -33,10 +33,21 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
name = "alloctests"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -50,10 +61,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.118"
|
||||
version = "0.1.160"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5"
|
||||
checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
@ -61,11 +73,19 @@ dependencies = [
|
||||
name = "core"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "coretests"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlmalloc"
|
||||
version = "0.2.6"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d"
|
||||
checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
@ -97,20 +117,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
@ -119,11 +128,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
@ -131,9 +139,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
@ -142,9 +150,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -161,11 +169,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"adler2",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
@ -173,9 +181,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.3"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"memchr",
|
||||
@ -188,7 +196,6 @@ name = "panic_abort"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"libc",
|
||||
@ -211,14 +218,22 @@ name = "proc_macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core",
|
||||
"rustc-literal-escaper",
|
||||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiler_builtins"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "4.5.0"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
@ -226,15 +241,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "r-efi-alloc"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
|
||||
checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"r-efi",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
@ -245,6 +284,15 @@ dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-literal-escaper"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-alloc"
|
||||
version = "1.99.0"
|
||||
@ -266,6 +314,12 @@ dependencies = [
|
||||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "std"
|
||||
version = "0.0.0"
|
||||
@ -286,10 +340,13 @@ dependencies = [
|
||||
"panic_unwind",
|
||||
"r-efi",
|
||||
"r-efi-alloc",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"rustc-demangle",
|
||||
"std_detect",
|
||||
"unwind",
|
||||
"wasi",
|
||||
"windows-targets 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -298,6 +355,7 @@ version = "0.1.5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -306,10 +364,8 @@ dependencies = [
|
||||
name = "sysroot"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"proc_macro",
|
||||
"profiler_builtins",
|
||||
"std",
|
||||
"test",
|
||||
]
|
||||
@ -326,9 +382,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
@ -348,12 +404,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unwinding"
|
||||
version = "0.2.2"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882"
|
||||
checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli 0.30.0",
|
||||
"gimli",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
@ -370,13 +426,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
@ -33,7 +33,7 @@ impl BuildArg {
|
||||
}
|
||||
arg => {
|
||||
if !build_arg.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown argument `{}`", arg));
|
||||
return Err(format!("Unknown argument `{arg}`"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,14 +105,14 @@ pub fn create_build_sysroot_content(start_dir: &Path) -> Result<(), String> {
|
||||
if !start_dir.is_dir() {
|
||||
create_dir(start_dir)?;
|
||||
}
|
||||
copy_file("build_system/build_sysroot/Cargo.toml", &start_dir.join("Cargo.toml"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.lock", &start_dir.join("Cargo.lock"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.toml", start_dir.join("Cargo.toml"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.lock", start_dir.join("Cargo.lock"))?;
|
||||
|
||||
let src_dir = start_dir.join("src");
|
||||
if !src_dir.is_dir() {
|
||||
create_dir(&src_dir)?;
|
||||
}
|
||||
copy_file("build_system/build_sysroot/lib.rs", &start_dir.join("src/lib.rs"))
|
||||
copy_file("build_system/build_sysroot/lib.rs", start_dir.join("src/lib.rs"))
|
||||
}
|
||||
|
||||
pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Result<(), String> {
|
||||
@ -169,7 +169,7 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
|
||||
run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
|
||||
};
|
||||
walk_dir(
|
||||
start_dir.join(&format!("target/{}/{}/deps", config.target_triple, channel)),
|
||||
start_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)),
|
||||
&mut copier.clone(),
|
||||
&mut copier,
|
||||
false,
|
||||
|
@ -17,12 +17,12 @@ enum CleanArg {
|
||||
impl CleanArg {
|
||||
fn new() -> Result<Self, String> {
|
||||
// We skip the binary and the "clean" option.
|
||||
for arg in std::env::args().skip(2) {
|
||||
if let Some(arg) = std::env::args().nth(2) {
|
||||
return match arg.as_str() {
|
||||
"all" => Ok(Self::All),
|
||||
"ui-tests" => Ok(Self::UiTests),
|
||||
"--help" => Ok(Self::Help),
|
||||
a => Err(format!("Unknown argument `{}`", a)),
|
||||
a => Err(format!("Unknown argument `{a}`")),
|
||||
};
|
||||
}
|
||||
Ok(Self::default())
|
||||
|
@ -43,7 +43,7 @@ impl Args {
|
||||
}
|
||||
arg => {
|
||||
if !command_args.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown option {}", arg));
|
||||
return Err(format!("Unknown option {arg}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ impl Args {
|
||||
Some(p) => p.into(),
|
||||
None => PathBuf::from("./gcc"),
|
||||
};
|
||||
return Ok(Some(command_args));
|
||||
Ok(Some(command_args))
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ pub fn run() -> Result<(), String> {
|
||||
let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?;
|
||||
if result.ran_clone {
|
||||
let gcc_commit = args.config_info.get_gcc_commit()?;
|
||||
println!("Checking out GCC commit `{}`...", gcc_commit);
|
||||
println!("Checking out GCC commit `{gcc_commit}`...");
|
||||
run_command_with_output(
|
||||
&[&"git", &"checkout", &gcc_commit],
|
||||
Some(Path::new(&result.repo_dir)),
|
||||
|
@ -66,7 +66,7 @@ impl ConfigFile {
|
||||
"Expected a boolean for `download-gccjit`",
|
||||
);
|
||||
}
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{key}`")),
|
||||
}
|
||||
}
|
||||
match (config.gcc_path.as_mut(), config.download_gccjit) {
|
||||
@ -86,9 +86,7 @@ impl ConfigFile {
|
||||
let path = Path::new(gcc_path);
|
||||
*gcc_path = path
|
||||
.canonicalize()
|
||||
.map_err(|err| {
|
||||
format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err)
|
||||
})?
|
||||
.map_err(|err| format!("Failed to get absolute path of `{gcc_path}`: {err:?}"))?
|
||||
.display()
|
||||
.to_string();
|
||||
}
|
||||
@ -175,7 +173,7 @@ impl ConfigInfo {
|
||||
"--sysroot-panic-abort" => self.sysroot_panic_abort = true,
|
||||
"--gcc-path" => match args.next() {
|
||||
Some(arg) if !arg.is_empty() => {
|
||||
self.gcc_path = Some(arg.into());
|
||||
self.gcc_path = Some(arg);
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected a value after `--gcc-path`, found nothing".to_string());
|
||||
@ -244,7 +242,7 @@ impl ConfigInfo {
|
||||
let libgccjit_so = output_dir.join(libgccjit_so_name);
|
||||
if !libgccjit_so.is_file() && !self.no_download {
|
||||
// Download time!
|
||||
let tempfile_name = format!("{}.download", libgccjit_so_name);
|
||||
let tempfile_name = format!("{libgccjit_so_name}.download");
|
||||
let tempfile = output_dir.join(&tempfile_name);
|
||||
let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok();
|
||||
|
||||
@ -262,14 +260,14 @@ impl ConfigInfo {
|
||||
)
|
||||
})?;
|
||||
|
||||
println!("Downloaded libgccjit.so version {} successfully!", commit);
|
||||
println!("Downloaded libgccjit.so version {commit} successfully!");
|
||||
// We need to create a link named `libgccjit.so.0` because that's what the linker is
|
||||
// looking for.
|
||||
create_symlink(&libgccjit_so, output_dir.join(&format!("{}.0", libgccjit_so_name)))?;
|
||||
create_symlink(&libgccjit_so, output_dir.join(format!("{libgccjit_so_name}.0")))?;
|
||||
}
|
||||
|
||||
let gcc_path = output_dir.display().to_string();
|
||||
println!("Using `{}` as path for libgccjit", gcc_path);
|
||||
println!("Using `{gcc_path}` as path for libgccjit");
|
||||
self.gcc_path = Some(gcc_path);
|
||||
Ok(())
|
||||
}
|
||||
@ -286,8 +284,7 @@ impl ConfigInfo {
|
||||
// since we already have everything we need.
|
||||
if let Some(gcc_path) = &self.gcc_path {
|
||||
println!(
|
||||
"`--gcc-path` was provided, ignoring config file. Using `{}` as path for libgccjit",
|
||||
gcc_path
|
||||
"`--gcc-path` was provided, ignoring config file. Using `{gcc_path}` as path for libgccjit"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
@ -343,7 +340,7 @@ impl ConfigInfo {
|
||||
self.dylib_ext = match os_name.as_str() {
|
||||
"Linux" => "so",
|
||||
"Darwin" => "dylib",
|
||||
os => return Err(format!("unsupported OS `{}`", os)),
|
||||
os => return Err(format!("unsupported OS `{os}`")),
|
||||
}
|
||||
.to_string();
|
||||
let rustc = match env.get("RUSTC") {
|
||||
@ -355,10 +352,10 @@ impl ConfigInfo {
|
||||
None => return Err("no host found".to_string()),
|
||||
};
|
||||
|
||||
if self.target_triple.is_empty() {
|
||||
if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") {
|
||||
self.target_triple = overwrite.clone();
|
||||
}
|
||||
if self.target_triple.is_empty()
|
||||
&& let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE")
|
||||
{
|
||||
self.target_triple = overwrite.clone();
|
||||
}
|
||||
if self.target_triple.is_empty() {
|
||||
self.target_triple = self.host_triple.clone();
|
||||
@ -378,7 +375,7 @@ impl ConfigInfo {
|
||||
}
|
||||
|
||||
let current_dir =
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {error:?}"))?;
|
||||
let channel = if self.channel == Channel::Release {
|
||||
"release"
|
||||
} else if let Some(channel) = env.get("CHANNEL") {
|
||||
@ -391,15 +388,15 @@ impl ConfigInfo {
|
||||
self.cg_backend_path = current_dir
|
||||
.join("target")
|
||||
.join(channel)
|
||||
.join(&format!("librustc_codegen_gcc.{}", self.dylib_ext))
|
||||
.join(format!("librustc_codegen_gcc.{}", self.dylib_ext))
|
||||
.display()
|
||||
.to_string();
|
||||
self.sysroot_path =
|
||||
current_dir.join(&get_sysroot_dir()).join("sysroot").display().to_string();
|
||||
current_dir.join(get_sysroot_dir()).join("sysroot").display().to_string();
|
||||
if let Some(backend) = &self.backend {
|
||||
// This option is only used in the rust compiler testsuite. The sysroot is handled
|
||||
// by its build system directly so no need to set it ourselves.
|
||||
rustflags.push(format!("-Zcodegen-backend={}", backend));
|
||||
rustflags.push(format!("-Zcodegen-backend={backend}"));
|
||||
} else {
|
||||
rustflags.extend_from_slice(&[
|
||||
"--sysroot".to_string(),
|
||||
@ -412,10 +409,10 @@ impl ConfigInfo {
|
||||
// We have a different environment variable than RUSTFLAGS to make sure those flags are
|
||||
// only sent to rustc_codegen_gcc and not the LLVM backend.
|
||||
if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&cg_rustflags)?);
|
||||
rustflags.extend_from_slice(&split_args(cg_rustflags)?);
|
||||
}
|
||||
if let Some(test_flags) = env.get("TEST_FLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&test_flags)?);
|
||||
rustflags.extend_from_slice(&split_args(test_flags)?);
|
||||
}
|
||||
|
||||
if let Some(linker) = linker {
|
||||
@ -438,8 +435,8 @@ impl ConfigInfo {
|
||||
env.insert("RUSTC_LOG".to_string(), "warn".to_string());
|
||||
|
||||
let sysroot = current_dir
|
||||
.join(&get_sysroot_dir())
|
||||
.join(&format!("sysroot/lib/rustlib/{}/lib", self.target_triple));
|
||||
.join(get_sysroot_dir())
|
||||
.join(format!("sysroot/lib/rustlib/{}/lib", self.target_triple));
|
||||
let ld_library_path = format!(
|
||||
"{target}:{sysroot}:{gcc_path}",
|
||||
target = self.cargo_target_dir,
|
||||
@ -505,7 +502,7 @@ fn download_gccjit(
|
||||
with_progress_bar: bool,
|
||||
) -> Result<(), String> {
|
||||
let url = if std::env::consts::OS == "linux" && std::env::consts::ARCH == "x86_64" {
|
||||
format!("https://github.com/rust-lang/gcc/releases/download/master-{}/libgccjit.so", commit)
|
||||
format!("https://github.com/rust-lang/gcc/releases/download/master-{commit}/libgccjit.so")
|
||||
} else {
|
||||
eprintln!(
|
||||
"\
|
||||
@ -518,7 +515,7 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
||||
));
|
||||
};
|
||||
|
||||
println!("Downloading `{}`...", url);
|
||||
println!("Downloading `{url}`...");
|
||||
|
||||
// Try curl. If that fails and we are on windows, fallback to PowerShell.
|
||||
let mut ret = run_command_with_output(
|
||||
@ -538,7 +535,7 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
||||
if with_progress_bar { &"--progress-bar" } else { &"-s" },
|
||||
&url.as_str(),
|
||||
],
|
||||
Some(&output_dir),
|
||||
Some(output_dir),
|
||||
);
|
||||
if ret.is_err() && cfg!(windows) {
|
||||
eprintln!("Fallback to PowerShell");
|
||||
@ -549,12 +546,11 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
||||
&"-Command",
|
||||
&"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
|
||||
&format!(
|
||||
"(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
|
||||
url, tempfile_name,
|
||||
"(New-Object System.Net.WebClient).DownloadFile('{url}', '{tempfile_name}')",
|
||||
)
|
||||
.as_str(),
|
||||
],
|
||||
Some(&output_dir),
|
||||
Some(output_dir),
|
||||
);
|
||||
}
|
||||
ret
|
||||
|
@ -16,21 +16,21 @@ fn show_usage() {
|
||||
pub fn run() -> Result<(), String> {
|
||||
let mut check = false;
|
||||
// We skip binary name and the `info` command.
|
||||
let mut args = std::env::args().skip(2);
|
||||
while let Some(arg) = args.next() {
|
||||
let args = std::env::args().skip(2);
|
||||
for arg in args {
|
||||
match arg.as_str() {
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(());
|
||||
}
|
||||
"--check" => check = true,
|
||||
_ => return Err(format!("Unknown option {}", arg)),
|
||||
_ => return Err(format!("Unknown option {arg}")),
|
||||
}
|
||||
}
|
||||
|
||||
let cmd: &[&dyn AsRef<OsStr>] =
|
||||
if check { &[&"cargo", &"fmt", &"--check"] } else { &[&"cargo", &"fmt"] };
|
||||
|
||||
run_command_with_output(cmd, Some(&Path::new(".")))?;
|
||||
run_command_with_output(cmd, Some(&Path::new("build_system")))
|
||||
run_command_with_output(cmd, Some(Path::new(".")))?;
|
||||
run_command_with_output(cmd, Some(Path::new("build_system")))
|
||||
}
|
||||
|
289
build_system/src/fuzz.rs
Normal file
289
build_system/src/fuzz.rs
Normal file
@ -0,0 +1,289 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
mod reduce;
|
||||
|
||||
use crate::utils::run_command_with_output;
|
||||
|
||||
fn show_usage() {
|
||||
println!(
|
||||
r#"
|
||||
`fuzz` command help:
|
||||
--reduce : Reduces a file generated by rustlantis
|
||||
--help : Show this help
|
||||
--start : Start of the fuzzed range
|
||||
--count : The number of cases to fuzz
|
||||
-j --jobs : The number of threads to use during fuzzing"#
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run() -> Result<(), String> {
|
||||
// We skip binary name and the `fuzz` command.
|
||||
let mut args = std::env::args().skip(2);
|
||||
let mut start = 0;
|
||||
let mut count = 100;
|
||||
let mut threads =
|
||||
std::thread::available_parallelism().map(|threads| threads.get()).unwrap_or(1);
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--reduce" => {
|
||||
let Some(path) = args.next() else {
|
||||
return Err("--reduce must be provided with a path".into());
|
||||
};
|
||||
if !std::fs::exists(&path).unwrap_or(false) {
|
||||
return Err("--reduce must be provided with a valid path".into());
|
||||
}
|
||||
reduce::reduce(&path);
|
||||
return Ok(());
|
||||
}
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(());
|
||||
}
|
||||
"--start" => {
|
||||
start =
|
||||
str::parse(&args.next().ok_or_else(|| "Fuzz start not provided!".to_string())?)
|
||||
.map_err(|err| (format!("Fuzz start not a number {err:?}!")))?;
|
||||
}
|
||||
"--count" => {
|
||||
count =
|
||||
str::parse(&args.next().ok_or_else(|| "Fuzz count not provided!".to_string())?)
|
||||
.map_err(|err| (format!("Fuzz count not a number {err:?}!")))?;
|
||||
}
|
||||
"-j" | "--jobs" => {
|
||||
threads = str::parse(
|
||||
&args.next().ok_or_else(|| "Fuzz thread count not provided!".to_string())?,
|
||||
)
|
||||
.map_err(|err| (format!("Fuzz thread count not a number {err:?}!")))?;
|
||||
}
|
||||
_ => return Err(format!("Unknown option {arg}")),
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that we have a cloned version of rustlantis on hand.
|
||||
crate::utils::git_clone(
|
||||
"https://github.com/cbeuw/rustlantis.git",
|
||||
Some("clones/rustlantis".as_ref()),
|
||||
true,
|
||||
)
|
||||
.map_err(|err| (format!("Git clone failed with message: {err:?}!")))?;
|
||||
|
||||
// Ensure that we are on the newest rustlantis commit.
|
||||
let cmd: &[&dyn AsRef<OsStr>] = &[&"git", &"pull", &"origin"];
|
||||
run_command_with_output(cmd, Some(Path::new("clones/rustlantis")))?;
|
||||
|
||||
// Build the release version of rustlantis
|
||||
let cmd: &[&dyn AsRef<OsStr>] = &[&"cargo", &"build", &"--release"];
|
||||
run_command_with_output(cmd, Some(Path::new("clones/rustlantis")))?;
|
||||
// Fuzz a given range
|
||||
fuzz_range(start, start + count, threads);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fuzzes a range `start..end` with `threads`.
|
||||
fn fuzz_range(start: u64, end: u64, threads: usize) {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
// Total amount of files to fuzz
|
||||
let total = end - start;
|
||||
// Currently fuzzed element
|
||||
let start = Arc::new(AtomicU64::new(start));
|
||||
// Count time during fuzzing
|
||||
let start_time = Instant::now();
|
||||
let mut workers = Vec::with_capacity(threads);
|
||||
// Spawn `threads`..
|
||||
for _ in 0..threads {
|
||||
let start = start.clone();
|
||||
// .. which each will ..
|
||||
workers.push(std::thread::spawn(move || {
|
||||
// ... grab the next fuzz seed ...
|
||||
while start.load(Ordering::Relaxed) < end {
|
||||
let next = start.fetch_add(1, Ordering::Relaxed);
|
||||
// .. test that seed .
|
||||
match test(next, false) {
|
||||
Err(err) => {
|
||||
// If the test failed at compile-time...
|
||||
println!("test({next}) failed because {err:?}");
|
||||
// ... copy that file to the directory `target/fuzz/compiletime_error`...
|
||||
let mut out_path: std::path::PathBuf =
|
||||
"target/fuzz/compiletime_error".into();
|
||||
std::fs::create_dir_all(&out_path).unwrap();
|
||||
// .. into a file named `fuzz{seed}.rs`.
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(err, out_path).unwrap();
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
// If the test failed at run-time...
|
||||
println!("The LLVM and GCC results don't match for {err:?}");
|
||||
// ... generate a new file, which prints temporaries(instead of hashing them)...
|
||||
let mut out_path: std::path::PathBuf = "target/fuzz/runtime_error".into();
|
||||
std::fs::create_dir_all(&out_path).unwrap();
|
||||
let Ok(Err(tmp_print_err)) = test(next, true) else {
|
||||
// ... if that file does not reproduce the issue...
|
||||
// ... save the original sample in a file named `fuzz{seed}.rs`...
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(err, &out_path).unwrap();
|
||||
continue;
|
||||
};
|
||||
// ... if that new file still produces the issue, copy it to `fuzz{seed}.rs`..
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(tmp_print_err, &out_path).unwrap();
|
||||
// ... and start reducing it, using some properties of `rustlantis` to speed up the process.
|
||||
reduce::reduce(&out_path);
|
||||
}
|
||||
// If the test passed, do nothing
|
||||
Ok(Ok(())) => (),
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
// The "manager" thread loop.
|
||||
while start.load(Ordering::Relaxed) < end || !workers.iter().all(|t| t.is_finished()) {
|
||||
// Every 500 ms...
|
||||
let five_hundred_millis = Duration::from_millis(500);
|
||||
std::thread::sleep(five_hundred_millis);
|
||||
// ... calculate the remaining fuzz iters ...
|
||||
let remaining = end - start.load(Ordering::Relaxed);
|
||||
// ... fix the count(the start counter counts the cases that
|
||||
// begun fuzzing, and not only the ones that are done)...
|
||||
let fuzzed = (total - remaining).saturating_sub(threads as u64);
|
||||
// ... and the fuzz speed ...
|
||||
let iter_per_sec = fuzzed as f64 / start_time.elapsed().as_secs_f64();
|
||||
// .. and use them to display fuzzing stats.
|
||||
println!(
|
||||
"fuzzed {fuzzed} cases({}%), at rate {iter_per_sec} iter/s, remaining ~{}s",
|
||||
(100 * fuzzed) as f64 / total as f64,
|
||||
(remaining as f64) / iter_per_sec
|
||||
)
|
||||
}
|
||||
drop(workers);
|
||||
}
|
||||
|
||||
/// Builds & runs a file with LLVM.
|
||||
fn debug_llvm(path: &std::path::Path) -> Result<Vec<u8>, String> {
|
||||
// Build a file named `llvm_elf`...
|
||||
let exe_path = path.with_extension("llvm_elf");
|
||||
// ... using the LLVM backend ...
|
||||
let output = std::process::Command::new("rustc")
|
||||
.arg(path)
|
||||
.arg("-o")
|
||||
.arg(&exe_path)
|
||||
.output()
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
// ... check that the compilation succeeded ...
|
||||
if !output.status.success() {
|
||||
return Err(format!("LLVM compilation failed:{output:?}"));
|
||||
}
|
||||
// ... run the resulting executable ...
|
||||
let output =
|
||||
std::process::Command::new(&exe_path).output().map_err(|err| format!("{err:?}"))?;
|
||||
// ... check it run normally ...
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"The program at {path:?}, compiled with LLVM, exited unsuccessfully:{output:?}"
|
||||
));
|
||||
}
|
||||
// ... cleanup that executable ...
|
||||
std::fs::remove_file(exe_path).map_err(|err| format!("{err:?}"))?;
|
||||
// ... and return the output(stdout + stderr - this allows UB checks to fire).
|
||||
let mut res = output.stdout;
|
||||
res.extend(output.stderr);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Builds & runs a file with GCC.
|
||||
fn release_gcc(path: &std::path::Path) -> Result<Vec<u8>, String> {
|
||||
// Build a file named `gcc_elf`...
|
||||
let exe_path = path.with_extension("gcc_elf");
|
||||
// ... using the GCC backend ...
|
||||
let output = std::process::Command::new("./y.sh")
|
||||
.arg("rustc")
|
||||
.arg(path)
|
||||
.arg("-O")
|
||||
.arg("-o")
|
||||
.arg(&exe_path)
|
||||
.output()
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
// ... check that the compilation succeeded ...
|
||||
if !output.status.success() {
|
||||
return Err(format!("GCC compilation failed:{output:?}"));
|
||||
}
|
||||
// ... run the resulting executable ..
|
||||
let output =
|
||||
std::process::Command::new(&exe_path).output().map_err(|err| format!("{err:?}"))?;
|
||||
// ... check it run normally ...
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"The program at {path:?}, compiled with GCC, exited unsuccessfully:{output:?}"
|
||||
));
|
||||
}
|
||||
// ... cleanup that executable ...
|
||||
std::fs::remove_file(exe_path).map_err(|err| format!("{err:?}"))?;
|
||||
// ... and return the output(stdout + stderr - this allows UB checks to fire).
|
||||
let mut res = output.stdout;
|
||||
res.extend(output.stderr);
|
||||
Ok(res)
|
||||
}
|
||||
type ResultCache = Option<(Vec<u8>, Vec<u8>)>;
|
||||
/// Generates a new rustlantis file, & compares the result of running it with GCC and LLVM.
|
||||
fn test(seed: u64, print_tmp_vars: bool) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
// Generate a Rust source...
|
||||
let source_file = generate(seed, print_tmp_vars)?;
|
||||
test_file(&source_file, true)
|
||||
}
|
||||
/// Tests a file with a cached LLVM result. Used for reduction, when it is known
|
||||
/// that a given transformation should not change the execution result.
|
||||
fn test_cached(
|
||||
source_file: &Path,
|
||||
remove_tmps: bool,
|
||||
cache: &mut ResultCache,
|
||||
) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
// Test `source_file` with release GCC ...
|
||||
let gcc_res = release_gcc(source_file)?;
|
||||
if cache.is_none() {
|
||||
// ...test `source_file` with debug LLVM ...
|
||||
*cache = Some((debug_llvm(source_file)?, gcc_res.clone()));
|
||||
}
|
||||
let (llvm_res, old_gcc) = cache.as_ref().unwrap();
|
||||
// ... compare the results ...
|
||||
if *llvm_res != gcc_res && gcc_res == *old_gcc {
|
||||
// .. if they don't match, report an error.
|
||||
Ok(Err(source_file.to_path_buf()))
|
||||
} else {
|
||||
if remove_tmps {
|
||||
std::fs::remove_file(source_file).map_err(|err| format!("{err:?}"))?;
|
||||
}
|
||||
Ok(Ok(()))
|
||||
}
|
||||
}
|
||||
fn test_file(
|
||||
source_file: &Path,
|
||||
remove_tmps: bool,
|
||||
) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
let mut uncached = None;
|
||||
test_cached(source_file, remove_tmps, &mut uncached)
|
||||
}
|
||||
|
||||
/// Generates a new rustlantis file for us to run tests on.
|
||||
fn generate(seed: u64, print_tmp_vars: bool) -> Result<std::path::PathBuf, String> {
|
||||
use std::io::Write;
|
||||
let mut out_path = std::env::temp_dir();
|
||||
out_path.push(format!("fuzz{seed}.rs"));
|
||||
// We need to get the command output here.
|
||||
let mut generate = std::process::Command::new("cargo");
|
||||
generate
|
||||
.args(["run", "--release", "--bin", "generate"])
|
||||
.arg(format!("{seed}"))
|
||||
.current_dir("clones/rustlantis");
|
||||
if print_tmp_vars {
|
||||
generate.arg("--debug");
|
||||
}
|
||||
let out = generate.output().map_err(|err| format!("{err:?}"))?;
|
||||
// Stuff the rustlantis output in a source file.
|
||||
std::fs::File::create(&out_path)
|
||||
.map_err(|err| format!("{err:?}"))?
|
||||
.write_all(&out.stdout)
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
Ok(out_path)
|
||||
}
|
432
build_system/src/fuzz/reduce.rs
Normal file
432
build_system/src/fuzz/reduce.rs
Normal file
@ -0,0 +1,432 @@
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::ResultCache;
|
||||
|
||||
/// Saves a reduced file for a given `stage`
|
||||
fn save_reduction(lines: &[String], path: &Path, stage: &str) {
|
||||
let mut path = path.to_path_buf();
|
||||
path.set_extension(format!("rs.{stage}"));
|
||||
let mut file = std::fs::File::create(&path).expect("Could not create the reduced example file");
|
||||
for line in lines {
|
||||
file.write_all(line.as_bytes()).expect("Could not save the reduced example");
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a given reduction is valid.
|
||||
fn test_reduction(lines: &[String], path: &Path, cache: &mut ResultCache) -> bool {
|
||||
let mut path = path.to_path_buf();
|
||||
path.set_extension("rs_reduced");
|
||||
let mut file = std::fs::File::create(&path).expect("Could not create the reduced example file");
|
||||
for line in lines {
|
||||
file.write_all(line.as_bytes()).expect("Could not save the reduced example");
|
||||
}
|
||||
let res = super::test_cached(&path, false, cache);
|
||||
let Ok(Err(_)) = res else {
|
||||
return false;
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
/// Removes duplicate assignments in bulk.
|
||||
/// If a line A = B is followed directly by A = C,
|
||||
/// then removing the first line ought to be fully sound,
|
||||
/// and not change the behaviour of the program at all. Detect & remove such lines.
|
||||
fn remove_dup_assign(
|
||||
file: &mut Vec<String>,
|
||||
path: &PathBuf,
|
||||
starts: usize,
|
||||
ends: usize,
|
||||
cache: &mut ResultCache,
|
||||
) {
|
||||
let mut file_copy = file.clone();
|
||||
let mut reduction_count = 0;
|
||||
// Not worth it.
|
||||
if ends - starts < 8 {
|
||||
return;
|
||||
}
|
||||
for index in starts..ends {
|
||||
let Some((prefix, _)) = file_copy[index].split_once('=') else {
|
||||
continue;
|
||||
};
|
||||
let Some((prefix2, postifx2)) = file_copy[index + 1].split_once('=') else {
|
||||
continue;
|
||||
};
|
||||
let prefix = prefix.trim();
|
||||
let prefix2 = prefix2.trim();
|
||||
// FIXME: Right now, remove_dup_assign cares about assignments to the exact same place.
|
||||
// However, given an assigemnt like this:
|
||||
// ```
|
||||
// A.0 = 1_u32;
|
||||
// A = (2_u32, 3.0);
|
||||
// ```
|
||||
// The first assignment could be safely omitted.
|
||||
// Additionally, we try to check if the second assignment could depend on the first one.
|
||||
// In such cases, the result is likely to change, so we bail.
|
||||
if prefix == prefix2 && !postifx2.contains(prefix) {
|
||||
file_copy[index] = "".into();
|
||||
reduction_count += 1;
|
||||
}
|
||||
}
|
||||
// We have removed no lines - no point in testing.
|
||||
if reduction_count == 0 {
|
||||
return;
|
||||
}
|
||||
// Check if the removed lines affected the execution result in any way, shape or form.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {reduction_count} lines `remove_dup_assign`");
|
||||
*file = file_copy;
|
||||
} else {
|
||||
// The execution result changed.
|
||||
// This can occur if the second assignment depended on the first one.
|
||||
// Eg.
|
||||
// ```
|
||||
// a = b + c;
|
||||
// a = a + d;
|
||||
// ```
|
||||
remove_dup_assign(file, path, starts, (starts + ends) / 2, cache);
|
||||
remove_dup_assign(file, path, (starts + ends) / 2, ends, cache);
|
||||
}
|
||||
save_reduction(file, path, "remove_dup_assign");
|
||||
}
|
||||
|
||||
/// Removes all the unneeded calls to `dump_var`. This is not something tools like `cvise` can do,
|
||||
/// but it greately speeds up MIR interpretation + native execution.
|
||||
fn remove_dump_var(file: &mut Vec<String>, path: &PathBuf) {
|
||||
let mut curr = 0;
|
||||
// ... try disabling `dump_vars` one by one, until only the necessary ones are left.
|
||||
while curr < file.len() {
|
||||
let Some(line) = file[curr..].iter().position(|line| line.contains("dump_var")) else {
|
||||
// No more `dump_var`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
// Make the line absolute again.
|
||||
let line = line + curr;
|
||||
let mut file_copy = file.clone();
|
||||
// Try removing 3 consecutive lines(the call, block end and block beginning). This effectively removes a `dump_var`.
|
||||
file_copy.remove(line);
|
||||
file_copy.remove(line);
|
||||
file_copy.remove(line);
|
||||
// Not cached - the execution result can change.
|
||||
let mut uncached = None;
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, &mut uncached) {
|
||||
println!("Reduced {path:?} by 3 lines `remove_dump_var`");
|
||||
*file = file_copy;
|
||||
curr = line;
|
||||
} else {
|
||||
curr = line + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_dump_var");
|
||||
}
|
||||
|
||||
/// Replaces matches with gotos where possible.
|
||||
/// This exploits some properties of rustlantis(match arm order),
|
||||
/// and is only soundly applicable to MIR generated by it.
|
||||
/// Still, it is not something `cvise` can do, but it simplifies the code a ton.
|
||||
fn match_to_goto(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
let Some(match_starts) = file[curr..].iter().position(|line| line.contains("match")) else {
|
||||
// No more `match`es to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let match_starts = match_starts + curr;
|
||||
// Find the end of the match
|
||||
let Some(match_ends) = file[match_starts..].iter().position(|line| line.contains('}'))
|
||||
else {
|
||||
// Can't find match end - exit early.
|
||||
break;
|
||||
};
|
||||
let match_ends = match_ends + match_starts;
|
||||
let match_body = &file[match_starts..match_ends];
|
||||
|
||||
// Find where this match should normally jump to.
|
||||
// This *should* be the second-last arm of the match, as per the paper(the remaining blocks are decoys).
|
||||
// If this ever changes, this reduction may not always be sound.
|
||||
// This is not a problem, however: we NEED to use MIRI for reduction anwyway,
|
||||
// and it will catch this issue.
|
||||
let jumps_to = &match_body[match_body.len() - 2].trim();
|
||||
let Some((_, bb_ident)) = jumps_to.split_once("bb") else {
|
||||
break;
|
||||
};
|
||||
// We now have the number of the block we jump to at runtime.
|
||||
let bb_ident = bb_ident.trim_matches(',');
|
||||
// Try replacing this match with an unconditional jump.
|
||||
let mut file_copy = file.clone();
|
||||
for _ in match_starts..(match_ends + 1) {
|
||||
file_copy.remove(match_starts);
|
||||
}
|
||||
file_copy.insert(match_starts, format!("Goto(bb{bb_ident})\n"));
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `match_to_goto`", match_ends - match_starts);
|
||||
*file = file_copy;
|
||||
curr = match_starts;
|
||||
} else {
|
||||
curr = match_ends;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "match_to_goto");
|
||||
}
|
||||
|
||||
/// At this point, we can try "killing" blocks, by replacing their bodies with calls to `abort`.
|
||||
/// This is always sound(the program aborts, so no UB can occur after the block),
|
||||
/// and allows us to safely remove *a lot* of unneeded blocks.
|
||||
fn block_abort(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to kill - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Find the beginning of the next block to find the end of this block.
|
||||
let Some(block_ends) = file[(block_starts + 1)..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to kill - exit early.
|
||||
break;
|
||||
};
|
||||
let block_ends = block_starts + block_ends;
|
||||
let block_starts = block_starts + 1;
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the block body...
|
||||
for _ in block_starts..(block_ends) {
|
||||
file_copy.remove(block_starts);
|
||||
}
|
||||
// ..and insert an unconditional call to abort.
|
||||
file_copy.insert(
|
||||
block_starts,
|
||||
"Call(tmp = core::intrinsics::abort(), ReturnTo(bb1), UnwindUnreachable())\n"
|
||||
.to_string(),
|
||||
);
|
||||
file_copy.insert(block_starts, "let tmp = ();\n".to_string());
|
||||
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `block_abort`", block_ends - block_starts - 2);
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_ends;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "block_abort");
|
||||
}
|
||||
|
||||
/// Removes unreachable basic blocks
|
||||
fn remove_block(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
// Next, we try to outright remove blocks.
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Find the beginning of the next block to find the end of this block.
|
||||
let Some(block_ends) = file[(block_starts + 1)..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_ends = block_starts + block_ends + 1;
|
||||
// Large blocks are likely to be necessary.
|
||||
if block_ends - block_starts > 6 {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
}
|
||||
let mut file_copy = file.clone();
|
||||
file_copy.drain(block_starts..block_ends);
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `remove_blocks`", block_ends - block_starts);
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_starts + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_block");
|
||||
}
|
||||
|
||||
/// Merges blocks ending with unconditional jumps.
|
||||
fn linearize_cf(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
// Next, we try to linearize the control flow. What the does that mean?
|
||||
// Given a sequence like this:
|
||||
// Goto(bb22)
|
||||
// }
|
||||
// bb22 = {
|
||||
// We remove those 3 lines, merging the blocks together. This is not something `cvise` can do,
|
||||
// and it makes other transformations easier.
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Extract the block id.
|
||||
let Some((block, _)) = file[block_starts].split_once('=') else {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
};
|
||||
let block = block.trim();
|
||||
if file[block_starts - 2].trim() != format!("Goto({block})") {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
}
|
||||
let mut file_copy = file.clone();
|
||||
// Try removing 3 consecutive lines(the goto, block end and block beginning). This effectively removes a `Goto(next)`.
|
||||
file_copy.remove(block_starts - 2);
|
||||
file_copy.remove(block_starts - 2);
|
||||
file_copy.remove(block_starts - 2);
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by 3 lines `linearize_cf`");
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_starts + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "linearize_cf");
|
||||
}
|
||||
|
||||
/// Replaces a call to a given function with a 0 assignment to the destination place, and a Goto.
|
||||
/// This is always sound, because:
|
||||
/// 1. All the functions arguments are always initialized
|
||||
/// 2. and point to initialized memory(the operand of &raw must be an initialized place in rustlantis).
|
||||
fn remove_fn_calls(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
let Some(fn_call) =
|
||||
file[curr..].iter().position(|line| line.contains("Call(") && line.contains(" = fn"))
|
||||
else {
|
||||
// No more calls to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let fn_call = fn_call + curr;
|
||||
let line = file[fn_call].trim();
|
||||
// Skip the Call(
|
||||
let line = &line["Call(".len()..];
|
||||
// Extract the destination place
|
||||
let Some((place, line)) = line.split_once('=') else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
// Skip till the return block id.
|
||||
let Some((_, line)) = line.split_once("ReturnTo(") else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
// Extract the full return block
|
||||
let Some((block, _)) = line.split_once(')') else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the call.
|
||||
file_copy.remove(fn_call);
|
||||
file_copy.insert(fn_call, format!("Goto({block})\n"));
|
||||
file_copy.insert(fn_call, format!("{place} = 0;\n"));
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} using `remove_fn_calls` {cache:?}");
|
||||
*file = file_copy;
|
||||
curr = fn_call;
|
||||
} else {
|
||||
curr = fn_call + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_fn_calls");
|
||||
}
|
||||
|
||||
/// Fully removes unreachable functions.
|
||||
fn remove_fns(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
// Find a function start
|
||||
let Some(fn_start) = file[curr..].iter().position(|line| {
|
||||
line.contains("#[custom_mir(dialect = \"runtime\", phase = \"initial\")]")
|
||||
}) else {
|
||||
// No more functions to remove - exit early.
|
||||
break;
|
||||
};
|
||||
// Find the next function(and use that to find the end of this one).
|
||||
// FIXME: this check is flawed: it will never remove the very last function(the one before main).
|
||||
// The other checks will turn that function into a single call to abort, but it is still annoying that it is kept.
|
||||
let fn_start = fn_start + curr;
|
||||
let Some(fn_end) = file[(fn_start + 3)..].iter().position(|line| line.contains("fn fn"))
|
||||
else {
|
||||
// No more functions to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let fn_end = fn_start + 2 + fn_end;
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the function.\\
|
||||
file_copy.drain(fn_start..fn_end);
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `remove_fns`", fn_end - fn_start);
|
||||
*file = file_copy;
|
||||
} else {
|
||||
curr = fn_start + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_fns");
|
||||
}
|
||||
|
||||
pub(super) fn reduce(path: impl AsRef<Path>) {
|
||||
let path = path.as_ref().to_owned();
|
||||
// ... read the file to a buffer ..
|
||||
let file = std::fs::read_to_string(&path).expect("Could not open the file to reduce");
|
||||
let mut file: Vec<_> = file.split_inclusive('\n').map(|s| s.to_string()).collect();
|
||||
|
||||
// ... and run reduction passes.
|
||||
println!("running `remove_dump_var` on {path:?}.");
|
||||
remove_dump_var(&mut file, &path);
|
||||
// After `dump_var`, the execution results ought not to change. Cache them.
|
||||
let mut cache = None;
|
||||
// Fill the cache
|
||||
assert!(
|
||||
test_reduction(&file, &path, &mut cache),
|
||||
"Reduction error: check that the input file is a valid reproducer."
|
||||
);
|
||||
println!("cache:{cache:?}");
|
||||
println!("running `remove_fn_calls` on {path:?}.");
|
||||
remove_fn_calls(&mut file, &path, &mut cache);
|
||||
println!("running `remove_fns` on {path:?}.");
|
||||
remove_fns(&mut file, &path, &mut cache);
|
||||
let len = file.len();
|
||||
println!("running `remove_dup_assign` on {path:?}.");
|
||||
remove_dup_assign(&mut file, &path, 0, len, &mut cache);
|
||||
file.retain(|line| !line.is_empty());
|
||||
println!("running `match_to_goto` on {path:?}.");
|
||||
match_to_goto(&mut file, &path, &mut cache);
|
||||
println!("running `block_abort` on {path:?}.");
|
||||
block_abort(&mut file, &path, &mut cache);
|
||||
println!("running `remove_block` on {path:?}.");
|
||||
remove_block(&mut file, &path, &mut cache);
|
||||
println!("running `linearize_cf` on {path:?}.");
|
||||
linearize_cf(&mut file, &path, &mut cache);
|
||||
let mut out = std::fs::File::create(&path).expect("Could not save the reduction result.");
|
||||
let file = file.into_iter().collect::<String>();
|
||||
out.write_all(file.as_bytes()).expect("failed to write into file");
|
||||
}
|
@ -15,7 +15,7 @@ pub fn run() -> Result<(), String> {
|
||||
config.no_download = true;
|
||||
config.setup_gcc_path()?;
|
||||
if let Some(gcc_path) = config.gcc_path {
|
||||
println!("{}", gcc_path);
|
||||
println!("{gcc_path}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ mod clean;
|
||||
mod clone_gcc;
|
||||
mod config;
|
||||
mod fmt;
|
||||
mod fuzz;
|
||||
mod info;
|
||||
mod prepare;
|
||||
mod rust_tools;
|
||||
@ -42,7 +43,8 @@ Commands:
|
||||
test : Runs tests for the project.
|
||||
info : Displays information about the build environment and project configuration.
|
||||
clone-gcc : Clones the GCC compiler from a specified source.
|
||||
fmt : Runs rustfmt"
|
||||
fmt : Runs rustfmt
|
||||
fuzz : Fuzzes `cg_gcc` using rustlantis"
|
||||
);
|
||||
}
|
||||
|
||||
@ -56,6 +58,7 @@ pub enum Command {
|
||||
Test,
|
||||
Info,
|
||||
Fmt,
|
||||
Fuzz,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -75,6 +78,7 @@ fn main() {
|
||||
Some("info") => Command::Info,
|
||||
Some("clone-gcc") => Command::CloneGcc,
|
||||
Some("fmt") => Command::Fmt,
|
||||
Some("fuzz") => Command::Fuzz,
|
||||
Some("--help") => {
|
||||
usage();
|
||||
process::exit(0);
|
||||
@ -97,6 +101,7 @@ fn main() {
|
||||
Command::Info => info::run(),
|
||||
Command::CloneGcc => clone_gcc::run(),
|
||||
Command::Fmt => fmt::run(),
|
||||
Command::Fuzz => fuzz::run(),
|
||||
} {
|
||||
eprintln!("Command failed to run: {e}");
|
||||
process::exit(1);
|
||||
|
@ -18,9 +18,9 @@ fn prepare_libcore(
|
||||
if let Some(path) = sysroot_source {
|
||||
rustlib_dir = Path::new(&path)
|
||||
.canonicalize()
|
||||
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
|
||||
if !rustlib_dir.is_dir() {
|
||||
return Err(format!("Custom sysroot path {:?} not found", rustlib_dir));
|
||||
return Err(format!("Custom sysroot path {rustlib_dir:?} not found"));
|
||||
}
|
||||
} else {
|
||||
let rustc_path = match get_rustc_path() {
|
||||
@ -36,17 +36,17 @@ fn prepare_libcore(
|
||||
rustlib_dir = parent
|
||||
.join("../lib/rustlib/src/rust")
|
||||
.canonicalize()
|
||||
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
|
||||
if !rustlib_dir.is_dir() {
|
||||
return Err("Please install `rust-src` component".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let sysroot_dir = sysroot_path.join("sysroot_src");
|
||||
if sysroot_dir.is_dir() {
|
||||
if let Err(error) = fs::remove_dir_all(&sysroot_dir) {
|
||||
return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,));
|
||||
}
|
||||
if sysroot_dir.is_dir()
|
||||
&& let Err(error) = fs::remove_dir_all(&sysroot_dir)
|
||||
{
|
||||
return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,));
|
||||
}
|
||||
|
||||
let sysroot_library_dir = sysroot_dir.join("library");
|
||||
@ -122,7 +122,7 @@ fn prepare_rand() -> Result<(), String> {
|
||||
// Apply patch for the rand crate.
|
||||
let file_path = "patches/crates/0001-Remove-deny-warnings.patch";
|
||||
let rand_dir = Path::new("build/rand");
|
||||
println!("[GIT] apply `{}`", file_path);
|
||||
println!("[GIT] apply `{file_path}`");
|
||||
let path = Path::new("../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], Some(rand_dir))?;
|
||||
@ -149,7 +149,7 @@ fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -
|
||||
where
|
||||
F: Fn(&Path) -> Result<(), String>,
|
||||
{
|
||||
let clone_result = git_clone_root_dir(repo_url, &Path::new(crate::BUILD_DIR), false)?;
|
||||
let clone_result = git_clone_root_dir(repo_url, Path::new(crate::BUILD_DIR), false)?;
|
||||
if !clone_result.ran_clone {
|
||||
println!("`{}` has already been cloned", clone_result.repo_name);
|
||||
}
|
||||
|
@ -1,24 +1,22 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::ConfigInfo;
|
||||
use crate::utils::{
|
||||
get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info,
|
||||
rustc_version_info,
|
||||
};
|
||||
use crate::utils::{get_toolchain, rustc_toolchain_version_info, rustc_version_info};
|
||||
|
||||
fn args(command: &str) -> Result<Option<Vec<String>>, String> {
|
||||
// We skip the binary and the "cargo"/"rustc" option.
|
||||
if let Some("--help") = std::env::args().skip(2).next().as_deref() {
|
||||
if let Some("--help") = std::env::args().nth(2).as_deref() {
|
||||
usage(command);
|
||||
return Ok(None);
|
||||
}
|
||||
let args = std::env::args().skip(2).collect::<Vec<_>>();
|
||||
if args.is_empty() {
|
||||
return Err(format!(
|
||||
"Expected at least one argument for `{}` subcommand, found none",
|
||||
command
|
||||
"Expected at least one argument for `{command}` subcommand, found none"
|
||||
));
|
||||
}
|
||||
Ok(Some(args))
|
||||
@ -27,12 +25,11 @@ fn args(command: &str) -> Result<Option<Vec<String>>, String> {
|
||||
fn usage(command: &str) {
|
||||
println!(
|
||||
r#"
|
||||
`{}` command help:
|
||||
`{command}` command help:
|
||||
|
||||
[args] : Arguments to be passed to the cargo command
|
||||
--help : Show this help
|
||||
"#,
|
||||
command,
|
||||
)
|
||||
}
|
||||
|
||||
@ -51,10 +48,10 @@ impl RustcTools {
|
||||
// expected.
|
||||
let current_dir = std::env::current_dir()
|
||||
.and_then(|path| path.canonicalize())
|
||||
.map_err(|error| format!("Failed to get current directory path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to get current directory path: {error:?}"))?;
|
||||
let current_exe = std::env::current_exe()
|
||||
.and_then(|path| path.canonicalize())
|
||||
.map_err(|error| format!("Failed to get current exe path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to get current exe path: {error:?}"))?;
|
||||
let mut parent_dir =
|
||||
current_exe.components().map(|comp| comp.as_os_str()).collect::<Vec<_>>();
|
||||
// We run this script from "build_system/target/release/y", so we need to remove these elements.
|
||||
@ -68,7 +65,7 @@ impl RustcTools {
|
||||
));
|
||||
}
|
||||
}
|
||||
let parent_dir = PathBuf::from(parent_dir.join(&OsStr::new("/")));
|
||||
let parent_dir = PathBuf::from(parent_dir.join(OsStr::new("/")));
|
||||
std::env::set_current_dir(&parent_dir).map_err(|error| {
|
||||
format!("Failed to go to `{}` folder: {:?}", parent_dir.display(), error)
|
||||
})?;
|
||||
@ -92,11 +89,31 @@ impl RustcTools {
|
||||
std::env::set_current_dir(¤t_dir).map_err(|error| {
|
||||
format!("Failed to go back to `{}` folder: {:?}", current_dir.display(), error)
|
||||
})?;
|
||||
let toolchain = format!("+{}", toolchain);
|
||||
let toolchain = format!("+{toolchain}");
|
||||
Ok(Some(Self { toolchain, args, env, config }))
|
||||
}
|
||||
}
|
||||
|
||||
fn exec(input: &[&dyn AsRef<OsStr>], env: &HashMap<String, String>) -> Result<(), String> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// We use `exec` to call the `execvp` syscall instead of creating a new process where the
|
||||
// command will be executed because very few signals can actually kill a current process,
|
||||
// so if segmentation fault (SIGSEGV signal) happens and we raise to the current process,
|
||||
// it will simply do nothing and we won't have the nice error message for the shell.
|
||||
let error = crate::utils::get_command_inner(input, None, Some(env)).exec();
|
||||
eprintln!("execvp syscall failed: {error:?}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
if crate::utils::run_command_with_output_and_env_no_err(input, None, Some(env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cargo() -> Result<(), String> {
|
||||
let Some(mut tools) = RustcTools::new("cargo")? else { return Ok(()) };
|
||||
let rustflags = tools.env.get("RUSTFLAGS").cloned().unwrap_or_default();
|
||||
@ -105,11 +122,7 @@ pub fn run_cargo() -> Result<(), String> {
|
||||
for arg in &tools.args {
|
||||
command.push(arg);
|
||||
}
|
||||
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
exec(&command, &tools.env)
|
||||
}
|
||||
|
||||
pub fn run_rustc() -> Result<(), String> {
|
||||
@ -118,8 +131,5 @@ pub fn run_rustc() -> Result<(), String> {
|
||||
for arg in &tools.args {
|
||||
command.push(arg);
|
||||
}
|
||||
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
exec(&command, &tools.env)
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ use crate::build;
|
||||
use crate::config::{Channel, ConfigInfo};
|
||||
use crate::utils::{
|
||||
create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file,
|
||||
run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info,
|
||||
split_args, walk_dir,
|
||||
run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env,
|
||||
rustc_version_info, split_args, walk_dir,
|
||||
};
|
||||
|
||||
type Env = HashMap<String, String>;
|
||||
@ -42,7 +42,7 @@ fn get_runners() -> Runners {
|
||||
);
|
||||
runners.insert("--extended-regex-tests", ("Run extended regex tests", extended_regex_tests));
|
||||
runners.insert("--mini-tests", ("Run mini tests", mini_tests));
|
||||
|
||||
runners.insert("--cargo-tests", ("Run cargo tests", cargo_tests));
|
||||
runners
|
||||
}
|
||||
|
||||
@ -53,9 +53,9 @@ fn get_number_after_arg(
|
||||
match args.next() {
|
||||
Some(nb) if !nb.is_empty() => match usize::from_str(&nb) {
|
||||
Ok(nb) => Ok(nb),
|
||||
Err(_) => Err(format!("Expected a number after `{}`, found `{}`", option, nb)),
|
||||
Err(_) => Err(format!("Expected a number after `{option}`, found `{nb}`")),
|
||||
},
|
||||
_ => Err(format!("Expected a number after `{}`, found nothing", option)),
|
||||
_ => Err(format!("Expected a number after `{option}`, found nothing")),
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,8 +76,8 @@ fn show_usage() {
|
||||
for (option, (doc, _)) in get_runners() {
|
||||
// FIXME: Instead of using the hard-coded `23` value, better to compute it instead.
|
||||
let needed_spaces = 23_usize.saturating_sub(option.len());
|
||||
let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect();
|
||||
println!(" {}{}: {}", option, spaces, doc);
|
||||
let spaces: String = std::iter::repeat_n(' ', needed_spaces).collect();
|
||||
println!(" {option}{spaces}: {doc}");
|
||||
}
|
||||
println!(" --help : Show this help");
|
||||
}
|
||||
@ -88,6 +88,8 @@ struct TestArg {
|
||||
use_system_gcc: bool,
|
||||
runners: Vec<String>,
|
||||
flags: Vec<String>,
|
||||
/// Additional arguments, to be passed to commands like `cargo test`.
|
||||
test_args: Vec<String>,
|
||||
nb_parts: Option<usize>,
|
||||
current_part: Option<usize>,
|
||||
sysroot_panic_abort: bool,
|
||||
@ -137,13 +139,14 @@ impl TestArg {
|
||||
test_arg.sysroot_features.push(feature);
|
||||
}
|
||||
_ => {
|
||||
return Err(format!("Expected an argument after `{}`, found nothing", arg));
|
||||
return Err(format!("Expected an argument after `{arg}`, found nothing"));
|
||||
}
|
||||
},
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(None);
|
||||
}
|
||||
"--" => test_arg.test_args.extend(&mut args),
|
||||
x if runners.contains_key(x)
|
||||
&& !test_arg.runners.iter().any(|runner| runner == x) =>
|
||||
{
|
||||
@ -151,7 +154,7 @@ impl TestArg {
|
||||
}
|
||||
arg => {
|
||||
if !test_arg.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown option {}", arg));
|
||||
return Err(format!("Unknown option {arg}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,7 +192,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
command.push(&"--release");
|
||||
&tmp_env
|
||||
} else {
|
||||
&env
|
||||
env
|
||||
};
|
||||
for flag in args.flags.iter() {
|
||||
command.push(flag);
|
||||
@ -203,6 +206,33 @@ fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
create_dir(&path)
|
||||
}
|
||||
|
||||
fn cargo_tests(test_env: &Env, test_args: &TestArg) -> Result<(), String> {
|
||||
// First, we call `mini_tests` to build minicore for us. This ensures we are testing with a working `minicore`,
|
||||
// and that any changes we have made affect `minicore`(since it would get rebuilt).
|
||||
mini_tests(test_env, test_args)?;
|
||||
// Then, we copy some of the env vars from `test_env`
|
||||
// We don't want to pass things like `RUSTFLAGS`, since they contain the -Zcodegen-backend flag.
|
||||
// That would force `cg_gcc` to *rebuild itself* and only then run tests, which is undesirable.
|
||||
let mut env = HashMap::new();
|
||||
env.insert(
|
||||
"LD_LIBRARY_PATH".into(),
|
||||
test_env.get("LD_LIBRARY_PATH").expect("LD_LIBRARY_PATH missing!").to_string(),
|
||||
);
|
||||
env.insert(
|
||||
"LIBRARY_PATH".into(),
|
||||
test_env.get("LIBRARY_PATH").expect("LIBRARY_PATH missing!").to_string(),
|
||||
);
|
||||
env.insert(
|
||||
"CG_RUSTFLAGS".into(),
|
||||
test_env.get("CG_RUSTFLAGS").map(|s| s.as_str()).unwrap_or("").to_string(),
|
||||
);
|
||||
// Pass all the default args + the user-specified ones.
|
||||
let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"test"];
|
||||
args.extend(test_args.test_args.iter().map(|s| s as &dyn AsRef<OsStr>));
|
||||
run_command_with_output_and_env(&args, None, Some(&env))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[BUILD] mini_core");
|
||||
@ -222,7 +252,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[BUILD] example");
|
||||
@ -234,7 +264,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[AOT] mini_core_hello_world");
|
||||
@ -249,14 +279,14 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
let command: &[&dyn AsRef<OsStr>] = &[
|
||||
&Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"),
|
||||
&"abc",
|
||||
&"bcd",
|
||||
];
|
||||
maybe_run_command_in_vm(&command, env, args)?;
|
||||
maybe_run_command_in_vm(command, env, args)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -454,22 +484,47 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
||||
} else {
|
||||
run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?;
|
||||
}
|
||||
|
||||
let mut patches = Vec::new();
|
||||
walk_dir(
|
||||
"patches/tests",
|
||||
&mut |_| Ok(()),
|
||||
&mut |file_path: &Path| {
|
||||
patches.push(file_path.to_path_buf());
|
||||
Ok(())
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
patches.sort();
|
||||
// TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils
|
||||
// module.
|
||||
for file_path in patches {
|
||||
println!("[GIT] apply `{}`", file_path.display());
|
||||
let path = Path::new("../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], rust_dir)?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?;
|
||||
run_command_with_output(
|
||||
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
|
||||
rust_dir,
|
||||
)?;
|
||||
}
|
||||
|
||||
let cargo = String::from_utf8(
|
||||
run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve cargo path: {:?}", error))
|
||||
.map_err(|error| format!("Failed to retrieve cargo path: {error:?}"))
|
||||
.and_then(|cargo| {
|
||||
let cargo = cargo.trim().to_owned();
|
||||
if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) }
|
||||
if cargo.is_empty() { Err("`cargo` path is empty".to_string()) } else { Ok(cargo) }
|
||||
})?;
|
||||
let rustc = String::from_utf8(
|
||||
run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc path: {:?}", error))
|
||||
.map_err(|error| format!("Failed to retrieve rustc path: {error:?}"))
|
||||
.and_then(|rustc| {
|
||||
let rustc = rustc.trim().to_owned();
|
||||
if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) }
|
||||
if rustc.is_empty() { Err("`rustc` path is empty".to_string()) } else { Ok(rustc) }
|
||||
})?;
|
||||
let llvm_filecheck = match run_command_with_env(
|
||||
&[
|
||||
@ -479,7 +534,8 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
||||
which FileCheck-11 || \
|
||||
which FileCheck-12 || \
|
||||
which FileCheck-13 || \
|
||||
which FileCheck-14",
|
||||
which FileCheck-14 || \
|
||||
which FileCheck",
|
||||
],
|
||||
rust_dir,
|
||||
Some(env),
|
||||
@ -487,13 +543,15 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
||||
Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
Err(_) => {
|
||||
eprintln!("Failed to retrieve LLVM FileCheck, ignoring...");
|
||||
// FIXME: the test tests/run-make/no-builtins-attribute will fail if we cannot find
|
||||
// FileCheck.
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
let file_path = rust_dir_path.join("config.toml");
|
||||
std::fs::write(
|
||||
&file_path,
|
||||
&format!(
|
||||
format!(
|
||||
r#"change-id = 115898
|
||||
|
||||
[rust]
|
||||
@ -532,7 +590,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
let codegen_backend_path = format!(
|
||||
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
|
||||
pwd = std::env::current_dir()
|
||||
.map_err(|error| format!("`current_dir` failed: {:?}", error))?
|
||||
.map_err(|error| format!("`current_dir` failed: {error:?}"))?
|
||||
.display(),
|
||||
channel = args.config_info.channel.as_str(),
|
||||
dylib_ext = args.config_info.dylib_ext,
|
||||
@ -587,11 +645,11 @@ where
|
||||
F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>,
|
||||
{
|
||||
let toolchain = get_toolchain()?;
|
||||
let toolchain_arg = format!("+{}", toolchain);
|
||||
let toolchain_arg = format!("+{toolchain}");
|
||||
let rustc_version = String::from_utf8(
|
||||
run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc version: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve rustc version: {error:?}"))?;
|
||||
let rustc_toolchain_version = String::from_utf8(
|
||||
run_command_with_env(
|
||||
&[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"],
|
||||
@ -600,20 +658,19 @@ where
|
||||
)?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc +toolchain version: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve rustc +toolchain version: {error:?}"))?;
|
||||
|
||||
if rustc_version != rustc_toolchain_version {
|
||||
eprintln!(
|
||||
"rustc_codegen_gcc is built for `{}` but the default rustc version is `{}`.",
|
||||
rustc_toolchain_version, rustc_version,
|
||||
"rustc_codegen_gcc is built for `{rustc_toolchain_version}` but the default rustc version is `{rustc_version}`.",
|
||||
);
|
||||
eprintln!("Using `{}`.", rustc_toolchain_version);
|
||||
eprintln!("Using `{rustc_toolchain_version}`.");
|
||||
}
|
||||
let mut env = env.clone();
|
||||
let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
|
||||
env.insert("RUSTDOCFLAGS".to_string(), rustflags);
|
||||
let mut cargo_command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &toolchain_arg];
|
||||
cargo_command.extend_from_slice(&command);
|
||||
cargo_command.extend_from_slice(command);
|
||||
callback(&cargo_command, cwd, &env)
|
||||
}
|
||||
|
||||
@ -680,7 +737,15 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
println!("[TEST] libcore");
|
||||
let path = get_sysroot_dir().join("sysroot_src/library/coretests");
|
||||
let _ = remove_dir_all(path.join("target"));
|
||||
run_cargo_command(&[&"test"], Some(&path), env, args)?;
|
||||
// TODO(antoyo): run in release mode when we fix the failures.
|
||||
// TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed:
|
||||
// https://github.com/rust-lang/rust/issues/141503
|
||||
run_cargo_command(
|
||||
&[&"test", &"--", &"--skip", &"f16::test_total_cmp"],
|
||||
Some(&path),
|
||||
env,
|
||||
args,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -818,7 +883,7 @@ fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<
|
||||
// Tests generating errors.
|
||||
let file = File::open(file_path)
|
||||
.map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
|
||||
for line in BufReader::new(file).lines().filter_map(|line| line.ok()) {
|
||||
for line in BufReader::new(file).lines().map_while(Result::ok) {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
@ -887,7 +952,7 @@ where
|
||||
|
||||
if !prepare_files_callback(&rust_path)? {
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("Keeping all {} tests", test_type);
|
||||
println!("Keeping all {test_type} tests");
|
||||
}
|
||||
|
||||
if test_type == "ui" {
|
||||
@ -919,8 +984,7 @@ where
|
||||
"borrowck",
|
||||
"test-attrs",
|
||||
]
|
||||
.iter()
|
||||
.any(|name| *name == dir_name)
|
||||
.contains(&dir_name)
|
||||
{
|
||||
remove_dir_all(dir).map_err(|error| {
|
||||
format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
|
||||
@ -975,10 +1039,7 @@ where
|
||||
if nb_parts > 0 {
|
||||
let current_part = args.current_part.unwrap();
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!(
|
||||
"Splitting ui_test into {} parts (and running part {})",
|
||||
nb_parts, current_part
|
||||
);
|
||||
println!("Splitting ui_test into {nb_parts} parts (and running part {current_part})");
|
||||
let out = String::from_utf8(
|
||||
run_command(
|
||||
&[
|
||||
@ -996,7 +1057,7 @@ where
|
||||
)?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve output of find command: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve output of find command: {error:?}"))?;
|
||||
let mut files = out
|
||||
.split('\n')
|
||||
.map(|line| line.trim())
|
||||
@ -1016,7 +1077,7 @@ where
|
||||
}
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[TEST] rustc {} test suite", test_type);
|
||||
println!("[TEST] rustc {test_type} test suite");
|
||||
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
|
||||
|
||||
let extra =
|
||||
@ -1040,7 +1101,7 @@ where
|
||||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
],
|
||||
@ -1051,19 +1112,18 @@ where
|
||||
}
|
||||
|
||||
fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
//test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "ui")
|
||||
}
|
||||
|
||||
fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
let result1 = Ok(());
|
||||
/*test_rustc_inner(
|
||||
let result1 = test_rustc_inner(
|
||||
env,
|
||||
args,
|
||||
retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
)*/
|
||||
);
|
||||
|
||||
let result2 = test_rustc_inner(
|
||||
env,
|
||||
@ -1084,14 +1144,13 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
false,
|
||||
"ui",
|
||||
)?;
|
||||
Ok(())
|
||||
/*test_rustc_inner(
|
||||
test_rustc_inner(
|
||||
env,
|
||||
args,
|
||||
remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
)*/
|
||||
)
|
||||
}
|
||||
|
||||
fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
@ -1118,7 +1177,7 @@ fn retain_files_callback<'a>(
|
||||
run_command(
|
||||
&[
|
||||
&"find",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"-mindepth",
|
||||
&"1",
|
||||
&"-type",
|
||||
@ -1137,7 +1196,7 @@ fn retain_files_callback<'a>(
|
||||
run_command(
|
||||
&[
|
||||
&"find",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"-type",
|
||||
&"f",
|
||||
&"-name",
|
||||
@ -1152,15 +1211,12 @@ fn retain_files_callback<'a>(
|
||||
}
|
||||
|
||||
// Putting back only the failing ones.
|
||||
if let Ok(files) = std::fs::read_to_string(&file_path) {
|
||||
if let Ok(files) = std::fs::read_to_string(file_path) {
|
||||
for file in files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty()) {
|
||||
run_command(&[&"git", &"checkout", &"--", &file], Some(&rust_path))?;
|
||||
run_command(&[&"git", &"checkout", &"--", &file], Some(rust_path))?;
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"Failed to read `{}`, not putting back failing {} tests",
|
||||
file_path, test_type
|
||||
);
|
||||
println!("Failed to read `{file_path}`, not putting back failing {test_type} tests");
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
@ -1188,8 +1244,7 @@ fn remove_files_callback<'a>(
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"Failed to read `{}`, not putting back failing {} tests",
|
||||
file_path, test_type
|
||||
"Failed to read `{file_path}`, not putting back failing {test_type} tests"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -1202,7 +1257,7 @@ fn remove_files_callback<'a>(
|
||||
remove_file(&path)?;
|
||||
}
|
||||
} else {
|
||||
println!("Failed to read `{}`, not putting back failing ui tests", file_path);
|
||||
println!("Failed to read `{file_path}`, not putting back failing ui tests");
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
@ -1217,7 +1272,9 @@ fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
// asm_tests(env, args)?;
|
||||
test_libcore(env, args)?;
|
||||
extended_sysroot_tests(env, args)?;
|
||||
cargo_tests(env, args)?;
|
||||
test_rustc(env, args)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(unix)]
|
||||
use std::ffi::c_int;
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
#[cfg(unix)]
|
||||
@ -9,11 +7,6 @@ use std::os::unix::process::ExitStatusExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitStatus, Output};
|
||||
|
||||
#[cfg(unix)]
|
||||
unsafe extern "C" {
|
||||
fn raise(signal: c_int) -> c_int;
|
||||
}
|
||||
|
||||
fn exec_command(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
@ -27,17 +20,14 @@ fn exec_command(
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if let Some(signal) = status.signal() {
|
||||
unsafe {
|
||||
raise(signal as _);
|
||||
}
|
||||
// In case the signal didn't kill the current process.
|
||||
return Err(command_error(input, &cwd, format!("Process received signal {}", signal)));
|
||||
return Err(command_error(input, &cwd, format!("Process received signal {signal}")));
|
||||
}
|
||||
}
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
fn get_command_inner(
|
||||
pub(crate) fn get_command_inner(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
env: Option<&HashMap<String, String>>,
|
||||
@ -75,18 +65,18 @@ fn check_exit_status(
|
||||
);
|
||||
let input = input.iter().map(|i| i.as_ref()).collect::<Vec<&OsStr>>();
|
||||
if show_err {
|
||||
eprintln!("Command `{:?}` failed", input);
|
||||
eprintln!("Command `{input:?}` failed");
|
||||
}
|
||||
if let Some(output) = output {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
if !stdout.is_empty() {
|
||||
error.push_str("\n==== STDOUT ====\n");
|
||||
error.push_str(&*stdout);
|
||||
error.push_str(&stdout);
|
||||
}
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
if !stderr.is_empty() {
|
||||
error.push_str("\n==== STDERR ====\n");
|
||||
error.push_str(&*stderr);
|
||||
error.push_str(&stderr);
|
||||
}
|
||||
}
|
||||
Err(error)
|
||||
@ -136,6 +126,7 @@ pub fn run_command_with_output_and_env(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn run_command_with_output_and_env_no_err(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
@ -242,7 +233,7 @@ pub fn get_toolchain() -> Result<String, String> {
|
||||
if !line.starts_with("channel") {
|
||||
return None;
|
||||
}
|
||||
line.split('"').skip(1).next()
|
||||
line.split('"').nth(1)
|
||||
})
|
||||
.next()
|
||||
{
|
||||
@ -281,7 +272,7 @@ fn git_clone_inner(
|
||||
}
|
||||
|
||||
fn get_repo_name(url: &str) -> String {
|
||||
let repo_name = url.split('/').last().unwrap();
|
||||
let repo_name = url.split('/').next_back().unwrap();
|
||||
match repo_name.strip_suffix(".git") {
|
||||
Some(n) => n.to_string(),
|
||||
None => repo_name.to_string(),
|
||||
|
@ -77,18 +77,18 @@ fn main() {
|
||||
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);
|
||||
let hundred_u128 = 100u128;
|
||||
let hundred_i128 = 100i128;
|
||||
let hundred_f32 = 100.0f32;
|
||||
let hundred_f64 = 100.0f64;
|
||||
assert_eq!(hundred_u128 as f32, 100.0);
|
||||
assert_eq!(hundred_u128 as f64, 100.0);
|
||||
assert_eq!(hundred_f32 as u128, 100);
|
||||
assert_eq!(hundred_f64 as u128, 100);
|
||||
assert_eq!(hundred_i128 as f32, 100.0);
|
||||
assert_eq!(hundred_i128 as f64, 100.0);
|
||||
assert_eq!(hundred_f32 as i128, 100);
|
||||
assert_eq!(hundred_f64 as i128, 100);
|
||||
|
||||
let _a = 1u32 << 2u8;
|
||||
|
||||
|
39
patches/0001-Pin-compiler_builtins-to-0.1.160.patch
Normal file
39
patches/0001-Pin-compiler_builtins-to-0.1.160.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From cdb3d407740e4f15c3746051f8ba89b8e74e99d3 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Fri, 30 May 2025 13:46:22 -0400
|
||||
Subject: [PATCH] Pin compiler_builtins to 0.1.160
|
||||
|
||||
---
|
||||
library/alloc/Cargo.toml | 2 +-
|
||||
library/std/Cargo.toml | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
|
||||
index 9d0d957..365c9dc 100644
|
||||
--- a/library/alloc/Cargo.toml
|
||||
+++ b/library/alloc/Cargo.toml
|
||||
@@ -16,7 +16,7 @@ bench = false
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core", public = true }
|
||||
-compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[features]
|
||||
compiler-builtins-mem = ['compiler_builtins/mem']
|
||||
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
|
||||
index 4ff4895..31371f0 100644
|
||||
--- a/library/std/Cargo.toml
|
||||
+++ b/library/std/Cargo.toml
|
||||
@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
|
||||
panic_unwind = { path = "../panic_unwind", optional = true }
|
||||
panic_abort = { path = "../panic_abort" }
|
||||
core = { path = "../core", public = true }
|
||||
-compiler_builtins = { version = "=0.1.159" }
|
||||
+compiler_builtins = { version = "=0.1.160" }
|
||||
unwind = { path = "../unwind" }
|
||||
hashbrown = { version = "0.15", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
--
|
||||
2.49.0
|
||||
|
@ -0,0 +1,25 @@
|
||||
From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001
|
||||
From: Antoni Boucher <bouanto@zoho.com>
|
||||
Date: Fri, 13 Jun 2025 20:25:33 -0400
|
||||
Subject: [PATCH] Workaround to make a run-make test pass
|
||||
|
||||
---
|
||||
tests/run-make/linker-warning/rmake.rs | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
|
||||
index bc21739fefc..0946a7e2a48 100644
|
||||
--- a/tests/run-make/linker-warning/rmake.rs
|
||||
+++ b/tests/run-make/linker-warning/rmake.rs
|
||||
@@ -55,7 +55,7 @@ fn main() {
|
||||
diff()
|
||||
.expected_file("short-error.txt")
|
||||
.actual_text("(linker error)", out.stderr())
|
||||
- .normalize(r#"/rustc[^/]*/"#, "/rustc/")
|
||||
+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/")
|
||||
.normalize(
|
||||
regex::escape(run_make_support::build_root().to_str().unwrap()),
|
||||
"/build-root",
|
||||
--
|
||||
2.49.0
|
||||
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-05-12"
|
||||
channel = "nightly-2025-05-21"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
@ -158,6 +158,7 @@ fn create_wrapper_function(
|
||||
}
|
||||
} else {
|
||||
assert!(output.is_none());
|
||||
block.add_eval(None, ret);
|
||||
block.end_with_void_return(None);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
// cSpell:ignoreRegExp [afkspqvwy]reg
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use gccjit::{LValue, RValue, ToRValue, Type};
|
||||
@ -138,7 +140,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
// `outputs.len() + inputs.len()`.
|
||||
let mut labels = vec![];
|
||||
|
||||
// Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
|
||||
// Clobbers collected from `out("explicit register") _` and `inout("explicit_reg") var => _`
|
||||
let mut clobbers = vec![];
|
||||
|
||||
// We're trying to preallocate space for the template
|
||||
@ -203,7 +205,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
// is also used as an in register, do not add it to the clobbers list.
|
||||
// it will be treated as a lateout register with `out_place: None`
|
||||
if !late {
|
||||
bug!("input registers can only be used as lateout regisers");
|
||||
bug!("input registers can only be used as lateout registers");
|
||||
}
|
||||
("r", dummy_output_type(self.cx, reg.reg_class()))
|
||||
} else {
|
||||
@ -641,7 +643,8 @@ fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
InlineAsmReg::Arm(reg) => reg.name(),
|
||||
InlineAsmReg::AArch64(reg) => reg.name(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use crate::gcc_util::to_gcc_features;
|
||||
/// Checks if the function `instance` is recursively inline.
|
||||
/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
|
||||
#[cfg(feature = "master")]
|
||||
fn resursively_inline<'gcc, 'tcx>(
|
||||
fn recursively_inline<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) -> bool {
|
||||
@ -61,7 +61,7 @@ fn inline_attr<'gcc, 'tcx>(
|
||||
//
|
||||
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost.
|
||||
// We *only* need to check all the terminators of a function marked with this attribute.
|
||||
if resursively_inline(cx, instance) {
|
||||
if recursively_inline(cx, instance) {
|
||||
Some(FnAttribute::Inline)
|
||||
} else {
|
||||
Some(FnAttribute::AlwaysInline)
|
||||
|
@ -11,11 +11,12 @@
|
||||
// does not remove it?
|
||||
//
|
||||
// TODO(antoyo): for performance, check which optimizations the C++ frontend enables.
|
||||
//
|
||||
// cSpell:disable
|
||||
// Fix these warnings:
|
||||
// /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
|
||||
// /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
|
||||
// /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization
|
||||
// cSpell:enable
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -186,6 +186,7 @@ pub(crate) fn codegen(
|
||||
|
||||
if fat_lto {
|
||||
let lto_path = format!("{}.lto", path);
|
||||
// cSpell:disable
|
||||
// FIXME(antoyo): The LTO frontend generates the following warning:
|
||||
// ../build_sysroot/sysroot_src/library/core/src/num/dec2flt/lemire.rs:150:15: warning: type of ‘_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ does not match original declaration [-Wlto-type-mismatch]
|
||||
// 150 | let (lo5, hi5) = POWER_OF_FIVE_128[index];
|
||||
@ -193,6 +194,7 @@ pub(crate) fn codegen(
|
||||
// lto1: note: ‘_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ was previously declared here
|
||||
//
|
||||
// This option is to mute it to make the UI tests pass with LTO enabled.
|
||||
// cSpell:enable
|
||||
context.add_driver_option("-Wno-lto-type-mismatch");
|
||||
// NOTE: this doesn't actually generate an executable. With the above
|
||||
// flags, it combines the .o files together in another .o.
|
||||
|
@ -765,7 +765,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
match self.cx.type_kind(a_type) {
|
||||
TypeKind::Half | TypeKind::Float => {
|
||||
TypeKind::Half => {
|
||||
let fmodf = self.context.get_builtin_function("fmodf");
|
||||
let f32_type = self.type_f32();
|
||||
let a = self.context.new_cast(self.location, a, f32_type);
|
||||
let b = self.context.new_cast(self.location, b, f32_type);
|
||||
let result = self.context.new_call(self.location, fmodf, &[a, b]);
|
||||
return self.context.new_cast(self.location, result, a_type);
|
||||
}
|
||||
TypeKind::Float => {
|
||||
let fmodf = self.context.get_builtin_function("fmodf");
|
||||
return self.context.new_call(self.location, fmodf, &[a, b]);
|
||||
}
|
||||
@ -774,8 +782,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
return self.context.new_call(self.location, fmod, &[a, b]);
|
||||
}
|
||||
TypeKind::FP128 => {
|
||||
let fmodl = self.context.get_builtin_function("fmodl");
|
||||
return self.context.new_call(self.location, fmodl, &[a, b]);
|
||||
let f128_type = self.type_f128();
|
||||
let fmodf128 = self.context.new_function(
|
||||
None,
|
||||
gccjit::FunctionType::Extern,
|
||||
f128_type,
|
||||
&[
|
||||
self.context.new_parameter(None, f128_type, "a"),
|
||||
self.context.new_parameter(None, f128_type, "b"),
|
||||
],
|
||||
"fmodf128",
|
||||
false,
|
||||
);
|
||||
return self.context.new_call(self.location, fmodf128, &[a, b]);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -924,7 +943,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
// dereference after a drop, for instance.
|
||||
// FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
|
||||
// Ideally, we shouldn't need to do this check.
|
||||
let aligned_type = if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type {
|
||||
// FractalFir: the `align == self.int128_align` check ensures we *do* call `get_aligned` if
|
||||
// the alignment of a `u128`/`i128` is not the one mandated by the ABI. This ensures we handle
|
||||
// under-aligned loads correctly.
|
||||
let aligned_type = if (pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type)
|
||||
&& align == self.int128_align
|
||||
{
|
||||
pointee_ty
|
||||
} else {
|
||||
pointee_ty.get_aligned(align.bytes())
|
||||
@ -1010,13 +1034,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
let b_offset = a.size(self).align_to(b.align(self).abi);
|
||||
|
||||
let mut load = |i, scalar: &abi::Scalar, align| {
|
||||
let llptr = if i == 0 {
|
||||
let ptr = if i == 0 {
|
||||
place.val.llval
|
||||
} else {
|
||||
self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes()))
|
||||
};
|
||||
let llty = place.layout.scalar_pair_element_gcc_type(self, i);
|
||||
let load = self.load(llty, llptr, align);
|
||||
let load = self.load(llty, ptr, align);
|
||||
scalar_load_metadata(self, load, scalar);
|
||||
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
|
||||
unreachable!();
|
||||
/*
|
||||
// Create a fn pointer with the new signature.
|
||||
let ptrty = fn_abi.ptr_to_gcc_type(cx);
|
||||
let ptrtype = fn_abi.ptr_to_gcc_type(cx);
|
||||
|
||||
// This is subtle and surprising, but sometimes we have to bitcast
|
||||
// the resulting fn pointer. The reason has to do with external
|
||||
@ -59,7 +59,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
|
||||
// This can occur on either a crate-local or crate-external
|
||||
// reference. It also occurs when testing libcore and in some
|
||||
// other weird situations. Annoying.
|
||||
if cx.val_ty(func) != ptrty {
|
||||
if cx.val_ty(func) != ptrtype {
|
||||
// TODO(antoyo): cast the pointer.
|
||||
func
|
||||
}
|
||||
|
102
src/common.rs
102
src/common.rs
@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
||||
use crate::consts::const_alloc_to_gcc;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::type_of::LayoutGccExt;
|
||||
|
||||
@ -46,12 +45,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
|
||||
let context = &cx.context;
|
||||
let byte_type = context.new_type::<u8>();
|
||||
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
|
||||
let elements: Vec<_> =
|
||||
bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect();
|
||||
context.new_array_constructor(None, typ, &elements)
|
||||
// Instead of always using an array of bytes, use an array of larger integers of target endianness
|
||||
// if possible. This reduces the amount of `rvalues` we use, which reduces memory usage significantly.
|
||||
//
|
||||
// FIXME(FractalFir): Consider using `global_set_initializer` instead. Before this is done, we need to confirm that
|
||||
// `global_set_initializer` is more memory efficient than the current solution.
|
||||
// `global_set_initializer` calls `global_set_initializer_rvalue` under the hood - does it generate an array of rvalues,
|
||||
// or is it using a more efficient representation?
|
||||
match bytes.len() % 8 {
|
||||
0 => {
|
||||
let context = &cx.context;
|
||||
let byte_type = context.new_type::<u64>();
|
||||
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8);
|
||||
let elements: Vec<_> = bytes
|
||||
.chunks_exact(8)
|
||||
.map(|arr| {
|
||||
let arr: [u8; 8] = arr.try_into().unwrap();
|
||||
context.new_rvalue_from_long(
|
||||
byte_type,
|
||||
// Since we are representing arbitrary byte runs as integers, we need to follow the target
|
||||
// endianness.
|
||||
match cx.sess().target.options.endian {
|
||||
rustc_abi::Endian::Little => u64::from_le_bytes(arr) as i64,
|
||||
rustc_abi::Endian::Big => u64::from_be_bytes(arr) as i64,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
context.new_array_constructor(None, typ, &elements)
|
||||
}
|
||||
4 => {
|
||||
let context = &cx.context;
|
||||
let byte_type = context.new_type::<u32>();
|
||||
let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4);
|
||||
let elements: Vec<_> = bytes
|
||||
.chunks_exact(4)
|
||||
.map(|arr| {
|
||||
let arr: [u8; 4] = arr.try_into().unwrap();
|
||||
context.new_rvalue_from_int(
|
||||
byte_type,
|
||||
match cx.sess().target.options.endian {
|
||||
rustc_abi::Endian::Little => u32::from_le_bytes(arr) as i32,
|
||||
rustc_abi::Endian::Big => u32::from_be_bytes(arr) as i32,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
context.new_array_constructor(None, typ, &elements)
|
||||
}
|
||||
_ => {
|
||||
let context = cx.context;
|
||||
let byte_type = context.new_type::<u8>();
|
||||
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
|
||||
let elements: Vec<_> = bytes
|
||||
.iter()
|
||||
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
|
||||
.collect();
|
||||
context.new_array_constructor(None, typ, &elements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_is_pointer(typ: Type<'_>) -> bool {
|
||||
@ -185,14 +237,15 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
|
||||
// FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
|
||||
// the paths for floating-point values.
|
||||
if ty == self.float_type {
|
||||
// TODO: Remove this code?
|
||||
/*if ty == self.float_type {
|
||||
return self
|
||||
.context
|
||||
.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
|
||||
}
|
||||
if ty == self.double_type {
|
||||
return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
|
||||
}
|
||||
}*/
|
||||
|
||||
let value = self.const_uint_big(self.type_ix(bitsize), data);
|
||||
let bytesize = layout.size(self).bytes();
|
||||
@ -212,7 +265,20 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
let alloc_id = prov.alloc_id();
|
||||
let base_addr = match self.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
// For ZSTs directly codegen an aligned pointer.
|
||||
// This avoids generating a zero-sized constant value and actually needing a
|
||||
// real address at runtime.
|
||||
if alloc.inner().len() == 0 {
|
||||
assert_eq!(offset.bytes(), 0);
|
||||
let val = self.const_usize(alloc.inner().align.bytes());
|
||||
return if matches!(layout.primitive(), Pointer(_)) {
|
||||
self.context.new_cast(None, val, ty)
|
||||
} else {
|
||||
self.const_bitcast(val, ty)
|
||||
};
|
||||
}
|
||||
|
||||
let init = self.const_data_from_alloc(alloc);
|
||||
let alloc = alloc.inner();
|
||||
let value = match alloc.mutability {
|
||||
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
|
||||
@ -234,7 +300,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
}),
|
||||
)))
|
||||
.unwrap_memory();
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
let init = self.const_data_from_alloc(alloc);
|
||||
self.static_addr_of(init, alloc.inner().align, None)
|
||||
}
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
@ -257,7 +323,19 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
}
|
||||
|
||||
fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
|
||||
const_alloc_to_gcc(self, alloc)
|
||||
// We ignore the alignment for the purpose of deduping RValues
|
||||
// The alignment is not handled / used in any way by `const_alloc_to_gcc`,
|
||||
// so it is OK to overwrite it here.
|
||||
let mut mock_alloc = alloc.inner().clone();
|
||||
mock_alloc.align = rustc_abi::Align::MAX;
|
||||
// Check if the rvalue is already in the cache - if so, just return it directly.
|
||||
if let Some(res) = self.const_cache.borrow().get(&mock_alloc) {
|
||||
return *res;
|
||||
}
|
||||
// Rvalue not in the cache - convert and add it.
|
||||
let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc);
|
||||
self.const_cache.borrow_mut().insert(mock_alloc, res);
|
||||
res
|
||||
}
|
||||
|
||||
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
|
||||
|
@ -36,18 +36,14 @@ fn set_global_alignment<'gcc, 'tcx>(
|
||||
|
||||
impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
|
||||
// TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the
|
||||
// following:
|
||||
for (value, variable) in &*self.const_globals.borrow() {
|
||||
if format!("{:?}", value) == format!("{:?}", cv) {
|
||||
if let Some(global_variable) = self.global_lvalues.borrow().get(variable) {
|
||||
let alignment = align.bits() as i32;
|
||||
if alignment > global_variable.get_alignment() {
|
||||
global_variable.set_alignment(alignment);
|
||||
}
|
||||
if let Some(variable) = self.const_globals.borrow().get(&cv) {
|
||||
if let Some(global_variable) = self.global_lvalues.borrow().get(variable) {
|
||||
let alignment = align.bits() as i32;
|
||||
if alignment > global_variable.get_alignment() {
|
||||
global_variable.set_alignment(alignment);
|
||||
}
|
||||
return *variable;
|
||||
}
|
||||
return *variable;
|
||||
}
|
||||
let global_value = self.static_addr_of_mut(cv, align, kind);
|
||||
#[cfg(feature = "master")]
|
||||
@ -288,8 +284,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
global
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_alloc_to_gcc<'gcc>(
|
||||
/// Converts a given const alloc to a gcc Rvalue, without any caching or deduplication.
|
||||
/// YOU SHOULD NOT call this function directly - that may break the semantics of Rust.
|
||||
/// Use `const_data_from_alloc` instead.
|
||||
pub(crate) fn const_alloc_to_gcc_uncached<'gcc>(
|
||||
cx: &CodegenCx<'gcc, '_>,
|
||||
alloc: ConstAllocation<'_>,
|
||||
) -> RValue<'gcc> {
|
||||
@ -321,7 +319,7 @@ pub fn const_alloc_to_gcc<'gcc>(
|
||||
// and we properly interpret the provenance as a relocation pointer offset.
|
||||
alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
|
||||
)
|
||||
.expect("const_alloc_to_llvm: could not read relocation pointer")
|
||||
.expect("const_alloc_to_gcc_uncached: could not read relocation pointer")
|
||||
as u64;
|
||||
|
||||
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
|
||||
@ -360,7 +358,7 @@ fn codegen_static_initializer<'gcc, 'tcx>(
|
||||
def_id: DefId,
|
||||
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
|
||||
let alloc = cx.tcx.eval_static_initializer(def_id)?;
|
||||
Ok((const_alloc_to_gcc(cx, alloc), alloc))
|
||||
Ok((cx.const_data_from_alloc(alloc), alloc))
|
||||
}
|
||||
|
||||
fn check_and_apply_linkage<'gcc, 'tcx>(
|
||||
|
@ -1,14 +1,16 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gccjit::{
|
||||
Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type,
|
||||
};
|
||||
use rustc_abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
|
||||
use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::errors as ssa_errors;
|
||||
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
|
||||
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::mir::interpret::Allocation;
|
||||
use rustc_middle::mir::mono::CodegenUnit;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::{
|
||||
@ -28,6 +30,8 @@ use crate::common::SignType;
|
||||
|
||||
#[cfg_attr(not(feature = "master"), allow(dead_code))]
|
||||
pub struct CodegenCx<'gcc, 'tcx> {
|
||||
/// A cache of converted ConstAllocs
|
||||
pub const_cache: RefCell<HashMap<Allocation, RValue<'gcc>>>,
|
||||
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
|
||||
pub context: &'gcc Context<'gcc>,
|
||||
|
||||
@ -129,6 +133,9 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>,
|
||||
/// The alignment of a u128/i128 type.
|
||||
// We cache this, since it is needed for alignment checks during loads.
|
||||
pub int128_align: Align,
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
@ -220,6 +227,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
}
|
||||
|
||||
let mut cx = Self {
|
||||
int128_align: tcx
|
||||
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.i128))
|
||||
.expect("Can't get the layout of `i128`")
|
||||
.align
|
||||
.abi,
|
||||
const_cache: Default::default(),
|
||||
codegen_unit,
|
||||
context,
|
||||
current_func: RefCell::new(None),
|
||||
@ -428,8 +441,8 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
// `rust_eh_personality` function, but rather we wired it up to the
|
||||
// CRT's custom personality function, which forces LLVM to consider
|
||||
// landing pads as "landing pads for SEH".
|
||||
if let Some(llpersonality) = self.eh_personality.get() {
|
||||
return llpersonality;
|
||||
if let Some(personality_func) = self.eh_personality.get() {
|
||||
return personality_func;
|
||||
}
|
||||
let tcx = self.tcx;
|
||||
let func = match tcx.lang_items().eh_personality() {
|
||||
|
@ -143,6 +143,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||
// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
|
||||
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
|
||||
// cSpell:disable
|
||||
match (arch, s) {
|
||||
// FIXME: seems like x87 does not exist?
|
||||
("x86", "x87") => smallvec![],
|
||||
@ -181,6 +182,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
|
||||
("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
|
||||
(_, s) => smallvec![s],
|
||||
}
|
||||
// cSpell:enable
|
||||
}
|
||||
|
||||
fn arch_to_gcc(name: &str) -> &str {
|
||||
|
@ -2,6 +2,8 @@
|
||||
//! This module exists because some integer types are not supported on some gcc platforms, e.g.
|
||||
//! 128-bit integers on 32-bit platforms and thus require to be handled manually.
|
||||
|
||||
// cSpell:words cmpti divti modti mulodi muloti udivti umodti
|
||||
|
||||
use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
|
||||
use rustc_abi::{CanonAbi, Endian, ExternAbi};
|
||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
@ -913,9 +915,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
|
||||
debug_assert!(value_type.dyncast_array().is_some());
|
||||
let name_suffix = match self.type_kind(dest_typ) {
|
||||
// cSpell:disable
|
||||
TypeKind::Float => "tisf",
|
||||
TypeKind::Double => "tidf",
|
||||
TypeKind::FP128 => "tixf",
|
||||
TypeKind::FP128 => "titf",
|
||||
// cSpell:enable
|
||||
kind => panic!("cannot cast a non-native integer to type {:?}", kind),
|
||||
};
|
||||
let sign = if signed { "" } else { "un" };
|
||||
@ -957,8 +961,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
|
||||
debug_assert!(dest_typ.dyncast_array().is_some());
|
||||
let name_suffix = match self.type_kind(value_type) {
|
||||
// cSpell:disable
|
||||
TypeKind::Float => "sfti",
|
||||
TypeKind::Double => "dfti",
|
||||
// cSpell:enable
|
||||
kind => panic!("cannot cast a {:?} to non-native integer", kind),
|
||||
};
|
||||
let sign = if signed { "" } else { "uns" };
|
||||
|
20150
src/intrinsic/archs.rs
20150
src/intrinsic/archs.rs
File diff suppressed because it is too large
Load Diff
@ -1012,7 +1012,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
|
||||
};
|
||||
let func = cx.context.get_builtin_function(gcc_name);
|
||||
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
|
||||
return func;
|
||||
func
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
@ -1548,10 +1548,13 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
|
||||
"llvm.x86.tcmmrlfp16ps" => "__builtin_trap",
|
||||
|
||||
// NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py
|
||||
_ => include!("archs.rs"),
|
||||
_ => map_arch_intrinsic(name),
|
||||
};
|
||||
|
||||
let func = cx.context.get_target_builtin_function(gcc_name);
|
||||
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
|
||||
func
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
include!("archs.rs");
|
||||
|
@ -196,6 +196,95 @@ fn get_simple_function<'gcc, 'tcx>(
|
||||
))
|
||||
}
|
||||
|
||||
fn get_simple_function_f128<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
) -> Option<Function<'gcc>> {
|
||||
if !cx.supports_f128_type {
|
||||
return None;
|
||||
}
|
||||
|
||||
let f128_type = cx.type_f128();
|
||||
let func_name = match name {
|
||||
sym::ceilf128 => "ceilf128",
|
||||
sym::floorf128 => "floorf128",
|
||||
sym::truncf128 => "truncf128",
|
||||
sym::roundf128 => "roundf128",
|
||||
sym::round_ties_even_f128 => "roundevenf128",
|
||||
sym::sqrtf128 => "sqrtf128",
|
||||
_ => return None,
|
||||
};
|
||||
Some(cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
f128_type,
|
||||
&[cx.context.new_parameter(None, f128_type, "a")],
|
||||
func_name,
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
fn get_simple_function_f128_2args<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
) -> Option<Function<'gcc>> {
|
||||
if !cx.supports_f128_type {
|
||||
return None;
|
||||
}
|
||||
|
||||
let f128_type = cx.type_f128();
|
||||
let func_name = match name {
|
||||
sym::maxnumf128 => "fmaxf128",
|
||||
sym::minnumf128 => "fminf128",
|
||||
_ => return None,
|
||||
};
|
||||
Some(cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
f128_type,
|
||||
&[
|
||||
cx.context.new_parameter(None, f128_type, "a"),
|
||||
cx.context.new_parameter(None, f128_type, "b"),
|
||||
],
|
||||
func_name,
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
fn f16_builtin<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
args: &[OperandRef<'tcx, RValue<'gcc>>],
|
||||
) -> RValue<'gcc> {
|
||||
let f32_type = cx.type_f32();
|
||||
let builtin_name = match name {
|
||||
sym::ceilf16 => "__builtin_ceilf",
|
||||
sym::floorf16 => "__builtin_floorf",
|
||||
sym::fmaf16 => "fmaf",
|
||||
sym::maxnumf16 => "__builtin_fmaxf",
|
||||
sym::minnumf16 => "__builtin_fminf",
|
||||
sym::powf16 => "__builtin_powf",
|
||||
sym::powif16 => {
|
||||
let func = cx.context.get_builtin_function("__builtin_powif");
|
||||
let arg0 = cx.context.new_cast(None, args[0].immediate(), f32_type);
|
||||
let args = [arg0, args[1].immediate()];
|
||||
let result = cx.context.new_call(None, func, &args);
|
||||
return cx.context.new_cast(None, result, cx.type_f16());
|
||||
}
|
||||
sym::roundf16 => "__builtin_roundf",
|
||||
sym::round_ties_even_f16 => "__builtin_rintf",
|
||||
sym::sqrtf16 => "__builtin_sqrtf",
|
||||
sym::truncf16 => "__builtin_truncf",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let func = cx.context.get_builtin_function(builtin_name);
|
||||
let args: Vec<_> =
|
||||
args.iter().map(|arg| cx.context.new_cast(None, arg.immediate(), f32_type)).collect();
|
||||
let result = cx.context.new_call(None, func, &args);
|
||||
cx.context.new_cast(None, result, cx.type_f16())
|
||||
}
|
||||
|
||||
impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn codegen_intrinsic_call(
|
||||
&mut self,
|
||||
@ -211,7 +300,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
let fn_args = instance.args;
|
||||
|
||||
let simple = get_simple_intrinsic(self, name);
|
||||
let simple_func = get_simple_function(self, name);
|
||||
let simple_func = get_simple_function(self, name)
|
||||
.or_else(|| get_simple_function_f128(self, name))
|
||||
.or_else(|| get_simple_function_f128_2args(self, name));
|
||||
|
||||
// FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved:
|
||||
// https://github.com/rust-lang/rust-clippy/issues/12497
|
||||
@ -234,17 +325,55 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
sym::fmaf16 => {
|
||||
// TODO(antoyo): use the correct builtin for f16.
|
||||
let func = self.cx.context.get_builtin_function("fmaf");
|
||||
let args: Vec<_> = args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
self.cx.context.new_cast(self.location, arg.immediate(), self.cx.type_f32())
|
||||
})
|
||||
.collect();
|
||||
let result = self.cx.context.new_call(self.location, func, &args);
|
||||
self.cx.context.new_cast(self.location, result, self.cx.type_f16())
|
||||
sym::ceilf16
|
||||
| sym::floorf16
|
||||
| sym::fmaf16
|
||||
| sym::maxnumf16
|
||||
| sym::minnumf16
|
||||
| sym::powf16
|
||||
| sym::powif16
|
||||
| sym::roundf16
|
||||
| sym::round_ties_even_f16
|
||||
| sym::sqrtf16
|
||||
| sym::truncf16 => f16_builtin(self, name, args),
|
||||
sym::fmaf128 => {
|
||||
let f128_type = self.cx.type_f128();
|
||||
let func = self.cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
f128_type,
|
||||
&[
|
||||
self.cx.context.new_parameter(None, f128_type, "a"),
|
||||
self.cx.context.new_parameter(None, f128_type, "b"),
|
||||
self.cx.context.new_parameter(None, f128_type, "c"),
|
||||
],
|
||||
"fmaf128",
|
||||
false,
|
||||
);
|
||||
self.cx.context.new_call(
|
||||
self.location,
|
||||
func,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
sym::powif128 => {
|
||||
let f128_type = self.cx.type_f128();
|
||||
let func = self.cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
f128_type,
|
||||
&[
|
||||
self.cx.context.new_parameter(None, f128_type, "a"),
|
||||
self.cx.context.new_parameter(None, self.int_type, "b"),
|
||||
],
|
||||
"__powitf2",
|
||||
false,
|
||||
);
|
||||
self.cx.context.new_call(
|
||||
self.location,
|
||||
func,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
sym::is_val_statically_known => {
|
||||
let a = args[0].immediate();
|
||||
@ -526,7 +655,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
|
||||
fn type_checked_load(
|
||||
&mut self,
|
||||
_llvtable: Self::Value,
|
||||
_vtable: Self::Value,
|
||||
_vtable_byte_offset: u64,
|
||||
_typeid: Self::Value,
|
||||
) -> Self::Value {
|
||||
@ -622,23 +751,23 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
// We instead thus allocate some scratch space...
|
||||
let scratch_size = cast.size(bx);
|
||||
let scratch_align = cast.align(bx);
|
||||
let llscratch = bx.alloca(scratch_size, scratch_align);
|
||||
bx.lifetime_start(llscratch, scratch_size);
|
||||
let scratch = bx.alloca(scratch_size, scratch_align);
|
||||
bx.lifetime_start(scratch, scratch_size);
|
||||
|
||||
// ... where we first store the value...
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, scratch, scratch_align);
|
||||
|
||||
// ... and then memcpy it to the intended destination.
|
||||
bx.memcpy(
|
||||
dst.val.llval,
|
||||
self.layout.align.abi,
|
||||
llscratch,
|
||||
scratch,
|
||||
scratch_align,
|
||||
bx.const_usize(self.layout.size.bytes()),
|
||||
MemFlags::empty(),
|
||||
);
|
||||
|
||||
bx.lifetime_end(llscratch, scratch_size);
|
||||
bx.lifetime_end(scratch, scratch_size);
|
||||
}
|
||||
} else {
|
||||
OperandValue::Immediate(val).store(bx, dst);
|
||||
|
@ -1081,7 +1081,9 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
let (_, element_ty1) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty2) = args[2].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (pointer_count, underlying_ty) = match *element_ty1.kind() {
|
||||
ty::RawPtr(p_ty, mutbl) if p_ty == in_elem && mutbl == hir::Mutability::Mut => {
|
||||
ty::RawPtr(p_ty, mutability)
|
||||
if p_ty == in_elem && mutability == hir::Mutability::Mut =>
|
||||
{
|
||||
(ptr_count(element_ty1), non_ptr(element_ty1))
|
||||
}
|
||||
_ => {
|
||||
|
22
src/lib.rs
22
src/lib.rs
@ -3,10 +3,12 @@
|
||||
* TODO(antoyo): support #[inline] attributes.
|
||||
* TODO(antoyo): support LTO (gcc's equivalent to Full LTO is -flto -flto-partition=one — https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html).
|
||||
* For Thin LTO, this might be helpful:
|
||||
// cspell:disable-next-line
|
||||
* In gcc 4.6 -fwhopr was removed and became default with -flto. The non-whopr path can still be executed via -flto-partition=none.
|
||||
* Or the new incremental LTO (https://www.phoronix.com/news/GCC-Incremental-LTO-Patches)?
|
||||
*
|
||||
* Maybe some missing optizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
|
||||
* Maybe some missing optimizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
|
||||
// cspell:disable-next-line
|
||||
* Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans.
|
||||
* TODO: disable debug info always being emitted. Perhaps this slows down things?
|
||||
*
|
||||
@ -206,7 +208,7 @@ impl CodegenBackend for GccCodegenBackend {
|
||||
#[cfg(not(feature = "master"))]
|
||||
{
|
||||
let temp_dir = TempDir::new().expect("cannot create temporary directory");
|
||||
let temp_file = temp_dir.into_path().join("result.asm");
|
||||
let temp_file = temp_dir.keep().join("result.asm");
|
||||
let check_context = Context::default();
|
||||
check_context.set_print_errors_to_stderr(false);
|
||||
let _int128_ty = check_context.new_c_type(CType::UInt128t);
|
||||
@ -430,10 +432,11 @@ impl WriteBackendMethods for GccCodegenBackend {
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::write::link(cgcx, dcx, modules)
|
||||
}
|
||||
|
||||
fn autodiff(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_module: &ModuleCodegen<Self::Module>,
|
||||
_diff_fncs: Vec<AutoDiffItem>,
|
||||
_diff_functions: Vec<AutoDiffItem>,
|
||||
_config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
unimplemented!()
|
||||
@ -494,12 +497,14 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig
|
||||
return false;
|
||||
}
|
||||
target_info.cpu_supports(feature)
|
||||
// cSpell:disable
|
||||
/*
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
*/
|
||||
// cSpell:enable
|
||||
})
|
||||
.map(Symbol::intern)
|
||||
.collect()
|
||||
@ -508,13 +513,16 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
|
||||
let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16);
|
||||
let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128);
|
||||
|
||||
TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
// There are no known bugs with GCC support for f16 or f128
|
||||
has_reliable_f16: true,
|
||||
has_reliable_f16_math: true,
|
||||
has_reliable_f128: true,
|
||||
has_reliable_f128_math: true,
|
||||
has_reliable_f16,
|
||||
has_reliable_f16_math: has_reliable_f16,
|
||||
has_reliable_f128,
|
||||
has_reliable_f128_math: has_reliable_f128,
|
||||
}
|
||||
}
|
||||
|
14
src/type_.rs
14
src/type_.rs
@ -302,13 +302,13 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
||||
#[cfg_attr(feature = "master", allow(unused_mut))]
|
||||
fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
|
||||
#[cfg(not(feature = "master"))]
|
||||
if let Some(struct_type) = ty.is_struct() {
|
||||
if struct_type.get_field_count() == 0 {
|
||||
// NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
|
||||
// size of usize::MAX in test_binary_search, we workaround this by setting the size to
|
||||
// zero for ZSTs.
|
||||
len = 0;
|
||||
}
|
||||
if let Some(struct_type) = ty.is_struct()
|
||||
&& struct_type.get_field_count() == 0
|
||||
{
|
||||
// NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
|
||||
// size of usize::MAX in test_binary_search, we workaround this by setting the size to
|
||||
// zero for ZSTs.
|
||||
len = 0;
|
||||
}
|
||||
|
||||
self.context.new_array_type(None, ty, len)
|
||||
|
@ -217,7 +217,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
||||
let ty = match *self.ty.kind() {
|
||||
// NOTE: we cannot remove this match like in the LLVM codegen because the call
|
||||
// to fn_ptr_backend_type handle the on-stack attribute.
|
||||
// TODO(antoyo): find a less hackish way to hande the on-stack attribute.
|
||||
// TODO(antoyo): find a less hackish way to handle the on-stack attribute.
|
||||
ty::FnPtr(sig_tys, hdr) => cx
|
||||
.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())),
|
||||
_ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
|
||||
|
@ -1,26 +1,12 @@
|
||||
tests/ui/allocator/no_std-alloc-error-handler-custom.rs
|
||||
tests/ui/allocator/no_std-alloc-error-handler-default.rs
|
||||
tests/ui/asm/may_unwind.rs
|
||||
tests/ui/functions-closures/parallel-codegen-closures.rs
|
||||
tests/ui/linkage-attr/linkage1.rs
|
||||
tests/ui/lto/dylib-works.rs
|
||||
tests/ui/sepcomp/sepcomp-cci.rs
|
||||
tests/ui/sepcomp/sepcomp-extern.rs
|
||||
tests/ui/sepcomp/sepcomp-fns-backwards.rs
|
||||
tests/ui/sepcomp/sepcomp-fns.rs
|
||||
tests/ui/sepcomp/sepcomp-statics.rs
|
||||
tests/ui/asm/x86_64/may_unwind.rs
|
||||
tests/ui/panics/catch-unwind-bang.rs
|
||||
tests/ui/drop/dynamic-drop-async.rs
|
||||
tests/ui/cfg/cfg-panic-abort.rs
|
||||
tests/ui/drop/repeat-drop.rs
|
||||
tests/ui/coroutine/panic-drops-resume.rs
|
||||
tests/ui/fmt/format-args-capture.rs
|
||||
tests/ui/coroutine/panic-drops.rs
|
||||
tests/ui/intrinsics/panic-uninitialized-zeroed.rs
|
||||
tests/ui/iterators/iter-sum-overflow-debug.rs
|
||||
tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
|
||||
tests/ui/mir/mir_calls_to_shims.rs
|
||||
tests/ui/mir/mir_drop_order.rs
|
||||
tests/ui/mir/mir_let_chains_drop_order.rs
|
||||
tests/ui/oom_unwind.rs
|
||||
@ -31,27 +17,15 @@ tests/ui/unwind-no-uwtable.rs
|
||||
tests/ui/parser/unclosed-delimiter-in-dep.rs
|
||||
tests/ui/consts/missing_span_in_backtrace.rs
|
||||
tests/ui/drop/dynamic-drop.rs
|
||||
tests/ui/issues/issue-43853.rs
|
||||
tests/ui/issues/issue-47364.rs
|
||||
tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
|
||||
tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs
|
||||
tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
|
||||
tests/ui/simd/issue-17170.rs
|
||||
tests/ui/simd/issue-39720.rs
|
||||
tests/ui/alloc-error/default-alloc-error-hook.rs
|
||||
tests/ui/coroutine/panic-safe.rs
|
||||
tests/ui/issues/issue-14875.rs
|
||||
tests/ui/issues/issue-29948.rs
|
||||
tests/ui/panics/nested_panic_caught.rs
|
||||
tests/ui/process/println-with-broken-pipe.rs
|
||||
tests/ui/lto/thin-lto-inlines2.rs
|
||||
tests/ui/lto/weak-works.rs
|
||||
tests/ui/panic-runtime/lto-abort.rs
|
||||
tests/ui/lto/thin-lto-inlines.rs
|
||||
tests/ui/lto/thin-lto-global-allocator.rs
|
||||
tests/ui/lto/msvc-imp-present.rs
|
||||
tests/ui/panic-runtime/lto-abort.rs
|
||||
tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
|
||||
tests/ui/lto/all-crates.rs
|
||||
tests/ui/async-await/deep-futures-are-freeze.rs
|
||||
tests/ui/coroutine/resume-after-return.rs
|
||||
tests/ui/simd/masked-load-store.rs
|
||||
@ -59,15 +33,11 @@ tests/ui/simd/repr_packed.rs
|
||||
tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
|
||||
tests/ui/consts/try-operator.rs
|
||||
tests/ui/coroutine/unwind-abort-mix.rs
|
||||
tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
|
||||
tests/ui/impl-trait/equality-in-canonical-query.rs
|
||||
tests/ui/consts/issue-miri-1910.rs
|
||||
tests/ui/mir/mir_heavy_promoted.rs
|
||||
tests/ui/consts/const_cmp_type_id.rs
|
||||
tests/ui/consts/issue-73976-monomorphic.rs
|
||||
tests/ui/consts/issue-94675.rs
|
||||
tests/ui/traits/const-traits/const-drop-fail.rs
|
||||
tests/ui/traits/const-traits/const-drop.rs
|
||||
tests/ui/runtime/on-broken-pipe/child-processes.rs
|
||||
tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
|
||||
tests/ui/sanitizer/cfi/async-closures.rs
|
||||
@ -85,14 +55,9 @@ tests/ui/sanitizer/cfi/can-reveal-opaques.rs
|
||||
tests/ui/sanitizer/kcfi-mangling.rs
|
||||
tests/ui/statics/const_generics.rs
|
||||
tests/ui/backtrace/dylib-dep.rs
|
||||
tests/ui/errors/pic-linker.rs
|
||||
tests/ui/delegation/fn-header.rs
|
||||
tests/ui/consts/zst_no_llvm_alloc.rs
|
||||
tests/ui/consts/const-eval/parse_ints.rs
|
||||
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
|
||||
tests/ui/simd/intrinsic/generic-as.rs
|
||||
tests/ui/backtrace/backtrace.rs
|
||||
tests/ui/lifetimes/tail-expr-lock-poisoning.rs
|
||||
tests/ui/runtime/rt-explody-panic-payloads.rs
|
||||
tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
|
||||
tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
|
||||
@ -108,4 +73,9 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
|
||||
tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
|
||||
tests/ui/simd/simd-bitmask-notpow2.rs
|
||||
tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
|
||||
tests/ui/numbers-arithmetic/u128-as-f32.rs
|
||||
tests/ui/lto/all-crates.rs
|
||||
tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
|
||||
tests/ui/coroutine/panic-drops-resume.rs
|
||||
tests/ui/coroutine/panic-drops.rs
|
||||
tests/ui/coroutine/panic-safe.rs
|
||||
|
@ -57,10 +57,10 @@ pub fn main_inner(profile: Profile) {
|
||||
|
||||
#[cfg(not(feature = "master"))]
|
||||
fn filter(filename: &Path) -> bool {
|
||||
if let Some(filename) = filename.to_str() {
|
||||
if filename.ends_with("gep.rs") {
|
||||
return false;
|
||||
}
|
||||
if let Some(filename) = filename.to_str()
|
||||
&& filename.ends_with("gep.rs")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rust_filter(filename)
|
||||
}
|
||||
|
31
tests/run/packed_u128.rs
Normal file
31
tests/run/packed_u128.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Compiler:
|
||||
//
|
||||
// Run-time:
|
||||
// status: 0
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
#![no_main]
|
||||
|
||||
extern crate mini_core;
|
||||
use intrinsics::black_box;
|
||||
use mini_core::*;
|
||||
#[repr(packed(1))]
|
||||
pub struct ScalarInt {
|
||||
data: u128,
|
||||
size: u8,
|
||||
}
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
fn read_data(a: &ScalarInt) {
|
||||
black_box(a.data);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
|
||||
let data =
|
||||
[black_box(ScalarInt { data: 0, size: 1 }), black_box(ScalarInt { data: 0, size: 1 })];
|
||||
read_data(&data[1]);
|
||||
0
|
||||
}
|
2
tools/cspell_dicts/rust.txt
Normal file
2
tools/cspell_dicts/rust.txt
Normal file
@ -0,0 +1,2 @@
|
||||
lateout
|
||||
repr
|
75
tools/cspell_dicts/rustc_codegen_gcc.txt
Normal file
75
tools/cspell_dicts/rustc_codegen_gcc.txt
Normal file
@ -0,0 +1,75 @@
|
||||
aapcs
|
||||
addo
|
||||
archs
|
||||
ashl
|
||||
ashr
|
||||
cgcx
|
||||
clzll
|
||||
cmse
|
||||
codegened
|
||||
csky
|
||||
ctlz
|
||||
ctpop
|
||||
cttz
|
||||
ctzll
|
||||
flto
|
||||
fmaximumf
|
||||
fmuladd
|
||||
fmuladdf
|
||||
fminimumf
|
||||
fmul
|
||||
fptosi
|
||||
fptosui
|
||||
fptoui
|
||||
fwrapv
|
||||
gimple
|
||||
hrtb
|
||||
immediates
|
||||
liblto
|
||||
llbb
|
||||
llcx
|
||||
llextra
|
||||
llfn
|
||||
lgcc
|
||||
llmod
|
||||
llresult
|
||||
llret
|
||||
ltrans
|
||||
llty
|
||||
llval
|
||||
llvals
|
||||
loong
|
||||
lshr
|
||||
masm
|
||||
maximumf
|
||||
maxnumf
|
||||
mavx
|
||||
mcmodel
|
||||
minimumf
|
||||
minnumf
|
||||
monomorphization
|
||||
monomorphizations
|
||||
monomorphized
|
||||
monomorphizing
|
||||
movnt
|
||||
mulo
|
||||
nvptx
|
||||
pointee
|
||||
powitf
|
||||
reassoc
|
||||
riscv
|
||||
rlib
|
||||
roundevenf
|
||||
rustc
|
||||
sitofp
|
||||
sizet
|
||||
spir
|
||||
subo
|
||||
sysv
|
||||
tbaa
|
||||
uitofp
|
||||
unord
|
||||
uninlined
|
||||
utrunc
|
||||
xabort
|
||||
zext
|
@ -168,25 +168,39 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"../src/intrinsic/archs.rs",
|
||||
)
|
||||
# A hashmap of all architectures. This allows us to first match on the architecture, and then on the intrinsics.
|
||||
# This speeds up the comparison, and makes our code considerably smaller.
|
||||
# Since all intrinsic names start with "llvm.", we skip that prefix.
|
||||
print("Updating content of `{}`...".format(output_file))
|
||||
with open(output_file, "w", encoding="utf8") as out:
|
||||
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
|
||||
out.write("// DO NOT EDIT IT!\n")
|
||||
out.write("match name {\n")
|
||||
out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n")
|
||||
out.write("fn map_arch_intrinsic(name:&str)->&str{\n")
|
||||
out.write('let Some(name) = name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
|
||||
out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
|
||||
out.write("match arch {\n")
|
||||
for arch in archs:
|
||||
if len(intrinsics[arch]) == 0:
|
||||
continue
|
||||
out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str) -> &str {{ match name {{".format(arch,arch))
|
||||
intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
|
||||
out.write(' // {}\n'.format(arch))
|
||||
for entry in intrinsics[arch]:
|
||||
llvm_name = entry[0].removeprefix("llvm.");
|
||||
llvm_name = llvm_name.removeprefix(arch);
|
||||
llvm_name = llvm_name.removeprefix(".");
|
||||
if entry[2] is True: # if it is a duplicate
|
||||
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
|
||||
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
elif "_round_mask" in entry[1]:
|
||||
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(entry[0], entry[1]))
|
||||
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
else:
|
||||
out.write(' "{}" => "{}",\n'.format(entry[0], entry[1]))
|
||||
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
|
||||
out.write("}\n")
|
||||
out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
|
||||
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
|
||||
out.write("}} }} {}(name) }}\n,".format(arch))
|
||||
out.write(' _ => unimplemented!("***** unsupported LLVM architecture {}", name),\n')
|
||||
out.write("}\n}")
|
||||
subprocess.call(["rustfmt", output_file])
|
||||
print("Done!")
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user