Merge commit 'fda0bb9588' into subtree-update_cg_gcc_2025-06-18

This commit is contained in:
Guillaume Gomez 2025-06-18 15:11:44 +02:00
parent 265f4a7b63
commit efb79975f6
54 changed files with 11917 additions and 10357 deletions

27
.cspell.json Normal file
View 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*"
]
}

View file

@ -12,6 +12,8 @@ permissions:
env: env:
# Enable backtraces for easier debugging # Enable backtraces for easier debugging
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
# For the run-make tests.
LLVM_BIN_DIR: /usr/bin
jobs: jobs:
build: build:
@ -48,7 +50,7 @@ jobs:
- name: Install packages - name: Install packages
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. # `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 - name: Install rustfmt & clippy
run: rustup component add rustfmt clippy run: rustup component add rustfmt clippy
@ -61,11 +63,15 @@ jobs:
sudo dpkg --force-overwrite -i ${{ matrix.libgccjit_version.gcc }} sudo dpkg --force-overwrite -i ${{ matrix.libgccjit_version.gcc }}
echo 'gcc-path = "/usr/lib/"' > config.toml 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 - name: Set env
run: | run: |
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV 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 #- name: Cache rust repository
## We only clone the rust repository for rustc tests ## We only clone the rust repository for rustc tests
@ -76,12 +82,22 @@ jobs:
#path: rust #path: rust
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }} #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 - name: Build
run: | run: |
./y.sh prepare --only-libcore
./y.sh build --sysroot ./y.sh build --sysroot
./y.sh test --mini-tests ./y.sh test --cargo-tests
cargo test
- name: Run y.sh cargo build - name: Run y.sh cargo build
run: | run: |
@ -101,20 +117,19 @@ jobs:
run: | run: |
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} ./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: duplicates:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: python tools/check_intrinsics_duplicates.py - 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: build_system:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:

View file

@ -66,8 +66,8 @@ jobs:
run: | run: |
sudo dpkg --force-overwrite -i gcc-15.deb sudo dpkg --force-overwrite -i gcc-15.deb
echo 'gcc-path = "/usr/lib"' > config.toml 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 - name: Set env
run: | run: |

View file

@ -65,8 +65,8 @@ jobs:
- name: Set env - name: Set env
run: | run: |
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV 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 #- name: Cache rust repository
## We only clone the rust repository for rustc tests ## We only clone the rust repository for rustc tests
@ -95,7 +95,7 @@ jobs:
./y.sh prepare --only-libcore --cross ./y.sh prepare --only-libcore --cross
./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
./y.sh test --mini-tests ./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 ./y.sh clean all
- name: Prepare dependencies - name: Prepare dependencies

View file

@ -12,6 +12,8 @@ permissions:
env: env:
# Enable backtraces for easier debugging # Enable backtraces for easier debugging
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
# For the run-make tests.
LLVM_BIN_DIR: /usr/bin
jobs: jobs:
build: build:
@ -36,7 +38,8 @@ jobs:
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
- name: Install packages - 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 - name: Download artifact
run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb 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 sudo dpkg --force-overwrite -i gcc-15.deb
echo 'gcc-path = "/usr/lib/"' > config.toml 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 - name: Set env
run: | run: |
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
- name: Build - name: Build
run: | run: |
./y.sh prepare --only-libcore ./y.sh prepare --only-libcore
EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
./y.sh test --mini-tests ./y.sh test --cargo-tests
cargo test
./y.sh clean all ./y.sh clean all
- name: Prepare dependencies - name: Prepare dependencies

View file

@ -90,7 +90,7 @@ jobs:
if: ${{ !matrix.cargo_runner }} if: ${{ !matrix.cargo_runner }}
run: | run: |
./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore ./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 - name: Run stdarch tests
if: ${{ !matrix.cargo_runner }} if: ${{ !matrix.cargo_runner }}

3
.gitignore vendored
View file

@ -19,4 +19,5 @@ tools/llvmint-2
llvm llvm
build_system/target build_system/target
config.toml config.toml
build build
rustlantis

View file

@ -33,7 +33,7 @@ To run specific tests, use appropriate flags such as:
- `./y.sh test --test-libcore` - `./y.sh test --test-libcore`
- `./y.sh test --std-tests` - `./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`: Additionally, you can run the tests of `libgccjit`:

View file

@ -81,6 +81,18 @@ dependencies = [
"unicode-width", "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]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.1" version = "0.3.1"
@ -111,9 +123,9 @@ checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.14" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -137,6 +149,12 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.8.4" version = "1.8.4"
@ -166,9 +184,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.42" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -188,12 +206,12 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.14.0" version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [ dependencies = [
"cfg-if",
"fastrand", "fastrand",
"getrandom",
"once_cell", "once_cell",
"rustix", "rustix",
"windows-sys", "windows-sys",
@ -242,6 +260,15 @@ dependencies = [
"winapi-util", "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]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -345,3 +372,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 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",
]

View file

@ -31,7 +31,7 @@ gccjit = "2.7"
[dev-dependencies] [dev-dependencies]
boml = "0.3.1" boml = "0.3.1"
lang_tester = "0.8.0" lang_tester = "0.8.0"
tempfile = "3.7.1" tempfile = "3.20"
[profile.dev] [profile.dev]
# By compiling dependencies with optimizations, performing tests gets much faster. # By compiling dependencies with optimizations, performing tests gets much faster.

9
_typos.toml Normal file
View 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"]

View file

@ -1,24 +1,24 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.22.0" version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"gimli 0.29.0", "gimli",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
[[package]] [[package]]
name = "adler" name = "adler2"
version = "1.0.2" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -33,10 +33,21 @@ dependencies = [
] ]
[[package]] [[package]]
name = "allocator-api2" name = "alloctests"
version = "0.2.18" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -50,10 +61,11 @@ dependencies = [
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.118" version = "0.1.160"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895"
dependencies = [ dependencies = [
"cc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -61,11 +73,19 @@ dependencies = [
name = "core" name = "core"
version = "0.0.0" version = "0.0.0"
[[package]]
name = "coretests"
version = "0.0.0"
dependencies = [
"rand",
"rand_xorshift",
]
[[package]] [[package]]
name = "dlmalloc" name = "dlmalloc"
version = "0.2.6" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d" checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"compiler_builtins", "compiler_builtins",
@ -97,20 +117,9 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.29.0" version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
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"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
@ -119,11 +128,10 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [ dependencies = [
"allocator-api2",
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -131,9 +139,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.4.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
@ -142,9 +150,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.155" version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
dependencies = [ dependencies = [
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -161,11 +169,11 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.4" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler", "adler2",
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -173,9 +181,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.36.3" version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"memchr", "memchr",
@ -188,7 +196,6 @@ name = "panic_abort"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"alloc", "alloc",
"cfg-if",
"compiler_builtins", "compiler_builtins",
"core", "core",
"libc", "libc",
@ -211,14 +218,22 @@ name = "proc_macro"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"core", "core",
"rustc-literal-escaper",
"std", "std",
] ]
[[package]]
name = "profiler_builtins"
version = "0.0.0"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "r-efi" name = "r-efi"
version = "4.5.0" version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -226,15 +241,39 @@ dependencies = [
[[package]] [[package]]
name = "r-efi-alloc" name = "r-efi-alloc"
version = "1.0.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7" checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"r-efi", "r-efi",
"rustc-std-workspace-core", "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]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.24" version = "0.1.24"
@ -245,6 +284,15 @@ dependencies = [
"rustc-std-workspace-core", "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]] [[package]]
name = "rustc-std-workspace-alloc" name = "rustc-std-workspace-alloc"
version = "1.99.0" version = "1.99.0"
@ -266,6 +314,12 @@ dependencies = [
"std", "std",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "std" name = "std"
version = "0.0.0" version = "0.0.0"
@ -286,10 +340,13 @@ dependencies = [
"panic_unwind", "panic_unwind",
"r-efi", "r-efi",
"r-efi-alloc", "r-efi-alloc",
"rand",
"rand_xorshift",
"rustc-demangle", "rustc-demangle",
"std_detect", "std_detect",
"unwind", "unwind",
"wasi", "wasi",
"windows-targets 0.0.0",
] ]
[[package]] [[package]]
@ -298,6 +355,7 @@ version = "0.1.5"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"compiler_builtins", "compiler_builtins",
"libc",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -306,10 +364,8 @@ dependencies = [
name = "sysroot" name = "sysroot"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"alloc",
"compiler_builtins",
"core",
"proc_macro", "proc_macro",
"profiler_builtins",
"std", "std",
"test", "test",
] ]
@ -326,9 +382,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.13" version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -348,12 +404,12 @@ dependencies = [
[[package]] [[package]]
name = "unwinding" name = "unwinding"
version = "0.2.2" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"gimli 0.30.0", "gimli",
"rustc-std-workspace-core", "rustc-std-workspace-core",
] ]
@ -370,13 +426,17 @@ dependencies = [
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-targets"
version = "0.0.0"
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"

View file

@ -33,7 +33,7 @@ impl BuildArg {
} }
arg => { arg => {
if !build_arg.config_info.parse_argument(arg, &mut args)? { 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() { if !start_dir.is_dir() {
create_dir(start_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.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.lock", start_dir.join("Cargo.lock"))?;
let src_dir = start_dir.join("src"); let src_dir = start_dir.join("src");
if !src_dir.is_dir() { if !src_dir.is_dir() {
create_dir(&src_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> { 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(|_| ()) run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
}; };
walk_dir( 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.clone(),
&mut copier, &mut copier,
false, false,

View file

@ -17,12 +17,12 @@ enum CleanArg {
impl CleanArg { impl CleanArg {
fn new() -> Result<Self, String> { fn new() -> Result<Self, String> {
// We skip the binary and the "clean" option. // 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() { return match arg.as_str() {
"all" => Ok(Self::All), "all" => Ok(Self::All),
"ui-tests" => Ok(Self::UiTests), "ui-tests" => Ok(Self::UiTests),
"--help" => Ok(Self::Help), "--help" => Ok(Self::Help),
a => Err(format!("Unknown argument `{}`", a)), a => Err(format!("Unknown argument `{a}`")),
}; };
} }
Ok(Self::default()) Ok(Self::default())

View file

@ -43,7 +43,7 @@ impl Args {
} }
arg => { arg => {
if !command_args.config_info.parse_argument(arg, &mut args)? { 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(), Some(p) => p.into(),
None => PathBuf::from("./gcc"), 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)?; let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?;
if result.ran_clone { if result.ran_clone {
let gcc_commit = args.config_info.get_gcc_commit()?; 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( run_command_with_output(
&[&"git", &"checkout", &gcc_commit], &[&"git", &"checkout", &gcc_commit],
Some(Path::new(&result.repo_dir)), Some(Path::new(&result.repo_dir)),

View file

@ -66,7 +66,7 @@ impl ConfigFile {
"Expected a boolean for `download-gccjit`", "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) { match (config.gcc_path.as_mut(), config.download_gccjit) {
@ -86,9 +86,7 @@ impl ConfigFile {
let path = Path::new(gcc_path); let path = Path::new(gcc_path);
*gcc_path = path *gcc_path = path
.canonicalize() .canonicalize()
.map_err(|err| { .map_err(|err| format!("Failed to get absolute path of `{gcc_path}`: {err:?}"))?
format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err)
})?
.display() .display()
.to_string(); .to_string();
} }
@ -175,7 +173,7 @@ impl ConfigInfo {
"--sysroot-panic-abort" => self.sysroot_panic_abort = true, "--sysroot-panic-abort" => self.sysroot_panic_abort = true,
"--gcc-path" => match args.next() { "--gcc-path" => match args.next() {
Some(arg) if !arg.is_empty() => { 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()); 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); let libgccjit_so = output_dir.join(libgccjit_so_name);
if !libgccjit_so.is_file() && !self.no_download { if !libgccjit_so.is_file() && !self.no_download {
// Download time! // 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 tempfile = output_dir.join(&tempfile_name);
let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); 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 // We need to create a link named `libgccjit.so.0` because that's what the linker is
// looking for. // 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(); 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); self.gcc_path = Some(gcc_path);
Ok(()) Ok(())
} }
@ -286,8 +284,7 @@ impl ConfigInfo {
// since we already have everything we need. // since we already have everything we need.
if let Some(gcc_path) = &self.gcc_path { if let Some(gcc_path) = &self.gcc_path {
println!( println!(
"`--gcc-path` was provided, ignoring config file. Using `{}` as path for libgccjit", "`--gcc-path` was provided, ignoring config file. Using `{gcc_path}` as path for libgccjit"
gcc_path
); );
return Ok(()); return Ok(());
} }
@ -343,7 +340,7 @@ impl ConfigInfo {
self.dylib_ext = match os_name.as_str() { self.dylib_ext = match os_name.as_str() {
"Linux" => "so", "Linux" => "so",
"Darwin" => "dylib", "Darwin" => "dylib",
os => return Err(format!("unsupported OS `{}`", os)), os => return Err(format!("unsupported OS `{os}`")),
} }
.to_string(); .to_string();
let rustc = match env.get("RUSTC") { let rustc = match env.get("RUSTC") {
@ -355,10 +352,10 @@ impl ConfigInfo {
None => return Err("no host found".to_string()), None => return Err("no host found".to_string()),
}; };
if self.target_triple.is_empty() { if self.target_triple.is_empty()
if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") { && let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE")
self.target_triple = overwrite.clone(); {
} self.target_triple = overwrite.clone();
} }
if self.target_triple.is_empty() { if self.target_triple.is_empty() {
self.target_triple = self.host_triple.clone(); self.target_triple = self.host_triple.clone();
@ -378,7 +375,7 @@ impl ConfigInfo {
} }
let current_dir = 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 { let channel = if self.channel == Channel::Release {
"release" "release"
} else if let Some(channel) = env.get("CHANNEL") { } else if let Some(channel) = env.get("CHANNEL") {
@ -391,15 +388,15 @@ impl ConfigInfo {
self.cg_backend_path = current_dir self.cg_backend_path = current_dir
.join("target") .join("target")
.join(channel) .join(channel)
.join(&format!("librustc_codegen_gcc.{}", self.dylib_ext)) .join(format!("librustc_codegen_gcc.{}", self.dylib_ext))
.display() .display()
.to_string(); .to_string();
self.sysroot_path = 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 { if let Some(backend) = &self.backend {
// This option is only used in the rust compiler testsuite. The sysroot is handled // 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. // 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 { } else {
rustflags.extend_from_slice(&[ rustflags.extend_from_slice(&[
"--sysroot".to_string(), "--sysroot".to_string(),
@ -412,10 +409,10 @@ impl ConfigInfo {
// We have a different environment variable than RUSTFLAGS to make sure those flags are // 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. // only sent to rustc_codegen_gcc and not the LLVM backend.
if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { 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") { 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 { if let Some(linker) = linker {
@ -438,8 +435,8 @@ impl ConfigInfo {
env.insert("RUSTC_LOG".to_string(), "warn".to_string()); env.insert("RUSTC_LOG".to_string(), "warn".to_string());
let sysroot = current_dir let sysroot = current_dir
.join(&get_sysroot_dir()) .join(get_sysroot_dir())
.join(&format!("sysroot/lib/rustlib/{}/lib", self.target_triple)); .join(format!("sysroot/lib/rustlib/{}/lib", self.target_triple));
let ld_library_path = format!( let ld_library_path = format!(
"{target}:{sysroot}:{gcc_path}", "{target}:{sysroot}:{gcc_path}",
target = self.cargo_target_dir, target = self.cargo_target_dir,
@ -505,7 +502,7 @@ fn download_gccjit(
with_progress_bar: bool, with_progress_bar: bool,
) -> Result<(), String> { ) -> Result<(), String> {
let url = if std::env::consts::OS == "linux" && std::env::consts::ARCH == "x86_64" { 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 { } else {
eprintln!( 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. // Try curl. If that fails and we are on windows, fallback to PowerShell.
let mut ret = run_command_with_output( 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" }, if with_progress_bar { &"--progress-bar" } else { &"-s" },
&url.as_str(), &url.as_str(),
], ],
Some(&output_dir), Some(output_dir),
); );
if ret.is_err() && cfg!(windows) { if ret.is_err() && cfg!(windows) {
eprintln!("Fallback to PowerShell"); eprintln!("Fallback to PowerShell");
@ -549,12 +546,11 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
&"-Command", &"-Command",
&"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
&format!( &format!(
"(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", "(New-Object System.Net.WebClient).DownloadFile('{url}', '{tempfile_name}')",
url, tempfile_name,
) )
.as_str(), .as_str(),
], ],
Some(&output_dir), Some(output_dir),
); );
} }
ret ret

View file

@ -16,21 +16,21 @@ fn show_usage() {
pub fn run() -> Result<(), String> { pub fn run() -> Result<(), String> {
let mut check = false; let mut check = false;
// We skip binary name and the `info` command. // We skip binary name and the `info` command.
let mut args = std::env::args().skip(2); let args = std::env::args().skip(2);
while let Some(arg) = args.next() { for arg in args {
match arg.as_str() { match arg.as_str() {
"--help" => { "--help" => {
show_usage(); show_usage();
return Ok(()); return Ok(());
} }
"--check" => check = true, "--check" => check = true,
_ => return Err(format!("Unknown option {}", arg)), _ => return Err(format!("Unknown option {arg}")),
} }
} }
let cmd: &[&dyn AsRef<OsStr>] = let cmd: &[&dyn AsRef<OsStr>] =
if check { &[&"cargo", &"fmt", &"--check"] } else { &[&"cargo", &"fmt"] }; if check { &[&"cargo", &"fmt", &"--check"] } else { &[&"cargo", &"fmt"] };
run_command_with_output(cmd, Some(&Path::new(".")))?; 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("build_system")))
} }

289
build_system/src/fuzz.rs Normal file
View 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)
}

View 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");
}

View file

@ -15,7 +15,7 @@ pub fn run() -> Result<(), String> {
config.no_download = true; config.no_download = true;
config.setup_gcc_path()?; config.setup_gcc_path()?;
if let Some(gcc_path) = config.gcc_path { if let Some(gcc_path) = config.gcc_path {
println!("{}", gcc_path); println!("{gcc_path}");
} }
Ok(()) Ok(())
} }

View file

@ -5,6 +5,7 @@ mod clean;
mod clone_gcc; mod clone_gcc;
mod config; mod config;
mod fmt; mod fmt;
mod fuzz;
mod info; mod info;
mod prepare; mod prepare;
mod rust_tools; mod rust_tools;
@ -42,7 +43,8 @@ Commands:
test : Runs tests for the project. test : Runs tests for the project.
info : Displays information about the build environment and project configuration. info : Displays information about the build environment and project configuration.
clone-gcc : Clones the GCC compiler from a specified source. 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, Test,
Info, Info,
Fmt, Fmt,
Fuzz,
} }
fn main() { fn main() {
@ -75,6 +78,7 @@ fn main() {
Some("info") => Command::Info, Some("info") => Command::Info,
Some("clone-gcc") => Command::CloneGcc, Some("clone-gcc") => Command::CloneGcc,
Some("fmt") => Command::Fmt, Some("fmt") => Command::Fmt,
Some("fuzz") => Command::Fuzz,
Some("--help") => { Some("--help") => {
usage(); usage();
process::exit(0); process::exit(0);
@ -97,6 +101,7 @@ fn main() {
Command::Info => info::run(), Command::Info => info::run(),
Command::CloneGcc => clone_gcc::run(), Command::CloneGcc => clone_gcc::run(),
Command::Fmt => fmt::run(), Command::Fmt => fmt::run(),
Command::Fuzz => fuzz::run(),
} { } {
eprintln!("Command failed to run: {e}"); eprintln!("Command failed to run: {e}");
process::exit(1); process::exit(1);

View file

@ -18,9 +18,9 @@ fn prepare_libcore(
if let Some(path) = sysroot_source { if let Some(path) = sysroot_source {
rustlib_dir = Path::new(&path) rustlib_dir = Path::new(&path)
.canonicalize() .canonicalize()
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?; .map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
if !rustlib_dir.is_dir() { 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 { } else {
let rustc_path = match get_rustc_path() { let rustc_path = match get_rustc_path() {
@ -36,17 +36,17 @@ fn prepare_libcore(
rustlib_dir = parent rustlib_dir = parent
.join("../lib/rustlib/src/rust") .join("../lib/rustlib/src/rust")
.canonicalize() .canonicalize()
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?; .map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
if !rustlib_dir.is_dir() { if !rustlib_dir.is_dir() {
return Err("Please install `rust-src` component".to_string()); return Err("Please install `rust-src` component".to_string());
} }
} }
let sysroot_dir = sysroot_path.join("sysroot_src"); let sysroot_dir = sysroot_path.join("sysroot_src");
if sysroot_dir.is_dir() { if sysroot_dir.is_dir()
if let Err(error) = fs::remove_dir_all(&sysroot_dir) { && let Err(error) = fs::remove_dir_all(&sysroot_dir)
return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,)); {
} return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,));
} }
let sysroot_library_dir = sysroot_dir.join("library"); let sysroot_library_dir = sysroot_dir.join("library");
@ -122,7 +122,7 @@ fn prepare_rand() -> Result<(), String> {
// Apply patch for the rand crate. // Apply patch for the rand crate.
let file_path = "patches/crates/0001-Remove-deny-warnings.patch"; let file_path = "patches/crates/0001-Remove-deny-warnings.patch";
let rand_dir = Path::new("build/rand"); let rand_dir = Path::new("build/rand");
println!("[GIT] apply `{}`", file_path); println!("[GIT] apply `{file_path}`");
let path = Path::new("../..").join(file_path); let path = Path::new("../..").join(file_path);
run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?; run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?;
run_command_with_output(&[&"git", &"add", &"-A"], 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 where
F: Fn(&Path) -> Result<(), String>, 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 { if !clone_result.ran_clone {
println!("`{}` has already been cloned", clone_result.repo_name); println!("`{}` has already been cloned", clone_result.repo_name);
} }

View file

@ -1,24 +1,22 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
use std::path::PathBuf; use std::path::PathBuf;
use crate::config::ConfigInfo; use crate::config::ConfigInfo;
use crate::utils::{ use crate::utils::{get_toolchain, rustc_toolchain_version_info, rustc_version_info};
get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info,
rustc_version_info,
};
fn args(command: &str) -> Result<Option<Vec<String>>, String> { fn args(command: &str) -> Result<Option<Vec<String>>, String> {
// We skip the binary and the "cargo"/"rustc" option. // 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); usage(command);
return Ok(None); return Ok(None);
} }
let args = std::env::args().skip(2).collect::<Vec<_>>(); let args = std::env::args().skip(2).collect::<Vec<_>>();
if args.is_empty() { if args.is_empty() {
return Err(format!( return Err(format!(
"Expected at least one argument for `{}` subcommand, found none", "Expected at least one argument for `{command}` subcommand, found none"
command
)); ));
} }
Ok(Some(args)) Ok(Some(args))
@ -27,12 +25,11 @@ fn args(command: &str) -> Result<Option<Vec<String>>, String> {
fn usage(command: &str) { fn usage(command: &str) {
println!( println!(
r#" r#"
`{}` command help: `{command}` command help:
[args] : Arguments to be passed to the cargo command [args] : Arguments to be passed to the cargo command
--help : Show this help --help : Show this help
"#, "#,
command,
) )
} }
@ -51,10 +48,10 @@ impl RustcTools {
// expected. // expected.
let current_dir = std::env::current_dir() let current_dir = std::env::current_dir()
.and_then(|path| path.canonicalize()) .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() let current_exe = std::env::current_exe()
.and_then(|path| path.canonicalize()) .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 = let mut parent_dir =
current_exe.components().map(|comp| comp.as_os_str()).collect::<Vec<_>>(); 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. // 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| { std::env::set_current_dir(&parent_dir).map_err(|error| {
format!("Failed to go to `{}` folder: {:?}", parent_dir.display(), error) format!("Failed to go to `{}` folder: {:?}", parent_dir.display(), error)
})?; })?;
@ -92,11 +89,31 @@ impl RustcTools {
std::env::set_current_dir(&current_dir).map_err(|error| { std::env::set_current_dir(&current_dir).map_err(|error| {
format!("Failed to go back to `{}` folder: {:?}", current_dir.display(), 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 })) 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> { pub fn run_cargo() -> Result<(), String> {
let Some(mut tools) = RustcTools::new("cargo")? else { return Ok(()) }; let Some(mut tools) = RustcTools::new("cargo")? else { return Ok(()) };
let rustflags = tools.env.get("RUSTFLAGS").cloned().unwrap_or_default(); 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 { for arg in &tools.args {
command.push(arg); command.push(arg);
} }
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() { exec(&command, &tools.env)
std::process::exit(1);
}
Ok(())
} }
pub fn run_rustc() -> Result<(), String> { pub fn run_rustc() -> Result<(), String> {
@ -118,8 +131,5 @@ pub fn run_rustc() -> Result<(), String> {
for arg in &tools.args { for arg in &tools.args {
command.push(arg); command.push(arg);
} }
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() { exec(&command, &tools.env)
std::process::exit(1);
}
Ok(())
} }

View file

@ -9,8 +9,8 @@ use crate::build;
use crate::config::{Channel, ConfigInfo}; use crate::config::{Channel, ConfigInfo};
use crate::utils::{ use crate::utils::{
create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file, 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, run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env,
split_args, walk_dir, rustc_version_info, split_args, walk_dir,
}; };
type Env = HashMap<String, String>; 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("--extended-regex-tests", ("Run extended regex tests", extended_regex_tests));
runners.insert("--mini-tests", ("Run mini tests", mini_tests)); runners.insert("--mini-tests", ("Run mini tests", mini_tests));
runners.insert("--cargo-tests", ("Run cargo tests", cargo_tests));
runners runners
} }
@ -53,9 +53,9 @@ fn get_number_after_arg(
match args.next() { match args.next() {
Some(nb) if !nb.is_empty() => match usize::from_str(&nb) { Some(nb) if !nb.is_empty() => match usize::from_str(&nb) {
Ok(nb) => Ok(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() { for (option, (doc, _)) in get_runners() {
// FIXME: Instead of using the hard-coded `23` value, better to compute it instead. // FIXME: Instead of using the hard-coded `23` value, better to compute it instead.
let needed_spaces = 23_usize.saturating_sub(option.len()); let needed_spaces = 23_usize.saturating_sub(option.len());
let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect(); let spaces: String = std::iter::repeat_n(' ', needed_spaces).collect();
println!(" {}{}: {}", option, spaces, doc); println!(" {option}{spaces}: {doc}");
} }
println!(" --help : Show this help"); println!(" --help : Show this help");
} }
@ -88,6 +88,8 @@ struct TestArg {
use_system_gcc: bool, use_system_gcc: bool,
runners: Vec<String>, runners: Vec<String>,
flags: Vec<String>, flags: Vec<String>,
/// Additional arguments, to be passed to commands like `cargo test`.
test_args: Vec<String>,
nb_parts: Option<usize>, nb_parts: Option<usize>,
current_part: Option<usize>, current_part: Option<usize>,
sysroot_panic_abort: bool, sysroot_panic_abort: bool,
@ -137,13 +139,14 @@ impl TestArg {
test_arg.sysroot_features.push(feature); 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" => { "--help" => {
show_usage(); show_usage();
return Ok(None); return Ok(None);
} }
"--" => test_arg.test_args.extend(&mut args),
x if runners.contains_key(x) x if runners.contains_key(x)
&& !test_arg.runners.iter().any(|runner| runner == x) => && !test_arg.runners.iter().any(|runner| runner == x) =>
{ {
@ -151,7 +154,7 @@ impl TestArg {
} }
arg => { arg => {
if !test_arg.config_info.parse_argument(arg, &mut args)? { 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"); command.push(&"--release");
&tmp_env &tmp_env
} else { } else {
&env env
}; };
for flag in args.flags.iter() { for flag in args.flags.iter() {
command.push(flag); command.push(flag);
@ -203,6 +206,33 @@ fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
create_dir(&path) 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> { fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
// FIXME: create a function "display_if_not_quiet" or something along the line. // FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[BUILD] mini_core"); println!("[BUILD] mini_core");
@ -222,7 +252,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target", &"--target",
&args.config_info.target_triple, &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. // FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[BUILD] example"); println!("[BUILD] example");
@ -234,7 +264,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target", &"--target",
&args.config_info.target_triple, &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. // FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[AOT] mini_core_hello_world"); println!("[AOT] mini_core_hello_world");
@ -249,14 +279,14 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target", &"--target",
&args.config_info.target_triple, &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>] = &[ let command: &[&dyn AsRef<OsStr>] = &[
&Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"), &Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"),
&"abc", &"abc",
&"bcd", &"bcd",
]; ];
maybe_run_command_in_vm(&command, env, args)?; maybe_run_command_in_vm(command, env, args)?;
Ok(()) Ok(())
} }
@ -454,22 +484,47 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
} else { } else {
run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?; 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( let cargo = String::from_utf8(
run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, 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| { .and_then(|cargo| {
let cargo = cargo.trim().to_owned(); 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( let rustc = String::from_utf8(
run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))? run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?
.stdout, .stdout,
) )
.map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) .map_err(|error| format!("Failed to retrieve rustc path: {error:?}"))
.and_then(|rustc| { .and_then(|rustc| {
let rustc = rustc.trim().to_owned(); 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( 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-11 || \
which FileCheck-12 || \ which FileCheck-12 || \
which FileCheck-13 || \ which FileCheck-13 || \
which FileCheck-14", which FileCheck-14 || \
which FileCheck",
], ],
rust_dir, rust_dir,
Some(env), 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(), Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(),
Err(_) => { Err(_) => {
eprintln!("Failed to retrieve LLVM FileCheck, ignoring..."); 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() String::new()
} }
}; };
let file_path = rust_dir_path.join("config.toml"); let file_path = rust_dir_path.join("config.toml");
std::fs::write( std::fs::write(
&file_path, &file_path,
&format!( format!(
r#"change-id = 115898 r#"change-id = 115898
[rust] [rust]
@ -532,7 +590,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
let codegen_backend_path = format!( let codegen_backend_path = format!(
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}", "{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
pwd = std::env::current_dir() pwd = std::env::current_dir()
.map_err(|error| format!("`current_dir` failed: {:?}", error))? .map_err(|error| format!("`current_dir` failed: {error:?}"))?
.display(), .display(),
channel = args.config_info.channel.as_str(), channel = args.config_info.channel.as_str(),
dylib_ext = args.config_info.dylib_ext, dylib_ext = args.config_info.dylib_ext,
@ -587,11 +645,11 @@ where
F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>, F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>,
{ {
let toolchain = get_toolchain()?; let toolchain = get_toolchain()?;
let toolchain_arg = format!("+{}", toolchain); let toolchain_arg = format!("+{toolchain}");
let rustc_version = String::from_utf8( let rustc_version = String::from_utf8(
run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout, 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( let rustc_toolchain_version = String::from_utf8(
run_command_with_env( run_command_with_env(
&[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"], &[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"],
@ -600,20 +658,19 @@ where
)? )?
.stdout, .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 { if rustc_version != rustc_toolchain_version {
eprintln!( eprintln!(
"rustc_codegen_gcc is built for `{}` but the default rustc version is `{}`.", "rustc_codegen_gcc is built for `{rustc_toolchain_version}` but the default rustc version is `{rustc_version}`.",
rustc_toolchain_version, rustc_version,
); );
eprintln!("Using `{}`.", rustc_toolchain_version); eprintln!("Using `{rustc_toolchain_version}`.");
} }
let mut env = env.clone(); let mut env = env.clone();
let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
env.insert("RUSTDOCFLAGS".to_string(), rustflags); env.insert("RUSTDOCFLAGS".to_string(), rustflags);
let mut cargo_command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &toolchain_arg]; 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) callback(&cargo_command, cwd, &env)
} }
@ -680,7 +737,15 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
println!("[TEST] libcore"); println!("[TEST] libcore");
let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let path = get_sysroot_dir().join("sysroot_src/library/coretests");
let _ = remove_dir_all(path.join("target")); 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(()) Ok(())
} }
@ -818,7 +883,7 @@ fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<
// Tests generating errors. // Tests generating errors.
let file = File::open(file_path) let file = File::open(file_path)
.map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?; .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(); let line = line.trim();
if line.is_empty() { if line.is_empty() {
continue; continue;
@ -887,7 +952,7 @@ where
if !prepare_files_callback(&rust_path)? { if !prepare_files_callback(&rust_path)? {
// FIXME: create a function "display_if_not_quiet" or something along the line. // 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" { if test_type == "ui" {
@ -919,8 +984,7 @@ where
"borrowck", "borrowck",
"test-attrs", "test-attrs",
] ]
.iter() .contains(&dir_name)
.any(|name| *name == dir_name)
{ {
remove_dir_all(dir).map_err(|error| { remove_dir_all(dir).map_err(|error| {
format!("Failed to remove folder `{}`: {:?}", dir.display(), error) format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
@ -975,10 +1039,7 @@ where
if nb_parts > 0 { if nb_parts > 0 {
let current_part = args.current_part.unwrap(); let current_part = args.current_part.unwrap();
// FIXME: create a function "display_if_not_quiet" or something along the line. // FIXME: create a function "display_if_not_quiet" or something along the line.
println!( println!("Splitting ui_test into {nb_parts} parts (and running part {current_part})");
"Splitting ui_test into {} parts (and running part {})",
nb_parts, current_part
);
let out = String::from_utf8( let out = String::from_utf8(
run_command( run_command(
&[ &[
@ -996,7 +1057,7 @@ where
)? )?
.stdout, .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 let mut files = out
.split('\n') .split('\n')
.map(|line| line.trim()) .map(|line| line.trim())
@ -1016,7 +1077,7 @@ where
} }
// FIXME: create a function "display_if_not_quiet" or something along the line. // 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()); env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
let extra = let extra =
@ -1040,7 +1101,7 @@ where
&"always", &"always",
&"--stage", &"--stage",
&"0", &"0",
&format!("tests/{}", test_type), &format!("tests/{test_type}"),
&"--compiletest-rustc-args", &"--compiletest-rustc-args",
&rustc_args, &rustc_args,
], ],
@ -1051,19 +1112,18 @@ where
} }
fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> { 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") test_rustc_inner(env, args, |_| Ok(false), false, "ui")
} }
fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> { fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
let result1 = Ok(()); let result1 = test_rustc_inner(
/*test_rustc_inner(
env, env,
args, args,
retain_files_callback("tests/failing-run-make-tests.txt", "run-make"), retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
false, false,
"run-make", "run-make",
)*/ );
let result2 = test_rustc_inner( let result2 = test_rustc_inner(
env, env,
@ -1084,14 +1144,13 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
false, false,
"ui", "ui",
)?; )?;
Ok(()) test_rustc_inner(
/*test_rustc_inner(
env, env,
args, args,
remove_files_callback("tests/failing-run-make-tests.txt", "run-make"), remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
false, false,
"run-make", "run-make",
)*/ )
} }
fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String> { fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String> {
@ -1118,7 +1177,7 @@ fn retain_files_callback<'a>(
run_command( run_command(
&[ &[
&"find", &"find",
&format!("tests/{}", test_type), &format!("tests/{test_type}"),
&"-mindepth", &"-mindepth",
&"1", &"1",
&"-type", &"-type",
@ -1137,7 +1196,7 @@ fn retain_files_callback<'a>(
run_command( run_command(
&[ &[
&"find", &"find",
&format!("tests/{}", test_type), &format!("tests/{test_type}"),
&"-type", &"-type",
&"f", &"f",
&"-name", &"-name",
@ -1152,15 +1211,12 @@ fn retain_files_callback<'a>(
} }
// Putting back only the failing ones. // 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()) { 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 { } else {
println!( println!("Failed to read `{file_path}`, not putting back failing {test_type} tests");
"Failed to read `{}`, not putting back failing {} tests",
file_path, test_type
);
} }
Ok(true) Ok(true)
@ -1188,8 +1244,7 @@ fn remove_files_callback<'a>(
} }
} else { } else {
println!( println!(
"Failed to read `{}`, not putting back failing {} tests", "Failed to read `{file_path}`, not putting back failing {test_type} tests"
file_path, test_type
); );
} }
} else { } else {
@ -1202,7 +1257,7 @@ fn remove_files_callback<'a>(
remove_file(&path)?; remove_file(&path)?;
} }
} else { } 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) Ok(true)
@ -1217,7 +1272,9 @@ fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
// asm_tests(env, args)?; // asm_tests(env, args)?;
test_libcore(env, args)?; test_libcore(env, args)?;
extended_sysroot_tests(env, args)?; extended_sysroot_tests(env, args)?;
cargo_tests(env, args)?;
test_rustc(env, args)?; test_rustc(env, args)?;
Ok(()) Ok(())
} }

View file

@ -1,7 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
#[cfg(unix)]
use std::ffi::c_int;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs; use std::fs;
#[cfg(unix)] #[cfg(unix)]
@ -9,11 +7,6 @@ use std::os::unix::process::ExitStatusExt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus, Output}; use std::process::{Command, ExitStatus, Output};
#[cfg(unix)]
unsafe extern "C" {
fn raise(signal: c_int) -> c_int;
}
fn exec_command( fn exec_command(
input: &[&dyn AsRef<OsStr>], input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>, cwd: Option<&Path>,
@ -27,17 +20,14 @@ fn exec_command(
#[cfg(unix)] #[cfg(unix)]
{ {
if let Some(signal) = status.signal() { if let Some(signal) = status.signal() {
unsafe {
raise(signal as _);
}
// In case the signal didn't kill the current process. // 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) Ok(status)
} }
fn get_command_inner( pub(crate) fn get_command_inner(
input: &[&dyn AsRef<OsStr>], input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>, cwd: Option<&Path>,
env: Option<&HashMap<String, String>>, 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>>(); let input = input.iter().map(|i| i.as_ref()).collect::<Vec<&OsStr>>();
if show_err { if show_err {
eprintln!("Command `{:?}` failed", input); eprintln!("Command `{input:?}` failed");
} }
if let Some(output) = output { if let Some(output) = output {
let stdout = String::from_utf8_lossy(&output.stdout); let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.is_empty() { if !stdout.is_empty() {
error.push_str("\n==== STDOUT ====\n"); error.push_str("\n==== STDOUT ====\n");
error.push_str(&*stdout); error.push_str(&stdout);
} }
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
if !stderr.is_empty() { if !stderr.is_empty() {
error.push_str("\n==== STDERR ====\n"); error.push_str("\n==== STDERR ====\n");
error.push_str(&*stderr); error.push_str(&stderr);
} }
} }
Err(error) Err(error)
@ -136,6 +126,7 @@ pub fn run_command_with_output_and_env(
Ok(()) Ok(())
} }
#[cfg(not(unix))]
pub fn run_command_with_output_and_env_no_err( pub fn run_command_with_output_and_env_no_err(
input: &[&dyn AsRef<OsStr>], input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>, cwd: Option<&Path>,
@ -242,7 +233,7 @@ pub fn get_toolchain() -> Result<String, String> {
if !line.starts_with("channel") { if !line.starts_with("channel") {
return None; return None;
} }
line.split('"').skip(1).next() line.split('"').nth(1)
}) })
.next() .next()
{ {
@ -281,7 +272,7 @@ fn git_clone_inner(
} }
fn get_repo_name(url: &str) -> String { 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") { match repo_name.strip_suffix(".git") {
Some(n) => n.to_string(), Some(n) => n.to_string(),
None => repo_name.to_string(), None => repo_name.to_string(),

View file

@ -77,18 +77,18 @@ fn main() {
assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128); assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
// Check that all u/i128 <-> float casts work correctly. // Check that all u/i128 <-> float casts work correctly.
let houndred_u128 = 100u128; let hundred_u128 = 100u128;
let houndred_i128 = 100i128; let hundred_i128 = 100i128;
let houndred_f32 = 100.0f32; let hundred_f32 = 100.0f32;
let houndred_f64 = 100.0f64; let hundred_f64 = 100.0f64;
assert_eq!(houndred_u128 as f32, 100.0); assert_eq!(hundred_u128 as f32, 100.0);
assert_eq!(houndred_u128 as f64, 100.0); assert_eq!(hundred_u128 as f64, 100.0);
assert_eq!(houndred_f32 as u128, 100); assert_eq!(hundred_f32 as u128, 100);
assert_eq!(houndred_f64 as u128, 100); assert_eq!(hundred_f64 as u128, 100);
assert_eq!(houndred_i128 as f32, 100.0); assert_eq!(hundred_i128 as f32, 100.0);
assert_eq!(houndred_i128 as f64, 100.0); assert_eq!(hundred_i128 as f64, 100.0);
assert_eq!(houndred_f32 as i128, 100); assert_eq!(hundred_f32 as i128, 100);
assert_eq!(houndred_f64 as i128, 100); assert_eq!(hundred_f64 as i128, 100);
let _a = 1u32 << 2u8; let _a = 1u32 << 2u8;

View 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

View file

@ -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

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2025-05-12" channel = "nightly-2025-05-21"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"] components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -158,6 +158,7 @@ fn create_wrapper_function(
} }
} else { } else {
assert!(output.is_none()); assert!(output.is_none());
block.add_eval(None, ret);
block.end_with_void_return(None); block.end_with_void_return(None);
} }

View file

@ -1,3 +1,5 @@
// cSpell:ignoreRegExp [afkspqvwy]reg
use std::borrow::Cow; use std::borrow::Cow;
use gccjit::{LValue, RValue, ToRValue, Type}; 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()`. // `outputs.len() + inputs.len()`.
let mut labels = vec![]; 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![]; let mut clobbers = vec![];
// We're trying to preallocate space for the template // 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. // 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` // it will be treated as a lateout register with `out_place: None`
if !late { 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())) ("r", dummy_output_type(self.cx, reg.reg_class()))
} else { } 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!(), _ => unimplemented!(),
} }
} }

View file

@ -16,7 +16,7 @@ use crate::gcc_util::to_gcc_features;
/// Checks if the function `instance` is recursively inline. /// 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. /// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
#[cfg(feature = "master")] #[cfg(feature = "master")]
fn resursively_inline<'gcc, 'tcx>( fn recursively_inline<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>, cx: &CodegenCx<'gcc, 'tcx>,
instance: ty::Instance<'tcx>, instance: ty::Instance<'tcx>,
) -> bool { ) -> bool {
@ -61,7 +61,7 @@ fn inline_attr<'gcc, 'tcx>(
// //
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost. // 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. // 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) Some(FnAttribute::Inline)
} else { } else {
Some(FnAttribute::AlwaysInline) Some(FnAttribute::AlwaysInline)

View file

@ -11,11 +11,12 @@
// does not remove it? // does not remove it?
// //
// TODO(antoyo): for performance, check which optimizations the C++ frontend enables. // TODO(antoyo): for performance, check which optimizations the C++ frontend enables.
// // cSpell:disable
// Fix these warnings: // 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 `_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: 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 // /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::ffi::{CStr, CString};
use std::fs::{self, File}; use std::fs::{self, File};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};

View file

@ -186,6 +186,7 @@ pub(crate) fn codegen(
if fat_lto { if fat_lto {
let lto_path = format!("{}.lto", path); let lto_path = format!("{}.lto", path);
// cSpell:disable
// FIXME(antoyo): The LTO frontend generates the following warning: // 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] // ../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]; // 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 // 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. // 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"); context.add_driver_option("-Wno-lto-type-mismatch");
// NOTE: this doesn't actually generate an executable. With the above // NOTE: this doesn't actually generate an executable. With the above
// flags, it combines the .o files together in another .o. // flags, it combines the .o files together in another .o.

View file

@ -765,7 +765,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
#[cfg(feature = "master")] #[cfg(feature = "master")]
match self.cx.type_kind(a_type) { 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"); let fmodf = self.context.get_builtin_function("fmodf");
return self.context.new_call(self.location, fmodf, &[a, b]); 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]); return self.context.new_call(self.location, fmod, &[a, b]);
} }
TypeKind::FP128 => { TypeKind::FP128 => {
let fmodl = self.context.get_builtin_function("fmodl"); let f128_type = self.type_f128();
return self.context.new_call(self.location, fmodl, &[a, b]); 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. // dereference after a drop, for instance.
// FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. // 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. // 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 pointee_ty
} else { } else {
pointee_ty.get_aligned(align.bytes()) 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 b_offset = a.size(self).align_to(b.align(self).abi);
let mut load = |i, scalar: &abi::Scalar, align| { let mut load = |i, scalar: &abi::Scalar, align| {
let llptr = if i == 0 { let ptr = if i == 0 {
place.val.llval place.val.llval
} else { } else {
self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes())) self.inbounds_ptradd(place.val.llval, self.const_usize(b_offset.bytes()))
}; };
let llty = place.layout.scalar_pair_element_gcc_type(self, i); 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); scalar_load_metadata(self, load, scalar);
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
}; };

View file

@ -34,7 +34,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
unreachable!(); unreachable!();
/* /*
// Create a fn pointer with the new signature. // 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 // This is subtle and surprising, but sometimes we have to bitcast
// the resulting fn pointer. The reason has to do with external // 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 // This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some // reference. It also occurs when testing libcore and in some
// other weird situations. Annoying. // other weird situations. Annoying.
if cx.val_ty(func) != ptrty { if cx.val_ty(func) != ptrtype {
// TODO(antoyo): cast the pointer. // TODO(antoyo): cast the pointer.
func func
} }

View file

@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability;
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use crate::consts::const_alloc_to_gcc;
use crate::context::CodegenCx; use crate::context::CodegenCx;
use crate::type_of::LayoutGccExt; 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> { pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
let context = &cx.context; // Instead of always using an array of bytes, use an array of larger integers of target endianness
let byte_type = context.new_type::<u8>(); // if possible. This reduces the amount of `rvalues` we use, which reduces memory usage significantly.
let typ = context.new_array_type(None, byte_type, bytes.len() as u64); //
let elements: Vec<_> = // FIXME(FractalFir): Consider using `global_set_initializer` instead. Before this is done, we need to confirm that
bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect(); // `global_set_initializer` is more memory efficient than the current solution.
context.new_array_constructor(None, typ, &elements) // `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 { 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 // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
// the paths for floating-point values. // the paths for floating-point values.
if ty == self.float_type { // TODO: Remove this code?
/*if ty == self.float_type {
return self return self
.context .context
.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
} }
if ty == self.double_type { if ty == self.double_type {
return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); 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 value = self.const_uint_big(self.type_ix(bitsize), data);
let bytesize = layout.size(self).bytes(); 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 alloc_id = prov.alloc_id();
let base_addr = match self.tcx.global_alloc(alloc_id) { let base_addr = match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => { 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 alloc = alloc.inner();
let value = match alloc.mutability { let value = match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), 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(); .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) self.static_addr_of(init, alloc.inner().align, None)
} }
GlobalAlloc::Static(def_id) => { 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 { 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 { fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {

View file

@ -36,18 +36,14 @@ fn set_global_alignment<'gcc, 'tcx>(
impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'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> { 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 if let Some(variable) = self.const_globals.borrow().get(&cv) {
// following: if let Some(global_variable) = self.global_lvalues.borrow().get(variable) {
for (value, variable) in &*self.const_globals.borrow() { let alignment = align.bits() as i32;
if format!("{:?}", value) == format!("{:?}", cv) { if alignment > global_variable.get_alignment() {
if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { global_variable.set_alignment(alignment);
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); let global_value = self.static_addr_of_mut(cv, align, kind);
#[cfg(feature = "master")] #[cfg(feature = "master")]
@ -288,8 +284,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
global global
} }
} }
/// Converts a given const alloc to a gcc Rvalue, without any caching or deduplication.
pub fn const_alloc_to_gcc<'gcc>( /// 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, '_>, cx: &CodegenCx<'gcc, '_>,
alloc: ConstAllocation<'_>, alloc: ConstAllocation<'_>,
) -> RValue<'gcc> { ) -> RValue<'gcc> {
@ -321,7 +319,7 @@ pub fn const_alloc_to_gcc<'gcc>(
// and we properly interpret the provenance as a relocation pointer offset. // and we properly interpret the provenance as a relocation pointer offset.
alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), 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; as u64;
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); 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, def_id: DefId,
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> { ) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?; 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>( fn check_and_apply_linkage<'gcc, 'tcx>(

View file

@ -1,14 +1,16 @@
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use gccjit::{ use gccjit::{
Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type, 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::base::wants_msvc_seh;
use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::layout::{ use rustc_middle::ty::layout::{
@ -28,6 +30,8 @@ use crate::common::SignType;
#[cfg_attr(not(feature = "master"), allow(dead_code))] #[cfg_attr(not(feature = "master"), allow(dead_code))]
pub struct CodegenCx<'gcc, 'tcx> { 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 codegen_unit: &'tcx CodegenUnit<'tcx>,
pub context: &'gcc Context<'gcc>, pub context: &'gcc Context<'gcc>,
@ -129,6 +133,9 @@ pub struct CodegenCx<'gcc, 'tcx> {
#[cfg(feature = "master")] #[cfg(feature = "master")]
pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>, 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> { impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@ -220,6 +227,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
} }
let mut cx = Self { 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, codegen_unit,
context, context,
current_func: RefCell::new(None), 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 // `rust_eh_personality` function, but rather we wired it up to the
// CRT's custom personality function, which forces LLVM to consider // CRT's custom personality function, which forces LLVM to consider
// landing pads as "landing pads for SEH". // landing pads as "landing pads for SEH".
if let Some(llpersonality) = self.eh_personality.get() { if let Some(personality_func) = self.eh_personality.get() {
return llpersonality; return personality_func;
} }
let tcx = self.tcx; let tcx = self.tcx;
let func = match tcx.lang_items().eh_personality() { let func = match tcx.lang_items().eh_personality() {

View file

@ -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 // 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]> { 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 }; let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
// cSpell:disable
match (arch, s) { match (arch, s) {
// FIXME: seems like x87 does not exist? // FIXME: seems like x87 does not exist?
("x86", "x87") => smallvec![], ("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"], ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
(_, s) => smallvec![s], (_, s) => smallvec![s],
} }
// cSpell:enable
} }
fn arch_to_gcc(name: &str) -> &str { fn arch_to_gcc(name: &str) -> &str {

View file

@ -2,6 +2,8 @@
//! This module exists because some integer types are not supported on some gcc platforms, e.g. //! 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. //! 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 gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
use rustc_abi::{CanonAbi, Endian, ExternAbi}; use rustc_abi::{CanonAbi, Endian, ExternAbi};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; 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()); debug_assert!(value_type.dyncast_array().is_some());
let name_suffix = match self.type_kind(dest_typ) { let name_suffix = match self.type_kind(dest_typ) {
// cSpell:disable
TypeKind::Float => "tisf", TypeKind::Float => "tisf",
TypeKind::Double => "tidf", TypeKind::Double => "tidf",
TypeKind::FP128 => "tixf", TypeKind::FP128 => "titf",
// cSpell:enable
kind => panic!("cannot cast a non-native integer to type {:?}", kind), kind => panic!("cannot cast a non-native integer to type {:?}", kind),
}; };
let sign = if signed { "" } else { "un" }; let sign = if signed { "" } else { "un" };
@ -957,8 +961,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
debug_assert!(dest_typ.dyncast_array().is_some()); debug_assert!(dest_typ.dyncast_array().is_some());
let name_suffix = match self.type_kind(value_type) { let name_suffix = match self.type_kind(value_type) {
// cSpell:disable
TypeKind::Float => "sfti", TypeKind::Float => "sfti",
TypeKind::Double => "dfti", TypeKind::Double => "dfti",
// cSpell:enable
kind => panic!("cannot cast a {:?} to non-native integer", kind), kind => panic!("cannot cast a {:?} to non-native integer", kind),
}; };
let sign = if signed { "" } else { "uns" }; let sign = if signed { "" } else { "uns" };

File diff suppressed because it is too large Load diff

View file

@ -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); let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func); cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func; func
} }
#[cfg(feature = "master")] #[cfg(feature = "master")]
@ -1548,10 +1548,13 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.x86.tcmmrlfp16ps" => "__builtin_trap", "llvm.x86.tcmmrlfp16ps" => "__builtin_trap",
// NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py // 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); let func = cx.context.get_target_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func); cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
func func
} }
#[cfg(feature = "master")]
include!("archs.rs");

View file

@ -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> { impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn codegen_intrinsic_call( fn codegen_intrinsic_call(
&mut self, &mut self,
@ -211,7 +300,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let fn_args = instance.args; let fn_args = instance.args;
let simple = get_simple_intrinsic(self, name); 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: // FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved:
// https://github.com/rust-lang/rust-clippy/issues/12497 // 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<_>>(), &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
) )
} }
sym::fmaf16 => { sym::ceilf16
// TODO(antoyo): use the correct builtin for f16. | sym::floorf16
let func = self.cx.context.get_builtin_function("fmaf"); | sym::fmaf16
let args: Vec<_> = args | sym::maxnumf16
.iter() | sym::minnumf16
.map(|arg| { | sym::powf16
self.cx.context.new_cast(self.location, arg.immediate(), self.cx.type_f32()) | sym::powif16
}) | sym::roundf16
.collect(); | sym::round_ties_even_f16
let result = self.cx.context.new_call(self.location, func, &args); | sym::sqrtf16
self.cx.context.new_cast(self.location, result, self.cx.type_f16()) | 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 => { sym::is_val_statically_known => {
let a = args[0].immediate(); let a = args[0].immediate();
@ -526,7 +655,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
fn type_checked_load( fn type_checked_load(
&mut self, &mut self,
_llvtable: Self::Value, _vtable: Self::Value,
_vtable_byte_offset: u64, _vtable_byte_offset: u64,
_typeid: Self::Value, _typeid: Self::Value,
) -> 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... // We instead thus allocate some scratch space...
let scratch_size = cast.size(bx); let scratch_size = cast.size(bx);
let scratch_align = cast.align(bx); let scratch_align = cast.align(bx);
let llscratch = bx.alloca(scratch_size, scratch_align); let scratch = bx.alloca(scratch_size, scratch_align);
bx.lifetime_start(llscratch, scratch_size); bx.lifetime_start(scratch, scratch_size);
// ... where we first store the value... // ... 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. // ... and then memcpy it to the intended destination.
bx.memcpy( bx.memcpy(
dst.val.llval, dst.val.llval,
self.layout.align.abi, self.layout.align.abi,
llscratch, scratch,
scratch_align, scratch_align,
bx.const_usize(self.layout.size.bytes()), bx.const_usize(self.layout.size.bytes()),
MemFlags::empty(), MemFlags::empty(),
); );
bx.lifetime_end(llscratch, scratch_size); bx.lifetime_end(scratch, scratch_size);
} }
} else { } else {
OperandValue::Immediate(val).store(bx, dst); OperandValue::Immediate(val).store(bx, dst);

View file

@ -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_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 (_, element_ty2) = args[2].layout.ty.simd_size_and_type(bx.tcx());
let (pointer_count, underlying_ty) = match *element_ty1.kind() { 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)) (ptr_count(element_ty1), non_ptr(element_ty1))
} }
_ => { _ => {

View file

@ -3,10 +3,12 @@
* TODO(antoyo): support #[inline] attributes. * 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). * 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: * 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. * 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)? * 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. * Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans.
* TODO: disable debug info always being emitted. Perhaps this slows down things? * TODO: disable debug info always being emitted. Perhaps this slows down things?
* *
@ -206,7 +208,7 @@ impl CodegenBackend for GccCodegenBackend {
#[cfg(not(feature = "master"))] #[cfg(not(feature = "master"))]
{ {
let temp_dir = TempDir::new().expect("cannot create temporary directory"); 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(); let check_context = Context::default();
check_context.set_print_errors_to_stderr(false); check_context.set_print_errors_to_stderr(false);
let _int128_ty = check_context.new_c_type(CType::UInt128t); let _int128_ty = check_context.new_c_type(CType::UInt128t);
@ -430,10 +432,11 @@ impl WriteBackendMethods for GccCodegenBackend {
) -> Result<ModuleCodegen<Self::Module>, FatalError> { ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::write::link(cgcx, dcx, modules) back::write::link(cgcx, dcx, modules)
} }
fn autodiff( fn autodiff(
_cgcx: &CodegenContext<Self>, _cgcx: &CodegenContext<Self>,
_module: &ModuleCodegen<Self::Module>, _module: &ModuleCodegen<Self::Module>,
_diff_fncs: Vec<AutoDiffItem>, _diff_functions: Vec<AutoDiffItem>,
_config: &ModuleConfig, _config: &ModuleConfig,
) -> Result<(), FatalError> { ) -> Result<(), FatalError> {
unimplemented!() unimplemented!()
@ -494,12 +497,14 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig
return false; return false;
} }
target_info.cpu_supports(feature) target_info.cpu_supports(feature)
// cSpell:disable
/* /*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, 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 sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
*/ */
// cSpell:enable
}) })
.map(Symbol::intern) .map(Symbol::intern)
.collect() .collect()
@ -508,13 +513,16 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig
let target_features = f(false); let target_features = f(false);
let unstable_target_features = f(true); 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 { TargetConfig {
target_features, target_features,
unstable_target_features, unstable_target_features,
// There are no known bugs with GCC support for f16 or f128 // There are no known bugs with GCC support for f16 or f128
has_reliable_f16: true, has_reliable_f16,
has_reliable_f16_math: true, has_reliable_f16_math: has_reliable_f16,
has_reliable_f128: true, has_reliable_f128,
has_reliable_f128_math: true, has_reliable_f128_math: has_reliable_f128,
} }
} }

View file

@ -302,13 +302,13 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
#[cfg_attr(feature = "master", allow(unused_mut))] #[cfg_attr(feature = "master", allow(unused_mut))]
fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
#[cfg(not(feature = "master"))] #[cfg(not(feature = "master"))]
if let Some(struct_type) = ty.is_struct() { if let Some(struct_type) = ty.is_struct()
if struct_type.get_field_count() == 0 { && 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 // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
// zero for ZSTs. // size of usize::MAX in test_binary_search, we workaround this by setting the size to
len = 0; // zero for ZSTs.
} len = 0;
} }
self.context.new_array_type(None, ty, len) self.context.new_array_type(None, ty, len)

View file

@ -217,7 +217,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
let ty = match *self.ty.kind() { let ty = match *self.ty.kind() {
// NOTE: we cannot remove this match like in the LLVM codegen because the call // NOTE: we cannot remove this match like in the LLVM codegen because the call
// to fn_ptr_backend_type handle the on-stack attribute. // 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 ty::FnPtr(sig_tys, hdr) => cx
.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())), .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), _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),

View file

@ -1,26 +1,12 @@
tests/ui/allocator/no_std-alloc-error-handler-custom.rs tests/ui/allocator/no_std-alloc-error-handler-custom.rs
tests/ui/allocator/no_std-alloc-error-handler-default.rs tests/ui/allocator/no_std-alloc-error-handler-default.rs
tests/ui/asm/may_unwind.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/asm/x86_64/may_unwind.rs
tests/ui/panics/catch-unwind-bang.rs
tests/ui/drop/dynamic-drop-async.rs tests/ui/drop/dynamic-drop-async.rs
tests/ui/cfg/cfg-panic-abort.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/intrinsics/panic-uninitialized-zeroed.rs
tests/ui/iterators/iter-sum-overflow-debug.rs tests/ui/iterators/iter-sum-overflow-debug.rs
tests/ui/iterators/iter-sum-overflow-overflow-checks.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_drop_order.rs
tests/ui/mir/mir_let_chains_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs
tests/ui/oom_unwind.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/parser/unclosed-delimiter-in-dep.rs
tests/ui/consts/missing_span_in_backtrace.rs tests/ui/consts/missing_span_in_backtrace.rs
tests/ui/drop/dynamic-drop.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/rfcs/rfc-2091-track-caller/std-panic-locations.rs
tests/ui/simd/issue-17170.rs tests/ui/simd/issue-17170.rs
tests/ui/simd/issue-39720.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-14875.rs
tests/ui/issues/issue-29948.rs tests/ui/issues/issue-29948.rs
tests/ui/panics/nested_panic_caught.rs
tests/ui/process/println-with-broken-pipe.rs tests/ui/process/println-with-broken-pipe.rs
tests/ui/lto/thin-lto-inlines2.rs tests/ui/lto/thin-lto-inlines2.rs
tests/ui/lto/weak-works.rs tests/ui/panic-runtime/lto-abort.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/lto/lto-thin-rustc-loads-linker-plugin.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/async-await/deep-futures-are-freeze.rs
tests/ui/coroutine/resume-after-return.rs tests/ui/coroutine/resume-after-return.rs
tests/ui/simd/masked-load-store.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/async-await/in-trait/dont-project-to-specializable-projection.rs
tests/ui/consts/try-operator.rs tests/ui/consts/try-operator.rs
tests/ui/coroutine/unwind-abort-mix.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/consts/issue-miri-1910.rs
tests/ui/mir/mir_heavy_promoted.rs
tests/ui/consts/const_cmp_type_id.rs tests/ui/consts/const_cmp_type_id.rs
tests/ui/consts/issue-73976-monomorphic.rs tests/ui/consts/issue-73976-monomorphic.rs
tests/ui/consts/issue-94675.rs tests/ui/consts/issue-94675.rs
tests/ui/traits/const-traits/const-drop-fail.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/runtime/on-broken-pipe/child-processes.rs
tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
tests/ui/sanitizer/cfi/async-closures.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/sanitizer/kcfi-mangling.rs
tests/ui/statics/const_generics.rs tests/ui/statics/const_generics.rs
tests/ui/backtrace/dylib-dep.rs tests/ui/backtrace/dylib-dep.rs
tests/ui/errors/pic-linker.rs
tests/ui/delegation/fn-header.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/consts/const-eval/parse_ints.rs
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
tests/ui/simd/intrinsic/generic-as.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/runtime/rt-explody-panic-payloads.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.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/codegen/equal-pointers-unequal/strict-provenance/zero.rs
tests/ui/simd/simd-bitmask-notpow2.rs tests/ui/simd/simd-bitmask-notpow2.rs
tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.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/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

View file

@ -57,10 +57,10 @@ pub fn main_inner(profile: Profile) {
#[cfg(not(feature = "master"))] #[cfg(not(feature = "master"))]
fn filter(filename: &Path) -> bool { fn filter(filename: &Path) -> bool {
if let Some(filename) = filename.to_str() { if let Some(filename) = filename.to_str()
if filename.ends_with("gep.rs") { && filename.ends_with("gep.rs")
return false; {
} return false;
} }
rust_filter(filename) rust_filter(filename)
} }

31
tests/run/packed_u128.rs Normal file
View 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
}

View file

@ -0,0 +1,2 @@
lateout
repr

View 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

View file

@ -168,25 +168,39 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
"../src/intrinsic/archs.rs", "../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)) print("Updating content of `{}`...".format(output_file))
with open(output_file, "w", encoding="utf8") as out: with open(output_file, "w", encoding="utf8") as out:
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n") out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
out.write("// DO NOT EDIT IT!\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: for arch in archs:
if len(intrinsics[arch]) == 0: if len(intrinsics[arch]) == 0:
continue 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])) intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
out.write(' // {}\n'.format(arch)) out.write(' // {}\n'.format(arch))
for entry in intrinsics[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 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]: 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: else:
out.write(' "{}" => "{}",\n'.format(entry[0], entry[1])) out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n') out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
out.write("}\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!") print("Done!")